From 4fd4e8f066b93a87e9c47502ada723ddb9e35cd7 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 30 Jan 2026 17:10:22 +0000 Subject: [PATCH] Make CROSS JOIN a join reorder barrier again, as the SQLite documentation says it is. It mistakenly stopped being a join barrier with check-in [c1ea064948ba08c4]. FossilOrigin-Name: d294106ecb78d765305ab740007f4a678e28baa13ae403fe57ea9cbfc259620f --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 22 +++++++++++++++------- test/where2.test | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index ea4319c897..aa0bc802d0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\snew\sCLI\sso\sthat\sthe\s".eqp"\ssetting\sdoes\snot\saffect\sthe\soutput\sof\sother\sdot\ncommands\ssuch\sas\s.schema\sor\s.tables. -D 2026-01-30T16:03:22.503 +C Make\sCROSS\sJOIN\sa\sjoin\sreorder\sbarrier\sagain,\sas\sthe\sSQLite\sdocumentation\ssays\sit\sis.\s\sIt\nmistakenly\sstopped\sbeing\sa\sjoin\sbarrier\swith\scheck-in\s[c1ea064948ba08c4]. +D 2026-01-30T17:10:22.815 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -820,7 +820,7 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab F src/wal.c 505a98fbc599a971d92cb90371cf54546c404cd61e04fd093e7b0c8ff978f9b6 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 -F src/where.c 13ba955e83c92d60d7da92f22ffc332741c720638f149b0783f9de2446963c2d +F src/where.c 4992c31e356b185a71bb3e9fc1ac6d747864240d5da4e81ec39b7ab38706332e F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da F src/wherecode.c 71c5c6804b7f882dec8ec858758accae02fcfca13df3cc720f1f258e663ec7c5 F src/whereexpr.c cadb37fbaa2cb6d1ec1687923c3ac21aed4187d198f4500c00a01abb24c3cb44 @@ -2024,7 +2024,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 52237a8cb27ebbf6583469429bb5733d1b94ac37d09c3dbd0f487952ed0ab3f8 +F test/where2.test 1dbff4ab847068a52b927a0c1a7cf7faed4c8cae081fbcdac9b052a3a209aefa F test/where3.test 4ccb156ae33de86414a52775a6f590a9d60ba2cbc7a93a24fa331b7bcf5b6030 F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 @@ -2194,8 +2194,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 293ec20e29e46d822a98302f8a0ba52ad6f74a7e93f780536d393730c2edbf61 -R 6219427f72f1032a75f0a00a557f2be0 +P a5a1b69b3feedb507ecfe2e9ddc039d7c01e1bb54e3e881df5010481886cdef9 +R 2c69c84e0f52c569a5c3b3b4ea6a7f1a U drh -Z 9a3047fdcb8c1ee9e50be3311ebce2d4 +Z fa98c5b69b350e02a0236ff7a868f9da # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 6b3edb18fb..37ae2bd790 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a5a1b69b3feedb507ecfe2e9ddc039d7c01e1bb54e3e881df5010481886cdef9 +d294106ecb78d765305ab740007f4a678e28baa13ae403fe57ea9cbfc259620f diff --git a/src/where.c b/src/where.c index 141746fbbc..4c367f6557 100644 --- a/src/where.c +++ b/src/where.c @@ -4849,7 +4849,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ sqlite3 *db = pWInfo->pParse->db; int rc = SQLITE_OK; int bFirstPastRJ = 0; - int hasRightJoin = 0; + int hasRightCrossJoin = 0; WhereLoop *pNew; @@ -4876,12 +4876,20 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ ** prevents the right operand of a RIGHT JOIN from being swapped with ** other elements even further to the right. ** - ** The JT_LTORJ case and the hasRightJoin flag work together to - ** prevent FROM-clause terms from moving from the right side of - ** a LEFT JOIN over to the left side of that join if the LEFT JOIN - ** is itself on the left side of a RIGHT JOIN. + ** The hasRightCrossJoin flag prevent FROM-clause terms from moving + ** from the right side of a LEFT JOIN or CROSS JOIN over to the + ** left side of that same join. This is a required restriction in + ** the case of LEFT JOIN - an incorrect answer may results if it is + ** not enforced. This restriction is not required for CROSS JOIN. + ** It is provided merely as a means of controlling join order, under + ** the theory that no real-world queries that care about performance + ** actually use the CROSS JOIN syntax. */ - if( pItem->fg.jointype & JT_LTORJ ) hasRightJoin = 1; + if( pItem->fg.jointype & (JT_LTORJ|JT_CROSS) ){ + testcase( pItem->fg.jointype & JT_LTORJ ); + testcase( pItem->fg.jointype & JT_CROSS ); + hasRightCrossJoin = 1; + } mPrereq |= mPrior; bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0; }else if( pItem->fg.fromExists ){ @@ -4895,7 +4903,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ mPrereq |= (pTerm->prereqAll & (pNew->maskSelf-1)); } } - }else if( !hasRightJoin ){ + }else if( !hasRightCrossJoin ){ mPrereq = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE diff --git a/test/where2.test b/test/where2.test index 83740bffdf..6045cb1177 100644 --- a/test/where2.test +++ b/test/where2.test @@ -794,4 +794,41 @@ do_execsql_test where2-15.1 { ORDER BY a,EXISTS(SELECT 1 FROM t1 LEFT JOIN (SELECT x AS y FROM t2) AS s2 ON t1.b=s2.y),x; } {12 34 NULL | 56 78 78 | 90 12 12 |} +# Demonstrate that CROSS JOIN is a join reordering barrier. +# +reset_db +do_execsql_test where2-16.1 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT); + CREATE TABLE t2(c INTEGER PRIMARY KEY, d INT); + CREATE TABLE t3(e INTEGER PRIMARY KEY, f INT); + CREATE TABLE t4(g INTEGER PRIMARY KEY, h INT); +} + +# Here the query planner wants to move t4 forward so that it is in front of +# t1. Ensure that does not happen. +do_execsql_test where2-16.2 { + EXPLAIN QUERY PLAN + SELECT * + FROM t1, t2 CROSS JOIN t3, t4 + WHERE t4.g=1 + AND t1.a=t4.h + AND t2.c=t1.b + AND t3.e=t2.d; +} {~/.* t4 .* t[12] .*/} + +# In this case the planner wants to move t1 to come after t4. Ensure that +# does not happen. +do_execsql_test where2-16.2 { + EXPLAIN QUERY PLAN + SELECT * + FROM t1, t2 CROSS JOIN t3, t4 + WHERE t2.c=1 + AND t3.e=t2.d + AND t4.g=t3.f + AND t1.a=t4.h; +} {~/.* t[34] .* t1 .*/} + + + + finish_test -- 2.47.3