-C Steal\sthe\stest/joinI.test\sfrom\sthe\son-clause-error-fix\sbranch\sthat\ndemonstrates\sthat\sthis\sbranch\sdoes\snot\swork.
-D 2025-08-22T19:30:26.745
+C Fix\sthe\scases\sin\sjoinI.test\son\sthis\sbranch.
+D 2025-08-23T16:26:36.004
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c f8d1d011aba0964ff1bdccd049d4d2c2fec217efd90d202a4bb775e926b2c25d
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c a8dadaafc129724107aee67153732e3cd3637207993e2f60073b76344edba239
+F src/select.c 32ccbdbc89ba40065891c891a6a9dcd50fb3171eaf041b8549929f479dd540cb
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 7a313bfc16ea0a3b48f9b0fe69f887c971cc7884ce05969f9f02a229b8a31aae
+F src/sqliteInt.h 27c73e48878d31ef230ba867d1f8c3af6aed357fd93ccc605d3f1aae007ea62b
F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364
F src/status.c 0e72e4f6be6ccfde2488eb63210297e75f569f3ce9920f6c3d77590ec6ce5ffd
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
F test/joinH.test fd76024ff104baec16417db5cafc0894ad4e0863e70803e63c1bba0322706339
-F test/joinI.test 78cae6f746a78f32d8aedb8cf7b93bcd802c245db0986330844dfb1a6700ebab
+F test/joinI.test c30a1096c80a1300f088feb64fd356309cd14059d78352426550d2676f015ab4
F test/journal1.test bc61a4228db11bffca118bd358ba4b868524bf080f3532749de6c539656e20fa
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
F test/journal3.test e5aeff93a7776cf644dbc48dec277655cff80a1cd24689036abc87869b120ea6
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 0ec8a8f64434f8cc04f02a356ecaa409ebd886566ba09c32f0fff8ebd103a609
-R 1752fb5ac5dd2e1a0b7a8c6b08170380
-U drh
-Z 1500a43de7f87186b8488707b788a405
+P d163535ec8d463d74112d38a606fa4d900e66deb1a414c947973cd1880e41526
+R 690bd5803e72eefc9593af834d5d854a
+U dan
+Z fa70e0c9e7cfdd60641dd6afc4b1e883
# Remove this line to create a well-formed Fossil manifest.
}
/*
-** The xExpr and xSelect callbacks for the search of invalid ON clause terms.
+** Type used for Walker callbacks by selectCheckOnClauses().
+*/
+typedef struct CheckOnCtx CheckOnCtx;
+struct CheckOnCtx {
+ SrcList *pSrc; /* SrcList for this context */
+ int iJoin; /* Cursor numbers must be =< than this */
+ CheckOnCtx *pParent; /* Parent context */
+};
+
+/*
+** True if the SrcList passed as the only argument contains at least
+** one RIGHT or FULL JOIN. False otherwise.
+*/
+#define hasRightJoin(pSrc) (((pSrc)->a[0].fg.jointype & JT_LTORJ)!=0)
+
+/*
+** The xExpr callback 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)
+ CheckOnCtx *pCtx = pWalker->u.pCheckOnCtx;
+
+ /* Check if pExpr is root or near-root of an ON clause constraint that needs
+ ** to be checked to ensure that it does not refer to tables in its FROM
+ ** clause to the right of itself. i.e. it is either:
+ **
+ ** + an ON clause on an OUTER join, or
+ ** + an ON clause on an INNER join within a FROM that features at
+ ** least one RIGHT or FULL join.
+ */
+ if( (ExprHasProperty(pExpr, EP_OuterON))
+ || (ExprHasProperty(pExpr, EP_InnerON) && hasRightJoin(pCtx->pSrc))
){
- if( pExpr->w.iJoin<pExpr->iTable ){
- if( ExprHasProperty(pExpr, EP_OuterON) || pWalker->eCode ){
- sqlite3ErrorMsg(pWalker->pParse,
- "ON clause references tables to its right");
- return WRC_Abort;
+ /* If CheckOnCtx.iJoin is already set, then fall through and process
+ ** this expression node as normal. Or, if CheckOnCtx.iJoin is still 0,
+ ** set it to the cursor number of the RHS of the join to which this
+ ** ON expression was attached and then iterate through the entire
+ ** expression. */
+ assert( pCtx->iJoin==0 || pCtx->iJoin==pExpr->w.iJoin );
+ if( pCtx->iJoin==0 ){
+ pCtx->iJoin = pExpr->w.iJoin;
+ sqlite3WalkExprNN(pWalker, pExpr);
+ pCtx->iJoin = 0;
+ return WRC_Prune;
+ }
+ }
+
+ if( pExpr->op==TK_COLUMN ){
+ /* A column expression. Find the SrcList (if any) to which it refers.
+ ** Then, if CheckOnCtx.iJoin indicates that this expression is part of an
+ ** ON clause from that SrcList (i.e. if iJoin is non-zero), check that it
+ ** does not refer to a table to the right of CheckOnCtx.iJoin. */
+ do {
+ SrcList *pSrc = pCtx->pSrc;
+ int iTab = pExpr->iTable;
+ if( iTab>=pSrc->a[0].iCursor && iTab<=pSrc->a[pSrc->nSrc-1].iCursor ){
+ if( pCtx->iJoin && iTab>pCtx->iJoin ){
+ sqlite3ErrorMsg(pWalker->pParse,
+ "ON clause references tables to its right");
+ return WRC_Abort;
+ }
+ break;
}
- }
+ pCtx = pCtx->pParent;
+ }while( pCtx );
}
return WRC_Continue;
}
+
+/*
+** The xSelect callback for the search of invalid ON clause terms.
+*/
static int selectCheckOnClausesSelect(Walker *pWalker, Select *pSelect){
- UNUSED_PARAMETER(pWalker);
- if( (pSelect->selFlags & SF_OnToWhere)==0 ){
- return WRC_Prune;
- }else{
+ CheckOnCtx *pCtx = pWalker->u.pCheckOnCtx;
+ if( pSelect->pSrc==pCtx->pSrc || pSelect->pSrc->nSrc==0 ){
return WRC_Continue;
+ }else{
+ CheckOnCtx sCtx;
+ memset(&sCtx, 0, sizeof(sCtx));
+ sCtx.pSrc = pSelect->pSrc;
+ sCtx.pParent = pCtx;
+ pWalker->u.pCheckOnCtx = &sCtx;
+ sqlite3WalkSelect(pWalker, pSelect);
+ pWalker->u.pCheckOnCtx = pCtx;
+ pSelect->selFlags &= ~SF_OnToWhere;
+ return WRC_Prune;
}
}
*/
static void selectCheckOnClauses(Parse *pParse, Select *pSelect){
Walker w;
-
+ CheckOnCtx sCtx;
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);
+ w.u.pCheckOnCtx = &sCtx;
+ memset(&sCtx, 0, sizeof(sCtx));
+ sCtx.pSrc = pSelect->pSrc;
+ sqlite3WalkExprNN(&w, pSelect->pWhere);
pSelect->selFlags &= ~SF_OnToWhere;
}