aboutsummaryrefslogtreecommitdiff
path: root/src/fkey.c
diff options
context:
space:
mode:
authordan <dan@noemail.net>2009-10-01 16:09:04 +0000
committerdan <dan@noemail.net>2009-10-01 16:09:04 +0000
commite7a94d8128bd3c5037ab66a76586a24a9f16fa31 (patch)
treebd9306cec4aa19c2db791c85a8a336ae9a730e30 /src/fkey.c
parentd583502e7d85fe76c3b1567445c5bf52c2dd6d71 (diff)
downloadsqlite-e7a94d8128bd3c5037ab66a76586a24a9f16fa31.tar.gz
sqlite-e7a94d8128bd3c5037ab66a76586a24a9f16fa31.zip
If an update does not modify any child or parent key columns, omit foreign key processing for the statement.
FossilOrigin-Name: edff3500058eb8ad2381f855ef7a09ecb680f7b8
Diffstat (limited to 'src/fkey.c')
-rw-r--r--src/fkey.c74
1 files changed, 47 insertions, 27 deletions
diff --git a/src/fkey.c b/src/fkey.c
index 7ec256d7b..4d6a32ad6 100644
--- a/src/fkey.c
+++ b/src/fkey.c
@@ -672,14 +672,11 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
** For an UPDATE operation, this function is called twice. Once before
** the original record is deleted from the table using the calling convention
** described for DELETE. Then again after the original record is deleted
-** but before the new record is inserted using the INSERT convention. In
-** both cases parameter pChanges is passed the list of columns being
-** updated by the statement.
+** but before the new record is inserted using the INSERT convention.
*/
void sqlite3FkCheck(
Parse *pParse, /* Parse context */
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 regNew /* New row data is stored here */
){
@@ -725,11 +722,6 @@ void sqlite3FkCheck(
}
assert( pFKey->nCol==1 || (aiFree && pIdx) );
- /* If the key does not overlap with the pChanges list, skip this FK. */
- if( pChanges ){
- /* TODO */
- }
-
if( aiFree ){
aiCol = aiFree;
}else{
@@ -782,14 +774,6 @@ void sqlite3FkCheck(
}
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
** the foreign key that refers to this table is attached to). This
** is required for the sqlite3WhereXXX() interface. */
@@ -822,14 +806,11 @@ void sqlite3FkCheck(
/*
** This function is called before generating code to update or delete a
-** row contained in table pTab. If the operation is an update, then
-** pChanges is a pointer to the list of columns to modify. If this is a
-** delete, then pChanges is NULL.
+** row contained in table pTab.
*/
u32 sqlite3FkOldmask(
Parse *pParse, /* Parse context */
- Table *pTab, /* Table being modified */
- ExprList *pChanges /* Non-NULL for UPDATE operations */
+ Table *pTab /* Table being modified */
){
u32 mask = 0;
if( pParse->db->flags&SQLITE_ForeignKeys ){
@@ -851,9 +832,13 @@ u32 sqlite3FkOldmask(
/*
** This function is called before generating code to update or delete a
-** row contained in table pTab. If the operation is an update, then
-** pChanges is a pointer to the list of columns to modify. If this is a
-** delete, then pChanges is NULL.
+** row contained in table pTab. If the operation is a DELETE, then
+** parameter aChange is passed a NULL value. For an UPDATE, aChange points
+** 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
** true. If there is no foreign key related processing, this function
@@ -862,10 +847,45 @@ u32 sqlite3FkOldmask(
int sqlite3FkRequired(
Parse *pParse, /* Parse context */
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( 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;
}