/* ** 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; curTemp = (BtCursor *)sqlite3Malloc(sqlite3BtreeCursorSize()); if( curTemp ){ assert( sqlite3_mutex_held(db->mutex) ); for(iDb=0; allOk && iDb<db->nDb; iDb++){ Btree *pBt; pBt = db->aDb[iDb].pBt; if( pBt==0 ) continue; memset(curTemp, 0, sqlite3BtreeCursorSize()); rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, curTemp); if( rc==SQLITE_OK ){ rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie); if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){ allOk = 0; } sqlite3BtreeCloseCursor(curTemp); } if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; } } sqlite3_free(curTemp); }else{ allOk = 0; db->mallocFailed = 1; } return allOk; }
/* ** Usage: btree_close_cursor ID ** ** Close a cursor opened using btree_cursor. */ static int btree_close_cursor( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; Btree *pBt; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); pBt = pCur->pBtree; sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCloseCursor(pCur); sqlite3BtreeLeave(pBt); ckfree((char *)pCur); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } return SQLITE_OK; }
/* ** Close a cursor and release all the resources that cursor happens ** to hold. */ void sqlite3VdbeFreeCursor(Cursor *pCx){ if( pCx==0 ){ return; } if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } if( pCx->pBt ){ sqlite3BtreeClose(pCx->pBt); } sqliteFree(pCx->pData); sqliteFree(pCx->aType); sqliteFree(pCx); }
/* ** 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 && iDb<db->nDb; 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].pSchema->schema_cookie ){ allOk = 0; } sqlite3BtreeCloseCursor(curTemp); } } return allOk; }
/* * Print statistics for tables and/or indexes using DB->stat_print() * * If msgfile is NULL, then statistics will be printed into stdout, otherwise * the statistics will be printed into the designated output stream. * * If name input is NULL, then statistics for all tables and indexes are * printed, otherwise only the statistics for that table or index is printed. * * Returns SQLITE_OK if there are no errors, -1 if an error occurred. */ SQLITE_API int bdbSqlDbStatPrint(sqlite3 *db, FILE *msgfile, char *name) { BtCursor cur, *pCur = NULL; Btree *p; char **azResult = NULL; char *zErrMsg = NULL; char *zSql = NULL; DB *dbp; FILE *out; int i, rc, nRow, iTable, openTransaction = 0; if (!db || !db->aDb) return -1; p = db->aDb[0].pBt; assert(p); if (!(out = msgfile)) out = stdout; /* Construct query to get root page number(s) */ if (!name) { zSql = sqlite3_mprintf( "SELECT type,name,rootpage FROM sqlite_master"); } else { zSql = sqlite3_mprintf( "SELECT type,name,rootpage FROM sqlite_master " "WHERE name='%q'", name); } if (!zSql) { fprintf(stderr, "Error: memory allocation failed\n"); goto err; } rc = sqlite3_get_table(db, zSql, &azResult, &nRow, 0, &zErrMsg); (void)sqlite3_free(zSql); if (zErrMsg) { fprintf(stderr, "Error: %s\n", zErrMsg); (void)sqlite3_free(zErrMsg); if (rc == SQLITE_OK) rc = -1; goto err; } else if (rc != SQLITE_OK) { fprintf(stderr, "Error: querying sqlite_master\n"); goto err; } else if (nRow < 1) goto err; rc = sqlite3BtreeBeginTrans(p, 0); if (rc != SQLITE_OK) { fprintf(stderr, "Error: could not enter a transaction\n"); goto err; } openTransaction = 1; /* Print stats for all tables in query's result */ for (i = 1; i <= nRow; i++) { fprintf(out, "Statistics for %s \"%s\"\n", azResult[3*i], azResult[3*i + 1]); iTable = atoi(azResult[3*i + 2]); pCur = &cur; (void)sqlite3BtreeCursorZero(pCur); /* Acquire a read cursor to retrieve the dbp for the table */ rc = sqlite3BtreeCursor(p, iTable, 0, NULL, pCur); if (pCur->eState == CURSOR_FAULT) rc = pCur->error; if (rc != SQLITE_OK) { fprintf(stderr, "Error: could not create cursor\n"); goto err; } assert(pCur->cached_db && pCur->cached_db->dbp); dbp = pCur->cached_db->dbp; (void)dbp->set_msgfile(dbp, out); (void)dbp->stat_print(dbp, DB_STAT_ALL); (void)sqlite3BtreeCloseCursor(&cur); pCur = NULL; } err: if (pCur) (void)sqlite3BtreeCloseCursor(pCur); if (openTransaction) sqlite3BtreeCommit(p); if (azResult) (void)sqlite3_free_table(azResult); return rc; }
/* ** 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; Db *pDb; char const *azArg[4]; 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 && iDb<db->nDb ); assert( db->aDb[iDb].pSchema ); /* 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; azArg[3] = 0; initData.db = db; initData.iDb = iDb; initData.pzErrMsg = pzErrMsg; rc = sqlite3InitCallback(&initData, 3, (char **)azArg, 0); if( rc ){ sqlite3SafetyOn(db); return initData.rc; } pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); if( pTab ){ pTab->readOnly = 1; } sqlite3SafetyOn(db); /* Create a cursor to hold the database open */ pDb = &db->aDb[iDb]; if( pDb->pBt==0 ){ if( !OMIT_TEMPDB && iDb==1 ){ DbSetProperty(db, 1, DB_SchemaLoaded); } return SQLITE_OK; } rc = sqlite3BtreeCursor(pDb->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 2:UTF-16LE 3:UTF-16BE ** meta[5] The user cookie. Used by the application. ** meta[6] ** meta[7] ** meta[8] ** meta[9] ** ** Note: The #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 && i<sizeof(meta)/sizeof(meta[0]); i++){ rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]); } if( rc ){ sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); sqlite3BtreeCloseCursor(curMain); return rc; } }else{ memset(meta, 0, sizeof(meta)); } pDb->pSchema->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 ENC(db). */ ENC(db) = (u8)meta[4]; db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0); }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( meta[4]!=ENC(db) ){ sqlite3BtreeCloseCursor(curMain); sqlite3SetString(pzErrMsg, "attached databases must use the same" " text encoding as main database", (char*)0); return SQLITE_ERROR; } } }else{ DbSetProperty(db, iDb, DB_Empty); } pDb->pSchema->enc = ENC(db); size = meta[2]; if( size==0 ){ size = MAX_PAGES; } pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); /* ** file_format==1 Version 3.0.0. ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants */ pDb->pSchema->file_format = meta[1]; if( pDb->pSchema->file_format==0 ){ pDb->pSchema->file_format = 1; } if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){ sqlite3BtreeCloseCursor(curMain); sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); return SQLITE_ERROR; } /* 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 FROM '%q'.%s", db->aDb[iDb].zName, zMasterName); sqlite3SafetyOff(db); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); if( rc==SQLITE_ABORT ) rc = initData.rc; sqlite3SafetyOn(db); sqliteFree(zSql); #ifndef SQLITE_OMIT_ANALYZE if( rc==SQLITE_OK ){ sqlite3AnalysisLoad(db, iDb); } #endif sqlite3BtreeCloseCursor(curMain); } if( sqlite3MallocFailed() ){ /* 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; }
/* ** 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; Db *pDb; char const *azArg[4]; 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 && iDb<db->nDb ); assert( db->aDb[iDb].pSchema ); assert( sqlite3_mutex_held(db->mutex) ); assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); /* 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. */ azArg[0] = zMasterName; azArg[1] = "1"; azArg[2] = zMasterSchema; azArg[3] = 0; initData.db = db; initData.iDb = iDb; initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; (void)sqlite3SafetyOff(db); sqlite3InitCallback(&initData, 3, (char **)azArg, 0); (void)sqlite3SafetyOn(db); if( initData.rc ){ rc = initData.rc; goto error_out; } pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); if( pTab ){ pTab->tabFlags |= TF_Readonly; } /* Create a cursor to hold the database open */ pDb = &db->aDb[iDb]; if( pDb->pBt==0 ){ if( !OMIT_TEMPDB && iDb==1 ){ DbSetProperty(db, 1, DB_SchemaLoaded); } return SQLITE_OK; } curMain = sqlite3MallocZero(sqlite3BtreeCursorSize()); if( !curMain ){ rc = SQLITE_NOMEM; goto error_out; } sqlite3BtreeEnter(pDb->pBt); rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, curMain); if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){ sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc)); goto initone_error_out; } /* 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 2:UTF-16LE 3:UTF-16BE ** meta[5] The user cookie. Used by the application. ** meta[6] Incremental-vacuum flag. ** meta[7] ** meta[8] ** meta[9] ** ** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to ** the possible values of meta[4]. */ if( rc==SQLITE_OK ){ int i; for(i=0; i<ArraySize(meta); i++){ rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]); if( rc ){ sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc)); goto initone_error_out; } } }else{ memset(meta, 0, sizeof(meta)); } pDb->pSchema->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 ENC(db). */ ENC(db) = (u8)meta[4]; db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0); }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( meta[4]!=ENC(db) ){ sqlite3SetString(pzErrMsg, db, "attached databases must use the same" " text encoding as main database"); rc = SQLITE_ERROR; goto initone_error_out; } } }else{ DbSetProperty(db, iDb, DB_Empty); } pDb->pSchema->enc = ENC(db); if( pDb->pSchema->cache_size==0 ){ size = meta[2]; if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; } if( size<0 ) size = -size; pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } /* ** file_format==1 Version 3.0.0. ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants */ pDb->pSchema->file_format = (u8)meta[1]; if( pDb->pSchema->file_format==0 ){ pDb->pSchema->file_format = 1; } if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){ sqlite3SetString(pzErrMsg, db, "unsupported file format"); rc = SQLITE_ERROR; goto initone_error_out; } /* Ticket #2804: When we open a database in the newer file format, ** clear the legacy_file_format pragma flag so that a VACUUM will ** not downgrade the database and thus invalidate any descending ** indices that the user might have created. */ if( iDb==0 && meta[1]>=4 ){ db->flags &= ~SQLITE_LegacyFileFmt; } /* 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(db, "SELECT name, rootpage, sql FROM '%q'.%s", db->aDb[iDb].zName, zMasterName); (void)sqlite3SafetyOff(db); #ifndef SQLITE_OMIT_AUTHORIZATION { int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); xAuth = db->xAuth; db->xAuth = 0; #endif rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; } #endif if( rc==SQLITE_OK ) rc = initData.rc; (void)sqlite3SafetyOn(db); sqlite3DbFree(db, zSql); #ifndef SQLITE_OMIT_ANALYZE if( rc==SQLITE_OK ){ sqlite3AnalysisLoad(db, iDb); } #endif } if( db->mallocFailed ){ rc = SQLITE_NOMEM; sqlite3ResetInternalSchema(db, 0); } if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){ /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider ** the schema loaded, even if errors occurred. In this situation the ** current sqlite3_prepare() operation will fail, but the following one ** will attempt to compile the supplied statement against whatever subset ** of the schema was loaded before the error occurred. The primary ** purpose of this is to allow access to the sqlite_master table ** even when its contents have been corrupted. */ DbSetProperty(db, iDb, DB_SchemaLoaded); rc = SQLITE_OK; } /* Jump here for an error that occurs after successfully allocating ** curMain and calling sqlite3BtreeEnter(). For an error that occurs ** before that point, jump to error_out. */ initone_error_out: sqlite3BtreeCloseCursor(curMain); sqlite3_free(curMain); sqlite3BtreeLeave(pDb->pBt); error_out: if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; } return rc; }
/* ** 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 && iDb<db->nDb ); /* 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 && i<sizeof(meta)/sizeof(meta[0]); i++){ rc = sqlite3BtreeGetMeta(db->aDb[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; }
void testUpdate() { puts("testUpdate()"); sqlite3 *db; char * file = UPDATE_FILE; int rc = sqlite3_open(file, &db); if (rc != SQLITE_OK) { printf("failed open: %d \n", rc); return; } if (db->nDb == 0) { puts("backends count is zero"); goto close; } Btree *pBt = db->aDb[0].pBt; rc = sqlite3BtreeBeginTrans(pBt, 1); if (rc != SQLITE_OK) { printf("failed begin transaction: %d", rc); goto close; } char* pData = "Test data"; int nData = strlen(pData); BtCursor cur; int x = 0; for (x = 1; x <= 3; x++) { int table = 0; rc = sqlite3BtreeCreateTable(pBt, &table, BTREE_INTKEY | BTREE_LEAFDATA); if (rc != SQLITE_OK) { printf("failed create table: %d", rc); goto close; } memset(&cur, 0, sizeof(BtCursor)); rc = sqlite3BtreeCursor(pBt, table, 0, 0, &cur); if (rc != SQLITE_OK) { printf("failed get cursor: %d", rc); goto close; } int y = 0; for (y = 1; y <= 3; y++) { rc = sqlite3BtreeInsert(&cur, NULL, y, pData, nData, 0, 0); if (rc != SQLITE_OK) { printf("failed insert data: %d", rc); goto close; } } rc = sqlite3BtreeCloseCursor(&cur); if (rc != SQLITE_OK) { printf("failed close cursor: %d", rc); goto close; } } rc = sqlite3BtreeCommit(pBt); if (rc != SQLITE_OK) { printf("failed commit transaction: %d", rc); } else { puts("success commit transaction"); } sqlite3_close(db); rc = sqlite3_open(file, &db); if (rc != SQLITE_OK) { printf("failed open: %d \n", rc); return; } if (db->nDb == 0) { puts("backends count is zero"); goto close; } pBt = db->aDb[0].pBt; rc = sqlite3BtreeBeginTrans(pBt, 1); if (rc != SQLITE_OK) { printf("failed begin transaction: %d", rc); goto close; } int pages = 0; rc = sqlite3PagerPagecount(pBt->pBt->pPager, &pages); if (rc != SQLITE_OK) { printf("failed get pages count: %d \n", rc); goto close; } if (pages == 0) { puts("pages count is zero"); goto close; } printf("pages count: %d \n", pages); pData = "Data test"; nData = strlen(pData); x = 0; for (x = 1; x <= pages; x++) { memset(&cur, 0, sizeof(BtCursor)); rc = sqlite3BtreeCursor(pBt, x, 1, 0, &cur); if (rc != SQLITE_OK) { printf("failed get cursor: %d", rc); goto close; } int next = 0; rc = sqlite3BtreeFirst(&cur, &next); if (rc != SQLITE_OK) { printf("failed first(): %d \n", rc); goto closeCursor; } if (next != 0) { puts("cursor is empty"); goto closeCursor; } sqlite3BtreeCacheOverflow(&cur); do { rc = sqlite3BtreePutData(&cur,0,nData,pData); if (rc != SQLITE_OK) { printf("failed putData(): %d \n", rc); goto closeCursor; } puts("data updated"); } while (SQLITE_OK == sqlite3BtreeNext(&cur, &next) && next == 0); closeCursor: rc = sqlite3BtreeCloseCursor(&cur); if (rc != SQLITE_OK) { printf("failed close cursor: %d", rc); goto close; } } rc = sqlite3BtreeCommit(pBt); if (rc != SQLITE_OK) { printf("failed commit transaction: %d", rc); } else { puts("success commit transaction"); } close: sqlite3_close(db); }
/* ** Reset an Agg structure. Delete all its contents. ** ** For installable aggregate functions, if the step function has been ** called, make sure the finalizer function has also been called. The ** finalizer might need to free memory that was allocated as part of its ** private context. If the finalizer has not been called yet, call it ** now. ** ** If db is NULL, then this is being called from sqliteVdbeReset(). In ** this case clean up all references to the temp-table used for ** aggregates (if it was ever opened). ** ** If db is not NULL, then this is being called from with an OP_AggReset ** opcode. Open the temp-table, if it has not already been opened and ** delete the contents of the table used for aggregate information, ready ** for the next round of aggregate processing. */ int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){ int rc = 0; BtCursor *pCsr = pAgg->pCsr; assert( (pCsr && pAgg->nTab>0) || (!pCsr && pAgg->nTab==0) || sqlite3_malloc_failed ); /* If pCsr is not NULL, then the table used for aggregate information ** is open. Loop through it and free the AggElem* structure pointed at ** by each entry. If the finalizer has not been called for an AggElem, ** do that too. Finally, clear the btree table itself. */ if( pCsr ){ int res; assert( pAgg->pBtree ); assert( pAgg->nTab>0 ); rc=sqlite3BtreeFirst(pCsr, &res); while( res==0 && rc==SQLITE_OK ){ AggElem *pElem; rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem); if( res!=SQLITE_OK ){ return rc; } assert( pAgg->apFunc!=0 ); freeAggElem(pElem, pAgg); rc=sqlite3BtreeNext(pCsr, &res); } if( rc!=SQLITE_OK ){ return rc; } sqlite3BtreeCloseCursor(pCsr); sqlite3BtreeClearTable(pAgg->pBtree, pAgg->nTab); }else{ /* The cursor may not be open because the aggregator was never used, ** or it could be that it was used but there was no GROUP BY clause. */ if( pAgg->pCurrent ){ freeAggElem(pAgg->pCurrent, pAgg); } } /* If db is not NULL and we have not yet and we have not yet opened ** the temporary btree then do so and create the table to store aggregate ** information. ** ** If db is NULL, then close the temporary btree if it is open. */ if( db ){ if( !pAgg->pBtree ){ assert( pAgg->nTab==0 ); rc = sqlite3BtreeFactory(db, ":memory:", 0, TEMP_PAGES, &pAgg->pBtree); if( rc!=SQLITE_OK ) return rc; sqlite3BtreeBeginTrans(pAgg->pBtree, 1); rc = sqlite3BtreeCreateTable(pAgg->pBtree, &pAgg->nTab, 0); if( rc!=SQLITE_OK ) return rc; } assert( pAgg->nTab!=0 ); rc = sqlite3BtreeCursor(pAgg->pBtree, pAgg->nTab, 1, sqlite3VdbeRecordCompare, pKeyInfo, &pAgg->pCsr); if( rc!=SQLITE_OK ) return rc; }else{ if( pAgg->pBtree ){ sqlite3BtreeClose(pAgg->pBtree); pAgg->pBtree = 0; pAgg->nTab = 0; } pAgg->pCsr = 0; } if( pAgg->apFunc ){ sqliteFree(pAgg->apFunc); pAgg->apFunc = 0; } pAgg->pCurrent = 0; pAgg->nMem = 0; pAgg->searching = 0; return SQLITE_OK; }
/* * Use Bulk Get/Put to copy the given number of pages worth of * records from the source database to the destination database, * this function should be called until all tables are copied, at * which point it will return SQLITE_DONE. Both Btrees need to * have transactions before calling this function. * p->pSrc - Source Btree * p->tables - Contains a list of iTables to copy, gotten using * btreeGetTables(). * p->currentTable - Index in tables of the current table being copied. * p->srcCur - Cursor on the current source table being copied. * p->pDest - Destiniation Btree. * p->destCur - BtCursor on the destination table being copied into. * pages - Number of pages worth of data to copy. */ static int btreeCopyPages(sqlite3_backup *p, int *pages) { DB *dbp; DBT dataOut, dataIn; char bufOut[MULTI_BUFSIZE], bufIn[MULTI_BUFSIZE]; int ret, rc, copied, srcIsDupIndex; void *in, *out, *app; ret = 0; rc = SQLITE_OK; dbp = NULL; copied = 0; memset(&dataOut, 0, sizeof(dataOut)); memset(&dataIn, 0, sizeof(dataIn)); dataOut.flags = DB_DBT_USERMEM; dataIn.flags = DB_DBT_USERMEM; dataOut.data = bufOut; dataOut.ulen = sizeof(bufOut); dataIn.data = bufIn; dataIn.ulen = sizeof(bufIn); while (*pages < 0 || *pages > copied) { /* No tables left to copy */ if (p->tables[p->currentTable] == -1) { u32 val; /* * Update the schema file format and largest rootpage * in the meta data. Other meta data values should * not be changed. */ sqlite3BtreeGetMeta(p->pSrc, 1, &val); if (p->pSrc->db->errCode == SQLITE_BUSY) { rc = SQLITE_BUSY; goto err; } rc = sqlite3BtreeUpdateMeta(p->pDest, 1, val); if (rc != SQLITE_OK) goto err; sqlite3BtreeGetMeta(p->pSrc, 3, &val); if (p->pSrc->db->errCode == SQLITE_BUSY) { rc = SQLITE_BUSY; goto err; } rc = sqlite3BtreeUpdateMeta(p->pDest, 3, val); if (rc != SQLITE_OK) goto err; ret = SQLITE_DONE; goto err; } /* If not currently copying a table, get the next table. */ if (!p->srcCur) { rc = btreeGetUserTable(p->pSrc, p->srcTxn, &dbp, p->tables[p->currentTable]); if (rc != SQLITE_OK) goto err; assert(dbp); memset(&p->destCur, 0, sizeof(p->destCur)); /* * Open a cursor on the destination table, this will * create the table and allow the Btree to manage the * DB object. */ sqlite3BtreeCursor(p->pDest, p->tables[p->currentTable], 1, dbp->app_private, &p->destCur); if ((rc = p->destCur.error) != SQLITE_OK) { app = dbp->app_private; dbp->close(dbp, DB_NOSYNC); if (app) sqlite3DbFree(p->pSrcDb, app); goto err; } /* Open a cursor on the source table. */ if ((ret = dbp->cursor(dbp, p->srcTxn, &p->srcCur, 0)) != 0) goto err; dbp = 0; } srcIsDupIndex = isDupIndex((p->tables[p->currentTable] & 1) ? BTREE_INTKEY : 0, p->pSrc->pBt->dbStorage, p->srcCur->dbp->app_private, p->srcCur->dbp); /* * Copy the current table until the given number of * pages is copied, or the entire table has been copied. */ while (*pages < 0 || *pages > copied) { DBT key, data; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); /* Do a Bulk Get from the source table. */ ret = p->srcCur->get(p->srcCur, &key, &dataOut, DB_NEXT | DB_MULTIPLE_KEY); if (ret == DB_NOTFOUND) break; if (ret != 0) goto err; /* Copy the records into the Bulk buffer. */ DB_MULTIPLE_INIT(out, &dataOut); DB_MULTIPLE_WRITE_INIT(in, &dataIn); DB_MULTIPLE_KEY_NEXT(out, &dataOut, key.data, key.size, data.data, data.size); while (out) { /* * Have to translate the index formats if they * are not the same. */ if (p->destCur.isDupIndex != srcIsDupIndex) { if (srcIsDupIndex) { p->destCur.key = key; p->destCur.data = data; if (!btreeCreateIndexKey( &p->destCur)) { rc = SQLITE_NOMEM; goto err; } DB_MULTIPLE_KEY_WRITE_NEXT(in, &dataIn, p->destCur.index.data, p->destCur.index.size, p->destCur.data.data, 0); } else { /* Copy the key into the cursor * index since spliting the key * requires changing the * internal memory. */ if (!allocateCursorIndex( &p->destCur, key.size)) { rc = SQLITE_NOMEM; goto err; } memcpy(p->destCur.index.data, key.data, key.size); p->destCur.index.size = key.size; p->destCur.key.data = p->destCur.index.data; p->destCur.key.size = p->destCur.index.size; splitIndexKey(&p->destCur); DB_MULTIPLE_KEY_WRITE_NEXT( in, &dataIn, p->destCur.key.data, p->destCur.key.size, p->destCur.data.data, p->destCur.data.size); } } else DB_MULTIPLE_KEY_WRITE_NEXT(in, &dataIn, key.data, key.size, data.data, data.size); DB_MULTIPLE_KEY_NEXT(out, &dataOut, key.data, key.size, data.data, data.size); } /* Insert into the destination table. */ dbp = p->destCur.cached_db->dbp; if ((ret = dbp->put(dbp, p->pDest->savepoint_txn, &dataIn, 0, DB_MULTIPLE_KEY)) != 0) goto err; dbp = NULL; copied += MULTI_BUFSIZE/SQLITE_DEFAULT_PAGE_SIZE; } /* * Done copying the current table, time to look for a new * table to copy. */ if (ret == DB_NOTFOUND) { ret = 0; rc = sqlite3BtreeCloseCursor(&p->destCur); if (p->srcCur) { app = p->srcCur->dbp->app_private; dbp = p->srcCur->dbp; p->srcCur->close(p->srcCur); ret = dbp->close(dbp, DB_NOSYNC); if (app) sqlite3DbFree(p->pSrcDb, app); } p->srcCur = NULL; if (ret != 0 || rc != SQLITE_OK) goto err; p->currentTable += 1; } } goto done; err: if (ret == SQLITE_DONE) return ret; done: return MAP_ERR(rc, ret); }
/* Close or free all handles and commit or rollback the transaction. */ static int backupCleanup(sqlite3_backup *p) { int rc, rc2, ret; void *app; DB *db; rc = rc2 = SQLITE_OK; if (!p || p->rc == SQLITE_OK) return rc; rc2 = sqlite3BtreeCloseCursor(&p->destCur); if (rc2 != SQLITE_OK) rc = rc2; if (p->srcCur) { db = p->srcCur->dbp; app = db->app_private; if ((ret = p->srcCur->close(p->srcCur)) == 0) ret = db->close(db, DB_NOSYNC); rc2 = dberr2sqlite(ret); /* * The KeyInfo was allocated in btreeSetupIndex, * so have to deallocate it here. */ if (app) sqlite3DbFree(p->pSrcDb, app); } if (rc2 != SQLITE_OK) rc = rc2; p->srcCur = 0; /* * May retry on a locked or busy error, so keep * these values. */ if (p->rc != SQLITE_LOCKED && p->rc != SQLITE_BUSY) { if (p->srcName) sqlite3_free(p->srcName); if (p->destName != 0) sqlite3_free(p->destName); p->srcName = p->destName = NULL; } if (p->tables != 0) sqlite3_free(p->tables); p->tables = NULL; if (p->pSrc->nBackup) p->pSrc->nBackup--; if (p->pDest != NULL && p->pDest->nBackup) p->pDest->nBackup--; if (p->srcTxn) { if (p->rc == SQLITE_DONE) ret = p->srcTxn->commit(p->srcTxn, 0); else ret = p->srcTxn->abort(p->srcTxn); rc2 = dberr2sqlite(ret); } p->srcTxn = 0; if (rc2 != SQLITE_OK && sqlite3BtreeIsInTrans(p->pDest)) { rc = rc2; if (p->rc == SQLITE_DONE) rc2 = sqlite3BtreeCommit(p->pDest); else rc2 = sqlite3BtreeRollback(p->pDest); if (rc2 != SQLITE_OK) rc = rc2; } if (p->pDest && p->openDest) { char path[512]; /* * If successfully done then delete the old backup, if * an error then delete the current database and restore * the old backup. */ sqlite3_snprintf(sizeof(path), path, "%s%s", p->fullName, BACKUP_SUFFIX); if (p->rc == SQLITE_DONE) { rc2 = btreeDeleteEnvironment(p->pDest, path, 0); } else { rc2 = btreeDeleteEnvironment(p->pDest, p->fullName, 0); if (!__os_exists(NULL, path, 0)) __os_rename(NULL, path, p->fullName, 0); } if (rc == SQLITE_OK) rc = rc2; if (rc == SQLITE_OK) { p->pDest = NULL; p->pDestDb->aDb[p->iDb].pBt = NULL; p->openDest = 0; rc = sqlite3BtreeOpen(p->fullName, p->pDestDb, &p->pDest, SQLITE_DEFAULT_CACHE_SIZE | SQLITE_OPEN_MAIN_DB, p->pDestDb->openFlags); p->pDestDb->aDb[p->iDb].pBt = p->pDest; if (rc == SQLITE_OK) { p->pDestDb->aDb[p->iDb].pSchema = sqlite3SchemaGet(p->pDestDb, p->pDest); if (!p->pDestDb->aDb[p->iDb].pSchema) p->rc = SQLITE_NOMEM; } else p->pDestDb->aDb[p->iDb].pSchema = NULL; if (rc == SQLITE_OK) p->pDest->pBt->db_oflags |= DB_CREATE; /* * Have to delete the schema here on error to avoid * assert failure. */ if (p->pDest == NULL && p->pDestDb->aDb[p->iDb].pSchema != NULL) { sqlite3SchemaClear( p->pDestDb->aDb[p->iDb].pSchema); p->pDestDb->aDb[p->iDb].pSchema = NULL; } #ifdef SQLITE_HAS_CODEC if (rc == SQLITE_OK) { if (p->iDb == 0) rc = sqlite3_key(p->pDestDb, p->pSrc->pBt->encrypt_pwd, p->pSrc->pBt->encrypt_pwd_len); else rc = sqlite3CodecAttach(p->pDestDb, p->iDb, p->pSrc->pBt->encrypt_pwd, p->pSrc->pBt->encrypt_pwd_len); } #endif } } if (p->rc != SQLITE_LOCKED && p->rc != SQLITE_BUSY) { if (p->fullName != 0) sqlite3_free(p->fullName); p->fullName = NULL; } p->lastUpdate = p->pSrc->updateDuringBackup; return rc; }