From 2053f313bfc498262f13c04793b93867f58544ba Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 12 Jan 2021 20:16:31 +0000 Subject: [PATCH 01/23] Lexer and grammar rules for a RETURNING clause on DELETE/INSERT/UPDATE. 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 | 22 ++++++++++++---------- manifest.uuid | 2 +- src/build.c | 8 ++++++++ src/parse.y | 22 +++++++++++++++++----- src/sqliteInt.h | 2 ++ tool/mkkeywordhash.c | 11 +++++++++-- 6 files changed, 49 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index 018db97054..9c330a0aad 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 730c7d084c..1bce0b6baa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -35824c1bcbd89ae4a94acfbe511bfbd888c418b981819e72bc9a991fc82d136c \ No newline at end of file +abf8da815646055df5b871d54b99994c1470182dee7952fc5fd627e4379406cb \ No newline at end of file diff --git a/src/build.c b/src/build.c index 50289c6a1d..5b4bbe499b 100644 --- a/src/build.c +++ b/src/build.c @@ -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. diff --git a/src/parse.y b/src/parse.y index faec4b5cf5..4c79d4a87a 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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;} diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 6d1e598d94..c7dd11862f 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 diff --git a/tool/mkkeywordhash.c b/tool/mkkeywordhash.c index f8537a85bd..ea3763fd19 100644 --- a/tool/mkkeywordhash.c +++ b/tool/mkkeywordhash.c @@ -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 }, From b83524795427e9ad8131fe9827e397f973b37932 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 29 Jan 2021 19:32:17 +0000 Subject: [PATCH 02/23] Working prototype. FossilOrigin-Name: b7ef4dc21f187ff4ff679e823782535188c3814aa6ce720b3a01c6d3ba4ef9f5 --- manifest | 26 +++++++++++++------------- manifest.uuid | 2 +- src/build.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- src/fkey.c | 3 ++- src/parse.y | 4 ++-- src/resolve.c | 11 +++++++---- src/sqliteInt.h | 17 ++++++++++++++++- src/trigger.c | 20 +++++++++++++++++--- src/vdbe.h | 1 + src/vdbeaux.c | 14 ++++++++++++++ 10 files changed, 117 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index d18146bacc..4720b86680 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Incorporate\sthe\ssqlite3TriggerList()\soptimization\sfrom\strunk.\s\sAnd\smove\nthe\spReturning\sfield\sto\sthe\suninitialized\sarea\sin\sthe\sParse\sobject,\sto\nsave\smemset()\stime. -D 2021-01-29T14:22:56.875 +C Working\sprototype. +D 2021-01-29T19:32:17.139 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 47d9fe97d5c0d74506154e3597f8a23b81a00080751dc4d11fec91ee22796f4c F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 -F src/build.c ba8af18891c07501a185ecd02a2bc13a593de9bfd59dbffa5d126780c0c9fb8e +F src/build.c 2aded84176695b0f885eec582f3afbe667737998a14fb39b3eb6623626a8f2b5 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410 @@ -495,7 +495,7 @@ F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c F src/delete.c 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe F src/expr.c 47c85263e6d179424e6b09e2c79db5704ab5b8cbc2fae2ee3285faa2566f2e74 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 -F src/fkey.c 83372403298e6a7dd989a47aaacdbaa5b4307b5199dbd56e07d4896066b3de72 +F src/fkey.c df06098e66c95bb5169e2e79eb59583efe00794e6345e196e776dd6f4b1ea33b F src/func.c 796a7a4a0ff5eee82a04ee3c8265c5ebf9c6a9f5625621c5f97ed94f6224d7d9 F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 @@ -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 6b462c25bae7e0c53f2935f9157f82abeba07754905ef8835c978742c5473ff3 +F src/parse.y 67ba503780de64b967ae195b7e14c33531329228e1bc0b83d63324beb733680b F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a @@ -539,14 +539,14 @@ F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf F src/prepare.c f288cbc35f79eb32e162de7e80a63ebe00d80e639dcfac071bee11570cbdb16f F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 -F src/resolve.c 1948a92ca9eab776632816b97e57c61d933474a78aad4f4ef835c916a83dbb1c +F src/resolve.c b714e6f9f3cdfb6ba287bb5ef76888ec8cd9e15c98a608c82bc3300b99a245d7 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 738cb746189f721f59972993c13085fa2975c4cbfd04ba26445f3b42c81237dc F src/shell.c.in 9ebc74e4f05cfbd0f4a36060fdaeff1da4e9af4458358722bc08c5a1ab9a0879 F src/sqlite.h.in 0af968a1fa3c717261e1df0ed105fa7bddb4d82de7e0adb3eab49e6aa81b4de7 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h aebfa715feaf134b5d0cf6a2dccb4a4d0172d7915658c69abd5b3a0cb3b794d3 +F src/sqliteInt.h e3ad4cc28df195a9676d9f108d2cd1d41da6b505950797dc069094d90fd9f197 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -607,17 +607,17 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 731ea5ed6b308574b7dc2a5d2a9187ef5510a3692cc1ea06a34608a084b8f376 +F src/trigger.c 39ac8d708d6c929817c230fba0cf1ef5bd7ac52ce883df8ab49bcdc28817a787 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 F src/vdbe.c 102d21260bddbb43c845603c3a2d6b4f3762e72f836ccda12991f291485d2539 -F src/vdbe.h 83603854bfa5851af601fc0947671eb260f4363e62e960e8a994fb9bbcd2aaa1 +F src/vdbe.h a71bf43572d3de57923d1928ac01ae8d355cd67e94462ba4f7462265cedbef9a F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9 -F src/vdbeaux.c e91d74e24babcf61969279b193e228cf4f8bc724a9cc59ed287db064326876f8 +F src/vdbeaux.c 7ae7b2d7d97250d7100065eca7f04324f331b16b8165775f1724af10c7240d11 F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1 F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f F src/vdbesort.c f5b5e473a7cee44e47a94817b042fd7172cf3aa2c0a7928a8339d612bcfdec5a @@ -1898,7 +1898,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 5fbcb208d24d45169fc53ad8738dd3545d9bbd26b7434e31afc7f6419cd4e958 0defaf730bdc82212a5d3feeb2e16f16423b1691b0aaa7da1787eb82ea39ae9e -R c5cf37660ce1737a23c63b9fdc43eb3e +P 29fbaf0e3eabda08500f350bc32e9f339e5732a65bfa62822eefb692a2ff0243 +R 0f4eeb3bbbe288c435a7916147e604d5 U drh -Z c6d2a25c829d2b926a3cb0974507f1ba +Z cf32b347d108b527d7c22e05c5929805 diff --git a/manifest.uuid b/manifest.uuid index 64051cb566..9c5f6afd5b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -29fbaf0e3eabda08500f350bc32e9f339e5732a65bfa62822eefb692a2ff0243 \ No newline at end of file +b7ef4dc21f187ff4ff679e823782535188c3814aa6ce720b3a01c6d3ba4ef9f5 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 5b4bbe499b..99ecad4d63 100644 --- a/src/build.c +++ b/src/build.c @@ -1243,13 +1243,55 @@ void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ } #endif +/* +** Name of the magic TEMP trigger used to implement RETURNING +*/ +#define RETURNING_TRIGGER "sqlite_returning" + +/* +** Delete the data structures associated with the RETURNING clause. +*/ +static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){ + Hash *pHash; + pHash = &(db->aDb[1].pSchema->trigHash); + assert( sqlite3HashFind(pHash, RETURNING_TRIGGER)==&pRet->retTrig ); + sqlite3HashInsert(pHash, RETURNING_TRIGGER, 0); + sqlite3ExprListDelete(db, pRet->pReturnEL); + sqlite3DbFree(db, pRet); +} + /* ** Add the RETURNING clause to the parser currently underway. */ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ + Returning *pRet; + Hash *pHash; + sqlite3 *db = pParse->db; + pRet = sqlite3DbMallocZero(db, sizeof(*pRet)); + if( pRet==0 ){ + sqlite3ExprListDelete(db, pList); + return; + } + pRet->pParse = pParse; + pRet->pReturnEL = pList; sqlite3ParserAddCleanup(pParse, - (void(*)(sqlite3*,void*))sqlite3ExprListDelete, pList); - pParse->pReturning = pList; + (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet); + pRet->retTrig.zName = "sqlite_returning"; + pRet->retTrig.op = TK_RETURNING; + pRet->retTrig.tr_tm = TRIGGER_AFTER; + pRet->retTrig.bReturning = 1; + pRet->retTrig.pSchema = db->aDb[1].pSchema; + pRet->retTrig.step_list = &pRet->retTStep; + pRet->retTStep.op = TK_SELECT; + pRet->retTStep.eTrigDest = SRT_Output; + pRet->retTStep.pTrig = &pRet->retTrig; + pRet->retTStep.pSelect = &pRet->retSel; + pRet->retSel.op = TK_ALL; + pRet->retSel.pEList = pList; + pRet->retSel.pSrc = (SrcList*)&pRet->retSrcList; + pHash = &(db->aDb[1].pSchema->trigHash); + assert( sqlite3HashFind(pHash, RETURNING_TRIGGER)==0 ); + sqlite3HashInsert(pHash, "sqlite_returning", &pRet->retTrig); } /* diff --git a/src/fkey.c b/src/fkey.c index 959e994d17..4cb92e2915 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -1352,7 +1352,8 @@ static Trigger *fkActionTrigger( switch( action ){ case OE_Restrict: - pStep->op = TK_SELECT; + pStep->op = TK_SELECT; + pStep->eTrigDest = SRT_Discard; break; case OE_Cascade: if( !pChanges ){ diff --git a/src/parse.y b/src/parse.y index 4c79d4a87a..591cde3b9d 100644 --- a/src/parse.y +++ b/src/parse.y @@ -905,7 +905,7 @@ where_opt_ret(A) ::= WHERE expr(X) RETURNING selcollist(Y). // %if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) - where_opt(W) orderby_opt(O) limit_opt(L). { + where_opt_ret(W) orderby_opt(O) limit_opt(L). { sqlite3SrcListIndexedBy(pParse, X, &I); X = sqlite3SrcListAppendList(pParse, X, F); sqlite3ExprListCheckLength(pParse,Y,"set list"); @@ -920,7 +920,7 @@ cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) } %else cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) - where_opt(W). { + where_opt_ret(W). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3ExprListCheckLength(pParse,Y,"set list"); X = sqlite3SrcListAppendList(pParse, X, F); diff --git a/src/resolve.c b/src/resolve.c index b55bdc4187..fa46954da8 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -371,23 +371,26 @@ static int lookupName( ** it is a new.* or old.* trigger argument reference. Or ** maybe it is an excluded.* from an upsert. */ - if( zDb==0 && zTab!=0 && cntTab==0 ){ + if( zDb==0 && cntTab==0 ){ pTab = 0; #ifndef SQLITE_OMIT_TRIGGER if( pParse->pTriggerTab!=0 ){ int op = pParse->eTriggerOp; assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); - if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){ + if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){ pExpr->iTable = 1; pTab = pParse->pTriggerTab; - }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){ + }else if( op!=TK_INSERT && zTab && sqlite3StrICmp("old",zTab)==0 ){ pExpr->iTable = 0; pTab = pParse->pTriggerTab; + }else if( pParse->bReturning ){ + pExpr->iTable = op!=TK_DELETE; + pTab = pParse->pTriggerTab; } } #endif /* SQLITE_OMIT_TRIGGER */ #ifndef SQLITE_OMIT_UPSERT - if( (pNC->ncFlags & NC_UUpsert)!=0 ){ + if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab ){ Upsert *pUpsert = pNC->uNC.pUpsert; if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ pTab = pUpsert->pUpsertSrc->a[0].pTab; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c66b44290c..231ead5062 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1159,6 +1159,7 @@ typedef struct ParseCleanup ParseCleanup; typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; typedef struct RenameToken RenameToken; +typedef struct Returning Returning; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; @@ -3429,6 +3430,7 @@ struct Parse { u32 oldmask; /* Mask of old.* columns referenced */ u32 newmask; /* Mask of new.* columns referenced */ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ + u8 bReturning; /* Coding a RETURNING trigger */ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ u8 disableTriggers; /* True to disable triggers */ @@ -3441,7 +3443,6 @@ struct Parse { int aTempReg[8]; /* Holding area for temporary registers */ Token sNameToken; /* Token with unqualified schema object name */ - ExprList *pReturning; /* The RETURNING clause, if any */ /************************************************************************ ** Above is constant between recursions. Below is reset before and after @@ -3579,6 +3580,7 @@ struct Trigger { char *table; /* The table or view to which the trigger applies */ u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */ u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ + u8 bReturning; /* This trigger implements a RETURNING clause */ Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */ IdList *pColumns; /* If this is an UPDATE OF trigger, the is stored here */ @@ -3639,6 +3641,7 @@ struct Trigger { struct TriggerStep { u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */ u8 orconf; /* OE_Rollback etc. */ + u8 eTrigDest; /* SRT_ destination value for SELECT */ Trigger *pTrig; /* The trigger that this step is a part of */ Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */ char *zTarget; /* Target table for DELETE, UPDATE, INSERT */ @@ -3652,6 +3655,18 @@ struct TriggerStep { TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */ }; +/* +** Information about a RETURNING clause +*/ +struct Returning { + Parse *pParse; /* The parse that includes the RETURNING clause */ + ExprList *pReturnEL; /* List of expressions to return */ + Trigger retTrig; /* The transient trigger that implements RETURNING */ + TriggerStep retTStep; /* The trigger step */ + Select retSel; /* The SELECT statement that implements RETURNING */ + u64 retSrcList; /* The empty FROM clause of the SELECT */ +}; + /* ** An objected used to accumulate the text of a string where we ** do not necessarily know how big the string will be in the end. diff --git a/src/trigger.c b/src/trigger.c index a9378fd3a3..5508e4d151 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -65,11 +65,16 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ while( p ){ Trigger *pTrig = (Trigger *)sqliteHashData(p); if( pTrig->pTabSchema==pTab->pSchema - && 0==sqlite3StrICmp(pTrig->table, pTab->zName) + && 0==sqlite3StrICmp(pTrig->table, pTab->zName) ){ pTrig->pNext = pList; pList = pTrig; - } + }else if( pTrig->op==TK_RETURNING ){ + pTrig->table = pTab->zName; + pTrig->pTabSchema = pTab->pSchema; + pTrig->pNext = pList; + pList = pTrig; + } p = sqliteHashNext(p); } } @@ -405,6 +410,7 @@ TriggerStep *sqlite3TriggerSelectStep( return 0; } pTriggerStep->op = TK_SELECT; + pTriggerStep->eTrigDest = SRT_Discard; pTriggerStep->pSelect = pSelect; pTriggerStep->orconf = OE_Default; pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); @@ -563,6 +569,7 @@ TriggerStep *sqlite3TriggerDeleteStep( */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ if( pTrigger==0 ) return; + assert( !pTrigger->bReturning ); sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); @@ -734,6 +741,9 @@ Trigger *sqlite3TriggersExist( for(p=pList; p; p=p->pNext){ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ mask |= p->tr_tm; + }else if( p->op==TK_RETURNING ){ + p->op = op; + mask |= TRIGGER_AFTER; } } if( pMask ){ @@ -849,7 +859,7 @@ static int codeTriggerProgram( default: assert( pStep->op==TK_SELECT ); { SelectDest sDest; Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0); - sqlite3SelectDestInit(&sDest, SRT_Discard, 0); + sqlite3SelectDestInit(&sDest, pStep->eTrigDest, 0); sqlite3Select(pParse, pSelect, &sDest); sqlite3SelectDelete(db, pSelect); break; @@ -947,6 +957,7 @@ static TriggerPrg *codeRowTrigger( pSubParse->pToplevel = pTop; pSubParse->zAuthContext = pTrigger->zName; pSubParse->eTriggerOp = pTrigger->op; + pSubParse->bReturning = pTrigger->bReturning; pSubParse->nQueryLoop = pParse->nQueryLoop; pSubParse->disableVtab = pParse->disableVtab; @@ -996,6 +1007,9 @@ static TriggerPrg *codeRowTrigger( if( db->mallocFailed==0 && pParse->nErr==0 ){ pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); } + if( pTrigger->bReturning ){ + sqlite3VdbeColumnInfoXfer(pParse->pVdbe, v); + } pProgram->nMem = pSubParse->nMem; pProgram->nCsr = pSubParse->nTab; pProgram->token = (void *)pTrigger; diff --git a/src/vdbe.h b/src/vdbe.h index 17f11fdd77..48be53df7f 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -259,6 +259,7 @@ void sqlite3VdbeResetStepResult(Vdbe*); void sqlite3VdbeRewind(Vdbe*); int sqlite3VdbeReset(Vdbe*); void sqlite3VdbeSetNumCols(Vdbe*,int); +void sqlite3VdbeColumnInfoXfer(Vdbe*,Vdbe*); int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); void sqlite3VdbeCountChanges(Vdbe*); sqlite3 *sqlite3VdbeDb(Vdbe*); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 7b9b792054..9ea20628fe 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2595,6 +2595,20 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ initMemArray(p->aColName, n, db, MEM_Null); } +/* +** Transfer the column count and name information from one Vdbe to +** another. +*/ +void sqlite3VdbeColumnInfoXfer(Vdbe *pTo, Vdbe *pFrom){ + sqlite3 *db = pTo->db; + assert( db==pFrom->db ); + sqlite3DbFree(db, pTo->aColName); + pTo->aColName = pFrom->aColName; + pFrom->aColName = 0; + pTo->nResColumn = pFrom->nResColumn; + pFrom->nResColumn = 0; +} + /* ** Set the name of the idx'th column to be returned by the SQL statement. ** zName must be a pointer to a nul terminated string. From dac9a5f7df0e65f35d6f9de423a90cb7eb52c8b6 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 29 Jan 2021 21:18:46 +0000 Subject: [PATCH 03/23] Allow "*" wildcards in the RETURNING clause. FossilOrigin-Name: b0e3ae303db2a035583a05848ab7977e612d7e40c77e31ea9e0166de443c901f --- manifest | 18 +++++++------- manifest.uuid | 2 +- src/build.c | 3 +-- src/fkey.c | 1 - src/sqliteInt.h | 4 ++-- src/trigger.c | 63 ++++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 70 insertions(+), 21 deletions(-) diff --git a/manifest b/manifest index 4720b86680..562358c6c0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Working\sprototype. -D 2021-01-29T19:32:17.139 +C Allow\s"*"\swildcards\sin\sthe\sRETURNING\sclause. +D 2021-01-29T21:18:46.467 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 47d9fe97d5c0d74506154e3597f8a23b81a00080751dc4d11fec91ee22796f4c F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 -F src/build.c 2aded84176695b0f885eec582f3afbe667737998a14fb39b3eb6623626a8f2b5 +F src/build.c 2da961ffeb6253117a859ddfc682b20969ff7ebd0ec8c9f88636ea16cdc512b4 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410 @@ -495,7 +495,7 @@ F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c F src/delete.c 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe F src/expr.c 47c85263e6d179424e6b09e2c79db5704ab5b8cbc2fae2ee3285faa2566f2e74 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 -F src/fkey.c df06098e66c95bb5169e2e79eb59583efe00794e6345e196e776dd6f4b1ea33b +F src/fkey.c 02e4a3311885cd2b31eb17fd58dc2fc738cd2c823d0d39e4dd5595169c6f8bc3 F src/func.c 796a7a4a0ff5eee82a04ee3c8265c5ebf9c6a9f5625621c5f97ed94f6224d7d9 F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 @@ -546,7 +546,7 @@ F src/shell.c.in 9ebc74e4f05cfbd0f4a36060fdaeff1da4e9af4458358722bc08c5a1ab9a087 F src/sqlite.h.in 0af968a1fa3c717261e1df0ed105fa7bddb4d82de7e0adb3eab49e6aa81b4de7 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h e3ad4cc28df195a9676d9f108d2cd1d41da6b505950797dc069094d90fd9f197 +F src/sqliteInt.h 0fda3b2c05b1559135aa2c4ecb8e75bd2085ba4433310bbb5427d97c2d81315d F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 39ac8d708d6c929817c230fba0cf1ef5bd7ac52ce883df8ab49bcdc28817a787 +F src/trigger.c 47629a1e3fd483347d6cf468d7d397ab50f3ead4286d837ad7054de418767e38 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1898,7 +1898,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 29fbaf0e3eabda08500f350bc32e9f339e5732a65bfa62822eefb692a2ff0243 -R 0f4eeb3bbbe288c435a7916147e604d5 +P b7ef4dc21f187ff4ff679e823782535188c3814aa6ce720b3a01c6d3ba4ef9f5 +R 4fd580e848a9786e2403b5294c0c89d9 U drh -Z cf32b347d108b527d7c22e05c5929805 +Z d7647504631490a0d91f2ce3b7260d98 diff --git a/manifest.uuid b/manifest.uuid index 9c5f6afd5b..e387b3e2f7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b7ef4dc21f187ff4ff679e823782535188c3814aa6ce720b3a01c6d3ba4ef9f5 \ No newline at end of file +b0e3ae303db2a035583a05848ab7977e612d7e40c77e31ea9e0166de443c901f \ No newline at end of file diff --git a/src/build.c b/src/build.c index 99ecad4d63..a25c9c6d80 100644 --- a/src/build.c +++ b/src/build.c @@ -1282,8 +1282,7 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ pRet->retTrig.bReturning = 1; pRet->retTrig.pSchema = db->aDb[1].pSchema; pRet->retTrig.step_list = &pRet->retTStep; - pRet->retTStep.op = TK_SELECT; - pRet->retTStep.eTrigDest = SRT_Output; + pRet->retTStep.op = TK_RETURNING; pRet->retTStep.pTrig = &pRet->retTrig; pRet->retTStep.pSelect = &pRet->retSel; pRet->retSel.op = TK_ALL; diff --git a/src/fkey.c b/src/fkey.c index 4cb92e2915..59e12b5fa8 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -1353,7 +1353,6 @@ static Trigger *fkActionTrigger( switch( action ){ case OE_Restrict: pStep->op = TK_SELECT; - pStep->eTrigDest = SRT_Discard; break; case OE_Cascade: if( !pChanges ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 231ead5062..3cadb7f53a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3639,9 +3639,9 @@ struct Trigger { * */ struct TriggerStep { - u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */ + u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT, + ** or TK_RETURNING */ u8 orconf; /* OE_Rollback etc. */ - u8 eTrigDest; /* SRT_ destination value for SELECT */ Trigger *pTrig; /* The trigger that this step is a part of */ Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */ char *zTarget; /* Target table for DELETE, UPDATE, INSERT */ diff --git a/src/trigger.c b/src/trigger.c index 5508e4d151..a20c14197b 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -410,7 +410,6 @@ TriggerStep *sqlite3TriggerSelectStep( return 0; } pTriggerStep->op = TK_SELECT; - pTriggerStep->eTrigDest = SRT_Discard; pTriggerStep->pSelect = pSelect; pTriggerStep->orconf = OE_Default; pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); @@ -788,6 +787,46 @@ SrcList *sqlite3TriggerStepSrc( return pSrc; } +/* The input list pList is the list of result set terms from a RETURNING +** clause. The table that we are returning from is pTab. +** +** This routine makes a copy of the pList, and at the same time expands +** any "*" wildcards to be the complete set of columns from pTab. +*/ +static ExprList *sqlite3ExpandReturning( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* The arguments to RETURNING */ + Table *pTab /* The table being updated */ +){ + ExprList *pNew = 0; + sqlite3 *db = pParse->db; + int i; + for(i=0; inExpr; i++){ + Expr *pOldExpr = pList->a[i].pExpr; + if( ALWAYS(pOldExpr!=0) && pOldExpr->op==TK_ASTERISK ){ + int j; + for(j=0; jnCol; j++){ + Expr *pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[j].zName); + pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); + if( !db->mallocFailed ){ + struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; + pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[j].zName); + pItem->eEName = ENAME_NAME; + } + } + }else{ + Expr *pNewExpr = sqlite3ExprDup(db, pOldExpr, 0); + pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); + if( pList->a[i].zEName!=0 && !db->mallocFailed ){ + struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; + pItem->zEName = sqlite3DbStrDup(db, pList->a[i].zEName); + pItem->eEName = pList->a[i].eEName; + } + } + } + return pNew; +} + /* ** Generate VDBE code for the statements inside the body of a single ** trigger. @@ -837,6 +876,7 @@ static int codeTriggerProgram( sqlite3ExprDup(db, pStep->pWhere, 0), pParse->eOrconf, 0, 0, 0 ); + sqlite3VdbeAddOp0(v, OP_ResetCount); break; } case TK_INSERT: { @@ -847,6 +887,7 @@ static int codeTriggerProgram( pParse->eOrconf, sqlite3UpsertDup(db, pStep->pUpsert) ); + sqlite3VdbeAddOp0(v, OP_ResetCount); break; } case TK_DELETE: { @@ -854,20 +895,30 @@ static int codeTriggerProgram( sqlite3TriggerStepSrc(pParse, pStep), sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0 ); + sqlite3VdbeAddOp0(v, OP_ResetCount); break; } - default: assert( pStep->op==TK_SELECT ); { + case TK_SELECT: { SelectDest sDest; Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0); - sqlite3SelectDestInit(&sDest, pStep->eTrigDest, 0); + sqlite3SelectDestInit(&sDest, SRT_Discard, 0); sqlite3Select(pParse, pSelect, &sDest); sqlite3SelectDelete(db, pSelect); break; } + default: assert( pStep->op==TK_RETURNING ); { + Select *pSelect = pStep->pSelect; + ExprList *pList = pSelect->pEList; + SelectDest sDest; + pSelect->pEList = + sqlite3ExpandReturning(pParse, pList, pParse->pTriggerTab); + sqlite3SelectDestInit(&sDest, SRT_Output, 0); + sqlite3Select(pParse, pSelect, &sDest); + sqlite3ExprListDelete(db, pSelect->pEList); + pSelect->pEList = pList; + break; + } } - if( pStep->op!=TK_SELECT ){ - sqlite3VdbeAddOp0(v, OP_ResetCount); - } } return 0; From d086aa0a480f6fabf0bb4f0952ae84d79d4295f4 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 29 Jan 2021 21:31:59 +0000 Subject: [PATCH 04/23] RETURNING works even if "PRAGMA count_changes=ON" is set. FossilOrigin-Name: a9122d97577b239704cdee1a90a3b0dbff8bdf9dea2324d7315bd47238dcc8eb --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/build.c | 2 ++ src/delete.c | 1 + src/insert.c | 1 + src/update.c | 1 + 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 562358c6c0..65a114c0e4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Allow\s"*"\swildcards\sin\sthe\sRETURNING\sclause. -D 2021-01-29T21:18:46.467 +C RETURNING\sworks\seven\sif\s"PRAGMA\scount_changes=ON"\sis\sset. +D 2021-01-29T21:31:59.474 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -485,14 +485,14 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c 47d9fe97d5c0d74506154e3597f8a23b81a00080751dc4d11fec91ee22796f4c F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 -F src/build.c 2da961ffeb6253117a859ddfc682b20969ff7ebd0ec8c9f88636ea16cdc512b4 +F src/build.c 0453da1ba48d8bf17855bb3d7dfaadbaf5fd0871f249f2e5b98a7231aeac7ae1 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 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe +F src/delete.c a4b3a6db02d2e705edf41bdb378d4c53c106f305fd8e7b441713fe87f69ea624 F src/expr.c 47c85263e6d179424e6b09e2c79db5704ab5b8cbc2fae2ee3285faa2566f2e74 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 02e4a3311885cd2b31eb17fd58dc2fc738cd2c823d0d39e4dd5595169c6f8bc3 @@ -502,7 +502,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 9b970eff058a858fbd9f2db71425ef195942c2610855daa66ae23024432d52f5 +F src/insert.c 8f725611e5c5943cfd40461a8fa518538d8be666ef09097a29f7272ccd3ab0a0 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 1c5de7b3fabcdf05f4fe563aab5d81d175b89c67a8678a12ba86629356afa356 @@ -608,7 +608,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/trigger.c 47629a1e3fd483347d6cf468d7d397ab50f3ead4286d837ad7054de418767e38 -F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 +F src/update.c 3dbc7189ffcf361c2149f1b1d0841a8a9689d27f15c5e72e6f14ebc447e6b0c0 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048 @@ -1898,7 +1898,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 b7ef4dc21f187ff4ff679e823782535188c3814aa6ce720b3a01c6d3ba4ef9f5 -R 4fd580e848a9786e2403b5294c0c89d9 +P b0e3ae303db2a035583a05848ab7977e612d7e40c77e31ea9e0166de443c901f +R 0b4d4b086e5a69193a34b592f53c4e83 U drh -Z d7647504631490a0d91f2ce3b7260d98 +Z 1de82168e812ff82dbf4f00b9d1c7aff diff --git a/manifest.uuid b/manifest.uuid index e387b3e2f7..672cce1dac 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b0e3ae303db2a035583a05848ab7977e612d7e40c77e31ea9e0166de443c901f \ No newline at end of file +a9122d97577b239704cdee1a90a3b0dbff8bdf9dea2324d7315bd47238dcc8eb \ No newline at end of file diff --git a/src/build.c b/src/build.c index a25c9c6d80..74c5319caa 100644 --- a/src/build.c +++ b/src/build.c @@ -1267,6 +1267,8 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ Returning *pRet; Hash *pHash; sqlite3 *db = pParse->db; + assert( !pParse->bReturning ); + pParse->bReturning = 1; pRet = sqlite3DbMallocZero(db, sizeof(*pRet)); if( pRet==0 ){ sqlite3ExprListDelete(db, pList); diff --git a/src/delete.c b/src/delete.c index 064ae7325a..e9b092b245 100644 --- a/src/delete.c +++ b/src/delete.c @@ -387,6 +387,7 @@ void sqlite3DeleteFrom( if( (db->flags & SQLITE_CountRows)!=0 && !pParse->nested && !pParse->pTriggerTab + && !pParse->bReturning ){ memCnt = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); diff --git a/src/insert.c b/src/insert.c index 6047969c07..4f549f3523 100644 --- a/src/insert.c +++ b/src/insert.c @@ -954,6 +954,7 @@ void sqlite3Insert( if( (db->flags & SQLITE_CountRows)!=0 && !pParse->nested && !pParse->pTriggerTab + && !pParse->bReturning ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); diff --git a/src/update.c b/src/update.c index f8cb2afedb..82a6eb6356 100644 --- a/src/update.c +++ b/src/update.c @@ -643,6 +643,7 @@ void sqlite3Update( if( (db->flags&SQLITE_CountRows)!=0 && !pParse->pTriggerTab && !pParse->nested + && !pParse->bReturning && pUpsert==0 ){ regRowCount = ++pParse->nMem; From 8f4e2e25c4b5bff5e43bca2f9f166ff48311d6a3 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 29 Jan 2021 22:33:05 +0000 Subject: [PATCH 05/23] Better handling of errors in RETURNING due to corrupt database files. FossilOrigin-Name: 6aa2a058d136d0b24d94c5cbe1ce447eb435c1a1c7cdce5e435f1548bb3f05e7 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/build.c | 1 - src/trigger.c | 3 +-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 65a114c0e4..0499237a61 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C RETURNING\sworks\seven\sif\s"PRAGMA\scount_changes=ON"\sis\sset. -D 2021-01-29T21:31:59.474 +C Better\shandling\sof\serrors\sin\sRETURNING\sdue\sto\scorrupt\sdatabase\sfiles. +D 2021-01-29T22:33:05.109 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 47d9fe97d5c0d74506154e3597f8a23b81a00080751dc4d11fec91ee22796f4c F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 -F src/build.c 0453da1ba48d8bf17855bb3d7dfaadbaf5fd0871f249f2e5b98a7231aeac7ae1 +F src/build.c 451f832bfcbcb3004b09909608c452f1488863111167378355f95782c95bb358 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 47629a1e3fd483347d6cf468d7d397ab50f3ead4286d837ad7054de418767e38 +F src/trigger.c 7d9f9ba8723a84aed98f9446b30144acb539674b433ca7584145128791a60050 F src/update.c 3dbc7189ffcf361c2149f1b1d0841a8a9689d27f15c5e72e6f14ebc447e6b0c0 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1898,7 +1898,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 b0e3ae303db2a035583a05848ab7977e612d7e40c77e31ea9e0166de443c901f -R 0b4d4b086e5a69193a34b592f53c4e83 +P a9122d97577b239704cdee1a90a3b0dbff8bdf9dea2324d7315bd47238dcc8eb +R fb4fe290c70a72991d2bf3bb937da403 U drh -Z 1de82168e812ff82dbf4f00b9d1c7aff +Z ed1108ccda3615e26a51d20c5efe4e6c diff --git a/manifest.uuid b/manifest.uuid index 672cce1dac..4c38766895 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a9122d97577b239704cdee1a90a3b0dbff8bdf9dea2324d7315bd47238dcc8eb \ No newline at end of file +6aa2a058d136d0b24d94c5cbe1ce447eb435c1a1c7cdce5e435f1548bb3f05e7 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 74c5319caa..4143221c39 100644 --- a/src/build.c +++ b/src/build.c @@ -1254,7 +1254,6 @@ void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){ Hash *pHash; pHash = &(db->aDb[1].pSchema->trigHash); - assert( sqlite3HashFind(pHash, RETURNING_TRIGGER)==&pRet->retTrig ); sqlite3HashInsert(pHash, RETURNING_TRIGGER, 0); sqlite3ExprListDelete(db, pRet->pReturnEL); sqlite3DbFree(db, pRet); diff --git a/src/trigger.c b/src/trigger.c index a20c14197b..4520059442 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -567,8 +567,7 @@ TriggerStep *sqlite3TriggerDeleteStep( ** Recursively delete a Trigger structure */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ - if( pTrigger==0 ) return; - assert( !pTrigger->bReturning ); + if( pTrigger==0 || pTrigger->bReturning ) return; sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); From ba71a8a01bf2559eefe526e3b44f07e9ff2da5b8 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 30 Jan 2021 01:30:26 +0000 Subject: [PATCH 06/23] Test cases added. RETURNING works with UPSERT as does PG. FossilOrigin-Name: f5698f96e27c9b8669ec6016bb9920ef7580c4146eb61d628a0f62be5135ce94 --- manifest | 15 ++++---- manifest.uuid | 2 +- src/trigger.c | 8 ++-- src/vdbeaux.c | 5 ++- test/returning1.test | 87 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 test/returning1.test diff --git a/manifest b/manifest index 0499237a61..97aab3c71b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Better\shandling\sof\serrors\sin\sRETURNING\sdue\sto\scorrupt\sdatabase\sfiles. -D 2021-01-29T22:33:05.109 +C Test\scases\sadded.\s\sRETURNING\sworks\swith\sUPSERT\sas\sdoes\sPG. +D 2021-01-30T01:30:26.496 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 7d9f9ba8723a84aed98f9446b30144acb539674b433ca7584145128791a60050 +F src/trigger.c 88f616cbd1aa538f3d6bebc4e9b9fb95b566771b45c0690f21223de0317ace54 F src/update.c 3dbc7189ffcf361c2149f1b1d0841a8a9689d27f15c5e72e6f14ebc447e6b0c0 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -617,7 +617,7 @@ F src/vdbe.c 102d21260bddbb43c845603c3a2d6b4f3762e72f836ccda12991f291485d2539 F src/vdbe.h a71bf43572d3de57923d1928ac01ae8d355cd67e94462ba4f7462265cedbef9a F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9 -F src/vdbeaux.c 7ae7b2d7d97250d7100065eca7f04324f331b16b8165775f1724af10c7240d11 +F src/vdbeaux.c 2be30e4918126122fa358ef8303206cad0feffe17d320077c77ff5c2a34f3626 F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1 F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f F src/vdbesort.c f5b5e473a7cee44e47a94817b042fd7172cf3aa2c0a7928a8339d612bcfdec5a @@ -1286,6 +1286,7 @@ F test/releasetest.tcl fb76d8fcc95ac29d6356cd9e52b726ab9e43a24082897618dfbcb7c2b F test/releasetest_data.tcl b9cb30360759b80d92d4ea86b84ebfd8035b97f9078a482deb3cf9d0b2442655 F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb +F test/returning1.test 684e1c73d961422a7376c932fcdd6dacf02bad21d12f749cfe8c19991ef379f6 F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6 F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a @@ -1898,7 +1899,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 a9122d97577b239704cdee1a90a3b0dbff8bdf9dea2324d7315bd47238dcc8eb -R fb4fe290c70a72991d2bf3bb937da403 +P 6aa2a058d136d0b24d94c5cbe1ce447eb435c1a1c7cdce5e435f1548bb3f05e7 +R c5d28b15f2cd5974ae8ec5b186394cb6 U drh -Z ed1108ccda3615e26a51d20c5efe4e6c +Z 4324b62b15638b065ad3c0261246302c diff --git a/manifest.uuid b/manifest.uuid index 4c38766895..b8ff6b9b92 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6aa2a058d136d0b24d94c5cbe1ce447eb435c1a1c7cdce5e435f1548bb3f05e7 \ No newline at end of file +f5698f96e27c9b8669ec6016bb9920ef7580c4146eb61d628a0f62be5135ce94 \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index 4520059442..baf78eb8c2 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -567,7 +567,8 @@ TriggerStep *sqlite3TriggerDeleteStep( ** Recursively delete a Trigger structure */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ - if( pTrigger==0 || pTrigger->bReturning ) return; + if( pTrigger==0 ) return; + assert( !pTrigger->bReturning ); sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); @@ -739,7 +740,7 @@ Trigger *sqlite3TriggersExist( for(p=pList; p; p=p->pNext){ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ mask |= p->tr_tm; - }else if( p->op==TK_RETURNING ){ + }else if( p->bReturning ){ p->op = op; mask |= TRIGGER_AFTER; } @@ -912,6 +913,7 @@ static int codeTriggerProgram( pSelect->pEList = sqlite3ExpandReturning(pParse, pList, pParse->pTriggerTab); sqlite3SelectDestInit(&sDest, SRT_Output, 0); + pSelect->selFlags = 0; sqlite3Select(pParse, pSelect, &sDest); sqlite3ExprListDelete(db, pSelect->pEList); pSelect->pEList = pList; @@ -1215,7 +1217,7 @@ void sqlite3CodeRowTrigger( || p->pSchema==pParse->db->aDb[1].pSchema ); /* Determine whether we should code this trigger */ - if( p->op==op + if( (p->op==op || p->bReturning) && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns, pChanges) ){ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 9ea20628fe..c7c2125751 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2602,7 +2602,10 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ void sqlite3VdbeColumnInfoXfer(Vdbe *pTo, Vdbe *pFrom){ sqlite3 *db = pTo->db; assert( db==pFrom->db ); - sqlite3DbFree(db, pTo->aColName); + if( pTo->nResColumn ){ + releaseMemArray(pTo->aColName, pTo->nResColumn*COLNAME_N); + sqlite3DbFree(db, pTo->aColName); + } pTo->aColName = pFrom->aColName; pFrom->aColName = 0; pTo->nResColumn = pFrom->nResColumn; diff --git a/test/returning1.test b/test/returning1.test new file mode 100644 index 0000000000..52fb8812a6 --- /dev/null +++ b/test/returning1.test @@ -0,0 +1,87 @@ +# 2021-01-28 +# +# 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 the new RETURNING clause +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix returning1 + +do_execsql_test 1.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c DEFAULT 'pax'); + INSERT INTO t1(b) VALUES(10),('happy'),(NULL) RETURNING a,b,c; +} {1 10 pax 2 happy pax 3 {} pax} +do_execsql_test 1.1 { + SELECT * FROM t1; +} {1 10 pax 2 happy pax 3 {} pax} +do_execsql_test 1.2 { + INSERT INTO t1(b,c) VALUES(5,99) RETURNING b,c,a,rowid; +} {5 99 4 4} +do_execsql_test 1.3 { + SELECT * FROM t1; +} {1 10 pax 2 happy pax 3 {} pax 4 5 99} +do_execsql_test 1.4 { + INSERT INTO t1 DEFAULT VALUES RETURNING *; +} {5 {} pax} +do_execsql_test 1.5 { + SELECT * FROM t1; +} {1 10 pax 2 happy pax 3 {} pax 4 5 99 5 {} pax} +do_execsql_test 1.6 { + CREATE TABLE t2(x,y,z); + INSERT INTO t2 VALUES(11,12,13),(21,'b','c'),(31,'b-value',4.75); +} +do_execsql_test 1.7 { + INSERT INTO t1 SELECT * FROM t2 RETURNING *; +} {11 12 13 21 b c 31 b-value 4.75} +do_execsql_test 1.8 { + SELECT *, '|' FROM t1; +} {1 10 pax | 2 happy pax | 3 {} pax | 4 5 99 | 5 {} pax | 11 12 13 | 21 b c | 31 b-value 4.75 |} + +do_execsql_test 2.1 { + UPDATE t1 SET c='bellum' WHERE c='pax' RETURNING rowid, b, '|'; +} {1 10 | 2 happy | 3 {} | 5 {} |} +do_execsql_test 2.2 { + SELECT *, '|' FROM t1; +} {1 10 bellum | 2 happy bellum | 3 {} bellum | 4 5 99 | 5 {} bellum | 11 12 13 | 21 b c | 31 b-value 4.75 |} + +do_execsql_test 3.1 { + DELETE FROM t1 WHERE c='bellum' RETURNING rowid, *, '|'; +} {1 1 10 bellum | 2 2 happy bellum | 3 3 {} bellum | 5 5 {} bellum |} +do_execsql_test 3.2 { + SELECT *, '|' FROM t1; +} {4 5 99 | 11 12 13 | 21 b c | 31 b-value 4.75 |} + +do_execsql_test 4.1 { + CREATE TABLE t4(a INT, b INT DEFAULT 1234, c INT DEFAULT -16); + CREATE UNIQUE INDEX t4a ON t4(a); + INSERT INTO t4(a,b,c) VALUES(1,2,3); +} {} +do_execsql_test 4.2 { + INSERT INTO t4(a,b,c) VALUES(1,22,33) + ON CONFLICT(a) DO UPDATE SET b=44 + RETURNING *; +} {1 44 3} +do_execsql_test 4.3 { + SELECT * FROM t4; +} {1 44 3} +do_execsql_test 4.4 { + DELETE FROM t4; + INSERT INTO t4 VALUES(1,2,3),(4,5,6),(7,8,9); +} {} +do_execsql_test 4.5 { + INSERT INTO t4(a,b,c) VALUES(2,3,4),(4,5,6),(5,6,7) + ON CONFLICT(a) DO UPDATE SET b=100 + RETURNING *, '|'; +} {2 3 4 | 4 100 6 | 5 6 7 |} + + +finish_test From 16d861ffc27142a17e4e888d8ff57280e3ac754c Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 30 Jan 2021 02:22:38 +0000 Subject: [PATCH 07/23] When running the RETURNING trigger, if it is tagged as a DELETE trigger, do not use it as INSERT or UPDATE. FossilOrigin-Name: 3c7a6e04ddde34961d8e9d0443913e572a80853cf14a8263cec19523c39ca744 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/trigger.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 97aab3c71b..332c29a24d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Test\scases\sadded.\s\sRETURNING\sworks\swith\sUPSERT\sas\sdoes\sPG. -D 2021-01-30T01:30:26.496 +C When\srunning\sthe\sRETURNING\strigger,\sif\sit\sis\stagged\sas\sa\sDELETE\strigger,\ndo\snot\suse\sit\sas\sINSERT\sor\sUPDATE. +D 2021-01-30T02:22:38.436 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 88f616cbd1aa538f3d6bebc4e9b9fb95b566771b45c0690f21223de0317ace54 +F src/trigger.c 0b683379a7855f50bfd114cc7590bc1a10d4c8008dcc23e335e307459a36daba F src/update.c 3dbc7189ffcf361c2149f1b1d0841a8a9689d27f15c5e72e6f14ebc447e6b0c0 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 6aa2a058d136d0b24d94c5cbe1ce447eb435c1a1c7cdce5e435f1548bb3f05e7 -R c5d28b15f2cd5974ae8ec5b186394cb6 +P f5698f96e27c9b8669ec6016bb9920ef7580c4146eb61d628a0f62be5135ce94 +R c9a80a1d4c54684acda1e51b55904277 U drh -Z 4324b62b15638b065ad3c0261246302c +Z 993208c24ec6d120a7fb4e41ada97fae diff --git a/manifest.uuid b/manifest.uuid index b8ff6b9b92..0fa6e547a7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f5698f96e27c9b8669ec6016bb9920ef7580c4146eb61d628a0f62be5135ce94 \ No newline at end of file +3c7a6e04ddde34961d8e9d0443913e572a80853cf14a8263cec19523c39ca744 \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index baf78eb8c2..6a3498c457 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -740,7 +740,7 @@ Trigger *sqlite3TriggersExist( for(p=pList; p; p=p->pNext){ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ mask |= p->tr_tm; - }else if( p->bReturning ){ + }else if( p->bReturning && (p->op==TK_RETURNING || p->op!=TK_DELETE) ){ p->op = op; mask |= TRIGGER_AFTER; } @@ -1217,7 +1217,7 @@ void sqlite3CodeRowTrigger( || p->pSchema==pParse->db->aDb[1].pSchema ); /* Determine whether we should code this trigger */ - if( (p->op==op || p->bReturning) + if( (p->op==op || (p->bReturning && p->op!=TK_DELETE)) && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns, pChanges) ){ From 343256b9b0b4cc05b978f087c39518c01dee6eca Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 30 Jan 2021 02:34:47 +0000 Subject: [PATCH 08/23] Another attempt to get trigger selection correct for RETURNING triggers. FossilOrigin-Name: 1b8ed52275a54800df90682d694b482f55f26c6c4a420659f9a3b7bfc61e8abe --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/trigger.c | 4 +++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 332c29a24d..00cf98647f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\srunning\sthe\sRETURNING\strigger,\sif\sit\sis\stagged\sas\sa\sDELETE\strigger,\ndo\snot\suse\sit\sas\sINSERT\sor\sUPDATE. -D 2021-01-30T02:22:38.436 +C Another\sattempt\sto\sget\strigger\sselection\scorrect\sfor\sRETURNING\striggers. +D 2021-01-30T02:34:47.012 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 0b683379a7855f50bfd114cc7590bc1a10d4c8008dcc23e335e307459a36daba +F src/trigger.c 6b312904df04c5e8bac6d801448736b5170d7902ea62d87615845938cf466836 F src/update.c 3dbc7189ffcf361c2149f1b1d0841a8a9689d27f15c5e72e6f14ebc447e6b0c0 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 f5698f96e27c9b8669ec6016bb9920ef7580c4146eb61d628a0f62be5135ce94 -R c9a80a1d4c54684acda1e51b55904277 +P 3c7a6e04ddde34961d8e9d0443913e572a80853cf14a8263cec19523c39ca744 +R 62218e74d94127b5c670903aeb07216b U drh -Z 993208c24ec6d120a7fb4e41ada97fae +Z 08397caac37c2d39eeda13ae69545f62 diff --git a/manifest.uuid b/manifest.uuid index 0fa6e547a7..6e7cdb23a9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3c7a6e04ddde34961d8e9d0443913e572a80853cf14a8263cec19523c39ca744 \ No newline at end of file +1b8ed52275a54800df90682d694b482f55f26c6c4a420659f9a3b7bfc61e8abe \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index 6a3498c457..e22439cf47 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -740,7 +740,8 @@ Trigger *sqlite3TriggersExist( for(p=pList; p; p=p->pNext){ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ mask |= p->tr_tm; - }else if( p->bReturning && (p->op==TK_RETURNING || p->op!=TK_DELETE) ){ + }else if( p->bReturning + && (p->op==TK_RETURNING || (p->op!=TK_DELETE && op!=TK_DELETE)) ){ p->op = op; mask |= TRIGGER_AFTER; } @@ -1221,6 +1222,7 @@ void sqlite3CodeRowTrigger( && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns, pChanges) ){ + p->op = op; sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump); } } From 658f0a36796bc6508bbc01379bb1725775e9a9b7 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 30 Jan 2021 02:43:26 +0000 Subject: [PATCH 09/23] Fix a memory deallocation problem that comes up when doing a RETURNING query on a corrupt database. I think I fixed this before, but it got unfixed with stale editor content. FossilOrigin-Name: 02b1415efb7d9849499afe4e9dbf7e470484bf144d6ca3d28fdc38fc0ac10afa --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/trigger.c | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 00cf98647f..1654f29a1a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Another\sattempt\sto\sget\strigger\sselection\scorrect\sfor\sRETURNING\striggers. -D 2021-01-30T02:34:47.012 +C Fix\sa\smemory\sdeallocation\sproblem\sthat\scomes\sup\swhen\sdoing\sa\sRETURNING\squery\non\sa\scorrupt\sdatabase.\s\sI\sthink\sI\sfixed\sthis\sbefore,\sbut\sit\sgot\sunfixed\swith\nstale\seditor\scontent. +D 2021-01-30T02:43:26.023 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 6b312904df04c5e8bac6d801448736b5170d7902ea62d87615845938cf466836 +F src/trigger.c ec5ba098328dccba9b5c2e5e9946df4dab1d551ae8b7d1b0bdaec65914bf2bfa F src/update.c 3dbc7189ffcf361c2149f1b1d0841a8a9689d27f15c5e72e6f14ebc447e6b0c0 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 3c7a6e04ddde34961d8e9d0443913e572a80853cf14a8263cec19523c39ca744 -R 62218e74d94127b5c670903aeb07216b +P 1b8ed52275a54800df90682d694b482f55f26c6c4a420659f9a3b7bfc61e8abe +R cf21e41910dc0faee5037ce4e11838eb U drh -Z 08397caac37c2d39eeda13ae69545f62 +Z 8a2777d3702d0168b2e6293ee5f1e515 diff --git a/manifest.uuid b/manifest.uuid index 6e7cdb23a9..828d783ff4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1b8ed52275a54800df90682d694b482f55f26c6c4a420659f9a3b7bfc61e8abe \ No newline at end of file +02b1415efb7d9849499afe4e9dbf7e470484bf144d6ca3d28fdc38fc0ac10afa \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index e22439cf47..805b960364 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -567,8 +567,7 @@ TriggerStep *sqlite3TriggerDeleteStep( ** Recursively delete a Trigger structure */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ - if( pTrigger==0 ) return; - assert( !pTrigger->bReturning ); + if( pTrigger==0 || pTrigger->bReturning ) return; sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); From cf4108bbc687170edaeaed2548524bec3b63b5eb Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 30 Jan 2021 03:06:19 +0000 Subject: [PATCH 10/23] Fix handling of an OOM condition in sqlite3AddReturning(). FossilOrigin-Name: 52204cd768f115d13249ff0e3a252b716620f7ad16a6962e1192a09137a78596 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/build.c | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 1654f29a1a..5b308e9abc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\smemory\sdeallocation\sproblem\sthat\scomes\sup\swhen\sdoing\sa\sRETURNING\squery\non\sa\scorrupt\sdatabase.\s\sI\sthink\sI\sfixed\sthis\sbefore,\sbut\sit\sgot\sunfixed\swith\nstale\seditor\scontent. -D 2021-01-30T02:43:26.023 +C Fix\shandling\sof\san\sOOM\scondition\sin\ssqlite3AddReturning(). +D 2021-01-30T03:06:19.421 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 47d9fe97d5c0d74506154e3597f8a23b81a00080751dc4d11fec91ee22796f4c F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 -F src/build.c 451f832bfcbcb3004b09909608c452f1488863111167378355f95782c95bb358 +F src/build.c d708731a10a780723f7f6d996c1a7ff827ce2153bb4b6e964a59176fc373a6a3 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410 @@ -1899,7 +1899,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 1b8ed52275a54800df90682d694b482f55f26c6c4a420659f9a3b7bfc61e8abe -R cf21e41910dc0faee5037ce4e11838eb +P 02b1415efb7d9849499afe4e9dbf7e470484bf144d6ca3d28fdc38fc0ac10afa +R 0f2932eca63747c13c7de64fbcf0f21a U drh -Z 8a2777d3702d0168b2e6293ee5f1e515 +Z 484e428235115814320582a3c935b7db diff --git a/manifest.uuid b/manifest.uuid index 828d783ff4..6b582d77da 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -02b1415efb7d9849499afe4e9dbf7e470484bf144d6ca3d28fdc38fc0ac10afa \ No newline at end of file +52204cd768f115d13249ff0e3a252b716620f7ad16a6962e1192a09137a78596 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 4143221c39..e9e35333c4 100644 --- a/src/build.c +++ b/src/build.c @@ -1277,6 +1277,7 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ pRet->pReturnEL = pList; sqlite3ParserAddCleanup(pParse, (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet); + if( db->mallocFailed ) return; pRet->retTrig.zName = "sqlite_returning"; pRet->retTrig.op = TK_RETURNING; pRet->retTrig.tr_tm = TRIGGER_AFTER; From 0166df0bdad64754cb72f205a823575dae7b45ea Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 30 Jan 2021 12:07:32 +0000 Subject: [PATCH 11/23] Fix a obsolete assert() in the bytecode engine. Improved OOM detection in sqlite3AddReturning(). FossilOrigin-Name: 138b10d54a83e1e7d5b3cdbe593a5073b05e632d1823e1b74d85835435b9ee3d --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/build.c | 5 ++++- src/vdbe.c | 9 +++++---- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index 5b308e9abc..9eb9587464 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\shandling\sof\san\sOOM\scondition\sin\ssqlite3AddReturning(). -D 2021-01-30T03:06:19.421 +C Fix\sa\sobsolete\sassert()\sin\sthe\sbytecode\sengine.\s\sImproved\sOOM\sdetection\nin\ssqlite3AddReturning(). +D 2021-01-30T12:07:32.582 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 47d9fe97d5c0d74506154e3597f8a23b81a00080751dc4d11fec91ee22796f4c F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 -F src/build.c d708731a10a780723f7f6d996c1a7ff827ce2153bb4b6e964a59176fc373a6a3 +F src/build.c ff2cdab3c86156c3c1808e282daaf04d298e532ef11478844964107496898cf9 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410 @@ -613,7 +613,7 @@ F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 -F src/vdbe.c 102d21260bddbb43c845603c3a2d6b4f3762e72f836ccda12991f291485d2539 +F src/vdbe.c 5761ca995715f12825faba7a465c6aa1c92cf88f3199fc221d312268edfde6f5 F src/vdbe.h a71bf43572d3de57923d1928ac01ae8d355cd67e94462ba4f7462265cedbef9a F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9 @@ -1899,7 +1899,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 02b1415efb7d9849499afe4e9dbf7e470484bf144d6ca3d28fdc38fc0ac10afa -R 0f2932eca63747c13c7de64fbcf0f21a +P 52204cd768f115d13249ff0e3a252b716620f7ad16a6962e1192a09137a78596 +R 2383351840f532b10fd8d9e8187ff10e U drh -Z 484e428235115814320582a3c935b7db +Z 835a3a4123d883b7f5aa3b3a2eaef96a diff --git a/manifest.uuid b/manifest.uuid index 6b582d77da..37afd6a33a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -52204cd768f115d13249ff0e3a252b716620f7ad16a6962e1192a09137a78596 \ No newline at end of file +138b10d54a83e1e7d5b3cdbe593a5073b05e632d1823e1b74d85835435b9ee3d \ No newline at end of file diff --git a/src/build.c b/src/build.c index e9e35333c4..b0dac9965d 100644 --- a/src/build.c +++ b/src/build.c @@ -1292,7 +1292,10 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ pRet->retSel.pSrc = (SrcList*)&pRet->retSrcList; pHash = &(db->aDb[1].pSchema->trigHash); assert( sqlite3HashFind(pHash, RETURNING_TRIGGER)==0 ); - sqlite3HashInsert(pHash, "sqlite_returning", &pRet->retTrig); + if( sqlite3HashInsert(pHash, "sqlite_returning", &pRet->retTrig) + ==&pRet->retTrig ){ + sqlite3OomFault(db); + } } /* diff --git a/src/vdbe.c b/src/vdbe.c index 3a00515e57..d38d9a0689 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -1470,9 +1470,10 @@ case OP_ResultRow: { goto abort_due_to_error; } - /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then - ** DML statements invoke this opcode to return the number of rows - ** modified to the user. This is the only way that a VM that + /* DML statements can invoke this opcode to return the number of rows + ** modified to the user if the "PRAGMA count_changes=ON" pragma has been + ** run. DML statement triggers can invoke this satement to implement + ** the RETURNING clause. Thess are the only ways that a VM that ** opens a statement transaction may invoke this opcode. ** ** In case this is such a statement, close any statement transaction @@ -1485,7 +1486,7 @@ case OP_ResultRow: { ** The statement transaction is never a top-level transaction. Hence ** the RELEASE call below can never fail. */ - assert( p->iStatement==0 || db->flags&SQLITE_CountRows ); + assert( p->iStatement==0 || db->flags&SQLITE_CountRows || p->pFrame ); rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE); assert( rc==SQLITE_OK ); From a8a64a078ff8e44f175f1985d75cb91c25f8f5e3 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 30 Jan 2021 14:17:18 +0000 Subject: [PATCH 12/23] Chagne the OP_ResultRow opcode so that it does not cancel pending statement transactions. FossilOrigin-Name: fea91e3a511b14dafcc4da92c59188f927ec60ed91441335183da6b4e7866c1b --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbe.c | 20 -------------------- 3 files changed, 7 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 9eb9587464..fabb001c84 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sobsolete\sassert()\sin\sthe\sbytecode\sengine.\s\sImproved\sOOM\sdetection\nin\ssqlite3AddReturning(). -D 2021-01-30T12:07:32.582 +C Chagne\sthe\sOP_ResultRow\sopcode\sso\sthat\sit\sdoes\snot\scancel\npending\sstatement\stransactions. +D 2021-01-30T14:17:18.189 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -613,7 +613,7 @@ F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 -F src/vdbe.c 5761ca995715f12825faba7a465c6aa1c92cf88f3199fc221d312268edfde6f5 +F src/vdbe.c d715b1eeb37168afec92185bcf3dc6da175abafd247821af200ac7eeab68a706 F src/vdbe.h a71bf43572d3de57923d1928ac01ae8d355cd67e94462ba4f7462265cedbef9a F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9 @@ -1899,7 +1899,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 52204cd768f115d13249ff0e3a252b716620f7ad16a6962e1192a09137a78596 -R 2383351840f532b10fd8d9e8187ff10e +P 138b10d54a83e1e7d5b3cdbe593a5073b05e632d1823e1b74d85835435b9ee3d +R 570c84bd891a98ecddec602b36250bc2 U drh -Z 835a3a4123d883b7f5aa3b3a2eaef96a +Z 60be8821ffce46f579893c6cfdf10955 diff --git a/manifest.uuid b/manifest.uuid index 37afd6a33a..23a12179ec 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -138b10d54a83e1e7d5b3cdbe593a5073b05e632d1823e1b74d85835435b9ee3d \ No newline at end of file +fea91e3a511b14dafcc4da92c59188f927ec60ed91441335183da6b4e7866c1b \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index d38d9a0689..6547b41553 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -1470,26 +1470,6 @@ case OP_ResultRow: { goto abort_due_to_error; } - /* DML statements can invoke this opcode to return the number of rows - ** modified to the user if the "PRAGMA count_changes=ON" pragma has been - ** run. DML statement triggers can invoke this satement to implement - ** the RETURNING clause. Thess are the only ways that a VM that - ** opens a statement transaction may invoke this opcode. - ** - ** In case this is such a statement, close any statement transaction - ** opened by this VM before returning control to the user. This is to - ** ensure that statement-transactions are always nested, not overlapping. - ** If the open statement-transaction is not closed here, then the user - ** may step another VM that opens its own statement transaction. This - ** may lead to overlapping statement transactions. - ** - ** The statement transaction is never a top-level transaction. Hence - ** the RELEASE call below can never fail. - */ - assert( p->iStatement==0 || db->flags&SQLITE_CountRows || p->pFrame ); - rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE); - assert( rc==SQLITE_OK ); - /* Invalidate all ephemeral cursor row caches */ p->cacheCtr = (p->cacheCtr + 2)|1; From 1832f2921dcfee91d4ab68b6612acd75d54d4f43 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 30 Jan 2021 16:16:42 +0000 Subject: [PATCH 13/23] Add an ALWAYS() to an unreachable branch. FossilOrigin-Name: 6bb6de42b62acd35ade6c95a11bb4c9b35e7e9a24620731ae36364c4d5c3bc31 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/resolve.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index fabb001c84..80f6d36869 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Chagne\sthe\sOP_ResultRow\sopcode\sso\sthat\sit\sdoes\snot\scancel\npending\sstatement\stransactions. -D 2021-01-30T14:17:18.189 +C Add\san\sALWAYS()\sto\san\sunreachable\sbranch. +D 2021-01-30T16:16:42.507 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -539,7 +539,7 @@ F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf F src/prepare.c f288cbc35f79eb32e162de7e80a63ebe00d80e639dcfac071bee11570cbdb16f F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 -F src/resolve.c b714e6f9f3cdfb6ba287bb5ef76888ec8cd9e15c98a608c82bc3300b99a245d7 +F src/resolve.c f6761473ea4b51190fc52f8f2121498b78717266e106e7bff12849ea2d52165f F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 738cb746189f721f59972993c13085fa2975c4cbfd04ba26445f3b42c81237dc F src/shell.c.in 9ebc74e4f05cfbd0f4a36060fdaeff1da4e9af4458358722bc08c5a1ab9a0879 @@ -1899,7 +1899,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 138b10d54a83e1e7d5b3cdbe593a5073b05e632d1823e1b74d85835435b9ee3d -R 570c84bd891a98ecddec602b36250bc2 +P fea91e3a511b14dafcc4da92c59188f927ec60ed91441335183da6b4e7866c1b +R 8cd82e0fb3b2559278f1acef6be93a28 U drh -Z 60be8821ffce46f579893c6cfdf10955 +Z 32c0d1eece5071f19ef4a6007df09364 diff --git a/manifest.uuid b/manifest.uuid index 23a12179ec..c7413ce5bb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fea91e3a511b14dafcc4da92c59188f927ec60ed91441335183da6b4e7866c1b \ No newline at end of file +6bb6de42b62acd35ade6c95a11bb4c9b35e7e9a24620731ae36364c4d5c3bc31 \ No newline at end of file diff --git a/src/resolve.c b/src/resolve.c index fa46954da8..5074a28812 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -390,7 +390,7 @@ static int lookupName( } #endif /* SQLITE_OMIT_TRIGGER */ #ifndef SQLITE_OMIT_UPSERT - if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab ){ + if( (pNC->ncFlags & NC_UUpsert)!=0 && ALWAYS(zTab) ){ Upsert *pUpsert = pNC->uNC.pUpsert; if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ pTab = pUpsert->pUpsertSrc->a[0].pTab; From 28828c550fe957516ca2d49cd485ae3cb209ea4a Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 30 Jan 2021 21:55:38 +0000 Subject: [PATCH 14/23] Improved comments on the new code. FossilOrigin-Name: a38f0c1d7c1d7635732ac370d8fbc7e6a2005378e4621da7bc4f51a2f99912d1 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/build.c | 31 +++++++++++++++++++++++-------- src/trigger.c | 18 ++++++++++++++---- 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 80f6d36869..33c213e5b0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\san\sALWAYS()\sto\san\sunreachable\sbranch. -D 2021-01-30T16:16:42.507 +C Improved\scomments\son\sthe\snew\scode. +D 2021-01-30T21:55:38.166 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 47d9fe97d5c0d74506154e3597f8a23b81a00080751dc4d11fec91ee22796f4c F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 -F src/build.c ff2cdab3c86156c3c1808e282daaf04d298e532ef11478844964107496898cf9 +F src/build.c 118e1076282415229420d04f9cc25bb148a2c412d82ea3c319136d2122c842e5 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c ec5ba098328dccba9b5c2e5e9946df4dab1d551ae8b7d1b0bdaec65914bf2bfa +F src/trigger.c 207168409c59f346df3a8b4556f0f35fdf721cd35e06fb3c75ea76b7ce95ed35 F src/update.c 3dbc7189ffcf361c2149f1b1d0841a8a9689d27f15c5e72e6f14ebc447e6b0c0 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 fea91e3a511b14dafcc4da92c59188f927ec60ed91441335183da6b4e7866c1b -R 8cd82e0fb3b2559278f1acef6be93a28 +P 6bb6de42b62acd35ade6c95a11bb4c9b35e7e9a24620731ae36364c4d5c3bc31 +R 9e0cb8b9c72d2bfe4a3d882f4b872a05 U drh -Z 32c0d1eece5071f19ef4a6007df09364 +Z 296f4bf266bf4139fc832ba9efb3047c diff --git a/manifest.uuid b/manifest.uuid index c7413ce5bb..32aff6c58f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6bb6de42b62acd35ade6c95a11bb4c9b35e7e9a24620731ae36364c4d5c3bc31 \ No newline at end of file +a38f0c1d7c1d7635732ac370d8fbc7e6a2005378e4621da7bc4f51a2f99912d1 \ No newline at end of file diff --git a/src/build.c b/src/build.c index b0dac9965d..25f61e8156 100644 --- a/src/build.c +++ b/src/build.c @@ -1244,23 +1244,38 @@ void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ #endif /* -** Name of the magic TEMP trigger used to implement RETURNING +** Name of the special TEMP trigger used to implement RETURNING. The +** name begins with "sqlite_" so that it is guaranteed not to collide +** with any application-generated triggers. */ -#define RETURNING_TRIGGER "sqlite_returning" +#define RETURNING_TRIGGER_NAME "sqlite_returning" /* -** Delete the data structures associated with the RETURNING clause. +** Clean up the data structures associated with the RETURNING clause. */ static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){ Hash *pHash; pHash = &(db->aDb[1].pSchema->trigHash); - sqlite3HashInsert(pHash, RETURNING_TRIGGER, 0); + sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, 0); sqlite3ExprListDelete(db, pRet->pReturnEL); sqlite3DbFree(db, pRet); } /* -** Add the RETURNING clause to the parser currently underway. +** Add the RETURNING clause to the parse currently underway. +** +** This routine creates a special TEMP trigger that will fire for each row +** of the DML statement. That TEMP trigger contains a single SELECT +** statement with a result set that is the argument of the RETURNING clause. +** The trigger has the Trigger.bReturning flag and an opcode of +** TK_RETURNING instead of TK_SELECT, so that the trigger code generator +** knows to handle it specially. The TEMP trigger is automatically +** removed at the end of the parse. +** +** When this routine is called, we do not yet know if the RETURNING clause +** is attached to a DELETE, INSERT, or UPDATE, so construct it as a +** RETURNING trigger instead. It will then be converted into the appropriate +** type on the first call to sqlite3TriggersExist(). */ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ Returning *pRet; @@ -1278,7 +1293,7 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ sqlite3ParserAddCleanup(pParse, (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet); if( db->mallocFailed ) return; - pRet->retTrig.zName = "sqlite_returning"; + pRet->retTrig.zName = RETURNING_TRIGGER_NAME; pRet->retTrig.op = TK_RETURNING; pRet->retTrig.tr_tm = TRIGGER_AFTER; pRet->retTrig.bReturning = 1; @@ -1291,8 +1306,8 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ pRet->retSel.pEList = pList; pRet->retSel.pSrc = (SrcList*)&pRet->retSrcList; pHash = &(db->aDb[1].pSchema->trigHash); - assert( sqlite3HashFind(pHash, RETURNING_TRIGGER)==0 ); - if( sqlite3HashInsert(pHash, "sqlite_returning", &pRet->retTrig) + assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 ); + if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig) ==&pRet->retTrig ){ sqlite3OomFault(db); } diff --git a/src/trigger.c b/src/trigger.c index 805b960364..5463d2dd0f 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -739,10 +739,14 @@ Trigger *sqlite3TriggersExist( for(p=pList; p; p=p->pNext){ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ mask |= p->tr_tm; - }else if( p->bReturning - && (p->op==TK_RETURNING || (p->op!=TK_DELETE && op!=TK_DELETE)) ){ + }else if( p->op==TK_RETURNING ){ + /* The first time a RETURNING trigger is seen, the "op" value tells + ** us what time of trigger it should be. */ p->op = op; mask |= TRIGGER_AFTER; + }else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE ){ + /* Also fire a RETURNING trigger for INSERT on the UPDATE of an UPSERT */ + mask |= TRIGGER_AFTER; } } if( pMask ){ @@ -1216,13 +1220,19 @@ void sqlite3CodeRowTrigger( assert( p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema ); - /* Determine whether we should code this trigger */ - if( (p->op==op || (p->bReturning && p->op!=TK_DELETE)) + /* Determine whether we should code this trigger. One of two choices: + ** 1. The trigger is an exact match to the current DML statement + ** 2. This is a RETURNING trigger for INSERT but we are currently + ** doing the UPDATE part of an UPSERT. + */ + if( (p->op==op || (p->bReturning && p->op==TK_INSERT && op==TK_UPDATE)) && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns, pChanges) ){ + u8 origOp = p->op; p->op = op; sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump); + p->op = origOp; } } } From 662fe7964744f40f5e75e71a5c2f50cbc3817a72 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 31 Jan 2021 12:41:20 +0000 Subject: [PATCH 15/23] When setting the number of result columns in a RETURNING trigger, be sure to set that value in the top-level bytecode program, not in the immediate caller of the trigger. FossilOrigin-Name: 1f1ce7ceb9807d22efea496f33908040ee196a31cd192f27ec0fb3e23afb729c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/trigger.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 33c213e5b0..0955fb3250 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\scomments\son\sthe\snew\scode. -D 2021-01-30T21:55:38.166 +C When\ssetting\sthe\snumber\sof\sresult\scolumns\sin\sa\sRETURNING\strigger,\sbe\ssure\nto\sset\sthat\svalue\sin\sthe\stop-level\sbytecode\sprogram,\snot\sin\sthe\simmediate\ncaller\sof\sthe\strigger. +D 2021-01-31T12:41:20.387 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 207168409c59f346df3a8b4556f0f35fdf721cd35e06fb3c75ea76b7ce95ed35 +F src/trigger.c 424f81a5631a06dda99d70c6bfa3e7e6ead74ab9eb757b77f75a14a18ef7d419 F src/update.c 3dbc7189ffcf361c2149f1b1d0841a8a9689d27f15c5e72e6f14ebc447e6b0c0 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 6bb6de42b62acd35ade6c95a11bb4c9b35e7e9a24620731ae36364c4d5c3bc31 -R 9e0cb8b9c72d2bfe4a3d882f4b872a05 +P a38f0c1d7c1d7635732ac370d8fbc7e6a2005378e4621da7bc4f51a2f99912d1 +R 34ba0ebdbec7699355883290972263ed U drh -Z 296f4bf266bf4139fc832ba9efb3047c +Z 1a944974e641f069223aa2fcb2319010 diff --git a/manifest.uuid b/manifest.uuid index 32aff6c58f..ca1e4d426c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a38f0c1d7c1d7635732ac370d8fbc7e6a2005378e4621da7bc4f51a2f99912d1 \ No newline at end of file +1f1ce7ceb9807d22efea496f33908040ee196a31cd192f27ec0fb3e23afb729c \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index 5463d2dd0f..ae86c7c9af 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -1064,7 +1064,7 @@ static TriggerPrg *codeRowTrigger( pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); } if( pTrigger->bReturning ){ - sqlite3VdbeColumnInfoXfer(pParse->pVdbe, v); + sqlite3VdbeColumnInfoXfer(sqlite3ParseToplevel(pParse)->pVdbe, v); } pProgram->nMem = pSubParse->nMem; pProgram->nCsr = pSubParse->nTab; From 18e5607211405d3852bbc61e39794ebb32574ebc Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 31 Jan 2021 15:50:36 +0000 Subject: [PATCH 16/23] New opcode OP_ChngCntRow used to output the result of PRAGMA change_count. Only this new opcode, and not OP_ResultRow, checks for foreign key errors. Faster performance, and now also works with RETURNING. FossilOrigin-Name: 154fc2b15465c7c92a1af0a93851421aec42a81bab54840a9701f2c78068e14e --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/delete.c | 2 +- src/insert.c | 2 +- src/update.c | 2 +- src/vdbe.c | 29 ++++++++++++++++++++--------- 6 files changed, 33 insertions(+), 22 deletions(-) diff --git a/manifest b/manifest index 0955fb3250..a461a2acbd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\ssetting\sthe\snumber\sof\sresult\scolumns\sin\sa\sRETURNING\strigger,\sbe\ssure\nto\sset\sthat\svalue\sin\sthe\stop-level\sbytecode\sprogram,\snot\sin\sthe\simmediate\ncaller\sof\sthe\strigger. -D 2021-01-31T12:41:20.387 +C New\sopcode\sOP_ChngCntRow\sused\sto\soutput\sthe\sresult\sof\sPRAGMA\schange_count.\nOnly\sthis\snew\sopcode,\sand\snot\sOP_ResultRow,\schecks\sfor\sforeign\skey\serrors.\nFaster\sperformance,\sand\snow\salso\sworks\swith\sRETURNING. +D 2021-01-31T15:50:36.442 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -492,7 +492,7 @@ F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410 F src/date.c dace306a10d9b02ee553d454c8e1cf8d3c9b932e137738a6b15b90253a9bfc10 F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c -F src/delete.c a4b3a6db02d2e705edf41bdb378d4c53c106f305fd8e7b441713fe87f69ea624 +F src/delete.c 352ea931218c45a3daf17472d4141b9c7fc026d85da3f1ade404ea5bb6d67f77 F src/expr.c 47c85263e6d179424e6b09e2c79db5704ab5b8cbc2fae2ee3285faa2566f2e74 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 02e4a3311885cd2b31eb17fd58dc2fc738cd2c823d0d39e4dd5595169c6f8bc3 @@ -502,7 +502,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 8f725611e5c5943cfd40461a8fa518538d8be666ef09097a29f7272ccd3ab0a0 +F src/insert.c 97be36c52c667a64aacbba76398544d224268d62444b67d011a077c486e375bb F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 1c5de7b3fabcdf05f4fe563aab5d81d175b89c67a8678a12ba86629356afa356 @@ -608,12 +608,12 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/trigger.c 424f81a5631a06dda99d70c6bfa3e7e6ead74ab9eb757b77f75a14a18ef7d419 -F src/update.c 3dbc7189ffcf361c2149f1b1d0841a8a9689d27f15c5e72e6f14ebc447e6b0c0 +F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 -F src/vdbe.c d715b1eeb37168afec92185bcf3dc6da175abafd247821af200ac7eeab68a706 +F src/vdbe.c 9b9a714318e49b59a282b4e175080dc53a07b8099895fa21613e6b80fbad3727 F src/vdbe.h a71bf43572d3de57923d1928ac01ae8d355cd67e94462ba4f7462265cedbef9a F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9 @@ -1899,7 +1899,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 a38f0c1d7c1d7635732ac370d8fbc7e6a2005378e4621da7bc4f51a2f99912d1 -R 34ba0ebdbec7699355883290972263ed +P 1f1ce7ceb9807d22efea496f33908040ee196a31cd192f27ec0fb3e23afb729c +R ed51f62c70425c1aaf20f4ecddc8579f U drh -Z 1a944974e641f069223aa2fcb2319010 +Z 39d7fe9d2d8727b4a3ee19f9ebc8e8e1 diff --git a/manifest.uuid b/manifest.uuid index ca1e4d426c..7749366dc6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1f1ce7ceb9807d22efea496f33908040ee196a31cd192f27ec0fb3e23afb729c \ No newline at end of file +154fc2b15465c7c92a1af0a93851421aec42a81bab54840a9701f2c78068e14e \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index e9b092b245..b2edaa9ab9 100644 --- a/src/delete.c +++ b/src/delete.c @@ -609,7 +609,7 @@ void sqlite3DeleteFrom( ** invoke the callback function. */ if( memCnt ){ - sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1); + sqlite3VdbeAddOp2(v, OP_ChngCntRow, memCnt, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC); } diff --git a/src/insert.c b/src/insert.c index 4f549f3523..2f22121f7d 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1319,7 +1319,7 @@ insert_end: ** invoke the callback function. */ if( regRowCount ){ - sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); + sqlite3VdbeAddOp2(v, OP_ChngCntRow, regRowCount, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC); } diff --git a/src/update.c b/src/update.c index 82a6eb6356..b360766b68 100644 --- a/src/update.c +++ b/src/update.c @@ -1107,7 +1107,7 @@ void sqlite3Update( ** that information. */ if( regRowCount ){ - sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); + sqlite3VdbeAddOp2(v, OP_ChngCntRow, regRowCount, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC); } diff --git a/src/vdbe.c b/src/vdbe.c index 6547b41553..bb18277891 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -1445,6 +1445,26 @@ case OP_IntCopy: { /* out2 */ break; } +/* Opcode: ChngCntRow P1 P2 * * * +** Synopsis: output=r[P1] +** +** Output value in register P1 as the chance count for a DML statement, +** due to the "PRAGMA count_changes=ON" setting. Or, if there was a +** foreign key error in the statement, trigger the error now. +** +** This opcode is a variant of OP_ResultRow that checks the foreign key +** immediate constraint count and throws an error if the count is +** non-zero. The P2 opcode must be 1. +*/ +case OP_ChngCntRow: { + assert( pOp->p2==1 ); + if( (rc = sqlite3VdbeCheckFk(p,0))!=SQLITE_OK ){ + goto abort_due_to_error; + } + /* Fall through to the next case, OP_String */ + /* no break */ deliberate_fall_through +} + /* Opcode: ResultRow P1 P2 * * * ** Synopsis: output=r[P1@P2] ** @@ -1461,15 +1481,6 @@ case OP_ResultRow: { assert( pOp->p1>0 ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); - /* If this statement has violated immediate foreign key constraints, do - ** not return the number of rows modified. And do not RELEASE the statement - ** transaction. It needs to be rolled back. */ - if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){ - assert( db->flags&SQLITE_CountRows ); - assert( p->usesStmtJournal ); - goto abort_due_to_error; - } - /* Invalidate all ephemeral cursor row caches */ p->cacheCtr = (p->cacheCtr + 2)|1; From 9407b6ef29d676da3184ccd456a46049c5b3c448 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sun, 31 Jan 2021 16:45:10 +0000 Subject: [PATCH 17/23] Mark an unreachable branch as ALWAYS(). FossilOrigin-Name: cb8b797a64f65fca01c5faaeb30cbe4a53b56b81e696d1b62a90362d7ef8f924 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/trigger.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index a461a2acbd..b7675c721e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\sopcode\sOP_ChngCntRow\sused\sto\soutput\sthe\sresult\sof\sPRAGMA\schange_count.\nOnly\sthis\snew\sopcode,\sand\snot\sOP_ResultRow,\schecks\sfor\sforeign\skey\serrors.\nFaster\sperformance,\sand\snow\salso\sworks\swith\sRETURNING. -D 2021-01-31T15:50:36.442 +C Mark\san\sunreachable\sbranch\sas\sALWAYS(). +D 2021-01-31T16:45:10.780 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 424f81a5631a06dda99d70c6bfa3e7e6ead74ab9eb757b77f75a14a18ef7d419 +F src/trigger.c b380259579a6d9dc3fa50d49b1b18ebfe42c10f12d3c5b3d0e2f7c3b35c45574 F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 1f1ce7ceb9807d22efea496f33908040ee196a31cd192f27ec0fb3e23afb729c -R ed51f62c70425c1aaf20f4ecddc8579f +P 154fc2b15465c7c92a1af0a93851421aec42a81bab54840a9701f2c78068e14e +R cea5f0df7552de24bb2dee28a7a1e3f6 U drh -Z 39d7fe9d2d8727b4a3ee19f9ebc8e8e1 +Z fb166b95a911fcb55830f05a31923ad0 diff --git a/manifest.uuid b/manifest.uuid index 7749366dc6..3f622440c0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -154fc2b15465c7c92a1af0a93851421aec42a81bab54840a9701f2c78068e14e \ No newline at end of file +cb8b797a64f65fca01c5faaeb30cbe4a53b56b81e696d1b62a90362d7ef8f924 \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index ae86c7c9af..de926f305d 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -821,7 +821,7 @@ static ExprList *sqlite3ExpandReturning( }else{ Expr *pNewExpr = sqlite3ExprDup(db, pOldExpr, 0); pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); - if( pList->a[i].zEName!=0 && !db->mallocFailed ){ + if( !db->mallocFailed && ALWAYS(pList->a[i].zEName!=0) ){ struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; pItem->zEName = sqlite3DbStrDup(db, pList->a[i].zEName); pItem->eEName = pList->a[i].eEName; From 7baf3d411b6dc45c4478741958e383bab5fc666a Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 1 Feb 2021 01:57:55 +0000 Subject: [PATCH 18/23] Modify RETURNING so that it does not return changes implemented by cascading foreign keys or by triggers. FossilOrigin-Name: 6e62470a737cbde7f3fdcd027b98eb0b3dd11d063c63501d3c18448e93f5959f --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/trigger.c | 5 ++++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index b7675c721e..98f33922b5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Mark\san\sunreachable\sbranch\sas\sALWAYS(). -D 2021-01-31T16:45:10.780 +C Modify\sRETURNING\sso\sthat\sit\sdoes\snot\sreturn\schanges\simplemented\sby\ncascading\sforeign\skeys\sor\sby\striggers. +D 2021-02-01T01:57:55.870 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c b380259579a6d9dc3fa50d49b1b18ebfe42c10f12d3c5b3d0e2f7c3b35c45574 +F src/trigger.c 30cb8be5ef144f5c9036cf45faa007aeb8cfebe3bc766fc58072730416d6bc57 F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 154fc2b15465c7c92a1af0a93851421aec42a81bab54840a9701f2c78068e14e -R cea5f0df7552de24bb2dee28a7a1e3f6 +P cb8b797a64f65fca01c5faaeb30cbe4a53b56b81e696d1b62a90362d7ef8f924 +R 199f69fc6dd65199d262c6cd91e2535c U drh -Z fb166b95a911fcb55830f05a31923ad0 +Z 013370d4bb9ad0b56cd61fbf8918d3d1 diff --git a/manifest.uuid b/manifest.uuid index 3f622440c0..d10e387699 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cb8b797a64f65fca01c5faaeb30cbe4a53b56b81e696d1b62a90362d7ef8f924 \ No newline at end of file +6e62470a737cbde7f3fdcd027b98eb0b3dd11d063c63501d3c18448e93f5959f \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index de926f305d..ca9033b2d6 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -742,9 +742,11 @@ Trigger *sqlite3TriggersExist( }else if( p->op==TK_RETURNING ){ /* The first time a RETURNING trigger is seen, the "op" value tells ** us what time of trigger it should be. */ + assert( sqlite3IsToplevel(pParse) ); p->op = op; mask |= TRIGGER_AFTER; - }else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE ){ + }else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE + && sqlite3IsToplevel(pParse) ){ /* Also fire a RETURNING trigger for INSERT on the UPDATE of an UPSERT */ mask |= TRIGGER_AFTER; } @@ -1228,6 +1230,7 @@ void sqlite3CodeRowTrigger( if( (p->op==op || (p->bReturning && p->op==TK_INSERT && op==TK_UPDATE)) && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns, pChanges) + && (sqlite3IsToplevel(pParse) || !p->bReturning) ){ u8 origOp = p->op; p->op = op; From d33d3a2ba729a11fd901ffda566fc22e87bcf5ad Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 1 Feb 2021 21:26:09 +0000 Subject: [PATCH 19/23] Add a few test cases for RETURNING together with UPDATE/DELETE LIMIT. FossilOrigin-Name: 7611c77d6baa84086ff18cbd045127fd682c6d5c434af5404e34fbe631fedfe1 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/wherelimit.test | 22 +++++++++++++++++----- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 98f33922b5..6d658d3ecb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Modify\sRETURNING\sso\sthat\sit\sdoes\snot\sreturn\schanges\simplemented\sby\ncascading\sforeign\skeys\sor\sby\striggers. -D 2021-02-01T01:57:55.870 +C Add\sa\sfew\stest\scases\sfor\sRETURNING\stogether\swith\sUPDATE/DELETE\sLIMIT. +D 2021-02-01T21:26:09.061 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1752,7 +1752,7 @@ F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b F test/whereL.test 1afe47227f093dc0547236491fb37529b7be9724b8575925a321001b80e6a23a F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864 F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3 -F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0 +F test/wherelimit.test daa0fd9122c5745cc459ec40b8d3c16ce13ce8382b5b847e7cfff4b871260cbf F test/wherelimit2.test 657a3f24aadee62d058c5091ea682dc4af4b95ffe32f137155be49799a58e721 F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2aeee74 F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972 @@ -1899,7 +1899,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 cb8b797a64f65fca01c5faaeb30cbe4a53b56b81e696d1b62a90362d7ef8f924 -R 199f69fc6dd65199d262c6cd91e2535c +P 6e62470a737cbde7f3fdcd027b98eb0b3dd11d063c63501d3c18448e93f5959f +R ebbe9120e496309466d7b572d1580227 U drh -Z 013370d4bb9ad0b56cd61fbf8918d3d1 +Z 59e7c95767d01f130d57c6f24563b271 diff --git a/manifest.uuid b/manifest.uuid index d10e387699..f40ec8c986 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6e62470a737cbde7f3fdcd027b98eb0b3dd11d063c63501d3c18448e93f5959f \ No newline at end of file +7611c77d6baa84086ff18cbd045127fd682c6d5c434af5404e34fbe631fedfe1 \ No newline at end of file diff --git a/test/wherelimit.test b/test/wherelimit.test index 8db7a0cc28..aeadc6f39b 100644 --- a/test/wherelimit.test +++ b/test/wherelimit.test @@ -94,21 +94,31 @@ ifcapable {update_delete_limit} { execsql {DELETE FROM t1 ORDER BY x LIMIT 5} execsql {SELECT count(*) FROM t1} } {15} + create_test_data 4 + do_test wherelimit-1.3b { + # limit 5 + execsql {DELETE FROM t1 RETURNING x, y, '|' ORDER BY x, y LIMIT 5} + } {1 1 | 1 2 | 1 3 | 1 4 | 2 1 |} + do_test wherelimit-1.3c { + execsql {SELECT count(*) FROM t1} + } {11} do_test wherelimit-1.4 { # limit 5, offset 2 - execsql {DELETE FROM t1 ORDER BY x LIMIT 5 OFFSET 2} + execsql {DELETE FROM t1 RETURNING x, y, '|' ORDER BY x LIMIT 5 OFFSET 2} + } {2 4 | 3 1 | 3 2 | 3 3 | 3 4 |} + do_test wherelimit-1.4cnt { execsql {SELECT count(*) FROM t1} - } {10} + } {6} do_test wherelimit-1.5 { # limit 5, offset -2 execsql {DELETE FROM t1 ORDER BY x LIMIT 5 OFFSET -2} execsql {SELECT count(*) FROM t1} - } {5} + } {1} do_test wherelimit-1.6 { # limit -5 (no limit), offset 2 execsql {DELETE FROM t1 ORDER BY x LIMIT 2, -5} execsql {SELECT count(*) FROM t1} - } {2} + } {1} do_test wherelimit-1.7 { # limit 5, offset -2 (no offset) execsql {DELETE FROM t1 ORDER BY x LIMIT -2, 5} @@ -227,7 +237,9 @@ ifcapable {update_delete_limit} { } {11} create_test_data 6 do_test wherelimit-3.2 { - execsql {UPDATE t1 SET y=1 WHERE x=1 LIMIT 5} + execsql {UPDATE t1 SET y=1 WHERE x=1 RETURNING x, old.y, '|' LIMIT 5} + } {1 1 | 1 2 | 1 3 | 1 4 | 1 5 |} + do_test wherelimit-3.2cnt { execsql {SELECT count(*) FROM t1 WHERE y=1} } {10} do_test wherelimit-3.3 { From c9be8630982cf8c797a0773da67958d9786bc2f3 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 2 Feb 2021 00:16:15 +0000 Subject: [PATCH 20/23] Allow the RETURNING trigger to exist for virtual tables. FossilOrigin-Name: 2f244ab4a2ba2bdb608cf44ef02e00738ad58c10a76d9e4222dc843a17103d92 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/trigger.c | 12 +++++++----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 6d658d3ecb..65556f2f8c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\sfew\stest\scases\sfor\sRETURNING\stogether\swith\sUPDATE/DELETE\sLIMIT. -D 2021-02-01T21:26:09.061 +C Allow\sthe\sRETURNING\strigger\sto\sexist\sfor\svirtual\stables. +D 2021-02-02T00:16:15.269 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 30cb8be5ef144f5c9036cf45faa007aeb8cfebe3bc766fc58072730416d6bc57 +F src/trigger.c 80c38e0d22bf062b2076a348885f40450dea5a0f5a4335916b71201653962e61 F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 6e62470a737cbde7f3fdcd027b98eb0b3dd11d063c63501d3c18448e93f5959f -R ebbe9120e496309466d7b572d1580227 +P 7611c77d6baa84086ff18cbd045127fd682c6d5c434af5404e34fbe631fedfe1 +R 037a63c21faae44932a1c96611422080 U drh -Z 59e7c95767d01f130d57c6f24563b271 +Z 602a59ff4156534125d9199fea478bc0 diff --git a/manifest.uuid b/manifest.uuid index f40ec8c986..5ddb54f697 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7611c77d6baa84086ff18cbd045127fd682c6d5c434af5404e34fbe631fedfe1 \ No newline at end of file +2f244ab4a2ba2bdb608cf44ef02e00738ad58c10a76d9e4222dc843a17103d92 \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index ca9033b2d6..efc10bb837 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -735,7 +735,8 @@ Trigger *sqlite3TriggersExist( if( (pParse->db->flags & SQLITE_EnableTrigger)!=0 ){ pList = sqlite3TriggerList(pParse, pTab); } - assert( pList==0 || IsVirtual(pTab)==0 ); + assert( pList==0 || IsVirtual(pTab)==0 + || (pList->bReturning && pList->pNext==0) ); for(p=pList; p; p=p->pNext){ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ mask |= p->tr_tm; @@ -810,13 +811,14 @@ static ExprList *sqlite3ExpandReturning( for(i=0; inExpr; i++){ Expr *pOldExpr = pList->a[i].pExpr; if( ALWAYS(pOldExpr!=0) && pOldExpr->op==TK_ASTERISK ){ - int j; - for(j=0; jnCol; j++){ - Expr *pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[j].zName); + int jj; + for(jj=0; jjnCol; jj++){ + if( IsHiddenColumn(pTab->aCol+jj) ) continue; + Expr *pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zName); pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); if( !db->mallocFailed ){ struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; - pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[j].zName); + pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zName); pItem->eEName = ENAME_NAME; } } From 709dd13927c9ecc9f53aff461124d97e6b273f6a Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 2 Feb 2021 12:01:22 +0000 Subject: [PATCH 21/23] Report an error if RETURNING is used for DELETE or UPDATE of a virtual table. FossilOrigin-Name: bd5dee8425327fde0429043ce325b910f1b7951988d9a448a8eeeb713a46bc81 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/trigger.c | 5 +++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 65556f2f8c..502b6f6d4c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Allow\sthe\sRETURNING\strigger\sto\sexist\sfor\svirtual\stables. -D 2021-02-02T00:16:15.269 +C Report\san\serror\sif\sRETURNING\sis\sused\sfor\sDELETE\sor\sUPDATE\sof\sa\svirtual\stable. +D 2021-02-02T12:01:22.075 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 80c38e0d22bf062b2076a348885f40450dea5a0f5a4335916b71201653962e61 +F src/trigger.c 0e8d33e9ba2c9ce2a3ded92b6d81afd56bac39dc0faf18455b3b49f71a451195 F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 7611c77d6baa84086ff18cbd045127fd682c6d5c434af5404e34fbe631fedfe1 -R 037a63c21faae44932a1c96611422080 +P 2f244ab4a2ba2bdb608cf44ef02e00738ad58c10a76d9e4222dc843a17103d92 +R a875c66b94135d7bf08c2474b75d1d9b U drh -Z 602a59ff4156534125d9199fea478bc0 +Z 7903baa82d2a34245eb14a08b0ad275c diff --git a/manifest.uuid b/manifest.uuid index 5ddb54f697..9fd2b15429 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2f244ab4a2ba2bdb608cf44ef02e00738ad58c10a76d9e4222dc843a17103d92 \ No newline at end of file +bd5dee8425327fde0429043ce325b910f1b7951988d9a448a8eeeb713a46bc81 \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index efc10bb837..dd645324d3 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -746,6 +746,11 @@ Trigger *sqlite3TriggersExist( assert( sqlite3IsToplevel(pParse) ); p->op = op; mask |= TRIGGER_AFTER; + if( IsVirtual(pTab) && op!=TK_INSERT ){ + sqlite3ErrorMsg(pParse, + "%s RETURNING is not available on virtual tables", + op==TK_DELETE ? "DELETE" : "UPDATE"); + } }else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE && sqlite3IsToplevel(pParse) ){ /* Also fire a RETURNING trigger for INSERT on the UPDATE of an UPSERT */ From cb83dc9e957fe5e21d8ee560e1e25838fdc1c342 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 2 Feb 2021 20:46:11 +0000 Subject: [PATCH 22/23] Do not allow aggregates in a RETURNING clause. Fix a memory leak that occurs when window functions are used in a RETURNING clause. FossilOrigin-Name: 2e9bd94b9ad37c7e4123b7324f2fe42d3609a65af449eb8a0064057647709a73 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/trigger.c | 13 ++++++++++--- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 502b6f6d4c..81bc47332a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Report\san\serror\sif\sRETURNING\sis\sused\sfor\sDELETE\sor\sUPDATE\sof\sa\svirtual\stable. -D 2021-02-02T12:01:22.075 +C Do\snot\sallow\saggregates\sin\sa\sRETURNING\sclause.\s\sFix\sa\smemory\sleak\sthat\noccurs\swhen\swindow\sfunctions\sare\sused\sin\sa\sRETURNING\sclause. +D 2021-02-02T20:46:11.972 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 0e8d33e9ba2c9ce2a3ded92b6d81afd56bac39dc0faf18455b3b49f71a451195 +F src/trigger.c a9357898b5965f579c6384b6538aa7297e3d38a132e87e1fc0e1e5b276a4cf21 F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 2f244ab4a2ba2bdb608cf44ef02e00738ad58c10a76d9e4222dc843a17103d92 -R a875c66b94135d7bf08c2474b75d1d9b +P bd5dee8425327fde0429043ce325b910f1b7951988d9a448a8eeeb713a46bc81 +R cd87aa40fae996ae8358e0b84594bda6 U drh -Z 7903baa82d2a34245eb14a08b0ad275c +Z 25e8d0af3fd413c8e6c9d01783338232 diff --git a/manifest.uuid b/manifest.uuid index 9fd2b15429..fec5166aaa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bd5dee8425327fde0429043ce325b910f1b7951988d9a448a8eeeb713a46bc81 \ No newline at end of file +2e9bd94b9ad37c7e4123b7324f2fe42d3609a65af449eb8a0064057647709a73 \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index dd645324d3..52811617ee 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -923,13 +923,20 @@ static int codeTriggerProgram( Select *pSelect = pStep->pSelect; ExprList *pList = pSelect->pEList; SelectDest sDest; + Select *pNew; pSelect->pEList = sqlite3ExpandReturning(pParse, pList, pParse->pTriggerTab); sqlite3SelectDestInit(&sDest, SRT_Output, 0); - pSelect->selFlags = 0; - sqlite3Select(pParse, pSelect, &sDest); + pNew = sqlite3SelectDup(db, pSelect, 0); + if( pNew ){ + sqlite3Select(pParse, pNew, &sDest); + if( pNew->selFlags & (SF_Aggregate|SF_HasAgg|SF_WinRewrite) ){ + sqlite3ErrorMsg(pParse, "aggregates not allowed in RETURNING"); + } + sqlite3SelectDelete(db, pNew); + } sqlite3ExprListDelete(db, pSelect->pEList); - pSelect->pEList = pList; + pStep->pSelect->pEList = pList; break; } } From 2aa41c82dab03eedefe393ee87a0b179285bf447 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 3 Feb 2021 00:55:34 +0000 Subject: [PATCH 23/23] Modify the SQLITE_DBCONFIG_ENABLE_TRIGGER setting so that it only disables main-schema triggers and allows TEMP trigger to continue operating. This is safe, since only the application (not an attacker) can add TEMP triggers. It will also all us to disengage SQLITE_DBCONFIG_ENABLE_TRIGGER on Fossil databases since Fossil has no main-schema triggers but does use TEMP triggers. FossilOrigin-Name: a10c5a2503ff2998f6ee40f721aab8c9579052e535dc141bd57d10551eaea387 --- manifest | 14 ++++++------ manifest.uuid | 2 +- src/sqlite.h.in | 8 ++++++- src/trigger.c | 57 ++++++++++++++++++++++++++++++++----------------- 4 files changed, 52 insertions(+), 29 deletions(-) diff --git a/manifest b/manifest index 8baca9a552..8950ada11e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Load\senhancements\sfrom\strunk\sinto\sthe\sreturning\sbranch. -D 2021-02-03T00:05:57.450 +C Modify\sthe\sSQLITE_DBCONFIG_ENABLE_TRIGGER\ssetting\sso\sthat\sit\sonly\sdisables\nmain-schema\striggers\sand\sallows\sTEMP\strigger\sto\scontinue\soperating.\s\sThis\sis\nsafe,\ssince\sonly\sthe\sapplication\s(not\san\sattacker)\scan\sadd\sTEMP\striggers.\nIt\swill\salso\sall\sus\sto\sdisengage\sSQLITE_DBCONFIG_ENABLE_TRIGGER\son\sFossil\ndatabases\ssince\sFossil\shas\sno\smain-schema\striggers\sbut\sdoes\suse\sTEMP\striggers. +D 2021-02-03T00:55:34.680 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -543,7 +543,7 @@ F src/resolve.c f6761473ea4b51190fc52f8f2121498b78717266e106e7bff12849ea2d52165f F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 738cb746189f721f59972993c13085fa2975c4cbfd04ba26445f3b42c81237dc F src/shell.c.in 9ebc74e4f05cfbd0f4a36060fdaeff1da4e9af4458358722bc08c5a1ab9a0879 -F src/sqlite.h.in 0af968a1fa3c717261e1df0ed105fa7bddb4d82de7e0adb3eab49e6aa81b4de7 +F src/sqlite.h.in 8855a19f37ade8dad189a9e48233a2ebe1b46faf469c7eb0906a654e252dcc57 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e F src/sqliteInt.h 0fda3b2c05b1559135aa2c4ecb8e75bd2085ba4433310bbb5427d97c2d81315d @@ -607,7 +607,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c a9357898b5965f579c6384b6538aa7297e3d38a132e87e1fc0e1e5b276a4cf21 +F src/trigger.c 0a242d65dd9b9822d4e990653eb4ece3557dcda01374934aa3cc1f9718d8dee3 F src/update.c 0f5a61f0787199983530a33f6fffe4f52742f35fcdf6ccfad1078b1a8bc17723 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1899,7 +1899,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 2e9bd94b9ad37c7e4123b7324f2fe42d3609a65af449eb8a0064057647709a73 e4ccfac09b6fe8cc3aec29d10f4e4c83097964f29882343db52ed91f6f0dde1c -R 189e18b39cf3d0cb3ef657405a5431b5 +P b84c7f60c2e1e7debf9f50622087f87d60c6870061d61e14e59cc1ba0775ee92 +R 02daf4bf169cb22bac4b88e2c2565d05 U drh -Z 8f661fe5807957ca703992c48d933956 +Z cfd272038413f78f81e2c24e00e99d6f diff --git a/manifest.uuid b/manifest.uuid index 53886e64e3..e1651727c4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b84c7f60c2e1e7debf9f50622087f87d60c6870061d61e14e59cc1ba0775ee92 \ No newline at end of file +a10c5a2503ff2998f6ee40f721aab8c9579052e535dc141bd57d10551eaea387 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index c17d012002..8a9470f01b 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2115,7 +2115,13 @@ struct sqlite3_mem_methods { ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether triggers are disabled or enabled ** following this call. The second parameter may be a NULL pointer, in -** which case the trigger setting is not reported back. +** which case the trigger setting is not reported back. +** +**

