/ Check-in [557c6905]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Modify the OP_Once opcode so that it works correctly in trigger sub-programs. This is a candidate fix for [7bbfb7d442].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 557c69055a300b4082830b5f4803091dca1c3140
User & Date: dan 2011-12-09 13:24:16
References
2012-12-06
20:19
Cherrypick [557c69055a3] and [0064bab7714] (OP_Once-related fixes for triggers). check-in: 0d7b5d45 user: dan tags: branch-3.7.9
Context
2011-12-09
18:06
Change the VDBE so that all registers are initialized to "Invalid" instead of NULL and report errors on any attempted read of an Invalid register. This will help prevent future bugs similar to [7bbfb7d442]. check-in: 0064bab7 user: drh tags: trunk
16:21
Make no assumptions about the initial state of VDBE registers. check-in: 521d72bd user: drh tags: uninit-vdbe-mem
13:24
Modify the OP_Once opcode so that it works correctly in trigger sub-programs. This is a candidate fix for [7bbfb7d442]. check-in: 557c6905 user: dan tags: trunk
05:52
The Windows OS flavor #ifdefs must be performed after the 'windows.h' file has been included. check-in: 3702a31e user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/expr.c.

  1370   1370     if( IsVirtual(pTab) ) return 0;        /* FROM clause not a virtual table */
  1371   1371     pEList = p->pEList;
  1372   1372     if( pEList->nExpr!=1 ) return 0;       /* One column in the result set */
  1373   1373     if( pEList->a[0].pExpr->op!=TK_COLUMN ) return 0; /* Result is a column */
  1374   1374     return 1;
  1375   1375   }
  1376   1376   #endif /* SQLITE_OMIT_SUBQUERY */
         1377  +
         1378  +/*
         1379  +** Code an OP_Once instruction and allocate space for its flag. Return the 
         1380  +** address of the new instruction.
         1381  +*/
         1382  +int sqlite3CodeOnce(Parse *pParse){
         1383  +  Vdbe *v = sqlite3GetVdbe(pParse);      /* Virtual machine being coded */
         1384  +  return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
         1385  +}
  1377   1386   
  1378   1387   /*
  1379   1388   ** This function is used by the implementation of the IN (...) operator.
  1380   1389   ** It's job is to find or create a b-tree structure that may be used
  1381   1390   ** either to test for membership of the (...) set or to iterate through
  1382   1391   ** its members, skipping duplicates.
  1383   1392   **
................................................................................
  1466   1475   
  1467   1476       /* This function is only called from two places. In both cases the vdbe
  1468   1477       ** has already been allocated. So assume sqlite3GetVdbe() is always
  1469   1478       ** successful here.
  1470   1479       */
  1471   1480       assert(v);
  1472   1481       if( iCol<0 ){
  1473         -      int iMem = ++pParse->nMem;
  1474   1482         int iAddr;
  1475   1483   
  1476         -      iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
         1484  +      iAddr = sqlite3CodeOnce(pParse);
  1477   1485   
  1478   1486         sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
  1479   1487         eType = IN_INDEX_ROWID;
  1480   1488   
  1481   1489         sqlite3VdbeJumpHere(v, iAddr);
  1482   1490       }else{
  1483   1491         Index *pIdx;                         /* Iterator variable */
................................................................................
  1495   1503         int affinity_ok = (pTab->aCol[iCol].affinity==aff||aff==SQLITE_AFF_NONE);
  1496   1504   
  1497   1505         for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
  1498   1506           if( (pIdx->aiColumn[0]==iCol)
  1499   1507            && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
  1500   1508            && (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None))
  1501   1509           ){
  1502         -          int iMem = ++pParse->nMem;
  1503   1510             int iAddr;
  1504   1511             char *pKey;
  1505   1512     
  1506   1513             pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx);
  1507         -          iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
         1514  +          iAddr = sqlite3CodeOnce(pParse);
  1508   1515     
  1509   1516             sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
  1510   1517                                  pKey,P4_KEYINFO_HANDOFF);
  1511   1518             VdbeComment((v, "%s", pIdx->zName));
  1512   1519             eType = IN_INDEX_INDEX;
  1513   1520   
  1514   1521             sqlite3VdbeJumpHere(v, iAddr);
