]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix the OR-to-IN optimization so that it works in cases where there are
authordrh <>
Wed, 17 Jun 2026 13:31:01 +0000 (13:31 +0000)
committerdrh <>
Wed, 17 Jun 2026 13:31:01 +0000 (13:31 +0000)
conflicting collation sequences on the equality constraints within the OR.
[bugs:/info/2026-06-17T05:04:48Z|Bug 2026-06-17T05:04:48Z].

FossilOrigin-Name: 984c9b181801c1de06782335eb049f32d1dc1d5739a7fb9c94630c22159a4f8c

manifest
manifest.uuid
src/whereexpr.c
test/where2.test

index ed469bf3bb27ada8fd1f19d66f50cf8c9f30fb50..6a295f305266689fa285b167d903392026717852 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Typo\sfix\sin\sa\scomment\sused\sto\sgenerate\sdocumentation.\s\sNo\schanges\sto\scode.\n[forum:/info/2026-06-16T23:18:50Z|Forum\s2026-06-16T23:18:50Z].
-D 2026-06-16T23:59:58.512
+C Fix\sthe\sOR-to-IN\soptimization\sso\sthat\sit\sworks\sin\scases\swhere\sthere\sare\nconflicting\scollation\ssequences\son\sthe\sequality\sconstraints\swithin\sthe\sOR.\n[bugs:/info/2026-06-17T05:04:48Z|Bug\s2026-06-17T05:04:48Z].
+D 2026-06-17T13:31:01.199
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -822,7 +822,7 @@ F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
 F src/where.c 33e4a6558ee69f33d6a4e7069e3a40a55959d14e5653a9a83926e70305d471f3
 F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
 F src/wherecode.c bc39ccbe3648f01157038b16cc55bdbff128590972b7185521b5526dc2815765
-F src/whereexpr.c a1e22cf9f6cb59770d9652c757dcf1924078ad2d48a9da89e254be9327677465
+F src/whereexpr.c 906d30c21470bbafc31bbc2cd07a0753bdd57169caed6ba75b8b4fc0ecb24134
 F src/window.c c0a38cd32473e8e8e7bc435039f914a36ca42465506dc491c65870c01ddac9fb
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/affinity2.test 4d7a34d328e58ca2a2d78fd76c27614a41ca7ddf4312ded9c68c04f430b3b47d
@@ -2036,7 +2036,7 @@ F test/walslow.test 0c51843836c9dcf40a5ac05aa781bfb977b396ee2c872d92bd48b79d5dd9
 F test/walthread.test d562f51a61191ccfab64940df7aa1cef87c902fa5ab742590ef7f859dfe6a44b
 F test/walvfs.test e1a6ad0f3c78e98b55c3d5f0889cf366cc0d0a1cb2bccb44ac9ec67384adc4a1
 F test/where.test 5087c72d26fd075a1644c8512be9fe18de9bf2d2b0754f7fd9b74a1c6540c4fc
-F test/where2.test b73f8ee8f94b850764c429efe2d48171090628737dcc3df64a9f2214da02089f
+F test/where2.test 5d93a8aec78386539aa01cf72926eb39d90de4ce1bfb6d517f56ae9bf704ba8a
 F test/where3.test 4ccb156ae33de86414a52775a6f590a9d60ba2cbc7a93a24fa331b7bcf5b6030
 F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
@@ -2208,8 +2208,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 3f3fb9b638f59ad982beafb7c117f24ddd3da612e62c862510805fa672ffae06
-R 2749023ec3b3a42db0202431b16ac364
+P 7386faef618acb006086d688fcea854a7c555ac1bcfcaa294ea86e964e4ce75f
+R 836fd25a1bda58cdd1d612594b2acd20
 U drh
-Z a9125302b24a90e1badf9939a73e768f
+Z 09733955458454de050382ab21f95241
 # Remove this line to create a well-formed Fossil manifest.
index 03a8dbee288253d023847623c8f69777ca2d891f..fb21897fe17fde037adb3095ff21c7cab0d1d2cc 100644 (file)
@@ -1 +1 @@
-7386faef618acb006086d688fcea854a7c555ac1bcfcaa294ea86e964e4ce75f
+984c9b181801c1de06782335eb049f32d1dc1d5739a7fb9c94630c22159a4f8c
index c8c94ec8d9d156a91ba62239105994a7ac703ae0..890e5a1c5fdcd5a0fad3de31e63223301d49521b 100644 (file)
@@ -907,29 +907,56 @@ static void exprAnalyzeOrTerm(
       }
     }
 
-    /* At this point, okToChngToIN is true if original pTerm satisfies
-    ** case 1.  In that case, construct a new virtual term that is
-    ** pTerm converted into an IN operator.
+    /* At this point, okToChngToIN is true if original pTerm is a
+    ** candidate to satisfy case 1, though we are not yet certain that
+    ** the collating sequences are all compatible.  Try to construct a
+    ** new virtual term that is pTerm converted from an OR operator
+    ** into an IN operator.
+    **
+    ** During construction, verify that the collating sequences on all
+    ** subterms of the OR are compatible.  Omit the construction of the
+    ** new IN operator if there are any collating sequence mismatches.
     */
     if( okToChngToIN ){
       Expr *pDup;            /* A transient duplicate expression */
       ExprList *pList = 0;   /* The RHS of the IN operator */
       Expr *pLeft = 0;       /* The LHS of the IN operator */
+      CollSeq *pCollSeq = 0; /* Collating sequence to use */
       Expr *pNew;            /* The complete IN operator */
 
       for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){
+        Expr *pThis;
         if( (pOrTerm->wtFlags & TERM_OK)==0 ) continue;
         assert( pOrTerm->eOperator & WO_EQ );
         assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 );
         assert( pOrTerm->leftCursor==iCursor );
         assert( pOrTerm->u.x.leftColumn==iColumn );