Originally this option disabled all triggers. ^(However, since +** SQLite version 3.35.0, TEMP triggers are still allowed even if +** this option is off. So, in other words, this option now only disables +** triggers in the main database schema or in the schemas of ATTACH-ed +** databases.)^ ** ** [[SQLITE_DBCONFIG_ENABLE_VIEW]] **

SQLITE_DBCONFIG_ENABLE_VIEW
diff --git a/src/trigger.c b/src/trigger.c index 52811617ee..ef0a90b24f 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -732,31 +732,48 @@ Trigger *sqlite3TriggersExist( Trigger *pList = 0; Trigger *p; - if( (pParse->db->flags & SQLITE_EnableTrigger)!=0 ){ - pList = sqlite3TriggerList(pParse, pTab); - } + pList = sqlite3TriggerList(pParse, pTab); assert( pList==0 || IsVirtual(pTab)==0 || (pList->bReturning && pList->pNext==0) ); - for(p=pList; p; p=p->pNext){ - if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ - mask |= p->tr_tm; - }else if( p->op==TK_RETURNING ){ - /* The first time a RETURNING trigger is seen, the "op" value tells - ** us what time of trigger it should be. */ - assert( sqlite3IsToplevel(pParse) ); - p->op = op; - mask |= TRIGGER_AFTER; - if( IsVirtual(pTab) && op!=TK_INSERT ){ - sqlite3ErrorMsg(pParse, - "%s RETURNING is not available on virtual tables", - op==TK_DELETE ? "DELETE" : "UPDATE"); + if( pList!=0 ){ + p = pList; + if( (pParse->db->flags & SQLITE_EnableTrigger)==0 + && pTab->pTrigger!=0 + ){ + /* The SQLITE_DBCONFIG_ENABLE_TRIGGER setting is off. That means that + ** only TEMP triggers are allowed. Truncate the pList so that it + ** includes only TEMP triggers */ + if( pList==pTab->pTrigger ){ + pList = 0; + goto exit_triggers_exist; } - }else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE - && sqlite3IsToplevel(pParse) ){ - /* Also fire a RETURNING trigger for INSERT on the UPDATE of an UPSERT */ - mask |= TRIGGER_AFTER; + while( ALWAYS(p->pNext) && p->pNext!=pTab->pTrigger ) p = p->pNext; + p->pNext = 0; + p = pList; } + do{ + if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ + mask |= p->tr_tm; + }else if( p->op==TK_RETURNING ){ + /* The first time a RETURNING trigger is seen, the "op" value tells + ** us what time of trigger it should be. */ + assert( sqlite3IsToplevel(pParse) ); + p->op = op; + mask |= TRIGGER_AFTER; + if( IsVirtual(pTab) && op!=TK_INSERT ){ + sqlite3ErrorMsg(pParse, + "%s RETURNING is not available on virtual tables", + op==TK_DELETE ? "DELETE" : "UPDATE"); + } + }else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE + && sqlite3IsToplevel(pParse) ){ + /* Also fire a RETURNING trigger for an UPSERT */ + mask |= TRIGGER_AFTER; + } + p = p->pNext; + }while( p ); } +exit_triggers_exist: if( pMask ){ *pMask = mask; }