Fix the ALTER TABLE RENAME command so that it converts FOREIGN KEY constraints

in ATTACH-ed and in TEMP tables as well as in the main database.
Ticket [13336e9c3c8c3f].

FossilOrigin-Name: ab197d0aaf18016ac2dd3674f49bea5f1556451c
This commit is contained in:
drh 2010-02-15 18:03:20 +00:00
parent 622d288790
commit 9a6ffc845b
5 changed files with 189 additions and 19 deletions

View File

@ -1,8 +1,8 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
C When\screating\sa\strigger\son\sa\smain\sdatabase\stable\swhen\sthere\sis\sa\sTEMP\stable\nwith\sthe\ssame\sname,\smake\ssure\sthe\strigger\sis\sbound\sto\sthe\smain\stable.\nTicket\s[985771e11612].
D 2010-02-15T16:54:55
C Fix\sthe\sALTER\sTABLE\sRENAME\scommand\sso\sthat\sit\sconverts\sFOREIGN\sKEY\sconstraints\nin\sATTACH-ed\sand\sin\sTEMP\stables\sas\swell\sas\sin\sthe\smain\sdatabase.\nTicket\s[13336e9c3c8c3f].
D 2010-02-15T18:03:20
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in c5827ead754ab32b9585487177c93bb00b9497b3
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -104,7 +104,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
F src/alter.c 92ba938565d7cc6bfe92aad6cc90c00800ff21d3
F src/alter.c e6f4d11b1c0b23642fc46bac9abe0753c4294e05
F src/analyze.c 55155f05ee9ab4ce33b7a4d19c449053f8935200
F src/attach.c a6b5e97c84c46c731aad064c413e40e12cb718b7
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
@ -341,7 +341,7 @@ F test/expr.test 9f521ae22f00e074959f72ce2e55d46b9ed23f68
F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8
F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
F test/fkey2.test add654160d1b066f7b866d63d4435954ccbcab7d
F test/fkey2.test e71f5baf9bb42cdba4700d73cba6f4d82fd6b925
F test/fkey3.test 42f88d6048d8dc079e2a8cf7baad1cc1483a7620
F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
@ -596,7 +596,7 @@ F test/tclsqlite.test bf4227eb236a4c097aa7974a2bf7d3225acf34be
F test/tempdb.test 1bf52da28a9c24e29717362a87722dff08feb72b
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
F test/tester.tcl f38dd7ca63d81197c853989dbd39dfa3582c9ce7
F test/tester.tcl e1f581c7a2648a0aaa51135c4d2e7be68f4b9292
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
@ -790,14 +790,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P c727601eecd85a26dbd4fc36823d77bec34da3c3
R 45004b2e132c529777330e8469a3dee0
P ec914af32675e472694270d46f3ba2214eb2fe90
R b63197d6039614d907827a453eecec99
U drh
Z b2e9d944fd601fa751cf2872dbab1f73
Z 49dfd565a21afaa90179ba63716c3b3a
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFLeXxioxKgR168RlERAlHrAJ4+sjtvvNq54HhErGM+S2FPfikqFwCfQzkv
9UxvOxpkUFkuGCjFzxJh+7w=
=TAZV
iD8DBQFLeYxroxKgR168RlERAp42AJ9eXZoQAtGar3vAWWJ+ElAji3XDgACfTqUL
/luMg2NSLMumM1Iu2R9tVWU=
=ahs6
-----END PGP SIGNATURE-----

View File

@ -1 +1 @@
ec914af32675e472694270d46f3ba2214eb2fe90
ab197d0aaf18016ac2dd3674f49bea5f1556451c

View File

@ -479,9 +479,9 @@ void sqlite3AlterRenameTable(
** for which the renamed table is the parent table. */
if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){
sqlite3NestedParse(pParse,
"UPDATE sqlite_master SET "
"UPDATE \"%w\".%s SET "
"sql = sqlite_rename_parent(sql, %Q, %Q) "
"WHERE %s;", zTabName, zName, zWhere);
"WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere);
sqlite3DbFree(db, zWhere);
}
}

View File

