mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-06 15:49:35 +03:00
When ALTER TABLE RENAME TO is used to change the name of a table that is the parent table of a foreign key constraint, modify that foreign key constraint to use the new table name.
FossilOrigin-Name: b4a10c39e726dc190e9597e382baddc034294114
This commit is contained in:
18
manifest
18
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Avoid\schecking\sif\san\sinsert\sor\sdelete\shas\s"fixed"\san\soutstanding\sFK\sconstraint\sviolation\sif\sthe\sconstraint\scounter\sindicates\sthat\sthe\sdatabase\scontains\sno\ssuch\sviolations.
|
C When\sALTER\sTABLE\sRENAME\sTO\sis\sused\sto\schange\sthe\sname\sof\sa\stable\sthat\sis\sthe\sparent\stable\sof\sa\sforeign\skey\sconstraint,\smodify\sthat\sforeign\skey\sconstraint\sto\suse\sthe\snew\stable\sname.
|
||||||
D 2009-09-25T17:03:14
|
D 2009-09-26T17:51:48
|
||||||
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
|
||||||
@@ -99,7 +99,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
|||||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||||
F src/alter.c e771528da07315e0416bf9788399fb3dc2fecb5e
|
F src/alter.c 082657ce3a584a512ed472e3163c09ed399e17f4
|
||||||
F src/analyze.c 5a8b8aa3d170eac5e71af45458cec61f83c623ee
|
F src/analyze.c 5a8b8aa3d170eac5e71af45458cec61f83c623ee
|
||||||
F src/attach.c 13995348fc5a26cdd136a50806faf292aabc173f
|
F src/attach.c 13995348fc5a26cdd136a50806faf292aabc173f
|
||||||
F src/auth.c d6a88bf8e81e6a079ccb8881002b327e42ec46b9
|
F src/auth.c d6a88bf8e81e6a079ccb8881002b327e42ec46b9
|
||||||
@@ -116,7 +116,7 @@ F src/date.c 657ff12ca0f1195b531561afacbb38b772d16638
|
|||||||
F src/delete.c 2a3d6fc0861b2f8dbd9feb7847b390267b281c60
|
F src/delete.c 2a3d6fc0861b2f8dbd9feb7847b390267b281c60
|
||||||
F src/expr.c c7f3f718bd5c392344ec8694a41c1824f30cf375
|
F src/expr.c c7f3f718bd5c392344ec8694a41c1824f30cf375
|
||||||
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
||||||
F src/fkey.c 542de974e3ed3a507f00b68d1486a4cbeaf4d8bb
|
F src/fkey.c ee4e0d2465c2c092b2b6ab4be7e33ae33d6c6dac
|
||||||
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
|
||||||
@@ -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 7dcffff0e91ff07e3f7752c4d8e87f9582443a20
|
F src/sqliteInt.h 21510d10a6794c633e044e8396acb7899396a9e8
|
||||||
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
|
||||||
@@ -330,7 +330,7 @@ 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 4b22c954c3923ffe366feb664b33b1b438abb5b1
|
F test/fkey2.test 13e99ef0cafe6947638f748aea7b1a7ee8aecb1a
|
||||||
F test/fkey3.test 2183cac9075f3aae4875106eb9255bb73618444e
|
F test/fkey3.test 2183cac9075f3aae4875106eb9255bb73618444e
|
||||||
F test/fkey_malloc.test da912d000bb6ceb1cd11b655de1989762fa71ceb
|
F test/fkey_malloc.test da912d000bb6ceb1cd11b655de1989762fa71ceb
|
||||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||||
@@ -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 9fd54b0aa73ed74c65f7db53cb666752f13263f9
|
P 519144ac437b5842e4213f0e81e05c709939c2ab
|
||||||
R 5e90fcf7b135a7c55fc18c54261d65ee
|
R 67b182d615cf1918bbb959f1c1561217
|
||||||
U dan
|
U dan
|
||||||
Z 1aaee7b75a94b33f2eb5b3e61baf845b
|
Z 1c73bf12a1b7498f5704501d82682485
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
519144ac437b5842e4213f0e81e05c709939c2ab
|
b4a10c39e726dc190e9597e382baddc034294114
|
||||||
145
src/alter.c
145
src/alter.c
@@ -85,6 +85,67 @@ static void renameTableFunc(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This C function implements an SQL user function that is used by SQL code
|
||||||
|
** generated by the ALTER TABLE ... RENAME command to modify the definition
|
||||||
|
** of any foreign key constraints that use the table being renamed as the
|
||||||
|
** parent table. It is passed three arguments:
|
||||||
|
**
|
||||||
|
** 1) The complete text of the CREATE TABLE statement being modified,
|
||||||
|
** 2) The old name of the table being renamed, and
|
||||||
|
** 3) The new name of the table being renamed.
|
||||||
|
**
|
||||||
|
** It returns the new CREATE TABLE statement. For example:
|
||||||
|
**
|
||||||
|
** sqlite_rename_parent('CREATE TABLE t1(a REFERENCES t2)', 't2', 't3')
|
||||||
|
** -> 'CREATE TABLE t1(a REFERENCES t3)'
|
||||||
|
*/
|
||||||
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||||
|
static void renameParentFunc(
|
||||||
|
sqlite3_context *context,
|
||||||
|
int NotUsed,
|
||||||
|
sqlite3_value **argv
|
||||||
|
){
|
||||||
|
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||||
|
char *zOutput = 0;
|
||||||
|
char *zResult;
|
||||||
|
unsigned char const *zInput = sqlite3_value_text(argv[0]);
|
||||||
|
unsigned char const *zOld = sqlite3_value_text(argv[1]);
|
||||||
|
unsigned char const *zNew = sqlite3_value_text(argv[2]);
|
||||||
|
|
||||||
|
unsigned const char *z; /* Pointer to token */
|
||||||
|
int n; /* Length of token z */
|
||||||
|
int token; /* Type of token */
|
||||||
|
|
||||||
|
for(z=zInput; *z; z=z+n){
|
||||||
|
n = sqlite3GetToken(z, &token);
|
||||||
|
if( token==TK_REFERENCES ){
|
||||||
|
char *zParent;
|
||||||
|
do {
|
||||||
|
z += n;
|
||||||
|
n = sqlite3GetToken(z, &token);
|
||||||
|
}while( token==TK_SPACE );
|
||||||
|
|
||||||
|
zParent = sqlite3DbStrNDup(db, (const char *)z, n);
|
||||||
|
sqlite3Dequote(zParent);
|
||||||
|
if( 0==sqlite3StrICmp((const char *)zOld, zParent) ){
|
||||||
|
char *zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"",
|
||||||
|
(zOutput?zOutput:""), z-zInput, zInput, (const char *)zNew
|
||||||
|
);
|
||||||
|
sqlite3DbFree(db, zOutput);
|
||||||
|
zOutput = zOut;
|
||||||
|
zInput = &z[n];
|
||||||
|
}
|
||||||
|
sqlite3DbFree(db, zParent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zResult = sqlite3MPrintf(db, "%s%s", (zOutput?zOutput:""), zInput),
|
||||||
|
sqlite3_result_text(context, zResult, -1, SQLITE_DYNAMIC);
|
||||||
|
sqlite3DbFree(db, zOutput);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_TRIGGER
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
/* This function is used by SQL generated to implement the
|
/* This function is used by SQL generated to implement the
|
||||||
** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
|
** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
|
||||||
@@ -172,6 +233,52 @@ void sqlite3AlterFunctions(sqlite3 *db){
|
|||||||
sqlite3CreateFunc(db, "sqlite_rename_trigger", 2, SQLITE_UTF8, 0,
|
sqlite3CreateFunc(db, "sqlite_rename_trigger", 2, SQLITE_UTF8, 0,
|
||||||
renameTriggerFunc, 0, 0);
|
renameTriggerFunc, 0, 0);
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||||
|
sqlite3CreateFunc(db, "sqlite_rename_parent", 3, SQLITE_UTF8, 0,
|
||||||
|
renameParentFunc, 0, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This function is used to create the text of expressions of the form:
|
||||||
|
**
|
||||||
|
** name=<constant1> OR name=<constant2> OR ...
|
||||||
|
**
|
||||||
|
** If argument zWhere is NULL, then a pointer string containing the text
|
||||||
|
** "name=<constant>" is returned, where <constant> is the quoted version
|
||||||
|
** of the string passed as argument zConstant. The returned buffer is
|
||||||
|
** allocated using sqlite3DbMalloc(). It is the responsibility of the
|
||||||
|
** caller to ensure that it is eventually freed.
|
||||||
|
**
|
||||||
|
** If argument zWhere is not NULL, then the string returned is
|
||||||
|
** "<where> OR name=<constant>", where <where> is the contents of zWhere.
|
||||||
|
** In this case zWhere is passed to sqlite3DbFree() before returning.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
static char *whereOrName(sqlite3 *db, char *zWhere, char *zConstant){
|
||||||
|
char *zNew;
|
||||||
|
if( !zWhere ){
|
||||||
|
zNew = sqlite3MPrintf(db, "name=%Q", zConstant);
|
||||||
|
}else{
|
||||||
|
zNew = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, zConstant);
|
||||||
|
sqlite3DbFree(db, zWhere);
|
||||||
|
}
|
||||||
|
return zNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Generate the text of a WHERE expression which can be used to select all
|
||||||
|
** tables that have foreign key constraints that refer to table pTab (i.e.
|
||||||
|
** constraints for which pTab is the parent table) from the sqlite_master
|
||||||
|
** table.
|
||||||
|
*/
|
||||||
|
static char *whereForeignKeys(Parse *pParse, Table *pTab){
|
||||||
|
FKey *p;
|
||||||
|
char *zWhere = 0;
|
||||||
|
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
||||||
|
zWhere = whereOrName(pParse->db, zWhere, p->pFrom->zName);
|
||||||
|
}
|
||||||
|
return zWhere;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -183,7 +290,6 @@ void sqlite3AlterFunctions(sqlite3 *db){
|
|||||||
static char *whereTempTriggers(Parse *pParse, Table *pTab){
|
static char *whereTempTriggers(Parse *pParse, Table *pTab){
|
||||||
Trigger *pTrig;
|
Trigger *pTrig;
|
||||||
char *zWhere = 0;
|
char *zWhere = 0;
|
||||||
char *tmp = 0;
|
|
||||||
const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */
|
const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */
|
||||||
|
|
||||||
/* If the table is not located in the temp-db (in which case NULL is
|
/* If the table is not located in the temp-db (in which case NULL is
|
||||||
@@ -195,13 +301,7 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
|
|||||||
sqlite3 *db = pParse->db;
|
sqlite3 *db = pParse->db;
|
||||||
for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){
|
for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){
|
||||||
if( pTrig->pSchema==pTempSchema ){
|
if( pTrig->pSchema==pTempSchema ){
|
||||||
if( !zWhere ){
|
zWhere = whereOrName(db, zWhere, pTrig->zName);
|
||||||
zWhere = sqlite3MPrintf(db, "name=%Q", pTrig->zName);
|
|
||||||
}else{
|
|
||||||
tmp = zWhere;
|
|
||||||
zWhere = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, pTrig->zName);
|
|
||||||
sqlite3DbFree(db, tmp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,7 +339,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Drop the table and index from the internal schema */
|
/* Drop the table and index from the internal schema. */
|
||||||
sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
|
sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
|
||||||
|
|
||||||
/* Reload the table, index and permanent trigger schemas. */
|
/* Reload the table, index and permanent trigger schemas. */
|
||||||
@@ -370,6 +470,21 @@ void sqlite3AlterRenameTable(
|
|||||||
zTabName = pTab->zName;
|
zTabName = pTab->zName;
|
||||||
nTabName = sqlite3Utf8CharLen(zTabName, -1);
|
nTabName = sqlite3Utf8CharLen(zTabName, -1);
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||||
|
if( db->flags&SQLITE_ForeignKeys ){
|
||||||
|
/* If foreign-key support is enabled, rewrite the CREATE TABLE
|
||||||
|
** statements corresponding to all child tables of foreign key constraints
|
||||||
|
** for which the renamed table is the parent table. */
|
||||||
|
if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){
|
||||||
|
sqlite3NestedParse(pParse,
|
||||||
|
"UPDATE sqlite_master SET "
|
||||||
|
"sql = sqlite_rename_parent(sql, %Q, %Q) "
|
||||||
|
"WHERE %s;", zTabName, zName, zWhere);
|
||||||
|
sqlite3DbFree(db, zWhere);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Modify the sqlite_master table to use the new table name. */
|
/* Modify the sqlite_master table to use the new table name. */
|
||||||
sqlite3NestedParse(pParse,
|
sqlite3NestedParse(pParse,
|
||||||
"UPDATE %Q.%s SET "
|
"UPDATE %Q.%s SET "
|
||||||
@@ -421,6 +536,18 @@ void sqlite3AlterRenameTable(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||||
|
if( db->flags&SQLITE_ForeignKeys ){
|
||||||
|
FKey *p;
|
||||||
|
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
||||||
|
Table *pFrom = p->pFrom;
|
||||||
|
if( pFrom!=pTab ){
|
||||||
|
reloadTableSchema(pParse, p->pFrom, pFrom->zName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Drop and reload the internal table schema. */
|
/* Drop and reload the internal table schema. */
|
||||||
reloadTableSchema(pParse, pTab, zName);
|
reloadTableSchema(pParse, pTab, zName);
|
||||||
|
|
||||||
|
|||||||
10
src/fkey.c
10
src/fkey.c
@@ -517,7 +517,7 @@ static void fkScanChildren(
|
|||||||
** NULL pointer (as there are no FK constraints for which t2 is the parent
|
** NULL pointer (as there are no FK constraints for which t2 is the parent
|
||||||
** table).
|
** table).
|
||||||
*/
|
*/
|
||||||
static FKey *fkRefering(Table *pTab){
|
FKey *sqlite3FkReferences(Table *pTab){
|
||||||
int nName = sqlite3Strlen30(pTab->zName);
|
int nName = sqlite3Strlen30(pTab->zName);
|
||||||
return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName, nName);
|
return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName, nName);
|
||||||
}
|
}
|
||||||
@@ -645,7 +645,7 @@ void sqlite3FkCheck(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through all the foreign key constraints that refer to this table */
|
/* Loop through all the foreign key constraints that refer to this table */
|
||||||
for(pFKey = fkRefering(pTab); pFKey; pFKey=pFKey->pNextTo){
|
for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){
|
||||||
int iGoto; /* Address of OP_Goto instruction */
|
int iGoto; /* Address of OP_Goto instruction */
|
||||||
Index *pIdx = 0; /* Foreign key index for pFKey */
|
Index *pIdx = 0; /* Foreign key index for pFKey */
|
||||||
SrcList *pSrc;
|
SrcList *pSrc;
|
||||||
@@ -740,7 +740,7 @@ u32 sqlite3FkOldmask(
|
|||||||
for(p=pTab->pFKey; p; p=p->pNextFrom){
|
for(p=pTab->pFKey; p; p=p->pNextFrom){
|
||||||
for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom);
|
for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom);
|
||||||
}
|
}
|
||||||
for(p=fkRefering(pTab); p; p=p->pNextTo){
|
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
||||||
Index *pIdx = 0;
|
Index *pIdx = 0;
|
||||||
locateFkeyIndex(0, pTab, p, &pIdx, 0);
|
locateFkeyIndex(0, pTab, p, &pIdx, 0);
|
||||||
if( pIdx ){
|
if( pIdx ){
|
||||||
@@ -767,7 +767,7 @@ int sqlite3FkRequired(
|
|||||||
ExprList *pChanges /* Non-NULL for UPDATE operations */
|
ExprList *pChanges /* Non-NULL for UPDATE operations */
|
||||||
){
|
){
|
||||||
if( pParse->db->flags&SQLITE_ForeignKeys ){
|
if( pParse->db->flags&SQLITE_ForeignKeys ){
|
||||||
if( fkRefering(pTab) || pTab->pFKey ) return 1;
|
if( sqlite3FkReferences(pTab) || pTab->pFKey ) return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -968,7 +968,7 @@ void sqlite3FkActions(
|
|||||||
** trigger sub-program. */
|
** trigger sub-program. */
|
||||||
if( pParse->db->flags&SQLITE_ForeignKeys ){
|
if( pParse->db->flags&SQLITE_ForeignKeys ){
|
||||||
FKey *pFKey; /* Iterator variable */
|
FKey *pFKey; /* Iterator variable */
|
||||||
for(pFKey = fkRefering(pTab); pFKey; pFKey=pFKey->pNextTo){
|
for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){
|
||||||
Trigger *pAction = fkActionTrigger(pParse, pTab, pFKey, pChanges);
|
Trigger *pAction = fkActionTrigger(pParse, pTab, pFKey, pChanges);
|
||||||
if( pAction ){
|
if( pAction ){
|
||||||
sqlite3CodeRowTriggerDirect(pParse, pAction, pTab, regOld, OE_Abort, 0);
|
sqlite3CodeRowTriggerDirect(pParse, pAction, pTab, regOld, OE_Abort, 0);
|
||||||
|
|||||||
@@ -2952,6 +2952,7 @@ VTable *sqlite3GetVTable(sqlite3*, Table*);
|
|||||||
void sqlite3FkActions(Parse*, Table*, ExprList*, int);
|
void sqlite3FkActions(Parse*, Table*, ExprList*, int);
|
||||||
int sqlite3FkRequired(Parse*, Table*, ExprList*);
|
int sqlite3FkRequired(Parse*, Table*, ExprList*);
|
||||||
u32 sqlite3FkOldmask(Parse*, Table*, ExprList*);
|
u32 sqlite3FkOldmask(Parse*, Table*, ExprList*);
|
||||||
|
FKey *sqlite3FkReferences(Table *);
|
||||||
#else
|
#else
|
||||||
#define sqlite3FkCheck(a,b,c,d,e)
|
#define sqlite3FkCheck(a,b,c,d,e)
|
||||||
#define sqlite3FkActions(a,b,c,d)
|
#define sqlite3FkActions(a,b,c,d)
|
||||||
|
|||||||
@@ -804,6 +804,61 @@ do_test fkey2-14.1.6 {
|
|||||||
}
|
}
|
||||||
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
|
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
|
||||||
|
|
||||||
|
|
||||||
|
# Test the sqlite_rename_parent() function directly.
|
||||||
|
#
|
||||||
|
proc test_rename_parent {zCreate zOld zNew} {
|
||||||
|
db eval {SELECT sqlite_rename_parent($zCreate, $zOld, $zNew)}
|
||||||
|
}
|
||||||
|
do_test fkey2-14.2.1.1 {
|
||||||
|
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
|
||||||
|
} {{CREATE TABLE t1(a REFERENCES "t3")}}
|
||||||
|
do_test fkey2-14.2.1.2 {
|
||||||
|
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
|
||||||
|
} {{CREATE TABLE t1(a REFERENCES t2)}}
|
||||||
|
do_test fkey2-14.2.1.3 {
|
||||||
|
test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3
|
||||||
|
} {{CREATE TABLE t1(a REFERENCES "t3")}}
|
||||||
|
|
||||||
|
# Test ALTER TABLE RENAME TABLE a bit.
|
||||||
|
#
|
||||||
|
do_test fkey2-14.2.2.1 {
|
||||||
|
drop_all_tables
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1);
|
||||||
|
CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
|
||||||
|
CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
|
||||||
|
}
|
||||||
|
execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
|
||||||
|
} [list \
|
||||||
|
{CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1)} \
|
||||||
|
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)} \
|
||||||
|
{CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)} \
|
||||||
|
]
|
||||||
|
do_test fkey2-14.2.2.2 {
|
||||||
|
execsql { ALTER TABLE t1 RENAME TO t4 }
|
||||||
|
execsql { SELECT sql FROM sqlite_master WHERE type = 'table'}
|
||||||
|
} [list \
|
||||||
|
{CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4")} \
|
||||||
|
{CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)} \
|
||||||
|
{CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \
|
||||||
|
]
|
||||||
|
do_test fkey2-14.2.2.3 {
|
||||||
|
catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
|
||||||
|
} {1 {foreign key constraint failed}}
|
||||||
|
do_test fkey2-14.2.2.4 {
|
||||||
|
execsql { INSERT INTO t4 VALUES(1, NULL) }
|
||||||
|
} {}
|
||||||
|
do_test fkey2-14.2.2.5 {
|
||||||
|
catchsql { UPDATE t4 SET b = 5 }
|
||||||
|
} {1 {foreign key constraint failed}}
|
||||||
|
do_test fkey2-14.2.2.6 {
|
||||||
|
catchsql { UPDATE t4 SET b = 1 }
|
||||||
|
} {0 {}}
|
||||||
|
do_test fkey2-14.2.2.7 {
|
||||||
|
execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
|
||||||
|
} {}
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
# The following tests, fkey2-15.*, test that unnecessary FK related scans
|
# The following tests, fkey2-15.*, test that unnecessary FK related scans
|
||||||
# and lookups are avoided when the constraint counters are zero.
|
# and lookups are avoided when the constraint counters are zero.
|
||||||
|
|||||||
Reference in New Issue
Block a user