diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 6 | ||||
-rw-r--r-- | src/build.c | 11 | ||||
-rw-r--r-- | src/main.c | 25 | ||||
-rw-r--r-- | src/shell.c | 8 | ||||
-rw-r--r-- | src/sqlite.h.in | 2 | ||||
-rw-r--r-- | src/sqliteInt.h | 1 | ||||
-rw-r--r-- | src/test1.c | 17 |
7 files changed, 48 insertions, 22 deletions
diff --git a/src/btree.c b/src/btree.c index f9f76c2eb..eb5151351 100644 --- a/src/btree.c +++ b/src/btree.c @@ -175,6 +175,12 @@ static int hasSharedCacheTableLock( for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){ Index *pIdx = (Index *)sqliteHashData(p); if( pIdx->tnum==(int)iRoot ){ + if( iTab ){ + /* Two or more indexes share the same root page. There must + ** be imposter tables. So just return true. The assert is not + ** useful in that case. */ + return 1; + } iTab = pIdx->pTable->tnum; } } diff --git a/src/build.c b/src/build.c index f02989bff..7e3ce1b76 100644 --- a/src/build.c +++ b/src/build.c @@ -1731,11 +1731,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ assert( pPk!=0 ); nPk = pPk->nKeyCol; - /* Make sure every column of the PRIMARY KEY is NOT NULL */ - for(i=0; i<nPk; i++){ - pTab->aCol[pPk->aiColumn[i]].notNull = 1; + /* Make sure every column of the PRIMARY KEY is NOT NULL. (Except, + ** do not enforce this for imposter tables.) */ + if( !db->init.imposterTable ){ + for(i=0; i<nPk; i++){ + pTab->aCol[pPk->aiColumn[i]].notNull = 1; + } + pPk->uniqNotNull = 1; } - pPk->uniqNotNull = 1; /* The root page of the PRIMARY KEY is the table root page */ pPk->tnum = pTab->tnum; diff --git a/src/main.c b/src/main.c index 0d6f1be24..11585e7dc 100644 --- a/src/main.c +++ b/src/main.c @@ -3599,15 +3599,30 @@ int sqlite3_test_control(int op, ...){ break; } - /* sqlite3_test_control(SQLITE_TESTCTRL_INITMODE, db, busy, iDb, newTnum); + /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); ** - ** Set the db->init.busy, db->init.iDb, and db->init.tnum fields. + ** This test control is used to create imposter tables. "db" is a pointer + ** to the database connection. dbName is the database name (ex: "main" or + ** "temp") which will receive the imposter. "onOff" turns imposter mode on + ** or off. "tnum" is the root page of the b-tree to which the imposter + ** table should connect. + ** + ** Enable imposter mode only when the schema has already been parsed. Then + ** run a single CREATE TABLE statement to construct the imposter table in the + ** parsed schema. Then turn imposter mode back off again. + ** + ** If onOff==0 and tnum>0 then reset the schema for all databases, causing + ** the schema to be reparsed the next time it is needed. This has the + ** effect of erasing all imposter tables. */ - case SQLITE_TESTCTRL_INITMODE: { + case SQLITE_TESTCTRL_IMPOSTER: { sqlite3 *db = va_arg(ap, sqlite3*); - db->init.busy = va_arg(ap,int); - db->init.iDb = va_arg(ap,int); + db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*)); + db->init.busy = db->init.imposterTable = va_arg(ap,int); db->init.newTnum = va_arg(ap,int); + if( db->init.busy==0 && db->init.newTnum>0 ){ + sqlite3ResetAllSchemasOfConnection(db); + } break; } } diff --git a/src/shell.c b/src/shell.c index 1a191e0fd..3130f4c6d 100644 --- a/src/shell.c +++ b/src/shell.c @@ -3536,7 +3536,7 @@ static int do_meta_command(char *zLine, ShellState *p){ { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC }, { "byteorder", SQLITE_TESTCTRL_BYTEORDER }, { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT }, - { "initmode", SQLITE_TESTCTRL_INITMODE }, + { "imposter", SQLITE_TESTCTRL_IMPOSTER }, }; int testctrl = -1; int rc = 0; @@ -3629,14 +3629,14 @@ static int do_meta_command(char *zLine, ShellState *p){ break; #endif - case SQLITE_TESTCTRL_INITMODE: + case SQLITE_TESTCTRL_IMPOSTER: if( nArg==5 ){ rc = sqlite3_test_control(testctrl, p->db, - integerValue(azArg[2]), + azArg[2], integerValue(azArg[3]), integerValue(azArg[4])); }else{ - fprintf(stderr,"Usage: .testctrl initmode fBusy iDb newTnum\n"); + fprintf(stderr,"Usage: .testctrl initmode dbName onoff tnum\n"); rc = 1; } break; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 722b9235a..f256cea45 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6260,7 +6260,7 @@ int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_SORTER_MMAP 24 -#define SQLITE_TESTCTRL_INITMODE 25 +#define SQLITE_TESTCTRL_IMPOSTER 25 #define SQLITE_TESTCTRL_LAST 25 /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 379456d5f..0bc6f679d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1087,6 +1087,7 @@ struct sqlite3 { u8 iDb; /* Which db file is being initialized */ u8 busy; /* TRUE if currently initializing */ u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ + u8 imposterTable; /* Building an imposter table */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ diff --git a/src/test1.c b/src/test1.c index b9503cf39..a87fcd859 100644 --- a/src/test1.c +++ b/src/test1.c @@ -5915,7 +5915,7 @@ static int test_test_control( } aVerb[] = { { "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT }, { "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP }, - { "SQLITE_TESTCTRL_INITMODE", SQLITE_TESTCTRL_INITMODE }, + { "SQLITE_TESTCTRL_IMPOSTER", SQLITE_TESTCTRL_IMPOSTER }, }; int iVerb; int iFlag; @@ -5957,18 +5957,19 @@ static int test_test_control( break; } - case SQLITE_TESTCTRL_INITMODE: { - int fBusy, iDb, newTnum; + case SQLITE_TESTCTRL_IMPOSTER: { + int onOff, tnum; + const char *zDbName; sqlite3 *db; if( objc!=6 ){ - Tcl_WrongNumArgs(interp, 2, objv, "DB fBusy iDb newTnum"); + Tcl_WrongNumArgs(interp, 2, objv, "DB dbName onOff tnum"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR; - if( Tcl_GetIntFromObj(interp, objv[3], &fBusy) ) return TCL_ERROR; - if( Tcl_GetIntFromObj(interp, objv[4], &iDb) ) return TCL_ERROR; - if( Tcl_GetIntFromObj(interp, objv[5], &newTnum) ) return TCL_ERROR; - sqlite3_test_control(SQLITE_TESTCTRL_INITMODE, db, fBusy, iDb, newTnum); + zDbName = Tcl_GetString(objv[3]); + if( Tcl_GetIntFromObj(interp, objv[4], &onOff) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[5], &tnum) ) return TCL_ERROR; + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zDbName, onOff, tnum); break; } } |