?? main.c
字號:
/*** 2001 September 15**** 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.***************************************************************************** Main file for the SQLite library. The routines in this file** implement the programmer interface to the library. Routines in** other files are for internal use by SQLite and should not be** accessed by users of the library.**** $Id: qt/main.c 3.3.4 edited Mar 30 2004 $*/#include "sqliteInt.h"#include "os.h"#include <ctype.h>/*** A pointer to this structure is used to communicate information** from sqliteInit into the sqliteInitCallback.*/typedef struct { sqlite *db; /* The database being initialized */ char **pzErrMsg; /* Error message stored here */} InitData;/*** Fill the InitData structure with an error message that indicates** that the database is corrupt.*/static void corruptSchema(InitData *pData, const char *zExtra){ sqliteSetString(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 sqliteInit() below for additional information.**** Each callback contains the following information:**** argv[0] = "file-format" or "schema-cookie" or "table" or "index"** argv[1] = table or index name or meta statement type.** argv[2] = root page number for table or index. NULL for meta.** argv[3] = SQL text for a CREATE TABLE or CREATE INDEX statement.** argv[4] = "1" for temporary files, "0" for main database, "2" or more** for auxiliary database files.***/staticint sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){ InitData *pData = (InitData*)pInit; int nErr = 0; assert( argc==5 ); if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ if( argv[0]==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; assert( db->init.busy ); db->init.iDb = atoi(argv[4]); assert( db->init.iDb>=0 && db->init.iDb<db->nDb ); db->init.newTnum = atoi(argv[2]); if( sqlite_exec(db, argv[3], 0, 0, &zErr) ){ corruptSchema(pData, zErr); sqlite_freemem(zErr); } db->init.iDb = 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. */ int iDb; Index *pIndex; iDb = atoi(argv[4]); assert( iDb>=0 && iDb<db->nDb ); pIndex = sqliteFindIndex(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]); } } break; } default: { /* This can not happen! */ nErr = 1; assert( nErr==0 ); } } return nErr;}/*** This is a callback procedure used to reconstruct a table. The** name of the table to be reconstructed is passed in as argv[0].**** This routine is used to automatically upgrade a database from** format version 1 or 2 to version 3. The correct operation of** this routine relys on the fact that no indices are used when** copying a table out to a temporary file.**** The change from version 2 to version 3 occurred between SQLite** version 2.5.6 and 2.6.0 on 2002-July-18. */staticint upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){ InitData *pData = (InitData*)pInit; int rc; Table *pTab; Trigger *pTrig; char *zErr = 0; pTab = sqliteFindTable(pData->db, argv[0], 0); assert( pTab!=0 ); assert( sqliteStrICmp(pTab->zName, argv[0])==0 ); if( pTab ){ pTrig = pTab->pTrigger; pTab->pTrigger = 0; /* Disable all triggers before rebuilding the table */ } rc = sqlite_exec_printf(pData->db, "CREATE TEMP TABLE sqlite_x AS SELECT * FROM '%q'; " "DELETE FROM '%q'; " "INSERT INTO '%q' SELECT * FROM sqlite_x; " "DROP TABLE sqlite_x;", 0, 0, &zErr, argv[0], argv[0], argv[0]); if( zErr ){ if( *pData->pzErrMsg ) sqlite_freemem(*pData->pzErrMsg); *pData->pzErrMsg = zErr; } /* If an error occurred in the SQL above, then the transaction will ** rollback which will delete the internal symbol tables. This will ** cause the structure that pTab points to be deleted. In case that ** happened, we need to refetch pTab. */ pTab = sqliteFindTable(pData->db, argv[0], 0); if( pTab ){ assert( sqliteStrICmp(pTab->zName, argv[0])==0 ); pTab->pTrigger = pTrig; /* Re-enable triggers */ } return rc!=SQLITE_OK;}/*** 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 sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){ int rc; BtCursor *curMain; int size; Table *pTab; char *azArg[6]; char zDbNum[30]; int meta[SQLITE_N_BTREE_META]; InitData initData; /* ** The master database table has a structure like this */ static char master_schema[] = "CREATE TABLE sqlite_master(\n" " type text,\n" " name text,\n" " tbl_name text,\n" " rootpage integer,\n" " sql text\n" ")" ; static 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" ")" ; /* The following SQL will read the schema from the master tables. ** The first version works with SQLite file formats 2 or greater. ** The second version is for format 1 files. ** ** Beginning with file format 2, the rowid for new table entries ** (including entries in sqlite_master) is an increasing integer. ** So for file format 2 and later, we can play back sqlite_master ** and all the CREATE statements will appear in the right order. ** But with file format 1, table entries were random and so we ** have to make sure the CREATE TABLEs occur before their corresponding ** CREATE INDEXs. (We don't have to deal with CREATE VIEW or ** CREATE TRIGGER in file format 1 because those constructs did ** not exist then.) */ static char init_script[] = "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master " "UNION ALL " "SELECT type, name, rootpage, sql, 0 FROM sqlite_master"; static char older_init_script[] = "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master " "UNION ALL " "SELECT type, name, rootpage, sql, 0 FROM sqlite_master " "WHERE type='table' " "UNION ALL " "SELECT type, name, rootpage, sql, 0 FROM sqlite_master " "WHERE type='index'"; assert( iDb>=0 && iDb!=1 && iDb<db->nDb ); /* Construct the schema tables: sqlite_master and sqlite_temp_master */ sqliteSafetyOff(db); azArg[0] = "table"; azArg[1] = MASTER_NAME; azArg[2] = "2"; azArg[3] = master_schema; sprintf(zDbNum, "%d", iDb); azArg[4] = zDbNum; azArg[5] = 0; initData.db = db; initData.pzErrMsg = pzErrMsg; sqliteInitCallback(&initData, 5, azArg, 0); pTab = sqliteFindTable(db, MASTER_NAME, "main"); if( pTab ){ pTab->readOnly = 1; } if( iDb==0 ){ azArg[1] = TEMP_MASTER_NAME; azArg[3] = temp_master_schema; azArg[4] = "1"; sqliteInitCallback(&initData, 5, azArg, 0); pTab = sqliteFindTable(db, TEMP_MASTER_NAME, "temp"); if( pTab ){ pTab->readOnly = 1; } } sqliteSafetyOn(db); /* Create a cursor to hold the database open */ if( db->aDb[iDb].pBt==0 ) return SQLITE_OK; rc = sqliteBtreeCursor(db->aDb[iDb].pBt, 2, 0, &curMain); if( rc ){ sqliteSetString(pzErrMsg, sqlite_error_string(rc), (char*)0); return rc; } /* Get the database meta information */ rc = sqliteBtreeGetMeta(db->aDb[iDb].pBt, meta); if( rc ){ sqliteSetString(pzErrMsg, sqlite_error_string(rc), (char*)0); sqliteBtreeCloseCursor(curMain); return rc; } db->aDb[iDb].schema_cookie = meta[1]; if( iDb==0 ){ db->next_cookie = meta[1]; db->file_format = meta[2]; size = meta[3]; if( size==0 ){ size = MAX_PAGES; } db->cache_size = size; db->safety_level = meta[4]; if( db->safety_level==0 ) db->safety_level = 2; /* ** file_format==1 Version 2.1.0. ** file_format==2 Version 2.2.0. Add support for INTEGER PRIMARY KEY. ** file_format==3 Version 2.6.0. Fix empty-string index bug. ** file_format==4 Version 2.7.0. Add support for separate numeric and ** text datatypes. */ if( db->file_format==0 ){ /* This happens if the database was initially empty */ db->file_format = 4; }else if( db->file_format>4 ){ sqliteBtreeCloseCursor(curMain); sqliteSetString(pzErrMsg, "unsupported file format", (char*)0); return SQLITE_ERROR; } }else if( db->file_format!=meta[2] || db->file_format<4 ){ assert( db->file_format>=4 ); if( meta[2]==0 ){ sqliteSetString(pzErrMsg, "cannot attach empty database: ", db->aDb[iDb].zName, (char*)0); }else{ sqliteSetString(pzErrMsg, "incompatible file format in auxiliary " "database: ", db->aDb[iDb].zName, (char*)0); } sqliteBtreeClose(db->aDb[iDb].pBt); db->aDb[iDb].pBt = 0; return SQLITE_FORMAT; } sqliteBtreeSetCacheSize(db->aDb[iDb].pBt, db->cache_size); sqliteBtreeSetSafetyLevel(db->aDb[iDb].pBt, meta[4]==0 ? 2 : meta[4]); /* Read the schema information out of the schema tables */ assert( db->init.busy ); sqliteSafetyOff(db); if( iDb==0 ){ rc = sqlite_exec(db, db->file_format>=2 ? init_script : older_init_script, sqliteInitCallback, &initData, 0); }else{ char *zSql = 0; sqliteSetString(&zSql, "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"", db->aDb[iDb].zName, "\".sqlite_master", (char*)0); rc = sqlite_exec(db, zSql, sqliteInitCallback, &initData, 0); sqliteFree(zSql); } sqliteSafetyOn(db); sqliteBtreeCloseCursor(curMain); if( sqlite_malloc_failed ){ sqliteSetString(pzErrMsg, "out of memory", (char*)0); rc = SQLITE_NOMEM; sqliteResetInternalSchema(db, 0); } if( rc==SQLITE_OK ){ DbSetProperty(db, iDb, DB_SchemaLoaded); if( iDb==0 ){ DbSetProperty(db, 1, DB_SchemaLoaded); } }else{ sqliteResetInternalSchema(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. An** attempt is made to initialize the database as soon as it** is opened. If that fails (perhaps because another process
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -