]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix for the "(x AND y) OR z" bug backported to version 3.6.21. branch-3.6.21
authordrh <drh@noemail.net>
Wed, 16 Dec 2009 23:28:31 +0000 (23:28 +0000)
committerdrh <drh@noemail.net>
Wed, 16 Dec 2009 23:28:31 +0000 (23:28 +0000)
FossilOrigin-Name: 867347323b0c095159411de36cbd87b09c1b2863

VERSION
manifest
manifest.uuid
src/sqliteInt.h
src/where.c
test/tkt-31338dca7e.test [new file with mode: 0644]
test/where8.test

diff --git a/VERSION b/VERSION
index 1bff231925344ad918564502f5d135a192fd0c60..cec9d2efc3d88257f3bf244595038bc92d251f1b 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.6.21
+3.6.21.1
index d8e009b5426ccee2d9dd0c11da6b09b374d9487a..5746e93a8b0dd1e36c59dd8c0a1fafe2682b3cc3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,14 +1,14 @@
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
-C Version\s3.6.21\srelease\scandidate\s3.
-D 2009-12-07T16:39:13
+C Fix\sfor\sthe\s"(x\sAND\sy)\sOR\sz"\sbug\sbackported\sto\sversion\s3.6.21.
+D 2009-12-16T23:28:32
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in c5827ead754ab32b9585487177c93bb00b9497b3
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
 F Makefile.vxworks 10010ddbf52e2503c7c49c7c0b7c7a096f8638a6
 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
-F VERSION aa30c4b131a981624ab576df19eb4c5c9cd582ac
+F VERSION 1e6bf6cfcc755751b88c848e449f7ff02a049511
 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
 F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
 F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
@@ -169,7 +169,7 @@ F src/select.c 2f9ed7482e7a25b0b127fc41693bbdbe1caf5647
 F src/shell.c f4948cb6d30665d755a6b5e0ec313d1094aab828
 F src/sqlite.h.in 2d34605565e021851255e0bbcb15f8c1930d1f6f
 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
-F src/sqliteInt.h e946a6a3f2df015cdbc7668e9626987e8badbb5f
+F src/sqliteInt.h 93d5d01d9ea57b95ba709733dce830ec056deb84
 F src/sqliteLimit.h 3afab2291762b5d09ae20c18feb8e9fa935a60a6
 F src/status.c e651be6b30d397d86384c6867bc016e4913bcac7
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -222,7 +222,7 @@ F src/vdbemem.c 1e16e3a16e55f4c3452834f0e041726021aa66e0
 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
 F src/vtab.c 456fc226614569f0e46f216e33265bea268bd917
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
-F src/where.c 11b5b00c49d53e767a7eb855bc60790edeca6185
+F src/where.c f20ee9a15c1ccb8b94cd31e3f8c6868e1358fc07
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
 F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
@@ -602,6 +602,7 @@ F test/thread_common.tcl b65e6b1d1d90dc885e10ad080896c6c56eef0819
 F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
 F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9
 F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28
+F test/tkt-31338dca7e.test 5741cd48de500347a437ba1be58c8335e83c5a5e
 F test/tkt-3fe897352e.test 8084dad39807eac10b10720c84193bd1a5980973
 F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
 F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
@@ -745,7 +746,7 @@ F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
 F test/where6.test 42c4373595f4409d9c6a9987b4a60000ad664faf
 F test/where7.test fdd58ab9dec9f97679e65d4414bf5e07d725d79f
-F test/where8.test 434f08974964b10378d67867773a2c3aedaf1d4b
+F test/where8.test 2bb8ea44b745fcc93db150fac9ce33d12e499760
 F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
 F test/where9.test be19e1a92f80985c1a121b4678bf7d2123eaa623
 F test/whereA.test 1d1674254614147c866ab9b59af6582f454a858c
@@ -779,14 +780,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P cd50acf37fd1e3b388f98fb2df7ed03cff454b24
-R 5d0b6a47a50c8a9cdc60d3d4d61a8cf2
+P 1ed88e9d01e9eda5cbc622e7614277f29bcc551c
+R e7d1ff5fd98ae55ae61bf91d3d4df1c9
 U drh
-Z 8b76b0c0726e570aef93558fa0c3fdc7
+Z 49479a3b1562abdd14a885a8865e0fa5
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.6 (GNU/Linux)
 
