/ Check-in [95708ae2]
Login

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

Overview
Comment:Merge the [002caede898] fix into trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 95708ae2235658c3a49679e2fe252a058793366a
User & Date: drh 2011-09-16 01:38:53
Context
2011-09-16
16:00
Further streamlining of the subquery materializer. New test cases for ticket [002caede898a] check-in: ff8b76b2 user: drh tags: trunk
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
00:40
Cleanup/fix error handling when no arguments are supplied to the SQLite analyzer. check-in: 3fc566ac user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/expr.c.

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

Changes to src/select.c.

  3797   3797   #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
  3798   3798     for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
  3799   3799       struct SrcList_item *pItem = &pTabList->a[i];
  3800   3800       SelectDest dest;
  3801   3801       Select *pSub = pItem->pSelect;
  3802   3802       int isAggSub;
  3803   3803   
  3804         -    if( pSub==0 || pItem->isPopulated ) continue;
         3804  +    if( pSub==0 ) continue;
         3805  +    if( pItem->addrFillSub ){
         3806  +      sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
         3807  +      continue;
         3808  +    }
  3805   3809   
  3806   3810       /* Increment Parse.nHeight by the height of the largest expression
  3807   3811       ** tree refered to by this, the parent select. The child select
  3808   3812       ** may contain expression trees of at most
  3809   3813       ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit
  3810   3814       ** more conservative than necessary, but much easier than enforcing
  3811   3815       ** an exact limit.
  3812   3816       */
  3813   3817       pParse->nHeight += sqlite3SelectExprHeight(p);
  3814   3818   
  3815         -    /* Check to see if the subquery can be absorbed into the parent. */
  3816   3819       isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
  3817   3820       if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
         3821  +      /* This subquery can be absorbed into its parent. */
  3818   3822         if( isAggSub ){
  3819   3823           isAgg = 1;
  3820   3824           p->selFlags |= SF_Aggregate;
  3821   3825         }
  3822   3826         i = -1;
  3823   3827       }else{
         3828  +      /* Generate a subroutine that will fill an ephemeral table with
         3829  +      ** the content of this subquery.  pItem->addrFillSub will point
         3830  +      ** to the address of the generated subroutine.  pItem->regReturn
         3831  +      ** is a register allocated to hold the subroutine return address
         3832  +      */
         3833  +      int topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
         3834  +      int onceAddr = 0;
         3835  +      assert( pItem->addrFillSub==0 );
         3836  +      pItem->addrFillSub = topAddr+1;
         3837  +      pItem->regReturn = ++pParse->nMem;
         3838  +      if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){
         3839  +        /* If the subquery is no correlated and if we are not inside of
         3840  +        ** a trigger, then we only need to compute the value of the subquery
         3841  +        ** once. */
         3842  +        int regOnce = ++pParse->nMem;
         3843  +        onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce);
         3844  +      }
  3824   3845         sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
  3825         -      assert( pItem->isPopulated==0 );
  3826   3846         explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
  3827   3847         sqlite3Select(pParse, pSub, &dest);
  3828         -      pItem->isPopulated = 1;
  3829   3848         pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
         3849  +      if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
         3850  +      sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
         3851  +      sqlite3VdbeJumpHere(v, topAddr);
         3852  +      sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, topAddr+1);
  3830   3853       }
  3831   3854       if( /*pParse->nErr ||*/ db->mallocFailed ){
  3832   3855         goto select_end;
  3833   3856       }
  3834   3857       pParse->nHeight -= sqlite3SelectExprHeight(p);
  3835   3858       pTabList = p->pSrc;
  3836   3859       if( !IgnorableOrderby(pDest) ){
................................................................................
  3963   3986       if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
  3964   3987   
  3965   3988       /* If sorting index that was created by a prior OP_OpenEphemeral 
  3966   3989       ** instruction ended up not being needed, then change the OP_OpenEphemeral
  3967   3990       ** into an OP_Noop.
  3968   3991       */
  3969   3992       if( addrSortIndex>=0 && pOrderBy==0 ){
  3970         -      sqlite3VdbeChangeToNoop(v, addrSortIndex, 1);
         3993  +      sqlite3VdbeChangeToNoop(v, addrSortIndex);
  3971   3994         p->addrOpenEphm[2] = -1;
  3972   3995       }
  3973   3996   
  3974   3997       if( pWInfo->eDistinct ){
  3975   3998         VdbeOp *pOp;                /* No longer required OpenEphemeral instr. */
  3976   3999        
  3977   4000         assert( addrDistinctIndex>=0 );
................................................................................
  4246   4269   
  4247   4270         /* End of the loop
  4248   4271         */
  4249   4272         if( groupBySort ){
  4250   4273           sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
  4251   4274         }else{
  4252   4275           sqlite3WhereEnd(pWInfo);
  4253         -        sqlite3VdbeChangeToNoop(v, addrSortingIdx, 1);
         4276  +        sqlite3VdbeChangeToNoop(v, addrSortingIdx);
  4254   4277         }
  4255   4278   
  4256   4279         /* Output the final row of result
  4257   4280         */
  4258   4281         sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow);
  4259   4282         VdbeComment((v, "output final row"));
  4260   4283   

Changes to src/sqliteInt.h.

  1848   1848     i16 nAlloc;      /* Number of entries allocated in a[] below */
  1849   1849     struct SrcList_item {
  1850   1850       char *zDatabase;  /* Name of database holding this table */
  1851   1851       char *zName;      /* Name of the table */
  1852   1852       char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
  1853   1853       Table *pTab;      /* An SQL table corresponding to zName */
  1854   1854       Select *pSelect;  /* A SELECT statement used in place of a table name */
  1855         -    u8 isPopulated;   /* Temporary table associated with SELECT is populated */
         1855  +    int addrFillSub;  /* Address of subroutine to manifest a subquery */
         1856  +    int regReturn;    /* Register holding return address of addrFillSub */
  1856   1857       u8 jointype;      /* Type of join between this able and the previous */
  1857   1858       u8 notIndexed;    /* True if there is a NOT INDEXED clause */
  1858   1859       u8 isCorrelated;  /* True if sub-query is correlated */
  1859   1860   #ifndef SQLITE_OMIT_EXPLAIN
  1860   1861       u8 iSelectId;     /* If pSelect!=0, the id of the sub-select in EQP */
  1861   1862   #endif
  1862   1863       int iCursor;      /* The VDBE cursor number used to access this table */

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;

Changes to test/tkt-31338dca7e.test.

    69     69      CREATE INDEX t4x ON t4(x);
    70     70       SELECT * FROM t3, t4, t5
    71     71        WHERE (v=111 AND x=w AND z!=999) OR (v=333 AND x=444)
    72     72        ORDER BY v, w, x, y, z;
    73     73     }
    74     74   } {111 222 222 333 888 333 444 444 555 888 333 444 444 555 999}
    75     75   
           76  +
           77  +# Ticket [2c2de252666662f5459904fc33a9f2956cbff23c]
           78  +#
           79  +do_test tkt-31338-3.1 {
           80  +  foreach x [db eval {SELECT name FROM sqlite_master WHERE type='table'}] {
           81  +     db eval "DROP TABLE $x"
           82  +  }
           83  +  db eval {
           84  +    CREATE TABLE t1(a,b,c,d);
           85  +    CREATE TABLE t2(e,f);
           86  +    INSERT INTO t1 VALUES(1,2,3,4);
           87  +    INSERT INTO t2 VALUES(10,-8);
           88  +    CREATE INDEX t1a ON t1(a);
           89  +    CREATE INDEX t1b ON t1(b);
           90  +    CREATE TABLE t3(g);
           91  +    INSERT INTO t3 VALUES(4);
           92  +    CREATE TABLE t4(h);
           93  +    INSERT INTO t4 VALUES(5);
           94  +    
           95  +    SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h
           96  +     WHERE (a=1 AND h=4)
           97  +         OR (b IN (
           98  +               SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2)
           99  +               GROUP BY e
          100  +            ));
          101  +  }    
          102  +} {4 1 2 3 4 {}}
          103  +do_test tkt-31338-3.2 {
          104  +  db eval {    
          105  +    SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h
          106  +     WHERE (a=1 AND h=4)
          107  +         OR (b=2 AND b NOT IN (
          108  +               SELECT x+1 FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2)
          109  +               GROUP BY e
          110  +            ));
          111  +  }    
          112  +} {4 1 2 3 4 {}}
          113  +
    76    114   
    77    115   finish_test