/ Check-in [bf984e98]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix the row-values in UPDATE statements within TRIGGER problem identified by ticket [8c9458e7].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | branch-3.16
Files: files | file ages | folders
SHA1: bf984e980c14c9adc54ad010d3a7d199dd53edd6
User & Date: drh 2017-01-03 15:57:18
Context
2017-01-03
15:59
Defer size checking on row-value assignments for when the RHS is a SELECT until after the "*" wildcards have been expanded. check-in: 5c892938 user: drh tags: branch-3.16
15:57
Fix the row-values in UPDATE statements within TRIGGER problem identified by ticket [8c9458e7]. check-in: bf984e98 user: drh tags: branch-3.16
01:24
Fix the row-values in UPDATE statements within TRIGGER problem identified by ticket [8c9458e7]. check-in: f12ed3ce user: drh tags: trunk
2017-01-02
11:57
Version 3.16.0 check-in: 04ac0b75 user: drh tags: trunk, release, version-3.16.0
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/expr.c.

  1084   1084   ** to enforce this constraint.
  1085   1085   */
  1086   1086   static int dupedExprStructSize(Expr *p, int flags){
  1087   1087     int nSize;
  1088   1088     assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
  1089   1089     assert( EXPR_FULLSIZE<=0xfff );
  1090   1090     assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
  1091         -  if( 0==flags ){
         1091  +  if( 0==flags || p->op==TK_SELECT_COLUMN ){
  1092   1092       nSize = EXPR_FULLSIZE;
  1093   1093     }else{
  1094   1094       assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
  1095   1095       assert( !ExprHasProperty(p, EP_FromJoin) ); 
  1096   1096       assert( !ExprHasProperty(p, EP_MemToken) );
  1097   1097       assert( !ExprHasProperty(p, EP_NoReduce) );
  1098   1098       if( p->pLeft || p->x.pList ){
................................................................................
  1227   1227         if( pzBuffer ){
  1228   1228           *pzBuffer = zAlloc;
  1229   1229         }
  1230   1230       }else{
  1231   1231         if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
  1232   1232           if( pNew->op==TK_SELECT_COLUMN ){
  1233   1233             pNew->pLeft = p->pLeft;
         1234  +          assert( p->iColumn==0 || p->pRight==0 );
         1235  +          assert( p->pRight==0  || p->pRight==p->pLeft );
  1234   1236           }else{
  1235   1237             pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
  1236   1238           }
  1237   1239           pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
  1238   1240         }
  1239   1241       }
  1240   1242     }
................................................................................
  1289   1291     assert( flags==0 || flags==EXPRDUP_REDUCE );
  1290   1292     return p ? exprDup(db, p, flags, 0) : 0;
  1291   1293   }
  1292   1294   ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
  1293   1295     ExprList *pNew;
  1294   1296     struct ExprList_item *pItem, *pOldItem;
  1295   1297     int i;
         1298  +  Expr *pPriorSelectCol = 0;
  1296   1299     assert( db!=0 );
  1297   1300     if( p==0 ) return 0;
  1298   1301     pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
  1299   1302     if( pNew==0 ) return 0;
  1300   1303     pNew->nExpr = i = p->nExpr;
  1301   1304     if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
  1302   1305     pNew->a = pItem = sqlite3DbMallocRawNN(db,  i*sizeof(p->a[0]) );
................................................................................
  1303   1306     if( pItem==0 ){
  1304   1307       sqlite3DbFree(db, pNew);
  1305   1308       return 0;
  1306   1309     } 
  1307   1310     pOldItem = p->a;
  1308   1311     for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
  1309   1312       Expr *pOldExpr = pOldItem->pExpr;
         1313  +    Expr *pNewExpr;
  1310   1314       pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags);
         1315  +    if( pOldExpr 
         1316  +     && pOldExpr->op==TK_SELECT_COLUMN
         1317  +     && (pNewExpr = pItem->pExpr)!=0 
         1318  +    ){
         1319  +      assert( pNewExpr->iColumn==0 || i>0 );
         1320  +      if( pNewExpr->iColumn==0 ){
         1321  +        assert( pOldExpr->pLeft==pOldExpr->pRight );
         1322  +        pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight;
         1323  +      }else{
         1324  +        assert( i>0 );
         1325  +        assert( pItem[-1].pExpr!=0 );
         1326  +        assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 );
         1327  +        assert( pPriorSelectCol==pItem[-1].pExpr->pLeft );
         1328  +        pNewExpr->pLeft = pPriorSelectCol;
         1329  +      }
         1330  +    }
  1311   1331       pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
  1312   1332       pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
  1313   1333       pItem->sortOrder = pOldItem->sortOrder;
  1314   1334       pItem->done = 0;
  1315   1335       pItem->bSpanIsTab = pOldItem->bSpanIsTab;
  1316   1336       pItem->u = pOldItem->u;
  1317   1337     }

Changes to test/rowvalue.test.

   329    329   } {1 {sub-select returns 2 columns - expected 1}}
   330    330   do_catchsql_test 15.4 {
   331    331     DELETE FROM x1 WHERE  a<(SELECT * FROM (SELECT b,2));
   332    332   } {1 {sub-select returns 2 columns - expected 1}}
   333    333   do_catchsql_test 15.5 {
   334    334     INSERT INTO x1(a,b) VALUES(1,(SELECT * FROM (SELECT 1,2))<3);
   335    335   } {1 {row value misused}}
          336  +
          337  +#-------------------------------------------------------------------------
          338  +# Row-values used in UPDATE statements within TRIGGERs
          339  +#
          340  +# Ticket https://www.sqlite.org/src/info/8c9458e703666e1a
          341  +#
          342  +do_execsql_test 16.1 {
          343  +  CREATE TABLE t16a(a,b,c);
          344  +  INSERT INTO t16a VALUES(1,2,3);
          345  +  CREATE TABLE t16b(x);
          346  +  INSERT INTO t16b(x) VALUES(1);
          347  +  CREATE TRIGGER t16r AFTER UPDATE ON t16b BEGIN
          348  +     UPDATE t16a SET (a,b,c)=(SELECT new.x,new.x+1,new.x+2);
          349  +  END;
          350  +  UPDATE t16b SET x=7;
          351  +  SELECT * FROM t16a;
          352  +} {7 8 9}
          353  +do_execsql_test 16.2 {
          354  +  UPDATE t16b SET x=97;
          355  +  SELECT * FROM t16a;
          356  +} {97 98 99}
   336    357   
   337    358   finish_test