diff --git a/Makefile.in b/Makefile.in index 05fe8851f4..f2b192b4cc 100644 --- a/Makefile.in +++ b/Makefile.in @@ -115,7 +115,7 @@ TCC += -DSQLITE_OMIT_CURSOR LIBOBJ = alter.lo attach.lo auth.lo btree.lo build.lo callback.lo date.lo \ delete.lo expr.lo func.lo hash.lo insert.lo \ main.lo opcodes.lo os_unix.lo os_win.lo \ - pager.lo parse.lo pragma.lo printf.lo random.lo \ + pager.lo parse.lo pragma.lo prepare.lo printf.lo random.lo \ select.lo table.lo tokenize.lo trigger.lo update.lo \ util.lo vacuum.lo vdbe.lo vdbeapi.lo vdbeaux.lo vdbemem.lo \ where.lo utf.lo legacy.lo @@ -145,6 +145,7 @@ SRC = \ $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ $(TOP)/src/pragma.c \ + $(TOP)/src/prepare.c \ $(TOP)/src/printf.c \ $(TOP)/src/random.c \ $(TOP)/src/select.c \ @@ -333,6 +334,9 @@ parse.c: $(TOP)/src/parse.y lemon$(BEXE) pragma.lo: $(TOP)/src/pragma.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/pragma.c +prepare.lo: $(TOP)/src/prepare.c $(HDR) + $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/prepare.c + printf.lo: $(TOP)/src/printf.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/printf.c diff --git a/main.mk b/main.mk index cd95c57fa3..578ce172f7 100644 --- a/main.mk +++ b/main.mk @@ -57,7 +57,7 @@ TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src LIBOBJ+= alter.o attach.o auth.o btree.o build.o callback.o date.o delete.o \ expr.o func.o hash.o insert.o \ main.o opcodes.o os_unix.o os_win.o \ - pager.o parse.o pragma.o printf.o random.o \ + pager.o parse.o pragma.o prepare.o printf.o random.o \ select.o table.o tclsqlite.o tokenize.o trigger.o \ update.o util.o vacuum.o \ vdbe.o vdbeapi.o vdbeaux.o vdbemem.o \ @@ -88,6 +88,7 @@ SRC = \ $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ $(TOP)/src/pragma.c \ + $(TOP)/src/prepare.c \ $(TOP)/src/printf.c \ $(TOP)/src/random.c \ $(TOP)/src/select.c \ @@ -268,6 +269,9 @@ parse.c: $(TOP)/src/parse.y lemon pragma.o: $(TOP)/src/pragma.c $(HDR) $(TCCX) $(TCL_FLAGS) -c $(TOP)/src/pragma.c +prepare.o: $(TOP)/src/prepare.c $(HDR) + $(TCCX) $(TCL_FLAGS) -c $(TOP)/src/prepare.c + printf.o: $(TOP)/src/printf.c $(HDR) $(TCCX) $(TCL_FLAGS) -c $(TOP)/src/printf.c diff --git a/manifest b/manifest index 69ac2d872a..ba6c1dc2aa 100644 --- a/manifest +++ b/manifest @@ -1,6 +1,6 @@ -C Remove\sthe\sconfig.h\sfile\sfrom\sthe\sbuild.\s\sTicket\s#1224.\s(CVS\s2480) -D 2005-05-24T20:19:58 -F Makefile.in b2b2d69640853c3917fedd9296e9003d610d86b1 +C Split\smain.c\sinto\stwo\sfiles\sto\smake\sbuilding\swithout\sthe\sparser\seasier.\s(CVS\s2481) +D 2005-05-25T04:11:56 +F Makefile.in 8129e7f261d405db783676f9ca31e0841768c652 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F VERSION 44187d7938af15a89b7b2dcd0016ffe5ec84961f @@ -16,7 +16,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826 -F main.mk 4695aa29032a0665c2becf38a29180b38b90e178 +F main.mk 8972f361ff4d9f3e215c4a346c91424620c87fc4 F mkdll.sh 5ec23622515d5bf8969404e80cfb5e220ddf0512 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodeh.awk 7563ad235670e864ead95cf672be3fe081450ae0 @@ -43,7 +43,7 @@ F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/insert.c 34c25c33f51a43644a42cc091ac967b070c6b6d5 F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b -F src/main.c 8de9c03d8388d2ccb3a89bdf0596f2280e21b655 +F src/main.c 8954071c07b29636c57c4cb7b445562210738e29 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 F src/os.h e5438be25cf96858787bf9b60fc7a2420e139ee3 F src/os_common.h 0e7f428ba0a6c40a61bc56c4e96f493231301b73 @@ -57,6 +57,7 @@ F src/pager.c f86d79d37eb4e30d8e2201dbe12497370719320c F src/pager.h 0d9153d6269d60d04af3dd84a0cc0a96253cf4a4 F src/parse.y 72cd7553f05fbc7b63ea9476108d0da6237f2818 F src/pragma.c 0ed94a1aa982802a9cf2a932c48d99b60683fa53 +F src/prepare.c d53602d2f8e097225ae7c76ec764ae68f759ba47 F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c 43cc2a76e3e00dabc59da82d0dcdef23cdba43a3 @@ -280,7 +281,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b -P 5fadb464eb77b4b998d8555f83401769960ea904 -R 559b7971d270b59c0ead6f07efa2b008 -U drh -Z c2b1f0d897d1329ca3d0de496bb83bf1 +P 3e64f1ab417f371e9875915303b898c5b45f0807 +R f1df240b45731b7db4ecb585924f1d63 +U danielk1977 +Z 9396e64a640a1eaa13d2b45263343304 diff --git a/manifest.uuid b/manifest.uuid index 87caa8643a..084c77d1cd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3e64f1ab417f371e9875915303b898c5b45f0807 \ No newline at end of file +d50915fafbde6859a5c2c3fc5cc9b99553b54e21 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 445a0889f0..4d6d59da36 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.290 2005/05/24 20:19:59 drh Exp $ +** $Id: main.c,v 1.291 2005/05/25 04:11:56 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -35,18 +35,6 @@ const int sqlite3one = 1; static sqlite3 *pDbList = 0; #endif - -/* -** Fill the InitData structure with an error message that indicates -** that the database is corrupt. -*/ -static void corruptSchema(InitData *pData, const char *zExtra){ - if( !sqlite3_malloc_failed ){ - sqlite3SetString(pData->pzErrMsg, "malformed database schema", - zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); - } -} - #ifndef SQLITE_OMIT_UTF16 /* ** Return the transient sqlite3_value object used for encoding conversions @@ -60,354 +48,6 @@ sqlite3_value *sqlite3GetTransientValue(sqlite3 *db){ } #endif -/* -** 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] = 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. -** -*/ -int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ - InitData *pData = (InitData*)pInit; - sqlite3 *db = pData->db; - int iDb; - - assert( argc==4 ); - if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ - if( argv[1]==0 || argv[3]==0 ){ - corruptSchema(pData, 0); - return 1; - } - 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; - } - }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 0; -} - -/* -** Attempt to read the database schema and initialize internal -** data structures for a single database file. The index of the -** database file is given by iDb. iDb==0 is used for the main -** database. iDb==1 should never be used. iDb>=2 is used for -** auxiliary databases. Return one of the SQLITE_ error codes to -** indicate success or failure. -*/ -static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ - int rc; - BtCursor *curMain; - int size; - Table *pTab; - char const *azArg[5]; - char zDbNum[30]; - int meta[10]; - InitData initData; - char const *zMasterSchema; - char const *zMasterName = SCHEMA_TABLE(iDb); - - /* - ** The master database table has a structure like this - */ - static const char master_schema[] = - "CREATE TABLE sqlite_master(\n" - " type text,\n" - " name text,\n" - " tbl_name text,\n" - " rootpage integer,\n" - " sql text\n" - ")" - ; -#ifndef SQLITE_OMIT_TEMPDB - static const char temp_master_schema[] = - "CREATE TEMP TABLE sqlite_temp_master(\n" - " type text,\n" - " name text,\n" - " tbl_name text,\n" - " rootpage integer,\n" - " sql text\n" - ")" - ; -#else - #define temp_master_schema 0 -#endif - - assert( iDb>=0 && iDbnDb ); - - /* zMasterSchema and zInitScript are set to point at the master schema - ** and initialisation script appropriate for the database being - ** initialised. zMasterName is the name of the master table. - */ - if( !OMIT_TEMPDB && iDb==1 ){ - zMasterSchema = temp_master_schema; - }else{ - zMasterSchema = master_schema; - } - zMasterName = SCHEMA_TABLE(iDb); - - /* Construct the schema tables. */ - sqlite3SafetyOff(db); - azArg[0] = zMasterName; - azArg[1] = "1"; - azArg[2] = zMasterSchema; - sprintf(zDbNum, "%d", iDb); - azArg[3] = zDbNum; - azArg[4] = 0; - initData.db = db; - initData.pzErrMsg = pzErrMsg; - rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0); - if( rc!=SQLITE_OK ){ - sqlite3SafetyOn(db); - return rc; - } - pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); - if( pTab ){ - pTab->readOnly = 1; - } - sqlite3SafetyOn(db); - - /* Create a cursor to hold the database open - */ - if( db->aDb[iDb].pBt==0 ){ - if( !OMIT_TEMPDB && iDb==1 ) DbSetProperty(db, 1, DB_SchemaLoaded); - return SQLITE_OK; - } - rc = sqlite3BtreeCursor(db->aDb[iDb].pBt, MASTER_ROOT, 0, 0, 0, &curMain); - if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){ - sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); - return rc; - } - - /* Get the database meta information. - ** - ** Meta values are as follows: - ** meta[0] Schema cookie. Changes with each schema change. - ** meta[1] File format of schema layer. - ** meta[2] Size of the page cache. - ** meta[3] Use freelist if 0. Autovacuum if greater than zero. - ** meta[4] Db text encoding. 1:UTF-8 3:UTF-16 LE 4:UTF-16 BE - ** meta[5] The user cookie. Used by the application. - ** meta[6] - ** meta[7] - ** meta[8] - ** meta[9] - ** - ** Note: The hash defined SQLITE_UTF* symbols in sqliteInt.h correspond to - ** the possible values of meta[4]. - */ - if( rc==SQLITE_OK ){ - int i; - for(i=0; rc==SQLITE_OK && iaDb[iDb].pBt, i+1, (u32 *)&meta[i]); - } - if( rc ){ - sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); - sqlite3BtreeCloseCursor(curMain); - return rc; - } - }else{ - memset(meta, 0, sizeof(meta)); - } - db->aDb[iDb].schema_cookie = meta[0]; - - /* If opening a non-empty database, check the text encoding. For the - ** main database, set sqlite3.enc to the encoding of the main database. - ** For an attached db, it is an error if the encoding is not the same - ** as sqlite3.enc. - */ - if( meta[4] ){ /* text encoding */ - if( iDb==0 ){ - /* If opening the main database, set db->enc. */ - db->enc = (u8)meta[4]; - db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0); - }else{ - /* If opening an attached database, the encoding much match db->enc */ - if( meta[4]!=db->enc ){ - sqlite3BtreeCloseCursor(curMain); - sqlite3SetString(pzErrMsg, "attached databases must use the same" - " text encoding as main database", (char*)0); - return SQLITE_ERROR; - } - } - } - - size = meta[2]; - if( size==0 ){ size = MAX_PAGES; } - db->aDb[iDb].cache_size = size; - - if( iDb==0 ){ - db->file_format = meta[1]; - if( db->file_format==0 ){ - /* This happens if the database was initially empty */ - db->file_format = 1; - } - - if( db->file_format==2 || db->file_format==3 ){ - /* File format 2 is treated exactly as file format 1. New - ** databases are created with file format 1. - */ - db->file_format = 1; - } - } - - /* - ** file_format==1 Version 3.0.0. - ** file_format==2 Version 3.1.3. - ** file_format==3 Version 3.1.4. - ** - ** Version 3.0 can only use files with file_format==1. Version 3.1.3 - ** can read and write files with file_format==1 or file_format==2. - ** Version 3.1.4 can read and write file formats 1, 2 and 3. - */ - if( meta[1]>3 ){ - sqlite3BtreeCloseCursor(curMain); - sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); - return SQLITE_ERROR; - } - - sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->aDb[iDb].cache_size); - - /* Read the schema information out of the schema tables - */ - assert( db->init.busy ); - if( rc==SQLITE_EMPTY ){ - /* For an empty database, there is nothing to read */ - rc = SQLITE_OK; - }else{ - char *zSql; - zSql = sqlite3MPrintf( - "SELECT name, rootpage, sql, '%s' FROM '%q'.%s", - zDbNum, db->aDb[iDb].zName, zMasterName); - sqlite3SafetyOff(db); - rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); - sqlite3SafetyOn(db); - sqliteFree(zSql); - sqlite3BtreeCloseCursor(curMain); - } - if( sqlite3_malloc_failed ){ - sqlite3SetString(pzErrMsg, "out of memory", (char*)0); - rc = SQLITE_NOMEM; - sqlite3ResetInternalSchema(db, 0); - } - if( rc==SQLITE_OK ){ - DbSetProperty(db, iDb, DB_SchemaLoaded); - }else{ - sqlite3ResetInternalSchema(db, iDb); - } - return rc; -} - -/* -** Initialize all database files - the main database file, the file -** used to store temporary tables, and any additional database files -** created using ATTACH statements. Return a success code. If an -** error occurs, write an error message into *pzErrMsg. -** -** After the database is initialized, the SQLITE_Initialized -** bit is set in the flags field of the sqlite structure. -*/ -int sqlite3Init(sqlite3 *db, char **pzErrMsg){ - int i, rc; - - if( db->init.busy ) return SQLITE_OK; - assert( (db->flags & SQLITE_Initialized)==0 ); - rc = SQLITE_OK; - db->init.busy = 1; - for(i=0; rc==SQLITE_OK && inDb; i++){ - if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; - rc = sqlite3InitOne(db, i, pzErrMsg); - if( rc ){ - sqlite3ResetInternalSchema(db, i); - } - } - - /* Once all the other databases have been initialised, load the schema - ** for the TEMP database. This is loaded last, as the TEMP database - ** schema may contain references to objects in other databases. - */ -#ifndef SQLITE_OMIT_TEMPDB - if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ - rc = sqlite3InitOne(db, 1, pzErrMsg); - if( rc ){ - sqlite3ResetInternalSchema(db, 1); - } - } -#endif - - db->init.busy = 0; - if( rc==SQLITE_OK ){ - db->flags |= SQLITE_Initialized; - sqlite3CommitInternalChanges(db); - } - - if( rc!=SQLITE_OK ){ - db->flags &= ~SQLITE_Initialized; - } - return rc; -} - -/* -** This routine is a no-op if the database schema is already initialised. -** Otherwise, the schema is loaded. An error code is returned. -*/ -int sqlite3ReadSchema(Parse *pParse){ - int rc = SQLITE_OK; - sqlite3 *db = pParse->db; - if( !db->init.busy ){ - if( (db->flags & SQLITE_Initialized)==0 ){ - rc = sqlite3Init(db, &pParse->zErrMsg); - } - } - assert( rc!=SQLITE_OK || (db->flags & SQLITE_Initialized)||db->init.busy ); - if( rc!=SQLITE_OK ){ - pParse->rc = rc; - pParse->nErr++; - } - return rc; -} - /* ** The version of the library */ @@ -1025,154 +665,6 @@ int sqlite3_errcode(sqlite3 *db){ return db->errCode; } -/* -** Check schema cookies in all databases. If any cookie is out -** of date, return 0. If all schema cookies are current, return 1. -*/ -static int schemaIsValid(sqlite3 *db){ - int iDb; - int rc; - BtCursor *curTemp; - int cookie; - int allOk = 1; - - for(iDb=0; allOk && iDbnDb; iDb++){ - Btree *pBt; - pBt = db->aDb[iDb].pBt; - if( pBt==0 ) continue; - rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp); - if( rc==SQLITE_OK ){ - rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie); - if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){ - allOk = 0; - } - sqlite3BtreeCloseCursor(curTemp); - } - } - return allOk; -} - -/* -** Compile the UTF-8 encoded SQL statement zSql into a statement handle. -*/ -int sqlite3_prepare( - sqlite3 *db, /* Database handle. */ - const char *zSql, /* UTF-8 encoded SQL statement. */ - int nBytes, /* Length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ - const char** pzTail /* OUT: End of parsed string */ -){ - Parse sParse; - char *zErrMsg = 0; - int rc = SQLITE_OK; - - if( sqlite3_malloc_failed ){ - return SQLITE_NOMEM; - } - - assert( ppStmt ); - *ppStmt = 0; - if( sqlite3SafetyOn(db) ){ - return SQLITE_MISUSE; - } - - memset(&sParse, 0, sizeof(sParse)); - sParse.db = db; - sqlite3RunParser(&sParse, zSql, &zErrMsg); - - if( sqlite3_malloc_failed ){ - rc = SQLITE_NOMEM; - sqlite3RollbackAll(db); - sqlite3ResetInternalSchema(db, 0); - db->flags &= ~SQLITE_InTrans; - goto prepare_out; - } - if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; - if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){ - sParse.rc = SQLITE_SCHEMA; - } - if( sParse.rc==SQLITE_SCHEMA ){ - sqlite3ResetInternalSchema(db, 0); - } - if( pzTail ) *pzTail = sParse.zTail; - rc = sParse.rc; - -#ifndef SQLITE_OMIT_EXPLAIN - if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ - sqlite3VdbeSetNumCols(sParse.pVdbe, 5); - sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC); - } -#endif - -prepare_out: - if( sqlite3SafetyOff(db) ){ - rc = SQLITE_MISUSE; - } - if( rc==SQLITE_OK ){ - *ppStmt = (sqlite3_stmt*)sParse.pVdbe; - }else if( sParse.pVdbe ){ - sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); - } - - if( zErrMsg ){ - sqlite3Error(db, rc, "%s", zErrMsg); - sqliteFree(zErrMsg); - }else{ - sqlite3Error(db, rc, 0); - } - return rc; -} - -#ifndef SQLITE_OMIT_UTF16 -/* -** Compile the UTF-16 encoded SQL statement zSql into a statement handle. -*/ -int sqlite3_prepare16( - sqlite3 *db, /* Database handle. */ - const void *zSql, /* UTF-8 encoded SQL statement. */ - int nBytes, /* Length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ - const void **pzTail /* OUT: End of parsed string */ -){ - /* This function currently works by first transforming the UTF-16 - ** encoded string to UTF-8, then invoking sqlite3_prepare(). The - ** tricky bit is figuring out the pointer to return in *pzTail. - */ - char const *zSql8 = 0; - char const *zTail8 = 0; - int rc; - sqlite3_value *pTmp; - - if( sqlite3SafetyCheck(db) ){ - return SQLITE_MISUSE; - } - pTmp = sqlite3GetTransientValue(db); - sqlite3ValueSetStr(pTmp, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); - zSql8 = sqlite3ValueText(pTmp, SQLITE_UTF8); - if( !zSql8 ){ - sqlite3Error(db, SQLITE_NOMEM, 0); - return SQLITE_NOMEM; - } - rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8); - - if( zTail8 && pzTail ){ - /* If sqlite3_prepare returns a tail pointer, we calculate the - ** equivalent pointer into the UTF-16 string by counting the unicode - ** characters between zSql8 and zTail8, and then returning a pointer - ** the same number of characters into the UTF-16 string. - */ - int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8); - *pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed); - } - - return rc; -} -#endif /* SQLITE_OMIT_UTF16 */ - /* ** This routine does the work of opening a database on behalf of ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" diff --git a/src/prepare.c b/src/prepare.c new file mode 100644 index 0000000000..1d2e6cda3b --- /dev/null +++ b/src/prepare.c @@ -0,0 +1,529 @@ +/* +** 2005 May 25 +** +** 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. +** +************************************************************************* +** This file contains the implementation of the sqlite3_prepare() +** interface, and routines that contribute to loading the database schema +** from disk. +** +** $Id: prepare.c,v 1.1 2005/05/25 04:11:56 danielk1977 Exp $ +*/ +#include "sqliteInt.h" +#include "os.h" +#include + +/* +** Fill the InitData structure with an error message that indicates +** that the database is corrupt. +*/ +static void corruptSchema(InitData *pData, const char *zExtra){ + if( !sqlite3_malloc_failed ){ + sqlite3SetString(pData->pzErrMsg, "malformed database schema", + zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); + } +} + +/* +** 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] = 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. +** +*/ +int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ + InitData *pData = (InitData*)pInit; + sqlite3 *db = pData->db; + int iDb; + + assert( argc==4 ); + if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ + if( argv[1]==0 || argv[3]==0 ){ + corruptSchema(pData, 0); + return 1; + } + 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; + } + }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 0; +} + +/* +** Attempt to read the database schema and initialize internal +** data structures for a single database file. The index of the +** database file is given by iDb. iDb==0 is used for the main +** database. iDb==1 should never be used. iDb>=2 is used for +** auxiliary databases. Return one of the SQLITE_ error codes to +** indicate success or failure. +*/ +static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ + int rc; + BtCursor *curMain; + int size; + Table *pTab; + char const *azArg[5]; + char zDbNum[30]; + int meta[10]; + InitData initData; + char const *zMasterSchema; + char const *zMasterName = SCHEMA_TABLE(iDb); + + /* + ** The master database table has a structure like this + */ + static const char master_schema[] = + "CREATE TABLE sqlite_master(\n" + " type text,\n" + " name text,\n" + " tbl_name text,\n" + " rootpage integer,\n" + " sql text\n" + ")" + ; +#ifndef SQLITE_OMIT_TEMPDB + static const char temp_master_schema[] = + "CREATE TEMP TABLE sqlite_temp_master(\n" + " type text,\n" + " name text,\n" + " tbl_name text,\n" + " rootpage integer,\n" + " sql text\n" + ")" + ; +#else + #define temp_master_schema 0 +#endif + + assert( iDb>=0 && iDbnDb ); + + /* zMasterSchema and zInitScript are set to point at the master schema + ** and initialisation script appropriate for the database being + ** initialised. zMasterName is the name of the master table. + */ + if( !OMIT_TEMPDB && iDb==1 ){ + zMasterSchema = temp_master_schema; + }else{ + zMasterSchema = master_schema; + } + zMasterName = SCHEMA_TABLE(iDb); + + /* Construct the schema tables. */ + sqlite3SafetyOff(db); + azArg[0] = zMasterName; + azArg[1] = "1"; + azArg[2] = zMasterSchema; + sprintf(zDbNum, "%d", iDb); + azArg[3] = zDbNum; + azArg[4] = 0; + initData.db = db; + initData.pzErrMsg = pzErrMsg; + rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0); + if( rc!=SQLITE_OK ){ + sqlite3SafetyOn(db); + return rc; + } + pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); + if( pTab ){ + pTab->readOnly = 1; + } + sqlite3SafetyOn(db); + + /* Create a cursor to hold the database open + */ + if( db->aDb[iDb].pBt==0 ){ + if( !OMIT_TEMPDB && iDb==1 ) DbSetProperty(db, 1, DB_SchemaLoaded); + return SQLITE_OK; + } + rc = sqlite3BtreeCursor(db->aDb[iDb].pBt, MASTER_ROOT, 0, 0, 0, &curMain); + if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){ + sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); + return rc; + } + + /* Get the database meta information. + ** + ** Meta values are as follows: + ** meta[0] Schema cookie. Changes with each schema change. + ** meta[1] File format of schema layer. + ** meta[2] Size of the page cache. + ** meta[3] Use freelist if 0. Autovacuum if greater than zero. + ** meta[4] Db text encoding. 1:UTF-8 3:UTF-16 LE 4:UTF-16 BE + ** meta[5] The user cookie. Used by the application. + ** meta[6] + ** meta[7] + ** meta[8] + ** meta[9] + ** + ** Note: The hash defined SQLITE_UTF* symbols in sqliteInt.h correspond to + ** the possible values of meta[4]. + */ + if( rc==SQLITE_OK ){ + int i; + for(i=0; rc==SQLITE_OK && iaDb[iDb].pBt, i+1, (u32 *)&meta[i]); + } + if( rc ){ + sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); + sqlite3BtreeCloseCursor(curMain); + return rc; + } + }else{ + memset(meta, 0, sizeof(meta)); + } + db->aDb[iDb].schema_cookie = meta[0]; + + /* If opening a non-empty database, check the text encoding. For the + ** main database, set sqlite3.enc to the encoding of the main database. + ** For an attached db, it is an error if the encoding is not the same + ** as sqlite3.enc. + */ + if( meta[4] ){ /* text encoding */ + if( iDb==0 ){ + /* If opening the main database, set db->enc. */ + db->enc = (u8)meta[4]; + db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0); + }else{ + /* If opening an attached database, the encoding much match db->enc */ + if( meta[4]!=db->enc ){ + sqlite3BtreeCloseCursor(curMain); + sqlite3SetString(pzErrMsg, "attached databases must use the same" + " text encoding as main database", (char*)0); + return SQLITE_ERROR; + } + } + } + + size = meta[2]; + if( size==0 ){ size = MAX_PAGES; } + db->aDb[iDb].cache_size = size; + + if( iDb==0 ){ + db->file_format = meta[1]; + if( db->file_format==0 ){ + /* This happens if the database was initially empty */ + db->file_format = 1; + } + + if( db->file_format==2 || db->file_format==3 ){ + /* File format 2 is treated exactly as file format 1. New + ** databases are created with file format 1. + */ + db->file_format = 1; + } + } + + /* + ** file_format==1 Version 3.0.0. + ** file_format==2 Version 3.1.3. + ** file_format==3 Version 3.1.4. + ** + ** Version 3.0 can only use files with file_format==1. Version 3.1.3 + ** can read and write files with file_format==1 or file_format==2. + ** Version 3.1.4 can read and write file formats 1, 2 and 3. + */ + if( meta[1]>3 ){ + sqlite3BtreeCloseCursor(curMain); + sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); + return SQLITE_ERROR; + } + + sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->aDb[iDb].cache_size); + + /* Read the schema information out of the schema tables + */ + assert( db->init.busy ); + if( rc==SQLITE_EMPTY ){ + /* For an empty database, there is nothing to read */ + rc = SQLITE_OK; + }else{ + char *zSql; + zSql = sqlite3MPrintf( + "SELECT name, rootpage, sql, '%s' FROM '%q'.%s", + zDbNum, db->aDb[iDb].zName, zMasterName); + sqlite3SafetyOff(db); + rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); + sqlite3SafetyOn(db); + sqliteFree(zSql); + sqlite3BtreeCloseCursor(curMain); + } + if( sqlite3_malloc_failed ){ + sqlite3SetString(pzErrMsg, "out of memory", (char*)0); + rc = SQLITE_NOMEM; + sqlite3ResetInternalSchema(db, 0); + } + if( rc==SQLITE_OK ){ + DbSetProperty(db, iDb, DB_SchemaLoaded); + }else{ + sqlite3ResetInternalSchema(db, iDb); + } + return rc; +} + +/* +** Initialize all database files - the main database file, the file +** used to store temporary tables, and any additional database files +** created using ATTACH statements. Return a success code. If an +** error occurs, write an error message into *pzErrMsg. +** +** After the database is initialized, the SQLITE_Initialized +** bit is set in the flags field of the sqlite structure. +*/ +int sqlite3Init(sqlite3 *db, char **pzErrMsg){ + int i, rc; + + if( db->init.busy ) return SQLITE_OK; + assert( (db->flags & SQLITE_Initialized)==0 ); + rc = SQLITE_OK; + db->init.busy = 1; + for(i=0; rc==SQLITE_OK && inDb; i++){ + if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; + rc = sqlite3InitOne(db, i, pzErrMsg); + if( rc ){ + sqlite3ResetInternalSchema(db, i); + } + } + + /* Once all the other databases have been initialised, load the schema + ** for the TEMP database. This is loaded last, as the TEMP database + ** schema may contain references to objects in other databases. + */ +#ifndef SQLITE_OMIT_TEMPDB + if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ + rc = sqlite3InitOne(db, 1, pzErrMsg); + if( rc ){ + sqlite3ResetInternalSchema(db, 1); + } + } +#endif + + db->init.busy = 0; + if( rc==SQLITE_OK ){ + db->flags |= SQLITE_Initialized; + sqlite3CommitInternalChanges(db); + } + + if( rc!=SQLITE_OK ){ + db->flags &= ~SQLITE_Initialized; + } + return rc; +} + +/* +** This routine is a no-op if the database schema is already initialised. +** Otherwise, the schema is loaded. An error code is returned. +*/ +int sqlite3ReadSchema(Parse *pParse){ + int rc = SQLITE_OK; + sqlite3 *db = pParse->db; + if( !db->init.busy ){ + if( (db->flags & SQLITE_Initialized)==0 ){ + rc = sqlite3Init(db, &pParse->zErrMsg); + } + } + assert( rc!=SQLITE_OK || (db->flags & SQLITE_Initialized)||db->init.busy ); + if( rc!=SQLITE_OK ){ + pParse->rc = rc; + pParse->nErr++; + } + return rc; +} + + +/* +** Check schema cookies in all databases. If any cookie is out +** of date, return 0. If all schema cookies are current, return 1. +*/ +static int schemaIsValid(sqlite3 *db){ + int iDb; + int rc; + BtCursor *curTemp; + int cookie; + int allOk = 1; + + for(iDb=0; allOk && iDbnDb; iDb++){ + Btree *pBt; + pBt = db->aDb[iDb].pBt; + if( pBt==0 ) continue; + rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie); + if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){ + allOk = 0; + } + sqlite3BtreeCloseCursor(curTemp); + } + } + return allOk; +} + +/* +** Compile the UTF-8 encoded SQL statement zSql into a statement handle. +*/ +int sqlite3_prepare( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char** pzTail /* OUT: End of parsed string */ +){ + Parse sParse; + char *zErrMsg = 0; + int rc = SQLITE_OK; + + if( sqlite3_malloc_failed ){ + return SQLITE_NOMEM; + } + + assert( ppStmt ); + *ppStmt = 0; + if( sqlite3SafetyOn(db) ){ + return SQLITE_MISUSE; + } + + memset(&sParse, 0, sizeof(sParse)); + sParse.db = db; + sqlite3RunParser(&sParse, zSql, &zErrMsg); + + if( sqlite3_malloc_failed ){ + rc = SQLITE_NOMEM; + sqlite3RollbackAll(db); + sqlite3ResetInternalSchema(db, 0); + db->flags &= ~SQLITE_InTrans; + goto prepare_out; + } + if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; + if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){ + sParse.rc = SQLITE_SCHEMA; + } + if( sParse.rc==SQLITE_SCHEMA ){ + sqlite3ResetInternalSchema(db, 0); + } + if( pzTail ) *pzTail = sParse.zTail; + rc = sParse.rc; + +#ifndef SQLITE_OMIT_EXPLAIN + if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ + sqlite3VdbeSetNumCols(sParse.pVdbe, 5); + sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC); + } +#endif + +prepare_out: + if( sqlite3SafetyOff(db) ){ + rc = SQLITE_MISUSE; + } + if( rc==SQLITE_OK ){ + *ppStmt = (sqlite3_stmt*)sParse.pVdbe; + }else if( sParse.pVdbe ){ + sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); + } + + if( zErrMsg ){ + sqlite3Error(db, rc, "%s", zErrMsg); + sqliteFree(zErrMsg); + }else{ + sqlite3Error(db, rc, 0); + } + return rc; +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** Compile the UTF-16 encoded SQL statement zSql into a statement handle. +*/ +int sqlite3_prepare16( + sqlite3 *db, /* Database handle. */ + const void *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const void **pzTail /* OUT: End of parsed string */ +){ + /* This function currently works by first transforming the UTF-16 + ** encoded string to UTF-8, then invoking sqlite3_prepare(). The + ** tricky bit is figuring out the pointer to return in *pzTail. + */ + char const *zSql8 = 0; + char const *zTail8 = 0; + int rc; + sqlite3_value *pTmp; + + if( sqlite3SafetyCheck(db) ){ + return SQLITE_MISUSE; + } + pTmp = sqlite3GetTransientValue(db); + sqlite3ValueSetStr(pTmp, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); + zSql8 = sqlite3ValueText(pTmp, SQLITE_UTF8); + if( !zSql8 ){ + sqlite3Error(db, SQLITE_NOMEM, 0); + return SQLITE_NOMEM; + } + rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8); + + if( zTail8 && pzTail ){ + /* If sqlite3_prepare returns a tail pointer, we calculate the + ** equivalent pointer into the UTF-16 string by counting the unicode + ** characters between zSql8 and zTail8, and then returning a pointer + ** the same number of characters into the UTF-16 string. + */ + int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8); + *pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed); + } + + return rc; +} +#endif /* SQLITE_OMIT_UTF16 */ +