From 234c39dff7d87225380cb97fc34c2807ad71ec12 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 24 Jul 2004 03:30:47 +0000 Subject: [PATCH] Progress towards getting prepared statements and CREATE and DROP to play nicely together. Work is incomplete. Some tests are known to fail. (CVS 1864) FossilOrigin-Name: 49b991492496e104f5eca620a5d465a742b7ff3a --- manifest | 24 ++++---- manifest.uuid | 2 +- src/build.c | 124 ++++++++++++++++----------------------- src/main.c | 150 +++++++++++++++++++----------------------------- src/sqliteInt.h | 13 ++++- src/tokenize.c | 8 ++- src/vdbe.c | 54 ++++++++++++----- test/misc4.test | 27 ++++++++- test/table.test | 36 ++++++------ 9 files changed, 223 insertions(+), 215 deletions(-) diff --git a/manifest b/manifest index b0e9b76d97..dc739a9826 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C First\scut\sat\sa\sanalysis\stool\sfor\sversion\s3.0\sdatabases.\s(CVS\s1862) -D 2004-07-23T00:01:39 +C Progress\stowards\sgetting\sprepared\sstatements\sand\sCREATE\sand\sDROP\sto\splay\nnicely\stogether.\s\sWork\sis\sincomplete.\s\sSome\stests\sare\sknown\sto\sfail.\s(CVS\s1864) +D 2004-07-24T03:30:48 F Makefile.in 4a5e570a9e2d35b09c31b3cf01b78cea764ade4b F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -29,7 +29,7 @@ F src/attach.c 784456629b3d7e50e4691f496700658fd1f16441 F src/auth.c 60db23b98bb94c8b0178180faaf49dc116674217 F src/btree.c edf4ece708350dec7f28ebd4620c6d33afe6993a F src/btree.h 94dfec0a1722d33359b23e7e310f2b64ffedf029 -F src/build.c 3a1356286569266873d5d1c910e7797a3bfd5761 +F src/build.c d1870caf93cce22e6991116e39cf5c05c73882ee F src/date.c e1bb384a7856c18dce9cadb0afbe6934ba5ddb00 F src/delete.c e81545e546f6bc87d7508a93a09ca70695265af3 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 @@ -39,7 +39,7 @@ F src/hash.c f0a2f22c2a7052d67053b5f4690ea3010bb3fb9f F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb F src/insert.c d99ffe87e1e1397f4233afcd06841d52d6b17b18 F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f -F src/main.c 447db2fb6121360814afd725ee93c22d6eef8e7f +F src/main.c c4ba7d8f674d7c880e2e0deea16432d63defa5b2 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 F src/os.h d1780e0db95cad01f213d48da22ab490eb4fd345 F src/os_common.h fe9604754116bd2f2702d58f82d2d8b89998cb21 @@ -60,7 +60,7 @@ F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c aefda626660086addca4ce85c34aeef5d0f44c25 F src/shell.c 93c96c847228c02fb84bb381875d87ee71fbbeb4 F src/sqlite.h.in 80de11cde2c9f78eff4dab0aad1eb5196d6e2a3f -F src/sqliteInt.h 049cb4f716f7b7ea3657f26c7e26a4f821aca53c +F src/sqliteInt.h 8cf9cf4bd02dacedbf3738ecfad49ea32e599e47 F src/table.c 4521c278892f60e4d630788c0ea5cf4db1e75c49 F src/tclsqlite.c 3ce001b3c301876a9c8163472077a4c10e0d49f3 F src/test1.c ef00096c283ccfec1b2ae5fdaccb85fb06e24281 @@ -68,13 +68,13 @@ F src/test2.c f4c2f3928f1998fd8cb75a81e33a60e025ea85d4 F src/test3.c 94d0a2a90bccd85802488cb42c69ec8afd2e4646 F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2 F src/test5.c b001fa7f1b9e2dc5c2331de62fc641b5ab2bd7a1 -F src/tokenize.c 900374b6b37f04748bcd48c2d29a41c251542935 +F src/tokenize.c 368c1c6eb11355188fc4423e77c1708856b16c9b F src/trigger.c 6aaf6d79cc2157c70a06031dd1531707d644cfb4 F src/update.c b66b1896c9da54678ba3eff2bf0b4d291a95986a F src/utf.c f03535db72bfa09e24202ccdd245f21d2fc65f0a F src/util.c 2aacc79b7bf5df5859813dafd3bf3258f67a5234 F src/vacuum.c b8546f4921719458cc537b9e736df52a8256399c -F src/vdbe.c 5a7d1ee9d7356df6b53be64c1776824a33f6f2fb +F src/vdbe.c 5d35f08682878165bfba796b298fe3615ae9c9fc F src/vdbe.h 75b241c02431b9c0f16eaa9cdbb34146c6287f52 F src/vdbeInt.h 7160653a006b6d2c4a00d204112a095bdf842ab6 F src/vdbeapi.c c5c6d8f162a9581dde497b1a4034f9a0bf54c355 @@ -140,7 +140,7 @@ F test/minmax.test 6513f9a1bb85fd35ff72b34b7b6634fad6b1e69c F test/misc1.test 72768ec8cabc952a4cfcddca43d566f9e0bce899 F test/misc2.test 703734f5817215ca54e364833b3bf5ff36fcc21e F test/misc3.test eb488314990bfc0959221a1acc465013238bf168 -F test/misc4.test 9e4291bb174e4357459e0b080f7ca9c6733150c9 +F test/misc4.test e941a0918df0bf3ab42563e35970d98288ddddf7 F test/misuse.test 2a64ce711419f2fd12806ed95af930fd4e7bb8f3 F test/notnull.test 7a08117a71e74b0321aaa937dbeb41a09d6eb1d0 F test/null.test c14d0f4739f21e929b8115b72bf0c765b6bb1721 @@ -161,7 +161,7 @@ F test/select5.test 3f3f0f31e674fa61f8a3bdb6af1517dfae674081 F test/select6.test a9e31906e700e7c7592c4d0acfc022808f718baf F test/sort.test 30fb9ea782a78da849a562d53233ec62d421bf61 F test/subselect.test cca16490d78613174bf90a8416fc21a383ec7c71 -F test/table.test b6d07f04c4157d1f2a37fb7febe36b250d468e31 +F test/table.test fd9a0f4992230e4ca89cd37ae3191a12750df1d0 F test/tableapi.test b21ab097e87a5484bb61029e69e1a4e5c5e65ede F test/tclsqlite.test 0ef39b0228a32601432cec20208ec4b35e9b5cdb F test/temptable.test 63a16e3ad19adf073cfbcdf7624c92ac5236522c @@ -240,7 +240,7 @@ F www/tclsqlite.tcl 06a86cba4d7fc88e2bcd633b57702d3d16abebb5 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 15774aab7d20eb4dfcb47378c8255e26b8cbbe19 -R 1451250ebcf80a0882a7e76f969566bf +P 7c7f698b2eda7b1b34f5ca7fe104145d8bbd8f56 +R b1b16f99b3da9325a0228f34d4f42233 U drh -Z af23712a2660f12a62a563c7e13af761 +Z b40eb69ee75bee6f41ad47e71f93841a diff --git a/manifest.uuid b/manifest.uuid index 0cd7ca1e25..8574843cd9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7c7f698b2eda7b1b34f5ca7fe104145d8bbd8f56 \ No newline at end of file +49b991492496e104f5eca620a5d465a742b7ff3a \ No newline at end of file diff --git a/src/build.c b/src/build.c index 7f27985f24..09427a9c3f 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.240 2004/07/22 01:19:35 drh Exp $ +** $Id: build.c,v 1.241 2004/07/24 03:30:48 drh Exp $ */ #include "sqliteInt.h" #include @@ -231,8 +231,8 @@ void sqlite3UnlinkAndDeleteIndex(sqlite *db, Index *pIndex){ /* ** Erase all schema information from the in-memory hash tables of -** a sigle database. This routine is called to reclaim memory -** before the closes. It is also called during a rollback +** a single database. This routine is called to reclaim memory +** before the database closes. It is also called during a rollback ** if there were schema changes during the transaction or if a ** schema-cookie mismatch occurs. ** @@ -1169,14 +1169,16 @@ void sqlite3ChangeCookie(sqlite *db, Vdbe *v, int iDb){ ** Measure the number of characters needed to output the given ** identifier. The number returned includes any quotes used ** but does not include the null terminator. +** +** The estimate is conservative. It might be larger that what is +** really needed. */ static int identLength(const char *z){ int n; - int needQuote = 0; for(n=0; *z; n++, z++){ - if( *z=='\'' ){ n++; needQuote=1; } + if( *z=='"' ){ n++; } } - return n + needQuote*2; + return n + 2; } /* @@ -1191,12 +1193,12 @@ static void identPut(char *z, int *pIdx, char *zIdent){ } needQuote = zIdent[j]!=0 || isdigit(zIdent[0]) || sqlite3KeywordCode(zIdent, j)!=TK_ID; - if( needQuote ) z[i++] = '\''; + if( needQuote ) z[i++] = '"'; for(j=0; zIdent[j]; j++){ z[i++] = zIdent[j]; - if( zIdent[j]=='\'' ) z[i++] = '\''; + if( zIdent[j]=='"' ) z[i++] = '"'; } - if( needQuote ) z[i++] = '\''; + if( needQuote ) z[i++] = '"'; z[i] = 0; *pIdx = i; } @@ -1209,16 +1211,18 @@ static void identPut(char *z, int *pIdx, char *zIdent){ static char *createTableStmt(Table *p){ int i, k, n; char *zStmt; - char *zSep, *zSep2, *zEnd; + char *zSep, *zSep2, *zEnd, *z; + Column *pCol; n = 0; - for(i=0; inCol; i++){ - n += identLength(p->aCol[i].zName); - if( p->aCol[i].zType ){ - n += (strlen(p->aCol[i].zType) + 1); + for(pCol = p->aCol, i=0; inCol; i++, pCol++){ + n += identLength(pCol->zName); + z = pCol->zType; + if( z ){ + n += (strlen(z) + 1); } } n += identLength(p->zName); - if( n<40 ){ + if( n<50 ){ zSep = ""; zSep2 = ","; zEnd = ")"; @@ -1234,15 +1238,15 @@ static char *createTableStmt(Table *p){ k = strlen(zStmt); identPut(zStmt, &k, p->zName); zStmt[k++] = '('; - for(i=0; inCol; i++){ + for(pCol=p->aCol, i=0; inCol; i++, pCol++){ strcpy(&zStmt[k], zSep); k += strlen(&zStmt[k]); zSep = zSep2; - identPut(zStmt, &k, p->aCol[i].zName); - if( p->aCol[i].zType ){ + identPut(zStmt, &k, pCol->zName); + if( (z = pCol->zType)!=0 ){ zStmt[k++] = ' '; - strcpy(&zStmt[k], p->aCol[i].zType); - k += strlen(p->aCol[i].zType); + strcpy(&zStmt[k], z); + k += strlen(z); } } strcpy(&zStmt[k], zEnd); @@ -1305,12 +1309,11 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){ if( p->pSelect==0 ){ /* A regular table */ - sqlite3VdbeOp3(v, OP_CreateTable, 0, p->iDb, (char*)&p->tnum, P3_POINTER); + sqlite3VdbeAddOp(v, OP_CreateTable, p->iDb, 0); }else{ /* A view */ sqlite3VdbeAddOp(v, OP_Integer, 0, 0); } - p->tnum = 0; sqlite3VdbeAddOp(v, OP_Close, 0, 0); @@ -1371,13 +1374,15 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){ sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0); sqlite3ChangeCookie(db, v, p->iDb); sqlite3VdbeAddOp(v, OP_Close, 0, 0); + sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0, + sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC); sqlite3EndWriteOperation(pParse); } /* Add the table to the in-memory representation of the database. */ - if( pParse->explain==0 && pParse->nErr==0 ){ + if( db->init.busy && pParse->nErr==0 ){ Table *pOld; FKey *pFKey; pOld = sqlite3HashInsert(&db->aDb[p->iDb].tblHash, @@ -1565,26 +1570,6 @@ static void sqliteViewResetAll(sqlite *db, int idx){ DbClearProperty(db, idx, DB_UnresetViews); } -#if 0 -/* -** Given a token, look up a table with that name. If not found, leave -** an error for the parser to find and return NULL. -*/ -Table *sqlite3TableFromToken(Parse *pParse, Token *pTok){ - char *zName; - Table *pTab; - zName = sqlite3NameFromToken(pTok); - if( zName==0 ) return 0; - pTab = sqlite3FindTable(pParse->db, zName, 0); - sqliteFree(zName); - if( pTab==0 ){ - sqlite3ErrorMsg(pParse, "no such table: %T", pTok); - pParse->checkSchema = 1; - } - return pTab; -} -#endif - /* ** This routine is called to do the work of a DROP TABLE statement. ** pName is the name of the table to be dropped. @@ -2099,7 +2084,7 @@ void sqlite3CreateIndex( /* Link the new Index structure to its table and to the other ** in-memory database structures. */ - if( !pParse->explain ){ + if( db->init.busy ){ Index *p; p = sqlite3HashInsert(&db->aDb[pIndex->iDb].idxHash, pIndex->zName, strlen(pIndex->zName)+1, pIndex); @@ -2108,14 +2093,9 @@ void sqlite3CreateIndex( goto exit_create_index; } db->flags |= SQLITE_InternChanges; - } - - /* If the db->init.busy is 1 it means we are reading the SQL off the - ** "sqlite_master" table on the disk. So do not write to the disk - ** again. Extract the table number from the db->init.newTnum field. - */ - if( db->init.busy && pTblName!=0 ){ - pIndex->tnum = db->init.newTnum; + if( pTblName!=0 ){ + pIndex->tnum = db->init.newTnum; + } } /* If the db->init.busy is 0 then create the index on disk. This @@ -2148,8 +2128,7 @@ void sqlite3CreateIndex( sqlite3VdbeOp3(v, OP_String8, 0, 0, "index", P3_STATIC); sqlite3VdbeOp3(v, OP_String8, 0, 0, pIndex->zName, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); - sqlite3VdbeOp3(v, OP_CreateIndex, 0, iDb,(char*)&pIndex->tnum,P3_POINTER); - pIndex->tnum = 0; + sqlite3VdbeAddOp(v, OP_CreateIndex, iDb, 0); if( pTblName ){ sqlite3VdbeAddOp(v, OP_Dup, 0, 0); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); @@ -2185,11 +2164,11 @@ void sqlite3CreateIndex( sqlite3VdbeResolveLabel(v, lbl2); sqlite3VdbeAddOp(v, OP_Close, 2, 0); sqlite3VdbeAddOp(v, OP_Close, 1, 0); - } - if( pTblName!=0 ){ sqlite3ChangeCookie(db, v, iDb); sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3EndWriteOperation(pParse); + sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, + sqlite3MPrintf("name='%q'", pIndex->zName), P3_DYNAMIC); } } @@ -2198,19 +2177,21 @@ void sqlite3CreateIndex( ** OE_Ignore. This is necessary for the correct operation of UPDATE ** and INSERT. */ - if( onError!=OE_Replace || pTab->pIndex==0 - || pTab->pIndex->onError==OE_Replace){ - pIndex->pNext = pTab->pIndex; - pTab->pIndex = pIndex; - }else{ - Index *pOther = pTab->pIndex; - while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ - pOther = pOther->pNext; + if( db->init.busy || pTblName==0 ){ + if( onError!=OE_Replace || pTab->pIndex==0 + || pTab->pIndex->onError==OE_Replace){ + pIndex->pNext = pTab->pIndex; + pTab->pIndex = pIndex; + }else{ + Index *pOther = pTab->pIndex; + while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ + pOther = pOther->pNext; + } + pIndex->pNext = pOther->pNext; + pOther->pNext = pIndex; } - pIndex->pNext = pOther->pNext; - pOther->pNext = pIndex; + pIndex = 0; } - pIndex = 0; /* Clean up before exiting */ exit_create_index: @@ -2244,13 +2225,6 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){ "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; } -/* - if( pIndex->iDb>1 ){ - sqlite3ErrorMsg(pParse, "cannot alter schema of attached " - "databases", 0); - goto exit_drop_index; - } -*/ #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; @@ -2272,7 +2246,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){ if( v ){ static VdbeOpList dropIndex[] = { { OP_Rewind, 0, ADDR(9), 0}, - { OP_String8, 0, 0, 0}, /* 1 */ + { OP_String8, 0, 0, 0}, /* 1 */ { OP_MemStore, 1, 1, 0}, { OP_MemLoad, 1, 0, 0}, /* 3 */ { OP_Column, 0, 1, 0}, diff --git a/src/main.c b/src/main.c index 24a4c19c49..f6cce31c69 100644 --- a/src/main.c +++ b/src/main.c @@ -14,21 +14,12 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.246 2004/07/22 01:19:35 drh Exp $ +** $Id: main.c,v 1.247 2004/07/24 03:30:48 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include -/* -** A pointer to this structure is used to communicate information -** from sqlite3Init into the sqlite3InitCallback. -*/ -typedef struct { - sqlite *db; /* The database being initialized */ - char **pzErrMsg; /* Error message stored here */ -} InitData; - /* ** The following constant value is used by the SQLITE_BIGENDIAN and ** SQLITE_LITTLEENDIAN macros. @@ -49,89 +40,69 @@ static void corruptSchema(InitData *pData, const char *zExtra){ /* ** This is the callback routine for the code that initializes the ** 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] = "table" or "index" or "view" or "trigger" -** argv[1] = name of thing being created -** argv[2] = root page number for table or index. NULL for trigger or view. -** argv[3] = SQL text for the CREATE statement. -** argv[4] = "1" for temporary files, "0" for main database, "2" or more +** argv[0] = name of thing being created +** argv[1] = root page number for table or index. NULL for trigger or view. +** argv[2] = SQL text for the CREATE statement. +** argv[3] = "1" for temporary files, "0" for main database, "2" or more ** for auxiliary database files. ** */ -static int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ InitData *pData = (InitData*)pInit; - int nErr = 0; + sqlite *db = pData->db; + int iDb; - assert( argc==5 ); + assert( argc==4 ); if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ - if( argv[0]==0 ){ + if( argv[1]==0 || argv[3]==0 ){ corruptSchema(pData, 0); return 1; } - switch( argv[0][0] ){ - case 'v': - case 'i': - case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */ - sqlite *db = pData->db; - if( argv[2]==0 || argv[4]==0 ){ - corruptSchema(pData, 0); - return 1; - } - if( argv[3] && argv[3][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. - */ - char *zErr; - int rc; - assert( db->init.busy ); - db->init.iDb = atoi(argv[4]); - assert( db->init.iDb>=0 && db->init.iDbnDb ); - db->init.newTnum = atoi(argv[2]); - rc = sqlite3_exec(db, argv[3], 0, 0, &zErr); - db->init.iDb = 0; - if( SQLITE_OK!=rc ){ - corruptSchema(pData, zErr); - sqlite3_free(zErr); - return rc; - } - }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. - */ - int iDb; - Index *pIndex; - - iDb = atoi(argv[4]); - assert( iDb>=0 && iDbnDb ); - pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zName); - if( pIndex==0 || pIndex->tnum!=0 ){ - /* This can occur if there exists an index on a TEMP table which - ** has the same name as another index on a permanent index. Since - ** the permanent table is hidden by the TEMP table, we can also - ** safely ignore the index on the permanent table. - */ - /* Do Nothing */; - }else{ - pIndex->tnum = atoi(argv[2]); - } - } + iDb = atoi(argv[3]); + assert( iDb>=0 && iDbnDb ); + if( argv[2] && argv[2][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. + */ + char *zErr; + int rc; + assert( db->init.busy ); + db->init.iDb = iDb; + db->init.newTnum = atoi(argv[1]); + rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); + db->init.iDb = 0; + if( SQLITE_OK!=rc ){ + corruptSchema(pData, zErr); + sqlite3_free(zErr); + return rc; } - break; - default: { - /* This can not happen! */ - nErr = 1; - assert( nErr==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].zName); + if( pIndex==0 || pIndex->tnum!=0 ){ + /* This can occur if there exists an index on a TEMP table which + ** has the same name as another index on a permanent index. Since + ** the permanent table is hidden by the TEMP table, we can also + ** safely ignore the index on the permanent table. + */ + /* Do Nothing */; + }else{ + pIndex->tnum = atoi(argv[1]); } } - return nErr; + return 0; } /* @@ -147,7 +118,7 @@ static int sqlite3InitOne(sqlite *db, int iDb, char **pzErrMsg){ BtCursor *curMain; int size; Table *pTab; - char const *azArg[6]; + char const *azArg[5]; char zDbNum[30]; int meta[10]; InitData initData; @@ -192,16 +163,15 @@ static int sqlite3InitOne(sqlite *db, int iDb, char **pzErrMsg){ /* Construct the schema tables. */ sqlite3SafetyOff(db); - azArg[0] = "table"; - azArg[1] = zMasterName; - azArg[2] = "1"; - azArg[3] = zMasterSchema; + azArg[0] = zMasterName; + azArg[1] = "1"; + azArg[2] = zMasterSchema; sprintf(zDbNum, "%d", iDb); - azArg[4] = zDbNum; - azArg[5] = 0; + azArg[3] = zDbNum; + azArg[4] = 0; initData.db = db; initData.pzErrMsg = pzErrMsg; - rc = sqlite3InitCallback(&initData, 5, (char **)azArg, 0); + rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0); if( rc!=SQLITE_OK ){ sqlite3SafetyOn(db); return rc; @@ -304,14 +274,14 @@ static int sqlite3InitOne(sqlite *db, int iDb, char **pzErrMsg){ /* For an empty database, there is nothing to read */ rc = SQLITE_OK; }else{ - char *zSql = 0; + char *zSql; + zSql = sqlite3MPrintf( + "SELECT name, rootpage, sql, %s FROM '%q'.%s", + zDbNum, db->aDb[iDb].zName, zMasterName); sqlite3SafetyOff(db); - sqlite3SetString(&zSql, - "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"", - db->aDb[iDb].zName, "\".", zMasterName, (char*)0); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); - sqliteFree(zSql); sqlite3SafetyOn(db); + sqliteFree(zSql); sqlite3BtreeCloseCursor(curMain); } if( sqlite3_malloc_failed ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d6cde4e5e5..cdab05c9a3 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.308 2004/07/22 15:02:25 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.309 2004/07/24 03:30:48 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1159,6 +1159,16 @@ struct DbFixer { const Token *pName; /* Name of the container - used for error messages */ }; +/* +** A pointer to this structure is used to communicate information +** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback. +*/ +typedef struct { + sqlite *db; /* The database being initialized */ + char **pzErrMsg; /* Error message stored here */ +} InitData; + + /* * This global flag is set for performance testing of triggers. When it is set * SQLite will perform the overhead of building new and old trigger references @@ -1210,6 +1220,7 @@ void sqlite3ExprDelete(Expr*); ExprList *sqlite3ExprListAppend(ExprList*,Expr*,Token*); void sqlite3ExprListDelete(ExprList*); int sqlite3Init(sqlite*, char**); +int sqlite3InitCallback(void*, int, char**, char**); void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); void sqlite3ResetInternalSchema(sqlite*, int); void sqlite3BeginParse(Parse*,int); diff --git a/src/tokenize.c b/src/tokenize.c index 8600cc6fd0..dde809146c 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.78 2004/06/18 06:02:35 danielk1977 Exp $ +** $Id: tokenize.c,v 1.79 2004/07/24 03:30:48 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -431,6 +431,11 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ sqlite3SetString(pzErrMsg, "out of memory", (char*)0); return 1; } +#ifndef NDEBUG + if( sqlite3OsFileExists("vdbe_sqltrace") ){ + printf("SQL To Compiler: [%s]\n", zSql); + } +#endif pParse->sLastToken.dyn = 0; pParse->zTail = zSql; while( sqlite3_malloc_failed==0 && zSql[i]!=0 ){ @@ -714,4 +719,3 @@ int sqlite3_complete16(const void *zSql){ sqlite3ValueFree(pVal); return rc; } - diff --git a/src/vdbe.c b/src/vdbe.c index beeae2d7c7..12e0978b3c 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.403 2004/07/21 02:53:30 drh Exp $ +** $Id: vdbe.c,v 1.404 2004/07/24 03:30:48 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -3670,24 +3670,19 @@ case OP_Clear: { break; } -/* Opcode: CreateTable * P2 P3 +/* Opcode: CreateTable P1 * * ** ** Allocate a new table in the main database file if P2==0 or in the ** auxiliary database file if P2==1. Push the page number ** for the root page of the new table onto the stack. ** -** The root page number is also written to a memory location that P3 -** points to. This is the mechanism is used to write the root page -** number into the parser's internal data structures that describe the -** new table. -** ** The difference between a table and an index is this: A table must ** have a 4-byte integer key and can have arbitrary data. An index ** has an arbitrary key but no data. ** ** See also: CreateIndex */ -/* Opcode: CreateIndex * P2 P3 +/* Opcode: CreateIndex P1 * * ** ** Allocate a new index in the main database file if P2==0 or in the ** auxiliary database file if P2==1. Push the page number of the @@ -3699,28 +3694,59 @@ case OP_CreateIndex: case OP_CreateTable: { int pgno; int flags; - assert( pOp->p3!=0 && pOp->p3type==P3_POINTER ); - assert( pOp->p2>=0 && pOp->p2nDb ); - assert( db->aDb[pOp->p2].pBt!=0 ); + Db *pDb; + assert( pOp->p1>=0 && pOp->p1nDb ); + pDb = &db->aDb[pOp->p1]; + assert( pDb->pBt!=0 ); if( pOp->opcode==OP_CreateTable ){ /* flags = BTREE_INTKEY; */ flags = BTREE_LEAFDATA|BTREE_INTKEY; }else{ flags = BTREE_ZERODATA; } - rc = sqlite3BtreeCreateTable(db->aDb[pOp->p2].pBt, &pgno, flags); + rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags); pTos++; if( rc==SQLITE_OK ){ pTos->i = pgno; pTos->flags = MEM_Int; - *(u32*)pOp->p3 = pgno; - pOp->p3 = 0; }else{ pTos->flags = MEM_Null; } break; } +/* Opcode: ParseSchema P1 * P3 +** +** Read and parse all entries from the SQLITE_MASTER table of database P1 +** that match the WHERE clause P3. +** +** This opcode invokes the parser to create a new virtual machine, +** then runs the new virtual machine. It is thus a reentrant opcode. +*/ +case OP_ParseSchema: { + char *zSql; + int iDb = pOp->p1; + const char *zMaster; + InitData initData; + + assert( iDb>=0 && iDbnDb ); + zMaster = iDb==1 ? TEMP_MASTER_NAME : MASTER_NAME; + initData.db = db; + initData.pzErrMsg = &p->zErrMsg; + zSql = sqlite3MPrintf( + "SELECT name, rootpage, sql, %d FROM '%q'.%s WHERE %s", + pOp->p1, db->aDb[iDb].zName, zMaster, pOp->p3); + sqlite3SafetyOff(db); + assert( db->init.busy==0 ); + db->init.busy = 1; + rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); + db->init.busy = 0; + sqlite3SafetyOn(db); + sqliteFree(zSql); + break; +} + + /* Opcode: IntegrityCk * P2 * ** ** Do an analysis of the currently open database. Push onto the diff --git a/test/misc4.test b/test/misc4.test index 32d41644a8..a8222dac40 100644 --- a/test/misc4.test +++ b/test/misc4.test @@ -13,7 +13,7 @@ # This file implements tests for miscellanous features that were # left out of other test files. # -# $Id: misc4.test,v 1.3 2004/07/19 17:25:25 drh Exp $ +# $Id: misc4.test,v 1.4 2004/07/24 03:30:49 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -54,4 +54,29 @@ do_test misc4-1.3 { sqlite3_finalize $stmt } {SQLITE_SCHEMA} +# Prepare but do not execute various CREATE statements. Then before +# those statements are executed, try to use the tables, indices, views, +# are triggers that were created. +# +if 0 { +do_test misc4-2.1 { + set stmt [sqlite3_prepare $DB {CREATE TABLE t3(x);} -1 TAIL] + catchsql { +pragma vdbe_trace=on; + INSERT INTO t3 VALUES(1); + } +} {1 {no such table: t3}} +do_test misc4-2.2 { + sqlite3_step $stmt +} SQLITE_DONE +do_test misc4-2.3 { + sqlite3_finalize $stmt +} SQLITE_OK +do_test misc4-2.4 { + catchsql { + INSERT INTO t3 VALUES(1); + } +} {0 {}} +} + finish_test diff --git a/test/table.test b/test/table.test index 65514a3d92..224e4eb4e9 100644 --- a/test/table.test +++ b/test/table.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # -# $Id: table.test,v 1.28 2004/06/21 07:36:33 danielk1977 Exp $ +# $Id: table.test,v 1.29 2004/07/24 03:30:49 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -316,39 +316,39 @@ do_test table-8.1.1 { SELECT sql FROM sqlite_master WHERE name='t2'; } } {{CREATE TABLE t2( - 'desc' text, - 'asc' text, - 'explain' int, - '14_vac' boolean, + "desc" text, + "asc" text, + "explain" int, + "14_vac" boolean, fuzzy_dog_12 varchar(10), - 'begin' blob, - 'end' clob + "begin" blob, + "end" clob )}} do_test table-8.2 { execsql { - CREATE TABLE 't3''xyz'(a,b,c); - INSERT INTO [t3'xyz] VALUES(1,2,3); - SELECT * FROM [t3'xyz]; + CREATE TABLE "t3""xyz"(a,b,c); + INSERT INTO [t3"xyz] VALUES(1,2,3); + SELECT * FROM [t3"xyz]; } } {1 2 3} do_test table-8.3 { execsql2 { - CREATE TABLE [t4'abc] AS SELECT count(*) as cnt, max(b+c) FROM [t3'xyz]; - SELECT * FROM [t4'abc]; + CREATE TABLE [t4"abc] AS SELECT count(*) as cnt, max(b+c) FROM [t3"xyz]; + SELECT * FROM [t4"abc]; } } {cnt 1 max(b+c) 5} # Update for v3: The declaration type of anything except a column is now a # NULL pointer, so the created table has no column types. (Changed result -# from {{CREATE TABLE 't4''abc'(cnt NUMERIC,'max(b+c)' NUMERIC)}}). +# from {{CREATE TABLE 't4"abc'(cnt NUMERIC,"max(b+c)" NUMERIC)}}). do_test table-8.3.1 { execsql { - SELECT sql FROM sqlite_master WHERE name='t4''abc' + SELECT sql FROM sqlite_master WHERE name='t4"abc' } -} {{CREATE TABLE 't4''abc'(cnt,'max(b+c)')}} +} {{CREATE TABLE "t4""abc"(cnt,"max(b+c)")}} do_test table-8.4 { execsql2 { - CREATE TEMPORARY TABLE t5 AS SELECT count(*) AS [y'all] FROM [t3'xyz]; + CREATE TEMPORARY TABLE t5 AS SELECT count(*) AS [y'all] FROM [t3"xyz]; SELECT * FROM t5; } } {y'all 1} @@ -356,7 +356,7 @@ do_test table-8.5 { db close sqlite3 db test.db execsql2 { - SELECT * FROM [t4'abc]; + SELECT * FROM [t4"abc]; } } {cnt 1 max(b+c) 5} do_test table-8.6 { @@ -520,5 +520,3 @@ do_test table-12.2 { } {{CREATE TABLE t8(b number(5,10),h,i integer,j BLOB)}} finish_test - -