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

Fix conflict handling for the case when the rowid uses REPLACE but other

unique constraints use FAIL or IGNORE.

FossilOrigin-Name: 573cc27427af297185f11aac8dce88ca31f471ca
This commit is contained in:
drh
2013-11-05 19:41:32 +00:00
parent 5a9a37b7b4
commit 8d1b82e40b
4 changed files with 390 additions and 14 deletions

View File

@@ -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;