aboutsummaryrefslogtreecommitdiff
path: root/src/insert.c
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2013-11-05 19:41:32 +0000
committerdrh <drh@noemail.net>2013-11-05 19:41:32 +0000
commit8d1b82e40bf69f65ab8371ff2dd718ffeff4f43f (patch)
tree17c970758b8930f9819d470ab19057152610532c /src/insert.c
parent5a9a37b7b418cedf1a3e4b1ea42afe0c9b1722c2 (diff)
downloadsqlite-8d1b82e40bf69f65ab8371ff2dd718ffeff4f43f.tar.gz
sqlite-8d1b82e40bf69f65ab8371ff2dd718ffeff4f43f.zip
Fix conflict handling for the case when the rowid uses REPLACE but other
unique constraints use FAIL or IGNORE. FossilOrigin-Name: 573cc27427af297185f11aac8dce88ca31f471ca
Diffstat (limited to 'src/insert.c')
-rw-r--r--src/insert.c33
1 files changed, 26 insertions, 7 deletions
diff --git a/src/insert.c b/src/insert.c
index d65c49ed5..ff3da9482 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -1229,7 +1229,9 @@ void sqlite3GenerateConstraintChecks(
int j1; /* Addresss of jump instruction */
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
- u8 isUpdate;
+ int ipkTop = 0; /* Top of the rowid change constraint check */
+ int ipkBottom = 0; /* Bottom of the rowid change constraint check */
+ u8 isUpdate; /* True if this is an UPDATE operation */
isUpdate = regOldData!=0;
db = pParse->db;
@@ -1345,6 +1347,20 @@ void sqlite3GenerateConstraintChecks(
sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
}
+ /* If the response to a rowid conflict is REPLACE but the response
+ ** to some other UNIQUE constraint is FAIL or IGNORE, then we need
+ ** to defer the running of the rowid conflict checking until after
+ ** the UNIQUE constraints have run.
+ */
+ if( onError==OE_Replace && overrideError!=OE_Replace ){
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->onError==OE_Ignore || pIdx->onError==OE_Fail ){
+ ipkTop = sqlite3VdbeAddOp0(v, OP_Goto);
+ break;
+ }
+ }
+ }
+
/* Check to see if the new rowid already exists in the table. Skip
** the following conflict logic if it does not. */
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData);
@@ -1400,12 +1416,16 @@ void sqlite3GenerateConstraintChecks(
break;
}
case OE_Ignore: {
- assert( seenReplace==0 );
+ /*assert( seenReplace==0 );*/
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
break;
}
}
sqlite3VdbeResolveLabel(v, addrRowidOk);
+ if( ipkTop ){
+ ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto);
+ sqlite3VdbeJumpHere(v, ipkTop);
+ }
}
/* Test all UNIQUE constraints by creating entries for each UNIQUE
@@ -1475,10 +1495,6 @@ void sqlite3GenerateConstraintChecks(
}else if( onError==OE_Default ){
onError = OE_Abort;
}
- if( seenReplace ){
- if( onError==OE_Ignore ) onError = OE_Replace;
- else if( onError==OE_Fail ) onError = OE_Abort;
- }
/* Check to see if the new index entry will be unique */
regR = sqlite3GetTempRange(pParse, nPkField);
@@ -1544,7 +1560,6 @@ void sqlite3GenerateConstraintChecks(
break;
}
case OE_Ignore: {
- assert( seenReplace==0 );
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
break;
}
@@ -1564,6 +1579,10 @@ void sqlite3GenerateConstraintChecks(
sqlite3VdbeResolveLabel(v, addrUniqueOk);
sqlite3ReleaseTempRange(pParse, regR, nPkField);
}
+ if( ipkTop ){
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ipkTop+1);
+ sqlite3VdbeJumpHere(v, ipkBottom);
+ }
if( pbMayReplace ){
*pbMayReplace = seenReplace;