-iD8DBQFLHS+0oxKgR168RlERArAKAJ97NTyJvzQHmWC2GXt2Xt7D52m04QCeLeQt
-HYPTNDWgvT/KRZ19RtHNjDQ=
-=tE2+
+iD8DBQFLKW0joxKgR168RlERAlZgAJoDPgJ9k9EK/kFQwfqfQ0gY5Pb57wCePWTc
+6VlIsxRe62S0m1PuLBEsM9E=
+=g+YX
 -----END PGP SIGNATURE-----
index b4e4637fcfa97b281feb56ef6b77708bf6f0ebd8..1978f23a93b7f0058bfddaa9b5e6ced8029f8866 100644 (file)
@@ -1 +1 @@
-1ed88e9d01e9eda5cbc622e7614277f29bcc551c
\ No newline at end of file
+867347323b0c095159411de36cbd87b09c1b2863
\ No newline at end of file
index 1202971a84a269911d9351e4d50d4e1ef77b90c5..1e15dbd167ef467a6c94e93a98c10ff7bc110b03 100644 (file)
@@ -1894,6 +1894,7 @@ struct WhereLevel {
 #define WHERE_OMIT_OPEN        0x0010 /* Table cursor are already open */
 #define WHERE_OMIT_CLOSE       0x0020 /* Omit close of table & index cursors */
 #define WHERE_FORCE_TABLE      0x0040 /* Do not use an index-only search */
+#define WHERE_ONETABLE_ONLY    0x0080 /* Only code the 1st table in pTabList */
 
 /*
 ** The WHERE clause processing routine has two halves.  The
@@ -1906,6 +1907,7 @@ struct WhereInfo {
   Parse *pParse;       /* Parsing and code generating context */
   u16 wctrlFlags;      /* Flags originally passed to sqlite3WhereBegin() */
   u8 okOnePass;        /* Ok to use one-pass algorithm for UPDATE or DELETE */
+  u8 untestedTerms;    /* Not all WHERE terms resolved by outer loop */
   SrcList *pTabList;             /* List of tables in the join */
   int iTop;                      /* The very beginning of the WHERE loop */
   int iContinue;                 /* Jump here to continue with next record */
index 067ec4079b9f2e6ced2fd43793771b1f1e7e37aa..f6d9ab296ed0bf36465da9240c80b12c99e00bc9 100644 (file)
@@ -3265,13 +3265,14 @@ static Bitmask codeOneLoopStart(
     */
     WhereClause *pOrWc;    /* The OR-clause broken out into subterms */
     WhereTerm *pFinal;     /* Final subterm within the OR-clause. */
-    SrcList oneTab;        /* Shortened table list */
+    SrcList *pOrTab;       /* Shortened table list or OR-clause generation */
 
     int regReturn = ++pParse->nMem;           /* Register used with OP_Gosub */
     int regRowset = 0;                        /* Register for RowSet object */
     int regRowid = 0;                         /* Register holding rowid */
     int iLoopBody = sqlite3VdbeMakeLabel(v);  /* Start of loop body */
     int iRetInit;                             /* Address of regReturn init */
+    int untestedTerms = 0;             /* Some terms not completely tested */
     int ii;
    
     pTerm = pLevel->plan.u.pTerm;
@@ -3280,11 +3281,29 @@ static Bitmask codeOneLoopStart(
     assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
     pOrWc = &pTerm->u.pOrInfo->wc;
     pFinal = &pOrWc->a[pOrWc->nTerm-1];
+    pLevel->op = OP_Return;
+    pLevel->p1 = regReturn;
 
-    /* Set up a SrcList containing just the table being scanned by this loop. */
-    oneTab.nSrc = 1;
-    oneTab.nAlloc = 1;
-    oneTab.a[0] = *pTabItem;
+    /* Set up a new SrcList ni pOrTab containing the table being scanned
+    ** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
+    ** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
+    */
+    if( pWInfo->nLevel>1 ){
+      int nNotReady;                 /* The number of notReady tables */
+      struct SrcList_item *origSrc;     /* Original list of tables */
+      nNotReady = pWInfo->nLevel - iLevel - 1;
+      pOrTab = sqlite3StackAllocRaw(pParse->db,
+                            sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
+      if( pOrTab==0 ) return notReady;
+      pOrTab->nSrc = pOrTab->nAlloc = nNotReady + 1;
+      memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem));
+      origSrc = pWInfo->pTabList->a;
+      for(k=1; k<=nNotReady; k++){
+        memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k]));
+      }
+    }else{
+      pOrTab = pWInfo->pTabList;
+    }
 
     /* Initialize the rowset register to contain NULL. An SQL NULL is 
     ** equivalent to an empty rowset.
@@ -3309,8 +3328,9 @@ static Bitmask codeOneLoopStart(
       if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
         WhereInfo *pSubWInfo;          /* Info for single OR-term scan */
         /* Loop through table entries that match term pOrTerm. */
