]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Lexer and grammar rules for a RETURNING clause on DELETE/INSERT/UPDATE.
authordrh <>
Tue, 12 Jan 2021 20:16:31 +0000 (20:16 +0000)
committerdrh <>
Tue, 12 Jan 2021 20:16:31 +0000 (20:16 +0000)
Actually making this work, though, will involve a lot more code which will
likely slow down processing for the common case where there is no
RETURNING clause.  Furthermore, RETURNING seems to be of limited usefulness
and it is not standard SQL.  So we abandon it here.  These experimental
changes are parked in a branch as an historical reference.  If circumstances
changes, we might take up the cause again some day.

FossilOrigin-Name: abf8da815646055df5b871d54b99994c1470182dee7952fc5fd627e4379406cb

manifest
manifest.uuid
src/build.c
src/parse.y
src/sqliteInt.h
tool/mkkeywordhash.c

index 018db9705447676df0df70129f69f9fcc7d7be01..9c330a0aad6bf085d479ff4f14b708a73f5ce854 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Merge\sthe\sParseCleanup\senhancement\sto\strunk.
-D 2021-01-12T16:26:36.110
+C Lexer\sand\sgrammar\srules\sfor\sa\sRETURNING\sclause\son\sDELETE/INSERT/UPDATE.\nActually\smaking\sthis\swork,\sthough,\swill\sinvolve\sa\slot\smore\scode\swhich\swill\nlikely\sslow\sdown\sprocessing\sfor\sthe\scommon\scase\swhere\sthere\sis\sno\nRETURNING\sclause.\s\sFurthermore,\sRETURNING\sseems\sto\sbe\sof\slimited\susefulness\nand\sit\sis\snot\sstandard\sSQL.\s\sSo\swe\sabandon\sit\shere.\s\sThese\sexperimental\nchanges\sare\sparked\sin\sa\sbranch\sas\san\shistorical\sreference.\s\sIf\scircumstances\nchanges,\swe\smight\stake\sup\sthe\scause\sagain\ssome\sday.
+D 2021-01-12T20:16:31.150
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -484,7 +484,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
 F src/btree.c 0f9cb686871ae668817673f0823b55d1bcadbc86ea28bd22c590b064a8322d5a
 F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e
 F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331
-F src/build.c d4c06261b0e532523ede58dc511381a7a9c155132e4b65a6bb2ff76fe657793a
+F src/build.c ba8af18891c07501a185ecd02a2bc13a593de9bfd59dbffa5d126780c0c9fb8e
 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410
@@ -529,7 +529,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 6c8aa09a7fa6e0867c3a3d67ef61b911aa392c9b084a61dc632cd93732aef8ad
+F src/parse.y 6b462c25bae7e0c53f2935f9157f82abeba07754905ef8835c978742c5473ff3
 F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
 F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
@@ -545,7 +545,7 @@ F src/shell.c.in 79bceb990e4bac23a09bb8dd65783ea4867b8bfca9242b5a82b884043e65109
 F src/sqlite.h.in 0af968a1fa3c717261e1df0ed105fa7bddb4d82de7e0adb3eab49e6aa81b4de7
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
-F src/sqliteInt.h c7c7e0e79769885a1c7fa519299bdb222e83e2d7d4843ed6ca1cd9a585016386
+F src/sqliteInt.h de0ba6b4f9bcddd665b4aa8feead3108e737536f061bad85992ffbad8050239f
 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -1823,7 +1823,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 24e4396ae665d985fed9e040e8b748129c1a12d77eeeae7ad4609821c41ba7bf
+F tool/mkkeywordhash.c 750f25aef0e23f8e3367af6d824fbf5ed7d3e285f27cea91aa2dd72c367630eb
 F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
 F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
 F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
@@ -1895,8 +1895,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 8f3ab5da4c8906b63e2c1a0021a3ba4f60e7199e8640518060f998876a002663 38ef8ab9830e12acd2c710e113939b1f8dced02612c6933c37a3c948a4030d0a
-R a2b97b3e175b432108521b3e9366ef42
-T +closed 38ef8ab9830e12acd2c710e113939b1f8dced02612c6933c37a3c948a4030d0a
+P 35824c1bcbd89ae4a94acfbe511bfbd888c418b981819e72bc9a991fc82d136c
+R f88ede067372ddc1781e1314bfb966d4
+T *branch * returning
+T *sym-returning *
+T -sym-trunk *
 U drh
-Z 9c0d514193cce7631d3a6adc01edb18c
+Z a56a87fefbb361b1248407b671a1766d
index 730c7d084cc0e490efa7ceae154d891dd0797b26..1bce0b6baabd48fc43288454e8aeddd88094c541 100644 (file)
@@ -1 +1 @@
-35824c1bcbd89ae4a94acfbe511bfbd888c418b981819e72bc9a991fc82d136c
\ No newline at end of file
+abf8da815646055df5b871d54b99994c1470182dee7952fc5fd627e4379406cb
\ No newline at end of file
index 50289c6a1d4bf3fcc7cd4cdb4c74b72aee717080..5b4bbe499b119de80be141c3786f8b964d7518ec 100644 (file)
@@ -1243,6 +1243,14 @@ void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
 }
 #endif
 
