/ Check-in [7f00552b]
Login

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

Overview
Comment:Add the new OP_Once opcode. Use it to clean up and simplify various one-time initialization sections in the code, including the fix for ticket [002caede898ae].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tkt-002caede898
Files: files | file ages | folders
SHA1: 7f00552b739fad79517b042a6ed61abe743a917b
User & Date: drh 2011-09-16 01:34:43
Original Comment: Add the new OP_Once opcode. Use it to clean up and simplify various one-time initialization sections in the code, including the fix for ticket [002caede898ae].
Context
2011-09-16
01:38
Merge the [002caede898] fix into trunk. check-in: 95708ae2 user: drh tags: trunk
01:34
Add the new OP_Once opcode. Use it to clean up and simplify various one-time initialization sections in the code, including the fix for ticket [002caede898ae]. Closed-Leaf check-in: 7f00552b user: drh tags: tkt-002caede898
2011-09-15
23:58
Materialize subqueries using a subroutine and invoke that subroutine prior to each use of the materialization. Fix for ticket [002caede898aee4] check-in: 4b8357ee user: drh tags: tkt-002caede898
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/expr.c.

  1458   1458       ** successful here.
  1459   1459       */
  1460   1460       assert(v);
  1461   1461       if( iCol<0 ){
  1462   1462         int iMem = ++pParse->nMem;
  1463   1463         int iAddr;
  1464   1464   
  1465         -      iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem);
  1466         -      sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem);
         1465  +      iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
  1467   1466   
  1468   1467         sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
  1469   1468         eType = IN_INDEX_ROWID;
  1470   1469   
  1471   1470         sqlite3VdbeJumpHere(v, iAddr);
  1472   1471       }else{
  1473   1472         Index *pIdx;                         /* Iterator variable */
................................................................................
  1490   1489            && (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None))
  1491   1490           ){
  1492   1491             int iMem = ++pParse->nMem;
  1493   1492             int iAddr;
  1494   1493             char *pKey;
  1495   1494     
  1496   1495             pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx);
  1497         -          iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem);
  1498         -          sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem);
         1496  +          iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
  1499   1497     
  1500   1498             sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
  1501   1499                                  pKey,P4_KEYINFO_HANDOFF);
  1502   1500             VdbeComment((v, "%s", pIdx->zName));
  1503   1501             eType = IN_INDEX_INDEX;
  1504   1502   
  1505   1503             sqlite3VdbeJumpHere(v, iAddr);
