From: drh <> Date: Wed, 17 Jun 2026 13:31:01 +0000 (+0000) Subject: Fix the OR-to-IN optimization so that it works in cases where there are X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=aa1579de80b0db8c5d323b775fd6e4a1b4b58b35;p=thirdparty%2Fsqlite.git Fix the OR-to-IN optimization so that it works in cases where there are 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 --- diff --git a/manifest b/manifest index ed469bf3bb..6a295f3052 100644 --- 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. diff --git a/manifest.uuid b/manifest.uuid index 03a8dbee28..fb21897fe1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7386faef618acb006086d688fcea854a7c555ac1bcfcaa294ea86e964e4ce75f +984c9b181801c1de06782335eb049f32d1dc1d5739a7fb9c94630c22159a4f8c diff --git a/src/whereexpr.c b/src/whereexpr.c index c8c94ec8d9..890e5a1c5f 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -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); diff --git a/test/where2.test b/test/where2.test index 21d266e118..cfdcf0b57f 100644 --- a/test/where2.test +++ b/test/where2.test @@ -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 {