]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix an issue going back to version 3.39.0 with transitive IS constraints
authordrh <>
Mon, 16 Jun 2025 17:36:11 +0000 (17:36 +0000)
committerdrh <>
Mon, 16 Jun 2025 17:36:11 +0000 (17:36 +0000)
in queries that make use of RIGHT JOIN.  Problem reported by
[forum:/forumpost/68f29a2005|forum post 68f29a2005].

FossilOrigin-Name: 9441fff52cc4e19c44df1a77ffe474f409d519b270c7166ce17f99e6ea48fc1e

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

index 13333671ff38dc637ef5bf091cf3caf1cfacb676..4deedc051acb6a8fccf3c4d7849b1bfdb28f2ee4 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Improved\sdebugging\soutput\sfor\sthe\stransitive\sconstraint\soptimization.
-D 2025-06-16T16:07:14.948
+C Fix\san\sissue\sgoing\sback\sto\sversion\s3.39.0\swith\stransitive\sIS\sconstraints\nin\squeries\sthat\smake\suse\sof\sRIGHT\sJOIN.\s\sProblem\sreported\sby\n[forum:/forumpost/68f29a2005|forum\spost\s68f29a2005].
+D 2025-06-16T17:36:11.335
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -870,7 +870,7 @@ F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
 F src/where.c a99fa3061a0155d2cb0e2c91df76dbf834750272a8d79ec5e2dce3ed4e6abad6
 F src/whereInt.h 02b646ea41a8342815b3628f8064c32618ea2e0f20b83216ea08cad11f0ac5aa
 F src/wherecode.c 9710e62379c000189476404f923d4d1b192d0def222fdd287b820cc085a0d555
-F src/whereexpr.c e853a9e53397fbddd75df4dd49ecc77bc978746ff0a8fe69bb7420e1dfc3ce53
+F src/whereexpr.c cf86bb36c5c4560aa13f81853bc8a345da441a0cce5cccbb634a80ea517f6cc0
 F src/window.c d01227141f622f24fbe36ca105fbe6ef023f9fd98f1ccd65da95f88886565db5
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/affinity2.test 4d7a34d328e58ca2a2d78fd76c27614a41ca7ddf4312ded9c68c04f430b3b47d
@@ -1360,7 +1360,7 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
 F test/ioerr5.test 5984da7bf74b6540aa356f2ab0c6ae68a6d12039a3d798a9ac6a100abc17d520
 F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
 F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9
-F test/join.test 255c1f42b7fe027b518cadb2bf40f41a793a95e7f8db2bceb54faaf59ff19c6c
+F test/join.test 2fcfd84640cfd9ff48f31b4b0d370c4d5498c355ae4384544668ca54d37ae186
 F test/join2.test f59d63264fb24784ae9c3bc9d867eb569cd6d442da5660f8852effe5c1938c27
 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
@@ -2208,8 +2208,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P a29627d7e7f8344d9a099cc133bda85250b02dc5ee5f358ba59691e0816b5b2d
-R 34371f8634c67d772cafde5946603d67
+P 94b53c20e9bc8687c44272419aa7a93076eebdeae9a4f50b95b96a49993f9c0d
+R 9792eecd1b6591bc063a59b87986da50
 U drh
-Z fb90426037785b3f69c83ee4d927ce82
+Z 7fae65e62acbc3e4e5d9b145df615a7d
 # Remove this line to create a well-formed Fossil manifest.
