More complete parsing of UPSERT, including UPSERT within a trigger.
The sqlite3Insert() logic to actually perform the UPSERT is not yet implemented, however. FossilOrigin-Name: 5cc2a5a315a2f26b392811de45b3dc352873a173c2c6c65f37ce2e5f88a71cd2
This commit is contained in:
parent
26cf56f80b
commit
2c2e844a36
23
manifest
23
manifest
@ -1,5 +1,5 @@
|
||||
C Demonstration\sof\show\sthe\sparser\scan\sbe\saugmented\sto\srecognize\sa\nPostgreSQL-style\sUPSERT.\s\sThis\scheck-in\simplements\sparsing\sonly.
|
||||
D 2018-04-06T19:36:49.704
|
||||
C More\scomplete\sparsing\sof\sUPSERT,\sincluding\sUPSERT\swithin\sa\strigger.\nThe\ssqlite3Insert()\slogic\sto\sactually\sperform\sthe\sUPSERT\sis\snot\syet\nimplemented,\showever.
|
||||
D 2018-04-07T15:04:05.872
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 7016fc56c6b9bfe5daac4f34be8be38d8c0b5fab79ccbfb764d3b23bf1c6fff3
|
||||
@ -452,7 +452,7 @@ F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c b9ff71cc2913d1d57698a1e22bf853261a9a642baf62bdf40ddeb3809adb85b5
|
||||
F src/insert.c 5e7a7dd617950277436e9d7f0b4782a310dc73a70a22fa1ed704f84dd687b638
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c f6e4e416a736369f9e80eba609f0acda97148a8b0453784d670c78d3eed2f302
|
||||
F src/main.c 1648fc7a9bcfdbfd9a9a04af96ff2796c3164b3f3c7e56ed63a3c51cd11d198d
|
||||
@ -480,7 +480,7 @@ F src/os_win.c eb03c6d52f893bcd7fdd4c6006674c13c1b5e49543fec98d605201af2997171c
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 1bb6a57fa0465296a4d6109a1a64610a0e7adde1f3acf3ef539a9d972908ce8f
|
||||
F src/pager.h c571b064df842ec8f2e90855dead9acf4cbe0d1b2c05afe0ef0d0145f7fd0388
|
||||
F src/parse.y b6f9277147926f21ef287fbb8bc6592d801bc8f369d414af47ff2f230f026ea0
|
||||
F src/parse.y 2779b5f1a24508825b7b883d73ba1632f9cc1715ffbf7b0b864b98f867742aa9
|
||||
F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
|
||||
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||
@ -496,7 +496,7 @@ F src/shell.c.in d6a07811aa9f3b10200c15ab8dd4b6b998849a3b0c8b125bfa980329a33c26a
|
||||
F src/sqlite.h.in e0be726ea6e4e6571724d39d242472ecd8bd1ba6f84ade88e1641bde98a6d02b
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 83a3c4ce93d650bedfd1aa558cb85a516bd6d094445ee989740827d0d944368d
|
||||
F src/sqliteInt.h a4837c57f9a3e2af100bc59f4be60d16b823f18131f8cef6a6685440f775eebd
|
||||
F src/sqliteInt.h a1a986e2b9d1c7920e355bb88f6c4a1db2667befc59dcadfdb0ae559d5ba7c70
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@ -555,7 +555,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 5b0c661a85f783d35b9883830736eeb63be4aefc4f6b7d9cd081d48782c041e2
|
||||
F src/treeview.c 14d5d1254702ec96876aa52642cb31548612384134970409fae333b25b39d6bb
|
||||
F src/trigger.c a34539c69433276d37b0da9a89c117726ff2d292c0902895af1f393a983cd3a1
|
||||
F src/trigger.c 974377de987711636aa7faec963863ae8864139a051d5ba2a2a4a0329dcd8895
|
||||
F src/update.c 97d4c9514229f540f8c441e124d5af7f93c5b030c9574539d01e99462e273998
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
||||
@ -1645,7 +1645,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
|
||||
F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e
|
||||
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
|
||||
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
|
||||
F tool/mkkeywordhash.c 2e852ac0dfdc5af18886dc1ce7e9676d11714ae3df0a282dc7d90b3a0fe2033c
|
||||
F tool/mkkeywordhash.c 9f5fee138b7f8d0ccde7baad1564db8de36e76e1bd1ee7a417a1fe6cecf599fb
|
||||
F tool/mkmsvcmin.tcl 8baf26690b80d861d0ac341b29880eec6ade39e4f11fe690271ded9cb90563a3
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 4ee2a30ccbd900dc4d5cdb61bdab87cd2166cd2affcc78c9cc0b8d22a65b2eee
|
||||
@ -1717,10 +1717,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 602fbd8149b53d8f0e9a223cc1aec912e7df03fca35071e8d707776ce225371c
|
||||
R 944a876dd463c4d747f0489cc93d0c37
|
||||
T *branch * upsert
|
||||
T *sym-upsert *
|
||||
T -sym-trunk *
|
||||
P 9b22905b15791170998a5d1bcf42c7b60b5064f6848fff827bd55e864bf724aa
|
||||
R 1c5f4cdb7d88fb6bd739d670ffaa88be
|
||||
U drh
|
||||
Z e91165cd71d725e31774ced0fb05304c
|
||||
Z 62c48cab2b4c90f71fb632bd2119d13f
|
||||
|
@ -1 +1 @@
|
||||
9b22905b15791170998a5d1bcf42c7b60b5064f6848fff827bd55e864bf724aa
|
||||
5cc2a5a315a2f26b392811de45b3dc352873a173c2c6c65f37ce2e5f88a71cd2
|
@ -488,7 +488,8 @@ void sqlite3Insert(
|
||||
SrcList *pTabList, /* Name of table into which we are inserting */
|
||||
Select *pSelect, /* A SELECT statement to use as the data source */
|
||||
IdList *pColumn, /* Column names corresponding to IDLIST. */
|
||||
int onError /* How to handle constraint errors */
|
||||
int onError, /* How to handle constraint errors */
|
||||
ExprList *pUpsert /* Upsert values */
|
||||
){
|
||||
sqlite3 *db; /* The main database structure */
|
||||
Table *pTab; /* The table to insert into. aka TABLE */
|
||||
@ -527,6 +528,11 @@ void sqlite3Insert(
|
||||
int tmask; /* Mask of trigger times */
|
||||
#endif
|
||||
|
||||
/* The conflict resolution type is always OE_Update or OE_Replace when
|
||||
** there is an upsert clause */
|
||||
assert( onError==OE_Update || pUpsert==0 );
|
||||
assert( OE_Update==OE_Replace );
|
||||
|
||||
db = pParse->db;
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
goto insert_cleanup;
|
||||
@ -1074,6 +1080,7 @@ insert_end:
|
||||
insert_cleanup:
|
||||
sqlite3SrcListDelete(db, pTabList);
|
||||
sqlite3ExprListDelete(db, pList);
|
||||
sqlite3ExprListDelete(db, pUpsert);
|
||||
sqlite3SelectDelete(db, pSelect);
|
||||
sqlite3IdListDelete(db, pColumn);
|
||||
sqlite3DbFree(db, aRegIdx);
|
||||
|
65
src/parse.y
65
src/parse.y
@ -98,6 +98,22 @@
|
||||
*/
|
||||
struct TrigEvent { int a; IdList * b; };
|
||||
|
||||
/*
|
||||
** An instance of this object holds the argument of the ON CONFLICT
|
||||
** clause of an UPSERT.
|
||||
**
|
||||
** The ON CONFLICT clause takes three forms, identified by the Upsert.e
|
||||
** field:
|
||||
**
|
||||
** OE_None: No ON CONFLICT clause
|
||||
** OE_Ignore: ON CONFLICT DO NOTHING
|
||||
** OE_Update: ON CONFLICT DO UPDATE ...
|
||||
*/
|
||||
struct Upsert {
|
||||
ExprList *p; /* column=expr entries for the UPDATE. Or NULL */
|
||||
int e; /* OE_None, OE_Replace, or OE_Ignore */
|
||||
};
|
||||
|
||||
/*
|
||||
** Disable lookaside memory allocation for objects that might be
|
||||
** shared across database connections.
|
||||
@ -205,7 +221,7 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
//
|
||||
%fallback ID
|
||||
ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW
|
||||
CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
||||
CONFLICT DATABASE DEFERRED DESC DETACH DO EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
||||
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN
|
||||
QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW
|
||||
ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
|
||||
@ -842,18 +858,48 @@ setlist(A) ::= LP idlist(X) RP EQ expr(Y). {
|
||||
|
||||
////////////////////////// The INSERT command /////////////////////////////////
|
||||
//
|
||||
cmd ::= with(W) insert_cmd(R) INTO fullname(X) idlist_opt(F) select(S) upsert. {
|
||||
cmd ::= with(W) insert_cmd(R) INTO fullname(X) idlist_opt(F) select(S)
|
||||
upsert(U). {
|
||||
sqlite3WithPush(pParse, W, 1);
|
||||
sqlite3Insert(pParse, X, S, F, R);
|
||||
sqlite3Insert(pParse, X, S, F, upsertType(pParse, R, U.e), U.p);
|
||||
}
|
||||
cmd ::= with(W) insert_cmd(R) INTO fullname(X) idlist_opt(F) DEFAULT VALUES.
|
||||
{
|
||||
sqlite3WithPush(pParse, W, 1);
|
||||
sqlite3Insert(pParse, X, 0, F, R);
|
||||
sqlite3Insert(pParse, X, 0, F, R, 0);
|
||||
}
|
||||
|
||||
upsert ::= .
|
||||
upsert ::= ON CONFLICT SET setlist.
|
||||
%type upsert {struct Upsert}
|
||||
%destructor upsert {sqlite3ExprListDelete(pParse->db,$$.p);}
|
||||
upsert(A) ::= . {
|
||||
A.p = 0;
|
||||
A.e = OE_None;
|
||||
}
|
||||
upsert(A) ::= ON CONFLICT DO UPDATE SET setlist(X). {
|
||||
A.p = X; /*A-overwrites-X*/
|
||||
A.e = OE_Update;
|
||||
}
|
||||
upsert(A) ::= ON CONFLICT DO NOTHING. {
|
||||
A.p = 0;
|
||||
A.e = OE_Ignore;
|
||||
}
|
||||
|
||||
%include {
|
||||
/* Compute and return the correct conflict resolution strategy for an
|
||||
** INSERT statement. If the statement begins with REPLACE or with
|
||||
** INSERT OR, and it contains an ON CONFLICT clause, throw an error.
|
||||
*/
|
||||
static int upsertType(Parse *pParse, int orconf, int upsertType){
|
||||
if( upsertType!=OE_None ){
|
||||
if( orconf!=OE_Default ){
|
||||
sqlite3ErrorMsg(pParse, "ON CONFLICT clause not allowed");
|
||||
}
|
||||
return upsertType;
|
||||
}else{
|
||||
return orconf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
%type insert_cmd {int}
|
||||
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
|
||||
@ -1400,9 +1446,10 @@ trigger_cmd(A) ::=
|
||||
|
||||
// INSERT
|
||||
trigger_cmd(A) ::= scanpt(B) insert_cmd(R) INTO
|
||||
trnm(X) idlist_opt(F) select(S) scanpt(Z).
|
||||
{A = sqlite3TriggerInsertStep(pParse->db,&X,F,S,R,B,Z);/*A-overwrites-R*/}
|
||||
|
||||
trnm(X) idlist_opt(F) select(S) upsert(U) scanpt(Z). {
|
||||
A = sqlite3TriggerInsertStep(pParse->db,&X,F,S,upsertType(pParse,R,U.e),
|
||||
U.p,B,Z);/*A-overwrites-R*/
|
||||
}
|
||||
// DELETE
|
||||
trigger_cmd(A) ::= DELETE(B) FROM trnm(X) tridxby where_opt(Y) scanpt(E).
|
||||
{A = sqlite3TriggerDeleteStep(pParse->db, &X, Y, B.z, E);}
|
||||
|
@ -2046,6 +2046,7 @@ struct FKey {
|
||||
#define OE_Fail 3 /* Stop the operation but leave all prior changes */
|
||||
#define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */
|
||||
#define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */
|
||||
#define OE_Update 5 /* An UPSERT. Same value as OE_Replace. */
|
||||
|
||||
#define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */
|
||||
#define OE_SetNull 7 /* Set the foreign key value to NULL */
|
||||
@ -3207,7 +3208,7 @@ struct TriggerStep {
|
||||
Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */
|
||||
char *zTarget; /* Target table for DELETE, UPDATE, INSERT */
|
||||
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
|
||||
ExprList *pExprList; /* SET clause for UPDATE. */
|
||||
ExprList *pExprList; /* SET clause for UPDATE or UPSERT. */
|
||||
IdList *pIdList; /* Column names for INSERT */
|
||||
char *zSpan; /* Original SQL text of this command */
|
||||
TriggerStep *pNext; /* Next in the link-list */
|
||||
@ -3740,7 +3741,7 @@ void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
# define sqlite3AutoincrementBegin(X)
|
||||
# define sqlite3AutoincrementEnd(X)
|
||||
#endif
|
||||
void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int);
|
||||
void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, ExprList*);
|
||||
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
|
||||
IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
|
||||
int sqlite3IdListIndex(IdList*,const char*);
|
||||
@ -3916,7 +3917,8 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
|
||||
TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
|
||||
const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
|
||||
Select*,u8,const char*,const char*);
|
||||
Select*,u8,ExprList*,
|
||||
const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8,
|
||||
const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*,
|
||||
|
@ -416,6 +416,7 @@ TriggerStep *sqlite3TriggerInsertStep(
|
||||
IdList *pColumn, /* List of columns in pTableName to insert into */
|
||||
Select *pSelect, /* A SELECT statement that supplies values */
|
||||
u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
|
||||
ExprList *pUpsert, /* Upsert values */
|
||||
const char *zStart, /* Start of SQL text */
|
||||
const char *zEnd /* End of SQL text */
|
||||
){
|
||||
@ -430,6 +431,7 @@ TriggerStep *sqlite3TriggerInsertStep(
|
||||
pTriggerStep->orconf = orconf;
|
||||
}else{
|
||||
sqlite3IdListDelete(db, pColumn);
|
||||
sqlite3ExprListDelete(db, pUpsert);
|
||||
}
|
||||
sqlite3SelectDelete(db, pSelect);
|
||||
|
||||
@ -755,7 +757,8 @@ static int codeTriggerProgram(
|
||||
targetSrcList(pParse, pStep),
|
||||
sqlite3SelectDup(db, pStep->pSelect, 0),
|
||||
sqlite3IdListDup(db, pStep->pIdList),
|
||||
pParse->eOrconf
|
||||
pStep->pExprList ? OE_Update : pParse->eOrconf,
|
||||
sqlite3ExprListDup(db, pStep->pExprList, 0)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
@ -186,6 +186,7 @@ static Keyword aKeywordTable[] = {
|
||||
{ "DESC", "TK_DESC", ALWAYS },
|
||||
{ "DETACH", "TK_DETACH", ATTACH },
|
||||
{ "DISTINCT", "TK_DISTINCT", ALWAYS },
|
||||
{ "DO", "TK_DO", ALWAYS },
|
||||
{ "DROP", "TK_DROP", ALWAYS },
|
||||
{ "END", "TK_END", ALWAYS },
|
||||
{ "EACH", "TK_EACH", TRIGGER },
|
||||
@ -226,6 +227,7 @@ static Keyword aKeywordTable[] = {
|
||||
{ "NATURAL", "TK_JOIN_KW", ALWAYS },
|
||||
{ "NO", "TK_NO", FKEY },
|
||||
{ "NOT", "TK_NOT", ALWAYS },
|
||||
{ "NOTHING", "TK_NOTHING", ALWAYS },
|
||||
{ "NOTNULL", "TK_NOTNULL", ALWAYS },
|
||||
{ "NULL", "TK_NULL", ALWAYS },
|
||||
{ "OF", "TK_OF", ALWAYS },
|
||||
|
Loading…
x
Reference in New Issue
Block a user