From: drh <> Date: Mon, 1 Jun 2026 18:07:44 +0000 (+0000) Subject: Disable transitive WHERE constraints when there are explicit COLLATE X-Git-Tag: release~13 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=b2543d009832129cf2779cdc2af7a6eb0a2b4d0e;p=thirdparty%2Fsqlite.git Disable transitive WHERE constraints when there are explicit COLLATE operators. FossilOrigin-Name: 4c0455efe57d1e3c27327e942a1509de3eb7b0902bc3b90473e2cba8df90139b --- diff --git a/manifest b/manifest index 68bdecb6ed..e6d7045ae5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C For\sexpressions\sof\sthe\sform\s"(x,\sy...)\sIN\s(SELECT\sa,\sb\s...)"\swhere\sthe\s\nresult\sis\snot\strue,\sconsider\sthe\scollation\ssequences\sof\scolumns\s"a"\sand\s"b"\s\nwhen\sdeterminining\sif\sthe\sresult\sshould\sbe\sfalse\sor\sNULL. -D 2026-06-01T16:38:10.425 +C Disable\stransitive\sWHERE\sconstraints\swhen\sthere\sare\sexplicit\sCOLLATE\s\noperators. +D 2026-06-01T18:07:44.560 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -818,8 +818,8 @@ F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 F src/where.c a1caeb656f74e58de7e7310ee91c6dfb40e975c7dd9b18e61a965aea46a610f2 F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da -F src/wherecode.c 4d573077652f79780d6b50840ab8cbb72053dbb4eb230780dd2a146ab034475d -F src/whereexpr.c 95d97d148794a4afd751b899816da7286caa81ccda5840b6efdd9aed8218a804 +F src/wherecode.c bc39ccbe3648f01157038b16cc55bdbff128590972b7185521b5526dc2815765 +F src/whereexpr.c e167672449982d8b79bf3a2463324affc03399979689f735ac3a99ce87e14e2a F src/window.c c0a38cd32473e8e8e7bc435039f914a36ca42465506dc491c65870c01ddac9fb F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test 4d7a34d328e58ca2a2d78fd76c27614a41ca7ddf4312ded9c68c04f430b3b47d @@ -1885,7 +1885,7 @@ F test/trace3.test 2deeac66359c9f007f0fc9fb6336994a5d68fc1a65129f322a9e9546fd537 F test/trans.test 45f6f9ab6f66a7b5744f1caac06b558f95da62501916906cf55586a896f9f439 F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76 F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94 -F test/transitive1.test 342b398e4c68deee65a940c5af22a95f44c3090b6539c7a19175afb48ac3fb93 +F test/transitive1.test d6252d06ddc104d13372fce0da93af501546bf5d75cb4d2a1f83b8c27238997a F test/trigger1.test 141bd2bbfa82fa91aed7391f50517373c9823ff8f55af35e56313dbc75112ca1 F test/trigger2.test 30fcb3a6aa6782020d47968735ee6086ed795f73a7affa9406c8d5a36e7b5265 F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945 @@ -2198,9 +2198,9 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P dc1cc4d908df0e36447d0422ecbbbb6d2f59c7b49243407f8a9602e7bb0d1a00 -Q +04d7a9d788cf0bb811483baceb9142f67d4a2380d4af409d5300a92f7972472e -R 407f163d07684535b5d14e92c70ec991 +P 5ceba3fe8d9fb2b1e44a048b6e010d427b7f464b727b58824a2af1b53d57f1ec +Q +18ee3a17c589cfd34500b6a6547d0cb51aea4dd14b4e1e4b2d0cf0dbfb32378e +R efb476f2dd13a8f5e05df48686e926f1 U drh -Z c6afdb83ed161a9d5b4f6c0be022d3c7 +Z 6e37514e385a146b4e0673a6db0f81b9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a23f3edc2a..b6d4d2f722 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5ceba3fe8d9fb2b1e44a048b6e010d427b7f464b727b58824a2af1b53d57f1ec +4c0455efe57d1e3c27327e942a1509de3eb7b0902bc3b90473e2cba8df90139b diff --git a/src/wherecode.c b/src/wherecode.c index 8da485f64e..8a1a593c70 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2717,6 +2717,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( WO_EQ|WO_IN|WO_IS, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; + if( ExprHasProperty(pAlt->pExpr, EP_Collate) ) continue; if( (pAlt->eOperator & WO_IN) && ExprUseXSelect(pAlt->pExpr) && (pAlt->pExpr->x.pSelect->pEList->nExpr>1) diff --git a/src/whereexpr.c b/src/whereexpr.c index 6e1d46cb4b..334c469038 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -954,7 +954,8 @@ static void exprAnalyzeOrTerm( ** 3. Not originating in the ON clause of an OUTER JOIN ** 4. The operator is not IS or else the query does not contain RIGHT JOIN ** 5. The affinities of A and B must be compatible -** 6. Both operands use the same collating sequence +** 6. Both operands use the same collating sequence, and they must not +** use explicit COLLATE clauses. ** If this routine returns TRUE, that means that the RHS can be substituted ** for the LHS anyplace else in the WHERE clause where the LHS column occurs. ** This is an optimization. No harm comes from returning 0. But if 1 is @@ -965,7 +966,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr, SrcList *pSrc){ CollSeq *pColl; if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; /* (1) */ if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; /* (2) */ - if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* (3) */ + if( ExprHasProperty(pExpr, EP_OuterON|EP_Collate) ) return 0; /* (3) */ assert( pSrc!=0 ); if( pExpr->op==TK_IS && pSrc->nSrc>=2 diff --git a/test/transitive1.test b/test/transitive1.test index 1df4ecec58..60e8cacab0 100644 --- a/test/transitive1.test +++ b/test/transitive1.test @@ -14,6 +14,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix transitive1 do_execsql_test transitive1-100 { CREATE TABLE t1(a TEXT, b TEXT, c TEXT COLLATE NOCASE); @@ -437,4 +438,89 @@ do_execsql_test transitive1-900 { SELECT * FROM t1 CROSS JOIN t2 WHERE a=b AND b='ABC'; } {abc abc} +#------------------------------------------------------------------------- +reset_db +db cache size 0 + +do_execsql_test 1000 { + PRAGMA automatic_index = 0; + + CREATE TABLE t1(a TEXT); + CREATE TABLE t2(b TEXT); + + INSERT INTO t1 VALUES ('hello'); + INSERT INTO t1 VALUES ('Hello'); + INSERT INTO t1 VALUES ('HELLO'); + INSERT INTO t1 VALUES ('HeLLo'); + + INSERT INTO t2 VALUES ('hello'); + INSERT INTO t2 VALUES ('Hello'); + INSERT INTO t2 VALUES ('HELLO'); + INSERT INTO t2 VALUES ('HeLLo'); +} + +optimization_control db transitive 1 + +do_execsql_test 1010 { + SELECT t1.a, t2.b + FROM t1 CROSS JOIN t2 + WHERE t1.a = t2.b + AND t2.b COLLATE NOCASE = 'Hello'; +} { + hello hello + Hello Hello + HELLO HELLO + HeLLo HeLLo +} + +optimization_control db transitive 0 + +do_execsql_test 1020 { + SELECT t1.a, t2.b + FROM t1 CROSS JOIN t2 + WHERE t1.a = t2.b + AND t2.b COLLATE NOCASE = 'Hello'; +} { + hello hello + Hello Hello + HELLO HELLO + HeLLo HeLLo +} + +#------------------------------------------------------------------------- +reset_db + +do_execsql_test 1100 { + PRAGMA automatic_index = 0; + CREATE TABLE t1(x); + CREATE TABLE t2(y); + + INSERT INTO t1 VALUES('ABC'); + INSERT INTO t2 VALUES('abc'); +} + +do_execsql_test 1110 { + SELECT * FROM t1 CROSS JOIN t2 + WHERE (t1.x COLLATE nocase) = (t2.y COLLATE nocase) + AND (t2.y = 'ABC') +} {} + +#------------------------------------------------------------------------- +reset_db + +do_execsql_test 1200 { + PRAGMA automatic_index = 0; + CREATE TABLE t1(x); + CREATE TABLE t2(y); + + INSERT INTO t1 VALUES('ABC'); + INSERT INTO t2 VALUES('ABC'); +} + +do_execsql_test 1210 { + SELECT * FROM t1 CROSS JOIN t2 + WHERE t1.x = t2.y + AND (t1.x COLLATE nocase = 'abc') +} {ABC ABC} + finish_test