@ -1003,6 +1003,169 @@ ifcapable altertable {
do_test fkey2-14.2.2.7 {
execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
} {}
# Repeat for TEMP tables
#
drop_all_tables
do_test fkey2-14.1tmp.1 {
# Adding a column with a REFERENCES clause is not supported.
execsql {
CREATE TEMP TABLE t1(a PRIMARY KEY);
CREATE TEMP TABLE t2(a, b);
}
catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
} {0 {}}
do_test fkey2-14.1tmp.2 {
catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 }
} {0 {}}
do_test fkey2-14.1tmp.3 {
catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL}
} {0 {}}
do_test fkey2-14.1tmp.4 {
catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'}
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
do_test fkey2-14.1tmp.5 {
catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 }
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
do_test fkey2-14.1tmp.6 {
execsql {
PRAGMA foreign_keys = off;
ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
PRAGMA foreign_keys = on;
SELECT sql FROM sqlite_temp_master WHERE name='t2';
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
do_test fkey2-14.2tmp.1.1 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
do_test fkey2-14.2tmp.1.2 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
} {{CREATE TABLE t1(a REFERENCES t2)}}
do_test fkey2-14.2tmp.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.2tmp.2.1 {
drop_all_tables
execsql {
CREATE TEMP TABLE t1(a PRIMARY KEY, b REFERENCES t1);
CREATE TEMP TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
CREATE TEMP TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
}
execsql { SELECT sql FROM sqlite_temp_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.2tmp.2.2 {
execsql { ALTER TABLE t1 RENAME TO t4 }
execsql { SELECT sql FROM sqlite_temp_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.2tmp.2.3 {
catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
} {1 {foreign key constraint failed}}
do_test fkey2-14.2tmp.2.4 {
execsql { INSERT INTO t4 VALUES(1, NULL) }
} {}
do_test fkey2-14.2tmp.2.5 {
catchsql { UPDATE t4 SET b = 5 }
} {1 {foreign key constraint failed}}
do_test fkey2-14.2tmp.2.6 {
catchsql { UPDATE t4 SET b = 1 }
} {0 {}}
do_test fkey2-14.2tmp.2.7 {
execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
} {}
# Repeat for ATTACH-ed tables
#
drop_all_tables
do_test fkey2-14.1aux.1 {
# Adding a column with a REFERENCES clause is not supported.
execsql {
ATTACH ':memory:' AS aux;
CREATE TABLE aux.t1(a PRIMARY KEY);
CREATE TABLE aux.t2(a, b);
}
catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 }
} {0 {}}
do_test fkey2-14.1aux.2 {
catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 }
} {0 {}}
do_test fkey2-14.1aux.3 {
catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL}
} {0 {}}
do_test fkey2-14.1aux.4 {
catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'}
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
do_test fkey2-14.1aux.5 {
catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 }
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
do_test fkey2-14.1aux.6 {
execsql {
PRAGMA foreign_keys = off;
ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1;
PRAGMA foreign_keys = on;
SELECT sql FROM aux.sqlite_master WHERE name='t2';
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}}
do_test fkey2-14.2aux.1.1 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
} {{CREATE TABLE t1(a REFERENCES "t3")}}
do_test fkey2-14.2aux.1.2 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3
} {{CREATE TABLE t1(a REFERENCES t2)}}
do_test fkey2-14.2aux.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.2aux.2.1 {
drop_all_tables
execsql {
CREATE TABLE aux.t1(a PRIMARY KEY, b REFERENCES t1);
CREATE TABLE aux.t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2);
CREATE TABLE aux.t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1);
}
execsql { SELECT sql FROM aux.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.2aux.2.2 {
execsql { ALTER TABLE t1 RENAME TO t4 }
execsql { SELECT sql FROM aux.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.2aux.2.3 {
catchsql { INSERT INTO t3 VALUES(1, 2, 3) }
} {1 {foreign key constraint failed}}
do_test fkey2-14.2aux.2.4 {
execsql { INSERT INTO t4 VALUES(1, NULL) }
} {}
do_test fkey2-14.2aux.2.5 {
catchsql { UPDATE t4 SET b = 5 }
} {1 {foreign key constraint failed}}
do_test fkey2-14.2aux.2.6 {
catchsql { UPDATE t4 SET b = 1 }
} {0 {}}
do_test fkey2-14.2aux.2.7 {
execsql { INSERT INTO t3 VALUES(1, NULL, 1) }
} {}
}
do_test fkey-2.14.3.1 {

View File

@ -964,11 +964,18 @@ proc drop_all_tables {{db db}} {
set pk [$db one "PRAGMA foreign_keys"]
$db eval "PRAGMA foreign_keys = OFF"
}
foreach {t type} [$db eval {
SELECT name, type FROM sqlite_master
WHERE type IN('table', 'view') AND name NOT like 'sqlite_%'
}] {
$db eval "DROP $type $t"
foreach {idx name file} [db eval {PRAGMA database_list}] {
if {$idx==1} {
set master sqlite_temp_master
} else {
set master $name.sqlite_master
}
foreach {t type} [$db eval "
SELECT name, type FROM $master
WHERE type IN('table', 'view') AND name NOT like 'sqlite_%'
"] {
$db eval "DROP $type $t"
}
}
ifcapable trigger&&foreignkey {
$db eval "PRAGMA foreign_keys = $pk"