................................................................................
  1597   1604     **    *  The right-hand side is a correlated subquery
  1598   1605     **    *  The right-hand side is an expression list containing variables
  1599   1606     **    *  We are inside a trigger
  1600   1607     **
  1601   1608     ** If all of the above are false, then we can run this code just once
  1602   1609     ** save the results, and reuse the same result on subsequent invocations.
  1603   1610     */
  1604         -  if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->pTriggerTab ){
  1605         -    int mem = ++pParse->nMem;
  1606         -    testAddr = sqlite3VdbeAddOp1(v, OP_Once, mem);
         1611  +  if( !ExprHasAnyProperty(pExpr, EP_VarSelect) ){
         1612  +    testAddr = sqlite3CodeOnce(pParse);
  1607   1613     }
  1608   1614   
  1609   1615   #ifndef SQLITE_OMIT_EXPLAIN
  1610   1616     if( pParse->explain==2 ){
  1611   1617       char *zMsg = sqlite3MPrintf(
  1612   1618           pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr>=0?"":"CORRELATED ",
  1613   1619           pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId

Changes to src/select.c.

  3841   3841         int onceAddr = 0;
  3842   3842         int retAddr;
  3843   3843         assert( pItem->addrFillSub==0 );
  3844   3844         pItem->regReturn = ++pParse->nMem;
  3845   3845         topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
  3846   3846         pItem->addrFillSub = topAddr+1;
  3847   3847         VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
  3848         -      if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){
         3848  +      if( pItem->isCorrelated==0 ){
  3849   3849           /* If the subquery is no correlated and if we are not inside of
  3850   3850           ** a trigger, then we only need to compute the value of the subquery
  3851   3851           ** once. */
  3852         -        int regOnce = ++pParse->nMem;
  3853         -        onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce);
         3852  +        onceAddr = sqlite3CodeOnce(pParse);
  3854   3853         }
  3855   3854         sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
  3856   3855         explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
  3857   3856         sqlite3Select(pParse, pSub, &dest);
  3858   3857         pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
  3859   3858         if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
  3860   3859         retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);

Changes to src/sqliteInt.h.

  2200   2200     int aTempReg[8];     /* Holding area for temporary registers */
  2201   2201     int nRangeReg;       /* Size of the temporary register block */
  2202   2202     int iRangeReg;       /* First register in temporary register block */
  2203   2203     int nErr;            /* Number of errors seen */
  2204   2204     int nTab;            /* Number of previously allocated VDBE cursors */
  2205   2205     int nMem;            /* Number of memory cells used so far */
  2206   2206     int nSet;            /* Number of sets used so far */
         2207  +  int nOnce;           /* Number of OP_Once instructions so far */
  2207   2208     int ckBase;          /* Base register of data during check constraints */
  2208   2209     int iCacheLevel;     /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
  2209   2210     int iCacheCnt;       /* Counter used to generate aColCache[].lru values */
  2210   2211     u8 nColCache;        /* Number of entries in aColCache[] */
  2211   2212     u8 iColCache;        /* Next entry in aColCache[] to replace */
  2212   2213     struct yColCache {
  2213   2214       int iTable;           /* Table cursor number */
................................................................................
  2688   2689   void sqlite3AddCheckConstraint(Parse*, Expr*);
  2689   2690   void sqlite3AddColumnType(Parse*,Token*);
  2690   2691   void sqlite3AddDefaultValue(Parse*,ExprSpan*);
  2691   2692   void sqlite3AddCollateType(Parse*, Token*);
  2692   2693   void sqlite3EndTable(Parse*,Token*,Token*,Select*);
  2693   2694   int sqlite3ParseUri(const char*,const char*,unsigned int*,
  2694   2695                       sqlite3_vfs**,char**,char **);
         2696  +int sqlite3CodeOnce(Parse *);
  2695   2697   
  2696   2698   Bitvec *sqlite3BitvecCreate(u32);
  2697   2699   int sqlite3BitvecTest(Bitvec*, u32);
  2698   2700   int sqlite3BitvecSet(Bitvec*, u32);
  2699   2701   void sqlite3BitvecClear(Bitvec*, u32, void*);
  2700   2702   void sqlite3BitvecDestroy(Bitvec*);
  2701   2703   u32 sqlite3BitvecSize(Bitvec*);

Changes to src/trigger.c.

   900    900   
   901    901       transferParseError(pParse, pSubParse);
   902    902       if( db->mallocFailed==0 ){
   903    903         pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
   904    904       }
   905    905       pProgram->nMem = pSubParse->nMem;
   906    906       pProgram->nCsr = pSubParse->nTab;
          907  +    pProgram->nOnce = pSubParse->nOnce;
   907    908       pProgram->token = (void *)pTrigger;
   908    909       pPrg->aColmask[0] = pSubParse->oldmask;
   909    910       pPrg->aColmask[1] = pSubParse->newmask;
   910    911       sqlite3VdbeDelete(v);
   911    912     }
   912    913   
   913    914     assert( !pSubParse->pAinc       && !pSubParse->pZombieTab );

Changes to src/vdbe.c.

  2019   2019       sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1));
  2020   2020     }
  2021   2021     break;
  2022   2022   }
  2023   2023   
  2024   2024   /* Opcode: Once P1 P2 * * *
  2025   2025   **
  2026         -** Jump to P2 if the value in register P1 is a not null or zero.  If
  2027         -** the value is NULL or zero, fall through and change the P1 register
  2028         -** to an integer 1.
  2029         -**
  2030         -** When P1 is not used otherwise in a program, this opcode falls through
  2031         -** once and jumps on all subsequent invocations.  It is the equivalent
  2032         -** of "OP_If P1 P2", followed by "OP_Integer 1 P1".
         2026  +** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
         2027  +** set the flag and fall through to the next instruction.
  2033   2028   */
         2029  +case OP_Once: {             /* jump */
         2030  +  assert( pOp->p1<p->nOnceFlag );
         2031  +  if( p->aOnceFlag[pOp->p1] ){
         2032  +    pc = pOp->p2-1;
         2033  +  }else{
         2034  +    p->aOnceFlag[pOp->p1] = 1;
         2035  +  }
         2036  +  break;
         2037  +}
         2038  +
  2034   2039   /* Opcode: If P1 P2 P3 * *
  2035   2040   **
  2036   2041   ** Jump to P2 if the value in register P1 is true.  The value
  2037   2042   ** is considered true if it is numeric and non-zero.  If the value
  2038   2043   ** in P1 is NULL then take the jump if P3 is true.
  2039   2044   */
  2040   2045   /* Opcode: IfNot P1 P2 P3 * *
  2041   2046   **
  2042   2047   ** Jump to P2 if the value in register P1 is False.  The value
  2043   2048   ** is considered true if it has a numeric value of zero.  If the value
  2044   2049   ** in P1 is NULL then take the jump if P3 is true.
  2045   2050   */
  2046         -case OP_Once:               /* jump, in1 */
  2047   2051   case OP_If:                 /* jump, in1 */
  2048   2052   case OP_IfNot: {            /* jump, in1 */
  2049   2053     int c;
  2050   2054     pIn1 = &aMem[pOp->p1];
  2051   2055     if( pIn1->flags & MEM_Null ){
  2052   2056       c = pOp->p3;
  2053   2057     }else{
................................................................................
  2056   2060   #else
  2057   2061       c = sqlite3VdbeRealValue(pIn1)!=0.0;
  2058   2062   #endif
  2059   2063       if( pOp->opcode==OP_IfNot ) c = !c;
  2060   2064     }
  2061   2065     if( c ){
  2062   2066       pc = pOp->p2-1;
  2063         -  }else if( pOp->opcode==OP_Once ){
  2064         -    assert( (pIn1->flags & (MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))==0 );
  2065         -    memAboutToChange(p, pIn1);
  2066         -    pIn1->flags = MEM_Int;
  2067         -    pIn1->u.i = 1;
  2068         -    REGISTER_TRACE(pOp->p1, pIn1);
  2069   2067     }
  2070   2068     break;
  2071   2069   }
  2072   2070   
  2073   2071   /* Opcode: IsNull P1 P2 * * *
  2074   2072   **
  2075   2073   ** Jump to P2 if the value in register P1 is NULL.
................................................................................
  5106   5104       ** program stored in SubProgram.aOp. As well as these, one memory
  5107   5105       ** cell is required for each cursor used by the program. Set local
  5108   5106       ** variable nMem (and later, VdbeFrame.nChildMem) to this value.
  5109   5107       */
  5110   5108       nMem = pProgram->nMem + pProgram->nCsr;
  5111   5109       nByte = ROUND8(sizeof(VdbeFrame))
  5112   5110                 + nMem * sizeof(Mem)
  5113         -              + pProgram->nCsr * sizeof(VdbeCursor *);
         5111  +              + pProgram->nCsr * sizeof(VdbeCursor *)
         5112  +              + pProgram->nOnce * sizeof(u8);
  5114   5113       pFrame = sqlite3DbMallocZero(db, nByte);
  5115   5114       if( !pFrame ){
  5116   5115         goto no_mem;
  5117   5116       }
  5118   5117       sqlite3VdbeMemRelease(pRt);
  5119   5118       pRt->flags = MEM_Frame;
  5120   5119       pRt->u.pFrame = pFrame;
