mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Improved technique for parsing the ON and USING clauses of a join is faster
and uses less memory. FossilOrigin-Name: 158156a3e3d50042cafc75dea3aaaa68b1f2efb9c3d178518ea6e68e32e0d21c
This commit is contained in:
38
manifest
38
manifest
@ -1,5 +1,5 @@
|
||||
C Faster\sparsing\sof\sthe\sFROM\sclause\sin\sjoins\sfor\sthe\scommon\scase\swhere\sthere\nis\sno\sINDEXED\sBY\sclause.
|
||||
D 2022-04-06T19:46:20.282
|
||||
C Improved\stechnique\sfor\sparsing\sthe\sON\sand\sUSING\sclauses\sof\sa\sjoin\sis\sfaster\nand\suses\sless\smemory.
|
||||
D 2022-04-07T01:11:13.364
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -485,9 +485,9 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 006325f8844c65d885b3ba469b4c08d9dd0cd3e9ec481d5bcff621f224cb2302
|
||||
F src/alter.c 9395ece9850ad57c6fbb453aeb5185be4bae3b159c4b37611425c565124ee849
|
||||
F src/analyze.c 3a119baeb03053c154029877454d41bb8fd79d4d1eb583392f2289b3554a75bc
|
||||
F src/attach.c f26d400f3ffe2cdca01406bca70e5f58c5488bf165b4fc37c228136dfcf1b583
|
||||
F src/attach.c 4431f82f0247bf3aaf91589acafdff77d1882235c95407b36da1585c765fbbc8
|
||||
F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
|
||||
F src/backup.c a2891172438e385fdbe97c11c9745676bec54f518d4447090af97189fd8e52d7
|
||||
F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d
|
||||
@ -495,15 +495,15 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 45161c2d5c9527b9c9bbfd7478daf3e0a619cf4bbe3278378aaea3d4b4e4f5b5
|
||||
F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22
|
||||
F src/btreeInt.h 8ce1332edd89dfd2461d561ac10a0ab5601c8e06200cb5230596c3caaf54482e
|
||||
F src/build.c 4a265d49342cefc95ae739982a6197eae04a9258151f8e0bbe3ff8ab56aab801
|
||||
F src/build.c ff119be98394a65bc8be7afc39d4a791a66f03a778d396de3ec456f5dfaf39e8
|
||||
F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 026dbdcdbd8c3cde98a88483ee88310ff43150ab164ad768f12cc700a11495ad
|
||||
F src/date.c 15082566229d4b1e5f24fdb490bf9bcc68824b911d70e3573ef075a1b9e2d26f
|
||||
F src/dbpage.c a70be9a4879ac5392673a1050d526a72b8b2f9938df7049f65348566a2637db3
|
||||
F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d
|
||||
F src/delete.c dafdc71a097f84fbbf66164d8842ebcb9bacf74e069658001fd70b62ee0acbdb
|
||||
F src/expr.c 3cdb00b6c15f815c94836e7b4474b675155d1279e64804f6ab5816188a9b05b6
|
||||
F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce
|
||||
F src/expr.c 5e247a8dfabb92e9fd10b78a675dc5d25430433dfd9e316471b4447b548635ba
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 94927f9b46d72a9cb858c208febf04ceb0a3270c5fa5fd0b7f436cf16e09f72a
|
||||
F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761
|
||||
@ -541,7 +541,7 @@ F src/os_win.c a8ea80037e81127ca01959daa87387cc135f325c88dc745376c4f760de852a10
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 42120492784fc9bcd9082b5c9b5e329b7318c357f9f3574a1bbfcf7418910356
|
||||
F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3
|
||||
F src/parse.y a2786e72c5ce8a91df7dbad8306616d822ba7093f87cfa0d09fe351b83fa5828
|
||||
F src/parse.y afae75ce87abc2d87a8277ed811bc09d04da4b1760ace3e845cb1553f3a3dd0a
|
||||
F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65
|
||||
@ -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 ea935b87d6fb36c78b70cdc7b28561dc8f33f2ef37048389549c7b5ef9b0ba5e
|
||||
F src/resolve.c 18d99e7146852d6064559561769fcca0743eb32b14a97da6dbed373a30ee0e76
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c c3dab5fb5d25934bc384b0ffcbc1ab576ad8ce4a494a5eed3e1367c79c1416b1
|
||||
F src/select.c d6c04eb93395024af80f61a8c278a33c2a0333aeb7d57bb6aa737a6f1c4af4b8
|
||||
F src/shell.c.in 18832612e74c92bbd25d88e1f92685f66589262f68cca1001d2a43bd6dd0ed60
|
||||
F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e
|
||||
F src/sqliteInt.h f9484b03c663a20ac998627a416d8ef368950596e52e1186c5188ee93b695285
|
||||
F src/sqliteInt.h dbd5537c36a6b01fd67890487c3f7da468f16845500c115886f20adec06869ca
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@ -642,7 +642,7 @@ F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
|
||||
F src/where.c a2483d4fe7cde88638cd3140dd5d6ee3dc0c80d3b3fe20322a8d08dc451f97ae
|
||||
F src/whereInt.h 15d2975c3b4c193c78c26674400a840da8647fe1777ae3b026e2d15937b38a03
|
||||
F src/wherecode.c 555f598a9ddad81761f084710fdb4f8733fe31bc14cd6b19f8ca4274a7eaa04c
|
||||
F src/whereexpr.c 2a71f5491798460c9590317329234d332d9eb1717cba4f3403122189a75c465e
|
||||
F src/whereexpr.c 612f58f5f6e3e3bb94d10e2c56672ade8bbf94d4a928d3edb4e84e2ed3c00dca
|
||||
F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
|
||||
@ -878,7 +878,7 @@ F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5e
|
||||
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
|
||||
F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164
|
||||
F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8
|
||||
F test/e_select.test c5425a423da06d0494119db8361ebfc6de302929f7546ca596d56224137e0360
|
||||
F test/e_select.test 9b7ca08975c5444844b35ee60e09f973787a9f3317719715e8e6669abdf6aba2
|
||||
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
||||
F test/e_totalchanges.test c927f7499dc3aa28b9b556b7d6d115a2f0fe41f012b128d16bf1f3b30e9b41e4
|
||||
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
|
||||
@ -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 25cf0ac11c3b81fedfd166f9062166bdb39dea92f5a7c16cacbf6dc1f7f67020
|
||||
F test/join.test 85e9c88bf4700b45a48a6362cd47e0c0aefc572629827c31aa58a5978cabdfc5
|
||||
F test/join2.test 9bdc615841b91c97a16d68bad9508aea11fa0c6b34e5689847bcc4dac70e4990
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
@ -1628,7 +1628,7 @@ F test/tkt3911.test 74cd324f3ba653040cc6d94cc4857b290d12d633
|
||||
F test/tkt3918.test ea78bf164e4d55cbde0d83c671ef6fbe930a0032
|
||||
F test/tkt3922.test f26be40ab4fe6c00795629bd2006d96e270d9b1a
|
||||
F test/tkt3929.test cdf67acf5aa936ec4ffead81db87f8a71fe40e59
|
||||
F test/tkt3935.test e15261fedb9e30a4305a311da614a5d8e693c767
|
||||
F test/tkt3935.test 1ffcfffc148df51c8a01d1b3efae2d6c44cbeb0af1e0c5b88f4afe9a86d4ddb6
|
||||
F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da
|
||||
F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
|
||||
F test/tkt4018.test 18dbc6617f7a4b90e938d1bd6d26ad18daafaf08
|
||||
@ -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 82d5bb8fd3c0643102c1209e9ea353b168b7eb9c8db4406ab2ee2cbbdaead62c
|
||||
F test/vtab6.test 7167e8e526bc2e719e7818e18b2fd7bb8c455fa018b74e611943a86782e10125
|
||||
F test/vtab7.test 70c6f4a1d6177144a8236e4172d5fba92e683440374664ad1f04851fbb335d3c
|
||||
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
|
||||
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
|
||||
@ -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 84c239a071cfaf8af107646f01ef269e2915fd2384e95927d484f2e408ba6bbf
|
||||
R c85c19380822b3766b7352b207ade832
|
||||
P 848b7a0ea99ddc52091b78313f018c07d00a0e28aa6da8c1cae709c1d03468fe
|
||||
R f48eedde1f7cf0c2cbb2f0efc2fa0619
|
||||
U drh
|
||||
Z f7c9c9fec330149ee82e748d50b754aa
|
||||
Z 3a4c374a49d27fcf334d19f314ba8d15
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
848b7a0ea99ddc52091b78313f018c07d00a0e28aa6da8c1cae709c1d03468fe
|
||||
158156a3e3d50042cafc75dea3aaaa68b1f2efb9c3d178518ea6e68e32e0d21c
|
10
src/alter.c
10
src/alter.c
@ -858,13 +858,12 @@ static void unmapColumnIdlistNames(
|
||||
Parse *pParse,
|
||||
const IdList *pIdList
|
||||
){
|
||||
if( pIdList ){
|
||||
int ii;
|
||||
assert( pIdList!=0 );
|
||||
for(ii=0; ii<pIdList->nId; ii++){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Walker callback used by sqlite3RenameExprUnmap().
|
||||
@ -890,8 +889,11 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
||||
SrcList *pSrc = p->pSrc;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
|
||||
sqlite3WalkExpr(pWalker, pSrc->a[i].pOn);
|
||||
unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing);
|
||||
if( pSrc->a[i].fg.isUsing==0 ){
|
||||
sqlite3WalkExpr(pWalker, pSrc->a[i].u3.pOn);
|
||||
}else{
|
||||
unmapColumnIdlistNames(pParse, pSrc->a[i].u3.pUsing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,7 +480,11 @@ static int fixSelectCb(Walker *p, Select *pSelect){
|
||||
pItem->fg.fromDDL = 1;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( sqlite3WalkExpr(&pFix->w, pList->a[i].pOn) ) return WRC_Abort;
|
||||
if( pList->a[i].fg.isUsing==0
|
||||
&& sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn)
|
||||
){
|
||||
return WRC_Abort;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if( pSelect->pWith ){
|
||||
|
31
src/build.c
31
src/build.c
@ -4710,7 +4710,7 @@ void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
|
||||
*/
|
||||
int sqlite3IdListIndex(IdList *pList, const char *zName){
|
||||
int i;
|
||||
if( pList==0 ) return -1;
|
||||
assert( pList!=0 );
|
||||
for(i=0; i<pList->nId; i++){
|
||||
if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i;
|
||||
}
|
||||
@ -4913,8 +4913,11 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
||||
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
|
||||
sqlite3DeleteTable(db, pItem->pTab);
|
||||
if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
|
||||
if( pItem->pOn ) sqlite3ExprDelete(db, pItem->pOn);
|
||||
if( pItem->pUsing ) sqlite3IdListDelete(db, pItem->pUsing);
|
||||
if( pItem->fg.isUsing ){
|
||||
sqlite3IdListDelete(db, pItem->u3.pUsing);
|
||||
}else if( pItem->u3.pOn ){
|
||||
sqlite3ExprDelete(db, pItem->u3.pOn);
|
||||
}
|
||||
}
|
||||
sqlite3DbFreeNN(db, pList);
|
||||
}
|
||||
@ -4942,14 +4945,13 @@ SrcList *sqlite3SrcListAppendFromTerm(
|
||||
Token *pDatabase, /* Name of the database containing pTable */
|
||||
Token *pAlias, /* The right-hand side of the AS subexpression */
|
||||
Select *pSubquery, /* A subquery used in place of a table name */
|
||||
Expr *pOn, /* The ON clause of a join */
|
||||
IdList *pUsing /* The USING clause of a join */
|
||||
OnOrUsing *pOnUsing /* Either the ON clause or the USING clause */
|
||||
){
|
||||
SrcItem *pItem;
|
||||
sqlite3 *db = pParse->db;
|
||||
if( !p && (pOn || pUsing) ){
|
||||
if( !p && pOnUsing!=0 && (pOnUsing->pOn || pOnUsing->pUsing) ){
|
||||
sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s",
|
||||
(pOn ? "ON" : "USING")
|
||||
(pOnUsing->pOn ? "ON" : "USING")
|
||||
);
|
||||
goto append_from_error;
|
||||
}
|
||||
@ -4970,14 +4972,21 @@ SrcList *sqlite3SrcListAppendFromTerm(
|
||||
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
|
||||
}
|
||||
pItem->pSelect = pSubquery;
|
||||
pItem->pOn = pOn;
|
||||
pItem->pUsing = pUsing;
|
||||
assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );
|
||||
assert( pItem->fg.isUsing==0 );
|
||||
if( pOnUsing==0 ){
|
||||
pItem->u3.pOn = 0;
|
||||
}else if( pOnUsing->pUsing ){
|
||||
pItem->fg.isUsing = 1;
|
||||
pItem->u3.pUsing = pOnUsing->pUsing;
|
||||
}else{
|
||||
pItem->u3.pOn = pOnUsing->pOn;
|
||||
}
|
||||
return p;
|
||||
|
||||
append_from_error:
|
||||
assert( p==0 );
|
||||
sqlite3ExprDelete(db, pOn);
|
||||
sqlite3IdListDelete(db, pUsing);
|
||||
sqlite3ClearOnOrUsing(db, pOnUsing);
|
||||
sqlite3SelectDelete(db, pSubquery);
|
||||
return 0;
|
||||
}
|
||||
|
@ -128,8 +128,8 @@ void sqlite3MaterializeView(
|
||||
assert( pFrom->nSrc==1 );
|
||||
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
|
||||
pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
|
||||
assert( pFrom->a[0].pOn==0 );
|
||||
assert( pFrom->a[0].pUsing==0 );
|
||||
assert( pFrom->a[0].fg.isUsing==0 );
|
||||
assert( pFrom->a[0].u3.pOn==0 );
|
||||
}
|
||||
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
|
||||
SF_IncludeHidden, pLimit);
|
||||
|
20
src/expr.c
20
src/expr.c
@ -1249,6 +1249,18 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
if( p ) sqlite3ExprDeleteNN(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear both elements of an OnOrUsing object
|
||||
*/
|
||||
void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
|
||||
if( p==0 ){
|
||||
/* Nothing to clear */
|
||||
}else if( p->pOn ){
|
||||
sqlite3ExprDeleteNN(db, p->pOn);
|
||||
}else if( p->pUsing ){
|
||||
sqlite3IdListDelete(db, p->pUsing);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Arrange to cause pExpr to be deleted when the pParse is deleted.
|
||||
@ -1671,8 +1683,12 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
|
||||
pTab->nTabRef++;
|
||||
}
|
||||
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
|
||||
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
|
||||
pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
|
||||
if( pOldItem->fg.isUsing ){
|
||||
assert( pNewItem->fg.isUsing );
|
||||
pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing);
|
||||
}else{
|
||||
pNewItem->u3.pOn = sqlite3ExprDup(db, pOldItem->u3.pOn, flags);
|
||||
}
|
||||
pNewItem->colUsed = pOldItem->colUsed;
|
||||
}
|
||||
return pNew;
|
||||
|
47
src/parse.y
47
src/parse.y
@ -570,7 +570,7 @@ selectnowith(A) ::= selectnowith(A) multiselect_op(Y) oneselect(Z). {
|
||||
Token x;
|
||||
x.n = 0;
|
||||
parserDoubleLinkSelect(pParse, pRhs);
|
||||
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
|
||||
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0);
|
||||
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
|
||||
}
|
||||
if( pRhs ){
|
||||
@ -695,30 +695,26 @@ stl_prefix(A) ::= seltablist(A) joinop(Y). {
|
||||
if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y;
|
||||
}
|
||||
stl_prefix(A) ::= . {A = 0;}
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U);
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) on_using(N). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N);
|
||||
}
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) indexed_by(I)
|
||||
on_opt(N) using_opt(U). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U);
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) indexed_by(I) on_using(N). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N);
|
||||
sqlite3SrcListIndexedBy(pParse, A, &I);
|
||||
}
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z)
|
||||
on_opt(N) using_opt(U). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U);
|
||||
seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N);
|
||||
sqlite3SrcListFuncArgs(pParse, A, E);
|
||||
}
|
||||
%ifndef SQLITE_OMIT_SUBQUERY
|
||||
seltablist(A) ::= stl_prefix(A) LP select(S) RP
|
||||
as(Z) on_opt(N) using_opt(U). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,N,U);
|
||||
seltablist(A) ::= stl_prefix(A) LP select(S) RP as(Z) on_using(N). {
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,&N);
|
||||
}
|
||||
seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP
|
||||
as(Z) on_opt(N) using_opt(U). {
|
||||
if( A==0 && Z.n==0 && N==0 && U==0 ){
|
||||
seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP as(Z) on_using(N). {
|
||||
if( A==0 && Z.n==0 && N.pOn==0 && N.pUsing==0 ){
|
||||
A = F;
|
||||
}else if( F->nSrc==1 ){
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,N,U);
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,&N);
|
||||
if( A ){
|
||||
SrcItem *pNew = &A->a[A->nSrc-1];
|
||||
SrcItem *pOld = F->a;
|
||||
@ -739,7 +735,7 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z)
|
||||
Select *pSubquery;
|
||||
sqlite3SrcListShiftJoinType(F);
|
||||
pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0);
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,N,U);
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,&N);
|
||||
}
|
||||
}
|
||||
%endif SQLITE_OMIT_SUBQUERY
|
||||
@ -797,13 +793,14 @@ joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
|
||||
//
|
||||
// INSERT INTO tab SELECT * FROM aaa JOIN bbb WHERE true ON CONFLICT ...
|
||||
//
|
||||
// The [AND] and [OR] precedence marks in the rules for on_opt cause the
|
||||
// The [AND] and [OR] precedence marks in the rules for on_using cause the
|
||||
// ON in this context to always be interpreted as belonging to the JOIN.
|
||||
//
|
||||
%type on_opt {Expr*}
|
||||
%destructor on_opt {sqlite3ExprDelete(pParse->db, $$);}
|
||||
on_opt(N) ::= ON expr(E). {N = E;}
|
||||
on_opt(N) ::= . [OR] {N = 0;}
|
||||
%type on_using {OnOrUsing}
|
||||
//%destructor on_using {sqlite3ClearOnOrUsing(pParse->db, &$$);}
|
||||
on_using(N) ::= ON expr(E). {N.pOn = E; N.pUsing = 0;}
|
||||
on_using(N) ::= USING LP idlist(L) RP. {N.pOn = 0; N.pUsing = L;}
|
||||
on_using(N) ::= . [OR] {N.pOn = 0; N.pUsing = 0;}
|
||||
|
||||
// Note that this block abuses the Token type just a little. If there is
|
||||
// no "INDEXED BY" clause, the returned token is empty (z==0 && n==0). If
|
||||
@ -822,12 +819,6 @@ indexed_opt(A) ::= indexed_by(A).
|
||||
indexed_by(A) ::= INDEXED BY nm(X). {A = X;}
|
||||
indexed_by(A) ::= NOT INDEXED. {A.z=0; A.n=1;}
|
||||
|
||||
%type using_opt {IdList*}
|
||||
%destructor using_opt {sqlite3IdListDelete(pParse->db, $$);}
|
||||
using_opt(U) ::= USING LP idlist(L) RP. {U = L;}
|
||||
using_opt(U) ::= . {U = 0;}
|
||||
|
||||
|
||||
%type orderby_opt {ExprList*}
|
||||
%destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);}
|
||||
|
||||
|
@ -123,12 +123,11 @@ static void resolveAlias(
|
||||
** zCol.
|
||||
*/
|
||||
static int nameInUsingClause(IdList *pUsing, const char *zCol){
|
||||
if( pUsing ){
|
||||
int k;
|
||||
assert( pUsing!=0 );
|
||||
for(k=0; k<pUsing->nId; k++){
|
||||
if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -346,7 +345,11 @@ static int lookupName(
|
||||
*/
|
||||
if( cnt==1 ){
|
||||
if( pItem->fg.jointype & JT_NATURAL ) continue;
|
||||
if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
|
||||
if( pItem->fg.isUsing
|
||||
&& nameInUsingClause(pItem->u3.pUsing, zCol)
|
||||
){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
pMatch = pItem;
|
||||
|
48
src/select.c
48
src/select.c
@ -468,7 +468,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
||||
** every column that the two tables have in common.
|
||||
*/
|
||||
if( pRight->fg.jointype & JT_NATURAL ){
|
||||
if( pRight->pOn || pRight->pUsing ){
|
||||
if( pRight->fg.isUsing || pRight->u3.pOn ){
|
||||
sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
|
||||
"an ON or USING clause", 0);
|
||||
return 1;
|
||||
@ -487,23 +487,6 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
||||
}
|
||||
}
|
||||
|
||||
/* Disallow both ON and USING clauses in the same join
|
||||
*/
|
||||
if( pRight->pOn && pRight->pUsing ){
|
||||
sqlite3ErrorMsg(pParse, "cannot have both ON and USING "
|
||||
"clauses in the same join");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Add the ON clause to the end of the WHERE clause, connected by
|
||||
** an AND operator.
|
||||
*/
|
||||
if( pRight->pOn ){
|
||||
if( isOuter ) sqlite3SetJoinExpr(pRight->pOn, pRight->iCursor);
|
||||
p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->pOn);
|
||||
pRight->pOn = 0;
|
||||
}
|
||||
|
||||
/* Create extra terms on the WHERE clause for each column named
|
||||
** in the USING clause. Example: If the two tables to be joined are
|
||||
** A and B and the USING clause names X, Y, and Z, then add this
|
||||
@ -511,8 +494,9 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
||||
** Report an error if any column mentioned in the USING clause is
|
||||
** not contained in both tables to be joined.
|
||||
*/
|
||||
if( pRight->pUsing ){
|
||||
IdList *pList = pRight->pUsing;
|
||||
if( pRight->fg.isUsing ){
|
||||
IdList *pList = pRight->u3.pUsing;
|
||||
assert( pList!=0 );
|
||||
for(j=0; j<pList->nId; j++){
|
||||
char *zName; /* Name of the term in the USING clause */
|
||||
int iLeft; /* Table on the left with matching column name */
|
||||
@ -532,6 +516,15 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
||||
isOuter, &p->pWhere);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the ON clause to the end of the WHERE clause, connected by
|
||||
** an AND operator.
|
||||
*/
|
||||
else if( pRight->u3.pOn ){
|
||||
if( isOuter ) sqlite3SetJoinExpr(pRight->u3.pOn, pRight->iCursor);
|
||||
p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->u3.pOn);
|
||||
pRight->u3.pOn = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -4222,7 +4215,7 @@ static int flattenSubquery(
|
||||
pSubitem->zName = 0;
|
||||
pSubitem->zAlias = 0;
|
||||
pSubitem->pSelect = 0;
|
||||
assert( pSubitem->pOn==0 );
|
||||
assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 );
|
||||
|
||||
/* If the sub-query is a compound SELECT statement, then (by restrictions
|
||||
** 17 and 18 above) it must be a UNION ALL and the parent query must
|
||||
@ -4366,9 +4359,10 @@ static int flattenSubquery(
|
||||
** outer query.
|
||||
*/
|
||||
for(i=0; i<nSubSrc; i++){
|
||||
sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing);
|
||||
assert( pSrc->a[i+iFrom].fg.isTabFunc==0 );
|
||||
pSrc->a[i+iFrom] = pSubSrc->a[i];
|
||||
SrcItem *pItem = &pSrc->a[i+iFrom];
|
||||
if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
|
||||
assert( pItem->fg.isTabFunc==0 );
|
||||
*pItem = pSubSrc->a[i];
|
||||
iNewParent = pSubSrc->a[i].iCursor;
|
||||
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
|
||||
}
|
||||
@ -5092,7 +5086,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
|
||||
if( pNew==0 ) return WRC_Abort;
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0,0);
|
||||
pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0);
|
||||
if( pNewSrc==0 ) return WRC_Abort;
|
||||
*pNew = *p;
|
||||
p->pSrc = pNewSrc;
|
||||
@ -5703,7 +5697,9 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
** table to the right of the join */
|
||||
continue;
|
||||
}
|
||||
if( sqlite3IdListIndex(pFrom->pUsing, zName)>=0 ){
|
||||
if( pFrom->fg.isUsing
|
||||
&& sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0
|
||||
){
|
||||
/* In a join with a USING clause, omit columns in the
|
||||
** using clause from the table on the right. */
|
||||
continue;
|
||||
|
@ -1191,6 +1191,7 @@ typedef struct Lookaside Lookaside;
|
||||
typedef struct LookasideSlot LookasideSlot;
|
||||
typedef struct Module Module;
|
||||
typedef struct NameContext NameContext;
|
||||
typedef struct OnOrUsing OnOrUsing;
|
||||
typedef struct Parse Parse;
|
||||
typedef struct ParseCleanup ParseCleanup;
|
||||
typedef struct PreUpdate PreUpdate;
|
||||
@ -3075,10 +3076,13 @@ struct SrcItem {
|
||||
unsigned fromDDL :1; /* Comes from sqlite_schema */
|
||||
unsigned isCte :1; /* This is a CTE */
|
||||
unsigned notCte :1; /* This item may not match a CTE */
|
||||
unsigned isUsing :1; /* u3.pUsing is valid */
|
||||
} fg;
|
||||
int iCursor; /* The VDBE cursor number used to access this table */
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
union {
|
||||
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
|
||||
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
|
||||
} u3;
|
||||
Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
|
||||
union {
|
||||
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
|
||||
@ -3090,6 +3094,15 @@ struct SrcItem {
|
||||
} u2;
|
||||
};
|
||||
|
||||
/*
|
||||
** The OnOrUsing object represents either an ON clause or a USING clause.
|
||||
** It can never be both at the same time, but it can be neither.
|
||||
*/
|
||||
struct OnOrUsing {
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
};
|
||||
|
||||
/*
|
||||
** The following structure describes the FROM clause of a SELECT statement.
|
||||
** Each table or subquery in the FROM clause is a separate element of
|
||||
@ -4610,13 +4623,14 @@ SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
|
||||
SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
|
||||
SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
|
||||
SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
|
||||
Token*, Select*, Expr*, IdList*);
|
||||
Token*, Select*, OnOrUsing*);
|
||||
void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
|
||||
void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
|
||||
int sqlite3IndexedByLookup(Parse *, SrcItem *);
|
||||
void sqlite3SrcListShiftJoinType(SrcList*);
|
||||
void sqlite3SrcListAssignCursors(Parse*, SrcList*);
|
||||
void sqlite3IdListDelete(sqlite3*, IdList*);
|
||||
void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*);
|
||||
void sqlite3SrcListDelete(sqlite3*, SrcList*);
|
||||
Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
|
||||
void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
|
||||
|
@ -951,7 +951,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
|
||||
int i;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
|
||||
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn);
|
||||
if( pSrc->a[i].fg.isUsing==0 ){
|
||||
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
|
||||
}
|
||||
if( pSrc->a[i].fg.isTabFunc ){
|
||||
mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg);
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ do_join_test e_select-0.1.3 {
|
||||
} {9}
|
||||
do_catchsql_test e_select-0.1.4 {
|
||||
SELECT count(*) FROM t1, t2 ON (t1.a=t2.a) USING (a)
|
||||
} {1 {cannot have both ON and USING clauses in the same join}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_catchsql_test e_select-0.1.5 {
|
||||
SELECT count(*) FROM t1, t2 USING (a) ON (t1.a=t2.a)
|
||||
} {1 {near "ON": syntax error}}
|
||||
|
@ -307,7 +307,7 @@ do_test join-3.3 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b);
|
||||
}
|
||||
} {1 {cannot have both ON and USING clauses in the same join}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_test join-3.4.1 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 JOIN t2 USING(a);
|
||||
|
@ -34,13 +34,13 @@ do_test tkt3935.3 {
|
||||
|
||||
do_test tkt3935.4 {
|
||||
catchsql { SELECT a FROM (t1) AS t ON b USING(a) }
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_test tkt3935.5 {
|
||||
catchsql { SELECT a FROM (t1) AS t ON b }
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
do_test tkt3935.6 {
|
||||
catchsql { SELECT a FROM (SELECT * FROM t1) AS t ON b USING(a) }
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_test tkt3935.7 {
|
||||
catchsql { SELECT a FROM (SELECT * FROM t1) AS t ON b }
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
@ -49,7 +49,7 @@ do_test tkt3935.8 {
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
do_test tkt3935.9 {
|
||||
catchsql { SELECT a FROM t1 AS t ON b USING(a) }
|
||||
} {1 {a JOIN clause is required before ON}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_test tkt3935.10 {
|
||||
catchsql { SELECT a FROM t1 AS t USING(a) }
|
||||
} {1 {a JOIN clause is required before USING}}
|
||||
|
@ -263,7 +263,7 @@ do_test vtab6-3.3 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b);
|
||||
}
|
||||
} {1 {cannot have both ON and USING clauses in the same join}}
|
||||
} {1 {near "USING": syntax error}}
|
||||
do_test vtab6-3.4 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 JOIN t2 USING(a);
|
||||
|
Reference in New Issue
Block a user