1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-11 01:42:22 +03:00

Enhance UPSERT so that it allows multiple ON CONFLICT clauses and does

not require a conflict target for DO UPDATE.

FossilOrigin-Name: 6b01a24daab1e5bcb0768ebf994368d941b1dfc217bf6b661211d900331e68cf
This commit is contained in:
drh
2020-12-14 15:39:12 +00:00
7 changed files with 772 additions and 169 deletions

View File

@@ -2316,16 +2316,22 @@ struct FKey {
** is returned. REPLACE means that preexisting database rows that caused
** a UNIQUE constraint violation are removed so that the new insert or
** update can proceed. Processing continues and no error is reported.
** UPDATE applies to insert operations only and means that the insert
** is omitted and the DO UPDATE clause of an upsert is run instead.
**
** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys.
** RESTRICT, SETNULL, SETDFLT, and CASCADE actions apply only to foreign keys.
** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the
** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign
** key is set to NULL. CASCADE means that a DELETE or UPDATE of the
** key is set to NULL. SETDFLT means that the foreign key is set
** to its default value. CASCADE means that a DELETE or UPDATE of the
** referenced table row is propagated into the row that holds the
** foreign key.
**
** The OE_Default value is a place holder that means to use whatever
** conflict resolution algorthm is required from context.
**
** The following symbolic values are used to record which type
** of action to take.
** of conflict resolution action to take.
*/
#define OE_None 0 /* There is no constraint to check */
#define OE_Rollback 1 /* Fail the operation and rollback the transaction */
@@ -3079,15 +3085,21 @@ struct NameContext {
** WHERE clause is omitted.
*/
struct Upsert {
ExprList *pUpsertTarget; /* Optional description of conflicting index */
ExprList *pUpsertTarget; /* Optional description of conflict target */
Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */
ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
/* The fields above comprise the parse tree for the upsert clause.
** The fields below are used to transfer information from the INSERT
** processing down into the UPDATE processing while generating code.
** Upsert owns the memory allocated above, but not the memory below. */
Index *pUpsertIdx; /* Constraint that pUpsertTarget identifies */
Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */
/* Above this point is the parse tree for the ON CONFLICT clauses.
** The next group of fields stores intermediate data. */
void *pToFree; /* Free memory when deleting the Upsert object */
/* All fields above are owned by the Upsert object and must be freed
** when the Upsert is destroyed. The fields below are used to transfer
** information from the INSERT processing down into the UPDATE processing
** while generating code. The fields below are owned by the INSERT
** statement and will be freed by INSERT processing. */
Index *pUpsertIdx; /* UNIQUE constraint specified by pUpsertTarget */
SrcList *pUpsertSrc; /* Table to be updated */
int regData; /* First register holding array of VALUES */
int iDataCur; /* Index of the data cursor */
@@ -4837,15 +4849,19 @@ const char *sqlite3JournalModename(int);
#define sqlite3WithDelete(x,y)
#endif
#ifndef SQLITE_OMIT_UPSERT
Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*);
Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
void sqlite3UpsertDelete(sqlite3*,Upsert*);
Upsert *sqlite3UpsertDup(sqlite3*,Upsert*);
int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*);
void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
Upsert *sqlite3UpsertOfIndex(Upsert*,Index*);
int sqlite3UpsertNextIsIPK(Upsert*);
#else
#define sqlite3UpsertNew(v,w,x,y,z) ((Upsert*)0)
#define sqlite3UpsertNew(u,v,w,x,y,z) ((Upsert*)0)
#define sqlite3UpsertDelete(x,y)
#define sqlite3UpsertDup(x,y) ((Upsert*)0)
#define sqlite3UpsertDup(x,y) ((Upsert*)0)
#define sqlite3UpsertOfIndex(x,y) ((Upsert*)0)
#define sqlite3UpsertNextIsIPK(x) 0
#endif