-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
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
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
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
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
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
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
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
-c089cc4fbe2e5e53d76154146870d14fc3b8d342a49580e41a5616817099715c
\ No newline at end of file
+2b2e9f81cdc7a3ac1eacc087fbd0414ead732878aae296bab6b54b4a7cd0a06e
\ No newline at end of file
** 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
);
int iMem;
int iTab;
- sqlite3SchemaWritable(pParse, iDb);
sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab;
pParse->nTab += 3;
#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 ){
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
** 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) );
/* 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;
}
/*
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
sqlite3BtreeLeaveAll(db);
- if( bReleaseSchema ){
- db->mDbFlags &= ~DBFLAG_SchemaInuse;
- sqlite3SchemaReleaseAll(db);
- }
+ sqlite3UnlockReusableSchema(db, bReleaseSchema);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
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 */
};
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
}
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;
+ }
}
}
}
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;
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);
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
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
source $testdir/tester.tcl
set testprefix reuse1
+if 1 {
forcedelete test.db2
sqlite3 db2 test.db2
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 {
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
+
+