................................................................................
  5126   5125       pFrame->aMem = p->aMem;
  5127   5126       pFrame->nMem = p->nMem;
  5128   5127       pFrame->apCsr = p->apCsr;
  5129   5128       pFrame->nCursor = p->nCursor;
  5130   5129       pFrame->aOp = p->aOp;
  5131   5130       pFrame->nOp = p->nOp;
  5132   5131       pFrame->token = pProgram->token;
         5132  +    pFrame->aOnceFlag = p->aOnceFlag;
         5133  +    pFrame->nOnceFlag = p->nOnceFlag;
  5133   5134   
  5134   5135       pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
  5135   5136       for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
  5136   5137         pMem->flags = MEM_Null;
  5137   5138         pMem->db = db;
  5138   5139       }
  5139   5140     }else{
................................................................................
  5151   5152     p->pFrame = pFrame;
  5152   5153     p->aMem = aMem = &VdbeFrameMem(pFrame)[-1];
  5153   5154     p->nMem = pFrame->nChildMem;
  5154   5155     p->nCursor = (u16)pFrame->nChildCsr;
  5155   5156     p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
  5156   5157     p->aOp = aOp = pProgram->aOp;
  5157   5158     p->nOp = pProgram->nOp;
         5159  +  p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
         5160  +  p->nOnceFlag = pProgram->nOnce;
         5161  +  p->nOp = pProgram->nOp;
  5158   5162     pc = -1;
         5163  +  memset(p->aOnceFlag, 0, p->nOnceFlag);
  5159   5164   
  5160   5165     break;
  5161   5166   }
  5162   5167   
  5163   5168   /* Opcode: Param P1 P2 * * *
  5164   5169   **
  5165   5170   ** This opcode is only ever present in sub-programs called via the 

Changes to src/vdbe.h.

    78     78   ** A sub-routine used to implement a trigger program.
    79     79   */
    80     80   struct SubProgram {
    81     81     VdbeOp *aOp;                  /* Array of opcodes for sub-program */
    82     82     int nOp;                      /* Elements in aOp[] */
    83     83     int nMem;                     /* Number of memory cells required */
    84     84     int nCsr;                     /* Number of cursors required */
           85  +  int nOnce;                    /* Number of OP_Once instructions */
    85     86     void *token;                  /* id that may be used to recursive triggers */
    86     87     SubProgram *pNext;            /* Next sub-program already visited */
    87     88   };
    88     89   
    89     90   /*
    90     91   ** A smaller version of VdbeOp used for the VdbeAddOpList() function because
    91     92   ** it takes up less space.

Changes to src/vdbeInt.h.

   113    113   struct VdbeFrame {
   114    114     Vdbe *v;                /* VM this frame belongs to */
   115    115     int pc;                 /* Program Counter in parent (calling) frame */
   116    116     Op *aOp;                /* Program instructions for parent frame */
   117    117     int nOp;                /* Size of aOp array */
   118    118     Mem *aMem;              /* Array of memory cells for parent frame */
   119    119     int nMem;               /* Number of entries in aMem */
          120  +  u8 *aOnceFlag;          /* Array of OP_Once flags for parent frame */
          121  +  int nOnceFlag;          /* Number of entries in aOnceFlag */
   120    122     VdbeCursor **apCsr;     /* Array of Vdbe cursors for parent frame */
   121    123     u16 nCursor;            /* Number of entries in apCsr */
   122    124     void *token;            /* Copy of SubProgram.token */
   123    125     int nChildMem;          /* Number of memory cells for child frame */
   124    126     int nChildCsr;          /* Number of cursors for child frame */
   125    127     i64 lastRowid;          /* Last insert rowid (sqlite3.lastRowid) */
   126    128     int nChange;            /* Statement changes (Vdbe.nChanges)     */
