From a76ac88af86bb5a3753b7fec6c86bfcfaf64f439 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 8 Apr 2022 19:20:12 +0000 Subject: [PATCH 01/31] Preliminary code to support RIGHT JOIN. Everything seems to work, except that the code to compute the unmatched rows for the RIGHT JOIN has not yet been added, so the result of a RIGHT JOIN is currently the same as an INNER JOIN. FossilOrigin-Name: 415abd6731b8e8a605adabfa6066c8a852a8531c300df41325d5f7e75cae5a70 --- manifest | 33 +++++++++++---------- manifest.uuid | 2 +- src/build.c | 14 ++++++++- src/resolve.c | 4 +-- src/select.c | 10 ++----- src/sqliteInt.h | 15 +++++----- src/treeview.c | 6 +++- src/where.c | 79 +++++++++++++++++++++++-------------------------- src/wherecode.c | 6 ++-- src/whereexpr.c | 2 +- test/join.test | 12 ++++---- test/vtab6.test | 10 +++---- 12 files changed, 103 insertions(+), 90 deletions(-) diff --git a/manifest b/manifest index 4dcfbdb9c9..3f80acc376 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\ssqlite_dbpage\sfix\sat\s[/info/642a0b4752743216|check-in\s642a0b4752743]\nfrom\sabout\sa\smonth\sago\ssuch\sthat\sit\sstill\stakes\sa\stransaction\son\sall\sattached\ndatabases,\sbut\sit\sonly\sstarts\sa\sread\stransaction\sfor\sread-only\soperations,\nrather\sthan\sstarting\sa\swrite\stransaction\sfor\severything. -D 2022-04-08T17:01:29.519 +C Preliminary\scode\sto\ssupport\sRIGHT\sJOIN.\sEverything\sseems\sto\swork,\sexcept\sthat\nthe\scode\sto\scompute\sthe\sunmatched\srows\sfor\sthe\sRIGHT\sJOIN\shas\snot\syet\sbeen\nadded,\sso\sthe\sresult\sof\sa\sRIGHT\sJOIN\sis\scurrently\sthe\ssame\sas\san\sINNER\sJOIN. +D 2022-04-08T19:20:12.051 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -495,7 +495,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c 45161c2d5c9527b9c9bbfd7478daf3e0a619cf4bbe3278378aaea3d4b4e4f5b5 F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h 8ce1332edd89dfd2461d561ac10a0ab5601c8e06200cb5230596c3caaf54482e -F src/build.c ff119be98394a65bc8be7afc39d4a791a66f03a778d396de3ec456f5dfaf39e8 +F src/build.c 4a35acbeb5a73e5dfb0ed199a4ba601179cd22216654f9eb14c1dcfe993673e8 F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 026dbdcdbd8c3cde98a88483ee88310ff43150ab164ad768f12cc700a11495ad @@ -550,14 +550,14 @@ F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/prepare.c fd940149c691684e7c1073c3787a7170e44852b02d1275d2e30a5b58e89cfcaf F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c -F src/resolve.c 18d99e7146852d6064559561769fcca0743eb32b14a97da6dbed373a30ee0e76 +F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 7c106b3f36d483242b0a9c696614cd53d6f29e1ac81da6a3f0e9ea92f4211cc3 +F src/select.c cfa10564953f08eae09e0e92038b168403aade2879ba772cd5a47a08474da5fe F src/shell.c.in 1a8fbf932ecd582b1a5f66c1e8294f92c30d954616f5c7cc54c9623fcdbb028d F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e -F src/sqliteInt.h 364699d46b6cd2fbcaedfb907cedd42c8ed6e32a671f7f72edb257cad861c40b +F src/sqliteInt.h f8dc31c997573ac608a52bd98af91f21298d46b392732267aefa84b705be0e5c F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -617,7 +617,7 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c a38f52058b517929e264094abd0b5fd1e8e145a1aa43bc6f6a72ae5218f96c98 -F src/treeview.c 80a3d70bbc112399aa3cc7e777acc5d07c452e44c652630fc158d4594d86afd1 +F src/treeview.c d1401c129c980ace571f5071b91c349b8ad00bdb3d6f7112fb97a3da8bac85ff F src/trigger.c 372ada38f667c6823a3db15749eb668338e65c793394e55a37e56a489f2d1b55 F src/update.c 2cfaded82ca80ff56afb8c3ae5e88284e0824bfd86119827cc22481959f96f92 F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 @@ -639,10 +639,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c a17d57807aa63dca4f3204d01db7a863bc0290bd7913928582236d65c9ad4212 +F src/where.c c752850f0d4b21656ef2901484fb7c799a6d20efe1d13fa5e77a3554b7568625 F src/whereInt.h 15d2975c3b4c193c78c26674400a840da8647fe1777ae3b026e2d15937b38a03 -F src/wherecode.c 6292d7bf2d751b1ce68139a70e5468dd6615a9a9dab5b5e61c0053836723bb7a -F src/whereexpr.c 612f58f5f6e3e3bb94d10e2c56672ade8bbf94d4a928d3edb4e84e2ed3c00dca +F src/wherecode.c 7025f2a5b8b160af7ec4837e5d3c5befc2e61f0aafeea3f5f0403e46674f284f +F src/whereexpr.c a4542ee72e05e4ab9dfadb5ddc0116007dc2420763992a79dbe83aaf73212311 F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 @@ -1140,7 +1140,7 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9 -F test/join.test 85e9c88bf4700b45a48a6362cd47e0c0aefc572629827c31aa58a5978cabdfc5 +F test/join.test a1832675aa30f2b422ff934b553e30294ca899484710242a2119ebf21f20a66a F test/join2.test 9bdc615841b91c97a16d68bad9508aea11fa0c6b34e5689847bcc4dac70e4990 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 @@ -1711,7 +1711,7 @@ F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c840 F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3 F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391 -F test/vtab6.test 7167e8e526bc2e719e7818e18b2fd7bb8c455fa018b74e611943a86782e10125 +F test/vtab6.test 5f5c10c694763d9cb438ec12aab7d6899f0bd6e2fa120551e11dea3daa8063ca F test/vtab7.test 70c6f4a1d6177144a8236e4172d5fba92e683440374664ad1f04851fbb335d3c F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583 F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b @@ -1945,8 +1945,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 48f2e5a1fbaa8ceb32e08066766be74233b0c67ab430bbf7adfdff42cdb7b8ec -R 20c6686a28e5cb126a28d0c27a5e917b +P 8efd61e8518594e3e9c84681fc35796a78fe8885a97ad4dd19f1573ee8065b18 +R 322c8c2f976fdab57b24f3e90a096129 +T *branch * right-join +T *sym-right-join * +T -sym-trunk * U drh -Z 5fb2265312a791be3cfc50f876b63b0a +Z 04b77679382a7e72969224c19421c972 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 081aaf7939..9efedb98ec 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8efd61e8518594e3e9c84681fc35796a78fe8885a97ad4dd19f1573ee8065b18 \ No newline at end of file +415abd6731b8e8a605adabfa6066c8a852a8531c300df41325d5f7e75cae5a70 \ No newline at end of file diff --git a/src/build.c b/src/build.c index da862fa707..7181011c32 100644 --- a/src/build.c +++ b/src/build.c @@ -5071,10 +5071,22 @@ void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){ void sqlite3SrcListShiftJoinType(SrcList *p){ if( p ){ int i; + u8 allFlags = 0; for(i=p->nSrc-1; i>0; i--){ - p->a[i].fg.jointype = p->a[i-1].fg.jointype; + allFlags |= p->a[i].fg.jointype = p->a[i-1].fg.jointype; } p->a[0].fg.jointype = 0; + + /* All terms to the left of a RIGHT JOIN should be tagged with the + ** JT_LTORJ flags */ + if( allFlags & JT_RIGHT ){ + for(i=p->nSrc-1; ALWAYS(i>0) && (p->a[i].fg.jointype&JT_RIGHT)==0; i--){} + i--; + assert( i>=0 ); + do{ + p->a[i--].fg.jointype |= JT_LTORJ; + }while( i>=0 ); + } } } diff --git a/src/resolve.c b/src/resolve.c index 30785ca706..ac00564daa 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -367,9 +367,7 @@ static int lookupName( pExpr->iTable = pMatch->iCursor; assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pMatch->pTab; - /* RIGHT JOIN not (yet) supported */ - assert( (pMatch->fg.jointype & JT_RIGHT)==0 ); - if( (pMatch->fg.jointype & JT_LEFT)!=0 ){ + if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } pSchema = pExpr->y.pTab->pSchema; diff --git a/src/select.c b/src/select.c index 7ac23bd388..b9321aece7 100644 --- a/src/select.c +++ b/src/select.c @@ -301,10 +301,6 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){ sqlite3ErrorMsg(pParse, "unknown or unsupported join type: " "%T%s%T%s%T", pA, zSp1, pB, zSp2, pC); jointype = JT_INNER; - }else if( (jointype & JT_RIGHT)!=0 ){ - sqlite3ErrorMsg(pParse, - "RIGHT and FULL OUTER JOINs are not currently supported"); - jointype = JT_INNER; } return jointype; } @@ -6589,7 +6585,7 @@ int sqlite3Select( && i==0 && (p->selFlags & SF_ComplexResult)!=0 && (pTabList->nSrc==1 - || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) + || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0) ){ continue; } @@ -6741,8 +6737,8 @@ int sqlite3Select( */ if( i==0 && (pTabList->nSrc==1 - || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */ - && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) /* (2) */ + || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0) /* (1) */ + && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) /* (2) */ ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index ead20c9a2f..264a9d3731 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3132,13 +3132,14 @@ struct SrcList { /* ** Permitted values of the SrcList.a.jointype field */ -#define JT_INNER 0x0001 /* Any kind of inner or cross join */ -#define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */ -#define JT_NATURAL 0x0004 /* True for a "natural" join */ -#define JT_LEFT 0x0008 /* Left outer join */ -#define JT_RIGHT 0x0010 /* Right outer join */ -#define JT_OUTER 0x0020 /* The "OUTER" keyword is present */ -#define JT_ERROR 0x0040 /* unknown or unsupported join type */ +#define JT_INNER 0x01 /* Any kind of inner or cross join */ +#define JT_CROSS 0x02 /* Explicit use of the CROSS keyword */ +#define JT_NATURAL 0x04 /* True for a "natural" join */ +#define JT_LEFT 0x08 /* Left outer join */ +#define JT_RIGHT 0x10 /* Right outer join */ +#define JT_OUTER 0x20 /* The "OUTER" keyword is present */ +#define JT_LTORJ 0x40 /* One of the LEFT operands of a RIGHT JOIN */ +#define JT_ERROR 0x80 /* unknown or unsupported join type */ /* diff --git a/src/treeview.c b/src/treeview.c index 91aff8ddf1..f32064cd8e 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -144,8 +144,12 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx", pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed); } - if( pItem->fg.jointype & JT_LEFT ){ + if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){ + sqlite3_str_appendf(&x, " FULL-OUTER-JOIN"); + }else if( pItem->fg.jointype & JT_LEFT ){ sqlite3_str_appendf(&x, " LEFT-JOIN"); + }else if( pItem->fg.jointype & JT_RIGHT ){ + sqlite3_str_appendf(&x, " RIGHT-JOIN"); }else if( pItem->fg.jointype & JT_CROSS ){ sqlite3_str_appendf(&x, " CROSS-JOIN"); } diff --git a/src/where.c b/src/where.c index f08c350b06..60e314e758 100644 --- a/src/where.c +++ b/src/where.c @@ -732,13 +732,13 @@ static int termCanDriveIndex( char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0; - if( (pSrc->fg.jointype & JT_LEFT) + if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) && (pTerm->eOperator & WO_IS) ){ /* Cannot use an IS term from the WHERE clause as an index driver for - ** the RHS of a LEFT JOIN. Such a term can only be used if it is from - ** the ON clause. */ + ** the RHS of a LEFT JOIN or for the LHS of a RIGHT JOIN. Such a term + ** can only be used if it is from the ON clause. */ return 0; } if( (pTerm->prereqRight & notReady)!=0 ) return 0; @@ -808,7 +808,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex( ** WHERE clause (or the ON clause of a LEFT join) that constrain which ** rows of the target table (pSrc) that can be used. */ if( (pTerm->wtFlags & TERM_VIRTUAL)==0 - && ((pSrc->fg.jointype&JT_LEFT)==0 || ExprHasProperty(pExpr,EP_FromJoin)) + && ((pSrc->fg.jointype&(JT_LEFT|JT_LTORJ))==0 + || ExprHasProperty(pExpr,EP_FromJoin)) && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){ pPartial = sqlite3ExprAnd(pParse, pPartial, @@ -1081,7 +1082,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( const SrcItem *pTabItem; pLevel = &pWInfo->a[iLevel]; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; - if( pTabItem->fg.jointype & JT_LEFT ) continue; + if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue; pLoop = pLevel->pWLoop; if( NEVER(pLoop==0) ) continue; if( pLoop->prereq & notReady ) continue; @@ -1154,9 +1155,10 @@ static sqlite3_index_info *allocateIndexInfo( assert( pTerm->u.x.leftColumnnCol ); /* tag-20191211-002: WHERE-clause constraints are not useful to the - ** right-hand table of a LEFT JOIN. See tag-20191211-001 for the + ** right-hand table of a LEFT JOIN nor to the left-hand table of a + ** RIGHT JOIN. See tag-20191211-001 for the ** equivalent restriction for ordinary tables. */ - if( (pSrc->fg.jointype & JT_LEFT)!=0 + if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) ){ continue; @@ -2600,10 +2602,11 @@ static void whereLoopOutputAdjust( ** ** 2022-03-24: Self-culling only applies if either the extra terms ** are straight comparison operators that are non-true with NULL - ** operand, or if the loop is not a LEFT JOIN. + ** operand, or if the loop is not an OUTER JOIN. */ if( (pTerm->eOperator & 0x3f)!=0 - || (pWC->pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 + || (pWC->pWInfo->pTabList->a[pLoop->iTab].fg.jointype + & (JT_LEFT|JT_LTORJ))==0 ){ pLoop->wsFlags |= WHERE_SELFCULL; } @@ -2810,9 +2813,10 @@ static int whereLoopAddBtreeIndex( if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue; /* tag-20191211-001: Do not allow constraints from the WHERE clause to - ** be used by the right table of a LEFT JOIN. Only constraints in the + ** be used by the right table of a LEFT JOIN nor by the left table of a + ** RIGHT JOIN. Only constraints in the ** ON clause are allowed. See tag-20191211-002 for the vtab equivalent. */ - if( (pSrc->fg.jointype & JT_LEFT)!=0 + if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) ){ continue; @@ -4114,9 +4118,9 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ pNew->iTab = iTab; pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); - if( (pItem->fg.jointype & (JT_LEFT|JT_CROSS))!=0 ){ + if( (pItem->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the - ** right-hand-side of a LEFT or CROSS JOIN. */ + ** right-hand-side of a OUTER or CROSS JOIN. */ mPrereq = mPrior; }else{ mPrereq = 0; @@ -4125,7 +4129,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ if( IsVirtual(pItem->pTab) ){ SrcItem *p; for(p=&pItem[1]; pfg.jointype & (JT_LEFT|JT_CROSS)) ){ + if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){ mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); } } @@ -5844,6 +5848,10 @@ WhereInfo *sqlite3WhereBegin( } } if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); + if( pTabItem->fg.jointype & JT_RIGHT ){ + VdbeModuleComment((v, "TO-DO: Setup for the RIGHT JOIN of %s", + pTab->zName)); + } } pWInfo->iTop = sqlite3VdbeCurrentAddr(v); if( db->mallocFailed ) goto whereBeginError; @@ -6091,11 +6099,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ pWInfo->pTabList->a[pLevel->iFrom].pTab->zName)); } - /* The "break" point is here, just past the end of the outer loop. - ** Set it. - */ - sqlite3VdbeResolveLabel(v, pWInfo->iBreak); - assert( pWInfo->nLevel<=pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ int k, last; @@ -6106,6 +6109,16 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ assert( pTab!=0 ); pLoop = pLevel->pWLoop; + /* Do RIGHT JOIN processing. Generate code that will output the + ** unmatched rows of the right operand of the RIGHT JOIN with + ** all of the columns of the left operand set to NULL. + */ + if( pTabItem->fg.jointype & JT_RIGHT ){ + VdbeModuleComment((v, "TO-DO: RIGHT JOIN post-processing for %s", + pTab->zName)); + + } + /* For a co-routine, change all OP_Column references to the table of ** the co-routine into OP_Copy of result contained in a register. ** OP_Rowid becomes OP_Null. @@ -6117,29 +6130,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ continue; } -#ifdef SQLITE_ENABLE_EARLY_CURSOR_CLOSE - /* Close all of the cursors that were opened by sqlite3WhereBegin. - ** Except, do not close cursors that will be reused by the OR optimization - ** (WHERE_OR_SUBCLAUSE). And do not close the OP_OpenWrite cursors - ** created for the ONEPASS optimization. - */ - if( (pTab->tabFlags & TF_Ephemeral)==0 - && !IsView(pTab) - && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 - ){ - int ws = pLoop->wsFlags; - if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){ - sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); - } - if( (ws & WHERE_INDEXED)!=0 - && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0 - && pLevel->iIdxCur!=pWInfo->aiCurOnePass[1] - ){ - sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur); - } - } -#endif - /* If this scan uses an index, make VDBE code substitutions to read data ** from the index instead of from the table where possible. In some cases ** this optimization prevents the table from ever being read, which can @@ -6240,6 +6230,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ } } + /* The "break" point is here, just past the end of the outer loop. + ** Set it. + */ + sqlite3VdbeResolveLabel(v, pWInfo->iBreak); + /* Final cleanup */ if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo); diff --git a/src/wherecode.c b/src/wherecode.c index bab514a693..d349a94024 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2604,7 +2604,9 @@ Bitmask sqlite3WhereCodeOneLoopStart( } pE = pTerm->pExpr; assert( pE!=0 ); - if( (pTabItem->fg.jointype&JT_LEFT) && !ExprHasProperty(pE,EP_FromJoin) ){ + if( (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ)) + && !ExprHasProperty(pE,EP_FromJoin) + ){ continue; } @@ -2666,7 +2668,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; if( (pTerm->eOperator & WO_EQUIV)==0 ) continue; if( pTerm->leftCursor!=iCur ) continue; - if( pTabItem->fg.jointype & JT_LEFT ) continue; + if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue; pE = pTerm->pExpr; #ifdef WHERETRACE_ENABLED /* 0x800 */ if( sqlite3WhereTrace & 0x800 ){ diff --git a/src/whereexpr.c b/src/whereexpr.c index 26a521fffd..b74164d1f5 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -1831,7 +1831,7 @@ void sqlite3WhereTabFuncArgs( pRhs = sqlite3PExpr(pParse, TK_UPLUS, sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); - if( pItem->fg.jointype & JT_LEFT ){ + if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){ sqlite3SetJoinExpr(pTerm, pItem->iCursor); } whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); diff --git a/test/join.test b/test/join.test index f48a1a149d..fdacfc25c2 100644 --- a/test/join.test +++ b/test/join.test @@ -272,11 +272,13 @@ do_test join-2.2 { SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1; } } {1 2 3 {} 2 3 4 1 3 4 5 2} -do_test join-2.3 { - catchsql { - SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2; - } -} {1 {RIGHT and FULL OUTER JOINs are not currently supported}} + +#do_test join-2.3 { +# catchsql { +# SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2; +# } +#} {1 {RIGHT and FULL OUTER JOINs are not currently supported}} + do_test join-2.4 { execsql { SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d diff --git a/test/vtab6.test b/test/vtab6.test index ab52c9f15c..d8016e02f4 100644 --- a/test/vtab6.test +++ b/test/vtab6.test @@ -223,11 +223,11 @@ do_test vtab6-2.2 { SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1; } } {1 2 3 {} 2 3 4 1 3 4 5 2} -do_test vtab6-2.3 { - catchsql { - SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2; - } -} {1 {RIGHT and FULL OUTER JOINs are not currently supported}} +#do_test vtab6-2.3 { +# catchsql { +# SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2; +# } +#} {1 {RIGHT and FULL OUTER JOINs are not currently supported}} do_test vtab6-2.4 { execsql { SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d From c2308ad2a0cb4f6d957518c615d308ed79b42d04 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 9 Apr 2022 03:16:26 +0000 Subject: [PATCH 02/31] A few bits and bobs of code generation toward getting RIGHT JOIN to work. Much more remains to do. FossilOrigin-Name: 55b4543122646997d928598343bc467c993f971e86e9037c85430cc948750576 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/where.c | 18 ++++++++++++++++-- src/whereInt.h | 1 + src/wherecode.c | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 65eef2b977..639cdc85c3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\ssqlite3WhereMalloc()\sroutine\sfrom\strunk\sinto\sthe\sright-join\sbranch. -D 2022-04-09T03:12:52.801 +C A\sfew\sbits\sand\sbobs\sof\scode\sgeneration\stoward\sgetting\sRIGHT\sJOIN\sto\swork.\nMuch\smore\sremains\sto\sdo. +D 2022-04-09T03:16:26.838 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,9 +639,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 20b6907d66577c02bc2be434c3c8fd5f00f0112d467cb8ae5d97ced3af14f484 -F src/whereInt.h 41ce0a8c0368372d8422e420e05a1e037624ce52fae139c3c19538ee491fb4c0 -F src/wherecode.c 79813939e009cbd8a042d57e6c0cad1a437d8e2e19b8be61c70760089f055c89 +F src/where.c 3bd028fa90533d5caad6c3160e404eff2595ee751a8e2c1f4d1617975caa192c +F src/whereInt.h 5cd48fd01bff983a86d0ef02f8e0c9a5c870dbaebc4d7b2ae2212aefd5df9cd7 +F src/wherecode.c f25a1d1ad2a8d002805e107d2ec323db410ad0246a52b944d10b8d4da0e01f7c F src/whereexpr.c ac8985bbd983f34273b1e0d05cd738ff436331674c1b22f4caf6537e1eca4691 F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1945,8 +1945,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 415abd6731b8e8a605adabfa6066c8a852a8531c300df41325d5f7e75cae5a70 f237e1d8cc41b937f34288daebfacf5f7b0990a807a805e0cb6b45bc730192d6 -R 14570ffbcb3ed6fd5a47242c31653712 +P b1b3845aa38f469a27f07c8f6e8a98334f7967b19661ee4cf155d6997afd9d4c +R bc7d39cae3cf9a210e7fffa29f471f8f U drh -Z 80db52d601f5cc05776abad4ced7d9c5 +Z cd50394e42c6a1bed1272dd9e082a119 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b82dd29e59..1618a7c5ef 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b1b3845aa38f469a27f07c8f6e8a98334f7967b19661ee4cf155d6997afd9d4c \ No newline at end of file +55b4543122646997d928598343bc467c993f971e86e9037c85430cc948750576 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 338501090f..a5fab2cd51 100644 --- a/src/where.c +++ b/src/where.c @@ -5870,8 +5870,22 @@ WhereInfo *sqlite3WhereBegin( } if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); if( pTabItem->fg.jointype & JT_RIGHT ){ - VdbeModuleComment((v, "TO-DO: Setup for the RIGHT JOIN of %s", - pTab->zName)); + assert( pTab==pTabItem->pTab ); + pLevel->iRJMatch = pParse->nTab++; + if( HasRowid(pTab) ){ + KeyInfo *pInfo; + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pLevel->iRJMatch, 1); + pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0); + if( pInfo ){ + pInfo->aColl[0] = 0; + pInfo->aSortFlags[0] = 0; + sqlite3VdbeAppendP4(v, pInfo, P4_KEYINFO); + } + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pLevel->iRJMatch, pPk->nKeyCol); + sqlite3VdbeSetP4KeyInfo(pParse, pPk); + } } } pWInfo->iTop = sqlite3VdbeCurrentAddr(v); diff --git a/src/whereInt.h b/src/whereInt.h index e0f44d6bac..df62db4f10 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -75,6 +75,7 @@ struct WhereLevel { int addrLikeRep; /* LIKE range processing address */ #endif int regFilter; /* Bloom filter */ + int iRJMatch; /* Cursor or rowset used for matched RIGHT JOIN rows */ u8 iFrom; /* Which entry in the FROM clause */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ int p1, p2; /* Operands of the opcode used to end the loop */ diff --git a/src/wherecode.c b/src/wherecode.c index 74873de091..5b8ed8934b 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2721,6 +2721,41 @@ Bitmask sqlite3WhereCodeOneLoopStart( } } + /* For a RIGHT OUTER JOIN, record the fact that the current row has + ** been matched at least once. + */ + if( pLevel->iRJMatch ){ + Table *pTab; + int nPk; + int r; + int jmp1 = 0; + + pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab; + if( HasRowid(pTab) ){ + r = sqlite3GetTempRange(pParse, 2); + sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1); + nPk = 1; + }else{ + int iPk; + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + nPk = pPk->nKeyCol; + r = sqlite3GetTempRange(pParse, nPk+1); + for(iPk=0; iPkaiColumn[iPk]; + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+1+iPk); + } + } + jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, pLevel->iRJMatch, 0, r+1, nPk); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_MakeRecord, r+1, nPk, r); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pLevel->iRJMatch, r, r+1, nPk); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + sqlite3VdbeJumpHere(v, jmp1); + + /* Release the array of temp registers */ + sqlite3ReleaseTempRange(pParse, r, nPk+1); + } + #if WHERETRACE_ENABLED /* 0x20800 */ if( sqlite3WhereTrace & 0x20000 ){ sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n", From 7c1734b09e436176c2aac461e835c29532403ad4 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 9 Apr 2022 12:27:20 +0000 Subject: [PATCH 03/31] The interior of the RIGHT JOIN loop is now a subroutine. FossilOrigin-Name: 549f5a7ee639de80f049445002f58e93c805f9a3d3db1987ec9d139ccef4805e --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/where.c | 19 +++++++++++++++---- src/whereInt.h | 13 ++++++++++++- src/wherecode.c | 24 +++++++++++++++++++----- 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index 639cdc85c3..f63c9edb92 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C A\sfew\sbits\sand\sbobs\sof\scode\sgeneration\stoward\sgetting\sRIGHT\sJOIN\sto\swork.\nMuch\smore\sremains\sto\sdo. -D 2022-04-09T03:16:26.838 +C The\sinterior\sof\sthe\sRIGHT\sJOIN\sloop\sis\snow\sa\ssubroutine. +D 2022-04-09T12:27:20.408 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,9 +639,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 3bd028fa90533d5caad6c3160e404eff2595ee751a8e2c1f4d1617975caa192c -F src/whereInt.h 5cd48fd01bff983a86d0ef02f8e0c9a5c870dbaebc4d7b2ae2212aefd5df9cd7 -F src/wherecode.c f25a1d1ad2a8d002805e107d2ec323db410ad0246a52b944d10b8d4da0e01f7c +F src/where.c 8aed75fc91e396b4576fcd8fc38e617a049496102e36ab92f1ff79b88c06ad27 +F src/whereInt.h ecf0d9fe3e35f2546e660c6389e56aedb6fd2434e31a0449b261ff55ebc6df2d +F src/wherecode.c 39532c183ea306ae44b5ab3119b244407b46970b088c59d5751c5724b4b6ec15 F src/whereexpr.c ac8985bbd983f34273b1e0d05cd738ff436331674c1b22f4caf6537e1eca4691 F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1945,8 +1945,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P b1b3845aa38f469a27f07c8f6e8a98334f7967b19661ee4cf155d6997afd9d4c -R bc7d39cae3cf9a210e7fffa29f471f8f +P 55b4543122646997d928598343bc467c993f971e86e9037c85430cc948750576 +R d55a6c933c69ce9dd22747640f9c6ba1 U drh -Z cd50394e42c6a1bed1272dd9e082a119 +Z 4ad8351a3e92bf37b209fecc61321431 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1618a7c5ef..e1f7456fca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -55b4543122646997d928598343bc467c993f971e86e9037c85430cc948750576 \ No newline at end of file +549f5a7ee639de80f049445002f58e93c805f9a3d3db1987ec9d139ccef4805e \ No newline at end of file diff --git a/src/where.c b/src/where.c index a5fab2cd51..afcecd77bf 100644 --- a/src/where.c +++ b/src/where.c @@ -5869,12 +5869,18 @@ WhereInfo *sqlite3WhereBegin( } } if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); - if( pTabItem->fg.jointype & JT_RIGHT ){ + if( (pTabItem->fg.jointype & JT_RIGHT)!=0 + && (pLevel->pRJ = sqlite3WhereMalloc(pWInfo, sizeof(WhereRightJoin)))!=0 + ){ + WhereRightJoin *pRJ = pLevel->pRJ; + pRJ->iMatch = pParse->nTab++; + pRJ->regBloom = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); + pRJ->regReturn = ++pParse->nMem; assert( pTab==pTabItem->pTab ); - pLevel->iRJMatch = pParse->nTab++; if( HasRowid(pTab) ){ KeyInfo *pInfo; - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pLevel->iRJMatch, 1); + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1); pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0); if( pInfo ){ pInfo->aColl[0] = 0; @@ -5883,7 +5889,7 @@ WhereInfo *sqlite3WhereBegin( } }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pLevel->iRJMatch, pPk->nKeyCol); + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, pPk->nKeyCol); sqlite3VdbeSetP4KeyInfo(pParse, pPk); } } @@ -5999,6 +6005,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ for(i=pWInfo->nLevel-1; i>=0; i--){ int addr; pLevel = &pWInfo->a[i]; + if( pLevel->pRJ ){ + WhereRightJoin *pRJ = (WhereRightJoin*)pLevel->pRJ; + sqlite3VdbeChangeP2(v, pRJ->addrSubrtn-1, sqlite3VdbeCurrentAddr(v)); + sqlite3VdbeAddOp2(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn); + } pLoop = pLevel->pWLoop; if( pLevel->op!=OP_Noop ){ #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT diff --git a/src/whereInt.h b/src/whereInt.h index df62db4f10..7b5be3011d 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -33,6 +33,7 @@ typedef struct WhereScan WhereScan; typedef struct WhereOrCost WhereOrCost; typedef struct WhereOrSet WhereOrSet; typedef struct WhereMemBlock WhereMemBlock; +typedef struct WhereRightJoin WhereRightJoin; /* ** This object is a header on a block of allocated memory that will be @@ -43,6 +44,16 @@ struct WhereMemBlock { u8 sz; /* Bytes of space */ }; +/* +** Extra information attached to a WhereLevel that is a RIGHT JOIN. +*/ +struct WhereRightJoin { + int iMatch; /* Cursor used to determine prior matched rows */ + int regBloom; /* Bloom filter for iRJMatch */ + int regReturn; /* Return register for the interior subroutine */ + int addrSubrtn; /* Starting address for the interior subroutine */ +}; + /* ** This object contains information needed to implement a single nested ** loop in WHERE clause. @@ -75,7 +86,7 @@ struct WhereLevel { int addrLikeRep; /* LIKE range processing address */ #endif int regFilter; /* Bloom filter */ - int iRJMatch; /* Cursor or rowset used for matched RIGHT JOIN rows */ + WhereRightJoin *pRJ; /* Extra information for RIGHT JOIN */ u8 iFrom; /* Which entry in the FROM clause */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ int p1, p2; /* Operands of the opcode used to end the loop */ diff --git a/src/wherecode.c b/src/wherecode.c index 5b8ed8934b..853646c713 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2724,12 +2724,18 @@ Bitmask sqlite3WhereCodeOneLoopStart( /* For a RIGHT OUTER JOIN, record the fact that the current row has ** been matched at least once. */ - if( pLevel->iRJMatch ){ + if( pLevel->pRJ ){ Table *pTab; int nPk; int r; int jmp1 = 0; + WhereRightJoin *pRJ = pLevel->pRJ; + /* pTab is the right-hand table of the RIGHT JOIN. Generate code that + ** will record that the current row of that table has been matched at + ** least once. This is accomplished by storing the PK for the row in + ** both the iMatch index and the regBloom Bloom filter. + */ pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab; if( HasRowid(pTab) ){ r = sqlite3GetTempRange(pParse, 2); @@ -2745,15 +2751,23 @@ Bitmask sqlite3WhereCodeOneLoopStart( sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+1+iPk); } } - jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, pLevel->iRJMatch, 0, r+1, nPk); + jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, 0, r+1, nPk); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, r+1, nPk, r); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pLevel->iRJMatch, r, r+1, nPk); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pRJ->iMatch, r, r+1, nPk); + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3VdbeJumpHere(v, jmp1); - - /* Release the array of temp registers */ sqlite3ReleaseTempRange(pParse, r, nPk+1); + + /* Create a subroutine used to process all interior loops and code + ** of the RIGHT JOIN. During normal operation, the subroutine will + ** be in-line with the rest of the code. But at the end, a separate + ** loop will run that invokes this subroutine for unmatched rows + ** of pTab, with all tables to left begin set to NULL. + */ + sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn); + pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v); } #if WHERETRACE_ENABLED /* 0x20800 */ From 86c1beb402ef54c1427d5f2e6bbc38ebe1249843 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 9 Apr 2022 14:48:35 +0000 Subject: [PATCH 04/31] Add byte-code that computes unmatched rows on the right table of a RIGHT JOIN. Compiles, and the code looks semi-reasonable, but still does not run. Incremental check-in. FossilOrigin-Name: 2db5a498e74241dd19ef51c601f1a2b3b687faed3e1be2d1e3ada737406ac8e9 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index f63c9edb92..c3406710bb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\sinterior\sof\sthe\sRIGHT\sJOIN\sloop\sis\snow\sa\ssubroutine. -D 2022-04-09T12:27:20.408 +C Add\sbyte-code\sthat\scomputes\sunmatched\srows\son\sthe\sright\stable\sof\sa\sRIGHT\sJOIN.\nCompiles,\sand\sthe\scode\slooks\ssemi-reasonable,\sbut\sstill\sdoes\snot\srun.\nIncremental\scheck-in. +D 2022-04-09T14:48:35.562 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 8aed75fc91e396b4576fcd8fc38e617a049496102e36ab92f1ff79b88c06ad27 +F src/where.c 7d0b140d373dce6b86e4023239265db5c4af465ea3cf1ff92f9a38369518e166 F src/whereInt.h ecf0d9fe3e35f2546e660c6389e56aedb6fd2434e31a0449b261ff55ebc6df2d F src/wherecode.c 39532c183ea306ae44b5ab3119b244407b46970b088c59d5751c5724b4b6ec15 F src/whereexpr.c ac8985bbd983f34273b1e0d05cd738ff436331674c1b22f4caf6537e1eca4691 @@ -1945,8 +1945,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 55b4543122646997d928598343bc467c993f971e86e9037c85430cc948750576 -R d55a6c933c69ce9dd22747640f9c6ba1 +P 549f5a7ee639de80f049445002f58e93c805f9a3d3db1987ec9d139ccef4805e +R 897adc2c472d0e3292a88884e473c6ff U drh -Z 4ad8351a3e92bf37b209fecc61321431 +Z 9e61af1d71063444102e67ca76812f4f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e1f7456fca..3031369ad5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -549f5a7ee639de80f049445002f58e93c805f9a3d3db1987ec9d139ccef4805e \ No newline at end of file +2db5a498e74241dd19ef51c601f1a2b3b687faed3e1be2d1e3ada737406ac8e9 \ No newline at end of file diff --git a/src/where.c b/src/where.c index afcecd77bf..eec8ccb981 100644 --- a/src/where.c +++ b/src/where.c @@ -6006,7 +6006,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ int addr; pLevel = &pWInfo->a[i]; if( pLevel->pRJ ){ - WhereRightJoin *pRJ = (WhereRightJoin*)pLevel->pRJ; + /* Terminate the subroutine that forms the interior of the loop of + ** the RIGHT JOIN table */ + WhereRightJoin *pRJ = pLevel->pRJ; sqlite3VdbeChangeP2(v, pRJ->addrSubrtn-1, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp2(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn); } @@ -6159,10 +6161,49 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ ** unmatched rows of the right operand of the RIGHT JOIN with ** all of the columns of the left operand set to NULL. */ - if( pTabItem->fg.jointype & JT_RIGHT ){ - VdbeModuleComment((v, "TO-DO: RIGHT JOIN post-processing for %s", - pTab->zName)); - + if( pLevel->pRJ ){ + WhereRightJoin *pRJ = pLevel->pRJ; + Expr *pSubWhere = 0; + WhereClause *pWC = &pWInfo->sWC; + WhereInfo *pSubWInfo; + SrcList sFrom; + for(k=0; knTerm; k++){ + WhereTerm *pTerm = &pWC->a[i]; + if( pTerm->wtFlags & TERM_VIRTUAL ) break; + if( pTerm->prereqAll & ~pLoop->maskSelf ) continue; + pSubWhere = sqlite3ExprAnd(pParse, pSubWhere, + sqlite3ExprDup(db, pTerm->pExpr, 0)); + } + sFrom.nSrc = 1; + sFrom.nAlloc = 1; + memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem)); + sFrom.a[0].fg.jointype = 0; + pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0, + WHERE_OR_SUBCLAUSE, 0); + if( pSubWInfo ){ + int iCur = pLevel->iTabCur; + int r = ++pParse->nMem; + int nPk; + int addrCont = sqlite3WhereContinueLabel(pSubWInfo); + if( HasRowid(pTab) ){ + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r); + nPk = 1; + }else{ + int iPk; + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + nPk = pPk->nKeyCol; + pParse->nMem += nPk - 1; + for(iPk=0; iPkaiColumn[iPk]; + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); + } + } + sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, addrCont, r, nPk); + sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk); + sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn); + sqlite3WhereEnd(pSubWInfo); + } + sqlite3ExprDelete(pParse->db, pSubWhere); } /* For a co-routine, change all OP_Column references to the table of From de24dd706e3f5e23389ad314a8941af8f56c8a2f Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 9 Apr 2022 18:48:11 +0000 Subject: [PATCH 05/31] Bug fixes. A basic FULL OUTER JOIN now works. FossilOrigin-Name: 34bbeeb77bd530b2b1f0390e9e552f65ae35f09a74d80a09dd327e64f9be51a1 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 6 ++++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index c3406710bb..f2bc29afed 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sbyte-code\sthat\scomputes\sunmatched\srows\son\sthe\sright\stable\sof\sa\sRIGHT\sJOIN.\nCompiles,\sand\sthe\scode\slooks\ssemi-reasonable,\sbut\sstill\sdoes\snot\srun.\nIncremental\scheck-in. -D 2022-04-09T14:48:35.562 +C Bug\sfixes.\s\sA\sbasic\sFULL\sOUTER\sJOIN\snow\sworks. +D 2022-04-09T18:48:11.005 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 7d0b140d373dce6b86e4023239265db5c4af465ea3cf1ff92f9a38369518e166 +F src/where.c ddeca7f959c3da448012737c0bf0c283232a317c7ef0bdc6587352f4189bd8aa F src/whereInt.h ecf0d9fe3e35f2546e660c6389e56aedb6fd2434e31a0449b261ff55ebc6df2d F src/wherecode.c 39532c183ea306ae44b5ab3119b244407b46970b088c59d5751c5724b4b6ec15 F src/whereexpr.c ac8985bbd983f34273b1e0d05cd738ff436331674c1b22f4caf6537e1eca4691 @@ -1945,8 +1945,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 549f5a7ee639de80f049445002f58e93c805f9a3d3db1987ec9d139ccef4805e -R 897adc2c472d0e3292a88884e473c6ff +P 2db5a498e74241dd19ef51c601f1a2b3b687faed3e1be2d1e3ada737406ac8e9 +R 0ae50938e4462db8bba3d38695099c31 U drh -Z 9e61af1d71063444102e67ca76812f4f +Z 29e379e6c2c78a86783f35cb54daa623 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3031369ad5..df20f470e8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2db5a498e74241dd19ef51c601f1a2b3b687faed3e1be2d1e3ada737406ac8e9 \ No newline at end of file +34bbeeb77bd530b2b1f0390e9e552f65ae35f09a74d80a09dd327e64f9be51a1 \ No newline at end of file diff --git a/src/where.c b/src/where.c index eec8ccb981..bec9da8db0 100644 --- a/src/where.c +++ b/src/where.c @@ -6009,7 +6009,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ /* Terminate the subroutine that forms the interior of the loop of ** the RIGHT JOIN table */ WhereRightJoin *pRJ = pLevel->pRJ; - sqlite3VdbeChangeP2(v, pRJ->addrSubrtn-1, sqlite3VdbeCurrentAddr(v)); + sqlite3VdbeChangeP1(v, pRJ->addrSubrtn-1, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp2(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn); } pLoop = pLevel->pWLoop; @@ -6184,6 +6184,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ int iCur = pLevel->iTabCur; int r = ++pParse->nMem; int nPk; + int jmp; int addrCont = sqlite3WhereContinueLabel(pSubWInfo); if( HasRowid(pTab) ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r); @@ -6198,8 +6199,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); } } - sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, addrCont, r, nPk); + jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk); sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk); + sqlite3VdbeJumpHere(v, jmp); sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn); sqlite3WhereEnd(pSubWInfo); } From ac8c438a79012f60c8acbbf9b9793fb18b91a518 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 9 Apr 2022 20:11:05 +0000 Subject: [PATCH 06/31] Add a simple test case. (It is not difficult to create additional test cases that assert, at this point.) FossilOrigin-Name: f2201d5dcfc552bdddd0780b3f466bdaa886e557f147335c085395bfc001f6b0 --- manifest | 11 ++++++----- manifest.uuid | 2 +- test/join7.test | 28 ++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 test/join7.test diff --git a/manifest b/manifest index f2bc29afed..ad2ff76bde 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bug\sfixes.\s\sA\sbasic\sFULL\sOUTER\sJOIN\snow\sworks. -D 2022-04-09T18:48:11.005 +C Add\sa\ssimple\stest\scase.\s\s(It\sis\snot\sdifficult\sto\screate\sadditional\stest\ncases\sthat\sassert,\sat\sthis\spoint.) +D 2022-04-09T20:11:05.917 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1146,6 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c +F test/join7.test b62546e7961a535f5ec2df1f7bd1b4deb60f40dd42444d3d409d53d8890988e2 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1945,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 2db5a498e74241dd19ef51c601f1a2b3b687faed3e1be2d1e3ada737406ac8e9 -R 0ae50938e4462db8bba3d38695099c31 +P 34bbeeb77bd530b2b1f0390e9e552f65ae35f09a74d80a09dd327e64f9be51a1 +R d71d5d031d27efcdf2eb198054735b86 U drh -Z 29e379e6c2c78a86783f35cb54daa623 +Z 3028a815e9da0bf5b69ea97a441052fd # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index df20f470e8..e71d4e93df 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -34bbeeb77bd530b2b1f0390e9e552f65ae35f09a74d80a09dd327e64f9be51a1 \ No newline at end of file +f2201d5dcfc552bdddd0780b3f466bdaa886e557f147335c085395bfc001f6b0 \ No newline at end of file diff --git a/test/join7.test b/test/join7.test new file mode 100644 index 0000000000..7edeaaa92a --- /dev/null +++ b/test/join7.test @@ -0,0 +1,28 @@ +# 2022-04-09 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests for RIGHT and FULL OUTER JOINs. + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test join7-1.1 { + CREATE TABLE t1(a int,b int); + INSERT INTO t1 VALUES(1,2),(1,3),(1,4); + CREATE INDEX t1a ON t1(a); + CREATE TABLE t2(c int,d int); + INSERT INTO t2 VALUES(3,33),(4,44),(5,55); + CREATE INDEX t2c ON t2(c); + SELECT quote(b), quote(d), '|' FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY b; +} {NULL 55 | 2 NULL | 3 33 | 4 44 |} + +finish_test From a20c71e9e8300d9c60a83fb3d47b600c556bd952 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 10 Apr 2022 16:13:37 +0000 Subject: [PATCH 07/31] More RIGHT JOIN test cases and a bug fix. FossilOrigin-Name: 19e8ad690a140ca40838bf31a377c19010fcbbc2554a4f1746737543043e334b --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 6 ++++-- test/join7.test | 42 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index ad2ff76bde..9c8c01eb3f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\ssimple\stest\scase.\s\s(It\sis\snot\sdifficult\sto\screate\sadditional\stest\ncases\sthat\sassert,\sat\sthis\spoint.) -D 2022-04-09T20:11:05.917 +C More\sRIGHT\sJOIN\stest\scases\sand\sa\sbug\sfix. +D 2022-04-10T16:13:37.815 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c ddeca7f959c3da448012737c0bf0c283232a317c7ef0bdc6587352f4189bd8aa +F src/where.c ca328251a356781a30c31f924ac935e4e5c8796e2174f50f18fbe3748de27073 F src/whereInt.h ecf0d9fe3e35f2546e660c6389e56aedb6fd2434e31a0449b261ff55ebc6df2d F src/wherecode.c 39532c183ea306ae44b5ab3119b244407b46970b088c59d5751c5724b4b6ec15 F src/whereexpr.c ac8985bbd983f34273b1e0d05cd738ff436331674c1b22f4caf6537e1eca4691 @@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c -F test/join7.test b62546e7961a535f5ec2df1f7bd1b4deb60f40dd42444d3d409d53d8890988e2 +F test/join7.test bdd814adf382f3202e8a1f0c0e03afc53d99cc389d80dfa2b25fc846635473f7 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 34bbeeb77bd530b2b1f0390e9e552f65ae35f09a74d80a09dd327e64f9be51a1 -R d71d5d031d27efcdf2eb198054735b86 +P f2201d5dcfc552bdddd0780b3f466bdaa886e557f147335c085395bfc001f6b0 +R af557aa48dcfca848766b5b48b1cbd15 U drh -Z 3028a815e9da0bf5b69ea97a441052fd +Z 2e79fb43e827a0cdd68dfc64d0cf2a68 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e71d4e93df..64168f852f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f2201d5dcfc552bdddd0780b3f466bdaa886e557f147335c085395bfc001f6b0 \ No newline at end of file +19e8ad690a140ca40838bf31a377c19010fcbbc2554a4f1746737543043e334b \ No newline at end of file diff --git a/src/where.c b/src/where.c index bec9da8db0..4216829e25 100644 --- a/src/where.c +++ b/src/where.c @@ -5766,8 +5766,10 @@ WhereInfo *sqlite3WhereBegin( /* noop */ }else #endif - if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 - && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ + if( ((pLoop->wsFlags & WHERE_IDX_ONLY)==0 + && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0) + || (pTabItem->fg.jointype & (JT_LTORJ|JT_RIGHT))!=0 + ){ int op = OP_OpenRead; if( pWInfo->eOnePass!=ONEPASS_OFF ){ op = OP_OpenWrite; diff --git a/test/join7.test b/test/join7.test index 7edeaaa92a..9478edae65 100644 --- a/test/join7.test +++ b/test/join7.test @@ -22,7 +22,45 @@ do_execsql_test join7-1.1 { CREATE TABLE t2(c int,d int); INSERT INTO t2 VALUES(3,33),(4,44),(5,55); CREATE INDEX t2c ON t2(c); - SELECT quote(b), quote(d), '|' FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY b; -} {NULL 55 | 2 NULL | 3 33 | 4 44 |} + SELECT quote(b), quote(d) FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; +} { + NULL 55 + 2 NULL + 3 33 + 4 44 +} +do_execsql_test join7-1.2 { + SELECT quote(a), quote(c) FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; +} { + NULL 5 + 1 NULL + 1 3 + 1 4 +} +do_execsql_test join7-1.3 { + SELECT quote(a), quote(b), quote(c), quote(d) + FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; +} { + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 +} +do_execsql_test join7-1.4 { + SELECT quote(a), quote(b), quote(c), quote(d) + FROM t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; +} { + NULL NULL 5 55 + 1 3 3 33 + 1 4 4 44 +} +do_execsql_test join7-1.5 { + SELECT quote(a), quote(b), quote(c), quote(d) + FROM t1 LEFT OUTER JOIN t2 ON b=c ORDER BY +b; +} { + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 +} finish_test From e21e36dd2cf71d4164bc188774fab5e4d2976cb6 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 10 Apr 2022 17:14:48 +0000 Subject: [PATCH 08/31] More test cases and bug fixes. FossilOrigin-Name: 140e97fde94fdc3babdd456ce1b22900ead0e40e2afe63d89d21ccdbf141b607 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 11 +++++++++-- test/join7.test | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 9c8c01eb3f..37810b9bd5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\sRIGHT\sJOIN\stest\scases\sand\sa\sbug\sfix. -D 2022-04-10T16:13:37.815 +C More\stest\scases\sand\sbug\sfixes. +D 2022-04-10T17:14:48.880 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c ca328251a356781a30c31f924ac935e4e5c8796e2174f50f18fbe3748de27073 +F src/where.c 4e72f26033d0977c4f5a21a06968d319b8c6eae8507f47a6245291cf570151a4 F src/whereInt.h ecf0d9fe3e35f2546e660c6389e56aedb6fd2434e31a0449b261ff55ebc6df2d F src/wherecode.c 39532c183ea306ae44b5ab3119b244407b46970b088c59d5751c5724b4b6ec15 F src/whereexpr.c ac8985bbd983f34273b1e0d05cd738ff436331674c1b22f4caf6537e1eca4691 @@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c -F test/join7.test bdd814adf382f3202e8a1f0c0e03afc53d99cc389d80dfa2b25fc846635473f7 +F test/join7.test efcf2ed9d568ab8d2f4145c25fd2a8ea5abc56290c3c5345f9af9aa7e08af693 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f2201d5dcfc552bdddd0780b3f466bdaa886e557f147335c085395bfc001f6b0 -R af557aa48dcfca848766b5b48b1cbd15 +P 19e8ad690a140ca40838bf31a377c19010fcbbc2554a4f1746737543043e334b +R 9017b4087148be50d8587c5d8e48484b U drh -Z 2e79fb43e827a0cdd68dfc64d0cf2a68 +Z 12573aa0d9ba0f1640cbd083fd7493c6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 64168f852f..c3bfc576aa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -19e8ad690a140ca40838bf31a377c19010fcbbc2554a4f1746737543043e334b \ No newline at end of file +140e97fde94fdc3babdd456ce1b22900ead0e40e2afe63d89d21ccdbf141b607 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 4216829e25..56c3a01712 100644 --- a/src/where.c +++ b/src/where.c @@ -5894,6 +5894,7 @@ WhereInfo *sqlite3WhereBegin( sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, pPk->nKeyCol); sqlite3VdbeSetP4KeyInfo(pParse, pPk); } + pLoop->wsFlags &= ~WHERE_IDX_ONLY; } } pWInfo->iTop = sqlite3VdbeCurrentAddr(v); @@ -6169,10 +6170,15 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ WhereClause *pWC = &pWInfo->sWC; WhereInfo *pSubWInfo; SrcList sFrom; + Bitmask mAll = 0; + for(k=0; k<=i; k++){ + mAll |= pWInfo->a[k].pWLoop->maskSelf; + } for(k=0; knTerm; k++){ - WhereTerm *pTerm = &pWC->a[i]; + WhereTerm *pTerm = &pWC->a[k]; if( pTerm->wtFlags & TERM_VIRTUAL ) break; - if( pTerm->prereqAll & ~pLoop->maskSelf ) continue; + if( pTerm->prereqAll & ~mAll ) continue; + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; pSubWhere = sqlite3ExprAnd(pParse, pSubWhere, sqlite3ExprDup(db, pTerm->pExpr, 0)); } @@ -6208,6 +6214,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3WhereEnd(pSubWInfo); } sqlite3ExprDelete(pParse->db, pSubWhere); + continue; } /* For a co-routine, change all OP_Column references to the table of diff --git a/test/join7.test b/test/join7.test index 9478edae65..019ac322f1 100644 --- a/test/join7.test +++ b/test/join7.test @@ -63,4 +63,43 @@ do_execsql_test join7-1.5 { 1 4 4 44 } +do_execsql_test join7-2.1 { + SELECT quote(a), quote(b), quote(c), quote(d) + FROM t1 FULL OUTER JOIN t2 ON b=c AND a=1 ORDER BY +b; +} { + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 +} +do_execsql_test join7-2.2 { + SELECT quote(a), quote(b), quote(c), quote(d) + FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a=1 ORDER BY +b; +} { + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 +} +do_execsql_test join7-2.3 { + SELECT quote(a), quote(b), quote(c), quote(d) + FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a IS NULL ORDER BY +d; +} { + NULL NULL 3 33 + NULL NULL 4 44 + NULL NULL 5 55 +} +do_execsql_test join7-2.4 { + SELECT quote(a), quote(b), quote(c), quote(d) + FROM t1 FULL OUTER JOIN t2 ON b=c AND d<=0 ORDER BY +b, +d; +} { + NULL NULL 3 33 + NULL NULL 4 44 + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 NULL NULL + 1 4 NULL NULL +} + + + finish_test From fcde633f7cd4e8c3de41a4f3250f45cd38f49490 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 10 Apr 2022 19:51:22 +0000 Subject: [PATCH 09/31] When the left-most table of a RIGHT JOIN is implemented as a co-routine, make sure all its columns are flushed to NULL when it finishes so that they appear to be NULL during the RIGHT JOIN post-processing. FossilOrigin-Name: f84b2beca719758979d7a5a63c3d16d5121a7518b3fbe5039af474a83dd569c2 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/select.c | 3 +++ test/join7.test | 45 ++++++++++++++++++++++++++------------------- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 37810b9bd5..300a7c0914 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\stest\scases\sand\sbug\sfixes. -D 2022-04-10T17:14:48.880 +C When\sthe\sleft-most\stable\sof\sa\sRIGHT\sJOIN\sis\simplemented\sas\sa\sco-routine,\s\nmake\ssure\sall\sits\scolumns\sare\sflushed\sto\sNULL\swhen\sit\sfinishes\sso\sthat\nthey\sappear\sto\sbe\sNULL\sduring\sthe\sRIGHT\sJOIN\spost-processing. +D 2022-04-10T19:51:22.704 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -552,7 +552,7 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c cfa10564953f08eae09e0e92038b168403aade2879ba772cd5a47a08474da5fe +F src/select.c 3d723c58ce6f8b15ef2a3f7b816010efe11d3cf046f44ba9711b70a93d4144e7 F src/shell.c.in 1a8fbf932ecd582b1a5f66c1e8294f92c30d954616f5c7cc54c9623fcdbb028d F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c -F test/join7.test efcf2ed9d568ab8d2f4145c25fd2a8ea5abc56290c3c5345f9af9aa7e08af693 +F test/join7.test 5a41d7b6089c05d3a081b73b9f1404f802104c8f6354eaaafdce07dcc03538f2 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 19e8ad690a140ca40838bf31a377c19010fcbbc2554a4f1746737543043e334b -R 9017b4087148be50d8587c5d8e48484b +P 140e97fde94fdc3babdd456ce1b22900ead0e40e2afe63d89d21ccdbf141b607 +R 4785f5aaf180af8e1a0a99264df2d1f5 U drh -Z 12573aa0d9ba0f1640cbd083fd7493c6 +Z 69bb375996d123a078fecd333472e7f3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c3bfc576aa..ac3f707f78 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -140e97fde94fdc3babdd456ce1b22900ead0e40e2afe63d89d21ccdbf141b607 \ No newline at end of file +f84b2beca719758979d7a5a63c3d16d5121a7518b3fbe5039af474a83dd569c2 \ No newline at end of file diff --git a/src/select.c b/src/select.c index b9321aece7..3672a7c0f8 100644 --- a/src/select.c +++ b/src/select.c @@ -6755,6 +6755,9 @@ int sqlite3Select( pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; pItem->regResult = dest.iSdst; + if( pItem->fg.jointype & JT_LTORJ ){ + sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSdst, dest.iSdst+dest.nSdst-1); + } sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); diff --git a/test/join7.test b/test/join7.test index 019ac322f1..b92bf3d9c8 100644 --- a/test/join7.test +++ b/test/join7.test @@ -15,6 +15,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +db nullvalue NULL do_execsql_test join7-1.1 { CREATE TABLE t1(a int,b int); INSERT INTO t1 VALUES(1,2),(1,3),(1,4); @@ -22,7 +23,8 @@ do_execsql_test join7-1.1 { CREATE TABLE t2(c int,d int); INSERT INTO t2 VALUES(3,33),(4,44),(5,55); CREATE INDEX t2c ON t2(c); - SELECT quote(b), quote(d) FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; + CREATE VIEW dual AS SELECT 'x' AS dummy; + SELECT b, d FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; } { NULL 55 2 NULL @@ -30,7 +32,7 @@ do_execsql_test join7-1.1 { 4 44 } do_execsql_test join7-1.2 { - SELECT quote(a), quote(c) FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; + SELECT a, c FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; } { NULL 5 1 NULL @@ -38,25 +40,36 @@ do_execsql_test join7-1.2 { 1 4 } do_execsql_test join7-1.3 { - SELECT quote(a), quote(b), quote(c), quote(d) - FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; } { NULL NULL 5 55 1 2 NULL NULL 1 3 3 33 1 4 4 44 } -do_execsql_test join7-1.4 { - SELECT quote(a), quote(b), quote(c), quote(d) - FROM t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; +do_execsql_test join7-1.4a { + SELECT * FROM t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; } { NULL NULL 5 55 1 3 3 33 1 4 4 44 } +do_execsql_test join7-1.4b { + SELECT * FROM dual JOIN t1 ON true RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; +} { + NULL NULL NULL 5 55 + x 1 3 3 33 + x 1 4 4 44 +} +do_execsql_test join7-1.4c { + SELECT * FROM dual CROSS JOIN t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; +} { + NULL NULL NULL 5 55 + x 1 3 3 33 + x 1 4 4 44 +} do_execsql_test join7-1.5 { - SELECT quote(a), quote(b), quote(c), quote(d) - FROM t1 LEFT OUTER JOIN t2 ON b=c ORDER BY +b; + SELECT * FROM t1 LEFT OUTER JOIN t2 ON b=c ORDER BY +b; } { 1 2 NULL NULL 1 3 3 33 @@ -64,8 +77,7 @@ do_execsql_test join7-1.5 { } do_execsql_test join7-2.1 { - SELECT quote(a), quote(b), quote(c), quote(d) - FROM t1 FULL OUTER JOIN t2 ON b=c AND a=1 ORDER BY +b; + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND a=1 ORDER BY +b; } { NULL NULL 5 55 1 2 NULL NULL @@ -73,24 +85,21 @@ do_execsql_test join7-2.1 { 1 4 4 44 } do_execsql_test join7-2.2 { - SELECT quote(a), quote(b), quote(c), quote(d) - FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a=1 ORDER BY +b; + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a=1 ORDER BY +b; } { 1 2 NULL NULL 1 3 3 33 1 4 4 44 } do_execsql_test join7-2.3 { - SELECT quote(a), quote(b), quote(c), quote(d) - FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a IS NULL ORDER BY +d; + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a IS NULL ORDER BY +d; } { NULL NULL 3 33 NULL NULL 4 44 NULL NULL 5 55 } do_execsql_test join7-2.4 { - SELECT quote(a), quote(b), quote(c), quote(d) - FROM t1 FULL OUTER JOIN t2 ON b=c AND d<=0 ORDER BY +b, +d; + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND d<=0 ORDER BY +b, +d; } { NULL NULL 3 33 NULL NULL 4 44 @@ -100,6 +109,4 @@ do_execsql_test join7-2.4 { 1 4 NULL NULL } - - finish_test From 62ed36bb5dd4e8a15042d9752abc4223cae3be14 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 10 Apr 2022 20:28:41 +0000 Subject: [PATCH 10/31] Minor improvements to the sqlite3SrcListShiftJoinType() routine. This started out to be an effort to convert RIGHT JOIN to LEFT JOIN if the join was on the first pair of relations, but that messes up the "*" expansion and so won't work. FossilOrigin-Name: a48902c71ed30c83de7dbd26d1c7956136c35dc53b1076bc8b1ebcba568a3fd3 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/build.c | 15 +++++++++++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 300a7c0914..c280af91e6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\sthe\sleft-most\stable\sof\sa\sRIGHT\sJOIN\sis\simplemented\sas\sa\sco-routine,\s\nmake\ssure\sall\sits\scolumns\sare\sflushed\sto\sNULL\swhen\sit\sfinishes\sso\sthat\nthey\sappear\sto\sbe\sNULL\sduring\sthe\sRIGHT\sJOIN\spost-processing. -D 2022-04-10T19:51:22.704 +C Minor\simprovements\sto\sthe\ssqlite3SrcListShiftJoinType()\sroutine.\s\sThis\sstarted\nout\sto\sbe\san\seffort\sto\sconvert\sRIGHT\sJOIN\sto\sLEFT\sJOIN\sif\sthe\sjoin\swas\son\nthe\sfirst\spair\sof\srelations,\sbut\sthat\smesses\sup\sthe\s"*"\sexpansion\sand\sso\swon't\nwork. +D 2022-04-10T20:28:41.210 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -495,7 +495,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c 45161c2d5c9527b9c9bbfd7478daf3e0a619cf4bbe3278378aaea3d4b4e4f5b5 F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h 8ce1332edd89dfd2461d561ac10a0ab5601c8e06200cb5230596c3caaf54482e -F src/build.c 4a35acbeb5a73e5dfb0ed199a4ba601179cd22216654f9eb14c1dcfe993673e8 +F src/build.c d30ef1cbd19efbaf8596521589f2a56292325e03f0801bf160608da7b03a03ff F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 026dbdcdbd8c3cde98a88483ee88310ff43150ab164ad768f12cc700a11495ad @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 140e97fde94fdc3babdd456ce1b22900ead0e40e2afe63d89d21ccdbf141b607 -R 4785f5aaf180af8e1a0a99264df2d1f5 +P f84b2beca719758979d7a5a63c3d16d5121a7518b3fbe5039af474a83dd569c2 +R cd052684f405fbc67ae88c7e7611d8e4 U drh -Z 69bb375996d123a078fecd333472e7f3 +Z ff6cefb3fcd28c733eed400a6a07e7f1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ac3f707f78..a904647d09 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f84b2beca719758979d7a5a63c3d16d5121a7518b3fbe5039af474a83dd569c2 \ No newline at end of file +a48902c71ed30c83de7dbd26d1c7956136c35dc53b1076bc8b1ebcba568a3fd3 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 7181011c32..22f7a79e05 100644 --- a/src/build.c +++ b/src/build.c @@ -5067,14 +5067,21 @@ void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){ ** The operator is "natural cross join". The A and B operands are stored ** in p->a[0] and p->a[1], respectively. The parser initially stores the ** operator with A. This routine shifts that operator over to B. +** +** Additional changes: +** +** * All tables to the left of the right-most RIGHT JOIN are tagged with +** JT_LTORJ (mnemonic: Left Table Of Right Join) so that the +** code generator can easily tell that the table is part of +** the left operand of at least one RIGHT JOIN. */ void sqlite3SrcListShiftJoinType(SrcList *p){ - if( p ){ - int i; + if( p && p->nSrc>1 ){ + int i = p->nSrc-1; u8 allFlags = 0; - for(i=p->nSrc-1; i>0; i--){ + do{ allFlags |= p->a[i].fg.jointype = p->a[i-1].fg.jointype; - } + }while( (--i)>0 ); p->a[0].fg.jointype = 0; /* All terms to the left of a RIGHT JOIN should be tagged with the From 9debb58e4801ad5737ff88fbc117a1fc06695efa Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 10 Apr 2022 23:01:20 +0000 Subject: [PATCH 11/31] Revisit [f84b2beca7197589]: disallow co-routine implementations of tables that are to the left of a RIGHT JOIN, to avoid other complications. FossilOrigin-Name: cf00ebfc4b77f45ec466b0d57d7c22c7f48acab19e4e55b168eb4b53f390d887 --- manifest | 14 +-- manifest.uuid | 2 +- src/select.c | 12 ++- test/join7.test | 235 +++++++++++++++++++++++++++++------------------- 4 files changed, 155 insertions(+), 108 deletions(-) diff --git a/manifest b/manifest index c280af91e6..8ce42c41cd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\simprovements\sto\sthe\ssqlite3SrcListShiftJoinType()\sroutine.\s\sThis\sstarted\nout\sto\sbe\san\seffort\sto\sconvert\sRIGHT\sJOIN\sto\sLEFT\sJOIN\sif\sthe\sjoin\swas\son\nthe\sfirst\spair\sof\srelations,\sbut\sthat\smesses\sup\sthe\s"*"\sexpansion\sand\sso\swon't\nwork. -D 2022-04-10T20:28:41.210 +C Revisit\s[f84b2beca7197589]:\sdisallow\sco-routine\simplementations\sof\stables\nthat\sare\sto\sthe\sleft\sof\sa\sRIGHT\sJOIN,\sto\savoid\sother\scomplications. +D 2022-04-10T23:01:20.947 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -552,7 +552,7 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 3d723c58ce6f8b15ef2a3f7b816010efe11d3cf046f44ba9711b70a93d4144e7 +F src/select.c 4b67f6d827a695cc78057f501dc84c95ce17863fc2047936859e7839d3191ba8 F src/shell.c.in 1a8fbf932ecd582b1a5f66c1e8294f92c30d954616f5c7cc54c9623fcdbb028d F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c -F test/join7.test 5a41d7b6089c05d3a081b73b9f1404f802104c8f6354eaaafdce07dcc03538f2 +F test/join7.test b3e62ec45f9d8a17a4d13df7533805554e893d214554b4d998815834f7f674fa F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f84b2beca719758979d7a5a63c3d16d5121a7518b3fbe5039af474a83dd569c2 -R cd052684f405fbc67ae88c7e7611d8e4 +P a48902c71ed30c83de7dbd26d1c7956136c35dc53b1076bc8b1ebcba568a3fd3 +R ca36fcb77f7ad090453c7879b10dd2ed U drh -Z ff6cefb3fcd28c733eed400a6a07e7f1 +Z 2c5ea1399770dbe9a9af46dae89e29ee # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a904647d09..550964364e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a48902c71ed30c83de7dbd26d1c7956136c35dc53b1076bc8b1ebcba568a3fd3 \ No newline at end of file +cf00ebfc4b77f45ec466b0d57d7c22c7f48acab19e4e55b168eb4b53f390d887 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 3672a7c0f8..80b488777b 100644 --- a/src/select.c +++ b/src/select.c @@ -6727,18 +6727,19 @@ int sqlite3Select( /* Generate code to implement the subquery ** - ** The subquery is implemented as a co-routine if: + ** The subquery is implemented as a co-routine all of the following are + ** true: + ** ** (1) the subquery is guaranteed to be the outer loop (so that ** it does not need to be computed more than once), and ** (2) the subquery is not a CTE that should be materialized - ** - ** TODO: Are there other reasons beside (1) and (2) to use a co-routine - ** implementation? + ** (3) the subquery is not part of a left operand for a RIGHT JOIN */ if( i==0 && (pTabList->nSrc==1 || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0) /* (1) */ && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) /* (2) */ + && (pTabList->a[0].fg.jointype & JT_LTORJ)==0 /* (3) */ ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. @@ -6755,9 +6756,6 @@ int sqlite3Select( pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; pItem->regResult = dest.iSdst; - if( pItem->fg.jointype & JT_LTORJ ){ - sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSdst, dest.iSdst+dest.nSdst-1); - } sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); diff --git a/test/join7.test b/test/join7.test index b92bf3d9c8..3b49664649 100644 --- a/test/join7.test +++ b/test/join7.test @@ -15,98 +15,147 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -db nullvalue NULL -do_execsql_test join7-1.1 { - CREATE TABLE t1(a int,b int); - INSERT INTO t1 VALUES(1,2),(1,3),(1,4); - CREATE INDEX t1a ON t1(a); - CREATE TABLE t2(c int,d int); - INSERT INTO t2 VALUES(3,33),(4,44),(5,55); - CREATE INDEX t2c ON t2(c); - CREATE VIEW dual AS SELECT 'x' AS dummy; - SELECT b, d FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; +foreach {id schema} { + 1 { + CREATE TABLE t1(a INT, b INT); + INSERT INTO t1 VALUES(1,2),(1,3),(1,4); + CREATE INDEX t1a ON t1(a); + CREATE TABLE t2(c INT, d INT); + INSERT INTO t2 VALUES(3,33),(4,44),(5,55); + CREATE INDEX t2c ON t2(c); + CREATE VIEW dual(dummy) AS VALUES('x'); + } + 2 { + CREATE TABLE t1(a INT, b INT); + INSERT INTO t1 VALUES(1,2),(1,3),(1,4); + CREATE INDEX t1ab ON t1(a,b); + CREATE TABLE t2(c INT, d INT); + INSERT INTO t2 VALUES(3,33),(4,44),(5,55); + CREATE INDEX t2cd ON t2(c,d); + CREATE VIEW dual(dummy) AS VALUES('x'); + } + 3 { + CREATE TABLE t1(a INT, b INT); + INSERT INTO t1 VALUES(1,2),(1,3),(1,4); + CREATE INDEX t1a ON t1(a); + CREATE TABLE t2(c INT, d INT PRIMARY KEY) WITHOUT ROWID; + INSERT INTO t2 VALUES(3,33),(4,44),(5,55); + CREATE INDEX t2c ON t2(c); + CREATE VIEW dual(dummy) AS VALUES('x'); + } + 4 { + CREATE TABLE t1(a INT, b INT); + INSERT INTO t1 VALUES(1,2),(1,3),(1,4); + CREATE TABLE t2(c INTEGER PRIMARY KEY, d INT); + INSERT INTO t2 VALUES(3,33),(4,44),(5,55); + CREATE VIEW dual(dummy) AS VALUES('x'); + } + 5 { + CREATE TABLE t1(a INT, b INT); + INSERT INTO t1 VALUES(1,2),(1,3),(1,4); + CREATE TABLE t2(c INT PRIMARY KEY, d INT) WITHOUT ROWID; + INSERT INTO t2 VALUES(3,33),(4,44),(5,55); + CREATE VIEW dual(dummy) AS VALUES('x'); + } + 6 { + CREATE TABLE t1(a INT, b INT); + INSERT INTO t1 VALUES(1,2),(1,3),(1,4); + CREATE VIEW t2(c,d) AS VALUES(3,33),(4,44),(5,55); + CREATE VIEW dual(dummy) AS VALUES('x'); + } + 7 { + CREATE VIEW t1(a,b) AS VALUES(1,2),(1,3),(1,4); + CREATE TABLE t2(c INTEGER PRIMARY KEY, d INT); + INSERT INTO t2 VALUES(3,33),(4,44),(5,55); + CREATE VIEW dual(dummy) AS VALUES('x'); + } } { - NULL 55 - 2 NULL - 3 33 - 4 44 -} -do_execsql_test join7-1.2 { - SELECT a, c FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; -} { - NULL 5 - 1 NULL - 1 3 - 1 4 -} -do_execsql_test join7-1.3 { - SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; -} { - NULL NULL 5 55 - 1 2 NULL NULL - 1 3 3 33 - 1 4 4 44 -} -do_execsql_test join7-1.4a { - SELECT * FROM t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; -} { - NULL NULL 5 55 - 1 3 3 33 - 1 4 4 44 -} -do_execsql_test join7-1.4b { - SELECT * FROM dual JOIN t1 ON true RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; -} { - NULL NULL NULL 5 55 - x 1 3 3 33 - x 1 4 4 44 -} -do_execsql_test join7-1.4c { - SELECT * FROM dual CROSS JOIN t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; -} { - NULL NULL NULL 5 55 - x 1 3 3 33 - x 1 4 4 44 -} -do_execsql_test join7-1.5 { - SELECT * FROM t1 LEFT OUTER JOIN t2 ON b=c ORDER BY +b; -} { - 1 2 NULL NULL - 1 3 3 33 - 1 4 4 44 -} - -do_execsql_test join7-2.1 { - SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND a=1 ORDER BY +b; -} { - NULL NULL 5 55 - 1 2 NULL NULL - 1 3 3 33 - 1 4 4 44 -} -do_execsql_test join7-2.2 { - SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a=1 ORDER BY +b; -} { - 1 2 NULL NULL - 1 3 3 33 - 1 4 4 44 -} -do_execsql_test join7-2.3 { - SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a IS NULL ORDER BY +d; -} { - NULL NULL 3 33 - NULL NULL 4 44 - NULL NULL 5 55 -} -do_execsql_test join7-2.4 { - SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND d<=0 ORDER BY +b, +d; -} { - NULL NULL 3 33 - NULL NULL 4 44 - NULL NULL 5 55 - 1 2 NULL NULL - 1 3 NULL NULL - 1 4 NULL NULL -} - + reset_db + db nullvalue NULL + db eval $schema + do_execsql_test join7-$id.1 { + SELECT b, d FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; + } { + NULL 55 + 2 NULL + 3 33 + 4 44 + } + do_execsql_test join7-$id.2 { + SELECT a, c FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; + } { + NULL 5 + 1 NULL + 1 3 + 1 4 + } + do_execsql_test join7-$id.3 { + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; + } { + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 + } + do_execsql_test join7-$id.4 { + SELECT * FROM t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; + } { + NULL NULL 5 55 + 1 3 3 33 + 1 4 4 44 + } + do_execsql_test join7-$id.5 { + SELECT * FROM dual JOIN t1 ON true RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; + } { + NULL NULL NULL 5 55 + x 1 3 3 33 + x 1 4 4 44 + } + do_execsql_test join7-$id.6 { + SELECT * FROM dual CROSS JOIN t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; + } { + NULL NULL NULL 5 55 + x 1 3 3 33 + x 1 4 4 44 + } + do_execsql_test join7-$id.7 { + SELECT * FROM t1 LEFT OUTER JOIN t2 ON b=c ORDER BY +b; + } { + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 + } + do_execsql_test join7-$id.8 { + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND a=1 ORDER BY +b; + } { + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 + } + do_execsql_test join7-$id.9 { + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a=1 ORDER BY +b; + } { + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 + } + do_execsql_test join7-$id.10 { + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a IS NULL ORDER BY +d; + } { + NULL NULL 3 33 + NULL NULL 4 44 + NULL NULL 5 55 + } + do_execsql_test join7-$id.11 { + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND d<=0 ORDER BY +b, +d; + } { + NULL NULL 3 33 + NULL NULL 4 44 + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 NULL NULL + 1 4 NULL NULL + } +} finish_test From 529394e5c1399577be9a882b2f8be11fa1966cf5 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 10 Apr 2022 23:48:47 +0000 Subject: [PATCH 12/31] Cannot use an automatic index on the right table of a RIGHT JOIN because automatic indexes must be WHERE_IDX_ONLY, but the RIGHT JOIN post-processing does not know how to work with an index-only scan. FossilOrigin-Name: beb4401dc09fb68e85ddcf3f99598527691535d0eb7693168f440e5a5a076e3f --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 1 + test/join7.test | 9 ++++++++- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 8ce42c41cd..df80bde0ca 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Revisit\s[f84b2beca7197589]:\sdisallow\sco-routine\simplementations\sof\stables\nthat\sare\sto\sthe\sleft\sof\sa\sRIGHT\sJOIN,\sto\savoid\sother\scomplications. -D 2022-04-10T23:01:20.947 +C Cannot\suse\san\sautomatic\sindex\son\sthe\sright\stable\sof\sa\sRIGHT\sJOIN\sbecause\nautomatic\sindexes\smust\sbe\sWHERE_IDX_ONLY,\sbut\sthe\sRIGHT\sJOIN\spost-processing\ndoes\snot\sknow\show\sto\swork\swith\san\sindex-only\sscan. +D 2022-04-10T23:48:47.410 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 4e72f26033d0977c4f5a21a06968d319b8c6eae8507f47a6245291cf570151a4 +F src/where.c cfc0926a221884af46cf933c9462e85e391022cb6aa06a65523e7464294b75d0 F src/whereInt.h ecf0d9fe3e35f2546e660c6389e56aedb6fd2434e31a0449b261ff55ebc6df2d F src/wherecode.c 39532c183ea306ae44b5ab3119b244407b46970b088c59d5751c5724b4b6ec15 F src/whereexpr.c ac8985bbd983f34273b1e0d05cd738ff436331674c1b22f4caf6537e1eca4691 @@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c -F test/join7.test b3e62ec45f9d8a17a4d13df7533805554e893d214554b4d998815834f7f674fa +F test/join7.test 790f5fcb7de07fd7e231610ea0e3da7064cba09c1c1e0c3d879adf0c422680e7 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a48902c71ed30c83de7dbd26d1c7956136c35dc53b1076bc8b1ebcba568a3fd3 -R ca36fcb77f7ad090453c7879b10dd2ed +P cf00ebfc4b77f45ec466b0d57d7c22c7f48acab19e4e55b168eb4b53f390d887 +R ace46715d37ee9d472092f5415672d4e U drh -Z 2c5ea1399770dbe9a9af46dae89e29ee +Z 7d6e1f7d66be1a3fd82f66b8d4846d22 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 550964364e..f40c2481c6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cf00ebfc4b77f45ec466b0d57d7c22c7f48acab19e4e55b168eb4b53f390d887 \ No newline at end of file +beb4401dc09fb68e85ddcf3f99598527691535d0eb7693168f440e5a5a076e3f \ No newline at end of file diff --git a/src/where.c b/src/where.c index 56c3a01712..adae72a4fe 100644 --- a/src/where.c +++ b/src/where.c @@ -3324,6 +3324,7 @@ static int whereLoopAddBtree( && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ && !pSrc->fg.isCorrelated /* Not a correlated subquery */ && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ + && (pSrc->fg.jointype & JT_RIGHT)==0 /* Not the right tab of a RIGHT JOIN */ ){ /* Generate auto-index WhereLoops */ LogEst rLogSize; /* Logarithm of the number of rows in the table */ diff --git a/test/join7.test b/test/join7.test index 3b49664649..e2e45dc94b 100644 --- a/test/join7.test +++ b/test/join7.test @@ -69,10 +69,17 @@ foreach {id schema} { INSERT INTO t2 VALUES(3,33),(4,44),(5,55); CREATE VIEW dual(dummy) AS VALUES('x'); } + 8 { + CREATE TABLE t1(a INT, b INT); + INSERT INTO t1 VALUES(1,2),(1,3),(1,4); + CREATE TABLE t2(c INT, d INT); + INSERT INTO t2 VALUES(3,33),(4,44),(5,55); + CREATE VIEW dual(dummy) AS VALUES('x'); + } } { reset_db db nullvalue NULL - db eval $schema + do_execsql_test join7-$id.setup $schema {} do_execsql_test join7-$id.1 { SELECT b, d FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; } { From 41798d5bbc742999a8e8808eff7c2e29c9d4f32f Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 00:21:53 +0000 Subject: [PATCH 13/31] Do not allow query flattening nor the push-down optimization on the right operand of a RIGHT JOIN. FossilOrigin-Name: 5aa0c9ea9cf53c13bf266278b479b2e7af3aa5c6b144bd49ff155a4eb3c23c96 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/select.c | 16 +++++++++++----- test/join7.test | 11 +++++++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index df80bde0ca..bb5ed20c48 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Cannot\suse\san\sautomatic\sindex\son\sthe\sright\stable\sof\sa\sRIGHT\sJOIN\sbecause\nautomatic\sindexes\smust\sbe\sWHERE_IDX_ONLY,\sbut\sthe\sRIGHT\sJOIN\spost-processing\ndoes\snot\sknow\show\sto\swork\swith\san\sindex-only\sscan. -D 2022-04-10T23:48:47.410 +C Do\snot\sallow\squery\sflattening\snor\sthe\spush-down\soptimization\son\sthe\nright\soperand\sof\sa\sRIGHT\sJOIN. +D 2022-04-11T00:21:53.844 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -552,7 +552,7 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 4b67f6d827a695cc78057f501dc84c95ce17863fc2047936859e7839d3191ba8 +F src/select.c 451df0c74466d56d9d69be0d06047b1a0be7d1fa0397ac7d9211f05eb5f06318 F src/shell.c.in 1a8fbf932ecd582b1a5f66c1e8294f92c30d954616f5c7cc54c9623fcdbb028d F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c -F test/join7.test 790f5fcb7de07fd7e231610ea0e3da7064cba09c1c1e0c3d879adf0c422680e7 +F test/join7.test 059f7ab42737fbd835dfc791354f1b182585566b540b013f3ed46bfa1e80ba42 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cf00ebfc4b77f45ec466b0d57d7c22c7f48acab19e4e55b168eb4b53f390d887 -R ace46715d37ee9d472092f5415672d4e +P beb4401dc09fb68e85ddcf3f99598527691535d0eb7693168f440e5a5a076e3f +R b2c7edceb2230e0242166af62b7682c3 U drh -Z 7d6e1f7d66be1a3fd82f66b8d4846d22 +Z a361fbcfdefe8d9e9f1c63be816d7720 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f40c2481c6..b9ca607662 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -beb4401dc09fb68e85ddcf3f99598527691535d0eb7693168f440e5a5a076e3f \ No newline at end of file +5aa0c9ea9cf53c13bf266278b479b2e7af3aa5c6b144bd49ff155a4eb3c23c96 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 80b488777b..2d09085f8a 100644 --- a/src/select.c +++ b/src/select.c @@ -3975,6 +3975,7 @@ static void renumberCursors( ** table and ** (3c) the outer query may not be an aggregate. ** (3d) the outer query may not be DISTINCT. +** See also (26) for restrictions on RIGHT JOIN. ** ** (4) The subquery can not be DISTINCT. ** @@ -4073,6 +4074,9 @@ static void renumberCursors( ** function in the select list or ORDER BY clause, flattening ** is not attempted. ** +** (26) The subquery may not be the right operand of a RIGHT JOIN. +** See also (3) for restrictions on LEFT JOIN. +** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query @@ -4172,14 +4176,15 @@ static int flattenSubquery( ** See also tickets #306, #350, and #3300. */ if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){ - isLeftJoin = 1; - if( pSubSrc->nSrc>1 /* (3a) */ - || isAgg /* (3b) */ - || IsVirtual(pSubSrc->a[0].pTab) /* (3c) */ - || (p->selFlags & SF_Distinct)!=0 /* (3d) */ + if( pSubSrc->nSrc>1 /* (3a) */ + || isAgg /* (3b) */ + || IsVirtual(pSubSrc->a[0].pTab) /* (3c) */ + || (p->selFlags & SF_Distinct)!=0 /* (3d) */ + || (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */ ){ return 0; } + isLeftJoin = 1; } #ifdef SQLITE_EXTRA_IFNULLROW else if( iFrom>0 && !isAgg ){ @@ -6707,6 +6712,7 @@ int sqlite3Select( if( OptimizationEnabled(db, SQLITE_PushDown) && (pItem->fg.isCte==0 || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2)) + && (pItem->fg.jointype & JT_RIGHT)==0 && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor, (pItem->fg.jointype & JT_OUTER)!=0) ){ diff --git a/test/join7.test b/test/join7.test index e2e45dc94b..c1cd9ff6cb 100644 --- a/test/join7.test +++ b/test/join7.test @@ -76,6 +76,17 @@ foreach {id schema} { INSERT INTO t2 VALUES(3,33),(4,44),(5,55); CREATE VIEW dual(dummy) AS VALUES('x'); } + 9 { + CREATE TABLE t1(a INT, b INT); + INSERT INTO t1 VALUES(1,2),(1,3),(1,4); + CREATE TABLE t2a(c INTEGER PRIMARY KEY, i1 INT); + CREATE TABLE t2b(i1 INTEGER PRIMARY KEY, d INT); + CREATE VIEW t2(c,d) AS SELECT c, d FROM t2a NATURAL JOIN t2b; + INSERT INTO t2a VALUES(3,93),(4,94),(5,95),(6,96),(7,97); + INSERT INTO t2b VALUES(91,11),(92,22),(93,33),(94,44),(95,55); + CREATE TABLE dual(dummy TEXT); + INSERT INTO dual(dummy) VALUES('x'); + } } { reset_db db nullvalue NULL From 8a28ce7bc217871f58e0ce71aa207bbcaf1b338e Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 00:54:30 +0000 Subject: [PATCH 14/31] Show the JT_LTORJ flag in TreeView debugging output. FossilOrigin-Name: 21eb44919f38abad30b75181ca8aec38b453b94dba2815caf7e946e07faa40d7 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/treeview.c | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index bb5ed20c48..6152eb5dd2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sallow\squery\sflattening\snor\sthe\spush-down\soptimization\son\sthe\nright\soperand\sof\sa\sRIGHT\sJOIN. -D 2022-04-11T00:21:53.844 +C Show\sthe\sJT_LTORJ\sflag\sin\sTreeView\sdebugging\soutput. +D 2022-04-11T00:54:30.476 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -617,7 +617,7 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c a38f52058b517929e264094abd0b5fd1e8e145a1aa43bc6f6a72ae5218f96c98 -F src/treeview.c d1401c129c980ace571f5071b91c349b8ad00bdb3d6f7112fb97a3da8bac85ff +F src/treeview.c 7e50db6ae3bf4d2cb2451b72885667160b6670b0d17bc8d59525b0de6aabf036 F src/trigger.c 372ada38f667c6823a3db15749eb668338e65c793394e55a37e56a489f2d1b55 F src/update.c 2cfaded82ca80ff56afb8c3ae5e88284e0824bfd86119827cc22481959f96f92 F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P beb4401dc09fb68e85ddcf3f99598527691535d0eb7693168f440e5a5a076e3f -R b2c7edceb2230e0242166af62b7682c3 +P 5aa0c9ea9cf53c13bf266278b479b2e7af3aa5c6b144bd49ff155a4eb3c23c96 +R 1822de81f6d5e04eb79ec5cea58d30a4 U drh -Z a361fbcfdefe8d9e9f1c63be816d7720 +Z 5ed5c4da0a2f8bbe8f27f2f95fe823d4 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b9ca607662..cbc7f3de0c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5aa0c9ea9cf53c13bf266278b479b2e7af3aa5c6b144bd49ff155a4eb3c23c96 \ No newline at end of file +21eb44919f38abad30b75181ca8aec38b453b94dba2815caf7e946e07faa40d7 \ No newline at end of file diff --git a/src/treeview.c b/src/treeview.c index f32064cd8e..d2ccb545b2 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -153,6 +153,9 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ }else if( pItem->fg.jointype & JT_CROSS ){ sqlite3_str_appendf(&x, " CROSS-JOIN"); } + if( pItem->fg.jointype & JT_LTORJ ){ + sqlite3_str_appendf(&x, " LTORJ"); + } if( pItem->fg.fromDDL ){ sqlite3_str_appendf(&x, " DDL"); } From 79d26586710bc91822bcaf4c2838e153e62aa6c8 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 10:38:28 +0000 Subject: [PATCH 15/31] Ensure that the JT_LTORJ flag is preserved when flattening a subquery that is on the left side of a RIGHT JOIN. FossilOrigin-Name: ccb61fb1f30e2741b19c1a0cbd2951715224852c86234a3c6a4bbd2e1187634a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/select.c | 4 +++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 6152eb5dd2..b853591122 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Show\sthe\sJT_LTORJ\sflag\sin\sTreeView\sdebugging\soutput. -D 2022-04-11T00:54:30.476 +C Ensure\sthat\sthe\sJT_LTORJ\sflag\sis\spreserved\swhen\sflattening\sa\ssubquery\sthat\nis\son\sthe\sleft\sside\sof\sa\sRIGHT\sJOIN. +D 2022-04-11T10:38:28.801 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -552,7 +552,7 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 451df0c74466d56d9d69be0d06047b1a0be7d1fa0397ac7d9211f05eb5f06318 +F src/select.c e889b6a0fee9341820adc9a421f6cabb69171360f7750c0ba175e0a6ac0fd537 F src/shell.c.in 1a8fbf932ecd582b1a5f66c1e8294f92c30d954616f5c7cc54c9623fcdbb028d F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 5aa0c9ea9cf53c13bf266278b479b2e7af3aa5c6b144bd49ff155a4eb3c23c96 -R 1822de81f6d5e04eb79ec5cea58d30a4 +P 21eb44919f38abad30b75181ca8aec38b453b94dba2815caf7e946e07faa40d7 +R 582e9a3c8a9436aaf5a30603f3b09f3b U drh -Z 5ed5c4da0a2f8bbe8f27f2f95fe823d4 +Z 8d7ebe62739250aad2468a2b76ceb82f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cbc7f3de0c..654a625162 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -21eb44919f38abad30b75181ca8aec38b453b94dba2815caf7e946e07faa40d7 \ No newline at end of file +ccb61fb1f30e2741b19c1a0cbd2951715224852c86234a3c6a4bbd2e1187634a \ No newline at end of file diff --git a/src/select.c b/src/select.c index 2d09085f8a..08824150e8 100644 --- a/src/select.c +++ b/src/select.c @@ -4373,6 +4373,7 @@ static int flattenSubquery( for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){ int nSubSrc; u8 jointype = 0; + u8 ltorj = pSrc->a[iFrom].fg.jointype & JT_LTORJ; assert( pSub!=0 ); pSubSrc = pSub->pSrc; /* FROM clause of subquery */ nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */ @@ -4411,10 +4412,11 @@ static int flattenSubquery( if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing); assert( pItem->fg.isTabFunc==0 ); *pItem = pSubSrc->a[i]; + pItem->fg.jointype |= ltorj; iNewParent = pSubSrc->a[i].iCursor; memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); } - pSrc->a[iFrom].fg.jointype = jointype; + pSrc->a[iFrom].fg.jointype = jointype | ltorj; /* Now begin substituting subquery result set expressions for ** references to the iParent in the outer query. From b77c07a715dacfb4ffa968c6ac26ac46bf18776c Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 11:59:25 +0000 Subject: [PATCH 16/31] Fix some comments that refer to LEFT JOIN that should refer to OUTER JOIN. No changes to code. FossilOrigin-Name: 5be5ede5cca1cd5ef863fe0feb2b4a990f4a42865281a6c2e4eb816f48847dc6 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/expr.c | 4 ++-- src/select.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 7663e4d4cb..1ac8ab2ca0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\sExpr.w.iJoin\sname\schange\sfrom\strunk\sinto\sthe\sright-join\sbranch. -D 2022-04-11T11:48:17.550 +C Fix\ssome\scomments\sthat\srefer\sto\sLEFT\sJOIN\sthat\sshould\srefer\sto\sOUTER\sJOIN.\nNo\schanges\sto\scode. +D 2022-04-11T11:59:25.896 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -503,7 +503,7 @@ F src/date.c 15082566229d4b1e5f24fdb490bf9bcc68824b911d70e3573ef075a1b9e2d26f F src/dbpage.c 90661a87e1db8bfbc8d2ebbdcd3749651ddb287c555c07a28fb17c7c591ffb68 F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce -F src/expr.c 5e247a8dfabb92e9fd10b78a675dc5d25430433dfd9e316471b4447b548635ba +F src/expr.c d5be48b7f3f58026a7e8386ad8cb65c3550bbec79b0fe053a69594a81a5b20e9 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 94927f9b46d72a9cb858c208febf04ceb0a3270c5fa5fd0b7f436cf16e09f72a F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761 @@ -552,7 +552,7 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 360720df7dbf31977fb265aa49fc9b99599e16de521ac5a7a683c16d26d65acf +F src/select.c 178edb7fc4e6f5dabbd9c3755eb601151af78eaf69af73cc6bfe8195121c3d41 F src/shell.c.in eb7f10d5e2c47bd014d92ec5db1def21fcc1ed56ffaaa4ee715b6c37c370b47f F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ccb61fb1f30e2741b19c1a0cbd2951715224852c86234a3c6a4bbd2e1187634a e8c00442d2daedec079748d13147bf73b0ec3c3cf432bce2cdccb706bdff2853 -R 0d4dae690860c958443834a66cabd1f6 +P 29927926eb32acd963e2c496ad67d55177615ec4150fd218afaf2f9a730cabec +R 6a36a3a28fad2aa38e4b5d7c8bda927a U drh -Z a424a48ba2c370ac2094114fa017cf8b +Z 390b95acc02a593d1c52fcc716321c1e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 21a1d0077c..11566ff6d2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -29927926eb32acd963e2c496ad67d55177615ec4150fd218afaf2f9a730cabec \ No newline at end of file +5be5ede5cca1cd5ef863fe0feb2b4a990f4a42865281a6c2e4eb816f48847dc6 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 2c00bb498d..fcef002f24 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2179,7 +2179,7 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ /* If pWalker->eCode is 2 then any term of the expression that comes from - ** the ON or USING clauses of a left join disqualifies the expression + ** the ON or USING clauses of an outer join disqualifies the expression ** from being considered constant. */ if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){ pWalker->eCode = 0; @@ -5817,7 +5817,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ ** in an incorrect answer. ** ** Terms of p that are marked with EP_FromJoin (and hence that come from -** the ON or USING clauses of LEFT JOINS) are excluded from the analysis. +** the ON or USING clauses of OUTER JOINS) are excluded from the analysis. ** ** This routine is used to check if a LEFT JOIN can be converted into ** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE diff --git a/src/select.c b/src/select.c index 1c929d0b94..3e4f783a33 100644 --- a/src/select.c +++ b/src/select.c @@ -408,7 +408,7 @@ static void addWhereTerm( ** expression. ** ** The EP_FromJoin property is used on terms of an expression to tell -** the LEFT OUTER JOIN processing logic that this term is part of the +** the OUTER JOIN processing logic that this term is part of the ** join restriction specified in the ON or USING clause and not a part ** of the more general WHERE clause. These terms are moved over to the ** WHERE clause during join processing but we need to remember that they From 3a6e4c59c480d0f00ba70b44529ba9925f61064b Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 12:38:06 +0000 Subject: [PATCH 17/31] Make a distinction between (1) WHERE clause constraints, (2) ON/USING constraints on outer joins, and (3) ON/USING clause constraints on inner joins. Formerly, there was no distinctionb between 1 and 3, but RIGHT JOIN needs to know the difference. Make RIGHT JOIN aware of this difference and add test cases. FossilOrigin-Name: 0f6f61c3664cc87209c2a6f9b6df3a750d1510723fcde209c33db8feaf48bcf3 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/select.c | 33 ++++++++++++++++++--------------- src/sqliteInt.h | 4 ++-- src/where.c | 8 ++++++-- src/whereexpr.c | 6 +++++- test/join7.test | 11 +++++++++++ 7 files changed, 53 insertions(+), 31 deletions(-) diff --git a/manifest b/manifest index 1ac8ab2ca0..235ea5152d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\ssome\scomments\sthat\srefer\sto\sLEFT\sJOIN\sthat\sshould\srefer\sto\sOUTER\sJOIN.\nNo\schanges\sto\scode. -D 2022-04-11T11:59:25.896 +C Make\sa\sdistinction\sbetween\s(1)\sWHERE\sclause\sconstraints,\s(2)\sON/USING\nconstraints\son\souter\sjoins,\sand\s(3)\sON/USING\sclause\sconstraints\son\sinner\njoins.\s\sFormerly,\sthere\swas\sno\sdistinctionb\sbetween\s1\sand\s3,\sbut\sRIGHT\sJOIN\nneeds\sto\sknow\sthe\sdifference.\s\sMake\sRIGHT\sJOIN\saware\sof\sthis\sdifference\sand\nadd\stest\scases. +D 2022-04-11T12:38:06.753 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -552,12 +552,12 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 178edb7fc4e6f5dabbd9c3755eb601151af78eaf69af73cc6bfe8195121c3d41 +F src/select.c 41d1b171d123a98bff4a2ddbe5ef7c47324274ca967030615506c4e246e96c12 F src/shell.c.in eb7f10d5e2c47bd014d92ec5db1def21fcc1ed56ffaaa4ee715b6c37c370b47f F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e -F src/sqliteInt.h 8a804f402410b06958bf6376daa91f11e2667ebd60e149eb5a371654a71ce448 +F src/sqliteInt.h fa220cb1b04ae45fa34de634efec4c04ce668ddcb6316c8f3260a8cf1a31310b F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -639,10 +639,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c e05c2c85a894d0175983241789344e48ed134f79bb84adda23a6bff53c39cf42 +F src/where.c 8d8e54e2e29ac503ac5824cac0d368a9a45b0a2a3f129b0f2d50a1e3a891c62f F src/whereInt.h ecf0d9fe3e35f2546e660c6389e56aedb6fd2434e31a0449b261ff55ebc6df2d F src/wherecode.c 808e94b66f1bf052cbb77665ba08625ba93fbb0c343fe0ecafdfdd264bf0c6c9 -F src/whereexpr.c d79dd55b6ad4d072c16838e9709d7b144c321e463ebd216de224821c06bc1fd3 +F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5 F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 @@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c -F test/join7.test 059f7ab42737fbd835dfc791354f1b182585566b540b013f3ed46bfa1e80ba42 +F test/join7.test 87f08f814012b4593a7b6021ebfbcc0d2c837045cad012a3a38e810182fe268a F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 29927926eb32acd963e2c496ad67d55177615ec4150fd218afaf2f9a730cabec -R 6a36a3a28fad2aa38e4b5d7c8bda927a +P 5be5ede5cca1cd5ef863fe0feb2b4a990f4a42865281a6c2e4eb816f48847dc6 +R 9c8f191b416653ff62ae70d11a61358b U drh -Z 390b95acc02a593d1c52fcc716321c1e +Z e1bd204470110fd5d9bea7467b9ac13a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 11566ff6d2..41dbfa450d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5be5ede5cca1cd5ef863fe0feb2b4a990f4a42865281a6c2e4eb816f48847dc6 \ No newline at end of file +0f6f61c3664cc87209c2a6f9b6df3a750d1510723fcde209c33db8feaf48bcf3 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 3e4f783a33..79ff500f41 100644 --- a/src/select.c +++ b/src/select.c @@ -373,7 +373,7 @@ static void addWhereTerm( int iColLeft, /* Index of column in first table */ int iRight, /* Index of second table in pSrc */ int iColRight, /* Index of column in second table */ - int isOuterJoin, /* True if this is an OUTER join */ + u32 joinType, /* EP_FromJoin or EP_InnerJoin */ Expr **ppWhere /* IN/OUT: The WHERE clause to add to */ ){ sqlite3 *db = pParse->db; @@ -393,8 +393,8 @@ static void addWhereTerm( assert( pE2!=0 || pEq==0 ); /* Due to db->mallocFailed test ** in sqlite3DbMallocRawNN() called from ** sqlite3PExpr(). */ - if( pEq && isOuterJoin ){ - ExprSetProperty(pEq, EP_FromJoin); + if( pEq ){ + ExprSetProperty(pEq, joinType); assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(pEq, EP_NoReduce); pEq->w.iJoin = pE2->iTable; @@ -428,9 +428,10 @@ static void addWhereTerm( ** after the t1 loop and rows with t1.x!=5 will never appear in ** the output, which is incorrect. */ -void sqlite3SetJoinExpr(Expr *p, int iTable){ +void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){ + assert( joinFlag==EP_FromJoin || joinFlag==EP_InnerJoin ); while( p ){ - ExprSetProperty(p, EP_FromJoin); + ExprSetProperty(p, joinFlag); assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(p, EP_NoReduce); p->w.iJoin = iTable; @@ -439,11 +440,11 @@ void sqlite3SetJoinExpr(Expr *p, int iTable){ if( p->x.pList ){ int i; for(i=0; ix.pList->nExpr; i++){ - sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable); + sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable, joinFlag); } } } - sqlite3SetJoinExpr(p->pLeft, iTable); + sqlite3SetJoinExpr(p->pLeft, iTable, joinFlag); p = p->pRight; } } @@ -459,6 +460,7 @@ static void unsetJoinExpr(Expr *p, int iTable){ if( ExprHasProperty(p, EP_FromJoin) && (iTable<0 || p->w.iJoin==iTable) ){ ExprClearProperty(p, EP_FromJoin); + ExprSetProperty(p, EP_InnerJoin); } if( p->op==TK_COLUMN && p->iTable==iTable ){ ExprClearProperty(p, EP_CanBeNull); @@ -502,10 +504,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ pRight = &pLeft[1]; for(i=0; inSrc-1; i++, pRight++, pLeft++){ Table *pRightTab = pRight->pTab; - int isOuter; + u32 joinType; if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; - isOuter = (pRight->fg.jointype & JT_OUTER)!=0; + joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_FromJoin : EP_InnerJoin; /* When the NATURAL keyword is present, add WHERE clause terms for ** every column that the two tables have in common. @@ -525,7 +527,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ zName = pRightTab->aCol[j].zCnName; if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 1) ){ addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j, - isOuter, &p->pWhere); + joinType, &p->pWhere); } } } @@ -556,7 +558,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ return 1; } addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, iRightCol, - isOuter, &p->pWhere); + joinType, &p->pWhere); } } @@ -564,7 +566,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ ** an AND operator. */ else if( pRight->u3.pOn ){ - if( isOuter ) sqlite3SetJoinExpr(pRight->u3.pOn, pRight->iCursor); + sqlite3SetJoinExpr(pRight->u3.pOn, pRight->iCursor, joinType); p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->u3.pOn); pRight->u3.pOn = 0; } @@ -3724,8 +3726,9 @@ static Expr *substExpr( if( pSubst->isLeftJoin ){ ExprSetProperty(pNew, EP_CanBeNull); } - if( ExprHasProperty(pExpr,EP_FromJoin) ){ - sqlite3SetJoinExpr(pNew, pExpr->w.iJoin); + if( ExprHasProperty(pExpr,EP_FromJoin|EP_InnerJoin) ){ + sqlite3SetJoinExpr(pNew, pExpr->w.iJoin, + pExpr->flags & (EP_FromJoin|EP_InnerJoin)); } sqlite3ExprDelete(db, pExpr); pExpr = pNew; @@ -4452,7 +4455,7 @@ static int flattenSubquery( pWhere = pSub->pWhere; pSub->pWhere = 0; if( isLeftJoin>0 ){ - sqlite3SetJoinExpr(pWhere, iNewParent); + sqlite3SetJoinExpr(pWhere, iNewParent, EP_FromJoin); } if( pWhere ){ if( pParent->pWhere ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 7f8a8e0151..b9eb970c7a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2887,7 +2887,7 @@ struct Expr { #define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ #define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ - /* 0x400000 // Available */ +#define EP_InnerJoin 0x400000 /* Originates in ON/USING of an inner join */ #define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ #define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */ #define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */ @@ -4829,7 +4829,7 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int); int sqlite3JoinType(Parse*, Token*, Token*, Token*); int sqlite3ColumnIndex(Table *pTab, const char *zCol); -void sqlite3SetJoinExpr(Expr*,int); +void sqlite3SetJoinExpr(Expr*,int,u32); void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); void sqlite3DeferForeignKey(Parse*, int); #ifndef SQLITE_OMIT_AUTHORIZATION diff --git a/src/where.c b/src/where.c index 3fbe69e593..1cd8f4ded8 100644 --- a/src/where.c +++ b/src/where.c @@ -6172,14 +6172,18 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ WhereInfo *pSubWInfo; SrcList sFrom; Bitmask mAll = 0; - for(k=0; k<=i; k++){ + for(k=0; ka[k].pWLoop->maskSelf; + iIdxCur = pWInfo->a[k].iIdxCur; + if( iIdxCur ) sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur); } + mAll |= pLoop->maskSelf; for(k=0; knTerm; k++){ WhereTerm *pTerm = &pWC->a[k]; if( pTerm->wtFlags & TERM_VIRTUAL ) break; if( pTerm->prereqAll & ~mAll ) continue; - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin) ) continue; pSubWhere = sqlite3ExprAnd(pParse, pSubWhere, sqlite3ExprDup(db, pTerm->pExpr, 0)); } diff --git a/src/whereexpr.c b/src/whereexpr.c index b622eed1b3..90c344806e 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -1809,6 +1809,7 @@ void sqlite3WhereTabFuncArgs( if( pArgs==0 ) return; for(j=k=0; jnExpr; j++){ Expr *pRhs; + u32 joinType; while( knCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;} if( k>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d", @@ -1826,8 +1827,11 @@ void sqlite3WhereTabFuncArgs( sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){ - sqlite3SetJoinExpr(pTerm, pItem->iCursor); + joinType = EP_FromJoin; + }else{ + joinType = EP_InnerJoin; } + sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } diff --git a/test/join7.test b/test/join7.test index c1cd9ff6cb..3b7d1f684e 100644 --- a/test/join7.test +++ b/test/join7.test @@ -175,5 +175,16 @@ foreach {id schema} { 1 3 NULL NULL 1 4 NULL NULL } + do_execsql_test join7-$id.12 { + SELECT a, b, c, d + FROM t2 FULL OUTER JOIN t1 ON b=c AND d<=0 ORDER BY +b, +d; + } { + NULL NULL 3 33 + NULL NULL 4 44 + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 NULL NULL + 1 4 NULL NULL + } } finish_test From 37259f4e6b5c4645aa732b0e2c7dada27c3f3259 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 13:13:57 +0000 Subject: [PATCH 18/31] New test cases. FossilOrigin-Name: d5f6791b86f946b348f5ddc9cedc0df4a86b17854a97554140799caf74c602f3 --- manifest | 12 ++++---- manifest.uuid | 2 +- test/join7.test | 74 +++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 69 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index 235ea5152d..86737b58ad 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\sa\sdistinction\sbetween\s(1)\sWHERE\sclause\sconstraints,\s(2)\sON/USING\nconstraints\son\souter\sjoins,\sand\s(3)\sON/USING\sclause\sconstraints\son\sinner\njoins.\s\sFormerly,\sthere\swas\sno\sdistinctionb\sbetween\s1\sand\s3,\sbut\sRIGHT\sJOIN\nneeds\sto\sknow\sthe\sdifference.\s\sMake\sRIGHT\sJOIN\saware\sof\sthis\sdifference\sand\nadd\stest\scases. -D 2022-04-11T12:38:06.753 +C New\stest\scases. +D 2022-04-11T13:13:57.688 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c -F test/join7.test 87f08f814012b4593a7b6021ebfbcc0d2c837045cad012a3a38e810182fe268a +F test/join7.test 1046604adf0c14d511b9fdd32d0ae0dbd0b72bf5bdb743f8c2e2308ab2ece16d F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 5be5ede5cca1cd5ef863fe0feb2b4a990f4a42865281a6c2e4eb816f48847dc6 -R 9c8f191b416653ff62ae70d11a61358b +P 0f6f61c3664cc87209c2a6f9b6df3a750d1510723fcde209c33db8feaf48bcf3 +R f9db99ab6a64191d51c5383e6585d61d U drh -Z e1bd204470110fd5d9bea7467b9ac13a +Z 5631bbf7326a120ea1b6b188ec3bde18 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 41dbfa450d..7b36e498af 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f6f61c3664cc87209c2a6f9b6df3a750d1510723fcde209c33db8feaf48bcf3 \ No newline at end of file +d5f6791b86f946b348f5ddc9cedc0df4a86b17854a97554140799caf74c602f3 \ No newline at end of file diff --git a/test/join7.test b/test/join7.test index 3b7d1f684e..fc6d898fc4 100644 --- a/test/join7.test +++ b/test/join7.test @@ -87,11 +87,22 @@ foreach {id schema} { CREATE TABLE dual(dummy TEXT); INSERT INTO dual(dummy) VALUES('x'); } + 10 { + CREATE TABLE t1(a INT, b INT, PRIMARY KEY(a,b)) WITHOUT ROWID; + INSERT INTO t1 VALUES(1,2),(1,3),(1,4); + CREATE TABLE t2a(c INTEGER PRIMARY KEY, i1 INT); + CREATE TABLE t2b(i1 INTEGER PRIMARY KEY, d INT); + CREATE VIEW t2(c,d) AS SELECT c, d FROM t2a NATURAL JOIN t2b; + INSERT INTO t2a VALUES(3,93),(4,94),(5,95),(6,96),(7,97); + INSERT INTO t2b VALUES(91,11),(92,22),(93,33),(94,44),(95,55); + CREATE TABLE dual(dummy TEXT); + INSERT INTO dual(dummy) VALUES('x'); + } } { reset_db db nullvalue NULL do_execsql_test join7-$id.setup $schema {} - do_execsql_test join7-$id.1 { + do_execsql_test join7-$id.10 { SELECT b, d FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; } { NULL 55 @@ -99,7 +110,7 @@ foreach {id schema} { 3 33 4 44 } - do_execsql_test join7-$id.2 { + do_execsql_test join7-$id.20 { SELECT a, c FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; } { NULL 5 @@ -107,7 +118,7 @@ foreach {id schema} { 1 3 1 4 } - do_execsql_test join7-$id.3 { + do_execsql_test join7-$id.30 { SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c ORDER BY +b; } { NULL NULL 5 55 @@ -115,35 +126,66 @@ foreach {id schema} { 1 3 3 33 1 4 4 44 } - do_execsql_test join7-$id.4 { + do_execsql_test join7-$id.31 { + SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c ORDER BY +b; + } { + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 + } + do_execsql_test join7-$id.40 { SELECT * FROM t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; } { NULL NULL 5 55 1 3 3 33 1 4 4 44 } - do_execsql_test join7-$id.5 { + do_execsql_test join7-$id.50 { + SELECT t1.*, t2.* FROM t2 LEFT OUTER JOIN t1 ON b=c ORDER BY +b; + } { + NULL NULL 5 55 + 1 3 3 33 + 1 4 4 44 + } + do_execsql_test join7-$id.60 { SELECT * FROM dual JOIN t1 ON true RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; } { NULL NULL NULL 5 55 x 1 3 3 33 x 1 4 4 44 } - do_execsql_test join7-$id.6 { + do_execsql_test join7-$id.70 { + SELECT t1.*, t2.* + FROM t2 LEFT JOIN (dual JOIN t1 ON true) ON b=c ORDER BY +b; + } { + NULL NULL 5 55 + 1 3 3 33 + 1 4 4 44 + } + do_execsql_test join7-$id.80 { SELECT * FROM dual CROSS JOIN t1 RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; } { NULL NULL NULL 5 55 x 1 3 3 33 x 1 4 4 44 } - do_execsql_test join7-$id.7 { + do_execsql_test join7-$id.81 { + SELECT dual.*, t1.*, t2.* + FROM t1 CROSS JOIN dual RIGHT OUTER JOIN t2 ON b=c ORDER BY +b; + } { + NULL NULL NULL 5 55 + x 1 3 3 33 + x 1 4 4 44 + } + do_execsql_test join7-$id.90 { SELECT * FROM t1 LEFT OUTER JOIN t2 ON b=c ORDER BY +b; } { 1 2 NULL NULL 1 3 3 33 1 4 4 44 } - do_execsql_test join7-$id.8 { + do_execsql_test join7-$id.100 { SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND a=1 ORDER BY +b; } { NULL NULL 5 55 @@ -151,21 +193,29 @@ foreach {id schema} { 1 3 3 33 1 4 4 44 } - do_execsql_test join7-$id.9 { + do_execsql_test join7-$id.101 { + SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c AND a=1 ORDER BY +b; + } { + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 + } + do_execsql_test join7-$id.110 { SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a=1 ORDER BY +b; } { 1 2 NULL NULL 1 3 3 33 1 4 4 44 } - do_execsql_test join7-$id.10 { + do_execsql_test join7-$id.120 { SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a IS NULL ORDER BY +d; } { NULL NULL 3 33 NULL NULL 4 44 NULL NULL 5 55 } - do_execsql_test join7-$id.11 { + do_execsql_test join7-$id.130 { SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c AND d<=0 ORDER BY +b, +d; } { NULL NULL 3 33 @@ -175,7 +225,7 @@ foreach {id schema} { 1 3 NULL NULL 1 4 NULL NULL } - do_execsql_test join7-$id.12 { + do_execsql_test join7-$id.140 { SELECT a, b, c, d FROM t2 FULL OUTER JOIN t1 ON b=c AND d<=0 ORDER BY +b, +d; } { From c583719b65d2fca51178d40826f3b325329fe12a Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 14:26:37 +0000 Subject: [PATCH 19/31] Show LEFT and RIGHT JOIN processing in the EXPLAIN QUERY PLAN output. FossilOrigin-Name: d91faeffea5cf0585fb71e5311fdcc6b8be85c7e9c732050b4448e617c970101 --- ext/rtree/rtreeC.test | 2 +- manifest | 30 +++++++++++++++--------------- manifest.uuid | 2 +- src/sqliteInt.h | 2 +- src/where.c | 4 +++- src/wherecode.c | 13 ++++++++----- test/autoindex1.test | 2 +- test/fts3join.test | 2 +- test/index6.test | 2 +- test/join2.test | 16 ++++++++-------- test/join5.test | 6 +++--- test/where9.test | 4 ++-- 12 files changed, 45 insertions(+), 40 deletions(-) diff --git a/ext/rtree/rtreeC.test b/ext/rtree/rtreeC.test index 75afcd7e22..bddc7d3030 100644 --- a/ext/rtree/rtreeC.test +++ b/ext/rtree/rtreeC.test @@ -342,7 +342,7 @@ do_eqp_execsql_test 7.2 { QUERY PLAN |--SCAN xdir |--SCAN rt VIRTUAL TABLE INDEX 2:B0D1 - `--SCAN ydir + `--SCAN ydir LEFT-JOIN } { 5 1 2 7 12 14 {} 5 2 2 7 8 12 10 diff --git a/manifest b/manifest index 86737b58ad..6a3bfffcd7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\stest\scases. -D 2022-04-11T13:13:57.688 +C Show\sLEFT\sand\sRIGHT\sJOIN\sprocessing\sin\sthe\sEXPLAIN\sQUERY\sPLAN\soutput. +D 2022-04-11T14:26:37.296 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -409,7 +409,7 @@ F ext/rtree/rtree8.test 2d99006a1386663978c9e1df167554671e4f711c419175b39f332719 F ext/rtree/rtree9.test fd3c9384ef8aabbc127b3878764070398f136eebc551cd20484b570f2cc1956a F ext/rtree/rtreeA.test a7fd235d8194115fa2e14d300337931eb2e960fe8a46cdfb66add2206412ea41 F ext/rtree/rtreeB.test 4cec297f8e5c588654bbf3c6ed0903f10612be8a2878055dd25faf8c71758bc9 -F ext/rtree/rtreeC.test c4bfa9a61c6788c03e4a9ce40ab2cfc6100982559effd9842d1b658e1d47aa5f +F ext/rtree/rtreeC.test 2978b194d09b13e106bdb0e1c5b408b9d42eb338c1082bf43c87ef43bd626147 F ext/rtree/rtreeD.test fe46aa7f012e137bd58294409b16c0d43976c3bb92c8f710481e577c4a1100dc F ext/rtree/rtreeE.test e65d3fc625da1800b412fc8785817327d43ccfec5f5973912d8c9e471928caa9 F ext/rtree/rtreeF.test 81ffa7ef51c4e4618d497a57328c265bf576990c7070633b623b23cd450ed331 @@ -557,7 +557,7 @@ F src/shell.c.in eb7f10d5e2c47bd014d92ec5db1def21fcc1ed56ffaaa4ee715b6c37c370b47 F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e -F src/sqliteInt.h fa220cb1b04ae45fa34de634efec4c04ce668ddcb6316c8f3260a8cf1a31310b +F src/sqliteInt.h cfdfe65eeb87d3fa8319481fb541586f49e93d5715e9f487ae83362844a9abc7 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -639,9 +639,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 8d8e54e2e29ac503ac5824cac0d368a9a45b0a2a3f129b0f2d50a1e3a891c62f +F src/where.c d5ad5f449c937f78b60a154c4ed9b6ccc6d4874ae14f7375e910f07addd143ab F src/whereInt.h ecf0d9fe3e35f2546e660c6389e56aedb6fd2434e31a0449b261ff55ebc6df2d -F src/wherecode.c 808e94b66f1bf052cbb77665ba08625ba93fbb0c343fe0ecafdfdd264bf0c6c9 +F src/wherecode.c bdf7de22c7ac38ad92e78214231a6054019521bfab943c2bfd5ddfb9e8ad9255 F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5 F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -704,7 +704,7 @@ F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1 F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec F test/autoinc.test 997d6f185f138229dc4251583a1d04816423dddc2fc034871a01aeb1d728cb39 -F test/autoindex1.test fe27af92eaf884bd9c38f94be3e8afa04ec494e5eefb189902026181a6175f5e +F test/autoindex1.test 523b26034dc5e0c5ff0865055b4593f75863b82f17748dec9ca64bb8b267c502 F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df F test/autoindex3.test 2d13958a5617e987624a428d7aed91bf51f322b49b476e3573fadec697ce6da5 F test/autoindex4.test 75cb1191a552b8201351f5a50d160fcb9387a0fbbfb820c77798bfee7da3f8cf @@ -1008,7 +1008,7 @@ F test/fts3fault.test 798e45af84be7978ca33d5bdc94246eb44724db24174b5d8e9b1ac46c5 F test/fts3fault2.test 6a17a11d8034b1c4eca9f3091649273d56c49ff049e2173df8060f94341e9da0 F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 F test/fts3fuzz001.test e3c7b0ce9b04cc02281dcc96812a277f02df03cd7dc082055d87e11eb18aaf56 -F test/fts3join.test b285c919559af5b093c51abb2c07ce7ec0156dbc9573f444b78dabd9f3040db2 +F test/fts3join.test ee25def5e763ea8879c19e74f862d5191410ccc7259338887a3685e97f512662 F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6 F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594096a703a4a F test/fts3matchinfo2.test 00144e841704b8debfcdf6097969cd9f2a1cf759e2203cda42583648f2e6bf58 @@ -1110,7 +1110,7 @@ F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407 F test/index3.test 51685f39345462b84fcf77eb8537af847fdf438cc96b05c45d6aaca4e473ade0 F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7 -F test/index6.test 5a7ab531c692ff3b3d139ef8ea6709fab40f9c6862ed418b4976752a5481da3a +F test/index6.test 6e5b6943f6a97a34898e48c4d0d4990caf55c12c00465a43a9c33d2fd9a3a820 F test/index7.test b238344318e0b4e42126717f6554f0e7dfd0b39cecad4b736039b43e1e3b6eb3 F test/index8.test caa097735c91dbc23d8a402f5e63a2a03c83840ba3928733ed7f9a03f8a912a3 F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721 @@ -1141,10 +1141,10 @@ F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9 F test/join.test a1832675aa30f2b422ff934b553e30294ca899484710242a2119ebf21f20a66a -F test/join2.test 9bdc615841b91c97a16d68bad9508aea11fa0c6b34e5689847bcc4dac70e4990 +F test/join2.test bf5ce6bfcef40dd49cfa51dd338eee62551e1efd85cadc68456c9beb43a06914 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 -F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc +F test/join5.test c4df54e2e204d7f1417bfbdd21ca324b4b07415c647595cc47798eacfddc96d3 F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/join7.test 1046604adf0c14d511b9fdd32d0ae0dbd0b72bf5bdb743f8c2e2308ab2ece16d F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 @@ -1778,7 +1778,7 @@ F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b F test/where7.test 1c1bf436bf31b913d4764a2b62ac6e98b9681e5c7ae2b562605592a56b7e946b F test/where8.test 461ca40265ed996a6305da99bb024b0e41602bb586acf544c08f95922358e49f -F test/where9.test 1ffb75edc50a8faa6e7bd77f8221d783febb00b44b0bdb32fb48cec6e38eca95 +F test/where9.test 2db942671a002621eff4f713e347bb25243295f79d8990297cd160bebcfde3f7 F test/whereA.test 9d1077b117f1b68d5f739d94f36956c36cf995eb87bb19b77b2e81af020edd20 F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0f6f61c3664cc87209c2a6f9b6df3a750d1510723fcde209c33db8feaf48bcf3 -R f9db99ab6a64191d51c5383e6585d61d +P d5f6791b86f946b348f5ddc9cedc0df4a86b17854a97554140799caf74c602f3 +R e0e6850d0795cb014db7acec54c6d9c7 U drh -Z 5631bbf7326a120ea1b6b188ec3bde18 +Z 41018e27e5349147bcae79649d9ca497 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7b36e498af..2b59843c0c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d5f6791b86f946b348f5ddc9cedc0df4a86b17854a97554140799caf74c602f3 \ No newline at end of file +d91faeffea5cf0585fb71e5311fdcc6b8be85c7e9c732050b4448e617c970101 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index b9eb970c7a..330d58fa48 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3163,7 +3163,7 @@ struct SrcList { #define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ #define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */ #define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ - /* 0x1000 not currently used */ +#define WHERE_RIGHT_JOIN 0x1000 /* Processing a RIGHT JOIN */ /* 0x2000 not currently used */ #define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ /* 0x8000 not currently used */ diff --git a/src/where.c b/src/where.c index 1cd8f4ded8..3677759ce8 100644 --- a/src/where.c +++ b/src/where.c @@ -6191,8 +6191,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ sFrom.nAlloc = 1; memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem)); sFrom.a[0].fg.jointype = 0; + ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTab->zName)); pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0, - WHERE_OR_SUBCLAUSE, 0); + WHERE_RIGHT_JOIN, 0); if( pSubWInfo ){ int iCur = pLevel->iTabCur; int r = ++pParse->nMem; @@ -6219,6 +6220,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3WhereEnd(pSubWInfo); } sqlite3ExprDelete(pParse->db, pSubWhere); + ExplainQueryPlanPop(pParse); continue; } diff --git a/src/wherecode.c b/src/wherecode.c index 0c81048678..410d6f206e 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -204,6 +204,9 @@ int sqlite3WhereExplainOneScan( pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif + if( pItem->fg.jointype & JT_LEFT ){ + sqlite3_str_appendf(&str, " LEFT-JOIN"); + } #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS if( pLoop->nOut>=10 ){ sqlite3_str_appendf(&str, " (~%llu rows)", @@ -1150,7 +1153,7 @@ static void codeDeferredSeek( pWInfo->bDeferredSeek = 1; sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur); - if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) + if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN)) && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) ){ int i; @@ -1502,7 +1505,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( ** initialize a memory cell that records if this table matches any ** row of the left table of the join. */ - assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) + assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN)) || pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0 ); if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){ @@ -2140,7 +2143,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( /* Seek the table cursor, if required */ omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 - && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0; + && (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0; if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ @@ -2174,7 +2177,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( ** move forward to the next index. ** https://sqlite.org/src/info/4e8e4857d32d401f */ - if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ + if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 ){ whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo); } @@ -2193,7 +2196,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( /* The following assert() is not a requirement, merely an observation: ** The OR-optimization doesn't work for the right hand table of ** a LEFT JOIN: */ - assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ); + assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 ); } /* Record the instruction used to terminate the loop. */ diff --git a/test/autoindex1.test b/test/autoindex1.test index 6b437f1867..2cd4900400 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -283,7 +283,7 @@ do_eqp_test autoindex1-600a { | `--CORRELATED SCALAR SUBQUERY xxxxxx | `--SEARCH later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date Date: Mon, 11 Apr 2022 14:43:11 +0000 Subject: [PATCH 20/31] Do not attempt the LEFT JOIN strength reduction optimization on a FULL JOIN. FossilOrigin-Name: 7ef3e99a73d70405a185d5d31f2d97d3bd99568fd6f10941e75d6c0baa27dc4f --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/select.c | 2 +- test/join7.test | 7 +++++++ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 6a3bfffcd7..fc6f19d7ac 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Show\sLEFT\sand\sRIGHT\sJOIN\sprocessing\sin\sthe\sEXPLAIN\sQUERY\sPLAN\soutput. -D 2022-04-11T14:26:37.296 +C Do\snot\sattempt\sthe\sLEFT\sJOIN\sstrength\sreduction\soptimization\son\sa\sFULL\sJOIN. +D 2022-04-11T14:43:11.140 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -552,7 +552,7 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 41d1b171d123a98bff4a2ddbe5ef7c47324274ca967030615506c4e246e96c12 +F src/select.c 67d793d9d3008699bc67a079de9eafc0c07d84c12fb867e5b735a79a456a77cb F src/shell.c.in eb7f10d5e2c47bd014d92ec5db1def21fcc1ed56ffaaa4ee715b6c37c370b47f F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test c4df54e2e204d7f1417bfbdd21ca324b4b07415c647595cc47798eacfddc96d3 F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c -F test/join7.test 1046604adf0c14d511b9fdd32d0ae0dbd0b72bf5bdb743f8c2e2308ab2ece16d +F test/join7.test 55bb771ea4a1bfe13a30cc4e1d1e248e52ed995027f578b4301cfed24b38fccc F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d5f6791b86f946b348f5ddc9cedc0df4a86b17854a97554140799caf74c602f3 -R e0e6850d0795cb014db7acec54c6d9c7 +P d91faeffea5cf0585fb71e5311fdcc6b8be85c7e9c732050b4448e617c970101 +R 5d3448a355057fba04d29e5742ae9a58 U drh -Z 41018e27e5349147bcae79649d9ca497 +Z a47161e29e441e2be838325980d1fa2a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2b59843c0c..8d2561664e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d91faeffea5cf0585fb71e5311fdcc6b8be85c7e9c732050b4448e617c970101 \ No newline at end of file +7ef3e99a73d70405a185d5d31f2d97d3bd99568fd6f10941e75d6c0baa27dc4f \ No newline at end of file diff --git a/src/select.c b/src/select.c index 79ff500f41..cede26d1c7 100644 --- a/src/select.c +++ b/src/select.c @@ -6509,7 +6509,7 @@ int sqlite3Select( /* Convert LEFT JOIN into JOIN if there are terms of the right table ** of the LEFT JOIN used in the WHERE clause. */ - if( (pItem->fg.jointype & JT_LEFT)!=0 + if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==JT_LEFT && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor) && OptimizationEnabled(db, SQLITE_SimplifyJoin) ){ diff --git a/test/join7.test b/test/join7.test index fc6d898fc4..a2c020f324 100644 --- a/test/join7.test +++ b/test/join7.test @@ -208,6 +208,13 @@ foreach {id schema} { 1 3 3 33 1 4 4 44 } + do_execsql_test join7-$id.111 { + SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c WHERE a=1 ORDER BY +b; + } { + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 + } do_execsql_test join7-$id.120 { SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a IS NULL ORDER BY +d; } { From 6134b2dff2d5df510210880f935bbd2b0a08f93c Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 17:27:38 +0000 Subject: [PATCH 21/31] Fix handling of "continue" and "break" from inside the loop for the right operand of a RIGHT JOIN. FossilOrigin-Name: b6e773a26c2c6ee76ea61acb059b4e676d07ea62f6db9c513638f8986557cf04 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/vdbe.c | 10 +++++++--- src/where.c | 11 ++++++++--- src/whereInt.h | 1 + test/join7.test | 26 ++++++++++++++++++++++++++ test/where.test | 9 +++++++++ 7 files changed, 62 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index fc6f19d7ac..fce667eaea 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sattempt\sthe\sLEFT\sJOIN\sstrength\sreduction\soptimization\son\sa\sFULL\sJOIN. -D 2022-04-11T14:43:11.140 +C Fix\shandling\sof\s"continue"\sand\s"break"\sfrom\sinside\sthe\sloop\sfor\sthe\sright\noperand\sof\sa\sRIGHT\sJOIN. +D 2022-04-11T17:27:38.662 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -624,7 +624,7 @@ F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23 F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3 -F src/vdbe.c eefc5a96938cc113a95e36a42b626bf594a7f0b8bb56ae299accbbf015b973cd +F src/vdbe.c 871c55b7eea607980465a3e9d5c1ba1af679789be5e9181af11ed2ff9ffd420f F src/vdbe.h 89f5edb1422c8783a0b29db836e409876f2b3e847f78e2b21b1fbcc48a93f85f F src/vdbeInt.h 5f3d0abcf30c2b7a6672ad4386f18be0fca9c9b2cefe18f85a2e3df74f2613bf F src/vdbeapi.c 354c893f1500cf524cc45c32879b9c68893a28b77e3442c24668d6afe4236217 @@ -639,8 +639,8 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c d5ad5f449c937f78b60a154c4ed9b6ccc6d4874ae14f7375e910f07addd143ab -F src/whereInt.h ecf0d9fe3e35f2546e660c6389e56aedb6fd2434e31a0449b261ff55ebc6df2d +F src/where.c e704ad49ef2907633148e2c2d2a22abba229f0ded23a498e4b9587fd02c6d965 +F src/whereInt.h cd6bddac3a26640b92d86e2b45ecc6e82d663cbcac6fd5d6d9690dfb280b1668 F src/wherecode.c bdf7de22c7ac38ad92e78214231a6054019521bfab943c2bfd5ddfb9e8ad9255 F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5 F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f @@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test c4df54e2e204d7f1417bfbdd21ca324b4b07415c647595cc47798eacfddc96d3 F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c -F test/join7.test 55bb771ea4a1bfe13a30cc4e1d1e248e52ed995027f578b4301cfed24b38fccc +F test/join7.test e5c9b1b729d7e1d0b4195e99833e0ff0cf2d88e7fdd32b49af1044f4c76f72d9 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1770,7 +1770,7 @@ F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2a F test/walvfs.test bccb3e0d235ef85e276f491d34db32c9ada1ea67be8d9f10aabe7b30319ec656 F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec F test/wapptest.tcl 899594e25684861d5b0c0880fb012364def50ef8097041b8ddf74be5ba7fa270 x -F test/where.test f114842c1851d257a26770f2ad55119b084001c0e1b8c214f886f45152d37cd8 +F test/where.test 8c6bbd0cae8feae142a7946e3484a802fa566bacf38452b1c3e48cb77321f9a4 F test/where2.test 03c21a11e7b90e2845fc3c8b4002fc44cc2797fa74c86ee47d70bd7ea4f29ed6 F test/where3.test 5b4ffc0ac2ea0fe92f02b1244b7531522fe4d7bccf6fa8741d54e82c10e67753 F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d91faeffea5cf0585fb71e5311fdcc6b8be85c7e9c732050b4448e617c970101 -R 5d3448a355057fba04d29e5742ae9a58 +P 7ef3e99a73d70405a185d5d31f2d97d3bd99568fd6f10941e75d6c0baa27dc4f +R 6de58d614948b06c1662abe14fed19fe U drh -Z a47161e29e441e2be838325980d1fa2a +Z e47a7befddcb419a51a3526b7bfafbab # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8d2561664e..11c7f5d20d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7ef3e99a73d70405a185d5d31f2d97d3bd99568fd6f10941e75d6c0baa27dc4f \ No newline at end of file +b6e773a26c2c6ee76ea61acb059b4e676d07ea62f6db9c513638f8986557cf04 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 18286c297b..45a47756eb 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -993,8 +993,12 @@ jump_to_p2: /* Opcode: Return P1 P2 P3 * * ** -** Jump to the next instruction after the address in register P1. After -** the jump, register P1 becomes undefined. +** Jump to the next instruction after the address stored in register P1. +** +** It used to be that after the jump, register P1 would become undefined. +** However, for the subroutine used for the inner loop of a RIGHT JOIN, +** it is useful for R1 register to be unchanged, so that is what happens +** now. ** ** P2 is not used by the byte-code engine. However, if P2 is positive ** and also less than the current address, then the "EXPLAIN" output @@ -1012,7 +1016,7 @@ case OP_Return: { /* in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags==MEM_Int ); pOp = &aOp[pIn1->u.i]; - pIn1->flags = MEM_Undefined; + /* pIn1->flags = MEM_Undefined; */ break; } diff --git a/src/where.c b/src/where.c index 3677759ce8..defbc860fc 100644 --- a/src/where.c +++ b/src/where.c @@ -5880,6 +5880,7 @@ WhereInfo *sqlite3WhereBegin( pRJ->regBloom = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); pRJ->regReturn = ++pParse->nMem; + pRJ->addrInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, pRJ->regReturn); assert( pTab==pTabItem->pTab ); if( HasRowid(pTab) ){ KeyInfo *pInfo; @@ -6013,7 +6014,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ /* Terminate the subroutine that forms the interior of the loop of ** the RIGHT JOIN table */ WhereRightJoin *pRJ = pLevel->pRJ; - sqlite3VdbeChangeP1(v, pRJ->addrSubrtn-1, sqlite3VdbeCurrentAddr(v)); + int addrHere = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeChangeP1(v, pRJ->addrSubrtn-1, addrHere); + sqlite3VdbeChangeP1(v, pRJ->addrInit, addrHere); + sqlite3VdbeResolveLabel(v, pLevel->addrCont); + pLevel->addrCont = 0; sqlite3VdbeAddOp2(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn); } pLoop = pLevel->pWLoop; @@ -6043,7 +6048,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ } #endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */ /* The common case: Advance to the next row */ - sqlite3VdbeResolveLabel(v, pLevel->addrCont); + if( pLevel->addrCont ) sqlite3VdbeResolveLabel(v, pLevel->addrCont); sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3); sqlite3VdbeChangeP5(v, pLevel->p5); VdbeCoverage(v); @@ -6058,7 +6063,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek); #endif - }else{ + }else if( pLevel->addrCont ){ sqlite3VdbeResolveLabel(v, pLevel->addrCont); } if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){ diff --git a/src/whereInt.h b/src/whereInt.h index 7b5be3011d..6be8234e27 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -52,6 +52,7 @@ struct WhereRightJoin { int regBloom; /* Bloom filter for iRJMatch */ int regReturn; /* Return register for the interior subroutine */ int addrSubrtn; /* Starting address for the interior subroutine */ + int addrInit; /* OP_Integer used for early init of regReturn */ }; /* diff --git a/test/join7.test b/test/join7.test index a2c020f324..a0507be1d9 100644 --- a/test/join7.test +++ b/test/join7.test @@ -215,6 +215,24 @@ foreach {id schema} { 1 3 3 33 1 4 4 44 } + do_execsql_test join7-$id.115 { + SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c + WHERE a=1 OR a IS NULL ORDER BY +b; + } { + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 + } + do_execsql_test join7-$id.116 { + SELECT t1.*, t2.* FROM t2 FULL OUTER JOIN t1 ON b=c + WHERE a=1 OR a IS NULL ORDER BY +b; + } { + NULL NULL 5 55 + 1 2 NULL NULL + 1 3 3 33 + 1 4 4 44 + } do_execsql_test join7-$id.120 { SELECT * FROM t1 FULL OUTER JOIN t2 ON b=c WHERE a IS NULL ORDER BY +d; } { @@ -243,5 +261,13 @@ foreach {id schema} { 1 3 NULL NULL 1 4 NULL NULL } + do_execsql_test join7-$id.141 { + SELECT a, b, c, d + FROM t2 FULL OUTER JOIN t1 ON b=c AND d<=0 + ORDER BY +b, +d LIMIT 2 OFFSET 2 + } { + NULL NULL 5 55 + 1 2 NULL NULL + } } finish_test diff --git a/test/where.test b/test/where.test index 8ee57b8b6f..2f53f2cb49 100644 --- a/test/where.test +++ b/test/where.test @@ -1348,16 +1348,25 @@ do_execsql_test where-18.1 { INSERT INTO t181 VALUES(1); SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL; } {1} +do_execsql_test where-18.1rj { + SELECT DISTINCT a FROM t182 RIGHT JOIN t181 ON a=b ORDER BY c IS NULL; +} {1} do_execsql_test where-18.2 { SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c; } {1} do_execsql_test where-18.3 { SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c; } {1} +do_execsql_test where-18.3rj { + SELECT DISTINCT a FROM t182 RIGHT JOIN t181 ON a=b ORDER BY c; +} {1} do_execsql_test where-18.4 { INSERT INTO t181 VALUES(1),(1),(1),(1); SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c; } {1} +do_execsql_test where-18.4rj { + SELECT DISTINCT a FROM t182 RIGHT JOIN t181 ON a=b ORDER BY +c; +} {1} do_execsql_test where-18.5 { INSERT INTO t181 VALUES(2); SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL, +a; From ec27077c4f1dc2753ab3f26be7024c3b8af5491c Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 18:54:23 +0000 Subject: [PATCH 22/31] New test cases added. FossilOrigin-Name: bdd1499c0fa4f8aadf4857a0ccc0d839c250369f29766ebef80330964905e63b --- manifest | 22 +++++++++++----------- manifest.uuid | 2 +- test/affinity3.test | 32 ++++++++++++++++++++++++++++++++ test/aggnested.test | 11 +++++++++++ test/autoindex4.test | 25 +++++++++++++++++++++++++ test/btree01.test | 3 +++ test/collate2.test | 24 +++++++++++++++++++++--- test/join2.test | 15 +++++++++++++++ 8 files changed, 119 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index fce667eaea..0a663ec1c8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\shandling\sof\s"continue"\sand\s"break"\sfrom\sinside\sthe\sloop\sfor\sthe\sright\noperand\sof\sa\sRIGHT\sJOIN. -D 2022-04-11T17:27:38.662 +C New\stest\scases\sadded. +D 2022-04-11T18:54:23.445 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -646,9 +646,9 @@ F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249 F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 -F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7 +F test/affinity3.test b5c19d504dec222c0dc66642673d23dce915d35737b68e74d9f237b80493eb53 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 -F test/aggnested.test cc47afa5e11e0d6771a85a4993fa6ff721480ddb53ea538ec3fdbafb720bd505 +F test/aggnested.test 7269d07ac879fce161cb26c8fabe65cba5715742fac8a1fccac570dcdaf28f00 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13 F test/alter.test 313073774ab5c3f2ef1d3f0d03757c9d3a81284ae7e1b4a6ca34db088f886896 @@ -707,7 +707,7 @@ F test/autoinc.test 997d6f185f138229dc4251583a1d04816423dddc2fc034871a01aeb1d728 F test/autoindex1.test 523b26034dc5e0c5ff0865055b4593f75863b82f17748dec9ca64bb8b267c502 F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df F test/autoindex3.test 2d13958a5617e987624a428d7aed91bf51f322b49b476e3573fadec697ce6da5 -F test/autoindex4.test 75cb1191a552b8201351f5a50d160fcb9387a0fbbfb820c77798bfee7da3f8cf +F test/autoindex4.test 5df39313526b6f22a26bd119bbd97ca69f28386ab3c671fc10568d921c41eb08 F test/autoindex5.test 2ee94f033b87ca0160e08d81034c507aff8e230df2627f0304fa309b2fee19a3 F test/autovacuum.test 00671369bbf96c6a49989a9425f5b78b94075d6a4b031e5e00000c2c32f365df F test/autovacuum2.test 76f7eb4fe6a6bf6d33a196a7141dba98886d2fb53a268d7feca285d5da4759d7 @@ -752,7 +752,7 @@ F test/boundary3.tcl 23361e108a125dca9c4080c2feb884fe54d69243 F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45 F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983 F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b -F test/btree01.test 8e1ba2f857608ad8fbf9fcc11f33b15b083711162f9566b0a21fb573f2008593 +F test/btree01.test fef17d9e999ac4f04095948e3438fbe674f4e07bb2c63bb1cad41d87baee077f F test/btree02.test 7555a5440453d900410160a52554fe6478af4faf53098f7235f1f443d5a1d6cc F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3 F test/busy.test 510dc6daaad18bcbbc085bcc6217d6dc418def5e73f72ce1475eea0cb7834727 @@ -777,7 +777,7 @@ F test/close.test eccbad8ecd611d974cbf47278c3d4e5874faf02d811338d5d348af42d56d64 F test/closure01.test 9905883f1b171a4638f98fc764879f154e214a306d3d8daf412a15e7f3a9b1e0 F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91 F test/collate1.test 71a6f27fdc93a92f14d8ab80c05e1937656a5a03197e1a10157314554d630ce8 -F test/collate2.test 9aaa410a00734e48bcb27f3872617d6f69b2a621 +F test/collate2.test 471c6f74573382b89b0f8b88a05256faa52f7964f9e4799e76708a3b1ece6ba4 F test/collate3.test 89defc49983ddfbf0a0555aca8c0521a676f56a5 F test/collate4.test c953715fb498b87163e3e73dd94356bff1f317bd F test/collate5.test 65d928034d30d2d263a80f6359f7549ee1598ec6 @@ -1141,7 +1141,7 @@ F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9 F test/join.test a1832675aa30f2b422ff934b553e30294ca899484710242a2119ebf21f20a66a -F test/join2.test bf5ce6bfcef40dd49cfa51dd338eee62551e1efd85cadc68456c9beb43a06914 +F test/join2.test 9751dac84a46a960281ca372fe2350252ef40286dde3c542540bccdea9a2d5c6 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test c4df54e2e204d7f1417bfbdd21ca324b4b07415c647595cc47798eacfddc96d3 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7ef3e99a73d70405a185d5d31f2d97d3bd99568fd6f10941e75d6c0baa27dc4f -R 6de58d614948b06c1662abe14fed19fe +P b6e773a26c2c6ee76ea61acb059b4e676d07ea62f6db9c513638f8986557cf04 +R ea6a6206ccd15b1ede34fe0a185bc5f1 U drh -Z e47a7befddcb419a51a3526b7bfafbab +Z 7ac11620004b739208f6ff19e0608f85 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 11c7f5d20d..3f8fbe197f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b6e773a26c2c6ee76ea61acb059b4e676d07ea62f6db9c513638f8986557cf04 \ No newline at end of file +bdd1499c0fa4f8aadf4857a0ccc0d839c250369f29766ebef80330964905e63b \ No newline at end of file diff --git a/test/affinity3.test b/test/affinity3.test index ef1533a8f8..48942de72e 100644 --- a/test/affinity3.test +++ b/test/affinity3.test @@ -30,11 +30,24 @@ do_execsql_test affinity3-100 { FROM customer c LEFT JOIN apr i ON i.id=c.id; + CREATE VIEW v1rj AS + SELECT c.id, i.apr + FROM apr i + RIGHT JOIN customer c ON i.id=c.id; + CREATE VIEW v2 AS SELECT c.id, v1.apr FROM customer c LEFT JOIN v1 ON v1.id=c.id; + CREATE VIEW v2rj AS + SELECT c.id, v1.apr + FROM v1 RIGHT JOIN customer c ON v1.id=c.id; + + CREATE VIEW v2rjrj AS + SELECT c.id, v1rj.apr + FROM v1rj RIGHT JOIN customer c ON v1rj.id=c.id; + INSERT INTO customer (id) VALUES (1); INSERT INTO apr (id, apr) VALUES (1, 12); INSERT INTO customer (id) VALUES (2); @@ -44,16 +57,35 @@ do_execsql_test affinity3-110 { PRAGMA automatic_index=ON; SELECT id, (apr / 100), typeof(apr) apr_type FROM v1; } {1 0.12 real 2 0.1201 real} +do_execsql_test affinity3-111 { + PRAGMA automatic_index=ON; + SELECT id, (apr / 100), typeof(apr) apr_type FROM v1rj; +} {1 0.12 real 2 0.1201 real} do_execsql_test affinity3-120 { SELECT id, (apr / 100), typeof(apr) apr_type FROM v2; } {1 0.12 real 2 0.1201 real} +do_execsql_test affinity3-121 { + SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rj; +} {1 0.12 real 2 0.1201 real} +do_execsql_test affinity3-122 { + SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rjrj; +} {1 0.12 real 2 0.1201 real} do_execsql_test affinity3-130 { PRAGMA automatic_index=OFF; SELECT id, (apr / 100), typeof(apr) apr_type FROM v1; } {1 0.12 real 2 0.1201 real} +do_execsql_test affinity3-131 { + SELECT id, (apr / 100), typeof(apr) apr_type FROM v1rj; +} {1 0.12 real 2 0.1201 real} do_execsql_test affinity3-140 { SELECT id, (apr / 100), typeof(apr) apr_type FROM v2; } {1 0.12 real 2 0.1201 real} +do_execsql_test affinity3-141 { + SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rj; +} {1 0.12 real 2 0.1201 real} +do_execsql_test affinity3-142 { + SELECT id, (apr / 100), typeof(apr) apr_type FROM v2rjrj; +} {1 0.12 real 2 0.1201 real} # Ticket https://www.sqlite.org/src/info/7ffd1ca1d2ad4ecf (2017-01-16) # Incorrect affinity when using automatic indexes diff --git a/test/aggnested.test b/test/aggnested.test index 35d5f1e3a6..1b8b608803 100644 --- a/test/aggnested.test +++ b/test/aggnested.test @@ -137,6 +137,17 @@ do_test aggnested-3.1 { GROUP BY curr.id1); } } {1 1} +do_test aggnested-3.1-rj { + db eval { + SELECT + (SELECT sum(value2==xyz) FROM t2) + FROM + (SELECT curr.value1 as xyz + FROM t1 AS other RIGHT JOIN t1 AS curr + GROUP BY curr.id1); + } +} {1 1} + do_test aggnested-3.2 { db eval { DROP TABLE IF EXISTS t1; diff --git a/test/autoindex4.test b/test/autoindex4.test index 24604af588..d9ab783e42 100644 --- a/test/autoindex4.test +++ b/test/autoindex4.test @@ -32,12 +32,21 @@ do_execsql_test autoindex4-1.1 { do_execsql_test autoindex4-1.2 { SELECT *, '|' FROM t1 LEFT JOIN t2 ON a=234 AND x=555; } {123 abc {} {} | 234 def {} {} | 234 ghi {} {} | 345 jkl {} {} |} +do_execsql_test autoindex4-1.2-rj { + SELECT t1.*, t2.*, '|' FROM t2 RIGHT JOIN t1 ON a=234 AND x=555; +} {123 abc {} {} | 234 def {} {} | 234 ghi {} {} | 345 jkl {} {} |} do_execsql_test autoindex4-1.3 { SELECT *, '|' FROM t1 LEFT JOIN t2 ON x=555 WHERE a=234; } {234 def {} {} | 234 ghi {} {} |} +do_execsql_test autoindex4-1.3-rj { + SELECT t1.*, t2.*, '|' FROM t2 RIGHT JOIN t1 ON x=555 WHERE a=234; +} {234 def {} {} | 234 ghi {} {} |} do_execsql_test autoindex4-1.4 { SELECT *, '|' FROM t1 LEFT JOIN t2 WHERE a=234 AND x=555; } {} +do_execsql_test autoindex4-1.4-rj { + SELECT t1.*, t2.*, '|' FROM t2 RIGHT JOIN t1 WHERE a=234 AND x=555; +} {} do_execsql_test autoindex4-2.0 { @@ -69,6 +78,14 @@ do_execsql_test autoindex4-3.0 { ORDER BY Items.ItemName; } {Item1 Item2} do_execsql_test autoindex4-3.1 { + SELECT Items.ItemName + FROM A + RIGHT JOIN Items ON (A.Name = Items.ItemName and Items.ItemName = 'dummy') + LEFT JOIN B ON (B.Name = Items.ItemName) + WHERE Items.Name = 'Parent' + ORDER BY Items.ItemName; +} {Item1 Item2} +do_execsql_test autoindex4-3.10 { CREATE INDEX Items_x1 ON Items(ItemName,Name) WHERE ItemName = 'dummy'; SELECT Items.ItemName @@ -78,6 +95,14 @@ do_execsql_test autoindex4-3.1 { WHERE Items.Name = 'Parent' ORDER BY Items.ItemName; } {Item1 Item2} +do_execsql_test autoindex4-3.11 { + SELECT Items.ItemName + FROM A + RIGHT JOIN Items ON (A.Name = Items.ItemName and Items.ItemName = 'dummy') + LEFT JOIN B ON (B.Name = Items.ItemName) + WHERE Items.Name = 'Parent' + ORDER BY Items.ItemName; +} {Item1 Item2} # 2021-11-30 - Enhancement to help the automatic index mechanism to # create a partial index more often. diff --git a/test/btree01.test b/test/btree01.test index 9c309760d5..6e4717ae65 100644 --- a/test/btree01.test +++ b/test/btree01.test @@ -148,6 +148,9 @@ do_execsql_test btree01-2.1 { INSERT INTO t2(y) VALUES(198),(187),(100); SELECT y, c FROM t2 LEFT JOIN t1 ON y=a ORDER BY x; } {198 99 187 {} 100 50} +do_execsql_test btree01-2.2 { + SELECT y, c FROM t1 RIGHT JOIN t2 ON y=a ORDER BY x; +} {198 99 187 {} 100 50} finish_test diff --git a/test/collate2.test b/test/collate2.test index d5aadb4eb5..281aa35709 100644 --- a/test/collate2.test +++ b/test/collate2.test @@ -684,16 +684,34 @@ do_test collate2-5.3 { SELECT collate2t1.b FROM collate2t2 NATURAL JOIN collate2t1; } } {aa} -do_test collate2-5.4 { +do_test collate2-5.4.1 { execsql { - SELECT collate2t2.b FROM collate2t1 LEFT OUTER JOIN collate2t2 USING (b) order by collate2t1.oid; + SELECT collate2t2.b FROM collate2t1 LEFT JOIN collate2t2 USING (b) order by collate2t1.oid; } } {{} aa {} {} {} aa {} {} {} aa {} {} {} aa {} {} {}} -do_test collate2-5.5 { +do_test collate2-5.4.2 { + execsql { + SELECT collate2t2.b FROM collate2t2 RIGHT JOIN collate2t1 ON collate2t1.b=collate2t2.b + ORDER BY collate2t1.oid; + } +} {{} aa {} {} {} aa {} {} {} aa {} {} {} aa {} {} {}} +do_test collate2-5.4.3 { + execsql { + SELECT collate2t2.b FROM collate2t1 LEFT JOIN collate2t2 ON collate2t2.b=collate2t1.b + ORDER BY collate2t1.oid; + } +} {{} aa {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}} +do_test collate2-5.5.1 { execsql { SELECT collate2t1.b, collate2t2.b FROM collate2t2 LEFT OUTER JOIN collate2t1 USING (b); } } {aa aa} +do_test collate2-5.5.2 { + execsql { + SELECT collate2t1.b, collate2t2.b + FROM collate2t1 RIGHT JOIN collate2t2 ON collate2t2.b=collate2t1.b + } +} {aa aa} do_execsql_test 6.1 { CREATE TABLE t1(x); diff --git a/test/join2.test b/test/join2.test index 8af242b1ad..4142fd15b3 100644 --- a/test/join2.test +++ b/test/join2.test @@ -63,6 +63,12 @@ do_test join2-1.6 { t1 NATURAL LEFT OUTER JOIN t2 NATURAL JOIN t3 } } {1 11 111 1111} +do_test join2-1.6-rj { + execsql { + SELECT * FROM + t2 NATURAL RIGHT OUTER JOIN t1 NATURAL JOIN t3 + } +} {11 111 1 1111} ifcapable subquery { do_test join2-1.7 { execsql { @@ -70,6 +76,12 @@ ifcapable subquery { t1 NATURAL LEFT OUTER JOIN (t2 NATURAL JOIN t3) } } {1 11 111 1111 2 22 {} {} 3 33 {} {}} + do_test join2-1.7-rj { + execsql { + SELECT * FROM + (t2 NATURAL JOIN t3) NATURAL RIGHT JOIN t1 + } + } {11 111 1111 1 {} {} {} 2 {} {} {} 3} } #------------------------------------------------------------------------- @@ -88,6 +100,9 @@ do_execsql_test 2.0 { do_catchsql_test 2.1 { SELECT * FROM aa LEFT JOIN cc ON (a=b) JOIN bb ON (b=coalesce(c,1)); } {1 {ON clause references tables to its right}} +do_catchsql_test 2.1b { + SELECT * FROM aa RIGHT JOIN cc ON (a=b) JOIN bb ON (b=coalesce(c,1)); +} {1 {ON clause references tables to its right}} do_catchsql_test 2.2 { SELECT * FROM aa JOIN cc ON (a=b) JOIN bb ON (b=c); } {0 {one one one}} From c133bab72a60fc020fffce0a329c1a4092f20aa0 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 20:15:52 +0000 Subject: [PATCH 23/31] The query flattener must add TK_IF_NULL_ROW opcodes on substituted values that land on the left operand of a RIGHT JOIN, just as it already does for the right operand of a LEFT JOIN. FossilOrigin-Name: 8e02cdf5b1128f5e5b82d93903063415ec312694e5ccdd19e99fa35433f1b68a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/select.c | 52 +++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index 0a663ec1c8..a2d3e3fd54 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\stest\scases\sadded. -D 2022-04-11T18:54:23.445 +C The\squery\sflattener\smust\sadd\sTK_IF_NULL_ROW\sopcodes\son\ssubstituted\svalues\nthat\sland\son\sthe\sleft\soperand\sof\sa\sRIGHT\sJOIN,\sjust\sas\sit\salready\sdoes\sfor\nthe\sright\soperand\sof\sa\sLEFT\sJOIN. +D 2022-04-11T20:15:52.179 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -552,7 +552,7 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 67d793d9d3008699bc67a079de9eafc0c07d84c12fb867e5b735a79a456a77cb +F src/select.c fdec126045cf441883836756d6d949367e8a2945c53fa6e98d6c51a08d7efc81 F src/shell.c.in eb7f10d5e2c47bd014d92ec5db1def21fcc1ed56ffaaa4ee715b6c37c370b47f F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P b6e773a26c2c6ee76ea61acb059b4e676d07ea62f6db9c513638f8986557cf04 -R ea6a6206ccd15b1ede34fe0a185bc5f1 +P bdd1499c0fa4f8aadf4857a0ccc0d839c250369f29766ebef80330964905e63b +R 1528160c8ffde5ccc7d4edc8311e6b3e U drh -Z 7ac11620004b739208f6ff19e0608f85 +Z 0a6599330cad92a7a73b62ce77e2586b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3f8fbe197f..bd94247551 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bdd1499c0fa4f8aadf4857a0ccc0d839c250369f29766ebef80330964905e63b \ No newline at end of file +8e02cdf5b1128f5e5b82d93903063415ec312694e5ccdd19e99fa35433f1b68a \ No newline at end of file diff --git a/src/select.c b/src/select.c index cede26d1c7..7230ff90c9 100644 --- a/src/select.c +++ b/src/select.c @@ -3654,12 +3654,40 @@ static int multiSelectOrderBy( ** ** All references to columns in table iTable are to be replaced by corresponding ** expressions in pEList. +** +** ## About "isOuterJoin": +** +** The isOuterJoin column indicates that the replacement will occur into a +** position in the parent that NULL-able due to an OUTER JOIN. Either the +** target slot in the parent is the right operand of a LEFT JOIN, or one of +** the left operands of a RIGHT JOIN. In either case, we need to potentially +** bypass the substituted expression with OP_IfNullRow. +** +** Suppose the original expression integer constant. Even though the table +** has the nullRow flag set, because the expression is an integer constant, +** it will not be NULLed out. So instead, we insert an OP_IfNullRow opcode +** that checks to see if the nullRow flag is set on the table. If the nullRow +** flag is set, then the value in the register is set to NULL and the original +** expression is bypassed. If the nullRow flag is not set, then the original +** expression runs to populate the register. +** +** Example where this is needed: +** +** CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT); +** CREATE TABLE t2(x INT UNIQUE); +** +** SELECT a,b,m,x FROM t1 LEFT JOIN (SELECT 59 AS m,x FROM t2) ON b=x; +** +** When the subquery on the right side of the LEFT JOIN is flattened, we +** have to add OP_IfNullRow in front of the OP_Integer that implements the +** "m" value of the subquery so that a NULL will be loaded instead of 59 +** when processing a non-matched row of the left. */ typedef struct SubstContext { Parse *pParse; /* The parsing context */ int iTable; /* Replace references to this table */ int iNewTable; /* New table number */ - int isLeftJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */ + int isOuterJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */ ExprList *pEList; /* Replacement expressions */ } SubstContext; @@ -3709,7 +3737,7 @@ static Expr *substExpr( sqlite3VectorErrorMsg(pSubst->pParse, pCopy); }else{ sqlite3 *db = pSubst->pParse->db; - if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){ + if( pSubst->isOuterJoin && pCopy->op!=TK_COLUMN ){ memset(&ifNullRow, 0, sizeof(ifNullRow)); ifNullRow.op = TK_IF_NULL_ROW; ifNullRow.pLeft = pCopy; @@ -3723,7 +3751,7 @@ static Expr *substExpr( sqlite3ExprDelete(db, pNew); return pExpr; } - if( pSubst->isLeftJoin ){ + if( pSubst->isOuterJoin ){ ExprSetProperty(pNew, EP_CanBeNull); } if( ExprHasProperty(pExpr,EP_FromJoin|EP_InnerJoin) ){ @@ -4105,7 +4133,7 @@ static int flattenSubquery( SrcList *pSubSrc; /* The FROM clause of the subquery */ int iParent; /* VDBE cursor number of the pSub result set temp table */ int iNewParent = -1;/* Replacement table for iParent */ - int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */ + int isOuterJoin = 0; /* True if pSub is the right side of a LEFT JOIN */ int i; /* Loop counter */ Expr *pWhere; /* The WHERE clause */ SrcItem *pSubitem; /* The subquery */ @@ -4178,7 +4206,7 @@ static int flattenSubquery( ** ** See also tickets #306, #350, and #3300. */ - if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){ + if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){ if( pSubSrc->nSrc>1 /* (3a) */ || isAgg /* (3b) */ || IsVirtual(pSubSrc->a[0].pTab) /* (3c) */ @@ -4187,15 +4215,15 @@ static int flattenSubquery( ){ return 0; } - isLeftJoin = 1; + isOuterJoin = 1; } #ifdef SQLITE_EXTRA_IFNULLROW else if( iFrom>0 && !isAgg ){ - /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for + /* Setting isOuterJoin to -1 causes OP_IfNullRow opcodes to be generated for ** every reference to any result column from subquery in a join, even ** though they are not necessary. This will stress-test the OP_IfNullRow ** opcode. */ - isLeftJoin = -1; + isOuterJoin = -1; } #endif @@ -4208,7 +4236,7 @@ static int flattenSubquery( if( pSub->pOrderBy ){ return 0; /* Restriction (20) */ } - if( isAgg || (p->selFlags & SF_Distinct)!=0 || isLeftJoin>0 ){ + if( isAgg || (p->selFlags & SF_Distinct)!=0 || isOuterJoin>0 ){ return 0; /* (17d1), (17d2), or (17f) */ } for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){ @@ -4454,7 +4482,7 @@ static int flattenSubquery( } pWhere = pSub->pWhere; pSub->pWhere = 0; - if( isLeftJoin>0 ){ + if( isOuterJoin>0 ){ sqlite3SetJoinExpr(pWhere, iNewParent, EP_FromJoin); } if( pWhere ){ @@ -4469,7 +4497,7 @@ static int flattenSubquery( x.pParse = pParse; x.iTable = iParent; x.iNewTable = iNewParent; - x.isLeftJoin = isLeftJoin; + x.isOuterJoin = isOuterJoin; x.pEList = pSub->pEList; substSelect(&x, pParent, 0); } @@ -4930,7 +4958,7 @@ static int pushDownWhereTerms( x.pParse = pParse; x.iTable = iCursor; x.iNewTable = iCursor; - x.isLeftJoin = 0; + x.isOuterJoin = 0; x.pEList = pSubq->pEList; pNew = substExpr(&x, pNew); #ifndef SQLITE_OMIT_WINDOWFUNC From b087de063bed22932287aff4f12a2e5a3083aa8d Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 11 Apr 2022 21:00:38 +0000 Subject: [PATCH 24/31] Fix RIGHT JOIN for virtual tables. FossilOrigin-Name: 75a9116e98b9ac5c1a4c62a01143a016d9ba6a0b495ff7af7468c11947a3e888 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 7 ++++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index a2d3e3fd54..aa0aec2054 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\squery\sflattener\smust\sadd\sTK_IF_NULL_ROW\sopcodes\son\ssubstituted\svalues\nthat\sland\son\sthe\sleft\soperand\sof\sa\sRIGHT\sJOIN,\sjust\sas\sit\salready\sdoes\sfor\nthe\sright\soperand\sof\sa\sLEFT\sJOIN. -D 2022-04-11T20:15:52.179 +C Fix\sRIGHT\sJOIN\sfor\svirtual\stables. +D 2022-04-11T21:00:38.338 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c e704ad49ef2907633148e2c2d2a22abba229f0ded23a498e4b9587fd02c6d965 +F src/where.c 728d2d5c6259b576c33a2f5107b871e9819484509126bd40ade8b95224852655 F src/whereInt.h cd6bddac3a26640b92d86e2b45ecc6e82d663cbcac6fd5d6d9690dfb280b1668 F src/wherecode.c bdf7de22c7ac38ad92e78214231a6054019521bfab943c2bfd5ddfb9e8ad9255 F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P bdd1499c0fa4f8aadf4857a0ccc0d839c250369f29766ebef80330964905e63b -R 1528160c8ffde5ccc7d4edc8311e6b3e +P 8e02cdf5b1128f5e5b82d93903063415ec312694e5ccdd19e99fa35433f1b68a +R 5708722e4ffecbe2e31f6fd1bda81037 U drh -Z 0a6599330cad92a7a73b62ce77e2586b +Z 577b70851c6bc25c90b72e9816f63b4e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bd94247551..fb8b6444cb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8e02cdf5b1128f5e5b82d93903063415ec312694e5ccdd19e99fa35433f1b68a \ No newline at end of file +75a9116e98b9ac5c1a4c62a01143a016d9ba6a0b495ff7af7468c11947a3e888 \ No newline at end of file diff --git a/src/where.c b/src/where.c index defbc860fc..f1d3ad2655 100644 --- a/src/where.c +++ b/src/where.c @@ -6181,7 +6181,12 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ int iIdxCur; mAll |= pWInfo->a[k].pWLoop->maskSelf; iIdxCur = pWInfo->a[k].iIdxCur; - if( iIdxCur ) sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur); + if( iIdxCur ){ + sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur); + } + if( pWInfo->a[k].pWLoop->wsFlags & WHERE_VIRTUALTABLE ){ + sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); + } } mAll |= pLoop->maskSelf; for(k=0; knTerm; k++){ From a70782407d12bae34240167814b49e1593048aca Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 12 Apr 2022 13:46:21 +0000 Subject: [PATCH 25/31] Always explicitly set each table cursor to NullRow before doing the RIGHT-JOIN unmatched row pass. This is a cheap opcode, and it adds an extra layer of defense against incorrect results. FossilOrigin-Name: a3d14e61ca22167296fee125a3e9aa63413408955e03bb3f9d85fa9f22df1b79 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 4 +--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index aa0aec2054..3cd8c98914 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sRIGHT\sJOIN\sfor\svirtual\stables. -D 2022-04-11T21:00:38.338 +C Always\sexplicitly\sset\seach\stable\scursor\sto\sNullRow\sbefore\sdoing\sthe\sRIGHT-JOIN\nunmatched\srow\spass.\s\sThis\sis\sa\scheap\sopcode,\sand\sit\sadds\san\sextra\slayer\sof\ndefense\sagainst\sincorrect\sresults. +D 2022-04-12T13:46:21.228 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 728d2d5c6259b576c33a2f5107b871e9819484509126bd40ade8b95224852655 +F src/where.c 2e4c4a9140a5feb5d55613786f253e2684408e830fc1108abd854d95ef926d68 F src/whereInt.h cd6bddac3a26640b92d86e2b45ecc6e82d663cbcac6fd5d6d9690dfb280b1668 F src/wherecode.c bdf7de22c7ac38ad92e78214231a6054019521bfab943c2bfd5ddfb9e8ad9255 F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8e02cdf5b1128f5e5b82d93903063415ec312694e5ccdd19e99fa35433f1b68a -R 5708722e4ffecbe2e31f6fd1bda81037 +P 75a9116e98b9ac5c1a4c62a01143a016d9ba6a0b495ff7af7468c11947a3e888 +R 7f21190d047eb5dd5ac5fcbb3009e4d3 U drh -Z 577b70851c6bc25c90b72e9816f63b4e +Z fd007c71d1edd8db14c7de90c355f1d6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fb8b6444cb..55b041541b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -75a9116e98b9ac5c1a4c62a01143a016d9ba6a0b495ff7af7468c11947a3e888 \ No newline at end of file +a3d14e61ca22167296fee125a3e9aa63413408955e03bb3f9d85fa9f22df1b79 \ No newline at end of file diff --git a/src/where.c b/src/where.c index f1d3ad2655..2883653317 100644 --- a/src/where.c +++ b/src/where.c @@ -6180,13 +6180,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ for(k=0; ka[k].pWLoop->maskSelf; + sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); iIdxCur = pWInfo->a[k].iIdxCur; if( iIdxCur ){ sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur); } - if( pWInfo->a[k].pWLoop->wsFlags & WHERE_VIRTUALTABLE ){ - sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); - } } mAll |= pLoop->maskSelf; for(k=0; knTerm; k++){ From 61dac44eb91f0e9f37eb5ccdfe9877f0cdc39a97 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 12 Apr 2022 14:23:45 +0000 Subject: [PATCH 26/31] The multi-index OR optimization does not work for RIGHT join, so disallow it. FossilOrigin-Name: 34c2f7b237fa4e0e1cd94fb9c44ebe194b86b88dc575055cc46c7f3695d02756 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 3cd8c98914..1b8dc3a8c1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Always\sexplicitly\sset\seach\stable\scursor\sto\sNullRow\sbefore\sdoing\sthe\sRIGHT-JOIN\nunmatched\srow\spass.\s\sThis\sis\sa\scheap\sopcode,\sand\sit\sadds\san\sextra\slayer\sof\ndefense\sagainst\sincorrect\sresults. -D 2022-04-12T13:46:21.228 +C The\smulti-index\sOR\soptimization\sdoes\snot\swork\sfor\sRIGHT\sjoin,\sso\sdisallow\sit. +D 2022-04-12T14:23:45.158 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 2e4c4a9140a5feb5d55613786f253e2684408e830fc1108abd854d95ef926d68 +F src/where.c 5473af25fd2acd2898574950f51e4eaec77d57c450c0d3339905f3db42c6bb30 F src/whereInt.h cd6bddac3a26640b92d86e2b45ecc6e82d663cbcac6fd5d6d9690dfb280b1668 F src/wherecode.c bdf7de22c7ac38ad92e78214231a6054019521bfab943c2bfd5ddfb9e8ad9255 F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 75a9116e98b9ac5c1a4c62a01143a016d9ba6a0b495ff7af7468c11947a3e888 -R 7f21190d047eb5dd5ac5fcbb3009e4d3 +P a3d14e61ca22167296fee125a3e9aa63413408955e03bb3f9d85fa9f22df1b79 +R 4bae6c9d6bdd8a980fce4f657c738433 U drh -Z fd007c71d1edd8db14c7de90c355f1d6 +Z f042afe955449d12af108738d6fffc40 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 55b041541b..71af4118a6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a3d14e61ca22167296fee125a3e9aa63413408955e03bb3f9d85fa9f22df1b79 \ No newline at end of file +34c2f7b237fa4e0e1cd94fb9c44ebe194b86b88dc575055cc46c7f3695d02756 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 2883653317..4c9ba86b12 100644 --- a/src/where.c +++ b/src/where.c @@ -4016,6 +4016,9 @@ static int whereLoopAddOr( pItem = pWInfo->pTabList->a + pNew->iTab; iCur = pItem->iCursor; + /* The multi-index OR optimization does not work for RIGHT and FULL JOIN */ + if( pItem->fg.jointype & JT_RIGHT ) return SQLITE_OK; + for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 From 949e2ab49a8a815796d491506651043dd7d5fb55 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 12 Apr 2022 18:04:29 +0000 Subject: [PATCH 27/31] Factor out the RIGHT JOIN non-matched row loop from sqlite3WhereEnd(). This reduces the register pressure on that routine and helps it to run faster in the common case where there is no RIGHT JOIN. FossilOrigin-Name: beeecf1604d4fb11e45058f48cb2289c6542e0bc218d63a245198113d8d5476b --- manifest | 16 +++++------ manifest.uuid | 2 +- src/where.c | 59 +------------------------------------- src/whereInt.h | 5 ++++ src/wherecode.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 67 deletions(-) diff --git a/manifest b/manifest index b250272df0..a4942b77dc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\slatest\senhancements\sfrom\strunk\sinto\sthe\sright-join\sbranch. -D 2022-04-12T17:43:30.239 +C Factor\sout\sthe\sRIGHT\sJOIN\snon-matched\srow\sloop\sfrom\ssqlite3WhereEnd().\s\sThis\nreduces\sthe\sregister\spressure\son\sthat\sroutine\sand\shelps\sit\sto\srun\sfaster\nin\sthe\scommon\scase\swhere\sthere\sis\sno\sRIGHT\sJOIN. +D 2022-04-12T18:04:29.831 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,9 +639,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 5473af25fd2acd2898574950f51e4eaec77d57c450c0d3339905f3db42c6bb30 -F src/whereInt.h cd6bddac3a26640b92d86e2b45ecc6e82d663cbcac6fd5d6d9690dfb280b1668 -F src/wherecode.c bdf7de22c7ac38ad92e78214231a6054019521bfab943c2bfd5ddfb9e8ad9255 +F src/where.c 4176c858089e521de3f0961751016dc23314bd8bc5ae382ef2619eb38f6b968e +F src/whereInt.h ea1e4b6639c4c32246f4c54b733143df76109894adf08bedee4f3999ece62c2d +F src/wherecode.c 3b0cfb2f794ae3f84c01c6d1c38ccd99886c79caab5c18550b1781ccfc27aa9c F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5 F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 34c2f7b237fa4e0e1cd94fb9c44ebe194b86b88dc575055cc46c7f3695d02756 bff4f083eb1c35544988493a5d73a42e646c4250b841f5aae38c2183f0867a0e -R 6edf425faad4274a6a777cbfb5cf556e +P b3e57ba120067c79e0398e39da9f00ecb11a5e18c36479da4c36a39e88a78a27 +R bf3e23f39f0d1aa0a416881bc1478c40 U drh -Z d12d0f4af27fba9957f9dda2ef72c12a +Z ccf3d060da235adb8537400c4c3b77af # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 6963963ddb..4182150ca6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b3e57ba120067c79e0398e39da9f00ecb11a5e18c36479da4c36a39e88a78a27 \ No newline at end of file +beeecf1604d4fb11e45058f48cb2289c6542e0bc218d63a245198113d8d5476b \ No newline at end of file diff --git a/src/where.c b/src/where.c index 4c9ba86b12..836b7d6dc9 100644 --- a/src/where.c +++ b/src/where.c @@ -6174,64 +6174,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ ** all of the columns of the left operand set to NULL. */ if( pLevel->pRJ ){ - WhereRightJoin *pRJ = pLevel->pRJ; - Expr *pSubWhere = 0; - WhereClause *pWC = &pWInfo->sWC; - WhereInfo *pSubWInfo; - SrcList sFrom; - Bitmask mAll = 0; - for(k=0; ka[k].pWLoop->maskSelf; - sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); - iIdxCur = pWInfo->a[k].iIdxCur; - if( iIdxCur ){ - sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur); - } - } - mAll |= pLoop->maskSelf; - for(k=0; knTerm; k++){ - WhereTerm *pTerm = &pWC->a[k]; - if( pTerm->wtFlags & TERM_VIRTUAL ) break; - if( pTerm->prereqAll & ~mAll ) continue; - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin) ) continue; - pSubWhere = sqlite3ExprAnd(pParse, pSubWhere, - sqlite3ExprDup(db, pTerm->pExpr, 0)); - } - sFrom.nSrc = 1; - sFrom.nAlloc = 1; - memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem)); - sFrom.a[0].fg.jointype = 0; - ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTab->zName)); - pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0, - WHERE_RIGHT_JOIN, 0); - if( pSubWInfo ){ - int iCur = pLevel->iTabCur; - int r = ++pParse->nMem; - int nPk; - int jmp; - int addrCont = sqlite3WhereContinueLabel(pSubWInfo); - if( HasRowid(pTab) ){ - sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r); - nPk = 1; - }else{ - int iPk; - Index *pPk = sqlite3PrimaryKeyIndex(pTab); - nPk = pPk->nKeyCol; - pParse->nMem += nPk - 1; - for(iPk=0; iPkaiColumn[iPk]; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); - } - } - jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk); - sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk); - sqlite3VdbeJumpHere(v, jmp); - sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn); - sqlite3WhereEnd(pSubWInfo); - } - sqlite3ExprDelete(pParse->db, pSubWhere); - ExplainQueryPlanPop(pParse); + sqlite3WhereRightJoinLoop(pWInfo, i, pLevel); continue; } diff --git a/src/whereInt.h b/src/whereInt.h index 6be8234e27..c8a188f80c 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -565,6 +565,11 @@ Bitmask sqlite3WhereCodeOneLoopStart( WhereLevel *pLevel, /* The current level pointer */ Bitmask notReady /* Which tables are currently available */ ); +SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( + WhereInfo *pWInfo, + int iLevel, + WhereLevel *pLevel +); /* whereexpr.c: */ void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); diff --git a/src/wherecode.c b/src/wherecode.c index 410d6f206e..d2cb85aee7 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2786,3 +2786,79 @@ Bitmask sqlite3WhereCodeOneLoopStart( #endif return pLevel->notReady; } + +/* +** Generate the code for the loop that finds all non-matched terms +** for a RIGHT JOIN. +*/ +SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( + WhereInfo *pWInfo, + int iLevel, + WhereLevel *pLevel +){ + Parse *pParse = pWInfo->pParse; + Vdbe *v = pParse->pVdbe; + WhereRightJoin *pRJ = pLevel->pRJ; + Expr *pSubWhere = 0; + WhereClause *pWC = &pWInfo->sWC; + WhereInfo *pSubWInfo; + WhereLoop *pLoop = pLevel->pWLoop; + SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; + SrcList sFrom; + Bitmask mAll = 0; + int k; + + for(k=0; ka[k].pWLoop->maskSelf; + sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); + iIdxCur = pWInfo->a[k].iIdxCur; + if( iIdxCur ){ + sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur); + } + } + mAll |= pLoop->maskSelf; + for(k=0; knTerm; k++){ + WhereTerm *pTerm = &pWC->a[k]; + if( pTerm->wtFlags & TERM_VIRTUAL ) break; + if( pTerm->prereqAll & ~mAll ) continue; + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin) ) continue; + pSubWhere = sqlite3ExprAnd(pParse, pSubWhere, + sqlite3ExprDup(pParse->db, pTerm->pExpr, 0)); + } + sFrom.nSrc = 1; + sFrom.nAlloc = 1; + memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem)); + sFrom.a[0].fg.jointype = 0; + ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName)); + pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0, + WHERE_RIGHT_JOIN, 0); + if( pSubWInfo ){ + int iCur = pLevel->iTabCur; + int r = ++pParse->nMem; + int nPk; + int jmp; + int addrCont = sqlite3WhereContinueLabel(pSubWInfo); + Table *pTab = pTabItem->pTab; + if( HasRowid(pTab) ){ + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r); + nPk = 1; + }else{ + int iPk; + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + nPk = pPk->nKeyCol; + pParse->nMem += nPk - 1; + for(iPk=0; iPkaiColumn[iPk]; + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); + } + } + jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk); + sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk); + sqlite3VdbeJumpHere(v, jmp); + sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn); + sqlite3WhereEnd(pSubWInfo); + } + sqlite3ExprDelete(pParse->db, pSubWhere); + ExplainQueryPlanPop(pParse); +} From 0879d5f9e04b3f309d8f9b669d29b12608052ebb Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 12 Apr 2022 18:40:14 +0000 Subject: [PATCH 28/31] For the bad join type error message "unknown or unsupported join type" remove the "or unsupported" clause, because we now support all valid join types. FossilOrigin-Name: ab0a0562dd3594cf50ee56f6b3a5847fa5dcadf69146d560e3e7a95651b8f405 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/select.c | 2 +- test/join.test | 12 ++++++------ test/vtab6.test | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index a4942b77dc..8fb8878ffd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Factor\sout\sthe\sRIGHT\sJOIN\snon-matched\srow\sloop\sfrom\ssqlite3WhereEnd().\s\sThis\nreduces\sthe\sregister\spressure\son\sthat\sroutine\sand\shelps\sit\sto\srun\sfaster\nin\sthe\scommon\scase\swhere\sthere\sis\sno\sRIGHT\sJOIN. -D 2022-04-12T18:04:29.831 +C For\sthe\sbad\sjoin\stype\serror\smessage\s"unknown\sor\sunsupported\sjoin\stype"\nremove\sthe\s"or\sunsupported"\sclause,\sbecause\swe\snow\ssupport\sall\svalid\sjoin\ntypes. +D 2022-04-12T18:40:14.753 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -552,7 +552,7 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c fdec126045cf441883836756d6d949367e8a2945c53fa6e98d6c51a08d7efc81 +F src/select.c 31148fafdfb7bac67389f3db8eba9ecaee1d8f41105d87d9cc53a5009ebedad5 F src/shell.c.in eb7f10d5e2c47bd014d92ec5db1def21fcc1ed56ffaaa4ee715b6c37c370b47f F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1140,7 +1140,7 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9 -F test/join.test a1832675aa30f2b422ff934b553e30294ca899484710242a2119ebf21f20a66a +F test/join.test d9c8cb2769b147b223f9dff8f694f56cfd9d0c097f8af9c7c6562b2e4ad256b5 F test/join2.test 9751dac84a46a960281ca372fe2350252ef40286dde3c542540bccdea9a2d5c6 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 @@ -1712,7 +1712,7 @@ F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c840 F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3 F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391 -F test/vtab6.test 5f5c10c694763d9cb438ec12aab7d6899f0bd6e2fa120551e11dea3daa8063ca +F test/vtab6.test fa609a4af96da30beceefa3cb624abe9be38c4747ab373d98179b24027d6b798 F test/vtab7.test 70c6f4a1d6177144a8236e4172d5fba92e683440374664ad1f04851fbb335d3c F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583 F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b @@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P b3e57ba120067c79e0398e39da9f00ecb11a5e18c36479da4c36a39e88a78a27 -R bf3e23f39f0d1aa0a416881bc1478c40 +P beeecf1604d4fb11e45058f48cb2289c6542e0bc218d63a245198113d8d5476b +R 94bd645abdceb148bbc9cc013d9cfae2 U drh -Z ccf3d060da235adb8537400c4c3b77af +Z 54dfd3d74916a39a639c494027c1dd34 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4182150ca6..f63e3cd4d9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -beeecf1604d4fb11e45058f48cb2289c6542e0bc218d63a245198113d8d5476b \ No newline at end of file +ab0a0562dd3594cf50ee56f6b3a5847fa5dcadf69146d560e3e7a95651b8f405 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 7230ff90c9..af3c30bfe1 100644 --- a/src/select.c +++ b/src/select.c @@ -298,7 +298,7 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){ const char *zSp2 = " "; if( pB==0 ){ zSp1++; } if( pC==0 ){ zSp2++; } - sqlite3ErrorMsg(pParse, "unknown or unsupported join type: " + sqlite3ErrorMsg(pParse, "unknown join type: " "%T%s%T%s%T", pA, zSp1, pB, zSp2, pC); jointype = JT_INNER; } diff --git a/test/join.test b/test/join.test index fdacfc25c2..d6e775436b 100644 --- a/test/join.test +++ b/test/join.test @@ -332,32 +332,32 @@ do_test join-3.7 { catchsql { SELECT * FROM t1 INNER OUTER JOIN t2; } -} {1 {unknown or unsupported join type: INNER OUTER}} +} {1 {unknown join type: INNER OUTER}} do_test join-3.8 { catchsql { SELECT * FROM t1 INNER OUTER CROSS JOIN t2; } -} {1 {unknown or unsupported join type: INNER OUTER CROSS}} +} {1 {unknown join type: INNER OUTER CROSS}} do_test join-3.9 { catchsql { SELECT * FROM t1 OUTER NATURAL INNER JOIN t2; } -} {1 {unknown or unsupported join type: OUTER NATURAL INNER}} +} {1 {unknown join type: OUTER NATURAL INNER}} do_test join-3.10 { catchsql { SELECT * FROM t1 LEFT BOGUS JOIN t2; } -} {1 {unknown or unsupported join type: LEFT BOGUS}} +} {1 {unknown join type: LEFT BOGUS}} do_test join-3.11 { catchsql { SELECT * FROM t1 INNER BOGUS CROSS JOIN t2; } -} {1 {unknown or unsupported join type: INNER BOGUS CROSS}} +} {1 {unknown join type: INNER BOGUS CROSS}} do_test join-3.12 { catchsql { SELECT * FROM t1 NATURAL AWK SED JOIN t2; } -} {1 {unknown or unsupported join type: NATURAL AWK SED}} +} {1 {unknown join type: NATURAL AWK SED}} do_test join-4.1 { execsql { diff --git a/test/vtab6.test b/test/vtab6.test index d8016e02f4..2ee5e27051 100644 --- a/test/vtab6.test +++ b/test/vtab6.test @@ -281,12 +281,12 @@ do_test vtab6-3.7 { catchsql { SELECT * FROM t1 INNER OUTER JOIN t2; } -} {1 {unknown or unsupported join type: INNER OUTER}} +} {1 {unknown join type: INNER OUTER}} do_test vtab6-3.7 { catchsql { SELECT * FROM t1 LEFT BOGUS JOIN t2; } -} {1 {unknown or unsupported join type: LEFT BOGUS}} +} {1 {unknown join type: LEFT BOGUS}} do_test vtab6-4.1 { execsql { From f7309bce1050a416e0ed1f4b375149a311abe960 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 12 Apr 2022 20:20:54 +0000 Subject: [PATCH 29/31] Ensure that the JT_LTORJ bit in the SrcItem.fg.jointype is preserved during query flattening. FossilOrigin-Name: 61259050152321bc57dbdfdc3edcabb4f18c021b1ee0491c1e04ae24c7a59d89 --- manifest | 13 +++++++------ manifest.uuid | 2 +- src/select.c | 3 ++- test/join8.test | 24 ++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 test/join8.test diff --git a/manifest b/manifest index 8fb8878ffd..06139b2324 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C For\sthe\sbad\sjoin\stype\serror\smessage\s"unknown\sor\sunsupported\sjoin\stype"\nremove\sthe\s"or\sunsupported"\sclause,\sbecause\swe\snow\ssupport\sall\svalid\sjoin\ntypes. -D 2022-04-12T18:40:14.753 +C Ensure\sthat\sthe\sJT_LTORJ\sbit\sin\sthe\sSrcItem.fg.jointype\sis\spreserved\sduring\nquery\sflattening. +D 2022-04-12T20:20:54.995 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -552,7 +552,7 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 31148fafdfb7bac67389f3db8eba9ecaee1d8f41105d87d9cc53a5009ebedad5 +F src/select.c d48e4ddfd0ff34caca8650a668eb3c9ba75bab21264026f0e9a9c2271334090c F src/shell.c.in eb7f10d5e2c47bd014d92ec5db1def21fcc1ed56ffaaa4ee715b6c37c370b47f F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1147,6 +1147,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test c4df54e2e204d7f1417bfbdd21ca324b4b07415c647595cc47798eacfddc96d3 F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/join7.test e5c9b1b729d7e1d0b4195e99833e0ff0cf2d88e7fdd32b49af1044f4c76f72d9 +F test/join8.test 72248c33b44f8fc8614c739eff176fd8e18ffab04896b9ce6fd7933854dd7d25 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1946,8 +1947,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P beeecf1604d4fb11e45058f48cb2289c6542e0bc218d63a245198113d8d5476b -R 94bd645abdceb148bbc9cc013d9cfae2 +P ab0a0562dd3594cf50ee56f6b3a5847fa5dcadf69146d560e3e7a95651b8f405 +R e0fbee6d64529aa79fe75ea2bbc77de8 U drh -Z 54dfd3d74916a39a639c494027c1dd34 +Z a261d34a7d2a2349b187bf56d06e0666 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f63e3cd4d9..ef1dbb8c11 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ab0a0562dd3594cf50ee56f6b3a5847fa5dcadf69146d560e3e7a95651b8f405 \ No newline at end of file +61259050152321bc57dbdfdc3edcabb4f18c021b1ee0491c1e04ae24c7a59d89 \ No newline at end of file diff --git a/src/select.c b/src/select.c index af3c30bfe1..2e5c1ac97a 100644 --- a/src/select.c +++ b/src/select.c @@ -4447,7 +4447,8 @@ static int flattenSubquery( iNewParent = pSubSrc->a[i].iCursor; memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); } - pSrc->a[iFrom].fg.jointype = jointype | ltorj; + pSrc->a[iFrom].fg.jointype &= JT_LTORJ; + pSrc->a[iFrom].fg.jointype |= jointype | ltorj; /* Now begin substituting subquery result set expressions for ** references to the iParent in the outer query. diff --git a/test/join8.test b/test/join8.test new file mode 100644 index 0000000000..0854d97292 --- /dev/null +++ b/test/join8.test @@ -0,0 +1,24 @@ +# 2022-04-12 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests for RIGHT and FULL OUTER JOINs. + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +db null NULL +do_execsql_test join8-10 { + CREATE TABLE t1(a,b,c); + CREATE TABLE t2(x,y); + CREATE INDEX t2x ON t2(x); + SELECT avg(DISTINCT b) FROM (SELECT * FROM t2 LEFT RIGHT JOIN t1 ON c); +} {NULL} +finish_test From 146e64d2e4f9ef6e3ce55eb87ebaeca794ec9396 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 13 Apr 2022 01:52:32 +0000 Subject: [PATCH 30/31] Add missing VdbeCoverage() macros on new branch byte-code opcodes. FossilOrigin-Name: 218c7167e562f5c327124f02a92de85079315320a221fb0508310d927596b14c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/wherecode.c | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 06139b2324..e1594d4e39 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sthat\sthe\sJT_LTORJ\sbit\sin\sthe\sSrcItem.fg.jointype\sis\spreserved\sduring\nquery\sflattening. -D 2022-04-12T20:20:54.995 +C Add\smissing\sVdbeCoverage()\smacros\son\snew\sbranch\sbyte-code\sopcodes. +D 2022-04-13T01:52:32.481 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -641,7 +641,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c 4176c858089e521de3f0961751016dc23314bd8bc5ae382ef2619eb38f6b968e F src/whereInt.h ea1e4b6639c4c32246f4c54b733143df76109894adf08bedee4f3999ece62c2d -F src/wherecode.c 3b0cfb2f794ae3f84c01c6d1c38ccd99886c79caab5c18550b1781ccfc27aa9c +F src/wherecode.c e0f7b26a9c2de2cbaa635e5c1ef47b9c22250b0245a14a4b785ff4c61215fa13 F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5 F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1947,8 +1947,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ab0a0562dd3594cf50ee56f6b3a5847fa5dcadf69146d560e3e7a95651b8f405 -R e0fbee6d64529aa79fe75ea2bbc77de8 +P 61259050152321bc57dbdfdc3edcabb4f18c021b1ee0491c1e04ae24c7a59d89 +R 3ebbb5ad8363d344d9fe2023b4974777 U drh -Z a261d34a7d2a2349b187bf56d06e0666 +Z 8ce073acecbbfacea87c4e9aefc95045 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ef1dbb8c11..667dee749c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -61259050152321bc57dbdfdc3edcabb4f18c021b1ee0491c1e04ae24c7a59d89 \ No newline at end of file +218c7167e562f5c327124f02a92de85079315320a221fb0508310d927596b14c \ No newline at end of file diff --git a/src/wherecode.c b/src/wherecode.c index d2cb85aee7..a438db5301 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2854,7 +2854,9 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( } } jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk); + VdbeCoverage(v); sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk); + VdbeCoverage(v); sqlite3VdbeJumpHere(v, jmp); sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn); sqlite3WhereEnd(pSubWInfo); From 12c35ec322dc2b394a3a6d8b3997ef60574414a0 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 13 Apr 2022 12:12:01 +0000 Subject: [PATCH 31/31] The rows of a RIGHT JOIN might come out in any arbitrary order. So disable the ORDER-BY/GROUP-BY optimizations if a RIGHT JOIN is involved. FossilOrigin-Name: d168f245ecf497368feea4697769930c00420ef47a584904dac85371b61fb78a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 5 +++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index e1594d4e39..4f666e4221 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\smissing\sVdbeCoverage()\smacros\son\snew\sbranch\sbyte-code\sopcodes. -D 2022-04-13T01:52:32.481 +C The\srows\sof\sa\sRIGHT\sJOIN\smight\scome\sout\sin\sany\sarbitrary\sorder.\s\sSo\sdisable\nthe\sORDER-BY/GROUP-BY\soptimizations\sif\sa\sRIGHT\sJOIN\sis\sinvolved. +D 2022-04-13T12:12:01.948 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 4176c858089e521de3f0961751016dc23314bd8bc5ae382ef2619eb38f6b968e +F src/where.c 793d09ef0d824efb953cdaff59102dcdd5390f8c59d1d5119ddfd26dcf5cd957 F src/whereInt.h ea1e4b6639c4c32246f4c54b733143df76109894adf08bedee4f3999ece62c2d F src/wherecode.c e0f7b26a9c2de2cbaa635e5c1ef47b9c22250b0245a14a4b785ff4c61215fa13 F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5 @@ -1947,8 +1947,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 61259050152321bc57dbdfdc3edcabb4f18c021b1ee0491c1e04ae24c7a59d89 -R 3ebbb5ad8363d344d9fe2023b4974777 +P 218c7167e562f5c327124f02a92de85079315320a221fb0508310d927596b14c +R ad78fe8a972588635938e37b65ef3078 U drh -Z 8ce073acecbbfacea87c4e9aefc95045 +Z 45a91ae6630079ad59ce11d407cbe16e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 667dee749c..66ed4d8aa0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -218c7167e562f5c327124f02a92de85079315320a221fb0508310d927596b14c \ No newline at end of file +d168f245ecf497368feea4697769930c00420ef47a584904dac85371b61fb78a \ No newline at end of file diff --git a/src/where.c b/src/where.c index 836b7d6dc9..1ce569d37b 100644 --- a/src/where.c +++ b/src/where.c @@ -5900,6 +5900,11 @@ WhereInfo *sqlite3WhereBegin( sqlite3VdbeSetP4KeyInfo(pParse, pPk); } pLoop->wsFlags &= ~WHERE_IDX_ONLY; + /* The nature of RIGHT JOIN processing is such that it messes up + ** the output order. So omit any ORDER BY/GROUP BY elimination + ** optimizations. We need to do an actual sort for RIGHT JOIN. */ + pWInfo->nOBSat = 0; + pWInfo->eDistinct = WHERE_DISTINCT_UNORDERED; } } pWInfo->iTop = sqlite3VdbeCurrentAddr(v);