Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b745cccfd9 | |||
| e076d6bc14 | |||
| aee35d7509 | |||
| 68097b4e93 | |||
| 1b6cc73096 | |||
| 478583bbd6 | |||
| bd4dfa9071 | |||
| 879746ca63 |
@@ -1,5 +1,5 @@
|
||||
C Fix\sanother\sproblem\shandling\scorrupt\sdatabase\sfiles\sin\sthe\sALTER\sTABLE\sDROP\sCOLUMN\scode.
|
||||
D 2021-02-19T18:39:32.279
|
||||
C Merge\schanges\sfrom\strunk.
|
||||
D 2021-02-20T12:47:54.421
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -485,15 +485,15 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 694020ad8a3af3d79b09f74c8f1421272a419cdea42a13401e3b0f7dea6e9c3e
|
||||
F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e
|
||||
F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331
|
||||
F src/build.c 3e1e1df6807c91c17b0e0cdf24d0e85176d7e006d9783ab3eb1afb154aa26822
|
||||
F src/build.c 6bb7341559433152ac5bc082209cbb1f6d62d8d369ca2a1c10387c5c9e8450d5
|
||||
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410
|
||||
F src/date.c dace306a10d9b02ee553d454c8e1cf8d3c9b932e137738a6b15b90253a9bfc10
|
||||
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
|
||||
F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c
|
||||
F src/delete.c 352ea931218c45a3daf17472d4141b9c7fc026d85da3f1ade404ea5bb6d67f77
|
||||
F src/expr.c 47c85263e6d179424e6b09e2c79db5704ab5b8cbc2fae2ee3285faa2566f2e74
|
||||
F src/delete.c 8517d4d57dc12e4cb9adec1801249ce18a3be3e6ccd75a266f66499a57e5b062
|
||||
F src/expr.c fe76d3b9f606347b1d84cb059264ed0ba0f33ecce57a864f1575bc3d8ae42ba9
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 73adaca988d0dd517d373b432dc9dfa2cd7fa3108b114260132a80832de19037
|
||||
F src/func.c 479f6929be027eb0210cbdde9d3529c012facf082d64a6b854a9415940761e5e
|
||||
@@ -530,23 +530,23 @@ F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c c49952ac5e9cc536778eff528091d79d38b3e45cbeeed4695dc05e207dc6547d
|
||||
F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f
|
||||
F src/parse.y cdc4e5efaf1618d82f6b241a30f1a586188bf37e9c55f967258ed15fe24c51a2
|
||||
F src/parse.y a8102583778a6aedb602042463d0deb7811c913845561d74de9a9da400f79504
|
||||
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
|
||||
F src/pragma.c 6daaaecc26a4b09481d21722525b079ce756751a43a79cc1d8f122d686806193
|
||||
F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf
|
||||
F src/prepare.c 7a534d100c556f45f10aee131f2e4244cb52547b7cf17e1c393f55d8abb62e97
|
||||
F src/prepare.c f634a9e799a6b1c136d8ee12479cffa22862bfb807d307b1db406aa0cdb042a5
|
||||
F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 52f81603cc40f78449f5b6aed96dbea9484b194771ecb1937e8c0f6547c186a0
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c 371a5c95d47d4e969337548ed9bd344788f15518a1c75921507355bd93815205
|
||||
F src/select.c 1078af8a2e416e83a5f7d05adbee974bce32d1e17f47acd592f18d542a14fa29
|
||||
F src/shell.c.in 844417f84df1f6c4fce1c815629a888cfdcf219e86513e9c332bbcc38832f477
|
||||
F src/sqlite.h.in 8855a19f37ade8dad189a9e48233a2ebe1b46faf469c7eb0906a654e252dcc57
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
|
||||
F src/sqliteInt.h 4bd449478df0444ccb9f6a8e6f210b2ceacdd59562f52630edb0bb2d8cc25094
|
||||
F src/sqliteInt.h 652ccfddec0d3df91439b09fda7a9c32a0af07e365f4a1377b5caff03888c2b1
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -606,7 +606,7 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9
|
||||
F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
|
||||
F src/treeview.c 734a65babc2a0bb725a5af33cf3e677f7a8b20ad5be6dc04e07c2ff6081c16e6
|
||||
F src/trigger.c 861c3ec2c5b0fc830bdf82470454a9324fad70cbaa96d2e208fb54577c9e8d28
|
||||
F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723
|
||||
F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
|
||||
@@ -628,7 +628,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 69e770e96fd56cc21608992bf2c6f1f3dc5cf2572d0495c6a643b06c3a679f14
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/walker.c d9c4e454ebb9499e908aa62d55b8994c375cf5355ac78f60d45af17f7890701c
|
||||
F src/where.c 6efc4a10bfe0ec908c4f3c9112afb7675c952204b4b0b255672f488860141fec
|
||||
F src/where.c 228cb57b51ca02853bb932c4548ffaa3949f40f8398a0f393683dd4c08cdbea0
|
||||
F src/whereInt.h ae03b5e3a4cca9bd9cb1b7d3c63faf8f1f177200fc8cecc87d3d0cab6ca338e6
|
||||
F src/wherecode.c 43a63441f8662ddf86b15975683a502ec33f08167e9636f4d19e38e265e95fd9
|
||||
F src/whereexpr.c f7b5469e83db3c3b9eb14e4ba44559a2e125523761d12e5ac8d8fb88301af393
|
||||
@@ -1832,7 +1832,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
|
||||
F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
|
||||
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
|
||||
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
|
||||
F tool/mkkeywordhash.c 750f25aef0e23f8e3367af6d824fbf5ed7d3e285f27cea91aa2dd72c367630eb
|
||||
F tool/mkkeywordhash.c 08b6e4d7a482a7f37a9a0032e7ba968e26624a027b6b2e9ba589be6f5e3d8c2c
|
||||
F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
|
||||
@@ -1904,7 +1904,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 05dbea9b26bdcb096194dc531816333f3784eca50b133fe3efede6ab0d233472
|
||||
R 654376f36a79c8c3f0a8b98f1eb136d6
|
||||
U dan
|
||||
Z 6b0bcca992d79748743aedfd1336dec2
|
||||
P 30bb18b45013bf2ac214863c97f64544511cae62029b9762c97cbb69ca658887 9edf2ddc4799c8830c4b7b91d7aacee50029a4b9db329fd4c5674fbedea33034
|
||||
R f20aa0dd913bdc4d647b2a24ee109141
|
||||
U drh
|
||||
Z 69e153bc572b9edf99468fd37ca7f36e
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
9edf2ddc4799c8830c4b7b91d7aacee50029a4b9db329fd4c5674fbedea33034
|
||||
7a90571e0a0e43017cf5b9636ff111e0d0f7f9e9a4678d39b0e4f9c176ae232e
|
||||
+147
-23
@@ -5204,24 +5204,112 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
/*
|
||||
** Create a new CTE object
|
||||
*/
|
||||
Cte *sqlite3CteNew(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Token *pName, /* Name of the common-table */
|
||||
ExprList *pArglist, /* Optional column name list for the table */
|
||||
Select *pQuery, /* Query used to initialize the table */
|
||||
int eMaterialize /* Force or prohibit materialization */
|
||||
){
|
||||
Cte *pNew;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
assert( eMaterialize==Materialize_Any
|
||||
|| eMaterialize==Materialize_Yes
|
||||
|| eMaterialize==Materialize_No );
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(*pNew));
|
||||
assert( pNew!=0 || db->mallocFailed );
|
||||
|
||||
if( db->mallocFailed ){
|
||||
sqlite3ExprListDelete(db, pArglist);
|
||||
sqlite3SelectDelete(db, pQuery);
|
||||
}else{
|
||||
pNew->pSelect = pQuery;
|
||||
pNew->pCols = pArglist;
|
||||
pNew->zName = sqlite3NameFromToken(pParse->db, pName);
|
||||
pNew->zCteErr = 0;
|
||||
pNew->eMaterialize = (u8)eMaterialize;
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Validate the back-reference from a SrcList_item back to its Cte object.
|
||||
** Raise an assertion fault if anything is wrong. This routine is for
|
||||
** sanity and design checking and does not appear in release builds.
|
||||
*/
|
||||
void sqlite3AssertValidCteBackRef(struct SrcList_item *pItem){
|
||||
Cte *pCte;
|
||||
if( !pItem->fg.isCte ) return; /* Nothing to check here */
|
||||
assert( pItem->pSelect!=0 );
|
||||
pCte = pItem->u2.pCteSrc;
|
||||
if( pCte==0 ) return;
|
||||
assert( pCte->eCteMagic==CTE_MAGIC );
|
||||
assert( pItem->pTab!=0 );
|
||||
assert( sqlite3_stricmp(pCte->zName, pItem->pTab->zName)==0 );
|
||||
assert( pCte->nRefCte>=1 );
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Clear information from a Cte object, but do not deallocate storage.
|
||||
*/
|
||||
static void cteClear(sqlite3 *db, Cte *pCte){
|
||||
sqlite3ExprListDelete(db, pCte->pCols);
|
||||
sqlite3SelectDelete(db, pCte->pSelect);
|
||||
sqlite3DbFree(db, pCte->zName);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( db==0 || db->pnBytesFreed==0 ){
|
||||
pCte->zName = 0;
|
||||
pCte->eCteMagic = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Free the contents of the CTE object passed as the second argument.
|
||||
*/
|
||||
void sqlite3CteDelete(sqlite3 *db, Cte *pCte){
|
||||
if( pCte ){
|
||||
cteClear(db, pCte);
|
||||
sqlite3DbFree(db, pCte);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is invoked once per CTE by the parser while parsing a
|
||||
** WITH clause.
|
||||
** WITH clause. Construct a new Cte object and append it to the
|
||||
** input With object, reallocating the With object as needed. If the
|
||||
** pWith input is NULL, then create a new With object.
|
||||
**
|
||||
** The returned With object is unowned. The caller needs to assign
|
||||
** ownership. Note, however, that ownership should not be assigned
|
||||
** until the object stops growing. The input pWith parameter must be
|
||||
** either NULL or a pointer to an unowned With object.
|
||||
*/
|
||||
With *sqlite3WithAdd(
|
||||
Parse *pParse, /* Parsing context */
|
||||
With *pWith, /* Existing WITH clause, or NULL */
|
||||
Token *pName, /* Name of the common-table */
|
||||
ExprList *pArglist, /* Optional column name list for the table */
|
||||
Select *pQuery /* Query used to initialize the table */
|
||||
Cte *pCte /* The CTE to add to the WITH clause */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
With *pNew;
|
||||
char *zName;
|
||||
|
||||
/* The input WITH clause is yet unowned */
|
||||
assert( pWith==0 || pWith->mOwner==0 );
|
||||
|
||||
if( pCte==0 ){
|
||||
return pWith;
|
||||
}
|
||||
|
||||
/* Check that the CTE name is unique within this WITH clause. If
|
||||
** not, store an error in the Parse structure. */
|
||||
zName = sqlite3NameFromToken(pParse->db, pName);
|
||||
zName = pCte->zName;
|
||||
if( zName && pWith ){
|
||||
int i;
|
||||
for(i=0; i<pWith->nCte; i++){
|
||||
@@ -5237,37 +5325,73 @@ With *sqlite3WithAdd(
|
||||
}else{
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
|
||||
}
|
||||
assert( (pNew!=0 && zName!=0) || db->mallocFailed );
|
||||
|
||||
if( db->mallocFailed ){
|
||||
sqlite3ExprListDelete(db, pArglist);
|
||||
sqlite3SelectDelete(db, pQuery);
|
||||
sqlite3DbFree(db, zName);
|
||||
sqlite3CteDelete(db, pCte);
|
||||
pNew = pWith;
|
||||
}else{
|
||||
pNew->a[pNew->nCte].pSelect = pQuery;
|
||||
pNew->a[pNew->nCte].pCols = pArglist;
|
||||
pNew->a[pNew->nCte].zName = zName;
|
||||
pNew->a[pNew->nCte].zCteErr = 0;
|
||||
pNew->a[pNew->nCte] = *pCte;
|
||||
sqlite3DbFree(db, pCte);
|
||||
pNew->nCte++;
|
||||
}
|
||||
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free the contents of the With object passed as the second argument.
|
||||
**
|
||||
** The sqlite3WithReleaseBySelect() causes the Select-object ownership
|
||||
** to be released, and sqlite3WithReleaseByParse() causes the Parse-object
|
||||
** ownership to be released. The With object is only deallocated after
|
||||
** both owners release it.
|
||||
*/
|
||||
void sqlite3WithDelete(sqlite3 *db, With *pWith){
|
||||
if( pWith ){
|
||||
int i;
|
||||
for(i=0; i<pWith->nCte; i++){
|
||||
struct Cte *pCte = &pWith->a[i];
|
||||
sqlite3ExprListDelete(db, pCte->pCols);
|
||||
sqlite3SelectDelete(db, pCte->pSelect);
|
||||
sqlite3DbFree(db, pCte->zName);
|
||||
}
|
||||
sqlite3DbFree(db, pWith);
|
||||
int i;
|
||||
for(i=0; i<pWith->nCte; i++){
|
||||
cteClear(db, &pWith->a[i]);
|
||||
}
|
||||
sqlite3DbFree(db, pWith);
|
||||
}
|
||||
void sqlite3WithReleaseBySelect(sqlite3 *db, With *pWith){
|
||||
if( pWith==0 ) return;
|
||||
if( db && db->pnBytesFreed ){
|
||||
if( pWith->mOwner==WithOwnedBySelect ) sqlite3WithDelete(db, pWith);
|
||||
}else{
|
||||
pWith->mOwner &= ~WithOwnedBySelect;
|
||||
if( pWith->mOwner==0 ) sqlite3WithDelete(db, pWith);
|
||||
}
|
||||
}
|
||||
void sqlite3WithReleaseByParse(sqlite3 *db, With *pWith){
|
||||
if( pWith==0 ) return;
|
||||
assert( db==0 || db->pnBytesFreed==0 );
|
||||
pWith->mOwner &= ~WithOwnedByParse;
|
||||
if( pWith->mOwner==0 ) sqlite3WithDelete(db, pWith);
|
||||
}
|
||||
|
||||
/*
|
||||
** Add Select-object or Parse-object ownership to a With object. If
|
||||
** the With object is already owned appropriately, then these routines
|
||||
** are no-ops.
|
||||
**
|
||||
** The first time that a With becomes owned by a Parse-object, make
|
||||
** arrangements to automatically release the ownership when the Parse
|
||||
** object is destroyed using a call to sqlite3ParserAddCleanup().
|
||||
** This involves a memory allocation. If that memory allocation fails,
|
||||
** the With object might be destroyed immediately. In that
|
||||
** case, return a NULL pointer. But usually, return a copy of the pWith
|
||||
** pointer.
|
||||
*/
|
||||
void sqlite3WithClaimedBySelect(With *pWith){
|
||||
pWith->mOwner |= WithOwnedBySelect;
|
||||
}
|
||||
With *sqlite3WithClaimedByParse(Parse *pParse, With *pWith){
|
||||
if( (pWith->mOwner & WithOwnedByParse)==0 ){
|
||||
pWith->mOwner |= WithOwnedByParse;
|
||||
pWith = (With*)sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3WithReleaseByParse,
|
||||
(void*)pWith);
|
||||
}
|
||||
return pWith;
|
||||
}
|
||||
|
||||
#endif /* !defined(SQLITE_OMIT_CTE) */
|
||||
|
||||
+1
-1
@@ -209,7 +209,7 @@ Expr *sqlite3LimitWhere(
|
||||
pSrc->a[0].pTab = 0;
|
||||
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
|
||||
pSrc->a[0].pTab = pTab;
|
||||
pSrc->a[0].pIBIndex = 0;
|
||||
pSrc->a[0].u2.pIBIndex = 0; assert( !pSrc->a[0].fg.isCte );
|
||||
|
||||
/* generate the SELECT expression tree. */
|
||||
pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0,
|
||||
|
||||
+2
-1
@@ -1401,6 +1401,7 @@ static With *withDup(sqlite3 *db, With *p){
|
||||
if( pRet ){
|
||||
int i;
|
||||
pRet->nCte = p->nCte;
|
||||
pRet->mOwner = WithOwnedBySelect;
|
||||
for(i=0; i<p->nCte; i++){
|
||||
pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0);
|
||||
pRet->a[i].pCols = sqlite3ExprListDup(db, p->a[i].pCols, 0);
|
||||
@@ -1544,7 +1545,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
||||
if( pNewItem->fg.isIndexedBy ){
|
||||
pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
|
||||
}
|
||||
pNewItem->pIBIndex = pOldItem->pIBIndex;
|
||||
pNewItem->u2 = pOldItem->u2;
|
||||
if( pNewItem->fg.isTabFunc ){
|
||||
pNewItem->u1.pFuncArg =
|
||||
sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
|
||||
|
||||
+40
-28
@@ -249,6 +249,9 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
%endif SQLITE_OMIT_WINDOWFUNC
|
||||
%ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
GENERATED ALWAYS
|
||||
%endif
|
||||
%ifndef SQLITE_OMIT_CTE
|
||||
MATERIALIZED
|
||||
%endif
|
||||
REINDEX RENAME CTIME_KW IF
|
||||
.
|
||||
@@ -510,29 +513,29 @@ cmd ::= select(X). {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
/* Link a With object to a Select object.
|
||||
** Both Select- and Parse-ownership is assigned to the With object
|
||||
*/
|
||||
static Select *linkWithToSelect(Parse *pParse, Select *pSelect, With *pWith){
|
||||
assert( pWith->mOwner==0 );
|
||||
if( pSelect ){
|
||||
pSelect->pWith = pWith;
|
||||
sqlite3WithClaimedBySelect(pWith);
|
||||
parserDoubleLinkSelect(pParse, pSelect);
|
||||
}else{
|
||||
sqlite3WithClaimedByParse(pParse,pWith);
|
||||
}
|
||||
return pSelect;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_CTE */
|
||||
} // end %include
|
||||
|
||||
|
||||
%ifndef SQLITE_OMIT_CTE
|
||||
select(A) ::= WITH wqlist(W) selectnowith(X). {
|
||||
Select *p = X;
|
||||
if( p ){
|
||||
p->pWith = W;
|
||||
parserDoubleLinkSelect(pParse, p);
|
||||
}else{
|
||||
sqlite3WithDelete(pParse->db, W);
|
||||
}
|
||||
A = p;
|
||||
}
|
||||
select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X). {
|
||||
Select *p = X;
|
||||
if( p ){
|
||||
p->pWith = W;
|
||||
parserDoubleLinkSelect(pParse, p);
|
||||
}else{
|
||||
sqlite3WithDelete(pParse->db, W);
|
||||
}
|
||||
A = p;
|
||||
}
|
||||
select(A) ::= WITH wqlist(W) selectnowith(X). { A = linkWithToSelect(pParse,X,W); }
|
||||
select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X).
|
||||
{ A = linkWithToSelect(pParse,X,W); }
|
||||
%endif /* SQLITE_OMIT_CTE */
|
||||
select(A) ::= selectnowith(X). {
|
||||
Select *p = X;
|
||||
@@ -1661,18 +1664,27 @@ anylist ::= anylist ANY.
|
||||
|
||||
//////////////////////// COMMON TABLE EXPRESSIONS ////////////////////////////
|
||||
%type wqlist {With*}
|
||||
%destructor wqlist {sqlite3WithDelete(pParse->db, $$);}
|
||||
%destructor wqlist {if($$)sqlite3WithDelete(pParse->db, $$);}
|
||||
%type wqitem {Cte*}
|
||||
%destructor wqitem {sqlite3CteDelete(pParse->db, $$);}
|
||||
%type wqas {int}
|
||||
|
||||
with ::= .
|
||||
%ifndef SQLITE_OMIT_CTE
|
||||
with ::= WITH wqlist(W). { sqlite3WithPush(pParse, W, 1); }
|
||||
with ::= WITH RECURSIVE wqlist(W). { sqlite3WithPush(pParse, W, 1); }
|
||||
with ::= WITH wqlist(W). { sqlite3WithPush(pParse, W); }
|
||||
with ::= WITH RECURSIVE wqlist(W). { sqlite3WithPush(pParse, W); }
|
||||
|
||||
wqlist(A) ::= nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
|
||||
A = sqlite3WithAdd(pParse, 0, &X, Y, Z); /*A-overwrites-X*/
|
||||
wqas(A) ::= AS. {A = Materialize_Any;}
|
||||
wqas(A) ::= AS MATERIALIZED. {A = Materialize_Yes;}
|
||||
wqas(A) ::= AS NOT MATERIALIZED. {A = Materialize_No;}
|
||||
wqitem(A) ::= nm(X) eidlist_opt(Y) wqas(F) LP select(Z) RP. {
|
||||
A = sqlite3CteNew(pParse, &X, Y, Z, F); /*A-overwrites-X*/
|
||||
}
|
||||
wqlist(A) ::= wqlist(A) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
|
||||
A = sqlite3WithAdd(pParse, A, &X, Y, Z);
|
||||
wqlist(A) ::= wqitem(X). {
|
||||
A = sqlite3WithAdd(pParse, 0, X); /*A-overwrites-X*/
|
||||
}
|
||||
wqlist(A) ::= wqlist(A) COMMA wqitem(X). {
|
||||
A = sqlite3WithAdd(pParse, A, X);
|
||||
}
|
||||
%endif SQLITE_OMIT_CTE
|
||||
|
||||
|
||||
+3
-1
@@ -597,7 +597,7 @@ void sqlite3ParserReset(Parse *pParse){
|
||||
**
|
||||
** testcase( pParse->earlyCleanup );
|
||||
*/
|
||||
void sqlite3ParserAddCleanup(
|
||||
void *sqlite3ParserAddCleanup(
|
||||
Parse *pParse, /* Destroy when this Parser finishes */
|
||||
void (*xCleanup)(sqlite3*,void*), /* The cleanup routine */
|
||||
void *pPtr /* Pointer to object to be cleaned up */
|
||||
@@ -610,10 +610,12 @@ void sqlite3ParserAddCleanup(
|
||||
pCleanup->xCleanup = xCleanup;
|
||||
}else{
|
||||
xCleanup(pParse->db, pPtr);
|
||||
pPtr = 0;
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
|
||||
pParse->earlyCleanup = 1;
|
||||
#endif
|
||||
}
|
||||
return pPtr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+60
-38
@@ -90,7 +90,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
||||
sqlite3WindowListDelete(db, p->pWinDefn);
|
||||
}
|
||||
#endif
|
||||
if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
|
||||
if( p->pWith ) sqlite3WithReleaseBySelect(db, p->pWith);
|
||||
if( bFree ) sqlite3DbFreeNN(db, p);
|
||||
p = pPrior;
|
||||
bFree = 1;
|
||||
@@ -4724,7 +4724,9 @@ int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){
|
||||
pParse->checkSchema = 1;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pFrom->pIBIndex = pIdx;
|
||||
assert( pFrom->fg.isCte==0 );
|
||||
assert( pFrom->pSelect==0 );
|
||||
pFrom->u2.pIBIndex = pIdx;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -4856,25 +4858,13 @@ static struct Cte *searchWith(
|
||||
|
||||
/* The code generator maintains a stack of active WITH clauses
|
||||
** with the inner-most WITH clause being at the top of the stack.
|
||||
**
|
||||
** This routine pushes the WITH clause passed as the second argument
|
||||
** onto the top of the stack. If argument bFree is true, then this
|
||||
** WITH clause will never be popped from the stack. In this case it
|
||||
** should be freed along with the Parse object. In other cases, when
|
||||
** bFree==0, the With object will be freed along with the SELECT
|
||||
** statement with which it is associated.
|
||||
*/
|
||||
void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
|
||||
void sqlite3WithPush(Parse *pParse, With *pWith){
|
||||
if( pWith ){
|
||||
assert( pParse->pWith!=pWith );
|
||||
pWith->pOuter = pParse->pWith;
|
||||
pParse->pWith = pWith;
|
||||
if( bFree ){
|
||||
sqlite3ParserAddCleanup(pParse,
|
||||
(void(*)(sqlite3*,void*))sqlite3WithDelete,
|
||||
pWith);
|
||||
testcase( pParse->earlyCleanup );
|
||||
}
|
||||
sqlite3WithClaimedByParse(pParse, pWith);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4939,6 +4929,17 @@ static int withExpand(
|
||||
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
|
||||
if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
|
||||
assert( pFrom->pSelect );
|
||||
if( pCte->eMaterialize==Materialize_Yes ){
|
||||
pFrom->pSelect->selFlags |= SF_OptBarrier;
|
||||
}
|
||||
assert( !pFrom->fg.isIndexedBy );
|
||||
pFrom->fg.isCte = 1;
|
||||
assert( (pCte->eCteMagic==0 && pCte->nRefCte==0)
|
||||
|| (pCte->eCteMagic==CTE_MAGIC && pCte->nRefCte>0) );
|
||||
pFrom->u2.pCteSrc = pCte;
|
||||
sqlite3WithClaimedByParse(pParse, pWith);
|
||||
pCte->nRefCte++;
|
||||
VVA_ONLY( pCte->eCteMagic = CTE_MAGIC );
|
||||
|
||||
/* Check if this is a recursive CTE. */
|
||||
pRecTerm = pSel = pFrom->pSelect;
|
||||
@@ -5119,7 +5120,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
}
|
||||
pTabList = p->pSrc;
|
||||
pEList = p->pEList;
|
||||
sqlite3WithPush(pParse, p->pWith, 0);
|
||||
sqlite3WithPush(pParse, p->pWith);
|
||||
|
||||
/* Make sure cursor numbers have been assigned to all entries in
|
||||
** the FROM clause of the SELECT statement.
|
||||
@@ -5758,9 +5759,10 @@ static void havingToWhere(Parse *pParse, Select *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if the pThis entry of pTabList is a self-join of a prior view.
|
||||
** If it is, then return the SrcList_item for the prior view. If it is not,
|
||||
** then return 0.
|
||||
** Check to see if the pThis entry of pTabList is a self-join of a prior view,
|
||||
** or any reuse of a CTE that is not necessarily a self-join.
|
||||
** If it is, then return the SrcList_item for the prior view or CTE.
|
||||
** If it is not, then return 0.
|
||||
*/
|
||||
static struct SrcList_item *isSelfJoinView(
|
||||
SrcList *pTabList, /* Search for self-joins in this FROM clause */
|
||||
@@ -5769,6 +5771,11 @@ static struct SrcList_item *isSelfJoinView(
|
||||
struct SrcList_item *pItem;
|
||||
assert( pThis->pSelect!=0 );
|
||||
if( pThis->pSelect->selFlags & SF_PushDown ) return 0;
|
||||
if( pThis->fg.isCte ){
|
||||
Cte *pCte = pThis->u2.pCteSrc;
|
||||
sqlite3AssertValidCteBackRef(pThis);
|
||||
return pCte->pCteMat;
|
||||
}
|
||||
for(pItem = pTabList->a; pItem<pThis; pItem++){
|
||||
Select *pS1;
|
||||
if( pItem->pSelect==0 ) continue;
|
||||
@@ -6080,6 +6087,9 @@ int sqlite3Select(
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Do not flatten across an optimization barrier */
|
||||
if( pSub->selFlags & SF_OptBarrier ) continue;
|
||||
|
||||
if( flattenSubquery(pParse, p, i, isAgg) ){
|
||||
if( pParse->nErr ) goto select_end;
|
||||
/* This subquery can be absorbed into its parent. */
|
||||
@@ -6145,6 +6155,7 @@ int sqlite3Select(
|
||||
*/
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pTabList->a[i];
|
||||
struct SrcList_item *pPrior;
|
||||
SelectDest dest;
|
||||
Select *pSub;
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
@@ -6204,6 +6215,7 @@ int sqlite3Select(
|
||||
** inside the subquery. This can help the subquery to run more efficiently.
|
||||
*/
|
||||
if( OptimizationEnabled(db, SQLITE_PushDown)
|
||||
&& (pSub->selFlags & SF_OptBarrier)==0
|
||||
&& pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
|
||||
(pItem->fg.jointype & JT_OUTER)!=0)
|
||||
){
|
||||
@@ -6222,18 +6234,27 @@ int sqlite3Select(
|
||||
zSavedAuthContext = pParse->zAuthContext;
|
||||
pParse->zAuthContext = pItem->zName;
|
||||
|
||||
/* Verify that the CTE back-reference information is valid */
|
||||
sqlite3AssertValidCteBackRef(pItem);
|
||||
|
||||
/* Generate code to implement the subquery
|
||||
**
|
||||
** The subquery is implemented as a co-routine if the subquery is
|
||||
** The subquery is implemented as a co-routine if (1) the subquery is
|
||||
** guaranteed to be the outer loop (so that it does not need to be
|
||||
** computed more than once)
|
||||
** computed more than once) and if (2) the subquery is a CTE that is
|
||||
** used only this one time.
|
||||
**
|
||||
** TODO: Are there other reasons beside (1) to use a co-routine
|
||||
** TODO: Are there other reasons beside (1) and (2) to use a co-routine
|
||||
** implementation?
|
||||
**
|
||||
** TODO: We might should allow a subquery that is an optimization barrier
|
||||
** to be implemented as a co-routine as long as we know that it is the
|
||||
** only use of the subquery.
|
||||
*/
|
||||
if( i==0
|
||||
&& (pTabList->nSrc==1
|
||||
|| (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
|
||||
&& (pItem->fg.isCte && pItem->u2.pCteSrc->nRefCte==1) /* (2) */
|
||||
){
|
||||
/* Implement a co-routine that will return a single row of the result
|
||||
** set on each invocation.
|
||||
@@ -6253,16 +6274,20 @@ int sqlite3Select(
|
||||
sqlite3VdbeEndCoroutine(v, pItem->regReturn);
|
||||
sqlite3VdbeJumpHere(v, addrTop-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}else if( (pPrior = isSelfJoinView(pTabList,pItem))!=0 ){
|
||||
/* This view has been previously materialized. Use the
|
||||
** prior materialization */
|
||||
if( pPrior->addrFillSub ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
|
||||
assert( pPrior->pSelect!=0 );
|
||||
pSub->nSelectRow = pPrior->pSelect->nSelectRow;
|
||||
}else{
|
||||
/* Generate a subroutine that will fill an ephemeral table with
|
||||
** the content of this subquery. pItem->addrFillSub will point
|
||||
** to the address of the generated subroutine. pItem->regReturn
|
||||
** is a register allocated to hold the subroutine return address
|
||||
*/
|
||||
/* Materialize the view */
|
||||
int topAddr;
|
||||
int onceAddr = 0;
|
||||
int retAddr;
|
||||
struct SrcList_item *pPrior;
|
||||
|
||||
testcase( pItem->addrFillSub==0 ); /* Ticket c52b09c7f38903b1311 */
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
@@ -6277,15 +6302,12 @@ int sqlite3Select(
|
||||
}else{
|
||||
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}
|
||||
pPrior = isSelfJoinView(pTabList, pItem);
|
||||
if( pPrior ){
|
||||
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
|
||||
assert( pPrior->pSelect!=0 );
|
||||
pSub->nSelectRow = pPrior->pSelect->nSelectRow;
|
||||
}else{
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId));
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId));
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
if( pItem->fg.isCte ){
|
||||
sqlite3AssertValidCteBackRef(pItem);
|
||||
pItem->u2.pCteSrc->pCteMat = pItem;
|
||||
}
|
||||
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
||||
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
||||
|
||||
+74
-17
@@ -1136,6 +1136,7 @@ typedef struct AutoincInfo AutoincInfo;
|
||||
typedef struct Bitvec Bitvec;
|
||||
typedef struct CollSeq CollSeq;
|
||||
typedef struct Column Column;
|
||||
typedef struct Cte Cte;
|
||||
typedef struct Db Db;
|
||||
typedef struct DbFixer DbFixer;
|
||||
typedef struct Schema Schema;
|
||||
@@ -2957,6 +2958,7 @@ struct SrcList {
|
||||
unsigned viaCoroutine :1; /* Implemented as a co-routine */
|
||||
unsigned isRecursive :1; /* True for recursive reference in WITH */
|
||||
unsigned fromDDL :1; /* Comes from sqlite_schema */
|
||||
unsigned isCte :1; /* True if table is a CTE */
|
||||
} fg;
|
||||
int iCursor; /* The VDBE cursor number used to access this table */
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
@@ -2966,7 +2968,10 @@ struct SrcList {
|
||||
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
|
||||
ExprList *pFuncArg; /* Arguments to table-valued-function */
|
||||
} u1;
|
||||
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
|
||||
union {
|
||||
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
|
||||
Cte *pCteSrc; /* The original CTE, if fg.isCte is true */
|
||||
} u2;
|
||||
} a[1]; /* One entry for each identifier on the list */
|
||||
};
|
||||
|
||||
@@ -3191,6 +3196,7 @@ struct Select {
|
||||
#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
|
||||
#define SF_UpdateFrom 0x0800000 /* Statement is an UPDATE...FROM */
|
||||
#define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */
|
||||
#define SF_OptBarrier 0x2000000 /* SELECT is an optimization barrier */
|
||||
|
||||
/*
|
||||
** The results of a SELECT can be distributed in several ways, as defined
|
||||
@@ -3873,20 +3879,55 @@ void sqlite3SelectWalkAssert2(Walker*, Select*);
|
||||
#define WRC_Prune 1 /* Omit children but continue walking siblings */
|
||||
#define WRC_Abort 2 /* Abandon the tree walk */
|
||||
|
||||
/*
|
||||
** Allowed values for Cte.eMaterialize
|
||||
*/
|
||||
#define Materialize_Any 0 /* Not specified */
|
||||
#define Materialize_Yes 1 /* AS MATERIALIZED ... */
|
||||
#define Materialize_No 2 /* AS NOT MATERIALIZED. Not currently used */
|
||||
|
||||
/*
|
||||
** An instance of this structure represents a set of one or more CTEs
|
||||
** (common table expressions) created by a single WITH clause.
|
||||
**
|
||||
** A With object describes an entire WITH clause, which is composed of
|
||||
** one or more Cte objects. During parsing, the Cte objects are created
|
||||
** separately for each common-table-expression, then copied into the
|
||||
** With object container.
|
||||
**
|
||||
** DUAL OWNERSHIP
|
||||
** The With object can be owned by a Select object (via the Select.pWith
|
||||
** field), or it can be owned by the Parse object of the current parse,
|
||||
** or by both. The With.mOwner bitmask determines who owns each With object.
|
||||
** The object is not deallocated until all owners have released it.
|
||||
*/
|
||||
struct With {
|
||||
int nCte; /* Number of CTEs in the WITH clause */
|
||||
With *pOuter; /* Containing WITH clause, or NULL */
|
||||
struct Cte { /* For each CTE in the WITH clause.... */
|
||||
char *zName; /* Name of this CTE */
|
||||
ExprList *pCols; /* List of explicit column names, or NULL */
|
||||
Select *pSelect; /* The definition of this CTE */
|
||||
const char *zCteErr; /* Error message for circular references */
|
||||
} a[1];
|
||||
struct Cte {
|
||||
char *zName; /* Name of this CTE */
|
||||
ExprList *pCols; /* List of explicit column names, or NULL */
|
||||
Select *pSelect; /* The definition of this CTE */
|
||||
const char *zCteErr; /* Error message for circular references */
|
||||
u8 eMaterialize; /* One of the Materialize_* options */
|
||||
u16 eCteMagic; /* Magic number for sanity checking */
|
||||
u32 nRefCte; /* Number of times used */
|
||||
struct SrcList_item *pCteMat; /* The materialization of this CTE */
|
||||
};
|
||||
struct With {
|
||||
int nCte; /* Number of CTEs in the WITH clause */
|
||||
int mOwner; /* Mask of bits to discribe ownership */
|
||||
With *pOuter; /* Containing WITH clause, or NULL */
|
||||
Cte a[1]; /* The CTEs of this WITH clause */
|
||||
};
|
||||
|
||||
/*
|
||||
** The correct value for Cte.eCteMagic if the Cte object is valid
|
||||
*/
|
||||
#define CTE_MAGIC 0x3f96 /* Magic number for valid Cte objects */
|
||||
|
||||
/*
|
||||
** Ownership flags for With.
|
||||
*/
|
||||
#define WithOwnedBySelect 0x01 /* Owned by a Select object */
|
||||
#define WithOwnedByParse 0x10 /* Owned by the Parse object */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
@@ -4876,7 +4917,7 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
|
||||
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
|
||||
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
|
||||
void sqlite3ParserReset(Parse*);
|
||||
void sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*);
|
||||
void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
char *sqlite3Normalize(Vdbe*, const char*);
|
||||
#endif
|
||||
@@ -4891,13 +4932,29 @@ const char *sqlite3JournalModename(int);
|
||||
int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*);
|
||||
Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,int);
|
||||
With *sqlite3WithAdd(Parse*,With*,Cte*);
|
||||
void sqlite3CteDelete(sqlite3*,Cte*);
|
||||
void sqlite3WithDelete(sqlite3*,With*);
|
||||
void sqlite3WithPush(Parse*, With*, u8);
|
||||
#else
|
||||
#define sqlite3WithPush(x,y,z)
|
||||
#define sqlite3WithDelete(x,y)
|
||||
#endif
|
||||
void sqlite3WithReleaseBySelect(sqlite3*,With*);
|
||||
void sqlite3WithReleaseByParse(sqlite3*,With*);
|
||||
void sqlite3WithClaimedBySelect(With*);
|
||||
With *sqlite3WithClaimedByParse(Parse*,With*);
|
||||
void sqlite3WithPush(Parse*, With*);
|
||||
# ifdef SQLITE_DEBUG
|
||||
void sqlite3AssertValidCteBackRef(struct SrcList_item*);
|
||||
# else
|
||||
# define sqlite3AssertValidCteBackRef(X)
|
||||
# endif
|
||||
#else /* if defined(SQLITE_OMIT_CTE) */
|
||||
# define sqlite3WithPush(PARSE,W)
|
||||
# deifne sqlite3WithDelete(Db,W)
|
||||
# define sqlite3WithReleaseBySelect(DB,W)
|
||||
# define sqlite3WithReleaseByParse(DB,W)
|
||||
# define sqlite3WithClaimedBySelect(W)
|
||||
# define sqlite3WithClaimedByParse(PARSE,W);
|
||||
# define sqlite3AssertValidCteBackRef(X)
|
||||
#endif /* SQLITE_OMIT_CTE */
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
|
||||
void sqlite3UpsertDelete(sqlite3*,Upsert*);
|
||||
|
||||
+9
-2
@@ -90,7 +90,8 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
|
||||
if( pWith==0 ) return;
|
||||
if( pWith->nCte==0 ) return;
|
||||
if( pWith->pOuter ){
|
||||
sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter);
|
||||
sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",
|
||||
pWith,pWith->pOuter);
|
||||
}else{
|
||||
sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith);
|
||||
}
|
||||
@@ -101,7 +102,10 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
|
||||
char zLine[1000];
|
||||
const struct Cte *pCte = &pWith->a[i];
|
||||
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
|
||||
sqlite3_str_appendf(&x, "%s", pCte->zName);
|
||||
sqlite3_str_appendf(&x, "%s%s (0x%p, n=%d)", pCte->zName,
|
||||
pCte->eMaterialize==Materialize_Any ? "" :
|
||||
pCte->eMaterialize==Materialize_Yes ? " MATERIALIZED" :
|
||||
" NOT MATERIALIZED", pCte, pCte->nRefCte);
|
||||
if( pCte->pCols && pCte->pCols->nExpr>0 ){
|
||||
char cSep = '(';
|
||||
int j;
|
||||
@@ -150,6 +154,9 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
|
||||
if( pItem->fg.fromDDL ){
|
||||
sqlite3_str_appendf(&x, " DDL");
|
||||
}
|
||||
if( pItem->fg.isCte && pItem->u2.pCteSrc ){
|
||||
sqlite3_str_appendf(&x, " CTE=0x%p", pItem->u2.pCteSrc);
|
||||
}
|
||||
sqlite3StrAccumFinish(&x);
|
||||
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
|
||||
if( pItem->pSelect ){
|
||||
|
||||
+4
-4
@@ -2954,9 +2954,9 @@ static int whereLoopAddBtree(
|
||||
pWC = pBuilder->pWC;
|
||||
assert( !IsVirtual(pSrc->pTab) );
|
||||
|
||||
if( pSrc->pIBIndex ){
|
||||
if( pSrc->fg.isIndexedBy ){
|
||||
/* An INDEXED BY clause specifies a particular index to use */
|
||||
pProbe = pSrc->pIBIndex;
|
||||
pProbe = pSrc->u2.pIBIndex;
|
||||
}else if( !HasRowid(pTab) ){
|
||||
pProbe = pTab->pIndex;
|
||||
}else{
|
||||
@@ -2992,7 +2992,7 @@ static int whereLoopAddBtree(
|
||||
if( !pBuilder->pOrSet /* Not part of an OR optimization */
|
||||
&& (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
|
||||
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
|
||||
&& pSrc->pIBIndex==0 /* Has no INDEXED BY clause */
|
||||
&& !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */
|
||||
&& !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */
|
||||
&& HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */
|
||||
&& !pSrc->fg.isCorrelated /* Not a correlated subquery */
|
||||
@@ -3042,7 +3042,7 @@ static int whereLoopAddBtree(
|
||||
/* Loop over all indices. If there was an INDEXED BY clause, then only
|
||||
** consider index pProbe. */
|
||||
for(; rc==SQLITE_OK && pProbe;
|
||||
pProbe=(pSrc->pIBIndex ? 0 : pProbe->pNext), iSortIdx++
|
||||
pProbe=(pSrc->fg.isIndexedBy ? 0 : pProbe->pNext), iSortIdx++
|
||||
){
|
||||
int isLeft = (pSrc->fg.jointype & JT_OUTER)!=0;
|
||||
if( pProbe->pPartIdxWhere!=0
|
||||
|
||||
@@ -229,7 +229,7 @@ static Keyword aKeywordTable[] = {
|
||||
{ "FOREIGN", "TK_FOREIGN", FKEY, 1 },
|
||||
{ "FROM", "TK_FROM", ALWAYS, 10 },
|
||||
{ "FULL", "TK_JOIN_KW", ALWAYS, 3 },
|
||||
{ "GENERATED", "TK_GENERATED", GENCOL, 1 },
|
||||
{ "GENERATED", "TK_GENERATED", ALWAYS, 1 },
|
||||
{ "GLOB", "TK_LIKE_KW", ALWAYS, 3 },
|
||||
{ "GROUP", "TK_GROUP", ALWAYS, 5 },
|
||||
{ "GROUPS", "TK_GROUPS", WINDOWFUNC, 2 },
|
||||
@@ -255,6 +255,7 @@ static Keyword aKeywordTable[] = {
|
||||
{ "LIKE", "TK_LIKE_KW", ALWAYS, 5 },
|
||||
{ "LIMIT", "TK_LIMIT", ALWAYS, 3 },
|
||||
{ "MATCH", "TK_MATCH", ALWAYS, 2 },
|
||||
{ "MATERIALIZED", "TK_MATERIALIZED", CTE, 12 },
|
||||
{ "NATURAL", "TK_JOIN_KW", ALWAYS, 3 },
|
||||
{ "NO", "TK_NO", FKEY|WINDOWFUNC, 2 },
|
||||
{ "NOT", "TK_NOT", ALWAYS, 10 },
|
||||
|
||||
Reference in New Issue
Block a user