................................................................................
   322    324     FILE *trace;            /* Write an execution trace here, if not NULL */
   323    325   #endif
   324    326     VdbeFrame *pFrame;      /* Parent frame */
   325    327     VdbeFrame *pDelFrame;   /* List of frame objects to free on VM reset */
   326    328     int nFrame;             /* Number of frames in pFrame list */
   327    329     u32 expmask;            /* Binding to these vars invalidates VM */
   328    330     SubProgram *pProgram;   /* Linked list of all sub-programs used by VM */
          331  +  int nOnceFlag;          /* Size of array aOnceFlag[] */
          332  +  u8 *aOnceFlag;          /* Flags for OP_Once */
   329    333   };
   330    334   
   331    335   /*
   332    336   ** The following are allowed values for Vdbe.magic
   333    337   */
   334    338   #define VDBE_MAGIC_INIT     0x26bceaa5    /* Building a VDBE program */
   335    339   #define VDBE_MAGIC_RUN      0xbdf20da3    /* VDBE is ready to execute */

Changes to src/vdbeaux.c.

  1465   1465     Parse *pParse                  /* Parsing context */
  1466   1466   ){
  1467   1467     sqlite3 *db;                   /* The database connection */
  1468   1468     int nVar;                      /* Number of parameters */
  1469   1469     int nMem;                      /* Number of VM memory registers */
  1470   1470     int nCursor;                   /* Number of cursors required */
  1471   1471     int nArg;                      /* Number of arguments in subprograms */
         1472  +  int nOnce;                     /* Number of OP_Once instructions */
  1472   1473     int n;                         /* Loop counter */
  1473   1474     u8 *zCsr;                      /* Memory available for allocation */
  1474   1475     u8 *zEnd;                      /* First byte past allocated memory */
  1475   1476     int nByte;                     /* How much extra memory is needed */
  1476   1477   
  1477   1478     assert( p!=0 );
  1478   1479     assert( p->nOp>0 );
................................................................................
  1480   1481     assert( p->magic==VDBE_MAGIC_INIT );
  1481   1482     db = p->db;
  1482   1483     assert( db->mallocFailed==0 );
  1483   1484     nVar = pParse->nVar;
  1484   1485     nMem = pParse->nMem;
  1485   1486     nCursor = pParse->nTab;
  1486   1487     nArg = pParse->nMaxArg;
         1488  +  nOnce = pParse->nOnce;
  1487   1489     
  1488   1490     /* For each cursor required, also allocate a memory cell. Memory
  1489   1491     ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
  1490   1492     ** the vdbe program. Instead they are used to allocate space for
  1491   1493     ** VdbeCursor/BtCursor structures. The blob of memory associated with 
  1492   1494     ** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
  1493   1495     ** stores the blob of memory associated with cursor 1, etc.
................................................................................
  1526   1528       nByte = 0;
  1527   1529       p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
  1528   1530       p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
  1529   1531       p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
  1530   1532       p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
  1531   1533       p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
  1532   1534                             &zCsr, zEnd, &nByte);
         1535  +    p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce*sizeof(u8), 
         1536  +                          &zCsr, zEnd, &nByte);
  1533   1537       if( nByte ){
  1534   1538         p->pFree = sqlite3DbMallocZero(db, nByte);
  1535   1539       }
  1536   1540       zCsr = p->pFree;
  1537   1541       zEnd = &zCsr[nByte];
  1538   1542     }while( nByte && !db->mallocFailed );
  1539   1543   
  1540   1544     p->nCursor = (u16)nCursor;
         1545  +  p->nOnceFlag = nOnce;
  1541   1546     if( p->aVar ){
  1542   1547       p->nVar = (ynVar)nVar;
  1543   1548       for(n=0; n<nVar; n++){
  1544   1549         p->aVar[n].flags = MEM_Null;
  1545   1550         p->aVar[n].db = db;
  1546   1551       }
  1547   1552     }
................................................................................
  1592   1597   /*
  1593   1598   ** Copy the values stored in the VdbeFrame structure to its Vdbe. This
  1594   1599   ** is used, for example, when a trigger sub-program is halted to restore
  1595   1600   ** control to the main program.
  1596   1601   */
  1597   1602   int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
  1598   1603     Vdbe *v = pFrame->v;
         1604  +  v->aOnceFlag = pFrame->aOnceFlag;
         1605  +  v->nOnceFlag = pFrame->nOnceFlag;
  1599   1606     v->aOp = pFrame->aOp;
  1600   1607     v->nOp = pFrame->nOp;
  1601   1608     v->aMem = pFrame->aMem;
  1602   1609     v->nMem = pFrame->nMem;
  1603   1610     v->apCsr = pFrame->apCsr;
  1604   1611     v->nCursor = pFrame->nCursor;
  1605   1612     v->db->lastRowid = pFrame->lastRowid;
................................................................................
  1638   1645       releaseMemArray(&p->aMem[1], p->nMem);
  1639   1646     }
  1640   1647     while( p->pDelFrame ){
  1641   1648       VdbeFrame *pDel = p->pDelFrame;
  1642   1649       p->pDelFrame = pDel->pParent;
  1643   1650       sqlite3VdbeFrameDelete(pDel);
  1644   1651     }
         1652  +  memset(p->aOnceFlag, 0, p->nOnceFlag);
  1645   1653   }
  1646   1654   
  1647   1655   /*
  1648   1656   ** Clean up the VM after execution.
  1649   1657   **
  1650   1658   ** This routine will automatically close any cursors, lists, and/or
  1651   1659   ** sorters that were left open.  It also deletes the values of

Changes to src/where.c.

  2001   2001   ){
  2002   2002     int nColumn;                /* Number of columns in the constructed index */
  2003   2003     WhereTerm *pTerm;           /* A single term of the WHERE clause */
  2004   2004     WhereTerm *pWCEnd;          /* End of pWC->a[] */
  2005   2005     int nByte;                  /* Byte of memory needed for pIdx */
  2006   2006     Index *pIdx;                /* Object describing the transient index */
  2007   2007     Vdbe *v;                    /* Prepared statement under construction */
  2008         -  int regIsInit;              /* Register set by initialization */
  2009   2008     int addrInit;               /* Address of the initialization bypass jump */
  2010   2009     Table *pTable;              /* The table being indexed */
  2011   2010     KeyInfo *pKeyinfo;          /* Key information for the index */   
  2012   2011     int addrTop;                /* Top of the index fill loop */
  2013   2012     int regRecord;              /* Register holding an index record */
  2014   2013     int n;                      /* Column counter */
  2015   2014     int i;                      /* Loop counter */