................................................................................
  1576   1574     int rMayHaveNull,       /* Register that records whether NULLs exist in RHS */
  1577   1575     int isRowid             /* If true, LHS of IN operator is a rowid */
  1578   1576   ){
  1579   1577     int testAddr = 0;                       /* One-time test address */
  1580   1578     int rReg = 0;                           /* Register storing resulting */
  1581   1579     Vdbe *v = sqlite3GetVdbe(pParse);
  1582   1580     if( NEVER(v==0) ) return 0;
         1581  +  assert( sqlite3VdbeCurrentAddr(v)>0 );
  1583   1582     sqlite3ExprCachePush(pParse);
  1584   1583   
  1585   1584     /* This code must be run in its entirety every time it is encountered
  1586   1585     ** if any of the following is true:
  1587   1586     **
  1588   1587     **    *  The right-hand side is a correlated subquery
  1589   1588     **    *  The right-hand side is an expression list containing variables
................................................................................
  1590   1589     **    *  We are inside a trigger
  1591   1590     **
  1592   1591     ** If all of the above are false, then we can run this code just once
  1593   1592     ** save the results, and reuse the same result on subsequent invocations.
  1594   1593     */
  1595   1594     if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->pTriggerTab ){
  1596   1595       int mem = ++pParse->nMem;
  1597         -    sqlite3VdbeAddOp1(v, OP_If, mem);
  1598         -    testAddr = sqlite3VdbeAddOp2(v, OP_Integer, 1, mem);
         1596  +    testAddr = sqlite3VdbeAddOp1(v, OP_Once, mem);
  1599   1597       assert( testAddr>0 || pParse->db->mallocFailed );
  1600   1598     }
  1601   1599   
  1602   1600   #ifndef SQLITE_OMIT_EXPLAIN
  1603   1601     if( pParse->explain==2 ){
  1604   1602       char *zMsg = sqlite3MPrintf(
  1605   1603           pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr?"":"CORRELATED ",
................................................................................
  1691   1689   
  1692   1690             /* If the expression is not constant then we will need to
  1693   1691             ** disable the test that was generated above that makes sure
  1694   1692             ** this code only executes once.  Because for a non-constant
  1695   1693             ** expression we need to rerun this code each time.
  1696   1694             */
  1697   1695             if( testAddr && !sqlite3ExprIsConstant(pE2) ){
  1698         -            sqlite3VdbeChangeToNoop(v, testAddr-1, 2);
         1696  +            sqlite3VdbeChangeToNoop(v, testAddr);
  1699   1697               testAddr = 0;
  1700   1698             }
  1701   1699   
  1702   1700             /* Evaluate the expression and insert it into the temp table */
  1703   1701             if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){
  1704   1702               sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns);
  1705   1703             }else{
................................................................................
  1762   1760         rReg = dest.iParm;
  1763   1761         ExprSetIrreducible(pExpr);
  1764   1762         break;
  1765   1763       }
  1766   1764     }
  1767   1765   
  1768   1766     if( testAddr ){
  1769         -    sqlite3VdbeJumpHere(v, testAddr-1);
         1767  +    sqlite3VdbeJumpHere(v, testAddr);
  1770   1768     }
  1771   1769     sqlite3ExprCachePop(pParse, 1);
  1772   1770   
  1773   1771     return rReg;
  1774   1772   }
  1775   1773   #endif /* SQLITE_OMIT_SUBQUERY */
  1776   1774   

Changes to src/select.c.

  3827   3827       }else{
  3828   3828         /* Generate a subroutine that will fill an ephemeral table with
  3829   3829         ** the content of this subquery.  pItem->addrFillSub will point
  3830   3830         ** to the address of the generated subroutine.  pItem->regReturn
  3831   3831         ** is a register allocated to hold the subroutine return address
  3832   3832         */
  3833   3833         int topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
  3834         -      int regOnce = 0;
         3834  +      int onceAddr = 0;
  3835   3835         assert( pItem->addrFillSub==0 );
  3836   3836         pItem->addrFillSub = topAddr+1;
  3837   3837         pItem->regReturn = ++pParse->nMem;
  3838   3838         if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){
  3839   3839           /* If the subquery is no correlated and if we are not inside of
  3840   3840           ** a trigger, then we only need to compute the value of the subquery
  3841   3841           ** once. */
  3842         -        regOnce = ++pParse->nMem;
  3843         -        sqlite3VdbeAddOp1(v, OP_If, regOnce);
  3844         -        sqlite3VdbeAddOp2(v, OP_Integer, 1, regOnce);
         3842  +        int regOnce = ++pParse->nMem;
         3843  +        onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce);
  3845   3844         }
  3846   3845         sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
  3847   3846         explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
  3848   3847         sqlite3Select(pParse, pSub, &dest);
  3849   3848         pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
  3850         -      if( regOnce ) sqlite3VdbeJumpHere(v, topAddr+1);
         3849  +      if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
  3851   3850         sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
  3852   3851         sqlite3VdbeJumpHere(v, topAddr);
  3853   3852         sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, topAddr+1);
  3854   3853       }
  3855   3854       if( /*pParse->nErr ||*/ db->mallocFailed ){
  3856   3855         goto select_end;
  3857   3856       }
