Extend the upsert syntax to allow a WHERE clause on the UPDATE.
FossilOrigin-Name: e4396c540a22fbc087a01050a32bfad514259d700c2381d7ac912580d7dca00f
diff --git a/src/build.c b/src/build.c
index 62d9bb0..2b3c8a1 100644
--- a/src/build.c
+++ b/src/build.c
@@ -4483,6 +4483,7 @@
Upsert *pNext = p->pUpsertNext;
sqlite3ExprListDelete(db, p->pUpsertTarget);
sqlite3ExprListDelete(db, p->pUpsertSet);
+ sqlite3ExprDelete(db, p->pUpsertWhere);
sqlite3DbFree(db, p);
p = pNext;
}
@@ -4491,17 +4492,16 @@
#ifndef SQLITE_OMIT_UPSERT
/*
-** Duplicate an Upsert object
+** Duplicate an Upsert object.
*/
Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
- Upsert *pNew;
if( p==0 ) return 0;
- pNew = sqlite3DbMallocRaw(db, sizeof(Upsert));
- if( pNew==0 ) return 0;
- pNew->pUpsertTarget = sqlite3ExprListDup(db, p->pUpsertTarget, 0);
- pNew->pUpsertSet = sqlite3ExprListDup(db, p->pUpsertSet, 0);
- pNew->pUpsertNext = sqlite3UpsertDup(db, p->pUpsertNext);
- return pNew;
+ return sqlite3UpsertNew(db,
+ sqlite3UpsertDup(db, p->pUpsertNext),
+ sqlite3ExprListDup(db, p->pUpsertTarget, 0),
+ sqlite3ExprListDup(db, p->pUpsertSet, 0),
+ sqlite3ExprDup(db, p->pUpsertWhere, 0)
+ );
}
#endif /* SQLITE_OMIT_UPSERT */
@@ -4511,9 +4511,10 @@
*/
Upsert *sqlite3UpsertNew(
sqlite3 *db, /* Determines which memory allocator to use */
- Upsert *pPrior, /* Append new upsert to the end of this one */
+ Upsert *pPrior, /* Append this upsert to the end of the new one */
ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */
- ExprList *pSet /* UPDATE columns, or NULL for a DO NOTHING */
+ ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */
+ Expr *pWhere /* WHERE clause for the ON CONFLICT UPDATE */
){
Upsert *pNew;
pNew = sqlite3DbMallocRaw(db, sizeof(Upsert));
@@ -4521,11 +4522,13 @@
sqlite3UpsertDelete(db, pPrior);
sqlite3ExprListDelete(db, pTarget);
sqlite3ExprListDelete(db, pSet);
+ sqlite3ExprDelete(db, pWhere);
return 0;
}else{
pNew->pUpsertTarget = pTarget;
pNew->pUpsertSet = pSet;
pNew->pUpsertNext = pPrior;
+ pNew->pUpsertWhere = pWhere;
}
return pNew;
}
diff --git a/src/parse.y b/src/parse.y
index 059cd26..7664361 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -870,14 +870,15 @@
%type upsert {Upsert*}
%destructor upsert {sqlite3UpsertDelete(pParse->db,$$);}
upsert(A) ::= . { A = 0; }
-upsert(A) ::= upsert(X) ON CONFLICT LP sortlist(Y) RP DO UPDATE SET setlist(Z).
- { A = sqlite3UpsertNew(pParse->db,X,Y,Z); /*X-overwrites-A*/ }
-upsert(A) ::= upsert(X) ON DUPLIATE KEY UPDATE setlist(Z).
- { A = sqlite3UpsertNew(pParse->db,X,0,Z); /*X-overwrites-A*/ }
+upsert(A) ::= upsert(X) ON CONFLICT LP sortlist(Y) RP
+ DO UPDATE SET setlist(Z) where_opt(W).
+ { A = sqlite3UpsertNew(pParse->db,X,Y,Z,W); /*X-overwrites-A*/ }
+upsert(A) ::= upsert(X) ON DUPLIATE KEY UPDATE setlist(Z) where_opt(W).
+ { A = sqlite3UpsertNew(pParse->db,X,0,Z,W); /*X-overwrites-A*/ }
upsert(A) ::= upsert(X) ON CONFLICT LP sortlist(Y) RP DO NOTHING.
- { A = sqlite3UpsertNew(pParse->db,X,Y,0); /*X-overwrites-A*/ }
+ { A = sqlite3UpsertNew(pParse->db,X,Y,0,0); /*X-overwrites-A*/ }
upsert(A) ::= upsert(X) ON CONFLICT DO NOTHING.
- { A = sqlite3UpsertNew(pParse->db,X,0,0); /*X-overwrites-A*/ }
+ { A = sqlite3UpsertNew(pParse->db,X,0,0,0); /*X-overwrites-A*/ }
%type insert_cmd {int}
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 1be52c2..bb23e25 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -2717,6 +2717,7 @@
struct Upsert {
ExprList *pUpsertTarget; /* Optional description of conflicting index */
ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */
+ Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
Upsert *pUpsertNext; /* Next ON CONFLICT clause in the list */
};
@@ -4270,11 +4271,11 @@
#define sqlite3WithDelete(x,y)
#endif
#ifndef SQLITE_OMIT_UPSERT
- Upsert *sqlite3UpsertNew(sqlite3*,Upsert*,ExprList*,ExprList*);
+ Upsert *sqlite3UpsertNew(sqlite3*,Upsert*,ExprList*,ExprList*,Expr*);
void sqlite3UpsertDelete(sqlite3*,Upsert*);
Upsert *sqlite3UpsertDup(sqlite3*,Upsert*);
#else
-#define sqlite3UpsertNew(x,y,z) ((Upsert*)0)
+#define sqlite3UpsertNew(x,y,z,w) ((Upsert*)0)
#define sqlite3UpsertDelete(x,y)
#define sqlite3UpsertDup(x,y) ((Upsert*)0)
#endif