]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a problems with RIGHT JOINs.
authordrh <>
Thu, 12 Mar 2026 22:55:20 +0000 (22:55 +0000)
committerdrh <>
Thu, 12 Mar 2026 22:55:20 +0000 (22:55 +0000)
FossilOrigin-Name: 6ca269b677c6cdc03628fc4f3634ee1b9b956170f9bc41ba8d37b15cc6571a88

manifest
manifest.uuid
src/resolve.c
src/select.c
src/sqliteInt.h
src/wherecode.c
test/joinI.test

index e38d0ac83be1ef099adcc37d60a6addc4b5e5044..69a6815fff535c0bdc4b2564a2ac9e1b654b2586 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Avoid\san\sobscure\srace\scondition\sbetween\sa\scheckpointer\sand\sa\swriter\swrapping\saround\sto\sthe\sstart\sof\sthe\swal\sfile.
-D 2026-03-06T15:01:02.461
+C Fix\sa\sproblems\swith\sRIGHT\sJOINs.
+D 2026-03-12T22:55:20.962
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -734,14 +734,14 @@ F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f
 F src/prepare.c 2af0b5c1ec787c8eebd21baa9d79caf4a4dc3a18e76ce2edbf2027d706bca37a
 F src/printf.c 7297c2aeed4d90d80c5ba82920d9e57b7bfad04b3466be1d7e042db382fe296e
 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
-F src/resolve.c 5616fbcf3b833c7c705b24371828215ad0925d0c0073216c4f153348d5753f0a
+F src/resolve.c 243888da9f31c48d0890f8c9df30ed4be6fd098d295b0fe1c297a7f3c453ca53
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c fa67ce1dd60744c315791085897c1571ffe5554bf3e0410942b5fc9d7e0a4b56
+F src/select.c 5abbd22cae7469dae0a600d78636be77a5682cc372cf8da744d68bbe23298df2
 F src/shell.c.in 2c7e751795f38bb1855c35b556419cab5b8ba22e0f6758f5a629338065d6b79f
 F src/sqlite.h.in c0979f9ac1f5be887397dd2a0bb485636893a81b34d64df85123aae9650c42f2
 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
 F src/sqlite3ext.h 7f236ca1b175ffe03316d974ef57df79b3938466c28d2f95caef5e08c57f3a52
-F src/sqliteInt.h 88f7fc9ce1630d9a5f7e0a8e1f3287cdc63882fba985c18e7eee1b9f457f59aa
+F src/sqliteInt.h 601512a60e48f88e5148fc0e15f1efd03372df2a18bdee312d1590d14da6b5c1
 F src/sqliteLimit.h 4bc72c1519a27c538b7575c240a4472c829d78d27d69a00ddd5a046a0dbfd73a
 F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -820,7 +820,7 @@ F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
 F src/where.c 287324fe73a0ae8e55b3be89bb2fe4148e3a8394e1e2f10ed2113713a037d8a3
 F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
-F src/wherecode.c 71c5c6804b7f882dec8ec858758accae02fcfca13df3cc720f1f258e663ec7c5
+F src/wherecode.c fe08356c7f20f4e2290204b9147bded3bbfe5453e2c590be0f9b0b5f1c959e76
 F src/whereexpr.c 403a44eeec1a0f0914fccc6a59376b6924bc00ef6728fe6ffce4cf3051b320fc
 F src/window.c 538195bbc75bb924e18e368fbd4ed731a3fe3f901351b44f6466ec486f53affe
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
@@ -1334,7 +1334,7 @@ F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be
 F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
 F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
 F test/joinH.test 1d2fc3190be68525fd9ce749b9468c40ba2930181e52fb5ee6f836051b38effb
-F test/joinI.test fc7d24a2b1e444979b83bd92c30ebb975cebb5b9eae4442ce94969bd8d083053
+F test/joinI.test a4d37143fcc39e915d9feb08e614a13f88dfe332d77152a3c526a2370ddb9a70
 F test/journal1.test bc61a4228db11bffca118bd358ba4b868524bf080f3532749de6c539656e20fa
 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
 F test/journal3.test e5aeff93a7776cf644dbc48dec277655cff80a1cd24689036abc87869b120ea6