................................................................................
  3987   3986       if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
  3988   3987   
  3989   3988       /* If sorting index that was created by a prior OP_OpenEphemeral 
  3990   3989       ** instruction ended up not being needed, then change the OP_OpenEphemeral
  3991   3990       ** into an OP_Noop.
  3992   3991       */
  3993   3992       if( addrSortIndex>=0 && pOrderBy==0 ){
  3994         -      sqlite3VdbeChangeToNoop(v, addrSortIndex, 1);
         3993  +      sqlite3VdbeChangeToNoop(v, addrSortIndex);
  3995   3994         p->addrOpenEphm[2] = -1;
  3996   3995       }
  3997   3996   
  3998   3997       if( pWInfo->eDistinct ){
  3999   3998         VdbeOp *pOp;                /* No longer required OpenEphemeral instr. */
  4000   3999        
  4001   4000         assert( addrDistinctIndex>=0 );
................................................................................
  4270   4269   
  4271   4270         /* End of the loop
  4272   4271         */
  4273   4272         if( groupBySort ){
  4274   4273           sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
  4275   4274         }else{
  4276   4275           sqlite3WhereEnd(pWInfo);
  4277         -        sqlite3VdbeChangeToNoop(v, addrSortingIdx, 1);
         4276  +        sqlite3VdbeChangeToNoop(v, addrSortingIdx);
  4278   4277         }
  4279   4278   
  4280   4279         /* Output the final row of result
  4281   4280         */
  4282   4281         sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow);
  4283   4282         VdbeComment((v, "output final row"));
  4284   4283   