index ddcc0577e25ccea471a2b6f7d6c5ab6264efff0c..d70cf843b8a816956d0c89aa8831556bc744a76b 100644 (file)
@@ -1 +1 @@
-94b53c20e9bc8687c44272419aa7a93076eebdeae9a4f50b95b96a49993f9c0d
+9441fff52cc4e19c44df1a77ffe474f409d519b270c7166ce17f99e6ea48fc1e
index ae1df73a73332befec63b5d0966e2db7607f4f7f..6dcbd0167fdabc51d821edd79f6ca462995469b8 100644 (file)
@@ -931,30 +931,38 @@ static void exprAnalyzeOrTerm(
 **   1.  The SQLITE_Transitive optimization must be enabled
 **   2.  Must be either an == or an IS operator
 **   3.  Not originating in the ON clause of an OUTER JOIN
-**   4.  The affinities of A and B must be compatible
-**   5a. Both operands use the same collating sequence OR
-**   5b. The overall collating sequence is BINARY
+**   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
+**   6a. Both operands use the same collating sequence OR
+**   6b. The overall collating sequence is BINARY
 ** 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
 ** returned when it should not be, then incorrect answers might result.
 */
-static int termIsEquivalence(Parse *pParse, Expr *pExpr){
+static int termIsEquivalence(Parse *pParse, Expr *pExpr, SrcList *pSrc){
   char aff1, aff2;
   CollSeq *pColl;
-  if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
-  if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
-  if( ExprHasProperty(pExpr, EP_OuterON) ) return 0;
+  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( pExpr->op==TK_IS && (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
+    return 0;                                                          /* (4) */
+  }
   aff1 = sqlite3ExprAffinity(pExpr->pLeft);
   aff2 = sqlite3ExprAffinity(pExpr->pRight);
   if( aff1!=aff2
    && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2))
   ){
-    return 0;
+    return 0;                                                          /* (5) */
   }
   pColl = sqlite3ExprCompareCollSeq(pParse, pExpr);
-  if( sqlite3IsBinary(pColl) ) return 1;
-  return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
+  if( !sqlite3IsBinary(pColl)
+   && !sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight)
+  ){
+    return 0;                                                          /* (6) */
+  }
+  return 1;
 }
 
 /*
@@ -1222,8 +1230,8 @@ static void exprAnalyze(
         if( op==TK_IS ) pNew->wtFlags |= TERM_IS;
         pTerm = &pWC->a[idxTerm];
         pTerm->wtFlags |= TERM_COPIED;
-
-        if( termIsEquivalence(pParse, pDup) ){
+        assert( pWInfo->pTabList!=0 );
+        if( termIsEquivalence(pParse, pDup, pWInfo->pTabList) ){
           pTerm->eOperator |= WO_EQUIV;
           eExtraOp = WO_EQUIV;
         }
index ef2f6335c588549287f9027fab48de20aeef84cd..b33a7560a1e419fbb1bc97eb74bc638a69030eec 100644 (file)
@@ -1342,4 +1342,31 @@ do_execsql_test join-31.8 {
   SELECT * FROM t3 LEFT JOIN t2 ON true JOIN t4 ON true NATURAL LEFT JOIN t1;
 } {3 NULL 4 NULL}
 
+# 2025-06-16 https://sqlite.org/forum/forumpost/68f29a2005
+#
+# The transitive-constraint optimization was not working for RIGHT JOIN.
+#
+reset_db
+db null NULL
+do_execsql_test join-32.1 {
+  CREATE TABLE t0(w INT);
+  CREATE TABLE t1(x INT);
+  CREATE TABLE t2(y INT UNIQUE);
+  CREATE VIEW v0(z) AS SELECT CAST(x AS INT) FROM t1 LEFT JOIN t2 ON true;
+  INSERT INTO t1(x) VALUES(123);
+  INSERT INTO t2(y) VALUES(NULL);
+}
+do_execsql_test join-32.2 {
+  SELECT *
+  FROM t0 JOIN v0 ON w=z
+          RIGHT JOIN t1 ON true
+          INNER JOIN t2 ON y IS z;
+} {NULL NULL 123 NULL}
+do_execsql_test join-32.3 {
+  SELECT *
+  FROM t0 JOIN v0 ON w=z
+          RIGHT JOIN t1 ON true
+          INNER JOIN t2 ON +y IS z;
+} {NULL NULL 123 NULL}
+
 finish_test