................................................................................
  2018   2017     Bitmask idxCols;            /* Bitmap of columns used for indexing */
  2019   2018     Bitmask extraCols;          /* Bitmap of additional columns */
  2020   2019   
  2021   2020     /* Generate code to skip over the creation and initialization of the
  2022   2021     ** transient index on 2nd and subsequent iterations of the loop. */
  2023   2022     v = pParse->pVdbe;
  2024   2023     assert( v!=0 );
  2025         -  regIsInit = ++pParse->nMem;
  2026         -  addrInit = sqlite3VdbeAddOp1(v, OP_Once, regIsInit);
         2024  +  addrInit = sqlite3CodeOnce(pParse);
  2027   2025   
  2028   2026     /* Count the number of columns that will be added to the index
  2029   2027     ** and used to match WHERE clause constraints */
  2030   2028     nColumn = 0;
  2031   2029     pTable = pSrc->pTab;
  2032   2030     pWCEnd = &pWC->a[pWC->nTerm];
  2033   2031     idxCols = 0;

Added test/tkt-7bbfb7d442.test.

            1  +# 2011 December 9
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.
           12  +#
           13  +# This file implements tests to verify that ticket [7bbfb7d442] has been
           14  +# fixed.  
           15  +#
           16  +
           17  +set testdir [file dirname $argv0]
           18  +source $testdir/tester.tcl
           19  +set testprefix tkt-7bbfb7d442
           20  +
           21  +do_execsql_test 1.1 {
           22  +  CREATE TABLE t1(a, b);
           23  +  INSERT INTO t1 VALUES(1, 'one');
           24  +  INSERT INTO t1 VALUES(2, 'two');
           25  +  INSERT INTO t1 VALUES(3, 'three');
           26  +
           27  +  CREATE TABLE t2(c, d);
           28  +  INSERT INTO t2 VALUES('one', 'I');
           29  +  INSERT INTO t2 VALUES('two', 'II');
           30  +  INSERT INTO t2 VALUES('three', 'III');
           31  +
           32  +  CREATE TABLE t3(t3_a PRIMARY KEY, t3_d);
           33  +  CREATE TRIGGER t3t AFTER INSERT ON t3 WHEN new.t3_d IS NULL BEGIN
           34  +    UPDATE t3 SET t3_d = (
           35  +      SELECT d FROM 
           36  +        (SELECT * FROM t2 WHERE (new.t3_a%2)=(rowid%2) LIMIT 10),
           37  +        (SELECT * FROM t1 WHERE (new.t3_a%2)=(rowid%2) LIMIT 10)
           38  +      WHERE a = new.t3_a AND b = c
           39  +    ) WHERE t3_a = new.t3_a;
           40  +  END;
           41  +}
           42  +
           43  +do_execsql_test 1.2 {
           44  +  INSERT INTO t3(t3_a) VALUES(1);
           45  +  INSERT INTO t3(t3_a) VALUES(2);
           46  +  INSERT INTO t3(t3_a) VALUES(3);
           47  +  SELECT * FROM t3;
           48  +} {1 I 2 II 3 III}
           49  +
           50  +do_execsql_test 1.3 { DELETE FROM t3 }
           51  +
           52  +do_execsql_test 1.4 {
           53  +  INSERT INTO t3(t3_a) SELECT 1 UNION SELECT 2 UNION SELECT 3;
           54  +  SELECT * FROM t3;
           55  +} {1 I 2 II 3 III}
           56  +
           57  +
           58  +
           59  +#-------------------------------------------------------------------------
           60  +# The following test case - 2.* - is from the original bug report as 
           61  +# posted to the mailing list.
           62  +#
           63  +do_execsql_test 2.1 {
           64  +  CREATE TABLE InventoryControl (
           65  +    InventoryControlId INTEGER PRIMARY KEY AUTOINCREMENT,
           66  +    SKU INTEGER NOT NULL,
           67  +    Variant INTEGER NOT NULL DEFAULT 0,
           68  +    ControlDate DATE NOT NULL,
           69  +    ControlState INTEGER NOT NULL DEFAULT -1,
           70  +    DeliveredQty VARCHAR(30)
           71  +  );
           72  +  
           73  +  CREATE TRIGGER TGR_InventoryControl_AfterInsert
           74  +  AFTER INSERT ON InventoryControl 
           75  +  FOR EACH ROW WHEN NEW.ControlState=-1 BEGIN 
           76  +
           77  +  INSERT OR REPLACE INTO InventoryControl(
           78  +        InventoryControlId,SKU,Variant,ControlDate,ControlState,DeliveredQty
           79  +  ) SELECT
           80  +          T1.InventoryControlId AS InventoryControlId,
           81  +          T1.SKU AS SKU,
           82  +          T1.Variant AS Variant,
           83  +          T1.ControlDate AS ControlDate,
           84  +          1 AS ControlState,
           85  +          COALESCE(T2.DeliveredQty,0) AS DeliveredQty
           86  +      FROM (
           87  +          SELECT
           88  +              NEW.InventoryControlId AS InventoryControlId,
           89  +              II.SKU AS SKU,
           90  +              II.Variant AS Variant,
           91  +              COALESCE(LastClosedIC.ControlDate,NEW.ControlDate) AS ControlDate
           92  +          FROM
           93  +              InventoryItem II
           94  +          LEFT JOIN
           95  +              InventoryControl LastClosedIC
           96  +              ON  LastClosedIC.InventoryControlId IN ( SELECT 99999 )
           97  +          WHERE
           98  +              II.SKU=NEW.SKU AND
           99  +              II.Variant=NEW.Variant
          100  +      )   T1
          101  +      LEFT JOIN (
          102  +          SELECT
          103  +              TD.SKU AS SKU,
          104  +              TD.Variant AS Variant,
          105  +              10 AS DeliveredQty
          106  +          FROM
          107  +              TransactionDetail TD
          108  +          WHERE
          109  +              TD.SKU=NEW.SKU AND
          110  +              TD.Variant=NEW.Variant
          111  +      )   T2
          112  +      ON  T2.SKU=T1.SKU AND
          113  +          T2.Variant=T1.Variant;
          114  +  END;
          115  +  
          116  +  CREATE TABLE InventoryItem (
          117  +    SKU INTEGER NOT NULL,
          118  +    Variant INTEGER NOT NULL DEFAULT 0,
          119  +    DeptCode INTEGER NOT NULL,
          120  +    GroupCode INTEGER NOT NULL,
          121  +    ItemDescription VARCHAR(120) NOT NULL,
          122  +    PRIMARY KEY(SKU, Variant)
          123  +  );
          124  +  
          125  +  INSERT INTO InventoryItem VALUES(220,0,1,170,'Scoth Tampon Recurer');
          126  +  INSERT INTO InventoryItem VALUES(31,0,1,110,'Fromage');
          127  +  
          128  +  CREATE TABLE TransactionDetail (
          129  +    TransactionId INTEGER NOT NULL,
          130  +    SKU INTEGER NOT NULL,
          131  +    Variant INTEGER NOT NULL DEFAULT 0,
          132  +    PRIMARY KEY(TransactionId, SKU, Variant)
          133  +  );
          134  +  INSERT INTO TransactionDetail(TransactionId, SKU, Variant) VALUES(44, 31, 0);
          135  +  
          136  +  
          137  +  INSERT INTO InventoryControl(SKU, Variant, ControlDate) SELECT 
          138  +      II.SKU AS SKU, II.Variant AS Variant, '2011-08-30' AS ControlDate 
          139  +      FROM InventoryItem II;
          140  +}
          141  +
          142  +do_execsql_test 2.2 {
          143  +  SELECT SKU, DeliveredQty FROM InventoryControl WHERE SKU=31
          144  +} {31 10}
          145  +
          146  +do_execsql_test 2.3 {
          147  +  SELECT CASE WHEN DeliveredQty=10 THEN "TEST PASSED!" ELSE "TEST FAILED!" END 
          148  +  FROM InventoryControl WHERE SKU=31; 
          149  +} {{TEST PASSED!}}
          150  +
          151  +
          152  +finish_test
          153  +
          154  +