+/*
+** Add the RETURNING clause to the parser currently underway.
+*/
+void sqlite3AddReturning(Parse *pParse, ExprList *pList){
+  sqlite3ParserAddCleanup(pParse,
+     (void(*)(sqlite3*,void*))sqlite3ExprListDelete, pList);
+  pParse->pReturning = pList;
+}
 
 /*
 ** Add a new column to the table currently being constructed.
index faec4b5cf582185878ecb472416166a23bcca275..4c79d4a87ae52a2c452492a70c6856832934044d 100644 (file)
@@ -868,7 +868,7 @@ limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
 /////////////////////////// The DELETE statement /////////////////////////////
 //
 %if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER
-cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W) 
+cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt_ret(W)
         orderby_opt(O) limit_opt(L). {
   sqlite3SrcListIndexedBy(pParse, X, &I);
 #ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
@@ -881,7 +881,7 @@ cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W)
   sqlite3DeleteFrom(pParse,X,W,O,L);
 }
 %else
-cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W). {
+cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt_ret(W). {
   sqlite3SrcListIndexedBy(pParse, X, &I);
   sqlite3DeleteFrom(pParse,X,W,0,0);
 }
@@ -889,9 +889,17 @@ cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W). {
 
 %type where_opt {Expr*}
 %destructor where_opt {sqlite3ExprDelete(pParse->db, $$);}
+%type where_opt_ret {Expr*}
+%destructor where_opt_ret {sqlite3ExprDelete(pParse->db, $$);}
 
 where_opt(A) ::= .                    {A = 0;}
 where_opt(A) ::= WHERE expr(X).       {A = X;}
+where_opt_ret(A) ::= .                                      {A = 0;}
+where_opt_ret(A) ::= WHERE expr(X).                         {A = X;}
+where_opt_ret(A) ::= RETURNING selcollist(X).               
+       {sqlite3AddReturning(pParse,X); A = 0;}
+where_opt_ret(A) ::= WHERE expr(X) RETURNING selcollist(Y).
+       {sqlite3AddReturning(pParse,Y); A = X;}
 
 ////////////////////////// The UPDATE command ////////////////////////////////
 //
@@ -946,7 +954,7 @@ cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) select(S)
         upsert(U). {
   sqlite3Insert(pParse, X, S, F, R, U);
 }
-cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES.
+cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES returning.
 {
   sqlite3Insert(pParse, X, 0, F, R, 0);
 }
@@ -959,16 +967,20 @@ cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES.
 // avoid unreachable code.
 //%destructor upsert {sqlite3UpsertDelete(pParse->db,$$);}
 upsert(A) ::= . { A = 0; }
+upsert(A) ::= RETURNING selcollist(X).  { A = 0; sqlite3AddReturning(pParse,X); }
 upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW)
               DO UPDATE SET setlist(Z) where_opt(W) upsert(N).
               { A = sqlite3UpsertNew(pParse->db,T,TW,Z,W,N);}
 upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO NOTHING upsert(N).
               { A = sqlite3UpsertNew(pParse->db,T,TW,0,0,N); }
-upsert(A) ::= ON CONFLICT DO NOTHING.
+upsert(A) ::= ON CONFLICT DO NOTHING returning.
               { A = sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
-upsert(A) ::= ON CONFLICT DO UPDATE SET setlist(Z) where_opt(W).
+upsert(A) ::= ON CONFLICT DO UPDATE SET setlist(Z) where_opt(W) returning.
               { A = sqlite3UpsertNew(pParse->db,0,0,Z,W,0);}
 
+returning ::= RETURNING selcollist(X).  {sqlite3AddReturning(pParse,X);}
+returning ::= .
+
 %type insert_cmd {int}
 insert_cmd(A) ::= INSERT orconf(R).   {A = R;}
 insert_cmd(A) ::= REPLACE.            {A = OE_Replace;}
index 6d1e598d9457bd81a7ee93476f790d9a4a9840f9..c7dd11862f2f121dbd00c8a69d023906cc1539a6 100644 (file)
@@ -3405,6 +3405,7 @@ struct Parse {
   int nLabelAlloc;     /* Number of slots in aLabel */
   int *aLabel;         /* Space to hold the labels */
   ExprList *pConstExpr;/* Constant expressions */
+  ExprList *pReturning;/* The RETURNING clause, if any */
   Token constraintName;/* Name of the constraint currently being parsed */
   yDbMask writeMask;   /* Start a write transaction on these databases */
   yDbMask cookieMask;  /* Bitmask of schema verified databases */
@@ -4248,6 +4249,7 @@ void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
 void sqlite3AddCollateType(Parse*, Token*);
 void sqlite3AddGenerated(Parse*,Expr*,Token*);
 void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
+void sqlite3AddReturning(Parse*,ExprList*);
 int sqlite3ParseUri(const char*,const char*,unsigned int*,
                     sqlite3_vfs**,char**,char **);
 #define sqlite3CodecQueryParameters(A,B,C) 0
index f8537a85bd9771bcdad513888e6650e334d7b580..ea3763fd196a064d3e3aa706caa8102d9a584475 100644 (file)
@@ -155,10 +155,16 @@ struct Keyword {
 #  define WINDOWFUNC 0x00100000
 #endif
 #ifdef SQLITE_OMIT_GENERATED_COLUMNS
-#  define GENCOL 0
+#  define GENCOL     0
 #else
-#  define GENCOL 0x00200000
+#  define GENCOL     0x00200000
 #endif
+#ifdef SQLITE_OMIT_RETURNING
+#  define RETURNING  0
+#else
+#  define RETURNING  0x00400000
+#endif
+
 
 /*
 ** These are the keywords
@@ -280,6 +286,7 @@ static Keyword aKeywordTable[] = {
   { "RENAME",           "TK_RENAME",       ALTER,            1      },
   { "REPLACE",          "TK_REPLACE",      CONFLICT,         10     },
   { "RESTRICT",         "TK_RESTRICT",     FKEY,             1      },
+  { "RETURNING",        "TK_RETURNING",    RETURNING,        10     },
   { "RIGHT",            "TK_JOIN_KW",      ALWAYS,           0      },
   { "ROLLBACK",         "TK_ROLLBACK",     ALWAYS,           1      },
   { "ROW",              "TK_ROW",          TRIGGER,          1      },