From: dan Date: Fri, 8 Feb 2019 19:30:09 +0000 (+0000) Subject: Add test cases and fix problems on this branch. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=30fdc47579aab50e132de8e4ae72fdc5a348fb59;p=thirdparty%2Fsqlite.git Add test cases and fix problems on this branch. FossilOrigin-Name: 2b2e9f81cdc7a3ac1eacc087fbd0414ead732878aae296bab6b54b4a7cd0a06e --- diff --git a/manifest b/manifest index 4fcd53ea16..6928642f3e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\slatest\strunk\sinto\sthis\sbranch. -D 2019-02-05T19:51:15.766 +C Add\stest\scases\sand\sfix\sproblems\son\sthis\sbranch. +D 2019-02-08T19:30:09.365 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4 @@ -449,7 +449,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c 995b37de876639f1b6c14fcf15f3ee1004e3cbea354ebb43d7f5c4de0d649a64 -F src/analyze.c 1f1af7b08ae033e93e290a5db828772c52f1a8219ed6ff90d35e6d1410b5b6d4 +F src/analyze.c e75c3c1d6534265f74a4763282f17e9ad946606ef0a68c5517fcfb355cc243d0 F src/attach.c 3f9b0f6c79500cc40f4e543bc130a0b4ee13f52b45cbb6735608776cbdb79f0e F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab @@ -459,7 +459,7 @@ F src/btree.c 84b7c5c3829b60823e15e7a8407462b69be3818f96518fef28f97ac0fbbca72b F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3 F src/btreeInt.h cd82f0f08886078bf99b29e1a7045960b1ca5d9d5829c38607e1299c508eaf00 F src/build.c 5c99b58734e8a5ddb94b1f5734b550d91a762926d11094067aeb5e85da0541bf -F src/callback.c e81b2c1812d01d8c43286a00d8635a99b6b02eacdd2eb4d9a1d30b5122d79cf1 +F src/callback.c b7a60c23069922009e08cfea99fb97fea93a1d67fd59bf3360b01cc5355937f7 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 109e58d00f62e8e71ee1eb5944ac18b90171c928ab2e082e058056e1137cc20b F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 @@ -509,7 +509,7 @@ F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c fffd5250a323579384a3b3904302b9fe87e186ba24602af3013f749a0234ae98 F src/pragma.c af67dedaad8bafe9a5f9adcec32a0da6dd118617dd8220ad1d118f5a6bf83a02 F src/pragma.h 66f3e237cbba0a40a322d4a5bb58fcffa35bff8289ca9e5635424300479f1a38 -F src/prepare.c ca6afe2f9a2522567cfac7231a0b7458a9da701c791c9170fd241229ed9c6b83 +F src/prepare.c e9fcf4a4f6dc6895ddb7ec8a1b06d6c90d38863a4b8e274d6f8bc10440e287e9 F src/printf.c cbf27c320091a83279d1738f68a27a9fe01698c607ce80516ab6bdb5a9c36a1a F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c c8f207247472c41ac73d738e1c1a80719ad253d1dbb617ed57740492b2a6c097 @@ -519,7 +519,7 @@ F src/shell.c.in d3c5b1c021dd66b71086c62679bcdaa8cb66521efa74cbdebf55ae19073c578 F src/sqlite.h.in 528af7447d87ca678409b3280faa3905bab5fab265590821b0df0c8bc956e3a2 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683 -F src/sqliteInt.h e58c4cad951936e53871976ba4e9ede918950cc5c5854aee442f6fc63ca05928 +F src/sqliteInt.h 7cd0076d582b6248e3adae6517a8ae5b9319ef90e24bb145cc3e986a68d113bd F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 41d9cc5d5f9d2a470dcf0a28432c66e25c15b86e51535283e9aef632adf02ac8 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -579,13 +579,13 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c 0a065eaa31f494ba31ac21d4a5d24a5a7865a7d849459f8c6266df1ac6b9aedf F src/treeview.c c6ff90da4cc1813ff2d9bb11f17d4d927db62c47e552faa1835edc47269d753d -F src/trigger.c 5714a8d2e38ba38720783a4a56bb43f3709d7421d2ee7a8f61460ded73b03b3d +F src/trigger.c 3d8c617337af6b6fced85deb6789fe170ba980785d3de381a01c95a7c94d5200 F src/update.c 0b973357d88092140531e07ff641139c26fb4380b0b9f5ed98c5f7691b4604d1 F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 F src/util.c 82a2e3f691a3b654be872e305dab1f455e565dedf5e6a90c818c1ab307c00432 F src/vacuum.c 7dbed4a756f014f3ce54e6ae3c403ee725e8179cf73fc6dd5c064e5627649f9f -F src/vdbe.c b7b6f965153607072917dbd81d654a268abf4872c58d556701d1549550766c02 +F src/vdbe.c 4b593855fb962534718b7f2cf1427d8c32d6d7743ea7e6debd0674345ca50812 F src/vdbe.h 323218c4bfd64c719ba85d05fbc87cdd126991cadb39e73ccac7b59f30c3d53e F src/vdbeInt.h a76d5eed62c76bcd8de7afd3147fac1bc40c5a870582664bcd7d071ef437c37f F src/vdbeapi.c 57a2d794a8833f269b878dbc24e955369bdb379af6c4e93ebc5ce1a20fa3daf4 @@ -1225,7 +1225,7 @@ F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/releasetest.tcl b290d538ffcb2ff711f09eadc7396c1a42580f3fb078605471dc8875ca0b4d1e x F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb -F test/reuse1.test b020ae24435771c741f322f3e97c2b1777ab33d0e149cb15f86b1e19ed98b3cb +F test/reuse1.test 34781abbe671ec6858fb5969efadc1b3be1f95a6b46483c227fa6055645a8482 F test/reuse2.test 39f4a78ddf2d9b1fe3e4131c70497db628cd3a313a4520860b98af2e024bf98d F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6 @@ -1806,7 +1806,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P e9c5e1891ff4f7e57131031f068efea87027ddab0cd7846e0514a105853be47d 79c073878d56fc638b751b0e61295df182f7ee6f8ebd7319c1eeac1608abbac8 -R e0bf86af82e0dd6cb9c64eb21edaa738 +P c089cc4fbe2e5e53d76154146870d14fc3b8d342a49580e41a5616817099715c +R 77a59edee58243bf8d8613a9bd9be0bd U dan -Z e90b87b039ce6a2df58baedc3ca48d1e +Z e97dab24c9f742264e19dce1e79156e6 diff --git a/manifest.uuid b/manifest.uuid index e24f36606c..d3006b0bf2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c089cc4fbe2e5e53d76154146870d14fc3b8d342a49580e41a5616817099715c \ No newline at end of file +2b2e9f81cdc7a3ac1eacc087fbd0414ead732878aae296bab6b54b4a7cd0a06e \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 5cf3c9eeae..c9c57c864d 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -216,6 +216,7 @@ static void openStatTable( ** side-effect of the CREATE TABLE statement is to leave the rootpage ** of the new table in register pParse->regRoot. This is important ** because the OpenWrite opcode below will be needing it. */ + sqlite3SchemaWritable(pParse, iDb); sqlite3NestedParse(pParse, "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); @@ -1339,7 +1340,6 @@ static void analyzeDatabase(Parse *pParse, int iDb){ int iMem; int iTab; - sqlite3SchemaWritable(pParse, iDb); sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; pParse->nTab += 3; diff --git a/src/callback.c b/src/callback.c index 9b9c441861..26239700cf 100644 --- a/src/callback.c +++ b/src/callback.c @@ -41,7 +41,7 @@ struct SchemaPool { #ifdef SQLITE_DEBUG static void assert_schema_state_ok(sqlite3 *db){ - if( IsReuseSchema(db) ){ + if( IsReuseSchema(db) && db->magic!=SQLITE_MAGIC_ZOMBIE ){ int i; for(i=0; inDb; i++){ if( i!=1 ){ diff --git a/src/prepare.c b/src/prepare.c index 367d85fd6d..bae9b28714 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -414,6 +414,20 @@ error_out: return rc; } +int sqlite3LockReusableSchema(sqlite3 *db){ + if( IsReuseSchema(db) && (db->mDbFlags & DBFLAG_SchemaInuse)==0 ){ + db->mDbFlags |= DBFLAG_SchemaInuse; + return 1; + } + return 0; +} +void sqlite3UnlockReusableSchema(sqlite3 *db, int bRelease){ + if( bRelease ){ + db->mDbFlags &= ~DBFLAG_SchemaInuse; + sqlite3SchemaReleaseAll(db); + } +} + /* ** Initialize all database files - the main database file, the file ** used to store temporary tables, and any additional database files @@ -425,8 +439,12 @@ error_out: ** file was of zero-length, then the DB_Empty flag is also set. */ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ - int i, rc; + int rc = SQLITE_OK; + int bReleaseSchema; + int i; int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange); + + bReleaseSchema = sqlite3LockReusableSchema(db); assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); @@ -436,20 +454,19 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ /* Do the main schema first */ if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, 0, pzErrMsg, 0); - if( rc ) return rc; } /* All other schemas after the main schema. The "temp" schema must be last */ - for(i=db->nDb-1; i>0; i--){ + for(i=db->nDb-1; rc==SQLITE_OK && i>0; i--){ assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) ); if( !DbHasProperty(db, i, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, i, pzErrMsg, 0); - if( rc ) return rc; } } - if( commit_internal ){ + if( rc==SQLITE_OK && commit_internal ){ sqlite3CommitInternalChanges(db); } - return SQLITE_OK; + sqlite3UnlockReusableSchema(db, bReleaseSchema); + return rc; } /* @@ -748,12 +765,7 @@ static int sqlite3LockAndPrepare( return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); - if( IsReuseSchema(db) ){ - if( (db->mDbFlags & DBFLAG_SchemaInuse)==0 ){ - db->mDbFlags |= DBFLAG_SchemaInuse; - bReleaseSchema = 1; - } - } + bReleaseSchema = sqlite3LockReusableSchema(db); sqlite3BtreeEnterAll(db); do{ /* Make multiple attempts to compile the SQL, until it either succeeds @@ -766,10 +778,7 @@ static int sqlite3LockAndPrepare( sqlite3BtreeLeaveAll(db); - if( bReleaseSchema ){ - db->mDbFlags &= ~DBFLAG_SchemaInuse; - sqlite3SchemaReleaseAll(db); - } + sqlite3UnlockReusableSchema(db, bReleaseSchema); rc = sqlite3ApiExit(db, rc); assert( (rc&db->errMask)==rc ); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 7f863c0c23..8ef150705c 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3262,6 +3262,7 @@ struct Trigger { the is stored here */ Schema *pSchema; /* Schema containing the trigger */ Schema *pTabSchema; /* Schema containing the table */ + char *zTabSchema; /* Temp triggers in IsReuseSchema() dbs only */ TriggerStep *step_list; /* Link list of trigger program steps */ Trigger *pNext; /* Next trigger associated with the table */ }; @@ -4330,6 +4331,9 @@ KeyInfo *sqlite3KeyInfoRef(KeyInfo*); KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int); +void sqlite3UnlockReusableSchema(sqlite3 *db, int bRelease); +int sqlite3LockReusableSchema(sqlite3 *db); + #ifdef SQLITE_DEBUG int sqlite3KeyInfoIsWriteable(KeyInfo*); #endif diff --git a/src/trigger.c b/src/trigger.c index e400e7c80d..ea83a32936 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -55,15 +55,24 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ } if( pTmpSchema!=pTab->pSchema ){ + sqlite3 *db = pParse->db; HashElem *p; - assert( sqlite3SchemaMutexHeld(pParse->db, 0, pTmpSchema) ); + char *zSchema = 0; + if( IsReuseSchema(db) ){ + zSchema = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; + } + assert( sqlite3SchemaMutexHeld(db, 0, pTmpSchema) ); for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){ Trigger *pTrig = (Trigger *)sqliteHashData(p); - if( pTrig->pTabSchema==pTab->pSchema - && 0==sqlite3StrICmp(pTrig->table, pTab->zName) + if( (zSchema==0 && pTrig->pTabSchema==pTab->pSchema) + || (zSchema!=0 && 0==sqlite3StrICmp(pTrig->zTabSchema, zSchema)) ){ - pTrig->pNext = (pList ? pList : pTab->pTrigger); - pList = pTrig; + if( 0==sqlite3StrICmp(pTrig->table, pTab->zName) + ){ + pTrig->pTabSchema = pTab->pSchema; + pTrig->pNext = (pList ? pList : pTab->pTrigger); + pList = pTrig; + } } } } @@ -244,6 +253,10 @@ void sqlite3BeginTrigger( pTrigger->zName = zName; zName = 0; pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); + if( IsReuseSchema(db) && iDb==1 ){ + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); + pTrigger->zTabSchema = sqlite3DbStrDup(db, db->aDb[iTabDb].zDbSName); + } pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; @@ -541,6 +554,7 @@ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); + sqlite3DbFree(db, pTrigger->zTabSchema); sqlite3ExprDelete(db, pTrigger->pWhen); sqlite3IdListDelete(db, pTrigger->pColumns); sqlite3DbFree(db, pTrigger); diff --git a/src/vdbe.c b/src/vdbe.c index 98df0a3977..ae31f61630 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -5761,6 +5761,7 @@ case OP_ParseSchema: { const char *zMaster; char *zSql; InitData initData; + int bRelease; /* Any prepared statement that invokes this opcode will hold mutexes ** on every btree. This is a prerequisite for invoking @@ -5797,12 +5798,21 @@ case OP_ParseSchema: { if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ + bRelease = sqlite3LockReusableSchema(db); + if( IsReuseSchema(db) ){ + rc = sqlite3Init(db, &p->zErrMsg); + if( rc ){ + sqlite3UnlockReusableSchema(db, bRelease); + goto abort_due_to_error; + } + } assert( db->init.busy==0 ); db->init.busy = 1; initData.rc = SQLITE_OK; initData.nInitRow = 0; assert( !db->mallocFailed ); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); + sqlite3UnlockReusableSchema(db, bRelease); if( rc==SQLITE_OK ) rc = initData.rc; if( rc==SQLITE_OK && initData.nInitRow==0 ){ /* The OP_ParseSchema opcode with a non-NULL P4 argument should parse diff --git a/test/reuse1.test b/test/reuse1.test index 8c58c50aef..47c7b1c31c 100644 --- a/test/reuse1.test +++ b/test/reuse1.test @@ -16,6 +16,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse1 +if 1 { forcedelete test.db2 sqlite3 db2 test.db2 @@ -36,7 +37,7 @@ do_test 1.2 { db close db2 close sqlite3 db2 test.db2 -reuse-schema 1 - sqlite3 db test.db -reuse-schema 1 + sqlite3 db test.db -reuse-schema 1 } {} do_execsql_test -db db2 1.3.1 { @@ -91,4 +92,301 @@ foreach {tn sql} { do_catchsql_test 1.5.$tn $sql {1 {attempt to modify read-only schema}} } +#------------------------------------------------------------------------- +# +reset_db +forcedelete test.db2 +ifcapable fts5 { + do_execsql_test 2.0 { + CREATE VIRTUAL TABLE ft USING fts5(a); + INSERT INTO ft VALUES('one'), ('two'), ('three'); + ATTACH 'test.db2' AS aux; + CREATE VIRTUAL TABLE aux.ft USING fts5(a); + INSERT INTO aux.ft VALUES('aux1'), ('aux2'), ('aux3'); + } + + db close + sqlite3 db test.db -reuse-schema 1 + + do_execsql_test 2.1 { + ATTACH 'test.db2' AS aux; + SELECT * FROM main.ft; + } {one two three} + + do_execsql_test 2.2 { + SELECT * FROM aux.ft; + } {aux1 aux2 aux3} + + do_execsql_test 2.2 { + SELECT * FROM aux.ft_content; + } {1 aux1 2 aux2 3 aux3} +} + +} + +#------------------------------------------------------------------------- +# +reset_db +forcedelete test.db2 +do_execsql_test 3.0 { + CREATE TABLE t1(a PRIMARY KEY, b, c); + CREATE VIEW v1 AS SELECT * FROM t1; + CREATE TRIGGER v1_ins INSTEAD OF INSERT ON v1 BEGIN + INSERT INTO t1 VALUES(new.a, new.b, new.c); + END; + CREATE TRIGGER v1_del INSTEAD OF DELETE ON v1 BEGIN + DELETE FROM t1 WHERE a=old.a; + END; + CREATE TRIGGER v1_up INSTEAD OF UPDATE ON v1 BEGIN + UPDATE t1 SET a=new.a, b=new.b, c=new.c WHERE a=old.a; + END; +} +forcecopy test.db test.db2 + +do_test 3.1 { + sqlite3 db2 test.db2 + execsql { INSERT INTO t1 VALUES(1, 2, 3) } db + execsql { INSERT INTO t1 VALUES(4, 5, 6) } db2 + db2 close + execsql { ATTACH 'test.db2' AS aux; } +} {} + +do_execsql_test 3.2 { + SELECT * FROM main.v1; +} {1 2 3} + +do_execsql_test 3.3 { + SELECT * FROM aux.v1; +} {4 5 6} + +db close +sqlite3 db test.db -reuse-schema 1 + +do_execsql_test 3.4 { ATTACH 'test.db2' AS aux } {} +do_execsql_test 3.5 { SELECT * FROM main.v1 } {1 2 3} +do_execsql_test 3.6 { SELECT * FROM aux.v1 } {4 5 6} + +do_execsql_test 3.7.1 { INSERT INTO aux.t1 VALUES(8, 9, 10); } +do_execsql_test 3.7.2 { SELECT * FROM main.v1 } {1 2 3} +do_execsql_test 3.7.3 { SELECT * FROM aux.v1 } {4 5 6 8 9 10} + +do_execsql_test 3.8.1 { DELETE FROM aux.t1 WHERE b=5 } +do_execsql_test 3.8.2 { SELECT * FROM main.v1 } {1 2 3} +do_execsql_test 3.8.3 { SELECT * FROM aux.v1 } {8 9 10} + +do_execsql_test 3.9.1 { UPDATE aux.t1 SET b='abc' } +do_execsql_test 3.9.2 { SELECT * FROM main.v1 } {1 2 3} +do_execsql_test 3.9.3 { SELECT * FROM aux.v1 } {8 abc 10} + +do_execsql_test 3.10.1 { INSERT INTO aux.v1 VALUES(11, 12, 13) } +do_execsql_test 3.10.2 { SELECT * FROM main.v1 } {1 2 3} +do_execsql_test 3.10.3 { SELECT * FROM aux.v1 } {8 abc 10 11 12 13} + +do_execsql_test 3.11.1 { DELETE FROM aux.v1 WHERE b='abc' } +do_execsql_test 3.11.2 { SELECT * FROM main.v1 } {1 2 3} +do_execsql_test 3.11.3 { SELECT * FROM aux.v1 } {11 12 13} + +do_execsql_test 3.12.1 { UPDATE aux.v1 SET b='def' } +do_execsql_test 3.12.2 { SELECT * FROM main.v1 } {1 2 3} +do_execsql_test 3.12.3 { SELECT * FROM aux.v1 } {11 def 13} + +do_execsql_test 3.13.1 { + CREATE TEMP TRIGGER xyz AFTER INSERT ON aux.t1 BEGIN + INSERT INTO v1 VALUES(new.a, new.b, new.c); + END +} +do_execsql_test 3.13.2 { + INSERT INTO aux.v1 VALUES('x', 'y', 'z'); +} +do_execsql_test 3.13.3 { + SELECT * FROM v1; +} {1 2 3 x y z} + +#------------------------------------------------------------------------- +# +reset_db +forcedelete test.db2 +do_execsql_test 4.0 { + CREATE TABLE t1(a PRIMARY KEY, b, c UNIQUE); + CREATE TABLE del(a, b, c); + CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN + INSERT INTO del VALUES(old.a, old.b, old.c); + END; +} +forcecopy test.db test.db2 + +db close +sqlite3 db test.db -reuse-schema 1 +execsql { + ATTACH 'test.db2' AS aux; + PRAGMA recursive_triggers = 1; +} + +do_execsql_test 4.1 { + INSERT INTO main.t1 VALUES(1, 2, 3); + INSERT INTO aux.t1 VALUES(4, 5, 6); +} + +do_execsql_test 4.2.1 { + INSERT OR REPLACE INTO aux.t1 VALUES('a', 'b', 6); + SELECT * FROM aux.t1; +} {a b 6} +do_execsql_test 4.2.2 { SELECT * FROM aux.del } {4 5 6} +do_execsql_test 4.2.3 { SELECT * FROM main.del } {} + +do_execsql_test 4.3.1 { + INSERT INTO aux.t1 VALUES('x', 'y', 'z'); + UPDATE OR REPLACE aux.t1 SET c='z' WHERE a='a'; +} {} +do_execsql_test 4.3.2 { SELECT * FROM aux.del } {4 5 6 x y z} +do_execsql_test 4.3.3 { SELECT * FROM main.del } {} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 5.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c); + CREATE INDEX i1 ON t1(b); + INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6); + ANALYZE; + PRAGMA writable_schema = 1; + DELETE FROM sqlite_stat1; +} +db close +forcecopy test.db test.db2 +sqlite3 db test.db -reuse-schema 1 +execsql { ATTACH 'test.db2' AS aux } + +foreach {tn sql} { + 1 { CREATE TABLE t3(x) } + 2 { DROP TABLE t2 } + 3 { CREATE INDEX i2 ON t2(b) } + 4 { DROP INDEX i1 } + 5 { ALTER TABLE t1 ADD COLUMN d } + 6 { ALTER TABLE t1 RENAME TO t3 } + 7 { ALTER TABLE t1 RENAME c TO d } +} { + do_catchsql_test 5.1.$tn $sql {1 {attempt to modify read-only schema}} +} + +do_execsql_test 5.2.1 { ANALYZE aux.t1 } {} +do_execsql_test 5.2.2 { SELECT * FROM aux.sqlite_stat1 } {t1 i1 {2 1}} +do_execsql_test 5.2.3 { SELECT * FROM main.sqlite_stat1 } {} + +do_test 5.3.0 { + sqlite3 db2 test.db2 + db2 eval { + PRAGMA writable_schema = 1; + DELETE FROM sqlite_stat1; + } +} {} + +do_execsql_test 5.3.1 { SELECT * FROM aux.sqlite_stat1 } {} +do_execsql_test 5.3.2 { ANALYZE aux } {} +do_execsql_test 5.3.3 { SELECT * FROM aux.sqlite_stat1 } {t1 i1 {2 1}} +do_execsql_test 5.3.4 { SELECT * FROM main.sqlite_stat1 } {} + +#------------------------------------------------------------------------- +# Attempting to run ANALYZE when the required sqlite_statXX functions +# are missing is an error (because it would modify the database schema). +# +reset_db +do_execsql_test 5.4 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c); + CREATE INDEX i1 ON t1(b); + INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6); +} +db close +sqlite3 db test.db -reuse-schema 1 +breakpoint +foreach {tn sql} { + 1 { ANALYZE } + 2 { ANALYZE t1 } + 3 { ANALYZE i1 } + 4 { ANALYZE main } + 5 { ANALYZE main.t1 } + 6 { ANALYZE main.i1 } +} { + do_catchsql_test 5.4.$tn $sql {1 {attempt to modify read-only schema}} +} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 6.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + CREATE VIEW v1 AS SELECT * FROM t1; +} +db close +forcecopy test.db test.db2 +sqlite3 db test.db -reuse-schema 1 +execsql { ATTACH 'test.db2' AS aux } + +do_execsql_test 6.1 { + INSERT INTO main.t1(a) VALUES(1), (2), (3); + INSERT INTO aux.t1(a) VALUES(4), (5), (6); + CREATE TEMP TABLE t2(i,t); + INSERT INTO t2 VALUES(2, 'two'), (5, 'five'); +} + +do_execsql_test 6.2 { + SELECT t FROM t2 WHERE i IN (SELECT a FROM aux.t1) +} {five} +do_execsql_test 6.3 { + SELECT t FROM t2 WHERE i IN (SELECT a FROM aux.v1) +} {five} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 7.0 { + CREATE TABLE p1(a PRIMARY KEY, b); + CREATE TABLE p2(a PRIMARY KEY, b); + CREATE TABLE c1(x REFERENCES p1 ON UPDATE CASCADE ON DELETE CASCADE); +} + +db close +forcecopy test.db test.db2 +sqlite3 db test.db -reuse-schema 1 +execsql { ATTACH 'test.db2' AS aux } + +do_execsql_test 7.1 { + INSERT INTO aux.p1 VALUES(1, 'one'); + INSERT INTO aux.p1 VALUES(2, 'two'); + PRAGMA foreign_keys = on; +} + +do_execsql_test 7.2 { + INSERT INTO aux.c1 VALUES(2); +} + +do_execsql_test 7.3.1 { + PRAGMA foreign_keys = off; + INSERT INTO main.p2 SELECT * FROM aux.p1; +} +do_execsql_test 7.3.2 { + SELECT * FROM main.p2; +} {1 one 2 two} + +do_execsql_test 7.3.3 { + INSERT INTO aux.p2 VALUES(1, 2); +} + +do_execsql_test 7.3.4 { + SELECT main.p2.a FROM main.p2, aux.p2; +} {1 2} + +do_execsql_test 7.3.5 { + SELECT * FROM main.p2, aux.p2; +} {1 one 1 2 2 two 1 2} + +do_execsql_test 7.4 { + SELECT count(*) FROM aux.p2; +} {1} + + finish_test + +