@@ -2173,9 +2173,11 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 3a24bf9374a04822505ef6db29374a107956c27a70fe5f6c2b468f8df8466dd4
-Q +7168988acbec2d8d51106a263e553f8942b8b23d983dbbe5028e0f9be68cbb83
-R 51d1b3d871c92ef5d9f39ecfaa790b27
+P 5aadfbbdd83b051b5f4a3f06eb60cf9b37aa1d62e676584719e6f785ecf148c7
+Q +cf2dc6dfad275dad8fef763a57baaaf6301b0d3bf1916be90f22200cbe0115d0
+Q +e956b36063e77b5ad0d8b8afb5dc942665f570d762929ff277e320c06ded8ce6
+Q +f27d578edac06eb28739f23351ab1cf07531bc7b32f4077e4dc9c8166f551d95
+R 6723709c10ad0e4cbb0f48842d99491e
 U drh
-Z c54f7e3caa8960fa656b031d5a1008d0
+Z 29bff4da4929fc4302c97fa479ce6268
 # Remove this line to create a well-formed Fossil manifest.
index bf93bdb242b2aa48123950b37d7630cc4d2ef92d..9b2080b1adf34cf7fd3e8339293bb08af3532314 100644 (file)
@@ -1 +1 @@
-5aadfbbdd83b051b5f4a3f06eb60cf9b37aa1d62e676584719e6f785ecf148c7
+6ca269b677c6cdc03628fc4f3634ee1b9b956170f9bc41ba8d37b15cc6571a88
index 16c193ca236b8bd5394bd22d53ffe69d76fd3201..c3ec56136304ab5c8d97c6e874d8374f2cc25752 100644 (file)
@@ -2079,6 +2079,14 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
       return WRC_Abort;
     }
 
+    /* If the SELECT statement contains ON clauses that were moved into
+    ** the WHERE clause, go through and verify that none of the terms
+    ** in the ON clauses reference tables to the right of the ON clause. */
+    if( (p->selFlags & SF_OnToWhere) ){
+      sqlite3SelectCheckOnClauses(pParse, p);
+      if( pParse->nErr ) return WRC_Abort;
+    }
+
     /* Advance to the next term of the compound
     */
     p = p->pPrior;
