mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Fix the DROP TABLE command so that it cannot be used to bypass foreign key constraints (if foreign key support is enabled).
FossilOrigin-Name: 8353808c9e70412fdee31bfda7810e948f1c7485
This commit is contained in:
22
manifest
22
manifest
@@ -1,5 +1,5 @@
|
||||
C Fix\ssome\sforeign\skey\sconstraint\srelated\sproblems\sthat\soccur\swhen\sa\srow\srefers\sto\sitself.
|
||||
D 2009-09-28T11:54:22
|
||||
C Fix\sthe\sDROP\sTABLE\scommand\sso\sthat\sit\scannot\sbe\sused\sto\sbypass\sforeign\skey\sconstraints\s(if\sforeign\skey\ssupport\sis\senabled).
|
||||
D 2009-09-28T14:49:02
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in 4ca3f1dd6efa2075bcb27f4dc43eef749877740d
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@@ -109,14 +109,14 @@ F src/btmutex.c 0f43a75bb5b8147b386e8e1c3e71ba734e3863b7
|
||||
F src/btree.c 9c425425784c5d569bc0309c22251698ba906451
|
||||
F src/btree.h 577448a890c2ab9b21e6ab74f073526184bceebe
|
||||
F src/btreeInt.h 1c86297e69380f6577e7ae67452597dd8d5c2705
|
||||
F src/build.c c6c8d4ce8c0a464bb25d0c3bfdb27834ad16d902
|
||||
F src/build.c 1988dad2799d0421cd9fb6431fd3a1667115522e
|
||||
F src/callback.c 10d237171472865f58fb07d515737238c9e06688
|
||||
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
|
||||
F src/date.c 657ff12ca0f1195b531561afacbb38b772d16638
|
||||
F src/delete.c 2a3d6fc0861b2f8dbd9feb7847b390267b281c60
|
||||
F src/expr.c c7f3f718bd5c392344ec8694a41c1824f30cf375
|
||||
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
||||
F src/fkey.c 5bbe13f5d9ffba1a21ec16fdc3ac1c0964a28597
|
||||
F src/fkey.c 8c5deb1775c5051327ebe9fc2fc54ef57890c83d
|
||||
F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606
|
||||
F src/global.c 271952d199a8cc59d4ce840b3bbbfd2f30c8ba32
|
||||
F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
|
||||
@@ -164,7 +164,7 @@ F src/select.c 1d0a13137532321b4364f964e46f057d271691e3
|
||||
F src/shell.c d6e64471aafb81f355262533393169a70529847a
|
||||
F src/sqlite.h.in 5af8181f815831a8672c3834c60e6b4418448bcc
|
||||
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
||||
F src/sqliteInt.h 21510d10a6794c633e044e8396acb7899396a9e8
|
||||
F src/sqliteInt.h 284a65c29bc4f2a77aa45994285fb55f7de537b9
|
||||
F src/sqliteLimit.h 504a3161886d2938cbd163054ad620b8356df758
|
||||
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
||||
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
|
||||
@@ -201,7 +201,7 @@ F src/test_tclvar.c 9e42fa59d3d2f064b7ab8628e7ab2dc8a9fe93d4
|
||||
F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac
|
||||
F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241
|
||||
F src/tokenize.c af8a56e6a50c5042fc305bfa796275e9bf26ff2b
|
||||
F src/trigger.c d2f31617a1852f7365aca54c5c85743b9114d462
|
||||
F src/trigger.c 643e27f94a0112071a993f457d6c4aae24782944
|
||||
F src/update.c a7a5f60bf65a88557b434ac40f2ae6d2f7ad2d2d
|
||||
F src/utf.c 99cf927eabb104621ba889ac0dd075fc1657ad30
|
||||
F src/util.c 59d4e9456bf1fe581f415a783fa0cee6115c8f35
|
||||
@@ -330,8 +330,8 @@ F test/expr.test 9f521ae22f00e074959f72ce2e55d46b9ed23f68
|
||||
F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8
|
||||
F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43
|
||||
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
|
||||
F test/fkey2.test b879ba958126da0bfdfcf5d4532840c0f5956c72
|
||||
F test/fkey3.test 2183cac9075f3aae4875106eb9255bb73618444e
|
||||
F test/fkey2.test d26f490838bb067d654f4daae3aa90a8a8c8b562
|
||||
F test/fkey3.test 4d8d87a72e0dee5b5411cf10dc05ad9edebbeac8
|
||||
F test/fkey_malloc.test da912d000bb6ceb1cd11b655de1989762fa71ceb
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
|
||||
@@ -755,7 +755,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P b4a10c39e726dc190e9597e382baddc034294114
|
||||
R 8c38d646c8a9549ba486066fb27ea41b
|
||||
P 9e503e2d0428c9e8df878c7c6594790232cca4e0
|
||||
R a460411e3ababe633f79d4b6b7ec5ee3
|
||||
U dan
|
||||
Z 7018674b123841c492121f6d9b33b5de
|
||||
Z e4a35317c102426902fe4c436cf5658b
|
||||
|
@@ -1 +1 @@
|
||||
9e503e2d0428c9e8df878c7c6594790232cca4e0
|
||||
8353808c9e70412fdee31bfda7810e948f1c7485
|
@@ -2061,6 +2061,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
sqlite3VdbeAddOp0(v, OP_VBegin);
|
||||
}
|
||||
#endif
|
||||
sqlite3FkDropTable(pParse, pName, pTab);
|
||||
|
||||
/* Drop all triggers associated with the table being dropped. Code
|
||||
** is generated to remove entries from sqlite_master and/or
|
||||
|
58
src/fkey.c
58
src/fkey.c
@@ -587,6 +587,64 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called to generate code that runs when table pTab is
|
||||
** being dropped from the database. The SrcList passed as the second argument
|
||||
** to this function contains a single entry guaranteed to resolve to
|
||||
** table pTab.
|
||||
**
|
||||
** Normally, no code is required. However, if either
|
||||
**
|
||||
** (a) The table is the parent table of a FK constraint, or
|
||||
** (b) The table is the child table of a deferred FK constraint and it is
|
||||
** determined at runtime that there are outstanding deferred FK
|
||||
** constraint violations in the database,
|
||||
**
|
||||
** then the equivalent of "DELETE FROM <tbl>" is executed before dropping
|
||||
** the table from the database. Triggers are disabled while running this
|
||||
** DELETE, but foreign key actions are not.
|
||||
*/
|
||||
void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) && !pTab->pSelect ){
|
||||
int iSkip = 0;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
|
||||
assert( v ); /* VDBE has already been allocated */
|
||||
if( sqlite3FkReferences(pTab)==0 ){
|
||||
/* Search for a deferred foreign key constraint for which this table
|
||||
** is the child table. If one cannot be found, return without
|
||||
** generating any VDBE code. If one can be found, then jump over
|
||||
** the entire DELETE if there are no outstanding deferred constraints
|
||||
** when this statement is run. */
|
||||
FKey *p;
|
||||
for(p=pTab->pFKey; p; p=p->pNextFrom){
|
||||
if( p->isDeferred ) break;
|
||||
}
|
||||
if( !p ) return;
|
||||
iSkip = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip);
|
||||
}
|
||||
|
||||
pParse->disableTriggers = 1;
|
||||
sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0);
|
||||
pParse->disableTriggers = 0;
|
||||
|
||||
/* If the DELETE has generated immediate foreign key constraint
|
||||
** violations, halt the VDBE and return an error at this point, before
|
||||
** any modifications to the schema are made. This is because statement
|
||||
** transactions are not able to rollback schema changes. */
|
||||
sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
|
||||
sqlite3HaltConstraint(
|
||||
pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
|
||||
);
|
||||
|
||||
if( iSkip ){
|
||||
sqlite3VdbeResolveLabel(v, iSkip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called when inserting, deleting or updating a row of
|
||||
** table pTab to generate VDBE code to perform foreign key constraint
|
||||
|
@@ -2122,6 +2122,7 @@ struct Parse {
|
||||
u32 oldmask; /* Mask of old.* columns referenced */
|
||||
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
|
||||
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
|
||||
u8 disableTriggers; /* True to disable triggers */
|
||||
|
||||
/* Above is constant between recursions. Below is reset before and after
|
||||
** each recursion */
|
||||
@@ -2949,15 +2950,17 @@ VTable *sqlite3GetVTable(sqlite3*, Table*);
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
void sqlite3FkCheck(Parse*, Table*, ExprList*, int, int);
|
||||
void sqlite3FkDropTable(Parse*, SrcList *, Table*);
|
||||
void sqlite3FkActions(Parse*, Table*, ExprList*, int);
|
||||
int sqlite3FkRequired(Parse*, Table*, ExprList*);
|
||||
u32 sqlite3FkOldmask(Parse*, Table*, ExprList*);
|
||||
FKey *sqlite3FkReferences(Table *);
|
||||
#else
|
||||
#define sqlite3FkCheck(a,b,c,d,e)
|
||||
#define sqlite3FkActions(a,b,c,d)
|
||||
#define sqlite3FkRequired(a,b,c) 0
|
||||
#define sqlite3FkCheck(a,b,c,d,e)
|
||||
#define sqlite3FkDropTable(a,b,c)
|
||||
#define sqlite3FkOldmask(a,b,c) 0
|
||||
#define sqlite3FkRequired(a,b,c) 0
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
void sqlite3FkDelete(Table*);
|
||||
|
@@ -50,6 +50,10 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
|
||||
Schema * const pTmpSchema = pParse->db->aDb[1].pSchema;
|
||||
Trigger *pList = 0; /* List of triggers to return */
|
||||
|
||||
if( pParse->disableTriggers ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( pTmpSchema!=pTab->pSchema ){
|
||||
HashElem *p;
|
||||
for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){
|
||||
|
@@ -75,12 +75,14 @@ ifcapable {!foreignkey||!trigger} {
|
||||
|
||||
proc drop_all_tables {{db db}} {
|
||||
set tbls [execsql {SELECT name FROM sqlite_master WHERE type = 'table'}]
|
||||
execsql { PRAGMA foreign_keys = OFF }
|
||||
foreach t [execsql {
|
||||
SELECT name FROM sqlite_master
|
||||
WHERE type = 'table' AND name NOT like 'sqlite_%'
|
||||
}] {
|
||||
execsql "DROP TABLE $t"
|
||||
}
|
||||
execsql { PRAGMA foreign_keys = ON }
|
||||
}
|
||||
|
||||
execsql { PRAGMA foreign_keys = on }
|
||||
|
@@ -48,5 +48,33 @@ do_test fkey3-1.3 {
|
||||
DROP TABLE t1;
|
||||
}
|
||||
} {1 {foreign key constraint failed}}
|
||||
|
||||
|
||||
do_test fkey3-1.4 {
|
||||
execsql {
|
||||
DROP TABLE t2;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test fkey3-1.5 {
|
||||
execsql {
|
||||
DROP TABLE t1;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test fkey3-2.1 {
|
||||
execsql {
|
||||
PRAGMA foreign_keys=ON;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY);
|
||||
INSERT INTO t1 VALUES(100);
|
||||
INSERT INTO t1 VALUES(101);
|
||||
CREATE TABLE t2(y INTEGER PRIMARY KEY REFERENCES t1 (x) ON UPDATE SET NULL);
|
||||
}
|
||||
execsql {
|
||||
INSERT INTO t2 VALUES(100);
|
||||
INSERT INTO t2 VALUES(101);
|
||||
SELECT 1, x FROM t1;
|
||||
SELECT 2, y FROM t2;
|
||||
}
|
||||
} {1 100 1 101 2 100 2 101}
|
||||
|
||||
finish_test
|
||||
|
Reference in New Issue
Block a user