-        pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0,
-                        WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | WHERE_FORCE_TABLE);
+        pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrTerm->pExpr, 0,
+                        WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE |
+                        WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY);
         if( pSubWInfo ){
           if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
             int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
@@ -3322,19 +3342,24 @@ static Bitmask codeOneLoopStart(
           }
           sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody);
 
+          /* The pSubWInfo->untestedTerms flag means that this OR term
+          ** contained one or more AND term from a notReady table.  The
+          ** terms from the notReady table could not be tested and will
+          ** need to be tested later.
+          */
+          if( pSubWInfo->untestedTerms ) untestedTerms = 1;
+
           /* Finish the loop through table entries that match term pOrTerm. */
           sqlite3WhereEnd(pSubWInfo);
         }
       }
     }
     sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
-    /* sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); */
     sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
     sqlite3VdbeResolveLabel(v, iLoopBody);
 
-    pLevel->op = OP_Return;
-    pLevel->p1 = regReturn;
-    disableTerm(pLevel, pTerm);
+    if( pWInfo->nLevel>1 ) sqlite3StackFree(pParse->db, pOrTab);
+    if( !untestedTerms ) disableTerm(pLevel, pTerm);
   }else
 #endif /* SQLITE_OMIT_OR_OPTIMIZATION */
 
