Compare commits

...

5 Commits

Author SHA1 Message Date
drh 68097b4e93 Change the syntax from "GENERATED AS" to "AS MATERIALIZED" so as to match
the syntax of PostgreSQL 12+.

FossilOrigin-Name: 78dcddd9697d95629c18131ab0842aa4d08bc3c7451cd0e7a8d83e4dde277bda
2021-02-16 00:48:51 +00:00
drh 1b6cc73096 Merge the LIKE operator fix from trunk.
FossilOrigin-Name: 8c8618780a2cb80c0c1f244fa8555ce36501ad7e435a2cfee1030bbdc8d644db
2021-02-15 17:51:32 +00:00
drh 478583bbd6 Merge minor fixes from trunk.
FossilOrigin-Name: d876b287e1d1fdc1db083fb9786889fb82117ec77defdaa078858e1092068166
2021-02-15 14:55:04 +00:00
drh bd4dfa9071 If the GENERATED keyword occurs before the AS keyword in a common table
expression (CTE) definition, then that CTE becomes an "optimization barrier".
For now, that means the CTE is always materialized.  It also means that
query flattener or pushdown optimizations that cross the CTE boundary are
omitted.

FossilOrigin-Name: 186ec18b24d16c5d4d7a5b5e98c7504892950a1018774cb7bb214fc011ec09f4
2021-02-13 23:46:26 +00:00
drh 879746ca63 Parsing of DML statements in a WITH clause. But at this point, it just
generates an error about "not yet supported".

FossilOrigin-Name: 964ff68d8fa4d72b1b4d510f1ec62a9674b75d4ebae4ba254bc2f99432857628
2021-02-12 21:07:58 +00:00
7 changed files with 120 additions and 41 deletions
+10 -10
View File
@@ -1,5 +1,5 @@
C Fix\san\sissue\swith\sthe\sLIKE\soperator\swhen\sit\sincludes\sthe\s"ESCAPE\s'_'"\sclause.\nTicket\s[c0aeea67d58ae0fd].
D 2021-02-15T17:02:01.949
C Change\sthe\ssyntax\sfrom\s"GENERATED\sAS"\sto\s"AS\sMATERIALIZED"\sso\sas\sto\smatch\nthe\ssyntax\sof\sPostgreSQL\s12+.
D 2021-02-16T00:48:51.202
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -485,7 +485,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c 694020ad8a3af3d79b09f74c8f1421272a419cdea42a13401e3b0f7dea6e9c3e
F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e
F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331
F src/build.c 1bae5588bfdf21bdf41e634f0a053d633fb1ae3a2896117b4eea76412b76c2e0
F src/build.c a777f43048a09704b75000c11e6c9fea825deafd676cd8f4e5357764f2d2fb06
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410
@@ -530,7 +530,7 @@ 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 67ba503780de64b967ae195b7e14c33531329228e1bc0b83d63324beb733680b
F src/parse.y a6d56266bf453e7fd57f47f39f85f36a8530792cae68f0672f7f03972c112397
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
@@ -541,12 +541,12 @@ F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 89e4faf6171e179edf279905e8e45c4f9dd108777dc60716396729fbd7cb045e
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 9b4c84fd2703ee3c8b5d4b189387482a84c26acf2c38ca4835db5b48c68a09d4
F src/select.c 0612a4097f86396f6ec000546dbc16479d6bbb9033a29a0dc07213801e9cd83f
F src/shell.c.in 9ebc74e4f05cfbd0f4a36060fdaeff1da4e9af4458358722bc08c5a1ab9a0879
F src/sqlite.h.in 8855a19f37ade8dad189a9e48233a2ebe1b46faf469c7eb0906a654e252dcc57
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
F src/sqliteInt.h 4cb469678a0dbf814e4efbde4488a0161a5398e9a63141830d9f676b4e9fb0cc
F src/sqliteInt.h e9122436bf0b69ef93f1d922805e891cac614db4b5f5b22efe25395a1a168555
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -1828,7 +1828,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
@@ -1900,7 +1900,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 7cc65ae57183b3c16f1102fca5603a36acda432e5d45e22a2996e5ebe069fc6a
R 3ed1929e1ca13bbf9ff7ef7c6dc85f4d
P 8c8618780a2cb80c0c1f244fa8555ce36501ad7e435a2cfee1030bbdc8d644db
R ba922d4317c055cbb896732be33e5b20
U drh
Z b9fb1ccb5459387ee6a14bca5dee2b45
Z c9282fd2eefaea59421fc4e9996c1c87
+1 -1
View File
@@ -1 +1 @@
27d4117980d125975b5e70eeea58a6ab07bcf066e71b5fcb81b822e05afdbab0
78dcddd9697d95629c18131ab0842aa4d08bc3c7451cd0e7a8d83e4dde277bda
+53 -13
View File
@@ -5204,6 +5204,49 @@ 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 eMaterialized /* Force or prohibit materialization */
){
Cte *pNew;
sqlite3 *db = pParse->db;
assert( eMaterialized==MAT_NotSpec || eMaterialized==MAT_Yes
|| eMaterialized==MAT_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->eMaterialized = (u8)eMaterialized;
}
return pNew;
}
/*
** Free the contents of the CTE object passed as the second argument.
*/
void sqlite3CteDelete(sqlite3 *db, Cte *pCte){
if( pCte ){
sqlite3ExprListDelete(db, pCte->pCols);
sqlite3SelectDelete(db, pCte->pSelect);
sqlite3DbFree(db, pCte->zName);
sqlite3DbFree(db, pCte);
}
}
/*
** This routine is invoked once per CTE by the parser while parsing a
** WITH clause.
@@ -5211,17 +5254,20 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
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;
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,21 +5283,15 @@ 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;
}
+16 -4
View File
@@ -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
.
@@ -1658,17 +1661,26 @@ anylist ::= anylist ANY.
//////////////////////// COMMON TABLE EXPRESSIONS ////////////////////////////
%type wqlist {With*}
%destructor wqlist {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); }
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=MAT_NotSpec;}
wqas(A) ::= AS MATERIALIZED. {A=MAT_Yes;}
//wqas(A) ::= AS NOT MATERIALIZED. {A=MAT_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
+16 -3
View File
@@ -4938,6 +4938,9 @@ static int withExpand(
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
assert( pFrom->pSelect );
if( pCte->eMaterialized==MAT_Yes ){
pFrom->pSelect->selFlags |= SF_OptBarrier;
}
/* Check if this is a recursive CTE. */
pRecTerm = pSel = pFrom->pSelect;
@@ -6070,6 +6073,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. */
@@ -6194,6 +6200,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)
){
@@ -6214,16 +6221,22 @@ int sqlite3Select(
/* 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 not optimization
** barrier.
**
** 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) */
&& (pSub->selFlags & SF_OptBarrier)==0 /* (2) */
){
/* Implement a co-routine that will return a single row of the result
** set on each invocation.
+22 -9
View File
@@ -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;
@@ -3185,6 +3186,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
@@ -3867,19 +3869,28 @@ 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.eMAterialized
*/
#define MAT_NotSpec 0 /* Not specified */
#define MAT_Yes 1 /* AS MATERIALIZED ... */
#define MAT_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.
*/
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 eMaterialized; /* One of the MAT_* values */
};
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];
int nCte; /* Number of CTEs in the WITH clause */
With *pOuter; /* Containing WITH clause, or NULL */
Cte a[1]; /* The CTEs of this WITH clause */
};
#ifdef SQLITE_DEBUG
@@ -4883,7 +4894,9 @@ 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
+2 -1
View File
@@ -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 },