Index: src/alter.c ================================================================== --- src/alter.c +++ src/alter.c @@ -134,12 +134,12 @@ ** that the table is being renamed to. */ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){ goto exit_rename_table; } - if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto - exit_rename_table; + if( SQLITE_OK!=sqlite3CheckObjectName(pParse,zName,"table",zName) ){ + goto exit_rename_table; } #ifndef SQLITE_OMIT_VIEW if( pTab->pSelect ){ sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName); Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -827,17 +827,42 @@ ** This routine is used to check if the UTF-8 string zName is a legal ** unqualified name for a new schema object (table, index, view or ** trigger). All names are legal except those that begin with the string ** "sqlite_" (in upper, lower or mixed case). This portion of the namespace ** is reserved for internal use. +** +** When parsing the sqlite_master table, this routine also checks to +** make sure the "type", "name", and "tbl_name" columns are consistent +** with the SQL. */ -int sqlite3CheckObjectName(Parse *pParse, const char *zName){ - if( !pParse->db->init.busy && pParse->nested==0 - && sqlite3WritableSchema(pParse->db)==0 - && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ - sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName); - return SQLITE_ERROR; +int sqlite3CheckObjectName( + Parse *pParse, /* Parsing context */ + const char *zName, /* Name of the object to check */ + const char *zType, /* Type of this object */ + const char *zTblName /* Parent table name for triggers and indexes */ +){ + sqlite3 *db = pParse->db; + if( sqlite3WritableSchema(db) || db->init.imposterTable ){ + /* Skip these error checks for writable_schema=ON */ + return SQLITE_OK; + } + if( db->init.busy ){ + if( sqlite3_stricmp(zType, db->init.azInit[0]) + || sqlite3_stricmp(zName, db->init.azInit[1]) + || sqlite3_stricmp(zTblName, db->init.azInit[2]) + ){ + sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */ + return SQLITE_ERROR; + } + }else{ + if( pParse->nested==0 + && 0==sqlite3StrNICmp(zName, "sqlite_", 7) + ){ + sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", + zName); + return SQLITE_ERROR; + } } return SQLITE_OK; } /* @@ -914,11 +939,11 @@ sqlite3RenameTokenMap(pParse, (void*)zName, pName); } } pParse->sNameToken = *pName; if( zName==0 ) return; - if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + if( sqlite3CheckObjectName(pParse, zName, isView?"view":"table", zName) ){ goto begin_table_error; } if( db->init.iDb==1 ) isTemp = 1; #ifndef SQLITE_OMIT_AUTHORIZATION assert( isTemp==0 || isTemp==1 ); @@ -3273,11 +3298,11 @@ */ if( pName ){ zName = sqlite3NameFromToken(db, pName); if( zName==0 ) goto exit_create_index; assert( pName->z!=0 ); - if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName,"index",pTab->zName) ){ goto exit_create_index; } if( !IN_RENAME_OBJECT ){ if( !db->init.busy ){ if( sqlite3FindTable(db, zName, 0)!=0 ){ Index: src/prepare.c ================================================================== --- src/prepare.c +++ src/prepare.c @@ -62,35 +62,37 @@ ** database. See sqlite3Init() below for additional information. ** This routine is also called from the OP_ParseSchema opcode of the VDBE. ** ** Each callback contains the following information: ** -** argv[0] = name of thing being created -** argv[1] = root page number for table or index. 0 for trigger or view. -** argv[2] = SQL text for the CREATE statement. +** argv[0] = type of object: "table", "index", "trigger", or "view". +** argv[1] = name of thing being created +** argv[2] = associated table if an index or trigger +** argv[3] = root page number for table or index. 0 for trigger or view. +** argv[4] = SQL text for the CREATE statement. ** */ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ InitData *pData = (InitData*)pInit; sqlite3 *db = pData->db; int iDb = pData->iDb; - assert( argc==3 ); + assert( argc==5 ); UNUSED_PARAMETER2(NotUsed, argc); assert( sqlite3_mutex_held(db->mutex) ); DbClearProperty(db, iDb, DB_Empty); pData->nInitRow++; if( db->mallocFailed ){ - corruptSchema(pData, argv[0], 0); + corruptSchema(pData, argv[1], 0); return 1; } assert( iDb>=0 && iDbnDb ); if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ - if( argv[1]==0 ){ - corruptSchema(pData, argv[0], 0); - }else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){ + if( argv[3]==0 ){ + corruptSchema(pData, argv[1], 0); + }else if( sqlite3_strnicmp(argv[4],"create ",7)==0 ){ /* Call the parser to process a CREATE TABLE, INDEX or VIEW. ** But because db->init.busy is set to 1, no VDBE code is generated ** or executed. All the parser does is build the internal data ** structures that describe the table, index, or view. */ @@ -99,13 +101,14 @@ sqlite3_stmt *pStmt; TESTONLY(int rcp); /* Return code from sqlite3_prepare() */ assert( db->init.busy ); db->init.iDb = iDb; - db->init.newTnum = sqlite3Atoi(argv[1]); + db->init.newTnum = sqlite3Atoi(argv[3]); db->init.orphanTrigger = 0; - TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0); + db->init.azInit = argv; + TESTONLY(rcp = ) sqlite3_prepare(db, argv[4], -1, &pStmt, 0); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */ if( SQLITE_OK!=rc ){ @@ -114,32 +117,32 @@ }else{ pData->rc = rc; if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){ - corruptSchema(pData, argv[0], sqlite3_errmsg(db)); + corruptSchema(pData, argv[1], sqlite3_errmsg(db)); } } } sqlite3_finalize(pStmt); - }else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){ - corruptSchema(pData, argv[0], 0); + }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){ + corruptSchema(pData, argv[1], 0); }else{ /* If the SQL column is blank it means this is an index that ** was created to be the PRIMARY KEY or to fulfill a UNIQUE ** constraint for a CREATE TABLE. The index should have already ** been created when we processed the CREATE TABLE. All we have ** to do here is record the root page number for that index. */ Index *pIndex; - pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName); + pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName); if( pIndex==0 - || sqlite3GetInt32(argv[1],&pIndex->tnum)==0 + || sqlite3GetInt32(argv[3],&pIndex->tnum)==0 || pIndex->tnum<2 || sqlite3IndexHasDuplicateRootPage(pIndex) ){ - corruptSchema(pData, argv[0], pIndex?"invalid rootpage":"orphan index"); + corruptSchema(pData, argv[1], pIndex?"invalid rootpage":"orphan index"); } } return 0; } @@ -156,11 +159,11 @@ int i; #ifndef SQLITE_OMIT_DEPRECATED int size; #endif Db *pDb; - char const *azArg[4]; + char const *azArg[6]; int meta[5]; InitData initData; const char *zMasterName; int openedTransaction = 0; @@ -175,22 +178,24 @@ /* Construct the in-memory representation schema tables (sqlite_master or ** sqlite_temp_master) by invoking the parser directly. The appropriate ** table name will be inserted automatically by the parser so we can just ** use the abbreviation "x" here. The parser will also automatically tag ** the schema table as read-only. */ - azArg[0] = zMasterName = SCHEMA_TABLE(iDb); - azArg[1] = "1"; - azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text," + azArg[0] = "table"; + azArg[1] = zMasterName = SCHEMA_TABLE(iDb); + azArg[2] = azArg[1]; + azArg[3] = "1"; + azArg[4] = "CREATE TABLE x(type text,name text,tbl_name text," "rootpage int,sql text)"; - azArg[3] = 0; + azArg[5] = 0; initData.db = db; initData.iDb = iDb; initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; initData.mInitFlags = mFlags; initData.nInitRow = 0; - sqlite3InitCallback(&initData, 3, (char **)azArg, 0); + sqlite3InitCallback(&initData, 5, (char **)azArg, 0); if( initData.rc ){ rc = initData.rc; goto error_out; } @@ -312,11 +317,11 @@ */ assert( db->init.busy ); { char *zSql; zSql = sqlite3MPrintf(db, - "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid", + "SELECT*FROM\"%w\".%s ORDER BY rowid", db->aDb[iDb].zDbSName, zMasterName); #ifndef SQLITE_OMIT_AUTHORIZATION { sqlite3_xauth xAuth; xAuth = db->xAuth; Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -1396,10 +1396,11 @@ u8 iDb; /* Which db file is being initialized */ u8 busy; /* TRUE if currently initializing */ unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */ unsigned imposterTable : 1; /* Building an imposter table */ unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */ + char **azInit; /* "type", "name", and "tbl_name" columns */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ int nVdbeWrite; /* Number of active VDBEs that read and write */ int nVdbeExec; /* Number of nested calls to VdbeExec() */ @@ -4266,11 +4267,11 @@ Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); Expr *sqlite3ExprSkipCollate(Expr*); int sqlite3CheckCollSeq(Parse *, CollSeq *); int sqlite3WritableSchema(sqlite3*); -int sqlite3CheckObjectName(Parse *, const char *); +int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*); void sqlite3VdbeSetChanges(sqlite3 *, int); int sqlite3AddInt64(i64*,i64); int sqlite3SubInt64(i64*,i64); int sqlite3MulInt64(i64*,i64); int sqlite3AbsInt32(int); Index: src/trigger.c ================================================================== --- src/trigger.c +++ src/trigger.c @@ -175,11 +175,15 @@ } /* Check that the trigger name is not reserved and that no trigger of the ** specified name exists */ zName = sqlite3NameFromToken(db, pName); - if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + if( zName==0 ){ + assert( db->mallocFailed ); + goto trigger_cleanup; + } + if( sqlite3CheckObjectName(pParse, zName, "trigger", pTab->zName) ){ goto trigger_cleanup; } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !IN_RENAME_OBJECT ){ if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -5961,11 +5961,11 @@ initData.db = db; initData.iDb = iDb; initData.pzErrMsg = &p->zErrMsg; initData.mInitFlags = 0; zSql = sqlite3MPrintf(db, - "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid", + "SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid", db->aDb[iDb].zDbSName, zMaster, pOp->p4.z); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ assert( db->init.busy==0 ); Index: test/corruptL.test ================================================================== --- test/corruptL.test +++ test/corruptL.test @@ -226,10 +226,11 @@ | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | end crash.txt.db }]} {} do_execsql_test 2.1 { + PRAGMA writable_schema=ON; -- bypass improved sqlite_master consistency checking INSERT INTO t1(b) VALUES(X'a0fee3669f9fddefc5cba913e4225d4b6ce2b04f26b87fad3ee6f9b7d90a1ea62a169bf41e5d32707a6ca5c3d05e4bde05c9d89eaaa8c50e74333d2e9fcd7dfe95528a3a016aac1102d825c5cd70cf99d8a88e0ea7f798d4334386518b7ad359beb168b93aba059a2a3bd93112d65b44c12b9904ea786b204d80531cdf0504bf9b203dbe927061974caf7b9f30cbc3397b61f802e732012a6663d41c3607d6f1c0dbcfd489adac05ca500c0b04439d894cd93a840159225ef73b627e178b9f84b3ffe66cf22a963a8368813ff7961fc47f573211ccec95e0220dcbb3bf429f4a50ba54d7a53784ac51bfef346e6ac8ae0d0e7c3175946e62ba2b'); } do_catchsql_test 2.2 { SELECT b,c FROM t1 ORDER BY a; @@ -375,10 +376,11 @@ | 496: 02 03 07 04 01 01 01 03 04 02 05 04 09 01 ff fd ................ | end crash-6b48ba69806134.db }]} {} do_catchsql_test 4.1 { + PRAGMA writable_schema=ON; -- bypass improved sqlite_master consistency checking INSERT INTO t3 SELECT * FROM t2; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- @@ -603,11 +605,11 @@ | 3840: 01 59 74 61 62 6c 65 73 71 6c 69 74 65 5f 73 65 .Ytablesqlite_se | 3856: 71 75 65 6e 63 65 73 71 6c 69 74 65 5f 73 65 71 quencesqlite_seq | 3872: 75 65 6e 63 65 04 43 52 45 41 54 45 20 54 41 42 uence.CREATE TAB | 3888: 4c 45 20 73 71 6c 69 74 65 5f 73 65 71 75 65 6e LE sqlite_sequen | 3904: 63 65 28 6e 61 6d 65 2c 73 65 71 29 81 04 01 07 ce(name,seq).... -| 3920: 17 11 11 01 81 73 74 61 c2 6c 65 74 31 74 31 02 .....sta.let1t1. +| 3920: 17 11 11 01 81 73 74 61 62 6c 65 74 31 74 31 02 .....stablet1t1. | 3936: 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 31 28 CREATE TABLE t1( | 3952: 61 20 52 45 41 4c 20 4e 4f 54 20 4e 55 4c 4c 20 a REAL NOT NULL | 3968: 44 45 46 41 55 4c 54 28 32 35 2b 33 32 29 2c 62 DEFAULT(25+32),b | 3984: 20 46 4c 4f 41 54 2c 63 20 44 4f 55 42 4c 45 20 FLOAT,c DOUBLE | 4000: 55 4e 49 51 55 45 2c 0a 64 20 43 4c 4f 42 2c 65 UNIQUE,.d CLOB,e @@ -833,10 +835,11 @@ | end a.db }]} {} do_catchsql_test 8.1 { + PRAGMA writable_schema=ON; -- bypass improved sqlite_master consistency checking INSERT INTO t3 SELECT * FROM t2; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db @@ -1002,10 +1005,11 @@ | 2512: 00 00 00 00 00 00 00 00 aa 00 00 00 00 00 00 00 ................ | end crash-41390d95d613b6.db }]} {} do_catchsql_test 10.1 { + PRAGMA writable_schema=ON; -- bypass improved sqlite_master consistency checking SELECT * FROM t1 WHERE a<='2019-05-09' ORDER BY a DESC; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- @@ -1055,9 +1059,10 @@ | 80: 49 45 74 00 00 00 00 00 00 00 00 00 00 00 00 00 IEt............. | end x.db }]} {} do_catchsql_test 11.1 { + PRAGMA writable_schema=ON; -- bypass improved sqlite_master consistency checking DELETE FROM t3 WHERE x IN (SELECT x FROM t4); } {1 {database disk image is malformed}} finish_test ADDED test/corruptM.test Index: test/corruptM.test ================================================================== --- /dev/null +++ test/corruptM.test @@ -0,0 +1,202 @@ +# 2019-08-12 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Check to ensure that the type, name, and tbl_name fields of the +# sqlite_master table are validated and errors are reported if they +# are inconsistent with the sql. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix corruptM + +# These tests deal with corrupt database files +# +database_may_be_corrupt + +db close +forcedelete test.db +sqlite3 db test.db +do_execsql_test corruptM-100 { + CREATE TABLE t1(a,b,c); + INSERT INTO t1 VALUES(111,222,333); + CREATE INDEX i1 ON t1(b); + CREATE VIEW v2 AS SELECT 15,22; + CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN SELECT 5; END; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 t1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} +do_execsql_test corruptM-101 { + PRAGMA writable_schema=on; + UPDATE sqlite_master SET tbl_name=NULL WHERE name='t1'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 {} | index i1 t1 | view v2 v2 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-102 { + catchsql { + PRAGMA quick_check; + } db2 +} {1 {malformed database schema (t1)}} +db2 close + +do_execsql_test corruptM-110 { + UPDATE sqlite_master SET tbl_name='tx' WHERE name='t1'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 tx | index i1 t1 | view v2 v2 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-111 { + catchsql { + PRAGMA quick_check; + } db2 +} {1 {malformed database schema (t1)}} +db2 close +do_execsql_test corruptM-112 { + UPDATE sqlite_master SET tbl_name='t1', type='tabl' WHERE name='t1'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {tabl t1 t1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-113 { + catchsql { + PRAGMA quick_check; + } db2 +} {1 {malformed database schema (t1)}} +db2 close +do_execsql_test corruptM-114 { + UPDATE sqlite_master SET tbl_name='t9',type='table',name='t9'WHERE name='t1'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t9 t9 | index i1 t1 | view v2 v2 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-114 { + catchsql { + PRAGMA quick_check; + } db2 +} {1 {malformed database schema (t9)}} +db2 close + +do_execsql_test corruptM-120 { + UPDATE sqlite_master SET name='t1',tbl_name='T1' WHERE name='t9'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 T1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-121 { + catchsql { + PRAGMA quick_check; + SELECT * FROM t1, v2; + } db2 +} {0 {ok 111 222 333 15 22}} +db2 close + +do_execsql_test corruptM-130 { + UPDATE sqlite_master SET type='view' WHERE name='t1'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {view t1 T1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-131 { + catchsql { + PRAGMA quick_check; + SELECT * FROM t1, v2; + } db2 +} {1 {malformed database schema (t1)}} +db2 close + +do_execsql_test corruptM-140 { + UPDATE sqlite_master SET type='table', tbl_name='t1' WHERE name='t1'; + UPDATE sqlite_master SET tbl_name='tx' WHERE name='i1'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 t1 | index i1 tx | view v2 v2 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-141 { + catchsql { + PRAGMA quick_check; + SELECT * FROM t1, v2; + } db2 +} {1 {malformed database schema (i1)}} +db2 close + +do_execsql_test corruptM-150 { + UPDATE sqlite_master SET type='table', tbl_name='t1' WHERE name='i1'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 t1 | table i1 t1 | view v2 v2 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-151 { + catchsql { + PRAGMA quick_check; + SELECT * FROM t1, v2; + } db2 +} {1 {malformed database schema (i1)}} +db2 close + +do_execsql_test corruptM-160 { + UPDATE sqlite_master SET type='view', tbl_name='t1' WHERE name='i1'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 t1 | view i1 t1 | view v2 v2 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-161 { + catchsql { + PRAGMA quick_check; + SELECT * FROM t1, v2; + } db2 +} {1 {malformed database schema (i1)}} +db2 close + +do_execsql_test corruptM-170 { + UPDATE sqlite_master SET type='index', tbl_name='t1' WHERE name='i1'; + UPDATE sqlite_master SET type='table', tbl_name='v2' WHERE name='v2'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 t1 | index i1 t1 | table v2 v2 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-171 { + catchsql { + PRAGMA quick_check; + SELECT * FROM t1, v2; + } db2 +} {1 {malformed database schema (v2)}} +db2 close + +do_execsql_test corruptM-180 { + UPDATE sqlite_master SET type='view',name='v3',tbl_name='v3' WHERE name='v2'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 t1 | index i1 t1 | view v3 v3 | trigger r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-181 { + catchsql { + PRAGMA quick_check; + SELECT * FROM t1, v2; + } db2 +} {1 {malformed database schema (v3)}} +db2 close + +do_execsql_test corruptM-190 { + UPDATE sqlite_master SET type='view',name='v2',tbl_name='v2' WHERE name='v3'; + UPDATE sqlite_master SET type='view' WHERE name='r1'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 t1 | index i1 t1 | view v2 v2 | view r1 t1 |} +sqlite3 db2 test.db +do_test corruptM-191 { + catchsql { + PRAGMA quick_check; + SELECT * FROM t1, v2; + } db2 +} {1 {malformed database schema (r1)}} +db2 close +do_execsql_test corruptM-192 { + UPDATE sqlite_master SET type='trigger',tbl_name='v2' WHERE name='r1'; + SELECT type, name, tbl_name, '|' FROM sqlite_master; +} {table t1 t1 | index i1 t1 | view v2 v2 | trigger r1 v2 |} +sqlite3 db2 test.db +do_test corruptM-193 { + catchsql { + PRAGMA quick_check; + SELECT * FROM t1, v2; + } db2 +} {1 {malformed database schema (r1)}} +db2 close + +finish_test Index: test/dbfuzz001.test ================================================================== --- test/dbfuzz001.test +++ test/dbfuzz001.test @@ -303,11 +303,11 @@ | 352: 64 65 78 74 32 63 64 74 32 05 43 52 45 41 54 45 dext2cdt2.CREATE | 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t | 384: 32 28 63 2c 64 29 28 05 06 17 11 11 01 3d 74 61 2(c,d)(......=ta | 400: 62 6c 65 74 33 74 33 07 43 52 45 41 54 45 20 54 blet3t3.CREATE T | 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f) -| 432: 28 02 06 17 11 11 01 3d 74 61 74 65 6c 03 62 74 (......=tatel.bt +| 432: 28 02 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (......=tablet2t | 448: 32 32 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 22CREATE TABLE t | 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$..... | 480: 01 35 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .5tablet1t1.CREA | 496: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 29 TE TABLE t1(a,b) | page 2 offset 512