SQLite

Check-in [78dcddd969]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Change the syntax from "GENERATED AS" to "AS MATERIALIZED" so as to match the syntax of PostgreSQL 12+.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | with-generated-as
Files: files | file ages | folders
SHA3-256: 78dcddd9697d95629c18131ab0842aa4d08bc3c7451cd0e7a8d83e4dde277bda
User & Date: drh 2021-02-16 00:48:51.202
Context
2021-02-16
16:32
Trying to get the new AS MATERIALIZE syntax of CTEs to work. There are still performance and memory management issues. This is a WIP check-in. (check-in: bf0fd9b23a user: drh tags: as-materialize)
00:48
Change the syntax from "GENERATED AS" to "AS MATERIALIZED" so as to match the syntax of PostgreSQL 12+. (Closed-Leaf check-in: 78dcddd969 user: drh tags: with-generated-as)
2021-02-15
17:51
Merge the LIKE operator fix from trunk. (check-in: 8c8618780a user: drh tags: with-generated-as)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/build.c.
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219


5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
** 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 bOptBarrier         /* This CTE should be an optimization barrier*/
){
  Cte *pNew;
  sqlite3 *db = pParse->db;



  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->bOptBarrier = bOptBarrier;
  }
  return pNew;
}

/*
** Free the contents of the CTE object passed as the second argument.
*/







|




>
>











|







5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
** 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.
*/
Changes to src/parse.y.
243
244
245
246
247
248
249

250

251
252
253
254
255
256
257
258
259
%ifdef SQLITE_OMIT_COMPOUND_SELECT
  EXCEPT INTERSECT UNION
%endif SQLITE_OMIT_COMPOUND_SELECT
%ifndef SQLITE_OMIT_WINDOWFUNC
  CURRENT FOLLOWING PARTITION PRECEDING RANGE UNBOUNDED
  EXCLUDE GROUPS OTHERS TIES
%endif SQLITE_OMIT_WINDOWFUNC

  GENERATED

%ifndef SQLITE_OMIT_GENERATED_COLUMNS
  ALWAYS
%endif
  REINDEX RENAME CTIME_KW IF
  .
%wildcard ANY.

// Define operator precedence early so that this is the first occurrence
// of the operator tokens in the grammer.  Keeping the operators together







>
|
>
|
|







243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
%ifdef SQLITE_OMIT_COMPOUND_SELECT
  EXCEPT INTERSECT UNION
%endif SQLITE_OMIT_COMPOUND_SELECT
%ifndef SQLITE_OMIT_WINDOWFUNC
  CURRENT FOLLOWING PARTITION PRECEDING RANGE UNBOUNDED
  EXCLUDE GROUPS OTHERS TIES
%endif SQLITE_OMIT_WINDOWFUNC
%ifndef SQLITE_OMIT_GENERATED_COLUMNS
  GENERATED ALWAYS
%endif
%ifndef SQLITE_OMIT_CTE
  MATERIALIZED
%endif
  REINDEX RENAME CTIME_KW IF
  .
%wildcard ANY.

// Define operator precedence early so that this is the first occurrence
// of the operator tokens in the grammer.  Keeping the operators together
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671

1672
1673
1674
1675
1676
1677
1678
1679
1680


//////////////////////// COMMON TABLE EXPRESSIONS ////////////////////////////
%type wqlist {With*}
%destructor wqlist {sqlite3WithDelete(pParse->db, $$);}
%type wqitem {Cte*}
%destructor wqitem {sqlite3CteDelete(pParse->db, $$);}
%type wqgen {int}

with ::= .
%ifndef SQLITE_OMIT_CTE
with ::= WITH wqlist(W).              { sqlite3WithPush(pParse, W, 1); }
with ::= WITH RECURSIVE wqlist(W).    { sqlite3WithPush(pParse, W, 1); }

wqgen(A) ::= .           {A=0;}

