summaryrefslogtreecommitdiff
path: root/ext/sqlite/libsqlite/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/sqlite/libsqlite/src/main.c')
-rw-r--r--ext/sqlite/libsqlite/src/main.c464
1 files changed, 233 insertions, 231 deletions
diff --git a/ext/sqlite/libsqlite/src/main.c b/ext/sqlite/libsqlite/src/main.c
index b708b00c2a..ebba7cbc57 100644
--- a/ext/sqlite/libsqlite/src/main.c
+++ b/ext/sqlite/libsqlite/src/main.c
@@ -29,6 +29,13 @@ typedef struct {
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){
+ sqliteSetString(pData->pzErrMsg, "malformed database schema", 0);
+}
/*
** This is the callback routine for the code that initializes the
@@ -40,7 +47,8 @@ typedef struct {
** 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
+** argv[4] = "1" for temporary files, "0" for main database, "2" or more
+** for auxiliary database files.
**
*/
static
@@ -49,15 +57,19 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
Parse sParse;
int nErr = 0;
- /* TODO: Do some validity checks on all fields. In particular,
- ** make sure fields do not contain NULLs. Otherwise we might core
- ** when attempting to initialize from a corrupt database file. */
-
assert( argc==5 );
+ if( argv[0]==0 ){
+ corruptSchema(pData);
+ return 1;
+ }
switch( argv[0][0] ){
case 'v':
case 'i':
case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
+ if( argv[2]==0 || argv[4]==0 ){
+ corruptSchema(pData);
+ return 1;
+ }
if( argv[3] && argv[3][0] ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
** But because sParse.initFlag is set to 1, no VDBE code is generated
@@ -67,7 +79,8 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
memset(&sParse, 0, sizeof(sParse));
sParse.db = pData->db;
sParse.initFlag = 1;
- sParse.isTemp = argv[4][0] - '0';
+ sParse.iDb = atoi(argv[4]);
+ sParse.useDb = -1;
sParse.newTnum = atoi(argv[2]);
sParse.useCallback = 1;
sqliteRunParser(&sParse, argv[3], pData->pzErrMsg);
@@ -78,7 +91,12 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
** 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 = sqliteFindIndex(pData->db, argv[1]);
+ int iDb;
+ Index *pIndex;
+
+ iDb = atoi(argv[4]);
+ assert( iDb>=0 && iDb<pData->db->nDb );
+ pIndex = sqliteFindIndex(pData->db, argv[1], pData->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
@@ -118,7 +136,7 @@ int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
Trigger *pTrig;
char *zErr = 0;
- pTab = sqliteFindTable(pData->db, argv[0]);
+ pTab = sqliteFindTable(pData->db, argv[0], 0);
assert( pTab!=0 );
assert( sqliteStrICmp(pTab->zName, argv[0])==0 );
if( pTab ){
@@ -141,7 +159,7 @@ int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
** cause the structure that pTab points to be deleted. In case that
** happened, we need to refetch pTab.
*/
- pTab = sqliteFindTable(pData->db, argv[0]);
+ pTab = sqliteFindTable(pData->db, argv[0], 0);
if( pTab ){
assert( sqliteStrICmp(pTab->zName, argv[0])==0 );
pTab->pTrigger = pTrig; /* Re-enable triggers */
@@ -153,22 +171,19 @@ int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
/*
** Attempt to read the database schema and initialize internal
-** data structures. Return one of the SQLITE_ error codes to
+** 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.
-**
-** 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
-** has the sqlite_master table locked) than another attempt
-** is made the first time the database is accessed.
*/
-int sqliteInit(sqlite *db, char **pzErrMsg){
+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];
Parse sParse;
InitData initData;
@@ -223,103 +238,161 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
"WHERE type='index'";
+ assert( iDb>=0 && iDb!=1 && iDb<db->nDb );
+
/* Construct the schema tables: sqlite_master and sqlite_temp_master
*/
azArg[0] = "table";
azArg[1] = MASTER_NAME;
azArg[2] = "2";
azArg[3] = master_schema;
- azArg[4] = "0";
+ 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);
+ pTab = sqliteFindTable(db, MASTER_NAME, "main");
if( pTab ){
pTab->readOnly = 1;
}
- azArg[1] = TEMP_MASTER_NAME;
- azArg[3] = temp_master_schema;
- azArg[4] = "1";
- sqliteInitCallback(&initData, 5, azArg, 0);
- pTab = sqliteFindTable(db, TEMP_MASTER_NAME);
- 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;
+ }
}
/* Create a cursor to hold the database open
*/
- if( db->pBe==0 ) return SQLITE_OK;
- rc = sqliteBtreeCursor(db->pBe, 2, 0, &curMain);
+ 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), 0);
- sqliteResetInternalSchema(db);
return rc;
}
/* Get the database meta information
*/
- rc = sqliteBtreeGetMeta(db->pBe, meta);
+ rc = sqliteBtreeGetMeta(db->aDb[iDb].pBt, meta);
if( rc ){
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
- sqliteResetInternalSchema(db);
sqliteBtreeCloseCursor(curMain);
return rc;
}
- db->schema_cookie = meta[1];
- db->next_cookie = db->schema_cookie;
- db->file_format = meta[2];
- size = meta[3];
- if( size==0 ){ size = MAX_PAGES; }
- db->cache_size = size;
- sqliteBtreeSetCacheSize(db->pBe, size);
- db->safety_level = meta[4];
- if( db->safety_level==0 ) db->safety_level = 2;
- sqliteBtreeSetSafetyLevel(db->pBe, db->safety_level);
-
- /*
- ** 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", 0);
- return SQLITE_ERROR;
+ 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", 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, 0);
+ }else{
+ sqliteSetString(pzErrMsg, "incompatible file format in auxiliary "
+ "database: ", db->aDb[iDb].zName, 0);
+ }
+ sqliteBtreeClose(db->aDb[iDb].pBt);
+ db->aDb[iDb].pBt = 0;
+ return SQLITE_FORMAT;
}
+ sqliteBtreeSetCacheSize(db->aDb[iDb].pBt, size);
+ sqliteBtreeSetSafetyLevel(db->aDb[iDb].pBt, meta[4]==0 ? 2 : meta[4]);
/* Read the schema information out of the schema tables
*/
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
- sParse.pBe = db->pBe;
sParse.xCallback = sqliteInitCallback;
sParse.pArg = (void*)&initData;
sParse.initFlag = 1;
+ sParse.useDb = -1;
sParse.useCallback = 1;
- sqliteRunParser(&sParse,
- db->file_format>=2 ? init_script : older_init_script,
- pzErrMsg);
+ if( iDb==0 ){
+ sqliteRunParser(&sParse,
+ db->file_format>=2 ? init_script : older_init_script,
+ pzErrMsg);
+ }else{
+ char *zSql = 0;
+ sqliteSetString(&zSql,
+ "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
+ db->aDb[iDb].zName, "\".sqlite_master", 0);
+ sqliteRunParser(&sParse, zSql, pzErrMsg);
+ sqliteFree(zSql);
+ }
+ sqliteBtreeCloseCursor(curMain);
if( sqlite_malloc_failed ){
sqliteSetString(pzErrMsg, "out of memory", 0);
sParse.rc = SQLITE_NOMEM;
- sqliteBtreeRollback(db->pBe);
- sqliteResetInternalSchema(db);
+ sqliteResetInternalSchema(db, 0);
}
if( sParse.rc==SQLITE_OK ){
+ DbSetProperty(db, iDb, DB_SchemaLoaded);
+ if( iDb==0 ){
+ DbSetProperty(db, 1, DB_SchemaLoaded);
+ }
+ }else{
+ sqliteResetInternalSchema(db, iDb);
+ }
+ return sParse.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
+** has the sqlite_master table locked) than another attempt
+** is made the first time the database is accessed.
+*/
+int sqliteInit(sqlite *db, char **pzErrMsg){
+ int i, rc;
+
+ assert( (db->flags & SQLITE_Initialized)==0 );
+ rc = SQLITE_OK;
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
+ if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue;
+ assert( i!=1 ); /* Should have been initialized together with 0 */
+ rc = sqliteInitOne(db, i, pzErrMsg);
+ }
+ if( rc==SQLITE_OK ){
db->flags |= SQLITE_Initialized;
sqliteCommitInternalChanges(db);
}else{
db->flags &= ~SQLITE_Initialized;
- sqliteResetInternalSchema(db);
}
- sqliteBtreeCloseCursor(curMain);
- return sParse.rc;
+ return rc;
}
/*
@@ -349,23 +422,27 @@ const char sqlite_encoding[] = "iso8859";
*/
sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
sqlite *db;
- int rc;
+ int rc, i;
/* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite) );
if( pzErrMsg ) *pzErrMsg = 0;
if( db==0 ) goto no_mem_on_open;
- sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
- sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
- sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0);
- sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
- sqliteHashInit(&db->aFKey, SQLITE_HASH_STRING, 1);
db->onError = OE_Default;
db->priorNewRowid = 0;
db->magic = SQLITE_MAGIC_BUSY;
+ db->nDb = 2;
+ db->aDb = db->aDbStatic;
+ sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
+ for(i=0; i<db->nDb; i++){
+ sqliteHashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
+ sqliteHashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0);
+ sqliteHashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);
+ sqliteHashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1);
+ }
/* Open the backend database driver */
- rc = sqliteBtreeOpen(zFilename, 0, MAX_PAGES, &db->pBe);
+ rc = sqliteBtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
if( rc!=SQLITE_OK ){
switch( rc ){
default: {
@@ -376,6 +453,8 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
sqliteStrRealloc(pzErrMsg);
return 0;
}
+ db->aDb[0].zName = "main";
+ db->aDb[1].zName = "temp";
/* Attempt to read the schema */
sqliteRegisterBuiltinFunctions(db);
@@ -412,9 +491,9 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
&initData,
&zErr);
if( rc==SQLITE_OK ){
- sqliteBtreeGetMeta(db->pBe, meta);
+ sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
meta[2] = 4;
- sqliteBtreeUpdateMeta(db->pBe, meta);
+ sqliteBtreeUpdateMeta(db->aDb[0].pBt, meta);
sqlite_exec(db, "COMMIT", 0, 0, 0);
}
if( rc!=SQLITE_OK ){
@@ -457,17 +536,26 @@ int sqlite_changes(sqlite *db){
*/
void sqlite_close(sqlite *db){
HashElem *i;
+ int j;
db->want_to_close = 1;
if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){
/* printf("DID NOT CLOSE\n"); fflush(stdout); */
return;
}
db->magic = SQLITE_MAGIC_CLOSED;
- sqliteBtreeClose(db->pBe);
- sqliteResetInternalSchema(db);
- if( db->pBeTemp ){
- sqliteBtreeClose(db->pBeTemp);
+ for(j=0; j<db->nDb; j++){
+ if( db->aDb[j].pBt ){
+ sqliteBtreeClose(db->aDb[j].pBt);
+ db->aDb[j].pBt = 0;
+ }
+ if( j>=2 ){
+ sqliteFree(db->aDb[j].zName);
+ db->aDb[j].zName = 0;
+ }
}
+ sqliteResetInternalSchema(db, 0);
+ assert( db->nDb<=2 );
+ assert( db->aDb==db->aDbStatic );
for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
FuncDef *pFunc, *pNext;
for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){
@@ -476,120 +564,21 @@ void sqlite_close(sqlite *db){
}
}
sqliteHashClear(&db->aFunc);
- sqliteHashClear(&db->aFKey);
sqliteFree(db);
}
/*
-** Return TRUE if the given SQL string ends in a semicolon.
-**
-** Special handling is require for CREATE TRIGGER statements.
-** Whenever the CREATE TRIGGER keywords are seen, the statement
-** must end with ";END;".
+** Rollback all database files.
*/
-int sqlite_complete(const char *zSql){
- int isComplete = 1;
- int requireEnd = 0;
- int seenText = 0;
- int seenCreate = 0;
- while( *zSql ){
- switch( *zSql ){
- case ';': {
- isComplete = 1;
- seenText = 1;
- seenCreate = 0;
- break;
- }
- case ' ':
- case '\t':
- case '\n':
- case '\f': {
- break;
- }
- case '[': {
- isComplete = 0;
- seenText = 1;
- seenCreate = 0;
- zSql++;
- while( *zSql && *zSql!=']' ){ zSql++; }
- if( *zSql==0 ) return 0;
- break;
- }
- case '"':
- case '\'': {
- int c = *zSql;
- isComplete = 0;
- seenText = 1;
- seenCreate = 0;
- zSql++;
- while( *zSql && *zSql!=c ){ zSql++; }
- if( *zSql==0 ) return 0;
- break;
- }
- case '-': {
- if( zSql[1]!='-' ){
- isComplete = 0;
- seenCreate = 0;
- break;
- }
- while( *zSql && *zSql!='\n' ){ zSql++; }
- if( *zSql==0 ) return seenText && isComplete && requireEnd==0;
- break;
- }
- case 'c':
- case 'C': {
- seenText = 1;
- if( !isComplete ) break;
- isComplete = 0;
- if( sqliteStrNICmp(zSql, "create", 6)!=0 ) break;
- if( !isspace(zSql[6]) ) break;
- zSql += 5;
- seenCreate = 1;
- while( isspace(zSql[1]) ) zSql++;
- if( sqliteStrNICmp(&zSql[1],"trigger", 7)!=0 ) break;
- zSql += 7;
- requireEnd++;
- break;
- }
- case 't':
- case 'T': {
- seenText = 1;
- if( !seenCreate ) break;
- seenCreate = 0;
- isComplete = 0;
- if( sqliteStrNICmp(zSql, "trigger", 7)!=0 ) break;
- if( !isspace(zSql[7]) ) break;
- zSql += 6;
- requireEnd++;
- break;
- }
- case 'e':
- case 'E': {
- seenCreate = 0;
- seenText = 1;
- if( !isComplete ) break;
- isComplete = 0;
- if( requireEnd==0 ) break;
- if( sqliteStrNICmp(zSql, "end", 3)!=0 ) break;
- zSql += 2;
- while( isspace(zSql[1]) ) zSql++;
- if( zSql[1]==';' ){
- zSql++;
- isComplete = 1;
- requireEnd--;
- }
- break;
- }
- default: {
- seenCreate = 0;
- seenText = 1;
- isComplete = 0;
- break;
- }
+void sqliteRollbackAll(sqlite *db){
+ int i;
+ for(i=0; i<db->nDb; i++){
+ if( db->aDb[i].pBt ){
+ sqliteBtreeRollback(db->aDb[i].pBt);
+ db->aDb[i].inTrans = 0;
}
- zSql++;
}
- return seenText && isComplete && requireEnd==0;
+ sqliteRollbackInternalChanges(db);
}
/*
@@ -632,21 +621,18 @@ static int sqliteMain(
if( db->pVdbe==0 ){ db->nChange = 0; }
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
- sParse.pBe = db->pBe;
sParse.xCallback = xCallback;
sParse.pArg = pArg;
+ sParse.useDb = -1;
sParse.useCallback = ppVm==0;
-#ifndef SQLITE_OMIT_TRACE
if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
-#endif
sqliteRunParser(&sParse, zSql, pzErrMsg);
if( sqlite_malloc_failed ){
sqliteSetString(pzErrMsg, "out of memory", 0);
sParse.rc = SQLITE_NOMEM;
- sqliteBtreeRollback(db->pBe);
- if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
+ sqliteRollbackAll(db);
+ sqliteResetInternalSchema(db, 0);
db->flags &= ~SQLITE_InTrans;
- sqliteResetInternalSchema(db);
}
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
@@ -654,7 +640,7 @@ static int sqliteMain(
}
sqliteStrRealloc(pzErrMsg);
if( sParse.rc==SQLITE_SCHEMA ){
- sqliteResetInternalSchema(db);
+ sqliteResetInternalSchema(db, 0);
}
if( sParse.useCallback==0 ){
assert( ppVm );
@@ -937,53 +923,69 @@ int sqlite_function_type(sqlite *db, const char *zName, int dataType){
** sqlite_exec().
*/
void *sqlite_trace(sqlite *db, void (*xTrace)(void*,const char*), void *pArg){
-#ifndef SQLITE_OMIT_TRACE
void *pOld = db->pTraceArg;
db->xTrace = xTrace;
db->pTraceArg = pArg;
return pOld;
-#else
- return 0;
-#endif
}
-
/*
-** Attempt to open the file named in the argument as the auxiliary database
-** file. The auxiliary database file is used to store TEMP tables. But
-** by using this API, it is possible to trick SQLite into opening two
-** separate databases and acting on them as if they were one.
+** This routine is called to create a connection to a database BTree
+** driver. If zFilename is the name of a file, then that file is
+** opened and used. If zFilename is the magic name ":memory:" then
+** the database is stored in memory (and is thus forgotten as soon as
+** the connection is closed.) If zFilename is NULL then the database
+** is for temporary use only and is deleted as soon as the connection
+** is closed.
**
-** This routine closes the existing auxiliary database file, which will
-** cause any previously created TEMP tables to be dropped.
+** A temporary database can be either a disk file (that is automatically
+** deleted when the file is closed) or a set of red-black trees held in memory,
+** depending on the values of the TEMP_STORE compile-time macro and the
+** db->temp_store variable, according to the following chart:
**
-** The zName parameter can be a NULL pointer or an empty string to cause
-** a temporary file to be opened and automatically deleted when closed.
+** TEMP_STORE db->temp_store Location of temporary database
+** ---------- -------------- ------------------------------
+** 0 any file
+** 1 1 file
+** 1 2 memory
+** 1 0 file
+** 2 1 file
+** 2 2 memory
+** 2 0 memory
+** 3 any memory
*/
-int sqlite_open_aux_file(sqlite *db, const char *zName, char **pzErrMsg){
- int rc;
- if( zName && zName[0]==0 ) zName = 0;
- if( sqliteSafetyOn(db) ) goto openaux_misuse;
- sqliteResetInternalSchema(db);
- if( db->pBeTemp!=0 ){
- sqliteBtreeClose(db->pBeTemp);
- }
- rc = sqliteBtreeOpen(zName, 0, MAX_PAGES, &db->pBeTemp);
- if( rc ){
- if( zName==0 ) zName = "a temporary file";
- sqliteSetString(pzErrMsg, "unable to open ", zName,
- ": ", sqlite_error_string(rc), 0);
- sqliteStrRealloc(pzErrMsg);
- sqliteSafetyOff(db);
- return rc;
+int sqliteBtreeFactory(
+ const sqlite *db, /* Main database when opening aux otherwise 0 */
+ const char *zFilename, /* Name of the file containing the BTree database */
+ int omitJournal, /* if TRUE then do not journal this file */
+ int nCache, /* How many pages in the page cache */
+ Btree **ppBtree){ /* Pointer to new Btree object written here */
+
+ assert( ppBtree != 0);
+
+#ifndef SQLITE_OMIT_INMEMORYDB
+ if( zFilename==0 ){
+ if (TEMP_STORE == 0) {
+ /* Always use file based temporary DB */
+ return sqliteBtreeOpen(0, omitJournal, nCache, ppBtree);
+ } else if (TEMP_STORE == 1 || TEMP_STORE == 2) {
+ /* Switch depending on compile-time and/or runtime settings. */
+ int location = db->temp_store==0 ? TEMP_STORE : db->temp_store;
+
+ if (location == 1) {
+ return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree);
+ } else {
+ return sqliteRbtreeOpen(0, 0, 0, ppBtree);
+ }
+ } else {
+ /* Always use in-core DB */
+ return sqliteRbtreeOpen(0, 0, 0, ppBtree);
+ }
+ }else if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){
+ return sqliteRbtreeOpen(0, 0, 0, ppBtree);
+ }else
+#endif
+ {
+ return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree);
}
- rc = sqliteInit(db, pzErrMsg);
- if( sqliteSafetyOff(db) ) goto openaux_misuse;
- sqliteStrRealloc(pzErrMsg);
- return rc;
-
-openaux_misuse:
- sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0);
- sqliteStrRealloc(pzErrMsg);
- return SQLITE_MISUSE;
}