From f78ceafdced34a38196128d413a5bc078c7c6203 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 28 Oct 2007 05:48:06 +0000 Subject: [PATCH] updated to sqlite-3.5.1 now that it's stable used new shared cache functionality (yay) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401651 --- extensions/sqlite/driver/SqDriver.cpp | 29 +- extensions/sqlite/driver/SqDriver.h | 1 + extensions/sqlite/msvc8/sm_sqlite.vcproj | 30 +- extensions/sqlite/sqlite-source/alter.c | 69 +- extensions/sqlite/sqlite-source/analyze.c | 22 +- extensions/sqlite/sqlite-source/attach.c | 37 +- extensions/sqlite/sqlite-source/auth.c | 9 +- extensions/sqlite/sqlite-source/btree.c | 1178 ++++++++--- extensions/sqlite/sqlite-source/btree.h | 57 +- extensions/sqlite/sqlite-source/btreeInt.h | 94 +- extensions/sqlite/sqlite-source/build.c | 248 ++- extensions/sqlite/sqlite-source/callback.c | 32 +- extensions/sqlite/sqlite-source/complete.c | 16 +- extensions/sqlite/sqlite-source/date.c | 49 +- extensions/sqlite/sqlite-source/delete.c | 6 +- extensions/sqlite/sqlite-source/expr.c | 274 +-- extensions/sqlite/sqlite-source/func.c | 258 +-- extensions/sqlite/sqlite-source/hash.c | 57 +- extensions/sqlite/sqlite-source/hash.h | 5 +- extensions/sqlite/sqlite-source/insert.c | 19 +- extensions/sqlite/sqlite-source/journal.c | 238 +++ extensions/sqlite/sqlite-source/keywordhash.h | 2 +- extensions/sqlite/sqlite-source/legacy.c | 12 +- extensions/sqlite/sqlite-source/main.c | 405 ++-- extensions/sqlite/sqlite-source/malloc.c | 815 +------ extensions/sqlite/sqlite-source/mem1.c | 229 ++ extensions/sqlite/sqlite-source/mem2.c | 546 +++++ extensions/sqlite/sqlite-source/mutex.c | 126 ++ extensions/sqlite/sqlite-source/mutex.h | 82 + extensions/sqlite/sqlite-source/mutex_unix.c | 223 ++ extensions/sqlite/sqlite-source/mutex_w32.c | 208 ++ extensions/sqlite/sqlite-source/opcodes.c | 291 +-- extensions/sqlite/sqlite-source/os.c | 294 ++- extensions/sqlite/sqlite-source/os.h | 368 +--- extensions/sqlite/sqlite-source/os_common.h | 73 +- extensions/sqlite/sqlite-source/os_unix.c | 1882 ++++++++--------- extensions/sqlite/sqlite-source/os_win.c | 1379 +++++------- extensions/sqlite/sqlite-source/pager.c | 1793 +++++++++++----- extensions/sqlite/sqlite-source/pager.h | 11 +- extensions/sqlite/sqlite-source/parse.c | 972 ++++----- extensions/sqlite/sqlite-source/pragma.c | 46 +- extensions/sqlite/sqlite-source/prepare.c | 119 +- extensions/sqlite/sqlite-source/printf.c | 86 +- extensions/sqlite/sqlite-source/random.c | 11 +- extensions/sqlite/sqlite-source/select.c | 236 ++- extensions/sqlite/sqlite-source/sqlite3.h | 1160 ++++++++-- extensions/sqlite/sqlite-source/sqlite3ext.h | 52 + extensions/sqlite/sqlite-source/sqliteInt.h | 372 ++-- extensions/sqlite/sqlite-source/sqliteLimit.h | 11 + extensions/sqlite/sqlite-source/table.c | 17 +- extensions/sqlite/sqlite-source/tokenize.c | 37 +- extensions/sqlite/sqlite-source/trigger.c | 109 +- extensions/sqlite/sqlite-source/update.c | 31 +- extensions/sqlite/sqlite-source/utf.c | 209 +- extensions/sqlite/sqlite-source/util.c | 58 +- extensions/sqlite/sqlite-source/vacuum.c | 8 +- extensions/sqlite/sqlite-source/vdbe.c | 170 +- extensions/sqlite/sqlite-source/vdbe.h | 1 + extensions/sqlite/sqlite-source/vdbeInt.h | 16 +- extensions/sqlite/sqlite-source/vdbeapi.c | 286 ++- extensions/sqlite/sqlite-source/vdbeaux.c | 352 +-- extensions/sqlite/sqlite-source/vdbeblob.c | 92 +- extensions/sqlite/sqlite-source/vdbefifo.c | 6 +- extensions/sqlite/sqlite-source/vdbemem.c | 110 +- extensions/sqlite/sqlite-source/vtab.c | 108 +- extensions/sqlite/sqlite-source/where.c | 104 +- 66 files changed, 9797 insertions(+), 6449 deletions(-) create mode 100644 extensions/sqlite/sqlite-source/journal.c create mode 100644 extensions/sqlite/sqlite-source/mem1.c create mode 100644 extensions/sqlite/sqlite-source/mem2.c create mode 100644 extensions/sqlite/sqlite-source/mutex.c create mode 100644 extensions/sqlite/sqlite-source/mutex.h create mode 100644 extensions/sqlite/sqlite-source/mutex_unix.c create mode 100644 extensions/sqlite/sqlite-source/mutex_w32.c diff --git a/extensions/sqlite/driver/SqDriver.cpp b/extensions/sqlite/driver/SqDriver.cpp index d3fe1b63..67b6fa6d 100644 --- a/extensions/sqlite/driver/SqDriver.cpp +++ b/extensions/sqlite/driver/SqDriver.cpp @@ -67,11 +67,14 @@ SqDriver::SqDriver() { m_Handle = BAD_HANDLE; m_pOpenLock = NULL; + m_bThreadSafe = false; } void SqDriver::Initialize() { m_pOpenLock = threader->MakeMutex(); + + InitializeThreadSafety(); } void SqDriver::Shutdown() @@ -80,6 +83,11 @@ void SqDriver::Shutdown() { m_pOpenLock->DestroyThis(); } + + if (m_bThreadSafe) + { + sqlite3_enable_shared_cache(0); + } } bool SqDriver::IsThreadSafe() @@ -89,10 +97,23 @@ bool SqDriver::IsThreadSafe() bool SqDriver::InitializeThreadSafety() { - /* sqlite should be thread safe if the locks are done right. - * we don't enable the "shared cache" because it can corrupt - * open databases! - */ + if (m_bThreadSafe) + { + return true; + } + + if (sqlite3_threadsafe() == 0) + { + return false; + } + + if (sqlite3_enable_shared_cache(1) != SQLITE_OK) + { + return false; + } + + m_bThreadSafe = true; + return true; } diff --git a/extensions/sqlite/driver/SqDriver.h b/extensions/sqlite/driver/SqDriver.h index 78384e83..2cd429e6 100644 --- a/extensions/sqlite/driver/SqDriver.h +++ b/extensions/sqlite/driver/SqDriver.h @@ -72,6 +72,7 @@ private: Handle_t m_Handle; IMutex *m_pOpenLock; List m_Cache; + bool m_bThreadSafe; }; extern SqDriver g_SqDriver; diff --git a/extensions/sqlite/msvc8/sm_sqlite.vcproj b/extensions/sqlite/msvc8/sm_sqlite.vcproj index 16839b5c..8d9eb24f 100644 --- a/extensions/sqlite/msvc8/sm_sqlite.vcproj +++ b/extensions/sqlite/msvc8/sm_sqlite.vcproj @@ -121,7 +121,7 @@ Name="VCCLCompilerTool" FavorSizeOrSpeed="1" AdditionalIncludeDirectories="..;..\sdk;..\..\..\public;..\..\..\public\sourcepawn;$(SOURCEMM)\sourcehook" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD;THREADSAFE;SQLITE_OMIT_LOAD_EXTENSION" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD;SQLITE_THREADSAFE;SQLITE_OMIT_LOAD_EXTENSION;_WIN32_WINNT=0x0400" RuntimeLibrary="0" EnableEnhancedInstructionSet="1" RuntimeTypeInfo="false" @@ -259,6 +259,10 @@ RelativePath="..\sqlite-source\keywordhash.h" > + + @@ -355,6 +359,10 @@ /> + + @@ -475,6 +483,10 @@ /> + + @@ -511,6 +523,22 @@ /> + + + + + + + + diff --git a/extensions/sqlite/sqlite-source/alter.c b/extensions/sqlite/sqlite-source/alter.c index c473a52d..8b8d914a 100644 --- a/extensions/sqlite/sqlite-source/alter.c +++ b/extensions/sqlite/sqlite-source/alter.c @@ -51,6 +51,8 @@ static void renameTableFunc( int len = 0; char *zRet; + sqlite3 *db = sqlite3_user_data(context); + /* The principle used to locate the table name in the CREATE TABLE ** statement is that the table name is the first token that is immediatedly ** followed by a left parenthesis - TK_LP - or "USING" TK_USING. @@ -76,9 +78,9 @@ static void renameTableFunc( assert( len>0 ); } while( token!=TK_LP && token!=TK_USING ); - zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql, + zRet = sqlite3MPrintf(db, "%.*s%Q%s", tname.z - zSql, zSql, zTableName, tname.z+tname.n); - sqlite3_result_text(context, zRet, -1, sqlite3FreeX); + sqlite3_result_text(context, zRet, -1, sqlite3_free); } } @@ -105,6 +107,8 @@ static void renameTriggerFunc( int len = 0; char *zRet; + sqlite3 *db = sqlite3_user_data(context); + /* The principle used to locate the table name in the CREATE TRIGGER ** statement is that the table name is the first token that is immediatedly ** preceded by either TK_ON or TK_DOT and immediatedly followed by one @@ -149,9 +153,9 @@ static void renameTriggerFunc( /* Variable tname now contains the token that is the old table-name ** in the CREATE TRIGGER statement. */ - zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql, + zRet = sqlite3MPrintf(db, "%.*s%Q%s", tname.z - zSql, zSql, zTableName, tname.z+tname.n); - sqlite3_result_text(context, zRet, -1, sqlite3FreeX); + sqlite3_result_text(context, zRet, -1, sqlite3_free); } } #endif /* !SQLITE_OMIT_TRIGGER */ @@ -174,7 +178,7 @@ void sqlite3AlterFunctions(sqlite3 *db){ for(i=0; ipSchema!=pTempSchema ){ + sqlite3 *db = pParse->db; for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ if( pTrig->pSchema==pTempSchema ){ if( !zWhere ){ - zWhere = sqlite3MPrintf("name=%Q", pTrig->name); + zWhere = sqlite3MPrintf(db, "name=%Q", pTrig->name); }else{ tmp = zWhere; - zWhere = sqlite3MPrintf("%s OR name=%Q", zWhere, pTrig->name); - sqliteFree(tmp); + zWhere = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, pTrig->name); + sqlite3_free(tmp); } } } @@ -229,6 +234,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){ v = sqlite3GetVdbe(pParse); if( !v ) return; + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); assert( iDb>=0 ); @@ -245,7 +251,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){ sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); /* Reload the table, index and permanent trigger schemas. */ - zWhere = sqlite3MPrintf("tbl_name=%Q", zName); + zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName); if( !zWhere ) return; sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC); @@ -281,8 +287,9 @@ void sqlite3AlterRenameTable( #endif int isVirtualRename = 0; /* True if this is a v-table with an xRename() */ - if( sqlite3MallocFailed() ) goto exit_rename_table; + if( db->mallocFailed ) goto exit_rename_table; assert( pSrc->nSrc==1 ); + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( !pTab ) goto exit_rename_table; @@ -290,7 +297,7 @@ void sqlite3AlterRenameTable( zDb = db->aDb[iDb].zName; /* Get a NULL terminated version of the new table name. */ - zName = sqlite3NameFromToken(pName); + zName = sqlite3NameFromToken(db, pName); if( !zName ) goto exit_rename_table; /* Check that a table or index named 'zName' does not already exist @@ -404,7 +411,7 @@ void sqlite3AlterRenameTable( "sql = sqlite_rename_trigger(sql, %Q), " "tbl_name = %Q " "WHERE %s;", zName, zName, zWhere); - sqliteFree(zWhere); + sqlite3_free(zWhere); } #endif @@ -413,7 +420,7 @@ void sqlite3AlterRenameTable( exit_rename_table: sqlite3SrcListDelete(pSrc); - sqliteFree(zName); + sqlite3_free(zName); } @@ -434,17 +441,20 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ char *zCol; /* Null-terminated column definition */ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ + sqlite3 *db; /* The database connection; */ if( pParse->nErr ) return; pNew = pParse->pNewTable; assert( pNew ); - iDb = sqlite3SchemaToIndex(pParse->db, pNew->pSchema); - zDb = pParse->db->aDb[iDb].zName; + db = pParse->db; + assert( sqlite3BtreeHoldsAllMutexes(db) ); + iDb = sqlite3SchemaToIndex(db, pNew->pSchema); + zDb = db->aDb[iDb].zName; zTab = pNew->zName; pCol = &pNew->aCol[pNew->nCol-1]; pDflt = pCol->pDflt; - pTab = sqlite3FindTable(pParse->db, zTab, zDb); + pTab = sqlite3FindTable(db, zTab, zDb); assert( pTab ); #ifndef SQLITE_OMIT_AUTHORIZATION @@ -485,8 +495,8 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ */ if( pDflt ){ sqlite3_value *pVal; - if( sqlite3ValueFromExpr(pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){ - /* malloc() has failed */ + if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){ + db->mallocFailed = 1; return; } if( !pVal ){ @@ -497,7 +507,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ } /* Modify the CREATE TABLE statement. */ - zCol = sqliteStrNDup((char*)pColDef->z, pColDef->n); + zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){ @@ -510,7 +520,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1, zTab ); - sqliteFree(zCol); + sqlite3_free(zCol); } /* If the default value of the new column is NULL, then set the file @@ -545,10 +555,12 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ int iDb; int i; int nAlloc; + sqlite3 *db = pParse->db; /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); - if( sqlite3MallocFailed() ) goto exit_begin_add_column; + assert( sqlite3BtreeHoldsAllMutexes(db) ); + if( db->mallocFailed ) goto exit_begin_add_column; pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( !pTab ) goto exit_begin_add_column; @@ -566,12 +578,12 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ } assert( pTab->addColOffset>0 ); - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); /* Put a copy of the Table struct in Parse.pNewTable for the ** sqlite3AddColumn() function and friends to modify. */ - pNew = (Table *)sqliteMalloc(sizeof(Table)); + pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table)); if( !pNew ) goto exit_begin_add_column; pParse->pNewTable = pNew; pNew->nRef = 1; @@ -579,20 +591,21 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ assert( pNew->nCol>0 ); nAlloc = (((pNew->nCol-1)/8)*8)+8; assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 ); - pNew->aCol = (Column *)sqliteMalloc(sizeof(Column)*nAlloc); - pNew->zName = sqliteStrDup(pTab->zName); + pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc); + pNew->zName = sqlite3DbStrDup(db, pTab->zName); if( !pNew->aCol || !pNew->zName ){ + db->mallocFailed = 1; goto exit_begin_add_column; } memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); for(i=0; inCol; i++){ Column *pCol = &pNew->aCol[i]; - pCol->zName = sqliteStrDup(pCol->zName); + pCol->zName = sqlite3DbStrDup(db, pCol->zName); pCol->zColl = 0; pCol->zType = 0; pCol->pDflt = 0; } - pNew->pSchema = pParse->db->aDb[iDb].pSchema; + pNew->pSchema = db->aDb[iDb].pSchema; pNew->addColOffset = pTab->addColOffset; pNew->nRef = 1; @@ -600,7 +613,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ sqlite3BeginWriteOperation(pParse, 0, iDb); v = sqlite3GetVdbe(pParse); if( !v ) goto exit_begin_add_column; - sqlite3ChangeCookie(pParse->db, v, iDb); + sqlite3ChangeCookie(db, v, iDb); exit_begin_add_column: sqlite3SrcListDelete(pSrc); diff --git a/extensions/sqlite/sqlite-source/analyze.c b/extensions/sqlite/sqlite-source/analyze.c index cb68fe09..7aef3f67 100644 --- a/extensions/sqlite/sqlite-source/analyze.c +++ b/extensions/sqlite/sqlite-source/analyze.c @@ -37,6 +37,8 @@ static void openStatTable( Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; + assert( sqlite3BtreeHoldsAllMutexes(db) ); + assert( sqlite3VdbeDb(v)==db ); pDb = &db->aDb[iDb]; if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){ /* The sqlite_stat1 tables does not exist. Create it. @@ -100,7 +102,7 @@ static void analyzeOneTable( /* Do no analysis for tables that have no indices */ return; } - + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); assert( iDb>=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION @@ -258,6 +260,7 @@ static void analyzeTable(Parse *pParse, Table *pTab){ int iStatCur; assert( pTab!=0 ); + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab++; @@ -288,6 +291,7 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return; } @@ -304,9 +308,9 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ if( iDb>=0 ){ analyzeDatabase(pParse, iDb); }else{ - z = sqlite3NameFromToken(pName1); + z = sqlite3NameFromToken(db, pName1); pTab = sqlite3LocateTable(pParse, z, 0); - sqliteFree(z); + sqlite3_free(z); if( pTab ){ analyzeTable(pParse, pTab); } @@ -316,10 +320,10 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); if( iDb>=0 ){ zDb = db->aDb[iDb].zName; - z = sqlite3NameFromToken(pTableName); + z = sqlite3NameFromToken(db, pTableName); if( z ){ pTab = sqlite3LocateTable(pParse, z, zDb); - sqliteFree(z); + sqlite3_free(z); if( pTab ){ analyzeTable(pParse, pTab); } @@ -382,6 +386,10 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ char *zSql; int rc; + assert( iDb>=0 && iDbnDb ); + assert( db->aDb[iDb].pBt!=0 ); + assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); + /* Clear any prior statistics */ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); @@ -397,12 +405,12 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ /* Load new statistics out of the sqlite_stat1 table */ - zSql = sqlite3MPrintf("SELECT idx, stat FROM %Q.sqlite_stat1", + zSql = sqlite3MPrintf(db, "SELECT idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase); sqlite3SafetyOff(db); rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); sqlite3SafetyOn(db); - sqliteFree(zSql); + sqlite3_free(zSql); return rc; } diff --git a/extensions/sqlite/sqlite-source/attach.c b/extensions/sqlite/sqlite-source/attach.c index 65b5e4b9..271116b7 100644 --- a/extensions/sqlite/sqlite-source/attach.c +++ b/extensions/sqlite/sqlite-source/attach.c @@ -73,8 +73,8 @@ static void attachFunc( const char *zName; const char *zFile; Db *aNew; - char zErr[128]; char *zErrDyn = 0; + char zErr[128]; zFile = (const char *)sqlite3_value_text(argv[0]); zName = (const char *)sqlite3_value_text(argv[1]); @@ -102,7 +102,8 @@ static void attachFunc( for(i=0; inDb; i++){ char *z = db->aDb[i].zName; if( z && zName && sqlite3StrICmp(z, zName)==0 ){ - sqlite3_snprintf(sizeof(zErr), zErr, "database %s is already in use", zName); + sqlite3_snprintf(sizeof(zErr), zErr, + "database %s is already in use", zName); goto attach_error; } } @@ -111,14 +112,16 @@ static void attachFunc( ** hash tables. */ if( db->aDb==db->aDbStatic ){ - aNew = sqliteMalloc( sizeof(db->aDb[0])*3 ); + aNew = sqlite3_malloc( sizeof(db->aDb[0])*3 ); if( aNew==0 ){ + db->mallocFailed = 1; return; } memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ - aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); + aNew = sqlite3_realloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); if( aNew==0 ){ + db->mallocFailed = 1; return; } } @@ -130,9 +133,11 @@ static void attachFunc( ** it to obtain the database schema. At this point the schema may ** or may not be initialised. */ - rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE, &aNew->pBt); + rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE, + db->openFlags | SQLITE_OPEN_MAIN_DB, + &aNew->pBt); if( rc==SQLITE_OK ){ - aNew->pSchema = sqlite3SchemaGet(aNew->pBt); + aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); if( !aNew->pSchema ){ rc = SQLITE_NOMEM; }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ @@ -142,7 +147,7 @@ static void attachFunc( } sqlite3PagerLockingMode(sqlite3BtreePager(aNew->pBt), db->dfltLockMode); } - aNew->zName = sqliteStrDup(zName); + aNew->zName = sqlite3DbStrDup(db, zName); aNew->safety_level = 3; #if SQLITE_HAS_CODEC @@ -155,7 +160,7 @@ static void attachFunc( switch( t ){ case SQLITE_INTEGER: case SQLITE_FLOAT: - zErrDyn = sqliteStrDup("Invalid key value"); + zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); rc = SQLITE_ERROR; break; @@ -195,8 +200,8 @@ static void attachFunc( } sqlite3ResetInternalSchema(db, 0); db->nDb = iDb; - if( rc==SQLITE_NOMEM ){ - sqlite3FailedMalloc(); + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ + db->mallocFailed = 1; sqlite3_snprintf(sizeof(zErr),zErr, "out of memory"); }else{ sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile); @@ -210,7 +215,7 @@ attach_error: /* Return an error if we get here */ if( zErrDyn ){ sqlite3_result_error(context, zErrDyn, -1); - sqliteFree(zErrDyn); + sqlite3_free(zErrDyn); }else{ zErr[sizeof(zErr)-1] = 0; sqlite3_result_error(context, zErr, -1); @@ -292,14 +297,14 @@ static void codeAttach( sqlite3* db = pParse->db; #ifndef SQLITE_OMIT_AUTHORIZATION - assert( sqlite3MallocFailed() || pAuthArg ); + assert( db->mallocFailed || pAuthArg ); if( pAuthArg ){ - char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span); + char *zAuthArg = sqlite3NameFromToken(db, &pAuthArg->span); if( !zAuthArg ){ goto attach_end; } rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); - sqliteFree(zAuthArg); + sqlite3_free(zAuthArg); if(rc!=SQLITE_OK ){ goto attach_end; } @@ -323,7 +328,7 @@ static void codeAttach( sqlite3ExprCode(pParse, pDbname); sqlite3ExprCode(pParse, pKey); - assert( v || sqlite3MallocFailed() ); + assert( v || db->mallocFailed ); if( v ){ sqlite3VdbeAddOp(v, OP_Function, 0, nFunc); pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); @@ -424,7 +429,7 @@ int sqlite3FixSrcList( zDb = pFix->zDb; for(i=0, pItem=pList->a; inSrc; i++, pItem++){ if( pItem->zDatabase==0 ){ - pItem->zDatabase = sqliteStrDup(zDb); + pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb); }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){ sqlite3ErrorMsg(pFix->pParse, "%s %T cannot reference objects in database %s", diff --git a/extensions/sqlite/sqlite-source/auth.c b/extensions/sqlite/sqlite-source/auth.c index b3d671ea..dd83eda0 100644 --- a/extensions/sqlite/sqlite-source/auth.c +++ b/extensions/sqlite/sqlite-source/auth.c @@ -74,9 +74,11 @@ int sqlite3_set_authorizer( int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pArg ){ + sqlite3_mutex_enter(db->mutex); db->xAuth = xAuth; db->pAuthArg = pArg; sqlite3ExpirePreparedStatements(db); + sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -103,11 +105,12 @@ static void sqliteAuthBadReturnCode(Parse *pParse, int rc){ void sqlite3AuthRead( Parse *pParse, /* The parser context */ Expr *pExpr, /* The expression to check authorization on */ + Schema *pSchema, /* The schema of the expression */ SrcList *pTabList /* All table that pExpr might refer to */ ){ sqlite3 *db = pParse->db; int rc; - Table *pTab; /* The table being read */ + Table *pTab = 0; /* The table being read */ const char *zCol; /* Name of the column of the table */ int iSrc; /* Index in pTabList->a[] of table being read */ const char *zDBase; /* Name of database being accessed */ @@ -116,7 +119,7 @@ void sqlite3AuthRead( if( db->xAuth==0 ) return; if( pExpr->op!=TK_COLUMN ) return; - iDb = sqlite3SchemaToIndex(pParse->db, pExpr->pSchema); + iDb = sqlite3SchemaToIndex(pParse->db, pSchema); if( iDb<0 ){ /* An attempt to read a column out of a subquery or other ** temporary table. */ @@ -133,8 +136,6 @@ void sqlite3AuthRead( */ assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx ); pTab = pStack->pTab; - }else{ - return; } if( pTab==0 ) return; if( pExpr->iColumn>=0 ){ diff --git a/extensions/sqlite/sqlite-source/btree.c b/extensions/sqlite/sqlite-source/btree.c index 35381b7e..0ba3655a 100644 --- a/extensions/sqlite/sqlite-source/btree.c +++ b/extensions/sqlite/sqlite-source/btree.c @@ -23,7 +23,6 @@ */ static const char zMagicHeader[] = SQLITE_FILE_HEADER; - /* ** Set this global variable to 1 to enable tracing using the TRACE ** macro. @@ -32,6 +31,40 @@ static const char zMagicHeader[] = SQLITE_FILE_HEADER; int sqlite3_btree_trace=0; /* True to enable tracing */ #endif + + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** A flag to indicate whether or not shared cache is enabled. Also, +** a list of BtShared objects that are eligible for participation +** in shared cache. The variables have file scope during normal builds, +** but the test harness needs to access these variables so we make them +** global for test builds. +*/ +#ifdef SQLITE_TEST +BtShared *sqlite3SharedCacheList = 0; +int sqlite3SharedCacheEnabled = 0; +#else +static BtShared *sqlite3SharedCacheList = 0; +static int sqlite3SharedCacheEnabled = 0; +#endif +#endif /* SQLITE_OMIT_SHARED_CACHE */ + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** Enable or disable the shared pager and schema features. +** +** This routine has no effect on existing database connections. +** The shared cache setting effects only future calls to +** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). +*/ +int sqlite3_enable_shared_cache(int enable){ + sqlite3SharedCacheEnabled = enable; + return SQLITE_OK; +} +#endif + + /* ** Forward declaration */ @@ -50,8 +83,9 @@ static int checkReadLocks(Btree*,Pgno,BtCursor*); #define queryTableLock(a,b,c) SQLITE_OK #define lockTable(a,b,c) SQLITE_OK #define unlockAllTables(a) -#else +#endif +#ifndef SQLITE_OMIT_SHARED_CACHE /* ** Query to see if btree handle p may obtain a lock of type eLock ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return @@ -62,8 +96,10 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){ BtShared *pBt = p->pBt; BtLock *pIter; + assert( sqlite3BtreeHoldsMutex(p) ); + /* This is a no-op if the shared-cache is not enabled */ - if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){ + if( !p->sharable ){ return SQLITE_OK; } @@ -96,7 +132,9 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){ } return SQLITE_OK; } +#endif /* !SQLITE_OMIT_SHARED_CACHE */ +#ifndef SQLITE_OMIT_SHARED_CACHE /* ** Add a lock on the table with root-page iTable to the shared-btree used ** by Btree handle p. Parameter eLock must be either READ_LOCK or @@ -110,8 +148,10 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){ BtLock *pLock = 0; BtLock *pIter; + assert( sqlite3BtreeHoldsMutex(p) ); + /* This is a no-op if the shared-cache is not enabled */ - if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){ + if( !p->sharable ){ return SQLITE_OK; } @@ -143,7 +183,7 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){ ** with table iTable, allocate one and link it into the list. */ if( !pLock ){ - pLock = (BtLock *)sqliteMalloc(sizeof(BtLock)); + pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock)); if( !pLock ){ return SQLITE_NOMEM; } @@ -164,7 +204,9 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){ return SQLITE_OK; } +#endif /* !SQLITE_OMIT_SHARED_CACHE */ +#ifndef SQLITE_OMIT_SHARED_CACHE /* ** Release all the table locks (locks obtained via calls to the lockTable() ** procedure) held by Btree handle p. @@ -172,17 +214,14 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){ static void unlockAllTables(Btree *p){ BtLock **ppIter = &p->pBt->pLock; - /* If the shared-cache extension is not enabled, there should be no - ** locks in the BtShared.pLock list, making this procedure a no-op. Assert - ** that this is the case. - */ - assert( sqlite3ThreadDataReadOnly()->useSharedData || 0==*ppIter ); + assert( sqlite3BtreeHoldsMutex(p) ); + assert( p->sharable || 0==*ppIter ); while( *ppIter ){ BtLock *pLock = *ppIter; if( pLock->pBtree==p ){ *ppIter = pLock->pNext; - sqliteFree(pLock); + sqlite3_free(pLock); }else{ ppIter = &pLock->pNext; } @@ -192,12 +231,23 @@ static void unlockAllTables(Btree *p){ static void releasePage(MemPage *pPage); /* Forward reference */ +/* +** Verify that the cursor holds a mutex on the BtShared +*/ +#ifndef NDEBUG +static int cursorHoldsMutex(BtCursor *p){ + return sqlite3_mutex_held(p->pBt->mutex); +} +#endif + + #ifndef SQLITE_OMIT_INCRBLOB /* ** Invalidate the overflow page-list cache for cursor pCur, if any. */ static void invalidateOverflowCache(BtCursor *pCur){ - sqliteFree(pCur->aOverflow); + assert( cursorHoldsMutex(pCur) ); + sqlite3_free(pCur->aOverflow); pCur->aOverflow = 0; } @@ -207,6 +257,7 @@ static void invalidateOverflowCache(BtCursor *pCur){ */ static void invalidateAllOverflowCache(BtShared *pBt){ BtCursor *p; + assert( sqlite3_mutex_held(pBt->mutex) ); for(p=pBt->pCursor; p; p=p->pNext){ invalidateOverflowCache(p); } @@ -225,6 +276,7 @@ static int saveCursorPosition(BtCursor *pCur){ assert( CURSOR_VALID==pCur->eState ); assert( 0==pCur->pKey ); + assert( cursorHoldsMutex(pCur) ); rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); @@ -235,13 +287,13 @@ static int saveCursorPosition(BtCursor *pCur){ ** data. */ if( rc==SQLITE_OK && 0==pCur->pPage->intKey){ - void *pKey = sqliteMalloc((int)pCur->nKey); + void *pKey = sqlite3_malloc(pCur->nKey); if( pKey ){ - rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey); + rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey); if( rc==SQLITE_OK ){ pCur->pKey = pKey; }else{ - sqliteFree(pKey); + sqlite3_free(pKey); } }else{ rc = SQLITE_NOMEM; @@ -266,6 +318,8 @@ static int saveCursorPosition(BtCursor *pCur){ */ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ BtCursor *p; + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pExcept==0 || pExcept->pBt==pBt ); for(p=pBt->pCursor; p; p=p->pNext){ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) && p->eState==CURSOR_VALID ){ @@ -282,7 +336,8 @@ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ ** Clear the current cursor position. */ static void clearCursorPosition(BtCursor *pCur){ - sqliteFree(pCur->pKey); + assert( cursorHoldsMutex(pCur) ); + sqlite3_free(pCur->pKey); pCur->pKey = 0; pCur->eState = CURSOR_INVALID; } @@ -300,7 +355,11 @@ static void clearCursorPosition(BtCursor *pCur){ */ int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ int rc; - assert( pCur->eState==CURSOR_REQUIRESEEK ); + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState>=CURSOR_REQUIRESEEK ); + if( pCur->eState==CURSOR_FAULT ){ + return pCur->skip; + } #ifndef SQLITE_OMIT_INCRBLOB if( pCur->isIncrblobHandle ){ return SQLITE_ABORT; @@ -309,7 +368,7 @@ int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ pCur->eState = CURSOR_INVALID; rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skip); if( rc==SQLITE_OK ){ - sqliteFree(pCur->pKey); + sqlite3_free(pCur->pKey); pCur->pKey = 0; assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); } @@ -317,7 +376,7 @@ int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ } #define restoreOrClearCursorPosition(p) \ - (p->eState==CURSOR_REQUIRESEEK ? \ + (p->eState>=CURSOR_REQUIRESEEK ? \ sqlite3BtreeRestoreOrClearCursorPosition(p) : \ SQLITE_OK) @@ -328,9 +387,11 @@ int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ ** input page number. */ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){ - int nPagesPerMapPage = (pBt->usableSize/5)+1; - int iPtrMap = (pgno-2)/nPagesPerMapPage; - int ret = (iPtrMap*nPagesPerMapPage) + 2; + int nPagesPerMapPage, iPtrMap, ret; + assert( sqlite3_mutex_held(pBt->mutex) ); + nPagesPerMapPage = (pBt->usableSize/5)+1; + iPtrMap = (pgno-2)/nPagesPerMapPage; + ret = (iPtrMap*nPagesPerMapPage) + 2; if( ret==PENDING_BYTE_PAGE(pBt) ){ ret++; } @@ -351,6 +412,7 @@ static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){ int offset; /* Offset in pointer map page */ int rc; + assert( sqlite3_mutex_held(pBt->mutex) ); /* The master-journal page number must never be used as a pointer map page */ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); @@ -393,6 +455,8 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ int offset; /* Offset of entry in pointer map */ int rc; + assert( sqlite3_mutex_held(pBt->mutex) ); + iPtrmap = PTRMAP_PAGENO(pBt, key); rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage); if( rc!=0 ){ @@ -421,11 +485,13 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ */ #define findCell(pPage, iCell) \ ((pPage)->aData + get2byte(&(pPage)->aData[(pPage)->cellOffset+2*(iCell)])) +#ifdef SQLITE_TEST u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell){ assert( iCell>=0 ); assert( iCellaData[pPage->hdrOffset+3]) ); return findCell(pPage, iCell); } +#endif /* ** This a more complex version of sqlite3BtreeFindCell() that works for @@ -433,6 +499,7 @@ u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell){ */ static u8 *findOverflowCell(MemPage *pPage, int iCell){ int i; + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); for(i=pPage->nOverflow-1; i>=0; i--){ int k; struct _OvflCell *pOvfl; @@ -465,6 +532,8 @@ void sqlite3BtreeParseCellPtr( int n; /* Number bytes in cell content header */ u32 nPayload; /* Number of bytes of cell payload */ + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + pInfo->pCell = pCell; assert( pPage->leaf==0 || pPage->leaf==1 ); n = pPage->childPtrSize; @@ -577,6 +646,7 @@ static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){ */ static int ptrmapPutOvfl(MemPage *pPage, int iCell){ u8 *pCell; + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pCell = findOverflowCell(pPage, iCell); return ptrmapPutOvflPtr(pPage, pCell); } @@ -606,7 +676,8 @@ static int defragmentPage(MemPage *pPage){ assert( pPage->pBt!=0 ); assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); assert( pPage->nOverflow==0 ); - temp = sqliteMalloc( pPage->pBt->pageSize ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + temp = sqlite3_malloc( pPage->pBt->pageSize ); if( temp==0 ) return SQLITE_NOMEM; data = pPage->aData; hdr = pPage->hdrOffset; @@ -634,7 +705,7 @@ static int defragmentPage(MemPage *pPage){ data[hdr+7] = 0; addr = cellOffset+2*nCell; memset(&data[addr], 0, brk-addr); - sqliteFree(temp); + sqlite3_free(temp); return SQLITE_OK; } @@ -662,6 +733,7 @@ static int allocateSpace(MemPage *pPage, int nByte){ data = pPage->aData; assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); if( nByte<4 ) nByte = 4; if( pPage->nFreenOverflow>0 ) return 0; pPage->nFree -= nByte; @@ -720,6 +792,7 @@ static void freeSpace(MemPage *pPage, int start, int size){ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) ); assert( (start + size)<=pPage->pBt->usableSize ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); if( size<4 ) size = 4; #ifdef SQLITE_SECURE_DELETE @@ -780,6 +853,7 @@ static void decodeFlags(MemPage *pPage, int flagByte){ BtShared *pBt; /* A copy of pPage->pBt */ assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->intKey = (flagByte & (PTF_INTKEY|PTF_LEAFDATA))!=0; pPage->zeroData = (flagByte & PTF_ZERODATA)!=0; pPage->leaf = (flagByte & PTF_LEAF)!=0; @@ -826,8 +900,10 @@ int sqlite3BtreeInitPage( pBt = pPage->pBt; assert( pBt!=0 ); assert( pParent==0 || pParent->pBt==pBt ); + assert( sqlite3_mutex_held(pBt->mutex) ); assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); - assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] ); + assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); + assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){ /* The parent page should never change unless the file is corrupt */ return SQLITE_CORRUPT_BKPT; @@ -894,8 +970,10 @@ static void zeroPage(MemPage *pPage, int flags){ int first; assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno ); - assert( &data[pBt->pageSize] == (unsigned char*)pPage ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage) == data ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( sqlite3_mutex_held(pBt->mutex) ); memset(&data[hdr], 0, pBt->usableSize - hdr); data[hdr] = flags; first = hdr + 8 + 4*((flags&PTF_LEAF)==0); @@ -933,6 +1011,7 @@ int sqlite3BtreeGetPage( MemPage *pPage; DbPage *pDbPage; + assert( sqlite3_mutex_held(pBt->mutex) ); rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent); if( rc ) return rc; pPage = (MemPage *)sqlite3PagerGetExtra(pDbPage); @@ -957,6 +1036,7 @@ static int getAndInitPage( MemPage *pParent /* Parent of the page */ ){ int rc; + assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } @@ -975,7 +1055,9 @@ static void releasePage(MemPage *pPage){ if( pPage ){ assert( pPage->aData ); assert( pPage->pBt ); - assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); sqlite3PagerUnref(pPage->pDbPage); } } @@ -989,8 +1071,10 @@ static void pageDestructor(DbPage *pData, int pageSize){ MemPage *pPage; assert( (pageSize & 7)==0 ); pPage = (MemPage *)sqlite3PagerGetExtra(pData); + assert( pPage->isInit==0 || sqlite3_mutex_held(pPage->pBt->mutex) ); if( pPage->pParent ){ MemPage *pParent = pPage->pParent; + assert( pParent->pBt==pPage->pBt ); pPage->pParent = 0; releasePage(pParent); } @@ -1010,6 +1094,7 @@ static void pageReinit(DbPage *pData, int pageSize){ assert( (pageSize & 7)==0 ); pPage = (MemPage *)sqlite3PagerGetExtra(pData); if( pPage->isInit ){ + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->isInit = 0; sqlite3BtreeInitPage(pPage, pPage->pParent); } @@ -1021,21 +1106,22 @@ static void pageReinit(DbPage *pData, int pageSize){ ** zFilename is the name of the database file. If zFilename is NULL ** a new database with a random name is created. This randomly named ** database file will be deleted when sqlite3BtreeClose() is called. +** If zFilename is ":memory:" then an in-memory database is created +** that is automatically destroyed when it is closed. */ int sqlite3BtreeOpen( const char *zFilename, /* Name of the file containing the BTree database */ sqlite3 *pSqlite, /* Associated database handle */ Btree **ppBtree, /* Pointer to new Btree object written here */ - int flags /* Options */ + int flags, /* Options */ + int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ ){ - BtShared *pBt; /* Shared part of btree structure */ + sqlite3_vfs *pVfs; /* The VFS to use for this btree */ + BtShared *pBt = 0; /* Shared part of btree structure */ Btree *p; /* Handle to return */ int rc = SQLITE_OK; int nReserve; unsigned char zDbHeader[100]; -#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) - const ThreadData *pTsdro; -#endif /* Set the variable isMemdb to true for an in-memory database, or ** false for a file-based database. This symbol is only required if @@ -1050,113 +1136,188 @@ int sqlite3BtreeOpen( #endif #endif - p = sqliteMalloc(sizeof(Btree)); + assert( pSqlite!=0 ); + assert( sqlite3_mutex_held(pSqlite->mutex) ); + + pVfs = pSqlite->pVfs; + p = sqlite3MallocZero(sizeof(Btree)); if( !p ){ return SQLITE_NOMEM; } p->inTrans = TRANS_NONE; p->pSqlite = pSqlite; - /* Try to find an existing Btree structure opened on zFilename. */ #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) - pTsdro = sqlite3ThreadDataReadOnly(); - if( pTsdro->useSharedData && zFilename && !isMemdb ){ - char *zFullPathname = sqlite3OsFullPathname(zFilename); - if( !zFullPathname ){ - sqliteFree(p); - return SQLITE_NOMEM; + /* + ** If this Btree is a candidate for shared cache, try to find an + ** existing BtShared object that we can share with + */ + if( (flags & BTREE_PRIVATE)==0 + && isMemdb==0 + && (pSqlite->flags & SQLITE_Vtab)==0 + && zFilename && zFilename[0] + ){ + if( sqlite3SharedCacheEnabled ){ + int nFullPathname = pVfs->mxPathname+1; + char *zFullPathname = (char *)sqlite3_malloc(nFullPathname); + sqlite3_mutex *mutexShared; + p->sharable = 1; + if( pSqlite ){ + pSqlite->flags |= SQLITE_SharedCache; + } + if( !zFullPathname ){ + sqlite3_free(p); + return SQLITE_NOMEM; + } + sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); + mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex_enter(mutexShared); + for(pBt=sqlite3SharedCacheList; pBt; pBt=pBt->pNext){ + assert( pBt->nRef>0 ); + if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) + && sqlite3PagerVfs(pBt->pPager)==pVfs ){ + p->pBt = pBt; + pBt->nRef++; + break; + } + } + sqlite3_mutex_leave(mutexShared); + sqlite3_free(zFullPathname); } - for(pBt=pTsdro->pBtree; pBt; pBt=pBt->pNext){ - assert( pBt->nRef>0 ); - if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) ){ - p->pBt = pBt; - *ppBtree = p; - pBt->nRef++; - sqliteFree(zFullPathname); - return SQLITE_OK; +#ifdef SQLITE_DEBUG + else{ + /* In debug mode, we mark all persistent databases as sharable + ** even when they are not. This exercises the locking code and + ** gives more opportunity for asserts(sqlite3_mutex_held()) + ** statements to find locking problems. + */ + p->sharable = 1; + } +#endif + } +#endif + if( pBt==0 ){ + /* + ** The following asserts make sure that structures used by the btree are + ** the right size. This is to guard against size changes that result + ** when compiling on a different architecture. + */ + assert( sizeof(i64)==8 || sizeof(i64)==4 ); + assert( sizeof(u64)==8 || sizeof(u64)==4 ); + assert( sizeof(u32)==4 ); + assert( sizeof(u16)==2 ); + assert( sizeof(Pgno)==4 ); + + pBt = sqlite3MallocZero( sizeof(*pBt) ); + if( pBt==0 ){ + rc = SQLITE_NOMEM; + goto btree_open_out; + } + rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, + EXTRA_SIZE, flags, vfsFlags); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); + } + if( rc!=SQLITE_OK ){ + goto btree_open_out; + } + p->pBt = pBt; + + sqlite3PagerSetDestructor(pBt->pPager, pageDestructor); + sqlite3PagerSetReiniter(pBt->pPager, pageReinit); + pBt->pCursor = 0; + pBt->pPage1 = 0; + pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager); + pBt->pageSize = get2byte(&zDbHeader[16]); + if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE + || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ + pBt->pageSize = 0; + sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize); + pBt->maxEmbedFrac = 64; /* 25% */ + pBt->minEmbedFrac = 32; /* 12.5% */ + pBt->minLeafFrac = 32; /* 12.5% */ +#ifndef SQLITE_OMIT_AUTOVACUUM + /* If the magic name ":memory:" will create an in-memory database, then + ** leave the autoVacuum mode at 0 (do not auto-vacuum), even if + ** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if + ** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a + ** regular file-name. In this case the auto-vacuum applies as per normal. + */ + if( zFilename && !isMemdb ){ + pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0); + pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0); + } +#endif + nReserve = 0; + }else{ + nReserve = zDbHeader[20]; + pBt->maxEmbedFrac = zDbHeader[21]; + pBt->minEmbedFrac = zDbHeader[22]; + pBt->minLeafFrac = zDbHeader[23]; + pBt->pageSizeFixed = 1; +#ifndef SQLITE_OMIT_AUTOVACUUM + pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0); + pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0); +#endif + } + pBt->usableSize = pBt->pageSize - nReserve; + assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ + sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize); + +#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) + /* Add the new BtShared object to the linked list sharable BtShareds. + */ + if( p->sharable ){ + sqlite3_mutex *mutexShared; + pBt->nRef = 1; + mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); + if( SQLITE_THREADSAFE ){ + pBt->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pBt->mutex==0 ){ + rc = SQLITE_NOMEM; + pSqlite->mallocFailed = 0; + goto btree_open_out; + } + } + sqlite3_mutex_enter(mutexShared); + pBt->pNext = sqlite3SharedCacheList; + sqlite3SharedCacheList = pBt; + sqlite3_mutex_leave(mutexShared); + } +#endif + } + +#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) + /* If the new Btree uses a sharable pBtShared, then link the new + ** Btree into the list of all sharable Btrees for the same connection. + ** The list is kept in ascending order by pBt address. + */ + if( p->sharable ){ + int i; + Btree *pSib; + for(i=0; inDb; i++){ + if( (pSib = pSqlite->aDb[i].pBt)!=0 && pSib->sharable ){ + while( pSib->pPrev ){ pSib = pSib->pPrev; } + if( p->pBtpBt ){ + p->pNext = pSib; + p->pPrev = 0; + pSib->pPrev = p; + }else{ + while( pSib->pNext && pSib->pNext->pBtpBt ){ + pSib = pSib->pNext; + } + p->pNext = pSib->pNext; + p->pPrev = pSib; + if( p->pNext ){ + p->pNext->pPrev = p; + } + pSib->pNext = p; + } + break; } } - sqliteFree(zFullPathname); } #endif - - /* - ** The following asserts make sure that structures used by the btree are - ** the right size. This is to guard against size changes that result - ** when compiling on a different architecture. - */ - assert( sizeof(i64)==8 || sizeof(i64)==4 ); - assert( sizeof(u64)==8 || sizeof(u64)==4 ); - assert( sizeof(u32)==4 ); - assert( sizeof(u16)==2 ); - assert( sizeof(Pgno)==4 ); - - pBt = sqliteMalloc( sizeof(*pBt) ); - if( pBt==0 ){ - rc = SQLITE_NOMEM; - goto btree_open_out; - } - rc = sqlite3PagerOpen(&pBt->pPager, zFilename, EXTRA_SIZE, flags); - if( rc==SQLITE_OK ){ - rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); - } - if( rc!=SQLITE_OK ){ - goto btree_open_out; - } - p->pBt = pBt; - - sqlite3PagerSetDestructor(pBt->pPager, pageDestructor); - sqlite3PagerSetReiniter(pBt->pPager, pageReinit); - pBt->pCursor = 0; - pBt->pPage1 = 0; - pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager); - pBt->pageSize = get2byte(&zDbHeader[16]); - if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE - || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ - pBt->pageSize = SQLITE_DEFAULT_PAGE_SIZE; - pBt->maxEmbedFrac = 64; /* 25% */ - pBt->minEmbedFrac = 32; /* 12.5% */ - pBt->minLeafFrac = 32; /* 12.5% */ -#ifndef SQLITE_OMIT_AUTOVACUUM - /* If the magic name ":memory:" will create an in-memory database, then - ** leave the autoVacuum mode at 0 (do not auto-vacuum), even if - ** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if - ** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a - ** regular file-name. In this case the auto-vacuum applies as per normal. - */ - if( zFilename && !isMemdb ){ - pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0); - pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0); - } -#endif - nReserve = 0; - }else{ - nReserve = zDbHeader[20]; - pBt->maxEmbedFrac = zDbHeader[21]; - pBt->minEmbedFrac = zDbHeader[22]; - pBt->minLeafFrac = zDbHeader[23]; - pBt->pageSizeFixed = 1; -#ifndef SQLITE_OMIT_AUTOVACUUM - pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0); - pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0); -#endif - } - pBt->usableSize = pBt->pageSize - nReserve; - assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ - sqlite3PagerSetPagesize(pBt->pPager, pBt->pageSize); - -#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) - /* Add the new btree to the linked list starting at ThreadData.pBtree. - ** There is no chance that a malloc() may fail inside of the - ** sqlite3ThreadData() call, as the ThreadData structure must have already - ** been allocated for pTsdro->useSharedData to be non-zero. - */ - if( pTsdro->useSharedData && zFilename && !isMemdb ){ - pBt->pNext = pTsdro->pBtree; - sqlite3ThreadData()->pBtree = pBt; - } -#endif - pBt->nRef = 1; *ppBtree = p; btree_open_out: @@ -1164,13 +1325,53 @@ btree_open_out: if( pBt && pBt->pPager ){ sqlite3PagerClose(pBt->pPager); } - sqliteFree(pBt); - sqliteFree(p); + sqlite3_free(pBt); + sqlite3_free(p); *ppBtree = 0; } return rc; } +/* +** Decrement the BtShared.nRef counter. When it reaches zero, +** remove the BtShared structure from the sharing list. Return +** true if the BtShared.nRef counter reaches zero and return +** false if it is still positive. +*/ +static int removeFromSharingList(BtShared *pBt){ +#ifndef SQLITE_OMIT_SHARED_CACHE + sqlite3_mutex *pMaster; + BtShared *pList; + int removed = 0; + + assert( sqlite3_mutex_notheld(pBt->mutex) ); + pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex_enter(pMaster); + pBt->nRef--; + if( pBt->nRef<=0 ){ + if( sqlite3SharedCacheList==pBt ){ + sqlite3SharedCacheList = pBt->pNext; + }else{ + pList = sqlite3SharedCacheList; + while( pList && pList->pNext!=pBt ){ + pList=pList->pNext; + } + if( pList ){ + pList->pNext = pBt->pNext; + } + } + if( SQLITE_THREADSAFE ){ + sqlite3_mutex_free(pBt->mutex); + } + removed = 1; + } + sqlite3_mutex_leave(pMaster); + return removed; +#else + return 1; +#endif +} + /* ** Close an open database and invalidate all cursors. */ @@ -1178,11 +1379,9 @@ int sqlite3BtreeClose(Btree *p){ BtShared *pBt = p->pBt; BtCursor *pCur; -#ifndef SQLITE_OMIT_SHARED_CACHE - ThreadData *pTsd; -#endif - /* Close all cursors opened via this handle. */ + assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + sqlite3BtreeEnter(p); pCur = pBt->pCursor; while( pCur ){ BtCursor *pTmp = pCur; @@ -1197,45 +1396,36 @@ int sqlite3BtreeClose(Btree *p){ ** this handle. */ sqlite3BtreeRollback(p); - sqliteFree(p); + sqlite3BtreeLeave(p); -#ifndef SQLITE_OMIT_SHARED_CACHE /* If there are still other outstanding references to the shared-btree ** structure, return now. The remainder of this procedure cleans ** up the shared-btree. */ - assert( pBt->nRef>0 ); - pBt->nRef--; - if( pBt->nRef ){ - return SQLITE_OK; + assert( p->wantToLock==0 && p->locked==0 ); + if( !p->sharable || removeFromSharingList(pBt) ){ + /* The pBt is no longer on the sharing list, so we can access + ** it without having to hold the mutex. + ** + ** Clean out and delete the BtShared object. + */ + assert( !pBt->pCursor ); + sqlite3PagerClose(pBt->pPager); + if( pBt->xFreeSchema && pBt->pSchema ){ + pBt->xFreeSchema(pBt->pSchema); + } + sqlite3_free(pBt->pSchema); + sqlite3_free(pBt); } - /* Remove the shared-btree from the thread wide list. Call - ** ThreadDataReadOnly() and then cast away the const property of the - ** pointer to avoid allocating thread data if it is not really required. - */ - pTsd = (ThreadData *)sqlite3ThreadDataReadOnly(); - if( pTsd->pBtree==pBt ){ - assert( pTsd==sqlite3ThreadData() ); - pTsd->pBtree = pBt->pNext; - }else{ - BtShared *pPrev; - for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext){} - if( pPrev ){ - assert( pTsd==sqlite3ThreadData() ); - pPrev->pNext = pBt->pNext; - } - } +#ifndef SQLITE_OMIT_SHARED_CACHE + assert( p->wantToLock==0 ); + assert( p->locked==0 ); + if( p->pPrev ) p->pPrev->pNext = p->pNext; + if( p->pNext ) p->pNext->pPrev = p->pPrev; #endif - /* Close the pager and free the shared-btree structure */ - assert( !pBt->pCursor ); - sqlite3PagerClose(pBt->pPager); - if( pBt->xFreeSchema && pBt->pSchema ){ - pBt->xFreeSchema(pBt->pSchema); - } - sqliteFree(pBt->pSchema); - sqliteFree(pBt); + sqlite3_free(p); return SQLITE_OK; } @@ -1244,8 +1434,11 @@ int sqlite3BtreeClose(Btree *p){ */ int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){ BtShared *pBt = p->pBt; + assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + sqlite3BtreeEnter(p); pBt->pBusyHandler = pHandler; sqlite3PagerSetBusyhandler(pBt->pPager, pHandler); + sqlite3BtreeLeave(p); return SQLITE_OK; } @@ -1266,7 +1459,10 @@ int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){ */ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ BtShared *pBt = p->pBt; + assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + sqlite3BtreeEnter(p); sqlite3PagerSetCachesize(pBt->pPager, mxPage); + sqlite3BtreeLeave(p); return SQLITE_OK; } @@ -1281,7 +1477,10 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ #ifndef SQLITE_OMIT_PAGER_PRAGMAS int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){ BtShared *pBt = p->pBt; + assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + sqlite3BtreeEnter(p); sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync); + sqlite3BtreeLeave(p); return SQLITE_OK; } #endif @@ -1292,8 +1491,13 @@ int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){ */ int sqlite3BtreeSyncDisabled(Btree *p){ BtShared *pBt = p->pBt; + int rc; + assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + sqlite3BtreeEnter(p); assert( pBt && pBt->pPager ); - return sqlite3PagerNosync(pBt->pPager); + rc = sqlite3PagerNosync(pBt->pPager); + sqlite3BtreeLeave(p); + return rc; } #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) @@ -1313,8 +1517,11 @@ int sqlite3BtreeSyncDisabled(Btree *p){ ** bytes per page is left unchanged. */ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){ + int rc = SQLITE_OK; BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); if( pBt->pageSizeFixed ){ + sqlite3BtreeLeave(p); return SQLITE_READONLY; } if( nReserve<0 ){ @@ -1324,10 +1531,12 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){ ((pageSize-1)&pageSize)==0 ){ assert( (pageSize & 7)==0 ); assert( !pBt->pPage1 && !pBt->pCursor ); - pBt->pageSize = sqlite3PagerSetPagesize(pBt->pPager, pageSize); + pBt->pageSize = pageSize; + rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize); } pBt->usableSize = pBt->pageSize - nReserve; - return SQLITE_OK; + sqlite3BtreeLeave(p); + return rc; } /* @@ -1337,7 +1546,11 @@ int sqlite3BtreeGetPageSize(Btree *p){ return p->pBt->pageSize; } int sqlite3BtreeGetReserve(Btree *p){ - return p->pBt->pageSize - p->pBt->usableSize; + int n; + sqlite3BtreeEnter(p); + n = p->pBt->pageSize - p->pBt->usableSize; + sqlite3BtreeLeave(p); + return n; } /* @@ -1346,7 +1559,11 @@ int sqlite3BtreeGetReserve(Btree *p){ ** Regardless of the value of mxPage, return the maximum page count. */ int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){ - return sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage); + int n; + sqlite3BtreeEnter(p); + n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage); + sqlite3BtreeLeave(p); + return n; } #endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */ @@ -1361,12 +1578,17 @@ int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){ return SQLITE_READONLY; #else BtShared *pBt = p->pBt; + int rc = SQLITE_OK; int av = (autoVacuum?1:0); + + sqlite3BtreeEnter(p); if( pBt->pageSizeFixed && av!=pBt->autoVacuum ){ - return SQLITE_READONLY; + rc = SQLITE_READONLY; + }else{ + pBt->autoVacuum = av; } - pBt->autoVacuum = av; - return SQLITE_OK; + sqlite3BtreeLeave(p); + return rc; #endif } @@ -1378,11 +1600,15 @@ int sqlite3BtreeGetAutoVacuum(Btree *p){ #ifdef SQLITE_OMIT_AUTOVACUUM return BTREE_AUTOVACUUM_NONE; #else - return ( + int rc; + sqlite3BtreeEnter(p); + rc = ( (!p->pBt->autoVacuum)?BTREE_AUTOVACUUM_NONE: (!p->pBt->incrVacuum)?BTREE_AUTOVACUUM_FULL: BTREE_AUTOVACUUM_INCR ); + sqlite3BtreeLeave(p); + return rc; #endif } @@ -1399,6 +1625,8 @@ int sqlite3BtreeGetAutoVacuum(Btree *p){ static int lockBtree(BtShared *pBt){ int rc, pageSize; MemPage *pPage1; + + assert( sqlite3_mutex_held(pBt->mutex) ); if( pBt->pPage1 ) return SQLITE_OK; rc = sqlite3BtreeGetPage(pBt, 1, &pPage1, 0); if( rc!=SQLITE_OK ) return rc; @@ -1420,7 +1648,9 @@ static int lockBtree(BtShared *pBt){ goto page1_init_failed; } pageSize = get2byte(&page1[16]); - if( ((pageSize-1)&pageSize)!=0 || pageSize<512 ){ + if( ((pageSize-1)&pageSize)!=0 || pageSize<512 || + (SQLITE_MAX_PAGE_SIZE<32768 && pageSize>SQLITE_MAX_PAGE_SIZE) + ){ goto page1_init_failed; } assert( (pageSize & 7)==0 ); @@ -1474,6 +1704,8 @@ page1_init_failed: */ static int lockBtreeWithRetry(Btree *pRef){ int rc = SQLITE_OK; + + assert( sqlite3BtreeHoldsMutex(pRef) ); if( pRef->inTrans==TRANS_NONE ){ u8 inTransaction = pRef->pBt->inTransaction; btreeIntegrity(pRef); @@ -1500,11 +1732,12 @@ static int lockBtreeWithRetry(Btree *pRef){ ** If there is a transaction in progress, this routine is a no-op. */ static void unlockBtreeIfUnused(BtShared *pBt){ + assert( sqlite3_mutex_held(pBt->mutex) ); if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){ if( sqlite3PagerRefcount(pBt->pPager)>=1 ){ if( pBt->pPage1->aData==0 ){ MemPage *pPage = pBt->pPage1; - pPage->aData = &((u8*)pPage)[-pBt->pageSize]; + pPage->aData = sqlite3PagerGetData(pPage->pDbPage); pPage->pBt = pBt; pPage->pgno = 1; } @@ -1523,6 +1756,8 @@ static int newDatabase(BtShared *pBt){ MemPage *pP1; unsigned char *data; int rc; + + assert( sqlite3_mutex_held(pBt->mutex) ); if( sqlite3PagerPagecount(pBt->pPager)>0 ) return SQLITE_OK; pP1 = pBt->pPage1; assert( pP1!=0 ); @@ -1589,6 +1824,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ BtShared *pBt = p->pBt; int rc = SQLITE_OK; + sqlite3BtreeEnter(p); btreeIntegrity(p); /* If the btree is already in a write-transaction, or it @@ -1596,12 +1832,13 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ ** is requested, this is a no-op. */ if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ - return SQLITE_OK; + goto trans_begun; } /* Write transactions are not possible on a read-only database */ if( pBt->readOnly && wrflag ){ - return SQLITE_READONLY; + rc = SQLITE_READONLY; + goto trans_begun; } /* If another database handle has already opened a write transaction @@ -1609,7 +1846,8 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ ** requested, return SQLITE_BUSY. */ if( pBt->inTransaction==TRANS_WRITE && wrflag ){ - return SQLITE_BUSY; + rc = SQLITE_BUSY; + goto trans_begun; } do { @@ -1646,7 +1884,10 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ } } + +trans_begun: btreeIntegrity(p); + sqlite3BtreeLeave(p); return rc; } @@ -1665,6 +1906,7 @@ static int setChildPtrmaps(MemPage *pPage){ int isInitOrig = pPage->isInit; Pgno pgno = pPage->pgno; + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); rc = sqlite3BtreeInitPage(pPage, pPage->pParent); if( rc!=SQLITE_OK ){ goto set_child_ptrmaps_out; @@ -1712,6 +1954,7 @@ set_child_ptrmaps_out: ** overflow page in the list. */ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); if( eType==PTRMAP_OVERFLOW2 ){ /* The pointer is always the first 4 bytes of the page in this case. */ if( get4byte(pPage->aData)!=iFrom ){ @@ -1777,6 +2020,8 @@ static int relocatePage( assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 || eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ); + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pDbPage->pBt==pBt ); /* Move page iDbPage from it's current location to page number iFreePage */ TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", @@ -1855,6 +2100,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin){ Pgno iLastPg; /* Last page in the database */ Pgno nFreeList; /* Number of pages still on the free-list */ + assert( sqlite3_mutex_held(pBt->mutex) ); iLastPg = pBt->nTrunc; if( iLastPg==0 ){ iLastPg = sqlite3PagerPagecount(pBt->pPager); @@ -1949,13 +2195,19 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin){ ** SQLITE_OK is returned. Otherwise an SQLite error code. */ int sqlite3BtreeIncrVacuum(Btree *p){ + int rc; BtShared *pBt = p->pBt; + + sqlite3BtreeEnter(p); assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); if( !pBt->autoVacuum ){ - return SQLITE_DONE; + rc = SQLITE_DONE; + }else{ + invalidateAllOverflowCache(pBt); + rc = incrVacuumStep(pBt, 0); } - invalidateAllOverflowCache(pBt); - return incrVacuumStep(pBt, 0); + sqlite3BtreeLeave(p); + return rc; } /* @@ -1974,6 +2226,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){ int nRef = sqlite3PagerRefcount(pPager); #endif + assert( sqlite3_mutex_held(pBt->mutex) ); invalidateAllOverflowCache(pBt); assert(pBt->autoVacuum); if( !pBt->incrVacuum ){ @@ -1994,7 +2247,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){ nFree = get4byte(&pBt->pPage1->aData[36]); nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+pgsz/5)/(pgsz/5); nFin = nOrig - nFree - nPtrmap; - if( nOrig>(unsigned)PENDING_BYTE_PAGE(pBt) && nFin<=PENDING_BYTE_PAGE(pBt) ){ + if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<=PENDING_BYTE_PAGE(pBt) ){ nFin--; } while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){ @@ -2009,7 +2262,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){ assert(nFin==0 || pBt->nTrunc==0 || nFin<=pBt->nTrunc); rc = SQLITE_OK; if( pBt->nTrunc ){ - sqlite3PagerWrite(pBt->pPage1->pDbPage); + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[32], 0); put4byte(&pBt->pPage1->aData[36], 0); pBt->nTrunc = nFin; @@ -2061,15 +2314,18 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){ if( p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt; Pgno nTrunc = 0; + sqlite3BtreeEnter(p); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ rc = autoVacuumCommit(pBt, &nTrunc); if( rc!=SQLITE_OK ){ + sqlite3BtreeLeave(p); return rc; } } #endif rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, nTrunc); + sqlite3BtreeLeave(p); } return rc; } @@ -2091,6 +2347,7 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){ int sqlite3BtreeCommitPhaseTwo(Btree *p){ BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); btreeIntegrity(p); /* If the handle has a write-transaction open, commit the shared-btrees @@ -2102,6 +2359,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p){ assert( pBt->nTransaction>0 ); rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); if( rc!=SQLITE_OK ){ + sqlite3BtreeLeave(p); return rc; } pBt->inTransaction = TRANS_READ; @@ -2128,6 +2386,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p){ unlockBtreeIfUnused(pBt); btreeIntegrity(p); + sqlite3BtreeLeave(p); return SQLITE_OK; } @@ -2136,10 +2395,12 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p){ */ int sqlite3BtreeCommit(Btree *p){ int rc; + sqlite3BtreeEnter(p); rc = sqlite3BtreeCommitPhaseOne(p, 0); if( rc==SQLITE_OK ){ rc = sqlite3BtreeCommitPhaseTwo(p); } + sqlite3BtreeLeave(p); return rc; } @@ -2148,17 +2409,50 @@ int sqlite3BtreeCommit(Btree *p){ ** Return the number of write-cursors open on this handle. This is for use ** in assert() expressions, so it is only compiled if NDEBUG is not ** defined. +** +** For the purposes of this routine, a write-cursor is any cursor that +** is capable of writing to the databse. That means the cursor was +** originally opened for writing and the cursor has not be disabled +** by having its state changed to CURSOR_FAULT. */ static int countWriteCursors(BtShared *pBt){ BtCursor *pCur; int r = 0; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ - if( pCur->wrFlag ) r++; + if( pCur->wrFlag && pCur->eState!=CURSOR_FAULT ) r++; } return r; } #endif +/* +** This routine sets the state to CURSOR_FAULT and the error +** code to errCode for every cursor on BtShared that pBtree +** references. +** +** Every cursor is tripped, including cursors that belong +** to other database connections that happen to be sharing +** the cache with pBtree. +** +** This routine gets called when a rollback occurs. +** All cursors using the same cache must be tripped +** to prevent them from trying to use the btree after +** the rollback. The rollback may have deleted tables +** or moved root pages, so it is not sufficient to +** save the state of the cursor. The cursor must be +** invalidated. +*/ +void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){ + BtCursor *p; + sqlite3BtreeEnter(pBtree); + for(p=pBtree->pBt->pCursor; p; p=p->pNext){ + clearCursorPosition(p); + p->eState = CURSOR_FAULT; + p->skip = errCode; + } + sqlite3BtreeLeave(pBtree); +} + /* ** Rollback the transaction in progress. All cursors will be ** invalided by this operation. Any attempt to use a cursor @@ -2173,6 +2467,7 @@ int sqlite3BtreeRollback(Btree *p){ BtShared *pBt = p->pBt; MemPage *pPage1; + sqlite3BtreeEnter(p); rc = saveAllCursors(pBt, 0, 0); #ifndef SQLITE_OMIT_SHARED_CACHE if( rc!=SQLITE_OK ){ @@ -2183,12 +2478,7 @@ int sqlite3BtreeRollback(Btree *p){ ** we cannot simply return the error to the caller. Instead, abort ** all queries that may be using any of the cursors that failed to save. */ - while( pBt->pCursor ){ - sqlite3 *db = pBt->pCursor->pBtree->pSqlite; - if( db ){ - sqlite3AbortOtherActiveVdbes(db, 0); - } - } + sqlite3BtreeTripAllCursors(p, rc); } #endif btreeIntegrity(p); @@ -2230,6 +2520,7 @@ int sqlite3BtreeRollback(Btree *p){ unlockBtreeIfUnused(pBt); btreeIntegrity(p); + sqlite3BtreeLeave(p); return rc; } @@ -2251,12 +2542,15 @@ int sqlite3BtreeRollback(Btree *p){ int sqlite3BtreeBeginStmt(Btree *p){ int rc; BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); if( (p->inTrans!=TRANS_WRITE) || pBt->inStmt ){ - return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + }else{ + assert( pBt->inTransaction==TRANS_WRITE ); + rc = pBt->readOnly ? SQLITE_OK : sqlite3PagerStmtBegin(pBt->pPager); + pBt->inStmt = 1; } - assert( pBt->inTransaction==TRANS_WRITE ); - rc = pBt->readOnly ? SQLITE_OK : sqlite3PagerStmtBegin(pBt->pPager); - pBt->inStmt = 1; + sqlite3BtreeLeave(p); return rc; } @@ -2268,12 +2562,14 @@ int sqlite3BtreeBeginStmt(Btree *p){ int sqlite3BtreeCommitStmt(Btree *p){ int rc; BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); if( pBt->inStmt && !pBt->readOnly ){ rc = sqlite3PagerStmtCommit(pBt->pPager); }else{ rc = SQLITE_OK; } pBt->inStmt = 0; + sqlite3BtreeLeave(p); return rc; } @@ -2288,13 +2584,13 @@ int sqlite3BtreeCommitStmt(Btree *p){ int sqlite3BtreeRollbackStmt(Btree *p){ int rc = SQLITE_OK; BtShared *pBt = p->pBt; - sqlite3MallocDisallow(); + sqlite3BtreeEnter(p); if( pBt->inStmt && !pBt->readOnly ){ rc = sqlite3PagerStmtRollback(pBt->pPager); assert( countWriteCursors(pBt)==0 ); pBt->inStmt = 0; } - sqlite3MallocAllow(); + sqlite3BtreeLeave(p); return rc; } @@ -2348,7 +2644,7 @@ static int dfltCompare( ** default comparison function is used. The comparison function is ** always ignored for INTKEY tables. */ -int sqlite3BtreeCursor( +static int btreeCursor( Btree *p, /* The btree */ int iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ @@ -2360,6 +2656,7 @@ int sqlite3BtreeCursor( BtCursor *pCur; BtShared *pBt = p->pBt; + assert( sqlite3BtreeHoldsMutex(p) ); *ppCur = 0; if( wrFlag ){ if( pBt->readOnly ){ @@ -2379,7 +2676,7 @@ int sqlite3BtreeCursor( return SQLITE_READONLY; } } - pCur = sqliteMalloc( sizeof(*pCur) ); + pCur = sqlite3MallocZero( sizeof(*pCur) ); if( pCur==0 ){ rc = SQLITE_NOMEM; goto create_cursor_exception; @@ -2401,6 +2698,7 @@ int sqlite3BtreeCursor( pCur->xCompare = xCmp ? xCmp : dfltCompare; pCur->pArg = pArg; pCur->pBtree = p; + pCur->pBt = pBt; pCur->wrFlag = wrFlag; pCur->pNext = pBt->pCursor; if( pCur->pNext ){ @@ -2411,21 +2709,40 @@ int sqlite3BtreeCursor( *ppCur = pCur; return SQLITE_OK; + create_cursor_exception: if( pCur ){ releasePage(pCur->pPage); - sqliteFree(pCur); + sqlite3_free(pCur); } unlockBtreeIfUnused(pBt); return rc; } +int sqlite3BtreeCursor( + Btree *p, /* The btree */ + int iTable, /* Root page of table to open */ + int wrFlag, /* 1 to write. 0 read-only */ + int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */ + void *pArg, /* First arg to xCompare() */ + BtCursor **ppCur /* Write new cursor here */ +){ + int rc; + sqlite3BtreeEnter(p); + rc = btreeCursor(p, iTable, wrFlag, xCmp, pArg, ppCur); + sqlite3BtreeLeave(p); + return rc; +} + /* ** Close a cursor. The read lock on the database file is released ** when the last cursor is closed. */ int sqlite3BtreeCloseCursor(BtCursor *pCur){ - BtShared *pBt = pCur->pBtree->pBt; + BtShared *pBt = pCur->pBt; + Btree *pBtree = pCur->pBtree; + + sqlite3BtreeEnter(pBtree); clearCursorPosition(pCur); if( pCur->pPrev ){ pCur->pPrev->pNext = pCur->pNext; @@ -2438,7 +2755,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ releasePage(pCur->pPage); unlockBtreeIfUnused(pBt); invalidateOverflowCache(pCur); - sqliteFree(pCur); + sqlite3_free(pCur); + sqlite3BtreeLeave(pBtree); return SQLITE_OK; } @@ -2447,6 +2765,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ ** The temporary cursor is not on the cursor list for the Btree. */ void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){ + assert( cursorHoldsMutex(pCur) ); memcpy(pTempCur, pCur, sizeof(*pCur)); pTempCur->pNext = 0; pTempCur->pPrev = 0; @@ -2460,6 +2779,7 @@ void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){ ** function above. */ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); if( pCur->pPage ){ sqlite3PagerUnref(pCur->pPage->pDbPage); } @@ -2518,7 +2838,10 @@ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){ ** itself, not the number of bytes in the key. */ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ - int rc = restoreOrClearCursorPosition(pCur); + int rc; + + assert( cursorHoldsMutex(pCur) ); + rc = restoreOrClearCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); if( pCur->eState==CURSOR_INVALID ){ @@ -2539,7 +2862,10 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ ** the database is empty) then *pSize is set to 0. */ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ - int rc = restoreOrClearCursorPosition(pCur); + int rc; + + assert( cursorHoldsMutex(pCur) ); + rc = restoreOrClearCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); if( pCur->eState==CURSOR_INVALID ){ @@ -2579,6 +2905,7 @@ static int getOverflowPage( Pgno next = 0; int rc; + assert( sqlite3_mutex_held(pBt->mutex) ); /* One of these must not be NULL. Otherwise, why call this function? */ assert(ppPage || pPgnoNext); @@ -2711,13 +3038,14 @@ static int accessPayload( int rc = SQLITE_OK; u32 nKey; int iIdx = 0; - MemPage *pPage = pCur->pPage; /* Btree page of current cursor entry */ - BtShared *pBt = pCur->pBtree->pBt; /* Btree this cursor belongs to */ + MemPage *pPage = pCur->pPage; /* Btree page of current cursor entry */ + BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ assert( pPage ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->idx>=0 && pCur->idxnCell ); assert( offset>=0 ); + assert( cursorHoldsMutex(pCur) ); getCellInfo(pCur); aPayload = pCur->info.pCell + pCur->info.nHeader; @@ -2761,7 +3089,7 @@ static int accessPayload( */ if( pCur->isIncrblobHandle && !pCur->aOverflow ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; - pCur->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOvfl); + pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl); if( nOvfl && !pCur->aOverflow ){ rc = SQLITE_NOMEM; } @@ -2791,8 +3119,8 @@ static int accessPayload( if( offset>=ovflSize ){ /* The only reason to read this page is to obtain the page ** number for the next page in the overflow chain. The page - ** data is not required. So first try to lookup the overflow - ** page-list cache, if any, then fall back to the getOverflowPage() + ** data is not required. So first try to lookup the overflow + ** page-list cache, if any, then fall back to the getOverflowPage() ** function. */ #ifndef SQLITE_OMIT_INCRBLOB @@ -2841,7 +3169,10 @@ static int accessPayload( ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ - int rc = restoreOrClearCursorPosition(pCur); + int rc; + + assert( cursorHoldsMutex(pCur) ); + rc = restoreOrClearCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage!=0 ); @@ -2865,7 +3196,10 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ ** the available payload. */ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ - int rc = restoreOrClearCursorPosition(pCur); + int rc; + + assert( cursorHoldsMutex(pCur) ); + rc = restoreOrClearCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage!=0 ); @@ -2906,6 +3240,7 @@ static const unsigned char *fetchPayload( assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur->eState==CURSOR_VALID ); + assert( cursorHoldsMutex(pCur) ); pPage = pCur->pPage; assert( pCur->idx>=0 && pCur->idxnCell ); getCellInfo(pCur); @@ -2936,18 +3271,23 @@ static const unsigned char *fetchPayload( ** b-tree page. Write the number of available bytes into *pAmt. ** ** The pointer returned is ephemeral. The key/data may move -** or be destroyed on the next call to any Btree routine. +** or be destroyed on the next call to any Btree routine, +** including calls from other threads against the same cache. +** Hence, a mutex on the BtShared should be held prior to calling +** this routine. ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){ + assert( cursorHoldsMutex(pCur) ); if( pCur->eState==CURSOR_VALID ){ return (const void*)fetchPayload(pCur, pAmt, 0); } return 0; } const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){ + assert( cursorHoldsMutex(pCur) ); if( pCur->eState==CURSOR_VALID ){ return (const void*)fetchPayload(pCur, pAmt, 1); } @@ -2963,8 +3303,9 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ int rc; MemPage *pNewPage; MemPage *pOldPage; - BtShared *pBt = pCur->pBtree->pBt; + BtShared *pBt = pCur->pBt; + assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage); if( rc ) return rc; @@ -2991,7 +3332,10 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ ** 1 is pointing to. */ int sqlite3BtreeIsRootPage(MemPage *pPage){ - MemPage *pParent = pPage->pParent; + MemPage *pParent; + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + pParent = pPage->pParent; if( pParent==0 ) return 1; if( pParent->pgno>1 ) return 0; if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1; @@ -3011,6 +3355,7 @@ void sqlite3BtreeMoveToParent(BtCursor *pCur){ MemPage *pPage; int idxParent; + assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); pPage = pCur->pPage; assert( pPage!=0 ); @@ -3032,9 +3377,17 @@ void sqlite3BtreeMoveToParent(BtCursor *pCur){ static int moveToRoot(BtCursor *pCur){ MemPage *pRoot; int rc = SQLITE_OK; - BtShared *pBt = pCur->pBtree->pBt; + Btree *p = pCur->pBtree; + BtShared *pBt = p->pBt; - if( pCur->eState==CURSOR_REQUIRESEEK ){ + assert( cursorHoldsMutex(pCur) ); + assert( CURSOR_INVALID < CURSOR_REQUIRESEEK ); + assert( CURSOR_VALID < CURSOR_REQUIRESEEK ); + assert( CURSOR_FAULT > CURSOR_REQUIRESEEK ); + if( pCur->eState>=CURSOR_REQUIRESEEK ){ + if( pCur->eState==CURSOR_FAULT ){ + return pCur->skip; + } clearCursorPosition(pCur); } pRoot = pCur->pPage; @@ -3073,17 +3426,17 @@ static int moveToRoot(BtCursor *pCur){ */ static int moveToLeftmost(BtCursor *pCur){ Pgno pgno; - int rc; + int rc = SQLITE_OK; MemPage *pPage; + assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( !(pPage = pCur->pPage)->leaf ){ + while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ assert( pCur->idx>=0 && pCur->idxnCell ); pgno = get4byte(findCell(pPage, pCur->idx)); rc = moveToChild(pCur, pgno); - if( rc ) return rc; } - return SQLITE_OK; + return rc; } /* @@ -3098,18 +3451,20 @@ static int moveToLeftmost(BtCursor *pCur){ */ static int moveToRightmost(BtCursor *pCur){ Pgno pgno; - int rc; + int rc = SQLITE_OK; MemPage *pPage; + assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( !(pPage = pCur->pPage)->leaf ){ + while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); pCur->idx = pPage->nCell; rc = moveToChild(pCur, pgno); - if( rc ) return rc; } - pCur->idx = pPage->nCell - 1; - pCur->info.nSize = 0; + if( rc==SQLITE_OK ){ + pCur->idx = pPage->nCell - 1; + pCur->info.nSize = 0; + } return SQLITE_OK; } @@ -3119,16 +3474,21 @@ static int moveToRightmost(BtCursor *pCur){ */ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int rc; + + assert( cursorHoldsMutex(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); rc = moveToRoot(pCur); - if( rc ) return rc; - if( pCur->eState==CURSOR_INVALID ){ - assert( pCur->pPage->nCell==0 ); - *pRes = 1; - return SQLITE_OK; + if( rc==SQLITE_OK ){ + if( pCur->eState==CURSOR_INVALID ){ + assert( pCur->pPage->nCell==0 ); + *pRes = 1; + rc = SQLITE_OK; + }else{ + assert( pCur->pPage->nCell>0 ); + *pRes = 0; + rc = moveToLeftmost(pCur); + } } - assert( pCur->pPage->nCell>0 ); - *pRes = 0; - rc = moveToLeftmost(pCur); return rc; } @@ -3138,16 +3498,20 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ */ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int rc; + + assert( cursorHoldsMutex(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); rc = moveToRoot(pCur); - if( rc ) return rc; - if( CURSOR_INVALID==pCur->eState ){ - assert( pCur->pPage->nCell==0 ); - *pRes = 1; - return SQLITE_OK; + if( rc==SQLITE_OK ){ + if( CURSOR_INVALID==pCur->eState ){ + assert( pCur->pPage->nCell==0 ); + *pRes = 1; + }else{ + assert( pCur->eState==CURSOR_VALID ); + *pRes = 0; + rc = moveToRightmost(pCur); + } } - assert( pCur->eState==CURSOR_VALID ); - *pRes = 0; - rc = moveToRightmost(pCur); return rc; } @@ -3177,6 +3541,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ ** ** *pRes>0 The cursor is left pointing at an entry that ** is larger than pKey. +** */ int sqlite3BtreeMoveto( BtCursor *pCur, /* The cursor to be moved */ @@ -3186,8 +3551,13 @@ int sqlite3BtreeMoveto( int *pRes /* Search result flag */ ){ int rc; + + assert( cursorHoldsMutex(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); rc = moveToRoot(pCur); - if( rc ) return rc; + if( rc ){ + return rc; + } assert( pCur->pPage ); assert( pCur->pPage->isInit ); if( pCur->eState==CURSOR_INVALID ){ @@ -3236,12 +3606,14 @@ int sqlite3BtreeMoveto( if( available>=nCellKey ){ c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey); }else{ - pCellKey = sqliteMallocRaw( nCellKey ); + pCellKey = sqlite3_malloc( nCellKey ); if( pCellKey==0 ) return SQLITE_NOMEM; rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey); c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey); - sqliteFree(pCellKey); - if( rc ) return rc; + sqlite3_free(pCellKey); + if( rc ){ + return rc; + } } } if( c==0 ){ @@ -3288,6 +3660,7 @@ int sqlite3BtreeMoveto( /* NOT REACHED */ } + /* ** Return TRUE if the cursor is not pointing at an entry of the table. ** @@ -3303,16 +3676,25 @@ int sqlite3BtreeEof(BtCursor *pCur){ return (CURSOR_VALID!=pCur->eState); } +/* +** Return the database connection handle for a cursor. +*/ +sqlite3 *sqlite3BtreeCursorDb(const BtCursor *pCur){ + assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); + return pCur->pBtree->pSqlite; +} + /* ** Advance the cursor to the next entry in the database. If ** successful then set *pRes=0. If the cursor ** was already pointing to the last entry in the database before ** this routine was called, then set *pRes=1. */ -int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ +static int btreeNext(BtCursor *pCur, int *pRes){ int rc; MemPage *pPage; + assert( cursorHoldsMutex(pCur) ); rc = restoreOrClearCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; @@ -3367,6 +3749,13 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ rc = moveToLeftmost(pCur); return rc; } +int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ + int rc; + assert( cursorHoldsMutex(pCur) ); + rc = btreeNext(pCur, pRes); + return rc; +} + /* ** Step the cursor to the back to the previous entry in the database. If @@ -3374,11 +3763,12 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ ** was already pointing to the first entry in the database before ** this routine was called, then set *pRes=1. */ -int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ +static int btreePrevious(BtCursor *pCur, int *pRes){ int rc; Pgno pgno; MemPage *pPage; + assert( cursorHoldsMutex(pCur) ); rc = restoreOrClearCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; @@ -3400,7 +3790,9 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ if( !pPage->leaf ){ pgno = get4byte( findCell(pPage, pCur->idx) ); rc = moveToChild(pCur, pgno); - if( rc ) return rc; + if( rc ){ + return rc; + } rc = moveToRightmost(pCur); }else{ while( pCur->idx==0 ){ @@ -3423,6 +3815,12 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ *pRes = 0; return rc; } +int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ + int rc; + assert( cursorHoldsMutex(pCur) ); + rc = btreePrevious(pCur, pRes); + return rc; +} /* ** Allocate a new page from the database file. @@ -3459,6 +3857,7 @@ static int allocateBtreePage( MemPage *pTrunk = 0; MemPage *pPrevTrunk = 0; + assert( sqlite3_mutex_held(pBt->mutex) ); pPage1 = pBt->pPage1; n = get4byte(&pPage1->aData[36]); if( n>0 ){ @@ -3691,6 +4090,7 @@ static int freePage(MemPage *pPage){ int rc, n, k; /* Prepare the page for freeing */ + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->pgno>1 ); pPage->isInit = 0; releasePage(pPage->pParent); @@ -3739,12 +4139,15 @@ static int freePage(MemPage *pPage){ /* The trunk is full. Turn the page being freed into a new ** trunk page with no leaves. */ rc = sqlite3PagerWrite(pPage->pDbPage); - if( rc ) return rc; - put4byte(pPage->aData, pTrunk->pgno); - put4byte(&pPage->aData[4], 0); - put4byte(&pPage1->aData[32], pPage->pgno); - TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", - pPage->pgno, pTrunk->pgno)); + if( rc==SQLITE_OK ){ + put4byte(pPage->aData, pTrunk->pgno); + put4byte(&pPage->aData[4], 0); + put4byte(&pPage1->aData[32], pPage->pgno); + TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", + pPage->pgno, pTrunk->pgno)); + } + }else if( k<0 ){ + rc = SQLITE_CORRUPT; }else{ /* Add the newly freed page as a leaf on the current trunk */ rc = sqlite3PagerWrite(pTrunk->pDbPage); @@ -3773,6 +4176,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){ int nOvfl; int ovflPageSize; + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); sqlite3BtreeParseCellPtr(pPage, pCell, &info); if( info.iOverflow==0 ){ return SQLITE_OK; /* No overflow pages. Return without doing anything */ @@ -3829,6 +4233,8 @@ static int fillInCell( int nHeader; CellInfo info; + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + /* Fill in the header. */ nHeader = 0; if( !pPage->leaf ){ @@ -3941,6 +4347,7 @@ static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){ MemPage *pThis; DbPage *pDbPage; + assert( sqlite3_mutex_held(pBt->mutex) ); assert( pNewParent!=0 ); if( pgno==0 ) return SQLITE_OK; assert( pBt->pPager!=0 ); @@ -3948,7 +4355,7 @@ static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){ if( pDbPage ){ pThis = (MemPage *)sqlite3PagerGetExtra(pDbPage); if( pThis->isInit ){ - assert( pThis->aData==(sqlite3PagerGetData(pDbPage)) ); + assert( pThis->aData==sqlite3PagerGetData(pDbPage) ); if( pThis->pParent!=pNewParent ){ if( pThis->pParent ) sqlite3PagerUnref(pThis->pParent->pDbPage); pThis->pParent = pNewParent; @@ -3984,6 +4391,7 @@ static int reparentChildPages(MemPage *pPage){ BtShared *pBt = pPage->pBt; int rc = SQLITE_OK; + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); if( pPage->leaf ) return SQLITE_OK; for(i=0; inCell; i++){ @@ -4018,6 +4426,7 @@ static void dropCell(MemPage *pPage, int idx, int sz){ assert( idx>=0 && idxnCell ); assert( sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); data = pPage->aData; ptr = &data[pPage->cellOffset + 2*idx]; pc = get2byte(ptr); @@ -4070,7 +4479,7 @@ static int insertCell( assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( sz==cellSizePtr(pPage, pCell) ); - assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip); @@ -4082,6 +4491,11 @@ static int insertCell( pPage->aOvfl[j].idx = i; pPage->nFree = 0; }else{ + int rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc!=SQLITE_OK ){ + return rc; + } + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); data = pPage->aData; hdr = pPage->hdrOffset; top = get2byte(&data[hdr+5]); @@ -4089,7 +4503,7 @@ static int insertCell( end = cellOffset + 2*pPage->nCell + 2; ins = cellOffset + 2*i; if( end > top - sz ){ - int rc = defragmentPage(pPage); + rc = defragmentPage(pPage); if( rc!=SQLITE_OK ) return rc; top = get2byte(&data[hdr+5]); assert( end + sz <= top ); @@ -4117,7 +4531,7 @@ static int insertCell( assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){ Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]); - int rc = ptrmapPut(pPage->pBt, pgnoOvfl, PTRMAP_OVERFLOW1, pPage->pgno); + rc = ptrmapPut(pPage->pBt, pgnoOvfl, PTRMAP_OVERFLOW1, pPage->pgno); if( rc!=SQLITE_OK ) return rc; } } @@ -4145,6 +4559,7 @@ static void assemblePage( u8 *data; /* Data for the page */ assert( pPage->nOverflow==0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); totalSize = 0; for(i=0; ipBt->mutex) ); + /* Allocate a new page. Insert the overflow cell from pPage ** into it. Then remove the overflow cell from pPage. */ @@ -4343,11 +4760,13 @@ static int balance_nonroot(MemPage *pPage){ u8 *aFrom = 0; #endif + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + /* ** Find the parent page. */ assert( pPage->isInit ); - assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( sqlite3PagerIswriteable(pPage->pDbPage) || pPage->nOverflow==1 ); pBt = pPage->pBt; pParent = pPage->pParent; assert( pParent ); @@ -4381,6 +4800,10 @@ static int balance_nonroot(MemPage *pPage){ } #endif + if( SQLITE_OK!=(rc = sqlite3PagerWrite(pPage->pDbPage)) ){ + return rc; + } + /* ** Find the cell in the parent page whose left child points back ** to pPage. The "idx" variable is the index of that cell. If pPage @@ -4450,7 +4873,7 @@ static int balance_nonroot(MemPage *pPage){ /* ** Allocate space for memory structures */ - apCell = sqliteMallocRaw( + apCell = sqlite3_malloc( nMaxCells*sizeof(u8*) /* apCell */ + nMaxCells*sizeof(int) /* szCell */ + ROUND8(sizeof(MemPage))*NB /* aCopy */ @@ -4483,12 +4906,10 @@ static int balance_nonroot(MemPage *pPage){ ** process of being overwritten. */ for(i=0; ipageSize]; - p->aData = &((u8*)p)[-pBt->pageSize]; - memcpy(p->aData, apOld[i]->aData, pBt->pageSize + sizeof(MemPage)); - /* The memcpy() above changes the value of p->aData so we have to - ** set it again. */ - p->aData = &((u8*)p)[-pBt->pageSize]; + MemPage *p = apCopy[i] = (MemPage*)aCopy[i]; + memcpy(p, apOld[i], sizeof(MemPage)); + p->aData = (void*)&p[1]; + memcpy(p->aData, apOld[i]->aData, pBt->pageSize); } /* @@ -4771,7 +5192,7 @@ static int balance_nonroot(MemPage *pPage){ memcpy(&pNew->aData[8], pCell, 4); pTemp = 0; }else if( leafData ){ - /* If the tree is a leaf-data tree, and the siblings are leaves, + /* If the tree is a leaf-data tree, and the siblings are leaves, ** then there is no divider cell in apCell[]. Instead, the divider ** cell consists of the integer key for the right-most cell of ** the sibling-page assembled above only. @@ -4861,7 +5282,7 @@ static int balance_nonroot(MemPage *pPage){ ** Cleanup before returning. */ balance_cleanup: - sqliteFree(apCell); + sqlite3_free(apCell); for(i=0; ipParent==0 ); assert( pPage->nCell==0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pBt = pPage->pBt; mxCellPerPage = MX_CELL(pBt); - apCell = sqliteMallocRaw( mxCellPerPage*(sizeof(u8*)+sizeof(int)) ); + apCell = sqlite3_malloc( mxCellPerPage*(sizeof(u8*)+sizeof(int)) ); if( apCell==0 ) return SQLITE_NOMEM; szCell = (int*)&apCell[mxCellPerPage]; if( pPage->leaf ){ @@ -4963,11 +5385,10 @@ static int balance_shallower(MemPage *pPage){ } } #endif - if( rc!=SQLITE_OK ) goto end_shallow_balance; releasePage(pChild); } end_shallow_balance: - sqliteFree(apCell); + sqlite3_free(apCell); return rc; } @@ -4995,6 +5416,7 @@ static int balance_deeper(MemPage *pPage){ assert( pPage->pParent==0 ); assert( pPage->nOverflow>0 ); pBt = pPage->pBt; + assert( sqlite3_mutex_held(pBt->mutex) ); rc = allocateBtreePage(pBt, &pChild, &pgnoChild, pPage->pgno, 0); if( rc ) return rc; assert( sqlite3PagerIswriteable(pChild->pDbPage) ); @@ -5043,8 +5465,10 @@ balancedeeper_out: */ static int balance(MemPage *pPage, int insert){ int rc = SQLITE_OK; + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); if( pPage->pParent==0 ){ - if( pPage->nOverflow>0 ){ + rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc==SQLITE_OK && pPage->nOverflow>0 ){ rc = balance_deeper(pPage); } if( rc==SQLITE_OK && pPage->nCell==0 ){ @@ -5079,6 +5503,7 @@ static int checkReadLocks(Btree *pBtree, Pgno pgnoRoot, BtCursor *pExclude){ BtCursor *p; BtShared *pBt = pBtree->pBt; sqlite3 *db = pBtree->pSqlite; + assert( sqlite3BtreeHoldsMutex(pBtree) ); for(p=pBt->pCursor; p; p=p->pNext){ if( p==pExclude ) continue; if( p->eState!=CURSOR_VALID ) continue; @@ -5116,13 +5541,16 @@ int sqlite3BtreeInsert( int loc; int szNew; MemPage *pPage; - BtShared *pBt = pCur->pBtree->pBt; + Btree *p = pCur->pBtree; + BtShared *pBt = p->pBt; unsigned char *oldCell; unsigned char *newCell = 0; + assert( cursorHoldsMutex(pCur) ); if( pBt->inTransaction!=TRANS_WRITE ){ /* Must start a transaction before doing an insert */ - return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + return rc; } assert( !pBt->readOnly ); if( !pCur->wrFlag ){ @@ -5131,6 +5559,9 @@ int sqlite3BtreeInsert( if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } + if( pCur->eState==CURSOR_FAULT ){ + return pCur->skip; + } /* Save the positions of any other cursors open on this table */ clearCursorPosition(pCur); @@ -5148,9 +5579,7 @@ int sqlite3BtreeInsert( pCur->pgnoRoot, nKey, nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); assert( pPage->isInit ); - rc = sqlite3PagerWrite(pPage->pDbPage); - if( rc ) return rc; - newCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); + newCell = sqlite3_malloc( MX_CELL_SIZE(pBt) ); if( newCell==0 ) return SQLITE_NOMEM; rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew); if( rc ) goto end_insert; @@ -5159,6 +5588,10 @@ int sqlite3BtreeInsert( if( loc==0 && CURSOR_VALID==pCur->eState ){ int szOld; assert( pCur->idx>=0 && pCur->idxnCell ); + rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ){ + goto end_insert; + } oldCell = findCell(pPage, pCur->idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); @@ -5183,7 +5616,7 @@ int sqlite3BtreeInsert( moveToRoot(pCur); } end_insert: - sqliteFree(newCell); + sqlite3_free(newCell); return rc; } @@ -5196,14 +5629,20 @@ int sqlite3BtreeDelete(BtCursor *pCur){ unsigned char *pCell; int rc; Pgno pgnoChild = 0; - BtShared *pBt = pCur->pBtree->pBt; + Btree *p = pCur->pBtree; + BtShared *pBt = p->pBt; + assert( cursorHoldsMutex(pCur) ); assert( pPage->isInit ); if( pBt->inTransaction!=TRANS_WRITE ){ /* Must start a transaction before doing a delete */ - return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + return rc; } assert( !pBt->readOnly ); + if( pCur->eState==CURSOR_FAULT ){ + return pCur->skip; + } if( pCur->idx >= pPage->nCell ){ return SQLITE_ERROR; /* The cursor is not pointing to anything */ } @@ -5236,7 +5675,9 @@ int sqlite3BtreeDelete(BtCursor *pCur){ pgnoChild = get4byte(pCell); } rc = clearCell(pPage, pCell); - if( rc ) return rc; + if( rc ){ + return rc; + } if( !pPage->leaf ){ /* @@ -5266,7 +5707,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ pNext = findCell(leafCur.pPage, leafCur.idx); szNext = cellSizePtr(leafCur.pPage, pNext); assert( MX_CELL_SIZE(pBt)>=szNext+4 ); - tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); + tempCell = sqlite3_malloc( MX_CELL_SIZE(pBt) ); if( tempCell==0 ){ rc = SQLITE_NOMEM; } @@ -5282,7 +5723,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ dropCell(leafCur.pPage, leafCur.idx, szNext); rc = balance(leafCur.pPage, 0); } - sqliteFree(tempCell); + sqlite3_free(tempCell); sqlite3BtreeReleaseTempCursor(&leafCur); }else{ TRACE(("DELETE: table=%d delete from leaf %d\n", @@ -5307,20 +5748,25 @@ int sqlite3BtreeDelete(BtCursor *pCur){ ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys ** BTREE_ZERODATA Used for SQL indices */ -int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ +static int btreeCreateTable(Btree *p, int *piTable, int flags){ BtShared *pBt = p->pBt; MemPage *pRoot; Pgno pgnoRoot; int rc; + + assert( sqlite3BtreeHoldsMutex(p) ); if( pBt->inTransaction!=TRANS_WRITE ){ /* Must start a transaction first */ - return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + return rc; } assert( !pBt->readOnly ); #ifdef SQLITE_OMIT_AUTOVACUUM rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); - if( rc ) return rc; + if( rc ){ + return rc; + } #else if( pBt->autoVacuum ){ Pgno pgnoMove; /* Move a page here to make room for the root-page */ @@ -5338,7 +5784,9 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ ** created so far, so the new root-page is (meta[3]+1). */ rc = sqlite3BtreeGetMeta(p, 4, &pgnoRoot); - if( rc!=SQLITE_OK ) return rc; + if( rc!=SQLITE_OK ){ + return rc; + } pgnoRoot++; /* The new root-page may not be allocated on a pointer-map page, or the @@ -5431,6 +5879,13 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ *piTable = (int)pgnoRoot; return SQLITE_OK; } +int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ + int rc; + sqlite3BtreeEnter(p); + rc = btreeCreateTable(p, piTable, flags); + sqlite3BtreeLeave(p); + return rc; +} /* ** Erase the given database page and all its children. Return @@ -5447,6 +5902,7 @@ static int clearDatabasePage( unsigned char *pCell; int i; + assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>sqlite3PagerPagecount(pBt->pPager) ){ return SQLITE_CORRUPT_BKPT; } @@ -5489,20 +5945,18 @@ cleardatabasepage_out: int sqlite3BtreeClearTable(Btree *p, int iTable){ int rc; BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); if( p->inTrans!=TRANS_WRITE ){ - return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + }else if( (rc = checkReadLocks(p, iTable, 0))!=SQLITE_OK ){ + /* nothing to do */ + }else if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){ + /* nothing to do */ + }else{ + rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0); } - rc = checkReadLocks(p, iTable, 0); - if( rc ){ - return rc; - } - - /* Save the position of all cursors open on this table */ - if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){ - return rc; - } - - return clearDatabasePage(pBt, (Pgno)iTable, 0, 0); + sqlite3BtreeLeave(p); + return rc; } /* @@ -5525,11 +5979,12 @@ int sqlite3BtreeClearTable(Btree *p, int iTable){ ** The last root page is recorded in meta[3] and the value of ** meta[3] is updated by this procedure. */ -int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ +static int btreeDropTable(Btree *p, int iTable, int *piMoved){ int rc; MemPage *pPage = 0; BtShared *pBt = p->pBt; + assert( sqlite3BtreeHoldsMutex(p) ); if( p->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } @@ -5631,6 +6086,13 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ } return rc; } +int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ + int rc; + sqlite3BtreeEnter(p); + rc = btreeDropTable(p, iTable, piMoved); + sqlite3BtreeLeave(p); + return rc; +} /* @@ -5649,6 +6111,8 @@ int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ unsigned char *pP1; BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); + /* Reading a meta-data value requires a read-lock on page 1 (and hence ** the sqlite_master table. We grab this lock regardless of whether or ** not the SQLITE_ReadUncommitted flag is set (the table rooted at page @@ -5656,12 +6120,16 @@ int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ */ rc = queryTableLock(p, 1, READ_LOCK); if( rc!=SQLITE_OK ){ + sqlite3BtreeLeave(p); return rc; } assert( idx>=0 && idx<=15 ); rc = sqlite3PagerGet(pBt->pPager, 1, &pDbPage); - if( rc ) return rc; + if( rc ){ + sqlite3BtreeLeave(p); + return rc; + } pP1 = (unsigned char *)sqlite3PagerGetData(pDbPage); *pMeta = get4byte(&pP1[36 + idx*4]); sqlite3PagerUnref(pDbPage); @@ -5675,6 +6143,7 @@ int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ /* Grab the read-lock on page 1. */ rc = lockTable(p, 1, READ_LOCK); + sqlite3BtreeLeave(p); return rc; } @@ -5687,20 +6156,26 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ unsigned char *pP1; int rc; assert( idx>=1 && idx<=15 ); + sqlite3BtreeEnter(p); if( p->inTrans!=TRANS_WRITE ){ - return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + }else{ + assert( pBt->pPage1!=0 ); + pP1 = pBt->pPage1->aData; + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + if( rc==SQLITE_OK ){ + put4byte(&pP1[36 + idx*4], iMeta); +#ifndef SQLITE_OMIT_AUTOVACUUM + if( idx==7 ){ + assert( pBt->autoVacuum || iMeta==0 ); + assert( iMeta==0 || iMeta==1 ); + pBt->incrVacuum = iMeta; + } +#endif + } } - assert( pBt->pPage1!=0 ); - pP1 = pBt->pPage1->aData; - rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); - if( rc ) return rc; - put4byte(&pP1[36 + idx*4], iMeta); - if( idx==7 ){ - assert( pBt->autoVacuum || iMeta==0 ); - assert( iMeta==0 || iMeta==1 ); - pBt->incrVacuum = iMeta; - } - return SQLITE_OK; + sqlite3BtreeLeave(p); + return rc; } /* @@ -5712,6 +6187,8 @@ int sqlite3BtreeFlags(BtCursor *pCur){ ** restoreOrClearCursorPosition() here. */ MemPage *pPage = pCur->pPage; + assert( cursorHoldsMutex(pCur) ); + assert( pPage->pBt==pCur->pBt ); return pPage ? pPage->aData[pPage->hdrOffset] : 0; } @@ -5740,18 +6217,18 @@ static void checkAppendMsg( pCheck->mxErr--; pCheck->nErr++; va_start(ap, zFormat); - zMsg2 = sqlite3VMPrintf(zFormat, ap); + zMsg2 = sqlite3VMPrintf(0, zFormat, ap); va_end(ap); if( zMsg1==0 ) zMsg1 = ""; if( pCheck->zErrMsg ){ char *zOld = pCheck->zErrMsg; pCheck->zErrMsg = 0; sqlite3SetString(&pCheck->zErrMsg, zOld, "\n", zMsg1, zMsg2, (char*)0); - sqliteFree(zOld); + sqlite3_free(zOld); }else{ sqlite3SetString(&pCheck->zErrMsg, zMsg1, zMsg2, (char*)0); } - sqliteFree(zMsg2); + sqlite3_free(zMsg2); } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -5994,7 +6471,7 @@ static int checkTreePage( */ data = pPage->aData; hdr = pPage->hdrOffset; - hit = sqliteMalloc( usableSize ); + hit = sqlite3MallocZero( usableSize ); if( hit ){ memset(hit, 1, get2byte(&data[hdr+5])); nCell = get2byte(&data[hdr+3]); @@ -6037,7 +6514,7 @@ static int checkTreePage( cnt, data[hdr+7], iPage); } } - sqliteFree(hit); + sqlite3_free(hit); releasePage(pPage); return depth+1; @@ -6067,9 +6544,11 @@ char *sqlite3BtreeIntegrityCheck( IntegrityCk sCheck; BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); nRef = sqlite3PagerRefcount(pBt->pPager); if( lockBtreeWithRetry(p)!=SQLITE_OK ){ - return sqliteStrDup("Unable to acquire a read lock on the database"); + sqlite3BtreeLeave(p); + return sqlite3StrDup("Unable to acquire a read lock on the database"); } sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; @@ -6084,13 +6563,15 @@ char *sqlite3BtreeIntegrityCheck( #endif if( sCheck.nPage==0 ){ unlockBtreeIfUnused(pBt); + sqlite3BtreeLeave(p); return 0; } - sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) ); + sCheck.anRef = sqlite3_malloc( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) ); if( !sCheck.anRef ){ unlockBtreeIfUnused(pBt); *pnErr = 1; - return sqlite3MPrintf("Unable to malloc %d bytes", + sqlite3BtreeLeave(p); + return sqlite3MPrintf(p->pSqlite, "Unable to malloc %d bytes", (sCheck.nPage+1)*sizeof(sCheck.anRef[0])); } for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; } @@ -6151,7 +6632,8 @@ char *sqlite3BtreeIntegrityCheck( /* Clean up and report errors. */ - sqliteFree(sCheck.anRef); + sqlite3BtreeLeave(p); + sqlite3_free(sCheck.anRef); *pnErr = sCheck.nErr; return sCheck.zErrMsg; } @@ -6159,6 +6641,9 @@ char *sqlite3BtreeIntegrityCheck( /* ** Return the full pathname of the underlying database file. +** +** The pager filename is invariant as long as the pager is +** open so it is safe to access without the BtShared mutex. */ const char *sqlite3BtreeGetFilename(Btree *p){ assert( p->pBt->pPager!=0 ); @@ -6167,6 +6652,9 @@ const char *sqlite3BtreeGetFilename(Btree *p){ /* ** Return the pathname of the directory that contains the database file. +** +** The pager directory name is invariant as long as the pager is +** open so it is safe to access without the BtShared mutex. */ const char *sqlite3BtreeGetDirname(Btree *p){ assert( p->pBt->pPager!=0 ); @@ -6177,6 +6665,9 @@ const char *sqlite3BtreeGetDirname(Btree *p){ ** Return the pathname of the journal file for this database. The return ** value of this routine is the same regardless of whether the journal file ** has been created or not. +** +** The pager journal filename is invariant as long as the pager is +** open so it is safe to access without the BtShared mutex. */ const char *sqlite3BtreeGetJournalname(Btree *p){ assert( p->pBt->pPager!=0 ); @@ -6191,7 +6682,7 @@ const char *sqlite3BtreeGetJournalname(Btree *p){ ** The size of file pBtFrom may be reduced by this operation. ** If anything goes wrong, the transaction on pBtFrom is rolled back. */ -int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ +static int btreeCopyFile(Btree *pTo, Btree *pFrom){ int rc = SQLITE_OK; Pgno i, nPage, nToPage, iSkip; @@ -6243,12 +6734,23 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ } return rc; } +int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ + int rc; + sqlite3BtreeEnter(pTo); + sqlite3BtreeEnter(pFrom); + rc = btreeCopyFile(pTo, pFrom); + sqlite3BtreeLeave(pFrom); + sqlite3BtreeLeave(pTo); + return rc; +} + #endif /* SQLITE_OMIT_VACUUM */ /* ** Return non-zero if a transaction is active. */ int sqlite3BtreeIsInTrans(Btree *p){ + assert( p==0 || sqlite3_mutex_held(p->pSqlite->mutex) ); return (p && (p->inTrans==TRANS_WRITE)); } @@ -6256,6 +6758,7 @@ int sqlite3BtreeIsInTrans(Btree *p){ ** Return non-zero if a statement transaction is active. */ int sqlite3BtreeIsInStmt(Btree *p){ + assert( sqlite3BtreeHoldsMutex(p) ); return (p->pBt && p->pBt->inStmt); } @@ -6263,6 +6766,7 @@ int sqlite3BtreeIsInStmt(Btree *p){ ** Return non-zero if a read (or write) transaction is active. */ int sqlite3BtreeIsInReadTrans(Btree *p){ + assert( sqlite3_mutex_held(p->pSqlite->mutex) ); return (p && (p->inTrans!=TRANS_NONE)); } @@ -6279,15 +6783,17 @@ int sqlite3BtreeIsInReadTrans(Btree *p){ ** ** Just before the shared-btree is closed, the function passed as the ** xFree argument when the memory allocation was made is invoked on the -** blob of allocated memory. This function should not call sqliteFree() +** blob of allocated memory. This function should not call sqlite3_free() ** on the memory, the btree layer does that. */ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); if( !pBt->pSchema ){ - pBt->pSchema = sqliteMalloc(nBytes); + pBt->pSchema = sqlite3MallocZero(nBytes); pBt->xFreeSchema = xFree; } + sqlite3BtreeLeave(p); return pBt->pSchema; } @@ -6296,7 +6802,12 @@ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ ** handle holds an exclusive lock on the sqlite_master table. */ int sqlite3BtreeSchemaLocked(Btree *p){ - return (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK); + int rc; + assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + sqlite3BtreeEnter(p); + rc = (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK); + sqlite3BtreeLeave(p); + return rc; } @@ -6309,10 +6820,12 @@ int sqlite3BtreeSchemaLocked(Btree *p){ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ int rc = SQLITE_OK; u8 lockType = (isWriteLock?WRITE_LOCK:READ_LOCK); + sqlite3BtreeEnter(p); rc = queryTableLock(p, iTab, lockType); if( rc==SQLITE_OK ){ rc = lockTable(p, iTab, lockType); } + sqlite3BtreeLeave(p); return rc; } #endif @@ -6326,10 +6839,15 @@ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ ** to change the length of the data stored. */ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ - + assert( cursorHoldsMutex(pCsr) ); + assert( sqlite3_mutex_held(pCsr->pBtree->pSqlite->mutex) ); assert(pCsr->isIncrblobHandle); - if( pCsr->eState==CURSOR_REQUIRESEEK ){ - return SQLITE_ABORT; + if( pCsr->eState>=CURSOR_REQUIRESEEK ){ + if( pCsr->eState==CURSOR_FAULT ){ + return pCsr->skip; + }else{ + return SQLITE_ABORT; + } } /* Check some preconditions: @@ -6340,8 +6858,8 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ if( !pCsr->wrFlag ){ return SQLITE_READONLY; } - assert( !pCsr->pBtree->pBt->readOnly - && pCsr->pBtree->pBt->inTransaction==TRANS_WRITE ); + assert( !pCsr->pBt->readOnly + && pCsr->pBt->inTransaction==TRANS_WRITE ); if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } @@ -6363,6 +6881,8 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ ** sqlite3BtreePutData()). */ void sqlite3BtreeCacheOverflow(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); assert(!pCur->isIncrblobHandle); assert(!pCur->aOverflow); pCur->isIncrblobHandle = 1; diff --git a/extensions/sqlite/sqlite-source/btree.h b/extensions/sqlite/sqlite-source/btree.h index 60188463..21541fc5 100644 --- a/extensions/sqlite/sqlite-source/btree.h +++ b/extensions/sqlite/sqlite-source/btree.h @@ -41,13 +41,26 @@ typedef struct Btree Btree; typedef struct BtCursor BtCursor; typedef struct BtShared BtShared; +typedef struct BtreeMutexArray BtreeMutexArray; + +/* +** This structure records all of the Btrees that need to hold +** a mutex before we enter sqlite3VdbeExec(). The Btrees are +** are placed in aBtree[] in order of aBtree[]->pBt. That way, +** we can always lock and unlock them all quickly. +*/ +struct BtreeMutexArray { + int nMutex; + Btree *aBtree[SQLITE_MAX_ATTACHED+1]; +}; int sqlite3BtreeOpen( const char *zFilename, /* Name of database file to open */ sqlite3 *db, /* Associated database connection */ Btree **, /* Return open Btree* here */ - int flags /* Flags */ + int flags, /* Flags */ + int vfsFlags /* Flags passed through to VFS open */ ); /* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the @@ -59,6 +72,14 @@ int sqlite3BtreeOpen( #define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */ #define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */ #define BTREE_MEMORY 4 /* In-memory DB. No argument */ +#define BTREE_READONLY 8 /* Open the database in read-only mode */ +#define BTREE_READWRITE 16 /* Open for both reading and writing */ +#define BTREE_CREATE 32 /* Create the database if it does not exist */ + +/* Additional values for the 4th argument of sqlite3BtreeOpen that +** are not associated with PAGER_ values. +*/ +#define BTREE_PRIVATE 64 /* Never share with other connections */ int sqlite3BtreeClose(Btree*); int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*); @@ -105,6 +126,7 @@ int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int); int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); +void sqlite3BtreeTripAllCursors(Btree*, int); int sqlite3BtreeCursor( Btree*, /* BTree containing table to open */ @@ -129,6 +151,7 @@ int sqlite3BtreeFlags(BtCursor*); int sqlite3BtreePrevious(BtCursor*, int *pRes); int sqlite3BtreeKeySize(BtCursor*, i64 *pSize); int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*); +sqlite3 *sqlite3BtreeCursorDb(const BtCursor*); const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt); const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt); int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); @@ -146,4 +169,36 @@ void sqlite3BtreeCursorList(Btree*); int sqlite3BtreePageDump(Btree*, int, int recursive); #endif +/* +** If we are not using shared cache, then there is no need to +** use mutexes to access the BtShared structures. So make the +** Enter and Leave procedures no-ops. +*/ +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE + void sqlite3BtreeEnter(Btree*); + void sqlite3BtreeLeave(Btree*); + int sqlite3BtreeHoldsMutex(Btree*); + void sqlite3BtreeEnterCursor(BtCursor*); + void sqlite3BtreeLeaveCursor(BtCursor*); + void sqlite3BtreeEnterAll(sqlite3*); + void sqlite3BtreeLeaveAll(sqlite3*); + int sqlite3BtreeHoldsAllMutexes(sqlite3*); + void sqlite3BtreeMutexArrayEnter(BtreeMutexArray*); + void sqlite3BtreeMutexArrayLeave(BtreeMutexArray*); + void sqlite3BtreeMutexArrayInsert(BtreeMutexArray*, Btree*); +#else +# define sqlite3BtreeEnter(X) +# define sqlite3BtreeLeave(X) +# define sqlite3BtreeHoldsMutex(X) 1 +# define sqlite3BtreeEnterCursor(X) +# define sqlite3BtreeLeaveCursor(X) +# define sqlite3BtreeEnterAll(X) +# define sqlite3BtreeLeaveAll(X) +# define sqlite3BtreeHoldsAllMutexes(X) 1 +# define sqlite3BtreeMutexArrayEnter(X) +# define sqlite3BtreeMutexArrayLeave(X) +# define sqlite3BtreeMutexArrayInsert(X,Y) +#endif + + #endif /* _BTREE_H_ */ diff --git a/extensions/sqlite/sqlite-source/btreeInt.h b/extensions/sqlite/sqlite-source/btreeInt.h index 1d73ff58..6d290893 100644 --- a/extensions/sqlite/sqlite-source/btreeInt.h +++ b/extensions/sqlite/sqlite-source/btreeInt.h @@ -248,7 +248,7 @@ typedef struct BtLock BtLock; /* ** Page type flags. An ORed combination of these flags appear as the -** first byte of every BTree page. +** first byte of on-disk image of every BTree page. */ #define PTF_INTKEY 0x01 #define PTF_ZERODATA 0x02 @@ -264,6 +264,9 @@ typedef struct BtLock BtLock; ** walk up the BTree from any leaf to the root. Care must be taken to ** unref() the parent page pointer when this page is no longer referenced. ** The pageDestructor() routine handles that chore. +** +** Access to all fields of this structure is controlled by the mutex +** stored in MemPage.pBt->mutex. */ struct MemPage { u8 isInit; /* True if previously initialized. MUST BE FIRST! */ @@ -276,8 +279,8 @@ struct MemPage { u8 hasData; /* True if this page stores data */ u8 hdrOffset; /* 100 for page 1. 0 otherwise */ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ - u16 maxLocal; /* Copy of Btree.maxLocal or Btree.maxLeaf */ - u16 minLocal; /* Copy of Btree.minLocal or Btree.minLeaf */ + u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ + u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ u16 idxParent; /* Index in parent of this node */ u16 nFree; /* Number of free bytes on the page */ @@ -286,8 +289,8 @@ struct MemPage { u8 *pCell; /* Pointers to the body of the overflow cell */ u16 idx; /* Insert this cell before idx-th non-overflow cell */ } aOvfl[5]; - BtShared *pBt; /* Pointer back to BTree structure */ - u8 *aData; /* Pointer back to the start of the page */ + BtShared *pBt; /* Pointer to BtShared that this page is part of */ + u8 *aData; /* Pointer to disk image of the page data */ DbPage *pDbPage; /* Pager page handle */ Pgno pgno; /* Page number for this page */ MemPage *pParent; /* The parent of this page. NULL for root */ @@ -300,11 +303,36 @@ struct MemPage { */ #define EXTRA_SIZE sizeof(MemPage) -/* Btree handle */ +/* A Btree handle +** +** A database connection contains a pointer to an instance of +** this object for every database file that it has open. This structure +** is opaque to the database connection. The database connection cannot +** see the internals of this structure and only deals with pointers to +** this structure. +** +** For some database files, the same underlying database cache might be +** shared between multiple connections. In that case, each contection +** has it own pointer to this object. But each instance of this object +** points to the same BtShared object. The database cache and the +** schema associated with the database file are all contained within +** the BtShared object. +** +** All fields in this structure are accessed under sqlite3.mutex. +** The pBt pointer itself may not be changed while there exists cursors +** in the referenced BtShared that point back to this Btree since those +** cursors have to do go through this Btree to find their BtShared and +** they often do so without holding sqlite3.mutex. +*/ struct Btree { - sqlite3 *pSqlite; - BtShared *pBt; - u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ + sqlite3 *pSqlite; /* The database connection holding this btree */ + BtShared *pBt; /* Sharable content of this btree */ + u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ + u8 sharable; /* True if we can share pBt with other pSqlite */ + u8 locked; /* True if pSqlite currently has pBt locked */ + int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */ + Btree *pNext; /* List of other sharable Btrees from the same pSqlite */ + Btree *pPrev; /* Back pointer of the same list */ }; /* @@ -312,15 +340,28 @@ struct Btree { ** ** If the shared-data extension is enabled, there may be multiple users ** of the Btree structure. At most one of these may open a write transaction, -** but any number may have active read transactions. Variable Btree.pDb -** points to the handle that owns any current write-transaction. +** but any number may have active read transactions. */ #define TRANS_NONE 0 #define TRANS_READ 1 #define TRANS_WRITE 2 /* -** Everything we need to know about an open database +** An instance of this object represents a single database file. +** +** A single database file can be in use as the same time by two +** or more database connections. When two or more connections are +** sharing the same database file, each connection has it own +** private Btree object for the file and each of those Btrees points +** to this one BtShared object. BtShared.nRef is the number of +** connections currently sharing this database file. +** +** Fields in this structure are accessed under the BtShared.mutex +** mutex, except for nRef and pNext which are accessed under the +** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field +** may not be modified once it is initially set as long as nRef>0. +** The pSchema field may be set once under BtShared.mutex and +** thereafter is unchanged as long as nRef>0. */ struct BtShared { Pager *pPager; /* The page cache */ @@ -345,13 +386,14 @@ struct BtShared { int minLeaf; /* Minimum local payload in a LEAFDATA table */ BusyHandler *pBusyHandler; /* Callback for when there is lock contention */ u8 inTransaction; /* Transaction state */ - int nRef; /* Number of references to this structure */ int nTransaction; /* Number of open transactions (read + write) */ void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */ void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ + sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */ #ifndef SQLITE_OMIT_SHARED_CACHE + int nRef; /* Number of references to this structure */ + BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ - BtShared *pNext; /* Next in ThreadData.pBtree linked list */ #endif }; @@ -373,12 +415,22 @@ struct CellInfo { }; /* -** A cursor is a pointer to a particular entry in the BTree. +** A cursor is a pointer to a particular entry within a particular +** b-tree within a database file. +** ** The entry is identified by its MemPage and the index in ** MemPage.aCell[] of the entry. +** +** When a single database file can shared by two more database connections, +** but cursors cannot be shared. Each cursor is associated with a +** particular database connection identified BtCursor.pBtree.pSqlite. +** +** Fields in this structure are accessed under the BtShared.mutex +** found at self->pBt->mutex. */ struct BtCursor { Btree *pBtree; /* The Btree to which this cursor belongs */ + BtShared *pBt; /* The BtShared this cursor points to */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */ void *pArg; /* First arg to xCompare() */ @@ -414,10 +466,18 @@ struct BtCursor { ** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in ** this state, restoreOrClearCursorPosition() can be called to attempt to ** seek the cursor to the saved position. +** +** CURSOR_FAULT: +** A unrecoverable error (an I/O error or a malloc failure) has occurred +** on a different connection that shares the BtShared cache with this +** cursor. The error has left the cache in an inconsistent state. +** Do nothing else with this cursor. Any attempt to use the cursor +** should return the error code stored in BtCursor.skip */ #define CURSOR_INVALID 0 #define CURSOR_VALID 1 #define CURSOR_REQUIRESEEK 2 +#define CURSOR_FAULT 3 /* ** The TRACE macro will print high-level status information about the @@ -530,8 +590,6 @@ struct BtLock { ** of handle p (type Btree*) are internally consistent. */ #define btreeIntegrity(p) \ - assert( p->inTrans!=TRANS_NONE || p->pBt->nTransactionpBt->nRef ); \ - assert( p->pBt->nTransaction<=p->pBt->nRef ); \ assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \ assert( p->pBt->inTransaction>=p->inTrans ); @@ -580,7 +638,9 @@ int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int); int sqlite3BtreeInitPage(MemPage *pPage, MemPage *pParent); void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*); void sqlite3BtreeParseCell(MemPage*, int, CellInfo*); +#ifdef SQLITE_TEST u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell); +#endif int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur); void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur); void sqlite3BtreeReleaseTempCursor(BtCursor *pCur); diff --git a/extensions/sqlite/sqlite-source/build.c b/extensions/sqlite/sqlite-source/build.c index 6ff50330..2323f2a4 100644 --- a/extensions/sqlite/sqlite-source/build.c +++ b/extensions/sqlite/sqlite-source/build.c @@ -69,7 +69,7 @@ void sqlite3TableLock( int nBytes; TableLock *p; - if( 0==sqlite3ThreadDataReadOnly()->useSharedData || iDb<0 ){ + if( iDb<0 ){ return; } @@ -82,13 +82,17 @@ void sqlite3TableLock( } nBytes = sizeof(TableLock) * (pParse->nTableLock+1); - pParse->aTableLock = sqliteReallocOrFree(pParse->aTableLock, nBytes); + pParse->aTableLock = + sqlite3DbReallocOrFree(pParse->db, pParse->aTableLock, nBytes); if( pParse->aTableLock ){ p = &pParse->aTableLock[pParse->nTableLock++]; p->iDb = iDb; p->iTab = iTab; p->isWriteLock = isWriteLock; p->zName = zName; + }else{ + pParse->nTableLock = 0; + pParse->db->mallocFailed = 1; } } @@ -99,7 +103,6 @@ void sqlite3TableLock( static void codeTableLocks(Parse *pParse){ int i; Vdbe *pVdbe; - assert( sqlite3ThreadDataReadOnly()->useSharedData || pParse->nTableLock==0 ); if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){ return; @@ -132,7 +135,8 @@ void sqlite3FinishCoding(Parse *pParse){ sqlite3 *db; Vdbe *v; - if( sqlite3MallocFailed() ) return; + db = pParse->db; + if( db->mallocFailed ) return; if( pParse->nested ) return; if( !pParse->pVdbe ){ if( pParse->rc==SQLITE_OK && pParse->nErr ){ @@ -144,7 +148,6 @@ void sqlite3FinishCoding(Parse *pParse){ /* Begin by generating some termination code at the end of the ** vdbe program */ - db = pParse->db; v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_Halt, 0, 0); @@ -161,6 +164,7 @@ void sqlite3FinishCoding(Parse *pParse){ sqlite3VdbeJumpHere(v, pParse->cookieGoto-1); for(iDb=0, mask=1; iDbnDb; mask<<=1, iDb++){ if( (mask & pParse->cookieMask)==0 ) continue; + sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0); sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]); } @@ -193,7 +197,7 @@ void sqlite3FinishCoding(Parse *pParse){ /* Get the VDBE program ready for execution */ - if( v && pParse->nErr==0 && !sqlite3MallocFailed() ){ + if( v && pParse->nErr==0 && !db->mallocFailed ){ #ifdef SQLITE_DEBUG FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; sqlite3VdbeTrace(v, trace); @@ -234,16 +238,17 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ if( pParse->nErr ) return; assert( pParse->nested<10 ); /* Nesting should only be of limited depth */ va_start(ap, zFormat); - zSql = sqlite3VMPrintf(zFormat, ap); + zSql = sqlite3VMPrintf(pParse->db, zFormat, ap); va_end(ap); if( zSql==0 ){ + pParse->db->mallocFailed = 1; return; /* A malloc must have failed */ } pParse->nested++; memcpy(saveBuf, &pParse->nVar, SAVE_SZ); memset(&pParse->nVar, 0, SAVE_SZ); sqlite3RunParser(pParse, zSql, 0); - sqliteFree(zSql); + sqlite3_free(zSql); memcpy(&pParse->nVar, saveBuf, SAVE_SZ); pParse->nested--; } @@ -336,8 +341,8 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){ ** Reclaim the memory used by an index */ static void freeIndex(Index *p){ - sqliteFree(p->zColAff); - sqliteFree(p); + sqlite3_free(p->zColAff); + sqlite3_free(p); } /* @@ -426,7 +431,7 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ for(i=j=2; inDb; i++){ struct Db *pDb = &db->aDb[i]; if( pDb->pBt==0 ){ - sqliteFree(pDb->zName); + sqlite3_free(pDb->zName); pDb->zName = 0; continue; } @@ -439,7 +444,7 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ db->nDb = j; if( db->nDb<=2 && db->aDb!=db->aDbStatic ){ memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0])); - sqliteFree(db->aDb); + sqlite3_free(db->aDb); db->aDb = db->aDbStatic; } } @@ -460,12 +465,12 @@ static void sqliteResetColumnNames(Table *pTable){ assert( pTable!=0 ); if( (pCol = pTable->aCol)!=0 ){ for(i=0; inCol; i++, pCol++){ - sqliteFree(pCol->zName); + sqlite3_free(pCol->zName); sqlite3ExprDelete(pCol->pDflt); - sqliteFree(pCol->zType); - sqliteFree(pCol->zColl); + sqlite3_free(pCol->zType); + sqlite3_free(pCol->zColl); } - sqliteFree(pTable->aCol); + sqlite3_free(pTable->aCol); } pTable->aCol = 0; pTable->nCol = 0; @@ -510,21 +515,21 @@ void sqlite3DeleteTable(Table *pTable){ pNextFKey = pFKey->pNextFrom; assert( sqlite3HashFind(&pTable->pSchema->aFKey, pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey ); - sqliteFree(pFKey); + sqlite3_free(pFKey); } #endif /* Delete the Table structure itself. */ sqliteResetColumnNames(pTable); - sqliteFree(pTable->zName); - sqliteFree(pTable->zColAff); + sqlite3_free(pTable->zName); + sqlite3_free(pTable->zColAff); sqlite3SelectDelete(pTable->pSelect); #ifndef SQLITE_OMIT_CHECK sqlite3ExprDelete(pTable->pCheck); #endif sqlite3VtabClear(pTable); - sqliteFree(pTable); + sqlite3_free(pTable); } /* @@ -571,10 +576,10 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){ ** are not \000 terminated and are not persistent. The returned string ** is \000 terminated and is persistent. */ -char *sqlite3NameFromToken(Token *pName){ +char *sqlite3NameFromToken(sqlite3 *db, Token *pName){ char *zName; if( pName ){ - zName = sqliteStrNDup((char*)pName->z, pName->n); + zName = sqlite3DbStrNDup(db, (char*)pName->z, pName->n); sqlite3Dequote(zName); }else{ zName = 0; @@ -606,7 +611,7 @@ int sqlite3FindDb(sqlite3 *db, Token *pName){ Db *pDb; /* A database whose name space is being searched */ char *zName; /* Name we are searching for */ - zName = sqlite3NameFromToken(pName); + zName = sqlite3NameFromToken(db, pName); if( zName ){ n = strlen(zName); for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){ @@ -615,7 +620,7 @@ int sqlite3FindDb(sqlite3 *db, Token *pName){ break; } } - sqliteFree(zName); + sqlite3_free(zName); } return i; } @@ -738,7 +743,7 @@ void sqlite3StartTable( if( !OMIT_TEMPDB && isTemp ) iDb = 1; pParse->sNameToken = *pName; - zName = sqlite3NameFromToken(pName); + zName = sqlite3NameFromToken(db, pName); if( zName==0 ) return; if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto begin_table_error; @@ -795,8 +800,9 @@ void sqlite3StartTable( } } - pTable = sqliteMalloc( sizeof(Table) ); + pTable = sqlite3DbMallocZero(db, sizeof(Table)); if( pTable==0 ){ + db->mallocFailed = 1; pParse->rc = SQLITE_NOMEM; pParse->nErr++; goto begin_table_error; @@ -841,6 +847,7 @@ void sqlite3StartTable( ** set them now. */ sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); /* file_format */ + sqlite3VdbeUsesBtree(v, iDb); lbl = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_If, 0, lbl); fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? @@ -881,7 +888,7 @@ void sqlite3StartTable( /* If an error occurs, we jump here */ begin_table_error: - sqliteFree(zName); + sqlite3_free(zName); return; } @@ -916,20 +923,20 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){ sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); return; } - z = sqlite3NameFromToken(pName); + z = sqlite3NameFromToken(pParse->db, pName); if( z==0 ) return; for(i=0; inCol; i++){ if( STRICMP(z, p->aCol[i].zName) ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); - sqliteFree(z); + sqlite3_free(z); return; } } if( (p->nCol & 0x7)==0 ){ Column *aNew; - aNew = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0])); + aNew = sqlite3DbRealloc(pParse->db,p->aCol,(p->nCol+8)*sizeof(p->aCol[0])); if( aNew==0 ){ - sqliteFree(z); + sqlite3_free(z); return; } p->aCol = aNew; @@ -1041,8 +1048,8 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){ i = p->nCol-1; if( i<0 ) return; pCol = &p->aCol[i]; - sqliteFree(pCol->zType); - pCol->zType = sqlite3NameFromToken(pType); + sqlite3_free(pCol->zType); + pCol->zType = sqlite3NameFromToken(pParse->db, pType); pCol->affinity = sqlite3AffinityType(pType); } @@ -1066,10 +1073,11 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){ pCol->zName); }else{ Expr *pCopy; + sqlite3 *db = pParse->db; sqlite3ExprDelete(pCol->pDflt); - pCol->pDflt = pCopy = sqlite3ExprDup(pExpr); + pCol->pDflt = pCopy = sqlite3ExprDup(db, pExpr); if( pCopy ){ - sqlite3TokenCopy(&pCopy->span, &pExpr->span); + sqlite3TokenCopy(db, &pCopy->span, &pExpr->span); } } } @@ -1159,11 +1167,13 @@ void sqlite3AddCheckConstraint( ){ #ifndef SQLITE_OMIT_CHECK Table *pTab = pParse->pNewTable; + sqlite3 *db = pParse->db; if( pTab && !IN_DECLARE_VTAB ){ /* The CHECK expression must be duplicated so that tokens refer ** to malloced space and not the (ephemeral) text of the CREATE TABLE ** statement */ - pTab->pCheck = sqlite3ExprAnd(pTab->pCheck, sqlite3ExprDup(pCheckExpr)); + pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck, + sqlite3ExprDup(db, pCheckExpr)); } #endif sqlite3ExprDelete(pCheckExpr); @@ -1182,7 +1192,7 @@ void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){ if( sqlite3LocateCollSeq(pParse, zType, nType) ){ Index *pIdx; - p->aCol[i].zColl = sqliteStrNDup(zType, nType); + p->aCol[i].zColl = sqlite3DbStrNDup(pParse->db, zType, nType); /* If the column is declared as " PRIMARY KEY COLLATE ", ** then an index may have been created on this column before the @@ -1326,7 +1336,7 @@ static char *createTableStmt(Table *p, int isTemp){ zEnd = "\n)"; } n += 35 + 6*p->nCol; - zStmt = sqliteMallocRaw( n ); + zStmt = sqlite3_malloc( n ); if( zStmt==0 ) return 0; sqlite3_snprintf(n, zStmt, !OMIT_TEMPDB&&isTemp ? "CREATE TEMP TABLE ":"CREATE TABLE "); @@ -1379,7 +1389,7 @@ void sqlite3EndTable( sqlite3 *db = pParse->db; int iDb; - if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3MallocFailed() ) { + if( (pEnd==0 && pSelect==0) || pParse->nErr || db->mallocFailed ) { return; } p = pParse->pNewTable; @@ -1491,10 +1501,12 @@ void sqlite3EndTable( /* Compute the complete text of the CREATE statement */ if( pSelect ){ - zStmt = createTableStmt(p, p->pSchema==pParse->db->aDb[1].pSchema); + zStmt = createTableStmt(p, p->pSchema==db->aDb[1].pSchema); }else{ n = pEnd->z - pParse->sNameToken.z + 1; - zStmt = sqlite3MPrintf("CREATE %s %.*s", zType2, n, pParse->sNameToken.z); + zStmt = sqlite3MPrintf(db, + "CREATE %s %.*s", zType2, n, pParse->sNameToken.z + ); } /* A slot for the record has already been allocated in the @@ -1513,7 +1525,7 @@ void sqlite3EndTable( p->zName, zStmt ); - sqliteFree(zStmt); + sqlite3_free(zStmt); sqlite3ChangeCookie(db, v, iDb); #ifndef SQLITE_OMIT_AUTOINCREMENT @@ -1533,7 +1545,7 @@ void sqlite3EndTable( /* Reparse everything to update our internal data structures */ sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, - sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC); + sqlite3MPrintf(db, "tbl_name='%q'",p->zName), P3_DYNAMIC); } @@ -1546,13 +1558,18 @@ void sqlite3EndTable( pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, strlen(p->zName)+1,p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ + db->mallocFailed = 1; return; } #ifndef SQLITE_OMIT_FOREIGN_KEY for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + void *data; int nTo = strlen(pFKey->zTo) + 1; pFKey->pNextTo = sqlite3HashFind(&pSchema->aFKey, pFKey->zTo, nTo); - sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey); + data = sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey); + if( data==(void *)pFKey ){ + db->mallocFailed = 1; + } } #endif pParse->pNewTable = 0; @@ -1594,6 +1611,7 @@ void sqlite3CreateView( DbFixer sFix; Token *pName; int iDb; + sqlite3 *db = pParse->db; if( pParse->nVar>0 ){ sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); @@ -1607,7 +1625,7 @@ void sqlite3CreateView( return; } sqlite3TwoPartName(pParse, pName1, pName2, &pName); - iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); + iDb = sqlite3SchemaToIndex(db, p->pSchema); if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName) && sqlite3FixSelect(&sFix, pSelect) ){ @@ -1620,12 +1638,12 @@ void sqlite3CreateView( ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ - p->pSelect = sqlite3SelectDup(pSelect); + p->pSelect = sqlite3SelectDup(db, pSelect); sqlite3SelectDelete(pSelect); - if( sqlite3MallocFailed() ){ + if( db->mallocFailed ){ return; } - if( !pParse->db->init.busy ){ + if( !db->init.busy ){ sqlite3ViewGetColumnNames(pParse, p); } @@ -1660,6 +1678,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ Select *pSel; /* Copy of the SELECT that implements the view */ int nErr = 0; /* Number of errors encountered */ int n; /* Temporarily holds the number of cursors assigned */ + sqlite3 *db = pParse->db; /* Database connection for malloc errors */ assert( pTable ); @@ -1700,7 +1719,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ ** statement that defines the view. */ assert( pTable->pSelect ); - pSel = sqlite3SelectDup(pTable->pSelect); + pSel = sqlite3SelectDup(db, pTable->pSelect); if( pSel ){ n = pParse->nTab; sqlite3SrcListAssignCursors(pParse, pSel->pSrc); @@ -1879,7 +1898,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ sqlite3 *db = pParse->db; int iDb; - if( pParse->nErr || sqlite3MallocFailed() ){ + if( pParse->nErr || db->mallocFailed ){ goto exit_drop_table; } assert( pName->nSrc==1 ); @@ -2082,8 +2101,10 @@ void sqlite3CreateForeignKey( nByte += strlen(pToCol->a[i].zName) + 1; } } - pFKey = sqliteMalloc( nByte ); - if( pFKey==0 ) goto fk_end; + pFKey = sqlite3DbMallocZero(pParse->db, nByte ); + if( pFKey==0 ){ + goto fk_end; + } pFKey->pFrom = p; pFKey->pNextFrom = p->pFKey; z = (char*)&pFKey[1]; @@ -2134,7 +2155,7 @@ void sqlite3CreateForeignKey( pFKey = 0; fk_end: - sqliteFree(pFKey); + sqlite3_free(pFKey); #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ sqlite3ExprListDelete(pFromCol); sqlite3ExprListDelete(pToCol); @@ -2175,11 +2196,12 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ - int iDb = sqlite3SchemaToIndex(pParse->db, pIndex->pSchema); + sqlite3 *db = pParse->db; /* The database connection */ + int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, - pParse->db->aDb[iDb].zName ) ){ + db->aDb[iDb].zName ) ){ return; } #endif @@ -2211,7 +2233,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3VdbeAddOp(v, OP_IsUnique, iIdx, addr2); sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort, "indexed columns are not unique", P3_STATIC); - assert( sqlite3MallocFailed() || addr2==sqlite3VdbeCurrentAddr(v) ); + assert( db->mallocFailed || addr2==sqlite3VdbeCurrentAddr(v) ); } sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0); sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1); @@ -2261,7 +2283,7 @@ void sqlite3CreateIndex( int nExtra = 0; char *zExtra; - if( pParse->nErr || sqlite3MallocFailed() || IN_DECLARE_VTAB ){ + if( pParse->nErr || db->mallocFailed || IN_DECLARE_VTAB ){ goto exit_create_index; } @@ -2339,7 +2361,7 @@ void sqlite3CreateIndex( ** own name. */ if( pName ){ - zName = sqlite3NameFromToken(pName); + zName = sqlite3NameFromToken(db, pName); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index; if( zName==0 ) goto exit_create_index; if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ @@ -2366,7 +2388,10 @@ void sqlite3CreateIndex( sqlite3_snprintf(sizeof(zBuf),zBuf,"_%d",n); zName = 0; sqlite3SetString(&zName, "sqlite_autoindex_", pTab->zName, zBuf, (char*)0); - if( zName==0 ) goto exit_create_index; + if( zName==0 ){ + db->mallocFailed = 1; + goto exit_create_index; + } } /* Check for authorization to create an index. @@ -2392,7 +2417,7 @@ void sqlite3CreateIndex( if( pList==0 ){ nullId.z = (u8*)pTab->aCol[pTab->nCol-1].zName; nullId.n = strlen((char*)nullId.z); - pList = sqlite3ExprListAppend(0, 0, &nullId); + pList = sqlite3ExprListAppend(pParse, 0, 0, &nullId); if( pList==0 ) goto exit_create_index; pList->a[0].sortOrder = sortOrder; } @@ -2412,7 +2437,7 @@ void sqlite3CreateIndex( */ nName = strlen(zName); nCol = pList->nExpr; - pIndex = sqliteMalloc( + pIndex = sqlite3DbMallocZero(db, sizeof(Index) + /* Index structure */ sizeof(int)*nCol + /* Index.aiColumn */ sizeof(int)*(nCol+1) + /* Index.aiRowEst */ @@ -2421,7 +2446,9 @@ void sqlite3CreateIndex( nName + 1 + /* Index.zName */ nExtra /* Collation sequence names */ ); - if( sqlite3MallocFailed() ) goto exit_create_index; + if( db->mallocFailed ){ + goto exit_create_index; + } pIndex->azColl = (char**)(&pIndex[1]); pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]); pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]); @@ -2548,6 +2575,7 @@ void sqlite3CreateIndex( pIndex->zName, strlen(pIndex->zName)+1, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ + db->mallocFailed = 1; goto exit_create_index; } db->flags |= SQLITE_InternChanges; @@ -2591,7 +2619,7 @@ void sqlite3CreateIndex( */ if( pStart && pEnd ){ /* A named index with an explicit CREATE INDEX statement */ - zStmt = sqlite3MPrintf("CREATE%s INDEX %.*s", + zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", onError==OE_None ? "" : " UNIQUE", pEnd->z - pName->z + 1, pName->z); @@ -2611,7 +2639,7 @@ void sqlite3CreateIndex( zStmt ); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); - sqliteFree(zStmt); + sqlite3_free(zStmt); /* Fill the index with data and reparse the schema. Code an OP_Expire ** to invalidate all pre-compiled statements. @@ -2620,7 +2648,7 @@ void sqlite3CreateIndex( sqlite3RefillIndex(pParse, pIndex, iMem); sqlite3ChangeCookie(db, v, iDb); sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, - sqlite3MPrintf("name='%q'", pIndex->zName), P3_DYNAMIC); + sqlite3MPrintf(db, "name='%q'", pIndex->zName), P3_DYNAMIC); sqlite3VdbeAddOp(v, OP_Expire, 0, 0); } } @@ -2653,7 +2681,7 @@ exit_create_index: } sqlite3ExprListDelete(pList); sqlite3SrcListDelete(pTblName); - sqliteFree(zName); + sqlite3_free(zName); return; } @@ -2666,6 +2694,7 @@ void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); + sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0); sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0); @@ -2718,7 +2747,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ sqlite3 *db = pParse->db; int iDb; - if( pParse->nErr || sqlite3MallocFailed() ){ + if( pParse->nErr || db->mallocFailed ){ goto exit_drop_index; } assert( pName->nSrc==1 ); @@ -2788,6 +2817,7 @@ exit_drop_index: ** pointer if the array was resized. */ void *sqlite3ArrayAllocate( + sqlite3 *db, /* Connection to notify of malloc failures */ void *pArray, /* Array of objects. Might be reallocated */ int szEntry, /* Size of each object in the array */ int initSize, /* Suggested initial allocation, in elements */ @@ -2800,7 +2830,7 @@ void *sqlite3ArrayAllocate( void *pNew; int newSize; newSize = (*pnAlloc)*2 + initSize; - pNew = sqliteRealloc(pArray, newSize*szEntry); + pNew = sqlite3DbRealloc(db, pArray, newSize*szEntry); if( pNew==0 ){ *pIdx = -1; return pArray; @@ -2821,14 +2851,15 @@ void *sqlite3ArrayAllocate( ** ** A new IdList is returned, or NULL if malloc() fails. */ -IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){ +IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){ int i; if( pList==0 ){ - pList = sqliteMalloc( sizeof(IdList) ); + pList = sqlite3DbMallocZero(db, sizeof(IdList) ); if( pList==0 ) return 0; pList->nAlloc = 0; } pList->a = sqlite3ArrayAllocate( + db, pList->a, sizeof(pList->a[0]), 5, @@ -2840,7 +2871,7 @@ IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){ sqlite3IdListDelete(pList); return 0; } - pList->a[i].zName = sqlite3NameFromToken(pToken); + pList->a[i].zName = sqlite3NameFromToken(db, pToken); return pList; } @@ -2851,10 +2882,10 @@ void sqlite3IdListDelete(IdList *pList){ int i; if( pList==0 ) return; for(i=0; inId; i++){ - sqliteFree(pList->a[i].zName); + sqlite3_free(pList->a[i].zName); } - sqliteFree(pList->a); - sqliteFree(pList); + sqlite3_free(pList->a); + sqlite3_free(pList); } /* @@ -2886,26 +2917,31 @@ int sqlite3IdListIndex(IdList *pList, const char *zName){ ** ** In other words, if call like this: ** -** sqlite3SrcListAppend(A,B,0); +** sqlite3SrcListAppend(D,A,B,0); ** ** Then B is a table name and the database name is unspecified. If called ** like this: ** -** sqlite3SrcListAppend(A,B,C); +** sqlite3SrcListAppend(D,A,B,C); ** ** Then C is the table name and B is the database name. */ -SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){ +SrcList *sqlite3SrcListAppend( + sqlite3 *db, /* Connection to notify of malloc failures */ + SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */ + Token *pTable, /* Table to append */ + Token *pDatabase /* Database of the table */ +){ struct SrcList_item *pItem; if( pList==0 ){ - pList = sqliteMalloc( sizeof(SrcList) ); + pList = sqlite3DbMallocZero(db, sizeof(SrcList) ); if( pList==0 ) return 0; pList->nAlloc = 1; } if( pList->nSrc>=pList->nAlloc ){ SrcList *pNew; pList->nAlloc *= 2; - pNew = sqliteRealloc(pList, + pNew = sqlite3DbRealloc(db, pList, sizeof(*pList) + (pList->nAlloc-1)*sizeof(pList->a[0]) ); if( pNew==0 ){ sqlite3SrcListDelete(pList); @@ -2923,8 +2959,8 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){ pDatabase = pTable; pTable = pTemp; } - pItem->zName = sqlite3NameFromToken(pTable); - pItem->zDatabase = sqlite3NameFromToken(pDatabase); + pItem->zName = sqlite3NameFromToken(db, pTable); + pItem->zDatabase = sqlite3NameFromToken(db, pDatabase); pItem->iCursor = -1; pItem->isPopulated = 0; pList->nSrc++; @@ -2937,7 +2973,7 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; struct SrcList_item *pItem; - assert(pList || sqlite3MallocFailed() ); + assert(pList || pParse->db->mallocFailed ); if( pList ){ for(i=0, pItem=pList->a; inSrc; i++, pItem++){ if( pItem->iCursor>=0 ) break; @@ -2957,15 +2993,15 @@ void sqlite3SrcListDelete(SrcList *pList){ struct SrcList_item *pItem; if( pList==0 ) return; for(pItem=pList->a, i=0; inSrc; i++, pItem++){ - sqliteFree(pItem->zDatabase); - sqliteFree(pItem->zName); - sqliteFree(pItem->zAlias); + sqlite3_free(pItem->zDatabase); + sqlite3_free(pItem->zName); + sqlite3_free(pItem->zAlias); sqlite3DeleteTable(pItem->pTab); sqlite3SelectDelete(pItem->pSelect); sqlite3ExprDelete(pItem->pOn); sqlite3IdListDelete(pItem->pUsing); } - sqliteFree(pList); + sqlite3_free(pList); } /* @@ -2985,6 +3021,7 @@ void sqlite3SrcListDelete(SrcList *pList){ ** term added. */ SrcList *sqlite3SrcListAppendFromTerm( + Parse *pParse, /* Parsing context */ SrcList *p, /* The left part of the FROM clause already seen */ Token *pTable, /* Name of the table to add to the FROM clause */ Token *pDatabase, /* Name of the database containing pTable */ @@ -2994,7 +3031,8 @@ SrcList *sqlite3SrcListAppendFromTerm( IdList *pUsing /* The USING clause of a join */ ){ struct SrcList_item *pItem; - p = sqlite3SrcListAppend(p, pTable, pDatabase); + sqlite3 *db = pParse->db; + p = sqlite3SrcListAppend(db, p, pTable, pDatabase); if( p==0 || p->nSrc==0 ){ sqlite3ExprDelete(pOn); sqlite3IdListDelete(pUsing); @@ -3003,7 +3041,7 @@ SrcList *sqlite3SrcListAppendFromTerm( } pItem = &p->a[p->nSrc-1]; if( pAlias && pAlias->n ){ - pItem->zAlias = sqlite3NameFromToken(pAlias); + pItem->zAlias = sqlite3NameFromToken(db, pAlias); } pItem->pSelect = pSubquery; pItem->pOn = pOn; @@ -3045,7 +3083,7 @@ void sqlite3BeginTransaction(Parse *pParse, int type){ int i; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3MallocFailed() ) return; + if( pParse->nErr || db->mallocFailed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return; v = sqlite3GetVdbe(pParse); @@ -3053,6 +3091,7 @@ void sqlite3BeginTransaction(Parse *pParse, int type){ if( type!=TK_DEFERRED ){ for(i=0; inDb; i++){ sqlite3VdbeAddOp(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1); + sqlite3VdbeUsesBtree(v, i); } } sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0); @@ -3066,7 +3105,7 @@ void sqlite3CommitTransaction(Parse *pParse){ Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3MallocFailed() ) return; + if( pParse->nErr || db->mallocFailed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return; v = sqlite3GetVdbe(pParse); @@ -3083,7 +3122,7 @@ void sqlite3RollbackTransaction(Parse *pParse){ Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3MallocFailed() ) return; + if( pParse->nErr || db->mallocFailed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return; v = sqlite3GetVdbe(pParse); @@ -3099,7 +3138,15 @@ void sqlite3RollbackTransaction(Parse *pParse){ int sqlite3OpenTempDatabase(Parse *pParse){ sqlite3 *db = pParse->db; if( db->aDb[1].pBt==0 && !pParse->explain ){ - int rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, + int rc; + static const int flags = + SQLITE_OPEN_READWRITE | + SQLITE_OPEN_CREATE | + SQLITE_OPEN_EXCLUSIVE | + SQLITE_OPEN_DELETEONCLOSE | + SQLITE_OPEN_TEMP_DB; + + rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags, &db->aDb[1].pBt); if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "unable to open a temporary database " @@ -3295,27 +3342,27 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ assert( pName1->z ); pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0); if( pColl ){ - char *zColl = sqliteStrNDup((const char *)pName1->z, pName1->n); + char *zColl = sqlite3DbStrNDup(db, (const char *)pName1->z, pName1->n); if( zColl ){ reindexDatabases(pParse, zColl); - sqliteFree(zColl); + sqlite3_free(zColl); } return; } } iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); if( iDb<0 ) return; - z = sqlite3NameFromToken(pObjName); + z = sqlite3NameFromToken(db, pObjName); if( z==0 ) return; zDb = db->aDb[iDb].zName; pTab = sqlite3FindTable(db, z, zDb); if( pTab ){ reindexTable(pParse, pTab, 0); - sqliteFree(z); + sqlite3_free(z); return; } pIndex = sqlite3FindIndex(db, z, zDb); - sqliteFree(z); + sqlite3_free(z); if( pIndex ){ sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3RefillIndex(pParse, pIndex, -1); @@ -3330,7 +3377,7 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ ** with OP_OpenRead or OP_OpenWrite to access database index pIdx. ** ** If successful, a pointer to the new structure is returned. In this case -** the caller is responsible for calling sqliteFree() on the returned +** the caller is responsible for calling sqlite3_free() on the returned ** pointer. If an error occurs (out of memory or missing collation ** sequence), NULL is returned and the state of pParse updated to reflect ** the error. @@ -3339,9 +3386,10 @@ KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){ int i; int nCol = pIdx->nColumn; int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol; - KeyInfo *pKey = (KeyInfo *)sqliteMalloc(nBytes); + KeyInfo *pKey = (KeyInfo *)sqlite3DbMallocZero(pParse->db, nBytes); if( pKey ){ + pKey->db = pParse->db; pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]); assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) ); for(i=0; inErr ){ - sqliteFree(pKey); + sqlite3_free(pKey); pKey = 0; } return pKey; diff --git a/extensions/sqlite/sqlite-source/callback.c b/extensions/sqlite/sqlite-source/callback.c index 33797932..e5a41c72 100644 --- a/extensions/sqlite/sqlite-source/callback.c +++ b/extensions/sqlite/sqlite-source/callback.c @@ -27,15 +27,15 @@ static void callCollNeeded(sqlite3 *db, const char *zName, int nName){ assert( !db->xCollNeeded || !db->xCollNeeded16 ); if( nName<0 ) nName = strlen(zName); if( db->xCollNeeded ){ - char *zExternal = sqliteStrNDup(zName, nName); + char *zExternal = sqlite3DbStrNDup(db, zName, nName); if( !zExternal ) return; db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal); - sqliteFree(zExternal); + sqlite3_free(zExternal); } #ifndef SQLITE_OMIT_UTF16 if( db->xCollNeeded16 ){ char const *zExternal; - sqlite3_value *pTmp = sqlite3ValueNew(); + sqlite3_value *pTmp = sqlite3ValueNew(db); sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC); zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE); if( zExternal ){ @@ -162,7 +162,7 @@ static CollSeq *findCollSeqEntry( pColl = sqlite3HashFind(&db->aCollSeq, zName, nName); if( 0==pColl && create ){ - pColl = sqliteMalloc( 3*sizeof(*pColl) + nName + 1 ); + pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1 ); if( pColl ){ CollSeq *pDel = 0; pColl[0].zName = (char*)&pColl[3]; @@ -179,9 +179,10 @@ static CollSeq *findCollSeqEntry( ** return the pColl pointer to be deleted (because it wasn't added ** to the hash table). */ - assert( !pDel || (sqlite3MallocFailed() && pDel==pColl) ); - if( pDel ){ - sqliteFree(pDel); + assert( pDel==0 || pDel==pColl ); + if( pDel!=0 ){ + db->mallocFailed = 1; + sqlite3_free(pDel); pColl = 0; } } @@ -303,14 +304,15 @@ FuncDef *sqlite3FindFunction( ** new entry to the hash table and return it. */ if( createFlag && bestmatch<6 && - (pBest = sqliteMalloc(sizeof(*pBest)+nName))!=0 ){ + (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName))!=0 ){ pBest->nArg = nArg; pBest->pNext = pFirst; pBest->iPrefEnc = enc; memcpy(pBest->zName, zName, nName); pBest->zName[nName] = 0; if( pBest==sqlite3HashInsert(&db->aFunc,pBest->zName,nName,(void*)pBest) ){ - sqliteFree(pBest); + db->mallocFailed = 1; + sqlite3_free(pBest); return 0; } } @@ -323,7 +325,7 @@ FuncDef *sqlite3FindFunction( /* ** Free all resources held by the schema structure. The void* argument points -** at a Schema struct. This function does not call sqliteFree() on the +** at a Schema struct. This function does not call sqlite3_free() on the ** pointer itself, it just cleans up subsiduary resources (i.e. the contents ** of the schema hash tables). */ @@ -356,14 +358,16 @@ void sqlite3SchemaFree(void *p){ ** Find and return the schema associated with a BTree. Create ** a new one if necessary. */ -Schema *sqlite3SchemaGet(Btree *pBt){ +Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ Schema * p; if( pBt ){ - p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree); + p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaFree); }else{ - p = (Schema *)sqliteMalloc(sizeof(Schema)); + p = (Schema *)sqlite3MallocZero(sizeof(Schema)); } - if( p && 0==p->file_format ){ + if( !p ){ + db->mallocFailed = 1; + }else if ( 0==p->file_format ){ sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0); diff --git a/extensions/sqlite/sqlite-source/complete.c b/extensions/sqlite/sqlite-source/complete.c index 660417b0..f35ca864 100644 --- a/extensions/sqlite/sqlite-source/complete.c +++ b/extensions/sqlite/sqlite-source/complete.c @@ -24,8 +24,16 @@ /* ** This is defined in tokenize.c. We just have to import the definition. */ -extern const char sqlite3IsIdChar[]; -#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsIdChar[c-0x20])) +#ifndef SQLITE_AMALGAMATION +#ifdef SQLITE_ASCII +extern const char sqlite3IsAsciiIdChar[]; +#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20])) +#endif +#ifdef SQLITE_EBCDIC +extern const char sqlite3IsEbcdicIdChar[]; +#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) +#endif +#endif /* SQLITE_AMALGAMATION */ /* @@ -248,9 +256,9 @@ int sqlite3_complete(const char *zSql){ int sqlite3_complete16(const void *zSql){ sqlite3_value *pVal; char const *zSql8; - int rc = 0; + int rc = SQLITE_NOMEM; - pVal = sqlite3ValueNew(); + pVal = sqlite3ValueNew(0); sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zSql8 ){ diff --git a/extensions/sqlite/sqlite-source/date.c b/extensions/sqlite/sqlite-source/date.c index 545107a0..c440db84 100644 --- a/extensions/sqlite/sqlite-source/date.c +++ b/extensions/sqlite/sqlite-source/date.c @@ -46,7 +46,6 @@ ** Richmond, Virginia (USA) */ #include "sqliteInt.h" -#include "os.h" #include #include #include @@ -303,7 +302,11 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){ ** as there is a time string. The time string can be omitted as long ** as there is a year and date. */ -static int parseDateOrTime(const char *zDate, DateTime *p){ +static int parseDateOrTime( + sqlite3_context *context, + const char *zDate, + DateTime *p +){ memset(p, 0, sizeof(*p)); if( parseYyyyMmDd(zDate,p)==0 ){ return 0; @@ -311,7 +314,7 @@ static int parseDateOrTime(const char *zDate, DateTime *p){ return 0; }else if( sqlite3StrICmp(zDate,"now")==0){ double r; - sqlite3OsCurrentTime(&r); + sqlite3OsCurrentTime((sqlite3_vfs *)sqlite3_user_data(context), &r); p->rJD = r; p->validJD = 1; return 0; @@ -423,7 +426,7 @@ static double localtimeOffset(DateTime *p){ #else { struct tm *pTm; - sqlite3OsEnterMutex(); + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); pTm = localtime(&t); y.Y = pTm->tm_year + 1900; y.M = pTm->tm_mon + 1; @@ -431,7 +434,7 @@ static double localtimeOffset(DateTime *p){ y.h = pTm->tm_hour; y.m = pTm->tm_min; y.s = pTm->tm_sec; - sqlite3OsLeaveMutex(); + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); } #endif y.validYMD = 1; @@ -651,11 +654,17 @@ static int parseModifier(const char *zMod, DateTime *p){ ** the resulting time into the DateTime structure p. Return 0 ** on success and 1 if there are any errors. */ -static int isDate(int argc, sqlite3_value **argv, DateTime *p){ +static int isDate( + sqlite3_context *context, + int argc, + sqlite3_value **argv, + DateTime *p +){ int i; const unsigned char *z; if( argc==0 ) return 1; - if( (z = sqlite3_value_text(argv[0]))==0 || parseDateOrTime((char*)z, p) ){ + z = sqlite3_value_text(argv[0]); + if( !z || parseDateOrTime(context, (char*)z, p) ){ return 1; } for(i=1; ipVfs), aFuncs[i].xFunc, 0, 0); } #else static const struct { diff --git a/extensions/sqlite/sqlite-source/delete.c b/extensions/sqlite/sqlite-source/delete.c index 64199b02..1516457f 100644 --- a/extensions/sqlite/sqlite-source/delete.c +++ b/extensions/sqlite/sqlite-source/delete.c @@ -115,10 +115,10 @@ void sqlite3DeleteFrom( #endif sContext.pParse = 0; - if( pParse->nErr || sqlite3MallocFailed() ){ + db = pParse->db; + if( pParse->nErr || db->mallocFailed ){ goto delete_from_cleanup; } - db = pParse->db; assert( pTabList->nSrc==1 ); /* Locate the table which we want to delete. This table has to be @@ -196,7 +196,7 @@ void sqlite3DeleteFrom( ** a ephemeral table. */ if( isView ){ - Select *pView = sqlite3SelectDup(pTab->pSelect); + Select *pView = sqlite3SelectDup(db, pTab->pSelect); sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0); sqlite3SelectDelete(pView); } diff --git a/extensions/sqlite/sqlite-source/expr.c b/extensions/sqlite/sqlite-source/expr.c index 09d9e54a..a18eeb7c 100644 --- a/extensions/sqlite/sqlite-source/expr.c +++ b/extensions/sqlite/sqlite-source/expr.c @@ -177,7 +177,7 @@ static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){ ** Argument pRight (but not pLeft) may be a null pointer. In this case, ** it is not considered. */ -CollSeq* sqlite3BinaryCompareCollSeq( +CollSeq *sqlite3BinaryCompareCollSeq( Parse *pParse, Expr *pLeft, Expr *pRight @@ -217,12 +217,18 @@ static int codeCompare( /* ** Construct a new expression node and return a pointer to it. Memory -** for this node is obtained from sqliteMalloc(). The calling function +** for this node is obtained from sqlite3_malloc(). The calling function ** is responsible for making sure the node eventually gets freed. */ -Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){ +Expr *sqlite3Expr( + sqlite3 *db, /* Handle for sqlite3DbMallocZero() (may be null) */ + int op, /* Expression opcode */ + Expr *pLeft, /* Left operand */ + Expr *pRight, /* Right operand */ + const Token *pToken /* Argument token */ +){ Expr *pNew; - pNew = sqliteMalloc( sizeof(Expr) ); + pNew = sqlite3DbMallocZero(db, sizeof(Expr)); if( pNew==0 ){ /* When malloc fails, delete pLeft and pRight. Expressions passed to ** this function must always be allocated with sqlite3Expr() for this @@ -258,16 +264,17 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){ } /* -** Works like sqlite3Expr() but frees its pLeft and pRight arguments -** if it fails due to a malloc problem. +** Works like sqlite3Expr() except that it takes an extra Parse* +** argument and notifies the associated connection object if malloc fails. */ -Expr *sqlite3ExprOrFree(int op, Expr *pLeft, Expr *pRight, const Token *pToken){ - Expr *pNew = sqlite3Expr(op, pLeft, pRight, pToken); - if( pNew==0 ){ - sqlite3ExprDelete(pLeft); - sqlite3ExprDelete(pRight); - } - return pNew; +Expr *sqlite3PExpr( + Parse *pParse, /* Parsing context */ + int op, /* Expression opcode */ + Expr *pLeft, /* Left operand */ + Expr *pRight, /* Right operand */ + const Token *pToken /* Argument token */ +){ + return sqlite3Expr(pParse->db, op, pLeft, pRight, pToken); } /* @@ -287,10 +294,10 @@ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){ int depth; if( pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", pToken); - return sqlite3Expr(TK_NULL, 0, 0, 0); + return sqlite3PExpr(pParse, TK_NULL, 0, 0, 0); } if( v==0 ) return 0; - p = sqlite3Expr(TK_REGISTER, 0, 0, pToken); + p = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, pToken); if( p==0 ){ return 0; /* Malloc failed */ } @@ -305,13 +312,13 @@ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){ ** Join two expressions using an AND operator. If either expression is ** NULL, then just return the other expression. */ -Expr *sqlite3ExprAnd(Expr *pLeft, Expr *pRight){ +Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){ if( pLeft==0 ){ return pRight; }else if( pRight==0 ){ return pLeft; }else{ - return sqlite3Expr(TK_AND, pLeft, pRight, 0); + return sqlite3Expr(db, TK_AND, pLeft, pRight, 0); } } @@ -322,7 +329,7 @@ Expr *sqlite3ExprAnd(Expr *pLeft, Expr *pRight){ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){ assert( pRight!=0 ); assert( pLeft!=0 ); - if( !sqlite3MallocFailed() && pRight->z && pLeft->z ){ + if( pExpr && pRight->z && pLeft->z ){ assert( pLeft->dyn==0 || pLeft->z[pLeft->n]==0 ); if( pLeft->dyn==0 && pRight->dyn==0 ){ pExpr->span.z = pLeft->z; @@ -337,10 +344,10 @@ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){ ** Construct a new expression node for a function with multiple ** arguments. */ -Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){ +Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){ Expr *pNew; assert( pToken ); - pNew = sqliteMalloc( sizeof(Expr) ); + pNew = sqlite3DbMallocZero(pParse->db, sizeof(Expr) ); if( pNew==0 ){ sqlite3ExprListDelete(pList); /* Avoid leaking memory when malloc fails */ return 0; @@ -373,6 +380,8 @@ Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){ */ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ Token *pToken; + sqlite3 *db = pParse->db; + if( pExpr==0 ) return; pToken = &pExpr->token; assert( pToken->n>=1 ); @@ -413,10 +422,14 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ pExpr->iTable = ++pParse->nVar; if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){ pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10; - pParse->apVarExpr = sqliteReallocOrFree(pParse->apVarExpr, - pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) ); + pParse->apVarExpr = + sqlite3DbReallocOrFree( + db, + pParse->apVarExpr, + pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) + ); } - if( !sqlite3MallocFailed() ){ + if( !db->mallocFailed ){ assert( pParse->apVarExpr!=0 ); pParse->apVarExpr[pParse->nVarExpr++] = pExpr; } @@ -432,26 +445,26 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ */ void sqlite3ExprDelete(Expr *p){ if( p==0 ) return; - if( p->span.dyn ) sqliteFree((char*)p->span.z); - if( p->token.dyn ) sqliteFree((char*)p->token.z); + if( p->span.dyn ) sqlite3_free((char*)p->span.z); + if( p->token.dyn ) sqlite3_free((char*)p->token.z); sqlite3ExprDelete(p->pLeft); sqlite3ExprDelete(p->pRight); sqlite3ExprListDelete(p->pList); sqlite3SelectDelete(p->pSelect); - sqliteFree(p); + sqlite3_free(p); } /* ** The Expr.token field might be a string literal that is quoted. ** If so, remove the quotation marks. */ -void sqlite3DequoteExpr(Expr *p){ +void sqlite3DequoteExpr(sqlite3 *db, Expr *p){ if( ExprHasAnyProperty(p, EP_Dequoted) ){ return; } ExprSetProperty(p, EP_Dequoted); if( p->token.dyn==0 ){ - sqlite3TokenCopy(&p->token, &p->token); + sqlite3TokenCopy(db, &p->token, &p->token); } sqlite3Dequote((char*)p->token.z); } @@ -469,62 +482,63 @@ void sqlite3DequoteExpr(Expr *p){ ** ** Any tables that the SrcList might point to are not duplicated. */ -Expr *sqlite3ExprDup(Expr *p){ +Expr *sqlite3ExprDup(sqlite3 *db, Expr *p){ Expr *pNew; if( p==0 ) return 0; - pNew = sqliteMallocRaw( sizeof(*p) ); + pNew = sqlite3DbMallocRaw(db, sizeof(*p) ); if( pNew==0 ) return 0; memcpy(pNew, p, sizeof(*pNew)); if( p->token.z!=0 ){ - pNew->token.z = (u8*)sqliteStrNDup((char*)p->token.z, p->token.n); + pNew->token.z = (u8*)sqlite3DbStrNDup(db, (char*)p->token.z, p->token.n); pNew->token.dyn = 1; }else{ assert( pNew->token.z==0 ); } pNew->span.z = 0; - pNew->pLeft = sqlite3ExprDup(p->pLeft); - pNew->pRight = sqlite3ExprDup(p->pRight); - pNew->pList = sqlite3ExprListDup(p->pList); - pNew->pSelect = sqlite3SelectDup(p->pSelect); + pNew->pLeft = sqlite3ExprDup(db, p->pLeft); + pNew->pRight = sqlite3ExprDup(db, p->pRight); + pNew->pList = sqlite3ExprListDup(db, p->pList); + pNew->pSelect = sqlite3SelectDup(db, p->pSelect); return pNew; } -void sqlite3TokenCopy(Token *pTo, Token *pFrom){ - if( pTo->dyn ) sqliteFree((char*)pTo->z); +void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){ + if( pTo->dyn ) sqlite3_free((char*)pTo->z); if( pFrom->z ){ pTo->n = pFrom->n; - pTo->z = (u8*)sqliteStrNDup((char*)pFrom->z, pFrom->n); + pTo->z = (u8*)sqlite3DbStrNDup(db, (char*)pFrom->z, pFrom->n); pTo->dyn = 1; }else{ pTo->z = 0; } } -ExprList *sqlite3ExprListDup(ExprList *p){ +ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){ ExprList *pNew; struct ExprList_item *pItem, *pOldItem; int i; if( p==0 ) return 0; - pNew = sqliteMalloc( sizeof(*pNew) ); + pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); if( pNew==0 ) return 0; + pNew->iECursor = 0; pNew->nExpr = pNew->nAlloc = p->nExpr; - pNew->a = pItem = sqliteMalloc( p->nExpr*sizeof(p->a[0]) ); + pNew->a = pItem = sqlite3DbMallocRaw(db, p->nExpr*sizeof(p->a[0]) ); if( pItem==0 ){ - sqliteFree(pNew); + sqlite3_free(pNew); return 0; } pOldItem = p->a; for(i=0; inExpr; i++, pItem++, pOldItem++){ Expr *pNewExpr, *pOldExpr; - pItem->pExpr = pNewExpr = sqlite3ExprDup(pOldExpr = pOldItem->pExpr); + pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr = pOldItem->pExpr); if( pOldExpr->span.z!=0 && pNewExpr ){ /* Always make a copy of the span for top-level expressions in the ** expression list. The logic in SELECT processing that determines ** the names of columns in the result set needs this information */ - sqlite3TokenCopy(&pNewExpr->span, &pOldExpr->span); + sqlite3TokenCopy(db, &pNewExpr->span, &pOldExpr->span); } assert( pNewExpr==0 || pNewExpr->span.z!=0 || pOldExpr->span.z==0 - || sqlite3MallocFailed() ); - pItem->zName = sqliteStrDup(pOldItem->zName); + || db->mallocFailed ); + pItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pItem->sortOrder = pOldItem->sortOrder; pItem->isAgg = pOldItem->isAgg; pItem->done = 0; @@ -540,22 +554,22 @@ ExprList *sqlite3ExprListDup(ExprList *p){ */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \ || !defined(SQLITE_OMIT_SUBQUERY) -SrcList *sqlite3SrcListDup(SrcList *p){ +SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){ SrcList *pNew; int i; int nByte; if( p==0 ) return 0; nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); - pNew = sqliteMallocRaw( nByte ); + pNew = sqlite3DbMallocRaw(db, nByte ); if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; inSrc; i++){ struct SrcList_item *pNewItem = &pNew->a[i]; struct SrcList_item *pOldItem = &p->a[i]; Table *pTab; - pNewItem->zDatabase = sqliteStrDup(pOldItem->zDatabase); - pNewItem->zName = sqliteStrDup(pOldItem->zName); - pNewItem->zAlias = sqliteStrDup(pOldItem->zAlias); + pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); + pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); + pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->jointype = pOldItem->jointype; pNewItem->iCursor = pOldItem->iCursor; pNewItem->isPopulated = pOldItem->isPopulated; @@ -563,49 +577,49 @@ SrcList *sqlite3SrcListDup(SrcList *p){ if( pTab ){ pTab->nRef++; } - pNewItem->pSelect = sqlite3SelectDup(pOldItem->pSelect); - pNewItem->pOn = sqlite3ExprDup(pOldItem->pOn); - pNewItem->pUsing = sqlite3IdListDup(pOldItem->pUsing); + pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect); + pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn); + pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing); pNewItem->colUsed = pOldItem->colUsed; } return pNew; } -IdList *sqlite3IdListDup(IdList *p){ +IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ IdList *pNew; int i; if( p==0 ) return 0; - pNew = sqliteMallocRaw( sizeof(*pNew) ); + pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); if( pNew==0 ) return 0; pNew->nId = pNew->nAlloc = p->nId; - pNew->a = sqliteMallocRaw( p->nId*sizeof(p->a[0]) ); + pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) ); if( pNew->a==0 ){ - sqliteFree(pNew); + sqlite3_free(pNew); return 0; } for(i=0; inId; i++){ struct IdList_item *pNewItem = &pNew->a[i]; struct IdList_item *pOldItem = &p->a[i]; - pNewItem->zName = sqliteStrDup(pOldItem->zName); + pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->idx = pOldItem->idx; } return pNew; } -Select *sqlite3SelectDup(Select *p){ +Select *sqlite3SelectDup(sqlite3 *db, Select *p){ Select *pNew; if( p==0 ) return 0; - pNew = sqliteMallocRaw( sizeof(*p) ); + pNew = sqlite3DbMallocRaw(db, sizeof(*p) ); if( pNew==0 ) return 0; pNew->isDistinct = p->isDistinct; - pNew->pEList = sqlite3ExprListDup(p->pEList); - pNew->pSrc = sqlite3SrcListDup(p->pSrc); - pNew->pWhere = sqlite3ExprDup(p->pWhere); - pNew->pGroupBy = sqlite3ExprListDup(p->pGroupBy); - pNew->pHaving = sqlite3ExprDup(p->pHaving); - pNew->pOrderBy = sqlite3ExprListDup(p->pOrderBy); + pNew->pEList = sqlite3ExprListDup(db, p->pEList); + pNew->pSrc = sqlite3SrcListDup(db, p->pSrc); + pNew->pWhere = sqlite3ExprDup(db, p->pWhere); + pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy); + pNew->pHaving = sqlite3ExprDup(db, p->pHaving); + pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy); pNew->op = p->op; - pNew->pPrior = sqlite3SelectDup(p->pPrior); - pNew->pLimit = sqlite3ExprDup(p->pLimit); - pNew->pOffset = sqlite3ExprDup(p->pOffset); + pNew->pPrior = sqlite3SelectDup(db, p->pPrior); + pNew->pLimit = sqlite3ExprDup(db, p->pLimit); + pNew->pOffset = sqlite3ExprDup(db, p->pOffset); pNew->iLimit = -1; pNew->iOffset = -1; pNew->isResolved = p->isResolved; @@ -619,7 +633,7 @@ Select *sqlite3SelectDup(Select *p){ return pNew; } #else -Select *sqlite3SelectDup(Select *p){ +Select *sqlite3SelectDup(sqlite3 *db, Select *p){ assert( p==0 ); return 0; } @@ -630,9 +644,15 @@ Select *sqlite3SelectDup(Select *p){ ** Add a new element to the end of an expression list. If pList is ** initially NULL, then create a new expression list. */ -ExprList *sqlite3ExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){ +ExprList *sqlite3ExprListAppend( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List to which to append. Might be NULL */ + Expr *pExpr, /* Expression to be appended */ + Token *pName /* AS keyword for the expression */ +){ + sqlite3 *db = pParse->db; if( pList==0 ){ - pList = sqliteMalloc( sizeof(ExprList) ); + pList = sqlite3DbMallocZero(db, sizeof(ExprList) ); if( pList==0 ){ goto no_mem; } @@ -641,7 +661,7 @@ ExprList *sqlite3ExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){ if( pList->nAlloc<=pList->nExpr ){ struct ExprList_item *a; int n = pList->nAlloc*2 + 4; - a = sqliteRealloc(pList->a, n*sizeof(pList->a[0])); + a = sqlite3DbRealloc(db, pList->a, n*sizeof(pList->a[0])); if( a==0 ){ goto no_mem; } @@ -652,7 +672,7 @@ ExprList *sqlite3ExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){ if( pExpr || pName ){ struct ExprList_item *pItem = &pList->a[pList->nExpr++]; memset(pItem, 0, sizeof(*pItem)); - pItem->zName = sqlite3NameFromToken(pName); + pItem->zName = sqlite3NameFromToken(db, pName); pItem->pExpr = pExpr; } return pList; @@ -680,7 +700,7 @@ void sqlite3ExprListCheckLength( } -#if SQLITE_MAX_EXPR_DEPTH>0 +#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 /* The following three functions, heightOfExpr(), heightOfExprList() ** and heightOfSelect(), are used to determine the maximum height ** of any expression tree referenced by the structure passed as the @@ -756,10 +776,10 @@ void sqlite3ExprListDelete(ExprList *pList){ assert( pList->nExpr<=pList->nAlloc ); for(pItem=pList->a, i=0; inExpr; i++, pItem++){ sqlite3ExprDelete(pItem->pExpr); - sqliteFree(pItem->zName); + sqlite3_free(pItem->zName); } - sqliteFree(pList->a); - sqliteFree(pList); + sqlite3_free(pList->a); + sqlite3_free(pList); } /* @@ -994,12 +1014,13 @@ static int lookupName( struct SrcList_item *pItem; /* Use for looping over pSrcList items */ struct SrcList_item *pMatch = 0; /* The matching pSrcList item */ NameContext *pTopNC = pNC; /* First namecontext in the list */ + Schema *pSchema = 0; /* Schema of the expression */ assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */ - zDb = sqlite3NameFromToken(pDbToken); - zTab = sqlite3NameFromToken(pTableToken); - zCol = sqlite3NameFromToken(pColumnToken); - if( sqlite3MallocFailed() ){ + zDb = sqlite3NameFromToken(db, pDbToken); + zTab = sqlite3NameFromToken(db, pTableToken); + zCol = sqlite3NameFromToken(db, pColumnToken); + if( db->mallocFailed ){ goto lookupname_end; } @@ -1032,7 +1053,7 @@ static int lookupName( } if( 0==(cntTab++) ){ pExpr->iTable = pItem->iCursor; - pExpr->pSchema = pTab->pSchema; + pSchema = pTab->pSchema; pMatch = pItem; } for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ @@ -1042,7 +1063,7 @@ static int lookupName( cnt++; pExpr->iTable = pItem->iCursor; pMatch = pItem; - pExpr->pSchema = pTab->pSchema; + pSchema = pTab->pSchema; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->affinity = pTab->aCol[j].affinity; @@ -1096,7 +1117,7 @@ static int lookupName( int iCol; Column *pCol = pTab->aCol; - pExpr->pSchema = pTab->pSchema; + pSchema = pTab->pSchema; cntTab++; for(iCol=0; iCol < pTab->nCol; iCol++, pCol++) { if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ @@ -1140,19 +1161,25 @@ static int lookupName( for(j=0; jnExpr; j++){ char *zAs = pEList->a[j].zName; if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ - Expr *pDup; + Expr *pDup, *pOrig; assert( pExpr->pLeft==0 && pExpr->pRight==0 ); assert( pExpr->pList==0 ); assert( pExpr->pSelect==0 ); - pDup = sqlite3ExprDup(pEList->a[j].pExpr); + pOrig = pEList->a[j].pExpr; + if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){ + sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); + sqlite3_free(zCol); + return 2; + } + pDup = sqlite3ExprDup(db, pOrig); if( pExpr->flags & EP_ExpCollate ){ pDup->pColl = pExpr->pColl; pDup->flags |= EP_ExpCollate; } - if( pExpr->span.dyn ) sqliteFree((char*)pExpr->span.z); - if( pExpr->token.dyn ) sqliteFree((char*)pExpr->token.z); + if( pExpr->span.dyn ) sqlite3_free((char*)pExpr->span.z); + if( pExpr->token.dyn ) sqlite3_free((char*)pExpr->token.z); memcpy(pExpr, pDup, sizeof(*pExpr)); - sqliteFree(pDup); + sqlite3_free(pDup); cnt = 1; pMatch = 0; assert( zTab==0 && zDb==0 ); @@ -1180,7 +1207,7 @@ static int lookupName( ** fields are not changed in any context. */ if( cnt==0 && zTab==0 && pColumnToken->z[0]=='"' ){ - sqliteFree(zCol); + sqlite3_free(zCol); return 0; } @@ -1197,11 +1224,15 @@ static int lookupName( }else if( zTab ){ sqlite3SetString(&z, zTab, ".", zCol, (char*)0); }else{ - z = sqliteStrDup(zCol); + z = sqlite3StrDup(zCol); + } + if( z ){ + sqlite3ErrorMsg(pParse, zErr, z); + sqlite3_free(z); + pTopNC->nErr++; + }else{ + db->mallocFailed = 1; } - sqlite3ErrorMsg(pParse, zErr, z); - sqliteFree(z); - pTopNC->nErr++; } /* If a column from a table in pSrcList is referenced, then record @@ -1222,18 +1253,18 @@ static int lookupName( lookupname_end: /* Clean up and return */ - sqliteFree(zDb); - sqliteFree(zTab); + sqlite3_free(zDb); + sqlite3_free(zTab); sqlite3ExprDelete(pExpr->pLeft); pExpr->pLeft = 0; sqlite3ExprDelete(pExpr->pRight); pExpr->pRight = 0; pExpr->op = TK_COLUMN; lookupname_end_2: - sqliteFree(zCol); + sqlite3_free(zCol); if( cnt==1 ){ assert( pNC!=0 ); - sqlite3AuthRead(pParse, pExpr, pNC->pSrcList); + sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); if( pMatch && !pMatch->pSelect ){ pExpr->pTab = pMatch->pTab; } @@ -1450,7 +1481,7 @@ int sqlite3ExprResolveNames( ){ int savedHasAgg; if( pExpr==0 ) return 0; -#if SQLITE_MAX_EXPR_DEPTH>0 +#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 if( (pExpr->nHeight+pNC->pParse->nHeight)>SQLITE_MAX_EXPR_DEPTH ){ sqlite3ErrorMsg(pNC->pParse, "Expression tree is too large (maximum depth %d)", @@ -1463,7 +1494,7 @@ int sqlite3ExprResolveNames( savedHasAgg = pNC->hasAgg; pNC->hasAgg = 0; walkExprTree(pExpr, nameResolverStep, pNC); -#if SQLITE_MAX_EXPR_DEPTH>0 +#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 pNC->pParse->nHeight -= pExpr->nHeight; #endif if( pNC->nErr>0 ){ @@ -1521,7 +1552,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ int mem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0); testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0); - assert( testAddr>0 || sqlite3MallocFailed() ); + assert( testAddr>0 || pParse->db->mallocFailed ); sqlite3VdbeAddOp(v, OP_MemInt, 1, mem); } @@ -1572,7 +1603,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ }else if( pExpr->pList ){ /* Case 2: expr IN (exprlist) ** - ** For each expression, build an index key from the evaluation and + ** For each expression, build an index key from the evaluation and ** store it in the temporary table. If is a column, then use ** that columns affinity when building index keys. If is not ** a column, use numeric affinity. @@ -1633,7 +1664,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ VdbeComment((v, "# Init EXISTS result")); } sqlite3ExprDelete(pSel->pLimit); - pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one); + pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one); if( sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0) ){ return; } @@ -1654,7 +1685,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ ** text z[0..n-1] on the stack. */ static void codeInteger(Vdbe *v, const char *z, int n){ - assert( z || sqlite3MallocFailed() ); + assert( z || v==0 || sqlite3VdbeDb(v)->mallocFailed ); if( z ){ int i; if( sqlite3GetInt32(z, &i) ){ @@ -1745,7 +1776,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ case TK_STRING: { assert( TK_FLOAT==OP_Real ); assert( TK_STRING==OP_String8 ); - sqlite3DequoteExpr(pExpr); + sqlite3DequoteExpr(pParse->db, pExpr); sqlite3VdbeOp3(v, op, 0, 0, (char*)pExpr->token.z, pExpr->token.n); break; } @@ -1848,13 +1879,13 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ assert( pLeft ); if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){ Token *p = &pLeft->token; - char *z = sqlite3MPrintf("-%.*s", p->n, p->z); + char *z = sqlite3MPrintf(pParse->db, "-%.*s", p->n, p->z); if( pLeft->op==TK_FLOAT ){ sqlite3VdbeOp3(v, OP_Real, 0, 0, z, p->n+1); }else{ codeInteger(v, z, p->n+1); } - sqliteFree(z); + sqlite3_free(z); break; } /* Fall through into TK_NOT */ @@ -1900,8 +1931,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ const char *zId; int constMask = 0; int i; - u8 enc = ENC(pParse->db); + sqlite3 *db = pParse->db; + u8 enc = ENC(db); CollSeq *pColl = 0; + zId = (char*)pExpr->token.z; nId = pExpr->token.n; pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0); @@ -1921,9 +1954,9 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ ** for function overloading. But we use the B term in "glob(B,A)". */ if( nExpr>=2 && (pExpr->flags & EP_InfixFunc) ){ - pDef = sqlite3VtabOverloadFunction(pDef, nExpr, pList->a[1].pExpr); + pDef = sqlite3VtabOverloadFunction(db, pDef, nExpr, pList->a[1].pExpr); }else if( nExpr>0 ){ - pDef = sqlite3VtabOverloadFunction(pDef, nExpr, pList->a[0].pExpr); + pDef = sqlite3VtabOverloadFunction(db, pDef, nExpr, pList->a[0].pExpr); } #endif for(i=0; itrigStack ){ sqlite3ErrorMsg(pParse, "RAISE() may only be used within a trigger-program"); - return; + return; } if( pExpr->iColumn!=OE_Ignore ){ assert( pExpr->iColumn==OE_Rollback || pExpr->iColumn == OE_Abort || pExpr->iColumn == OE_Fail ); - sqlite3DequoteExpr(pExpr); + sqlite3DequoteExpr(pParse->db, pExpr); sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn, (char*)pExpr->token.z, pExpr->token.n); } else { @@ -2383,9 +2416,10 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){ ** Add a new element to the pAggInfo->aCol[] array. Return the index of ** the new element. Return a negative number if malloc fails. */ -static int addAggInfoColumn(AggInfo *pInfo){ +static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){ int i; pInfo->aCol = sqlite3ArrayAllocate( + db, pInfo->aCol, sizeof(pInfo->aCol[0]), 3, @@ -2400,9 +2434,10 @@ static int addAggInfoColumn(AggInfo *pInfo){ ** Add a new element to the pAggInfo->aFunc[] array. Return the index of ** the new element. Return a negative number if malloc fails. */ -static int addAggInfoFunc(AggInfo *pInfo){ +static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){ int i; pInfo->aFunc = sqlite3ArrayAllocate( + db, pInfo->aFunc, sizeof(pInfo->aFunc[0]), 3, @@ -2426,7 +2461,6 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){ Parse *pParse = pNC->pParse; SrcList *pSrcList = pNC->pSrcList; AggInfo *pAggInfo = pNC->pAggInfo; - switch( pExpr->op ){ case TK_AGG_COLUMN: @@ -2452,7 +2486,9 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){ break; } } - if( k>=pAggInfo->nColumn && (k = addAggInfoColumn(pAggInfo))>=0 ){ + if( (k>=pAggInfo->nColumn) + && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 + ){ pCol = &pAggInfo->aCol[k]; pCol->pTab = pExpr->pTab; pCol->iTable = pExpr->iTable; @@ -2509,7 +2545,7 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){ /* pExpr is original. Make a new entry in pAggInfo->aFunc[] */ u8 enc = ENC(pParse->db); - i = addAggInfoFunc(pAggInfo); + i = addAggInfoFunc(pParse->db, pAggInfo); if( i>=0 ){ pItem = &pAggInfo->aFunc[i]; pItem->pExpr = pExpr; diff --git a/extensions/sqlite/sqlite-source/func.c b/extensions/sqlite/sqlite-source/func.c index 3bac3e85..82ed2d47 100644 --- a/extensions/sqlite/sqlite-source/func.c +++ b/extensions/sqlite/sqlite-source/func.c @@ -20,11 +20,10 @@ */ #include "sqliteInt.h" #include -/* #include */ #include #include #include "vdbeInt.h" -#include "os.h" + /* ** Return the collating function associated with a function. @@ -235,6 +234,19 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_result_double(context, r); } +/* +** Allocate nByte bytes of space using sqlite3_malloc(). If the +** allocation fails, call sqlite3_result_error_nomem() to notify +** the database handle that malloc() has failed. +*/ +static void *contextMalloc(sqlite3_context *context, int nByte){ + char *z = sqlite3_malloc(nByte); + if( !z && nByte>0 ){ + sqlite3_result_error_nomem(context); + } + return z; +} + /* ** Implementation of the upper() and lower() SQL functions. */ @@ -248,7 +260,7 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ /* Verify that the call to _bytes() does not invalidate the _text() pointer */ assert( z2==(char*)sqlite3_value_text(argv[0]) ); if( z2 ){ - z1 = sqlite3_malloc(n+1); + z1 = contextMalloc(context, n+1); if( z1 ){ memcpy(z1, z2, n+1); for(i=0; z1[i]; i++){ @@ -268,7 +280,7 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ /* Verify that the call to _bytes() does not invalidate the _text() pointer */ assert( z2==(char*)sqlite3_value_text(argv[0]) ); if( z2 ){ - z1 = sqlite3_malloc(n+1); + z1 = contextMalloc(context, n+1); if( z1 ){ memcpy(z1, z2, n+1); for(i=0; z1[i]; i++){ @@ -333,10 +345,10 @@ static void randomBlob( sqlite3_result_error_toobig(context); return; } - p = sqliteMalloc(n); + p = contextMalloc(context, n); if( p ){ sqlite3Randomness(n, p); - sqlite3_result_blob(context, (char*)p, n, sqlite3FreeX); + sqlite3_result_blob(context, (char*)p, n, sqlite3_free); } } @@ -397,15 +409,6 @@ static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 }; ** is case sensitive causing 'a' LIKE 'A' to be false */ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; -/* -** Read a single UTF-8 character and return its value. -*/ -u32 sqlite3ReadUtf8(const unsigned char *z){ - u32 c; - SQLITE_READ_UTF8(z, c); - return c; -} - /* ** Compare two UTF-8 strings for equality where the first string can ** potentially be a "glob" expression. Return true (1) if they @@ -440,97 +443,102 @@ static int patternCompare( const struct compareInfo *pInfo, /* Information about how to do the compare */ const int esc /* The escape character */ ){ - register int c; + int c, c2; int invert; int seen; - int c2; u8 matchOne = pInfo->matchOne; u8 matchAll = pInfo->matchAll; u8 matchSet = pInfo->matchSet; u8 noCase = pInfo->noCase; int prevEscape = 0; /* True if the previous character was 'escape' */ - while( (c = *zPattern)!=0 ){ + while( (c = sqlite3Utf8Read(zPattern,0,&zPattern))!=0 ){ if( !prevEscape && c==matchAll ){ - while( (c=zPattern[1]) == matchAll || c == matchOne ){ - if( c==matchOne ){ - if( *zString==0 ) return 0; - SQLITE_SKIP_UTF8(zString); + while( (c=sqlite3Utf8Read(zPattern,0,&zPattern)) == matchAll + || c == matchOne ){ + if( c==matchOne && sqlite3Utf8Read(zString, 0, &zString)==0 ){ + return 0; } - zPattern++; } - if( c && esc && sqlite3ReadUtf8(&zPattern[1])==esc ){ - u8 const *zTemp = &zPattern[1]; - SQLITE_SKIP_UTF8(zTemp); - c = *zTemp; - } - if( c==0 ) return 1; - if( c==matchSet ){ - assert( esc==0 ); /* This is GLOB, not LIKE */ - while( *zString && patternCompare(&zPattern[1],zString,pInfo,esc)==0 ){ + if( c==0 ){ + return 1; + }else if( c==esc ){ + c = sqlite3Utf8Read(zPattern, 0, &zPattern); + if( c==0 ){ + return 0; + } + }else if( c==matchSet ){ + assert( esc==0 ); /* This is GLOB, not LIKE */ + assert( matchSet<0x80 ); /* '[' is a single-byte character */ + while( *zString && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){ SQLITE_SKIP_UTF8(zString); } return *zString!=0; - }else{ - while( (c2 = *zString)!=0 ){ - if( noCase ){ - c2 = sqlite3UpperToLower[c2]; - c = sqlite3UpperToLower[c]; - while( c2 != 0 && c2 != c ){ c2 = sqlite3UpperToLower[*++zString]; } - }else{ - while( c2 != 0 && c2 != c ){ c2 = *++zString; } + } + while( (c2 = sqlite3Utf8Read(zString,0,&zString))!=0 ){ + if( noCase ){ + c2 = c2<0x80 ? sqlite3UpperToLower[c2] : c2; + c = c<0x80 ? sqlite3UpperToLower[c] : c; + while( c2 != 0 && c2 != c ){ + c2 = sqlite3Utf8Read(zString, 0, &zString); + if( c2<0x80 ) c2 = sqlite3UpperToLower[c2]; + } + }else{ + while( c2 != 0 && c2 != c ){ + c2 = sqlite3Utf8Read(zString, 0, &zString); } - if( c2==0 ) return 0; - if( patternCompare(&zPattern[1],zString,pInfo,esc) ) return 1; - SQLITE_SKIP_UTF8(zString); } + if( c2==0 ) return 0; + if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; + } + return 0; + }else if( !prevEscape && c==matchOne ){ + if( sqlite3Utf8Read(zString, 0, &zString)==0 ){ return 0; } - }else if( !prevEscape && c==matchOne ){ - if( *zString==0 ) return 0; - SQLITE_SKIP_UTF8(zString); - zPattern++; }else if( c==matchSet ){ int prior_c = 0; assert( esc==0 ); /* This only occurs for GLOB, not LIKE */ seen = 0; invert = 0; - c = sqlite3ReadUtf8(zString); + c = sqlite3Utf8Read(zString, 0, &zString); if( c==0 ) return 0; - c2 = *++zPattern; - if( c2=='^' ){ invert = 1; c2 = *++zPattern; } + c2 = sqlite3Utf8Read(zPattern, 0, &zPattern); + if( c2=='^' ){ + invert = 1; + c2 = sqlite3Utf8Read(zPattern, 0, &zPattern); + } if( c2==']' ){ if( c==']' ) seen = 1; - c2 = *++zPattern; + c2 = sqlite3Utf8Read(zPattern, 0, &zPattern); } - while( (c2 = sqlite3ReadUtf8(zPattern))!=0 && c2!=']' ){ - if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 && prior_c>0 ){ - zPattern++; - c2 = sqlite3ReadUtf8(zPattern); + while( c2 && c2!=']' ){ + if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ + c2 = sqlite3Utf8Read(zPattern, 0, &zPattern); if( c>=prior_c && c<=c2 ) seen = 1; prior_c = 0; - }else if( c==c2 ){ - seen = 1; - prior_c = c2; }else{ + if( c==c2 ){ + seen = 1; + } prior_c = c2; } - SQLITE_SKIP_UTF8(zPattern); + c2 = sqlite3Utf8Read(zPattern, 0, &zPattern); } - if( c2==0 || (seen ^ invert)==0 ) return 0; - SQLITE_SKIP_UTF8(zString); - zPattern++; - }else if( esc && !prevEscape && sqlite3ReadUtf8(zPattern)==esc){ + if( c2==0 || (seen ^ invert)==0 ){ + return 0; + } + }else if( esc==c && !prevEscape ){ prevEscape = 1; - SQLITE_SKIP_UTF8(zPattern); }else{ + c2 = sqlite3Utf8Read(zString, 0, &zString); if( noCase ){ - if( sqlite3UpperToLower[c] != sqlite3UpperToLower[*zString] ) return 0; - }else{ - if( c != *zString ) return 0; + c = c<0x80 ? sqlite3UpperToLower[c] : c; + c2 = c2<0x80 ? sqlite3UpperToLower[c2] : c2; + } + if( c!=c2 ){ + return 0; } - zPattern++; - zString++; prevEscape = 0; } } @@ -590,7 +598,7 @@ static void likeFunc( "ESCAPE expression must be a single character", -1); return; } - escape = sqlite3ReadUtf8(zEsc); + escape = sqlite3Utf8Read(zEsc, 0, &zEsc); } if( zA && zB ){ struct compareInfo *pInfo = sqlite3_user_data(context); @@ -670,10 +678,8 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_result_error_toobig(context); return; } - zText = (char *)sqliteMalloc((2*nBlob)+4); - if( !zText ){ - sqlite3_result_error(context, "out of memory", -1); - }else{ + zText = (char *)contextMalloc(context, (2*nBlob)+4); + if( zText ){ int i; for(i=0; i>4)&0x0F]; @@ -684,7 +690,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ zText[0] = 'X'; zText[1] = '\''; sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); - sqliteFree(zText); + sqlite3_free(zText); } break; } @@ -700,19 +706,19 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_result_error_toobig(context); return; } - z = sqliteMalloc( i+n+3 ); - if( z==0 ) return; - z[0] = '\''; - for(i=0, j=1; zArg[i]; i++){ - z[j++] = zArg[i]; - if( zArg[i]=='\'' ){ - z[j++] = '\''; + z = contextMalloc(context, i+n+3); + if( z ){ + z[0] = '\''; + for(i=0, j=1; zArg[i]; i++){ + z[j++] = zArg[i]; + if( zArg[i]=='\'' ){ + z[j++] = '\''; + } } + z[j++] = '\''; + z[j] = 0; + sqlite3_result_text(context, z, j, sqlite3_free); } - z[j++] = '\''; - z[j] = 0; - sqlite3_result_text(context, z, j, SQLITE_TRANSIENT); - sqliteFree(z); } } } @@ -737,15 +743,16 @@ static void hexFunc( return; } assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ - z = zHex = sqlite3_malloc(n*2 + 1); - if( zHex==0 ) return; - for(i=0; i>4)&0xf]; - *(z++) = hexdigits[c&0xf]; + z = zHex = contextMalloc(context, n*2 + 1); + if( zHex ){ + for(i=0; i>4)&0xf]; + *(z++) = hexdigits[c&0xf]; + } + *z = 0; + sqlite3_result_text(context, zHex, n*2, sqlite3_free); } - *z = 0; - sqlite3_result_text(context, zHex, n*2, sqlite3_free); } /* @@ -803,7 +810,7 @@ static void replaceFunc( assert( zRep==sqlite3_value_text(argv[2]) ); nOut = nStr + 1; assert( nOut=SQLITE_MAX_LENGTH ){ sqlite3_result_error_toobig(context); sqlite3_free(zOut); return; } + zOld = zOut; zOut = sqlite3_realloc(zOut, (int)nOut); if( zOut==0 ){ + sqlite3_result_error_nomem(context); + sqlite3_free(zOld); return; } memcpy(&zOut[j], zRep, nRep); @@ -875,7 +886,7 @@ static void trimFunc( SQLITE_SKIP_UTF8(z); } if( nChar>0 ){ - azChar = sqlite3_malloc( nChar*(sizeof(char*)+1) ); + azChar = contextMalloc(context, nChar*(sizeof(char*)+1)); if( azChar==0 ){ return; } @@ -1005,20 +1016,18 @@ static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){ ".-!,:*^+=_|?/<> "; int iMin, iMax, n, r, i; unsigned char zBuf[1000]; - if( argc>=1 ){ - iMin = sqlite3_value_int(argv[0]); - if( iMin<0 ) iMin = 0; - if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1; - }else{ - iMin = 1; - } - if( argc>=2 ){ - iMax = sqlite3_value_int(argv[1]); - if( iMax=sizeof(zBuf) ) iMax = sizeof(zBuf)-1; - }else{ - iMax = 50; - } + + /* It used to be possible to call randstr() with any number of arguments, + ** but now it is registered with SQLite as requiring exactly 2. + */ + assert(argc==2); + + iMin = sqlite3_value_int(argv[0]); + if( iMin<0 ) iMin = 0; + if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1; + iMax = sqlite3_value_int(argv[1]); + if( iMax=sizeof(zBuf) ) iMax = sizeof(zBuf)-1; n = iMin; if( iMax>iMin ){ sqlite3Randomness(sizeof(r), &r); @@ -1052,7 +1061,7 @@ static void destructor(void *p){ char *zVal = (char *)p; assert(zVal); zVal--; - sqliteFree(zVal); + sqlite3_free(zVal); test_destructor_count_var--; } static void test_destructor( @@ -1068,10 +1077,12 @@ static void test_destructor( assert( nArg==1 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; len = sqlite3ValueBytes(argv[0], ENC(db)); - zVal = sqliteMalloc(len+3); - zVal[len] = 0; - zVal[len-1] = 0; - assert( zVal ); + zVal = contextMalloc(pCtx, len+3); + if( !zVal ){ + return; + } + zVal[len+1] = 0; + zVal[len+2] = 0; zVal++; memcpy(zVal, sqlite3ValueText(argv[0], ENC(db)), len); if( ENC(db)==SQLITE_UTF8 ){ @@ -1105,15 +1116,16 @@ static void test_destructor_count( ** registration, the result for that argument is 1. The overall result ** is the individual argument results separated by spaces. */ -static void free_test_auxdata(void *p) {sqliteFree(p);} +static void free_test_auxdata(void *p) {sqlite3_free(p);} static void test_auxdata( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ int i; - char *zRet = sqliteMalloc(nArg*2); + char *zRet = contextMalloc(pCtx, nArg*2); if( !zRet ) return; + memset(zRet, 0, nArg*2); for(i=0; imallocFailed ){ int rc = sqlite3_overload_function(db, "MATCH", 2); assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); if( rc==SQLITE_NOMEM ){ - sqlite3FailedMalloc(); + db->mallocFailed = 1; } } #ifdef SQLITE_SSE diff --git a/extensions/sqlite/sqlite-source/hash.c b/extensions/sqlite/sqlite-source/hash.c index 8f34caba..a6bcdc32 100644 --- a/extensions/sqlite/sqlite-source/hash.c +++ b/extensions/sqlite/sqlite-source/hash.c @@ -41,8 +41,6 @@ void sqlite3HashInit(Hash *pNew, int keyClass, int copyKey){ pNew->count = 0; pNew->htsize = 0; pNew->ht = 0; - pNew->xMalloc = sqlite3MallocX; - pNew->xFree = sqlite3FreeX; } /* Remove all entries from a hash table. Reclaim all memory. @@ -55,15 +53,15 @@ void sqlite3HashClear(Hash *pH){ assert( pH!=0 ); elem = pH->first; pH->first = 0; - if( pH->ht ) pH->xFree(pH->ht); + if( pH->ht ) sqlite3_free(pH->ht); pH->ht = 0; pH->htsize = 0; while( elem ){ HashElem *next_elem = elem->next; if( pH->copyKey && elem->pKey ){ - pH->xFree(elem->pKey); + sqlite3_free(elem->pKey); } - pH->xFree(elem); + sqlite3_free(elem); elem = next_elem; } pH->count = 0; @@ -216,7 +214,7 @@ static void insertElement( /* Resize the hash table so that it cantains "new_size" buckets. ** "new_size" must be a power of 2. The hash table might fail -** to resize if sqliteMalloc() fails. +** to resize if sqlite3_malloc() fails. */ static void rehash(Hash *pH, int new_size){ struct _ht *new_ht; /* The new hash table */ @@ -224,9 +222,17 @@ static void rehash(Hash *pH, int new_size){ int (*xHash)(const void*,int); /* The hash function */ assert( (new_size & (new_size-1))==0 ); - new_ht = (struct _ht *)pH->xMalloc( new_size*sizeof(struct _ht) ); + + /* There is a call to sqlite3_malloc() inside rehash(). If there is + ** already an allocation at pH->ht, then if this malloc() fails it + ** is benign (since failing to resize a hash table is a performance + ** hit only, not a fatal error). + */ + sqlite3MallocBenignFailure(pH->htsize>0); + + new_ht = (struct _ht *)sqlite3MallocZero( new_size*sizeof(struct _ht) ); if( new_ht==0 ) return; - if( pH->ht ) pH->xFree(pH->ht); + if( pH->ht ) sqlite3_free(pH->ht); pH->ht = new_ht; pH->htsize = new_size; xHash = hashFunction(pH->keyClass); @@ -292,9 +298,9 @@ static void removeElementGivenHash( pEntry->chain = 0; } if( pH->copyKey ){ - pH->xFree(elem->pKey); + sqlite3_free(elem->pKey); } - pH->xFree( elem ); + sqlite3_free( elem ); pH->count--; if( pH->count<=0 ){ assert( pH->first==0 ); @@ -304,10 +310,11 @@ static void removeElementGivenHash( } /* Attempt to locate an element of the hash table pH with a key -** that matches pKey,nKey. Return the data for this element if it is -** found, or NULL if there is no match. +** that matches pKey,nKey. Return a pointer to the corresponding +** HashElem structure for this element if it is found, or NULL +** otherwise. */ -void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){ +HashElem *sqlite3HashFindElem(const Hash *pH, const void *pKey, int nKey){ int h; /* A hash on key */ HashElem *elem; /* The element that matches key */ int (*xHash)(const void*,int); /* The hash function */ @@ -318,6 +325,16 @@ void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){ h = (*xHash)(pKey,nKey); assert( (pH->htsize & (pH->htsize-1))==0 ); elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1)); + return elem; +} + +/* Attempt to locate an element of the hash table pH with a key +** that matches pKey,nKey. Return the data for this element if it is +** found, or NULL if there is no match. +*/ +void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){ + HashElem *elem; /* The element that matches key */ + elem = sqlite3HashFindElem(pH, pKey, nKey); return elem ? elem->data : 0; } @@ -356,16 +373,20 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){ removeElementGivenHash(pH,elem,h); }else{ elem->data = data; + if( !pH->copyKey ){ + elem->pKey = (void *)pKey; + } + assert(nKey==elem->nKey); } return old_data; } if( data==0 ) return 0; - new_elem = (HashElem*)pH->xMalloc( sizeof(HashElem) ); + new_elem = (HashElem*)sqlite3_malloc( sizeof(HashElem) ); if( new_elem==0 ) return data; if( pH->copyKey && pKey!=0 ){ - new_elem->pKey = pH->xMalloc( nKey ); + new_elem->pKey = sqlite3_malloc( nKey ); if( new_elem->pKey==0 ){ - pH->xFree(new_elem); + sqlite3_free(new_elem); return data; } memcpy((void*)new_elem->pKey, pKey, nKey); @@ -379,9 +400,9 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){ if( pH->htsize==0 ){ pH->count = 0; if( pH->copyKey ){ - pH->xFree(new_elem->pKey); + sqlite3_free(new_elem->pKey); } - pH->xFree(new_elem); + sqlite3_free(new_elem); return data; } } diff --git a/extensions/sqlite/sqlite-source/hash.h b/extensions/sqlite/sqlite-source/hash.h index 47076494..84a45270 100644 --- a/extensions/sqlite/sqlite-source/hash.h +++ b/extensions/sqlite/sqlite-source/hash.h @@ -33,10 +33,8 @@ struct Hash { char keyClass; /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */ char copyKey; /* True if copy of key made on insert */ int count; /* Number of entries in this table */ - HashElem *first; /* The first element of the array */ - void *(*xMalloc)(int); /* malloc() function to use */ - void (*xFree)(void *); /* free() function to use */ int htsize; /* Number of buckets in the hash table */ + HashElem *first; /* The first element of the array */ struct _ht { /* the hash table */ int count; /* Number of entries with this hash */ HashElem *chain; /* Pointer to first entry with this hash */ @@ -83,6 +81,7 @@ struct HashElem { void sqlite3HashInit(Hash*, int keytype, int copyKey); void *sqlite3HashInsert(Hash*, const void *pKey, int nKey, void *pData); void *sqlite3HashFind(const Hash*, const void *pKey, int nKey); +HashElem *sqlite3HashFindElem(const Hash*, const void *pKey, int nKey); void sqlite3HashClear(Hash*); /* diff --git a/extensions/sqlite/sqlite-source/insert.c b/extensions/sqlite/sqlite-source/insert.c index d99e3fa7..18fc30b4 100644 --- a/extensions/sqlite/sqlite-source/insert.c +++ b/extensions/sqlite/sqlite-source/insert.c @@ -41,7 +41,8 @@ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ */ int n; Table *pTab = pIdx->pTable; - pIdx->zColAff = (char *)sqliteMalloc(pIdx->nColumn+1); + sqlite3 *db = sqlite3VdbeDb(v); + pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+1); if( !pIdx->zColAff ){ return; } @@ -79,8 +80,9 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){ if( !pTab->zColAff ){ char *zColAff; int i; + sqlite3 *db = sqlite3VdbeDb(v); - zColAff = (char *)sqliteMalloc(pTab->nCol+1); + zColAff = (char *)sqlite3DbMallocZero(db, pTab->nCol+1); if( !zColAff ){ return; } @@ -356,10 +358,10 @@ void sqlite3Insert( int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */ #endif - if( pParse->nErr || sqlite3MallocFailed() ){ + db = pParse->db; + if( pParse->nErr || db->mallocFailed ){ goto insert_cleanup; } - db = pParse->db; /* Locate the table into which we will be inserting new information. */ @@ -462,7 +464,7 @@ void sqlite3Insert( /* Resolve the expressions in the SELECT statement and execute it. */ rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0); - if( rc || pParse->nErr || sqlite3MallocFailed() ){ + if( rc || pParse->nErr || db->mallocFailed ){ goto insert_cleanup; } @@ -1027,7 +1029,7 @@ void sqlite3GenerateConstraintChecks( assert( pParse->ckOffset==nCol ); pParse->ckOffset = 0; onError = overrideError!=OE_Default ? overrideError : OE_Abort; - if( onError==OE_Ignore || onError==OE_Replace ){ + if( onError==OE_Ignore ){ sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); }else{ @@ -1416,9 +1418,7 @@ static int xferOptimization( if( onError!=OE_Abort && onError!=OE_Rollback ){ return 0; /* Cannot do OR REPLACE or OR IGNORE or OR FAIL */ } - if( pSelect->pSrc==0 ){ - return 0; /* SELECT must have a FROM clause */ - } + assert(pSelect->pSrc); /* allocated even if there is no FROM clause */ if( pSelect->pSrc->nSrc!=1 ){ return 0; /* FROM clause must have exactly one term */ } @@ -1523,6 +1523,7 @@ static int xferOptimization( #endif iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema); v = sqlite3GetVdbe(pParse); + sqlite3CodeVerifySchema(pParse, iDbSrc); iSrc = pParse->nTab++; iDest = pParse->nTab++; counterMem = autoIncBegin(pParse, iDbDest, pDest); diff --git a/extensions/sqlite/sqlite-source/journal.c b/extensions/sqlite/sqlite-source/journal.c new file mode 100644 index 00000000..9e2b3b8e --- /dev/null +++ b/extensions/sqlite/sqlite-source/journal.c @@ -0,0 +1,238 @@ +/* +** 2007 August 22 +** +** 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. +** +************************************************************************* +** +** @(#) $Id$ +*/ + +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + +/* +** This file implements a special kind of sqlite3_file object used +** by SQLite to create journal files if the atomic-write optimization +** is enabled. +** +** The distinctive characteristic of this sqlite3_file is that the +** actual on disk file is created lazily. When the file is created, +** the caller specifies a buffer size for an in-memory buffer to +** be used to service read() and write() requests. The actual file +** on disk is not created or populated until either: +** +** 1) The in-memory representation grows too large for the allocated +** buffer, or +** 2) The xSync() method is called. +*/ + +#include "sqliteInt.h" + + +/* +** A JournalFile object is a subclass of sqlite3_file used by +** as an open file handle for journal files. +*/ +struct JournalFile { + sqlite3_io_methods *pMethod; /* I/O methods on journal files */ + int nBuf; /* Size of zBuf[] in bytes */ + char *zBuf; /* Space to buffer journal writes */ + int iSize; /* Amount of zBuf[] currently used */ + int flags; /* xOpen flags */ + sqlite3_vfs *pVfs; /* The "real" underlying VFS */ + sqlite3_file *pReal; /* The "real" underlying file descriptor */ + const char *zJournal; /* Name of the journal file */ +}; +typedef struct JournalFile JournalFile; + +/* +** If it does not already exists, create and populate the on-disk file +** for JournalFile p. +*/ +static int createFile(JournalFile *p){ + int rc = SQLITE_OK; + if( !p->pReal ){ + sqlite3_file *pReal = (sqlite3_file *)&p[1]; + rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0); + if( rc==SQLITE_OK ){ + p->pReal = pReal; + if( p->iSize>0 ){ + assert(p->iSize<=p->nBuf); + rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0); + } + } + } + return rc; +} + +/* +** Close the file. +*/ +static int jrnlClose(sqlite3_file *pJfd){ + JournalFile *p = (JournalFile *)pJfd; + if( p->pReal ){ + sqlite3OsClose(p->pReal); + } + sqlite3_free(p->zBuf); + return SQLITE_OK; +} + +/* +** Read data from the file. +*/ +static int jrnlRead( + sqlite3_file *pJfd, /* The journal file from which to read */ + void *zBuf, /* Put the results here */ + int iAmt, /* Number of bytes to read */ + sqlite_int64 iOfst /* Begin reading at this offset */ +){ + int rc = SQLITE_OK; + JournalFile *p = (JournalFile *)pJfd; + if( p->pReal ){ + rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); + }else{ + assert( iAmt+iOfst<=p->iSize ); + memcpy(zBuf, &p->zBuf[iOfst], iAmt); + } + return rc; +} + +/* +** Write data to the file. +*/ +static int jrnlWrite( + sqlite3_file *pJfd, /* The journal file into which to write */ + const void *zBuf, /* Take data to be written from here */ + int iAmt, /* Number of bytes to write */ + sqlite_int64 iOfst /* Begin writing at this offset into the file */ +){ + int rc = SQLITE_OK; + JournalFile *p = (JournalFile *)pJfd; + if( !p->pReal && (iOfst+iAmt)>p->nBuf ){ + rc = createFile(p); + } + if( rc==SQLITE_OK ){ + if( p->pReal ){ + rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); + }else{ + memcpy(&p->zBuf[iOfst], zBuf, iAmt); + if( p->iSize<(iOfst+iAmt) ){ + p->iSize = (iOfst+iAmt); + } + } + } + return rc; +} + +/* +** Truncate the file. +*/ +static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ + int rc = SQLITE_OK; + JournalFile *p = (JournalFile *)pJfd; + if( p->pReal ){ + rc = sqlite3OsTruncate(p->pReal, size); + }else if( sizeiSize ){ + p->iSize = size; + } + return rc; +} + +/* +** Sync the file. +*/ +static int jrnlSync(sqlite3_file *pJfd, int flags){ + int rc; + JournalFile *p = (JournalFile *)pJfd; + rc = createFile(p); + if( rc==SQLITE_OK ){ + rc = sqlite3OsSync(p->pReal, flags); + } + return rc; +} + +/* +** Query the size of the file in bytes. +*/ +static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){ + int rc = SQLITE_OK; + JournalFile *p = (JournalFile *)pJfd; + if( p->pReal ){ + rc = sqlite3OsFileSize(p->pReal, pSize); + }else{ + *pSize = (sqlite_int64) p->iSize; + } + return rc; +} + +/* +** Table of methods for JournalFile sqlite3_file object. +*/ +static struct sqlite3_io_methods JournalFileMethods = { + 1, /* iVersion */ + jrnlClose, /* xClose */ + jrnlRead, /* xRead */ + jrnlWrite, /* xWrite */ + jrnlTruncate, /* xTruncate */ + jrnlSync, /* xSync */ + jrnlFileSize, /* xFileSize */ + 0, /* xLock */ + 0, /* xUnlock */ + 0, /* xCheckReservedLock */ + 0, /* xFileControl */ + 0, /* xSectorSize */ + 0 /* xDeviceCharacteristics */ +}; + +/* +** Open a journal file. +*/ +int sqlite3JournalOpen( + sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */ + const char *zName, /* Name of the journal file */ + sqlite3_file *pJfd, /* Preallocated, blank file handle */ + int flags, /* Opening flags */ + int nBuf /* Bytes buffered before opening the file */ +){ + JournalFile *p = (JournalFile *)pJfd; + memset(p, 0, sqlite3JournalSize(pVfs)); + if( nBuf>0 ){ + p->zBuf = sqlite3MallocZero(nBuf); + if( !p->zBuf ){ + return SQLITE_NOMEM; + } + }else{ + return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0); + } + p->pMethod = &JournalFileMethods; + p->nBuf = nBuf; + p->flags = flags; + p->zJournal = zName; + p->pVfs = pVfs; + return SQLITE_OK; +} + +/* +** If the argument p points to a JournalFile structure, and the underlying +** file has not yet been created, create it now. +*/ +int sqlite3JournalCreate(sqlite3_file *p){ + if( p->pMethods!=&JournalFileMethods ){ + return SQLITE_OK; + } + return createFile((JournalFile *)p); +} + +/* +** Return the number of bytes required to store a JournalFile that uses vfs +** pVfs to create the underlying on-disk files. +*/ +int sqlite3JournalSize(sqlite3_vfs *pVfs){ + return (pVfs->szOsFile+sizeof(JournalFile)); +} +#endif diff --git a/extensions/sqlite/sqlite-source/keywordhash.h b/extensions/sqlite/sqlite-source/keywordhash.h index 93872189..609ff207 100644 --- a/extensions/sqlite/sqlite-source/keywordhash.h +++ b/extensions/sqlite/sqlite-source/keywordhash.h @@ -2,7 +2,7 @@ ** ** The code in this file has been automatically generated by ** -** $Header: /sqlite/sqlite/tool/mkkeywordhash.c,v 1.30 2007/05/04 18:30:41 drh Exp $ +** $Header: /sqlite/sqlite/tool/mkkeywordhash.c,v 1.31 2007/07/30 18:26:20 rse Exp $ ** ** The code in this file implements a function that determines whether ** or not a given identifier is really an SQL keyword. The same thing diff --git a/extensions/sqlite/sqlite-source/legacy.c b/extensions/sqlite/sqlite-source/legacy.c index 4249aa55..4f23ede0 100644 --- a/extensions/sqlite/sqlite-source/legacy.c +++ b/extensions/sqlite/sqlite-source/legacy.c @@ -18,7 +18,6 @@ */ #include "sqliteInt.h" -#include "os.h" #include /* @@ -47,6 +46,8 @@ int sqlite3_exec( int nCallback; if( zSql==0 ) return SQLITE_OK; + + sqlite3_mutex_enter(db->mutex); while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){ int nCol; char **azVals = 0; @@ -66,7 +67,7 @@ int sqlite3_exec( nCallback = 0; nCol = sqlite3_column_count(pStmt); - azCols = sqliteMalloc(2*nCol*sizeof(const char *) + 1); + azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char *) + 1); if( azCols==0 ){ goto exec_out; } @@ -108,15 +109,15 @@ int sqlite3_exec( } } - sqliteFree(azCols); + sqlite3_free(azCols); azCols = 0; } exec_out: if( pStmt ) sqlite3_finalize(pStmt); - if( azCols ) sqliteFree(azCols); + if( azCols ) sqlite3_free(azCols); - rc = sqlite3ApiExit(0, rc); + rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){ int nErrMsg = 1 + strlen(sqlite3_errmsg(db)); *pzErrMsg = sqlite3_malloc(nErrMsg); @@ -128,5 +129,6 @@ exec_out: } assert( (rc&db->errMask)==rc ); + sqlite3_mutex_leave(db->mutex); return rc; } diff --git a/extensions/sqlite/sqlite-source/main.c b/extensions/sqlite/sqlite-source/main.c index aeb650fa..b532708f 100644 --- a/extensions/sqlite/sqlite-source/main.c +++ b/extensions/sqlite/sqlite-source/main.c @@ -17,7 +17,6 @@ ** $Id$ */ #include "sqliteInt.h" -#include "os.h" #include /* @@ -26,6 +25,7 @@ const char sqlite3_version[] = SQLITE_VERSION; const char *sqlite3_libversion(void){ return sqlite3_version; } int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; } +int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } /* ** If the following function pointer is not NULL and if @@ -119,6 +119,7 @@ int sqlite3_close(sqlite3 *db){ if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } + sqlite3_mutex_enter(db->mutex); #ifdef SQLITE_SSE { @@ -142,6 +143,7 @@ int sqlite3_close(sqlite3 *db){ if( db->pVdbe ){ sqlite3Error(db, SQLITE_BUSY, "Unable to close due to unfinalised statements"); + sqlite3_mutex_leave(db->mutex); return SQLITE_BUSY; } assert( !sqlite3SafetyCheck(db) ); @@ -156,6 +158,7 @@ int sqlite3_close(sqlite3 *db){ */ if( db->magic!=SQLITE_MAGIC_CLOSED && sqlite3SafetyOn(db) ){ /* printf("DID NOT CLOSE\n"); fflush(stdout); */ + sqlite3_mutex_leave(db->mutex); return SQLITE_ERROR; } @@ -176,7 +179,7 @@ int sqlite3_close(sqlite3 *db){ FuncDef *pFunc, *pNext; for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){ pNext = pFunc->pNext; - sqliteFree(pFunc); + sqlite3_free(pFunc); } } @@ -188,7 +191,7 @@ int sqlite3_close(sqlite3 *db){ pColl[j].xDel(pColl[j].pUser); } } - sqliteFree(pColl); + sqlite3_free(pColl); } sqlite3HashClear(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -197,7 +200,7 @@ int sqlite3_close(sqlite3 *db){ if( pMod->xDestroy ){ pMod->xDestroy(pMod->pAux); } - sqliteFree(pMod); + sqlite3_free(pMod); } sqlite3HashClear(&db->aModule); #endif @@ -217,9 +220,10 @@ int sqlite3_close(sqlite3 *db){ ** the same sqliteMalloc() as the one that allocates the database ** structure? */ - sqliteFree(db->aDb[1].pSchema); - sqliteFree(db); - sqlite3ReleaseThreadData(); + sqlite3_free(db->aDb[1].pSchema); + sqlite3_mutex_leave(db->mutex); + sqlite3_mutex_free(db->mutex); + sqlite3_free(db); return SQLITE_OK; } @@ -229,6 +233,8 @@ int sqlite3_close(sqlite3 *db){ void sqlite3RollbackAll(sqlite3 *db){ int i; int inTrans = 0; + assert( sqlite3_mutex_held(db->mutex) ); + sqlite3MallocEnterBenignBlock(1); /* Enter benign region */ for(i=0; inDb; i++){ if( db->aDb[i].pBt ){ if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){ @@ -239,7 +245,10 @@ void sqlite3RollbackAll(sqlite3 *db){ } } sqlite3VtabRollback(db); + sqlite3MallocLeaveBenignBlock(); /* Leave benign region */ + if( db->flags&SQLITE_InternChanges ){ + sqlite3ExpirePreparedStatements(db); sqlite3ResetInternalSchema(db, 0); } @@ -303,7 +312,8 @@ static int sqliteDefaultBusyCallback( static const u8 totals[] = { 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 }; # define NDELAY (sizeof(delays)/sizeof(delays[0])) - int timeout = ((sqlite3 *)ptr)->busyTimeout; + sqlite3 *db = (sqlite3 *)ptr; + int timeout = db->busyTimeout; int delay, prior; assert( count>=0 ); @@ -318,14 +328,15 @@ static int sqliteDefaultBusyCallback( delay = timeout - prior; if( delay<=0 ) return 0; } - sqlite3OsSleep(delay); + sqlite3OsSleep(db->pVfs, delay*1000); return 1; #else + sqlite3 *db = (sqlite3 *)ptr; int timeout = ((sqlite3 *)ptr)->busyTimeout; if( (count+1)*1000 > timeout ){ return 0; } - sqlite3OsSleep(1000); + sqlite3OsSleep(db->pVfs, 1000000); return 1; #endif } @@ -361,9 +372,11 @@ int sqlite3_busy_handler( if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } + sqlite3_mutex_enter(db->mutex); db->busyHandler.xFunc = xBusy; db->busyHandler.pArg = pArg; db->busyHandler.nBusy = 0; + sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -380,6 +393,7 @@ void sqlite3_progress_handler( void *pArg ){ if( !sqlite3SafetyCheck(db) ){ + sqlite3_mutex_enter(db->mutex); if( nOps>0 ){ db->xProgress = xProgress; db->nProgressOps = nOps; @@ -389,6 +403,7 @@ void sqlite3_progress_handler( db->nProgressOps = 0; db->pProgressArg = 0; } + sqlite3_mutex_leave(db->mutex); } } #endif @@ -420,30 +435,6 @@ void sqlite3_interrupt(sqlite3 *db){ } } -/* -** Memory allocation routines that use SQLites internal memory -** memory allocator. Depending on how SQLite is compiled, the -** internal memory allocator might be just an alias for the -** system default malloc/realloc/free. Or the built-in allocator -** might do extra stuff like put sentinals around buffers to -** check for overruns or look for memory leaks. -** -** Use sqlite3_free() to free memory returned by sqlite3_mprintf(). -*/ -void sqlite3_free(void *p){ if( p ) sqlite3OsFree(p); } -void *sqlite3_malloc(int nByte){ return nByte>0 ? sqlite3OsMalloc(nByte) : 0; } -void *sqlite3_realloc(void *pOld, int nByte){ - if( pOld ){ - if( nByte>0 ){ - return sqlite3OsRealloc(pOld, nByte); - }else{ - sqlite3OsFree(pOld); - return 0; - } - }else{ - return sqlite3_malloc(nByte); - } -} /* ** This function is exactly the same as sqlite3_create_function(), except @@ -464,6 +455,7 @@ int sqlite3CreateFunc( FuncDef *p; int nName; + assert( sqlite3_mutex_held(db->mutex) ); if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } @@ -491,10 +483,13 @@ int sqlite3CreateFunc( int rc; rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8, pUserData, xFunc, xStep, xFinal); - if( rc!=SQLITE_OK ) return rc; - rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE, - pUserData, xFunc, xStep, xFinal); - if( rc!=SQLITE_OK ) return rc; + if( rc==SQLITE_OK ){ + rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE, + pUserData, xFunc, xStep, xFinal); + } + if( rc!=SQLITE_OK ){ + return rc; + } enc = SQLITE_UTF16BE; } #else @@ -511,7 +506,7 @@ int sqlite3CreateFunc( if( db->activeVdbeCnt ){ sqlite3Error(db, SQLITE_BUSY, "Unable to delete/modify user-function due to active statements"); - assert( !sqlite3MallocFailed() ); + assert( !db->mallocFailed ); return SQLITE_BUSY; }else{ sqlite3ExpirePreparedStatements(db); @@ -519,14 +514,16 @@ int sqlite3CreateFunc( } p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1); - if( p ){ - p->flags = 0; - p->xFunc = xFunc; - p->xStep = xStep; - p->xFinalize = xFinal; - p->pUserData = pUserData; - p->nArg = nArg; + assert(p || db->mallocFailed); + if( !p ){ + return SQLITE_NOMEM; } + p->flags = 0; + p->xFunc = xFunc; + p->xStep = xStep; + p->xFinalize = xFinal; + p->pUserData = pUserData; + p->nArg = nArg; return SQLITE_OK; } @@ -544,10 +541,12 @@ int sqlite3_create_function( void (*xFinal)(sqlite3_context*) ){ int rc; - assert( !sqlite3MallocFailed() ); + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal); - - return sqlite3ApiExit(db, rc); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; } #ifndef SQLITE_OMIT_UTF16 @@ -563,13 +562,14 @@ int sqlite3_create_function16( ){ int rc; char *zFunc8; - assert( !sqlite3MallocFailed() ); - - zFunc8 = sqlite3Utf16to8(zFunctionName, -1); + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); + zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1); rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal); - sqliteFree(zFunc8); - - return sqlite3ApiExit(db, rc); + sqlite3_free(zFunc8); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; } #endif @@ -592,11 +592,15 @@ int sqlite3_overload_function( int nArg ){ int nName = strlen(zName); + int rc; + sqlite3_mutex_enter(db->mutex); if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){ sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, 0, sqlite3InvalidFunction, 0, 0); } - return sqlite3ApiExit(db, SQLITE_OK); + rc = sqlite3ApiExit(db, SQLITE_OK); + sqlite3_mutex_leave(db->mutex); + return rc; } #ifndef SQLITE_OMIT_TRACE @@ -609,9 +613,12 @@ int sqlite3_overload_function( ** SQL statement. */ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ - void *pOld = db->pTraceArg; + void *pOld; + sqlite3_mutex_enter(db->mutex); + pOld = db->pTraceArg; db->xTrace = xTrace; db->pTraceArg = pArg; + sqlite3_mutex_leave(db->mutex); return pOld; } /* @@ -627,9 +634,12 @@ void *sqlite3_profile( void (*xProfile)(void*,const char*,sqlite_uint64), void *pArg ){ - void *pOld = db->pProfileArg; + void *pOld; + sqlite3_mutex_enter(db->mutex); + pOld = db->pProfileArg; db->xProfile = xProfile; db->pProfileArg = pArg; + sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_TRACE */ @@ -645,9 +655,12 @@ void *sqlite3_commit_hook( int (*xCallback)(void*), /* Function to invoke on each commit */ void *pArg /* Argument to the function */ ){ - void *pOld = db->pCommitArg; + void *pOld; + sqlite3_mutex_enter(db->mutex); + pOld = db->pCommitArg; db->xCommitCallback = xCallback; db->pCommitArg = pArg; + sqlite3_mutex_leave(db->mutex); return pOld; } @@ -660,9 +673,12 @@ void *sqlite3_update_hook( void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), void *pArg /* Argument to the function */ ){ - void *pRet = db->pUpdateArg; + void *pRet; + sqlite3_mutex_enter(db->mutex); + pRet = db->pUpdateArg; db->xUpdateCallback = xCallback; db->pUpdateArg = pArg; + sqlite3_mutex_leave(db->mutex); return pRet; } @@ -675,9 +691,12 @@ void *sqlite3_rollback_hook( void (*xCallback)(void*), /* Callback function */ void *pArg /* Argument to the function */ ){ - void *pRet = db->pRollbackArg; + void *pRet; + sqlite3_mutex_enter(db->mutex); + pRet = db->pRollbackArg; db->xRollbackCallback = xCallback; db->pRollbackArg = pArg; + sqlite3_mutex_leave(db->mutex); return pRet; } @@ -711,17 +730,19 @@ int sqlite3BtreeFactory( 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 */ + int vfsFlags, /* Flags passed through to vfsOpen */ Btree **ppBtree /* Pointer to new Btree object written here */ ){ - int btree_flags = 0; + int btFlags = 0; int rc; + assert( sqlite3_mutex_held(db->mutex) ); assert( ppBtree != 0); if( omitJournal ){ - btree_flags |= BTREE_OMIT_JOURNAL; + btFlags |= BTREE_OMIT_JOURNAL; } if( db->flags & SQLITE_NoReadlock ){ - btree_flags |= BTREE_NO_READLOCK; + btFlags |= BTREE_NO_READLOCK; } if( zFilename==0 ){ #if TEMP_STORE==0 @@ -740,7 +761,10 @@ int sqlite3BtreeFactory( #endif /* SQLITE_OMIT_MEMORYDB */ } - rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btree_flags); + if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (zFilename==0 || *zFilename==0) ){ + vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB; + } + rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btFlags, vfsFlags); if( rc==SQLITE_OK ){ sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler); sqlite3BtreeSetCacheSize(*ppBtree, nCache); @@ -754,17 +778,19 @@ int sqlite3BtreeFactory( */ const char *sqlite3_errmsg(sqlite3 *db){ const char *z; - assert( !sqlite3MallocFailed() ); if( !db ){ return sqlite3ErrStr(SQLITE_NOMEM); } if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ return sqlite3ErrStr(SQLITE_MISUSE); } + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); z = (char*)sqlite3_value_text(db->pErr); if( z==0 ){ z = sqlite3ErrStr(db->errCode); } + sqlite3_mutex_leave(db->mutex); return z; } @@ -794,13 +820,14 @@ const void *sqlite3_errmsg16(sqlite3 *db){ }; const void *z; - assert( !sqlite3MallocFailed() ); if( !db ){ return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]); } if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ return (void *)(&misuseBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]); } + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); z = sqlite3_value_text16(db->pErr); if( z==0 ){ sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode), @@ -808,6 +835,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){ z = sqlite3_value_text16(db->pErr); } sqlite3ApiExit(0, 0); + sqlite3_mutex_leave(db->mutex); return z; } #endif /* SQLITE_OMIT_UTF16 */ @@ -817,7 +845,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){ ** passed to this function, we assume a malloc() failed during sqlite3_open(). */ int sqlite3_errcode(sqlite3 *db){ - if( !db || sqlite3MallocFailed() ){ + if( !db || db->mallocFailed ){ return SQLITE_NOMEM; } if( sqlite3SafetyCheck(db) ){ @@ -844,6 +872,7 @@ static int createCollation( if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } + assert( sqlite3_mutex_held(db->mutex) ); /* If SQLITE_UTF16 is specified as the encoding type, transform this ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the @@ -912,21 +941,28 @@ static int createCollation( */ static int openDatabase( const char *zFilename, /* Database filename UTF-8 encoded */ - sqlite3 **ppDb /* OUT: Returned database handle */ + sqlite3 **ppDb, /* OUT: Returned database handle */ + unsigned flags, /* Operational flags */ + const char *zVfs /* Name of the VFS to use */ ){ sqlite3 *db; int rc; CollSeq *pColl; - assert( !sqlite3MallocFailed() ); - /* Allocate the sqlite data structure */ - db = sqliteMalloc( sizeof(sqlite3) ); + db = sqlite3MallocZero( sizeof(sqlite3) ); if( db==0 ) goto opendb_out; + db->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); + if( db->mutex==0 ){ + sqlite3_free(db); + db = 0; + goto opendb_out; + } + sqlite3_mutex_enter(db->mutex); db->errMask = 0xff; db->priorNewRowid = 0; - db->magic = SQLITE_MAGIC_BUSY; db->nDb = 2; + db->magic = SQLITE_MAGIC_BUSY; db->aDb = db->aDbStatic; db->autoCommit = 1; db->flags |= SQLITE_ShortColNames @@ -943,6 +979,14 @@ static int openDatabase( sqlite3HashInit(&db->aModule, SQLITE_HASH_STRING, 0); #endif + db->pVfs = sqlite3_vfs_find(zVfs); + if( !db->pVfs ){ + rc = SQLITE_ERROR; + db->magic = SQLITE_MAGIC_CLOSED; + sqlite3Error(db, rc, "no such vfs: %s", (zVfs?zVfs:"(null)")); + goto opendb_out; + } + /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. @@ -952,7 +996,7 @@ static int openDatabase( createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0) || (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0 ){ - assert( sqlite3MallocFailed() ); + assert( db->mallocFailed ); db->magic = SQLITE_MAGIC_CLOSED; goto opendb_out; } @@ -968,15 +1012,17 @@ static int openDatabase( } /* Open the backend database driver */ - rc = sqlite3BtreeFactory(db, zFilename, 0, SQLITE_DEFAULT_CACHE_SIZE, + db->openFlags = flags; + rc = sqlite3BtreeFactory(db, zFilename, 0, SQLITE_DEFAULT_CACHE_SIZE, + flags | SQLITE_OPEN_MAIN_DB, &db->aDb[0].pBt); if( rc!=SQLITE_OK ){ sqlite3Error(db, rc, 0); db->magic = SQLITE_MAGIC_CLOSED; goto opendb_out; } - db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt); - db->aDb[1].pSchema = sqlite3SchemaGet(0); + db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); + db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); /* The default safety_level for the main database is 'full'; for the temp @@ -990,7 +1036,7 @@ static int openDatabase( #endif db->magic = SQLITE_MAGIC_OPEN; - if( sqlite3MallocFailed() ){ + if( db->mallocFailed ){ goto opendb_out; } @@ -1010,21 +1056,28 @@ static int openDatabase( } #ifdef SQLITE_ENABLE_FTS1 - if( !sqlite3MallocFailed() ){ + if( !db->mallocFailed ){ extern int sqlite3Fts1Init(sqlite3*); rc = sqlite3Fts1Init(db); } #endif #ifdef SQLITE_ENABLE_FTS2 - if( !sqlite3MallocFailed() && rc==SQLITE_OK ){ + if( !db->mallocFailed && rc==SQLITE_OK ){ extern int sqlite3Fts2Init(sqlite3*); rc = sqlite3Fts2Init(db); } #endif +#ifdef SQLITE_ENABLE_FTS3 + if( !db->mallocFailed && rc==SQLITE_OK ){ + extern int sqlite3Fts3Init(sqlite3*); + rc = sqlite3Fts3Init(db); + } +#endif + #ifdef SQLITE_ENABLE_ICU - if( !sqlite3MallocFailed() && rc==SQLITE_OK ){ + if( !db->mallocFailed && rc==SQLITE_OK ){ extern int sqlite3IcuInit(sqlite3*); rc = sqlite3IcuInit(db); } @@ -1042,6 +1095,9 @@ static int openDatabase( #endif opendb_out: + if( db && db->mutex ){ + sqlite3_mutex_leave(db->mutex); + } if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){ sqlite3_close(db); db = 0; @@ -1057,7 +1113,16 @@ int sqlite3_open( const char *zFilename, sqlite3 **ppDb ){ - return openDatabase(zFilename, ppDb); + return openDatabase(zFilename, ppDb, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); +} +int sqlite3_open_v2( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb, /* OUT: SQLite db handle */ + int flags, /* Flags */ + const char *zVfs /* Name of VFS module to use */ +){ + return openDatabase(filename, ppDb, flags, zVfs); } #ifndef SQLITE_OMIT_UTF16 @@ -1069,17 +1134,18 @@ int sqlite3_open16( sqlite3 **ppDb ){ char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */ - int rc = SQLITE_OK; sqlite3_value *pVal; + int rc = SQLITE_NOMEM; assert( zFilename ); assert( ppDb ); *ppDb = 0; - pVal = sqlite3ValueNew(); + pVal = sqlite3ValueNew(0); sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC); zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zFilename8 ){ - rc = openDatabase(zFilename8, ppDb); + rc = openDatabase(zFilename8, ppDb, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); if( rc==SQLITE_OK && *ppDb ){ rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); if( rc!=SQLITE_OK ){ @@ -1094,45 +1160,6 @@ int sqlite3_open16( } #endif /* SQLITE_OMIT_UTF16 */ -/* -** The following routine destroys a virtual machine that is created by -** the sqlite3_compile() routine. The integer returned is an SQLITE_ -** success/failure code that describes the result of executing the virtual -** machine. -** -** This routine sets the error code and string returned by -** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16(). -*/ -int sqlite3_finalize(sqlite3_stmt *pStmt){ - int rc; - if( pStmt==0 ){ - rc = SQLITE_OK; - }else{ - rc = sqlite3VdbeFinalize((Vdbe*)pStmt); - } - return rc; -} - -/* -** Terminate the current execution of an SQL statement and reset it -** back to its starting state so that it can be reused. A success code from -** the prior execution is returned. -** -** This routine sets the error code and string returned by -** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16(). -*/ -int sqlite3_reset(sqlite3_stmt *pStmt){ - int rc; - if( pStmt==0 ){ - rc = SQLITE_OK; - }else{ - rc = sqlite3VdbeReset((Vdbe*)pStmt); - sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0); - assert( (rc & (sqlite3_db_handle(pStmt)->errMask))==rc ); - } - return rc; -} - /* ** Register a new collation sequence with the database handle db. */ @@ -1144,9 +1171,12 @@ int sqlite3_create_collation( int(*xCompare)(void*,int,const void*,int,const void*) ){ int rc; - assert( !sqlite3MallocFailed() ); + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); rc = createCollation(db, zName, enc, pCtx, xCompare, 0); - return sqlite3ApiExit(db, rc); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; } /* @@ -1161,9 +1191,12 @@ int sqlite3_create_collation_v2( void(*xDel)(void*) ){ int rc; - assert( !sqlite3MallocFailed() ); + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); rc = createCollation(db, zName, enc, pCtx, xCompare, xDel); - return sqlite3ApiExit(db, rc); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; } #ifndef SQLITE_OMIT_UTF16 @@ -1179,13 +1212,16 @@ int sqlite3_create_collation16( ){ int rc = SQLITE_OK; char *zName8; - assert( !sqlite3MallocFailed() ); - zName8 = sqlite3Utf16to8(zName, -1); + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); + zName8 = sqlite3Utf16to8(db, zName, -1); if( zName8 ){ rc = createCollation(db, zName8, enc, pCtx, xCompare, 0); - sqliteFree(zName8); + sqlite3_free(zName8); } - return sqlite3ApiExit(db, rc); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; } #endif /* SQLITE_OMIT_UTF16 */ @@ -1201,9 +1237,11 @@ int sqlite3_collation_needed( if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } + sqlite3_mutex_enter(db->mutex); db->xCollNeeded = xCollNeeded; db->xCollNeeded16 = 0; db->pCollNeededArg = pCollNeededArg; + sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -1220,9 +1258,11 @@ int sqlite3_collation_needed16( if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } + sqlite3_mutex_enter(db->mutex); db->xCollNeeded = 0; db->xCollNeeded16 = xCollNeeded16; db->pCollNeededArg = pCollNeededArg; + sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #endif /* SQLITE_OMIT_UTF16 */ @@ -1260,45 +1300,14 @@ int sqlite3Corrupt(void){ } #endif - -#ifndef SQLITE_OMIT_SHARED_CACHE -/* -** Enable or disable the shared pager and schema features for the -** current thread. -** -** This routine should only be called when there are no open -** database connections. -*/ -int sqlite3_enable_shared_cache(int enable){ - ThreadData *pTd = sqlite3ThreadData(); - if( pTd ){ - /* It is only legal to call sqlite3_enable_shared_cache() when there - ** are no currently open b-trees that were opened by the calling thread. - ** This condition is only easy to detect if the shared-cache were - ** previously enabled (and is being disabled). - */ - if( pTd->pBtree && !enable ){ - assert( pTd->useSharedData ); - return SQLITE_MISUSE; - } - - pTd->useSharedData = enable; - sqlite3ReleaseThreadData(); - } - return sqlite3ApiExit(0, SQLITE_OK); -} -#endif - /* ** This is a convenience routine that makes sure that all thread-specific ** data for this thread has been deallocated. +** +** SQLite no longer uses thread-specific data so this routine is now a +** no-op. It is retained for historical compatibility. */ void sqlite3_thread_cleanup(void){ - ThreadData *pTd = sqlite3OsThreadSpecificData(0); - if( pTd ){ - memset(pTd, 0, sizeof(*pTd)); - sqlite3OsThreadSpecificData(-1); - } } /* @@ -1333,6 +1342,7 @@ int sqlite3_table_column_metadata( if( sqlite3SafetyOn(db) ){ return SQLITE_MISUSE; } + sqlite3_mutex_enter(db->mutex); rc = sqlite3Init(db, &zErrMsg); if( SQLITE_OK!=rc ){ goto error_out; @@ -1409,34 +1419,67 @@ error_out: rc = SQLITE_ERROR; } sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg); - sqliteFree(zErrMsg); - return sqlite3ApiExit(db, rc); -} -#endif - -/* -** Set all the parameters in the compiled SQL statement to NULL. -*/ -int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ - int i; - int rc = SQLITE_OK; - for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){ - rc = sqlite3_bind_null(pStmt, i); - } + sqlite3_free(zErrMsg); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); return rc; } +#endif /* ** Sleep for a little while. Return the amount of time slept. */ int sqlite3_sleep(int ms){ - return sqlite3OsSleep(ms); + sqlite3_vfs *pVfs; + int rc; + pVfs = sqlite3_vfs_find(0); + + /* This function works in milliseconds, but the underlying OsSleep() + ** API uses microseconds. Hence the 1000's. + */ + rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000); + return rc; } /* ** Enable or disable the extended result codes. */ int sqlite3_extended_result_codes(sqlite3 *db, int onoff){ + sqlite3_mutex_enter(db->mutex); db->errMask = onoff ? 0xffffffff : 0xff; + sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } + +/* +** Invoke the xFileControl method on a particular database. +*/ +int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ + int rc = SQLITE_ERROR; + int iDb; + sqlite3_mutex_enter(db->mutex); + if( zDbName==0 ){ + iDb = 0; + }else{ + for(iDb=0; iDbnDb; iDb++){ + if( strcmp(db->aDb[iDb].zName, zDbName)==0 ) break; + } + } + if( iDbnDb ){ + Btree *pBtree = db->aDb[iDb].pBt; + if( pBtree ){ + Pager *pPager; + sqlite3BtreeEnter(pBtree); + pPager = sqlite3BtreePager(pBtree); + if( pPager ){ + sqlite3_file *fd = sqlite3PagerFile(pPager); + if( fd ){ + rc = sqlite3OsFileControl(fd, op, pArg); + } + } + sqlite3BtreeLeave(pBtree); + } + } + sqlite3_mutex_leave(db->mutex); + return rc; +} diff --git a/extensions/sqlite/sqlite-source/malloc.c b/extensions/sqlite/sqlite-source/malloc.c index 3716e547..5ac8a9f2 100644 --- a/extensions/sqlite/sqlite-source/malloc.c +++ b/extensions/sqlite/sqlite-source/malloc.c @@ -15,705 +15,122 @@ ** $Id$ */ #include "sqliteInt.h" -#include "os.h" #include #include /* -** MALLOC WRAPPER ARCHITECTURE -** -** The sqlite code accesses dynamic memory allocation/deallocation by invoking -** the following six APIs (which may be implemented as macros). -** -** sqlite3Malloc() -** sqlite3MallocRaw() -** sqlite3Realloc() -** sqlite3ReallocOrFree() -** sqlite3Free() -** sqlite3AllocSize() -** -** The function sqlite3FreeX performs the same task as sqlite3Free and is -** guaranteed to be a real function. The same holds for sqlite3MallocX -** -** The above APIs are implemented in terms of the functions provided in the -** operating-system interface. The OS interface is never accessed directly -** by code outside of this file. -** -** sqlite3OsMalloc() -** sqlite3OsRealloc() -** sqlite3OsFree() -** sqlite3OsAllocationSize() -** -** Functions sqlite3MallocRaw() and sqlite3Realloc() may invoke -** sqlite3_release_memory() if a call to sqlite3OsMalloc() or -** sqlite3OsRealloc() fails (or if the soft-heap-limit for the thread is -** exceeded). Function sqlite3Malloc() usually invokes -** sqlite3MallocRaw(). -** -** MALLOC TEST WRAPPER ARCHITECTURE -** -** The test wrapper provides extra test facilities to ensure the library -** does not leak memory and handles the failure of the underlying OS level -** allocation system correctly. It is only present if the library is -** compiled with the SQLITE_MEMDEBUG macro set. -** -** * Guardposts to detect overwrites. -** * Ability to cause a specific Malloc() or Realloc() to fail. -** * Audit outstanding memory allocations (i.e check for leaks). +** This routine runs when the memory allocator sees that the +** total memory allocation is about to exceed the soft heap +** limit. */ +static void softHeapLimitEnforcer( + void *NotUsed, + sqlite3_int64 inUse, + int allocSize +){ + sqlite3_release_memory(allocSize); +} -#define MAX(x,y) ((x)>(y)?(x):(y)) - -#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) /* -** Set the soft heap-size limit for the current thread. Passing a negative -** value indicates no limit. +** Set the soft heap-size limit for the current thread. Passing a +** zero or negative value indicates no limit. */ void sqlite3_soft_heap_limit(int n){ - ThreadData *pTd = sqlite3ThreadData(); - if( pTd ){ - pTd->nSoftHeapLimit = n; + sqlite3_uint64 iLimit; + int overage; + if( n<0 ){ + iLimit = 0; + }else{ + iLimit = n; + } + if( iLimit>0 ){ + sqlite3_memory_alarm(softHeapLimitEnforcer, 0, iLimit); + }else{ + sqlite3_memory_alarm(0, 0, 0); + } + overage = sqlite3_memory_used() - n; + if( overage>0 ){ + sqlite3_release_memory(overage); } - sqlite3ReleaseThreadData(); } /* ** Release memory held by SQLite instances created by the current thread. */ int sqlite3_release_memory(int n){ +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT return sqlite3PagerReleaseMemory(n); +#else + return SQLITE_OK; +#endif } -#else -/* If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, then define a version -** of sqlite3_release_memory() to be used by other code in this file. -** This is done for no better reason than to reduce the number of -** pre-processor #ifndef statements. -*/ -#define sqlite3_release_memory(x) 0 /* 0 == no memory freed */ -#endif -#ifdef SQLITE_MEMDEBUG -/*-------------------------------------------------------------------------- -** Begin code for memory allocation system test layer. -** -** Memory debugging is turned on by defining the SQLITE_MEMDEBUG macro. -** -** SQLITE_MEMDEBUG==1 -> Fence-posting only (thread safe) -** SQLITE_MEMDEBUG==2 -> Fence-posting + linked list of allocations (not ts) -** SQLITE_MEMDEBUG==3 -> Above + backtraces (not thread safe, req. glibc) -*/ - -/* Figure out whether or not to store backtrace() information for each malloc. -** The backtrace() function is only used if SQLITE_MEMDEBUG is set to 2 or -** greater and glibc is in use. If we don't want to use backtrace(), then just -** define it as an empty macro and set the amount of space reserved to 0. -*/ -#if defined(__GLIBC__) && SQLITE_MEMDEBUG>2 - extern int backtrace(void **, int); - #define TESTALLOC_STACKSIZE 128 - #define TESTALLOC_STACKFRAMES ((TESTALLOC_STACKSIZE-8)/sizeof(void*)) -#else - #define backtrace(x, y) - #define TESTALLOC_STACKSIZE 0 - #define TESTALLOC_STACKFRAMES 0 -#endif /* -** Number of 32-bit guard words. This should probably be a multiple of -** 2 since on 64-bit machines we want the value returned by sqliteMalloc() -** to be 8-byte aligned. -*/ -#ifndef TESTALLOC_NGUARD -# define TESTALLOC_NGUARD 2 -#endif - -/* -** Size reserved for storing file-name along with each malloc()ed blob. -*/ -#define TESTALLOC_FILESIZE 64 - -/* -** Size reserved for storing the user string. Each time a Malloc() or Realloc() -** call succeeds, up to TESTALLOC_USERSIZE bytes of the string pointed to by -** sqlite3_malloc_id are stored along with the other test system metadata. -*/ -#define TESTALLOC_USERSIZE 64 -const char *sqlite3_malloc_id = 0; - -/* -** Blocks used by the test layer have the following format: -** -** -** -** -** -** -** <32-bit line number> -** -** +** Allocate and zero memory. */ - -#define TESTALLOC_OFFSET_GUARD1(p) (sizeof(void *) * 2) -#define TESTALLOC_OFFSET_DATA(p) ( \ - TESTALLOC_OFFSET_GUARD1(p) + sizeof(u32) * TESTALLOC_NGUARD \ -) -#define TESTALLOC_OFFSET_GUARD2(p) ( \ - TESTALLOC_OFFSET_DATA(p) + sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD \ -) -#define TESTALLOC_OFFSET_LINENUMBER(p) ( \ - TESTALLOC_OFFSET_GUARD2(p) + sizeof(u32) * TESTALLOC_NGUARD \ -) -#define TESTALLOC_OFFSET_FILENAME(p) ( \ - TESTALLOC_OFFSET_LINENUMBER(p) + sizeof(u32) \ -) -#define TESTALLOC_OFFSET_USER(p) ( \ - TESTALLOC_OFFSET_FILENAME(p) + TESTALLOC_FILESIZE \ -) -#define TESTALLOC_OFFSET_STACK(p) ( \ - TESTALLOC_OFFSET_USER(p) + TESTALLOC_USERSIZE + 8 - \ - (TESTALLOC_OFFSET_USER(p) % 8) \ -) - -#define TESTALLOC_OVERHEAD ( \ - sizeof(void *)*2 + /* pPrev and pNext pointers */ \ - TESTALLOC_NGUARD*sizeof(u32)*2 + /* Guard words */ \ - sizeof(u32) + TESTALLOC_FILESIZE + /* File and line number */ \ - TESTALLOC_USERSIZE + /* User string */ \ - TESTALLOC_STACKSIZE /* backtrace() stack */ \ -) - - -/* -** For keeping track of the number of mallocs and frees. This -** is used to check for memory leaks. The iMallocFail and iMallocReset -** values are used to simulate malloc() failures during testing in -** order to verify that the library correctly handles an out-of-memory -** condition. -*/ -int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */ -int sqlite3_nFree; /* Number of sqliteFree() calls */ -int sqlite3_memUsed; /* TODO Total memory obtained from malloc */ -int sqlite3_memMax; /* TODO Mem usage high-water mark */ -int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */ -int sqlite3_iMallocReset = -1; /* When iMallocFail reaches 0, set to this */ - -void *sqlite3_pFirst = 0; /* Pointer to linked list of allocations */ -int sqlite3_nMaxAlloc = 0; /* High water mark of ThreadData.nAlloc */ -int sqlite3_mallocDisallowed = 0; /* assert() in sqlite3Malloc() if set */ -int sqlite3_isFail = 0; /* True if all malloc calls should fail */ -const char *sqlite3_zFile = 0; /* Filename to associate debug info with */ -int sqlite3_iLine = 0; /* Line number for debug info */ -int sqlite3_mallocfail_trace = 0; /* Print a msg on malloc fail if true */ - -/* -** Check for a simulated memory allocation failure. Return true if -** the failure should be simulated. Return false to proceed as normal. -*/ -int sqlite3TestMallocFail(){ - if( sqlite3_isFail ){ - return 1; - } - if( sqlite3_iMallocFail>=0 ){ - sqlite3_iMallocFail--; - if( sqlite3_iMallocFail==0 ){ - sqlite3_iMallocFail = sqlite3_iMallocReset; - sqlite3_isFail = 1; - if( sqlite3_mallocfail_trace ){ - sqlite3DebugPrintf("###_malloc_fails_###\n"); - } - return 1; - } - } - return 0; -} - -/* -** The argument is a pointer returned by sqlite3OsMalloc() or xRealloc(). -** assert() that the first and last (TESTALLOC_NGUARD*4) bytes are set to the -** values set by the applyGuards() function. -*/ -static void checkGuards(u32 *p) -{ - int i; - char *zAlloc = (char *)p; - char *z; - - /* First set of guard words */ - z = &zAlloc[TESTALLOC_OFFSET_GUARD1(p)]; - for(i=0; i1 -/* -** The argument points to an Os level allocation. Link it into the threads list -** of allocations. -*/ -static void linkAlloc(void *p){ - void **pp = (void **)p; - pp[0] = 0; - pp[1] = sqlite3_pFirst; - if( sqlite3_pFirst ){ - ((void **)sqlite3_pFirst)[0] = p; - } - sqlite3_pFirst = p; -} - -/* -** The argument points to an Os level allocation. Unlinke it from the threads -** list of allocations. -*/ -static void unlinkAlloc(void *p) -{ - void **pp = (void **)p; - if( p==sqlite3_pFirst ){ - assert(!pp[0]); - assert(!pp[1] || ((void **)(pp[1]))[0]==p); - sqlite3_pFirst = pp[1]; - if( sqlite3_pFirst ){ - ((void **)sqlite3_pFirst)[0] = 0; - } - }else{ - void **pprev = pp[0]; - void **pnext = pp[1]; - assert(pprev); - assert(pprev[1]==p); - pprev[1] = (void *)pnext; - if( pnext ){ - assert(pnext[0]==p); - pnext[0] = (void *)pprev; - } - } -} - -/* -** Pointer p is a pointer to an OS level allocation that has just been -** realloc()ed. Set the list pointers that point to this entry to it's new -** location. -*/ -static void relinkAlloc(void *p) -{ - void **pp = (void **)p; - if( pp[0] ){ - ((void **)(pp[0]))[1] = p; - }else{ - sqlite3_pFirst = p; - } - if( pp[1] ){ - ((void **)(pp[1]))[0] = p; - } -} -#else -#define linkAlloc(x) -#define relinkAlloc(x) -#define unlinkAlloc(x) -#endif - -/* -** This function sets the result of the Tcl interpreter passed as an argument -** to a list containing an entry for each currently outstanding call made to -** sqliteMalloc and friends by the current thread. Each list entry is itself a -** list, consisting of the following (in order): -** -** * The number of bytes allocated -** * The __FILE__ macro at the time of the sqliteMalloc() call. -** * The __LINE__ macro ... -** * The value of the sqlite3_malloc_id variable ... -** * The output of backtrace() (if available) ... -** -** Todo: We could have a version of this function that outputs to stdout, -** to debug memory leaks when Tcl is not available. -*/ -#if defined(TCLSH) && defined(SQLITE_DEBUG) && SQLITE_MEMDEBUG>1 -#include -int sqlite3OutstandingMallocs(Tcl_Interp *interp){ - void *p; - Tcl_Obj *pRes = Tcl_NewObj(); - Tcl_IncrRefCount(pRes); - - - for(p=sqlite3_pFirst; p; p=((void **)p)[1]){ - Tcl_Obj *pEntry = Tcl_NewObj(); - Tcl_Obj *pStack = Tcl_NewObj(); - char *z; - u32 iLine; - int nBytes = sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD; - char *zAlloc = (char *)p; - int i; - - Tcl_ListObjAppendElement(0, pEntry, Tcl_NewIntObj(nBytes)); - - z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)]; - Tcl_ListObjAppendElement(0, pEntry, Tcl_NewStringObj(z, -1)); - - z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)]; - memcpy(&iLine, z, sizeof(u32)); - Tcl_ListObjAppendElement(0, pEntry, Tcl_NewIntObj(iLine)); - - z = &zAlloc[TESTALLOC_OFFSET_USER(p)]; - Tcl_ListObjAppendElement(0, pEntry, Tcl_NewStringObj(z, -1)); - - z = &zAlloc[TESTALLOC_OFFSET_STACK(p)]; - for(i=0; inAlloc); -#endif - assert( !sqlite3_mallocDisallowed ); - if( !sqlite3TestMallocFail() ){ - u32 *p; - p = (u32 *)sqlite3OsMalloc(n + TESTALLOC_OVERHEAD); - assert(p); - sqlite3_nMalloc++; - applyGuards(p); - linkAlloc(p); - sqlite3OsLeaveMutex(); - return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]); - } - sqlite3OsLeaveMutex(); - return 0; -} - -static int OSSIZEOF(void *p){ - if( p ){ - u32 *pOs = (u32 *)getOsPointer(p); - return sqlite3OsAllocationSize(pOs) - TESTALLOC_OVERHEAD; - } - return 0; -} - -/* -** This is the test layer's wrapper around sqlite3OsFree(). The argument is a -** pointer to the space allocated for the application to use. -*/ -static void OSFREE(void *pFree){ - u32 *p; /* Pointer to the OS-layer allocation */ - sqlite3OsEnterMutex(); - p = (u32 *)getOsPointer(pFree); - checkGuards(p); - unlinkAlloc(p); - memset(pFree, 0x55, OSSIZEOF(pFree)); - sqlite3OsFree(p); - sqlite3_nFree++; - sqlite3OsLeaveMutex(); -} - -/* -** This is the test layer's wrapper around sqlite3OsRealloc(). -*/ -static void * OSREALLOC(void *pRealloc, int n){ -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - sqlite3_nMaxAlloc = - MAX(sqlite3_nMaxAlloc, sqlite3ThreadDataReadOnly()->nAlloc); -#endif - assert( !sqlite3_mallocDisallowed ); - if( !sqlite3TestMallocFail() ){ - u32 *p = (u32 *)getOsPointer(pRealloc); - checkGuards(p); - p = sqlite3OsRealloc(p, n + TESTALLOC_OVERHEAD); - applyGuards(p); - relinkAlloc(p); - return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]); - } - return 0; -} - -static void OSMALLOC_FAILED(){ - sqlite3_isFail = 0; -} - -#else -/* Define macros to call the sqlite3OsXXX interface directly if -** the SQLITE_MEMDEBUG macro is not defined. -*/ -#define OSMALLOC(x) sqlite3OsMalloc(x) -#define OSREALLOC(x,y) sqlite3OsRealloc(x,y) -#define OSFREE(x) sqlite3OsFree(x) -#define OSSIZEOF(x) sqlite3OsAllocationSize(x) -#define OSMALLOC_FAILED() - -#endif /* SQLITE_MEMDEBUG */ -/* -** End code for memory allocation system test layer. -**--------------------------------------------------------------------------*/ - -/* -** This routine is called when we are about to allocate n additional bytes -** of memory. If the new allocation will put is over the soft allocation -** limit, then invoke sqlite3_release_memory() to try to release some -** memory before continuing with the allocation. -** -** This routine also makes sure that the thread-specific-data (TSD) has -** be allocated. If it has not and can not be allocated, then return -** false. The updateMemoryUsedCount() routine below will deallocate -** the TSD if it ought to be. -** -** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is -** a no-op -*/ -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT -static int enforceSoftLimit(int n){ - ThreadData *pTsd = sqlite3ThreadData(); - if( pTsd==0 ){ - return 0; - } - assert( pTsd->nAlloc>=0 ); - if( n>0 && pTsd->nSoftHeapLimit>0 ){ - while( pTsd->nAlloc+n>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) ){} - } - return 1; -} -#else -# define enforceSoftLimit(X) 1 -#endif - -/* -** Update the count of total outstanding memory that is held in -** thread-specific-data (TSD). If after this update the TSD is -** no longer being used, then deallocate it. -** -** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is -** a no-op -*/ -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT -static void updateMemoryUsedCount(int n){ - ThreadData *pTsd = sqlite3ThreadData(); - if( pTsd ){ - pTsd->nAlloc += n; - assert( pTsd->nAlloc>=0 ); - if( pTsd->nAlloc==0 && pTsd->nSoftHeapLimit==0 ){ - sqlite3ReleaseThreadData(); - } - } -} -#else -#define updateMemoryUsedCount(x) /* no-op */ -#endif - -/* -** Allocate and return N bytes of uninitialised memory by calling -** sqlite3OsMalloc(). If the Malloc() call fails, attempt to free memory -** by calling sqlite3_release_memory(). -*/ -void *sqlite3MallocRaw(int n, int doMemManage){ - void *p = 0; - if( n>0 && !sqlite3MallocFailed() && (!doMemManage || enforceSoftLimit(n)) ){ - while( (p = OSMALLOC(n))==0 && sqlite3_release_memory(n) ){} - if( !p ){ - sqlite3FailedMalloc(); - OSMALLOC_FAILED(); - }else if( doMemManage ){ - updateMemoryUsedCount(OSSIZEOF(p)); - } - } - return p; -} - -/* -** Resize the allocation at p to n bytes by calling sqlite3OsRealloc(). The -** pointer to the new allocation is returned. If the Realloc() call fails, -** attempt to free memory by calling sqlite3_release_memory(). -*/ -void *sqlite3Realloc(void *p, int n){ - if( sqlite3MallocFailed() ){ - return 0; - } - - if( !p ){ - return sqlite3Malloc(n, 1); - }else{ - void *np = 0; -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - int origSize = OSSIZEOF(p); -#endif - if( enforceSoftLimit(n - origSize) ){ - while( (np = OSREALLOC(p, n))==0 && sqlite3_release_memory(n) ){} - if( !np ){ - sqlite3FailedMalloc(); - OSMALLOC_FAILED(); - }else{ - updateMemoryUsedCount(OSSIZEOF(np) - origSize); - } - } - return np; - } -} - -/* -** Free the memory pointed to by p. p must be either a NULL pointer or a -** value returned by a previous call to sqlite3Malloc() or sqlite3Realloc(). -*/ -void sqlite3FreeX(void *p){ - if( p ){ - updateMemoryUsedCount(0 - OSSIZEOF(p)); - OSFREE(p); - } -} - -/* -** A version of sqliteMalloc() that is always a function, not a macro. -** Currently, this is used only to alloc to allocate the parser engine. -*/ -void *sqlite3MallocX(int n){ - return sqliteMalloc(n); -} - -/* -** sqlite3Malloc -** sqlite3ReallocOrFree -** -** These two are implemented as wrappers around sqlite3MallocRaw(), -** sqlite3Realloc() and sqlite3Free(). -*/ -void *sqlite3Malloc(int n, int doMemManage){ - void *p = sqlite3MallocRaw(n, doMemManage); +void *sqlite3MallocZero(unsigned n){ + void *p = sqlite3_malloc(n); if( p ){ memset(p, 0, n); } return p; } -void *sqlite3ReallocOrFree(void *p, int n){ - void *pNew; - pNew = sqlite3Realloc(p, n); - if( !pNew ){ - sqlite3FreeX(p); + +/* +** Allocate and zero memory. If the allocation fails, make +** the mallocFailed flag in the connection pointer. +*/ +void *sqlite3DbMallocZero(sqlite3 *db, unsigned n){ + void *p = sqlite3DbMallocRaw(db, n); + if( p ){ + memset(p, 0, n); + } + return p; +} + +/* +** Allocate and zero memory. If the allocation fails, make +** the mallocFailed flag in the connection pointer. +*/ +void *sqlite3DbMallocRaw(sqlite3 *db, unsigned n){ + void *p = 0; + if( !db || db->mallocFailed==0 ){ + p = sqlite3_malloc(n); + if( !p && db ){ + db->mallocFailed = 1; + } + } + return p; +} + +/* +** Resize the block of memory pointed to by p to n bytes. If the +** resize fails, set the mallocFailed flag inthe connection object. +*/ +void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){ + void *pNew = 0; + if( db->mallocFailed==0 ){ + pNew = sqlite3_realloc(p, n); + if( !pNew ){ + db->mallocFailed = 1; + } } return pNew; } /* -** sqlite3ThreadSafeMalloc() and sqlite3ThreadSafeFree() are used in those -** rare scenarios where sqlite may allocate memory in one thread and free -** it in another. They are exactly the same as sqlite3Malloc() and -** sqlite3Free() except that: -** -** * The allocated memory is not included in any calculations with -** respect to the soft-heap-limit, and -** -** * sqlite3ThreadSafeMalloc() must be matched with ThreadSafeFree(), -** not sqlite3Free(). Calling sqlite3Free() on memory obtained from -** ThreadSafeMalloc() will cause an error somewhere down the line. +** Attempt to reallocate p. If the reallocation fails, then free p +** and set the mallocFailed flag in the database connection. */ -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT -void *sqlite3ThreadSafeMalloc(int n){ - (void)ENTER_MALLOC; - return sqlite3Malloc(n, 0); -} -void sqlite3ThreadSafeFree(void *p){ - (void)ENTER_MALLOC; - if( p ){ - OSFREE(p); +void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){ + void *pNew; + pNew = sqlite3DbRealloc(db, p, n); + if( !pNew ){ + sqlite3_free(p); } + return pNew; } -#endif - - -/* -** Return the number of bytes allocated at location p. p must be either -** a NULL pointer (in which case 0 is returned) or a pointer returned by -** sqlite3Malloc(), sqlite3Realloc() or sqlite3ReallocOrFree(). -** -** The number of bytes allocated does not include any overhead inserted by -** any malloc() wrapper functions that may be called. So the value returned -** is the number of bytes that were available to SQLite using pointer p, -** regardless of how much memory was actually allocated. -*/ -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT -int sqlite3AllocSize(void *p){ - return OSSIZEOF(p); -} -#endif /* ** Make a copy of a string in memory obtained from sqliteMalloc(). These @@ -727,14 +144,14 @@ char *sqlite3StrDup(const char *z){ int n; if( z==0 ) return 0; n = strlen(z)+1; - zNew = sqlite3MallocRaw(n, 1); + zNew = sqlite3_malloc(n); if( zNew ) memcpy(zNew, z, n); return zNew; } char *sqlite3StrNDup(const char *z, int n){ char *zNew; if( z==0 ) return 0; - zNew = sqlite3MallocRaw(n+1, 1); + zNew = sqlite3_malloc(n+1); if( zNew ){ memcpy(zNew, z, n); zNew[n] = 0; @@ -742,6 +159,21 @@ char *sqlite3StrNDup(const char *z, int n){ return zNew; } +char *sqlite3DbStrDup(sqlite3 *db, const char *z){ + char *zNew = sqlite3StrDup(z); + if( z && !zNew ){ + db->mallocFailed = 1; + } + return zNew; +} +char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){ + char *zNew = sqlite3StrNDup(z, n); + if( z && !zNew ){ + db->mallocFailed = 1; + } + return zNew; +} + /* ** Create a string from the 2nd and subsequent arguments (up to the ** first NULL argument), store the string in memory obtained from @@ -762,8 +194,8 @@ void sqlite3SetString(char **pz, ...){ nByte += strlen(z); } va_end(ap); - sqliteFree(*pz); - *pz = zResult = sqliteMallocRaw( nByte ); + sqlite3_free(*pz); + *pz = zResult = sqlite3_malloc(nByte); if( zResult==0 ){ return; } @@ -781,8 +213,8 @@ void sqlite3SetString(char **pz, ...){ /* ** This function must be called before exiting any API function (i.e. -** returning control to the user) that has called sqlite3Malloc or -** sqlite3Realloc. +** returning control to the user) that has called sqlite3_malloc or +** sqlite3_realloc. ** ** The returned value is normally a copy of the second argument to this ** function. However, if a malloc() failure has occured since the previous @@ -792,44 +224,17 @@ void sqlite3SetString(char **pz, ...){ ** then the connection error-code (the value returned by sqlite3_errcode()) ** is set to SQLITE_NOMEM. */ -int sqlite3_mallocHasFailed = 0; int sqlite3ApiExit(sqlite3* db, int rc){ - if( sqlite3MallocFailed() ){ - sqlite3_mallocHasFailed = 0; - sqlite3OsLeaveMutex(); + /* If the db handle is not NULL, then we must hold the connection handle + ** mutex here. Otherwise the read (and possible write) of db->mallocFailed + ** is unsafe, as is the call to sqlite3Error(). + */ + assert( !db || sqlite3_mutex_held(db->mutex) ); + if( db && db->mallocFailed ){ sqlite3Error(db, SQLITE_NOMEM, 0); + db->mallocFailed = 0; rc = SQLITE_NOMEM; } return rc & (db ? db->errMask : 0xff); } - -/* -** Set the "malloc has failed" condition to true for this thread. -*/ -void sqlite3FailedMalloc(){ - if( !sqlite3MallocFailed() ){ - sqlite3OsEnterMutex(); - assert( sqlite3_mallocHasFailed==0 ); - sqlite3_mallocHasFailed = 1; - } -} - -#ifdef SQLITE_MEMDEBUG -/* -** This function sets a flag in the thread-specific-data structure that will -** cause an assert to fail if sqliteMalloc() or sqliteRealloc() is called. -*/ -void sqlite3MallocDisallow(){ - assert( sqlite3_mallocDisallowed>=0 ); - sqlite3_mallocDisallowed++; -} - -/* -** This function clears the flag set in the thread-specific-data structure set -** by sqlite3MallocDisallow(). -*/ -void sqlite3MallocAllow(){ - assert( sqlite3_mallocDisallowed>0 ); - sqlite3_mallocDisallowed--; -} -#endif + diff --git a/extensions/sqlite/sqlite-source/mem1.c b/extensions/sqlite/sqlite-source/mem1.c new file mode 100644 index 00000000..fa99d8db --- /dev/null +++ b/extensions/sqlite/sqlite-source/mem1.c @@ -0,0 +1,229 @@ +/* +** 2007 August 14 +** +** 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 C functions that implement a memory +** allocation subsystem for use by SQLite. +** +** $Id$ +*/ + +/* +** This version of the memory allocator is the default. It is +** used when no other memory allocator is specified using compile-time +** macros. +*/ +#if !defined(SQLITE_MEMDEBUG) && !defined(SQLITE_OMIT_MEMORY_ALLOCATION) + +/* +** We will eventually construct multiple memory allocation subsystems +** suitable for use in various contexts: +** +** * Normal multi-threaded builds +** * Normal single-threaded builds +** * Debugging builds +** +** This initial version is suitable for use in normal multi-threaded +** builds. We envision that alternative versions will be stored in +** separate source files. #ifdefs will be used to select the code from +** one of the various memN.c source files for use in any given build. +*/ +#include "sqliteInt.h" + +/* +** All of the static variables used by this module are collected +** into a single structure named "mem". This is to keep the +** static variables organized and to reduce namespace pollution +** when this module is combined with other in the amalgamation. +*/ +static struct { + /* + ** The alarm callback and its arguments. The mem.mutex lock will + ** be held while the callback is running. Recursive calls into + ** the memory subsystem are allowed, but no new callbacks will be + ** issued. The alarmBusy variable is set to prevent recursive + ** callbacks. + */ + sqlite3_int64 alarmThreshold; + void (*alarmCallback)(void*, sqlite3_int64,int); + void *alarmArg; + int alarmBusy; + + /* + ** Mutex to control access to the memory allocation subsystem. + */ + sqlite3_mutex *mutex; + + /* + ** Current allocation and high-water mark. + */ + sqlite3_int64 nowUsed; + sqlite3_int64 mxUsed; + + +} mem; + +/* +** Enter the mutex mem.mutex. Allocate it if it is not already allocated. +*/ +static void enterMem(void){ + if( mem.mutex==0 ){ + mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); + } + sqlite3_mutex_enter(mem.mutex); +} + +/* +** Return the amount of memory currently checked out. +*/ +sqlite3_int64 sqlite3_memory_used(void){ + sqlite3_int64 n; + enterMem(); + n = mem.nowUsed; + sqlite3_mutex_leave(mem.mutex); + return n; +} + +/* +** Return the maximum amount of memory that has ever been +** checked out since either the beginning of this process +** or since the most recent reset. +*/ +sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ + sqlite3_int64 n; + enterMem(); + n = mem.mxUsed; + if( resetFlag ){ + mem.mxUsed = mem.nowUsed; + } + sqlite3_mutex_leave(mem.mutex); + return n; +} + +/* +** Change the alarm callback +*/ +int sqlite3_memory_alarm( + void(*xCallback)(void *pArg, sqlite3_int64 used,int N), + void *pArg, + sqlite3_int64 iThreshold +){ + enterMem(); + mem.alarmCallback = xCallback; + mem.alarmArg = pArg; + mem.alarmThreshold = iThreshold; + sqlite3_mutex_leave(mem.mutex); + return SQLITE_OK; +} + +/* +** Trigger the alarm +*/ +static void sqlite3MemsysAlarm(int nByte){ + void (*xCallback)(void*,sqlite3_int64,int); + sqlite3_int64 nowUsed; + void *pArg; + if( mem.alarmCallback==0 || mem.alarmBusy ) return; + mem.alarmBusy = 1; + xCallback = mem.alarmCallback; + nowUsed = mem.nowUsed; + pArg = mem.alarmArg; + sqlite3_mutex_leave(mem.mutex); + xCallback(pArg, nowUsed, nByte); + sqlite3_mutex_enter(mem.mutex); + mem.alarmBusy = 0; +} + +/* +** Allocate nBytes of memory +*/ +void *sqlite3_malloc(int nBytes){ + sqlite3_int64 *p = 0; + if( nBytes>0 ){ + enterMem(); + if( mem.alarmCallback!=0 && mem.nowUsed+nBytes>=mem.alarmThreshold ){ + sqlite3MemsysAlarm(nBytes); + } + p = malloc(nBytes+8); + if( p==0 ){ + sqlite3MemsysAlarm(nBytes); + p = malloc(nBytes+8); + } + if( p ){ + p[0] = nBytes; + p++; + mem.nowUsed += nBytes; + if( mem.nowUsed>mem.mxUsed ){ + mem.mxUsed = mem.nowUsed; + } + } + sqlite3_mutex_leave(mem.mutex); + } + return (void*)p; +} + +/* +** Free memory. +*/ +void sqlite3_free(void *pPrior){ + sqlite3_int64 *p; + int nByte; + if( pPrior==0 ){ + return; + } + assert( mem.mutex!=0 ); + p = pPrior; + p--; + nByte = (int)*p; + sqlite3_mutex_enter(mem.mutex); + mem.nowUsed -= nByte; + free(p); + sqlite3_mutex_leave(mem.mutex); +} + +/* +** Change the size of an existing memory allocation +*/ +void *sqlite3_realloc(void *pPrior, int nBytes){ + int nOld; + sqlite3_int64 *p; + if( pPrior==0 ){ + return sqlite3_malloc(nBytes); + } + if( nBytes<=0 ){ + sqlite3_free(pPrior); + return 0; + } + p = pPrior; + p--; + nOld = (int)p[0]; + assert( mem.mutex!=0 ); + sqlite3_mutex_enter(mem.mutex); + if( mem.nowUsed+nBytes-nOld>=mem.alarmThreshold ){ + sqlite3MemsysAlarm(nBytes-nOld); + } + p = realloc(p, nBytes+8); + if( p==0 ){ + sqlite3MemsysAlarm(nBytes); + p = realloc(p, nBytes+8); + } + if( p ){ + p[0] = nBytes; + p++; + mem.nowUsed += nBytes-nOld; + if( mem.nowUsed>mem.mxUsed ){ + mem.mxUsed = mem.nowUsed; + } + } + sqlite3_mutex_leave(mem.mutex); + return (void*)p; +} + +#endif /* !SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */ diff --git a/extensions/sqlite/sqlite-source/mem2.c b/extensions/sqlite/sqlite-source/mem2.c new file mode 100644 index 00000000..3cdf5cb8 --- /dev/null +++ b/extensions/sqlite/sqlite-source/mem2.c @@ -0,0 +1,546 @@ +/* +** 2007 August 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. +** +************************************************************************* +** This file contains the C functions that implement a memory +** allocation subsystem for use by SQLite. +** +** $Id$ +*/ + +/* +** This version of the memory allocator is used only if the +** SQLITE_MEMDEBUG macro is defined and SQLITE_OMIT_MEMORY_ALLOCATION +** is not defined. +*/ +#if defined(SQLITE_MEMDEBUG) && !defined(SQLITE_OMIT_MEMORY_ALLOCATION) + +/* +** We will eventually construct multiple memory allocation subsystems +** suitable for use in various contexts: +** +** * Normal multi-threaded builds +** * Normal single-threaded builds +** * Debugging builds +** +** This version is suitable for use in debugging builds. +** +** Features: +** +** * Every allocate has guards at both ends. +** * New allocations are initialized with randomness +** * Allocations are overwritten with randomness when freed +** * Optional logs of malloc activity generated +** * Summary of outstanding allocations with backtraces to the +** point of allocation. +** * The ability to simulate memory allocation failure +*/ +#include "sqliteInt.h" +#include + +/* +** The backtrace functionality is only available with GLIBC +*/ +#ifdef __GLIBC__ + extern int backtrace(void**,int); + extern void backtrace_symbols_fd(void*const*,int,int); +#else +# define backtrace(A,B) 0 +# define backtrace_symbols_fd(A,B,C) +#endif + +/* +** Each memory allocation looks like this: +** +** ------------------------------------------------------------------------ +** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard | +** ------------------------------------------------------------------------ +** +** The application code sees only a pointer to the allocation. We have +** to back up from the allocation pointer to find the MemBlockHdr. The +** MemBlockHdr tells us the size of the allocation and the number of +** backtrace pointers. There is also a guard word at the end of the +** MemBlockHdr. +*/ +struct MemBlockHdr { + struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */ + int iSize; /* Size of this allocation */ + char nBacktrace; /* Number of backtraces on this alloc */ + char nBacktraceSlots; /* Available backtrace slots */ + short nTitle; /* Bytes of title; includes '\0' */ + int iForeGuard; /* Guard word for sanity */ +}; + +/* +** Guard words +*/ +#define FOREGUARD 0x80F5E153 +#define REARGUARD 0xE4676B53 + +/* +** All of the static variables used by this module are collected +** into a single structure named "mem". This is to keep the +** static variables organized and to reduce namespace pollution +** when this module is combined with other in the amalgamation. +*/ +static struct { + /* + ** The alarm callback and its arguments. The mem.mutex lock will + ** be held while the callback is running. Recursive calls into + ** the memory subsystem are allowed, but no new callbacks will be + ** issued. The alarmBusy variable is set to prevent recursive + ** callbacks. + */ + sqlite3_int64 alarmThreshold; + void (*alarmCallback)(void*, sqlite3_int64, int); + void *alarmArg; + int alarmBusy; + + /* + ** Mutex to control access to the memory allocation subsystem. + */ + sqlite3_mutex *mutex; + + /* + ** Current allocation and high-water mark. + */ + sqlite3_int64 nowUsed; + sqlite3_int64 mxUsed; + + /* + ** Head and tail of a linked list of all outstanding allocations + */ + struct MemBlockHdr *pFirst; + struct MemBlockHdr *pLast; + + /* + ** The number of levels of backtrace to save in new allocations. + */ + int nBacktrace; + + /* + ** Title text to insert in front of each block + */ + int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ + char zTitle[100]; /* The title text */ + + /* + ** These values are used to simulate malloc failures. When + ** iFail is 1, simulate a malloc failures and reset the value + ** to iReset. + */ + int iFail; /* Decrement and fail malloc when this is 1 */ + int iReset; /* When malloc fails set iiFail to this value */ + int iFailCnt; /* Number of failures */ + int iBenignFailCnt; /* Number of benign failures */ + int iNextIsBenign; /* True if the next call to malloc may fail benignly */ + int iIsBenign; /* All malloc calls may fail benignly */ + + /* + ** sqlite3MallocDisallow() increments the following counter. + ** sqlite3MallocAllow() decrements it. + */ + int disallow; /* Do not allow memory allocation */ + + +} mem; + + +/* +** Enter the mutex mem.mutex. Allocate it if it is not already allocated. +*/ +static void enterMem(void){ + if( mem.mutex==0 ){ + mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); + } + sqlite3_mutex_enter(mem.mutex); +} + +/* +** Return the amount of memory currently checked out. +*/ +sqlite3_int64 sqlite3_memory_used(void){ + sqlite3_int64 n; + enterMem(); + n = mem.nowUsed; + sqlite3_mutex_leave(mem.mutex); + return n; +} + +/* +** Return the maximum amount of memory that has ever been +** checked out since either the beginning of this process +** or since the most recent reset. +*/ +sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ + sqlite3_int64 n; + enterMem(); + n = mem.mxUsed; + if( resetFlag ){ + mem.mxUsed = mem.nowUsed; + } + sqlite3_mutex_leave(mem.mutex); + return n; +} + +/* +** Change the alarm callback +*/ +int sqlite3_memory_alarm( + void(*xCallback)(void *pArg, sqlite3_int64 used, int N), + void *pArg, + sqlite3_int64 iThreshold +){ + enterMem(); + mem.alarmCallback = xCallback; + mem.alarmArg = pArg; + mem.alarmThreshold = iThreshold; + sqlite3_mutex_leave(mem.mutex); + return SQLITE_OK; +} + +/* +** Trigger the alarm +*/ +static void sqlite3MemsysAlarm(int nByte){ + void (*xCallback)(void*,sqlite3_int64,int); + sqlite3_int64 nowUsed; + void *pArg; + if( mem.alarmCallback==0 || mem.alarmBusy ) return; + mem.alarmBusy = 1; + xCallback = mem.alarmCallback; + nowUsed = mem.nowUsed; + pArg = mem.alarmArg; + sqlite3_mutex_leave(mem.mutex); + xCallback(pArg, nowUsed, nByte); + sqlite3_mutex_enter(mem.mutex); + mem.alarmBusy = 0; +} + +/* +** Given an allocation, find the MemBlockHdr for that allocation. +** +** This routine checks the guards at either end of the allocation and +** if they are incorrect it asserts. +*/ +static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ + struct MemBlockHdr *p; + int *pInt; + + p = (struct MemBlockHdr*)pAllocation; + p--; + assert( p->iForeGuard==FOREGUARD ); + assert( (p->iSize & 3)==0 ); + pInt = (int*)pAllocation; + assert( pInt[p->iSize/sizeof(int)]==REARGUARD ); + return p; +} + +/* +** This routine is called once the first time a simulated memory +** failure occurs. The sole purpose of this routine is to provide +** a convenient place to set a debugger breakpoint when debugging +** errors related to malloc() failures. +*/ +static void sqlite3MemsysFailed(void){ + mem.iFailCnt = 0; + mem.iBenignFailCnt = 0; +} + +/* +** Allocate nByte bytes of memory. +*/ +void *sqlite3_malloc(int nByte){ + struct MemBlockHdr *pHdr; + void **pBt; + char *z; + int *pInt; + void *p = 0; + int totalSize; + + if( nByte>0 ){ + enterMem(); + assert( mem.disallow==0 ); + if( mem.alarmCallback!=0 && mem.nowUsed+nByte>=mem.alarmThreshold ){ + sqlite3MemsysAlarm(nByte); + } + nByte = (nByte+3)&~3; + totalSize = nByte + sizeof(*pHdr) + sizeof(int) + + mem.nBacktrace*sizeof(void*) + mem.nTitle; + if( mem.iFail>0 ){ + if( mem.iFail==1 ){ + p = 0; + mem.iFail = mem.iReset; + if( mem.iFailCnt==0 ){ + sqlite3MemsysFailed(); /* A place to set a breakpoint */ + } + mem.iFailCnt++; + if( mem.iNextIsBenign || mem.iIsBenign ){ + mem.iBenignFailCnt++; + } + }else{ + p = malloc(totalSize); + mem.iFail--; + } + }else{ + p = malloc(totalSize); + if( p==0 ){ + sqlite3MemsysAlarm(nByte); + p = malloc(totalSize); + } + } + if( p ){ + z = p; + pBt = (void**)&z[mem.nTitle]; + pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace]; + pHdr->pNext = 0; + pHdr->pPrev = mem.pLast; + if( mem.pLast ){ + mem.pLast->pNext = pHdr; + }else{ + mem.pFirst = pHdr; + } + mem.pLast = pHdr; + pHdr->iForeGuard = FOREGUARD; + pHdr->nBacktraceSlots = mem.nBacktrace; + pHdr->nTitle = mem.nTitle; + if( mem.nBacktrace ){ + void *aAddr[40]; + pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1; + memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*)); + }else{ + pHdr->nBacktrace = 0; + } + if( mem.nTitle ){ + memcpy(z, mem.zTitle, mem.nTitle); + } + pHdr->iSize = nByte; + pInt = (int*)&pHdr[1]; + pInt[nByte/sizeof(int)] = REARGUARD; + memset(pInt, 0x65, nByte); + mem.nowUsed += nByte; + if( mem.nowUsed>mem.mxUsed ){ + mem.mxUsed = mem.nowUsed; + } + p = (void*)pInt; + } + sqlite3_mutex_leave(mem.mutex); + } + mem.iNextIsBenign = 0; + return p; +} + +/* +** Free memory. +*/ +void sqlite3_free(void *pPrior){ + struct MemBlockHdr *pHdr; + void **pBt; + char *z; + if( pPrior==0 ){ + return; + } + assert( mem.mutex!=0 ); + pHdr = sqlite3MemsysGetHeader(pPrior); + pBt = (void**)pHdr; + pBt -= pHdr->nBacktraceSlots; + sqlite3_mutex_enter(mem.mutex); + mem.nowUsed -= pHdr->iSize; + if( pHdr->pPrev ){ + assert( pHdr->pPrev->pNext==pHdr ); + pHdr->pPrev->pNext = pHdr->pNext; + }else{ + assert( mem.pFirst==pHdr ); + mem.pFirst = pHdr->pNext; + } + if( pHdr->pNext ){ + assert( pHdr->pNext->pPrev==pHdr ); + pHdr->pNext->pPrev = pHdr->pPrev; + }else{ + assert( mem.pLast==pHdr ); + mem.pLast = pHdr->pPrev; + } + z = (char*)pBt; + z -= pHdr->nTitle; + memset(z, 0x2b, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) + + pHdr->iSize + sizeof(int) + pHdr->nTitle); + free(z); + sqlite3_mutex_leave(mem.mutex); +} + +/* +** Change the size of an existing memory allocation. +** +** For this debugging implementation, we *always* make a copy of the +** allocation into a new place in memory. In this way, if the +** higher level code is using pointer to the old allocation, it is +** much more likely to break and we are much more liking to find +** the error. +*/ +void *sqlite3_realloc(void *pPrior, int nByte){ + struct MemBlockHdr *pOldHdr; + void *pNew; + if( pPrior==0 ){ + return sqlite3_malloc(nByte); + } + if( nByte<=0 ){ + sqlite3_free(pPrior); + return 0; + } + assert( mem.disallow==0 ); + pOldHdr = sqlite3MemsysGetHeader(pPrior); + pNew = sqlite3_malloc(nByte); + if( pNew ){ + memcpy(pNew, pPrior, nByteiSize ? nByte : pOldHdr->iSize); + if( nByte>pOldHdr->iSize ){ + memset(&((char*)pNew)[pOldHdr->iSize], 0x2b, nByte - pOldHdr->iSize); + } + sqlite3_free(pPrior); + } + return pNew; +} + +/* +** Set the number of backtrace levels kept for each allocation. +** A value of zero turns of backtracing. The number is always rounded +** up to a multiple of 2. +*/ +void sqlite3_memdebug_backtrace(int depth){ + if( depth<0 ){ depth = 0; } + if( depth>20 ){ depth = 20; } + depth = (depth+1)&0xfe; + mem.nBacktrace = depth; +} + +/* +** Set the title string for subsequent allocations. +*/ +void sqlite3_memdebug_settitle(const char *zTitle){ + int n = strlen(zTitle) + 1; + enterMem(); + if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1; + memcpy(mem.zTitle, zTitle, n); + mem.zTitle[n] = 0; + mem.nTitle = (n+3)&~3; + sqlite3_mutex_leave(mem.mutex); +} + +/* +** Open the file indicated and write a log of all unfreed memory +** allocations into that log. +*/ +void sqlite3_memdebug_dump(const char *zFilename){ + FILE *out; + struct MemBlockHdr *pHdr; + void **pBt; + out = fopen(zFilename, "w"); + if( out==0 ){ + fprintf(stderr, "** Unable to output memory debug output log: %s **\n", + zFilename); + return; + } + for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ + char *z = (char*)pHdr; + z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle; + fprintf(out, "**** %d bytes at %p from %s ****\n", + pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???"); + if( pHdr->nBacktrace ){ + fflush(out); + pBt = (void**)pHdr; + pBt -= pHdr->nBacktraceSlots; + backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out)); + fprintf(out, "\n"); + } + } + fclose(out); +} + +/* +** This routine is used to simulate malloc failures. +** +** After calling this routine, there will be iFail successful +** memory allocations and then a failure. If iRepeat is 1 +** all subsequent memory allocations will fail. If iRepeat is +** 0, only a single allocation will fail. If iRepeat is negative +** then the previous setting for iRepeat is unchanged. +** +** Each call to this routine overrides the previous. To disable +** the simulated allocation failure mechanism, set iFail to -1. +** +** This routine returns the number of simulated failures that have +** occurred since the previous call. +*/ +int sqlite3_memdebug_fail(int iFail, int iRepeat, int *piBenign){ + int n = mem.iFailCnt; + if( piBenign ){ + *piBenign = mem.iBenignFailCnt; + } + mem.iFail = iFail+1; + if( iRepeat>=0 ){ + mem.iReset = iRepeat; + } + mem.iFailCnt = 0; + mem.iBenignFailCnt = 0; + return n; +} + +int sqlite3_memdebug_pending(){ + return (mem.iFail-1); +} + +/* +** The following three functions are used to indicate to the test +** infrastructure which malloc() calls may fail benignly without +** affecting functionality. This can happen when resizing hash tables +** (failing to resize a hash-table is a performance hit, but not an +** error) or sometimes during a rollback operation. +** +** If the argument is true, sqlite3MallocBenignFailure() indicates that the +** next call to allocate memory may fail benignly. +** +** If sqlite3MallocEnterBenignBlock() is called with a non-zero argument, +** then all memory allocations requested before the next call to +** sqlite3MallocLeaveBenignBlock() may fail benignly. +*/ +void sqlite3MallocBenignFailure(int isBenign){ + if( isBenign ){ + mem.iNextIsBenign = 1; + } +} +void sqlite3MallocEnterBenignBlock(int isBenign){ + if( isBenign ){ + mem.iIsBenign = 1; + } +} +void sqlite3MallocLeaveBenignBlock(){ + mem.iIsBenign = 0; +} + +/* +** The following two routines are used to assert that no memory +** allocations occur between one call and the next. The use of +** these routines does not change the computed results in any way. +** These routines are like asserts. +*/ +void sqlite3MallocDisallow(void){ + assert( mem.mutex!=0 ); + sqlite3_mutex_enter(mem.mutex); + mem.disallow++; + sqlite3_mutex_leave(mem.mutex); +} +void sqlite3MallocAllow(void){ + assert( mem.mutex ); + sqlite3_mutex_enter(mem.mutex); + assert( mem.disallow>0 ); + mem.disallow--; + sqlite3_mutex_leave(mem.mutex); +} + +#endif /* SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */ diff --git a/extensions/sqlite/sqlite-source/mutex.c b/extensions/sqlite/sqlite-source/mutex.c new file mode 100644 index 00000000..687ee549 --- /dev/null +++ b/extensions/sqlite/sqlite-source/mutex.c @@ -0,0 +1,126 @@ +/* +** 2007 August 14 +** +** 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 C functions that implement mutexes. +** +** The implementation in this file does not provide any mutual +** exclusion and is thus suitable for use only in applications +** that use SQLite in a single thread. But this implementation +** does do a lot of error checking on mutexes to make sure they +** are called correctly and at appropriate times. Hence, this +** implementation is suitable for testing. +** debugging purposes +** +** $Id$ +*/ +#include "sqliteInt.h" + +#ifdef SQLITE_MUTEX_NOOP_DEBUG +/* +** In this implementation, mutexes do not provide any mutual exclusion. +** But the error checking is provided. This implementation is useful +** for test purposes. +*/ + +/* +** The mutex object +*/ +struct sqlite3_mutex { + int id; /* The mutex type */ + int cnt; /* Number of entries without a matching leave */ +}; + +/* +** The sqlite3_mutex_alloc() routine allocates a new +** mutex and returns a pointer to it. If it returns NULL +** that means that a mutex could not be allocated. +*/ +sqlite3_mutex *sqlite3_mutex_alloc(int id){ + static sqlite3_mutex aStatic[5]; + sqlite3_mutex *pNew = 0; + switch( id ){ + case SQLITE_MUTEX_FAST: + case SQLITE_MUTEX_RECURSIVE: { + pNew = sqlite3_malloc(sizeof(*pNew)); + if( pNew ){ + pNew->id = id; + pNew->cnt = 0; + } + break; + } + default: { + assert( id-2 >= 0 ); + assert( id-2 < sizeof(aStatic)/sizeof(aStatic[0]) ); + pNew = &aStatic[id-2]; + pNew->id = id; + break; + } + } + return pNew; +} + +/* +** This routine deallocates a previously allocated mutex. +*/ +void sqlite3_mutex_free(sqlite3_mutex *p){ + assert( p ); + assert( p->cnt==0 ); + assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); + sqlite3_free(p); +} + +/* +** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt +** to enter a mutex. If another thread is already within the mutex, +** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return +** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK +** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can +** be entered multiple times by the same thread. In such cases the, +** mutex must be exited an equal number of times before another thread +** can enter. If the same thread tries to enter any other kind of mutex +** more than once, the behavior is undefined. +*/ +void sqlite3_mutex_enter(sqlite3_mutex *p){ + assert( p ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); + p->cnt++; +} +int sqlite3_mutex_try(sqlite3_mutex *p){ + assert( p ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); + p->cnt++; + return SQLITE_OK; +} + +/* +** The sqlite3_mutex_leave() routine exits a mutex that was +** previously entered by the same thread. The behavior +** is undefined if the mutex is not currently entered or +** is not currently allocated. SQLite will never do either. +*/ +void sqlite3_mutex_leave(sqlite3_mutex *p){ + assert( p ); + assert( sqlite3_mutex_held(p) ); + p->cnt--; + assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); +} + +/* +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are +** intended for use inside assert() statements. +*/ +int sqlite3_mutex_held(sqlite3_mutex *p){ + return p==0 || p->cnt>0; +} +int sqlite3_mutex_notheld(sqlite3_mutex *p){ + return p==0 || p->cnt==0; +} +#endif /* SQLITE_MUTEX_NOOP_DEBUG */ diff --git a/extensions/sqlite/sqlite-source/mutex.h b/extensions/sqlite/sqlite-source/mutex.h new file mode 100644 index 00000000..008a1e52 --- /dev/null +++ b/extensions/sqlite/sqlite-source/mutex.h @@ -0,0 +1,82 @@ +/* +** 2007 August 28 +** +** 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 common header for all mutex implementations. +** The sqliteInt.h header #includes this file so that it is available +** to all source files. We break it out in an effort to keep the code +** better organized. +** +** NOTE: source files should *not* #include this header file directly. +** Source files should #include the sqliteInt.h file and let that file +** include this one indirectly. +** +** $Id$ +*/ + + +#ifdef SQLITE_MUTEX_APPDEF +/* +** If SQLITE_MUTEX_APPDEF is defined, then this whole module is +** omitted and equivalent functionality must be provided by the +** application that links against the SQLite library. +*/ +#else +/* +** Figure out what version of the code to use. The choices are +** +** SQLITE_MUTEX_NOOP For single-threaded applications that +** do not desire error checking. +** +** SQLITE_MUTEX_NOOP_DEBUG For single-threaded applications with +** error checking to help verify that mutexes +** are being used correctly even though they +** are not needed. Used when SQLITE_DEBUG is +** defined on single-threaded builds. +** +** SQLITE_MUTEX_PTHREADS For multi-threaded applications on Unix. +** +** SQLITE_MUTEX_W32 For multi-threaded applications on Win32. +** +** SQLITE_MUTEX_OS2 For multi-threaded applications on OS/2. +*/ +#define SQLITE_MUTEX_NOOP 1 /* The default */ +#if defined(SQLITE_DEBUG) && !SQLITE_THREADSAFE +# undef SQLITE_MUTEX_NOOP +# define SQLITE_MUTEX_NOOP_DEBUG +#endif +#if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_UNIX +# undef SQLITE_MUTEX_NOOP +# define SQLITE_MUTEX_PTHREADS +#endif +#if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_WIN +# undef SQLITE_MUTEX_NOOP +# define SQLITE_MUTEX_W32 +#endif +#if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_OS2 +# undef SQLITE_MUTEX_NOOP +# define SQLITE_MUTEX_OS2 +#endif + +#ifdef SQLITE_MUTEX_NOOP +/* +** If this is a no-op implementation, implement everything as macros. +*/ +#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8) +#define sqlite3_mutex_free(X) +#define sqlite3_mutex_enter(X) +#define sqlite3_mutex_try(X) SQLITE_OK +#define sqlite3_mutex_leave(X) +#define sqlite3_mutex_held(X) 1 +#define sqlite3_mutex_notheld(X) 1 +#endif + +#endif /* SQLITE_MUTEX_APPDEF */ diff --git a/extensions/sqlite/sqlite-source/mutex_unix.c b/extensions/sqlite/sqlite-source/mutex_unix.c new file mode 100644 index 00000000..941d6689 --- /dev/null +++ b/extensions/sqlite/sqlite-source/mutex_unix.c @@ -0,0 +1,223 @@ +/* +** 2007 August 28 +** +** 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 C functions that implement mutexes for pthreads +** +** $Id$ +*/ +#include "sqliteInt.h" + +/* +** The code in this file is only used if we are compiling threadsafe +** under unix with pthreads. +** +** Note that this implementation requires a version of pthreads that +** supports recursive mutexes. +*/ +#ifdef SQLITE_MUTEX_PTHREADS + +#include + +/* +** Each recursive mutex is an instance of the following structure. +*/ +struct sqlite3_mutex { + pthread_mutex_t mutex; /* Mutex controlling the lock */ + int id; /* Mutex type */ + int nRef; /* Number of entrances */ + pthread_t owner; /* Thread that is within this mutex */ +#ifdef SQLITE_DEBUG + int trace; /* True to trace changes */ +#endif +}; + +/* +** The sqlite3_mutex_alloc() routine allocates a new +** mutex and returns a pointer to it. If it returns NULL +** that means that a mutex could not be allocated. SQLite +** will unwind its stack and return an error. The argument +** to sqlite3_mutex_alloc() is one of these integer constants: +** +**
    +**
  • SQLITE_MUTEX_FAST +**
  • SQLITE_MUTEX_RECURSIVE +**
  • SQLITE_MUTEX_STATIC_MASTER +**
  • SQLITE_MUTEX_STATIC_MEM +**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_PRNG +**
  • SQLITE_MUTEX_STATIC_LRU +**
+** +** The first two constants cause sqlite3_mutex_alloc() to create +** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE +** is used but not necessarily so when SQLITE_MUTEX_FAST is used. +** The mutex implementation does not need to make a distinction +** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does +** not want to. But SQLite will only request a recursive mutex in +** cases where it really needs one. If a faster non-recursive mutex +** implementation is available on the host platform, the mutex subsystem +** might return such a mutex in response to SQLITE_MUTEX_FAST. +** +** The other allowed parameters to sqlite3_mutex_alloc() each return +** a pointer to a static preexisting mutex. Three static mutexes are +** used by the current version of SQLite. Future versions of SQLite +** may add additional static mutexes. Static mutexes are for internal +** use by SQLite only. Applications that use SQLite mutexes should +** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or +** SQLITE_MUTEX_RECURSIVE. +** +** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST +** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() +** returns a different mutex on every call. But for the static +** mutex types, the same mutex is returned on every call that has +** the same type number. +*/ +sqlite3_mutex *sqlite3_mutex_alloc(int iType){ + static sqlite3_mutex staticMutexes[] = { + { PTHREAD_MUTEX_INITIALIZER, }, + { PTHREAD_MUTEX_INITIALIZER, }, + { PTHREAD_MUTEX_INITIALIZER, }, + { PTHREAD_MUTEX_INITIALIZER, }, + { PTHREAD_MUTEX_INITIALIZER, }, + }; + sqlite3_mutex *p; + switch( iType ){ + case SQLITE_MUTEX_RECURSIVE: { + p = sqlite3MallocZero( sizeof(*p) ); + if( p ){ + pthread_mutexattr_t recursiveAttr; + pthread_mutexattr_init(&recursiveAttr); + pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&p->mutex, &recursiveAttr); + pthread_mutexattr_destroy(&recursiveAttr); + p->id = iType; + } + break; + } + case SQLITE_MUTEX_FAST: { + p = sqlite3MallocZero( sizeof(*p) ); + if( p ){ + p->id = iType; + pthread_mutex_init(&p->mutex, 0); + } + break; + } + default: { + assert( iType-2 >= 0 ); + assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) ); + p = &staticMutexes[iType-2]; + p->id = iType; + break; + } + } + return p; +} + + +/* +** This routine deallocates a previously +** allocated mutex. SQLite is careful to deallocate every +** mutex that it allocates. +*/ +void sqlite3_mutex_free(sqlite3_mutex *p){ + assert( p ); + assert( p->nRef==0 ); + assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); + pthread_mutex_destroy(&p->mutex); + sqlite3_free(p); +} + +/* +** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt +** to enter a mutex. If another thread is already within the mutex, +** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return +** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK +** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can +** be entered multiple times by the same thread. In such cases the, +** mutex must be exited an equal number of times before another thread +** can enter. If the same thread tries to enter any other kind of mutex +** more than once, the behavior is undefined. +*/ +void sqlite3_mutex_enter(sqlite3_mutex *p){ + assert( p ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); + pthread_mutex_lock(&p->mutex); + p->owner = pthread_self(); + p->nRef++; +#ifdef SQLITE_DEBUG + if( p->trace ){ + printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + } +#endif +} +int sqlite3_mutex_try(sqlite3_mutex *p){ + int rc; + assert( p ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); + if( pthread_mutex_trylock(&p->mutex)==0 ){ + p->owner = pthread_self(); + p->nRef++; + rc = SQLITE_OK; +#ifdef SQLITE_DEBUG + if( p->trace ){ + printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + } +#endif + }else{ + rc = SQLITE_BUSY; + } + return rc; +} + +/* +** The sqlite3_mutex_leave() routine exits a mutex that was +** previously entered by the same thread. The behavior +** is undefined if the mutex is not currently entered or +** is not currently allocated. SQLite will never do either. +*/ +void sqlite3_mutex_leave(sqlite3_mutex *p){ + assert( p ); + assert( sqlite3_mutex_held(p) ); + p->nRef--; + assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); +#ifdef SQLITE_DEBUG + if( p->trace ){ + printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + } +#endif + pthread_mutex_unlock(&p->mutex); +} + +/* +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are +** intended for use only inside assert() statements. On some platforms, +** there might be race conditions that can cause these routines to +** deliver incorrect results. In particular, if pthread_equal() is +** not an atomic operation, then these routines might delivery +** incorrect results. On most platforms, pthread_equal() is a +** comparison of two integers and is therefore atomic. But we are +** told that HPUX is not such a platform. If so, then these routines +** will not always work correctly on HPUX. +** +** On those platforms where pthread_equal() is not atomic, SQLite +** should be compiled without -DSQLITE_DEBUG and with -DNDEBUG to +** make sure no assert() statements are evaluated and hence these +** routines are never called. +*/ +#ifndef NDEBUG +int sqlite3_mutex_held(sqlite3_mutex *p){ + return p==0 || (p->nRef!=0 && pthread_equal(p->owner, pthread_self())); +} +int sqlite3_mutex_notheld(sqlite3_mutex *p){ + return p==0 || p->nRef==0 || pthread_equal(p->owner, pthread_self())==0; +} +#endif +#endif /* SQLITE_MUTEX_PTHREAD */ diff --git a/extensions/sqlite/sqlite-source/mutex_w32.c b/extensions/sqlite/sqlite-source/mutex_w32.c new file mode 100644 index 00000000..9e9f00c0 --- /dev/null +++ b/extensions/sqlite/sqlite-source/mutex_w32.c @@ -0,0 +1,208 @@ +/* +** 2007 August 14 +** +** 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 C functions that implement mutexes for win32 +** +** $Id$ +*/ +#include "sqliteInt.h" + +/* +** The code in this file is only used if we are compiling multithreaded +** on a win32 system. +*/ +#ifdef SQLITE_MUTEX_W32 + +/* +** Each recursive mutex is an instance of the following structure. +*/ +struct sqlite3_mutex { + CRITICAL_SECTION mutex; /* Mutex controlling the lock */ + int id; /* Mutex type */ + int nRef; /* Number of enterances */ + DWORD owner; /* Thread holding this mutex */ +}; + +/* +** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, +** or WinCE. Return false (zero) for Win95, Win98, or WinME. +** +** Here is an interesting observation: Win95, Win98, and WinME lack +** the LockFileEx() API. But we can still statically link against that +** API as long as we don't call it win running Win95/98/ME. A call to +** this routine is used to determine if the host is Win95/98/ME or +** WinNT/2K/XP so that we will know whether or not we can safely call +** the LockFileEx() API. +*/ +#if OS_WINCE +# define mutexIsNT() (1) +#else + static int mutexIsNT(void){ + static int osType = 0; + if( osType==0 ){ + OSVERSIONINFO sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + GetVersionEx(&sInfo); + osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; + } + return osType==2; + } +#endif /* OS_WINCE */ + + +/* +** The sqlite3_mutex_alloc() routine allocates a new +** mutex and returns a pointer to it. If it returns NULL +** that means that a mutex could not be allocated. SQLite +** will unwind its stack and return an error. The argument +** to sqlite3_mutex_alloc() is one of these integer constants: +** +**
    +**
  • SQLITE_MUTEX_FAST 0 +**
  • SQLITE_MUTEX_RECURSIVE 1 +**
  • SQLITE_MUTEX_STATIC_MASTER 2 +**
  • SQLITE_MUTEX_STATIC_MEM 3 +**
  • SQLITE_MUTEX_STATIC_PRNG 4 +**
+** +** The first two constants cause sqlite3_mutex_alloc() to create +** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE +** is used but not necessarily so when SQLITE_MUTEX_FAST is used. +** The mutex implementation does not need to make a distinction +** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does +** not want to. But SQLite will only request a recursive mutex in +** cases where it really needs one. If a faster non-recursive mutex +** implementation is available on the host platform, the mutex subsystem +** might return such a mutex in response to SQLITE_MUTEX_FAST. +** +** The other allowed parameters to sqlite3_mutex_alloc() each return +** a pointer to a static preexisting mutex. Three static mutexes are +** used by the current version of SQLite. Future versions of SQLite +** may add additional static mutexes. Static mutexes are for internal +** use by SQLite only. Applications that use SQLite mutexes should +** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or +** SQLITE_MUTEX_RECURSIVE. +** +** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST +** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() +** returns a different mutex on every call. But for the static +** mutex types, the same mutex is returned on every call that has +** the same type number. +*/ +sqlite3_mutex *sqlite3_mutex_alloc(int iType){ + sqlite3_mutex *p; + + switch( iType ){ + case SQLITE_MUTEX_FAST: + case SQLITE_MUTEX_RECURSIVE: { + p = sqlite3MallocZero( sizeof(*p) ); + if( p ){ + p->id = iType; + InitializeCriticalSection(&p->mutex); + } + break; + } + default: { + static sqlite3_mutex staticMutexes[5]; + static int isInit = 0; + while( !isInit ){ + static long lock = 0; + if( InterlockedIncrement(&lock)==1 ){ + int i; + for(i=0; i= 0 ); + assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) ); + p = &staticMutexes[iType-2]; + p->id = iType; + break; + } + } + return p; +} + + +/* +** This routine deallocates a previously +** allocated mutex. SQLite is careful to deallocate every +** mutex that it allocates. +*/ +void sqlite3_mutex_free(sqlite3_mutex *p){ + assert( p ); + assert( p->nRef==0 ); + assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); + DeleteCriticalSection(&p->mutex); + sqlite3_free(p); +} + +/* +** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt +** to enter a mutex. If another thread is already within the mutex, +** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return +** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK +** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can +** be entered multiple times by the same thread. In such cases the, +** mutex must be exited an equal number of times before another thread +** can enter. If the same thread tries to enter any other kind of mutex +** more than once, the behavior is undefined. +*/ +void sqlite3_mutex_enter(sqlite3_mutex *p){ + assert( p ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); + EnterCriticalSection(&p->mutex); + p->owner = GetCurrentThreadId(); + p->nRef++; +} +int sqlite3_mutex_try(sqlite3_mutex *p){ + int rc; + assert( p ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) ); + if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){ + p->owner = GetCurrentThreadId(); + p->nRef++; + rc = SQLITE_OK; + }else{ + rc = SQLITE_BUSY; + } + return rc; +} + +/* +** The sqlite3_mutex_leave() routine exits a mutex that was +** previously entered by the same thread. The behavior +** is undefined if the mutex is not currently entered or +** is not currently allocated. SQLite will never do either. +*/ +void sqlite3_mutex_leave(sqlite3_mutex *p){ + assert( p->nRef>0 ); + assert( p->owner==GetCurrentThreadId() ); + p->nRef--; + assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); + LeaveCriticalSection(&p->mutex); +} + +/* +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are +** intended for use only inside assert() statements. +*/ +int sqlite3_mutex_held(sqlite3_mutex *p){ + return p==0 || (p->nRef!=0 && p->owner==GetCurrentThreadId()); +} +int sqlite3_mutex_notheld(sqlite3_mutex *p){ + return p==0 || p->nRef==0 || p->owner!=GetCurrentThreadId(); +} +#endif /* SQLITE_MUTEX_W32 */ diff --git a/extensions/sqlite/sqlite-source/opcodes.c b/extensions/sqlite/sqlite-source/opcodes.c index 0b623599..ac283bd7 100644 --- a/extensions/sqlite/sqlite-source/opcodes.c +++ b/extensions/sqlite/sqlite-source/opcodes.c @@ -1,148 +1,151 @@ /* Automatically generated. Do not edit */ /* See the mkopcodec.awk script for details. */ #if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) -const char *const sqlite3OpcodeNames[] = { "?", - /* 1 */ "MemLoad", - /* 2 */ "VNext", - /* 3 */ "Column", - /* 4 */ "SetCookie", - /* 5 */ "IfMemPos", - /* 6 */ "Sequence", - /* 7 */ "MoveGt", - /* 8 */ "RowKey", - /* 9 */ "OpenWrite", - /* 10 */ "If", - /* 11 */ "Pop", - /* 12 */ "VRowid", - /* 13 */ "CollSeq", - /* 14 */ "OpenRead", - /* 15 */ "Expire", - /* 16 */ "Not", - /* 17 */ "AutoCommit", - /* 18 */ "IntegrityCk", - /* 19 */ "Sort", - /* 20 */ "Function", - /* 21 */ "Noop", - /* 22 */ "Return", - /* 23 */ "NewRowid", - /* 24 */ "IfMemNeg", - /* 25 */ "Variable", - /* 26 */ "String", - /* 27 */ "RealAffinity", - /* 28 */ "VRename", - /* 29 */ "ParseSchema", - /* 30 */ "VOpen", - /* 31 */ "Close", - /* 32 */ "CreateIndex", - /* 33 */ "IsUnique", - /* 34 */ "NotFound", - /* 35 */ "Int64", - /* 36 */ "MustBeInt", - /* 37 */ "Halt", - /* 38 */ "Rowid", - /* 39 */ "IdxLT", - /* 40 */ "AddImm", - /* 41 */ "Statement", - /* 42 */ "RowData", - /* 43 */ "MemMax", - /* 44 */ "Push", - /* 45 */ "NotExists", - /* 46 */ "MemIncr", - /* 47 */ "Gosub", - /* 48 */ "Integer", - /* 49 */ "MemInt", - /* 50 */ "Prev", - /* 51 */ "VColumn", - /* 52 */ "CreateTable", - /* 53 */ "Last", - /* 54 */ "IncrVacuum", - /* 55 */ "IdxRowid", - /* 56 */ "MakeIdxRec", - /* 57 */ "ResetCount", - /* 58 */ "FifoWrite", - /* 59 */ "Callback", - /* 60 */ "Or", - /* 61 */ "And", - /* 62 */ "ContextPush", - /* 63 */ "DropTrigger", - /* 64 */ "DropIndex", - /* 65 */ "IsNull", - /* 66 */ "NotNull", - /* 67 */ "Ne", - /* 68 */ "Eq", - /* 69 */ "Gt", - /* 70 */ "Le", - /* 71 */ "Lt", - /* 72 */ "Ge", - /* 73 */ "IdxGE", - /* 74 */ "BitAnd", - /* 75 */ "BitOr", - /* 76 */ "ShiftLeft", - /* 77 */ "ShiftRight", - /* 78 */ "Add", - /* 79 */ "Subtract", - /* 80 */ "Multiply", - /* 81 */ "Divide", - /* 82 */ "Remainder", - /* 83 */ "Concat", - /* 84 */ "IdxDelete", - /* 85 */ "Negative", - /* 86 */ "Vacuum", - /* 87 */ "BitNot", - /* 88 */ "String8", - /* 89 */ "MoveLe", - /* 90 */ "IfNot", - /* 91 */ "DropTable", - /* 92 */ "MakeRecord", - /* 93 */ "Delete", - /* 94 */ "AggFinal", - /* 95 */ "Dup", - /* 96 */ "Goto", - /* 97 */ "TableLock", - /* 98 */ "FifoRead", - /* 99 */ "Clear", - /* 100 */ "IdxGT", - /* 101 */ "MoveLt", - /* 102 */ "VerifyCookie", - /* 103 */ "AggStep", - /* 104 */ "Pull", - /* 105 */ "SetNumColumns", - /* 106 */ "AbsValue", - /* 107 */ "Transaction", - /* 108 */ "VFilter", - /* 109 */ "VDestroy", - /* 110 */ "ContextPop", - /* 111 */ "Next", - /* 112 */ "IdxInsert", - /* 113 */ "Distinct", - /* 114 */ "Insert", - /* 115 */ "Destroy", - /* 116 */ "ReadCookie", - /* 117 */ "ForceInt", - /* 118 */ "LoadAnalysis", - /* 119 */ "Explain", - /* 120 */ "IfMemZero", - /* 121 */ "OpenPseudo", - /* 122 */ "OpenEphemeral", - /* 123 */ "Null", - /* 124 */ "Blob", - /* 125 */ "Real", - /* 126 */ "HexBlob", - /* 127 */ "MemStore", - /* 128 */ "Rewind", - /* 129 */ "MoveGe", - /* 130 */ "VBegin", - /* 131 */ "VUpdate", - /* 132 */ "VCreate", - /* 133 */ "MemMove", - /* 134 */ "MemNull", - /* 135 */ "Found", - /* 136 */ "NullRow", - /* 137 */ "NotUsed_137", - /* 138 */ "ToText", - /* 139 */ "ToBlob", - /* 140 */ "ToNumeric", - /* 141 */ "ToInt", - /* 142 */ "ToReal", -}; +const char *sqlite3OpcodeName(int i){ + static const char *const azName[] = { "?", + /* 1 */ "MemLoad", + /* 2 */ "VNext", + /* 3 */ "Column", + /* 4 */ "SetCookie", + /* 5 */ "IfMemPos", + /* 6 */ "Sequence", + /* 7 */ "MoveGt", + /* 8 */ "RowKey", + /* 9 */ "OpenWrite", + /* 10 */ "If", + /* 11 */ "Pop", + /* 12 */ "VRowid", + /* 13 */ "CollSeq", + /* 14 */ "OpenRead", + /* 15 */ "Expire", + /* 16 */ "Not", + /* 17 */ "AutoCommit", + /* 18 */ "IntegrityCk", + /* 19 */ "Sort", + /* 20 */ "Function", + /* 21 */ "Noop", + /* 22 */ "Return", + /* 23 */ "NewRowid", + /* 24 */ "IfMemNeg", + /* 25 */ "Variable", + /* 26 */ "String", + /* 27 */ "RealAffinity", + /* 28 */ "VRename", + /* 29 */ "ParseSchema", + /* 30 */ "VOpen", + /* 31 */ "Close", + /* 32 */ "CreateIndex", + /* 33 */ "IsUnique", + /* 34 */ "NotFound", + /* 35 */ "Int64", + /* 36 */ "MustBeInt", + /* 37 */ "Halt", + /* 38 */ "Rowid", + /* 39 */ "IdxLT", + /* 40 */ "AddImm", + /* 41 */ "Statement", + /* 42 */ "RowData", + /* 43 */ "MemMax", + /* 44 */ "Push", + /* 45 */ "NotExists", + /* 46 */ "MemIncr", + /* 47 */ "Gosub", + /* 48 */ "Integer", + /* 49 */ "MemInt", + /* 50 */ "Prev", + /* 51 */ "VColumn", + /* 52 */ "CreateTable", + /* 53 */ "Last", + /* 54 */ "IncrVacuum", + /* 55 */ "IdxRowid", + /* 56 */ "MakeIdxRec", + /* 57 */ "ResetCount", + /* 58 */ "FifoWrite", + /* 59 */ "Callback", + /* 60 */ "Or", + /* 61 */ "And", + /* 62 */ "ContextPush", + /* 63 */ "DropTrigger", + /* 64 */ "DropIndex", + /* 65 */ "IsNull", + /* 66 */ "NotNull", + /* 67 */ "Ne", + /* 68 */ "Eq", + /* 69 */ "Gt", + /* 70 */ "Le", + /* 71 */ "Lt", + /* 72 */ "Ge", + /* 73 */ "IdxGE", + /* 74 */ "BitAnd", + /* 75 */ "BitOr", + /* 76 */ "ShiftLeft", + /* 77 */ "ShiftRight", + /* 78 */ "Add", + /* 79 */ "Subtract", + /* 80 */ "Multiply", + /* 81 */ "Divide", + /* 82 */ "Remainder", + /* 83 */ "Concat", + /* 84 */ "IdxDelete", + /* 85 */ "Negative", + /* 86 */ "Vacuum", + /* 87 */ "BitNot", + /* 88 */ "String8", + /* 89 */ "MoveLe", + /* 90 */ "IfNot", + /* 91 */ "DropTable", + /* 92 */ "MakeRecord", + /* 93 */ "Delete", + /* 94 */ "AggFinal", + /* 95 */ "Dup", + /* 96 */ "Goto", + /* 97 */ "TableLock", + /* 98 */ "FifoRead", + /* 99 */ "Clear", + /* 100 */ "IdxGT", + /* 101 */ "MoveLt", + /* 102 */ "VerifyCookie", + /* 103 */ "AggStep", + /* 104 */ "Pull", + /* 105 */ "SetNumColumns", + /* 106 */ "AbsValue", + /* 107 */ "Transaction", + /* 108 */ "VFilter", + /* 109 */ "VDestroy", + /* 110 */ "ContextPop", + /* 111 */ "Next", + /* 112 */ "IdxInsert", + /* 113 */ "Distinct", + /* 114 */ "Insert", + /* 115 */ "Destroy", + /* 116 */ "ReadCookie", + /* 117 */ "ForceInt", + /* 118 */ "LoadAnalysis", + /* 119 */ "Explain", + /* 120 */ "IfMemZero", + /* 121 */ "OpenPseudo", + /* 122 */ "OpenEphemeral", + /* 123 */ "Null", + /* 124 */ "Blob", + /* 125 */ "Real", + /* 126 */ "HexBlob", + /* 127 */ "MemStore", + /* 128 */ "Rewind", + /* 129 */ "MoveGe", + /* 130 */ "VBegin", + /* 131 */ "VUpdate", + /* 132 */ "VCreate", + /* 133 */ "MemMove", + /* 134 */ "MemNull", + /* 135 */ "Found", + /* 136 */ "NullRow", + /* 137 */ "NotUsed_137", + /* 138 */ "ToText", + /* 139 */ "ToBlob", + /* 140 */ "ToNumeric", + /* 141 */ "ToInt", + /* 142 */ "ToReal", + }; + return azName[i]; +} #endif diff --git a/extensions/sqlite/sqlite-source/os.c b/extensions/sqlite/sqlite-source/os.c index 7cd1ab99..3b6ca7bc 100644 --- a/extensions/sqlite/sqlite-source/os.c +++ b/extensions/sqlite/sqlite-source/os.c @@ -1,4 +1,4 @@ -/* + /* ** 2005 November 29 ** ** The author disclaims copyright to this source code. In place of @@ -15,82 +15,268 @@ */ #define _SQLITE_OS_C_ 1 #include "sqliteInt.h" -#include "os.h" #undef _SQLITE_OS_C_ +/* +** The default SQLite sqlite3_vfs implementations do not allocate +** memory (actually, os_unix.c allocates a small amount of memory +** from within OsOpen()), but some third-party implementations may. +** So we test the effects of a malloc() failing and the sqlite3OsXXX() +** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro. +** +** The following functions are instrumented for malloc() failure +** testing: +** +** sqlite3OsOpen() +** sqlite3OsRead() +** sqlite3OsWrite() +** sqlite3OsSync() +** sqlite3OsLock() +** +*/ +#ifdef SQLITE_TEST + #define DO_OS_MALLOC_TEST if (1) { \ + void *pTstAlloc = sqlite3_malloc(10); \ + if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \ + sqlite3_free(pTstAlloc); \ + } +#else + #define DO_OS_MALLOC_TEST +#endif + /* ** The following routines are convenience wrappers around methods -** of the OsFile object. This is mostly just syntactic sugar. All +** of the sqlite3_file object. This is mostly just syntactic sugar. All ** of this would be completely automatic if SQLite were coded using ** C++ instead of plain old C. */ -int sqlite3OsClose(OsFile **pId){ - OsFile *id; - if( pId!=0 && (id = *pId)!=0 ){ - return id->pMethod->xClose(pId); - }else{ - return SQLITE_OK; +int sqlite3OsClose(sqlite3_file *pId){ + int rc = SQLITE_OK; + if( pId->pMethods ){ + rc = pId->pMethods->xClose(pId); + pId->pMethods = 0; } + return rc; } -int sqlite3OsOpenDirectory(OsFile *id, const char *zName){ - return id->pMethod->xOpenDirectory(id, zName); +int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){ + DO_OS_MALLOC_TEST; + return id->pMethods->xRead(id, pBuf, amt, offset); } -int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ - return id->pMethod->xRead(id, pBuf, amt); +int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){ + DO_OS_MALLOC_TEST; + return id->pMethods->xWrite(id, pBuf, amt, offset); } -int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ - return id->pMethod->xWrite(id, pBuf, amt); +int sqlite3OsTruncate(sqlite3_file *id, i64 size){ + return id->pMethods->xTruncate(id, size); } -int sqlite3OsSeek(OsFile *id, i64 offset){ - return id->pMethod->xSeek(id, offset); +int sqlite3OsSync(sqlite3_file *id, int flags){ + DO_OS_MALLOC_TEST; + return id->pMethods->xSync(id, flags); } -int sqlite3OsTruncate(OsFile *id, i64 size){ - return id->pMethod->xTruncate(id, size); +int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ + return id->pMethods->xFileSize(id, pSize); } -int sqlite3OsSync(OsFile *id, int fullsync){ - return id->pMethod->xSync(id, fullsync); +int sqlite3OsLock(sqlite3_file *id, int lockType){ + DO_OS_MALLOC_TEST; + return id->pMethods->xLock(id, lockType); } -void sqlite3OsSetFullSync(OsFile *id, int value){ - id->pMethod->xSetFullSync(id, value); +int sqlite3OsUnlock(sqlite3_file *id, int lockType){ + return id->pMethods->xUnlock(id, lockType); } -int sqlite3OsFileSize(OsFile *id, i64 *pSize){ - return id->pMethod->xFileSize(id, pSize); +int sqlite3OsCheckReservedLock(sqlite3_file *id){ + return id->pMethods->xCheckReservedLock(id); } -int sqlite3OsLock(OsFile *id, int lockType){ - return id->pMethod->xLock(id, lockType); -} -int sqlite3OsUnlock(OsFile *id, int lockType){ - return id->pMethod->xUnlock(id, lockType); -} -int sqlite3OsCheckReservedLock(OsFile *id){ - return id->pMethod->xCheckReservedLock(id); -} -int sqlite3OsSectorSize(OsFile *id){ - int (*xSectorSize)(OsFile*) = id->pMethod->xSectorSize; - return xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE; +int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ + return id->pMethods->xFileControl(id,op,pArg); } -#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) - /* These methods are currently only used for testing and debugging. */ - int sqlite3OsFileHandle(OsFile *id){ - return id->pMethod->xFileHandle(id); +#ifdef SQLITE_TEST + /* The following two variables are used to override the values returned + ** by the xSectorSize() and xDeviceCharacteristics() vfs methods for + ** testing purposes. They are usually set by a test command implemented + ** in test6.c. + */ + int sqlite3_test_sector_size = 0; + int sqlite3_test_device_characteristics = 0; + int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ + int dc = id->pMethods->xDeviceCharacteristics(id); + return dc | sqlite3_test_device_characteristics; } - int sqlite3OsLockState(OsFile *id){ - return id->pMethod->xLockState(id); + int sqlite3OsSectorSize(sqlite3_file *id){ + if( sqlite3_test_sector_size==0 ){ + int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; + return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); + } + return sqlite3_test_sector_size; + } +#else + int sqlite3OsSectorSize(sqlite3_file *id){ + int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; + return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); + } + int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ + return id->pMethods->xDeviceCharacteristics(id); } #endif -#ifdef SQLITE_ENABLE_REDEF_IO /* -** A function to return a pointer to the virtual function table. -** This routine really does not accomplish very much since the -** virtual function table is a global variable and anybody who -** can call this function can just as easily access the variable -** for themselves. Nevertheless, we include this routine for -** backwards compatibility with an earlier redefinable I/O -** interface design. +** The next group of routines are convenience wrappers around the +** VFS methods. */ -struct sqlite3OsVtbl *sqlite3_os_switch(void){ - return &sqlite3Os; +int sqlite3OsOpen( + sqlite3_vfs *pVfs, + const char *zPath, + sqlite3_file *pFile, + int flags, + int *pFlagsOut +){ + DO_OS_MALLOC_TEST; + return pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut); +} +int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ + return pVfs->xDelete(pVfs, zPath, dirSync); +} +int sqlite3OsAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){ + return pVfs->xAccess(pVfs, zPath, flags); +} +int sqlite3OsGetTempname(sqlite3_vfs *pVfs, int nBufOut, char *zBufOut){ + return pVfs->xGetTempname(pVfs, nBufOut, zBufOut); +} +int sqlite3OsFullPathname( + sqlite3_vfs *pVfs, + const char *zPath, + int nPathOut, + char *zPathOut +){ + return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut); +} +void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ + return pVfs->xDlOpen(pVfs, zPath); +} +void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ + pVfs->xDlError(pVfs, nByte, zBufOut); +} +void *sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ + return pVfs->xDlSym(pVfs, pHandle, zSymbol); +} +void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){ + pVfs->xDlClose(pVfs, pHandle); +} +int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ + return pVfs->xRandomness(pVfs, nByte, zBufOut); +} +int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){ + return pVfs->xSleep(pVfs, nMicro); +} +int sqlite3OsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ + return pVfs->xCurrentTime(pVfs, pTimeOut); +} + +int sqlite3OsOpenMalloc( + sqlite3_vfs *pVfs, + const char *zFile, + sqlite3_file **ppFile, + int flags, + int *pOutFlags +){ + int rc = SQLITE_NOMEM; + sqlite3_file *pFile; + pFile = (sqlite3_file *)sqlite3_malloc(pVfs->szOsFile); + if( pFile ){ + rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); + if( rc!=SQLITE_OK ){ + sqlite3_free(pFile); + }else{ + *ppFile = pFile; + } + } + return rc; +} +int sqlite3OsCloseFree(sqlite3_file *pFile){ + int rc = SQLITE_OK; + if( pFile ){ + rc = sqlite3OsClose(pFile); + sqlite3_free(pFile); + } + return rc; +} + +/* +** The list of all registered VFS implementations. This list is +** initialized to the single VFS returned by sqlite3OsDefaultVfs() +** upon the first call to sqlite3_vfs_find(). +*/ +static sqlite3_vfs *vfsList = 0; + +/* +** Locate a VFS by name. If no name is given, simply return the +** first VFS on the list. +*/ +sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){ + sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_vfs *pVfs; + static int isInit = 0; + sqlite3_mutex_enter(mutex); + if( !isInit ){ + vfsList = sqlite3OsDefaultVfs(); + isInit = 1; + } + for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){ + if( zVfs==0 ) break; + if( strcmp(zVfs, pVfs->zName)==0 ) break; + } + sqlite3_mutex_leave(mutex); + return pVfs; +} + +/* +** Unlink a VFS from the linked list +*/ +static void vfsUnlink(sqlite3_vfs *pVfs){ + assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) ); + if( vfsList==pVfs ){ + vfsList = pVfs->pNext; + }else{ + sqlite3_vfs *p = vfsList; + while( p->pNext && p->pNext!=pVfs ){ + p = p->pNext; + } + if( p->pNext==pVfs ){ + p->pNext = pVfs->pNext; + } + } +} + +/* +** Register a VFS with the system. It is harmless to register the same +** VFS multiple times. The new VFS becomes the default if makeDflt is +** true. +*/ +int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ + sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_vfs_find(0); /* Make sure we are initialized */ + sqlite3_mutex_enter(mutex); + vfsUnlink(pVfs); + if( makeDflt || vfsList==0 ){ + pVfs->pNext = vfsList; + vfsList = pVfs; + }else{ + pVfs->pNext = vfsList->pNext; + vfsList->pNext = pVfs; + } + assert(vfsList); + sqlite3_mutex_leave(mutex); + return SQLITE_OK; +} + +/* +** Unregister a VFS so that it is no longer accessible. +*/ +int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ + sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex_enter(mutex); + vfsUnlink(pVfs); + assert(vfsList); + sqlite3_mutex_leave(mutex); + return SQLITE_OK; } -#endif diff --git a/extensions/sqlite/sqlite-source/os.h b/extensions/sqlite/sqlite-source/os.h index 76a9f2c4..554952df 100644 --- a/extensions/sqlite/sqlite-source/os.h +++ b/extensions/sqlite/sqlite-source/os.h @@ -13,13 +13,18 @@ ** This header file (together with is companion C source-code file ** "os.c") attempt to abstract the underlying operating system so that ** the SQLite library will work on both POSIX and windows systems. +** +** This header file is #include-ed by sqliteInt.h and thus ends up +** being included by every source file. */ #ifndef _SQLITE_OS_H_ #define _SQLITE_OS_H_ /* ** Figure out if we are dealing with Unix, Windows, or some other -** operating system. +** operating system. After the following block of preprocess macros, +** all of OS_UNIX, OS_WIN, OS_OS2, and OS_OTHER will defined to either +** 1 or 0. One of the four will be 1. The other three will be 0. */ #if defined(OS_OTHER) # if OS_OTHER==1 @@ -60,6 +65,7 @@ #endif + /* ** Define the maximum size of a temporary filename */ @@ -103,7 +109,7 @@ ** If sqlite is being embedded in another program, you may wish to change the ** prefix to reflect your program's name, so that if your program exits ** prematurely, old temporary files can be easily identified. This can be done -** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line. +** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line. ** ** 2006-10-31: The default prefix used to be "sqlite_". But then ** Mcafee started using SQLite in their anti-virus product and it @@ -117,92 +123,10 @@ ** enough to know that calling the developer will not help get rid ** of the file. */ -#ifndef TEMP_FILE_PREFIX -# define TEMP_FILE_PREFIX "etilqs_" +#ifndef SQLITE_TEMP_FILE_PREFIX +# define SQLITE_TEMP_FILE_PREFIX "etilqs_" #endif -/* -** Define the interfaces for Unix, Windows, and OS/2. -*/ -#if OS_UNIX -#define sqlite3OsOpenReadWrite sqlite3UnixOpenReadWrite -#define sqlite3OsOpenExclusive sqlite3UnixOpenExclusive -#define sqlite3OsOpenReadOnly sqlite3UnixOpenReadOnly -#define sqlite3OsDelete sqlite3UnixDelete -#define sqlite3OsFileExists sqlite3UnixFileExists -#define sqlite3OsFullPathname sqlite3UnixFullPathname -#define sqlite3OsIsDirWritable sqlite3UnixIsDirWritable -#define sqlite3OsSyncDirectory sqlite3UnixSyncDirectory -#define sqlite3OsTempFileName sqlite3UnixTempFileName -#define sqlite3OsRandomSeed sqlite3UnixRandomSeed -#define sqlite3OsSleep sqlite3UnixSleep -#define sqlite3OsCurrentTime sqlite3UnixCurrentTime -#define sqlite3OsEnterMutex sqlite3UnixEnterMutex -#define sqlite3OsLeaveMutex sqlite3UnixLeaveMutex -#define sqlite3OsInMutex sqlite3UnixInMutex -#define sqlite3OsThreadSpecificData sqlite3UnixThreadSpecificData -#define sqlite3OsMalloc sqlite3GenericMalloc -#define sqlite3OsRealloc sqlite3GenericRealloc -#define sqlite3OsFree sqlite3GenericFree -#define sqlite3OsAllocationSize sqlite3GenericAllocationSize -#define sqlite3OsDlopen sqlite3UnixDlopen -#define sqlite3OsDlsym sqlite3UnixDlsym -#define sqlite3OsDlclose sqlite3UnixDlclose -#endif -#if OS_WIN -#define sqlite3OsOpenReadWrite sqlite3WinOpenReadWrite -#define sqlite3OsOpenExclusive sqlite3WinOpenExclusive -#define sqlite3OsOpenReadOnly sqlite3WinOpenReadOnly -#define sqlite3OsDelete sqlite3WinDelete -#define sqlite3OsFileExists sqlite3WinFileExists -#define sqlite3OsFullPathname sqlite3WinFullPathname -#define sqlite3OsIsDirWritable sqlite3WinIsDirWritable -#define sqlite3OsSyncDirectory sqlite3WinSyncDirectory -#define sqlite3OsTempFileName sqlite3WinTempFileName -#define sqlite3OsRandomSeed sqlite3WinRandomSeed -#define sqlite3OsSleep sqlite3WinSleep -#define sqlite3OsCurrentTime sqlite3WinCurrentTime -#define sqlite3OsEnterMutex sqlite3WinEnterMutex -#define sqlite3OsLeaveMutex sqlite3WinLeaveMutex -#define sqlite3OsInMutex sqlite3WinInMutex -#define sqlite3OsThreadSpecificData sqlite3WinThreadSpecificData -#define sqlite3OsMalloc sqlite3GenericMalloc -#define sqlite3OsRealloc sqlite3GenericRealloc -#define sqlite3OsFree sqlite3GenericFree -#define sqlite3OsAllocationSize sqlite3GenericAllocationSize -#define sqlite3OsDlopen sqlite3WinDlopen -#define sqlite3OsDlsym sqlite3WinDlsym -#define sqlite3OsDlclose sqlite3WinDlclose -#endif -#if OS_OS2 -#define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite -#define sqlite3OsOpenExclusive sqlite3Os2OpenExclusive -#define sqlite3OsOpenReadOnly sqlite3Os2OpenReadOnly -#define sqlite3OsDelete sqlite3Os2Delete -#define sqlite3OsFileExists sqlite3Os2FileExists -#define sqlite3OsFullPathname sqlite3Os2FullPathname -#define sqlite3OsIsDirWritable sqlite3Os2IsDirWritable -#define sqlite3OsSyncDirectory sqlite3Os2SyncDirectory -#define sqlite3OsTempFileName sqlite3Os2TempFileName -#define sqlite3OsRandomSeed sqlite3Os2RandomSeed -#define sqlite3OsSleep sqlite3Os2Sleep -#define sqlite3OsCurrentTime sqlite3Os2CurrentTime -#define sqlite3OsEnterMutex sqlite3Os2EnterMutex -#define sqlite3OsLeaveMutex sqlite3Os2LeaveMutex -#define sqlite3OsInMutex sqlite3Os2InMutex -#define sqlite3OsThreadSpecificData sqlite3Os2ThreadSpecificData -#define sqlite3OsMalloc sqlite3GenericMalloc -#define sqlite3OsRealloc sqlite3GenericRealloc -#define sqlite3OsFree sqlite3GenericFree -#define sqlite3OsAllocationSize sqlite3GenericAllocationSize -#define sqlite3OsDlopen sqlite3Os2Dlopen -#define sqlite3OsDlsym sqlite3Os2Dlsym -#define sqlite3OsDlclose sqlite3Os2Dlclose -#endif - - - - /* ** If using an alternative OS interface, then we must have an "os_other.h" ** header file available for that interface. Presumably the "os_other.h" @@ -213,47 +137,6 @@ #endif - -/* -** Forward declarations -*/ -typedef struct OsFile OsFile; -typedef struct IoMethod IoMethod; - -/* -** An instance of the following structure contains pointers to all -** methods on an OsFile object. -*/ -struct IoMethod { - int (*xClose)(OsFile**); - int (*xOpenDirectory)(OsFile*, const char*); - int (*xRead)(OsFile*, void*, int amt); - int (*xWrite)(OsFile*, const void*, int amt); - int (*xSeek)(OsFile*, i64 offset); - int (*xTruncate)(OsFile*, i64 size); - int (*xSync)(OsFile*, int); - void (*xSetFullSync)(OsFile *id, int setting); - int (*xFileHandle)(OsFile *id); - int (*xFileSize)(OsFile*, i64 *pSize); - int (*xLock)(OsFile*, int); - int (*xUnlock)(OsFile*, int); - int (*xLockState)(OsFile *id); - int (*xCheckReservedLock)(OsFile *id); - int (*xSectorSize)(OsFile *id); -}; - -/* -** The OsFile object describes an open disk file in an OS-dependent way. -** The version of OsFile defined here is a generic version. Each OS -** implementation defines its own subclass of this structure that contains -** additional information needed to handle file I/O. But the pMethod -** entry (pointing to the virtual function table) always occurs first -** so that we can always find the appropriate methods. -*/ -struct OsFile { - IoMethod const *pMethod; -}; - /* ** The following values may be passed as the second argument to ** sqlite3OsLock(). The various locks exhibit the following semantics: @@ -345,204 +228,57 @@ extern unsigned int sqlite3_pending_byte; #define SHARED_FIRST (PENDING_BYTE+2) #define SHARED_SIZE 510 -/* -** Prototypes for operating system interface routines. +/* +** Functions for accessing sqlite3_file methods */ -int sqlite3OsClose(OsFile**); -int sqlite3OsOpenDirectory(OsFile*, const char*); -int sqlite3OsRead(OsFile*, void*, int amt); -int sqlite3OsWrite(OsFile*, const void*, int amt); -int sqlite3OsSeek(OsFile*, i64 offset); -int sqlite3OsTruncate(OsFile*, i64 size); -int sqlite3OsSync(OsFile*, int); -void sqlite3OsSetFullSync(OsFile *id, int setting); -int sqlite3OsFileSize(OsFile*, i64 *pSize); -int sqlite3OsLock(OsFile*, int); -int sqlite3OsUnlock(OsFile*, int); -int sqlite3OsCheckReservedLock(OsFile *id); -int sqlite3OsOpenReadWrite(const char*, OsFile**, int*); -int sqlite3OsOpenExclusive(const char*, OsFile**, int); -int sqlite3OsOpenReadOnly(const char*, OsFile**); -int sqlite3OsDelete(const char*); -int sqlite3OsFileExists(const char*); -char *sqlite3OsFullPathname(const char*); -int sqlite3OsIsDirWritable(char*); -int sqlite3OsSyncDirectory(const char*); -int sqlite3OsSectorSize(OsFile *id); -int sqlite3OsTempFileName(char*); -int sqlite3OsRandomSeed(char*); -int sqlite3OsSleep(int ms); -int sqlite3OsCurrentTime(double*); -void sqlite3OsEnterMutex(void); -void sqlite3OsLeaveMutex(void); -int sqlite3OsInMutex(int); -ThreadData *sqlite3OsThreadSpecificData(int); -void *sqlite3OsMalloc(int); -void *sqlite3OsRealloc(void *, int); -void sqlite3OsFree(void *); -int sqlite3OsAllocationSize(void *); -void *sqlite3OsDlopen(const char*); -void *sqlite3OsDlsym(void*, const char*); -int sqlite3OsDlclose(void*); +int sqlite3OsClose(sqlite3_file*); +int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); +int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset); +int sqlite3OsTruncate(sqlite3_file*, i64 size); +int sqlite3OsSync(sqlite3_file*, int); +int sqlite3OsFileSize(sqlite3_file*, i64 *pSize); +int sqlite3OsLock(sqlite3_file*, int); +int sqlite3OsUnlock(sqlite3_file*, int); +int sqlite3OsCheckReservedLock(sqlite3_file *id); +int sqlite3OsFileControl(sqlite3_file*,int,void*); +int sqlite3OsSectorSize(sqlite3_file *id); +int sqlite3OsDeviceCharacteristics(sqlite3_file *id); -#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) - int sqlite3OsFileHandle(OsFile *id); - int sqlite3OsLockState(OsFile *id); -#endif +/* +** Functions for accessing sqlite3_vfs methods +*/ +int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); +int sqlite3OsDelete(sqlite3_vfs *, const char *, int); +int sqlite3OsAccess(sqlite3_vfs *, const char *, int); +int sqlite3OsGetTempname(sqlite3_vfs *, int, char *); +int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *); +void *sqlite3OsDlOpen(sqlite3_vfs *, const char *); +void sqlite3OsDlError(sqlite3_vfs *, int, char *); +void *sqlite3OsDlSym(sqlite3_vfs *, void *, const char *); +void sqlite3OsDlClose(sqlite3_vfs *, void *); +int sqlite3OsRandomness(sqlite3_vfs *, int, char *); +int sqlite3OsSleep(sqlite3_vfs *, int); +int sqlite3OsCurrentTime(sqlite3_vfs *, double*); /* -** If the SQLITE_ENABLE_REDEF_IO macro is defined, then the OS-layer -** interface routines are not called directly but are invoked using -** pointers to functions. This allows the implementation of various -** OS-layer interface routines to be modified at run-time. There are -** obscure but legitimate reasons for wanting to do this. But for -** most users, a direct call to the underlying interface is preferable -** so the the redefinable I/O interface is turned off by default. +** Convenience functions for opening and closing files using +** sqlite3_malloc() to obtain space for the file-handle structure. */ -#ifdef SQLITE_ENABLE_REDEF_IO +int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*); +int sqlite3OsCloseFree(sqlite3_file *); /* -** When redefinable I/O is enabled, a single global instance of the -** following structure holds pointers to the routines that SQLite -** uses to talk with the underlying operating system. Modify this -** structure (before using any SQLite API!) to accomodate perculiar -** operating system interfaces or behaviors. +** Each OS-specific backend defines an instance of the following +** structure for returning a pointer to its sqlite3_vfs. If OS_OTHER +** is defined (meaning that the application-defined OS interface layer +** is used) then there is no default VFS. The application must +** register one or more VFS structures using sqlite3_vfs_register() +** before attempting to use SQLite. */ -struct sqlite3OsVtbl { - int (*xOpenReadWrite)(const char*, OsFile**, int*); - int (*xOpenExclusive)(const char*, OsFile**, int); - int (*xOpenReadOnly)(const char*, OsFile**); - - int (*xDelete)(const char*); - int (*xFileExists)(const char*); - char *(*xFullPathname)(const char*); - int (*xIsDirWritable)(char*); - int (*xSyncDirectory)(const char*); - int (*xTempFileName)(char*); - - int (*xRandomSeed)(char*); - int (*xSleep)(int ms); - int (*xCurrentTime)(double*); - - void (*xEnterMutex)(void); - void (*xLeaveMutex)(void); - int (*xInMutex)(int); - ThreadData *(*xThreadSpecificData)(int); - - void *(*xMalloc)(int); - void *(*xRealloc)(void *, int); - void (*xFree)(void *); - int (*xAllocationSize)(void *); - - void *(*xDlopen)(const char*); - void *(*xDlsym)(void*, const char*); - int (*xDlclose)(void*); -}; - -/* Macro used to comment out routines that do not exists when there is -** no disk I/O or extension loading -*/ -#ifdef SQLITE_OMIT_DISKIO -# define IF_DISKIO(X) 0 +#if OS_UNIX || OS_WIN || OS_OS2 +sqlite3_vfs *sqlite3OsDefaultVfs(void); #else -# define IF_DISKIO(X) X +# define sqlite3OsDefaultVfs(X) 0 #endif -#ifdef SQLITE_OMIT_LOAD_EXTENSION -# define IF_DLOPEN(X) 0 -#else -# define IF_DLOPEN(X) X -#endif - - -#if defined(_SQLITE_OS_C_) || defined(SQLITE_AMALGAMATION) - /* - ** The os.c file implements the global virtual function table. - ** We have to put this file here because the initializers - ** (ex: sqlite3OsRandomSeed) are macros that are about to be - ** redefined. - */ - struct sqlite3OsVtbl sqlite3Os = { - IF_DISKIO( sqlite3OsOpenReadWrite ), - IF_DISKIO( sqlite3OsOpenExclusive ), - IF_DISKIO( sqlite3OsOpenReadOnly ), - IF_DISKIO( sqlite3OsDelete ), - IF_DISKIO( sqlite3OsFileExists ), - IF_DISKIO( sqlite3OsFullPathname ), - IF_DISKIO( sqlite3OsIsDirWritable ), - IF_DISKIO( sqlite3OsSyncDirectory ), - IF_DISKIO( sqlite3OsTempFileName ), - sqlite3OsRandomSeed, - sqlite3OsSleep, - sqlite3OsCurrentTime, - sqlite3OsEnterMutex, - sqlite3OsLeaveMutex, - sqlite3OsInMutex, - sqlite3OsThreadSpecificData, - sqlite3OsMalloc, - sqlite3OsRealloc, - sqlite3OsFree, - sqlite3OsAllocationSize, - IF_DLOPEN( sqlite3OsDlopen ), - IF_DLOPEN( sqlite3OsDlsym ), - IF_DLOPEN( sqlite3OsDlclose ), - }; -#else - /* - ** Files other than os.c just reference the global virtual function table. - */ - extern struct sqlite3OsVtbl sqlite3Os; -#endif /* _SQLITE_OS_C_ */ - - -/* This additional API routine is available with redefinable I/O */ -struct sqlite3OsVtbl *sqlite3_os_switch(void); - - -/* -** Redefine the OS interface to go through the virtual function table -** rather than calling routines directly. -*/ -#undef sqlite3OsOpenReadWrite -#undef sqlite3OsOpenExclusive -#undef sqlite3OsOpenReadOnly -#undef sqlite3OsDelete -#undef sqlite3OsFileExists -#undef sqlite3OsFullPathname -#undef sqlite3OsIsDirWritable -#undef sqlite3OsSyncDirectory -#undef sqlite3OsTempFileName -#undef sqlite3OsRandomSeed -#undef sqlite3OsSleep -#undef sqlite3OsCurrentTime -#undef sqlite3OsEnterMutex -#undef sqlite3OsLeaveMutex -#undef sqlite3OsInMutex -#undef sqlite3OsThreadSpecificData -#undef sqlite3OsMalloc -#undef sqlite3OsRealloc -#undef sqlite3OsFree -#undef sqlite3OsAllocationSize -#define sqlite3OsOpenReadWrite sqlite3Os.xOpenReadWrite -#define sqlite3OsOpenExclusive sqlite3Os.xOpenExclusive -#define sqlite3OsOpenReadOnly sqlite3Os.xOpenReadOnly -#define sqlite3OsDelete sqlite3Os.xDelete -#define sqlite3OsFileExists sqlite3Os.xFileExists -#define sqlite3OsFullPathname sqlite3Os.xFullPathname -#define sqlite3OsIsDirWritable sqlite3Os.xIsDirWritable -#define sqlite3OsSyncDirectory sqlite3Os.xSyncDirectory -#define sqlite3OsTempFileName sqlite3Os.xTempFileName -#define sqlite3OsRandomSeed sqlite3Os.xRandomSeed -#define sqlite3OsSleep sqlite3Os.xSleep -#define sqlite3OsCurrentTime sqlite3Os.xCurrentTime -#define sqlite3OsEnterMutex sqlite3Os.xEnterMutex -#define sqlite3OsLeaveMutex sqlite3Os.xLeaveMutex -#define sqlite3OsInMutex sqlite3Os.xInMutex -#define sqlite3OsThreadSpecificData sqlite3Os.xThreadSpecificData -#define sqlite3OsMalloc sqlite3Os.xMalloc -#define sqlite3OsRealloc sqlite3Os.xRealloc -#define sqlite3OsFree sqlite3Os.xFree -#define sqlite3OsAllocationSize sqlite3Os.xAllocationSize - -#endif /* SQLITE_ENABLE_REDEF_IO */ #endif /* _SQLITE_OS_H_ */ diff --git a/extensions/sqlite/sqlite-source/os_common.h b/extensions/sqlite/sqlite-source/os_common.h index ba52314c..8de4be97 100644 --- a/extensions/sqlite/sqlite-source/os_common.h +++ b/extensions/sqlite/sqlite-source/os_common.h @@ -36,8 +36,8 @@ unsigned int sqlite3_pending_byte = 0x40000000; #endif -int sqlite3_os_trace = 0; #ifdef SQLITE_DEBUG +int sqlite3_os_trace = 0; #define OSTRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X) #define OSTRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y) #define OSTRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z) @@ -125,74 +125,3 @@ int sqlite3_open_file_count = 0; #else #define OpenCounter(X) #endif - -/* -** sqlite3GenericMalloc -** sqlite3GenericRealloc -** sqlite3GenericOsFree -** sqlite3GenericAllocationSize -** -** Implementation of the os level dynamic memory allocation interface in terms -** of the standard malloc(), realloc() and free() found in many operating -** systems. No rocket science here. -** -** There are two versions of these four functions here. The version -** implemented here is only used if memory-management or memory-debugging is -** enabled. This version allocates an extra 8-bytes at the beginning of each -** block and stores the size of the allocation there. -** -** If neither memory-management or debugging is enabled, the second -** set of implementations is used instead. -*/ -#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || defined (SQLITE_MEMDEBUG) -void *sqlite3GenericMalloc(int n){ - char *p = (char *)malloc(n+8); - assert(n>0); - assert(sizeof(int)<=8); - if( p ){ - *(int *)p = n; - p += 8; - } - return (void *)p; -} -void *sqlite3GenericRealloc(void *p, int n){ - char *p2 = ((char *)p - 8); - assert(n>0); - p2 = (char*)realloc(p2, n+8); - if( p2 ){ - *(int *)p2 = n; - p2 += 8; - } - return (void *)p2; -} -void sqlite3GenericFree(void *p){ - assert(p); - free((void *)((char *)p - 8)); -} -int sqlite3GenericAllocationSize(void *p){ - return p ? *(int *)((char *)p - 8) : 0; -} -#else -void *sqlite3GenericMalloc(int n){ - char *p = (char *)malloc(n); - return (void *)p; -} -void *sqlite3GenericRealloc(void *p, int n){ - assert(n>0); - p = realloc(p, n); - return p; -} -void sqlite3GenericFree(void *p){ - assert(p); - free(p); -} -/* Never actually used, but needed for the linker */ -int sqlite3GenericAllocationSize(void *p){ return 0; } -#endif - -/* -** The default size of a disk sector -*/ -#ifndef PAGER_SECTOR_SIZE -# define PAGER_SECTOR_SIZE 512 -#endif diff --git a/extensions/sqlite/sqlite-source/os_unix.c b/extensions/sqlite/sqlite-source/os_unix.c index cc8449f5..e95435e7 100644 --- a/extensions/sqlite/sqlite-source/os_unix.c +++ b/extensions/sqlite/sqlite-source/os_unix.c @@ -13,7 +13,6 @@ ** This file contains code that is specific to Unix systems. */ #include "sqliteInt.h" -#include "os.h" #if OS_UNIX /* This file is used on unix only */ /* #define SQLITE_ENABLE_LOCKING_STYLE 0 */ @@ -59,10 +58,7 @@ ** If we are to be thread-safe, include the pthreads header and define ** the SQLITE_UNIX_THREADS macro. */ -#ifndef THREADSAFE -# define THREADSAFE 1 -#endif -#if THREADSAFE +#if SQLITE_THREADSAFE # include # define SQLITE_UNIX_THREADS 1 #endif @@ -74,15 +70,25 @@ # define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 #endif +/* +** Maximum supported path-length. +*/ +#define MAX_PATHNAME 512 /* -** The unixFile structure is subclass of OsFile specific for the unix +** The unixFile structure is subclass of sqlite3_file specific for the unix ** protability layer. */ typedef struct unixFile unixFile; struct unixFile { - IoMethod const *pMethod; /* Always the first entry */ + sqlite3_io_methods const *pMethod; /* Always the first entry */ +#ifdef SQLITE_TEST + /* In test mode, increase the size of this structure a bit so that + ** it is larger than the struct CrashFile defined in test6.c. + */ + char aPadding[32]; +#endif struct openCnt *pOpen; /* Info about all open fd's on this inode */ struct lockInfo *pLock; /* Info about locks on this inode */ #ifdef SQLITE_ENABLE_LOCKING_STYLE @@ -90,45 +96,17 @@ struct unixFile { #endif /* SQLITE_ENABLE_LOCKING_STYLE */ int h; /* The file descriptor */ unsigned char locktype; /* The type of lock held on this fd */ - unsigned char isOpen; /* True if needs to be closed */ - unsigned char fullSync; /* Use F_FULLSYNC if available */ int dirfd; /* File descriptor for the directory */ - i64 offset; /* Seek offset */ -#ifdef SQLITE_UNIX_THREADS - pthread_t tid; /* The thread that "owns" this OsFile */ +#if SQLITE_THREADSAFE + pthread_t tid; /* The thread that "owns" this unixFile */ #endif }; -/* -** Provide the ability to override some OS-layer functions during -** testing. This is used to simulate OS crashes to verify that -** commits are atomic even in the event of an OS crash. -*/ -#ifdef SQLITE_CRASH_TEST - extern int sqlite3CrashTestEnable; - extern int sqlite3CrashOpenReadWrite(const char*, OsFile**, int*); - extern int sqlite3CrashOpenExclusive(const char*, OsFile**, int); - extern int sqlite3CrashOpenReadOnly(const char*, OsFile**, int); -# define CRASH_TEST_OVERRIDE(X,A,B,C) \ - if(sqlite3CrashTestEnable){ return X(A,B,C); } -#else -# define CRASH_TEST_OVERRIDE(X,A,B,C) /* no-op */ -#endif - - /* ** Include code that is common to all os_*.c files */ #include "os_common.h" -/* -** Do not include any of the File I/O interface procedures if the -** SQLITE_OMIT_DISKIO macro is defined (indicating that the database -** will be in-memory only) -*/ -#ifndef SQLITE_OMIT_DISKIO - - /* ** Define various macros that are missing from some systems. */ @@ -160,29 +138,29 @@ struct unixFile { ** The threadid macro resolves to the thread-id or to 0. Used for ** testing and debugging only. */ -#ifdef SQLITE_UNIX_THREADS +#if SQLITE_THREADSAFE #define threadid pthread_self() #else #define threadid 0 #endif /* -** Set or check the OsFile.tid field. This field is set when an OsFile -** is first opened. All subsequent uses of the OsFile verify that the -** same thread is operating on the OsFile. Some operating systems do +** Set or check the unixFile.tid field. This field is set when an unixFile +** is first opened. All subsequent uses of the unixFile verify that the +** same thread is operating on the unixFile. Some operating systems do ** not allow locks to be overridden by other threads and that restriction ** means that sqlite3* database handles cannot be moved from one thread ** to another. This logic makes sure a user does not try to do that ** by mistake. ** -** Version 3.3.1 (2006-01-15): OsFiles can be moved from one thread to +** Version 3.3.1 (2006-01-15): unixFile can be moved from one thread to ** another as long as we are running on a system that supports threads ** overriding each others locks (which now the most common behavior) -** or if no locks are held. But the OsFile.pLock field needs to be +** or if no locks are held. But the unixFile.pLock field needs to be ** recomputed because its key includes the thread-id. See the ** transferOwnership() function below for additional information */ -#if defined(SQLITE_UNIX_THREADS) +#if SQLITE_THREADSAFE # define SET_THREADID(X) (X)->tid = pthread_self() # define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \ !pthread_equal((X)->tid, pthread_self())) @@ -226,11 +204,11 @@ struct unixFile { ** locks to see if another thread has previously set a lock on that same ** inode. ** -** The OsFile structure for POSIX is no longer just an integer file +** The sqlite3_file structure for POSIX is no longer just an integer file ** descriptor. It is now a structure that holds the integer file ** descriptor and a pointer to a structure that describes the internal ** locks on the corresponding inode. There is one locking structure -** per inode, so if the same inode is opened twice, both OsFile structures +** per inode, so if the same inode is opened twice, both unixFile structures ** point to the same locking structure. The locking structure keeps ** a reference count (so we will know when to delete it) and a "cnt" ** field that tells us its internal lock status. cnt==0 means the @@ -249,11 +227,11 @@ struct unixFile { ** ** If you close a file descriptor that points to a file that has locks, ** all locks on that file that are owned by the current process are -** released. To work around this problem, each OsFile structure contains +** released. To work around this problem, each unixFile structure contains ** a pointer to an openCnt structure. There is one openCnt structure -** per open inode, which means that multiple OsFiles can point to a single -** openCnt. When an attempt is made to close an OsFile, if there are -** other OsFiles open on the same inode that are holding locks, the call +** per open inode, which means that multiple unixFile can point to a single +** openCnt. When an attempt is made to close an unixFile, if there are +** other unixFile open on the same inode that are holding locks, the call ** to close() the file descriptor is deferred until all of the locks clear. ** The openCnt structure keeps a list of file descriptors that need to ** be closed and that list is walked (and cleared) when the last lock @@ -303,7 +281,7 @@ struct unixFile { struct lockKey { dev_t dev; /* Device number */ ino_t ino; /* Inode number */ -#ifdef SQLITE_UNIX_THREADS +#if SQLITE_THREADSAFE pthread_t tid; /* Thread ID or zero if threads can override each other */ #endif }; @@ -313,9 +291,9 @@ struct lockKey { ** inode on each thread with a different process ID. (Threads have ** different process IDs on linux, but not on most other unixes.) ** -** A single inode can have multiple file descriptors, so each OsFile +** A single inode can have multiple file descriptors, so each unixFile ** structure contains a pointer to an instance of this object and this -** object keeps a count of the number of OsFiles pointing to it. +** object keeps a count of the number of unixFile pointing to it. */ struct lockInfo { struct lockKey key; /* The lookup key */ @@ -354,10 +332,8 @@ struct openCnt { ** openKey structures) into lockInfo and openCnt structures. Access to ** these hash tables must be protected by a mutex. */ -static Hash lockHash = {SQLITE_HASH_BINARY, 0, 0, 0, - sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0}; -static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0, - sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0}; +static Hash lockHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0}; +static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0}; #ifdef SQLITE_ENABLE_LOCKING_STYLE /* @@ -376,16 +352,26 @@ static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0, ** file systems that are known to be unsupported */ typedef enum { - posixLockingStyle = 0, /* standard posix-advisory locks */ - afpLockingStyle, /* use afp locks */ - flockLockingStyle, /* use flock() */ - dotlockLockingStyle, /* use .lock files */ - noLockingStyle, /* useful for read-only file system */ - unsupportedLockingStyle /* indicates unsupported file system */ + posixLockingStyle = 0, /* standard posix-advisory locks */ + afpLockingStyle, /* use afp locks */ + flockLockingStyle, /* use flock() */ + dotlockLockingStyle, /* use .lock files */ + noLockingStyle, /* useful for read-only file system */ + unsupportedLockingStyle /* indicates unsupported file system */ } sqlite3LockingStyle; #endif /* SQLITE_ENABLE_LOCKING_STYLE */ -#ifdef SQLITE_UNIX_THREADS +/* +** Helper functions to obtain and relinquish the global mutex. +*/ +static void enterMutex(){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); +} +static void leaveMutex(){ + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); +} + +#if SQLITE_THREADSAFE /* ** This variable records whether or not threads can override each others ** locks. @@ -522,19 +508,18 @@ static void testThreadLockingBehavior(int fd_orig){ close(fd); threadsOverrideEachOthersLocks = d[0].result==0 && d[1].result==0; } -#endif /* SQLITE_UNIX_THREADS */ +#endif /* SQLITE_THREADSAFE */ /* ** Release a lockInfo structure previously allocated by findLockInfo(). */ static void releaseLockInfo(struct lockInfo *pLock){ - assert( sqlite3OsInMutex(1) ); if (pLock == NULL) return; pLock->nRef--; if( pLock->nRef==0 ){ sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0); - sqlite3ThreadSafeFree(pLock); + sqlite3_free(pLock); } } @@ -542,14 +527,13 @@ static void releaseLockInfo(struct lockInfo *pLock){ ** Release a openCnt structure previously allocated by findLockInfo(). */ static void releaseOpenCnt(struct openCnt *pOpen){ - assert( sqlite3OsInMutex(1) ); if (pOpen == NULL) return; pOpen->nRef--; if( pOpen->nRef==0 ){ sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0); free(pOpen->aPending); - sqlite3ThreadSafeFree(pOpen); + sqlite3_free(pOpen); } } @@ -558,8 +542,10 @@ static void releaseOpenCnt(struct openCnt *pOpen){ ** Tests a byte-range locking query to see if byte range locks are ** supported, if not we fall back to dotlockLockingStyle. */ -static sqlite3LockingStyle sqlite3TestLockingStyle(const char *filePath, - int fd) { +static sqlite3LockingStyle sqlite3TestLockingStyle( + const char *filePath, + int fd +){ /* test byte-range lock using fcntl */ struct flock lockInfo; @@ -568,7 +554,7 @@ static sqlite3LockingStyle sqlite3TestLockingStyle(const char *filePath, lockInfo.l_whence = SEEK_SET; lockInfo.l_type = F_RDLCK; - if (fcntl(fd, F_GETLK, &lockInfo) != -1) { + if( fcntl(fd, F_GETLK, &lockInfo)!=-1 ) { return posixLockingStyle; } @@ -585,8 +571,10 @@ static sqlite3LockingStyle sqlite3TestLockingStyle(const char *filePath, ** assignments are based on Darwin/OSX behavior and have not been tested on ** other systems. */ -static sqlite3LockingStyle sqlite3DetectLockingStyle(const char *filePath, - int fd) { +static sqlite3LockingStyle sqlite3DetectLockingStyle( + const char *filePath, + int fd +){ #ifdef SQLITE_FIXED_LOCKING_STYLE return (sqlite3LockingStyle)SQLITE_FIXED_LOCKING_STYLE; @@ -601,7 +589,7 @@ static sqlite3LockingStyle sqlite3DetectLockingStyle(const char *filePath, if( (!strcmp(fsInfo.f_fstypename, "hfs")) || (!strcmp(fsInfo.f_fstypename, "ufs")) ) - return posixLockingStyle; + return posixLockingStyle; if(!strcmp(fsInfo.f_fstypename, "afpfs")) return afpLockingStyle; @@ -645,11 +633,10 @@ static int findLockInfo( rc = fstat(fd, &statbuf); if( rc!=0 ) return 1; - assert( sqlite3OsInMutex(1) ); memset(&key1, 0, sizeof(key1)); key1.dev = statbuf.st_dev; key1.ino = statbuf.st_ino; -#ifdef SQLITE_UNIX_THREADS +#if SQLITE_THREADSAFE if( threadsOverrideEachOthersLocks<0 ){ testThreadLockingBehavior(fd); } @@ -661,7 +648,7 @@ static int findLockInfo( pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1)); if( pLock==0 ){ struct lockInfo *pOld; - pLock = sqlite3ThreadSafeMalloc( sizeof(*pLock) ); + pLock = sqlite3_malloc( sizeof(*pLock) ); if( pLock==0 ){ rc = 1; goto exit_findlockinfo; @@ -673,7 +660,7 @@ static int findLockInfo( pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock); if( pOld!=0 ){ assert( pOld==pLock ); - sqlite3ThreadSafeFree(pLock); + sqlite3_free(pLock); rc = 1; goto exit_findlockinfo; } @@ -685,7 +672,7 @@ static int findLockInfo( pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2)); if( pOpen==0 ){ struct openCnt *pOld; - pOpen = sqlite3ThreadSafeMalloc( sizeof(*pOpen) ); + pOpen = sqlite3_malloc( sizeof(*pOpen) ); if( pOpen==0 ){ releaseLockInfo(pLock); rc = 1; @@ -699,7 +686,7 @@ static int findLockInfo( pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); if( pOld!=0 ){ assert( pOld==pOpen ); - sqlite3ThreadSafeFree(pOpen); + sqlite3_free(pOpen); releaseLockInfo(pLock); rc = 1; goto exit_findlockinfo; @@ -745,7 +732,7 @@ static const char *locktypeName(int locktype){ ** If the unixFile is locked and an ownership is wrong, then return ** SQLITE_MISUSE. SQLITE_OK is returned if everything works. */ -#ifdef SQLITE_UNIX_THREADS +#if SQLITE_THREADSAFE static int transferOwnership(unixFile *pFile){ int rc; pthread_t hSelf; @@ -783,240 +770,29 @@ static int transferOwnership(unixFile *pFile){ #endif /* -** Delete the named file +** Seek to the offset passed as the second argument, then read cnt +** bytes into pBuf. Return the number of bytes actually read. */ -int sqlite3UnixDelete(const char *zFilename){ - SimulateIOError(return SQLITE_IOERR_DELETE); - unlink(zFilename); - return SQLITE_OK; -} - -/* -** Return TRUE if the named file exists. -*/ -int sqlite3UnixFileExists(const char *zFilename){ - return access(zFilename, 0)==0; -} - -/* Forward declaration */ -static int allocateUnixFile( - int h, /* File descriptor of the open file */ - OsFile **pId, /* Write the real file descriptor here */ - const char *zFilename, /* Name of the file being opened */ - int delFlag /* If true, make sure the file deletes on close */ -); - -/* -** Attempt to open a file for both reading and writing. If that -** fails, try opening it read-only. If the file does not exist, -** try to create it. -** -** On success, a handle for the open file is written to *id -** and *pReadonly is set to 0 if the file was opened for reading and -** writing or 1 if the file was opened read-only. The function returns -** SQLITE_OK. -** -** On failure, the function returns SQLITE_CANTOPEN and leaves -** *id and *pReadonly unchanged. -*/ -int sqlite3UnixOpenReadWrite( - const char *zFilename, - OsFile **pId, - int *pReadonly -){ - int h; - - CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly); - assert( 0==*pId ); - h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, - SQLITE_DEFAULT_FILE_PERMISSIONS); - if( h<0 ){ -#ifdef EISDIR - if( errno==EISDIR ){ - return SQLITE_CANTOPEN; - } -#endif - h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); - if( h<0 ){ - return SQLITE_CANTOPEN; - } - *pReadonly = 1; - }else{ - *pReadonly = 0; - } - return allocateUnixFile(h, pId, zFilename, 0); -} - - -/* -** Attempt to open a new file for exclusive access by this process. -** The file will be opened for both reading and writing. To avoid -** a potential security problem, we do not allow the file to have -** previously existed. Nor do we allow the file to be a symbolic -** link. -** -** If delFlag is true, then make arrangements to automatically delete -** the file when it is closed. -** -** On success, write the file handle into *id and return SQLITE_OK. -** -** On failure, return SQLITE_CANTOPEN. -*/ -int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ - int h; - - CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag); - assert( 0==*pId ); - h = open(zFilename, - O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, - delFlag ? 0600 : SQLITE_DEFAULT_FILE_PERMISSIONS); - if( h<0 ){ - return SQLITE_CANTOPEN; - } - return allocateUnixFile(h, pId, zFilename, delFlag); -} - -/* -** Attempt to open a new file for read-only access. -** -** On success, write the file handle into *id and return SQLITE_OK. -** -** On failure, return SQLITE_CANTOPEN. -*/ -int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){ - int h; - - CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0); - assert( 0==*pId ); - h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); - if( h<0 ){ - return SQLITE_CANTOPEN; - } - return allocateUnixFile(h, pId, zFilename, 0); -} - -/* -** Attempt to open a file descriptor for the directory that contains a -** file. This file descriptor can be used to fsync() the directory -** in order to make sure the creation of a new file is actually written -** to disk. -** -** This routine is only meaningful for Unix. It is a no-op under -** windows since windows does not support hard links. -** -** If FULL_FSYNC is enabled, this function is not longer useful, -** a FULL_FSYNC sync applies to all pending disk operations. -** -** On success, a handle for a previously open file at *id is -** updated with the new directory file descriptor and SQLITE_OK is -** returned. -** -** On failure, the function returns SQLITE_CANTOPEN and leaves -** *id unchanged. -*/ -static int unixOpenDirectory( - OsFile *id, - const char *zDirname -){ - int h; - unixFile *pFile = (unixFile*)id; - assert( pFile!=0 ); - SET_THREADID(pFile); - assert( pFile->dirfd<0 ); - pFile->dirfd = h = open(zDirname, O_RDONLY|O_BINARY, 0); - if( h<0 ){ - return SQLITE_CANTOPEN; - } -#ifdef FD_CLOEXEC - fcntl(h, F_SETFD, fcntl(h, F_GETFD, 0) | FD_CLOEXEC); -#endif - OSTRACE3("OPENDIR %-3d %s\n", h, zDirname); - return SQLITE_OK; -} - -/* -** Create a temporary file name in zBuf. zBuf must be big enough to -** hold at least SQLITE_TEMPNAME_SIZE characters. -*/ -int sqlite3UnixTempFileName(char *zBuf){ - static const char *azDirs[] = { - 0, - "/var/tmp", - "/usr/tmp", - "/tmp", - ".", - }; - static const unsigned char zChars[] = - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789"; - int i, j; - struct stat buf; - const char *zDir = "."; - azDirs[0] = sqlite3_temp_directory; - for(i=0; ioffset then read cnt bytes into pBuf. -** Return the number of bytes actually read. Update the offset. -*/ -static int seekAndRead(unixFile *id, void *pBuf, int cnt){ +static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ int got; i64 newOffset; TIMER_START; #if defined(USE_PREAD) - got = pread(id->h, pBuf, cnt, id->offset); + got = pread(id->h, pBuf, cnt, offset); SimulateIOError( got = -1 ); #elif defined(USE_PREAD64) - got = pread64(id->h, pBuf, cnt, id->offset); + got = pread64(id->h, pBuf, cnt, offset); SimulateIOError( got = -1 ); #else - newOffset = lseek(id->h, id->offset, SEEK_SET); + newOffset = lseek(id->h, offset, SEEK_SET); SimulateIOError( newOffset-- ); - if( newOffset!=id->offset ){ + if( newOffset!=offset ){ return -1; } got = read(id->h, pBuf, cnt); #endif TIMER_END; - OSTRACE5("READ %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED); - if( got>0 ){ - id->offset += got; - } + OSTRACE5("READ %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED); return got; } @@ -1025,10 +801,15 @@ static int seekAndRead(unixFile *id, void *pBuf, int cnt){ ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ -static int unixRead(OsFile *id, void *pBuf, int amt){ +static int unixRead( + sqlite3_file *id, + void *pBuf, + int amt, + sqlite3_int64 offset +){ int got; assert( id ); - got = seekAndRead((unixFile*)id, pBuf, amt); + got = seekAndRead((unixFile*)id, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ @@ -1043,26 +824,23 @@ static int unixRead(OsFile *id, void *pBuf, int amt){ ** Seek to the offset in id->offset then read cnt bytes into pBuf. ** Return the number of bytes actually read. Update the offset. */ -static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){ +static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ int got; i64 newOffset; TIMER_START; #if defined(USE_PREAD) - got = pwrite(id->h, pBuf, cnt, id->offset); + got = pwrite(id->h, pBuf, cnt, offset); #elif defined(USE_PREAD64) - got = pwrite64(id->h, pBuf, cnt, id->offset); + got = pwrite64(id->h, pBuf, cnt, offset); #else - newOffset = lseek(id->h, id->offset, SEEK_SET); - if( newOffset!=id->offset ){ + newOffset = lseek(id->h, offset, SEEK_SET); + if( newOffset!=offset ){ return -1; } got = write(id->h, pBuf, cnt); #endif TIMER_END; - OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED); - if( got>0 ){ - id->offset += got; - } + OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED); return got; } @@ -1071,12 +849,18 @@ static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){ ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ -static int unixWrite(OsFile *id, const void *pBuf, int amt){ +static int unixWrite( + sqlite3_file *id, + const void *pBuf, + int amt, + sqlite3_int64 offset +){ int wrote = 0; assert( id ); assert( amt>0 ); - while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){ + while( amt>0 && (wrote = seekAndWrite((unixFile*)id, offset, pBuf, amt))>0 ){ amt -= wrote; + offset += wrote; pBuf = &((char*)pBuf)[wrote]; } SimulateIOError(( wrote=(-1), amt=1 )); @@ -1091,18 +875,6 @@ static int unixWrite(OsFile *id, const void *pBuf, int amt){ return SQLITE_OK; } -/* -** Move the read/write pointer in a file. -*/ -static int unixSeek(OsFile *id, i64 offset){ - assert( id ); -#ifdef SQLITE_TEST - if( offset ) SimulateDiskfullError(return SQLITE_FULL); -#endif - ((unixFile*)id)->offset = offset; - return SQLITE_OK; -} - #ifdef SQLITE_TEST /* ** Count the number of fullsyncs and normal syncs. This is used to test @@ -1205,25 +977,34 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ ** the directory entry for the journal was never created) and the transaction ** will not roll back - possibly leading to database corruption. */ -static int unixSync(OsFile *id, int dataOnly){ +static int unixSync(sqlite3_file *id, int flags){ int rc; unixFile *pFile = (unixFile*)id; + + int isDataOnly = (flags&SQLITE_SYNC_DATAONLY); + int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL; + + /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ + assert((flags&0x0F)==SQLITE_SYNC_NORMAL + || (flags&0x0F)==SQLITE_SYNC_FULL + ); + assert( pFile ); OSTRACE2("SYNC %-3d\n", pFile->h); - rc = full_fsync(pFile->h, pFile->fullSync, dataOnly); + rc = full_fsync(pFile->h, isFullsync, isDataOnly); SimulateIOError( rc=1 ); if( rc ){ return SQLITE_IOERR_FSYNC; } if( pFile->dirfd>=0 ){ OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd, - HAVE_FULLFSYNC, pFile->fullSync); + HAVE_FULLFSYNC, isFullsync); #ifndef SQLITE_DISABLE_DIRSYNC /* The directory sync is only attempted if full_fsync is ** turned off or unavailable. If a full_fsync occurred above, ** then the directory sync is superfluous. */ - if( (!HAVE_FULLFSYNC || !pFile->fullSync) && full_fsync(pFile->dirfd,0,0) ){ + if( (!HAVE_FULLFSYNC || !isFullsync) && full_fsync(pFile->dirfd,0,0) ){ /* ** We have received multiple reports of fsync() returning ** errors when applied to directories on certain file systems. @@ -1239,40 +1020,10 @@ static int unixSync(OsFile *id, int dataOnly){ return SQLITE_OK; } -/* -** Sync the directory zDirname. This is a no-op on operating systems other -** than UNIX. -** -** This is used to make sure the master journal file has truely been deleted -** before making changes to individual journals on a multi-database commit. -** The F_FULLFSYNC option is not needed here. -*/ -int sqlite3UnixSyncDirectory(const char *zDirname){ -#ifdef SQLITE_DISABLE_DIRSYNC - return SQLITE_OK; -#else - int fd; - int r; - fd = open(zDirname, O_RDONLY|O_BINARY, 0); - OSTRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname); - if( fd<0 ){ - return SQLITE_CANTOPEN; - } - r = fsync(fd); - close(fd); - SimulateIOError( r=1 ); - if( r ){ - return SQLITE_IOERR_DIR_FSYNC; - }else{ - return SQLITE_OK; - } -#endif -} - /* ** Truncate an open file to a specified size */ -static int unixTruncate(OsFile *id, i64 nByte){ +static int unixTruncate(sqlite3_file *id, i64 nByte){ int rc; assert( id ); rc = ftruncate(((unixFile*)id)->h, (off_t)nByte); @@ -1287,7 +1038,7 @@ static int unixTruncate(OsFile *id, i64 nByte){ /* ** Determine the current size of a file in bytes */ -static int unixFileSize(OsFile *id, i64 *pSize){ +static int unixFileSize(sqlite3_file *id, i64 *pSize){ int rc; struct stat buf; assert( id ); @@ -1306,12 +1057,12 @@ static int unixFileSize(OsFile *id, i64 *pSize){ ** non-zero. If the file is unlocked or holds only SHARED locks, then ** return zero. */ -static int unixCheckReservedLock(OsFile *id){ +static int unixCheckReservedLock(sqlite3_file *id){ int r = 0; unixFile *pFile = (unixFile*)id; assert( pFile ); - sqlite3OsEnterMutex(); /* Because pFile->pLock is shared across threads */ + enterMutex(); /* Because pFile->pLock is shared across threads */ /* Check if a thread in this process holds such a lock */ if( pFile->pLock->locktype>SHARED_LOCK ){ @@ -1332,7 +1083,7 @@ static int unixCheckReservedLock(OsFile *id){ } } - sqlite3OsLeaveMutex(); + leaveMutex(); OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r); return r; @@ -1362,7 +1113,7 @@ static int unixCheckReservedLock(OsFile *id){ ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ -static int unixLock(OsFile *id, int locktype){ +static int unixLock(sqlite3_file *id, int locktype){ /* The following describes the implementation of the various locks and ** lock transitions in terms of the POSIX advisory shared and exclusive ** lock primitives (called read-locks and write-locks below, to avoid @@ -1413,8 +1164,8 @@ static int unixLock(OsFile *id, int locktype){ locktypeName(pLock->locktype), pLock->cnt , getpid()); /* If there is already a lock of this type or more restrictive on the - ** OsFile, do nothing. Don't use the end_lock: exit path, as - ** sqlite3OsEnterMutex() hasn't been called yet. + ** unixFile, do nothing. Don't use the end_lock: exit path, as + ** enterMutex() hasn't been called yet. */ if( pFile->locktype>=locktype ){ OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h, @@ -1430,18 +1181,18 @@ static int unixLock(OsFile *id, int locktype){ /* This mutex is needed because pFile->pLock is shared across threads */ - sqlite3OsEnterMutex(); + enterMutex(); /* Make sure the current thread owns the pFile. */ rc = transferOwnership(pFile); if( rc!=SQLITE_OK ){ - sqlite3OsLeaveMutex(); + leaveMutex(); return rc; } pLock = pFile->pLock; - /* If some thread using this PID has a lock via a different OsFile* + /* If some thread using this PID has a lock via a different unixFile* ** handle that precludes the requested lock, return BUSY. */ if( (pFile->locktype!=pLock->locktype && @@ -1551,7 +1302,7 @@ static int unixLock(OsFile *id, int locktype){ } end_lock: - sqlite3OsLeaveMutex(); + leaveMutex(); OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), rc==SQLITE_OK ? "ok" : "failed"); return rc; @@ -1564,7 +1315,7 @@ end_lock: ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ -static int unixUnlock(OsFile *id, int locktype){ +static int unixUnlock(sqlite3_file *id, int locktype){ struct lockInfo *pLock; struct flock lock; int rc = SQLITE_OK; @@ -1581,7 +1332,7 @@ static int unixUnlock(OsFile *id, int locktype){ if( CHECK_THREADID(pFile) ){ return SQLITE_MISUSE; } - sqlite3OsEnterMutex(); + enterMutex(); pLock = pFile->pLock; assert( pLock->cnt!=0 ); if( pFile->locktype>SHARED_LOCK ){ @@ -1642,7 +1393,7 @@ static int unixUnlock(OsFile *id, int locktype){ pOpen->aPending = 0; } } - sqlite3OsLeaveMutex(); + leaveMutex(); pFile->locktype = locktype; return rc; } @@ -1650,44 +1401,41 @@ static int unixUnlock(OsFile *id, int locktype){ /* ** Close a file. */ -static int unixClose(OsFile **pId){ - unixFile *id = (unixFile*)*pId; +static int unixClose(sqlite3_file *id){ + unixFile *pFile = (unixFile *)id; + if( !pFile ) return SQLITE_OK; + unixUnlock(id, NO_LOCK); + if( pFile->dirfd>=0 ) close(pFile->dirfd); + pFile->dirfd = -1; + enterMutex(); - if( !id ) return SQLITE_OK; - unixUnlock(*pId, NO_LOCK); - if( id->dirfd>=0 ) close(id->dirfd); - id->dirfd = -1; - sqlite3OsEnterMutex(); - - if( id->pOpen->nLock ){ + if( pFile->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pOpen->aPending. It will be automatically closed when ** the last lock is cleared. */ int *aNew; - struct openCnt *pOpen = id->pOpen; + struct openCnt *pOpen = pFile->pOpen; aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) ); if( aNew==0 ){ /* If a malloc fails, just leak the file descriptor */ }else{ pOpen->aPending = aNew; - pOpen->aPending[pOpen->nPending] = id->h; + pOpen->aPending[pOpen->nPending] = pFile->h; pOpen->nPending++; } }else{ /* There are no outstanding locks so we can close the file immediately */ - close(id->h); + close(pFile->h); } - releaseLockInfo(id->pLock); - releaseOpenCnt(id->pOpen); + releaseLockInfo(pFile->pLock); + releaseOpenCnt(pFile->pOpen); - sqlite3OsLeaveMutex(); - id->isOpen = 0; - OSTRACE2("CLOSE %-3d\n", id->h); + leaveMutex(); + OSTRACE2("CLOSE %-3d\n", pFile->h); OpenCounter(-1); - sqlite3ThreadSafeFree(id); - *pId = 0; + memset(pFile, 0, sizeof(unixFile)); return SQLITE_OK; } @@ -1714,16 +1462,22 @@ struct ByteRangeLockPB2 int fd; /* file desc to assoc this lock with */ }; -#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2) +#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2) -/* return 0 on success, 1 on failure. To match the behavior of the - normal posix file locking (used in unixLock for example), we should - provide 'richer' return codes - specifically to differentiate between - 'file busy' and 'file system error' results */ -static int _AFPFSSetLock(const char *path, int fd, unsigned long long offset, - unsigned long long length, int setLockFlag) -{ - struct ByteRangeLockPB2 pb; +/* +** Return 0 on success, 1 on failure. To match the behavior of the +** normal posix file locking (used in unixLock for example), we should +** provide 'richer' return codes - specifically to differentiate between +** 'file busy' and 'file system error' results. +*/ +static int _AFPFSSetLock( + const char *path, + int fd, + unsigned long long offset, + unsigned long long length, + int setLockFlag +){ + struct ByteRangeLockPB2 pb; int err; pb.unLockFlag = setLockFlag ? 0 : 1; @@ -1749,7 +1503,7 @@ static int _AFPFSSetLock(const char *path, int fd, unsigned long long offset, ** non-zero. If the file is unlocked or holds only SHARED locks, then ** return zero. */ -static int afpUnixCheckReservedLock(OsFile *id){ +static int afpUnixCheckReservedLock(sqlite3_file *id){ int r = 0; unixFile *pFile = (unixFile*)id; @@ -1782,7 +1536,7 @@ static int afpUnixCheckReservedLock(OsFile *id){ /* AFP-style locking following the behavior of unixLock, see the unixLock ** function comments for details of lock management. */ -static int afpUnixLock(OsFile *id, int locktype) +static int afpUnixLock(sqlite3_file *id, int locktype) { int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; @@ -1793,8 +1547,8 @@ static int afpUnixLock(OsFile *id, int locktype) OSTRACE5("LOCK %d %s was %s pid=%d\n", pFile->h, locktypeName(locktype), locktypeName(pFile->locktype), getpid()); /* If there is already a lock of this type or more restrictive on the - ** OsFile, do nothing. Don't use the afp_end_lock: exit path, as - ** sqlite3OsEnterMutex() hasn't been called yet. + ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as + ** enterMutex() hasn't been called yet. */ if( pFile->locktype>=locktype ){ OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h, @@ -1810,13 +1564,13 @@ static int afpUnixLock(OsFile *id, int locktype) /* This mutex is needed because pFile->pLock is shared across threads */ - sqlite3OsEnterMutex(); + enterMutex(); /* Make sure the current thread owns the pFile. */ rc = transferOwnership(pFile); if( rc!=SQLITE_OK ){ - sqlite3OsLeaveMutex(); + leaveMutex(); return rc; } @@ -1903,7 +1657,7 @@ static int afpUnixLock(OsFile *id, int locktype) } afp_end_lock: - sqlite3OsLeaveMutex(); + leaveMutex(); OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), rc==SQLITE_OK ? "ok" : "failed"); return rc; @@ -1916,7 +1670,7 @@ afp_end_lock: ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ -static int afpUnixUnlock(OsFile *id, int locktype) { +static int afpUnixUnlock(sqlite3_file *id, int locktype) { struct flock lock; int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; @@ -1933,7 +1687,7 @@ static int afpUnixUnlock(OsFile *id, int locktype) { if( CHECK_THREADID(pFile) ){ return SQLITE_MISUSE; } - sqlite3OsEnterMutex(); + enterMutex(); if( pFile->locktype>SHARED_LOCK ){ if( locktype==SHARED_LOCK ){ int failed = 0; @@ -1977,33 +1731,30 @@ static int afpUnixUnlock(OsFile *id, int locktype) { } if (rc == SQLITE_OK) pFile->locktype = locktype; - sqlite3OsLeaveMutex(); + leaveMutex(); return rc; } /* ** Close a file & cleanup AFP specific locking context */ -static int afpUnixClose(OsFile **pId) { - unixFile *id = (unixFile*)*pId; - - if( !id ) return SQLITE_OK; +static int afpUnixClose(sqlite3_file *id) { + unixFile *pFile = (unixFile*)pId; + + if( !pFile ) return SQLITE_OK; afpUnixUnlock(*pId, NO_LOCK); /* free the AFP locking structure */ - if (id->lockingContext != NULL) { - if (((afpLockingContext *)id->lockingContext)->filePath != NULL) - sqlite3ThreadSafeFree(((afpLockingContext*)id->lockingContext)->filePath); - sqlite3ThreadSafeFree(id->lockingContext); + if (pFile->lockingContext != NULL) { + if (((afpLockingContext *)pFile->lockingContext)->filePath != NULL) + sqlite3_free(((afpLockingContext*)pFile->lockingContext)->filePath); + sqlite3_free(pFile->lockingContext); } - - if( id->dirfd>=0 ) close(id->dirfd); - id->dirfd = -1; - close(id->h); - id->isOpen = 0; - OSTRACE2("CLOSE %-3d\n", id->h); + + if( pFile->dirfd>=0 ) close(pFile->dirfd); + pFile->dirfd = -1; + close(pFile->h); + OSTRACE2("CLOSE %-3d\n", pFile->h); OpenCounter(-1); - sqlite3ThreadSafeFree(id); - *pId = 0; return SQLITE_OK; } @@ -2015,7 +1766,7 @@ static int afpUnixClose(OsFile **pId) { */ typedef void flockLockingContext; -static int flockUnixCheckReservedLock(OsFile *id) { +static int flockUnixCheckReservedLock(sqlite3_file *id) { unixFile *pFile = (unixFile*)id; if (pFile->locktype == RESERVED_LOCK) { @@ -2032,7 +1783,7 @@ static int flockUnixCheckReservedLock(OsFile *id) { } } -static int flockUnixLock(OsFile *id, int locktype) { +static int flockUnixLock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; /* if we already have a lock, it is exclusive. @@ -2054,7 +1805,7 @@ static int flockUnixLock(OsFile *id, int locktype) { } } -static int flockUnixUnlock(OsFile *id, int locktype) { +static int flockUnixUnlock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; assert( locktype<=SHARED_LOCK ); @@ -2083,23 +1834,20 @@ static int flockUnixUnlock(OsFile *id, int locktype) { /* ** Close a file. */ -static int flockUnixClose(OsFile **pId) { - unixFile *id = (unixFile*)*pId; +static int flockUnixClose(sqlite3_file *pId) { + unixFile *pFile = (unixFile*)*pId; - if( !id ) return SQLITE_OK; + if( !pFile ) return SQLITE_OK; flockUnixUnlock(*pId, NO_LOCK); - if( id->dirfd>=0 ) close(id->dirfd); - id->dirfd = -1; - sqlite3OsEnterMutex(); + if( pFile->dirfd>=0 ) close(pFile->dirfd); + pFile->dirfd = -1; + enterMutex(); - close(id->h); - sqlite3OsLeaveMutex(); - id->isOpen = 0; - OSTRACE2("CLOSE %-3d\n", id->h); + close(pFile->h); + leaveMutex(); + OSTRACE2("CLOSE %-3d\n", pFile->h); OpenCounter(-1); - sqlite3ThreadSafeFree(id); - *pId = 0; return SQLITE_OK; } @@ -2115,7 +1863,7 @@ struct dotlockLockingContext { }; -static int dotlockUnixCheckReservedLock(OsFile *id) { +static int dotlockUnixCheckReservedLock(sqlite3_file *id) { unixFile *pFile = (unixFile*)id; dotlockLockingContext *context = (dotlockLockingContext *) pFile->lockingContext; @@ -2133,7 +1881,7 @@ static int dotlockUnixCheckReservedLock(OsFile *id) { } } -static int dotlockUnixLock(OsFile *id, int locktype) { +static int dotlockUnixLock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; dotlockLockingContext *context = (dotlockLockingContext *) pFile->lockingContext; @@ -2167,7 +1915,7 @@ static int dotlockUnixLock(OsFile *id, int locktype) { return SQLITE_OK; } -static int dotlockUnixUnlock(OsFile *id, int locktype) { +static int dotlockUnixUnlock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; dotlockLockingContext *context = (dotlockLockingContext *) pFile->lockingContext; @@ -2194,31 +1942,28 @@ static int dotlockUnixUnlock(OsFile *id, int locktype) { /* ** Close a file. */ -static int dotlockUnixClose(OsFile **pId) { - unixFile *id = (unixFile*)*pId; +static int dotlockUnixClose(sqlite3_file *id) { + unixFile *pFile = (unixFile*)id; - if( !id ) return SQLITE_OK; + if( !pFile ) return SQLITE_OK; dotlockUnixUnlock(*pId, NO_LOCK); /* free the dotlock locking structure */ - if (id->lockingContext != NULL) { - if (((dotlockLockingContext *)id->lockingContext)->lockPath != NULL) - sqlite3ThreadSafeFree( ( (dotlockLockingContext *) - id->lockingContext)->lockPath); - sqlite3ThreadSafeFree(id->lockingContext); + if (pFile->lockingContext != NULL) { + if (((dotlockLockingContext *)pFile->lockingContext)->lockPath != NULL) + sqlite3_free( ( (dotlockLockingContext *) + pFile->lockingContext)->lockPath); + sqlite3_free(pFile->lockingContext); } - if( id->dirfd>=0 ) close(id->dirfd); - id->dirfd = -1; - sqlite3OsEnterMutex(); + if( pFile->dirfd>=0 ) close(pFile->dirfd); + pFile->dirfd = -1; + enterMutex(); - close(id->h); + close(pFile->h); - sqlite3OsLeaveMutex(); - id->isOpen = 0; - OSTRACE2("CLOSE %-3d\n", id->h); + leaveMutex(); + OSTRACE2("CLOSE %-3d\n", pFile->h); OpenCounter(-1); - sqlite3ThreadSafeFree(id); - *pId = 0; return SQLITE_OK; } @@ -2230,62 +1975,587 @@ static int dotlockUnixClose(OsFile **pId) { */ typedef void nolockLockingContext; -static int nolockUnixCheckReservedLock(OsFile *id) { +static int nolockUnixCheckReservedLock(sqlite3_file *id) { return 0; } -static int nolockUnixLock(OsFile *id, int locktype) { +static int nolockUnixLock(sqlite3_file *id, int locktype) { return SQLITE_OK; } -static int nolockUnixUnlock(OsFile *id, int locktype) { +static int nolockUnixUnlock(sqlite3_file *id, int locktype) { return SQLITE_OK; } /* ** Close a file. */ -static int nolockUnixClose(OsFile **pId) { - unixFile *id = (unixFile*)*pId; +static int nolockUnixClose(sqlite3_file *id) { + unixFile *pFile = (unixFile*)id; - if( !id ) return SQLITE_OK; - if( id->dirfd>=0 ) close(id->dirfd); - id->dirfd = -1; - sqlite3OsEnterMutex(); + if( !pFile ) return SQLITE_OK; + if( pFile->dirfd>=0 ) close(pFile->dirfd); + pFile->dirfd = -1; + enterMutex(); - close(id->h); + close(pFile->h); - sqlite3OsLeaveMutex(); - id->isOpen = 0; - OSTRACE2("CLOSE %-3d\n", id->h); + leaveMutex(); + OSTRACE2("CLOSE %-3d\n", pFile->h); OpenCounter(-1); - sqlite3ThreadSafeFree(id); - *pId = 0; return SQLITE_OK; } #endif /* SQLITE_ENABLE_LOCKING_STYLE */ + /* -** Turn a relative pathname into a full pathname. Return a pointer -** to the full pathname stored in space obtained from sqliteMalloc(). -** The calling function is responsible for freeing this space once it -** is no longer needed. +** Information and control of an open file handle. */ -char *sqlite3UnixFullPathname(const char *zRelative){ - char *zFull = 0; - if( zRelative[0]=='/' ){ - sqlite3SetString(&zFull, zRelative, (char*)0); - }else{ - char *zBuf = sqliteMalloc(5000); - if( zBuf==0 ){ - return 0; +static int unixFileControl(sqlite3_file *id, int op, void *pArg){ + switch( op ){ + case SQLITE_FCNTL_LOCKSTATE: { + *(int*)pArg = ((unixFile*)id)->locktype; + return SQLITE_OK; } - zBuf[0] = 0; - sqlite3SetString(&zFull, getcwd(zBuf, 5000), "/", zRelative, - (char*)0); - sqliteFree(zBuf); } + return SQLITE_ERROR; +} + +/* +** Return the sector size in bytes of the underlying block device for +** the specified file. This is almost always 512 bytes, but may be +** larger for some devices. +** +** SQLite code assumes this function cannot fail. It also assumes that +** if two files are created in the same file-system directory (i.e. +** a database and it's journal file) that the sector size will be the +** same for both. +*/ +static int unixSectorSize(sqlite3_file *id){ + return SQLITE_DEFAULT_SECTOR_SIZE; +} + +/* +** Return the device characteristics for the file. This is always 0. +*/ +static int unixDeviceCharacteristics(sqlite3_file *id){ + return 0; +} + +/* +** This vector defines all the methods that can operate on an sqlite3_file +** for unix. +*/ +static const sqlite3_io_methods sqlite3UnixIoMethod = { + 1, /* iVersion */ + unixClose, + unixRead, + unixWrite, + unixTruncate, + unixSync, + unixFileSize, + unixLock, + unixUnlock, + unixCheckReservedLock, + unixFileControl, + unixSectorSize, + unixDeviceCharacteristics +}; + +#ifdef SQLITE_ENABLE_LOCKING_STYLE +/* +** This vector defines all the methods that can operate on an sqlite3_file +** for unix with AFP style file locking. +*/ +static const sqlite3_io_methods sqlite3AFPLockingUnixIoMethod = { + 1, /* iVersion */ + unixClose, + unixRead, + unixWrite, + unixTruncate, + unixSync, + unixFileSize, + afpUnixLock, + afpUnixUnlock, + afpUnixCheckReservedLock, + unixFileControl, + unixSectorSize, + unixDeviceCharacteristics +}; + +/* +** This vector defines all the methods that can operate on an sqlite3_file +** for unix with flock() style file locking. +*/ +static const sqlite3_io_methods sqlite3FlockLockingUnixIoMethod = { + 1, /* iVersion */ + flockUnixClose, + unixRead, + unixWrite, + unixTruncate, + unixSync, + unixFileSize, + flockUnixLock, + flockUnixUnlock, + flockUnixCheckReservedLock, + unixFileControl, + unixSectorSize, + unixDeviceCharacteristics +}; + +/* +** This vector defines all the methods that can operate on an sqlite3_file +** for unix with dotlock style file locking. +*/ +static const sqlite3_io_methods sqlite3DotlockLockingUnixIoMethod = { + 1, /* iVersion */ + dotlockUnixClose, + unixRead, + unixWrite, + unixTruncate, + unixSync, + unixFileSize, + dotlockUnixLock, + dotlockUnixUnlock, + dotlockUnixCheckReservedLock, + unixFileControl, + unixSectorSize, + unixDeviceCharacteristics +}; + +/* +** This vector defines all the methods that can operate on an sqlite3_file +** for unix with dotlock style file locking. +*/ +static const sqlite3_io_methods sqlite3NolockLockingUnixIoMethod = { + 1, /* iVersion */ + nolockUnixClose, + unixRead, + unixWrite, + unixTruncate, + unixSync, + unixFileSize, + nolockUnixLock, + nolockUnixUnlock, + nolockUnixCheckReservedLock, + unixFileControl, + unixSectorSize, + unixDeviceCharacteristics +}; + +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ + +/* +** Allocate memory for a new unixFile and initialize that unixFile. +** Write a pointer to the new unixFile into *pId. +** If we run out of memory, close the file and return an error. +*/ +#ifdef SQLITE_ENABLE_LOCKING_STYLE +/* +** When locking extensions are enabled, the filepath and locking style +** are needed to determine the unixFile pMethod to use for locking operations. +** The locking-style specific lockingContext data structure is created +** and assigned here also. +*/ +static int fillInUnixFile( + int h, /* Open file descriptor of file being opened */ + int dirfd, /* Directory file descriptor */ + sqlite3_file *pId, /* Write completed initialization here */ + const char *zFilename, /* Name of the file being opened */ +){ + sqlite3LockingStyle lockingStyle; + unixFile *pNew = (unixFile *)pId; + int rc; + + memset(pNew, 0, sizeof(unixFile)); + lockingStyle = sqlite3DetectLockingStyle(zFilename, h); + if ( lockingStyle == posixLockingStyle ) { + enterMutex(); + rc = findLockInfo(h, &pNew->pLock, &pNew->pOpen); + leaveMutex(); + if( rc ){ + close(h); + unlink(zFilename); + return SQLITE_NOMEM; + } + } else { + /* pLock and pOpen are only used for posix advisory locking */ + pNew->pLock = NULL; + pNew->pOpen = NULL; + } + pNew->dirfd = -1; + pNew->h = h; + SET_THREADID(pNew); + pNew = sqlite3_malloc( sizeof(unixFile) ); + if( pNew==0 ){ + close(h); + enterMutex(); + releaseLockInfo(pNew->pLock); + releaseOpenCnt(pNew->pOpen); + leaveMutex(); + return SQLITE_NOMEM; + }else{ + switch(lockingStyle) { + case afpLockingStyle: { + /* afp locking uses the file path so it needs to be included in + ** the afpLockingContext */ + int nFilename; + pNew->pMethod = &sqlite3AFPLockingUnixIoMethod; + pNew->lockingContext = + sqlite3_malloc(sizeof(afpLockingContext)); + nFilename = strlen(zFilename)+1; + ((afpLockingContext *)pNew->lockingContext)->filePath = + sqlite3_malloc(nFilename); + memcpy(((afpLockingContext *)pNew->lockingContext)->filePath, + zFilename, nFilename); + srandomdev(); + break; + } + case flockLockingStyle: + /* flock locking doesn't need additional lockingContext information */ + pNew->pMethod = &sqlite3FlockLockingUnixIoMethod; + break; + case dotlockLockingStyle: { + /* dotlock locking uses the file path so it needs to be included in + ** the dotlockLockingContext */ + int nFilename; + pNew->pMethod = &sqlite3DotlockLockingUnixIoMethod; + pNew->lockingContext = sqlite3_malloc( + sizeof(dotlockLockingContext)); + nFilename = strlen(zFilename) + 6; + ((dotlockLockingContext *)pNew->lockingContext)->lockPath = + sqlite3_malloc( nFilename ); + sqlite3_snprintf(nFilename, + ((dotlockLockingContext *)pNew->lockingContext)->lockPath, + "%s.lock", zFilename); + break; + } + case posixLockingStyle: + /* posix locking doesn't need additional lockingContext information */ + pNew->pMethod = &sqlite3UnixIoMethod; + break; + case noLockingStyle: + case unsupportedLockingStyle: + default: + pNew->pMethod = &sqlite3NolockLockingUnixIoMethod; + } + OpenCounter(+1); + return SQLITE_OK; + } +} +#else /* SQLITE_ENABLE_LOCKING_STYLE */ +static int fillInUnixFile( + int h, /* Open file descriptor on file being opened */ + int dirfd, + sqlite3_file *pId, /* Write to the unixFile structure here */ + const char *zFilename /* Name of the file being opened */ +){ + unixFile *pNew = (unixFile *)pId; + int rc; + +#ifdef FD_CLOEXEC + fcntl(h, F_SETFD, fcntl(h, F_GETFD, 0) | FD_CLOEXEC); +#endif + + enterMutex(); + rc = findLockInfo(h, &pNew->pLock, &pNew->pOpen); + leaveMutex(); + if( rc ){ + close(h); + return SQLITE_NOMEM; + } + + OSTRACE3("OPEN %-3d %s\n", h, zFilename); + pNew->dirfd = -1; + pNew->h = h; + pNew->dirfd = dirfd; + SET_THREADID(pNew); + + pNew->pMethod = &sqlite3UnixIoMethod; + OpenCounter(+1); + return SQLITE_OK; +} +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ + +/* +** Open a file descriptor to the directory containing file zFilename. +** If successful, *pFd is set to the opened file descriptor and +** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM +** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined +** value. +** +** If SQLITE_OK is returned, the caller is responsible for closing +** the file descriptor *pFd using close(). +*/ +static int openDirectory(const char *zFilename, int *pFd){ + int ii; + int fd = -1; + char zDirname[MAX_PATHNAME+1]; + + sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); + for(ii=strlen(zDirname); ii>=0 && zDirname[ii]!='/'; ii--); + if( ii>0 ){ + zDirname[ii] = '\0'; + fd = open(zDirname, O_RDONLY|O_BINARY, 0); + if( fd>=0 ){ +#ifdef FD_CLOEXEC + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); +#endif + OSTRACE3("OPENDIR %-3d %s\n", fd, zDirname); + } + } + *pFd = fd; + return (fd>=0?SQLITE_OK:SQLITE_CANTOPEN); +} + +/* +** Open the file zPath. +** +** Previously, the SQLite OS layer used three functions in place of this +** one: +** +** sqlite3OsOpenReadWrite(); +** sqlite3OsOpenReadOnly(); +** sqlite3OsOpenExclusive(); +** +** These calls correspond to the following combinations of flags: +** +** ReadWrite() -> (READWRITE | CREATE) +** ReadOnly() -> (READONLY) +** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE) +** +** The old OpenExclusive() accepted a boolean argument - "delFlag". If +** true, the file was configured to be automatically deleted when the +** file handle closed. To achieve the same effect using this new +** interface, add the DELETEONCLOSE flag to those specified above for +** OpenExclusive(). +*/ +static int unixOpen( + sqlite3_vfs *pVfs, + const char *zPath, + sqlite3_file *pFile, + int flags, + int *pOutFlags +){ + int fd = 0; /* File descriptor returned by open() */ + int dirfd = -1; /* Directory file descriptor */ + int oflags = 0; /* Flags to pass to open() */ + int eType = flags&0xFFFFFF00; /* Type of file to open */ + + int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); + int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); + int isCreate = (flags & SQLITE_OPEN_CREATE); + int isReadonly = (flags & SQLITE_OPEN_READONLY); + int isReadWrite = (flags & SQLITE_OPEN_READWRITE); + + /* If creating a master or main-file journal, this function will open + ** a file-descriptor on the directory too. The first time unixSync() + ** is called the directory file descriptor will be fsync()ed and close()d. + */ + int isOpenDirectory = (isCreate && + (eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL) + ); + + /* Check the following statements are true: + ** + ** (a) Exactly one of the READWRITE and READONLY flags must be set, and + ** (b) if CREATE is set, then READWRITE must also be set, and + ** (c) if EXCLUSIVE is set, then CREATE must also be set. + ** (d) if DELETEONCLOSE is set, then CREATE must also be set. + */ + assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); + assert(isCreate==0 || isReadWrite); + assert(isExclusive==0 || isCreate); + assert(isDelete==0 || isCreate); + + + /* The main DB, main journal, and master journal are never automatically + ** deleted + */ + assert( eType!=SQLITE_OPEN_MAIN_DB || !isDelete ); + assert( eType!=SQLITE_OPEN_MAIN_JOURNAL || !isDelete ); + assert( eType!=SQLITE_OPEN_MASTER_JOURNAL || !isDelete ); + + /* Assert that the upper layer has set one of the "file-type" flags. */ + assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL + || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_TRANSIENT_DB + ); + + if( isReadonly ) oflags |= O_RDONLY; + if( isReadWrite ) oflags |= O_RDWR; + if( isCreate ) oflags |= O_CREAT; + if( isExclusive ) oflags |= (O_EXCL|O_NOFOLLOW); + oflags |= (O_LARGEFILE|O_BINARY); + + memset(pFile, 0, sizeof(unixFile)); + fd = open(zPath, oflags, isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS); + if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){ + /* Failed to open the file for read/write access. Try read-only. */ + flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); + flags |= SQLITE_OPEN_READONLY; + return unixOpen(pVfs, zPath, pFile, flags, pOutFlags); + } + if( fd<0 ){ + return SQLITE_CANTOPEN; + } + if( isDelete ){ + unlink(zPath); + } + if( pOutFlags ){ + *pOutFlags = flags; + } + + assert(fd!=0); + if( isOpenDirectory ){ + int rc = openDirectory(zPath, &dirfd); + if( rc!=SQLITE_OK ){ + close(fd); + return rc; + } + } + return fillInUnixFile(fd, dirfd, pFile, zPath); +} + +/* +** Delete the file at zPath. If the dirSync argument is true, fsync() +** the directory after deleting the file. +*/ +static int unixDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ + int rc = SQLITE_OK; + SimulateIOError(return SQLITE_IOERR_DELETE); + unlink(zPath); + if( dirSync ){ + int fd; + rc = openDirectory(zPath, &fd); + if( rc==SQLITE_OK ){ + if( fsync(fd) ){ + rc = SQLITE_IOERR_DIR_FSYNC; + } + close(fd); + } + } + return rc; +} + +/* +** Test the existance of or access permissions of file zPath. The +** test performed depends on the value of flags: +** +** SQLITE_ACCESS_EXISTS: Return 1 if the file exists +** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable. +** SQLITE_ACCESS_READONLY: Return 1 if the file is readable. +** +** Otherwise return 0. +*/ +static int unixAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){ + int amode = 0; + switch( flags ){ + case SQLITE_ACCESS_EXISTS: + amode = F_OK; + break; + case SQLITE_ACCESS_READWRITE: + amode = W_OK|R_OK; + break; + case SQLITE_ACCESS_READ: + amode = R_OK; + break; + + default: + assert(!"Invalid flags argument"); + } + return (access(zPath, amode)==0); +} + +/* +** Create a temporary file name in zBuf. zBuf must be allocated +** by the calling process and must be big enough to hold at least +** pVfs->mxPathname bytes. +*/ +static int unixGetTempname(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + static const char *azDirs[] = { + 0, + "/var/tmp", + "/usr/tmp", + "/tmp", + ".", + }; + static const unsigned char zChars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + int i, j; + struct stat buf; + const char *zDir = "."; + + /* It's odd to simulate an io-error here, but really this is just + ** using the io-error infrastructure to test that SQLite handles this + ** function failing. + */ + SimulateIOError( return SQLITE_ERROR ); + + azDirs[0] = sqlite3_temp_directory; + for(i=0; imxPathname==MAX_PATHNAME ); + assert( nBuf>=MAX_PATHNAME ); + sqlite3_snprintf(MAX_PATHNAME-17, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir); + j = strlen(zBuf); + sqlite3Randomness(15, &zBuf[j]); + for(i=0; i<15; i++, j++){ + zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; + } + zBuf[j] = 0; + }while( access(zBuf,0)==0 ); + return SQLITE_OK; +} + + +/* +** Turn a relative pathname into a full pathname. The relative path +** is stored as a nul-terminated string in the buffer pointed to by +** zPath. +** +** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes +** (in this case, MAX_PATHNAME bytes). The full-path is written to +** this buffer before returning. +*/ +static int unixFullPathname( + sqlite3_vfs *pVfs, /* Pointer to vfs object */ + const char *zPath, /* Possibly relative input path */ + int nOut, /* Size of output buffer in bytes */ + char *zOut /* Output buffer */ +){ + + /* It's odd to simulate an io-error here, but really this is just + ** using the io-error infrastructure to test that SQLite handles this + ** function failing. This function could fail if, for example, the + ** current working directly has been unlinked. + */ + SimulateIOError( return SQLITE_ERROR ); + + assert( pVfs->mxPathname==MAX_PATHNAME ); + zOut[MAX_PATHNAME-1] = '\0'; + if( zPath[0]=='/' ){ + sqlite3_snprintf(MAX_PATHNAME, zOut, "%s", zPath); + }else{ + int nCwd; + if( getcwd(zOut, MAX_PATHNAME-1)==0 ){ + return SQLITE_CANTOPEN; + } + nCwd = strlen(zOut); + sqlite3_snprintf(MAX_PATHNAME-nCwd, &zOut[nCwd], "/%s", zPath); + } + return SQLITE_OK; #if 0 /* @@ -2312,318 +2582,8 @@ char *sqlite3UnixFullPathname(const char *zRelative){ zFull[j] = 0; } #endif - - return zFull; } -/* -** Change the value of the fullsync flag in the given file descriptor. -*/ -static void unixSetFullSync(OsFile *id, int v){ - ((unixFile*)id)->fullSync = v; -} - -/* -** Return the underlying file handle for an OsFile -*/ -static int unixFileHandle(OsFile *id){ - return ((unixFile*)id)->h; -} - -/* -** Return an integer that indices the type of lock currently held -** by this handle. (Used for testing and analysis only.) -*/ -static int unixLockState(OsFile *id){ - return ((unixFile*)id)->locktype; -} - -/* -** Return the sector size in bytes of the underlying block device for -** the specified file. This is almost always 512 bytes, but may be -** larger for some devices. -** -** SQLite code assumes this function cannot fail. It also assumes that -** if two files are created in the same file-system directory (i.e. -** a database and it's journal file) that the sector size will be the -** same for both. -*/ -static int unixSectorSize(OsFile *id){ - return SQLITE_DEFAULT_SECTOR_SIZE; -} - -/* -** This vector defines all the methods that can operate on an OsFile -** for unix. -*/ -static const IoMethod sqlite3UnixIoMethod = { - unixClose, - unixOpenDirectory, - unixRead, - unixWrite, - unixSeek, - unixTruncate, - unixSync, - unixSetFullSync, - unixFileHandle, - unixFileSize, - unixLock, - unixUnlock, - unixLockState, - unixCheckReservedLock, - unixSectorSize, -}; - -#ifdef SQLITE_ENABLE_LOCKING_STYLE -/* - ** This vector defines all the methods that can operate on an OsFile - ** for unix with AFP style file locking. - */ -static const IoMethod sqlite3AFPLockingUnixIoMethod = { - afpUnixClose, - unixOpenDirectory, - unixRead, - unixWrite, - unixSeek, - unixTruncate, - unixSync, - unixSetFullSync, - unixFileHandle, - unixFileSize, - afpUnixLock, - afpUnixUnlock, - unixLockState, - afpUnixCheckReservedLock, - unixSectorSize, -}; - -/* - ** This vector defines all the methods that can operate on an OsFile - ** for unix with flock() style file locking. - */ -static const IoMethod sqlite3FlockLockingUnixIoMethod = { - flockUnixClose, - unixOpenDirectory, - unixRead, - unixWrite, - unixSeek, - unixTruncate, - unixSync, - unixSetFullSync, - unixFileHandle, - unixFileSize, - flockUnixLock, - flockUnixUnlock, - unixLockState, - flockUnixCheckReservedLock, - unixSectorSize, -}; - -/* - ** This vector defines all the methods that can operate on an OsFile - ** for unix with dotlock style file locking. - */ -static const IoMethod sqlite3DotlockLockingUnixIoMethod = { - dotlockUnixClose, - unixOpenDirectory, - unixRead, - unixWrite, - unixSeek, - unixTruncate, - unixSync, - unixSetFullSync, - unixFileHandle, - unixFileSize, - dotlockUnixLock, - dotlockUnixUnlock, - unixLockState, - dotlockUnixCheckReservedLock, - unixSectorSize, -}; - -/* - ** This vector defines all the methods that can operate on an OsFile - ** for unix with dotlock style file locking. - */ -static const IoMethod sqlite3NolockLockingUnixIoMethod = { - nolockUnixClose, - unixOpenDirectory, - unixRead, - unixWrite, - unixSeek, - unixTruncate, - unixSync, - unixSetFullSync, - unixFileHandle, - unixFileSize, - nolockUnixLock, - nolockUnixUnlock, - unixLockState, - nolockUnixCheckReservedLock, - unixSectorSize, -}; - -#endif /* SQLITE_ENABLE_LOCKING_STYLE */ - -/* -** Allocate memory for a new unixFile and initialize that unixFile. -** Write a pointer to the new unixFile into *pId. -** If we run out of memory, close the file and return an error. -*/ -#ifdef SQLITE_ENABLE_LOCKING_STYLE -/* - ** When locking extensions are enabled, the filepath and locking style - ** are needed to determine the unixFile pMethod to use for locking operations. - ** The locking-style specific lockingContext data structure is created - ** and assigned here also. - */ -static int allocateUnixFile( - int h, /* Open file descriptor of file being opened */ - OsFile **pId, /* Write completed initialization here */ - const char *zFilename, /* Name of the file being opened */ - int delFlag /* Delete-on-or-before-close flag */ -){ - sqlite3LockingStyle lockingStyle; - unixFile *pNew; - unixFile f; - int rc; - - memset(&f, 0, sizeof(f)); - lockingStyle = sqlite3DetectLockingStyle(zFilename, h); - if ( lockingStyle == posixLockingStyle ) { - sqlite3OsEnterMutex(); - rc = findLockInfo(h, &f.pLock, &f.pOpen); - sqlite3OsLeaveMutex(); - if( rc ){ - close(h); - unlink(zFilename); - return SQLITE_NOMEM; - } - } else { - /* pLock and pOpen are only used for posix advisory locking */ - f.pLock = NULL; - f.pOpen = NULL; - } - if( delFlag ){ - unlink(zFilename); - } - f.dirfd = -1; - f.h = h; - SET_THREADID(&f); - pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) ); - if( pNew==0 ){ - close(h); - sqlite3OsEnterMutex(); - releaseLockInfo(f.pLock); - releaseOpenCnt(f.pOpen); - sqlite3OsLeaveMutex(); - *pId = 0; - return SQLITE_NOMEM; - }else{ - *pNew = f; - switch(lockingStyle) { - case afpLockingStyle: { - /* afp locking uses the file path so it needs to be included in - ** the afpLockingContext */ - int nFilename; - pNew->pMethod = &sqlite3AFPLockingUnixIoMethod; - pNew->lockingContext = - sqlite3ThreadSafeMalloc(sizeof(afpLockingContext)); - nFilename = strlen(zFilename)+1; - ((afpLockingContext *)pNew->lockingContext)->filePath = - sqlite3ThreadSafeMalloc(nFilename); - memcpy(((afpLockingContext *)pNew->lockingContext)->filePath, - zFilename, nFilename); - srandomdev(); - break; - } - case flockLockingStyle: - /* flock locking doesn't need additional lockingContext information */ - pNew->pMethod = &sqlite3FlockLockingUnixIoMethod; - break; - case dotlockLockingStyle: { - /* dotlock locking uses the file path so it needs to be included in - ** the dotlockLockingContext */ - int nFilename; - pNew->pMethod = &sqlite3DotlockLockingUnixIoMethod; - pNew->lockingContext = sqlite3ThreadSafeMalloc( - sizeof(dotlockLockingContext)); - nFilename = strlen(zFilename) + 6; - ((dotlockLockingContext *)pNew->lockingContext)->lockPath = - sqlite3ThreadSafeMalloc( nFilename ); - sqlite3_snprintf(nFilename, - ((dotlockLockingContext *)pNew->lockingContext)->lockPath, - "%s.lock", zFilename); - break; - } - case posixLockingStyle: - /* posix locking doesn't need additional lockingContext information */ - pNew->pMethod = &sqlite3UnixIoMethod; - break; - case noLockingStyle: - case unsupportedLockingStyle: - default: - pNew->pMethod = &sqlite3NolockLockingUnixIoMethod; - } - *pId = (OsFile*)pNew; - OpenCounter(+1); - return SQLITE_OK; - } -} -#else /* SQLITE_ENABLE_LOCKING_STYLE */ -static int allocateUnixFile( - int h, /* Open file descriptor on file being opened */ - OsFile **pId, /* Write the resul unixFile structure here */ - const char *zFilename, /* Name of the file being opened */ - int delFlag /* If true, delete the file on or before closing */ -){ - unixFile *pNew; - unixFile f; - int rc; - -#ifdef FD_CLOEXEC - fcntl(h, F_SETFD, fcntl(h, F_GETFD, 0) | FD_CLOEXEC); -#endif - memset(&f, 0, sizeof(f)); - sqlite3OsEnterMutex(); - rc = findLockInfo(h, &f.pLock, &f.pOpen); - sqlite3OsLeaveMutex(); - if( delFlag ){ - unlink(zFilename); - } - if( rc ){ - close(h); - return SQLITE_NOMEM; - } - OSTRACE3("OPEN %-3d %s\n", h, zFilename); - f.dirfd = -1; - f.h = h; - SET_THREADID(&f); - pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) ); - if( pNew==0 ){ - close(h); - sqlite3OsEnterMutex(); - releaseLockInfo(f.pLock); - releaseOpenCnt(f.pOpen); - sqlite3OsLeaveMutex(); - *pId = 0; - return SQLITE_NOMEM; - }else{ - *pNew = f; - pNew->pMethod = &sqlite3UnixIoMethod; - *pId = (OsFile*)pNew; - OpenCounter(+1); - return SQLITE_OK; - } -} -#endif /* SQLITE_ENABLE_LOCKING_STYLE */ - -#endif /* SQLITE_OMIT_DISKIO */ -/*************************************************************************** -** Everything above deals with file I/O. Everything that follows deals -** with other miscellanous aspects of the operating system interface -****************************************************************************/ - #ifndef SQLITE_OMIT_LOAD_EXTENSION /* @@ -2631,23 +2591,46 @@ static int allocateUnixFile( ** within the shared library, and closing the shared library. */ #include -void *sqlite3UnixDlopen(const char *zFilename){ +static void *unixDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL); } -void *sqlite3UnixDlsym(void *pHandle, const char *zSymbol){ - return dlsym(pHandle, zSymbol); -} -int sqlite3UnixDlclose(void *pHandle){ - return dlclose(pHandle); -} -#endif /* SQLITE_OMIT_LOAD_EXTENSION */ /* -** Get information to seed the random number generator. The seed -** is written into the buffer zBuf[256]. The calling function must -** supply a sufficiently large buffer. +** SQLite calls this function immediately after a call to unixDlSym() or +** unixDlOpen() fails (returns a null pointer). If a more detailed error +** message is available, it is written to zBufOut. If no error message +** is available, zBufOut is left unmodified and SQLite uses a default +** error message. */ -int sqlite3UnixRandomSeed(char *zBuf){ +static void unixDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ + char *zErr; + enterMutex(); + zErr = dlerror(); + if( zErr ){ + sqlite3_snprintf(nBuf, zBufOut, "%s", zErr); + } + leaveMutex(); +} +static void *unixDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ + return dlsym(pHandle, zSymbol); +} +static void unixDlClose(sqlite3_vfs *pVfs, void *pHandle){ + dlclose(pHandle); +} +#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ + #define unixDlOpen 0 + #define unixDlError 0 + #define unixDlSym 0 + #define unixDlClose 0 +#endif + +/* +** Write nBuf bytes of random data to the supplied buffer zBuf. +*/ +static int unixRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + + assert(nBuf>=(sizeof(time_t)+sizeof(int))); + /* We have to initialize zBuf to prevent valgrind from reporting ** errors. The reports issued by valgrind are incorrect - we would ** prefer that the randomness be increased by making use of the @@ -2660,7 +2643,7 @@ int sqlite3UnixRandomSeed(char *zBuf){ ** that we always use the same random number sequence. This makes the ** tests repeatable. */ - memset(zBuf, 0, 256); + memset(zBuf, 0, nBuf); #if !defined(SQLITE_TEST) { int pid, fd; @@ -2670,9 +2653,9 @@ int sqlite3UnixRandomSeed(char *zBuf){ time(&t); memcpy(zBuf, &t, sizeof(t)); pid = getpid(); - memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid)); + memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid)); }else{ - read(fd, zBuf, 256); + read(fd, zBuf, nBuf); close(fd); } } @@ -2680,224 +2663,23 @@ int sqlite3UnixRandomSeed(char *zBuf){ return SQLITE_OK; } + /* ** Sleep for a little while. Return the amount of time slept. -** The argument is the number of milliseconds we want to sleep. +** The argument is the number of microseconds we want to sleep. +** The return value is the number of microseconds of sleep actually +** requested from the underlying operating system, a number which +** might be greater than or equal to the argument, but not less +** than the argument. */ -int sqlite3UnixSleep(int ms){ +static int unixSleep(sqlite3_vfs *pVfs, int microseconds){ #if defined(HAVE_USLEEP) && HAVE_USLEEP - usleep(ms*1000); - return ms; + usleep(microseconds); + return microseconds; #else - sleep((ms+999)/1000); - return 1000*((ms+999)/1000); -#endif -} - -/* -** Static variables used for thread synchronization. -** -** inMutex the nesting depth of the recursive mutex. The thread -** holding mutexMain can read this variable at any time. -** But is must hold mutexAux to change this variable. Other -** threads must hold mutexAux to read the variable and can -** never write. -** -** mutexOwner The thread id of the thread holding mutexMain. Same -** access rules as for inMutex. -** -** mutexOwnerValid True if the value in mutexOwner is valid. The same -** access rules apply as for inMutex. -** -** mutexMain The main mutex. Hold this mutex in order to get exclusive -** access to SQLite data structures. -** -** mutexAux An auxiliary mutex needed to access variables defined above. -** -** Mutexes are always acquired in this order: mutexMain mutexAux. It -** is not necessary to acquire mutexMain in order to get mutexAux - just -** do not attempt to acquire them in the reverse order: mutexAux mutexMain. -** Either get the mutexes with mutexMain first or get mutexAux only. -** -** When running on a platform where the three variables inMutex, mutexOwner, -** and mutexOwnerValid can be set atomically, the mutexAux is not required. -** On many systems, all three are 32-bit integers and writing to a 32-bit -** integer is atomic. I think. But there are no guarantees. So it seems -** safer to protect them using mutexAux. -*/ -static int inMutex = 0; -#ifdef SQLITE_UNIX_THREADS -static pthread_t mutexOwner; /* Thread holding mutexMain */ -static int mutexOwnerValid = 0; /* True if mutexOwner is valid */ -static pthread_mutex_t mutexMain = PTHREAD_MUTEX_INITIALIZER; /* The mutex */ -static pthread_mutex_t mutexAux = PTHREAD_MUTEX_INITIALIZER; /* Aux mutex */ -#endif - -/* -** The following pair of routine implement mutual exclusion for -** multi-threaded processes. Only a single thread is allowed to -** executed code that is surrounded by EnterMutex() and LeaveMutex(). -** -** SQLite uses only a single Mutex. There is not much critical -** code and what little there is executes quickly and without blocking. -** -** As of version 3.3.2, this mutex must be recursive. -*/ -void sqlite3UnixEnterMutex(){ -#ifdef SQLITE_UNIX_THREADS - pthread_mutex_lock(&mutexAux); - if( !mutexOwnerValid || !pthread_equal(mutexOwner, pthread_self()) ){ - pthread_mutex_unlock(&mutexAux); - pthread_mutex_lock(&mutexMain); - assert( inMutex==0 ); - assert( !mutexOwnerValid ); - pthread_mutex_lock(&mutexAux); - mutexOwner = pthread_self(); - mutexOwnerValid = 1; - } - inMutex++; - pthread_mutex_unlock(&mutexAux); -#else - inMutex++; -#endif -} -void sqlite3UnixLeaveMutex(){ - assert( inMutex>0 ); -#ifdef SQLITE_UNIX_THREADS - pthread_mutex_lock(&mutexAux); - inMutex--; - assert( pthread_equal(mutexOwner, pthread_self()) ); - if( inMutex==0 ){ - assert( mutexOwnerValid ); - mutexOwnerValid = 0; - pthread_mutex_unlock(&mutexMain); - } - pthread_mutex_unlock(&mutexAux); -#else - inMutex--; -#endif -} - -/* -** Return TRUE if the mutex is currently held. -** -** If the thisThrd parameter is true, return true only if the -** calling thread holds the mutex. If the parameter is false, return -** true if any thread holds the mutex. -*/ -int sqlite3UnixInMutex(int thisThrd){ -#ifdef SQLITE_UNIX_THREADS - int rc; - pthread_mutex_lock(&mutexAux); - rc = inMutex>0 && (thisThrd==0 || pthread_equal(mutexOwner,pthread_self())); - pthread_mutex_unlock(&mutexAux); - return rc; -#else - return inMutex>0; -#endif -} - -/* -** Remember the number of thread-specific-data blocks allocated. -** Use this to verify that we are not leaking thread-specific-data. -** Ticket #1601 -*/ -#ifdef SQLITE_TEST -int sqlite3_tsd_count = 0; -# ifdef SQLITE_UNIX_THREADS - static pthread_mutex_t tsd_counter_mutex = PTHREAD_MUTEX_INITIALIZER; -# define TSD_COUNTER(N) \ - pthread_mutex_lock(&tsd_counter_mutex); \ - sqlite3_tsd_count += N; \ - pthread_mutex_unlock(&tsd_counter_mutex); -# else -# define TSD_COUNTER(N) sqlite3_tsd_count += N -# endif -#else -# define TSD_COUNTER(N) /* no-op */ -#endif - -/* -** If called with allocateFlag>0, then return a pointer to thread -** specific data for the current thread. Allocate and zero the -** thread-specific data if it does not already exist. -** -** If called with allocateFlag==0, then check the current thread -** specific data. Return it if it exists. If it does not exist, -** then return NULL. -** -** If called with allocateFlag<0, check to see if the thread specific -** data is allocated and is all zero. If it is then deallocate it. -** Return a pointer to the thread specific data or NULL if it is -** unallocated or gets deallocated. -*/ -ThreadData *sqlite3UnixThreadSpecificData(int allocateFlag){ - static const ThreadData zeroData = {0}; /* Initializer to silence warnings - ** from broken compilers */ -#ifdef SQLITE_UNIX_THREADS - static pthread_key_t key; - static int keyInit = 0; - ThreadData *pTsd; - - if( !keyInit ){ - sqlite3OsEnterMutex(); - if( !keyInit ){ - int rc; - rc = pthread_key_create(&key, 0); - if( rc ){ - sqlite3OsLeaveMutex(); - return 0; - } - keyInit = 1; - } - sqlite3OsLeaveMutex(); - } - - pTsd = pthread_getspecific(key); - if( allocateFlag>0 ){ - if( pTsd==0 ){ - if( !sqlite3TestMallocFail() ){ - pTsd = sqlite3OsMalloc(sizeof(zeroData)); - } -#ifdef SQLITE_MEMDEBUG - sqlite3_isFail = 0; -#endif - if( pTsd ){ - *pTsd = zeroData; - pthread_setspecific(key, pTsd); - TSD_COUNTER(+1); - } - } - }else if( pTsd!=0 && allocateFlag<0 - && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ - sqlite3OsFree(pTsd); - pthread_setspecific(key, 0); - TSD_COUNTER(-1); - pTsd = 0; - } - return pTsd; -#else - static ThreadData *pTsd = 0; - if( allocateFlag>0 ){ - if( pTsd==0 ){ - if( !sqlite3TestMallocFail() ){ - pTsd = sqlite3OsMalloc( sizeof(zeroData) ); - } -#ifdef SQLITE_MEMDEBUG - sqlite3_isFail = 0; -#endif - if( pTsd ){ - *pTsd = zeroData; - TSD_COUNTER(+1); - } - } - }else if( pTsd!=0 && allocateFlag<0 - && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ - sqlite3OsFree(pTsd); - TSD_COUNTER(-1); - pTsd = 0; - } - return pTsd; + int seconds = (microseconds+999999)/1000000; + sleep(seconds); + return seconds*1000000; #endif } @@ -2914,7 +2696,7 @@ int sqlite3_current_time = 0; ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ -int sqlite3UnixCurrentTime(double *prNow){ +static int unixCurrentTime(sqlite3_vfs *pVfs, double *prNow){ #ifdef NO_GETTOD time_t t; time(&t); @@ -2932,4 +2714,36 @@ int sqlite3UnixCurrentTime(double *prNow){ return 0; } +/* +** Return a pointer to the sqlite3DefaultVfs structure. We use +** a function rather than give the structure global scope because +** some compilers (MSVC) do not allow forward declarations of +** initialized structures. +*/ +sqlite3_vfs *sqlite3OsDefaultVfs(void){ + static sqlite3_vfs unixVfs = { + 1, /* iVersion */ + sizeof(unixFile), /* szOsFile */ + MAX_PATHNAME, /* mxPathname */ + 0, /* pNext */ + "unix", /* zName */ + 0, /* pAppData */ + + unixOpen, /* xOpen */ + unixDelete, /* xDelete */ + unixAccess, /* xAccess */ + unixGetTempname, /* xGetTempName */ + unixFullPathname, /* xFullPathname */ + unixDlOpen, /* xDlOpen */ + unixDlError, /* xDlError */ + unixDlSym, /* xDlSym */ + unixDlClose, /* xDlClose */ + unixRandomness, /* xRandomness */ + unixSleep, /* xSleep */ + unixCurrentTime /* xCurrentTime */ + }; + + return &unixVfs; +} + #endif /* OS_UNIX */ diff --git a/extensions/sqlite/sqlite-source/os_win.c b/extensions/sqlite/sqlite-source/os_win.c index 9ebb9dc3..bcb1c6ec 100644 --- a/extensions/sqlite/sqlite-source/os_win.c +++ b/extensions/sqlite/sqlite-source/os_win.c @@ -13,9 +13,35 @@ ** This file contains code that is specific to windows. */ #include "sqliteInt.h" -#include "os.h" #if OS_WIN /* This file is used for windows only */ + +/* +** A Note About Memory Allocation: +** +** This driver uses malloc()/free() directly rather than going through +** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers +** are designed for use on embedded systems where memory is scarce and +** malloc failures happen frequently. Win32 does not typically run on +** embedded systems, and when it does the developers normally have bigger +** problems to worry about than running out of memory. So there is not +** a compelling need to use the wrappers. +** +** But there is a good reason to not use the wrappers. If we use the +** wrappers then we will get simulated malloc() failures within this +** driver. And that causes all kinds of problems for our tests. We +** could enhance SQLite to deal with simulated malloc failures within +** the OS driver, but the code to deal with those failure would not +** be exercised on Linux (which does not need to malloc() in the driver) +** and so we would have difficulty writing coverage tests for that +** code. Better to leave the code out, we think. +** +** The point of this discussion is as follows: When creating a new +** OS layer for an embedded system, if you use this file as an example, +** avoid the use of malloc()/free(). Those routines work ok on windows +** desktops but not so well in embedded systems. +*/ + #include #ifdef __CYGWIN__ @@ -59,12 +85,12 @@ typedef struct winceLock { #endif /* -** The winFile structure is a subclass of OsFile specific to the win32 +** The winFile structure is a subclass of sqlite3_file* specific to the win32 ** portability layer. */ typedef struct winFile winFile; struct winFile { - IoMethod const *pMethod;/* Must be first */ + const sqlite3_io_methods *pMethod;/* Must be first */ HANDLE h; /* Handle for accessing the file */ unsigned char locktype; /* Type of lock currently held on this file */ short sharedLockByte; /* Randomly chosen byte used as a shared lock */ @@ -78,13 +104,6 @@ struct winFile { }; -/* -** Do not include any of the File I/O interface procedures if the -** SQLITE_OMIT_DISKIO macro is defined (indicating that there database -** will be in-memory only) -*/ -#ifndef SQLITE_OMIT_DISKIO - /* ** The following variable is (normally) set once and never changes ** thereafter. It records whether the operating system is Win95 @@ -97,7 +116,11 @@ struct winFile { ** In order to facilitate testing on a WinNT system, the test fixture ** can manually set this value to 1 to emulate Win98 behavior. */ +#ifdef SQLITE_TEST int sqlite3_os_type = 0; +#else +static int sqlite3_os_type = 0; +#endif /* ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, @@ -127,20 +150,20 @@ int sqlite3_os_type = 0; /* ** Convert a UTF-8 string to microsoft unicode (UTF-16?). ** -** Space to hold the returned string is obtained from sqliteMalloc. +** Space to hold the returned string is obtained from malloc. */ static WCHAR *utf8ToUnicode(const char *zFilename){ int nChar; WCHAR *zWideFilename; nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); - zWideFilename = sqliteMalloc( nChar*sizeof(zWideFilename[0]) ); + zWideFilename = malloc( nChar*sizeof(zWideFilename[0]) ); if( zWideFilename==0 ){ return 0; } nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar); if( nChar==0 ){ - sqliteFree(zWideFilename); + free(zWideFilename); zWideFilename = 0; } return zWideFilename; @@ -148,21 +171,21 @@ static WCHAR *utf8ToUnicode(const char *zFilename){ /* ** Convert microsoft unicode to UTF-8. Space to hold the returned string is -** obtained from sqliteMalloc(). +** obtained from malloc(). */ static char *unicodeToUtf8(const WCHAR *zWideFilename){ int nByte; char *zFilename; nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); - zFilename = sqliteMalloc( nByte ); + zFilename = malloc( nByte ); if( zFilename==0 ){ return 0; } nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte, 0, 0); if( nByte == 0 ){ - sqliteFree(zFilename); + free(zFilename); zFilename = 0; } return zFilename; @@ -173,7 +196,7 @@ static char *unicodeToUtf8(const WCHAR *zWideFilename){ ** current codepage settings for file apis. ** ** Space to hold the returned string is obtained -** from sqliteMalloc. +** from malloc. */ static WCHAR *mbcsToUnicode(const char *zFilename){ int nByte; @@ -181,13 +204,13 @@ static WCHAR *mbcsToUnicode(const char *zFilename){ int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*sizeof(WCHAR); - zMbcsFilename = sqliteMalloc( nByte*sizeof(zMbcsFilename[0]) ); + zMbcsFilename = malloc( nByte*sizeof(zMbcsFilename[0]) ); if( zMbcsFilename==0 ){ return 0; } nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte); if( nByte==0 ){ - sqliteFree(zMbcsFilename); + free(zMbcsFilename); zMbcsFilename = 0; } return zMbcsFilename; @@ -198,7 +221,7 @@ static WCHAR *mbcsToUnicode(const char *zFilename){ ** user's Ansi codepage. ** ** Space to hold the returned string is obtained from -** sqliteMalloc(). +** malloc(). */ static char *unicodeToMbcs(const WCHAR *zWideFilename){ int nByte; @@ -206,14 +229,14 @@ static char *unicodeToMbcs(const WCHAR *zWideFilename){ int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0); - zFilename = sqliteMalloc( nByte ); + zFilename = malloc( nByte ); if( zFilename==0 ){ return 0; } nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte, 0, 0); if( nByte == 0 ){ - sqliteFree(zFilename); + free(zFilename); zFilename = 0; } return zFilename; @@ -221,7 +244,7 @@ static char *unicodeToMbcs(const WCHAR *zWideFilename){ /* ** Convert multibyte character string to UTF-8. Space to hold the -** returned string is obtained from sqliteMalloc(). +** returned string is obtained from malloc(). */ static char *mbcsToUtf8(const char *zFilename){ char *zFilenameUtf8; @@ -232,13 +255,13 @@ static char *mbcsToUtf8(const char *zFilename){ return 0; } zFilenameUtf8 = unicodeToUtf8(zTmpWide); - sqliteFree(zTmpWide); + free(zTmpWide); return zFilenameUtf8; } /* ** Convert UTF-8 to multibyte character string. Space to hold the -** returned string is obtained from sqliteMalloc(). +** returned string is obtained from malloc(). */ static char *utf8ToMbcs(const char *zFilename){ char *zFilenameMbcs; @@ -249,7 +272,7 @@ static char *utf8ToMbcs(const char *zFilename){ return 0; } zFilenameMbcs = unicodeToMbcs(zTmpWide); - sqliteFree(zTmpWide); + free(zTmpWide); return zFilenameMbcs; } @@ -267,7 +290,7 @@ struct tm *__cdecl localtime(const time_t *t) static struct tm y; FILETIME uTm, lTm; SYSTEMTIME pTm; - i64 t64; + sqlite3_int64 t64; t64 = *t; t64 = (t64 + 11644473600)*10000000; uTm.dwLowDateTime = t64 & 0xFFFFFFFF; @@ -329,7 +352,7 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){ /* Create/open the named mutex */ pFile->hMutex = CreateMutexW(NULL, FALSE, zName); if (!pFile->hMutex){ - sqliteFree(zName); + free(zName); return FALSE; } @@ -351,7 +374,7 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){ bInit = FALSE; } - sqliteFree(zName); + free(zName); /* If we succeeded in making the shared memory handle, map it. */ if (pFile->hShared){ @@ -410,7 +433,7 @@ static void winceDestroyLock(winFile *pFile){ if( pFile->zDeleteOnClose ){ DeleteFileW(pFile->zDeleteOnClose); - sqliteFree(pFile->zDeleteOnClose); + free(pFile->zDeleteOnClose); pFile->zDeleteOnClose = 0; } @@ -565,400 +588,10 @@ static BOOL winceLockFileEx( *****************************************************************************/ #endif /* OS_WINCE */ -/* -** Convert a UTF-8 filename into whatever form the underlying -** operating system wants filenames in. Space to hold the result -** is obtained from sqliteMalloc and must be freed by the calling -** function. -*/ -static void *convertUtf8Filename(const char *zFilename){ - void *zConverted = 0; - if( isNT() ){ - zConverted = utf8ToUnicode(zFilename); - }else{ - zConverted = utf8ToMbcs(zFilename); - } - /* caller will handle out of memory */ - return zConverted; -} - -/* -** Delete the named file. -** -** Note that windows does not allow a file to be deleted if some other -** process has it open. Sometimes a virus scanner or indexing program -** will open a journal file shortly after it is created in order to do -** whatever it is it does. While this other process is holding the -** file open, we will be unable to delete it. To work around this -** problem, we delay 100 milliseconds and try to delete again. Up -** to MX_DELETION_ATTEMPTs deletion attempts are run before giving -** up and returning an error. -*/ -#define MX_DELETION_ATTEMPTS 3 -int sqlite3WinDelete(const char *zFilename){ - int cnt = 0; - int rc; - void *zConverted = convertUtf8Filename(zFilename); - if( zConverted==0 ){ - return SQLITE_NOMEM; - } - SimulateIOError(return SQLITE_IOERR_DELETE); - if( isNT() ){ - do{ - rc = DeleteFileW(zConverted); - }while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff - && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); - }else{ -#if OS_WINCE - return SQLITE_NOMEM; -#else - do{ - rc = DeleteFileA(zConverted); - }while( rc==0 && GetFileAttributesA(zConverted)!=0xffffffff - && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); -#endif - } - sqliteFree(zConverted); - OSTRACE2("DELETE \"%s\"\n", zFilename); - return rc!=0 ? SQLITE_OK : SQLITE_IOERR; -} - -/* -** Return TRUE if the named file exists. -*/ -int sqlite3WinFileExists(const char *zFilename){ - int exists = 0; - void *zConverted = convertUtf8Filename(zFilename); - if( zConverted==0 ){ - return SQLITE_NOMEM; - } - if( isNT() ){ - exists = GetFileAttributesW((WCHAR*)zConverted) != 0xffffffff; - }else{ -#if OS_WINCE - return SQLITE_NOMEM; -#else - exists = GetFileAttributesA((char*)zConverted) != 0xffffffff; -#endif - } - sqliteFree(zConverted); - return exists; -} - -/* Forward declaration */ -static int allocateWinFile(winFile *pInit, OsFile **pId); - -/* -** Attempt to open a file for both reading and writing. If that -** fails, try opening it read-only. If the file does not exist, -** try to create it. -** -** On success, a handle for the open file is written to *id -** and *pReadonly is set to 0 if the file was opened for reading and -** writing or 1 if the file was opened read-only. The function returns -** SQLITE_OK. -** -** On failure, the function returns SQLITE_CANTOPEN and leaves -** *id and *pReadonly unchanged. -*/ -int sqlite3WinOpenReadWrite( - const char *zFilename, - OsFile **pId, - int *pReadonly -){ - winFile f; - HANDLE h; - void *zConverted = convertUtf8Filename(zFilename); - if( zConverted==0 ){ - return SQLITE_NOMEM; - } - assert( *pId==0 ); - - if( isNT() ){ - h = CreateFileW((WCHAR*)zConverted, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); - if( h==INVALID_HANDLE_VALUE ){ - h = CreateFileW((WCHAR*)zConverted, - GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); - if( h==INVALID_HANDLE_VALUE ){ - sqliteFree(zConverted); - return SQLITE_CANTOPEN; - } - *pReadonly = 1; - }else{ - *pReadonly = 0; - } -#if OS_WINCE - if (!winceCreateLock(zFilename, &f)){ - CloseHandle(h); - sqliteFree(zConverted); - return SQLITE_CANTOPEN; - } -#endif - }else{ -#if OS_WINCE - return SQLITE_NOMEM; -#else - h = CreateFileA((char*)zConverted, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); - if( h==INVALID_HANDLE_VALUE ){ - h = CreateFileA((char*)zConverted, - GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); - if( h==INVALID_HANDLE_VALUE ){ - sqliteFree(zConverted); - return SQLITE_CANTOPEN; - } - *pReadonly = 1; - }else{ - *pReadonly = 0; - } -#endif /* OS_WINCE */ - } - - sqliteFree(zConverted); - - f.h = h; -#if OS_WINCE - f.zDeleteOnClose = 0; -#endif - OSTRACE3("OPEN R/W %d \"%s\"\n", h, zFilename); - return allocateWinFile(&f, pId); -} - - -/* -** Attempt to open a new file for exclusive access by this process. -** The file will be opened for both reading and writing. To avoid -** a potential security problem, we do not allow the file to have -** previously existed. Nor do we allow the file to be a symbolic -** link. -** -** If delFlag is true, then make arrangements to automatically delete -** the file when it is closed. -** -** On success, write the file handle into *id and return SQLITE_OK. -** -** On failure, return SQLITE_CANTOPEN. -** -** Sometimes if we have just deleted a prior journal file, windows -** will fail to open a new one because there is a "pending delete". -** To work around this bug, we pause for 100 milliseconds and attempt -** a second open after the first one fails. The whole operation only -** fails if both open attempts are unsuccessful. -*/ -int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ - winFile f; - HANDLE h; - DWORD fileflags; - void *zConverted = convertUtf8Filename(zFilename); - if( zConverted==0 ){ - return SQLITE_NOMEM; - } - assert( *pId == 0 ); - fileflags = FILE_FLAG_RANDOM_ACCESS; -#if !OS_WINCE - if( delFlag ){ - fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE; - } -#endif - if( isNT() ){ - int cnt = 0; - do{ - h = CreateFileW((WCHAR*)zConverted, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - fileflags, - NULL - ); - }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) ); - }else{ -#if OS_WINCE - return SQLITE_NOMEM; -#else - int cnt = 0; - do{ - h = CreateFileA((char*)zConverted, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - fileflags, - NULL - ); - }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) ); -#endif /* OS_WINCE */ - } -#if OS_WINCE - if( delFlag && h!=INVALID_HANDLE_VALUE ){ - f.zDeleteOnClose = zConverted; - zConverted = 0; - } - f.hMutex = NULL; -#endif - sqliteFree(zConverted); - if( h==INVALID_HANDLE_VALUE ){ - return SQLITE_CANTOPEN; - } - f.h = h; - OSTRACE3("OPEN EX %d \"%s\"\n", h, zFilename); - return allocateWinFile(&f, pId); -} - -/* -** Attempt to open a new file for read-only access. -** -** On success, write the file handle into *id and return SQLITE_OK. -** -** On failure, return SQLITE_CANTOPEN. -*/ -int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){ - winFile f; - HANDLE h; - void *zConverted = convertUtf8Filename(zFilename); - if( zConverted==0 ){ - return SQLITE_NOMEM; - } - assert( *pId==0 ); - if( isNT() ){ - h = CreateFileW((WCHAR*)zConverted, - GENERIC_READ, - 0, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); - }else{ -#if OS_WINCE - return SQLITE_NOMEM; -#else - h = CreateFileA((char*)zConverted, - GENERIC_READ, - 0, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL - ); -#endif - } - sqliteFree(zConverted); - if( h==INVALID_HANDLE_VALUE ){ - return SQLITE_CANTOPEN; - } - f.h = h; -#if OS_WINCE - f.zDeleteOnClose = 0; - f.hMutex = NULL; -#endif - OSTRACE3("OPEN RO %d \"%s\"\n", h, zFilename); - return allocateWinFile(&f, pId); -} - -/* -** Attempt to open a file descriptor for the directory that contains a -** file. This file descriptor can be used to fsync() the directory -** in order to make sure the creation of a new file is actually written -** to disk. -** -** This routine is only meaningful for Unix. It is a no-op under -** windows since windows does not support hard links. -** -** On success, a handle for a previously open file is at *id is -** updated with the new directory file descriptor and SQLITE_OK is -** returned. -** -** On failure, the function returns SQLITE_CANTOPEN and leaves -** *id unchanged. -*/ -static int winOpenDirectory( - OsFile *id, - const char *zDirname -){ - return SQLITE_OK; -} - -/* -** Create a temporary file name in zBuf. zBuf must be big enough to -** hold at least SQLITE_TEMPNAME_SIZE characters. -*/ -int sqlite3WinTempFileName(char *zBuf){ - static char zChars[] = - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789"; - int i, j; - char zTempPath[SQLITE_TEMPNAME_SIZE]; - if( sqlite3_temp_directory ){ - strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30); - zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0; - }else if( isNT() ){ - char *zMulti; - WCHAR zWidePath[SQLITE_TEMPNAME_SIZE]; - GetTempPathW(SQLITE_TEMPNAME_SIZE-30, zWidePath); - zMulti = unicodeToUtf8(zWidePath); - if( zMulti ){ - strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30); - zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0; - sqliteFree(zMulti); - }else{ - return SQLITE_NOMEM; - } - }else{ - char *zUtf8; - char zMbcsPath[SQLITE_TEMPNAME_SIZE]; - GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zMbcsPath); - zUtf8 = mbcsToUtf8(zMbcsPath); - if( zUtf8 ){ - strncpy(zTempPath, zUtf8, SQLITE_TEMPNAME_SIZE-30); - zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0; - sqliteFree(zUtf8); - }else{ - return SQLITE_NOMEM; - } - } - for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} - zTempPath[i] = 0; - for(;;){ - sqlite3_snprintf(SQLITE_TEMPNAME_SIZE, zBuf, - "%s\\"TEMP_FILE_PREFIX, zTempPath); - j = strlen(zBuf); - sqlite3Randomness(15, &zBuf[j]); - for(i=0; i<15; i++, j++){ - zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; - } - zBuf[j] = 0; - if( !sqlite3OsFileExists(zBuf) ) break; - } - OSTRACE2("TEMP FILENAME: %s\n", zBuf); - return SQLITE_OK; -} +/***************************************************************************** +** The next group of routines implement the I/O methods specified +** by the sqlite3_io_methods object. +******************************************************************************/ /* ** Close a file. @@ -971,36 +604,51 @@ int sqlite3WinTempFileName(char *zBuf){ ** giving up and returning an error. */ #define MX_CLOSE_ATTEMPT 3 -static int winClose(OsFile **pId){ - winFile *pFile; - int rc = 1; - if( pId && (pFile = (winFile*)*pId)!=0 ){ - int rc, cnt = 0; - OSTRACE2("CLOSE %d\n", pFile->h); - do{ - rc = CloseHandle(pFile->h); - }while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) ); +static int winClose(sqlite3_file *id){ + int rc, cnt = 0; + winFile *pFile = (winFile*)id; + OSTRACE2("CLOSE %d\n", pFile->h); + do{ + rc = CloseHandle(pFile->h); + }while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) ); #if OS_WINCE - winceDestroyLock(pFile); + winceDestroyLock(pFile); #endif - OpenCounter(-1); - sqliteFree(pFile); - *pId = 0; - } + OpenCounter(-1); return rc ? SQLITE_OK : SQLITE_IOERR; } +/* +** Some microsoft compilers lack this definition. +*/ +#ifndef INVALID_SET_FILE_POINTER +# define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ -static int winRead(OsFile *id, void *pBuf, int amt){ +static int winRead( + sqlite3_file *id, /* File to read from */ + void *pBuf, /* Write content into this buffer */ + int amt, /* Number of bytes to read */ + sqlite3_int64 offset /* Begin reading at this offset */ +){ + LONG upperBits = (offset>>32) & 0x7fffffff; + LONG lowerBits = offset & 0xffffffff; + DWORD rc; DWORD got; + winFile *pFile = (winFile*)id; assert( id!=0 ); SimulateIOError(return SQLITE_IOERR_READ); - OSTRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); - if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){ + OSTRACE3("READ %d lock=%d\n", pFile->h, pFile->locktype); + rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); + if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){ + return SQLITE_FULL; + } + if( !ReadFile(pFile->h, pBuf, amt, &got, 0) ){ return SQLITE_IOERR_READ; } if( got==(DWORD)amt ){ @@ -1015,16 +663,31 @@ static int winRead(OsFile *id, void *pBuf, int amt){ ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ -static int winWrite(OsFile *id, const void *pBuf, int amt){ - int rc = 0; +static int winWrite( + sqlite3_file *id, /* File to write into */ + const void *pBuf, /* The bytes to be written */ + int amt, /* Number of bytes to write */ + sqlite3_int64 offset /* Offset into the file to begin writing at */ +){ + LONG upperBits = (offset>>32) & 0x7fffffff; + LONG lowerBits = offset & 0xffffffff; + DWORD rc; DWORD wrote; + winFile *pFile = (winFile*)id; assert( id!=0 ); - SimulateIOError(return SQLITE_IOERR_READ); + SimulateIOError(return SQLITE_IOERR_WRITE); SimulateDiskfullError(return SQLITE_FULL); - OSTRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); + OSTRACE3("WRITE %d lock=%d\n", pFile->h, pFile->locktype); + rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); + if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){ + return SQLITE_FULL; + } assert( amt>0 ); - while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0 - && wrote>0 ){ + while( + amt>0 + && (rc = WriteFile(pFile->h, pBuf, amt, &wrote, 0))!=0 + && wrote>0 + ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } @@ -1035,75 +698,56 @@ static int winWrite(OsFile *id, const void *pBuf, int amt){ } /* -** Some microsoft compilers lack this definition. +** Truncate an open file to a specified size */ -#ifndef INVALID_SET_FILE_POINTER -# define INVALID_SET_FILE_POINTER ((DWORD)-1) -#endif - -/* -** Move the read/write pointer in a file. -*/ -static int winSeek(OsFile *id, i64 offset){ - LONG upperBits = offset>>32; - LONG lowerBits = offset & 0xffffffff; - DWORD rc; - assert( id!=0 ); -#ifdef SQLITE_TEST - if( offset ) SimulateDiskfullError(return SQLITE_FULL); -#endif - rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN); - OSTRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset); - if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){ - return SQLITE_FULL; - } +static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ + LONG upperBits = (nByte>>32) & 0x7fffffff; + LONG lowerBits = nByte & 0xffffffff; + winFile *pFile = (winFile*)id; + OSTRACE3("TRUNCATE %d %lld\n", pFile->h, nByte); + SimulateIOError(return SQLITE_IOERR_TRUNCATE); + SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); + SetEndOfFile(pFile->h); return SQLITE_OK; } +#ifdef SQLITE_TEST +/* +** Count the number of fullsyncs and normal syncs. This is used to test +** that syncs and fullsyncs are occuring at the right times. +*/ +int sqlite3_sync_count = 0; +int sqlite3_fullsync_count = 0; +#endif + /* ** Make sure all writes to a particular file are committed to disk. */ -static int winSync(OsFile *id, int dataOnly){ - assert( id!=0 ); - OSTRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); - if( FlushFileBuffers(((winFile*)id)->h) ){ +static int winSync(sqlite3_file *id, int flags){ + winFile *pFile = (winFile*)id; + OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype); +#ifdef SQLITE_TEST + if( flags & SQLITE_SYNC_FULL ){ + sqlite3_fullsync_count++; + } + sqlite3_sync_count++; +#endif + if( FlushFileBuffers(pFile->h) ){ return SQLITE_OK; }else{ return SQLITE_IOERR; } } -/* -** Sync the directory zDirname. This is a no-op on operating systems other -** than UNIX. -*/ -int sqlite3WinSyncDirectory(const char *zDirname){ - SimulateIOError(return SQLITE_IOERR_READ); - return SQLITE_OK; -} - -/* -** Truncate an open file to a specified size -*/ -static int winTruncate(OsFile *id, i64 nByte){ - LONG upperBits = nByte>>32; - assert( id!=0 ); - OSTRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte); - SimulateIOError(return SQLITE_IOERR_TRUNCATE); - SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN); - SetEndOfFile(((winFile*)id)->h); - return SQLITE_OK; -} - /* ** Determine the current size of a file in bytes */ -static int winFileSize(OsFile *id, i64 *pSize){ +static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ + winFile *pFile = (winFile*)id; DWORD upperBits, lowerBits; - assert( id!=0 ); SimulateIOError(return SQLITE_IOERR_FSTAT); - lowerBits = GetFileSize(((winFile*)id)->h, &upperBits); - *pSize = (((i64)upperBits)<<32) + lowerBits; + lowerBits = GetFileSize(pFile->h, &upperBits); + *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; return SQLITE_OK; } @@ -1119,19 +763,20 @@ static int winFileSize(OsFile *id, i64 *pSize){ ** Different API routines are called depending on whether or not this ** is Win95 or WinNT. */ -static int getReadLock(winFile *id){ +static int getReadLock(winFile *pFile){ int res; if( isNT() ){ OVERLAPPED ovlp; ovlp.Offset = SHARED_FIRST; ovlp.OffsetHigh = 0; ovlp.hEvent = 0; - res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 0, SHARED_SIZE,0,&ovlp); + res = LockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY, + 0, SHARED_SIZE, 0, &ovlp); }else{ int lk; sqlite3Randomness(sizeof(lk), &lk); - id->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1); - res = LockFile(id->h, SHARED_FIRST+id->sharedLockByte, 0, 1, 0); + pFile->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1); + res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } return res; } @@ -1149,39 +794,6 @@ static int unlockReadLock(winFile *pFile){ return res; } -#ifndef SQLITE_OMIT_PAGER_PRAGMAS -/* -** Check that a given pathname is a directory and is writable -** -*/ -int sqlite3WinIsDirWritable(char *zDirname){ - int fileAttr; - void *zConverted; - if( zDirname==0 ) return 0; - if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0; - - zConverted = convertUtf8Filename(zDirname); - if( zConverted==0 ){ - return SQLITE_NOMEM; - } - if( isNT() ){ - fileAttr = GetFileAttributesW((WCHAR*)zConverted); - }else{ -#if OS_WINCE - return 0; -#else - fileAttr = GetFileAttributesA((char*)zConverted); -#endif - } - sqliteFree(zConverted); - if( fileAttr == 0xffffffff ) return 0; - if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){ - return 0; - } - return 1; -} -#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ - /* ** Lock the file with the lock specified by parameter locktype - one ** of the following: @@ -1208,10 +820,10 @@ int sqlite3WinIsDirWritable(char *zDirname){ ** It is not possible to lower the locking level one step at a time. You ** must go straight to locking level 0. */ -static int winLock(OsFile *id, int locktype){ +static int winLock(sqlite3_file *id, int locktype){ int rc = SQLITE_OK; /* Return code from subroutines */ int res = 1; /* Result of a windows lock call */ - int newLocktype; /* Set id->locktype to this value before exiting */ + int newLocktype; /* Set pFile->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ winFile *pFile = (winFile*)id; @@ -1320,7 +932,7 @@ static int winLock(OsFile *id, int locktype){ ** file by this or any other process. If such a lock is held, return ** non-zero, otherwise zero. */ -static int winCheckReservedLock(OsFile *id){ +static int winCheckReservedLock(sqlite3_file *id){ int rc; winFile *pFile = (winFile*)id; assert( pFile!=0 ); @@ -1349,10 +961,10 @@ static int winCheckReservedLock(OsFile *id){ ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine ** might return SQLITE_IOERR; */ -static int winUnlock(OsFile *id, int locktype){ +static int winUnlock(sqlite3_file *id, int locktype){ int type; - int rc = SQLITE_OK; winFile *pFile = (winFile*)id; + int rc = SQLITE_OK; assert( pFile!=0 ); assert( locktype<=SHARED_LOCK ); OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype, @@ -1380,75 +992,16 @@ static int winUnlock(OsFile *id, int locktype){ } /* -** Turn a relative pathname into a full pathname. Return a pointer -** to the full pathname stored in space obtained from sqliteMalloc(). -** The calling function is responsible for freeing this space once it -** is no longer needed. +** Control and query of the open file handle. */ -char *sqlite3WinFullPathname(const char *zRelative){ - char *zFull; -#if defined(__CYGWIN__) - int nByte; - nByte = strlen(zRelative) + MAX_PATH + 1001; - zFull = sqliteMalloc( nByte ); - if( zFull==0 ) return 0; - if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0; -#elif OS_WINCE - /* WinCE has no concept of a relative pathname, or so I am told. */ - zFull = sqliteStrDup(zRelative); -#else - int nByte; - void *zConverted; - zConverted = convertUtf8Filename(zRelative); - if( isNT() ){ - WCHAR *zTemp; - nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3; - zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) ); - if( zTemp==0 ){ - sqliteFree(zConverted); - return 0; +static int winFileControl(sqlite3_file *id, int op, void *pArg){ + switch( op ){ + case SQLITE_FCNTL_LOCKSTATE: { + *(int*)pArg = ((winFile*)id)->locktype; + return SQLITE_OK; } - GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0); - sqliteFree(zConverted); - zFull = unicodeToUtf8(zTemp); - sqliteFree(zTemp); - }else{ - char *zTemp; - nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3; - zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) ); - if( zTemp==0 ){ - sqliteFree(zConverted); - return 0; - } - GetFullPathNameA((char*)zConverted, nByte, zTemp, 0); - sqliteFree(zConverted); - zFull = mbcsToUtf8(zTemp); - sqliteFree(zTemp); } -#endif - return zFull; -} - -/* -** The fullSync option is meaningless on windows. This is a no-op. -*/ -static void winSetFullSync(OsFile *id, int v){ - return; -} - -/* -** Return the underlying file handle for an OsFile -*/ -static int winFileHandle(OsFile *id){ - return (int)((winFile*)id)->h; -} - -/* -** Return an integer that indices the type of lock currently held -** by this handle. (Used for testing and analysis only.) -*/ -static int winLockState(OsFile *id){ - return ((winFile*)id)->locktype; + return SQLITE_ERROR; } /* @@ -1461,71 +1014,377 @@ static int winLockState(OsFile *id){ ** a database and it's journal file) that the sector size will be the ** same for both. */ -static int winSectorSize(OsFile *id){ +static int winSectorSize(sqlite3_file *id){ return SQLITE_DEFAULT_SECTOR_SIZE; } /* -** This vector defines all the methods that can operate on an OsFile -** for win32. +** Return a vector of device characteristics. */ -static const IoMethod sqlite3WinIoMethod = { +static int winDeviceCharacteristics(sqlite3_file *id){ + return 0; +} + +/* +** This vector defines all the methods that can operate on an +** sqlite3_file for win32. +*/ +static const sqlite3_io_methods winIoMethod = { + 1, /* iVersion */ winClose, - winOpenDirectory, winRead, winWrite, - winSeek, winTruncate, winSync, - winSetFullSync, - winFileHandle, winFileSize, winLock, winUnlock, - winLockState, winCheckReservedLock, + winFileControl, winSectorSize, + winDeviceCharacteristics }; +/*************************************************************************** +** Here ends the I/O methods that form the sqlite3_io_methods object. +** +** The next block of code implements the VFS methods. +****************************************************************************/ + /* -** Allocate memory for an OsFile. Initialize the new OsFile -** to the value given in pInit and return a pointer to the new -** OsFile. If we run out of memory, close the file and return NULL. +** Convert a UTF-8 filename into whatever form the underlying +** operating system wants filenames in. Space to hold the result +** is obtained from malloc and must be freed by the calling +** function. */ -static int allocateWinFile(winFile *pInit, OsFile **pId){ - winFile *pNew; - pNew = sqliteMalloc( sizeof(*pNew) ); - if( pNew==0 ){ - CloseHandle(pInit->h); -#if OS_WINCE - sqliteFree(pInit->zDeleteOnClose); -#endif - *pId = 0; - return SQLITE_NOMEM; +static void *convertUtf8Filename(const char *zFilename){ + void *zConverted = 0; + if( isNT() ){ + zConverted = utf8ToUnicode(zFilename); }else{ - *pNew = *pInit; - pNew->pMethod = &sqlite3WinIoMethod; - pNew->locktype = NO_LOCK; - pNew->sharedLockByte = 0; - *pId = (OsFile*)pNew; - OpenCounter(+1); - return SQLITE_OK; + zConverted = utf8ToMbcs(zFilename); } + /* caller will handle out of memory */ + return zConverted; +} + +/* +** Open a file. +*/ +static int winOpen( + sqlite3_vfs *pVfs, /* Not used */ + const char *zName, /* Name of the file (UTF-8) */ + sqlite3_file *id, /* Write the SQLite file handle here */ + int flags, /* Open mode flags */ + int *pOutFlags /* Status return flags */ +){ + HANDLE h; + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD dwCreationDisposition; + DWORD dwFlagsAndAttributes = 0; + winFile *pFile = (winFile*)id; + void *zConverted = convertUtf8Filename(zName); + if( zConverted==0 ){ + return SQLITE_NOMEM; + } + + if( flags & SQLITE_OPEN_READWRITE ){ + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + }else{ + dwDesiredAccess = GENERIC_READ; + } + if( flags & SQLITE_OPEN_CREATE ){ + dwCreationDisposition = OPEN_ALWAYS; + }else{ + dwCreationDisposition = OPEN_EXISTING; + } + if( flags & SQLITE_OPEN_MAIN_DB ){ + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + }else{ + dwShareMode = 0; + } + if( flags & (SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_TEMP_JOURNAL + | SQLITE_OPEN_SUBJOURNAL) ){ + dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY + | FILE_ATTRIBUTE_HIDDEN + | FILE_FLAG_DELETE_ON_CLOSE; + }else{ + dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; + } + if( flags & (SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_TEMP_DB) ){ + dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS; + }else{ + dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN; + } + if( isNT() ){ + h = CreateFileW((WCHAR*)zConverted, + dwDesiredAccess, + dwShareMode, + NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL + ); + }else{ +#if OS_WINCE + return SQLITE_NOMEM; +#else + h = CreateFileA((char*)zConverted, + dwDesiredAccess, + dwShareMode, + NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL + ); +#endif + } + if( h==INVALID_HANDLE_VALUE ){ + free(zConverted); + if( flags & SQLITE_OPEN_READWRITE ){ + return winOpen(0, zName, id, + ((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags); + }else{ + return SQLITE_CANTOPEN; + } + } + if( pOutFlags ){ + if( flags & SQLITE_OPEN_READWRITE ){ + *pOutFlags = SQLITE_OPEN_READWRITE; + }else{ + *pOutFlags = SQLITE_OPEN_READONLY; + } + } + memset(pFile, 0, sizeof(*pFile)); + pFile->pMethod = &winIoMethod; + pFile->h = h; +#if OS_WINCE + if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) == + (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB) + && !winceCreateLock(zFilename, pFile) + ){ + CloseHandle(h); + free(zConverted); + return SQLITE_CANTOPEN; + } + if( dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE ){ + pFile->zDeleteOnClose = zConverted; + }else +#endif + { + free(zConverted); + } + OpenCounter(+1); + return SQLITE_OK; +} + +/* +** Delete the named file. +** +** Note that windows does not allow a file to be deleted if some other +** process has it open. Sometimes a virus scanner or indexing program +** will open a journal file shortly after it is created in order to do +** whatever it is it does. While this other process is holding the +** file open, we will be unable to delete it. To work around this +** problem, we delay 100 milliseconds and try to delete again. Up +** to MX_DELETION_ATTEMPTs deletion attempts are run before giving +** up and returning an error. +*/ +#define MX_DELETION_ATTEMPTS 3 +static int winDelete( + sqlite3_vfs *pVfs, /* Not used on win32 */ + const char *zFilename, /* Name of file to delete */ + int syncDir /* Not used on win32 */ +){ + int cnt = 0; + int rc; + void *zConverted = convertUtf8Filename(zFilename); + if( zConverted==0 ){ + return SQLITE_NOMEM; + } + SimulateIOError(return SQLITE_IOERR_DELETE); + if( isNT() ){ + do{ + rc = DeleteFileW(zConverted); + }while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff + && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); + }else{ +#if OS_WINCE + return SQLITE_NOMEM; +#else + do{ + rc = DeleteFileA(zConverted); + }while( rc==0 && GetFileAttributesA(zConverted)!=0xffffffff + && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); +#endif + } + free(zConverted); + OSTRACE2("DELETE \"%s\"\n", zFilename); + return rc!=0 ? SQLITE_OK : SQLITE_IOERR; +} + +/* +** Check the existance and status of a file. +*/ +static int winAccess( + sqlite3_vfs *pVfs, /* Not used on win32 */ + const char *zFilename, /* Name of file to check */ + int flags /* Type of test to make on this file */ +){ + DWORD attr; + int rc; + void *zConverted = convertUtf8Filename(zFilename); + if( zConverted==0 ){ + return SQLITE_NOMEM; + } + if( isNT() ){ + attr = GetFileAttributesW((WCHAR*)zConverted); + }else{ +#if OS_WINCE + return SQLITE_NOMEM; +#else + attr = GetFileAttributesA((char*)zConverted); +#endif + } + free(zConverted); + switch( flags ){ + case SQLITE_ACCESS_READ: + case SQLITE_ACCESS_EXISTS: + rc = attr!=0xffffffff; + break; + case SQLITE_ACCESS_READWRITE: + rc = (attr & FILE_ATTRIBUTE_READONLY)==0; + break; + default: + assert(!"Invalid flags argument"); + } + return rc; } -#endif /* SQLITE_OMIT_DISKIO */ -/*************************************************************************** -** Everything above deals with file I/O. Everything that follows deals -** with other miscellanous aspects of the operating system interface -****************************************************************************/ +/* +** Create a temporary file name in zBuf. zBuf must be big enough to +** hold at pVfs->mxPathname characters. +*/ +static int winGetTempname(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + static char zChars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + int i, j; + char zTempPath[MAX_PATH+1]; + if( sqlite3_temp_directory ){ + sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory); + }else if( isNT() ){ + char *zMulti; + WCHAR zWidePath[MAX_PATH]; + GetTempPathW(MAX_PATH-30, zWidePath); + zMulti = unicodeToUtf8(zWidePath); + if( zMulti ){ + sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti); + free(zMulti); + }else{ + return SQLITE_NOMEM; + } + }else{ + char *zUtf8; + char zMbcsPath[MAX_PATH]; + GetTempPathA(MAX_PATH-30, zMbcsPath); + zUtf8 = mbcsToUtf8(zMbcsPath); + if( zUtf8 ){ + sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8); + free(zUtf8); + }else{ + return SQLITE_NOMEM; + } + } + for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} + zTempPath[i] = 0; + sqlite3_snprintf(pVfs->mxPathname-30, zBuf, + "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); + j = strlen(zBuf); + sqlite3Randomness(20, &zBuf[j]); + for(i=0; i<20; i++, j++){ + zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; + } + zBuf[j] = 0; + OSTRACE2("TEMP FILENAME: %s\n", zBuf); + return SQLITE_OK; +} -#if !defined(SQLITE_OMIT_LOAD_EXTENSION) +/* +** Turn a relative pathname into a full pathname. Write the full +** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname +** bytes in size. +*/ +static int winFullPathname( + sqlite3_vfs *pVfs, /* Pointer to vfs object */ + const char *zRelative, /* Possibly relative input path */ + int nFull, /* Size of output buffer in bytes */ + char *zFull /* Output buffer */ +){ + +#if defined(__CYGWIN__) + cygwin_conv_to_full_win32_path(zRelative, zFull); + return SQLITE_OK; +#endif + +#if OS_WINCE + /* WinCE has no concept of a relative pathname, or so I am told. */ + sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative); +#endif + +#if !OS_WINCE && !defined(__CYGWIN__) + int nByte; + void *zConverted; + char *zOut; + zConverted = convertUtf8Filename(zRelative); + if( isNT() ){ + WCHAR *zTemp; + nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3; + zTemp = malloc( nByte*sizeof(zTemp[0]) ); + if( zTemp==0 ){ + free(zConverted); + return SQLITE_NOMEM; + } + GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0); + free(zConverted); + zOut = unicodeToUtf8(zTemp); + free(zTemp); + }else{ + char *zTemp; + nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3; + zTemp = malloc( nByte*sizeof(zTemp[0]) ); + if( zTemp==0 ){ + free(zConverted); + return SQLITE_NOMEM; + } + GetFullPathNameA((char*)zConverted, nByte, zTemp, 0); + free(zConverted); + zOut = mbcsToUtf8(zTemp); + free(zTemp); + } + if( zOut ){ + sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut); + free(zOut); + return SQLITE_OK; + }else{ + return SQLITE_NOMEM; + } +#endif +} + +#ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Interfaces for opening a shared library, finding entry points ** within the shared library, and closing the shared library. */ -void *sqlite3WinDlopen(const char *zFilename){ +/* +** Interfaces for opening a shared library, finding entry points +** within the shared library, and closing the shared library. +*/ +static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ HANDLE h; void *zConverted = convertUtf8Filename(zFilename); if( zConverted==0 ){ @@ -1540,11 +1399,21 @@ void *sqlite3WinDlopen(const char *zFilename){ h = LoadLibraryA((char*)zConverted); #endif } - sqliteFree(zConverted); + free(zConverted); return (void*)h; - } -void *sqlite3WinDlsym(void *pHandle, const char *zSymbol){ +static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + 0, + zBufOut, + nBuf-1, + 0 + ); +} +void *winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ #if OS_WINCE /* The GetProcAddressA() routine is only available on wince. */ return GetProcAddressA((HANDLE)pHandle, zSymbol); @@ -1554,104 +1423,56 @@ void *sqlite3WinDlsym(void *pHandle, const char *zSymbol){ return GetProcAddress((HANDLE)pHandle, zSymbol); #endif } -int sqlite3WinDlclose(void *pHandle){ - return FreeLibrary((HANDLE)pHandle); +void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ + FreeLibrary((HANDLE)pHandle); } -#endif /* !SQLITE_OMIT_LOAD_EXTENSION */ +#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ + #define winDlOpen 0 + #define winDlError 0 + #define winDlSym 0 + #define winDlClose 0 +#endif + /* -** Get information to seed the random number generator. The seed -** is written into the buffer zBuf[256]. The calling function must -** supply a sufficiently large buffer. +** Write up to nBuf bytes of randomness into zBuf. */ -int sqlite3WinRandomSeed(char *zBuf){ - /* We have to initialize zBuf to prevent valgrind from reporting - ** errors. The reports issued by valgrind are incorrect - we would - ** prefer that the randomness be increased by making use of the - ** uninitialized space in zBuf - but valgrind errors tend to worry - ** some users. Rather than argue, it seems easier just to initialize - ** the whole array and silence valgrind, even if that means less randomness - ** in the random seed. - ** - ** When testing, initializing zBuf[] to zero is all we do. That means - ** that we always use the same random number sequence.* This makes the - ** tests repeatable. - */ - memset(zBuf, 0, 256); - GetSystemTime((LPSYSTEMTIME)zBuf); - return SQLITE_OK; +static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + int n = 0; + if( sizeof(SYSTEMTIME)<=nBuf-n ){ + SYSTEMTIME x; + GetSystemTime(&x); + memcpy(&zBuf[n], &x, sizeof(x)); + n += sizeof(x); + } + if( sizeof(DWORD)<=nBuf-n ){ + DWORD pid = GetCurrentProcessId(); + memcpy(&zBuf[n], &pid, sizeof(pid)); + n += sizeof(pid); + } + if( sizeof(DWORD)<=nBuf-n ){ + DWORD cnt = GetTickCount(); + memcpy(&zBuf[n], &cnt, sizeof(cnt)); + n += sizeof(cnt); + } + if( sizeof(LARGE_INTEGER)<=nBuf-n ){ + LARGE_INTEGER i; + QueryPerformanceCounter(&i); + memcpy(&zBuf[n], &i, sizeof(i)); + n += sizeof(i); + } + return n; } + /* ** Sleep for a little while. Return the amount of time slept. */ -int sqlite3WinSleep(int ms){ - Sleep(ms); - return ms; +static int winSleep(sqlite3_vfs *pVfs, int microsec){ + Sleep((microsec+999)/1000); + return ((microsec+999)/1000)*1000; } -/* -** Static variables used for thread synchronization -*/ -static int inMutex = 0; -#ifdef SQLITE_W32_THREADS - static DWORD mutexOwner; - static CRITICAL_SECTION cs; -#endif - -/* -** The following pair of routines implement mutual exclusion for -** multi-threaded processes. Only a single thread is allowed to -** executed code that is surrounded by EnterMutex() and LeaveMutex(). -** -** SQLite uses only a single Mutex. There is not much critical -** code and what little there is executes quickly and without blocking. -** -** Version 3.3.1 and earlier used a simple mutex. Beginning with -** version 3.3.2, a recursive mutex is required. -*/ -void sqlite3WinEnterMutex(){ -#ifdef SQLITE_W32_THREADS - static int isInit = 0; - while( !isInit ){ - static long lock = 0; - if( InterlockedIncrement(&lock)==1 ){ - InitializeCriticalSection(&cs); - isInit = 1; - }else{ - Sleep(1); - } - } - EnterCriticalSection(&cs); - mutexOwner = GetCurrentThreadId(); -#endif - inMutex++; -} -void sqlite3WinLeaveMutex(){ - assert( inMutex ); - inMutex--; -#ifdef SQLITE_W32_THREADS - assert( mutexOwner==GetCurrentThreadId() ); - LeaveCriticalSection(&cs); -#endif -} - -/* -** Return TRUE if the mutex is currently held. -** -** If the thisThreadOnly parameter is true, return true if and only if the -** calling thread holds the mutex. If the parameter is false, return -** true if any thread holds the mutex. -*/ -int sqlite3WinInMutex(int thisThreadOnly){ -#ifdef SQLITE_W32_THREADS - return inMutex>0 && (thisThreadOnly==0 || mutexOwner==GetCurrentThreadId()); -#else - return inMutex>0; -#endif -} - - /* ** The following variable, if set to a non-zero value, becomes the result ** returned from sqlite3OsCurrentTime(). This is used for testing. @@ -1665,7 +1486,7 @@ int sqlite3_current_time = 0; ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ -int sqlite3WinCurrentTime(double *prNow){ +int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ FILETIME ft; /* FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). @@ -1688,71 +1509,37 @@ int sqlite3WinCurrentTime(double *prNow){ return 0; } -/* -** Remember the number of thread-specific-data blocks allocated. -** Use this to verify that we are not leaking thread-specific-data. -** Ticket #1601 -*/ -#ifdef SQLITE_TEST -int sqlite3_tsd_count = 0; -# define TSD_COUNTER_INCR InterlockedIncrement(&sqlite3_tsd_count) -# define TSD_COUNTER_DECR InterlockedDecrement(&sqlite3_tsd_count) -#else -# define TSD_COUNTER_INCR /* no-op */ -# define TSD_COUNTER_DECR /* no-op */ -#endif - - /* -** If called with allocateFlag>1, then return a pointer to thread -** specific data for the current thread. Allocate and zero the -** thread-specific data if it does not already exist necessary. -** -** If called with allocateFlag==0, then check the current thread -** specific data. Return it if it exists. If it does not exist, -** then return NULL. -** -** If called with allocateFlag<0, check to see if the thread specific -** data is allocated and is all zero. If it is then deallocate it. -** Return a pointer to the thread specific data or NULL if it is -** unallocated or gets deallocated. +** Return a pointer to the sqlite3DefaultVfs structure. We use +** a function rather than give the structure global scope because +** some compilers (MSVC) do not allow forward declarations of +** initialized structures. */ -ThreadData *sqlite3WinThreadSpecificData(int allocateFlag){ - static int key; - static int keyInit = 0; - static const ThreadData zeroData = {0}; - ThreadData *pTsd; - - if( !keyInit ){ - sqlite3OsEnterMutex(); - if( !keyInit ){ - key = TlsAlloc(); - if( key==0xffffffff ){ - sqlite3OsLeaveMutex(); - return 0; - } - keyInit = 1; - } - sqlite3OsLeaveMutex(); - } - pTsd = TlsGetValue(key); - if( allocateFlag>0 ){ - if( !pTsd ){ - pTsd = sqlite3OsMalloc( sizeof(zeroData) ); - if( pTsd ){ - *pTsd = zeroData; - TlsSetValue(key, pTsd); - TSD_COUNTER_INCR; - } - } - }else if( pTsd!=0 && allocateFlag<0 - && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ - sqlite3OsFree(pTsd); - TlsSetValue(key, 0); - TSD_COUNTER_DECR; - pTsd = 0; - } - return pTsd; +sqlite3_vfs *sqlite3OsDefaultVfs(void){ + static sqlite3_vfs winVfs = { + 1, /* iVersion */ + sizeof(winFile), /* szOsFile */ + MAX_PATH, /* mxPathname */ + 0, /* pNext */ + "win32", /* zName */ + 0, /* pAppData */ + + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winGetTempname, /* xGetTempName */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime /* xCurrentTime */ + }; + + return &winVfs; } + #endif /* OS_WIN */ diff --git a/extensions/sqlite/sqlite-source/pager.c b/extensions/sqlite/sqlite-source/pager.c index a57e2a6b..a33b2f71 100644 --- a/extensions/sqlite/sqlite-source/pager.c +++ b/extensions/sqlite/sqlite-source/pager.c @@ -22,8 +22,6 @@ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" -#include "os.h" -#include "pager.h" #include #include @@ -50,7 +48,7 @@ ** to print out file-descriptors. ** ** PAGERID() takes a pointer to a Pager struct as it's argument. The -** associated file-descriptor is returned. FILEHANDLEID() takes an OsFile +** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file ** struct as it's argument. */ #define PAGERID(p) ((int)(p->fd)) @@ -133,6 +131,40 @@ */ #define FORCE_ALIGNMENT(X) (((X)+7)&~7) +typedef struct PgHdr PgHdr; + +/* +** Each pager stores all currently unreferenced pages in a list sorted +** in least-recently-used (LRU) order (i.e. the first item on the list has +** not been referenced in a long time, the last item has been recently +** used). An instance of this structure is included as part of each +** pager structure for this purpose (variable Pager.lru). +** +** Additionally, if memory-management is enabled, all unreferenced pages +** are stored in a global LRU list (global variable sqlite3LruPageList). +** +** In both cases, the PagerLruList.pFirstSynced variable points to +** the first page in the corresponding list that does not require an +** fsync() operation before it's memory can be reclaimed. If no such +** page exists, PagerLruList.pFirstSynced is set to NULL. +*/ +typedef struct PagerLruList PagerLruList; +struct PagerLruList { + PgHdr *pFirst; /* First page in LRU list */ + PgHdr *pLast; /* Last page in LRU list (the most recently used) */ + PgHdr *pFirstSynced; /* First page in list with PgHdr.needSync==0 */ +}; + +/* +** The following structure contains the next and previous pointers used +** to link a PgHdr structure into a PagerLruList linked list. +*/ +typedef struct PagerLruLink PagerLruLink; +struct PagerLruLink { + PgHdr *pNext; + PgHdr *pPrev; +}; + /* ** Each in-memory image of a page begins with the following header. ** This header is only visible to this pager module. The client @@ -223,12 +255,11 @@ ** content is needed in the future, it should be read from the ** original database file. */ -typedef struct PgHdr PgHdr; struct PgHdr { Pager *pPager; /* The pager to which this page belongs */ Pgno pgno; /* The page number for this page */ PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */ - PgHdr *pNextFree, *pPrevFree; /* Freelist of pages where nRef==0 */ + PagerLruLink free; /* Next and previous free pages */ PgHdr *pNextAll; /* A list of all pages */ u8 inJournal; /* TRUE if has been written to journal */ u8 dirty; /* TRUE if we need to write back changes */ @@ -237,12 +268,14 @@ struct PgHdr { u8 needRead; /* Read content if PagerWrite() is called */ short int nRef; /* Number of users of this page */ PgHdr *pDirty, *pPrevDirty; /* Dirty pages */ - u32 notUsed; /* Buffer space */ +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + PagerLruLink gfree; /* Global list of nRef==0 pages */ +#endif #ifdef SQLITE_CHECK_PAGES u32 pageHash; #endif - /* pPager->pageSize bytes of page data follow this header */ - /* Pager.nExtra bytes of local data follow the page data */ + void *pData; /* Page data */ + /* Pager.nExtra bytes of local data appended to this header */ }; /* @@ -279,11 +312,10 @@ struct PgHistory { ** Convert a pointer to a PgHdr into a pointer to its data ** and back again. */ -#define PGHDR_TO_DATA(P) ((void*)(&(P)[1])) -#define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1]) -#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize]) +#define PGHDR_TO_DATA(P) ((P)->pData) +#define PGHDR_TO_EXTRA(G,P) ((void*)&((G)[1])) #define PGHDR_TO_HIST(P,PGR) \ - ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra]) + ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->nExtra]) /* ** A open page cache is an instance of the following structure. @@ -297,6 +329,7 @@ struct PgHistory { ** APIs, they may still be used successfully. */ struct Pager { + sqlite3_vfs *pVfs; /* OS functions to use for IO */ u8 journalOpen; /* True if journal file descriptors is valid */ u8 journalStarted; /* True if header of journal is synced */ u8 useJournal; /* Use a rollback journal on this file */ @@ -306,7 +339,7 @@ struct Pager { u8 stmtAutoopen; /* Open stmt journal when main journal is opened*/ u8 noSync; /* Do not sync the journal if true */ u8 fullSync; /* Do extra syncs of the journal for robustness */ - u8 full_fsync; /* Use F_FULLFSYNC when available */ + u8 sync_flags; /* One of SYNC_NORMAL or SYNC_FULL */ u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */ u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ @@ -318,6 +351,7 @@ struct Pager { u8 doNotSync; /* Boolean. While true, do not spill the cache */ u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */ u8 changeCountDone; /* Set after incrementing the change-counter */ + u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ int errCode; /* One of several kinds of errors */ int dbSize; /* Number of pages in the file */ int origDbSize; /* dbSize before the current change */ @@ -336,11 +370,11 @@ struct Pager { char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ char *zDirectory; /* Directory hold database and journal files */ - OsFile *fd, *jfd; /* File descriptors for database and journal */ - OsFile *stfd; /* File descriptor for the statement subjournal*/ + char *zStmtJrnl; /* Name of the statement journal file */ + sqlite3_file *fd, *jfd; /* File descriptors for database and journal */ + sqlite3_file *stfd; /* File descriptor for the statement subjournal*/ BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */ - PgHdr *pFirst, *pLast; /* List of free pages */ - PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */ + PagerLruList lru; /* LRU list of free pages */ PgHdr *pAll; /* List of all pages */ PgHdr *pStmt; /* List of pages in the statement subjournal */ PgHdr *pDirty; /* List of all dirty pages */ @@ -363,7 +397,10 @@ struct Pager { int nHash; /* Size of the pager hash table */ PgHdr **aHash; /* Hash table to map page number to PgHdr */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - Pager *pNext; /* Linked list of pagers in this thread */ + Pager *pNext; /* Doubly linked list of pagers on which */ + Pager *pPrev; /* sqlite3_release_memory() will work */ + int iInUseMM; /* Non-zero if unavailable to MM */ + int iInUseDB; /* Non-zero if in sqlite3_release_memory() */ #endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ char dbFileVers[16]; /* Changes whenever database file changes */ @@ -384,6 +421,16 @@ int sqlite3_pager_pgfree_count = 0; /* Number of cache pages freed */ # define PAGER_INCR(v) #endif +/* +** The following variable points to the head of a double-linked list +** of all pagers that are eligible for page stealing by the +** sqlite3_release_memory() interface. Access to this list is +** protected by the SQLITE_MUTEX_STATIC_MEM2 mutex. +*/ +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT +static Pager *sqlite3PagerList = 0; +static PagerLruList sqlite3LruPageList = {0, 0, 0}; +#endif /* @@ -453,6 +500,38 @@ static const unsigned char aJournalMagic[] = { */ #define PAGER_MAX_PGNO 2147483647 +/* +** The pagerEnter() and pagerLeave() routines acquire and release +** a mutex on each pager. The mutex is recursive. +** +** This is a special-purpose mutex. It only provides mutual exclusion +** between the Btree and the Memory Management sqlite3_release_memory() +** function. It does not prevent, for example, two Btrees from accessing +** the same pager at the same time. Other general-purpose mutexes in +** the btree layer handle that chore. +*/ +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + static void pagerEnter(Pager *p){ + p->iInUseDB++; + if( p->iInUseMM && p->iInUseDB==1 ){ + sqlite3_mutex *mutex; + mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); + p->iInUseDB = 0; + sqlite3_mutex_enter(mutex); + p->iInUseDB = 1; + sqlite3_mutex_leave(mutex); + } + assert( p->iInUseMM==0 ); + } + static void pagerLeave(Pager *p){ + p->iInUseDB--; + assert( p->iInUseDB>=0 ); + } +#else +# define pagerEnter(X) +# define pagerLeave(X) +#endif + /* ** Enable reference count tracking (for debugging) here: */ @@ -472,6 +551,130 @@ static const unsigned char aJournalMagic[] = { # define REFINFO(X) #endif +/* +** Add page pPg to the end of the linked list managed by structure +** pList (pPg becomes the last entry in the list - the most recently +** used). Argument pLink should point to either pPg->free or pPg->gfree, +** depending on whether pPg is being added to the pager-specific or +** global LRU list. +*/ +static void listAdd(PagerLruList *pList, PagerLruLink *pLink, PgHdr *pPg){ + pLink->pNext = 0; + pLink->pPrev = pList->pLast; + +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + assert(pLink==&pPg->free || pLink==&pPg->gfree); + assert(pLink==&pPg->gfree || pList!=&sqlite3LruPageList); +#endif + + if( pList->pLast ){ + int iOff = (char *)pLink - (char *)pPg; + PagerLruLink *pLastLink = (PagerLruLink *)(&((u8 *)pList->pLast)[iOff]); + pLastLink->pNext = pPg; + }else{ + assert(!pList->pFirst); + pList->pFirst = pPg; + } + + pList->pLast = pPg; + if( !pList->pFirstSynced && pPg->needSync==0 ){ + pList->pFirstSynced = pPg; + } +} + +/* +** Remove pPg from the list managed by the structure pointed to by pList. +** +** Argument pLink should point to either pPg->free or pPg->gfree, depending +** on whether pPg is being added to the pager-specific or global LRU list. +*/ +static void listRemove(PagerLruList *pList, PagerLruLink *pLink, PgHdr *pPg){ + int iOff = (char *)pLink - (char *)pPg; + +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + assert(pLink==&pPg->free || pLink==&pPg->gfree); + assert(pLink==&pPg->gfree || pList!=&sqlite3LruPageList); +#endif + + if( pPg==pList->pFirst ){ + pList->pFirst = pLink->pNext; + } + if( pPg==pList->pLast ){ + pList->pLast = pLink->pPrev; + } + if( pLink->pPrev ){ + PagerLruLink *pPrevLink = (PagerLruLink *)(&((u8 *)pLink->pPrev)[iOff]); + pPrevLink->pNext = pLink->pNext; + } + if( pLink->pNext ){ + PagerLruLink *pNextLink = (PagerLruLink *)(&((u8 *)pLink->pNext)[iOff]); + pNextLink->pPrev = pLink->pPrev; + } + if( pPg==pList->pFirstSynced ){ + PgHdr *p = pLink->pNext; + while( p && p->needSync ){ + PagerLruLink *pL = (PagerLruLink *)(&((u8 *)p)[iOff]); + p = pL->pNext; + } + pList->pFirstSynced = p; + } + + pLink->pNext = pLink->pPrev = 0; +} + +/* +** Add page pPg to the list of free pages for the pager. If +** memory-management is enabled, also add the page to the global +** list of free pages. +*/ +static void lruListAdd(PgHdr *pPg){ + listAdd(&pPg->pPager->lru, &pPg->free, pPg); +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + if( !pPg->pPager->memDb ){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); + listAdd(&sqlite3LruPageList, &pPg->gfree, pPg); + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); + } +#endif +} + +/* +** Remove page pPg from the list of free pages for the associated pager. +** If memory-management is enabled, also remove pPg from the global list +** of free pages. +*/ +static void lruListRemove(PgHdr *pPg){ + listRemove(&pPg->pPager->lru, &pPg->free, pPg); +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + if( !pPg->pPager->memDb ){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); + listRemove(&sqlite3LruPageList, &pPg->gfree, pPg); + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); + } +#endif +} + +/* +** This function is called just after the needSync flag has been cleared +** from all pages managed by pPager (usually because the journal file +** has just been synced). It updates the pPager->lru.pFirstSynced variable +** and, if memory-management is enabled, the sqlite3LruPageList.pFirstSynced +** variable also. +*/ +static void lruListSetFirstSynced(Pager *pPager){ + pPager->lru.pFirstSynced = pPager->lru.pFirst; +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + if( !pPager->memDb ){ + PgHdr *p; + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); + for(p=sqlite3LruPageList.pFirst; p && p->needSync; p=p->gfree.pNext); + assert(p==pPager->lru.pFirstSynced || p==sqlite3LruPageList.pFirstSynced); + sqlite3LruPageList.pFirstSynced = p; + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); + } +#endif +} + /* ** Return true if page *pPg has already been written to the statement ** journal (or statement snapshot has been created, if *pPg is part @@ -495,12 +698,15 @@ static int pageInStatement(PgHdr *pPg){ static void pager_resize_hash_table(Pager *pPager, int N){ PgHdr **aHash, *pPg; assert( N>0 && (N&(N-1))==0 ); - aHash = sqliteMalloc( sizeof(aHash[0])*N ); + pagerLeave(pPager); + sqlite3MallocBenignFailure((int)pPager->aHash); + aHash = sqlite3MallocZero( sizeof(aHash[0])*N ); + pagerEnter(pPager); if( aHash==0 ){ /* Failure to rehash is not an error. It is only a performance hit. */ return; } - sqliteFree(pPager->aHash); + sqlite3_free(pPager->aHash); pPager->nHash = N; pPager->aHash = aHash; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ @@ -526,9 +732,9 @@ static void pager_resize_hash_table(Pager *pPager, int N){ ** ** All values are stored on disk as big-endian. */ -static int read32bits(OsFile *fd, u32 *pRes){ +static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){ unsigned char ac[4]; - int rc = sqlite3OsRead(fd, ac, sizeof(ac)); + int rc = sqlite3OsRead(fd, ac, sizeof(ac), offset); if( rc==SQLITE_OK ){ *pRes = sqlite3Get4byte(ac); } @@ -544,12 +750,58 @@ static int read32bits(OsFile *fd, u32 *pRes){ ** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK ** on success or an error code is something goes wrong. */ -static int write32bits(OsFile *fd, u32 val){ +static int write32bits(sqlite3_file *fd, i64 offset, u32 val){ char ac[4]; put32bits(ac, val); - return sqlite3OsWrite(fd, ac, 4); + return sqlite3OsWrite(fd, ac, 4, offset); } +/* +** If file pFd is open, call sqlite3OsUnlock() on it. +*/ +static int osUnlock(sqlite3_file *pFd, int eLock){ + if( !pFd->pMethods ){ + return SQLITE_OK; + } + return sqlite3OsUnlock(pFd, eLock); +} + +/* +** This function determines whether or not the atomic-write optimization +** can be used with this pager. The optimization can be used if: +** +** (a) the value returned by OsDeviceCharacteristics() indicates that +** a database page may be written atomically, and +** (b) the value returned by OsSectorSize() is less than or equal +** to the page size. +** +** If the optimization cannot be used, 0 is returned. If it can be used, +** then the value returned is the size of the journal file when it +** contains rollback data for exactly one page. +*/ +#ifdef SQLITE_ENABLE_ATOMIC_WRITE +static int jrnlBufferSize(Pager *pPager){ + int dc; /* Device characteristics */ + int nSector; /* Sector size */ + int nPage; /* Page size */ + sqlite3_file *fd = pPager->fd; + + if( fd->pMethods ){ + dc = sqlite3OsDeviceCharacteristics(fd); + nSector = sqlite3OsSectorSize(fd); + nPage = pPager->pageSize; + } + + assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); + assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); + + if( !fd->pMethods || (dc&(SQLITE_IOCAP_ATOMIC|(nPage>>8))&&nSector<=nPage) ){ + return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager); + } + return 0; +} +#endif + /* ** This function should be called when an error occurs within the pager ** code. The first argument is a pointer to the pager structure, the @@ -557,18 +809,37 @@ static int write32bits(OsFile *fd, u32 val){ ** The value returned is a copy of the second argument to this function. ** ** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT, or SQLITE_FULL -** the error becomes persistent. All subsequent API calls on this Pager -** will immediately return the same error code. +** the error becomes persistent. Until the persisten error is cleared, +** subsequent API calls on this Pager will immediately return the same +** error code. +** +** A persistent error indicates that the contents of the pager-cache +** cannot be trusted. This state can be cleared by completely discarding +** the contents of the pager-cache. If a transaction was active when +** the persistent error occured, then the rollback journal may need +** to be replayed. */ +static void pager_unlock(Pager *pPager); static int pager_error(Pager *pPager, int rc){ int rc2 = rc & 0xff; - assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK ); + assert( + pPager->errCode==SQLITE_FULL || + pPager->errCode==SQLITE_OK || + (pPager->errCode & 0xff)==SQLITE_IOERR + ); if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR || rc2==SQLITE_CORRUPT ){ pPager->errCode = rc; + if( pPager->state==PAGER_UNLOCK && pPager->nRef==0 ){ + /* If the pager is already unlocked, call pager_unlock() now to + ** clear the error state and ensure that the pager-cache is + ** completely empty. + */ + pager_unlock(pPager); + } } return rc; } @@ -616,14 +887,19 @@ static void checkPage(PgHdr *pPg){ /* ** When this is called the journal file for pager pPager must be open. ** The master journal file name is read from the end of the file and -** written into memory obtained from sqliteMalloc(). *pzMaster is -** set to point at the memory and SQLITE_OK returned. The caller must -** sqliteFree() *pzMaster. +** written into memory supplied by the caller. ** -** If no master journal file name is present *pzMaster is set to 0 and +** zMaster must point to a buffer of at least nMaster bytes allocated by +** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is +** enough space to write the master journal name). If the master journal +** name in the journal is longer than nMaster bytes (including a +** nul-terminator), then this is handled as if no master journal name +** were present in the journal. +** +** If no master journal file name is present zMaster[0] is set to 0 and ** SQLITE_OK returned. */ -static int readMasterJournal(OsFile *pJrnl, char **pzMaster){ +static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, int nMaster){ int rc; u32 len; i64 szJ; @@ -631,51 +907,41 @@ static int readMasterJournal(OsFile *pJrnl, char **pzMaster){ int i; unsigned char aMagic[8]; /* A buffer to hold the magic header */ - *pzMaster = 0; + zMaster[0] = '\0'; rc = sqlite3OsFileSize(pJrnl, &szJ); if( rc!=SQLITE_OK || szJ<16 ) return rc; - rc = sqlite3OsSeek(pJrnl, szJ-16); - if( rc!=SQLITE_OK ) return rc; - - rc = read32bits(pJrnl, &len); + rc = read32bits(pJrnl, szJ-16, &len); if( rc!=SQLITE_OK ) return rc; - rc = read32bits(pJrnl, &cksum); + if( len>=nMaster ){ + return SQLITE_OK; + } + + rc = read32bits(pJrnl, szJ-12, &cksum); if( rc!=SQLITE_OK ) return rc; - rc = sqlite3OsRead(pJrnl, aMagic, 8); + rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8); if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc; - rc = sqlite3OsSeek(pJrnl, szJ-16-len); - if( rc!=SQLITE_OK ) return rc; - - *pzMaster = (char *)sqliteMalloc(len+1); - if( !*pzMaster ){ - return SQLITE_NOMEM; - } - rc = sqlite3OsRead(pJrnl, *pzMaster, len); + rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len); if( rc!=SQLITE_OK ){ - sqliteFree(*pzMaster); - *pzMaster = 0; return rc; } + zMaster[len] = '\0'; /* See if the checksum matches the master journal name */ for(i=0; ijournalOff; if( c ){ @@ -706,7 +972,6 @@ static int seekJournalHdr(Pager *pPager){ assert( offset>=c ); assert( (offset-c)journalOff = offset; - return sqlite3OsSeek(pPager->jfd, pPager->journalOff); } /* @@ -731,23 +996,40 @@ static int writeJournalHdr(Pager *pPager){ pPager->stmtHdrOff = pPager->journalOff; } - rc = seekJournalHdr(pPager); - if( rc ) return rc; - + seekJournalHdr(pPager); pPager->journalHdr = pPager->journalOff; - pPager->journalOff += JOURNAL_HDR_SZ(pPager); - /* FIX ME: - ** - ** Possibly for a pager not in no-sync mode, the journal magic should not - ** be written until nRec is filled in as part of next syncJournal(). - ** - ** Actually maybe the whole journal header should be delayed until that - ** point. Think about this. - */ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); - /* The nRec Field. 0xFFFFFFFF for no-sync journals. */ - put32bits(&zHeader[sizeof(aJournalMagic)], pPager->noSync ? 0xffffffff : 0); + + /* + ** Write the nRec Field - the number of page records that follow this + ** journal header. Normally, zero is written to this value at this time. + ** After the records are added to the journal (and the journal synced, + ** if in full-sync mode), the zero is overwritten with the true number + ** of records (see syncJournal()). + ** + ** A faster alternative is to write 0xFFFFFFFF to the nRec field. When + ** reading the journal this value tells SQLite to assume that the + ** rest of the journal file contains valid page records. This assumption + ** is dangerous, as if a failure occured whilst writing to the journal + ** file it may contain some garbage data. There are two scenarios + ** where this risk can be ignored: + ** + ** * When the pager is in no-sync mode. Corruption can follow a + ** power failure in this case anyway. + ** + ** * When the SQLITE_IOCAP_SAFE_APPEND flag is set. This guarantees + ** that garbage data is never appended to the journal file. + */ + assert(pPager->fd->pMethods||pPager->noSync); + if( (pPager->noSync) + || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) + ){ + put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); + }else{ + put32bits(&zHeader[sizeof(aJournalMagic)], 0); + } + /* The random check-hash initialiser */ sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); @@ -756,17 +1038,15 @@ static int writeJournalHdr(Pager *pPager){ /* The assumed sector size for this process */ put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize); IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, sizeof(zHeader))) - rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader)); + rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader),pPager->journalOff); + pPager->journalOff += JOURNAL_HDR_SZ(pPager); /* The journal header has been written successfully. Seek the journal ** file descriptor to the end of the journal header sector. */ if( rc==SQLITE_OK ){ IOTRACE(("JTAIL %p %lld\n", pPager, pPager->journalOff-1)) - rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff-1); - if( rc==SQLITE_OK ){ - rc = sqlite3OsWrite(pPager->jfd, "\000", 1); - } + rc = sqlite3OsWrite(pPager->jfd, "\000", 1, pPager->journalOff-1); } return rc; } @@ -795,28 +1075,29 @@ static int readJournalHdr( ){ int rc; unsigned char aMagic[8]; /* A buffer to hold the magic header */ + i64 jrnlOff; - rc = seekJournalHdr(pPager); - if( rc ) return rc; - + seekJournalHdr(pPager); if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){ return SQLITE_DONE; } + jrnlOff = pPager->journalOff; - rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic)); + rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic), jrnlOff); if( rc ) return rc; + jrnlOff += sizeof(aMagic); if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ return SQLITE_DONE; } - rc = read32bits(pPager->jfd, pNRec); + rc = read32bits(pPager->jfd, jrnlOff, pNRec); if( rc ) return rc; - rc = read32bits(pPager->jfd, &pPager->cksumInit); + rc = read32bits(pPager->jfd, jrnlOff+4, &pPager->cksumInit); if( rc ) return rc; - rc = read32bits(pPager->jfd, pDbSize); + rc = read32bits(pPager->jfd, jrnlOff+8, pDbSize); if( rc ) return rc; /* Update the assumed sector-size to match the value used by @@ -825,12 +1106,11 @@ static int readJournalHdr( ** is being called from within pager_playback(). The local value ** of Pager.sectorSize is restored at the end of that routine. */ - rc = read32bits(pPager->jfd, (u32 *)&pPager->sectorSize); + rc = read32bits(pPager->jfd, jrnlOff+12, (u32 *)&pPager->sectorSize); if( rc ) return rc; pPager->journalOff += JOURNAL_HDR_SZ(pPager); - rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff); - return rc; + return SQLITE_OK; } @@ -857,6 +1137,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ int rc; int len; int i; + i64 jrnlOff; u32 cksum = 0; char zBuf[sizeof(aJournalMagic)+2*4]; @@ -873,21 +1154,23 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ ** the journal has already been synced. */ if( pPager->fullSync ){ - rc = seekJournalHdr(pPager); - if( rc!=SQLITE_OK ) return rc; + seekJournalHdr(pPager); } + jrnlOff = pPager->journalOff; pPager->journalOff += (len+20); - rc = write32bits(pPager->jfd, PAGER_MJ_PGNO(pPager)); + rc = write32bits(pPager->jfd, jrnlOff, PAGER_MJ_PGNO(pPager)); if( rc!=SQLITE_OK ) return rc; + jrnlOff += 4; - rc = sqlite3OsWrite(pPager->jfd, zMaster, len); + rc = sqlite3OsWrite(pPager->jfd, zMaster, len, jrnlOff); if( rc!=SQLITE_OK ) return rc; + jrnlOff += len; put32bits(zBuf, len); put32bits(&zBuf[4], cksum); memcpy(&zBuf[8], aJournalMagic, sizeof(aJournalMagic)); - rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic)); + rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic), jrnlOff); pPager->needSync = !pPager->noSync; return rc; } @@ -930,38 +1213,6 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ return p; } -/* -** Unlock the database file. -*/ -static void pager_unlock(Pager *pPager){ - if( !pPager->exclusiveMode ){ - if( !MEMDB ){ - sqlite3OsUnlock(pPager->fd, NO_LOCK); - pPager->dbSize = -1; - IOTRACE(("UNLOCK %p\n", pPager)) - } - pPager->state = PAGER_UNLOCK; - pPager->changeCountDone = 0; - } -} - -/* -** Execute a rollback if a transaction is active and unlock the -** database file. This is a no-op if the pager has already entered -** the error-state. -*/ -static void pagerUnlockAndRollback(Pager *p){ - if( p->errCode ) return; - assert( p->state>=PAGER_RESERVED || p->journalOpen==0 ); - if( p->state>=PAGER_RESERVED ){ - sqlite3PagerRollback(p); - } - pager_unlock(p); - assert( p->errCode || !p->journalOpen || (p->exclusiveMode&&!p->journalOff) ); - assert( p->errCode || !p->stmtOpen || p->exclusiveMode ); -} - - /* ** Clear the in-memory cache. This routine ** sets the state of the pager back to what it was when it was first @@ -975,20 +1226,90 @@ static void pager_reset(Pager *pPager){ IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); PAGER_INCR(sqlite3_pager_pgfree_count); pNext = pPg->pNextAll; - sqliteFree(pPg); + lruListRemove(pPg); + sqlite3_free(pPg->pData); + sqlite3_free(pPg); } + assert(pPager->lru.pFirst==0); + assert(pPager->lru.pFirstSynced==0); + assert(pPager->lru.pLast==0); pPager->pStmt = 0; - pPager->pFirst = 0; - pPager->pFirstSynced = 0; - pPager->pLast = 0; pPager->pAll = 0; + pPager->pDirty = 0; pPager->nHash = 0; - sqliteFree(pPager->aHash); + sqlite3_free(pPager->aHash); pPager->nPage = 0; pPager->aHash = 0; pPager->nRef = 0; } +/* +** Unlock the database file. +** +** If the pager is currently in error state, discard the contents of +** the cache and reset the Pager structure internal state. If there is +** an open journal-file, then the next time a shared-lock is obtained +** on the pager file (by this or any other process), it will be +** treated as a hot-journal and rolled back. +*/ +static void pager_unlock(Pager *pPager){ + if( !pPager->exclusiveMode ){ + if( !MEMDB ){ + if( pPager->fd->pMethods ){ + osUnlock(pPager->fd, NO_LOCK); + } + pPager->dbSize = -1; + IOTRACE(("UNLOCK %p\n", pPager)) + + /* If Pager.errCode is set, the contents of the pager cache cannot be + ** trusted. Now that the pager file is unlocked, the contents of the + ** cache can be discarded and the error code safely cleared. + */ + if( pPager->errCode ){ + pPager->errCode = SQLITE_OK; + pager_reset(pPager); + if( pPager->stmtOpen ){ + sqlite3OsClose(pPager->stfd); + sqlite3_free(pPager->aInStmt); + pPager->aInStmt = 0; + } + if( pPager->journalOpen ){ + sqlite3OsClose(pPager->jfd); + pPager->journalOpen = 0; + sqlite3_free(pPager->aInJournal); + pPager->aInJournal = 0; + } + pPager->stmtOpen = 0; + pPager->stmtInUse = 0; + pPager->journalOff = 0; + pPager->journalStarted = 0; + pPager->stmtAutoopen = 0; + pPager->origDbSize = 0; + } + } + + if( !MEMDB || pPager->errCode==SQLITE_OK ){ + pPager->state = PAGER_UNLOCK; + pPager->changeCountDone = 0; + } + } +} + +/* +** Execute a rollback if a transaction is active and unlock the +** database file. If the pager has already entered the error state, +** do not attempt the rollback. +*/ +static void pagerUnlockAndRollback(Pager *p){ + assert( p->state>=PAGER_RESERVED || p->journalOpen==0 ); + if( p->errCode==SQLITE_OK && p->state>=PAGER_RESERVED ){ + sqlite3PagerRollback(p); + } + pager_unlock(p); + assert( p->errCode || !p->journalOpen || (p->exclusiveMode&&!p->journalOff) ); + assert( p->errCode || !p->stmtOpen || p->exclusiveMode ); +} + /* ** This routine ends a transaction. A transaction is ended by either ** a COMMIT or a ROLLBACK. @@ -1016,23 +1337,22 @@ static int pager_end_transaction(Pager *pPager){ } sqlite3PagerStmtCommit(pPager); if( pPager->stmtOpen && !pPager->exclusiveMode ){ - sqlite3OsClose(&pPager->stfd); + sqlite3OsClose(pPager->stfd); pPager->stmtOpen = 0; } if( pPager->journalOpen ){ if( pPager->exclusiveMode && (rc = sqlite3OsTruncate(pPager->jfd, 0))==SQLITE_OK ){; - sqlite3OsSeek(pPager->jfd, 0); pPager->journalOff = 0; pPager->journalStarted = 0; }else{ - sqlite3OsClose(&pPager->jfd); + sqlite3OsClose(pPager->jfd); pPager->journalOpen = 0; if( rc==SQLITE_OK ){ - rc = sqlite3OsDelete(pPager->zJournal); + rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); } } - sqliteFree( pPager->aInJournal ); + sqlite3_free( pPager->aInJournal ); pPager->aInJournal = 0; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->inJournal = 0; @@ -1052,7 +1372,7 @@ static int pager_end_transaction(Pager *pPager){ } if( !pPager->exclusiveMode ){ - rc2 = sqlite3OsUnlock(pPager->fd, SHARED_LOCK); + rc2 = osUnlock(pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; }else if( pPager->state==PAGER_SYNCED ){ pPager->state = PAGER_EXCLUSIVE; @@ -1060,7 +1380,7 @@ static int pager_end_transaction(Pager *pPager){ pPager->origDbSize = 0; pPager->setMaster = 0; pPager->needSync = 0; - pPager->pFirstSynced = pPager->pFirst; + lruListSetFirstSynced(pPager); pPager->dbSize = -1; return (rc==SQLITE_OK?rc2:rc); @@ -1107,7 +1427,12 @@ static void makeClean(PgHdr*); ** are not used in statement journals because statement journals do not ** need to survive power failures. */ -static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){ +static int pager_playback_one_page( + Pager *pPager, + sqlite3_file *jfd, + i64 offset, + int useCksum +){ int rc; PgHdr *pPg; /* An existing page in the cache */ Pgno pgno; /* The page number of a page in journal */ @@ -1120,9 +1445,9 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){ assert( jfd == (useCksum ? pPager->jfd : pPager->stfd) ); assert( aData ); - rc = read32bits(jfd, &pgno); + rc = read32bits(jfd, offset, &pgno); if( rc!=SQLITE_OK ) return rc; - rc = sqlite3OsRead(jfd, aData, pPager->pageSize); + rc = sqlite3OsRead(jfd, aData, pPager->pageSize, offset+4); if( rc!=SQLITE_OK ) return rc; pPager->journalOff += pPager->pageSize + 4; @@ -1138,7 +1463,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){ return SQLITE_OK; } if( useCksum ){ - rc = read32bits(jfd, &cksum); + rc = read32bits(jfd, offset+pPager->pageSize+4, &cksum); if( rc ) return rc; pPager->journalOff += 4; if( pager_cksum(pPager, aData)!=cksum ){ @@ -1180,10 +1505,8 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){ PAGERTRACE4("PLAYBACK %d page %d hash(%08x)\n", PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, aData)); if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){ - rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize); - if( rc==SQLITE_OK ){ - rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize); - } + i64 offset = (pgno-1)*(i64)pPager->pageSize; + rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize, offset); if( pPg ){ makeClean(pPg); } @@ -1223,67 +1546,79 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){ ** This routine checks if it is possible to delete the master journal file, ** and does so if it is. ** +** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not +** available for use within this function. +** +** ** The master journal file contains the names of all child journals. ** To tell if a master journal can be deleted, check to each of the ** children. If all children are either missing or do not refer to ** a different master journal, then this master journal can be deleted. */ -static int pager_delmaster(const char *zMaster){ +static int pager_delmaster(Pager *pPager, const char *zMaster){ + sqlite3_vfs *pVfs = pPager->pVfs; int rc; int master_open = 0; - OsFile *master = 0; + sqlite3_file *pMaster; + sqlite3_file *pJournal; char *zMasterJournal = 0; /* Contents of master journal file */ i64 nMasterJournal; /* Size of master journal file */ /* Open the master journal file exclusively in case some other process ** is running this routine also. Not that it makes too much difference. */ - rc = sqlite3OsOpenReadOnly(zMaster, &master); - assert( rc!=SQLITE_OK || master ); + pMaster = (sqlite3_file *)sqlite3_malloc(pVfs->szOsFile * 2); + pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile); + if( !pMaster ){ + rc = SQLITE_NOMEM; + }else{ + int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL); + rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0); + } if( rc!=SQLITE_OK ) goto delmaster_out; master_open = 1; - rc = sqlite3OsFileSize(master, &nMasterJournal); + + rc = sqlite3OsFileSize(pMaster, &nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; if( nMasterJournal>0 ){ char *zJournal; char *zMasterPtr = 0; + int nMasterPtr = pPager->pVfs->mxPathname+1; /* Load the entire master journal file into space obtained from - ** sqliteMalloc() and pointed to by zMasterJournal. + ** sqlite3_malloc() and pointed to by zMasterJournal. */ - zMasterJournal = (char *)sqliteMalloc(nMasterJournal); + zMasterJournal = (char *)sqlite3_malloc(nMasterJournal + nMasterPtr); if( !zMasterJournal ){ rc = SQLITE_NOMEM; goto delmaster_out; } - rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal); + zMasterPtr = &zMasterJournal[nMasterJournal]; + rc = sqlite3OsRead(pMaster, zMasterJournal, nMasterJournal, 0); if( rc!=SQLITE_OK ) goto delmaster_out; zJournal = zMasterJournal; while( (zJournal-zMasterJournal)state>=PAGER_EXCLUSIVE ){ + if( pPager->state>=PAGER_EXCLUSIVE && pPager->fd->pMethods ){ rc = sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage); } if( rc==SQLITE_OK ){ @@ -1331,7 +1667,14 @@ static int pager_truncate(Pager *pPager, int nPage){ ** by sqlite3OsSectorSize() and the pageSize. */ static void setSectorSize(Pager *pPager){ - pPager->sectorSize = sqlite3OsSectorSize(pPager->fd); + assert(pPager->fd->pMethods||pPager->tempFile); + if( !pPager->tempFile ){ + /* Sector size doesn't matter for temporary files. Also, the file + ** may not have been opened yet, in whcih case the OsSectorSize() + ** call will segfault. + */ + pPager->sectorSize = sqlite3OsSectorSize(pPager->fd); + } if( pPager->sectorSizepageSize ){ pPager->sectorSize = pPager->pageSize; } @@ -1391,6 +1734,7 @@ static void setSectorSize(Pager *pPager){ ** and an error code is returned. */ static int pager_playback(Pager *pPager, int isHot){ + sqlite3_vfs *pVfs = pPager->pVfs; i64 szJ; /* Size of the journal file in bytes */ u32 nRec; /* Number of Records in the journal */ int i; /* Loop counter */ @@ -1412,16 +1756,18 @@ static int pager_playback(Pager *pPager, int isHot){ ** present on disk, then the journal is not hot and does not need to be ** played back. */ - rc = readMasterJournal(pPager->jfd, &zMaster); + zMaster = pPager->pTmpSpace; + rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); assert( rc!=SQLITE_DONE ); - if( rc!=SQLITE_OK || (zMaster && !sqlite3OsFileExists(zMaster)) ){ - sqliteFree(zMaster); + if( rc!=SQLITE_OK + || (zMaster[0] && !sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS)) + ){ zMaster = 0; if( rc==SQLITE_DONE ) rc = SQLITE_OK; goto end_playback; } - sqlite3OsSeek(pPager->jfd, 0); pPager->journalOff = 0; + zMaster = 0; /* This loop terminates either when the readJournalHdr() call returns ** SQLITE_DONE or an IO error occurs. */ @@ -1451,10 +1797,15 @@ static int pager_playback(Pager *pPager, int isHot){ } /* If nRec is 0 and this rollback is of a transaction created by this - ** process. In this case the rest of the journal file consists of - ** journalled copies of pages that need to be read back into the cache. + ** process and if this is the final header in the journal, then it means + ** that this part of the journal was being filled but has not yet been + ** synced to disk. Compute the number of pages based on the remaining + ** size of the file. + ** + ** The third term of the test was added to fix ticket #2565. */ - if( nRec==0 && !isHot ){ + if( nRec==0 && !isHot && + pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){ nRec = (szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager); } @@ -1471,7 +1822,7 @@ static int pager_playback(Pager *pPager, int isHot){ /* Copy original pages out of the journal and back into the database file. */ for(i=0; ijfd, 1); + rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; @@ -1487,17 +1838,18 @@ static int pager_playback(Pager *pPager, int isHot){ assert( 0 ); end_playback: + if( rc==SQLITE_OK ){ + zMaster = pPager->pTmpSpace; + rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); + } if( rc==SQLITE_OK ){ rc = pager_end_transaction(pPager); } - if( zMaster ){ + if( rc==SQLITE_OK && zMaster[0] ){ /* If there was a master journal and this routine will return success, ** see if it is possible to delete the master journal. */ - if( rc==SQLITE_OK ){ - rc = pager_delmaster(zMaster); - } - sqliteFree(zMaster); + rc = pager_delmaster(pPager, zMaster); } /* The Pager.sectorSize variable may have been updated while rolling @@ -1558,7 +1910,6 @@ static int pager_stmt_playback(Pager *pPager){ /* Figure out how many records are in the statement journal. */ assert( pPager->stmtInUse && pPager->journalOpen ); - sqlite3OsSeek(pPager->stfd, 0); nRec = pPager->stmtNRec; /* Copy original pages out of the statement journal and back into the @@ -1566,8 +1917,9 @@ static int pager_stmt_playback(Pager *pPager){ ** each record since power-failure recovery is not important to statement ** journals. */ - for(i=nRec-1; i>=0; i--){ - rc = pager_playback_one_page(pPager, pPager->stfd, 0); + for(i=0; ipageSize); + rc = pager_playback_one_page(pPager, pPager->stfd, offset, 0); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } @@ -1580,14 +1932,10 @@ static int pager_stmt_playback(Pager *pPager){ ** If it is not zero, then Pager.stmtHdrOff is the offset to the start ** of the first journal header written during this statement transaction. */ - rc = sqlite3OsSeek(pPager->jfd, pPager->stmtJSize); - if( rc!=SQLITE_OK ){ - goto end_stmt_playback; - } pPager->journalOff = pPager->stmtJSize; pPager->cksumInit = pPager->stmtCksum; while( pPager->journalOff < hdrOff ){ - rc = pager_playback_one_page(pPager, pPager->jfd, 1); + rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } @@ -1604,7 +1952,7 @@ static int pager_stmt_playback(Pager *pPager){ nJRec = (szJ - pPager->journalOff) / (pPager->pageSize+8); } for(i=nJRec-1; i>=0 && pPager->journalOff < szJ; i--){ - rc = pager_playback_one_page(pPager, pPager->jfd, 1); + rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } @@ -1661,7 +2009,7 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int full_fsync){ pPager->noSync = level==1 || pPager->tempFile; pPager->fullSync = level==3 && !pPager->tempFile; - pPager->full_fsync = full_fsync; + pPager->sync_flags = (full_fsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL); if( pPager->noSync ) pPager->needSync = 0; } #endif @@ -1679,25 +2027,26 @@ int sqlite3_opentemp_count = 0; ** Open a temporary file. ** ** Write the file descriptor into *fd. Return SQLITE_OK on success or some -** other error code if we fail. -** -** The OS will automatically delete the temporary file when it is -** closed. +** other error code if we fail. The OS will automatically delete the temporary +** file when it is closed. */ -static int sqlite3PagerOpentemp(OsFile **pFd){ - int cnt = 8; +static int sqlite3PagerOpentemp( + sqlite3_vfs *pVfs, /* The virtual file system layer */ + sqlite3_file *pFile, /* Write the file descriptor here */ + char *zFilename, /* Name of the file. Might be NULL */ + int vfsFlags /* Flags passed through to the VFS */ +){ int rc; - char zFile[SQLITE_TEMPNAME_SIZE]; + assert( zFilename!=0 ); #ifdef SQLITE_TEST sqlite3_opentemp_count++; /* Used for testing and analysis only */ #endif - do{ - cnt--; - sqlite3OsTempFileName(zFile); - rc = sqlite3OsOpenExclusive(zFile, pFd, 1); - assert( rc!=SQLITE_OK || *pFd ); - }while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM ); + + vfsFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | + SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE; + rc = sqlite3OsOpen(pVfs, zFilename, pFile, vfsFlags, 0); + assert( rc!=SQLITE_OK || pFile->pMethods ); return rc; } @@ -1716,15 +2065,15 @@ static int sqlite3PagerOpentemp(OsFile **pFd){ ** in-memory database. */ int sqlite3PagerOpen( + sqlite3_vfs *pVfs, /* The virtual file system to use */ Pager **ppPager, /* Return the Pager structure here */ const char *zFilename, /* Name of the database file to open */ int nExtra, /* Extra bytes append to each in-memory page */ - int flags /* flags controlling this file */ + int flags, /* flags controlling this file */ + int vfsFlags /* flags passed through to sqlite3_vfs.xOpen() */ ){ + u8 *pPtr; Pager *pPager = 0; - char *zFullPathname = 0; - int nameLen; /* Compiler is wrong. This is always initialized before use */ - OsFile *fd = 0; int rc = SQLITE_OK; int i; int tempFile = 0; @@ -1732,93 +2081,142 @@ int sqlite3PagerOpen( int readOnly = 0; int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; int noReadlock = (flags & PAGER_NO_READLOCK)!=0; - char zTemp[SQLITE_TEMPNAME_SIZE]; -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to - ** malloc() must have already been made by this thread before it gets - ** to this point. This means the ThreadData must have been allocated already - ** so that ThreadData.nAlloc can be set. It would be nice to assert - ** that ThreadData.nAlloc is non-zero, but alas this breaks test cases - ** written to invoke the pager directly. - */ - ThreadData *pTsd = sqlite3ThreadData(); - assert( pTsd ); -#endif + int journalFileSize = sqlite3JournalSize(pVfs); + int nDefaultPage = SQLITE_DEFAULT_PAGE_SIZE; + char *zPathname; + int nPathname; - /* We used to test if malloc() had already failed before proceeding. - ** But the way this function is used in SQLite means that can never - ** happen. Furthermore, if the malloc-failed flag is already set, - ** either the call to sqliteStrDup() or sqliteMalloc() below will - ** fail shortly and SQLITE_NOMEM returned anyway. - */ + /* The default return is a NULL pointer */ *ppPager = 0; - /* Open the pager file and set zFullPathname to point at malloc()ed - ** memory containing the complete filename (i.e. including the directory). - */ + /* Compute the full pathname */ + nPathname = pVfs->mxPathname+1; + zPathname = sqlite3_malloc(nPathname); + if( zPathname==0 ){ + return SQLITE_NOMEM; + } if( zFilename && zFilename[0] ){ #ifndef SQLITE_OMIT_MEMORYDB if( strcmp(zFilename,":memory:")==0 ){ memDb = 1; - zFullPathname = sqliteStrDup(""); + zPathname[0] = 0; }else #endif { - zFullPathname = sqlite3OsFullPathname(zFilename); - if( zFullPathname ){ - rc = sqlite3OsOpenReadWrite(zFullPathname, &fd, &readOnly); - assert( rc!=SQLITE_OK || fd ); - } + rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); } }else{ - rc = sqlite3PagerOpentemp(&fd); - sqlite3OsTempFileName(zTemp); - zFilename = zTemp; - zFullPathname = sqlite3OsFullPathname(zFilename); - if( rc==SQLITE_OK ){ - tempFile = 1; - } + rc = sqlite3OsGetTempname(pVfs, nPathname, zPathname); } + if( rc!=SQLITE_OK ){ + sqlite3_free(zPathname); + return rc; + } + nPathname = strlen(zPathname); - /* Allocate the Pager structure. As part of the same allocation, allocate - ** space for the full paths of the file, directory and journal - ** (Pager.zFilename, Pager.zDirectory and Pager.zJournal). + /* Allocate memory for the pager structure */ + pPager = sqlite3MallocZero( + sizeof(*pPager) + /* Pager structure */ + journalFileSize + /* The journal file structure */ + pVfs->szOsFile * 2 + /* The db and stmt journal files */ + 4*nPathname + 40 /* zFilename, zDirectory, zJournal, zStmtJrnl */ + ); + if( !pPager ){ + sqlite3_free(zPathname); + return SQLITE_NOMEM; + } + pPtr = (u8 *)&pPager[1]; + pPager->vfsFlags = vfsFlags; + pPager->fd = (sqlite3_file*)&pPtr[pVfs->szOsFile*0]; + pPager->stfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*1]; + pPager->jfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*2]; + pPager->zFilename = (char*)&pPtr[pVfs->szOsFile*2+journalFileSize]; + pPager->zDirectory = &pPager->zFilename[nPathname+1]; + pPager->zJournal = &pPager->zDirectory[nPathname+1]; + pPager->zStmtJrnl = &pPager->zJournal[nPathname+10]; + pPager->pVfs = pVfs; + memcpy(pPager->zFilename, zPathname, nPathname+1); + sqlite3_free(zPathname); + + /* Open the pager file. */ - if( zFullPathname ){ - nameLen = strlen(zFullPathname); - pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 ); - if( pPager && rc==SQLITE_OK ){ - pPager->pTmpSpace = (char *)sqliteMallocRaw(SQLITE_DEFAULT_PAGE_SIZE); + if( zFilename && zFilename[0] && !memDb ){ + if( nPathname>(pVfs->mxPathname - sizeof("-journal")) ){ + rc = SQLITE_CANTOPEN; + }else{ + int fout = 0; + rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, + pPager->vfsFlags, &fout); + readOnly = (fout&SQLITE_OPEN_READONLY); + + /* If the file was successfully opened for read/write access, + ** choose a default page size in case we have to create the + ** database file. The default page size is the maximum of: + ** + ** + SQLITE_DEFAULT_PAGE_SIZE, + ** + The value returned by sqlite3OsSectorSize() + ** + The largest page size that can be written atomically. + */ + if( rc==SQLITE_OK && !readOnly ){ + int iSectorSize = sqlite3OsSectorSize(pPager->fd); + if( nDefaultPagefd); + int ii; + assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); + assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); + assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); + for(ii=nDefaultPage; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ + if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ) nDefaultPage = ii; + } + } +#endif + if( nDefaultPage>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ + nDefaultPage = SQLITE_MAX_DEFAULT_PAGE_SIZE; + } + } } + }else if( !memDb ){ + /* If a temporary file is requested, it is not opened immediately. + ** In this case we accept the default page size and delay actually + ** opening the file until the first call to OsWrite(). + */ + tempFile = 1; + pPager->state = PAGER_EXCLUSIVE; } + if( pPager && rc==SQLITE_OK ){ + pPager->pTmpSpace = (char *)sqlite3_malloc(nDefaultPage); + } - /* If an error occured in either of the blocks above, free the memory - ** pointed to by zFullPathname, free the Pager structure and close the - ** file. Since the pager is not allocated there is no need to set + /* If an error occured in either of the blocks above. + ** Free the Pager structure and close the file. + ** Since the pager is not allocated there is no need to set ** any Pager.errMask variables. */ - if( !pPager || !zFullPathname || !pPager->pTmpSpace || rc!=SQLITE_OK ){ - sqlite3OsClose(&fd); - sqliteFree(zFullPathname); - sqliteFree(pPager); + if( !pPager || !pPager->pTmpSpace ){ + sqlite3OsClose(pPager->fd); + sqlite3_free(pPager); return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc); } - PAGERTRACE3("OPEN %d %s\n", FILEHANDLEID(fd), zFullPathname); - IOTRACE(("OPEN %p %s\n", pPager, zFullPathname)) - pPager->zFilename = (char*)&pPager[1]; - pPager->zDirectory = &pPager->zFilename[nameLen+1]; - pPager->zJournal = &pPager->zDirectory[nameLen+1]; - memcpy(pPager->zFilename, zFullPathname, nameLen+1); - memcpy(pPager->zDirectory, zFullPathname, nameLen+1); + PAGERTRACE3("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename); + IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename)) - for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){} + /* Fill in Pager.zDirectory[] */ + memcpy(pPager->zDirectory, pPager->zFilename, nPathname+1); + for(i=strlen(pPager->zDirectory); i>0 && pPager->zDirectory[i-1]!='/'; i--){} if( i>0 ) pPager->zDirectory[i-1] = 0; - memcpy(pPager->zJournal, zFullPathname,nameLen); - sqliteFree(zFullPathname); - memcpy(&pPager->zJournal[nameLen], "-journal",sizeof("-journal")); - pPager->fd = fd; + + /* Fill in Pager.zJournal[] and Pager.zStmtJrnl[] */ + memcpy(pPager->zJournal, pPager->zFilename, nPathname); + memcpy(&pPager->zJournal[nPathname], "-journal", 9); + memcpy(pPager->zStmtJrnl, pPager->zFilename, nPathname); + memcpy(&pPager->zStmtJrnl[nPathname], "-stmtjrnl", 10); + /* pPager->journalOpen = 0; */ pPager->useJournal = useJournal && !memDb; pPager->noReadlock = noReadlock && readOnly; @@ -1826,14 +2224,14 @@ int sqlite3PagerOpen( /* pPager->stmtInUse = 0; */ /* pPager->nRef = 0; */ pPager->dbSize = memDb-1; - pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE; + pPager->pageSize = nDefaultPage; /* pPager->stmtSize = 0; */ /* pPager->stmtJSize = 0; */ /* pPager->nPage = 0; */ pPager->mxPage = 100; pPager->mxPgno = SQLITE_MAX_PAGE_COUNT; - assert( PAGER_UNLOCK==0 ); /* pPager->state = PAGER_UNLOCK; */ + assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) ); /* pPager->errMask = 0; */ pPager->tempFile = tempFile; assert( tempFile==PAGER_LOCKINGMODE_NORMAL @@ -1845,11 +2243,12 @@ int sqlite3PagerOpen( /* pPager->needSync = 0; */ pPager->noSync = pPager->tempFile || !useJournal; pPager->fullSync = (pPager->noSync?0:1); + pPager->sync_flags = SQLITE_SYNC_NORMAL; /* pPager->pFirst = 0; */ /* pPager->pFirstSynced = 0; */ /* pPager->pLast = 0; */ pPager->nExtra = FORCE_ALIGNMENT(nExtra); - assert(fd||memDb); + assert(pPager->fd->pMethods||memDb||tempFile); if( !memDb ){ setSectorSize(pPager); } @@ -1857,8 +2256,20 @@ int sqlite3PagerOpen( /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ *ppPager = pPager; #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - pPager->pNext = pTsd->pPager; - pTsd->pPager = pPager; + pPager->iInUseMM = 0; + pPager->iInUseDB = 0; + if( !memDb ){ + sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); + sqlite3_mutex_enter(mutex); + pPager->pNext = sqlite3PagerList; + if( sqlite3PagerList ){ + assert( sqlite3PagerList->pPrev==0 ); + sqlite3PagerList->pPrev = pPager; + } + pPager->pPrev = 0; + sqlite3PagerList = pPager; + sqlite3_mutex_leave(mutex); + } #endif return SQLITE_OK; } @@ -1894,18 +2305,32 @@ void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*,int)){ } /* -** Set the page size. Return the new size. If the suggest new page -** size is inappropriate, then an alternative page size is selected -** and returned. +** Set the page size to *pPageSize. If the suggest new page size is +** inappropriate, then an alternative page size is set to that +** value before returning. */ -int sqlite3PagerSetPagesize(Pager *pPager, int pageSize){ - assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE ); - if( !pPager->memDb && pPager->nRef==0 ){ - pager_reset(pPager); - pPager->pageSize = pageSize; - pPager->pTmpSpace = sqlite3ReallocOrFree(pPager->pTmpSpace, pageSize); +int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize){ + int rc = SQLITE_OK; + u16 pageSize = *pPageSize; + assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); + if( pageSize && pageSize!=pPager->pageSize + && !pPager->memDb && pPager->nRef==0 + ){ + char *pNew = (char *)sqlite3_malloc(pageSize); + if( !pNew ){ + rc = SQLITE_NOMEM; + }else{ + pagerEnter(pPager); + pager_reset(pPager); + pPager->pageSize = pageSize; + setSectorSize(pPager); + sqlite3_free(pPager->pTmpSpace); + pPager->pTmpSpace = pNew; + pagerLeave(pPager); + } } - return pPager->pageSize; + *pPageSize = pPager->pageSize; + return rc; } /* @@ -1960,12 +2385,10 @@ void enable_simulated_io_errors(void){ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){ int rc = SQLITE_OK; memset(pDest, 0, N); - if( MEMDB==0 ){ - disable_simulated_io_errors(); - sqlite3OsSeek(pPager->fd, 0); - enable_simulated_io_errors(); + assert(MEMDB||pPager->fd->pMethods||pPager->tempFile); + if( pPager->fd->pMethods ){ IOTRACE(("DBHDR %p 0 %d\n", pPager, N)) - rc = sqlite3OsRead(pPager->fd, pDest, N); + rc = sqlite3OsRead(pPager->fd, pDest, N, 0); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } @@ -1983,7 +2406,7 @@ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){ ** file is 4096 bytes, 5 is returned instead of 4. */ int sqlite3PagerPagecount(Pager *pPager){ - i64 n; + i64 n = 0; int rc; assert( pPager!=0 ); if( pPager->errCode ){ @@ -1992,8 +2415,12 @@ int sqlite3PagerPagecount(Pager *pPager){ if( pPager->dbSize>=0 ){ n = pPager->dbSize; } else { - if( (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){ + assert(pPager->fd->pMethods||pPager->tempFile); + if( (pPager->fd->pMethods) + && (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){ + pPager->nRef++; pager_error(pPager, rc); + pPager->nRef--; return 0; } if( n>0 && npageSize ){ @@ -2020,8 +2447,8 @@ int sqlite3PagerPagecount(Pager *pPager){ ** Clear a PgHistory block */ static void clearHistory(PgHistory *pHist){ - sqliteFree(pHist->pOrig); - sqliteFree(pHist->pStmt); + sqlite3_free(pHist->pOrig); + sqlite3_free(pHist->pStmt); pHist->pOrig = 0; pHist->pStmt = 0; } @@ -2069,27 +2496,8 @@ static void unlinkHashChain(Pager *pPager, PgHdr *pPg){ static void unlinkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; - /* Keep the pFirstSynced pointer pointing at the first synchronized page */ - if( pPg==pPager->pFirstSynced ){ - PgHdr *p = pPg->pNextFree; - while( p && p->needSync ){ p = p->pNextFree; } - pPager->pFirstSynced = p; - } - - /* Unlink from the freelist */ - if( pPg->pPrevFree ){ - pPg->pPrevFree->pNextFree = pPg->pNextFree; - }else{ - assert( pPager->pFirst==pPg ); - pPager->pFirst = pPg->pNextFree; - } - if( pPg->pNextFree ){ - pPg->pNextFree->pPrevFree = pPg->pPrevFree; - }else{ - assert( pPager->pLast==pPg ); - pPager->pLast = pPg->pPrevFree; - } - pPg->pNextFree = pPg->pPrevFree = 0; + /* Unlink from free page list */ + lruListRemove(pPg); /* Unlink from the pgno hash table */ unlinkHashChain(pPager, pPg); @@ -2125,7 +2533,8 @@ static void pager_truncate_cache(Pager *pPager){ PAGER_INCR(sqlite3_pager_pgfree_count); unlinkPage(pPg); makeClean(pPg); - sqliteFree(pPg); + sqlite3_free(pPg->pData); + sqlite3_free(pPg); pPager->nPage--; } } @@ -2183,13 +2592,17 @@ int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){ pager_truncate_cache(pPager); return SQLITE_OK; } + pagerEnter(pPager); rc = syncJournal(pPager); + pagerLeave(pPager); if( rc!=SQLITE_OK ){ return rc; } /* Get an exclusive lock on the database before truncating. */ + pagerEnter(pPager); rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); + pagerLeave(pPager); if( rc!=SQLITE_OK ){ return rc; } @@ -2214,14 +2627,19 @@ int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){ */ int sqlite3PagerClose(Pager *pPager){ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to - ** malloc() must have already been made by this thread before it gets - ** to this point. This means the ThreadData must have been allocated already - ** so that ThreadData.nAlloc can be set. - */ - ThreadData *pTsd = sqlite3ThreadData(); - assert( pPager ); - assert( pTsd && pTsd->nAlloc ); + if( !MEMDB ){ + sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); + sqlite3_mutex_enter(mutex); + if( pPager->pPrev ){ + pPager->pPrev->pNext = pPager->pNext; + }else{ + sqlite3PagerList = pPager->pNext; + } + if( pPager->pNext ){ + pPager->pNext->pPrev = pPager->pPrev; + } + sqlite3_mutex_leave(mutex); + } #endif disable_simulated_io_errors(); @@ -2234,34 +2652,22 @@ int sqlite3PagerClose(Pager *pPager){ IOTRACE(("CLOSE %p\n", pPager)) assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) ); if( pPager->journalOpen ){ - sqlite3OsClose(&pPager->jfd); + sqlite3OsClose(pPager->jfd); } - sqliteFree(pPager->aInJournal); + sqlite3_free(pPager->aInJournal); if( pPager->stmtOpen ){ - sqlite3OsClose(&pPager->stfd); + sqlite3OsClose(pPager->stfd); } - sqlite3OsClose(&pPager->fd); + sqlite3OsClose(pPager->fd); /* Temp files are automatically deleted by the OS ** if( pPager->tempFile ){ ** sqlite3OsDelete(pPager->zFilename); ** } */ -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - /* Remove the pager from the linked list of pagers starting at - ** ThreadData.pPager if memory-management is enabled. - */ - if( pPager==pTsd->pPager ){ - pTsd->pPager = pPager->pNext; - }else{ - Pager *pTmp; - for(pTmp = pTsd->pPager; pTmp->pNext!=pPager; pTmp=pTmp->pNext){} - pTmp->pNext = pPager->pNext; - } -#endif - sqliteFree(pPager->aHash); - sqliteFree(pPager->pTmpSpace); - sqliteFree(pPager); + sqlite3_free(pPager->aHash); + sqlite3_free(pPager->pTmpSpace); + sqlite3_free(pPager); return SQLITE_OK; } @@ -2286,21 +2692,7 @@ Pgno sqlite3PagerPagenumber(DbPage *p){ static void _page_ref(PgHdr *pPg){ if( pPg->nRef==0 ){ /* The page is currently on the freelist. Remove it. */ - if( pPg==pPg->pPager->pFirstSynced ){ - PgHdr *p = pPg->pNextFree; - while( p && p->needSync ){ p = p->pNextFree; } - pPg->pPager->pFirstSynced = p; - } - if( pPg->pPrevFree ){ - pPg->pPrevFree->pNextFree = pPg->pNextFree; - }else{ - pPg->pPager->pFirst = pPg->pNextFree; - } - if( pPg->pNextFree ){ - pPg->pNextFree->pPrevFree = pPg->pPrevFree; - }else{ - pPg->pPager->pLast = pPg->pPrevFree; - } + lruListRemove(pPg); pPg->pPager->nRef++; } pPg->nRef++; @@ -2324,7 +2716,9 @@ static void _page_ref(PgHdr *pPg){ ** a reference to the page data. */ int sqlite3PagerRef(DbPage *pPg){ + pagerEnter(pPg->pPager); page_ref(pPg); + pagerLeave(pPg->pPager); return SQLITE_OK; } @@ -2343,7 +2737,12 @@ int sqlite3PagerRef(DbPage *pPg){ ** is synced, then the nRec field is updated, then a second sync occurs. ** ** For temporary databases, we do not care if we are able to rollback -** after a power failure, so sync occurs. +** after a power failure, so no sync occurs. +** +** If the IOCAP_SEQUENTIAL flag is set for the persistent media on which +** the database is stored, then OsSync() is never called on the journal +** file. In this case all that is required is to update the nRec field in +** the journal header. ** ** This routine clears the needSync field of every page current held in ** memory. @@ -2352,12 +2751,15 @@ static int syncJournal(Pager *pPager){ PgHdr *pPg; int rc = SQLITE_OK; + /* Sync the journal before modifying the main database ** (assuming there is a journal and it needs to be synced.) */ if( pPager->needSync ){ if( !pPager->tempFile ){ + int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); assert( pPager->journalOpen ); + /* assert( !pPager->noSync ); // noSync might be set if synchronous ** was turned off after the transaction was started. Ticket #615 */ #ifndef NDEBUG @@ -2371,33 +2773,39 @@ static int syncJournal(Pager *pPager){ assert( pPager->journalOff==jSz ); } #endif - { + if( 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){ /* Write the nRec value into the journal file header. If in ** full-synchronous mode, sync the journal first. This ensures that ** all data has really hit the disk before nRec is updated to mark - ** it as a candidate for rollback. + ** it as a candidate for rollback. + ** + ** This is not required if the persistent media supports the + ** SAFE_APPEND property. Because in this case it is not possible + ** for garbage data to be appended to the file, the nRec field + ** is populated with 0xFFFFFFFF when the journal header is written + ** and never needs to be updated. */ - if( pPager->fullSync ){ + i64 jrnlOff; + if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){ PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager)); IOTRACE(("JSYNC %p\n", pPager)) - rc = sqlite3OsSync(pPager->jfd, 0); + rc = sqlite3OsSync(pPager->jfd, pPager->sync_flags); if( rc!=0 ) return rc; } - rc = sqlite3OsSeek(pPager->jfd, - pPager->journalHdr + sizeof(aJournalMagic)); - if( rc ) return rc; - IOTRACE(("JHDR %p %lld %d\n", pPager, - pPager->journalHdr + sizeof(aJournalMagic), 4)) - rc = write32bits(pPager->jfd, pPager->nRec); - if( rc ) return rc; - rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff); + jrnlOff = pPager->journalHdr + sizeof(aJournalMagic); + IOTRACE(("JHDR %p %lld %d\n", pPager, jrnlOff, 4)); + rc = write32bits(pPager->jfd, jrnlOff, pPager->nRec); if( rc ) return rc; } - PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager)); - IOTRACE(("JSYNC %p\n", pPager)) - rc = sqlite3OsSync(pPager->jfd, pPager->full_fsync); - if( rc!=0 ) return rc; + if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){ + PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager)); + IOTRACE(("JSYNC %p\n", pPager)) + rc = sqlite3OsSync(pPager->jfd, pPager->sync_flags| + (pPager->sync_flags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0) + ); + if( rc!=0 ) return rc; + } pPager->journalStarted = 1; } pPager->needSync = 0; @@ -2407,7 +2815,7 @@ static int syncJournal(Pager *pPager){ for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->needSync = 0; } - pPager->pFirstSynced = pPager->pFirst; + lruListSetFirstSynced(pPager); } #ifndef NDEBUG @@ -2419,7 +2827,7 @@ static int syncJournal(Pager *pPager){ for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ assert( pPg->needSync==0 ); } - assert( pPager->pFirstSynced==pPager->pFirst ); + assert( pPager->lru.pFirstSynced==pPager->lru.pFirst ); } #endif @@ -2507,6 +2915,7 @@ static PgHdr *sort_pagelist(PgHdr *pIn){ */ static int pager_write_pagelist(PgHdr *pList){ Pager *pPager; + PgHdr *p; int rc; if( pList==0 ) return SQLITE_OK; @@ -2534,21 +2943,32 @@ static int pager_write_pagelist(PgHdr *pList){ } pList = sort_pagelist(pList); + for(p=pList; p; p=p->pDirty){ + assert( p->dirty ); + p->dirty = 0; + } while( pList ){ - assert( pList->dirty ); - rc = sqlite3OsSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize); - if( rc ) return rc; + + /* If the file has not yet been opened, open it now. */ + if( !pPager->fd->pMethods ){ + assert(pPager->tempFile); + rc = sqlite3PagerOpentemp(pPager->pVfs, pPager->fd, pPager->zFilename, + pPager->vfsFlags); + if( rc ) return rc; + } + /* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3PagerTruncate() was called to ** make the file smaller (presumably by auto-vacuum code). Do not write ** any such pages to the file. */ if( pList->pgno<=pPager->dbSize ){ + i64 offset = (pList->pgno-1)*(i64)pPager->pageSize; char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6); PAGERTRACE4("STORE %d page %d hash(%08x)\n", PAGERID(pPager), pList->pgno, pager_pagehash(pList)); IOTRACE(("PGOUT %p %d\n", pPager, pList->pgno)); - rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize); + rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); PAGER_INCR(sqlite3_pager_writedb_count); PAGER_INCR(pPager->nWrite); if( pList->pgno==1 ){ @@ -2561,7 +2981,6 @@ static int pager_write_pagelist(PgHdr *pList){ } #endif if( rc ) return rc; - pList->dirty = 0; #ifdef SQLITE_CHECK_PAGES pList->pageHash = pager_pagehash(pList); #endif @@ -2588,15 +3007,16 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){ ** database with the same name. Just delete the journal. */ static int hasHotJournal(Pager *pPager){ + sqlite3_vfs *pVfs = pPager->pVfs; if( !pPager->useJournal ) return 0; - if( !sqlite3OsFileExists(pPager->zJournal) ){ + if( !sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS) ){ return 0; } if( sqlite3OsCheckReservedLock(pPager->fd) ){ return 0; } if( sqlite3PagerPagecount(pPager)==0 ){ - sqlite3OsDelete(pPager->zJournal); + sqlite3OsDelete(pVfs, pPager->zJournal, 0); return 0; }else{ return 1; @@ -2609,28 +3029,33 @@ static int hasHotJournal(Pager *pPager){ ** This routine may return SQLITE_IOERR, SQLITE_FULL or SQLITE_OK. It ** does not set the pPager->errCode variable. */ -static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){ +static int pager_recycle(Pager *pPager, PgHdr **ppPg){ PgHdr *pPg; *ppPg = 0; + /* It is illegal to call this function unless the pager object + ** pointed to by pPager has at least one free page (page with nRef==0). + */ assert(!MEMDB); + assert(pPager->lru.pFirst); /* Find a page to recycle. Try to locate a page that does not ** require us to do an fsync() on the journal. */ - pPg = pPager->pFirstSynced; + pPg = pPager->lru.pFirstSynced; /* If we could not find a page that does not require an fsync() ** on the journal file then fsync the journal file. This is a ** very slow operation, so we work hard to avoid it. But sometimes ** it can't be helped. */ - if( pPg==0 && pPager->pFirst && syncOk && !MEMDB){ + if( pPg==0 && pPager->lru.pFirst){ + int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); int rc = syncJournal(pPager); if( rc!=0 ){ return rc; } - if( pPager->fullSync ){ + if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){ /* If in full-sync mode, write a new journal header into the ** journal file. This is done to avoid ever modifying a journal ** header that is involved in the rollback of pages that have @@ -2645,10 +3070,7 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){ return rc; } } - pPg = pPager->pFirst; - } - if( pPg==0 ){ - return SQLITE_OK; + pPg = pPager->lru.pFirst; } assert( pPg->nRef==0 ); @@ -2662,6 +3084,7 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){ pPg->dirty = 1; pPg->pDirty = 0; rc = pager_write_pagelist( pPg ); + pPg->dirty = 0; if( rc!=SQLITE_OK ){ return rc; } @@ -2690,105 +3113,136 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){ return SQLITE_OK; } +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* ** This function is called to free superfluous dynamically allocated memory ** held by the pager system. Memory in use by any SQLite pager allocated -** by the current thread may be sqliteFree()ed. +** by the current thread may be sqlite3_free()ed. ** ** nReq is the number of bytes of memory required. Once this much has -** been released, the function returns. A negative value for nReq means -** free as much memory as possible. The return value is the total number +** been released, the function returns. The return value is the total number ** of bytes of memory released. */ -#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) int sqlite3PagerReleaseMemory(int nReq){ - const ThreadData *pTsdro = sqlite3ThreadDataReadOnly(); - int nReleased = 0; - int i; + int nReleased = 0; /* Bytes of memory released so far */ + sqlite3_mutex *mutex; /* The MEM2 mutex */ + Pager *pPager; /* For looping over pagers */ + int rc = SQLITE_OK; - /* If the the global mutex is held, this subroutine becomes a - ** o-op; zero bytes of memory are freed. This is because - ** some of the code invoked by this function may also - ** try to obtain the mutex, resulting in a deadlock. + /* Acquire the memory-management mutex */ - if( sqlite3OsInMutex(0) ){ - return 0; + mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); + sqlite3_mutex_enter(mutex); + + /* Signal all database connections that memory management wants + ** to have access to the pagers. + */ + for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){ + pPager->iInUseMM = 1; } - /* Outermost loop runs for at most two iterations. First iteration we - ** try to find memory that can be released without calling fsync(). Second - ** iteration (which only runs if the first failed to free nReq bytes of - ** memory) is permitted to call fsync(). This is of course much more - ** expensive. - */ - for(i=0; i<=1; i++){ - - /* Loop through all the SQLite pagers opened by the current thread. */ - Pager *pPager = pTsdro->pPager; - for( ; pPager && (nReq<0 || nReleasedpNext){ - PgHdr *pPg; - int rc; - - if( MEMDB ){ - continue; + while( rc==SQLITE_OK && (nReq<0 || nReleasedneedSync || pPg->pPager->iInUseDB) ){ + pPg = pPg->gfree.pNext; + } + if( !pPg ){ + pPg = sqlite3LruPageList.pFirst; + while( pPg && pPg->pPager->iInUseDB ){ + pPg = pPg->gfree.pNext; } + } + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); - /* For each pager, try to free as many pages as possible (without - ** calling fsync() if this is the first iteration of the outermost - ** loop). + /* If pPg==0, then the block above has failed to find a page to + ** recycle. In this case return early - no further memory will + ** be released. + */ + if( !pPg ) break; + + pPager = pPg->pPager; + assert(!pPg->needSync || pPg==pPager->lru.pFirst); + assert(pPg->needSync || pPg==pPager->lru.pFirstSynced); + + rc = pager_recycle(pPager, &pRecycled); + assert(pRecycled==pPg || rc!=SQLITE_OK); + if( rc==SQLITE_OK ){ + /* We've found a page to free. At this point the page has been + ** removed from the page hash-table, free-list and synced-list + ** (pFirstSynced). It is still in the all pages (pAll) list. + ** Remove it from this list before freeing. + ** + ** Todo: Check the Pager.pStmt list to make sure this is Ok. It + ** probably is though. */ - while( SQLITE_OK==(rc = pager_recycle(pPager, i, &pPg)) && pPg) { - /* We've found a page to free. At this point the page has been - ** removed from the page hash-table, free-list and synced-list - ** (pFirstSynced). It is still in the all pages (pAll) list. - ** Remove it from this list before freeing. - ** - ** Todo: Check the Pager.pStmt list to make sure this is Ok. It - ** probably is though. - */ - PgHdr *pTmp; - assert( pPg ); - if( pPg==pPager->pAll ){ - pPager->pAll = pPg->pNextAll; - }else{ - for( pTmp=pPager->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){} - pTmp->pNextAll = pPg->pNextAll; - } - nReleased += sqliteAllocSize(pPg); - IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); - PAGER_INCR(sqlite3_pager_pgfree_count); - sqliteFree(pPg); - } - - if( rc!=SQLITE_OK ){ - /* An error occured whilst writing to the database file or - ** journal in pager_recycle(). The error is not returned to the - ** caller of this function. Instead, set the Pager.errCode variable. - ** The error will be returned to the user (or users, in the case - ** of a shared pager cache) of the pager for which the error occured. - */ - assert( (rc&0xff)==SQLITE_IOERR || rc==SQLITE_FULL ); - assert( pPager->state>=PAGER_RESERVED ); - pager_error(pPager, rc); + PgHdr *pTmp; + assert( pPg ); + if( pPg==pPager->pAll ){ + pPager->pAll = pPg->pNextAll; + }else{ + for( pTmp=pPager->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){} + pTmp->pNextAll = pPg->pNextAll; } + nReleased += ( + sizeof(*pPg) + pPager->pageSize + + sizeof(u32) + pPager->nExtra + + MEMDB*sizeof(PgHistory) + ); + IOTRACE(("PGFREE %p %d *\n", pPager, pPg->pgno)); + PAGER_INCR(sqlite3_pager_pgfree_count); + sqlite3_free(pPg->pData); + sqlite3_free(pPg); + pPager->nPage--; + }else{ + /* An error occured whilst writing to the database file or + ** journal in pager_recycle(). The error is not returned to the + ** caller of this function. Instead, set the Pager.errCode variable. + ** The error will be returned to the user (or users, in the case + ** of a shared pager cache) of the pager for which the error occured. + */ + assert( + (rc&0xff)==SQLITE_IOERR || + rc==SQLITE_FULL || + rc==SQLITE_BUSY + ); + assert( pPager->state>=PAGER_RESERVED ); + pager_error(pPager, rc); } } + /* Clear the memory management flags and release the mutex + */ + for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){ + pPager->iInUseMM = 0; + } + sqlite3_mutex_leave(mutex); + + /* Return the number of bytes released + */ return nReleased; } -#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT && !SQLITE_OMIT_DISKIO */ +#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ /* ** Read the content of page pPg out of the database file. */ static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){ int rc; + i64 offset; assert( MEMDB==0 ); - rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize); - if( rc==SQLITE_OK ){ - rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg), - pPager->pageSize); + assert(pPager->fd->pMethods||pPager->tempFile); + if( !pPager->fd->pMethods ){ + return SQLITE_IOERR_SHORT_READ; } + offset = (pgno-1)*(i64)pPager->pageSize; + rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize, offset); PAGER_INCR(sqlite3_pager_readdb_count); PAGER_INCR(pPager->nRead); IOTRACE(("PGIN %p %d\n", pPager, pgno)); @@ -2814,8 +3268,31 @@ static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){ */ static int pagerSharedLock(Pager *pPager){ int rc = SQLITE_OK; + int isHot = 0; - if( pPager->state==PAGER_UNLOCK ){ + /* If this database is opened for exclusive access, has no outstanding + ** page references and is in an error-state, now is the chance to clear + ** the error. Discard the contents of the pager-cache and treat any + ** open journal file as a hot-journal. + */ + if( !MEMDB && pPager->exclusiveMode && pPager->nRef==0 && pPager->errCode ){ + if( pPager->journalOpen ){ + isHot = 1; + } + pager_reset(pPager); + pPager->errCode = SQLITE_OK; + } + + /* If the pager is still in an error state, do not proceed. The error + ** state will be cleared at some point in the future when all page + ** references are dropped and the cache can be discarded. + */ + if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ + return pPager->errCode; + } + + if( pPager->state==PAGER_UNLOCK || isHot ){ + sqlite3_vfs *pVfs = pPager->pVfs; if( !MEMDB ){ assert( pPager->nRef==0 ); if( !pPager->noReadlock ){ @@ -2829,7 +3306,7 @@ static int pagerSharedLock(Pager *pPager){ /* If a journal file exists, and there is no RESERVED lock on the ** database file, then it either needs to be played back or deleted. */ - if( hasHotJournal(pPager) ){ + if( hasHotJournal(pPager) || isHot ){ /* Get an EXCLUSIVE lock on the database file. At this point it is ** important that a RESERVED lock is not obtained on the way to the ** EXCLUSIVE lock. If it were, another process might open the @@ -2841,12 +3318,14 @@ static int pagerSharedLock(Pager *pPager){ ** second process will get to this point in the code and fail to ** obtain it's own EXCLUSIVE lock on the database file. */ - rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK); - if( rc!=SQLITE_OK ){ - pager_unlock(pPager); - return pager_error(pPager, rc); + if( pPager->statefd, EXCLUSIVE_LOCK); + if( rc!=SQLITE_OK ){ + pager_unlock(pPager); + return pager_error(pPager, rc); + } + pPager->state = PAGER_EXCLUSIVE; } - pPager->state = PAGER_EXCLUSIVE; /* Open the journal for reading only. Return SQLITE_BUSY if ** we are unable to open the journal file. @@ -2856,26 +3335,29 @@ static int pagerSharedLock(Pager *pPager){ ** a write lock, so there is never any chance of two or more ** processes opening the journal at the same time. ** - ** Open the journal for read/write access. This is because in - ** exclusive-access mode the file descriptor will be kept open and + ** Open the journal for read/write access. This is because in + ** exclusive-access mode the file descriptor will be kept open and ** possibly used for a transaction later on. On some systems, the ** OsTruncate() call used in exclusive-access mode also requires ** a read/write file handle. */ - rc = SQLITE_BUSY; - if( sqlite3OsFileExists(pPager->zJournal) ){ - int ro; - assert( !pPager->tempFile ); - rc = sqlite3OsOpenReadWrite(pPager->zJournal, &pPager->jfd, &ro); - assert( rc!=SQLITE_OK || pPager->jfd ); - if( ro ){ - rc = SQLITE_BUSY; - sqlite3OsClose(&pPager->jfd); + if( !isHot ){ + rc = SQLITE_BUSY; + if( sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS) ){ + int fout = 0; + int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL; + assert( !pPager->tempFile ); + rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout); + assert( rc!=SQLITE_OK || pPager->jfd->pMethods ); + if( fout&SQLITE_OPEN_READONLY ){ + rc = SQLITE_BUSY; + sqlite3OsClose(pPager->jfd); + } } } if( rc!=SQLITE_OK ){ pager_unlock(pPager); - return SQLITE_BUSY; + return ((rc==SQLITE_NOMEM||rc==SQLITE_IOERR_NOMEM)?rc:SQLITE_BUSY); } pPager->journalOpen = 1; pPager->journalStarted = 0; @@ -2921,11 +3403,7 @@ static int pagerSharedLock(Pager *pPager){ if( pPager->dbSize>0 ){ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); - rc = sqlite3OsSeek(pPager->fd, 24); - if( rc!=SQLITE_OK ){ - return rc; - } - rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers)); + rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); if( rc!=SQLITE_OK ){ return rc; } @@ -2982,13 +3460,14 @@ static int pagerSharedLock(Pager *pPager){ static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ int rc = SQLITE_OK; PgHdr *pPg; + void *pData; /* Create a new PgHdr if any of the four conditions defined - ** above is met: */ + ** above are met: */ if( pPager->nPagemxPage - || pPager->pFirst==0 + || pPager->lru.pFirst==0 || MEMDB - || (pPager->pFirstSynced==0 && pPager->doNotSync) + || (pPager->lru.pFirstSynced==0 && pPager->doNotSync) ){ if( pPager->nPage>=pPager->nHash ){ pager_resize_hash_table(pPager, @@ -2998,9 +3477,17 @@ static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ goto pager_allocate_out; } } - pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize - + sizeof(u32) + pPager->nExtra + pagerLeave(pPager); + pPg = sqlite3_malloc( sizeof(*pPg) + sizeof(u32) + pPager->nExtra + MEMDB*sizeof(PgHistory) ); + if( pPg ){ + pData = sqlite3_malloc( pPager->pageSize ); + if( pData==0 ){ + sqlite3_free(pPg); + pPg = 0; + } + } + pagerEnter(pPager); if( pPg==0 ){ rc = SQLITE_NOMEM; goto pager_allocate_out; @@ -3009,13 +3496,14 @@ static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ if( MEMDB ){ memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory)); } + pPg->pData = pData; pPg->pPager = pPager; pPg->pNextAll = pPager->pAll; pPager->pAll = pPg; pPager->nPage++; }else{ /* Recycle an existing page with a zero ref-count. */ - rc = pager_recycle(pPager, 1, &pPg); + rc = pager_recycle(pPager, &pPg); if( rc==SQLITE_BUSY ){ rc = SQLITE_IOERR_BLOCKED; } @@ -3082,7 +3570,7 @@ static int pager_get_content(PgHdr *pPg){ ** called again with noContent==0, that means that the content is needed ** and the disk read should occur at that point. */ -int sqlite3PagerAcquire( +static int pagerAcquire( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ @@ -3104,9 +3592,6 @@ int sqlite3PagerAcquire( */ assert( pPager!=0 ); *ppPage = 0; - if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ - return pPager->errCode; - } /* If this is the first page accessed, then get a SHARED lock ** on the database file. pagerSharedLock() is a no-op if @@ -3132,7 +3617,9 @@ int sqlite3PagerAcquire( pPg->pgno = pgno; assert( !MEMDB || pgno>pPager->stmtSize ); if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ +#if 0 sqlite3CheckMemory(pPager->aInJournal, pgno/8); +#endif assert( pPager->journalOpen ); pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0; pPg->needSync = 0; @@ -3151,8 +3638,8 @@ int sqlite3PagerAcquire( } nMax = sqlite3PagerPagecount(pPager); if( pPager->errCode ){ - sqlite3PagerUnref(pPg); rc = pPager->errCode; + sqlite3PagerUnref(pPg); return rc; } @@ -3205,6 +3692,19 @@ int sqlite3PagerAcquire( *ppPage = pPg; return SQLITE_OK; } +int sqlite3PagerAcquire( + Pager *pPager, /* The pager open on the database file */ + Pgno pgno, /* Page number to fetch */ + DbPage **ppPage, /* Write a pointer to the page here */ + int noContent /* Do not bother reading content from disk if true */ +){ + int rc; + pagerEnter(pPager); + rc = pagerAcquire(pPager, pgno, ppPage, noContent); + pagerLeave(pPager); + return rc; +} + /* ** Acquire a page if it is already in the in-memory cache. Do @@ -3218,21 +3718,20 @@ int sqlite3PagerAcquire( ** has ever happened. */ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ - PgHdr *pPg; + PgHdr *pPg = 0; assert( pPager!=0 ); assert( pgno!=0 ); + pagerEnter(pPager); if( pPager->state==PAGER_UNLOCK ){ assert( !pPager->pAll || pPager->exclusiveMode ); - return 0; + }else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ + /* Do nothing */ + }else if( (pPg = pager_lookup(pPager, pgno))!=0 ){ + page_ref(pPg); } - if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ - return 0; - } - pPg = pager_lookup(pPager, pgno); - if( pPg==0 ) return 0; - page_ref(pPg); + pagerLeave(pPager); return pPg; } @@ -3245,10 +3744,12 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ ** removed. */ int sqlite3PagerUnref(DbPage *pPg){ + Pager *pPager = pPg->pPager; /* Decrement the reference count for this page */ assert( pPg->nRef>0 ); + pagerEnter(pPg->pPager); pPg->nRef--; REFINFO(pPg); @@ -3258,19 +3759,8 @@ int sqlite3PagerUnref(DbPage *pPg){ ** destructor and add the page to the freelist. */ if( pPg->nRef==0 ){ - Pager *pPager; - pPager = pPg->pPager; - pPg->pNextFree = 0; - pPg->pPrevFree = pPager->pLast; - pPager->pLast = pPg; - if( pPg->pPrevFree ){ - pPg->pPrevFree->pNextFree = pPg; - }else{ - pPager->pFirst = pPg; - } - if( pPg->needSync==0 && pPager->pFirstSynced==0 ){ - pPager->pFirstSynced = pPg; - } + + lruListAdd(pPg); if( pPager->xDestructor ){ pPager->xDestructor(pPg, pPager->pageSize); } @@ -3284,6 +3774,7 @@ int sqlite3PagerUnref(DbPage *pPg){ pagerUnlockAndRollback(pPager); } } + pagerLeave(pPager); return SQLITE_OK; } @@ -3295,6 +3786,9 @@ int sqlite3PagerUnref(DbPage *pPg){ ** write lock if anything goes wrong. */ static int pager_open_journal(Pager *pPager){ + sqlite3_vfs *pVfs = pPager->pVfs; + int flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE); + int rc; assert( !MEMDB ); assert( pPager->state>=PAGER_RESERVED ); @@ -3302,26 +3796,36 @@ static int pager_open_journal(Pager *pPager){ assert( pPager->useJournal ); assert( pPager->aInJournal==0 ); sqlite3PagerPagecount(pPager); - pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); + pagerLeave(pPager); + pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 ); + pagerEnter(pPager); if( pPager->aInJournal==0 ){ rc = SQLITE_NOMEM; goto failed_to_open_journal; } - rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd, - pPager->tempFile); - assert( rc!=SQLITE_OK || pPager->jfd ); + + if( pPager->tempFile ){ + flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL); + }else{ + flags |= (SQLITE_OPEN_MAIN_JOURNAL); + } +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + rc = sqlite3JournalOpen( + pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager) + ); +#else + rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); +#endif + assert( rc!=SQLITE_OK || pPager->jfd->pMethods ); pPager->journalOff = 0; pPager->setMaster = 0; pPager->journalHdr = 0; if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ){ - sqlite3OsDelete(pPager->zJournal); + sqlite3OsDelete(pVfs, pPager->zJournal, 0); } goto failed_to_open_journal; } - sqlite3OsSetFullSync(pPager->jfd, pPager->full_fsync); - sqlite3OsSetFullSync(pPager->fd, pPager->full_fsync); - sqlite3OsOpenDirectory(pPager->jfd, pPager->zDirectory); pPager->journalOpen = 1; pPager->journalStarted = 0; pPager->needSync = 0; @@ -3338,7 +3842,7 @@ static int pager_open_journal(Pager *pPager){ if( pPager->stmtAutoopen && rc==SQLITE_OK ){ rc = sqlite3PagerStmtBegin(pPager); } - if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ + if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && rc!=SQLITE_IOERR_NOMEM ){ rc = pager_end_transaction(pPager); if( rc==SQLITE_OK ){ rc = SQLITE_FULL; @@ -3347,7 +3851,7 @@ static int pager_open_journal(Pager *pPager){ return rc; failed_to_open_journal: - sqliteFree(pPager->aInJournal); + sqlite3_free(pPager->aInJournal); pPager->aInJournal = 0; return rc; } @@ -3382,6 +3886,7 @@ failed_to_open_journal: int sqlite3PagerBegin(DbPage *pPg, int exFlag){ Pager *pPager = pPg->pPager; int rc = SQLITE_OK; + pagerEnter(pPager); assert( pPg->nRef>0 ); assert( pPager->state!=PAGER_UNLOCK ); if( pPager->state==PAGER_SHARED ){ @@ -3398,6 +3903,7 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){ } } if( rc!=SQLITE_OK ){ + pagerLeave(pPager); return rc; } pPager->dirtyCache = 0; @@ -3416,7 +3922,9 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){ assert( pPager->origDbSize==0 ); assert( pPager->aInJournal==0 ); sqlite3PagerPagecount(pPager); - pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); + pagerLeave(pPager); + pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 ); + pagerEnter(pPager); if( !pPager->aInJournal ){ rc = SQLITE_NOMEM; }else{ @@ -3425,6 +3933,7 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){ } } assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK ); + pagerLeave(pPager); return rc; } @@ -3453,11 +3962,14 @@ static void makeClean(PgHdr *pPg){ if( pPg->dirty ){ pPg->dirty = 0; if( pPg->pDirty ){ + assert( pPg->pDirty->pPrevDirty==pPg ); pPg->pDirty->pPrevDirty = pPg->pPrevDirty; } if( pPg->pPrevDirty ){ + assert( pPg->pPrevDirty->pDirty==pPg ); pPg->pPrevDirty->pDirty = pPg->pDirty; }else{ + assert( pPg->pPager->pDirty==pPg ); pPg->pPager->pDirty = pPg->pDirty; } } @@ -3546,40 +4058,41 @@ static int pager_write(PgHdr *pPg){ */ if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){ if( (int)pPg->pgno <= pPager->origDbSize ){ - int szPg; if( MEMDB ){ PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); PAGERTRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); assert( pHist->pOrig==0 ); - pHist->pOrig = sqliteMallocRaw( pPager->pageSize ); + pHist->pOrig = sqlite3_malloc( pPager->pageSize ); if( pHist->pOrig ){ memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize); } }else{ - u32 cksum, saved; - char *pData2, *pEnd; + u32 cksum; + char *pData2; + /* We should never write to the journal file the page that ** contains the database locks. The following assert verifies ** that we do not. */ assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); pData2 = CODEC2(pPager, pData, pPg->pgno, 7); cksum = pager_cksum(pPager, (u8*)pData2); - pEnd = pData2 + pPager->pageSize; - pData2 -= 4; - saved = *(u32*)pEnd; - put32bits(pEnd, cksum); - szPg = pPager->pageSize+8; - put32bits(pData2, pPg->pgno); - rc = sqlite3OsWrite(pPager->jfd, pData2, szPg); - IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, - pPager->journalOff, szPg)); + rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, + pPager->journalOff + 4); + pPager->journalOff += pPager->pageSize+4; + } + if( rc==SQLITE_OK ){ + rc = write32bits(pPager->jfd, pPager->journalOff, cksum); + pPager->journalOff += 4; + } + IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, + pPager->journalOff, pPager->pageSize)); PAGER_INCR(sqlite3_pager_writej_count); - pPager->journalOff += szPg; PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)\n", PAGERID(pPager), pPg->pgno, pPg->needSync, pager_pagehash(pPg)); - *(u32*)pEnd = saved; - /* An error has occured writing to the journal file. The + /* An error has occured writing to the journal file. The ** transaction will be rolled back by the layer above. */ if( rc!=SQLITE_OK ){ @@ -3618,16 +4131,19 @@ static int pager_write(PgHdr *pPg){ if( MEMDB ){ PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); assert( pHist->pStmt==0 ); - pHist->pStmt = sqliteMallocRaw( pPager->pageSize ); + pHist->pStmt = sqlite3_malloc( pPager->pageSize ); if( pHist->pStmt ){ memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize); } PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); page_add_to_stmt_list(pPg); }else{ - char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7)-4; - put32bits(pData2, pPg->pgno); - rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize+4); + i64 offset = pPager->stmtNRec*(4+pPager->pageSize); + char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7); + rc = write32bits(pPager->stfd, offset, pPg->pgno); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4); + } PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); if( rc!=SQLITE_OK ){ return rc; @@ -3668,11 +4184,13 @@ int sqlite3PagerWrite(DbPage *pDbPage){ Pager *pPager = pPg->pPager; Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); + pagerEnter(pPager); if( !MEMDB && nPagePerSector>1 ){ Pgno nPageCount; /* Total number of pages in database file */ Pgno pg1; /* First page of the sector pPg is located on. */ int nPage; /* Number of pages starting at pg1 to journal */ int ii; + int needSync = 0; /* Set the doNotSync flag to 1. This is because we cannot allow a journal ** header to be written between the pages journaled by this function. @@ -3700,25 +4218,47 @@ int sqlite3PagerWrite(DbPage *pDbPage){ for(ii=0; iiaInJournal || pg==pPg->pgno || pg>pPager->origDbSize || !(pPager->aInJournal[pg/8]&(1<<(pg&7))) ) { if( pg!=PAGER_MJ_PGNO(pPager) ){ - PgHdr *pPage; rc = sqlite3PagerGet(pPager, pg, &pPage); if( rc==SQLITE_OK ){ rc = pager_write(pPage); + if( pPage->needSync ){ + needSync = 1; + } sqlite3PagerUnref(pPage); } } + }else if( (pPage = pager_lookup(pPager, pg)) ){ + if( pPage->needSync ){ + needSync = 1; + } } } + /* If the PgHdr.needSync flag is set for any of the nPage pages + ** starting at pg1, then it needs to be set for all of them. Because + ** writing to any of these nPage pages may damage the others, the + ** journal file must contain sync()ed copies of all of them + ** before any of them can be written out to the database file. + */ + if( needSync ){ + for(ii=0; iineedSync = 1; + } + assert(pPager->needSync); + } + assert( pPager->doNotSync==1 ); pPager->doNotSync = 0; }else{ rc = pager_write(pDbPage); } + pagerLeave(pPager); return rc; } @@ -3742,6 +4282,7 @@ int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void *pData){ PgHdr *pPg; int rc; + pagerEnter(pPager); rc = sqlite3PagerGet(pPager, pgno, &pPg); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pPg); @@ -3750,6 +4291,7 @@ int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void *pData){ } sqlite3PagerUnref(pPg); } + pagerLeave(pPager); return rc; } #endif @@ -3783,6 +4325,7 @@ void sqlite3PagerDontWrite(DbPage *pDbPage){ Pager *pPager = pPg->pPager; if( MEMDB ) return; + pagerEnter(pPager); pPg->alwaysRollback = 1; if( pPg->dirty && !pPager->stmtInUse ){ assert( pPager->state>=PAGER_SHARED ); @@ -3804,6 +4347,7 @@ void sqlite3PagerDontWrite(DbPage *pDbPage){ #endif } } + pagerLeave(pPager); } /* @@ -3820,6 +4364,7 @@ void sqlite3PagerDontWrite(DbPage *pDbPage){ void sqlite3PagerDontRollback(DbPage *pPg){ Pager *pPager = pPg->pPager; + pagerEnter(pPager); assert( pPager->state>=PAGER_RESERVED ); if( pPager->journalOpen==0 ) return; if( pPg->alwaysRollback || pPager->alwaysRollback || MEMDB ) return; @@ -3842,6 +4387,7 @@ void sqlite3PagerDontRollback(DbPage *pPg){ assert( pPager->aInStmt!=0 ); pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); } + pagerLeave(pPager); } @@ -3849,27 +4395,39 @@ void sqlite3PagerDontRollback(DbPage *pPg){ ** This routine is called to increment the database file change-counter, ** stored at byte 24 of the pager file. */ -static int pager_incr_changecounter(Pager *pPager){ +static int pager_incr_changecounter(Pager *pPager, int isDirect){ PgHdr *pPgHdr; u32 change_counter; - int rc; + int rc = SQLITE_OK; if( !pPager->changeCountDone ){ /* Open page 1 of the file for writing. */ rc = sqlite3PagerGet(pPager, 1, &pPgHdr); if( rc!=SQLITE_OK ) return rc; - rc = sqlite3PagerWrite(pPgHdr); - if( rc!=SQLITE_OK ) return rc; - + + if( !isDirect ){ + rc = sqlite3PagerWrite(pPgHdr); + if( rc!=SQLITE_OK ){ + sqlite3PagerUnref(pPgHdr); + return rc; + } + } + /* Increment the value just read and write it back to byte 24. */ change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers); change_counter++; put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter); + + if( isDirect && pPager->fd->pMethods ){ + const void *zBuf = PGHDR_TO_DATA(pPgHdr); + rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); + } + /* Release the page reference. */ sqlite3PagerUnref(pPgHdr); pPager->changeCountDone = 1; } - return SQLITE_OK; + return rc; } /* @@ -3894,13 +4452,53 @@ int sqlite3PagerCommitPhaseOne(Pager *pPager, const char *zMaster, Pgno nTrunc){ PAGERTRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n", pPager->zFilename, zMaster, nTrunc); + pagerEnter(pPager); /* If this is an in-memory db, or no pages have been written to, or this ** function has already been called, it is a no-op. */ if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){ PgHdr *pPg; - assert( pPager->journalOpen ); + +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + /* The atomic-write optimization can be used if all of the + ** following are true: + ** + ** + The file-system supports the atomic-write property for + ** blocks of size page-size, and + ** + This commit is not part of a multi-file transaction, and + ** + Exactly one page has been modified and store in the journal file. + ** + ** If the optimization can be used, then the journal file will never + ** be created for this transaction. + */ + int useAtomicWrite = ( + !zMaster && + pPager->journalOff==jrnlBufferSize(pPager) && + nTrunc==0 && + (0==pPager->pDirty || 0==pPager->pDirty->pDirty) + ); + if( useAtomicWrite ){ + /* Update the nRec field in the journal file. */ + int offset = pPager->journalHdr + sizeof(aJournalMagic); + assert(pPager->nRec==1); + rc = write32bits(pPager->jfd, offset, pPager->nRec); + + /* Update the db file change counter. The following call will modify + ** the in-memory representation of page 1 to include the updated + ** change counter and then write page 1 directly to the database + ** file. Because of the atomic-write property of the host file-system, + ** this is safe. + */ + if( rc==SQLITE_OK ){ + rc = pager_incr_changecounter(pPager, 1); + } + }else{ + rc = sqlite3JournalCreate(pPager->jfd); + } + + if( !useAtomicWrite && rc==SQLITE_OK ) +#endif /* If a master journal file name has already been written to the ** journal file, then no sync is required. This happens when it is @@ -3909,7 +4507,8 @@ int sqlite3PagerCommitPhaseOne(Pager *pPager, const char *zMaster, Pgno nTrunc){ ** transaction the m-j name will have already been written. */ if( !pPager->setMaster ){ - rc = pager_incr_changecounter(pPager); + assert( pPager->journalOpen ); + rc = pager_incr_changecounter(pPager, 0); if( rc!=SQLITE_OK ) goto sync_exit; #ifndef SQLITE_OMIT_AUTOVACUUM if( nTrunc!=0 ){ @@ -3933,8 +4532,8 @@ int sqlite3PagerCommitPhaseOne(Pager *pPager, const char *zMaster, Pgno nTrunc){ rc = writeMasterJournal(pPager, zMaster); if( rc!=SQLITE_OK ) goto sync_exit; rc = syncJournal(pPager); - if( rc!=SQLITE_OK ) goto sync_exit; } + if( rc!=SQLITE_OK ) goto sync_exit; #ifndef SQLITE_OMIT_AUTOVACUUM if( nTrunc!=0 ){ @@ -3946,12 +4545,16 @@ int sqlite3PagerCommitPhaseOne(Pager *pPager, const char *zMaster, Pgno nTrunc){ /* Write all dirty pages to the database file */ pPg = pager_get_all_dirty_pages(pPager); rc = pager_write_pagelist(pPg); - if( rc!=SQLITE_OK ) goto sync_exit; + if( rc!=SQLITE_OK ){ + while( pPg && !pPg->dirty ){ pPg = pPg->pDirty; } + pPager->pDirty = pPg; + goto sync_exit; + } pPager->pDirty = 0; /* Sync the database file. */ if( !pPager->noSync ){ - rc = sqlite3OsSync(pPager->fd, 0); + rc = sqlite3OsSync(pPager->fd, pPager->sync_flags); } IOTRACE(("DBSYNC %p\n", pPager)) @@ -3969,6 +4572,7 @@ sync_exit: */ rc = SQLITE_BUSY; } + pagerLeave(pPager); return rc; } @@ -3990,6 +4594,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ if( pPager->statejournalOpen || !pPager->dirtyCache ); assert( pPager->state==PAGER_SYNCED || !pPager->dirtyCache ); rc = pager_end_transaction(pPager); - return pager_error(pPager, rc); + rc = pager_error(pPager, rc); + pagerLeave(pPager); + return rc; } /* @@ -4073,8 +4680,10 @@ int sqlite3PagerRollback(Pager *pPager){ return SQLITE_OK; } + pagerEnter(pPager); if( !pPager->dirtyCache || !pPager->journalOpen ){ rc = pager_end_transaction(pPager); + pagerLeave(pPager); return rc; } @@ -4082,6 +4691,7 @@ int sqlite3PagerRollback(Pager *pPager){ if( pPager->state>=PAGER_EXCLUSIVE ){ pager_playback(pPager, 0); } + pagerLeave(pPager); return pPager->errCode; } if( pPager->state==PAGER_RESERVED ){ @@ -4101,7 +4711,9 @@ int sqlite3PagerRollback(Pager *pPager){ ** cache. So call pager_error() on the way out to make any error ** persistent. */ - return pager_error(pPager, rc); + rc = pager_error(pPager, rc); + pagerLeave(pPager); + return rc; } /* @@ -4147,7 +4759,7 @@ int *sqlite3PagerStats(Pager *pPager){ ** open. A new statement journal is created that can be used to rollback ** changes of a single SQL command within a larger transaction. */ -int sqlite3PagerStmtBegin(Pager *pPager){ +static int pagerStmtBegin(Pager *pPager){ int rc; assert( !pPager->stmtInUse ); assert( pPager->state>=PAGER_SHARED ); @@ -4163,7 +4775,10 @@ int sqlite3PagerStmtBegin(Pager *pPager){ return SQLITE_OK; } assert( pPager->journalOpen ); - pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 ); + pagerLeave(pPager); + assert( pPager->aInStmt==0 ); + pPager->aInStmt = sqlite3MallocZero( pPager->dbSize/8 + 1 ); + pagerEnter(pPager); if( pPager->aInStmt==0 ){ /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */ return SQLITE_NOMEM; @@ -4178,8 +4793,11 @@ int sqlite3PagerStmtBegin(Pager *pPager){ pPager->stmtHdrOff = 0; pPager->stmtCksum = pPager->cksumInit; if( !pPager->stmtOpen ){ - rc = sqlite3PagerOpentemp(&pPager->stfd); - if( rc ) goto stmt_begin_failed; + rc = sqlite3PagerOpentemp(pPager->pVfs, pPager->stfd, pPager->zStmtJrnl, + SQLITE_OPEN_SUBJOURNAL); + if( rc ){ + goto stmt_begin_failed; + } pPager->stmtOpen = 1; pPager->stmtNRec = 0; } @@ -4188,23 +4806,30 @@ int sqlite3PagerStmtBegin(Pager *pPager){ stmt_begin_failed: if( pPager->aInStmt ){ - sqliteFree(pPager->aInStmt); + sqlite3_free(pPager->aInStmt); pPager->aInStmt = 0; } return rc; } +int sqlite3PagerStmtBegin(Pager *pPager){ + int rc; + pagerEnter(pPager); + rc = pagerStmtBegin(pPager); + pagerLeave(pPager); + return rc; +} /* ** Commit a statement. */ int sqlite3PagerStmtCommit(Pager *pPager){ + pagerEnter(pPager); if( pPager->stmtInUse ){ PgHdr *pPg, *pNext; PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); if( !MEMDB ){ - sqlite3OsSeek(pPager->stfd, 0); /* sqlite3OsTruncate(pPager->stfd, 0); */ - sqliteFree( pPager->aInStmt ); + sqlite3_free( pPager->aInStmt ); pPager->aInStmt = 0; }else{ for(pPg=pPager->pStmt; pPg; pPg=pNext){ @@ -4213,7 +4838,7 @@ int sqlite3PagerStmtCommit(Pager *pPager){ assert( pHist->inStmt ); pHist->inStmt = 0; pHist->pPrevStmt = pHist->pNextStmt = 0; - sqliteFree(pHist->pStmt); + sqlite3_free(pHist->pStmt); pHist->pStmt = 0; } } @@ -4222,6 +4847,7 @@ int sqlite3PagerStmtCommit(Pager *pPager){ pPager->pStmt = 0; } pPager->stmtAutoopen = 0; + pagerLeave(pPager); return SQLITE_OK; } @@ -4230,6 +4856,7 @@ int sqlite3PagerStmtCommit(Pager *pPager){ */ int sqlite3PagerStmtRollback(Pager *pPager){ int rc; + pagerEnter(pPager); if( pPager->stmtInUse ){ PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager)); if( MEMDB ){ @@ -4239,7 +4866,7 @@ int sqlite3PagerStmtRollback(Pager *pPager){ pHist = PGHDR_TO_HIST(pPg, pPager); if( pHist->pStmt ){ memcpy(PGHDR_TO_DATA(pPg), pHist->pStmt, pPager->pageSize); - sqliteFree(pHist->pStmt); + sqlite3_free(pHist->pStmt); pHist->pStmt = 0; } } @@ -4254,6 +4881,7 @@ int sqlite3PagerStmtRollback(Pager *pPager){ rc = SQLITE_OK; } pPager->stmtAutoopen = 0; + pagerLeave(pPager); return rc; } @@ -4264,6 +4892,22 @@ const char *sqlite3PagerFilename(Pager *pPager){ return pPager->zFilename; } +/* +** Return the VFS structure for the pager. +*/ +const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){ + return pPager->pVfs; +} + +/* +** Return the file handle for the database file associated +** with the pager. This might return NULL if the file has +** not yet been opened. +*/ +sqlite3_file *sqlite3PagerFile(Pager *pPager){ + return pPager->fd; +} + /* ** Return the directory of the database file. */ @@ -4323,6 +4967,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){ int h; Pgno needSyncPgno = 0; + pagerEnter(pPager); assert( pPg->nRef>0 ); PAGERTRACE5("MOVE %d page %d (needSync=%d) moves to %d\n", @@ -4399,6 +5044,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){ sqlite3PagerUnref(pPgHdr); } + pagerLeave(pPager); return SQLITE_OK; } #endif @@ -4441,17 +5087,6 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){ return (int)pPager->exclusiveMode; } -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) -/* -** Return the current state of the file lock for the given pager. -** The return value is one of NO_LOCK, SHARED_LOCK, RESERVED_LOCK, -** PENDING_LOCK, or EXCLUSIVE_LOCK. -*/ -int sqlite3PagerLockstate(Pager *pPager){ - return sqlite3OsLockState(pPager->fd); -} -#endif - #ifdef SQLITE_DEBUG /* ** Print a listing of all referenced pages and their ref count. diff --git a/extensions/sqlite/sqlite-source/pager.h b/extensions/sqlite/sqlite-source/pager.h index f3c82c29..731efdeb 100644 --- a/extensions/sqlite/sqlite-source/pager.h +++ b/extensions/sqlite/sqlite-source/pager.h @@ -54,12 +54,11 @@ typedef struct PgHdr DbPage; ** See source code comments for a detailed description of the following ** routines: */ -int sqlite3PagerOpen(Pager **ppPager, const char *zFilename, - int nExtra, int flags); +int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, int,int,int); void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler); void sqlite3PagerSetDestructor(Pager*, void(*)(DbPage*,int)); void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*,int)); -int sqlite3PagerSetPagesize(Pager*, int); +int sqlite3PagerSetPagesize(Pager*, u16*); int sqlite3PagerMaxPageCount(Pager*, int); int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); void sqlite3PagerSetCachesize(Pager*, int); @@ -86,6 +85,8 @@ void sqlite3PagerDontWrite(DbPage*); int sqlite3PagerRefcount(Pager*); void sqlite3PagerSetSafetyLevel(Pager*,int,int); const char *sqlite3PagerFilename(Pager*); +const sqlite3_vfs *sqlite3PagerVfs(Pager*); +sqlite3_file *sqlite3PagerFile(Pager*); const char *sqlite3PagerDirname(Pager*); const char *sqlite3PagerJournalname(Pager*); int sqlite3PagerNosync(Pager*); @@ -107,10 +108,6 @@ int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerIswriteable(DbPage*); #endif -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - int sqlite3PagerLockstate(Pager*); -#endif - #ifdef SQLITE_TEST int *sqlite3PagerStats(Pager*); void sqlite3PagerRefdump(Pager*); diff --git a/extensions/sqlite/sqlite-source/parse.c b/extensions/sqlite/sqlite-source/parse.c index 508d5bd5..4fb4866a 100644 --- a/extensions/sqlite/sqlite-source/parse.c +++ b/extensions/sqlite/sqlite-source/parse.c @@ -7,7 +7,6 @@ #line 56 "parse.y" #include "sqliteInt.h" -#include "parse.h" /* ** An instance of this structure holds information about the @@ -43,7 +42,7 @@ struct TrigEvent { int a; IdList * b; }; */ struct AttachKey { int type; Token key; }; -#line 48 "parse.c" +#line 47 "parse.c" /* Next is all token values, in a form suitable for use by makeheaders. ** This section will be null unless lemon is run with the -m switch. */ @@ -1267,9 +1266,9 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ case 155: case 189: case 206: -#line 374 "parse.y" +#line 373 "parse.y" {sqlite3SelectDelete((yypminor->yy219));} -#line 1274 "parse.c" +#line 1273 "parse.c" break; case 169: case 170: @@ -1281,9 +1280,9 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ case 221: case 223: case 235: -#line 627 "parse.y" +#line 633 "parse.y" {sqlite3ExprDelete((yypminor->yy172));} -#line 1288 "parse.c" +#line 1287 "parse.c" break; case 174: case 182: @@ -1297,40 +1296,40 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ case 215: case 216: case 222: -#line 876 "parse.y" +#line 887 "parse.y" {sqlite3ExprListDelete((yypminor->yy174));} -#line 1304 "parse.c" +#line 1303 "parse.c" break; case 188: case 193: case 201: case 202: -#line 489 "parse.y" +#line 490 "parse.y" {sqlite3SrcListDelete((yypminor->yy373));} -#line 1312 "parse.c" +#line 1311 "parse.c" break; case 205: case 208: case 214: -#line 506 "parse.y" +#line 507 "parse.y" {sqlite3IdListDelete((yypminor->yy432));} -#line 1319 "parse.c" +#line 1318 "parse.c" break; case 231: case 236: -#line 979 "parse.y" +#line 990 "parse.y" {sqlite3DeleteTriggerStep((yypminor->yy243));} -#line 1325 "parse.c" +#line 1324 "parse.c" break; case 233: -#line 965 "parse.y" +#line 976 "parse.y" {sqlite3IdListDelete((yypminor->yy370).b);} -#line 1330 "parse.c" +#line 1329 "parse.c" break; case 238: -#line 1052 "parse.y" +#line 1063 "parse.y" {sqlite3ExprDelete((yypminor->yy386));} -#line 1335 "parse.c" +#line 1334 "parse.c" break; default: break; /* If no destructor action specified: do nothing */ } @@ -1493,7 +1492,7 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ sqlite3ErrorMsg(pParse, "parser stack overflow"); pParse->parseError = 1; -#line 1499 "parse.c" +#line 1498 "parse.c" sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ } @@ -1944,67 +1943,67 @@ static void yy_reduce( case 303: case 305: case 309: -#line 97 "parse.y" +#line 96 "parse.y" { } -#line 1953 "parse.c" +#line 1952 "parse.c" break; case 3: -#line 100 "parse.y" +#line 99 "parse.y" { sqlite3FinishCoding(pParse); } -#line 1958 "parse.c" +#line 1957 "parse.c" break; case 6: -#line 103 "parse.y" +#line 102 "parse.y" { sqlite3BeginParse(pParse, 0); } -#line 1963 "parse.c" +#line 1962 "parse.c" break; case 7: -#line 105 "parse.y" +#line 104 "parse.y" { sqlite3BeginParse(pParse, 1); } -#line 1968 "parse.c" +#line 1967 "parse.c" break; case 8: -#line 106 "parse.y" +#line 105 "parse.y" { sqlite3BeginParse(pParse, 2); } -#line 1973 "parse.c" +#line 1972 "parse.c" break; case 9: -#line 112 "parse.y" +#line 111 "parse.y" {sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy46);} -#line 1978 "parse.c" +#line 1977 "parse.c" break; case 13: -#line 117 "parse.y" +#line 116 "parse.y" {yygotominor.yy46 = TK_DEFERRED;} -#line 1983 "parse.c" +#line 1982 "parse.c" break; case 14: case 15: case 16: case 107: case 109: -#line 118 "parse.y" +#line 117 "parse.y" {yygotominor.yy46 = yymsp[0].major;} -#line 1992 "parse.c" +#line 1991 "parse.c" break; case 17: case 18: -#line 121 "parse.y" +#line 120 "parse.y" {sqlite3CommitTransaction(pParse);} -#line 1998 "parse.c" +#line 1997 "parse.c" break; case 19: -#line 123 "parse.y" +#line 122 "parse.y" {sqlite3RollbackTransaction(pParse);} -#line 2003 "parse.c" +#line 2002 "parse.c" break; case 21: -#line 128 "parse.y" +#line 127 "parse.y" { sqlite3StartTable(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410,yymsp[-4].minor.yy46,0,0,yymsp[-2].minor.yy46); } -#line 2010 "parse.c" +#line 2009 "parse.c" break; case 22: case 25: @@ -2017,9 +2016,9 @@ static void yy_reduce( case 113: case 212: case 215: -#line 132 "parse.y" +#line 131 "parse.y" {yygotominor.yy46 = 0;} -#line 2025 "parse.c" +#line 2024 "parse.c" break; case 23: case 24: @@ -2029,40 +2028,40 @@ static void yy_reduce( case 111: case 213: case 216: -#line 133 "parse.y" +#line 132 "parse.y" {yygotominor.yy46 = 1;} -#line 2037 "parse.c" +#line 2036 "parse.c" break; case 26: -#line 139 "parse.y" +#line 138 "parse.y" { sqlite3EndTable(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy0,0); } -#line 2044 "parse.c" +#line 2043 "parse.c" break; case 27: -#line 142 "parse.y" +#line 141 "parse.y" { sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy219); sqlite3SelectDelete(yymsp[0].minor.yy219); } -#line 2052 "parse.c" +#line 2051 "parse.c" break; case 30: -#line 154 "parse.y" +#line 153 "parse.y" { yygotominor.yy410.z = yymsp[-2].minor.yy410.z; yygotominor.yy410.n = (pParse->sLastToken.z-yymsp[-2].minor.yy410.z) + pParse->sLastToken.n; } -#line 2060 "parse.c" +#line 2059 "parse.c" break; case 31: -#line 158 "parse.y" +#line 157 "parse.y" { sqlite3AddColumn(pParse,&yymsp[0].minor.yy410); yygotominor.yy410 = yymsp[0].minor.yy410; } -#line 2068 "parse.c" +#line 2067 "parse.c" break; case 32: case 33: @@ -2070,14 +2069,14 @@ static void yy_reduce( case 35: case 36: case 255: -#line 168 "parse.y" +#line 167 "parse.y" {yygotominor.yy410 = yymsp[0].minor.yy0;} -#line 2078 "parse.c" +#line 2077 "parse.c" break; case 38: -#line 229 "parse.y" +#line 228 "parse.y" {sqlite3AddColumnType(pParse,&yymsp[0].minor.yy410);} -#line 2083 "parse.c" +#line 2082 "parse.c" break; case 39: case 42: @@ -2090,142 +2089,142 @@ static void yy_reduce( case 252: case 253: case 254: -#line 230 "parse.y" +#line 229 "parse.y" {yygotominor.yy410 = yymsp[0].minor.yy410;} -#line 2098 "parse.c" +#line 2097 "parse.c" break; case 40: -#line 231 "parse.y" +#line 230 "parse.y" { yygotominor.yy410.z = yymsp[-3].minor.yy410.z; yygotominor.yy410.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy410.z; } -#line 2106 "parse.c" +#line 2105 "parse.c" break; case 41: -#line 235 "parse.y" +#line 234 "parse.y" { yygotominor.yy410.z = yymsp[-5].minor.yy410.z; yygotominor.yy410.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy410.z; } -#line 2114 "parse.c" +#line 2113 "parse.c" break; case 43: -#line 241 "parse.y" +#line 240 "parse.y" {yygotominor.yy410.z=yymsp[-1].minor.yy410.z; yygotominor.yy410.n=yymsp[0].minor.yy410.n+(yymsp[0].minor.yy410.z-yymsp[-1].minor.yy410.z);} -#line 2119 "parse.c" +#line 2118 "parse.c" break; case 50: case 52: -#line 252 "parse.y" +#line 251 "parse.y" {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy172);} -#line 2125 "parse.c" +#line 2124 "parse.c" break; case 51: -#line 253 "parse.y" +#line 252 "parse.y" {sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy172);} -#line 2130 "parse.c" +#line 2129 "parse.c" break; case 53: -#line 255 "parse.y" +#line 254 "parse.y" { - Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy172, 0, 0); + Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy172, 0, 0); sqlite3AddDefaultValue(pParse,p); } -#line 2138 "parse.c" +#line 2137 "parse.c" break; case 54: -#line 259 "parse.y" +#line 258 "parse.y" { - Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy410); + Expr *p = sqlite3PExpr(pParse, TK_STRING, 0, 0, &yymsp[0].minor.yy410); sqlite3AddDefaultValue(pParse,p); } -#line 2146 "parse.c" +#line 2145 "parse.c" break; case 56: -#line 268 "parse.y" +#line 267 "parse.y" {sqlite3AddNotNull(pParse, yymsp[0].minor.yy46);} -#line 2151 "parse.c" +#line 2150 "parse.c" break; case 57: -#line 270 "parse.y" +#line 269 "parse.y" {sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy46,yymsp[0].minor.yy46,yymsp[-2].minor.yy46);} -#line 2156 "parse.c" +#line 2155 "parse.c" break; case 58: -#line 271 "parse.y" +#line 270 "parse.y" {sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy46,0,0,0,0);} -#line 2161 "parse.c" +#line 2160 "parse.c" break; case 59: -#line 272 "parse.y" +#line 271 "parse.y" {sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy172);} -#line 2166 "parse.c" +#line 2165 "parse.c" break; case 60: -#line 274 "parse.y" +#line 273 "parse.y" {sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy410,yymsp[-1].minor.yy174,yymsp[0].minor.yy46);} -#line 2171 "parse.c" +#line 2170 "parse.c" break; case 61: -#line 275 "parse.y" +#line 274 "parse.y" {sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy46);} -#line 2176 "parse.c" +#line 2175 "parse.c" break; case 62: -#line 276 "parse.y" +#line 275 "parse.y" {sqlite3AddCollateType(pParse, (char*)yymsp[0].minor.yy410.z, yymsp[0].minor.yy410.n);} -#line 2181 "parse.c" +#line 2180 "parse.c" break; case 65: -#line 289 "parse.y" +#line 288 "parse.y" { yygotominor.yy46 = OE_Restrict * 0x010101; } -#line 2186 "parse.c" +#line 2185 "parse.c" break; case 66: -#line 290 "parse.y" +#line 289 "parse.y" { yygotominor.yy46 = (yymsp[-1].minor.yy46 & yymsp[0].minor.yy405.mask) | yymsp[0].minor.yy405.value; } -#line 2191 "parse.c" +#line 2190 "parse.c" break; case 67: -#line 292 "parse.y" +#line 291 "parse.y" { yygotominor.yy405.value = 0; yygotominor.yy405.mask = 0x000000; } -#line 2196 "parse.c" +#line 2195 "parse.c" break; case 68: -#line 293 "parse.y" +#line 292 "parse.y" { yygotominor.yy405.value = yymsp[0].minor.yy46; yygotominor.yy405.mask = 0x0000ff; } -#line 2201 "parse.c" +#line 2200 "parse.c" break; case 69: -#line 294 "parse.y" +#line 293 "parse.y" { yygotominor.yy405.value = yymsp[0].minor.yy46<<8; yygotominor.yy405.mask = 0x00ff00; } -#line 2206 "parse.c" +#line 2205 "parse.c" break; case 70: -#line 295 "parse.y" +#line 294 "parse.y" { yygotominor.yy405.value = yymsp[0].minor.yy46<<16; yygotominor.yy405.mask = 0xff0000; } -#line 2211 "parse.c" +#line 2210 "parse.c" break; case 71: -#line 297 "parse.y" +#line 296 "parse.y" { yygotominor.yy46 = OE_SetNull; } -#line 2216 "parse.c" +#line 2215 "parse.c" break; case 72: -#line 298 "parse.y" +#line 297 "parse.y" { yygotominor.yy46 = OE_SetDflt; } -#line 2221 "parse.c" +#line 2220 "parse.c" break; case 73: -#line 299 "parse.y" +#line 298 "parse.y" { yygotominor.yy46 = OE_Cascade; } -#line 2226 "parse.c" +#line 2225 "parse.c" break; case 74: -#line 300 "parse.y" +#line 299 "parse.y" { yygotominor.yy46 = OE_Restrict; } -#line 2231 "parse.c" +#line 2230 "parse.c" break; case 75: case 76: @@ -2234,97 +2233,97 @@ static void yy_reduce( case 95: case 96: case 166: -#line 302 "parse.y" +#line 301 "parse.y" {yygotominor.yy46 = yymsp[0].minor.yy46;} -#line 2242 "parse.c" +#line 2241 "parse.c" break; case 80: -#line 312 "parse.y" +#line 311 "parse.y" {yygotominor.yy410.n = 0; yygotominor.yy410.z = 0;} -#line 2247 "parse.c" +#line 2246 "parse.c" break; case 81: -#line 313 "parse.y" +#line 312 "parse.y" {yygotominor.yy410 = yymsp[-1].minor.yy0;} -#line 2252 "parse.c" +#line 2251 "parse.c" break; case 86: -#line 319 "parse.y" +#line 318 "parse.y" {sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy174,yymsp[0].minor.yy46,yymsp[-2].minor.yy46,0);} -#line 2257 "parse.c" +#line 2256 "parse.c" break; case 87: -#line 321 "parse.y" +#line 320 "parse.y" {sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy174,yymsp[0].minor.yy46,0,0,0,0);} -#line 2262 "parse.c" +#line 2261 "parse.c" break; case 88: -#line 322 "parse.y" +#line 321 "parse.y" {sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy172);} -#line 2267 "parse.c" +#line 2266 "parse.c" break; case 89: -#line 324 "parse.y" +#line 323 "parse.y" { sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy174, &yymsp[-3].minor.yy410, yymsp[-2].minor.yy174, yymsp[-1].minor.yy46); sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy46); } -#line 2275 "parse.c" +#line 2274 "parse.c" break; case 92: case 94: -#line 338 "parse.y" +#line 337 "parse.y" {yygotominor.yy46 = OE_Default;} -#line 2281 "parse.c" +#line 2280 "parse.c" break; case 97: -#line 343 "parse.y" +#line 342 "parse.y" {yygotominor.yy46 = OE_Ignore;} -#line 2286 "parse.c" +#line 2285 "parse.c" break; case 98: case 167: -#line 344 "parse.y" +#line 343 "parse.y" {yygotominor.yy46 = OE_Replace;} -#line 2292 "parse.c" +#line 2291 "parse.c" break; case 99: -#line 348 "parse.y" +#line 347 "parse.y" { sqlite3DropTable(pParse, yymsp[0].minor.yy373, 0, yymsp[-1].minor.yy46); } -#line 2299 "parse.c" +#line 2298 "parse.c" break; case 102: -#line 358 "parse.y" +#line 357 "parse.y" { sqlite3CreateView(pParse, &yymsp[-7].minor.yy0, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, yymsp[0].minor.yy219, yymsp[-6].minor.yy46, yymsp[-4].minor.yy46); } -#line 2306 "parse.c" +#line 2305 "parse.c" break; case 103: -#line 361 "parse.y" +#line 360 "parse.y" { sqlite3DropTable(pParse, yymsp[0].minor.yy373, 1, yymsp[-1].minor.yy46); } -#line 2313 "parse.c" +#line 2312 "parse.c" break; case 104: -#line 368 "parse.y" +#line 367 "parse.y" { sqlite3Select(pParse, yymsp[0].minor.yy219, SRT_Callback, 0, 0, 0, 0, 0); sqlite3SelectDelete(yymsp[0].minor.yy219); } -#line 2321 "parse.c" +#line 2320 "parse.c" break; case 105: case 128: -#line 378 "parse.y" +#line 377 "parse.y" {yygotominor.yy219 = yymsp[0].minor.yy219;} -#line 2327 "parse.c" +#line 2326 "parse.c" break; case 106: -#line 380 "parse.y" +#line 379 "parse.y" { if( yymsp[0].minor.yy219 ){ yymsp[0].minor.yy219->op = yymsp[-1].minor.yy46; @@ -2334,140 +2333,142 @@ static void yy_reduce( } yygotominor.yy219 = yymsp[0].minor.yy219; } -#line 2340 "parse.c" +#line 2339 "parse.c" break; case 108: -#line 391 "parse.y" +#line 390 "parse.y" {yygotominor.yy46 = TK_ALL;} -#line 2345 "parse.c" +#line 2344 "parse.c" break; case 110: -#line 395 "parse.y" +#line 394 "parse.y" { - yygotominor.yy219 = sqlite3SelectNew(yymsp[-6].minor.yy174,yymsp[-5].minor.yy373,yymsp[-4].minor.yy172,yymsp[-3].minor.yy174,yymsp[-2].minor.yy172,yymsp[-1].minor.yy174,yymsp[-7].minor.yy46,yymsp[0].minor.yy234.pLimit,yymsp[0].minor.yy234.pOffset); + yygotominor.yy219 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy174,yymsp[-5].minor.yy373,yymsp[-4].minor.yy172,yymsp[-3].minor.yy174,yymsp[-2].minor.yy172,yymsp[-1].minor.yy174,yymsp[-7].minor.yy46,yymsp[0].minor.yy234.pLimit,yymsp[0].minor.yy234.pOffset); } -#line 2352 "parse.c" +#line 2351 "parse.c" break; case 114: case 237: -#line 416 "parse.y" +#line 415 "parse.y" {yygotominor.yy174 = yymsp[-1].minor.yy174;} -#line 2358 "parse.c" +#line 2357 "parse.c" break; case 115: case 141: case 149: case 230: case 236: -#line 417 "parse.y" +#line 416 "parse.y" {yygotominor.yy174 = 0;} -#line 2367 "parse.c" +#line 2366 "parse.c" break; case 116: -#line 418 "parse.y" +#line 417 "parse.y" { - yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-2].minor.yy174,yymsp[-1].minor.yy172,yymsp[0].minor.yy410.n?&yymsp[0].minor.yy410:0); + yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy174,yymsp[-1].minor.yy172,yymsp[0].minor.yy410.n?&yymsp[0].minor.yy410:0); } -#line 2374 "parse.c" +#line 2373 "parse.c" break; case 117: -#line 421 "parse.y" +#line 420 "parse.y" { - yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-1].minor.yy174, sqlite3Expr(TK_ALL, 0, 0, 0), 0); + Expr *p = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0); + yygotominor.yy174 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy174, p, 0); } #line 2381 "parse.c" break; case 118: #line 424 "parse.y" { - Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0); - Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy410); - yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-3].minor.yy174, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0); + Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0); + Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy410); + Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); + yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy174, pDot, 0); } -#line 2390 "parse.c" +#line 2391 "parse.c" break; case 121: -#line 436 "parse.y" +#line 437 "parse.y" {yygotominor.yy410.n = 0;} -#line 2395 "parse.c" +#line 2396 "parse.c" break; case 122: -#line 448 "parse.y" -{yygotominor.yy373 = sqliteMalloc(sizeof(*yygotominor.yy373));} -#line 2400 "parse.c" +#line 449 "parse.y" +{yygotominor.yy373 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy373));} +#line 2401 "parse.c" break; case 123: -#line 449 "parse.y" +#line 450 "parse.y" { yygotominor.yy373 = yymsp[0].minor.yy373; sqlite3SrcListShiftJoinType(yygotominor.yy373); } -#line 2408 "parse.c" +#line 2409 "parse.c" break; case 124: -#line 457 "parse.y" +#line 458 "parse.y" { yygotominor.yy373 = yymsp[-1].minor.yy373; if( yygotominor.yy373 && yygotominor.yy373->nSrc>0 ) yygotominor.yy373->a[yygotominor.yy373->nSrc-1].jointype = yymsp[0].minor.yy46; } -#line 2416 "parse.c" +#line 2417 "parse.c" break; case 125: -#line 461 "parse.y" +#line 462 "parse.y" {yygotominor.yy373 = 0;} -#line 2421 "parse.c" +#line 2422 "parse.c" break; case 126: -#line 462 "parse.y" +#line 463 "parse.y" { - yygotominor.yy373 = sqlite3SrcListAppendFromTerm(yymsp[-5].minor.yy373,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,0,yymsp[-1].minor.yy172,yymsp[0].minor.yy432); + yygotominor.yy373 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy373,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,0,yymsp[-1].minor.yy172,yymsp[0].minor.yy432); } -#line 2428 "parse.c" +#line 2429 "parse.c" break; case 127: -#line 467 "parse.y" +#line 468 "parse.y" { - yygotominor.yy373 = sqlite3SrcListAppendFromTerm(yymsp[-6].minor.yy373,0,0,&yymsp[-2].minor.yy410,yymsp[-4].minor.yy219,yymsp[-1].minor.yy172,yymsp[0].minor.yy432); + yygotominor.yy373 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy373,0,0,&yymsp[-2].minor.yy410,yymsp[-4].minor.yy219,yymsp[-1].minor.yy172,yymsp[0].minor.yy432); } -#line 2435 "parse.c" +#line 2436 "parse.c" break; case 129: -#line 478 "parse.y" +#line 479 "parse.y" { sqlite3SrcListShiftJoinType(yymsp[0].minor.yy373); - yygotominor.yy219 = sqlite3SelectNew(0,yymsp[0].minor.yy373,0,0,0,0,0,0,0); + yygotominor.yy219 = sqlite3SelectNew(pParse,0,yymsp[0].minor.yy373,0,0,0,0,0,0,0); } -#line 2443 "parse.c" +#line 2444 "parse.c" break; case 130: -#line 485 "parse.y" +#line 486 "parse.y" {yygotominor.yy410.z=0; yygotominor.yy410.n=0;} -#line 2448 "parse.c" +#line 2449 "parse.c" break; case 132: -#line 490 "parse.y" -{yygotominor.yy373 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);} -#line 2453 "parse.c" +#line 491 "parse.y" +{yygotominor.yy373 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);} +#line 2454 "parse.c" break; case 133: -#line 494 "parse.y" +#line 495 "parse.y" { yygotominor.yy46 = JT_INNER; } -#line 2458 "parse.c" +#line 2459 "parse.c" break; case 134: -#line 495 "parse.y" +#line 496 "parse.y" { yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); } -#line 2463 "parse.c" +#line 2464 "parse.c" break; case 135: -#line 496 "parse.y" +#line 497 "parse.y" { yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy410,0); } -#line 2468 "parse.c" +#line 2469 "parse.c" break; case 136: -#line 498 "parse.y" +#line 499 "parse.y" { yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy410,&yymsp[-1].minor.yy410); } -#line 2473 "parse.c" +#line 2474 "parse.c" break; case 137: case 145: @@ -2477,9 +2478,9 @@ static void yy_reduce( case 202: case 225: case 227: -#line 502 "parse.y" +#line 503 "parse.y" {yygotominor.yy172 = yymsp[0].minor.yy172;} -#line 2485 "parse.c" +#line 2486 "parse.c" break; case 138: case 151: @@ -2487,237 +2488,237 @@ static void yy_reduce( case 203: case 226: case 228: -#line 503 "parse.y" +#line 504 "parse.y" {yygotominor.yy172 = 0;} -#line 2495 "parse.c" +#line 2496 "parse.c" break; case 139: case 171: -#line 507 "parse.y" +#line 508 "parse.y" {yygotominor.yy432 = yymsp[-1].minor.yy432;} -#line 2501 "parse.c" +#line 2502 "parse.c" break; case 140: case 170: -#line 508 "parse.y" +#line 509 "parse.y" {yygotominor.yy432 = 0;} -#line 2507 "parse.c" +#line 2508 "parse.c" break; case 142: case 150: case 229: -#line 519 "parse.y" +#line 520 "parse.y" {yygotominor.yy174 = yymsp[0].minor.yy174;} -#line 2514 "parse.c" +#line 2515 "parse.c" break; case 143: -#line 520 "parse.y" +#line 521 "parse.y" { - yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-3].minor.yy174,yymsp[-1].minor.yy172,0); + yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy174,yymsp[-1].minor.yy172,0); if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46; } -#line 2522 "parse.c" +#line 2523 "parse.c" break; case 144: -#line 524 "parse.y" +#line 525 "parse.y" { - yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[-1].minor.yy172,0); + yygotominor.yy174 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy172,0); if( yygotominor.yy174 && yygotominor.yy174->a ) yygotominor.yy174->a[0].sortOrder = yymsp[0].minor.yy46; } -#line 2530 "parse.c" +#line 2531 "parse.c" break; case 146: case 148: -#line 532 "parse.y" +#line 533 "parse.y" {yygotominor.yy46 = SQLITE_SO_ASC;} -#line 2536 "parse.c" +#line 2537 "parse.c" break; case 147: -#line 533 "parse.y" +#line 534 "parse.y" {yygotominor.yy46 = SQLITE_SO_DESC;} -#line 2541 "parse.c" +#line 2542 "parse.c" break; case 153: -#line 559 "parse.y" +#line 560 "parse.y" {yygotominor.yy234.pLimit = 0; yygotominor.yy234.pOffset = 0;} -#line 2546 "parse.c" +#line 2547 "parse.c" break; case 154: -#line 560 "parse.y" +#line 561 "parse.y" {yygotominor.yy234.pLimit = yymsp[0].minor.yy172; yygotominor.yy234.pOffset = 0;} -#line 2551 "parse.c" +#line 2552 "parse.c" break; case 155: -#line 562 "parse.y" +#line 563 "parse.y" {yygotominor.yy234.pLimit = yymsp[-2].minor.yy172; yygotominor.yy234.pOffset = yymsp[0].minor.yy172;} -#line 2556 "parse.c" +#line 2557 "parse.c" break; case 156: -#line 564 "parse.y" +#line 565 "parse.y" {yygotominor.yy234.pOffset = yymsp[-2].minor.yy172; yygotominor.yy234.pLimit = yymsp[0].minor.yy172;} -#line 2561 "parse.c" +#line 2562 "parse.c" break; case 157: -#line 568 "parse.y" +#line 569 "parse.y" {sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy373,yymsp[0].minor.yy172);} -#line 2566 "parse.c" +#line 2567 "parse.c" break; case 160: -#line 578 "parse.y" +#line 579 "parse.y" { sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy174,SQLITE_MAX_COLUMN,"set list"); sqlite3Update(pParse,yymsp[-3].minor.yy373,yymsp[-1].minor.yy174,yymsp[0].minor.yy172,yymsp[-4].minor.yy46); } -#line 2574 "parse.c" +#line 2575 "parse.c" break; case 161: -#line 587 "parse.y" -{yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);} -#line 2579 "parse.c" +#line 588 "parse.y" +{yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy174,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);} +#line 2580 "parse.c" break; case 162: -#line 588 "parse.y" -{yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);} -#line 2584 "parse.c" +#line 590 "parse.y" +{yygotominor.yy174 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);} +#line 2585 "parse.c" break; case 163: -#line 594 "parse.y" +#line 596 "parse.y" {sqlite3Insert(pParse, yymsp[-5].minor.yy373, yymsp[-1].minor.yy174, 0, yymsp[-4].minor.yy432, yymsp[-7].minor.yy46);} -#line 2589 "parse.c" +#line 2590 "parse.c" break; case 164: -#line 596 "parse.y" +#line 598 "parse.y" {sqlite3Insert(pParse, yymsp[-2].minor.yy373, 0, yymsp[0].minor.yy219, yymsp[-1].minor.yy432, yymsp[-4].minor.yy46);} -#line 2594 "parse.c" +#line 2595 "parse.c" break; case 165: -#line 598 "parse.y" +#line 600 "parse.y" {sqlite3Insert(pParse, yymsp[-3].minor.yy373, 0, 0, yymsp[-2].minor.yy432, yymsp[-5].minor.yy46);} -#line 2599 "parse.c" +#line 2600 "parse.c" break; case 168: case 231: -#line 608 "parse.y" -{yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-2].minor.yy174,yymsp[0].minor.yy172,0);} -#line 2605 "parse.c" +#line 611 "parse.y" +{yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy174,yymsp[0].minor.yy172,0);} +#line 2606 "parse.c" break; case 169: case 232: -#line 609 "parse.y" -{yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[0].minor.yy172,0);} -#line 2611 "parse.c" +#line 613 "parse.y" +{yygotominor.yy174 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy172,0);} +#line 2612 "parse.c" break; case 172: -#line 618 "parse.y" -{yygotominor.yy432 = sqlite3IdListAppend(yymsp[-2].minor.yy432,&yymsp[0].minor.yy410);} -#line 2616 "parse.c" +#line 623 "parse.y" +{yygotominor.yy432 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy432,&yymsp[0].minor.yy410);} +#line 2617 "parse.c" break; case 173: -#line 619 "parse.y" -{yygotominor.yy432 = sqlite3IdListAppend(0,&yymsp[0].minor.yy410);} -#line 2621 "parse.c" +#line 625 "parse.y" +{yygotominor.yy432 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy410);} +#line 2622 "parse.c" break; case 175: -#line 630 "parse.y" +#line 636 "parse.y" {yygotominor.yy172 = yymsp[-1].minor.yy172; sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); } -#line 2626 "parse.c" +#line 2627 "parse.c" break; case 176: case 181: case 182: -#line 631 "parse.y" -{yygotominor.yy172 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);} -#line 2633 "parse.c" +#line 637 "parse.y" +{yygotominor.yy172 = sqlite3PExpr(pParse, yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);} +#line 2634 "parse.c" break; case 177: case 178: -#line 632 "parse.y" -{yygotominor.yy172 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);} -#line 2639 "parse.c" +#line 638 "parse.y" +{yygotominor.yy172 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);} +#line 2640 "parse.c" break; case 179: -#line 634 "parse.y" +#line 640 "parse.y" { - Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy410); - Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy410); - yygotominor.yy172 = sqlite3Expr(TK_DOT, temp1, temp2, 0); + Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy410); + Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy410); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0); } -#line 2648 "parse.c" +#line 2649 "parse.c" break; case 180: -#line 639 "parse.y" +#line 645 "parse.y" { - Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy410); - Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy410); - Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy410); - Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0); - yygotominor.yy172 = sqlite3Expr(TK_DOT, temp1, temp4, 0); + Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy410); + Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy410); + Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy410); + Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0); } -#line 2659 "parse.c" +#line 2660 "parse.c" break; case 183: -#line 648 "parse.y" +#line 654 "parse.y" {yygotominor.yy172 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);} -#line 2664 "parse.c" +#line 2665 "parse.c" break; case 184: -#line 649 "parse.y" +#line 655 "parse.y" { Token *pToken = &yymsp[0].minor.yy0; - Expr *pExpr = yygotominor.yy172 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken); + Expr *pExpr = yygotominor.yy172 = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, pToken); sqlite3ExprAssignVarNumber(pParse, pExpr); } -#line 2673 "parse.c" +#line 2674 "parse.c" break; case 185: -#line 654 "parse.y" +#line 660 "parse.y" { yygotominor.yy172 = sqlite3ExprSetColl(pParse, yymsp[-2].minor.yy172, &yymsp[0].minor.yy410); } -#line 2680 "parse.c" +#line 2681 "parse.c" break; case 186: -#line 658 "parse.y" +#line 664 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_CAST, yymsp[-3].minor.yy172, 0, &yymsp[-1].minor.yy410); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy172, 0, &yymsp[-1].minor.yy410); sqlite3ExprSpan(yygotominor.yy172,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); } -#line 2688 "parse.c" +#line 2689 "parse.c" break; case 187: -#line 663 "parse.y" +#line 669 "parse.y" { if( yymsp[-1].minor.yy174 && yymsp[-1].minor.yy174->nExpr>SQLITE_MAX_FUNCTION_ARG ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); } - yygotominor.yy172 = sqlite3ExprFunction(yymsp[-1].minor.yy174, &yymsp[-4].minor.yy0); + yygotominor.yy172 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy174, &yymsp[-4].minor.yy0); sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); if( yymsp[-2].minor.yy46 && yygotominor.yy172 ){ yygotominor.yy172->flags |= EP_Distinct; } } -#line 2702 "parse.c" +#line 2703 "parse.c" break; case 188: -#line 673 "parse.y" +#line 679 "parse.y" { - yygotominor.yy172 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0); + yygotominor.yy172 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); } -#line 2710 "parse.c" +#line 2711 "parse.c" break; case 189: -#line 677 "parse.y" +#line 683 "parse.y" { /* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are ** treated as functions that return constants */ - yygotominor.yy172 = sqlite3ExprFunction(0,&yymsp[0].minor.yy0); + yygotominor.yy172 = sqlite3ExprFunction(pParse, 0,&yymsp[0].minor.yy0); if( yygotominor.yy172 ){ yygotominor.yy172->op = TK_CONST_FUNC; yygotominor.yy172->span = yymsp[0].minor.yy0; } } -#line 2723 "parse.c" +#line 2724 "parse.c" break; case 190: case 191: @@ -2727,129 +2728,129 @@ static void yy_reduce( case 195: case 196: case 197: -#line 686 "parse.y" -{yygotominor.yy172 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy172, yymsp[0].minor.yy172, 0);} -#line 2735 "parse.c" +#line 692 "parse.y" +{yygotominor.yy172 = sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy172,yymsp[0].minor.yy172,0);} +#line 2736 "parse.c" break; case 198: case 200: -#line 696 "parse.y" +#line 704 "parse.y" {yygotominor.yy72.eOperator = yymsp[0].minor.yy0; yygotominor.yy72.not = 0;} -#line 2741 "parse.c" +#line 2742 "parse.c" break; case 199: case 201: -#line 697 "parse.y" +#line 705 "parse.y" {yygotominor.yy72.eOperator = yymsp[0].minor.yy0; yygotominor.yy72.not = 1;} -#line 2747 "parse.c" +#line 2748 "parse.c" break; case 204: -#line 704 "parse.y" +#line 712 "parse.y" { ExprList *pList; - pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy172, 0); - pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy172, 0); + pList = sqlite3ExprListAppend(pParse,0, yymsp[-1].minor.yy172, 0); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-3].minor.yy172, 0); if( yymsp[0].minor.yy172 ){ - pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy172, 0); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy172, 0); } - yygotominor.yy172 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy72.eOperator); - if( yymsp[-2].minor.yy72.not ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0); + yygotominor.yy172 = sqlite3ExprFunction(pParse, pList, &yymsp[-2].minor.yy72.eOperator); + if( yymsp[-2].minor.yy72.not ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0); sqlite3ExprSpan(yygotominor.yy172, &yymsp[-3].minor.yy172->span, &yymsp[-1].minor.yy172->span); if( yygotominor.yy172 ) yygotominor.yy172->flags |= EP_InfixFunc; } -#line 2763 "parse.c" +#line 2764 "parse.c" break; case 205: -#line 717 "parse.y" -{ - yygotominor.yy172 = sqlite3Expr(yymsp[0].major, yymsp[-1].minor.yy172, 0, 0); - sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy172->span,&yymsp[0].minor.yy0); -} -#line 2771 "parse.c" - break; - case 206: -#line 721 "parse.y" -{ - yygotominor.yy172 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy172, 0, 0); - sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0); -} -#line 2779 "parse.c" - break; - case 207: #line 725 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy172, 0, 0); - sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0); + yygotominor.yy172 = sqlite3PExpr(pParse, yymsp[0].major, yymsp[-1].minor.yy172, 0, 0); + sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy172->span,&yymsp[0].minor.yy0); } -#line 2787 "parse.c" +#line 2772 "parse.c" break; - case 208: + case 206: #line 729 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy172, 0, 0); - sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy172->span,&yymsp[0].minor.yy0); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_ISNULL, yymsp[-2].minor.yy172, 0, 0); + sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0); } -#line 2795 "parse.c" +#line 2780 "parse.c" break; - case 209: + case 207: #line 733 "parse.y" { - yygotominor.yy172 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy172, 0, 0); - sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOTNULL, yymsp[-2].minor.yy172, 0, 0); + sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0); } -#line 2803 "parse.c" +#line 2788 "parse.c" break; - case 210: + case 208: #line 737 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy172, 0, 0); - sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOTNULL, yymsp[-3].minor.yy172, 0, 0); + sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy172->span,&yymsp[0].minor.yy0); } -#line 2811 "parse.c" +#line 2796 "parse.c" break; - case 211: + case 209: #line 741 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy172, 0, 0); + yygotominor.yy172 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy172, 0, 0); sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span); } -#line 2819 "parse.c" +#line 2804 "parse.c" + break; + case 210: +#line 745 "parse.y" +{ + yygotominor.yy172 = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy172, 0, 0); + sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span); +} +#line 2812 "parse.c" + break; + case 211: +#line 749 "parse.y" +{ + yygotominor.yy172 = sqlite3PExpr(pParse, TK_UPLUS, yymsp[0].minor.yy172, 0, 0); + sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span); +} +#line 2820 "parse.c" break; case 214: -#line 748 "parse.y" +#line 756 "parse.y" { - ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy172, 0); - pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy172, 0); - yygotominor.yy172 = sqlite3Expr(TK_BETWEEN, yymsp[-4].minor.yy172, 0, 0); + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy172, 0); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy172, 0); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy172, 0, 0); if( yygotominor.yy172 ){ yygotominor.yy172->pList = pList; }else{ sqlite3ExprListDelete(pList); } - if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0); + if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0); sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy172->span); } -#line 2835 "parse.c" +#line 2836 "parse.c" break; case 217: -#line 764 "parse.y" +#line 772 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy172, 0, 0); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy172, 0, 0); if( yygotominor.yy172 ){ yygotominor.yy172->pList = yymsp[-1].minor.yy174; sqlite3ExprSetHeight(yygotominor.yy172); }else{ sqlite3ExprListDelete(yymsp[-1].minor.yy174); } - if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0); + if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0); sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy0); } -#line 2850 "parse.c" +#line 2851 "parse.c" break; case 218: -#line 775 "parse.y" +#line 783 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_SELECT, 0, 0, 0); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0); if( yygotominor.yy172 ){ yygotominor.yy172->pSelect = yymsp[-1].minor.yy219; sqlite3ExprSetHeight(yygotominor.yy172); @@ -2858,43 +2859,43 @@ static void yy_reduce( } sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); } -#line 2864 "parse.c" +#line 2865 "parse.c" break; case 219: -#line 785 "parse.y" +#line 793 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy172, 0, 0); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy172, 0, 0); if( yygotominor.yy172 ){ yygotominor.yy172->pSelect = yymsp[-1].minor.yy219; sqlite3ExprSetHeight(yygotominor.yy172); }else{ sqlite3SelectDelete(yymsp[-1].minor.yy219); } - if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0); + if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0); sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy0); } -#line 2879 "parse.c" +#line 2880 "parse.c" break; case 220: -#line 796 "parse.y" +#line 804 "parse.y" { - SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410); - yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy172, 0, 0); + SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy172, 0, 0); if( yygotominor.yy172 ){ - yygotominor.yy172->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0); + yygotominor.yy172->pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); sqlite3ExprSetHeight(yygotominor.yy172); }else{ sqlite3SrcListDelete(pSrc); } - if( yymsp[-2].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0); + if( yymsp[-2].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0); sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy172->span,yymsp[0].minor.yy410.z?&yymsp[0].minor.yy410:&yymsp[-1].minor.yy410); } -#line 2895 "parse.c" +#line 2896 "parse.c" break; case 221: -#line 808 "parse.y" +#line 816 "parse.y" { - Expr *p = yygotominor.yy172 = sqlite3Expr(TK_EXISTS, 0, 0, 0); + Expr *p = yygotominor.yy172 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0); if( p ){ p->pSelect = yymsp[-1].minor.yy219; sqlite3ExprSpan(p,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); @@ -2903,12 +2904,12 @@ static void yy_reduce( sqlite3SelectDelete(yymsp[-1].minor.yy219); } } -#line 2909 "parse.c" +#line 2910 "parse.c" break; case 222: -#line 821 "parse.y" +#line 829 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, 0); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, 0); if( yygotominor.yy172 ){ yygotominor.yy172->pList = yymsp[-2].minor.yy174; sqlite3ExprSetHeight(yygotominor.yy172); @@ -2917,171 +2918,172 @@ static void yy_reduce( } sqlite3ExprSpan(yygotominor.yy172, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); } -#line 2923 "parse.c" +#line 2924 "parse.c" break; case 223: -#line 833 "parse.y" +#line 841 "parse.y" { - yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174, yymsp[-2].minor.yy172, 0); - yygotominor.yy174 = sqlite3ExprListAppend(yygotominor.yy174, yymsp[0].minor.yy172, 0); + yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy174, yymsp[-2].minor.yy172, 0); + yygotominor.yy174 = sqlite3ExprListAppend(pParse,yygotominor.yy174, yymsp[0].minor.yy172, 0); } -#line 2931 "parse.c" +#line 2932 "parse.c" break; case 224: -#line 837 "parse.y" +#line 845 "parse.y" { - yygotominor.yy174 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy172, 0); - yygotominor.yy174 = sqlite3ExprListAppend(yygotominor.yy174, yymsp[0].minor.yy172, 0); + yygotominor.yy174 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy172, 0); + yygotominor.yy174 = sqlite3ExprListAppend(pParse,yygotominor.yy174, yymsp[0].minor.yy172, 0); } -#line 2939 "parse.c" +#line 2940 "parse.c" break; case 233: -#line 864 "parse.y" +#line 874 "parse.y" { - sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy410, &yymsp[-5].minor.yy410, sqlite3SrcListAppend(0,&yymsp[-3].minor.yy410,0), yymsp[-1].minor.yy174, yymsp[-9].minor.yy46, + sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy410, &yymsp[-5].minor.yy410, + sqlite3SrcListAppend(pParse->db,0,&yymsp[-3].minor.yy410,0), yymsp[-1].minor.yy174, yymsp[-9].minor.yy46, &yymsp[-10].minor.yy0, &yymsp[0].minor.yy0, SQLITE_SO_ASC, yymsp[-7].minor.yy46); } -#line 2947 "parse.c" +#line 2949 "parse.c" break; case 234: case 281: -#line 870 "parse.y" +#line 881 "parse.y" {yygotominor.yy46 = OE_Abort;} -#line 2953 "parse.c" +#line 2955 "parse.c" break; case 235: -#line 871 "parse.y" +#line 882 "parse.y" {yygotominor.yy46 = OE_None;} -#line 2958 "parse.c" +#line 2960 "parse.c" break; case 238: -#line 881 "parse.y" +#line 892 "parse.y" { Expr *p = 0; if( yymsp[-1].minor.yy410.n>0 ){ - p = sqlite3Expr(TK_COLUMN, 0, 0, 0); + p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0); if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy410.z, yymsp[-1].minor.yy410.n); } - yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174, p, &yymsp[-2].minor.yy410); + yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy174, p, &yymsp[-2].minor.yy410); sqlite3ExprListCheckLength(pParse, yygotominor.yy174, SQLITE_MAX_COLUMN, "index"); if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46; } -#line 2972 "parse.c" +#line 2974 "parse.c" break; case 239: -#line 891 "parse.y" +#line 902 "parse.y" { Expr *p = 0; if( yymsp[-1].minor.yy410.n>0 ){ - p = sqlite3Expr(TK_COLUMN, 0, 0, 0); + p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0); if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy410.z, yymsp[-1].minor.yy410.n); } - yygotominor.yy174 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy410); + yygotominor.yy174 = sqlite3ExprListAppend(pParse,0, p, &yymsp[-2].minor.yy410); sqlite3ExprListCheckLength(pParse, yygotominor.yy174, SQLITE_MAX_COLUMN, "index"); if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46; } -#line 2986 "parse.c" +#line 2988 "parse.c" break; case 241: -#line 904 "parse.y" +#line 915 "parse.y" {yygotominor.yy410.z = 0; yygotominor.yy410.n = 0;} -#line 2991 "parse.c" +#line 2993 "parse.c" break; case 243: -#line 910 "parse.y" +#line 921 "parse.y" {sqlite3DropIndex(pParse, yymsp[0].minor.yy373, yymsp[-1].minor.yy46);} -#line 2996 "parse.c" +#line 2998 "parse.c" break; case 244: case 245: -#line 916 "parse.y" +#line 927 "parse.y" {sqlite3Vacuum(pParse);} -#line 3002 "parse.c" +#line 3004 "parse.c" break; case 246: -#line 924 "parse.y" +#line 935 "parse.y" {sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy410,0);} -#line 3007 "parse.c" +#line 3009 "parse.c" break; case 247: -#line 925 "parse.y" +#line 936 "parse.y" {sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy0,0);} -#line 3012 "parse.c" +#line 3014 "parse.c" break; case 248: -#line 926 "parse.y" +#line 937 "parse.y" { sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy410,1); } -#line 3019 "parse.c" +#line 3021 "parse.c" break; case 249: -#line 929 "parse.y" +#line 940 "parse.y" {sqlite3Pragma(pParse,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410,&yymsp[-1].minor.yy410,0);} -#line 3024 "parse.c" +#line 3026 "parse.c" break; case 250: -#line 930 "parse.y" +#line 941 "parse.y" {sqlite3Pragma(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410,0,0);} -#line 3029 "parse.c" +#line 3031 "parse.c" break; case 258: -#line 944 "parse.y" +#line 955 "parse.y" { Token all; all.z = yymsp[-3].minor.yy410.z; all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy410.z) + yymsp[0].minor.yy0.n; sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy243, &all); } -#line 3039 "parse.c" +#line 3041 "parse.c" break; case 259: -#line 953 "parse.y" +#line 964 "parse.y" { sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy410, &yymsp[-6].minor.yy410, yymsp[-5].minor.yy46, yymsp[-4].minor.yy370.a, yymsp[-4].minor.yy370.b, yymsp[-2].minor.yy373, yymsp[0].minor.yy172, yymsp[-10].minor.yy46, yymsp[-8].minor.yy46); yygotominor.yy410 = (yymsp[-6].minor.yy410.n==0?yymsp[-7].minor.yy410:yymsp[-6].minor.yy410); } -#line 3047 "parse.c" +#line 3049 "parse.c" break; case 260: case 263: -#line 959 "parse.y" +#line 970 "parse.y" { yygotominor.yy46 = TK_BEFORE; } -#line 3053 "parse.c" +#line 3055 "parse.c" break; case 261: -#line 960 "parse.y" +#line 971 "parse.y" { yygotominor.yy46 = TK_AFTER; } -#line 3058 "parse.c" +#line 3060 "parse.c" break; case 262: -#line 961 "parse.y" +#line 972 "parse.y" { yygotominor.yy46 = TK_INSTEAD;} -#line 3063 "parse.c" +#line 3065 "parse.c" break; case 264: case 265: -#line 966 "parse.y" +#line 977 "parse.y" {yygotominor.yy370.a = yymsp[0].major; yygotominor.yy370.b = 0;} -#line 3069 "parse.c" +#line 3071 "parse.c" break; case 266: -#line 968 "parse.y" +#line 979 "parse.y" {yygotominor.yy370.a = TK_UPDATE; yygotominor.yy370.b = yymsp[0].minor.yy432;} -#line 3074 "parse.c" +#line 3076 "parse.c" break; case 269: -#line 975 "parse.y" +#line 986 "parse.y" { yygotominor.yy172 = 0; } -#line 3079 "parse.c" +#line 3081 "parse.c" break; case 270: -#line 976 "parse.y" +#line 987 "parse.y" { yygotominor.yy172 = yymsp[0].minor.yy172; } -#line 3084 "parse.c" +#line 3086 "parse.c" break; case 271: -#line 980 "parse.y" +#line 991 "parse.y" { if( yymsp[-2].minor.yy243 ){ yymsp[-2].minor.yy243->pLast->pNext = yymsp[-1].minor.yy243; @@ -3091,171 +3093,171 @@ static void yy_reduce( yymsp[-2].minor.yy243->pLast = yymsp[-1].minor.yy243; yygotominor.yy243 = yymsp[-2].minor.yy243; } -#line 3097 "parse.c" +#line 3099 "parse.c" break; case 272: -#line 989 "parse.y" +#line 1000 "parse.y" { yygotominor.yy243 = 0; } -#line 3102 "parse.c" +#line 3104 "parse.c" break; case 273: -#line 995 "parse.y" -{ yygotominor.yy243 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy410, yymsp[-1].minor.yy174, yymsp[0].minor.yy172, yymsp[-4].minor.yy46); } -#line 3107 "parse.c" +#line 1006 "parse.y" +{ yygotominor.yy243 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-3].minor.yy410, yymsp[-1].minor.yy174, yymsp[0].minor.yy172, yymsp[-4].minor.yy46); } +#line 3109 "parse.c" break; case 274: -#line 1000 "parse.y" -{yygotominor.yy243 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy410, yymsp[-4].minor.yy432, yymsp[-1].minor.yy174, 0, yymsp[-7].minor.yy46);} -#line 3112 "parse.c" +#line 1011 "parse.y" +{yygotominor.yy243 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-5].minor.yy410, yymsp[-4].minor.yy432, yymsp[-1].minor.yy174, 0, yymsp[-7].minor.yy46);} +#line 3114 "parse.c" break; case 275: -#line 1003 "parse.y" -{yygotominor.yy243 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy410, yymsp[-1].minor.yy432, 0, yymsp[0].minor.yy219, yymsp[-4].minor.yy46);} -#line 3117 "parse.c" +#line 1014 "parse.y" +{yygotominor.yy243 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy410, yymsp[-1].minor.yy432, 0, yymsp[0].minor.yy219, yymsp[-4].minor.yy46);} +#line 3119 "parse.c" break; case 276: -#line 1007 "parse.y" -{yygotominor.yy243 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy410, yymsp[0].minor.yy172);} -#line 3122 "parse.c" +#line 1018 "parse.y" +{yygotominor.yy243 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-1].minor.yy410, yymsp[0].minor.yy172);} +#line 3124 "parse.c" break; case 277: -#line 1010 "parse.y" -{yygotominor.yy243 = sqlite3TriggerSelectStep(yymsp[0].minor.yy219); } -#line 3127 "parse.c" +#line 1021 "parse.y" +{yygotominor.yy243 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy219); } +#line 3129 "parse.c" break; case 278: -#line 1013 "parse.y" +#line 1024 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_RAISE, 0, 0, 0); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); if( yygotominor.yy172 ){ yygotominor.yy172->iColumn = OE_Ignore; sqlite3ExprSpan(yygotominor.yy172, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0); } } -#line 3138 "parse.c" +#line 3140 "parse.c" break; case 279: -#line 1020 "parse.y" +#line 1031 "parse.y" { - yygotominor.yy172 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy410); + yygotominor.yy172 = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy410); if( yygotominor.yy172 ) { yygotominor.yy172->iColumn = yymsp[-3].minor.yy46; sqlite3ExprSpan(yygotominor.yy172, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0); } } -#line 3149 "parse.c" +#line 3151 "parse.c" break; case 280: -#line 1030 "parse.y" +#line 1041 "parse.y" {yygotominor.yy46 = OE_Rollback;} -#line 3154 "parse.c" +#line 3156 "parse.c" break; case 282: -#line 1032 "parse.y" +#line 1043 "parse.y" {yygotominor.yy46 = OE_Fail;} -#line 3159 "parse.c" +#line 3161 "parse.c" break; case 283: -#line 1037 "parse.y" +#line 1048 "parse.y" { sqlite3DropTrigger(pParse,yymsp[0].minor.yy373,yymsp[-1].minor.yy46); } -#line 3166 "parse.c" +#line 3168 "parse.c" break; case 284: -#line 1044 "parse.y" +#line 1055 "parse.y" { sqlite3Attach(pParse, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, yymsp[0].minor.yy386); } -#line 3173 "parse.c" +#line 3175 "parse.c" break; case 285: -#line 1047 "parse.y" +#line 1058 "parse.y" { sqlite3Detach(pParse, yymsp[0].minor.yy172); } -#line 3180 "parse.c" +#line 3182 "parse.c" break; case 286: -#line 1053 "parse.y" +#line 1064 "parse.y" { yygotominor.yy386 = 0; } -#line 3185 "parse.c" +#line 3187 "parse.c" break; case 287: -#line 1054 "parse.y" +#line 1065 "parse.y" { yygotominor.yy386 = yymsp[0].minor.yy172; } -#line 3190 "parse.c" +#line 3192 "parse.c" break; case 290: -#line 1062 "parse.y" +#line 1073 "parse.y" {sqlite3Reindex(pParse, 0, 0);} -#line 3195 "parse.c" +#line 3197 "parse.c" break; case 291: -#line 1063 "parse.y" +#line 1074 "parse.y" {sqlite3Reindex(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);} -#line 3200 "parse.c" +#line 3202 "parse.c" break; case 292: -#line 1068 "parse.y" +#line 1079 "parse.y" {sqlite3Analyze(pParse, 0, 0);} -#line 3205 "parse.c" +#line 3207 "parse.c" break; case 293: -#line 1069 "parse.y" +#line 1080 "parse.y" {sqlite3Analyze(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);} -#line 3210 "parse.c" +#line 3212 "parse.c" break; case 294: -#line 1074 "parse.y" +#line 1085 "parse.y" { sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy373,&yymsp[0].minor.yy410); } -#line 3217 "parse.c" +#line 3219 "parse.c" break; case 295: -#line 1077 "parse.y" +#line 1088 "parse.y" { sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy410); } -#line 3224 "parse.c" +#line 3226 "parse.c" break; case 296: -#line 1080 "parse.y" +#line 1091 "parse.y" { sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy373); } -#line 3231 "parse.c" +#line 3233 "parse.c" break; case 299: -#line 1089 "parse.y" +#line 1100 "parse.y" {sqlite3VtabFinishParse(pParse,0);} -#line 3236 "parse.c" +#line 3238 "parse.c" break; case 300: -#line 1090 "parse.y" +#line 1101 "parse.y" {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} -#line 3241 "parse.c" +#line 3243 "parse.c" break; case 301: -#line 1091 "parse.y" +#line 1102 "parse.y" { sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, &yymsp[0].minor.yy410); } -#line 3248 "parse.c" +#line 3250 "parse.c" break; case 304: -#line 1096 "parse.y" +#line 1107 "parse.y" {sqlite3VtabArgInit(pParse);} -#line 3253 "parse.c" +#line 3255 "parse.c" break; case 306: case 307: case 308: case 310: -#line 1098 "parse.y" +#line 1109 "parse.y" {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} -#line 3261 "parse.c" +#line 3263 "parse.c" break; }; yygoto = yyRuleInfo[yyruleno].lhs; @@ -3322,7 +3324,7 @@ static void yy_syntax_error( } pParse->parseError = 1; } -#line 3329 "parse.c" +#line 3331 "parse.c" sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ } diff --git a/extensions/sqlite/sqlite-source/pragma.c b/extensions/sqlite/sqlite-source/pragma.c index 6844c249..fe3a5acd 100644 --- a/extensions/sqlite/sqlite-source/pragma.c +++ b/extensions/sqlite/sqlite-source/pragma.c @@ -14,18 +14,12 @@ ** $Id$ */ #include "sqliteInt.h" -#include "os.h" #include /* Ignore this whole file if pragmas are disabled */ #if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER) -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) -# include "pager.h" -# include "btree.h" -#endif - /* ** Interpret the given string as a safety level. Return 0 for OFF, ** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or @@ -264,12 +258,12 @@ void sqlite3Pragma( return; } - zLeft = sqlite3NameFromToken(pId); + zLeft = sqlite3NameFromToken(db, pId); if( !zLeft ) return; if( minusFlag ){ - zRight = sqlite3MPrintf("-%T", pValue); + zRight = sqlite3MPrintf(db, "-%T", pValue); }else{ - zRight = sqlite3NameFromToken(pValue); + zRight = sqlite3NameFromToken(db, pValue); } zDb = ((iDb>0)?pDb->zName:0); @@ -306,6 +300,7 @@ void sqlite3Pragma( }; int addr; if( sqlite3ReadSchema(pParse) ) goto pragma_out; + sqlite3VdbeUsesBtree(v, iDb); if( !zRight ){ sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P3_STATIC); @@ -342,7 +337,12 @@ void sqlite3Pragma( int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0; returnSingleInt(pParse, "page_size", size); }else{ - sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1); + /* Malloc may fail when setting the page-size, as there is an internal + ** buffer that the pager module resizes using sqlite3_realloc(). + */ + if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1) ){ + db->mallocFailed = 1; + } } }else @@ -461,6 +461,7 @@ void sqlite3Pragma( sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4); sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1); sqlite3VdbeChangeP1(v, iAddr+5, iDb); + sqlite3VdbeUsesBtree(v, iDb); } } } @@ -557,7 +558,9 @@ void sqlite3Pragma( sqlite3VdbeAddOp(v, OP_Callback, 1, 0); } }else{ - if( zRight[0] && !sqlite3OsIsDirWritable(zRight) ){ + if( zRight[0] + && !sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE) + ){ sqlite3ErrorMsg(pParse, "not a writable directory"); goto pragma_out; } @@ -567,7 +570,7 @@ void sqlite3Pragma( ){ invalidateTempStorage(pParse); } - sqliteFree(sqlite3_temp_directory); + sqlite3_free(sqlite3_temp_directory); if( zRight[0] ){ sqlite3_temp_directory = zRight; zRight = 0; @@ -864,7 +867,7 @@ void sqlite3Pragma( sqlite3VdbeAddOp(v, OP_IntegrityCk, 0, i); addr = sqlite3VdbeAddOp(v, OP_IsNull, -1, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, - sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName), + sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), P3_DYNAMIC); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Concat, 0, 0); @@ -1047,6 +1050,7 @@ void sqlite3Pragma( ){ int iCookie; /* Cookie index. 0 for schema-cookie, 6 for user-cookie. */ + sqlite3VdbeUsesBtree(v, iDb); switch( zLeft[0] ){ case 's': case 'S': iCookie = 0; @@ -1104,16 +1108,18 @@ void sqlite3Pragma( for(i=0; inDb; i++){ Btree *pBt; Pager *pPager; + const char *zState = "unknown"; + int j; if( db->aDb[i].zName==0 ) continue; sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, P3_STATIC); pBt = db->aDb[i].pBt; if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){ - sqlite3VdbeOp3(v, OP_String8, 0, 0, "closed", P3_STATIC); - }else{ - int j = sqlite3PagerLockstate(pPager); - sqlite3VdbeOp3(v, OP_String8, 0, 0, - (j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC); + zState = "closed"; + }else if( sqlite3_file_control(db, db->aDb[i].zName, + SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){ + zState = azLockName[j]; } + sqlite3VdbeOp3(v, OP_String8, 0, 0, zState, P3_STATIC); sqlite3VdbeAddOp(v, OP_Callback, 2, 0); } }else @@ -1173,8 +1179,8 @@ void sqlite3Pragma( #endif } pragma_out: - sqliteFree(zLeft); - sqliteFree(zRight); + sqlite3_free(zLeft); + sqlite3_free(zRight); } #endif /* SQLITE_OMIT_PRAGMA || SQLITE_OMIT_PARSER */ diff --git a/extensions/sqlite/sqlite-source/prepare.c b/extensions/sqlite/sqlite-source/prepare.c index 8cf17b7b..6a548aa4 100644 --- a/extensions/sqlite/sqlite-source/prepare.c +++ b/extensions/sqlite/sqlite-source/prepare.c @@ -16,7 +16,6 @@ ** $Id$ */ #include "sqliteInt.h" -#include "os.h" #include /* @@ -24,7 +23,7 @@ ** that the database is corrupt. */ static void corruptSchema(InitData *pData, const char *zExtra){ - if( !sqlite3MallocFailed() ){ + if( !pData->db->mallocFailed ){ sqlite3SetString(pData->pzErrMsg, "malformed database schema", zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); } @@ -48,9 +47,10 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ sqlite3 *db = pData->db; int iDb = pData->iDb; + assert( sqlite3_mutex_held(db->mutex) ); pData->rc = SQLITE_OK; DbClearProperty(db, iDb, DB_Empty); - if( sqlite3MallocFailed() ){ + if( db->mallocFailed ){ corruptSchema(pData, 0); return SQLITE_NOMEM; } @@ -79,7 +79,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ if( SQLITE_OK!=rc ){ pData->rc = rc; if( rc==SQLITE_NOMEM ){ - sqlite3FailedMalloc(); + db->mallocFailed = 1; }else if( rc!=SQLITE_INTERRUPT ){ corruptSchema(pData, zErr); } @@ -157,6 +157,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pSchema ); + assert( sqlite3_mutex_held(db->mutex) ); /* zMasterSchema and zInitScript are set to point at the master schema ** and initialisation script appropriate for the database being @@ -181,7 +182,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ rc = sqlite3InitCallback(&initData, 3, (char **)azArg, 0); if( rc ){ sqlite3SafetyOn(db); - return initData.rc; + rc = initData.rc; + goto error_out; } pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); if( pTab ){ @@ -198,10 +200,12 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ } return SQLITE_OK; } + sqlite3BtreeEnter(pDb->pBt); 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; + sqlite3BtreeLeave(pDb->pBt); + goto error_out; } /* Get the database meta information. @@ -229,7 +233,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ if( rc ){ sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); sqlite3BtreeCloseCursor(curMain); - return rc; + sqlite3BtreeLeave(pDb->pBt); + goto error_out; } }else{ memset(meta, 0, sizeof(meta)); @@ -252,6 +257,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ sqlite3BtreeCloseCursor(curMain); sqlite3SetString(pzErrMsg, "attached databases must use the same" " text encoding as main database", (char*)0); + sqlite3BtreeLeave(pDb->pBt); return SQLITE_ERROR; } } @@ -278,6 +284,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){ sqlite3BtreeCloseCursor(curMain); sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); + sqlite3BtreeLeave(pDb->pBt); return SQLITE_ERROR; } @@ -290,14 +297,14 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ rc = SQLITE_OK; }else{ char *zSql; - zSql = sqlite3MPrintf( + zSql = sqlite3MPrintf(db, "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); + sqlite3_free(zSql); #ifndef SQLITE_OMIT_ANALYZE if( rc==SQLITE_OK ){ sqlite3AnalysisLoad(db, iDb); @@ -305,7 +312,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ #endif sqlite3BtreeCloseCursor(curMain); } - if( sqlite3MallocFailed() ){ + if( db->mallocFailed ){ /* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */ rc = SQLITE_NOMEM; sqlite3ResetInternalSchema(db, 0); @@ -322,6 +329,12 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ DbSetProperty(db, iDb, DB_SchemaLoaded); rc = SQLITE_OK; } + sqlite3BtreeLeave(pDb->pBt); + +error_out: + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ + db->mallocFailed = 1; + } return rc; } @@ -337,8 +350,9 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ */ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int i, rc; - int called_initone = 0; + int commit_internal = !(db->flags&SQLITE_InternChanges); + assert( sqlite3_mutex_held(db->mutex) ); if( db->init.busy ) return SQLITE_OK; rc = SQLITE_OK; db->init.busy = 1; @@ -348,7 +362,6 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ if( rc ){ sqlite3ResetInternalSchema(db, i); } - called_initone = 1; } /* Once all the other databases have been initialised, load the schema @@ -361,12 +374,11 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ if( rc ){ sqlite3ResetInternalSchema(db, 1); } - called_initone = 1; } #endif db->init.busy = 0; - if( rc==SQLITE_OK && called_initone ){ + if( rc==SQLITE_OK && commit_internal ){ sqlite3CommitInternalChanges(db); } @@ -380,6 +392,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int sqlite3ReadSchema(Parse *pParse){ int rc = SQLITE_OK; sqlite3 *db = pParse->db; + assert( sqlite3_mutex_held(db->mutex) ); if( !db->init.busy ){ rc = sqlite3Init(db, &pParse->zErrMsg); } @@ -402,6 +415,7 @@ static int schemaIsValid(sqlite3 *db){ int cookie; int allOk = 1; + assert( sqlite3_mutex_held(db->mutex) ); for(iDb=0; allOk && iDbnDb; iDb++){ Btree *pBt; pBt = db->aDb[iDb].pBt; @@ -414,6 +428,9 @@ static int schemaIsValid(sqlite3 *db){ } sqlite3BtreeCloseCursor(curTemp); } + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ + db->mallocFailed = 1; + } } return allOk; } @@ -438,6 +455,7 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ ** more likely to cause a segfault than -1 (of course there are assert() ** statements too, but it never hurts to play the odds). */ + assert( sqlite3_mutex_held(db->mutex) ); if( pSchema ){ for(i=0; inDb; i++){ if( db->aDb[i].pSchema==pSchema ){ @@ -465,25 +483,28 @@ int sqlite3Prepare( int rc = SQLITE_OK; int i; - /* Assert that malloc() has not failed */ - assert( !sqlite3MallocFailed() ); - assert( ppStmt ); *ppStmt = 0; if( sqlite3SafetyOn(db) ){ return SQLITE_MISUSE; } + assert( !db->mallocFailed ); + assert( sqlite3_mutex_held(db->mutex) ); /* If any attached database schemas are locked, do not proceed with ** compilation. Instead return SQLITE_LOCKED immediately. */ for(i=0; inDb; i++) { Btree *pBt = db->aDb[i].pBt; - if( pBt && sqlite3BtreeSchemaLocked(pBt) ){ - const char *zDb = db->aDb[i].zName; - sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb); - sqlite3SafetyOff(db); - return SQLITE_LOCKED; + if( pBt ){ + int rc; + rc = sqlite3BtreeSchemaLocked(pBt); + if( rc ){ + const char *zDb = db->aDb[i].zName; + sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb); + sqlite3SafetyOff(db); + return SQLITE_LOCKED; + } } } @@ -494,17 +515,17 @@ int sqlite3Prepare( if( nBytes>SQLITE_MAX_SQL_LENGTH ){ return SQLITE_TOOBIG; } - zSqlCopy = sqlite3StrNDup(zSql, nBytes); + zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes); if( zSqlCopy ){ sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg); - sqliteFree(zSqlCopy); + sqlite3_free(zSqlCopy); } sParse.zTail = &zSql[nBytes]; }else{ sqlite3RunParser(&sParse, zSql, &zErrMsg); } - if( sqlite3MallocFailed() ){ + if( db->mallocFailed ){ sParse.rc = SQLITE_NOMEM; } if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; @@ -514,7 +535,7 @@ int sqlite3Prepare( if( sParse.rc==SQLITE_SCHEMA ){ sqlite3ResetInternalSchema(db, 0); } - if( sqlite3MallocFailed() ){ + if( db->mallocFailed ){ sParse.rc = SQLITE_NOMEM; } if( pzTail ){ @@ -547,7 +568,7 @@ int sqlite3Prepare( if( saveSqlFlag ){ sqlite3VdbeSetSql(sParse.pVdbe, zSql, sParse.zTail - zSql); } - if( rc!=SQLITE_OK || sqlite3MallocFailed() ){ + if( rc!=SQLITE_OK || db->mallocFailed ){ sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); assert(!(*ppStmt)); }else{ @@ -556,16 +577,35 @@ int sqlite3Prepare( if( zErrMsg ){ sqlite3Error(db, rc, "%s", zErrMsg); - sqliteFree(zErrMsg); + sqlite3_free(zErrMsg); }else{ sqlite3Error(db, rc, 0); } rc = sqlite3ApiExit(db, rc); - sqlite3ReleaseThreadData(); + /* sqlite3ReleaseThreadData(); */ assert( (rc&db->errMask)==rc ); return rc; } +static int sqlite3LockAndPrepare( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char **pzTail /* OUT: End of parsed string */ +){ + int rc; + if( sqlite3SafetyCheck(db) ){ + return SQLITE_MISUSE; + } + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, ppStmt, pzTail); + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); + return rc; +} /* ** Rerun the compilation of a statement after a schema change. @@ -577,13 +617,15 @@ int sqlite3Reprepare(Vdbe *p){ sqlite3_stmt *pNew; const char *zSql; sqlite3 *db; - + + assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) ); zSql = sqlite3VdbeGetSql(p); if( zSql==0 ){ return 0; } db = sqlite3VdbeDb(p); - rc = sqlite3Prepare(db, zSql, -1, 0, &pNew, 0); + assert( sqlite3_mutex_held(db->mutex) ); + rc = sqlite3LockAndPrepare(db, zSql, -1, 0, &pNew, 0); if( rc ){ assert( pNew==0 ); return 0; @@ -613,7 +655,7 @@ int sqlite3_prepare( sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ - return sqlite3Prepare(db,zSql,nBytes,0,ppStmt,pzTail); + return sqlite3LockAndPrepare(db,zSql,nBytes,0,ppStmt,pzTail); } int sqlite3_prepare_v2( sqlite3 *db, /* Database handle. */ @@ -622,7 +664,7 @@ int sqlite3_prepare_v2( sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ - return sqlite3Prepare(db,zSql,nBytes,1,ppStmt,pzTail); + return sqlite3LockAndPrepare(db,zSql,nBytes,1,ppStmt,pzTail); } @@ -649,9 +691,10 @@ static int sqlite3Prepare16( if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } - zSql8 = sqlite3Utf16to8(zSql, nBytes); + sqlite3_mutex_enter(db->mutex); + zSql8 = sqlite3Utf16to8(db, zSql, nBytes); if( zSql8 ){ - rc = sqlite3Prepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8); + rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8); } if( zTail8 && pzTail ){ @@ -663,8 +706,10 @@ static int sqlite3Prepare16( int chars_parsed = sqlite3Utf8CharLen(zSql8, zTail8-zSql8); *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed); } - sqliteFree(zSql8); - return sqlite3ApiExit(db, rc); + sqlite3_free(zSql8); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; } /* diff --git a/extensions/sqlite/sqlite-source/printf.c b/extensions/sqlite/sqlite-source/printf.c index 01ed7a1e..bea91e21 100644 --- a/extensions/sqlite/sqlite-source/printf.c +++ b/extensions/sqlite/sqlite-source/printf.c @@ -113,7 +113,7 @@ static const et_info fmtinfo[] = { { 'd', 10, 1, etRADIX, 0, 0 }, { 's', 0, 4, etSTRING, 0, 0 }, { 'g', 0, 1, etGENERIC, 30, 0 }, - { 'z', 0, 6, etDYNSTRING, 0, 0 }, + { 'z', 0, 4, etDYNSTRING, 0, 0 }, { 'q', 0, 4, etSQLESCAPE, 0, 0 }, { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, @@ -627,7 +627,7 @@ static int vxprintf( needQuote = !isnull && xtype==etSQLESCAPE2; n += i + 1 + needQuote*2; if( n>etBUFSIZE ){ - bufpt = zExtra = sqliteMalloc( n ); + bufpt = zExtra = sqlite3_malloc( n ); if( bufpt==0 ) return -1; }else{ bufpt = buf; @@ -701,7 +701,7 @@ static int vxprintf( } } if( zExtra ){ - sqliteFree(zExtra); + sqlite3_free(zExtra); } }/* End for loop over the format string */ return errorflag ? -1 : count; @@ -718,6 +718,7 @@ struct sgMprintf { int nTotal; /* Output size if unconstrained */ int nAlloc; /* Amount of space allocated in zText */ void *(*xRealloc)(void*,int); /* Function used to realloc memory */ + int iMallocFailed; /* True if xRealloc() has failed */ }; /* @@ -728,30 +729,39 @@ struct sgMprintf { */ static void mout(void *arg, const char *zNewText, int nNewChar){ struct sgMprintf *pM = (struct sgMprintf*)arg; + if( pM->iMallocFailed ) return; pM->nTotal += nNewChar; - if( pM->nChar + nNewChar + 1 > pM->nAlloc ){ - if( pM->xRealloc==0 ){ - nNewChar = pM->nAlloc - pM->nChar - 1; - }else{ - int nAlloc = pM->nChar + nNewChar*2 + 1; - if( pM->zText==pM->zBase ){ - pM->zText = pM->xRealloc(0, nAlloc); - if( pM->zText && pM->nChar ){ - memcpy(pM->zText, pM->zBase, pM->nChar); - } - }else{ - char *zNew; - zNew = pM->xRealloc(pM->zText, nAlloc); - if( zNew ){ - pM->zText = zNew; - }else{ - return; - } - } - pM->nAlloc = nAlloc; - } - } if( pM->zText ){ + if( pM->nChar + nNewChar + 1 > pM->nAlloc ){ + if( pM->xRealloc==0 ){ + nNewChar = pM->nAlloc - pM->nChar - 1; + }else{ + int nAlloc = pM->nChar + nNewChar*2 + 1; + if( pM->zText==pM->zBase ){ + pM->zText = pM->xRealloc(0, nAlloc); + if( pM->zText==0 ){ + pM->nAlloc = 0; + pM->iMallocFailed = 1; + return; + }else if( pM->nChar ){ + memcpy(pM->zText, pM->zBase, pM->nChar); + } + }else{ + char *zNew; + zNew = pM->xRealloc(pM->zText, nAlloc); + if( zNew ){ + pM->zText = zNew; + }else{ + pM->iMallocFailed = 1; + pM->xRealloc(pM->zText, 0); + pM->zText = 0; + pM->nAlloc = 0; + return; + } + } + pM->nAlloc = nAlloc; + } + } if( nNewChar>0 ){ memcpy(&pM->zText[pM->nChar], zNewText, nNewChar); pM->nChar += nNewChar; @@ -765,7 +775,7 @@ static void mout(void *arg, const char *zNewText, int nNewChar){ ** the consumer. */ static char *base_vprintf( - void *(*xRealloc)(void*,int), /* Routine to realloc memory. May be NULL */ + void *(*xRealloc)(void*, int), /* realloc() function. May be NULL */ int useInternal, /* Use internal %-conversions if true */ char *zInitBuf, /* Initially write here, before mallocing */ int nInitBuf, /* Size of zInitBuf[] */ @@ -777,15 +787,19 @@ static char *base_vprintf( sM.nChar = sM.nTotal = 0; sM.nAlloc = nInitBuf; sM.xRealloc = xRealloc; + sM.iMallocFailed = 0; vxprintf(mout, &sM, useInternal, zFormat, ap); - if( xRealloc ){ + assert(sM.iMallocFailed==0 || sM.zText==0); + if( xRealloc && !sM.iMallocFailed ){ if( sM.zText==sM.zBase ){ sM.zText = xRealloc(0, sM.nChar+1); if( sM.zText ){ memcpy(sM.zText, sM.zBase, sM.nChar+1); } }else if( sM.nAlloc>sM.nChar+10 ){ - char *zNew = xRealloc(sM.zText, sM.nChar+1); + char *zNew; + sqlite3MallocBenignFailure(1); + zNew = xRealloc(sM.zText, sM.nChar+1); if( zNew ){ sM.zText = zNew; } @@ -798,29 +812,37 @@ static char *base_vprintf( ** Realloc that is a real function, not a macro. */ static void *printf_realloc(void *old, int size){ - return sqliteRealloc(old,size); + return sqlite3_realloc(old, size); } /* ** Print into memory obtained from sqliteMalloc(). Use the internal ** %-conversion extensions. */ -char *sqlite3VMPrintf(const char *zFormat, va_list ap){ +char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){ + char *z; char zBase[SQLITE_PRINT_BUF_SIZE]; - return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap); + z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap); + if( z==0 && db!=0 ){ + db->mallocFailed = 1; + } + return z; } /* ** Print into memory obtained from sqliteMalloc(). Use the internal ** %-conversion extensions. */ -char *sqlite3MPrintf(const char *zFormat, ...){ +char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){ va_list ap; char *z; char zBase[SQLITE_PRINT_BUF_SIZE]; va_start(ap, zFormat); z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap); va_end(ap); + if( z==0 && db!=0 ){ + db->mallocFailed = 1; + } return z; } diff --git a/extensions/sqlite/sqlite-source/random.c b/extensions/sqlite/sqlite-source/random.c index 5adc84aa..b41b770d 100644 --- a/extensions/sqlite/sqlite-source/random.c +++ b/extensions/sqlite/sqlite-source/random.c @@ -18,7 +18,6 @@ ** $Id$ */ #include "sqliteInt.h" -#include "os.h" /* @@ -63,7 +62,7 @@ static int randomByte(void){ char k[256]; prng.j = 0; prng.i = 0; - sqlite3OsRandomSeed(k); + sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k); for(i=0; i<256; i++){ prng.s[i] = i; } @@ -92,9 +91,13 @@ static int randomByte(void){ */ void sqlite3Randomness(int N, void *pBuf){ unsigned char *zBuf = pBuf; - sqlite3OsEnterMutex(); + static sqlite3_mutex *mutex = 0; + if( mutex==0 ){ + mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG); + } + sqlite3_mutex_enter(mutex); while( N-- ){ *(zBuf++) = randomByte(); } - sqlite3OsLeaveMutex(); + sqlite3_mutex_leave(mutex); } diff --git a/extensions/sqlite/sqlite-source/select.c b/extensions/sqlite/sqlite-source/select.c index 6840d41b..dfa758dd 100644 --- a/extensions/sqlite/sqlite-source/select.c +++ b/extensions/sqlite/sqlite-source/select.c @@ -39,6 +39,7 @@ static void clearSelect(Select *p){ ** structure. */ Select *sqlite3SelectNew( + Parse *pParse, /* Parsing context */ ExprList *pEList, /* which columns to include in the result */ SrcList *pSrc, /* the FROM clause -- which tables to scan */ Expr *pWhere, /* the WHERE clause */ @@ -51,14 +52,15 @@ Select *sqlite3SelectNew( ){ Select *pNew; Select standin; - pNew = sqliteMalloc( sizeof(*pNew) ); + sqlite3 *db = pParse->db; + pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); assert( !pOffset || pLimit ); /* Can't have OFFSET without LIMIT. */ if( pNew==0 ){ pNew = &standin; memset(pNew, 0, sizeof(*pNew)); } if( pEList==0 ){ - pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0); + pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0,0,0), 0); } pNew->pEList = pEList; pNew->pSrc = pSrc; @@ -89,7 +91,7 @@ Select *sqlite3SelectNew( void sqlite3SelectDelete(Select *p){ if( p ){ clearSelect(p); - sqliteFree(p); + sqlite3_free(p); } } @@ -191,21 +193,23 @@ static void setToken(Token *p, const char *z){ ** ** {a"bc} -> {"a""bc"} */ -static void setQuotedToken(Token *p, const char *z){ - p->z = (u8 *)sqlite3MPrintf("\"%w\"", z); +static void setQuotedToken(Parse *pParse, Token *p, const char *z){ + p->z = (u8 *)sqlite3MPrintf(0, "\"%w\"", z); p->dyn = 1; if( p->z ){ p->n = strlen((char *)p->z); + }else{ + pParse->db->mallocFailed = 1; } } /* ** Create an expression node for an identifier with the name of zName */ -Expr *sqlite3CreateIdExpr(const char *zName){ +Expr *sqlite3CreateIdExpr(Parse *pParse, const char *zName){ Token dummy; setToken(&dummy, zName); - return sqlite3Expr(TK_ID, 0, 0, &dummy); + return sqlite3PExpr(pParse, TK_ID, 0, 0, &dummy); } @@ -214,6 +218,7 @@ Expr *sqlite3CreateIdExpr(const char *zName){ ** zCol column to be equal in the two tables pTab1 and pTab2. */ static void addWhereTerm( + Parse *pParse, /* Parsing context */ const char *zCol, /* Name of the column */ const Table *pTab1, /* First table */ const char *zAlias1, /* Alias for first table. May be NULL */ @@ -226,24 +231,24 @@ static void addWhereTerm( Expr *pE2a, *pE2b, *pE2c; Expr *pE; - pE1a = sqlite3CreateIdExpr(zCol); - pE2a = sqlite3CreateIdExpr(zCol); + pE1a = sqlite3CreateIdExpr(pParse, zCol); + pE2a = sqlite3CreateIdExpr(pParse, zCol); if( zAlias1==0 ){ zAlias1 = pTab1->zName; } - pE1b = sqlite3CreateIdExpr(zAlias1); + pE1b = sqlite3CreateIdExpr(pParse, zAlias1); if( zAlias2==0 ){ zAlias2 = pTab2->zName; } - pE2b = sqlite3CreateIdExpr(zAlias2); - pE1c = sqlite3ExprOrFree(TK_DOT, pE1b, pE1a, 0); - pE2c = sqlite3ExprOrFree(TK_DOT, pE2b, pE2a, 0); - pE = sqlite3ExprOrFree(TK_EQ, pE1c, pE2c, 0); + pE2b = sqlite3CreateIdExpr(pParse, zAlias2); + pE1c = sqlite3PExpr(pParse, TK_DOT, pE1b, pE1a, 0); + pE2c = sqlite3PExpr(pParse, TK_DOT, pE2b, pE2a, 0); + pE = sqlite3PExpr(pParse, TK_EQ, pE1c, pE2c, 0); if( pE ){ ExprSetProperty(pE, EP_FromJoin); pE->iRightJoinTable = iRightJoinTable; } - pE = sqlite3ExprAnd(*ppExpr, pE); + pE = sqlite3ExprAnd(pParse->db,*ppExpr, pE); if( pE ){ *ppExpr = pE; } @@ -325,7 +330,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ for(j=0; jnCol; j++){ char *zName = pLeftTab->aCol[j].zName; if( columnIndex(pRightTab, zName)>=0 ){ - addWhereTerm(zName, pLeftTab, pLeft->zAlias, + addWhereTerm(pParse, zName, pLeftTab, pLeft->zAlias, pRightTab, pRight->zAlias, pRight->iCursor, &p->pWhere); @@ -346,7 +351,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ */ if( pRight->pOn ){ setJoinExpr(pRight->pOn, pRight->iCursor); - p->pWhere = sqlite3ExprAnd(p->pWhere, pRight->pOn); + p->pWhere = sqlite3ExprAnd(pParse->db, p->pWhere, pRight->pOn); pRight->pOn = 0; } @@ -366,7 +371,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ "not present in both tables", zName); return 1; } - addWhereTerm(zName, pLeftTab, pLeft->zAlias, + addWhereTerm(pParse, zName, pLeftTab, pLeft->zAlias, pRightTab, pRight->zAlias, pRight->iCursor, &p->pWhere); } @@ -689,7 +694,7 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){ int i; nExpr = pList->nExpr; - pInfo = sqliteMalloc( sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) ); + pInfo = sqlite3DbMallocZero(db, sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) ); if( pInfo ){ pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr]; pInfo->nField = nExpr; @@ -992,7 +997,7 @@ static void generateColumnNames( #endif assert( v!=0 ); - if( pParse->colNamesSet || v==0 || sqlite3MallocFailed() ) return; + if( pParse->colNamesSet || v==0 || db->mallocFailed ) return; pParse->colNamesSet = 1; fullNames = (db->flags & SQLITE_FullColNames)!=0; shortNames = (db->flags & SQLITE_ShortColNames)!=0; @@ -1076,6 +1081,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ int i, j; ExprList *pEList; Column *aCol, *pCol; + sqlite3 *db = pParse->db; while( pSelect->pPrior ) pSelect = pSelect->pPrior; if( prepSelectStmt(pParse, pSelect) ){ @@ -1084,16 +1090,16 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ if( sqlite3SelectResolve(pParse, pSelect, 0) ){ return 0; } - pTab = sqliteMalloc( sizeof(Table) ); + pTab = sqlite3DbMallocZero(db, sizeof(Table) ); if( pTab==0 ){ return 0; } pTab->nRef = 1; - pTab->zName = zTabName ? sqliteStrDup(zTabName) : 0; + pTab->zName = zTabName ? sqlite3DbStrDup(db, zTabName) : 0; pEList = pSelect->pEList; pTab->nCol = pEList->nExpr; assert( pTab->nCol>0 ); - pTab->aCol = aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol ); + pTab->aCol = aCol = sqlite3DbMallocZero(db, sizeof(pTab->aCol[0])*pTab->nCol); for(i=0, pCol=aCol; inCol; i++, pCol++){ Expr *p, *pR; char *zType; @@ -1109,24 +1115,25 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ assert( p->pRight==0 || p->pRight->token.z==0 || p->pRight->token.z[0]!=0 ); if( (zName = pEList->a[i].zName)!=0 ){ /* If the column contains an "AS " phrase, use as the name */ - zName = sqliteStrDup(zName); + zName = sqlite3DbStrDup(db, zName); }else if( p->op==TK_DOT && (pR=p->pRight)!=0 && pR->token.z && pR->token.z[0] ){ /* For columns of the from A.B use B as the name */ - zName = sqlite3MPrintf("%T", &pR->token); + zName = sqlite3MPrintf(db, "%T", &pR->token); }else if( p->span.z && p->span.z[0] ){ /* Use the original text of the column expression as its name */ - zName = sqlite3MPrintf("%T", &p->span); + zName = sqlite3MPrintf(db, "%T", &p->span); }else{ /* If all else fails, make up a name */ - zName = sqlite3MPrintf("column%d", i+1); + zName = sqlite3MPrintf(db, "column%d", i+1); } - sqlite3Dequote(zName); - if( sqlite3MallocFailed() ){ - sqliteFree(zName); + if( !zName || db->mallocFailed ){ + db->mallocFailed = 1; + sqlite3_free(zName); sqlite3DeleteTable(pTab); return 0; } + sqlite3Dequote(zName); /* Make sure the column name is unique. If the name is not unique, ** append a integer to the name so that it becomes unique. @@ -1135,7 +1142,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ for(j=cnt=0; jpSrc; - zType = sqliteStrDup(columnType(&sNC, p, 0, 0, 0)); + zType = sqlite3DbStrDup(db, columnType(&sNC, p, 0, 0, 0)); pCol->zType = zType; pCol->affinity = sqlite3ExprAffinity(p); pColl = sqlite3ExprCollSeq(pParse, p); if( pColl ){ - pCol->zColl = sqliteStrDup(pColl->zName); + pCol->zColl = sqlite3DbStrDup(db, pColl->zName); } } pTab->iPKey = -1; @@ -1190,8 +1197,9 @@ static int prepSelectStmt(Parse *pParse, Select *p){ SrcList *pTabList; ExprList *pEList; struct SrcList_item *pFrom; + sqlite3 *db = pParse->db; - if( p==0 || p->pSrc==0 || sqlite3MallocFailed() ){ + if( p==0 || p->pSrc==0 || db->mallocFailed ){ return 1; } pTabList = p->pSrc; @@ -1220,7 +1228,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){ assert( pFrom->pSelect!=0 ); if( pFrom->zAlias==0 ){ pFrom->zAlias = - sqlite3MPrintf("sqlite_subquery_%p_", (void*)pFrom->pSelect); + sqlite3MPrintf(db, "sqlite_subquery_%p_", (void*)pFrom->pSelect); } assert( pFrom->pTab==0 ); pFrom->pTab = pTab = @@ -1255,7 +1263,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){ ** in the inner view. */ if( pFrom->pSelect==0 ){ - pFrom->pSelect = sqlite3SelectDup(pTab->pSelect); + pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect); } } #endif @@ -1301,7 +1309,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){ (pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){ /* This particular expression does not need to be expanded. */ - pNew = sqlite3ExprListAppend(pNew, a[k].pExpr, 0); + pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr, 0); if( pNew ){ pNew->a[pNew->nExpr-1].zName = a[k].zName; }else{ @@ -1315,7 +1323,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){ int tableSeen = 0; /* Set to 1 when TABLE matches */ char *zTName; /* text of name of TABLE */ if( pE->op==TK_DOT && pE->pLeft ){ - zTName = sqlite3NameFromToken(&pE->pLeft->token); + zTName = sqlite3NameFromToken(db, &pE->pLeft->token); }else{ zTName = 0; } @@ -1357,15 +1365,16 @@ static int prepSelectStmt(Parse *pParse, Select *p){ continue; } } - pRight = sqlite3Expr(TK_ID, 0, 0, 0); + pRight = sqlite3PExpr(pParse, TK_ID, 0, 0, 0); if( pRight==0 ) break; - setQuotedToken(&pRight->token, zName); + setQuotedToken(pParse, &pRight->token, zName); if( zTabName && (longNames || pTabList->nSrc>1) ){ - Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, 0); - pExpr = sqlite3Expr(TK_DOT, pLeft, pRight, 0); + Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, 0); + pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); if( pExpr==0 ) break; - setQuotedToken(&pLeft->token, zTabName); - setToken(&pExpr->span, sqlite3MPrintf("%s.%s", zTabName, zName)); + setQuotedToken(pParse, &pLeft->token, zTabName); + setToken(&pExpr->span, + sqlite3MPrintf(db, "%s.%s", zTabName, zName)); pExpr->span.dyn = 1; pExpr->token.z = 0; pExpr->token.n = 0; @@ -1376,9 +1385,9 @@ static int prepSelectStmt(Parse *pParse, Select *p){ pExpr->span.dyn = 0; } if( longNames ){ - pNew = sqlite3ExprListAppend(pNew, pExpr, &pExpr->span); + pNew = sqlite3ExprListAppend(pParse, pNew, pExpr, &pExpr->span); }else{ - pNew = sqlite3ExprListAppend(pNew, pExpr, &pRight->token); + pNew = sqlite3ExprListAppend(pParse, pNew, pExpr, &pRight->token); } } } @@ -1390,7 +1399,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){ } rc = 1; } - sqliteFree(zTName); + sqlite3_free(zTName); } } sqlite3ExprListDelete(pEList); @@ -1400,7 +1409,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){ sqlite3ErrorMsg(pParse, "too many columns in result set"); rc = SQLITE_ERROR; } - if( sqlite3MallocFailed() ){ + if( db->mallocFailed ){ rc = SQLITE_NOMEM; } return rc; @@ -1430,6 +1439,7 @@ static int matchOrderbyToColumn( int nErr = 0; int i, j; ExprList *pEList; + sqlite3 *db = pParse->db; if( pSelect==0 || pOrderBy==0 ) return 1; if( mustComplete ){ @@ -1462,23 +1472,23 @@ static int matchOrderbyToColumn( if( !mustComplete ) continue; iCol--; } - if( iCol<0 && (zLabel = sqlite3NameFromToken(&pE->token))!=0 ){ + if( iCol<0 && (zLabel = sqlite3NameFromToken(db, &pE->token))!=0 ){ for(j=0, pItem=pEList->a; jnExpr; j++, pItem++){ char *zName; int isMatch; if( pItem->zName ){ - zName = sqlite3StrDup(pItem->zName); + zName = sqlite3DbStrDup(db, pItem->zName); }else{ - zName = sqlite3NameFromToken(&pItem->pExpr->token); + zName = sqlite3NameFromToken(db, &pItem->pExpr->token); } isMatch = zName && sqlite3StrICmp(zName, zLabel)==0; - sqliteFree(zName); + sqlite3_free(zName); if( isMatch ){ iCol = j; break; } } - sqliteFree(zLabel); + sqlite3_free(zLabel); } if( iCol>=0 ){ pE->op = TK_COLUMN; @@ -1962,7 +1972,8 @@ static int multiSelect( assert( p->pRightmost==p ); nKeyCol = nCol + (pOrderBy ? pOrderBy->nExpr : 0); - pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nKeyCol*(sizeof(CollSeq*) + 1)); + pKeyInfo = sqlite3DbMallocZero(pParse->db, + sizeof(*pKeyInfo)+nKeyCol*(sizeof(CollSeq*) + 1)); if( !pKeyInfo ){ rc = SQLITE_NOMEM; goto multi_select_end; @@ -2037,7 +2048,7 @@ static int multiSelect( generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm); } - sqliteFree(pKeyInfo); + sqlite3_free(pKeyInfo); } multi_select_end: @@ -2046,6 +2057,10 @@ multi_select_end: #endif /* SQLITE_OMIT_COMPOUND_SELECT */ #ifndef SQLITE_OMIT_VIEW +/* Forward Declarations */ +static void substExprList(sqlite3*, ExprList*, int, ExprList*); +static void substSelect(sqlite3*, Select *, int, ExprList *); + /* ** Scan through the expression pExpr. Replace every reference to ** a column in table number iTable with a copy of the iColumn-th @@ -2059,9 +2074,12 @@ multi_select_end: ** changes to pExpr so that it refers directly to the source table ** of the subquery rather the result set of the subquery. */ -static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */ -static void substSelect(Select *, int, ExprList *); /* Forward Decl */ -static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){ +static void substExpr( + sqlite3 *db, /* Report malloc errors to this connection */ + Expr *pExpr, /* Expr in which substitution occurs */ + int iTable, /* Table to be substituted */ + ExprList *pEList /* Substitute expressions */ +){ if( pExpr==0 ) return; if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){ if( pExpr->iColumn<0 ){ @@ -2074,42 +2092,52 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){ assert( pNew!=0 ); pExpr->op = pNew->op; assert( pExpr->pLeft==0 ); - pExpr->pLeft = sqlite3ExprDup(pNew->pLeft); + pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft); assert( pExpr->pRight==0 ); - pExpr->pRight = sqlite3ExprDup(pNew->pRight); + pExpr->pRight = sqlite3ExprDup(db, pNew->pRight); assert( pExpr->pList==0 ); - pExpr->pList = sqlite3ExprListDup(pNew->pList); + pExpr->pList = sqlite3ExprListDup(db, pNew->pList); pExpr->iTable = pNew->iTable; pExpr->pTab = pNew->pTab; pExpr->iColumn = pNew->iColumn; pExpr->iAgg = pNew->iAgg; - sqlite3TokenCopy(&pExpr->token, &pNew->token); - sqlite3TokenCopy(&pExpr->span, &pNew->span); - pExpr->pSelect = sqlite3SelectDup(pNew->pSelect); + sqlite3TokenCopy(db, &pExpr->token, &pNew->token); + sqlite3TokenCopy(db, &pExpr->span, &pNew->span); + pExpr->pSelect = sqlite3SelectDup(db, pNew->pSelect); pExpr->flags = pNew->flags; } }else{ - substExpr(pExpr->pLeft, iTable, pEList); - substExpr(pExpr->pRight, iTable, pEList); - substSelect(pExpr->pSelect, iTable, pEList); - substExprList(pExpr->pList, iTable, pEList); + substExpr(db, pExpr->pLeft, iTable, pEList); + substExpr(db, pExpr->pRight, iTable, pEList); + substSelect(db, pExpr->pSelect, iTable, pEList); + substExprList(db, pExpr->pList, iTable, pEList); } } -static void substExprList(ExprList *pList, int iTable, ExprList *pEList){ +static void substExprList( + sqlite3 *db, /* Report malloc errors here */ + ExprList *pList, /* List to scan and in which to make substitutes */ + int iTable, /* Table to be substituted */ + ExprList *pEList /* Substitute values */ +){ int i; if( pList==0 ) return; for(i=0; inExpr; i++){ - substExpr(pList->a[i].pExpr, iTable, pEList); + substExpr(db, pList->a[i].pExpr, iTable, pEList); } } -static void substSelect(Select *p, int iTable, ExprList *pEList){ +static void substSelect( + sqlite3 *db, /* Report malloc errors here */ + Select *p, /* SELECT statement in which to make substitutions */ + int iTable, /* Table to be replaced */ + ExprList *pEList /* Substitute values */ +){ if( !p ) return; - substExprList(p->pEList, iTable, pEList); - substExprList(p->pGroupBy, iTable, pEList); - substExprList(p->pOrderBy, iTable, pEList); - substExpr(p->pHaving, iTable, pEList); - substExpr(p->pWhere, iTable, pEList); - substSelect(p->pPrior, iTable, pEList); + substExprList(db, p->pEList, iTable, pEList); + substExprList(db, p->pGroupBy, iTable, pEList); + substExprList(db, p->pOrderBy, iTable, pEList); + substExpr(db, p->pHaving, iTable, pEList); + substExpr(db, p->pWhere, iTable, pEList); + substSelect(db, p->pPrior, iTable, pEList); } #endif /* !defined(SQLITE_OMIT_VIEW) */ @@ -2192,6 +2220,7 @@ static void substSelect(Select *p, int iTable, ExprList *pEList){ ** the subquery before this routine runs. */ static int flattenSubquery( + sqlite3 *db, /* Database connection */ Select *p, /* The parent or outer SELECT statement */ int iFrom, /* Index in p->pSrc->a[] of the inner subquery */ int isAgg, /* True if outer SELECT uses aggregate functions */ @@ -2289,13 +2318,13 @@ static int flattenSubquery( int jointype = pSubitem->jointype; sqlite3DeleteTable(pSubitem->pTab); - sqliteFree(pSubitem->zDatabase); - sqliteFree(pSubitem->zName); - sqliteFree(pSubitem->zAlias); + sqlite3_free(pSubitem->zDatabase); + sqlite3_free(pSubitem->zName); + sqlite3_free(pSubitem->zAlias); if( nSubSrc>1 ){ int extra = nSubSrc - 1; for(i=1; ipSrc = pSrc; for(i=pSrc->nSrc-1; i-extra>=iFrom; i--){ @@ -2325,23 +2354,24 @@ static int flattenSubquery( for(i=0; inExpr; i++){ Expr *pExpr; if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){ - pList->a[i].zName = sqliteStrNDup((char*)pExpr->span.z, pExpr->span.n); + pList->a[i].zName = + sqlite3DbStrNDup(db, (char*)pExpr->span.z, pExpr->span.n); } } - substExprList(p->pEList, iParent, pSub->pEList); + substExprList(db, p->pEList, iParent, pSub->pEList); if( isAgg ){ - substExprList(p->pGroupBy, iParent, pSub->pEList); - substExpr(p->pHaving, iParent, pSub->pEList); + substExprList(db, p->pGroupBy, iParent, pSub->pEList); + substExpr(db, p->pHaving, iParent, pSub->pEList); } if( pSub->pOrderBy ){ assert( p->pOrderBy==0 ); p->pOrderBy = pSub->pOrderBy; pSub->pOrderBy = 0; }else if( p->pOrderBy ){ - substExprList(p->pOrderBy, iParent, pSub->pEList); + substExprList(db, p->pOrderBy, iParent, pSub->pEList); } if( pSub->pWhere ){ - pWhere = sqlite3ExprDup(pSub->pWhere); + pWhere = sqlite3ExprDup(db, pSub->pWhere); }else{ pWhere = 0; } @@ -2349,13 +2379,14 @@ static int flattenSubquery( assert( p->pHaving==0 ); p->pHaving = p->pWhere; p->pWhere = pWhere; - substExpr(p->pHaving, iParent, pSub->pEList); - p->pHaving = sqlite3ExprAnd(p->pHaving, sqlite3ExprDup(pSub->pHaving)); + substExpr(db, p->pHaving, iParent, pSub->pEList); + p->pHaving = sqlite3ExprAnd(db, p->pHaving, + sqlite3ExprDup(db, pSub->pHaving)); assert( p->pGroupBy==0 ); - p->pGroupBy = sqlite3ExprListDup(pSub->pGroupBy); + p->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy); }else{ - substExpr(p->pWhere, iParent, pSub->pEList); - p->pWhere = sqlite3ExprAnd(p->pWhere, pWhere); + substExpr(db, p->pWhere, iParent, pSub->pEList); + p->pWhere = sqlite3ExprAnd(db, p->pWhere, pWhere); } /* The flattened query is distinct if either the inner or the @@ -2571,7 +2602,8 @@ static int processOrderGroupBy( CollSeq *pColl = pE->pColl; int flags = pE->flags & EP_ExpCollate; sqlite3ExprDelete(pE); - pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr); + pE = sqlite3ExprDup(pParse->db, pEList->a[iCol-1].pExpr); + pOrderBy->a[i].pExpr = pE; if( pColl && flags ){ pE->pColl = pColl; pE->flags |= flags; @@ -2690,7 +2722,7 @@ int sqlite3SelectResolve( } } - if( sqlite3MallocFailed() ){ + if( pParse->db->mallocFailed ){ return SQLITE_NOMEM; } @@ -2897,8 +2929,10 @@ int sqlite3Select( int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ + sqlite3 *db; /* The database connection */ - if( p==0 || sqlite3MallocFailed() || pParse->nErr ){ + db = pParse->db; + if( p==0 || db->mallocFailed || pParse->nErr ){ return 1; } if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; @@ -2985,7 +3019,7 @@ int sqlite3Select( }else{ needRestoreContext = 0; } -#if SQLITE_MAX_EXPR_DEPTH>0 +#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 /* Increment Parse.nHeight by the height of the largest expression ** tree refered to by this, the parent select. The child select ** may contain expression trees of at most @@ -2997,7 +3031,7 @@ int sqlite3Select( #endif sqlite3Select(pParse, pItem->pSelect, SRT_EphemTab, pItem->iCursor, p, i, &isAgg, 0); -#if SQLITE_MAX_EXPR_DEPTH>0 +#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 pParse->nHeight -= sqlite3SelectExprHeight(p); #endif if( needRestoreContext ){ @@ -3027,7 +3061,7 @@ int sqlite3Select( */ #ifndef SQLITE_OMIT_VIEW if( pParent && pParentAgg && - flattenSubquery(pParent, parentTab, *pParentAgg, isAgg) ){ + flattenSubquery(db, pParent, parentTab, *pParentAgg, isAgg) ){ if( isAgg ) *pParentAgg = 1; goto select_end; } @@ -3154,7 +3188,7 @@ int sqlite3Select( goto select_end; } } - if( sqlite3MallocFailed() ) goto select_end; + if( db->mallocFailed ) goto select_end; /* Processing for aggregates with GROUP BY is very different and ** much more complex tha aggregates without a GROUP BY. @@ -3403,8 +3437,8 @@ select_end: generateColumnNames(pParse, pTabList, pEList); } - sqliteFree(sAggInfo.aCol); - sqliteFree(sAggInfo.aFunc); + sqlite3_free(sAggInfo.aCol); + sqlite3_free(sAggInfo.aFunc); return rc; } diff --git a/extensions/sqlite/sqlite-source/sqlite3.h b/extensions/sqlite/sqlite-source/sqlite3.h index d569b24c..861263b7 100644 --- a/extensions/sqlite/sqlite-source/sqlite3.h +++ b/extensions/sqlite/sqlite-source/sqlite3.h @@ -43,6 +43,14 @@ extern "C" { #endif + +/* +** Add the ability to override 'extern' +*/ +#ifndef SQLITE_EXTERN +# define SQLITE_EXTERN extern +#endif + /* ** Make sure these symbols where not defined by some previous header ** file. @@ -81,8 +89,8 @@ extern "C" { ** ** See also: [sqlite3_libversion()] and [sqlite3_libversion_number()]. */ -#define SQLITE_VERSION "3.4.1" -#define SQLITE_VERSION_NUMBER 3004001 +#define SQLITE_VERSION "3.5.1" +#define SQLITE_VERSION_NUMBER 3005001 /* ** CAPI3REF: Run-Time Library Version Numbers @@ -100,19 +108,44 @@ extern "C" { ** is provided for DLL users who can only access functions and not ** constants within the DLL. */ -extern const char sqlite3_version[]; +SQLITE_EXTERN const char sqlite3_version[]; const char *sqlite3_libversion(void); int sqlite3_libversion_number(void); +/* +** CAPI3REF: Test To See If The Library Is Threadsafe +** +** This routine returns TRUE (nonzero) if SQLite was compiled with +** all of its mutexes enabled and is thus threadsafe. It returns +** zero if the particular build is for single-threaded operation +** only. +** +** Really all this routine does is return true if SQLite was compiled +** with the -DSQLITE_THREADSAFE=1 option and false if +** compiled with -DSQLITE_THREADSAFE=0. If SQLite uses an +** application-defined mutex subsystem, malloc subsystem, collating +** sequence, VFS, SQL function, progress callback, commit hook, +** extension, or other accessories and these add-ons are not +** threadsafe, then clearly the combination will not be threadsafe +** either. Hence, this routine never reports that the library +** is guaranteed to be threadsafe, only when it is guaranteed not +** to be. +** +** This is an experimental API and may go away or change in future +** releases. +*/ +int sqlite3_threadsafe(void); + /* ** CAPI3REF: Database Connection Handle ** ** Each open SQLite database is represented by pointer to an instance of the ** opaque structure named "sqlite3". It is useful to think of an sqlite3 -** pointer as an object. The [sqlite3_open] interface is its constructor -** and [sqlite3_close] is its destructor. There are many other interfaces -** (such as [sqlite3_prepare_v2], [sqlite3_create_function], and -** [sqlite3_busy_timeout] to name but three) that are methods on this +** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and +** [sqlite3_open_v2()] interfaces are its constructors +** and [sqlite3_close()] is its destructor. There are many other interfaces +** (such as [sqlite3_prepare_v2()], [sqlite3_create_function()], and +** [sqlite3_busy_timeout()] to name but three) that are methods on this ** object. */ typedef struct sqlite3 sqlite3; @@ -137,26 +170,35 @@ typedef struct sqlite3 sqlite3; typedef long long int sqlite_int64; typedef unsigned long long int sqlite_uint64; #endif +typedef sqlite_int64 sqlite3_int64; +typedef sqlite_uint64 sqlite3_uint64; /* ** If compiling for a processor that lacks floating point support, ** substitute integer for floating-point */ #ifdef SQLITE_OMIT_FLOATING_POINT -# define double sqlite_int64 +# define double sqlite3_int64 #endif /* ** CAPI3REF: Closing A Database Connection ** ** Call this function with a pointer to a structure that was previously -** returned from [sqlite3_open()] and the corresponding database will by +** returned from [sqlite3_open()], [sqlite3_open16()], or +** [sqlite3_open_v2()] and the corresponding database will by ** closed. ** ** All SQL statements prepared using [sqlite3_prepare_v2()] or ** [sqlite3_prepare16_v2()] must be destroyed using [sqlite3_finalize()] ** before this routine is called. Otherwise, SQLITE_BUSY is returned and the ** database connection remains open. +** +** Passing this routine a database connection that has already been +** closed results in undefined behavior. If other interfaces that +** reference the same database connection are pending (either in the +** same thread or in different threads) when this routine is called, +** then the behavior is undefined and is almost certainly undesirable. */ int sqlite3_close(sqlite3 *); @@ -181,7 +223,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** invoked once for each row of the query result. This callback ** should normally return 0. If the callback returns a non-zero ** value then the query is aborted, all subsequent SQL statements -** are skipped and the sqlite3_exec() function returns the SQLITE_ABORT. +** are skipped and the sqlite3_exec() function returns the [SQLITE_ABORT]. ** ** The 4th parameter to this interface is an arbitrary pointer that is ** passed through to the callback function as its first parameter. @@ -202,9 +244,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** not while executing the callback) then an appropriate error ** message is written into memory obtained from [sqlite3_malloc()] and ** *errmsg is made to point to that message. The calling function -** is responsible for freeing the memory that holds the error -** message. Use [sqlite3_free()] for this. If errmsg==NULL, -** then no error message is ever written. +** is responsible for freeing the memory using [sqlite3_free()]. +** If errmsg==NULL, then no error message is ever written. ** ** The return value is is SQLITE_OK if there are no errors and ** some other [SQLITE_OK | return code] if there is an error. @@ -254,7 +295,7 @@ int sqlite3_exec( #define SQLITE_EMPTY 16 /* Database is empty */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ -#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */ +#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ #define SQLITE_MISMATCH 20 /* Data type mismatch */ #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ @@ -304,6 +345,382 @@ int sqlite3_exec( #define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8)) #define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8)) #define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) +#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8)) + +/* +** CAPI3REF: Flags For File Open Operations +** +** Combination of the following bit values are used as the +** third argument to the [sqlite3_open_v2()] interface and +** as fourth argument to the xOpen method of the +** [sqlite3_vfs] object. +** +*/ +#define SQLITE_OPEN_READONLY 0x00000001 +#define SQLITE_OPEN_READWRITE 0x00000002 +#define SQLITE_OPEN_CREATE 0x00000004 +#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 +#define SQLITE_OPEN_EXCLUSIVE 0x00000010 +#define SQLITE_OPEN_MAIN_DB 0x00000100 +#define SQLITE_OPEN_TEMP_DB 0x00000200 +#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 +#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 +#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 +#define SQLITE_OPEN_SUBJOURNAL 0x00002000 +#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 + +/* +** CAPI3REF: Device Characteristics +** +** The xDeviceCapabilities method of the [sqlite3_io_methods] +** object returns an integer which is a vector of the following +** bit values expressing I/O characteristics of the mass storage +** device that holds the file that the [sqlite3_io_methods] +** refers to. +** +** The SQLITE_IOCAP_ATOMIC property means that all writes of +** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values +** mean that writes of blocks that are nnn bytes in size and +** are aligned to an address which is an integer multiple of +** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means +** that when data is appended to a file, the data is appended +** first then the size of the file is extended, never the other +** way around. The SQLITE_IOCAP_SEQUENTIAL property means that +** information is written to disk in the same order as calls +** to xWrite(). +*/ +#define SQLITE_IOCAP_ATOMIC 0x00000001 +#define SQLITE_IOCAP_ATOMIC512 0x00000002 +#define SQLITE_IOCAP_ATOMIC1K 0x00000004 +#define SQLITE_IOCAP_ATOMIC2K 0x00000008 +#define SQLITE_IOCAP_ATOMIC4K 0x00000010 +#define SQLITE_IOCAP_ATOMIC8K 0x00000020 +#define SQLITE_IOCAP_ATOMIC16K 0x00000040 +#define SQLITE_IOCAP_ATOMIC32K 0x00000080 +#define SQLITE_IOCAP_ATOMIC64K 0x00000100 +#define SQLITE_IOCAP_SAFE_APPEND 0x00000200 +#define SQLITE_IOCAP_SEQUENTIAL 0x00000400 + +/* +** CAPI3REF: File Locking Levels +** +** SQLite uses one of the following integer values as the second +** argument to calls it makes to the xLock() and xUnlock() methods +** of an [sqlite3_io_methods] object. +*/ +#define SQLITE_LOCK_NONE 0 +#define SQLITE_LOCK_SHARED 1 +#define SQLITE_LOCK_RESERVED 2 +#define SQLITE_LOCK_PENDING 3 +#define SQLITE_LOCK_EXCLUSIVE 4 + +/* +** CAPI3REF: Synchronization Type Flags +** +** When SQLite invokes the xSync() method of an [sqlite3_io_methods] +** object it uses a combination of the following integer values as +** the second argument. +** +** When the SQLITE_SYNC_DATAONLY flag is used, it means that the +** sync operation only needs to flush data to mass storage. Inode +** information need not be flushed. The SQLITE_SYNC_NORMAL means +** to use normal fsync() semantics. The SQLITE_SYNC_FULL flag means +** to use Mac OS-X style fullsync instead of fsync(). +*/ +#define SQLITE_SYNC_NORMAL 0x00002 +#define SQLITE_SYNC_FULL 0x00003 +#define SQLITE_SYNC_DATAONLY 0x00010 + + +/* +** CAPI3REF: OS Interface Open File Handle +** +** An [sqlite3_file] object represents an open file in the OS +** interface layer. Individual OS interface implementations will +** want to subclass this object by appending additional fields +** for their own use. The pMethods entry is a pointer to an +** [sqlite3_io_methods] object that defines methods for performing +** I/O operations on the open file. +*/ +typedef struct sqlite3_file sqlite3_file; +struct sqlite3_file { + const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ +}; + +/* +** CAPI3REF: OS Interface File Virtual Methods Object +** +** Every file opened by the [sqlite3_vfs] xOpen method contains a pointer to +** an instance of the this object. This object defines the +** methods used to perform various operations against the open file. +** +** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or +** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). +* The second choice is an +** OS-X style fullsync. The SQLITE_SYNC_DATA flag may be ORed in to +** indicate that only the data of the file and not its inode needs to be +** synced. +** +** The integer values to xLock() and xUnlock() are one of +**
    +**
  • [SQLITE_LOCK_NONE], +**
  • [SQLITE_LOCK_SHARED], +**
  • [SQLITE_LOCK_RESERVED], +**
  • [SQLITE_LOCK_PENDING], or +**
  • [SQLITE_LOCK_EXCLUSIVE]. +**
+** xLock() increases the lock. xUnlock() decreases the lock. +** The xCheckReservedLock() method looks +** to see if any database connection, either in this +** process or in some other process, is holding an RESERVED, +** PENDING, or EXCLUSIVE lock on the file. It returns true +** if such a lock exists and false if not. +** +** The xFileControl() method is a generic interface that allows custom +** VFS implementations to directly control an open file using the +** [sqlite3_file_control()] interface. The second "op" argument +** is an integer opcode. The third +** argument is a generic pointer which is intended to be a pointer +** to a structure that may contain arguments or space in which to +** write return values. Potential uses for xFileControl() might be +** functions to enable blocking locks with timeouts, to change the +** locking strategy (for example to use dot-file locks), to inquire +** about the status of a lock, or to break stale locks. The SQLite +** core reserves opcodes less than 100 for its own use. +** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available. +** Applications that define a custom xFileControl method should use opcodes +** greater than 100 to avoid conflicts. +** +** The xSectorSize() method returns the sector size of the +** device that underlies the file. The sector size is the +** minimum write that can be performed without disturbing +** other bytes in the file. The xDeviceCharacteristics() +** method returns a bit vector describing behaviors of the +** underlying device: +** +**
    +**
  • [SQLITE_IOCAP_ATOMIC] +**
  • [SQLITE_IOCAP_ATOMIC512] +**
  • [SQLITE_IOCAP_ATOMIC1K] +**
  • [SQLITE_IOCAP_ATOMIC2K] +**
  • [SQLITE_IOCAP_ATOMIC4K] +**
  • [SQLITE_IOCAP_ATOMIC8K] +**
  • [SQLITE_IOCAP_ATOMIC16K] +**
  • [SQLITE_IOCAP_ATOMIC32K] +**
  • [SQLITE_IOCAP_ATOMIC64K] +**
  • [SQLITE_IOCAP_SAFE_APPEND] +**
  • [SQLITE_IOCAP_SEQUENTIAL] +**
+** +** The SQLITE_IOCAP_ATOMIC property means that all writes of +** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values +** mean that writes of blocks that are nnn bytes in size and +** are aligned to an address which is an integer multiple of +** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means +** that when data is appended to a file, the data is appended +** first then the size of the file is extended, never the other +** way around. The SQLITE_IOCAP_SEQUENTIAL property means that +** information is written to disk in the same order as calls +** to xWrite(). +*/ +typedef struct sqlite3_io_methods sqlite3_io_methods; +struct sqlite3_io_methods { + int iVersion; + int (*xClose)(sqlite3_file*); + int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); + int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); + int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); + int (*xSync)(sqlite3_file*, int flags); + int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); + int (*xLock)(sqlite3_file*, int); + int (*xUnlock)(sqlite3_file*, int); + int (*xCheckReservedLock)(sqlite3_file*); + int (*xFileControl)(sqlite3_file*, int op, void *pArg); + int (*xSectorSize)(sqlite3_file*); + int (*xDeviceCharacteristics)(sqlite3_file*); + /* Additional methods may be added in future releases */ +}; + +/* +** CAPI3REF: Standard File Control Opcodes +** +** These integer constants are opcodes for the xFileControl method +** of the [sqlite3_io_methods] object and to the [sqlite3_file_control()] +** interface. +** +** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This +** opcode cases the xFileControl method to write the current state of +** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], +** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) +** into an integer that the pArg argument points to. This capability +** is used during testing and only needs to be supported when SQLITE_TEST +** is defined. +*/ +#define SQLITE_FCNTL_LOCKSTATE 1 + +/* +** CAPI3REF: Mutex Handle +** +** The mutex module within SQLite defines [sqlite3_mutex] to be an +** abstract type for a mutex object. The SQLite core never looks +** at the internal representation of an [sqlite3_mutex]. It only +** deals with pointers to the [sqlite3_mutex] object. +** +** Mutexes are created using [sqlite3_mutex_alloc()]. +*/ +typedef struct sqlite3_mutex sqlite3_mutex; + +/* +** CAPI3REF: OS Interface Object +** +** An instance of this object defines the interface between the +** SQLite core and the underlying operating system. The "vfs" +** in the name of the object stands for "virtual file system". +** +** The iVersion field is initially 1 but may be larger for future +** versions of SQLite. Additional fields may be appended to this +** object when the iVersion value is increased. +** +** The szOsFile field is the size of the subclassed [sqlite3_file] +** structure used by this VFS. mxPathname is the maximum length of +** a pathname in this VFS. +** +** Registered vfs modules are kept on a linked list formed by +** the pNext pointer. The [sqlite3_vfs_register()] +** and [sqlite3_vfs_unregister()] interfaces manage this list +** in a thread-safe way. The [sqlite3_vfs_find()] interface +** searches the list. +** +** The pNext field is the only fields in the sqlite3_vfs +** structure that SQLite will ever modify. SQLite will only access +** or modify this field while holding a particular static mutex. +** The application should never modify anything within the sqlite3_vfs +** object once the object has been registered. +** +** The zName field holds the name of the VFS module. The name must +** be unique across all VFS modules. +** +** SQLite will guarantee that the zFilename string passed to +** xOpen() is a full pathname as generated by xFullPathname() and +** that the string will be valid and unchanged until xClose() is +** called. So the [sqlite3_file] can store a pointer to the +** filename if it needs to remember the filename for some reason. +** +** The flags argument to xOpen() is a copy of the flags argument +** to [sqlite3_open_v2()]. If [sqlite3_open()] or [sqlite3_open16()] +** is used, then flags is [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. +** If xOpen() opens a file read-only then it sets *pOutFlags to +** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be +** set. +** +** SQLite will also add one of the following flags to the xOpen() +** call, depending on the object being opened: +** +**
    +**
  • [SQLITE_OPEN_MAIN_DB] +**
  • [SQLITE_OPEN_MAIN_JOURNAL] +**
  • [SQLITE_OPEN_TEMP_DB] +**
  • [SQLITE_OPEN_TEMP_JOURNAL] +**
  • [SQLITE_OPEN_TRANSIENT_DB] +**
  • [SQLITE_OPEN_SUBJOURNAL] +**
  • [SQLITE_OPEN_MASTER_JOURNAL] +**
+** +** The file I/O implementation can use the object type flags to +** changes the way it deals with files. For example, an application +** that does not care about crash recovery or rollback, might make +** the open of a journal file a no-op. Writes to this journal are +** also a no-op. Any attempt to read the journal return SQLITE_IOERR. +** Or the implementation might recognize the a database file will +** be doing page-aligned sector reads and writes in a random order +** and set up its I/O subsystem accordingly. +** +** SQLite might also add one of the following flags to the xOpen +** method: +** +**
    +**
  • [SQLITE_OPEN_DELETEONCLOSE] +**
  • [SQLITE_OPEN_EXCLUSIVE] +**
+** +** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be +** deleted when it is closed. This will always be set for TEMP +** databases and journals and for subjournals. The +** [SQLITE_OPEN_EXCLUSIVE] flag means the file should be opened +** for exclusive access. This flag is set for all files except +** for the main database file. +** +** Space to hold the [sqlite3_file] structure passed as the third +** argument to xOpen is allocated by caller (the SQLite core). +** szOsFile bytes are allocated for this object. The xOpen method +** fills in the allocated space. +** +** The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] +** to test for the existance of a file, +** or [SQLITE_ACCESS_READWRITE] to test to see +** if a file is readable and writable, or [SQLITE_ACCESS_READ] +** to test to see if a file is at least readable. The file can be a +** directory. +** +** SQLite will always allocate at least mxPathname+1 byte for +** the output buffers for xGetTempname and xFullPathname. The exact +** size of the output buffer is also passed as a parameter to both +** methods. If the output buffer is not large enough, SQLITE_CANTOPEN +** should be returned. As this is handled as a fatal error by SQLite, +** vfs implementations should endevour to prevent this by setting +** mxPathname to a sufficiently large value. +** +** The xRandomness(), xSleep(), and xCurrentTime() interfaces +** are not strictly a part of the filesystem, but they are +** included in the VFS structure for completeness. +** The xRandomness() function attempts to return nBytes bytes +** of good-quality randomness into zOut. The return value is +** the actual number of bytes of randomness obtained. The +** xSleep() method cause the calling thread to sleep for at +** least the number of microseconds given. The xCurrentTime() +** method returns a Julian Day Number for the current date and +** time. +*/ +typedef struct sqlite3_vfs sqlite3_vfs; +struct sqlite3_vfs { + int iVersion; /* Structure version number */ + int szOsFile; /* Size of subclassed sqlite3_file */ + int mxPathname; /* Maximum file pathname length */ + sqlite3_vfs *pNext; /* Next registered VFS */ + const char *zName; /* Name of this virtual file system */ + void *pAppData; /* Pointer to application-specific data */ + int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, + int flags, int *pOutFlags); + int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); + int (*xAccess)(sqlite3_vfs*, const char *zName, int flags); + int (*xGetTempname)(sqlite3_vfs*, int nOut, char *zOut); + int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); + void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); + void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); + void *(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol); + void (*xDlClose)(sqlite3_vfs*, void*); + int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); + int (*xSleep)(sqlite3_vfs*, int microseconds); + int (*xCurrentTime)(sqlite3_vfs*, double*); + /* New fields may be appended in figure versions. The iVersion + ** value will increment whenever this happens. */ +}; + +/* +** CAPI3REF: Flags for the xAccess VFS method +** +** These integer constants can be used as the third parameter to +** the xAccess method of an [sqlite3_vfs] object. They determine +** the kind of what kind of permissions the xAccess method is +** looking for. With SQLITE_ACCESS_EXISTS, the xAccess method +** simply checks to see if the file exists. With SQLITE_ACCESS_READWRITE, +** the xAccess method checks to see if the file is both readable +** and writable. With SQLITE_ACCESS_READ the xAccess method +** checks to see if the file is readable. +*/ +#define SQLITE_ACCESS_EXISTS 0 +#define SQLITE_ACCESS_READWRITE 1 +#define SQLITE_ACCESS_READ 2 /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -341,8 +758,12 @@ int sqlite3_extended_result_codes(sqlite3*, int onoff); ** is running. But once the trigger terminates, the value returned ** by this routine reverts to the last value inserted before the ** trigger fired. +** +** If another thread does a new insert on the same database connection +** while this routine is running and thus changes the last insert rowid, +** then the return value of this routine is undefined. */ -sqlite_int64 sqlite3_last_insert_rowid(sqlite3*); +sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); /* ** CAPI3REF: Count The Number Of Rows Modified @@ -374,6 +795,10 @@ sqlite_int64 sqlite3_last_insert_rowid(sqlite3*); ** zero regardless of the number of elements that were originally in the ** table. To get an accurate count of the number of rows deleted, use ** "DELETE FROM table WHERE 1" instead. +** +** If another thread makes changes on the same database connection +** while this routine is running then the return value of this routine +** is undefined. */ int sqlite3_changes(sqlite3*); @@ -385,7 +810,7 @@ int sqlite3_changes(sqlite3*); ** was opened. This includes UPDATE, INSERT and DELETE statements executed ** as part of trigger programs. All changes are counted as soon as the ** statement that makes them is completed (when the statement handle is -** passed to [sqlite3_reset()] or [sqlite_finalise()]). +** passed to [sqlite3_reset()] or [sqlite3_finalize()]). ** ** See also the [sqlite3_change()] interface. ** @@ -396,6 +821,10 @@ int sqlite3_changes(sqlite3*); ** zero regardless of the number of elements that were originally in the ** table. To get an accurate count of the number of rows deleted, use ** "DELETE FROM table WHERE 1" instead. +** +** If another thread makes changes on the same database connection +** while this routine is running then the return value of this routine +** is undefined. */ int sqlite3_total_changes(sqlite3*); @@ -409,7 +838,9 @@ int sqlite3_total_changes(sqlite3*); ** immediately. ** ** It is safe to call this routine from a thread different from the -** thread that is currently running the database operation. +** thread that is currently running the database operation. But it +** is not safe to call this routine with a database connection that +** is closed or might close before sqlite3_interrupt() returns. ** ** The SQL operation that is interrupted will return [SQLITE_INTERRUPT]. ** If an interrupted operation was an update that is inside an @@ -502,6 +933,13 @@ int sqlite3_complete16(const void *sql); ** connection. Setting a new busy handler clears any previous one. ** Note that calling [sqlite3_busy_timeout()] will also set or clear ** the busy handler. +** +** When operating in [sqlite3_enable_shared_cache | shared cache mode], +** only a single busy handler can be defined for each database file. +** So if two database connections share a single cache, then changing +** the busy handler on one connection will also change the busy +** handler in the other connection. The busy handler is invoked +** in the thread that was running when the SQLITE_BUSY was hit. */ int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); @@ -535,27 +973,27 @@ int sqlite3_busy_timeout(sqlite3*, int ms); ** ** As an example, suppose the query result where this table: ** -**
+** 
 **        Name        | Age
 **        -----------------------
 **        Alice       | 43
 **        Bob         | 28
 **        Cindy       | 21
-** 
+**
** ** If the 3rd argument were &azResult then after the function returns ** azResult will contain the following data: ** -**
-**        azResult[0] = "Name";
-**        azResult[1] = "Age";
-**        azResult[2] = "Alice";
-**        azResult[3] = "43";
-**        azResult[4] = "Bob";
-**        azResult[5] = "28";
-**        azResult[6] = "Cindy";
-**        azResult[7] = "21";
-** 
+**
+**        azResult[0] = "Name";
+**        azResult[1] = "Age";
+**        azResult[2] = "Alice";
+**        azResult[3] = "43";
+**        azResult[4] = "Bob";
+**        azResult[5] = "28";
+**        azResult[6] = "Cindy";
+**        azResult[7] = "21";
+** 
** ** Notice that there is an extra row of data containing the column ** headers. But the *nrow return value is still 3. *ncolumn is @@ -588,7 +1026,7 @@ void sqlite3_free_table(char **result); ** from the standard C library. ** ** The sqlite3_mprintf() and sqlite3_vmprintf() routines write their -** results into memory obtained from [sqlite_malloc()]. +** results into memory obtained from [sqlite3_malloc()]. ** The strings returned by these two routines should be ** released by [sqlite3_free()]. Both routines return a ** NULL pointer if [sqlite3_malloc()] is unable to allocate enough @@ -616,7 +1054,7 @@ void sqlite3_free_table(char **result); ** These routines all implement some additional formatting ** options that are useful for constructing SQL statements. ** All of the usual printf formatting options apply. In addition, there -** is are "%q" and "%Q" options. +** is are "%q", "%Q", and "%z" options. ** ** The %q option works like %s in that it substitutes a null-terminated ** string from the argument list. But %q also doubles every '\'' character. @@ -669,24 +1107,118 @@ void sqlite3_free_table(char **result); ** ** The code above will render a correct SQL statement in the zSQL ** variable even if the zText variable is a NULL pointer. +** +** The "%z" formatting option works exactly like "%s" with the +** addition that after the string has been read and copied into +** the result, [sqlite3_free()] is called on the input string. */ char *sqlite3_mprintf(const char*,...); char *sqlite3_vmprintf(const char*, va_list); char *sqlite3_snprintf(int,char*,const char*, ...); /* -** CAPI3REF: Memory Allocation Functions +** CAPI3REF: Memory Allocation Subsystem ** -** SQLite uses its own memory allocator. On some installations, this -** memory allocator is identical to the standard malloc()/realloc()/free() -** and can be used interchangable. On others, the implementations are -** different. For maximum portability, it is best not to mix calls -** to the standard malloc/realloc/free with the sqlite versions. +** The SQLite core uses these three routines for all of its own +** internal memory allocation needs. (See the exception below.) +** The default implementation +** of the memory allocation subsystem uses the malloc(), realloc() +** and free() provided by the standard C library. However, if +** SQLite is compiled with the following C preprocessor macro +** +**
SQLITE_OMIT_MEMORY_ALLOCATION
+** +** then no implementation is provided for these routines by +** SQLite. The application that links against SQLite is +** expected to provide its own implementation. If the application +** does provide its own implementation for these routines, then +** it must also provide an implementations for +** [sqlite3_memory_alarm()], [sqlite3_memory_used()], and +** [sqlite3_memory_highwater()]. The alternative implementations +** for these last three routines need not actually work, but +** stub functions at least are needed to statisfy the linker. +** SQLite never calls [sqlite3_memory_highwater()] itself, but +** the symbol is included in a table as part of the +** [sqlite3_load_extension()] interface. The +** [sqlite3_memory_alarm()] and [sqlite3_memory_used()] interfaces +** are called by [sqlite3_soft_heap_limit()] and working implementations +** of both routines must be provided if [sqlite3_soft_heap_limit()] +** is to operate correctly. +** +** Exception: The windows OS interface layer calls +** the system malloc() and free() directly when converting +** filenames between the UTF-8 encoding used by SQLite +** and whatever filename encoding is used by the particular windows +** installation. Memory allocation errors are detected, but +** they are reported back as [SQLITE_CANTOPEN] or +** [SQLITE_IOERR] rather than [SQLITE_NOMEM]. */ void *sqlite3_malloc(int); void *sqlite3_realloc(void*, int); void sqlite3_free(void*); +/* +** CAPI3REF: Memory Allocator Statistics +** +** In addition to the basic three allocation routines +** [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()], +** the memory allocation subsystem included with the SQLite +** sources provides the interfaces shown below. +** +** The first of these two routines returns the amount of memory +** currently outstanding (malloced but not freed). The second +** returns the largest instantaneous amount of outstanding +** memory. The highwater mark is reset if the argument is +** true. +** +** The implementation of these routines in the SQLite core +** is omitted if the application is compiled with the +** SQLITE_OMIT_MEMORY_ALLOCATION macro defined. In that case, +** the application that links SQLite must provide its own +** alternative implementation. See the documentation on +** [sqlite3_malloc()] for additional information. +*/ +sqlite3_int64 sqlite3_memory_used(void); +sqlite3_int64 sqlite3_memory_highwater(int resetFlag); + +/* +** CAPI3REF: Memory Allocation Alarms +** +** The [sqlite3_memory_alarm] routine is used to register +** a callback on memory allocation events. +** +** This routine registers or clears a callbacks that fires when +** the amount of memory allocated exceeds iThreshold. Only +** a single callback can be registered at a time. Each call +** to [sqlite3_memory_alarm()] overwrites the previous callback. +** The callback is disabled by setting xCallback to a NULL +** pointer. +** +** The parameters to the callback are the pArg value, the +** amount of memory currently in use, and the size of the +** allocation that provoked the callback. The callback will +** presumably invoke [sqlite3_free()] to free up memory space. +** The callback may invoke [sqlite3_malloc()] or [sqlite3_realloc()] +** but if it does, no additional callbacks will be invoked by +** the recursive calls. +** +** The [sqlite3_soft_heap_limit()] interface works by registering +** a memory alarm at the soft heap limit and invoking +** [sqlite3_release_memory()] in the alarm callback. Application +** programs should not attempt to use the [sqlite3_memory_alarm()] +** interface because doing so will interfere with the +** [sqlite3_soft_heap_limit()] module. This interface is exposed +** only so that applications can provide their own +** alternative implementation when the SQLite core is +** compiled with SQLITE_OMIT_MEMORY_ALLOCATION. +*/ +int sqlite3_memory_alarm( + void(*xCallback)(void *pArg, sqlite3_int64 used, int N), + void *pArg, + sqlite3_int64 iThreshold +); + + /* ** CAPI3REF: Compile-Time Authorization Callbacks *** @@ -827,7 +1359,7 @@ int sqlite3_set_authorizer( */ void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); void *sqlite3_profile(sqlite3*, - void(*xProfile)(void*,const char*,sqlite_uint64), void*); + void(*xProfile)(void*,const char*,sqlite3_uint64), void*); /* ** CAPI3REF: Query Progress Callbacks @@ -866,25 +1398,65 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** CAPI3REF: Opening A New Database Connection ** ** Open the sqlite database file "filename". The "filename" is UTF-8 -** encoded for sqlite3_open() and UTF-16 encoded in the native byte order -** for sqlite3_open16(). An [sqlite3*] handle is returned in *ppDb, even +** encoded for [sqlite3_open()] and [sqlite3_open_v2()] and UTF-16 encoded +** in the native byte order for [sqlite3_open16()]. +** An [sqlite3*] handle is returned in *ppDb, even ** if an error occurs. If the database is opened (or created) successfully, -** then SQLITE_OK is returned. Otherwise an error code is returned. The -** sqlite3_errmsg() or sqlite3_errmsg16() routines can be used to obtain +** then [SQLITE_OK] is returned. Otherwise an error code is returned. The +** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain ** an English language description of the error. ** -** If the database file does not exist, then a new database will be created -** as needed. The default encoding for the database will be UTF-8 if -** sqlite3_open() is called and UTF-16 if sqlite3_open16 is used. +** The default encoding for the database will be UTF-8 if +** [sqlite3_open()] or [sqlite3_open_v2()] is called and +** UTF-16 if [sqlite3_open16()] is used. ** ** Whether or not an error occurs when it is opened, resources associated ** with the [sqlite3*] handle should be released by passing it to -** sqlite3_close() when it is no longer required. +** [sqlite3_close()] when it is no longer required. ** -** Note to windows users: The encoding used for the filename argument -** of sqlite3_open() must be UTF-8, not whatever codepage is currently -** defined. Filenames containing international characters must be converted -** to UTF-8 prior to passing them into sqlite3_open(). +** The [sqlite3_open_v2()] interface works like [sqlite3_open()] except that +** provides two additional parameters for additional control over the +** new database connection. The flags parameter can be one of: +** +**
    +**
  1. [SQLITE_OPEN_READONLY] +**
  2. [SQLITE_OPEN_READWRITE] +**
  3. [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE] +**
+** +** The first value opens the database read-only. If the database does +** not previously exist, an error is returned. The second option opens +** the database for reading and writing if possible, or reading only if +** if the file is write protected. In either case the database must already +** exist or an error is returned. The third option opens the database +** for reading and writing and creates it if it does not already exist. +** The third options is behavior that is always used for [sqlite3_open()] +** and [sqlite3_open16()]. +** +** If the filename is ":memory:", then an private +** in-memory database is created for the connection. This in-memory +** database will vanish when the database connection is closed. Future +** version of SQLite might make use of additional special filenames +** that begin with the ":" character. It is recommended that +** when a database filename really does begin with +** ":" that you prefix the filename with a pathname like "./" to +** avoid ambiguity. +** +** If the filename is an empty string, then a private temporary +** on-disk database will be created. This private database will be +** automatically deleted as soon as the database connection is closed. +** +** The fourth parameter to sqlite3_open_v2() is the name of the +** [sqlite3_vfs] object that defines the operating system +** interface that the new database connection should use. If the +** fourth parameter is a NULL pointer then the default [sqlite3_vfs] +** object is used. +** +** Note to windows users: The encoding used for the filename argument +** of [sqlite3_open()] and [sqlite3_open_v2()] must be UTF-8, not whatever +** codepage is currently defined. Filenames containing international +** characters must be converted to UTF-8 prior to passing them into +** [sqlite3_open()] or [sqlite3_open_v2()]. */ int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ @@ -894,6 +1466,12 @@ int sqlite3_open16( const void *filename, /* Database filename (UTF-16) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); +int sqlite3_open_v2( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb, /* OUT: SQLite db handle */ + int flags, /* Flags */ + const char *zVfs /* Name of VFS module to use */ +); /* ** CAPI3REF: Error Codes And Messages @@ -905,7 +1483,7 @@ int sqlite3_open16( ** most recent API call succeeded, the return value from sqlite3_errcode() ** is undefined. ** -** The sqlite3_errmsg() and sqlite3_errmsg16() return English-langauge +** The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF8 or UTF16 respectively. ** Memory to hold the error message string is managed internally. The ** string may be overwritten or deallocated by subsequent calls to SQLite @@ -916,8 +1494,11 @@ int sqlite3_open16( ** (overwriting the previous values). Note that calls to [sqlite3_errcode()], ** [sqlite3_errmsg()], and [sqlite3_errmsg16()] themselves do not affect the ** results of future invocations. Calls to API routines that do not return -** an error code (examples: [sqlite3_data_count()] or [sqlite3_mprintf()]) do -** not change the error code returned by this routine. +** an error code (example: [sqlite3_data_count()]) do not +** change the error code returned by this routine. Interfaces that are +** not associated with a specific database connection (examples: +** [sqlite3_mprintf()] or [sqlite3_enable_shared_cache()] do not change +** the return code. ** ** Assuming no other intervening sqlite3_* API calls are made, the error ** code returned by this function is associated with the same error as @@ -959,7 +1540,8 @@ typedef struct sqlite3_stmt sqlite3_stmt; ** program using one of these routines. ** ** The first argument "db" is an [sqlite3 | SQLite database handle] -** obtained from a prior call to [sqlite3_open()] or [sqlite3_open16()]. +** obtained from a prior call to [sqlite3_open()], [sqlite3_open_v2()] +** or [sqlite3_open16()]. ** The second argument "zSql" is the statement to be compiled, encoded ** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() ** interfaces uses UTF-8 and sqlite3_prepare16() and sqlite3_prepare16_v2() @@ -1127,7 +1709,8 @@ typedef struct sqlite3_context sqlite3_context; ** (just an integer to hold it size) while it is being processed. ** Zeroblobs are intended to serve as place-holders for BLOBs whose ** content is later written using -** [sqlite3_blob_open | increment BLOB I/O] routines. +** [sqlite3_blob_open | increment BLOB I/O] routines. A negative +** value for the zeroblob results in a zero-length BLOB. ** ** The sqlite3_bind_*() routines must be called after ** [sqlite3_prepare_v2()] (and its variants) or [sqlite3_reset()] and @@ -1144,7 +1727,7 @@ typedef struct sqlite3_context sqlite3_context; int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); int sqlite3_bind_double(sqlite3_stmt*, int, double); int sqlite3_bind_int(sqlite3_stmt*, int, int); -int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite_int64); +int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); int sqlite3_bind_null(sqlite3_stmt*, int); int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); @@ -1164,6 +1747,10 @@ int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); ** are used (where NNN is an integer) then there might be gaps in the ** numbering and the value returned by this interface is the index of the ** host parameter with the largest index value. +** +** The prepared statement must not be [sqlite3_finalize | finalized] +** prior to this routine returnning. Otherwise the results are undefined +** and probably undesirable. */ int sqlite3_bind_parameter_count(sqlite3_stmt*); @@ -1223,14 +1810,18 @@ int sqlite3_column_count(sqlite3_stmt *pStmt); ** in the result set of a SELECT statement. The sqlite3_column_name() ** interface returns a pointer to a UTF8 string and sqlite3_column_name16() ** returns a pointer to a UTF16 string. The first parameter is the -** [sqlite_stmt | prepared statement] that implements the SELECT statement. +** [sqlite3_stmt | prepared statement] that implements the SELECT statement. ** The second parameter is the column number. The left-most column is ** number 0. ** ** The returned string pointer is valid until either the -** [sqlite_stmt | prepared statement] is destroyed by [sqlite3_finalize()] +** [sqlite3_stmt | prepared statement] is destroyed by [sqlite3_finalize()] ** or until the next call sqlite3_column_name() or sqlite3_column_name16() ** on the same column. +** +** If sqlite3_malloc() fails during the processing of either routine +** (for example during a conversion from UTF-8 to UTF-16) then a +** NULL pointer is returned. */ const char *sqlite3_column_name(sqlite3_stmt*, int N); const void *sqlite3_column_name16(sqlite3_stmt*, int N); @@ -1268,6 +1859,10 @@ const void *sqlite3_column_name16(sqlite3_stmt*, int N); ** ** These APIs are only available if the library was compiled with the ** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined. +** +** If two or more threads call one or more of these routines against the same +** prepared statement and column at the same time then the results are +** undefined. */ const char *sqlite3_column_database_name(sqlite3_stmt*,int); const void *sqlite3_column_database_name16(sqlite3_stmt*,int); @@ -1354,11 +1949,11 @@ const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** With the legacy interface, a more specific error code (example: ** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) ** can be obtained by calling [sqlite3_reset()] on the -** [sqlite_stmt | prepared statement]. In the "v2" interface, +** [sqlite3_stmt | prepared statement]. In the "v2" interface, ** the more specific error code is returned directly by sqlite3_step(). ** ** [SQLITE_MISUSE] means that the this routine was called inappropriately. -** Perhaps it was called on a [sqlite_stmt | prepared statement] that has +** Perhaps it was called on a [sqlite3_stmt | prepared statement] that has ** already been [sqlite3_finalize | finalized] or on one that had ** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could ** be the case that the same database connection is being used by two or @@ -1389,7 +1984,7 @@ int sqlite3_step(sqlite3_stmt*); ** will return the same value as the [sqlite3_column_count()] function. ** After [sqlite3_step()] has returned an [SQLITE_DONE], [SQLITE_BUSY], or ** a [SQLITE_ERROR | error code], or before [sqlite3_step()] has been -** called on the [sqlite_stmt | prepared statement] for the first time, +** called on the [sqlite3_stmt | prepared statement] for the first time, ** this routine returns zero. */ int sqlite3_data_count(sqlite3_stmt *pStmt); @@ -1428,17 +2023,27 @@ int sqlite3_data_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Results Values From A Query ** -** These routines return information about the information -** in a single column of the current result row of a query. In every +** These routines return information about +** a single column of the current result row of a query. In every ** case the first argument is a pointer to the ** [sqlite3_stmt | SQL statement] that is being -** evaluate (the [sqlite_stmt*] that was returned from +** evaluated (the [sqlite3_stmt*] that was returned from ** [sqlite3_prepare_v2()] or one of its variants) and ** the second argument is the index of the column for which information -** should be returned. The left-most column has an index of 0. +** should be returned. The left-most column of the result set +** has an index of 0. ** ** If the SQL statement is not currently point to a valid row, or if the -** the column index is out of range, the result is undefined. +** the column index is out of range, the result is undefined. +** These routines may only be called when the most recent call to +** [sqlite3_step()] has returned [SQLITE_ROW] and neither +** [sqlite3_reset()] nor [sqlite3_finalize()] has been call subsequently. +** If any of these routines are called after [sqlite3_reset()] or +** [sqlite3_finalize()] or after [sqlite3_step()] has returned +** something other than [SQLITE_ROW], the results are undefined. +** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()] +** are called from a different thread while any of these routines +** are pending, then the results are undefined. ** ** The sqlite3_column_type() routine returns ** [SQLITE_INTEGER | datatype code] for the initial data type @@ -1461,6 +2066,11 @@ int sqlite3_data_count(sqlite3_stmt *pStmt); ** of the string. For clarity: the value returned is the number of ** bytes in the string, not the number of characters. ** +** Strings returned by sqlite3_column_text() and sqlite3_column_text16(), +** even zero-length strings, are always zero terminated. The return +** value from sqlite3_column_blob() for a zero-length blob is an arbitrary +** pointer, possibly even a NULL pointer. +** ** The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes() ** but leaves the result in UTF-16 instead of UTF-8. ** The zero terminator is not included in this count. @@ -1473,8 +2083,7 @@ int sqlite3_data_count(sqlite3_stmt *pStmt); ** **
** -**
Internal Requested -**
Type Type Conversion +**
Internal
Type
Requested
Type
Conversion ** **
NULL INTEGER Result is 0 **
NULL FLOAT Result is 0.0 @@ -1542,13 +2151,26 @@ int sqlite3_data_count(sqlite3_stmt *pStmt); ** find the size of the result. Do not mix call to sqlite3_column_text() or ** sqlite3_column_blob() with calls to sqlite3_column_bytes16(). And do not ** mix calls to sqlite3_column_text16() with calls to sqlite3_column_bytes(). +** +** The pointers returned are valid until a type conversion occurs as +** described above, or until [sqlite3_step()] or [sqlite3_reset()] or +** [sqlite3_finalize()] is called. The memory space used to hold strings +** and blobs is freed automatically. Do not pass the pointers returned +** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into +** [sqlite3_free()]. +** +** If a memory allocation error occurs during the evaluation of any +** of these routines, a default value is returned. The default value +** is either the integer 0, the floating point number 0.0, or a NULL +** pointer. Subsequent calls to [sqlite3_errcode()] will return +** [SQLITE_NOMEM]. */ const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); int sqlite3_column_bytes(sqlite3_stmt*, int iCol); int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); double sqlite3_column_double(sqlite3_stmt*, int iCol); int sqlite3_column_int(sqlite3_stmt*, int iCol); -sqlite_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); +sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); int sqlite3_column_type(sqlite3_stmt*, int iCol); @@ -1578,7 +2200,7 @@ int sqlite3_finalize(sqlite3_stmt *pStmt); ** CAPI3REF: Reset A Prepared Statement Object ** ** The sqlite3_reset() function is called to reset a -** [sqlite_stmt | compiled SQL statement] object. +** [sqlite3_stmt | compiled SQL statement] object. ** back to it's initial state, ready to be re-executed. ** Any SQL statement variables that had values bound to them using ** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values. @@ -1617,7 +2239,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt); ** its parameters. Any SQL function implementation should be able to work ** work with UTF-8, UTF-16le, or UTF-16be. But some implementations may be ** more efficient with one encoding than another. It is allowed to -** invoke sqlite_create_function() or sqlite3_create_function16() multiple +** invoke sqlite3_create_function() or sqlite3_create_function16() multiple ** times with the same function but with different values of eTextRep. ** When multiple implementations of the same function are available, SQLite ** will pick the one that involves the least amount of data conversion. @@ -1627,7 +2249,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt); ** ** The fifth parameter is an arbitrary pointer. The implementation ** of the function can gain access to this pointer using -** [sqlite_user_data()]. +** [sqlite3_user_data()]. ** ** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL @@ -1691,7 +2313,7 @@ int sqlite3_aggregate_count(sqlite3_context*); int sqlite3_expired(sqlite3_stmt*); int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); int sqlite3_global_recover(void); - +void sqlite3_thread_cleanup(void); /* ** CAPI3REF: Obtaining SQL Function Parameter Values @@ -1729,15 +2351,21 @@ int sqlite3_global_recover(void); ** Please pay particular attention to the fact that the pointer that ** is returned from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to -** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite_value_text()], +** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], ** or [sqlite3_value_text16()]. +** +** These routines must be called from the same thread as +** the SQL function that supplied the sqlite3_value* parameters. +** Or, if the sqlite3_value* argument comes from the [sqlite3_column_value()] +** interface, then these routines should be called from the same thread +** that ran [sqlite3_column_value()]. */ const void *sqlite3_value_blob(sqlite3_value*); int sqlite3_value_bytes(sqlite3_value*); int sqlite3_value_bytes16(sqlite3_value*); double sqlite3_value_double(sqlite3_value*); int sqlite3_value_int(sqlite3_value*); -sqlite_int64 sqlite3_value_int64(sqlite3_value*); +sqlite3_int64 sqlite3_value_int64(sqlite3_value*); const unsigned char *sqlite3_value_text(sqlite3_value*); const void *sqlite3_value_text16(sqlite3_value*); const void *sqlite3_value_text16le(sqlite3_value*); @@ -1762,6 +2390,9 @@ int sqlite3_value_numeric_type(sqlite3_value*); ** [sqlite3_context | SQL function context] that is the first ** parameter to the callback routine that implements the aggregate ** function. +** +** This routine must be called from the same thread in which +** the aggregate SQL function is running. */ void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); @@ -1772,6 +2403,9 @@ void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); ** and [sqlite3_create_function16()] routines ** used to register user functions is available to ** the implementation of the function using this call. +** +** This routine must be called from the same thread in which +** the SQL function is running. */ void *sqlite3_user_data(sqlite3_context*); @@ -1804,6 +2438,9 @@ void *sqlite3_user_data(sqlite3_context*); ** In practice, meta-data is preserved between function calls for ** expressions that are constant at compile time. This includes literal ** values and SQL variables. +** +** These routines must be called from the same thread in which +** the SQL function is running. */ void *sqlite3_get_auxdata(sqlite3_context*, int); void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*)); @@ -1850,14 +2487,18 @@ typedef void (*sqlite3_destructor_type)(void*); ** The sqlite3_result_toobig() cause the function implementation ** to throw and error indicating that a string or BLOB is to long ** to represent. +** +** These routines must be called from within the same thread as +** the SQL function associated with the [sqlite3_context] pointer. */ void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_double(sqlite3_context*, double); void sqlite3_result_error(sqlite3_context*, const char*, int); void sqlite3_result_error16(sqlite3_context*, const void*, int); void sqlite3_result_error_toobig(sqlite3_context*); +void sqlite3_result_error_nomem(sqlite3_context*); void sqlite3_result_int(sqlite3_context*, int); -void sqlite3_result_int64(sqlite3_context*, sqlite_int64); +void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); void sqlite3_result_null(sqlite3_context*); void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); @@ -2003,6 +2644,9 @@ int sqlite3_rekey( ** millisecond time resolution, then the time will be rounded up to ** the nearest second. The number of milliseconds of sleep actually ** requested from the operating system is returned. +** +** SQLite implements this interface by calling the xSleep() +** method of the default [sqlite3_vfs] object. */ int sqlite3_sleep(int); @@ -2015,20 +2659,31 @@ int sqlite3_sleep(int); ** is NULL pointer, then SQLite does a search for an appropriate temporary ** file directory. ** -** Once [sqlite3_open()] has been called, changing this variable will -** invalidate the current temporary database, if any. Generally speaking, -** it is not safe to invoke this routine after [sqlite3_open()] has -** been called. +** It is not safe to modify this variable once a database connection +** has been opened. It is intended that this variable be set once +** as part of process initialization and before any SQLite interface +** routines have been call and remain unchanged thereafter. */ -extern char *sqlite3_temp_directory; +SQLITE_EXTERN char *sqlite3_temp_directory; /* -** CAPI3REF: Test To See If The Databse Is In Auto-Commit Mode +** CAPI3REF: Test To See If The Database Is In Auto-Commit Mode ** ** Test to see whether or not the database connection is in autocommit ** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on ** by default. Autocommit is disabled by a BEGIN statement and reenabled ** by the next COMMIT or ROLLBACK. +** +** If certain kinds of errors occur on a statement within a multi-statement +** transactions (errors including [SQLITE_FULL], [SQLITE_IOERR], +** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the +** transaction might be rolled back automatically. The only way to +** find out if SQLite automatically rolled back the transaction after +** an error is to use this function. +** +** If another thread changes the autocommit status of the database +** connection while this routine is running, then the return value +** is undefined. */ int sqlite3_get_autocommit(sqlite3*); @@ -2095,7 +2750,7 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); */ void *sqlite3_update_hook( sqlite3*, - void(*)(void *,int ,char const *,char const *,sqlite_int64), + void(*)(void *,int ,char const *,char const *,sqlite3_int64), void* ); @@ -2107,38 +2762,26 @@ void *sqlite3_update_hook( ** Sharing is enabled if the argument is true and disabled if the argument ** is false. ** -** Cache sharing is enabled and disabled on a thread-by-thread basis. -** Each call to this routine enables or disables cache sharing only for -** connections created in the same thread in which this routine is called. -** There is no mechanism for sharing cache between database connections -** running in different threads. +** Beginning in SQLite version 3.5.0, cache sharing is enabled and disabled +** for an entire process. In prior versions of SQLite, sharing was +** enabled or disabled for each thread separately. ** -** Sharing must be disabled prior to shutting down a thread or else -** the thread will leak memory. Call this routine with an argument of -** 0 to turn off sharing. Or use the sqlite3_thread_cleanup() API. -** -** This routine must not be called when any database connections -** are active in the current thread. Enabling or disabling shared -** cache while there are active database connections will result -** in memory corruption. -** -** When the shared cache is enabled, the -** following routines must always be called from the same thread: -** [sqlite3_open()], [sqlite3_prepare_v2()], [sqlite3_step()], -** [sqlite3_reset()], [sqlite3_finalize()], and [sqlite3_close()]. -** This is due to the fact that the shared cache makes use of -** thread-specific storage so that it will be available for sharing -** with other connections. +** The cache sharing mode set by this interface effects all subsequent +** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. +** Existing database connections continue use the sharing mode that was +** in effect at the time they were opened. ** ** Virtual tables cannot be used with a shared cache. When shared -** cache is enabled, the sqlite3_create_module() API used to register +** cache is enabled, the [sqlite3_create_module()] API used to register ** virtual tables will always return an error. ** ** This routine returns [SQLITE_OK] if shared cache was ** enabled or disabled successfully. An [SQLITE_ERROR | error code] ** is returned otherwise. ** -** Shared cache is disabled by default for backward compatibility. +** Shared cache is disabled by default. But this might change in +** future releases of SQLite. Applications that care about shared +** cache setting should set it explicitly. */ int sqlite3_enable_shared_cache(int); @@ -2148,30 +2791,24 @@ int sqlite3_enable_shared_cache(int); ** Attempt to free N bytes of heap memory by deallocating non-essential ** memory allocations held by the database library (example: memory ** used to cache database pages to improve performance). -** -** This function is not a part of standard builds. It is only created -** if SQLite is compiled with the SQLITE_ENABLE_MEMORY_MANAGEMENT macro. */ int sqlite3_release_memory(int); /* ** CAPI3REF: Impose A Limit On Heap Size ** -** Place a "soft" limit on the amount of heap memory that may be allocated by -** SQLite within the current thread. If an internal allocation is requested -** that would exceed the specified limit, [sqlite3_release_memory()] is invoked -** one or more times to free up some space before the allocation is made. +** Place a "soft" limit on the amount of heap memory that may be allocated +** by SQLite. If an internal allocation is requested +** that would exceed the specified limit, [sqlite3_release_memory()] is +** invoked one or more times to free up some space before the allocation +** is made. ** -** The limit is called "soft", because if [sqlite3_release_memory()] cannot free -** sufficient memory to prevent the limit from being exceeded, the memory is -** allocated anyway and the current operation proceeds. -** -** Prior to shutting down a thread sqlite3_soft_heap_limit() must be set to -** zero (the default) or else the thread will leak memory. Alternatively, use -** the [sqlite3_thread_cleanup()] API. +** The limit is called "soft", because if [sqlite3_release_memory()] cannot +** free sufficient memory to prevent the limit from being exceeded, +** the memory is allocated anyway and the current operation proceeds. ** ** A negative or zero value for N means that there is no soft heap limit and -** [sqlite3_release_memory()] will only be called when memory is exhaused. +** [sqlite3_release_memory()] will only be called when memory is exhausted. ** The default value for the soft heap limit is zero. ** ** SQLite makes a best effort to honor the soft heap limit. But if it @@ -2179,27 +2816,22 @@ int sqlite3_release_memory(int); ** continue without error or notification. This is why the limit is ** called a "soft" limit. It is advisory only. ** -** This function is only available if the library was compiled with the -** SQLITE_ENABLE_MEMORY_MANAGEMENT option set. -** memory-management has been enabled. +** The soft heap limit is implemented using the [sqlite3_memory_alarm()] +** interface. Only a single memory alarm is available in the default +** implementation. This means that if the application also uses the +** memory alarm interface it will interfere with the operation of the +** soft heap limit and undefined behavior will result. +** +** Prior to SQLite version 3.5.0, this routine only constrained the memory +** allocated by a single thread - the same thread in which this routine +** runs. Beginning with SQLite version 3.5.0, the soft heap limit is +** applied to all threads. The value specified for the soft heap limit +** is an upper bound on the total memory allocation for all threads. In +** version 3.5.0 there is no mechanism for limiting the heap usage for +** individual threads. */ void sqlite3_soft_heap_limit(int); -/* -** CAPI3REF: Clean Up Thread Local Storage -** -** This routine makes sure that all thread-local storage has been -** deallocated for the current thread. -** -** This routine is not technically necessary. All thread-local storage -** will be automatically deallocated once memory-management and -** shared-cache are disabled and the soft heap limit has been set -** to zero. This routine is provided as a convenience for users who -** want to make absolutely sure they have not forgotten something -** prior to killing off a thread. -*/ -void sqlite3_thread_cleanup(void); - /* ** CAPI3REF: Extract Metadata About A Column Of A Table ** @@ -2273,7 +2905,7 @@ int sqlite3_table_column_metadata( char const **pzCollSeq, /* OUTPUT: Collation sequence name */ int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ int *pPrimaryKey, /* OUTPUT: True if column part of PK */ - int *pAutoinc /* OUTPUT: True if colums is auto-increment */ + int *pAutoinc /* OUTPUT: True if column is auto-increment */ ); /* @@ -2318,7 +2950,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff); ** ** Register an extension entry point that is automatically invoked ** whenever a new database connection is opened using -** [sqlite3_open()] or [sqlite3_open16()]. +** [sqlite3_open()], [sqlite3_open16()], or [sqlite3_open_v2()]. ** ** This API can be invoked at program startup in order to register ** one or more statically linked extensions that will be available @@ -2398,8 +3030,8 @@ struct sqlite3_module { int (*xNext)(sqlite3_vtab_cursor*); int (*xEof)(sqlite3_vtab_cursor*); int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); - int (*xRowid)(sqlite3_vtab_cursor*, sqlite_int64 *pRowid); - int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite_int64 *); + int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); + int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); int (*xBegin)(sqlite3_vtab *pVTab); int (*xSync)(sqlite3_vtab *pVTab); int (*xCommit)(sqlite3_vtab *pVTab); @@ -2430,7 +3062,7 @@ struct sqlite3_module { ** is usable) and false if it cannot. ** ** The optimizer automatically inverts terms of the form "expr OP column" -** and makes other simplificatinos to the WHERE clause in an attempt to +** and makes other simplifications to the WHERE clause in an attempt to ** get as many WHERE clause terms into the form shown above as possible. ** The aConstraint[] array only reports WHERE clause terms in the correct ** form that refer to the particular virtual table being queried. @@ -2459,24 +3091,24 @@ struct sqlite3_module { */ struct sqlite3_index_info { /* Inputs */ - const int nConstraint; /* Number of entries in aConstraint */ - const struct sqlite3_index_constraint { + int nConstraint; /* Number of entries in aConstraint */ + struct sqlite3_index_constraint { int iColumn; /* Column on left-hand side of constraint */ unsigned char op; /* Constraint operator */ unsigned char usable; /* True if this constraint is usable */ int iTermOffset; /* Used internally - xBestIndex should ignore */ - } *const aConstraint; /* Table of WHERE clause constraints */ - const int nOrderBy; /* Number of terms in the ORDER BY clause */ - const struct sqlite3_index_orderby { + } *aConstraint; /* Table of WHERE clause constraints */ + int nOrderBy; /* Number of terms in the ORDER BY clause */ + struct sqlite3_index_orderby { int iColumn; /* Column number */ unsigned char desc; /* True for DESC. False for ASC. */ - } *const aOrderBy; /* The ORDER BY clause */ + } *aOrderBy; /* The ORDER BY clause */ /* Outputs */ struct sqlite3_index_constraint_usage { int argvIndex; /* if >0, constraint is part of argv to xFilter */ unsigned char omit; /* Do not code a test for this constraint */ - } *const aConstraintUsage; + } *aConstraintUsage; int idxNum; /* Number used to identify the index */ char *idxStr; /* String, possibly obtained from sqlite3_malloc */ int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ @@ -2519,7 +3151,7 @@ int sqlite3_create_module_v2( /* ** Every module implementation uses a subclass of the following structure ** to describe a particular instance of the module. Each subclass will -** be taylored to the specific needs of the module implementation. The +** be tailored to the specific needs of the module implementation. The ** purpose of this superclass is to define certain fields that are common ** to all module implementations. ** @@ -2585,7 +3217,7 @@ int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); ** to be experimental. The interface might change in incompatible ways. ** If this is a problem for you, do not use the interface at this time. ** -** When the virtual-table mechanism stablizes, we will declare the +** When the virtual-table mechanism stabilizes, we will declare the ** interface fixed, support it indefinitely, and remove this comment. ** ****** EXPERIMENTAL - subject to change without notice ************** @@ -2599,7 +3231,7 @@ int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); ** [sqlite3_blob_open()] and destroyed by [sqlite3_blob_close()]. ** The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces ** can be used to read or write small subsections of the blob. -** The [sqltie3_blob_size()] interface returns the size of the +** The [sqlite3_blob_bytes()] interface returns the size of the ** blob in bytes. */ typedef struct sqlite3_blob sqlite3_blob; @@ -2631,7 +3263,7 @@ int sqlite3_blob_open( const char *zDb, const char *zTable, const char *zColumn, - sqlite_int64 iRow, + sqlite3_int64 iRow, int flags, sqlite3_blob **ppBlob ); @@ -2688,6 +3320,224 @@ int sqlite3_blob_read(sqlite3_blob *, void *z, int n, int iOffset); */ int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); +/* +** CAPI3REF: Virtual File System Objects +** +** A virtual filesystem (VFS) is an [sqlite3_vfs] object +** that SQLite uses to interact +** with the underlying operating system. Most builds come with a +** single default VFS that is appropriate for the host computer. +** New VFSes can be registered and existing VFSes can be unregistered. +** The following interfaces are provided. +** +** The sqlite3_vfs_find() interface returns a pointer to a VFS given its +** name. Names are case sensitive. If there is no match, a NULL +** pointer is returned. If zVfsName is NULL then the default +** VFS is returned. +** +** New VFSes are registered with sqlite3_vfs_register(). Each +** new VFS becomes the default VFS if the makeDflt flag is set. +** The same VFS can be registered multiple times without injury. +** To make an existing VFS into the default VFS, register it again +** with the makeDflt flag set. If two different VFSes with the +** same name are registered, the behavior is undefined. If a +** VFS is registered with a name that is NULL or an empty string, +** then the behavior is undefined. +** +** Unregister a VFS with the sqlite3_vfs_unregister() interface. +** If the default VFS is unregistered, another VFS is chosen as +** the default. The choice for the new VFS is arbitrary. +*/ +sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); +int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); +int sqlite3_vfs_unregister(sqlite3_vfs*); + +/* +** CAPI3REF: Mutexes +** +** The SQLite core uses these routines for thread +** synchronization. Though they are intended for internal +** use by SQLite, code that links against SQLite is +** permitted to use any of these routines. +** +** The SQLite source code contains multiple implementations +** of these mutex routines. An appropriate implementation +** is selected automatically at compile-time. The following +** implementations are available in the SQLite core: +** +**
    +**
  • SQLITE_MUTEX_OS2 +**
  • SQLITE_MUTEX_PTHREAD +**
  • SQLITE_MUTEX_W32 +**
  • SQLITE_MUTEX_NOOP +**
+** +** The SQLITE_MUTEX_NOOP implementation is a set of routines +** that does no real locking and is appropriate for use in +** a single-threaded application. The SQLITE_MUTEX_OS2, +** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations +** are appropriate for use on os/2, unix, and windows. +** +** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor +** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex +** implementation is included with the library. The +** mutex interface routines defined here become external +** references in the SQLite library for which implementations +** must be provided by the application. This facility allows an +** application that links against SQLite to provide its own mutex +** implementation without having to modify the SQLite core. +** +** The sqlite3_mutex_alloc() routine allocates a new +** mutex and returns a pointer to it. If it returns NULL +** that means that a mutex could not be allocated. SQLite +** will unwind its stack and return an error. The argument +** to sqlite3_mutex_alloc() is one of these integer constants: +** +**
    +**
  • SQLITE_MUTEX_FAST +**
  • SQLITE_MUTEX_RECURSIVE +**
  • SQLITE_MUTEX_STATIC_MASTER +**
  • SQLITE_MUTEX_STATIC_MEM +**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_PRNG +**
  • SQLITE_MUTEX_STATIC_LRU +**
+** +** The first two constants cause sqlite3_mutex_alloc() to create +** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE +** is used but not necessarily so when SQLITE_MUTEX_FAST is used. +** The mutex implementation does not need to make a distinction +** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does +** not want to. But SQLite will only request a recursive mutex in +** cases where it really needs one. If a faster non-recursive mutex +** implementation is available on the host platform, the mutex subsystem +** might return such a mutex in response to SQLITE_MUTEX_FAST. +** +** The other allowed parameters to sqlite3_mutex_alloc() each return +** a pointer to a static preexisting mutex. Four static mutexes are +** used by the current version of SQLite. Future versions of SQLite +** may add additional static mutexes. Static mutexes are for internal +** use by SQLite only. Applications that use SQLite mutexes should +** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or +** SQLITE_MUTEX_RECURSIVE. +** +** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST +** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() +** returns a different mutex on every call. But for the static +** mutex types, the same mutex is returned on every call that has +** the same type number. +** +** The sqlite3_mutex_free() routine deallocates a previously +** allocated dynamic mutex. SQLite is careful to deallocate every +** dynamic mutex that it allocates. The dynamic mutexes must not be in +** use when they are deallocated. Attempting to deallocate a static +** mutex results in undefined behavior. SQLite never deallocates +** a static mutex. +** +** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt +** to enter a mutex. If another thread is already within the mutex, +** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return +** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK +** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can +** be entered multiple times by the same thread. In such cases the, +** mutex must be exited an equal number of times before another thread +** can enter. If the same thread tries to enter any other kind of mutex +** more than once, the behavior is undefined. SQLite will never exhibit +** such behavior in its own use of mutexes. +** +** Some systems (ex: windows95) do not the operation implemented by +** sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() will +** always return SQLITE_BUSY. The SQLite core only ever uses +** sqlite3_mutex_try() as an optimization so this is acceptable behavior. +** +** The sqlite3_mutex_leave() routine exits a mutex that was +** previously entered by the same thread. The behavior +** is undefined if the mutex is not currently entered by the +** calling thread or is not currently allocated. SQLite will +** never do either. +** +** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. +*/ +sqlite3_mutex *sqlite3_mutex_alloc(int); +void sqlite3_mutex_free(sqlite3_mutex*); +void sqlite3_mutex_enter(sqlite3_mutex*); +int sqlite3_mutex_try(sqlite3_mutex*); +void sqlite3_mutex_leave(sqlite3_mutex*); + +/* +** CAPI3REF: Mutex Verifcation Routines +** +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines +** are intended for use inside assert() statements. The SQLite core +** never uses these routines except inside an assert() and applications +** are advised to follow the lead of the core. The core only +** provides implementations for these routines when it is compiled +** with the SQLITE_DEBUG flag. External mutex implementations +** are only required to provide these routines if SQLITE_DEBUG is +** defined and if NDEBUG is not defined. +** +** These routines should return true if the mutex in their argument +** is held or not held, respectively, by the calling thread. +** +** The implementation is not required to provided versions of these +** routines that actually work. +** If the implementation does not provide working +** versions of these routines, it should at least provide stubs +** that always return true so that one does not get spurious +** assertion failures. +** +** If the argument to sqlite3_mutex_held() is a NULL pointer then +** the routine should return 1. This seems counter-intuitive since +** clearly the mutex cannot be held if it does not exist. But the +** the reason the mutex does not exist is because the build is not +** using mutexes. And we do not want the assert() containing the +** call to sqlite3_mutex_held() to fail, so a non-zero return is +** the appropriate thing to do. The sqlite3_mutex_notheld() +** interface should also return 1 when given a NULL pointer. +*/ +int sqlite3_mutex_held(sqlite3_mutex*); +int sqlite3_mutex_notheld(sqlite3_mutex*); + +/* +** CAPI3REF: Mutex Types +** +** The [sqlite3_mutex_alloc()] interface takes a single argument +** which is one of these integer constants. +*/ +#define SQLITE_MUTEX_FAST 0 +#define SQLITE_MUTEX_RECURSIVE 1 +#define SQLITE_MUTEX_STATIC_MASTER 2 +#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ +#define SQLITE_MUTEX_STATIC_MEM2 4 /* sqlite3_release_memory() */ +#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ +#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ + +/* +** CAPI3REF: Low-Level Control Of Database Files +** +** The [sqlite3_file_control()] interface makes a direct call to the +** xFileControl method for the [sqlite3_io_methods] object associated +** with a particular database identified by the second argument. The +** name of the database is the name assigned to the database by the +** ATTACH SQL command that opened the +** database. To control the main database file, use the name "main" +** or a NULL pointer. The third and fourth parameters to this routine +** are passed directly through to the second and third parameters of +** the xFileControl method. The return value of the xFileControl +** method becomes the return value of this routine. +** +** If the second parameter (zDbName) does not match the name of any +** open database file, then SQLITE_ERROR is returned. This error +** code is not remembered and will not be recalled by [sqlite3_errcode()] +** or [sqlite3_errmsg()]. The underlying xFileControl method might +** also return SQLITE_ERROR. There is no way to distinguish between +** an incorrect zDbName and an SQLITE_ERROR return from the underlying +** xFileControl method. +** +** See also: [SQLITE_FCNTL_LOCKSTATE] +*/ +int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); + /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. diff --git a/extensions/sqlite/sqlite-source/sqlite3ext.h b/extensions/sqlite/sqlite-source/sqlite3ext.h index ef253310..ba4f9d6e 100644 --- a/extensions/sqlite/sqlite-source/sqlite3ext.h +++ b/extensions/sqlite/sqlite-source/sqlite3ext.h @@ -149,11 +149,39 @@ struct sqlite3_api_routines { const void * (*value_text16le)(sqlite3_value*); int (*value_type)(sqlite3_value*); char *(*vmprintf)(const char*,va_list); + /* Added ??? */ int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); + /* Added by 3.3.13 */ int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); int (*clear_bindings)(sqlite3_stmt*); + /* Added by 3.4.1 */ int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,void (*xDestroy)(void *)); + /* Added by 3.5.0 */ + int (*bind_zeroblob)(sqlite3_stmt*,int,int); + int (*blob_bytes)(sqlite3_blob*); + int (*blob_close)(sqlite3_blob*); + int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,int,sqlite3_blob**); + int (*blob_read)(sqlite3_blob*,void*,int,int); + int (*blob_write)(sqlite3_blob*,const void*,int,int); + int (*create_collation_v2)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*),void(*)(void*)); + int (*file_control)(sqlite3*,const char*,int,void*); + sqlite3_int64 (*memory_highwater)(int); + sqlite3_int64 (*memory_used)(void); + sqlite3_mutex *(*mutex_alloc)(int); + void (*mutex_enter)(sqlite3_mutex*); + void (*mutex_free)(sqlite3_mutex*); + void (*mutex_leave)(sqlite3_mutex*); + int (*mutex_try)(sqlite3_mutex*); + int (*open_v2)(const char*,sqlite3**,int,const char*); + int (*release_memory)(int); + void (*result_error_nomem)(sqlite3_context*); + void (*result_error_toobig)(sqlite3_context*); + int (*sleep)(int); + void (*soft_heap_limit)(int); + sqlite3_vfs *(*vfs_find)(const char*); + int (*vfs_register)(sqlite3_vfs*,int); + int (*vfs_unregister)(sqlite3_vfs*); }; /* @@ -290,6 +318,30 @@ struct sqlite3_api_routines { #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 #define sqlite3_clear_bindings sqlite3_api->clear_bindings +#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob +#define sqlite3_blob_bytes sqlite3_api->blob_bytes +#define sqlite3_blob_close sqlite3_api->blob_close +#define sqlite3_blob_open sqlite3_api->blob_open +#define sqlite3_blob_read sqlite3_api->blob_read +#define sqlite3_blob_write sqlite3_api->blob_write +#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2 +#define sqlite3_file_control sqlite3_api->file_control +#define sqlite3_memory_highwater sqlite3_api->memory_highwater +#define sqlite3_memory_used sqlite3_api->memory_used +#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc +#define sqlite3_mutex_enter sqlite3_api->mutex_enter +#define sqlite3_mutex_free sqlite3_api->mutex_free +#define sqlite3_mutex_leave sqlite3_api->mutex_leave +#define sqlite3_mutex_try sqlite3_api->mutex_try +#define sqlite3_open_v2 sqlite3_api->open_v2 +#define sqlite3_release_memory sqlite3_api->release_memory +#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem +#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig +#define sqlite3_sleep sqlite3_api->sleep +#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit +#define sqlite3_vfs_find sqlite3_api->vfs_find +#define sqlite3_vfs_register sqlite3_api->vfs_register +#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister #endif /* SQLITE_CORE */ #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api; diff --git a/extensions/sqlite/sqlite-source/sqliteInt.h b/extensions/sqlite/sqlite-source/sqliteInt.h index ee9a3c2f..c458d5ba 100644 --- a/extensions/sqlite/sqlite-source/sqliteInt.h +++ b/extensions/sqlite/sqlite-source/sqliteInt.h @@ -17,6 +17,76 @@ #define _SQLITEINT_H_ #include "sqliteLimit.h" +/* +** For testing purposes, the various size limit constants are really +** variables that we can modify in the testfixture. +*/ +#ifdef SQLITE_TEST + #undef SQLITE_MAX_LENGTH + #undef SQLITE_MAX_COLUMN + #undef SQLITE_MAX_SQL_LENGTH + #undef SQLITE_MAX_EXPR_DEPTH + #undef SQLITE_MAX_COMPOUND_SELECT + #undef SQLITE_MAX_VDBE_OP + #undef SQLITE_MAX_FUNCTION_ARG + #undef SQLITE_MAX_VARIABLE_NUMBER + #undef SQLITE_MAX_PAGE_SIZE + #undef SQLITE_MAX_PAGE_COUNT + #undef SQLITE_MAX_LIKE_PATTERN_LENGTH + + #define SQLITE_MAX_LENGTH sqlite3MAX_LENGTH + #define SQLITE_MAX_COLUMN sqlite3MAX_COLUMN + #define SQLITE_MAX_SQL_LENGTH sqlite3MAX_SQL_LENGTH + #define SQLITE_MAX_EXPR_DEPTH sqlite3MAX_EXPR_DEPTH + #define SQLITE_MAX_COMPOUND_SELECT sqlite3MAX_COMPOUND_SELECT + #define SQLITE_MAX_VDBE_OP sqlite3MAX_VDBE_OP + #define SQLITE_MAX_FUNCTION_ARG sqlite3MAX_FUNCTION_ARG + #define SQLITE_MAX_VARIABLE_NUMBER sqlite3MAX_VARIABLE_NUMBER + #define SQLITE_MAX_PAGE_SIZE sqlite3MAX_PAGE_SIZE + #define SQLITE_MAX_PAGE_COUNT sqlite3MAX_PAGE_COUNT + #define SQLITE_MAX_LIKE_PATTERN_LENGTH sqlite3MAX_LIKE_PATTERN_LENGTH + + extern int sqlite3MAX_LENGTH; + extern int sqlite3MAX_COLUMN; + extern int sqlite3MAX_SQL_LENGTH; + extern int sqlite3MAX_EXPR_DEPTH; + extern int sqlite3MAX_COMPOUND_SELECT; + extern int sqlite3MAX_VDBE_OP; + extern int sqlite3MAX_FUNCTION_ARG; + extern int sqlite3MAX_VARIABLE_NUMBER; + extern int sqlite3MAX_PAGE_SIZE; + extern int sqlite3MAX_PAGE_COUNT; + extern int sqlite3MAX_LIKE_PATTERN_LENGTH; +#endif + + +/* +** The SQLITE_THREADSAFE macro must be defined as either 0 or 1. +** Older versions of SQLite used an optional THREADSAFE macro. +** We support that for legacy +*/ +#if !defined(SQLITE_THREADSAFE) +#if defined(THREADSAFE) +# define SQLITE_THREADSAFE THREADSAFE +#else +# define SQLITE_THREADSAFE 1 +#endif +#endif + +/* +** We need to define _XOPEN_SOURCE as follows in order to enable +** recursive mutexes on most unix systems. But Mac OS X is different. +** The _XOPEN_SOURCE define causes problems for Mac OS X we are told, +** so it is omitted there. See ticket #2673. +** +** Later we learn that _XOPEN_SOURCE is poorly or incorrectly +** implemented on some systems. So we avoid defining it at all +** if it is already defined or if it is unneeded because we are +** not doing a threadsafe build. Ticket #2681. +*/ +#if !defined(_XOPEN_SOURCE) && !defined(__MACOS__) && SQLITE_THREADSAFE +# define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */ +#endif #if defined(SQLITE_TCL) || defined(TCLSH) # include @@ -184,7 +254,11 @@ typedef UINT8_TYPE i8; /* 1-byte signed integer */ ** Macros to determine whether the machine is big or little endian, ** evaluated at runtime. */ +#ifdef SQLITE_AMALGAMATION +const int sqlite3One; +#else extern const int sqlite3one; +#endif #if defined(i386) || defined(__i386__) || defined(_M_IX86) # define SQLITE_BIGENDIAN 0 # define SQLITE_LITTLEENDIAN 1 @@ -215,78 +289,10 @@ struct BusyHandler { ** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler typedefs. */ -#include "vdbe.h" #include "btree.h" +#include "vdbe.h" #include "pager.h" -#ifdef SQLITE_MEMDEBUG -/* -** The following global variables are used for testing and debugging -** only. They only work if SQLITE_MEMDEBUG is defined. -*/ -extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */ -extern int sqlite3_nFree; /* Number of sqliteFree() calls */ -extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */ -extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */ - -extern void *sqlite3_pFirst; /* Pointer to linked list of allocations */ -extern int sqlite3_nMaxAlloc; /* High water mark of ThreadData.nAlloc */ -extern int sqlite3_mallocDisallowed; /* assert() in sqlite3Malloc() if set */ -extern int sqlite3_isFail; /* True if all malloc calls should fail */ -extern const char *sqlite3_zFile; /* Filename to associate debug info with */ -extern int sqlite3_iLine; /* Line number for debug info */ - -#define ENTER_MALLOC (sqlite3_zFile = __FILE__, sqlite3_iLine = __LINE__) -#define sqliteMalloc(x) (ENTER_MALLOC, sqlite3Malloc(x,1)) -#define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x,1)) -#define sqliteRealloc(x,y) (ENTER_MALLOC, sqlite3Realloc(x,y)) -#define sqliteStrDup(x) (ENTER_MALLOC, sqlite3StrDup(x)) -#define sqliteStrNDup(x,y) (ENTER_MALLOC, sqlite3StrNDup(x,y)) -#define sqliteReallocOrFree(x,y) (ENTER_MALLOC, sqlite3ReallocOrFree(x,y)) - -#else - -#define ENTER_MALLOC 0 -#define sqliteMalloc(x) sqlite3Malloc(x,1) -#define sqliteMallocRaw(x) sqlite3MallocRaw(x,1) -#define sqliteRealloc(x,y) sqlite3Realloc(x,y) -#define sqliteStrDup(x) sqlite3StrDup(x) -#define sqliteStrNDup(x,y) sqlite3StrNDup(x,y) -#define sqliteReallocOrFree(x,y) sqlite3ReallocOrFree(x,y) - -#endif - -/* Variable sqlite3_mallocHasFailed is set to true after a malloc() -** failure occurs. -** -** The sqlite3MallocFailed() macro returns true if a malloc has failed -** in this thread since the last call to sqlite3ApiExit(), or false -** otherwise. -*/ -extern int sqlite3_mallocHasFailed; -#define sqlite3MallocFailed() (sqlite3_mallocHasFailed && sqlite3OsInMutex(1)) - -#define sqliteFree(x) sqlite3FreeX(x) -#define sqliteAllocSize(x) sqlite3AllocSize(x) - -/* -** An instance of this structure might be allocated to store information -** specific to a single thread. -*/ -struct ThreadData { - int dummy; /* So that this structure is never empty */ - -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - int nSoftHeapLimit; /* Suggested max mem allocation. No limit if <0 */ - int nAlloc; /* Number of bytes currently allocated */ - Pager *pPager; /* Linked list of all pagers in this thread */ -#endif - -#ifndef SQLITE_OMIT_SHARED_CACHE - u8 useSharedData; /* True if shared pagers and schemas are enabled */ - BtShared *pBtree; /* Linked list of all currently open BTrees */ -#endif -}; /* ** Name of the master database table. The master database table @@ -334,7 +340,6 @@ typedef struct NameContext NameContext; typedef struct Parse Parse; typedef struct Select Select; typedef struct SrcList SrcList; -typedef struct ThreadData ThreadData; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; @@ -345,6 +350,7 @@ typedef struct WhereInfo WhereInfo; typedef struct WhereLevel WhereLevel; #include "os.h" +#include "mutex.h" /* ** Each database file to be accessed by the system is an instance @@ -441,13 +447,16 @@ struct Schema { ** consistently. */ struct sqlite3 { + sqlite3_vfs *pVfs; /* OS Interface */ int nDb; /* Number of backends currently in use */ Db *aDb; /* All backends */ int flags; /* Miscellanous flags. See below */ + int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ + u8 mallocFailed; /* True if we have seen a malloc failure */ int nTable; /* Number of tables in the database */ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ i64 lastRowid; /* ROWID of most recent insert (see above) */ @@ -455,6 +464,7 @@ struct sqlite3 { int magic; /* Magic number for detect library misuse */ int nChange; /* Value returned by sqlite3_changes() */ int nTotalChange; /* Value returned by sqlite3_total_changes() */ + sqlite3_mutex *mutex; /* Connection mutex */ struct sqlite3InitInfo { /* Information used during initialization */ int iDb; /* When back is being initialized */ int newTnum; /* Rootpage of table being initialized */ @@ -545,6 +555,8 @@ struct sqlite3 { #define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */ #define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */ +#define SQLITE_SharedCache 0x00080000 /* Cache sharing is enabled */ +#define SQLITE_Vtab 0x00100000 /* There exists a virtual table */ /* ** Possible values for the sqlite.magic field. @@ -738,7 +750,7 @@ struct Table { int nModuleArg; /* Number of arguments to the module */ char **azModuleArg; /* Text of all module args. [0] is module name */ #endif - Schema *pSchema; + Schema *pSchema; /* Schema that contains this table */ }; /* @@ -796,7 +808,7 @@ struct FKey { }; /* -** SQLite supports many different ways to resolve a contraint +** SQLite supports many different ways to resolve a constraint ** error. ROLLBACK processing means that a constraint violation ** causes the operation in process to fail and for the current transaction ** to be rolled back. ABORT processing means the operation in process @@ -845,6 +857,7 @@ struct FKey { ** were larger. */ struct KeyInfo { + sqlite3 *db; /* The database connection */ u8 enc; /* Text encoding - one of the TEXT_Utf* values */ u8 incrKey; /* Increase 2nd key by epsilon before comparison */ int nField; /* Number of entries in aColl[] */ @@ -1016,8 +1029,8 @@ struct Expr { Select *pSelect; /* When the expression is a sub-select. Also the ** right side of " IN (