wqgen(A) ::= GENERATED.  {A=1;}
wqitem(A) ::= nm(X) eidlist_opt(Y) wqgen(F) AS LP select(Z) RP. {
  A = sqlite3CteNew(pParse, &X, Y, Z, F); /*A-overwrites-X*/
}
wqlist(A) ::= wqitem(X). {
  A = sqlite3WithAdd(pParse, 0, X); /*A-overwrites-X*/
}
wqlist(A) ::= wqlist(A) COMMA wqitem(X). {
  A = sqlite3WithAdd(pParse, A, X);







|






|
>
|
|







1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683


//////////////////////// 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); }

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) ::= wqitem(X). {
  A = sqlite3WithAdd(pParse, 0, X); /*A-overwrites-X*/
}
wqlist(A) ::= wqlist(A) COMMA wqitem(X). {
  A = sqlite3WithAdd(pParse, A, X);
Changes to src/select.c.
4934
4935
4936
4937
4938
4939
4940

4941

4942
4943
4944
4945
4946
4947
4948
    pTab->zName = sqlite3DbStrDup(db, pCte->zName);
    pTab->iPKey = -1;
    pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
    pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
    pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
    if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
    assert( pFrom->pSelect );

    if( pCte->bOptBarrier ) pFrom->pSelect->selFlags |= SF_OptBarrier;


    /* Check if this is a recursive CTE. */
    pRecTerm = pSel = pFrom->pSelect;
    bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
    while( bMayRecursive && pRecTerm->op==pSel->op ){
      int i;
      SrcList *pSrc = pRecTerm->pSrc;







>
|
>







4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
    pTab->zName = sqlite3DbStrDup(db, pCte->zName);
    pTab->iPKey = -1;
    pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
    pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
    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;
    bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
    while( bMayRecursive && pRecTerm->op==pSel->op ){
      int i;
      SrcList *pSrc = pRecTerm->pSrc;
Changes to src/sqliteInt.h.
3865
3866
3867
3868
3869
3870
3871







3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
** Return code from the parse-tree walking primitives and their
** callbacks.
*/
#define WRC_Continue    0   /* Continue down into children */
#define WRC_Prune       1   /* Omit children but continue walking siblings */
#define WRC_Abort       2   /* Abandon the tree walk */








/*
** 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 bOptBarrier;               /* Treat this CTE as an optimization barrier */
};
struct With {
  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 */
};








>
>
>
>
>
>
>









|







3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
** Return code from the parse-tree walking primitives and their
** callbacks.
*/
#define WRC_Continue    0   /* Continue down into children */
#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 */
  Cte a[1];                     /* The CTEs of this WITH clause */
};

Changes to tool/mkkeywordhash.c.
251
252
253
254
255
256
257

258
259
260
261
262
263
264
  { "JOIN",             "TK_JOIN",         ALWAYS,           5      },
  { "KEY",              "TK_KEY",          ALWAYS,           1      },
  { "LAST",             "TK_LAST",         ALWAYS,           4      },
  { "LEFT",             "TK_JOIN_KW",      ALWAYS,           5      },
  { "LIKE",             "TK_LIKE_KW",      ALWAYS,           5      },
  { "LIMIT",            "TK_LIMIT",        ALWAYS,           3      },
  { "MATCH",            "TK_MATCH",        ALWAYS,           2      },

  { "NATURAL",          "TK_JOIN_KW",      ALWAYS,           3      },
  { "NO",               "TK_NO",           FKEY|WINDOWFUNC,  2      },
  { "NOT",              "TK_NOT",          ALWAYS,           10     },
  { "NOTHING",          "TK_NOTHING",      UPSERT,           1      },
  { "NOTNULL",          "TK_NOTNULL",      ALWAYS,           3      },
  { "NULL",             "TK_NULL",         ALWAYS,           10     },
  { "NULLS",            "TK_NULLS",        ALWAYS,           3      },







>







251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  { "JOIN",             "TK_JOIN",         ALWAYS,           5      },
  { "KEY",              "TK_KEY",          ALWAYS,           1      },
  { "LAST",             "TK_LAST",         ALWAYS,           4      },
  { "LEFT",             "TK_JOIN_KW",      ALWAYS,           5      },
  { "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     },
  { "NOTHING",          "TK_NOTHING",      UPSERT,           1      },
  { "NOTNULL",          "TK_NOTNULL",      ALWAYS,           3      },
  { "NULL",             "TK_NULL",         ALWAYS,           10     },
  { "NULLS",            "TK_NULLS",        ALWAYS,           3      },