Omit unnecessary CHECK constraints in UPDATE statements, when none of the
columns referenced in the CHECK constraint are modified.
FossilOrigin-Name: 02fbdbc782dd98f080bf4482d820f36c0ef3d519
diff --git a/src/insert.c b/src/insert.c
index 95321cd..a77d3e9 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -1077,6 +1077,38 @@
#undef tmask
#endif
+/* This is the Walker callback from checkConstraintUnchanged(). Set
+** pWalker->eCode to 0 if this expression node references any of the
+** columns that are being modifed by an UPDATE statement.
+*/
+static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_COLUMN
+ && pExpr->iColumn>=0
+ && pWalker->u.aiCol[pExpr->iColumn]>=0
+ ){
+ pWalker->eCode = 0;
+ }
+ return WRC_Continue;
+}
+
+/*
+** pExpr is a CHECK constraint on a row that is being UPDATE-ed. The
+** only columns that are modified by the UPDATE are those for which
+** aiChng[i]>=0. Return true if CHECK constraint pExpr does not use
+** any of the changing columns. In other words, return true if this
+** CHECK constraint can be skipped when validating the new row in
+** the UPDATE statement.
+*/
+static int checkConstraintUnchanged(Expr *pExpr, int *aiChng){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.eCode = 1;
+ w.xExprCallback = checkConstraintExprNode;
+ w.u.aiCol = aiChng;
+ sqlite3WalkExpr(&w, pExpr);
+ return w.eCode;
+}
+
/*
** Generate code to do constraint checks prior to an INSERT or an UPDATE
** on table pTab.
@@ -1275,7 +1307,9 @@
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
for(i=0; i<pCheck->nExpr; i++){
int allOk = sqlite3VdbeMakeLabel(v);
- sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
+ Expr *pExpr = pCheck->a[i].pExpr;
+ if( aiChng && checkConstraintUnchanged(pExpr, aiChng) ) continue;
+ sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);
if( onError==OE_Ignore ){
sqlite3VdbeGoto(v, ignoreDest);
}else{