diff options
author | drh <drh@noemail.net> | 2019-10-26 17:08:06 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2019-10-26 17:08:06 +0000 |
commit | cbda9c7ac79f8751e18fba943e30fd67f8c68b02 (patch) | |
tree | 3111274b6b98a7bcb7b00d0db88bd2c38cc9d928 /src | |
parent | d3c468b758175adb95d0f20862047acdd7c2ab57 (diff) | |
download | sqlite-cbda9c7ac79f8751e18fba943e30fd67f8c68b02.tar.gz sqlite-cbda9c7ac79f8751e18fba943e30fd67f8c68b02.zip |
Performance optimization on sqlite3GenerateConstraintChecks() - bypass the
loop that checks each column for NOT NULL constraints if it is known in
advance that the table has no NOT NULL constraints.
FossilOrigin-Name: e3c3f4d7872f431a95627d52553101388c1e39458cc7e7f93fc81255f49a89a5
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 1 | ||||
-rw-r--r-- | src/insert.c | 107 |
2 files changed, 56 insertions, 52 deletions
diff --git a/src/build.c b/src/build.c index 22a57a240..9adc4d593 100644 --- a/src/build.c +++ b/src/build.c @@ -1836,6 +1836,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ pTab->aCol[i].notNull = OE_Abort; } } + pTab->tabFlags |= TF_HasNotNull; } /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY diff --git a/src/insert.c b/src/insert.c index 7e7fb0847..215aafb32 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1352,64 +1352,67 @@ void sqlite3GenerateConstraintChecks( /* Test all NOT NULL constraints. */ - for(i=0; i<nCol; i++){ - if( i==pTab->iPKey ){ - continue; /* ROWID is never NULL */ - } - if( aiChng && aiChng[i]<0 ){ - /* Don't bother checking for NOT NULL on columns that do not change */ - continue; - } - onError = pTab->aCol[i].notNull; - if( onError==OE_None ) continue; /* This column is allowed to be NULL */ - if( overrideError!=OE_Default ){ - onError = overrideError; - }else if( onError==OE_Default ){ - onError = OE_Abort; - } - if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){ - onError = OE_Abort; - } - assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail - || onError==OE_Ignore || onError==OE_Replace ); - addr1 = 0; - switch( onError ){ - case OE_Replace: { - assert( onError==OE_Replace ); - addr1 = sqlite3VdbeMakeLabel(pParse); - sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1); - VdbeCoverage(v); - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i); - sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1); - VdbeCoverage(v); + if( pTab->tabFlags & TF_HasNotNull ){ + for(i=0; i<nCol; i++){ + onError = pTab->aCol[i].notNull; + if( onError==OE_None ) continue; /* No NOT NULL on this column */ + assert( pTab->tabFlags & TF_HasNotNull ); + if( i==pTab->iPKey ){ + continue; /* ROWID is never NULL */ + } + if( aiChng && aiChng[i]<0 ){ + /* Don't bother checking for NOT NULL on columns that do not change */ + continue; + } + if( overrideError!=OE_Default ){ + onError = overrideError; + }else if( onError==OE_Default ){ onError = OE_Abort; - /* Fall through into the OE_Abort case to generate code that runs - ** if both the input and the default value are NULL */ } - case OE_Abort: - sqlite3MayAbort(pParse); - /* Fall through */ - case OE_Rollback: - case OE_Fail: { - char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, - pTab->aCol[i].zName); - sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, - regNewData+1+i); - sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); - sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); - VdbeCoverage(v); - if( addr1 ) sqlite3VdbeResolveLabel(v, addr1); - break; + if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){ + onError = OE_Abort; } - default: { - assert( onError==OE_Ignore ); - sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest); - VdbeCoverage(v); - break; + assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail + || onError==OE_Ignore || onError==OE_Replace ); + addr1 = 0; + switch( onError ){ + case OE_Replace: { + assert( onError==OE_Replace ); + addr1 = sqlite3VdbeMakeLabel(pParse); + sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1); + VdbeCoverage(v); + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i); + sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1); + VdbeCoverage(v); + onError = OE_Abort; + /* Fall through into the OE_Abort case to generate code that runs + ** if both the input and the default value are NULL */ + } + case OE_Abort: + sqlite3MayAbort(pParse); + /* Fall through */ + case OE_Rollback: + case OE_Fail: { + char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, + pTab->aCol[i].zName); + sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, + onError, regNewData+1+i); + sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); + sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); + VdbeCoverage(v); + if( addr1 ) sqlite3VdbeResolveLabel(v, addr1); + break; + } + default: { + assert( onError==OE_Ignore ); + sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest); + VdbeCoverage(v); + break; + } } } } - + /* Test all CHECK constraints */ #ifndef SQLITE_OMIT_CHECK |