Changes to src/vdbe.c.

  2017   2017       sqlite3VdbeMemSetNull(pOut);
  2018   2018     }else{
  2019   2019       sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1));
  2020   2020     }
  2021   2021     break;
  2022   2022   }
  2023   2023   
         2024  +/* Opcode: Once P1 P2 * * *
         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".
         2033  +*/
  2024   2034   /* Opcode: If P1 P2 P3 * *
  2025   2035   **
  2026   2036   ** Jump to P2 if the value in register P1 is true.  The value
  2027   2037   ** is considered true if it is numeric and non-zero.  If the value
  2028   2038   ** in P1 is NULL then take the jump if P3 is true.
  2029   2039   */
  2030   2040   /* Opcode: IfNot P1 P2 P3 * *
  2031   2041   **
  2032   2042   ** Jump to P2 if the value in register P1 is False.  The value
  2033   2043   ** is considered true if it has a numeric value of zero.  If the value
  2034   2044   ** in P1 is NULL then take the jump if P3 is true.
  2035   2045   */
         2046  +case OP_Once:               /* jump, in1 */
  2036   2047   case OP_If:                 /* jump, in1 */
  2037   2048   case OP_IfNot: {            /* jump, in1 */
  2038   2049     int c;
  2039   2050     pIn1 = &aMem[pOp->p1];
  2040   2051     if( pIn1->flags & MEM_Null ){
  2041   2052       c = pOp->p3;
  2042   2053     }else{
................................................................................
  2045   2056   #else
  2046   2057       c = sqlite3VdbeRealValue(pIn1)!=0.0;
  2047   2058   #endif
  2048   2059       if( pOp->opcode==OP_IfNot ) c = !c;
  2049   2060     }
  2050   2061     if( c ){
  2051   2062       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);
  2052   2069     }
  2053   2070     break;
  2054   2071   }
  2055   2072   
  2056   2073   /* Opcode: IsNull P1 P2 * * *
  2057   2074   **
  2058   2075   ** Jump to P2 if the value in register P1 is NULL.

Changes to src/vdbe.h.

   176    176   int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
   177    177   void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
   178    178   void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
   179    179   void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
   180    180   void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
   181    181   void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
   182    182   void sqlite3VdbeJumpHere(Vdbe*, int addr);
   183         -void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
          183  +void sqlite3VdbeChangeToNoop(Vdbe*, int addr);
   184    184   void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
   185    185   void sqlite3VdbeUsesBtree(Vdbe*, int);
   186    186   VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
   187    187   int sqlite3VdbeMakeLabel(Vdbe*);
   188    188   void sqlite3VdbeRunOnlyOnce(Vdbe*);
   189    189   void sqlite3VdbeDelete(Vdbe*);
   190    190   void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*);

Changes to src/vdbeaux.c.

   666    666   */
   667    667   void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){
   668    668     p->pNext = pVdbe->pProgram;
   669    669     pVdbe->pProgram = p;
   670    670   }
   671    671   
   672    672   /*
   673         -** Change N opcodes starting at addr to No-ops.
          673  +** Change the opcode at addr into OP_Noop
   674    674   */
   675         -void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){
          675  +void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
   676    676     if( p->aOp ){
   677    677       VdbeOp *pOp = &p->aOp[addr];
   678    678       sqlite3 *db = p->db;
   679         -    while( N-- ){
   680         -      freeP4(db, pOp->p4type, pOp->p4.p);
   681         -      memset(pOp, 0, sizeof(pOp[0]));
   682         -      pOp->opcode = OP_Noop;
   683         -      pOp++;
   684         -    }
          679  +    freeP4(db, pOp->p4type, pOp->p4.p);
          680  +    memset(pOp, 0, sizeof(pOp[0]));
          681  +    pOp->opcode = OP_Noop;
   685    682     }
   686    683   }
   687    684   
   688    685   /*
   689    686   ** Change the value of the P4 operand for a specific instruction.
   690    687   ** This routine is useful when a large program is loaded from a
   691    688   ** static array using sqlite3VdbeAddOpList but we want to make a

Changes to src/vdbeblob.c.

   269    269         sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
   270    270   
   271    271         /* Make sure a mutex is held on the table to be accessed */
   272    272         sqlite3VdbeUsesBtree(v, iDb); 
   273    273   
   274    274         /* Configure the OP_TableLock instruction */
   275    275   #ifdef SQLITE_OMIT_SHARED_CACHE
   276         -      sqlite3VdbeChangeToNoop(v, 2, 1);
          276  +      sqlite3VdbeChangeToNoop(v, 2);
   277    277   #else
   278    278         sqlite3VdbeChangeP1(v, 2, iDb);
   279    279         sqlite3VdbeChangeP2(v, 2, pTab->tnum);
   280    280         sqlite3VdbeChangeP3(v, 2, flags);
   281    281         sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
   282    282   #endif
   283    283   
   284    284         /* Remove either the OP_OpenWrite or OpenRead. Set the P2 
   285    285         ** parameter of the other to pTab->tnum.  */
   286         -      sqlite3VdbeChangeToNoop(v, 4 - flags, 1);
          286  +      sqlite3VdbeChangeToNoop(v, 4 - flags);
   287    287         sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum);
   288    288         sqlite3VdbeChangeP3(v, 3 + flags, iDb);
   289    289   
   290    290         /* Configure the number of columns. Configure the cursor to
   291    291         ** think that the table has one more column than it really
   292    292         ** does. An OP_Column to retrieve this imaginary column will
   293    293         ** always return an SQL NULL. This is useful because it means

Changes to src/where.c.

  1990   1990     Bitmask extraCols;          /* Bitmap of additional columns */
  1991   1991   
  1992   1992     /* Generate code to skip over the creation and initialization of the
  1993   1993     ** transient index on 2nd and subsequent iterations of the loop. */
  1994   1994     v = pParse->pVdbe;
  1995   1995     assert( v!=0 );
  1996   1996     regIsInit = ++pParse->nMem;
  1997         -  addrInit = sqlite3VdbeAddOp1(v, OP_If, regIsInit);
  1998         -  sqlite3VdbeAddOp2(v, OP_Integer, 1, regIsInit);
         1997  +  addrInit = sqlite3VdbeAddOp1(v, OP_Once, regIsInit);
  1999   1998   
  2000   1999     /* Count the number of columns that will be added to the index
  2001   2000     ** and used to match WHERE clause constraints */
  2002   2001     nColumn = 0;
  2003   2002     pTable = pSrc->pTab;
  2004   2003     pWCEnd = &pWC->a[pWC->nTerm];
  2005   2004     idxCols = 0;