]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add test cases and fix problems on this branch.
authordan <dan@noemail.net>
Fri, 8 Feb 2019 19:30:09 +0000 (19:30 +0000)
committerdan <dan@noemail.net>
Fri, 8 Feb 2019 19:30:09 +0000 (19:30 +0000)
FossilOrigin-Name: 2b2e9f81cdc7a3ac1eacc087fbd0414ead732878aae296bab6b54b4a7cd0a06e

manifest
manifest.uuid
src/analyze.c
src/callback.c
src/prepare.c
src/sqliteInt.h
src/trigger.c
src/vdbe.c
test/reuse1.test

index 4fcd53ea16e3c89a2610cb0a137f7f71b81417a0..6928642f3e764f2f5759085dd456539743e4e9b8 100644 (file)
--- 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
index e24f36606ca0bf09d0649cb909dd1757b7fad62f..d3006b0bf2b3dfa385054a4c0de3392baf03f522 100644 (file)
@@ -1 +1 @@
-c089cc4fbe2e5e53d76154146870d14fc3b8d342a49580e41a5616817099715c
\ No newline at end of file
+2b2e9f81cdc7a3ac1eacc087fbd0414ead732878aae296bab6b54b4a7cd0a06e
\ No newline at end of file
index 5cf3c9eeae4fc71d2522b84aedd68c2279608cb1..c9c57c864d35ea0c48b25d389499aba31e93c6b7 100644 (file)
@@ -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;
index 9b9c4418610bc070e194ce255d5325ff0fa913f7..26239700cf78834aa865912b2c88e110c88dc371 100644 (file)
@@ -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; i<db->nDb; i++){
       if( i!=1 ){
index 367d85fd6dd1b5756d264fa130529ca10b5d1731..bae9b2871446563dad2a99208c28f1b0da691051 100644 (file)
@@ -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 );
index 7f863c0c2328a54300afb32417f6d1628030088f..8ef150705cb14be0f5e40de7fac96653c744e2db 100644 (file)
@@ -3262,6 +3262,7 @@ struct Trigger {
                              the <column-list> 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
index e400e7c80d431d9062be7b3ae0a48675d6547173..ea83a32936cf81b49107ba1a5e28a652bd75f25d 100644 (file)
@@ -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);
index 98df0a39772f3f4df28b926a8c88fe3254bd7e50..ae31f616305705871f0b00cbaac37872f4c97514 100644 (file)
@@ -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
index 8c58c50aefcc46fe584b7de1ff19a893487e2a94..47c7b1c31cdc4c3fa787ac887d94a37c50e08396 100644 (file)
@@ -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
+
+