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