From: danielk1977 Date: Sat, 19 Jun 2004 04:23:25 +0000 (+0000) Subject: Backport of (1628) to version 2. (CVS 1631) X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f4ed02a34f63686b86a6ed533c9fa53aac5e5bf3;p=thirdparty%2Fsqlite.git Backport of (1628) to version 2. (CVS 1631) FossilOrigin-Name: cce250eaee59eac2d15437b564f049c5b241317c --- diff --git a/manifest b/manifest index 8e9840825b..59593a8a38 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sthe\spublish.sh\sscript\sso\sthat\sit\sno\slonger\sgenerates\sdocumentation\npages\s(that\sis\shandled\sby\sthe\sversion\s3.0.0\spublish.sh).\s\sAlso\sinsert\nversion\snumbers\sin\sthe\sfilenames\sof\sall\sbuild\sproducts.\s(CVS\s1601) -D 2004-06-16T01:21:01 +C Backport\sof\s(1628)\sto\sversion\s2.\s(CVS\s1631) +D 2004-06-19T04:23:25 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -36,7 +36,7 @@ F src/func.c 34fead7a33e82095f6412d3fafd379d47864b3be F src/hash.c 9b56ef3b291e25168f630d5643a4264ec011c70e F src/hash.h 3247573ab95b9dd90bcca0307a75d9a16da1ccc7 F src/insert.c c0485ee2d1b99322894e2d1e0b576fd05ed75616 -F src/main.c 94dd355768e2a389e184a069b6880f4bac100307 +F src/main.c 35b6917da56ff1abdfab7fc53d10b815dd4cac16 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/os.c edcd42ad1cf13e7322f814c50a3e6eb09d3915bb F src/os.h 250a3789be609adfee5c5aa20137ce8683276f24 @@ -138,7 +138,7 @@ F test/thread1.test 53f050d5be6932d9430df7756edd379366508ff6 F test/threadtest1.c f7f896e62ed46feae1dc411114a48c15a0f82ee2 F test/threadtest2.c d94ca4114fd1504f7e0ae724bcd83d4b40931d86 F test/trans.test 0cb8256daff1ae0da75321e00125338c6681158d -F test/trigger1.test 4538c1c7d6bbca5dfe619ea6e1682b07ece95b21 +F test/trigger1.test cf8c8bbdaa254b000242f89e024f9b44cafda093 F test/trigger2.test 0767ab30cb5a2c8402c8524f3d566b410b6f5263 F test/trigger3.test a95ccace88291449f5eae7139ec438a42f90654d F test/trigger4.test 542afce45774e8f8e1130b96b8675f414d6e4bd8 @@ -188,7 +188,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 24adf9ed5988d6e110a750f75b767fad163689c6 -R bad18b9b4e0f573517fda2790c833ba9 -U drh -Z 8af7b97de359371eafa7d3ea06076f21 +P f2b8d35825a2137e83419e9aebc9619a9db2ada8 +R 08b10f88d920f85f8c5d79ea0011a791 +U danielk1977 +Z 231032d5f4f2d83a2985bd8df240fe0c diff --git a/manifest.uuid b/manifest.uuid index b6be415622..87b2667aa4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f2b8d35825a2137e83419e9aebc9619a9db2ada8 \ No newline at end of file +cce250eaee59eac2d15437b564f049c5b241317c \ No newline at end of file diff --git a/src/main.c b/src/main.c index 27f237f7c1..25d0f9b3d1 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.164 2004/04/23 17:04:45 drh Exp $ +** $Id: main.c,v 1.164.2.1 2004/06/19 04:23:25 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -189,10 +189,13 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){ BtCursor *curMain; int size; Table *pTab; - char *azArg[6]; + char const *azArg[6]; char zDbNum[30]; int meta[SQLITE_N_BTREE_META]; InitData initData; + char const *zMasterSchema; + char const *zMasterName; + char *zSql = 0; /* ** The master database table has a structure like this @@ -216,62 +219,38 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){ ")" ; - /* The following SQL will read the schema from the master tables. - ** The first version works with SQLite file formats 2 or greater. - ** The second version is for format 1 files. - ** - ** Beginning with file format 2, the rowid for new table entries - ** (including entries in sqlite_master) is an increasing integer. - ** So for file format 2 and later, we can play back sqlite_master - ** and all the CREATE statements will appear in the right order. - ** But with file format 1, table entries were random and so we - ** have to make sure the CREATE TABLEs occur before their corresponding - ** CREATE INDEXs. (We don't have to deal with CREATE VIEW or - ** CREATE TRIGGER in file format 1 because those constructs did - ** not exist then.) + assert( iDb>=0 && iDbnDb ); + + /* zMasterSchema and zInitScript are set to point at the master schema + ** and initialisation script appropriate for the database being + ** initialised. zMasterName is the name of the master table. */ - static char init_script[] = - "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master " - "UNION ALL " - "SELECT type, name, rootpage, sql, 0 FROM sqlite_master"; - static char older_init_script[] = - "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master " - "UNION ALL " - "SELECT type, name, rootpage, sql, 0 FROM sqlite_master " - "WHERE type='table' " - "UNION ALL " - "SELECT type, name, rootpage, sql, 0 FROM sqlite_master " - "WHERE type='index'"; - - - assert( iDb>=0 && iDb!=1 && iDbnDb ); - - /* Construct the schema tables: sqlite_master and sqlite_temp_master + if( iDb==1 ){ + zMasterSchema = temp_master_schema; + zMasterName = TEMP_MASTER_NAME; + }else{ + zMasterSchema = master_schema; + zMasterName = MASTER_NAME; + } + + /* Construct the schema table. */ sqliteSafetyOff(db); azArg[0] = "table"; - azArg[1] = MASTER_NAME; + azArg[1] = zMasterName; azArg[2] = "2"; - azArg[3] = master_schema; + azArg[3] = zMasterSchema; sprintf(zDbNum, "%d", iDb); azArg[4] = zDbNum; azArg[5] = 0; initData.db = db; initData.pzErrMsg = pzErrMsg; - sqliteInitCallback(&initData, 5, azArg, 0); - pTab = sqliteFindTable(db, MASTER_NAME, "main"); + sqliteInitCallback(&initData, 5, (char **)azArg, 0); + pTab = sqliteFindTable(db, zMasterName, db->aDb[iDb].zName); if( pTab ){ pTab->readOnly = 1; - } - if( iDb==0 ){ - azArg[1] = TEMP_MASTER_NAME; - azArg[3] = temp_master_schema; - azArg[4] = "1"; - sqliteInitCallback(&initData, 5, azArg, 0); - pTab = sqliteFindTable(db, TEMP_MASTER_NAME, "temp"); - if( pTab ){ - pTab->readOnly = 1; - } + }else{ + return SQLITE_NOMEM; } sqliteSafetyOn(db); @@ -320,7 +299,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){ sqliteSetString(pzErrMsg, "unsupported file format", (char*)0); return SQLITE_ERROR; } - }else if( db->file_format!=meta[2] || db->file_format<4 ){ + }else if( iDb!=1 && (db->file_format!=meta[2] || db->file_format<4) ){ assert( db->file_format>=4 ); if( meta[2]==0 ){ sqliteSetString(pzErrMsg, "cannot attach empty database: ", @@ -340,18 +319,35 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){ */ assert( db->init.busy ); sqliteSafetyOff(db); - if( iDb==0 ){ - rc = sqlite_exec(db, - db->file_format>=2 ? init_script : older_init_script, - sqliteInitCallback, &initData, 0); + + /* The following SQL will read the schema from the master tables. + ** The first version works with SQLite file formats 2 or greater. + ** The second version is for format 1 files. + ** + ** Beginning with file format 2, the rowid for new table entries + ** (including entries in sqlite_master) is an increasing integer. + ** So for file format 2 and later, we can play back sqlite_master + ** and all the CREATE statements will appear in the right order. + ** But with file format 1, table entries were random and so we + ** have to make sure the CREATE TABLEs occur before their corresponding + ** CREATE INDEXs. (We don't have to deal with CREATE VIEW or + ** CREATE TRIGGER in file format 1 because those constructs did + ** not exist then.) + */ + if( db->file_format>=2 ){ + sqliteSetString(&zSql, + "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"", + db->aDb[iDb].zName, "\".", zMasterName, (char*)0); }else{ - char *zSql = 0; sqliteSetString(&zSql, - "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"", - db->aDb[iDb].zName, "\".sqlite_master", (char*)0); - rc = sqlite_exec(db, zSql, sqliteInitCallback, &initData, 0); - sqliteFree(zSql); + "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"", + db->aDb[iDb].zName, "\".", zMasterName, + " WHERE type IN ('table', 'index')" + " ORDER BY CASE type WHEN 'table' THEN 0 ELSE 1 END", (char*)0); } + rc = sqlite_exec(db, zSql, sqliteInitCallback, &initData, 0); + + sqliteFree(zSql); sqliteSafetyOn(db); sqliteBtreeCloseCursor(curMain); if( sqlite_malloc_failed ){ @@ -361,9 +357,6 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){ } if( rc==SQLITE_OK ){ DbSetProperty(db, iDb, DB_SchemaLoaded); - if( iDb==0 ){ - DbSetProperty(db, 1, DB_SchemaLoaded); - } }else{ sqliteResetInternalSchema(db, iDb); } @@ -391,13 +384,24 @@ int sqliteInit(sqlite *db, char **pzErrMsg){ rc = SQLITE_OK; db->init.busy = 1; for(i=0; rc==SQLITE_OK && inDb; i++){ - if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue; - assert( i!=1 ); /* Should have been initialized together with 0 */ + if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; rc = sqliteInitOne(db, i, pzErrMsg); if( rc ){ sqliteResetInternalSchema(db, i); } } + + /* Once all the other databases have been initialised, load the schema + ** for the TEMP database. This is loaded last, as the TEMP database + ** schema may contain references to objects in other databases. + */ + if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ + rc = sqliteInitOne(db, 1, pzErrMsg); + if( rc ){ + sqliteResetInternalSchema(db, 1); + } + } + db->init.busy = 0; if( rc==SQLITE_OK ){ db->flags |= SQLITE_Initialized; diff --git a/test/trigger1.test b/test/trigger1.test index b55ca12378..d8d08dec7b 100644 --- a/test/trigger1.test +++ b/test/trigger1.test @@ -412,5 +412,108 @@ do_test trigger-9.2 { } } {1 2 1 3 99 99 1 3} +execsql { + DROP TABLE t2; + DROP TABLE t3; + DROP TABLE t4; +} + +# Ticket #764. At one stage TEMP triggers would fail to re-install when the +# schema was reloaded. The following tests ensure that TEMP triggers are +# correctly re-installed. +# +# Also verify that references within trigger programs are resolved at +# statement compile time, not trigger installation time. This means, for +# example, that you can drop and re-create tables referenced by triggers. +do_test trigger-10.0 { + file delete -force test2.db + file delete -force test2.db-journal + sqlite db2 test2.db + execsql {CREATE TABLE t3(a, b, c);} db2 + db2 close + execsql { + ATTACH 'test2.db' AS aux; + } +} {} +do_test trigger-10.1 { + execsql { + CREATE TABLE t1(a, b, c); + CREATE temp TABLE t2(a, b, c); + CREATE TABLE insert_log(db, a, b, c); + } +} {} +do_test trigger-10.2 { + execsql { + CREATE TEMP TRIGGER trig1 AFTER INSERT ON t1 BEGIN + INSERT INTO insert_log VALUES('main', new.a, new.b, new.c); + END; + CREATE TEMP TRIGGER trig2 AFTER INSERT ON t2 BEGIN + INSERT INTO insert_log VALUES('temp', new.a, new.b, new.c); + END; + CREATE TEMP TRIGGER trig3 AFTER INSERT ON t3 BEGIN + INSERT INTO insert_log VALUES('aux', new.a, new.b, new.c); + END; + } +} {} +do_test trigger-10.3 { + execsql { + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t2 VALUES(4, 5, 6); + INSERT INTO t3 VALUES(7, 8, 9); + } +} {} +do_test trigger-10.4 { + execsql { + SELECT * FROM insert_log; + } +} {main 1 2 3 temp 4 5 6 aux 7 8 9} +do_test trigger-10.5 { + execsql { + BEGIN; + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t2 VALUES(4, 5, 6); + INSERT INTO t3 VALUES(7, 8, 9); + ROLLBACK; + } +} {} +do_test trigger-10.6 { + execsql { + SELECT * FROM insert_log; + } +} {main 1 2 3 temp 4 5 6 aux 7 8 9} +do_test trigger-10.7 { + execsql { + DELETE FROM insert_log; + INSERT INTO t1 VALUES(11, 12, 13); + INSERT INTO t2 VALUES(14, 15, 16); + INSERT INTO t3 VALUES(17, 18, 19); + } +} {} +do_test trigger-10.8 { + execsql { + SELECT * FROM insert_log; + } +} {main 11 12 13 temp 14 15 16 aux 17 18 19} +do_test trigger-10.8 { +# Drop and re-create the insert_log table in a different database. Note +# that we can change the column names because the trigger programs don't +# use them explicitly. + execsql { + DROP TABLE insert_log; + CREATE temp TABLE insert_log(db, d, e, f); + } +} {} +do_test trigger-10.10 { + execsql { + INSERT INTO t1 VALUES(21, 22, 23); + INSERT INTO t2 VALUES(24, 25, 26); + INSERT INTO t3 VALUES(27, 28, 29); + } +} {} +do_test trigger-10.11 { + execsql { + SELECT * FROM insert_log; + } +} {main 21 22 23 temp 24 25 26 aux 27 28 29} finish_test