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

Optimization: when doing an UPDATE on a table with indexes on an expression,

do not update the expression indexes if they do not refer to any of the
columns of the table being updated.

FossilOrigin-Name: a71b101635ed28a4c99734dabb20bd65ef1018c1d63ac143b7321cdb0fafa5d7
This commit is contained in:
drh
2018-09-15 21:38:48 +00:00
parent f7d3b7a56c
commit e9816d82a7
6 changed files with 102 additions and 25 deletions

View File

@@ -1126,14 +1126,15 @@ insert_cleanup:
#endif
/*
** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged()
** Meanings of bits in of pWalker->eCode for
** sqlite3ExprReferencesUpdatedColumn()
*/
#define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */
#define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */
/* This is the Walker callback from checkConstraintUnchanged(). Set
** bit 0x01 of pWalker->eCode if
** pWalker->eCode to 0 if this expression node references any of the
/* This is the Walker callback from sqlite3ExprReferencesUpdatedColumn().
* Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this
** expression node references any of the
** columns that are being modifed by an UPDATE statement.
*/
static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
@@ -1155,12 +1156,21 @@ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
** only columns that are modified by the UPDATE are those for which
** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true.
**
** Return true if CHECK constraint pExpr does not use any of the
** Return true if CHECK constraint pExpr uses any of the
** changing columns (or the rowid if it is changing). In other words,
** return true if this CHECK constraint can be skipped when validating
** return true if this CHECK constraint must be validated for
** the new row in the UPDATE statement.
**
** 2018-09-15: pExpr might also be an expression for an index-on-expressions.
** The operation of this routine is the same - return true if an only if
** the expression uses one or more of columns identified by the second and
** third arguments.
*/
static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
int sqlite3ExprReferencesUpdatedColumn(
Expr *pExpr, /* The expression to be checked */
int *aiChng, /* aiChng[x]>=0 if column x changed by the UPDATE */
int chngRowid /* True if UPDATE changes the rowid */
){
Walker w;
memset(&w, 0, sizeof(w));
w.eCode = 0;
@@ -1175,7 +1185,7 @@ static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
testcase( w.eCode==CKCNSTRNT_COLUMN );
testcase( w.eCode==CKCNSTRNT_ROWID );
testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) );
return !w.eCode;
return w.eCode!=0;
}
/*
@@ -1381,7 +1391,13 @@ void sqlite3GenerateConstraintChecks(
for(i=0; i<pCheck->nExpr; i++){
int allOk;
Expr *pExpr = pCheck->a[i].pExpr;
if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue;
if( aiChng
&& !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng)
){
/* The check constraints do not reference any of the columns being
** updated so there is no point it verifying the check constraint */
continue;
}
allOk = sqlite3VdbeMakeLabel(v);
sqlite3VdbeVerifyAbortable(v, onError);
sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);