1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

If an update does not modify any child or parent key columns, omit foreign key processing for the statement.

FossilOrigin-Name: edff3500058eb8ad2381f855ef7a09ecb680f7b8
This commit is contained in:
dan
2009-10-01 16:09:04 +00:00
parent d583502e7d
commit e7a94d8128
9 changed files with 94 additions and 59 deletions

View File

@ -1,5 +1,5 @@
C Add\stests\sto\scheck\sthat\sFK\ssupport\sinteracts\swith\scount-changes\scorrectly. C If\san\supdate\sdoes\snot\smodify\sany\schild\sor\sparent\skey\scolumns,\somit\sforeign\skey\sprocessing\sfor\sthe\sstatement.
D 2009-10-01T04:35:06 D 2009-10-01T16:09:04
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 4ca3f1dd6efa2075bcb27f4dc43eef749877740d F Makefile.in 4ca3f1dd6efa2075bcb27f4dc43eef749877740d
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -113,16 +113,16 @@ F src/build.c 1988dad2799d0421cd9fb6431fd3a1667115522e
F src/callback.c 10d237171472865f58fb07d515737238c9e06688 F src/callback.c 10d237171472865f58fb07d515737238c9e06688
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0 F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
F src/date.c 657ff12ca0f1195b531561afacbb38b772d16638 F src/date.c 657ff12ca0f1195b531561afacbb38b772d16638
F src/delete.c 2a3d6fc0861b2f8dbd9feb7847b390267b281c60 F src/delete.c 308e300d599d2d11b838687e2cf7309d42f29a1a
F src/expr.c c7f3f718bd5c392344ec8694a41c1824f30cf375 F src/expr.c c7f3f718bd5c392344ec8694a41c1824f30cf375
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
F src/fkey.c 8b438b1fda586519f8bb398538447fb2592bf668 F src/fkey.c b20074e0dcbf6bbaafa8a520ed12efb30bb6aac3
F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606 F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606
F src/global.c 271952d199a8cc59d4ce840b3bbbfd2f30c8ba32 F src/global.c 271952d199a8cc59d4ce840b3bbbfd2f30c8ba32
F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7 F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1 F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1
F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
F src/insert.c 719465bf5c46349550e3bda483b1b9f0b9b6aebf F src/insert.c 2fe2ef7bd03d6e0120e4525727c4ae7de5a2d571
F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0 F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
F src/legacy.c 303b4ffcf1ae652fcf5ef635846c563c254564f6 F src/legacy.c 303b4ffcf1ae652fcf5ef635846c563c254564f6
F src/lempar.c 0c4d1ab0a5ef2b0381eb81a732c54f68f27a574d F src/lempar.c 0c4d1ab0a5ef2b0381eb81a732c54f68f27a574d
@ -164,7 +164,7 @@ F src/select.c 1d0a13137532321b4364f964e46f057d271691e3
F src/shell.c d6e64471aafb81f355262533393169a70529847a F src/shell.c d6e64471aafb81f355262533393169a70529847a
F src/sqlite.h.in 5af8181f815831a8672c3834c60e6b4418448bcc F src/sqlite.h.in 5af8181f815831a8672c3834c60e6b4418448bcc
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17 F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
F src/sqliteInt.h 284a65c29bc4f2a77aa45994285fb55f7de537b9 F src/sqliteInt.h 6730f9584eed76460ed85d2ade13914a6b68caab
F src/sqliteLimit.h 504a3161886d2938cbd163054ad620b8356df758 F src/sqliteLimit.h 504a3161886d2938cbd163054ad620b8356df758
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
@ -202,7 +202,7 @@ F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac
F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241 F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241
F src/tokenize.c af8a56e6a50c5042fc305bfa796275e9bf26ff2b F src/tokenize.c af8a56e6a50c5042fc305bfa796275e9bf26ff2b
F src/trigger.c 643e27f94a0112071a993f457d6c4aae24782944 F src/trigger.c 643e27f94a0112071a993f457d6c4aae24782944
F src/update.c a7a5f60bf65a88557b434ac40f2ae6d2f7ad2d2d F src/update.c 2c8a64237e4fae604468d14380b877d169545b63
F src/utf.c 99cf927eabb104621ba889ac0dd075fc1657ad30 F src/utf.c 99cf927eabb104621ba889ac0dd075fc1657ad30
F src/util.c 59d4e9456bf1fe581f415a783fa0cee6115c8f35 F src/util.c 59d4e9456bf1fe581f415a783fa0cee6115c8f35
F src/vacuum.c 869d08eaab64e2a4eaf4ef9ea34b851892b65a75 F src/vacuum.c 869d08eaab64e2a4eaf4ef9ea34b851892b65a75
@ -330,8 +330,8 @@ F test/expr.test 9f521ae22f00e074959f72ce2e55d46b9ed23f68
F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8 F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8
F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43 F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
F test/fkey2.test 7ca63ae07839e700698655010788502b0e5d3e65 F test/fkey2.test 695b21b57e8e8916cd67cc232aa3d1d8dfd269df
F test/fkey3.test c17565b40c97a0dd5102610183c744611171b5ec F test/fkey3.test 42f88d6048d8dc079e2a8cf7baad1cc1483a7620
F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8 F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7 F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
@ -755,7 +755,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 0a0a17d87c990a811a2755b9d9d4141b611b49db P 5b8366154b2a91c1be3e7e52ec270ecdfe7d2bb1
R 71d9a87efb7de6c5e2fcba593dc5c2be R c95c8f6b969f3f74e7c6e66644a17c32
U dan U dan
Z 7c4cee03a1a1dae14dd3d77db4d5358b Z 8d8627e9a9b2426ee82543a58a4b15f8

View File

@ -1 +1 @@
5b8366154b2a91c1be3e7e52ec270ecdfe7d2bb1 edff3500058eb8ad2381f855ef7a09ecb680f7b8

View File

@ -342,7 +342,7 @@ void sqlite3DeleteFrom(
** this optimization caused the row change count (the value returned by ** this optimization caused the row change count (the value returned by
** API function sqlite3_count_changes) to be set incorrectly. */ ** API function sqlite3_count_changes) to be set incorrectly. */
if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab) if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab)
&& 0==sqlite3FkRequired(pParse, pTab, 0) && 0==sqlite3FkRequired(pParse, pTab, 0, 0)
){ ){
assert( !isView ); assert( !isView );
sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt, sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt,
@ -492,14 +492,14 @@ void sqlite3GenerateRowDelete(
/* If there are any triggers to fire, allocate a range of registers to /* If there are any triggers to fire, allocate a range of registers to
** use for the old.* references in the triggers. */ ** use for the old.* references in the triggers. */
if( sqlite3FkRequired(pParse, pTab, 0) || pTrigger ){ if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){
u32 mask; /* Mask of OLD.* columns in use */ u32 mask; /* Mask of OLD.* columns in use */
int iCol; /* Iterator used while populating OLD.* */ int iCol; /* Iterator used while populating OLD.* */
/* TODO: Could use temporary registers here. Also could attempt to /* TODO: Could use temporary registers here. Also could attempt to
** avoid copying the contents of the rowid register. */ ** avoid copying the contents of the rowid register. */
mask = sqlite3TriggerOldmask(pParse, pTrigger, 0, pTab, onconf); mask = sqlite3TriggerOldmask(pParse, pTrigger, 0, pTab, onconf);
mask |= sqlite3FkOldmask(pParse, pTab, 0); mask |= sqlite3FkOldmask(pParse, pTab);
iOld = pParse->nMem+1; iOld = pParse->nMem+1;
pParse->nMem += (1 + pTab->nCol); pParse->nMem += (1 + pTab->nCol);
@ -528,7 +528,7 @@ void sqlite3GenerateRowDelete(
/* Do FK processing. This call checks that any FK constraints that /* Do FK processing. This call checks that any FK constraints that
** refer to this table (i.e. constraints attached to other tables) ** refer to this table (i.e. constraints attached to other tables)
** are not violated by deleting this row. */ ** are not violated by deleting this row. */
sqlite3FkCheck(pParse, pTab, 0, iOld, 0); sqlite3FkCheck(pParse, pTab, iOld, 0);
} }
/* Delete the index and table entries. Skip this step if pTab is really /* Delete the index and table entries. Skip this step if pTab is really

View File

@ -672,14 +672,11 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
** For an UPDATE operation, this function is called twice. Once before ** For an UPDATE operation, this function is called twice. Once before
** the original record is deleted from the table using the calling convention ** the original record is deleted from the table using the calling convention
** described for DELETE. Then again after the original record is deleted ** described for DELETE. Then again after the original record is deleted
** but before the new record is inserted using the INSERT convention. In ** but before the new record is inserted using the INSERT convention.
** both cases parameter pChanges is passed the list of columns being
** updated by the statement.
*/ */
void sqlite3FkCheck( void sqlite3FkCheck(
Parse *pParse, /* Parse context */ Parse *pParse, /* Parse context */
Table *pTab, /* Row is being deleted from this table */ Table *pTab, /* Row is being deleted from this table */
ExprList *pChanges, /* Changed columns if this is an UPDATE */
int regOld, /* Previous row data is stored here */ int regOld, /* Previous row data is stored here */
int regNew /* New row data is stored here */ int regNew /* New row data is stored here */
){ ){
@ -725,11 +722,6 @@ void sqlite3FkCheck(
} }
assert( pFKey->nCol==1 || (aiFree && pIdx) ); assert( pFKey->nCol==1 || (aiFree && pIdx) );
/* If the key does not overlap with the pChanges list, skip this FK. */
if( pChanges ){
/* TODO */
}
if( aiFree ){ if( aiFree ){
aiCol = aiFree; aiCol = aiFree;
}else{ }else{
@ -782,14 +774,6 @@ void sqlite3FkCheck(
} }
assert( aiCol || pFKey->nCol==1 ); assert( aiCol || pFKey->nCol==1 );
/* Check if this update statement has modified any of the child key
** columns for this foreign key constraint. If it has not, there is
** no need to search the child table for rows in violation. This is
** just an optimization. Things would work fine without this check. */
if( pChanges ){
/* TODO */
}
/* Create a SrcList structure containing a single table (the table /* Create a SrcList structure containing a single table (the table
** the foreign key that refers to this table is attached to). This ** the foreign key that refers to this table is attached to). This
** is required for the sqlite3WhereXXX() interface. */ ** is required for the sqlite3WhereXXX() interface. */
@ -822,14 +806,11 @@ void sqlite3FkCheck(
/* /*
** This function is called before generating code to update or delete a ** This function is called before generating code to update or delete a
** row contained in table pTab. If the operation is an update, then ** row contained in table pTab.
** pChanges is a pointer to the list of columns to modify. If this is a
** delete, then pChanges is NULL.
*/ */
u32 sqlite3FkOldmask( u32 sqlite3FkOldmask(
Parse *pParse, /* Parse context */ Parse *pParse, /* Parse context */
Table *pTab, /* Table being modified */ Table *pTab /* Table being modified */
ExprList *pChanges /* Non-NULL for UPDATE operations */
){ ){
u32 mask = 0; u32 mask = 0;
if( pParse->db->flags&SQLITE_ForeignKeys ){ if( pParse->db->flags&SQLITE_ForeignKeys ){
@ -851,9 +832,13 @@ u32 sqlite3FkOldmask(
/* /*
** This function is called before generating code to update or delete a ** This function is called before generating code to update or delete a
** row contained in table pTab. If the operation is an update, then ** row contained in table pTab. If the operation is a DELETE, then
** pChanges is a pointer to the list of columns to modify. If this is a ** parameter aChange is passed a NULL value. For an UPDATE, aChange points
** delete, then pChanges is NULL. ** to an array of size N, where N is the number of columns in table pTab.
** If the i'th column is not modified by the UPDATE, then the corresponding
** entry in the aChange[] array is set to -1. If the column is modified,
** the value is 0 or greater. Parameter chngRowid is set to true if the
** UPDATE statement modifies the rowid fields of the table.
** **
** If any foreign key processing will be required, this function returns ** If any foreign key processing will be required, this function returns
** true. If there is no foreign key related processing, this function ** true. If there is no foreign key related processing, this function
@ -862,10 +847,45 @@ u32 sqlite3FkOldmask(
int sqlite3FkRequired( int sqlite3FkRequired(
Parse *pParse, /* Parse context */ Parse *pParse, /* Parse context */
Table *pTab, /* Table being modified */ Table *pTab, /* Table being modified */
ExprList *pChanges /* Non-NULL for UPDATE operations */ int *aChange, /* Non-NULL for UPDATE operations */
int chngRowid /* True for UPDATE that affects rowid */
){ ){
if( pParse->db->flags&SQLITE_ForeignKeys ){ if( pParse->db->flags&SQLITE_ForeignKeys ){
if( sqlite3FkReferences(pTab) || pTab->pFKey ) return 1; if( !aChange ){
/* A DELETE operation. Foreign key processing is required if the
** table in question is either the child or parent table for any
** foreign key constraint. */
return (sqlite3FkReferences(pTab) || pTab->pFKey);
}else{
/* This is an UPDATE. Foreign key processing is only required if the
** operation modifies one or more child or parent key columns. */
int i;
FKey *p;
/* Check if any child key columns are being modified. */
for(p=pTab->pFKey; p; p=p->pNextFrom){
for(i=0; i<p->nCol; i++){
int iChildKey = p->aCol[i].iFrom;
if( aChange[iChildKey]>=0 ) return 1;
if( iChildKey==pTab->iPKey && chngRowid ) return 1;
}
}
/* Check if any parent key columns are being modified. */
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
for(i=0; i<p->nCol; i++){
char *zKey = p->aCol[i].zCol;
int iKey;
for(iKey=0; iKey<pTab->nCol; iKey++){
Column *pCol = &pTab->aCol[iKey];
if( (zKey ? !sqlite3StrICmp(pCol->zName, zKey) : pCol->isPrimKey) ){
if( aChange[iKey]>=0 ) return 1;
if( iKey==pTab->iPKey && chngRowid ) return 1;
}
}
}
}
}
} }
return 0; return 0;
} }

View File

@ -979,7 +979,7 @@ void sqlite3Insert(
sqlite3GenerateConstraintChecks(pParse, pTab, baseCur, regIns, aRegIdx, sqlite3GenerateConstraintChecks(pParse, pTab, baseCur, regIns, aRegIdx,
keyColumn>=0, 0, onError, endOfLoop, &isReplace keyColumn>=0, 0, onError, endOfLoop, &isReplace
); );
sqlite3FkCheck(pParse, pTab, 0, 0, regIns); sqlite3FkCheck(pParse, pTab, 0, regIns);
sqlite3CompleteInsertion( sqlite3CompleteInsertion(
pParse, pTab, baseCur, regIns, aRegIdx, 0, appendFlag, isReplace==0 pParse, pTab, baseCur, regIns, aRegIdx, 0, appendFlag, isReplace==0
); );
@ -1271,7 +1271,7 @@ void sqlite3GenerateConstraintChecks(
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
} }
sqlite3MultiWrite(pParse); sqlite3MultiWrite(pParse);
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0) ){ if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
sqlite3GenerateRowDelete( sqlite3GenerateRowDelete(
pParse, pTab, baseCur, regRowid, 0, pTrigger, OE_Replace pParse, pTab, baseCur, regRowid, 0, pTrigger, OE_Replace
); );

View File

@ -2949,18 +2949,18 @@ VTable *sqlite3GetVTable(sqlite3*, Table*);
** provided (enforcement of FK constraints requires the triggers sub-system). ** provided (enforcement of FK constraints requires the triggers sub-system).
*/ */
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
void sqlite3FkCheck(Parse*, Table*, ExprList*, int, int); void sqlite3FkCheck(Parse*, Table*, int, int);
void sqlite3FkDropTable(Parse*, SrcList *, Table*); void sqlite3FkDropTable(Parse*, SrcList *, Table*);
void sqlite3FkActions(Parse*, Table*, ExprList*, int); void sqlite3FkActions(Parse*, Table*, ExprList*, int);
int sqlite3FkRequired(Parse*, Table*, ExprList*); int sqlite3FkRequired(Parse*, Table*, int*, int);
u32 sqlite3FkOldmask(Parse*, Table*, ExprList*); u32 sqlite3FkOldmask(Parse*, Table*);
FKey *sqlite3FkReferences(Table *); FKey *sqlite3FkReferences(Table *);
#else #else
#define sqlite3FkActions(a,b,c,d) #define sqlite3FkActions(a,b,c,d)
#define sqlite3FkCheck(a,b,c,d,e) #define sqlite3FkCheck(a,b,c,d)
#define sqlite3FkDropTable(a,b,c) #define sqlite3FkDropTable(a,b,c)
#define sqlite3FkOldmask(a,b,c) 0 #define sqlite3FkOldmask(a,b) 0
#define sqlite3FkRequired(a,b,c) 0 #define sqlite3FkRequired(a,b,c,d) 0
#endif #endif
#ifndef SQLITE_OMIT_FOREIGN_KEY #ifndef SQLITE_OMIT_FOREIGN_KEY
void sqlite3FkDelete(Table*); void sqlite3FkDelete(Table*);

View File

@ -159,8 +159,6 @@ void sqlite3Update(
# define isView 0 # define isView 0
#endif #endif
hasFK = sqlite3FkRequired(pParse, pTab, pChanges);
if( sqlite3ViewGetColumnNames(pParse, pTab) ){ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup; goto update_cleanup;
} }
@ -230,6 +228,8 @@ void sqlite3Update(
#endif #endif
} }
hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngRowid);
/* Allocate memory for the array aRegIdx[]. There is one entry in the /* Allocate memory for the array aRegIdx[]. There is one entry in the
** array for each index associated with table being updated. Fill in ** array for each index associated with table being updated. Fill in
** the value with a register number for indices that are to be used ** the value with a register number for indices that are to be used
@ -389,7 +389,7 @@ void sqlite3Update(
/* If there are triggers on this table, populate an array of registers /* If there are triggers on this table, populate an array of registers
** with the required old.* column data. */ ** with the required old.* column data. */
if( hasFK || pTrigger ){ if( hasFK || pTrigger ){
u32 oldmask = sqlite3FkOldmask(pParse, pTab, pChanges); u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0);
oldmask |= sqlite3TriggerOldmask(pParse, pTrigger, pChanges, pTab, onError); oldmask |= sqlite3TriggerOldmask(pParse, pTrigger, pChanges, pTab, onError);
for(i=0; i<pTab->nCol; i++){ for(i=0; i<pTab->nCol; i++){
if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){ if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){
@ -445,7 +445,9 @@ void sqlite3Update(
aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0); aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0);
/* Do FK constraint checks. */ /* Do FK constraint checks. */
sqlite3FkCheck(pParse, pTab, pChanges, regOldRowid, 0); if( hasFK ){
sqlite3FkCheck(pParse, pTab, regOldRowid, 0);
}
/* Delete the index entries associated with the current record. */ /* Delete the index entries associated with the current record. */
j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid); j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
@ -457,7 +459,9 @@ void sqlite3Update(
} }
sqlite3VdbeJumpHere(v, j1); sqlite3VdbeJumpHere(v, j1);
sqlite3FkCheck(pParse, pTab, pChanges, 0, regNewRowid); if( hasFK ){
sqlite3FkCheck(pParse, pTab, 0, regNewRowid);
}
/* Insert the new index entries and the new record. */ /* Insert the new index entries and the new record. */
sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, 1, 0, 0); sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, 1, 0, 0);
@ -465,7 +469,9 @@ void sqlite3Update(
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
** handle rows (possibly in other tables) that refer via a foreign key ** handle rows (possibly in other tables) that refer via a foreign key
** to the row just updated. */ ** to the row just updated. */
sqlite3FkActions(pParse, pTab, pChanges, regOldRowid); if( hasFK ){
sqlite3FkActions(pParse, pTab, pChanges, regOldRowid);
}
} }
/* Increment the row counter /* Increment the row counter

View File

@ -70,6 +70,9 @@ ifcapable {!foreignkey||!trigger} {
# #
# fkey2-17.*: Test that the "count_changes" pragma does not interfere with # fkey2-17.*: Test that the "count_changes" pragma does not interfere with
# FK constraint processing. # FK constraint processing.
#
# fkey2-18.*: Test that the authorization callback is invoked when processing
# FK constraints.
# #
# fkey2-genfkey.*: Tests that were used with the shell tool .genfkey # fkey2-genfkey.*: Tests that were used with the shell tool .genfkey
# command. Recycled to test the built-in implementation. # command. Recycled to test the built-in implementation.
@ -136,6 +139,8 @@ set FkeySimpleTests {
4.12 "UPDATE t7 SET b = 2" {1 {foreign key constraint failed}} 4.12 "UPDATE t7 SET b = 2" {1 {foreign key constraint failed}}
4.13 "UPDATE t7 SET b = 1" {0 {}} 4.13 "UPDATE t7 SET b = 1" {0 {}}
4.14 "INSERT INTO t8 VALUES('a', 'b')" {1 {foreign key constraint failed}} 4.14 "INSERT INTO t8 VALUES('a', 'b')" {1 {foreign key constraint failed}}
4.15 "UPDATE t7 SET b = 5" {1 {foreign key constraint failed}}
4.16 "UPDATE t7 SET rowid = 5" {1 {foreign key constraint failed}}
5.1 "INSERT INTO t9 VALUES(1, 3)" {1 {no such table: main.nosuchtable}} 5.1 "INSERT INTO t9 VALUES(1, 3)" {1 {no such table: main.nosuchtable}}
5.2 "INSERT INTO t10 VALUES(1, 3)" {1 {foreign key mismatch}} 5.2 "INSERT INTO t10 VALUES(1, 3)" {1 {foreign key mismatch}}
@ -1343,6 +1348,10 @@ do_test fkey2-17.2.10 {
execsql { SELECT * FROM high ; SELECT * FROM low } execsql { SELECT * FROM high ; SELECT * FROM low }
} {} } {}
#-------------------------------------------------------------------------
# Test that the authorization callback works.
#
execsql { PRAGMA count_changes = 0 } execsql { PRAGMA count_changes = 0 }
#------------------------------------------------------------------------- #-------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
# 2001 September 15 # 2009 September 15
# #
# The author disclaims copyright to this source code. In place of # The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing: # a legal notice, here is a blessing: