From: dan Date: Sat, 11 Jan 2014 19:19:36 +0000 (+0000) Subject: Update the parser so that sub-queries and CTEs may have WITH clauses. X-Git-Tag: version-3.8.3~45^2~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7d562dbe023a06bc8b7116c5415c5cb9b6a25cfc;p=thirdparty%2Fsqlite.git Update the parser so that sub-queries and CTEs may have WITH clauses. FossilOrigin-Name: 704d3931b855562a619769955969d439c42ca406 --- diff --git a/manifest b/manifest index 16d294c829..c9d03126cd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Parse\scommon\stable\sexpressions.\s\sBut\sdo\snot\sdo\sanything\swith\sthem\s(yet). -D 2014-01-11T13:22:17.016 +C Update\sthe\sparser\sso\sthat\ssub-queries\sand\sCTEs\smay\shave\sWITH\sclauses. +D 2014-01-11T19:19:36.147 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -169,7 +169,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c 11e29ef8cf16a42925fde036bcffbeffd9cc82df F src/btree.h a61ddebc78c66795a2b93181321a116746302cc9 F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0 -F src/build.c 198670a78fe748b6e60d6345a8aa1db57794511a +F src/build.c 1da29e4e93d9774599f1f791d011ba46d841000c F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd @@ -209,7 +209,7 @@ F src/os_unix.c 3a4dcb554d3c915075766162f28c3fd4cdb75968 F src/os_win.c 16eac0961603182ffc10c02b39fe830126538e07 F src/pager.c efa923693e958696eee69b205a20bfbc402c8480 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 -F src/parse.y 0ccd364dd3670ad5763a5e94dd11196ddc10927a +F src/parse.y 1e3fd22fc82930d0cce01f2ab90616100c59ee0c F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c 57fee9a9a617218f5037afbbe49b09da65bde56b @@ -224,7 +224,7 @@ F src/shell.c a3541193d5fce37e91dad8ef46a9505aa7c9b344 F src/sqlite.h.in d94a8b89522f526ba711182ee161e06f8669bcc9 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h bb093076ba1eb956330cca0ca2a206c91facab4b +F src/sqliteInt.h 2710b3a6c66edda9f193453268f6fe878ff5a0ca F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -1091,6 +1091,7 @@ F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d +F test/with1.test e8146198319c3627bb21ef085c58a827f35686a7 F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8 F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99 F test/without_rowid3.test eac3d5c8a1924725b58503a368f2cbd24fd6c8a0 @@ -1148,10 +1149,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 29ba458d849ad8864711cbe59fb10447a947e06a -R b8f42a0591e43b680c1e09056e8afd6e -T *branch * common-table-expr -T *sym-common-table-expr * -T -sym-trunk * -U drh -Z 9a38087dfe69ad33926bbf7c01c0b22a +P da98b7205eb3d7ec2ddbf8a8e24eee0b2ff499a5 +R bbb9d541af414d7b8bb3f418deb50875 +U dan +Z a973a84816d55810384771a899b1092b diff --git a/manifest.uuid b/manifest.uuid index 17610fd9e7..f6a009da18 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -da98b7205eb3d7ec2ddbf8a8e24eee0b2ff499a5 \ No newline at end of file +704d3931b855562a619769955969d439c42ca406 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 4fb4b4efa9..23628f73be 100644 --- a/src/build.c +++ b/src/build.c @@ -4200,22 +4200,26 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ } #ifndef SQLITE_OMIT_CTE -/* This routine is invoked when a single with_query of a -** common-table-expression has been parsed. Record the query. +/* +** This routine is invoked once per CTE by the parser while parsing a +** WITH clause. */ -void sqlite3CteAdd( +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 */ + IdList *pArglist, /* Optional column name list for the table */ Select *pQuery /* Query used to initialize the table */ ){ - sqlite3ExprListDelete(pParse->db, pArgList); + sqlite3IdListDelete(pParse->db, pArglist); sqlite3SelectDelete(pParse->db, pQuery); + return 0; } -/* This routine is invoked at the end of the entire WITH clause. +/* +** Free the contents of the With object passed as the second argument. */ -void sqlite3CteFinish(Parse *pParse, int isRecursive){ +void sqlite3WithDelete(sqlite3 *db, With *pWith){ /* TBD */ } #endif /* !defined(SQLITE_OMIT_CTE) */ diff --git a/src/parse.y b/src/parse.y index f4fa4b276d..c3cb2d62aa 100644 --- a/src/parse.y +++ b/src/parse.y @@ -396,7 +396,7 @@ cmd ::= DROP VIEW ifexists(E) fullname(X). { //////////////////////// The SELECT statement ///////////////////////////////// // -cmd ::= with select(X). { +cmd ::= select(X). { SelectDest dest = {SRT_Output, 0, 0, 0, 0}; sqlite3Select(pParse, X, &dest); sqlite3ExplainBegin(pParse->pVdbe); @@ -407,12 +407,16 @@ cmd ::= with select(X). { %type select {Select*} %destructor select {sqlite3SelectDelete(pParse->db, $$);} +%type selectnowith {Select*} +%destructor selectnowith {sqlite3SelectDelete(pParse->db, $$);} %type oneselect {Select*} %destructor oneselect {sqlite3SelectDelete(pParse->db, $$);} -select(A) ::= oneselect(X). {A = X;} +select(A) ::= with selectnowith(X). {A = X;} + +selectnowith(A) ::= oneselect(X). {A = X;} %ifndef SQLITE_OMIT_COMPOUND_SELECT -select(A) ::= select(X) multiselect_op(Y) oneselect(Z). { +selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). { if( Z ){ Z->op = (u8)Y; Z->pPrior = X; @@ -1365,13 +1369,19 @@ anylist ::= anylist ANY. //////////////////////// COMMON TABLE EXPRESSIONS //////////////////////////// -with ::= . +%type with {With*} +%type wqlist {With*} +%destructor with {sqlite3WithDelete(pParse->db, $$);} + +with(A) ::= . {A = 0;} %ifndef SQLITE_OMIT_CTE -with ::= WITH wqlist. {sqlite3CteFinish(pParse, 0);} -with ::= WITH RECURSIVE wqlist. {sqlite3CteFinish(pParse, 1);} -wqlist ::= with_query. -wqlist ::= wqlist COMMA with_query. -with_query ::= nm(X) idxlist_opt(Y) AS LP select(Z) RP. { - sqlite3CteAdd(pParse, &X, Y, Z); +with(A) ::= WITH wqlist(W). { A = W; } +with(A) ::= WITH RECURSIVE wqlist(W). { A = W; } + +wqlist(A) ::= nm(X) inscollist_opt(Y) AS LP select(Z) RP. { + A = sqlite3WithAdd(pParse, 0, &X, Y, Z); +} +wqlist(A) ::= wqlist(W) COMMA nm(X) inscollist_opt(Y) AS LP select(Z) RP. { + A = sqlite3WithAdd(pParse, W, &X, Y, Z); } %endif SQLITE_OMIT_CTE diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d517789da0..8846ffb04c 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -760,6 +760,7 @@ typedef struct VTable VTable; typedef struct VtabCtx VtabCtx; typedef struct Walker Walker; typedef struct WhereInfo WhereInfo; +typedef struct With With; /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and @@ -2631,6 +2632,19 @@ int sqlite3WalkSelectFrom(Walker*, Select*); #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 CTEs (common table +** expressions) created by a single WITH clause. +*/ +struct With { + int nCte; /* Number of CTEs */ + struct Cte { + const char *zName; /* Name of this CTE */ + IdList *pCol; /* List of explicit column names, or NULL */ + Select *pSelect; /* The contents of the CTE */ + } a[1]; +}; + /* ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. @@ -3330,8 +3344,8 @@ const char *sqlite3JournalModename(int); int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); #endif #ifndef SQLITE_OMIT_CTE - void sqlite3CteAdd(Parse*,Token*,ExprList*,Select*); - void sqlite3CteFinish(Parse*,int); + With *sqlite3WithAdd(Parse*,With*,Token*,IdList*,Select*); + void sqlite3WithDelete(sqlite3*,With*); #endif /* Declarations for functions in fkey.c. All of these are replaced by diff --git a/test/with1.test b/test/with1.test new file mode 100644 index 0000000000..80e879ada0 --- /dev/null +++ b/test/with1.test @@ -0,0 +1,40 @@ +# 2014 January 11 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the WITH clause. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix with1 + +do_execsql_test 1.0 { + CREATE TABLE t1(x INTEGER, y INTEGER); + WITH x(a) AS ( SELECT * FROM t1) SELECT 10 +} {10} + +do_execsql_test 1.1 { + SELECT * FROM ( WITH x AS ( SELECT * FROM t1) SELECT 10 ); +} {10} + +do_execsql_test 1.2 { + WITH x(a) AS ( SELECT * FROM t1) INSERT INTO t1 VALUES(1,2); +} {} + +do_execsql_test 1.3 { + WITH x(a) AS ( SELECT * FROM t1) DELETE FROM t1; +} {} + +do_execsql_test 1.4 { + WITH x(a) AS ( SELECT * FROM t1) UPDATE t1 SET x = y; +} {} + +finish_test