aboutsummaryrefslogtreecommitdiff
path: root/src/update.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/update.c')
-rw-r--r--src/update.c49
1 files changed, 29 insertions, 20 deletions
diff --git a/src/update.c b/src/update.c
index f0880de40..c5463bc73 100644
--- a/src/update.c
+++ b/src/update.c
@@ -115,12 +115,12 @@ void sqlite3Update(
int iDb; /* Database containing the table being updated */
int j1; /* Addresses of jump instructions */
int okOnePass; /* True for one-pass algorithm without the FIFO */
+ int hasFK; /* True if foreign key processing is required */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */
Trigger *pTrigger; /* List of triggers on pTab, if required */
#endif
- u32 oldmask = 0; /* Mask of OLD.* columns in use */
/* Register Allocations */
int regRowCount = 0; /* A count of rows changed */
@@ -159,6 +159,8 @@ void sqlite3Update(
# define isView 0
#endif
+ hasFK = sqlite3FkRequired(pParse, pTab, pChanges);
+
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
@@ -273,11 +275,11 @@ void sqlite3Update(
/* Allocate required registers. */
regOldRowid = regNewRowid = ++pParse->nMem;
- if( pTrigger ){
+ if( pTrigger || hasFK ){
regOld = pParse->nMem + 1;
pParse->nMem += pTab->nCol;
}
- if( chngRowid || pTrigger ){
+ if( chngRowid || pTrigger || hasFK ){
regNewRowid = ++pParse->nMem;
}
regNew = pParse->nMem + 1;
@@ -289,10 +291,6 @@ void sqlite3Update(
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
}
- /* If there are any triggers, set oldmask and new_col_mask. */
- oldmask = sqlite3TriggerOldmask(
- pParse, pTrigger, TK_UPDATE, pChanges, pTab, onError);
-
/* If we are trying to update a view, realize that view into
** a ephemeral table.
*/
@@ -378,9 +376,21 @@ void sqlite3Update(
** for example, then jump to the next iteration of the RowSet loop. */
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
+ /* If the record number will change, set register regNewRowid to
+ ** contain the new value. If the record number is not being modified,
+ ** then regNewRowid is the same register as regOldRowid, which is
+ ** already populated. */
+ assert( chngRowid || pTrigger || hasFK || regOldRowid==regNewRowid );
+ if( chngRowid ){
+ sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
+ sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid);
+ }
+
/* If there are triggers on this table, populate an array of registers
** with the required old.* column data. */
- if( pTrigger ){
+ if( hasFK || pTrigger ){
+ u32 oldmask = sqlite3FkOldmask(pParse, pTab, pChanges);
+ oldmask |= sqlite3TriggerOldmask(pParse, pTrigger, pChanges, pTab, onError);
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i);
@@ -389,18 +399,9 @@ void sqlite3Update(
sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i);
}
}
- }
-
- /* If the record number will change, set register regNewRowid to
- ** contain the new value. If the record number is not being modified,
- ** then regNewRowid is the same register as regOldRowid, which is
- ** already populated. */
- assert( chngRowid || pTrigger || regOldRowid==regNewRowid );
- if( chngRowid ){
- sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
- sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid);
- }else if( pTrigger ){
- sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
+ if( chngRowid==0 ){
+ sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
+ }
}
/* Populate the array of registers beginning at regNew with the new
@@ -443,6 +444,9 @@ void sqlite3Update(
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0);
+ /* Do FK constraint checks. */
+ sqlite3FkCheck(pParse, pTab, pChanges, regOldRowid, regNewRowid);
+
/* Delete the index entries associated with the current record. */
j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
@@ -455,6 +459,11 @@ void sqlite3Update(
/* Insert the new index entries and the new record. */
sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, 1, 0, 0);
+
+ /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
+ ** handle rows (possibly in other tables) that refer via a foreign key
+ ** to the row just updated. */
+ sqlite3FkActions(pParse, pTab, pChanges, regOldRowid);
}
/* Increment the row counter