index bc17ecf84646bb982a1e43585f2825b32b7541cc..3ef7cc0a31c6bd20b2cb64b967cef07834ee3d8b 100644 (file)
@@ -7601,7 +7601,7 @@ static int selectCheckOnClausesSelect(Walker *pWalker, Select *pSelect){
 ** Check all ON clauses in pSelect to verify that they do not reference
 ** columns to the right.
 */
-static void selectCheckOnClauses(Parse *pParse, Select *pSelect){
+void sqlite3SelectCheckOnClauses(Parse *pParse, Select *pSelect){
   Walker w;
   CheckOnCtx sCtx;
   assert( pSelect->selFlags & SF_OnToWhere );
@@ -7744,18 +7744,6 @@ int sqlite3Select(
   }
 #endif
 
-  /* If the SELECT statement contains ON clauses that were moved into
-  ** the WHERE clause, go through and verify that none of the terms
-  ** in the ON clauses reference tables to the right of the ON clause.
-  ** Do this now, after name resolution, but before query flattening
-  */
-  if( p->selFlags & SF_OnToWhere ){
-    selectCheckOnClauses(pParse, p);
-    if( pParse->nErr ){
-      goto select_end;
-    }
-  }
-
   /* If the SF_UFSrcCheck flag is set, then this function is being called
   ** as part of populating the temp table for an UPDATE...FROM statement.
   ** In this case, it is an error if the target object (pSrc->a[0]) name
index 523bcfb3bd92c7ecff95e5f0b22384a0efc6252d..fa53fe69440d0758083a4bb912ee13c75a13d545 100644 (file)
@@ -5086,6 +5086,7 @@ Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
                          Expr*,ExprList*,u32,Expr*);
 void sqlite3SelectDelete(sqlite3*, Select*);
 void sqlite3SelectDeleteGeneric(sqlite3*,void*);
+void sqlite3SelectCheckOnClauses(Parse *pParse, Select *pSelect);
 Table *sqlite3SrcListLookup(Parse*, SrcList*);
 int sqlite3IsReadOnly(Parse*, Table*, Trigger*);
 void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
index 1efa34a5da0ece4b8f9c21b115e0683ee5f0f66c..65ed980b8b3b599c09a123b11f45b82b58821259 100644 (file)
@@ -2892,6 +2892,15 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
                                  sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
     }
   }
+  if( pLevel->iIdxCur ){
+    /* pSubWhere may contain expressions that read from an index on the
+    ** table on the RHS of the right join. All such expressions first test
+    ** if the index is pointing at a NULL row, and if so, read from the
+    ** table cursor instead. So ensure that the index cursor really is 
+    ** pointing at a NULL row here, so that no values are read from it during
+    ** the scan of the RHS of the RIGHT join below.  */
+    sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur);
+  }
   pFrom = &uSrc.sSrc;
   pFrom->nSrc = 1;
   pFrom->nAlloc = 1;
index 577ca4c2c34857f02630a8a9504ec62a6c8ec899..d0194579d834462bef7965f0a98400c676027584 100644 (file)
@@ -121,5 +121,95 @@ do_execsql_test 5.1 {
     INNER JOIN child2 ON child2.child2key = parent1.child2key;
 }
 
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 6.0 {
+  CREATE TABLE t5(a, d);
+  CREATE TABLE t6(a, e);
+  INSERT INTO t5 VALUES(1, 'red');
+  INSERT INTO t6 VALUES(0, 1000);
+
+  CREATE TABLE t7(x);
+  CREATE TABLE t8(y);
+}
+
+do_catchsql_test 6.1 {
+  SELECT * FROM t6 CROSS JOIN (t7 RIGHT JOIN t8 ON (t6.a));
+} {1 {no such column: t6.a}}
+
+do_catchsql_test 6.4 {
+  SELECT * FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6;
+} {1 {ON clause references tables to its right}}
+
+do_catchsql_test 6.5 {
+  SELECT * FROM 
+  (SELECT * FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6);
+} {1 {ON clause references tables to its right}}
+
+do_catchsql_test 6.6 {
+  SELECT *, NOT EXISTS (
+      SELECT * FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6
+  ) FROM t5;
+} {1 {ON clause references tables to its right}}
+
+do_catchsql_test 6.7 {
+  SELECT *, NOT EXISTS (
+      SELECT 1 
+        EXCEPT 
+      SELECT 11 FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6
+  ) FROM t5;
+} {1 {ON clause references tables to its right}}
+
+do_catchsql_test 6.8 {
+  SELECT *, NOT EXISTS (
+      SELECT 11 FROM t7 RIGHT JOIN t8 ON (t6.a) CROSS JOIN t6
+        EXCEPT 
+      SELECT 1 
+  ) FROM t5;
+} {1 {ON clause references tables to its right}}
+
+#-------------------------------------------------------------------------
+# Forum post: https://sqlite.org/forum/forumpost/e3dba5426a
+#
+reset_db
+do_execsql_test 7.0 {
+  CREATE TABLE t1(a);
+  INSERT INTO t1 VALUES(1);
+  CREATE TABLE t2(d, e);
+  CREATE INDEX t2def ON t2(d, (e+1));
+  INSERT INTO t2 VALUES(1, 3);
+  INSERT INTO t2 VALUES(2, 555);
+  INSERT INTO t2 VALUES(3, 3);
+}
+do_execsql_test 7.1 {
+  SELECT * FROM t1 RIGHT JOIN t2 ON ( a=d ) WHERE (t2.e+1)!=4;
+} {{} 2 555}
+
+reset_db
+do_execsql_test 7.2 {
+  CREATE TABLE rt0(c0 INTEGER PRIMARY KEY, c1, c2);
+  CREATE TABLE t1 (c1 INTEGER, c2 BLOB, c4 INTEGER);
+  CREATE UNIQUE INDEX i81 ON t1(c1, c4, +c2);
+
+  INSERT INTO t1(c4) VALUES ('a');
+  INSERT INTO rt0(c1, c2) VALUES (0.0, 0.0);
+  INSERT INTO t1(c2, c1) VALUES (1, 'b');
+}
+do_execsql_test 7.2 {
+  SELECT count(*) FROM (
+      SELECT DISTINCT * FROM rt0 FULL JOIN t1 ON rt0.c0=t1.c1
+      WHERE ((rt0.c1 OR t1.c4)) IS NOT (+ t1.c2)
+  );
+} {1}
+do_execsql_test 7.3 {
+  SELECT count(*) FROM (
+      SELECT DISTINCT * FROM rt0 LEFT JOIN t1 ON rt0.c0=t1.c1
+      WHERE ((rt0.c1 OR t1.c4)) IS NOT (+ t1.c2)
+      UNION
+      SELECT DISTINCT * FROM rt0 RIGHT JOIN t1 ON rt0.c0=t1.c1
+      WHERE ((rt0.c1 OR t1.c4)) IS NOT (+ t1.c2)
+  );
+} {1}
+
 finish_test