@@ -3362,7 +3387,12 @@ static Bitmask codeOneLoopStart(
     testcase( pTerm->wtFlags & TERM_VIRTUAL );
     testcase( pTerm->wtFlags & TERM_CODED );
     if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
-    if( (pTerm->prereqAll & notReady)!=0 ) continue;
+    if( (pTerm->prereqAll & notReady)!=0 ){
+      testcase( pWInfo->untestedTerms==0
+               && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
+      pWInfo->untestedTerms = 1;
+      continue;
+    }
     pE = pTerm->pExpr;
     assert( pE!=0 );
     if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
@@ -3385,7 +3415,10 @@ static Bitmask codeOneLoopStart(
       testcase( pTerm->wtFlags & TERM_VIRTUAL );
       testcase( pTerm->wtFlags & TERM_CODED );
       if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
-      if( (pTerm->prereqAll & notReady)!=0 ) continue;
+      if( (pTerm->prereqAll & notReady)!=0 ){
+        assert( pWInfo->untestedTerms );
+        continue;
+      }
       assert( pTerm->pExpr );
       sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
       pTerm->wtFlags |= TERM_CODED;
@@ -3528,6 +3561,7 @@ WhereInfo *sqlite3WhereBegin(
 ){
   int i;                     /* Loop counter */
   int nByteWInfo;            /* Num. bytes allocated for WhereInfo struct */
+  int nTabList;              /* Number of elements in pTabList */
   WhereInfo *pWInfo;         /* Will become the return value of this function */
   Vdbe *v = pParse->pVdbe;   /* The virtual database engine */
   Bitmask notReady;          /* Cursors that are not yet positioned */
@@ -3547,6 +3581,13 @@ WhereInfo *sqlite3WhereBegin(
     return 0;
   }
 
+  /* This function normally generates a nested loop for all tables in 
+  ** pTabList.  But if the WHERE_ONETABLE_ONLY flag is set, then we should
+  ** only generate code for the first table in pTabList and assume that
+  ** any cursors associated with subsequent tables are uninitialized.
+  */
+  nTabList = (wctrlFlags & WHERE_ONETABLE_ONLY) ? 1 : pTabList->nSrc;
+
   /* Allocate and initialize the WhereInfo structure that will become the
   ** return value. A single allocation is used to store the WhereInfo
   ** struct, the contents of WhereInfo.a[], the WhereClause structure
@@ -3555,7 +3596,7 @@ WhereInfo *sqlite3WhereBegin(
   ** some architectures. Hence the ROUND8() below.
   */
   db = pParse->db;
-  nByteWInfo = ROUND8(sizeof(WhereInfo)+(pTabList->nSrc-1)*sizeof(WhereLevel));
+  nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
   pWInfo = sqlite3DbMallocZero(db, 
       nByteWInfo + 
       sizeof(WhereClause) +
@@ -3564,7 +3605,7 @@ WhereInfo *sqlite3WhereBegin(
   if( db->mallocFailed ){
     goto whereBeginError;
   }
-  pWInfo->nLevel = pTabList->nSrc;
+  pWInfo->nLevel = nTabList;
   pWInfo->pParse = pParse;
   pWInfo->pTabList = pTabList;
   pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
@@ -3583,7 +3624,7 @@ WhereInfo *sqlite3WhereBegin(
   /* Special case: a WHERE clause that is constant.  Evaluate the
   ** expression and either jump over all of the code or fall thru.
   */
-  if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){
+  if( pWhere && (nTabList==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){
     sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, SQLITE_JUMPIFNULL);
     pWhere = 0;
   }
@@ -3603,6 +3644,11 @@ WhereInfo *sqlite3WhereBegin(
   ** to virtual table cursors are set. This is used to selectively disable 
   ** the OR-to-IN transformation in exprAnalyzeOrTerm(). It is not helpful 
   ** with virtual tables.
+  **
+  ** Note that bitmasks are created for all pTabList->nSrc tables in
+  ** pTabList, not just the first nTabList tables.  nTabList is normally
+  ** equal to pTabList->nSrc but might be shortened to 1 if the
+  ** WHERE_ONETABLE_ONLY flag is set.
   */
   assert( pWC->vmask==0 && pMaskSet->n==0 );
   for(i=0; i<pTabList->nSrc; i++){
@@ -3654,7 +3700,7 @@ WhereInfo *sqlite3WhereBegin(
   pLevel = pWInfo->a;
   andFlags = ~0;
   WHERETRACE(("*** Optimizer Start ***\n"));
-  for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
+  for(i=iFrom=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
     WhereCost bestPlan;         /* Most efficient plan seen so far */
     Index *pIdx;                /* Index for FROM table at pTabItem */
     int j;                      /* For looping over FROM tables */
@@ -3699,8 +3745,8 @@ WhereInfo *sqlite3WhereBegin(
     */
     for(isOptimal=1; isOptimal>=0 && bestJ<0; isOptimal--){
       Bitmask mask = (isOptimal ? 0 : notReady);
-      assert( (pTabList->nSrc-iFrom)>1 || isOptimal );
-      for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
+      assert( (nTabList-iFrom)>1 || isOptimal );
+      for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
         int doNotReorder;    /* True if this table should not be reordered */
         WhereCost sCost;     /* Cost information from best[Virtual]Index() */
         ExprList *pOrderBy;  /* ORDER BY clause for index to optimize */
@@ -3797,7 +3843,7 @@ WhereInfo *sqlite3WhereBegin(
   ** searching those tables.
   */
   sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
-  for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
+  for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
     Table *pTab;     /* Table to open */
     int iDb;         /* Index of database containing table/index */
 
@@ -3876,7 +3922,7 @@ WhereInfo *sqlite3WhereBegin(
   ** program.
   */
   notReady = ~(Bitmask)0;
-  for(i=0; i<pTabList->nSrc; i++){
+  for(i=0; i<nTabList; i++){
     notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
     pWInfo->iContinue = pWInfo->a[i].addrCont;
   }
@@ -3888,7 +3934,7 @@ WhereInfo *sqlite3WhereBegin(
   ** the index is listed as "{}".  If the primary key is used the
   ** index name is '*'.
   */
-  for(i=0; i<pTabList->nSrc; i++){
+  for(i=0; i<nTabList; i++){
     char *z;
     int n;
     pLevel = &pWInfo->a[i];
@@ -3956,7 +4002,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
   /* Generate loop termination code.
   */
   sqlite3ExprCacheClear(pParse);
-  for(i=pTabList->nSrc-1; i>=0; i--){
+  for(i=pWInfo->nLevel-1; i>=0; i--){
     pLevel = &pWInfo->a[i];
     sqlite3VdbeResolveLabel(v, pLevel->addrCont);
     if( pLevel->op!=OP_Noop ){
@@ -4002,7 +4048,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
 
   /* Close all of the cursors that were opened by sqlite3WhereBegin.
   */
-  for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
+  assert( pWInfo->nLevel==1 || pWInfo->nLevel==pTabList->nSrc );
+  for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
     struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
     Table *pTab = pTabItem->pTab;
     assert( pTab!=0 );
diff --git a/test/tkt-31338dca7e.test b/test/tkt-31338dca7e.test
new file mode 100644 (file)
index 0000000..3f66816
--- /dev/null
@@ -0,0 +1,77 @@
+# 2009 December 16
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+# This file implements tests to verify that ticket [31338dca7e] has been
+# fixed.  Ticket [31338dca7e] demonstrates problems with the OR-clause
+# optimization in joins where the WHERE clause is of the form
+#
+#     (x AND y) OR z
+#
+# And the x and y subterms from from different tables of the join.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+do_test tkt-31338-1.1 {
+  db eval {
+    CREATE TABLE t1(x);
+    CREATE TABLE t2(y);
+    INSERT INTO t1 VALUES(111);
+    INSERT INTO t1 VALUES(222);
+    INSERT INTO t2 VALUES(333);
+    INSERT INTO t2 VALUES(444);
+    SELECT * FROM t1, t2
+     WHERE (x=111 AND y!=444) OR x=222
+     ORDER BY x, y;
+  }
+} {111 333 222 333 222 444}
+
+do_test tkt-31338-1.2 {
+  db eval {
+    CREATE INDEX t1x ON t1(x);
+    SELECT * FROM t1, t2
+     WHERE (x=111 AND y!=444) OR x=222
+     ORDER BY x, y;
+  }
+} {111 333 222 333 222 444}
+
+do_test tkt-31338-2.1 {
+  db eval {
+    CREATE TABLE t3(v,w);
+    CREATE TABLE t4(x,y);
+    CREATE TABLE t5(z);
+    INSERT INTO t3 VALUES(111,222);
+    INSERT INTO t3 VALUES(333,444);
+    INSERT INTO t4 VALUES(222,333);
+    INSERT INTO t4 VALUES(444,555);
+    INSERT INTO t5 VALUES(888);
+    INSERT INTO t5 VALUES(999);
+    
+    SELECT * FROM t3, t4, t5
+     WHERE (v=111 AND x=w AND z!=999) OR (v=333 AND x=444)
+     ORDER BY v, w, x, y, z;
+  }
+} {111 222 222 333 888 333 444 444 555 888 333 444 444 555 999}
+
+do_test tkt-31338-2.2 {
+  db eval {
+   CREATE INDEX t3v ON t3(v);
+   CREATE INDEX t4x ON t4(x);
+    SELECT * FROM t3, t4, t5
+     WHERE (v=111 AND x=w AND z!=999) OR (v=333 AND x=444)
+     ORDER BY v, w, x, y, z;
+  }
+} {111 222 222 333 888 333 444 444 555 888 333 444 444 555 999}
+
+
+finish_test
index 04146fe60a17ef2126851cf48e6a7d9449763abc..04657c047316bdf2ee5bb075d8ef30f6c0880fc2 100644 (file)
@@ -398,6 +398,10 @@ do_test where8-4.1 {
     INSERT INTO t4 VALUES('his', 'of', 378678316.5);
     INSERT INTO t4 VALUES(271.2019091, 'viewed', 3282306647);
     INSERT INTO t4 VALUES('hills', 'all', 'peak');
+    CREATE TABLE t5(s);
+    INSERT INTO t5 VALUES('tab-t5');
+    CREATE TABLE t6(t);
+    INSERT INTO t6 VALUES(123456);
     COMMIT;
   }
 } {}
@@ -639,6 +643,14 @@ foreach idxsql {
 197  { SELECT * FROM t3, t4 WHERE g = 2643383279 AND f = g }
 198  { SELECT * FROM t3, t4 WHERE g < 8979323846 }
 199  { SELECT * FROM t3, t4 WHERE 'are' <= b }
+200  { SELECT * FROM t3, t4 WHERE (a=1415926535 AND f=8628034825)
+                               OR (a=6939937510 AND f=2643383279) }
+201  { SELECT * FROM t3, t4, t5, t6
+        WHERE (a=1415926535 AND f=8628034825 AND s!='hello' AND t!=5)
+           OR (a=6939937510 AND f=2643383279 AND s='tab-t5' AND t=123456) }
+202  { SELECT * FROM t3, t4, t5, t6
+        WHERE (a=1415926535 AND f=8628034825 AND s!='hello' AND t==5)
+           OR (a=6939937510 AND f=2643383279 AND s='tab-t5' AND t!=123456) }
 
   } {
     do_test where8-4.$A.$B.1 {