diff --git a/manifest b/manifest index c098e4e21c..01c8ad28a1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\streeview\sso\sthat\sit\sshows\sthe\scontents\sof\sON\sclauses\swhile\nthey\sare\sstill\sattached\sto\sthe\sSrcItem\sobject\sand\sbefore\sthey\sare\nmoved\sinto\sthe\sWHERE\sclause. -D 2025-08-22T18:19:26.194 +C Remember\sif\sa\sSELECT\sstatement\scontains\san\sON\sclause.\s\sIf\sit\sdoes,\sthen\safter\nname\sresolution,\sscan\sthe\sWHERE\sclause\sto\sverify\sthat\sthe\sON\sclause\sdoes\snot\nreference\stables\sto\sits\sright. +D 2025-08-22T19:17:44.984 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -741,12 +741,12 @@ F src/printf.c 5f0c957af9699e849d786e8fbaa3baab648ca5612230dc17916434c14bc8698f F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c f8d1d011aba0964ff1bdccd049d4d2c2fec217efd90d202a4bb775e926b2c25d F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 -F src/select.c 78ebf432355e820962a5001277cb43ffe3d82441c6dc9c8f0aeb0b15fbd5dd02 +F src/select.c a8dadaafc129724107aee67153732e3cd3637207993e2f60073b76344edba239 F src/shell.c.in 0636915df0dbac6c780f04959f5d1055f206fb281b2c8fc8b113fe7bfc7d44ef F src/sqlite.h.in ebfc0358de0e18aabee7fa918f2f846894e23bebc74160fbe265c99046ee61b8 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 0bfd049bb2088cc44c2ad54f2079d1c6e43091a4e1ce8868779b75f6c1484f1e -F src/sqliteInt.h a54f83985985655d1276e9e356dd6ae19b8d0b62c2abc75cc9e8f402ea141207 +F src/sqliteInt.h 7a313bfc16ea0a3b48f9b0fe69f887c971cc7884ce05969f9f02a229b8a31aae F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364 F src/status.c 0e72e4f6be6ccfde2488eb63210297e75f569f3ce9920f6c3d77590ec6ce5ffd F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -826,7 +826,7 @@ F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 F src/where.c f2f075bd17065922235632feb368efe92a7f03d42797eb575267574fbf6d4218 F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da F src/wherecode.c 71c5c6804b7f882dec8ec858758accae02fcfca13df3cc720f1f258e663ec7c5 -F src/whereexpr.c 78c28a8da187816d5d82049f2e343fb39f4a8e30b5bf1bda9b96cecde40ca8bd +F src/whereexpr.c 403a44eeec1a0f0914fccc6a59376b6924bc00ef6728fe6ffce4cf3051b320fc F src/window.c d01227141f622f24fbe36ca105fbe6ef023f9fd98f1ccd65da95f88886565db5 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test 4d7a34d328e58ca2a2d78fd76c27614a41ca7ddf4312ded9c68c04f430b3b47d @@ -2169,8 +2169,11 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 9ada44eb6d26532e45cdd2ed8d5707f1734d0177a13b493ff9cf070e0a992522 -R 6e697a296e1f3201fc9a77e474a82c56 +P 3e285bc117bcbfafe083709d27cca776d6ba418a9f0f58a6d4178035fba2d6ca +R 96dd89e794ca1ca3ff39762daec8741d +T *branch * on-clause-fix-3rd-try +T *sym-on-clause-fix-3rd-try * +T -sym-trunk * U drh -Z ad617721d7c7f540adf02c29a96cfdc3 +Z 3d2156998fed14f6409bf44712a40780 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bb4c1eff6c..eda1ade79b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3e285bc117bcbfafe083709d27cca776d6ba418a9f0f58a6d4178035fba2d6ca +0ec8a8f64434f8cc04f02a356ecaa409ebd886566ba09c32f0fff8ebd103a609 diff --git a/src/select.c b/src/select.c index 8bdd13e272..b9cc333acc 100644 --- a/src/select.c +++ b/src/select.c @@ -660,6 +660,7 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->u3.pOn); pRight->u3.pOn = 0; pRight->fg.isOn = 1; + p->selFlags |= SF_OnToWhere; } } return 0; @@ -7495,6 +7496,50 @@ static SQLITE_NOINLINE void existsToJoin( } } +/* +** The xExpr and xSelect callbacks for the search of invalid ON clause terms. +*/ +static int selectCheckOnClausesExpr(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_COLUMN + && ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) + ){ + if( pExpr->w.iJoiniTable ){ + if( ExprHasProperty(pExpr, EP_OuterON) || pWalker->eCode ){ + sqlite3ErrorMsg(pWalker->pParse, + "ON clause references tables to its right"); + return WRC_Abort; + } + } + } + return WRC_Continue; +} +static int selectCheckOnClausesSelect(Walker *pWalker, Select *pSelect){ + UNUSED_PARAMETER(pWalker); + if( (pSelect->selFlags & SF_OnToWhere)==0 ){ + return WRC_Prune; + }else{ + return WRC_Continue; + } +} + +/* +** Check all ON clauses in pSelect to verify that they do not reference +** columns to the right. +*/ +static void selectCheckOnClauses(Parse *pParse, Select *pSelect){ + Walker w; + + assert( pSelect->selFlags & SF_OnToWhere ); + assert( pSelect->pSrc!=0 && pSelect->pSrc->nSrc>=2 ); + memset(&w, 0, sizeof(w)); + w.pParse = pParse; + w.eCode = (pSelect->pSrc->a[0].fg.jointype & JT_LTORJ)!=0; + w.xExprCallback = selectCheckOnClausesExpr; + w.xSelectCallback = selectCheckOnClausesSelect; + sqlite3WalkSelect(&w, pSelect); + pSelect->selFlags &= ~SF_OnToWhere; +} + /* ** Generate byte-code for the SELECT statement given in the p argument. ** @@ -7622,6 +7667,18 @@ int sqlite3Select( } #endif + /* If the SELECT statement contains ON clauses that were moved into + ** 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 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a09c94ae62..d80ede7c75 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3660,6 +3660,7 @@ struct Select { #define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */ #define SF_Correlated 0x20000000 /* True if references the outer context */ +#define SF_OnToWhere 0x40000000 /* One or more ON clauses moved to WHERE */ /* True if SrcItem X is a subquery that has SF_NestedFrom */ #define IsNestedFrom(X) \ diff --git a/src/whereexpr.c b/src/whereexpr.c index 0d17b0d752..0d99ca85e6 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -1170,21 +1170,7 @@ static void exprAnalyze( prereqAll |= x; extraRight = x-1; /* ON clause terms may not be used with an index ** on left table of a LEFT JOIN. Ticket #3015 */ - if( (prereqAll>>1)>=x ){ - sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); - return; - } }else if( (prereqAll>>1)>=x ){ - /* The ON clause of an INNER JOIN references a table to its right. - ** Most other SQL database engines raise an error. But SQLite versions - ** 3.0 through 3.38 just put the ON clause constraint into the WHERE - ** clause and carried on. Beginning with 3.39, raise an error only - ** if there is a RIGHT or FULL JOIN in the query. This makes SQLite - ** more like other systems, and also preserves legacy. */ - if( ALWAYS(pSrc->nSrc>0) && (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ - sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); - return; - } ExprClearProperty(pExpr, EP_InnerON); } }