-        pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
+        pThis = pOrTerm->pExpr;
+        pDup = sqlite3ExprDup(db, pThis->pRight, 0);
         pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup);
-        pLeft = pOrTerm->pExpr->pLeft;
+        if( pLeft==0 ){
+          pLeft = pThis->pLeft;
+          pCollSeq = sqlite3ExprCompareCollSeq(pParse, pThis);
+        }else{
+          assert( 0==sqlite3ExprCompare(pParse, pThis->pLeft, pLeft, -1) );
+          if( pCollSeq!=sqlite3ExprCompareCollSeq(pParse, pThis) ){
+            pLeft = 0;  /* Collating sequence mismatch */
+            break;
+          }
+        }
+      }
+      if( pLeft==0 ){
+        pNew = 0;  /* Collating sequence mismatch */
+      }else{
+        pDup = sqlite3ExprDup(db, pLeft, 0);
+        if( sqlite3ExprCollSeq(pParse, pDup)!=pCollSeq
+         && ALWAYS(pCollSeq!=0)
+        ){
+          assert( pCollSeq->zName!=0 );
+          pDup = sqlite3ExprAddCollateString(pParse, pDup, pCollSeq->zName);
+        }
+        pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0);
       }
-      assert( pLeft!=0 );
-      pDup = sqlite3ExprDup(db, pLeft, 0);
-      pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0);
       if( pNew ){
         int idxNew;
         transferJoinMarkings(pNew, pExpr);
index 21d266e1185416adfbcf6245517900b486f32f95..cfdcf0b57ff9f08a7bbf861957fea4c75964cf60 100644 (file)
@@ -456,6 +456,60 @@ ifcapable explain&&subquery {
   } {nosort t2249b * t2249a sqlite_autoindex_t2249a_1}
 }
 
+# Bug 2026-06-17T05:04:48Z
+#
+do_execsql_test where2-6.14.1 {
+  CREATE TABLE t614a(a TEXT COLLATE NOCASE, b TEXT COLLATE NOCASE);
+  INSERT INTO t614a VALUES('AAA','BBB');
+  CREATE TABLE t614b(x,y,c TEXT);
+  INSERT INTO t614b(c) VALUES('aaa'),('bbb');
+  CREATE INDEX t614b_c ON t614b(c);
+  SELECT c FROM t614a, t614b WHERE a=c OR b=c;
+} {aaa bbb}
+do_execsql_test where2-6.14.2 {
+  SELECT c FROM t614a, t614b WHERE c=a OR c=b;
+} {}
+do_execsql_test where2-6.14.3 {
+  SELECT c FROM t614a, t614b WHERE c=a OR b=c;
+} {bbb}
+do_execsql_test where2-6.14.4 {
+  SELECT c FROM t614a, t614b WHERE a=c OR c=b;
+} {aaa}
+do_execsql_test where2-6.15.1 {
+  CREATE TABLE t615a(a TEXT, b TEXT);
+  INSERT INTO t615a VALUES('AAA','BBB');
+  CREATE TABLE t615b(x,y,c TEXT COLLATE NOCASE);
+  INSERT INTO t615b(c) VALUES('aaa'),('bbb');
+  CREATE INDEX t615b_c ON t615b(c);
+  SELECT c FROM t615a, t615b WHERE c=a OR c=b;
+} {aaa bbb}
+do_execsql_test where2-6.15.2 {
+  SELECT c FROM t615a, t615b WHERE a=c OR b=c;
+} {}
+do_execsql_test where2-6.15.3 {
+  SELECT c FROM t615a, t615b WHERE c=a OR b=c;
+} {aaa}
+do_execsql_test where2-6.15.4 {
+  SELECT c FROM t615a, t615b WHERE a=c OR c=b;
+} {bbb}
+do_execsql_test where2-6.16.1 {
+  CREATE TABLE t616a(a TEXT COLLATE NOCASE, b TEXT COLLATE NOCASE);
+  INSERT INTO t616a VALUES('AAA','BBB');
+  CREATE TABLE t616b(x,y,c TEXT COLLATE NOCASE);
+  INSERT INTO t616b(c) VALUES('aaa'),('bbb');
+  CREATE INDEX t616b_c ON t616b(c);
+  SELECT c FROM t616a, t616b WHERE c=a OR c=b;
+} {aaa bbb}
+do_execsql_test where2-6.16.2 {
+  SELECT c FROM t616a, t616b WHERE a=c OR b=c;
+} {aaa bbb}
+do_execsql_test where2-6.16.3 {
+  SELECT c FROM t616a, t616b WHERE c=a OR b=c;
+} {aaa bbb}
+do_execsql_test where2-6.16.4 {
+  SELECT c FROM t616a, t616b WHERE a=c OR c=b;
+} {aaa bbb}
+
 # Variations on the order of terms in a WHERE clause in order
 # to make sure the OR optimizer can recognize them all.
 do_test where2-6.20 {