Index: SQLite.Interop/interop.c ================================================================== --- SQLite.Interop/interop.c +++ SQLite.Interop/interop.c @@ -55,11 +55,11 @@ return; } #endif assert( v!=0 ); - if( pParse->colNamesSet || v==0 || sqlite3ThreadData()->mallocFailed ) return; + if( pParse->colNamesSet || v==0 || sqlite3MallocFailed() ) return; pParse->colNamesSet = 1; fullNames = (db->flags & SQLITE_FullColNames)!=0; shortNames = (db->flags & SQLITE_ShortColNames)!=0; if (realNames) fullNames = 1; /*** ADDED - SQLite.Interop ***/ Index: SQLite.Interop/merge.h ================================================================== --- SQLite.Interop/merge.h +++ SQLite.Interop/merge.h @@ -1,13 +1,13 @@ // This code was automatically generated from assembly -// D:\src\SQLite.NET.Test\System.Data.SQLite\bin\CompactFramework\System.Data.SQLite.dll +// C:\src\SQLite.NET\System.Data.SQLite\bin\CompactFramework\System.Data.SQLite.dll #include #pragma data_seg(".clr") #pragma comment(linker, "/SECTION:.clr,ER") - char __ph[85156] = {0}; // The number of bytes to reserve + char __ph[85184] = {0}; // The number of bytes to reserve #pragma data_seg() typedef BOOL (WINAPI *DLLMAIN)(HANDLE, DWORD, LPVOID); extern BOOL WINAPI _DllMainCRTStartup(HANDLE, DWORD, LPVOID); Index: SQLite.Interop/merge_full.h ================================================================== --- SQLite.Interop/merge_full.h +++ SQLite.Interop/merge_full.h @@ -1,13 +1,13 @@ // This code was automatically generated from assembly -// D:\src\SQLite.NET.Test\System.Data.SQLite\bin\System.Data.SQLite.dll +// C:\src\SQLite.NET\System.Data.SQLite\bin\System.Data.SQLite.dll #include #pragma data_seg(".clr") #pragma comment(linker, "/SECTION:.clr,ER") - char __ph[96452] = {0}; // The number of bytes to reserve + char __ph[96380] = {0}; // The number of bytes to reserve #pragma data_seg() typedef BOOL (WINAPI *DLLMAIN)(HANDLE, DWORD, LPVOID); extern BOOL WINAPI _DllMainCRTStartup(HANDLE, DWORD, LPVOID); Index: SQLite.Interop/src/alter.c ================================================================== --- SQLite.Interop/src/alter.c +++ SQLite.Interop/src/alter.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that used to generate VDBE code ** that implements the ALTER TABLE command. ** -** $Id: alter.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: alter.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* @@ -160,11 +160,11 @@ #endif }; int i; for(i=0; imallocFailed ) goto exit_rename_table; + if( sqlite3MallocFailed() ) goto exit_rename_table; assert( pSrc->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); @@ -499,11 +499,11 @@ int i; int nAlloc; /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); - if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto exit_begin_add_column; + if( sqlite3MallocFailed() ) goto exit_begin_add_column; pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( !pTab ) goto exit_begin_add_column; /* Make sure this is not an attempt to ALTER a view. */ if( pTab->pSelect ){ Index: SQLite.Interop/src/analyze.c ================================================================== --- SQLite.Interop/src/analyze.c +++ SQLite.Interop/src/analyze.c @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.9 2006/01/16 15:51:47 rmsimpson Exp $ +** @(#) $Id: analyze.c,v 1.10 2006/01/23 19:45:55 rmsimpson Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" /* Index: SQLite.Interop/src/attach.c ================================================================== --- SQLite.Interop/src/attach.c +++ SQLite.Interop/src/attach.c @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** -** $Id: attach.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: attach.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" /* ** Resolve an expression that was part of an ATTACH or DETACH statement. This @@ -270,11 +270,11 @@ Vdbe *v; FuncDef *pFunc; sqlite3* db = pParse->db; #ifndef SQLITE_OMIT_AUTHORIZATION - assert( sqlite3ThreadDataReadOnly()->mallocFailed || pAuthArg ); + assert( sqlite3MallocFailed() || pAuthArg ); if( pAuthArg ){ char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span); if( !zAuthArg ){ goto attach_end; } @@ -301,11 +301,11 @@ v = sqlite3GetVdbe(pParse); sqlite3ExprCode(pParse, pFilename); sqlite3ExprCode(pParse, pDbname); sqlite3ExprCode(pParse, pKey); - assert(v || sqlite3ThreadDataReadOnly()->mallocFailed); + assert( v || sqlite3MallocFailed() ); if( v ){ sqlite3VdbeAddOp(v, OP_Function, 0, nFunc); pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF); @@ -343,12 +343,12 @@ /* ** Register the functions sqlite_attach and sqlite_detach. */ void sqlite3AttachFunctions(sqlite3 *db){ static const int enc = SQLITE_UTF8; - sqlite3_create_function(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0); - sqlite3_create_function(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0); + sqlite3CreateFunc(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0); + sqlite3CreateFunc(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0); } /* ** Initialize a DbFixer structure. This routine must be called prior ** to passing the structure to one of the sqliteFixAAAA() routines below. Index: SQLite.Interop/src/auth.c ================================================================== --- SQLite.Interop/src/auth.c +++ SQLite.Interop/src/auth.c @@ -12,11 +12,11 @@ ** This file contains code used to implement the sqlite3_set_authorizer() ** API. This facility is an optional feature of the library. Embedded ** systems that do not need this facility may omit it by recompiling ** the library with -DSQLITE_OMIT_AUTHORIZATION=1 ** -** $Id: auth.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: auth.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" /* ** All of the code in this file may be omitted by defining a single Index: SQLite.Interop/src/btree.c ================================================================== --- SQLite.Interop/src/btree.c +++ SQLite.Interop/src/btree.c @@ -7,11 +7,11 @@ ** 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: btree.c,v 1.17 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: btree.c,v 1.18 2006/01/23 19:45:55 rmsimpson Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: @@ -460,11 +460,12 @@ ** Routines to read and write variable-length integers. These used to ** be defined locally, but now we use the varint routines in the util.c ** file. */ #define getVarint sqlite3GetVarint -#define getVarint32 sqlite3GetVarint32 +/* #define getVarint32 sqlite3GetVarint32 */ +#define getVarint32(A,B) ((*B=*(A))<=0x7f?1:sqlite3GetVarint32(A,B)) #define putVarint sqlite3PutVarint /* The database page the PENDING_BYTE occupies. This page is never used. ** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They ** should possibly be consolidated (presumably in pager.h). @@ -504,49 +505,49 @@ #define restoreOrClearCursorPosition(a,b) SQLITE_OK #define saveAllCursors(a,b,c) SQLITE_OK #else +static void releasePage(MemPage *pPage); + /* ** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. */ static int saveCursorPosition(BtCursor *pCur){ - int rc = SQLITE_OK; + int rc; - assert( CURSOR_VALID==pCur->eState|| CURSOR_INVALID==pCur->eState ); + assert( CURSOR_VALID==pCur->eState ); assert( 0==pCur->pKey ); - if( pCur->eState==CURSOR_VALID ){ - rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); - - /* If this is an intKey table, then the above call to BtreeKeySize() - ** stores the integer key in pCur->nKey. In this case this value is - ** all that is required. Otherwise, if pCur is not open on an intKey - ** table, then malloc space for and store the pCur->nKey bytes of key - ** data. - */ - if( rc==SQLITE_OK && 0==pCur->pPage->intKey){ - void *pKey = sqliteMalloc(pCur->nKey); - if( pKey ){ - rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey); - if( rc==SQLITE_OK ){ - pCur->pKey = pKey; - }else{ - sqliteFree(pKey); - } - }else{ - rc = SQLITE_NOMEM; - } - } - assert( !pCur->pPage->intKey || !pCur->pKey ); - - /* Todo: Should we drop the reference to pCur->pPage here? */ - - if( rc==SQLITE_OK ){ - pCur->eState = CURSOR_REQUIRESEEK; - } + rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); + + /* If this is an intKey table, then the above call to BtreeKeySize() + ** stores the integer key in pCur->nKey. In this case this value is + ** all that is required. Otherwise, if pCur is not open on an intKey + ** table, then malloc space for and store the pCur->nKey bytes of key + ** data. + */ + if( rc==SQLITE_OK && 0==pCur->pPage->intKey){ + void *pKey = sqliteMalloc(pCur->nKey); + if( pKey ){ + rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey); + if( rc==SQLITE_OK ){ + pCur->pKey = pKey; + }else{ + sqliteFree(pKey); + } + }else{ + rc = SQLITE_NOMEM; + } + } + assert( !pCur->pPage->intKey || !pCur->pKey ); + + if( rc==SQLITE_OK ){ + releasePage(pCur->pPage); + pCur->pPage = 0; + pCur->eState = CURSOR_REQUIRESEEK; } return rc; } @@ -583,14 +584,13 @@ */ static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){ int rc = SQLITE_OK; assert( sqlite3ThreadDataReadOnly()->useSharedData ); assert( pCur->eState==CURSOR_REQUIRESEEK ); + pCur->eState = CURSOR_INVALID; if( doSeek ){ rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip); - }else{ - pCur->eState = CURSOR_INVALID; } if( rc==SQLITE_OK ){ sqliteFree(pCur->pKey); pCur->pKey = 0; assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState ); @@ -919,16 +919,20 @@ if( pPage->hasData ){ n += getVarint32(&pCell[n], &nPayload); }else{ nPayload = 0; } - n += getVarint(&pCell[n], (u64 *)&pInfo->nKey); - pInfo->nHeader = n; pInfo->nData = nPayload; - if( !pPage->intKey ){ - nPayload += pInfo->nKey; + if( pPage->intKey ){ + n += getVarint(&pCell[n], (u64 *)&pInfo->nKey); + }else{ + u32 x; + n += getVarint32(&pCell[n], &x); + pInfo->nKey = x; + nPayload += x; } + pInfo->nHeader = n; if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ int nSize; /* Total size of cell content in bytes */ @@ -1660,11 +1664,15 @@ pBt->usableSize = pBt->pageSize - nReserve; assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize); #ifndef SQLITE_OMIT_SHARED_CACHE - /* Add the new btree to the linked list starting at ThreadData.pBtree */ + /* 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 @@ -1710,18 +1718,23 @@ pBt->nRef--; if( pBt->nRef ){ return SQLITE_OK; } - /* Remove the shared-btree from the thread wide list */ - pTsd = sqlite3ThreadData(); + /* 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; } } #endif @@ -2435,26 +2448,29 @@ ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ int sqlite3BtreeCommit(Btree *p){ - int rc = SQLITE_OK; BtShared *pBt = p->pBt; btreeIntegrity(p); - unlockAllTables(p); /* If the handle has a write-transaction open, commit the shared-btrees ** transaction and set the shared state to TRANS_READ. */ if( p->inTrans==TRANS_WRITE ){ + int rc; assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->nTransaction>0 ); rc = sqlite3pager_commit(pBt->pPager); + if( rc!=SQLITE_OK ){ + return rc; + } pBt->inTransaction = TRANS_READ; pBt->inStmt = 0; } + unlockAllTables(p); /* If the handle has any kind of transaction open, decrement the transaction ** count of the shared btree. If the transaction count reaches 0, set ** the shared state to TRANS_NONE. The unlockBtreeIfUnused() call below ** will unlock the pager. @@ -2471,11 +2487,11 @@ */ p->inTrans = TRANS_NONE; unlockBtreeIfUnused(pBt); btreeIntegrity(p); - return rc; + return SQLITE_OK; } #ifndef NDEBUG /* ** Return the number of write-cursors open on this handle. This is for use @@ -2490,11 +2506,11 @@ } return r; } #endif -#ifdef SQLITE_TEST +#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) /* ** Print debugging information about all cursors to standard output. */ void sqlite3BtreeCursorList(Btree *p){ BtCursor *pCur; @@ -2609,16 +2625,19 @@ ** All cursors will be invalidated by this operation. Any attempt ** to use a cursor that was open at the beginning of this operation ** will result in an error. */ int sqlite3BtreeRollbackStmt(Btree *p){ - int rc; + int rc = SQLITE_OK; BtShared *pBt = p->pBt; - if( pBt->inStmt==0 || pBt->readOnly ) return SQLITE_OK; - rc = sqlite3pager_stmt_rollback(pBt->pPager); - assert( countWriteCursors(pBt)==0 ); - pBt->inStmt = 0; + sqlite3MallocDisallow(); + if( pBt->inStmt && !pBt->readOnly ){ + rc = sqlite3pager_stmt_rollback(pBt->pPager); + assert( countWriteCursors(pBt)==0 ); + pBt->inStmt = 0; + } + sqlite3MallocAllow(); return rc; } /* ** Default key comparison function to be used if no comparison function @@ -3166,13 +3185,12 @@ MemPage *pRoot; int rc = SQLITE_OK; BtShared *pBt = pCur->pBtree->pBt; restoreOrClearCursorPosition(pCur, 0); - assert( pCur->pPage ); pRoot = pCur->pPage; - if( pRoot->pgno==pCur->pgnoRoot ){ + if( pRoot && pRoot->pgno==pCur->pgnoRoot ){ assert( pRoot->isInit ); }else{ if( SQLITE_OK!=(rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0)) ){ @@ -3345,14 +3363,14 @@ if( tryRightmost ){ pCur->idx = upr; } pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize; if( pPage->hasData ){ - int dummy; + u32 dummy; pCell += getVarint32(pCell, &dummy); } - getVarint(pCell, &nCellKey); + getVarint(pCell, (u64 *)&nCellKey); if( nCellKeynKey ){ c = +1; tryRightmost = 0; @@ -3435,11 +3453,11 @@ ** 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){ int rc; - MemPage *pPage = pCur->pPage; + MemPage *pPage; #ifndef SQLITE_OMIT_SHARED_CACHE rc = restoreOrClearCursorPosition(pCur, 1); if( rc!=SQLITE_OK ){ return rc; @@ -3448,13 +3466,14 @@ pCur->skip = 0; *pRes = 0; return SQLITE_OK; } pCur->skip = 0; -#endif +#endif assert( pRes!=0 ); + pPage = pCur->pPage; if( CURSOR_INVALID==pCur->eState ){ *pRes = 1; return SQLITE_OK; } assert( pPage->isInit ); @@ -4425,12 +4444,14 @@ */ assert( pPage->isInit ); assert( sqlite3pager_iswriteable(pPage->aData) ); pBt = pPage->pBt; pParent = pPage->pParent; - sqlite3pager_write(pParent->aData); assert( pParent ); + if( SQLITE_OK!=(rc = sqlite3pager_write(pParent->aData)) ){ + return rc; + } TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno)); #ifndef SQLITE_OMIT_QUICKBALANCE /* ** A special case: If a new entry has just been inserted into a @@ -5262,13 +5283,13 @@ ** CURSOR_REQUIRESEEK state) and save the positions of any other cursors ** open on the same table. Then call sqlite3pager_write() on the page ** that the entry will be deleted from. */ if( - (rc = restoreOrClearCursorPosition(pCur, 1)) || - (rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) || - (rc = sqlite3pager_write(pPage->aData)) + (rc = restoreOrClearCursorPosition(pCur, 1))!=0 || + (rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur))!=0 || + (rc = sqlite3pager_write(pPage->aData))!=0 ){ return rc; } /* Locate the cell within it's page and leave pCell pointing to the @@ -5290,11 +5311,13 @@ ** next Cell after the one to be deleted is guaranteed to exist and ** to be a leaf so we can use it. */ BtCursor leafCur; unsigned char *pNext; - int szNext; + int szNext; /* The compiler warning is wrong: szNext is always + ** initialized before use. Adding an extra initialization + ** to silence the compiler slows down the code. */ int notUsed; unsigned char *tempCell = 0; assert( !pPage->leafData ); getTempCursor(pCur, &leafCur); rc = sqlite3BtreeNext(&leafCur, ¬Used); @@ -5529,26 +5552,35 @@ */ int sqlite3BtreeClearTable(Btree *p, int iTable){ int rc; BtCursor *pCur; BtShared *pBt = p->pBt; + sqlite3 *db = p->pSqlite; if( p->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } - for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ - if( pCur->pgnoRoot==(Pgno)iTable ){ - if( pCur->wrFlag==0 ) return SQLITE_LOCKED; - moveToRoot(pCur); + + /* If this connection is not in read-uncommitted mode and currently has + ** a read-cursor open on the table being cleared, return SQLITE_LOCKED. + */ + if( 0==db || 0==(db->flags&SQLITE_ReadUncommitted) ){ + for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ + if( pCur->pBtree==p && pCur->pgnoRoot==(Pgno)iTable ){ + if( 0==pCur->wrFlag ){ + return SQLITE_LOCKED; + } + moveToRoot(pCur); + } } } - rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0); -#if 0 - if( rc ){ - sqlite3BtreeRollback(pBt); + + /* Save the position of all cursors open on this table */ + if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){ + return rc; } -#endif - return rc; + + return clearDatabasePage(pBt, (Pgno)iTable, 0, 0); } /* ** Erase all information in a table and add the root of the table to ** the freelist. Except, the root of the principle table (the one on @@ -5856,11 +5888,11 @@ int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){ return btreePageDump(p->pBt, pgno, recursive, 0); } #endif -#ifdef SQLITE_TEST +#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) /* ** Fill aResult[] with information about the entry and page that the ** cursor is pointing to. ** ** aResult[0] = The page number @@ -6529,11 +6561,11 @@ /* ** The following debugging interface has to be in this file (rather ** than in, for example, test1.c) so that it can get access to ** the definition of BtShared. */ -#if defined(SQLITE_TEST) && defined(TCLSH) +#if defined(SQLITE_DEBUG) && defined(TCLSH) #include int sqlite3_shared_cache_report( void * clientData, Tcl_Interp *interp, int objc, Index: SQLite.Interop/src/btree.h ================================================================== --- SQLite.Interop/src/btree.h +++ SQLite.Interop/src/btree.h @@ -11,11 +11,11 @@ ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** -** @(#) $Id: btree.h,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** @(#) $Id: btree.h,v 1.17 2006/01/23 19:45:55 rmsimpson Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ /* TODO: This definition is just included so other modules compile. It Index: SQLite.Interop/src/build.c ================================================================== --- SQLite.Interop/src/build.c +++ SQLite.Interop/src/build.c @@ -20,11 +20,11 @@ ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: build.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* @@ -128,11 +128,11 @@ */ void sqlite3FinishCoding(Parse *pParse){ sqlite3 *db; Vdbe *v; - if( sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( sqlite3MallocFailed() ) return; if( pParse->nested ) return; if( !pParse->pVdbe ){ if( pParse->rc==SQLITE_OK && pParse->nErr ){ pParse->rc = SQLITE_ERROR; } @@ -1362,12 +1362,11 @@ ){ Table *p; sqlite3 *db = pParse->db; int iDb; - if( (pEnd==0 && pSelect==0) || - pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) { + if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3MallocFailed() ) { return; } p = pParse->pNewTable; if( p==0 ) return; @@ -1545,14 +1544,18 @@ db->nTable++; db->flags |= SQLITE_InternChanges; #ifndef SQLITE_OMIT_ALTERTABLE if( !p->pSelect ){ - const unsigned char *zName = pParse->sNameToken.z; + const char *zName = (const char *)pParse->sNameToken.z; + int nName; assert( !pSelect && pCons && pEnd ); - if( pCons->z==0 ) pCons = pEnd; - p->addColOffset = 13 + sqlite3utf8CharLen(zName, pCons->z - zName); + if( pCons->z==0 ){ + pCons = pEnd; + } + nName = (const char *)pCons->z - zName; + p->addColOffset = 13 + sqlite3utf8CharLen(zName, nName); } #endif } } @@ -1601,11 +1604,11 @@ ** 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); sqlite3SelectDelete(pSelect); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ return; } if( !pParse->db->init.busy ){ sqlite3ViewGetColumnNames(pParse, p); } @@ -1843,11 +1846,11 @@ Table *pTab; Vdbe *v; sqlite3 *db = pParse->db; int iDb; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( pParse->nErr || sqlite3MallocFailed() ){ goto exit_drop_table; } assert( pName->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase); @@ -2204,11 +2207,11 @@ struct ExprList_item *pListItem; /* For looping over pList */ int nCol; int nExtra = 0; char *zExtra; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( pParse->nErr || sqlite3MallocFailed() ){ goto exit_create_index; } /* ** Find the table that is to be indexed. Return early if not found. @@ -2358,13 +2361,13 @@ sizeof(char *)*nCol + /* Index.azColl */ sizeof(u8)*nCol + /* Index.aSortOrder */ nName + 1 + /* Index.zName */ nExtra /* Collation sequence names */ ); - if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto exit_create_index; + if( sqlite3MallocFailed() ) goto exit_create_index; pIndex->aiColumn = (int *)(&pIndex[1]); - pIndex->aiRowEst = (int *)(&pIndex->aiColumn[nCol]); + pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]); pIndex->azColl = (char **)(&pIndex->aiRowEst[nCol+1]); pIndex->aSortOrder = (u8 *)(&pIndex->azColl[nCol]); pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]); zExtra = (char *)(&pIndex->zName[nName+1]); strcpy(pIndex->zName, zName); @@ -2645,11 +2648,11 @@ Index *pIndex; Vdbe *v; sqlite3 *db = pParse->db; int iDb; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( pParse->nErr || sqlite3MallocFailed() ){ goto exit_drop_index; } assert( pName->nSrc==1 ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_drop_index; @@ -2854,11 +2857,11 @@ ** Assign cursors to all tables in a SrcList */ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; struct SrcList_item *pItem; - assert(pList || sqlite3ThreadDataReadOnly()->mallocFailed); + assert(pList || sqlite3MallocFailed() ); if( pList ){ for(i=0, pItem=pList->a; inSrc; i++, pItem++){ if( pItem->iCursor>=0 ) break; pItem->iCursor = pParse->nTab++; if( pItem->pSelect ){ @@ -2903,11 +2906,11 @@ sqlite3 *db; Vdbe *v; int i; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( pParse->nErr || sqlite3MallocFailed() ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return; v = sqlite3GetVdbe(pParse); if( !v ) return; if( type!=TK_DEFERRED ){ @@ -2924,11 +2927,11 @@ void sqlite3CommitTransaction(Parse *pParse){ sqlite3 *db; Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( pParse->nErr || sqlite3MallocFailed() ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return; v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 0); @@ -2941,11 +2944,11 @@ void sqlite3RollbackTransaction(Parse *pParse){ sqlite3 *db; Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( pParse->nErr || sqlite3MallocFailed() ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return; v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 1); @@ -3152,11 +3155,11 @@ return; }else if( pName2==0 || pName2->z==0 ){ assert( pName1->z ); pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0); if( pColl ){ - char *z = sqliteStrNDup(pName1->z, pName1->n); + char *z = sqliteStrNDup((const char *)pName1->z, pName1->n); if( z ){ reindexDatabases(pParse, z); sqliteFree(z); } return; Index: SQLite.Interop/src/callback.c ================================================================== --- SQLite.Interop/src/callback.c +++ SQLite.Interop/src/callback.c @@ -11,11 +11,11 @@ ************************************************************************* ** ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. ** -** $Id: callback.c,v 1.11 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: callback.c,v 1.12 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" /* @@ -177,11 +177,11 @@ /* If a malloc() failure occured in sqlite3HashInsert(), it will ** return the pColl pointer to be deleted (because it wasn't added ** to the hash table). */ assert( !pDel || - (sqlite3ThreadDataReadOnly()->mallocFailed && pDel==pColl) ); + (sqlite3MallocFailed() && pDel==pColl) ); sqliteFree(pDel); } } return pColl; } Index: SQLite.Interop/src/complete.c ================================================================== --- SQLite.Interop/src/complete.c +++ SQLite.Interop/src/complete.c @@ -14,11 +14,11 @@ ** This file contains C code that implements the sqlite3_complete() API. ** This code used to be part of the tokenizer.c source file. But by ** separating it out, the code will be automatically omitted from ** static links that do not use it. ** -** $Id: complete.c,v 1.9 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: complete.c,v 1.10 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_COMPLETE /* @@ -253,14 +253,11 @@ pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zSql8 ){ rc = sqlite3_complete(zSql8); - }else if( zSql ){ - rc = SQLITE_NOMEM; - sqlite3MallocClearFailed(); } sqlite3ValueFree(pVal); - return rc; + return sqlite3ApiExit(0, rc); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_COMPLETE */ Index: SQLite.Interop/src/date.c ================================================================== --- SQLite.Interop/src/date.c +++ SQLite.Interop/src/date.c @@ -14,11 +14,11 @@ ** ** There is only one exported symbol in this file - the function ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: date.c,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: date.c,v 1.17 2006/01/23 19:45:55 rmsimpson Exp $ ** ** NOTES: ** ** SQLite processes all times and dates as Julian Day numbers. The ** dates and times are stored as the number of days since noon @@ -974,11 +974,11 @@ { "current_date", 0, cdateFunc }, }; int i; for(i=0; inErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( pParse->nErr || sqlite3MallocFailed() ){ goto delete_from_cleanup; } db = pParse->db; assert( pTabList->nSrc==1 ); Index: SQLite.Interop/src/experimental.c ================================================================== --- SQLite.Interop/src/experimental.c +++ SQLite.Interop/src/experimental.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that are not a part of the official ** SQLite API. These routines are unsupported. ** -** $Id: experimental.c,v 1.5 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: experimental.c,v 1.6 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" /* ** Set all the parameters in the compiled SQL statement to NULL. Index: SQLite.Interop/src/expr.c ================================================================== --- SQLite.Interop/src/expr.c +++ SQLite.Interop/src/expr.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.22 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: expr.c,v 1.23 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* @@ -261,11 +261,11 @@ ** text between the two given tokens. */ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){ assert( pRight!=0 ); assert( pLeft!=0 ); - if( !sqlite3ThreadDataReadOnly()->mallocFailed && pRight->z && pLeft->z ){ + if( !sqlite3MallocFailed() && 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; pExpr->span.n = pRight->n + (pRight->z - pLeft->z); }else{ @@ -278,23 +278,20 @@ ** Construct a new expression node for a function with multiple ** arguments. */ Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){ Expr *pNew; + assert( pToken ); pNew = sqliteMalloc( sizeof(Expr) ); if( pNew==0 ){ sqlite3ExprListDelete(pList); /* Avoid leaking memory when malloc fails */ return 0; } pNew->op = TK_FUNCTION; pNew->pList = pList; - if( pToken ){ - assert( pToken->dyn==0 ); - pNew->token = *pToken; - }else{ - pNew->token.z = 0; - } + assert( pToken->dyn==0 ); + pNew->token = *pToken; pNew->span = pNew->token; return pNew; } /* @@ -356,11 +353,11 @@ if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){ pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10; sqliteReallocOrFree((void**)&pParse->apVarExpr, pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) ); } - if( !sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( !sqlite3MallocFailed() ){ assert( pParse->apVarExpr!=0 ); pParse->apVarExpr[pParse->nVarExpr++] = pExpr; } } } @@ -461,11 +458,11 @@ ** the names of columns in the result set needs this information */ sqlite3TokenCopy(&pNewExpr->span, &pOldExpr->span); } assert( pNewExpr==0 || pNewExpr->span.z!=0 || pOldExpr->span.z==0 - || sqlite3ThreadDataReadOnly()->mallocFailed ); + || sqlite3MallocFailed() ); pItem->zName = sqliteStrDup(pOldItem->zName); pItem->sortOrder = pOldItem->sortOrder; pItem->isAgg = pOldItem->isAgg; pItem->done = 0; } @@ -830,11 +827,11 @@ assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */ zDb = sqlite3NameFromToken(pDbToken); zTab = sqlite3NameFromToken(pTableToken); zCol = sqlite3NameFromToken(pColumnToken); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ goto lookupname_end; } pExpr->iTable = -1; while( pNC && cnt==0 ){ @@ -1307,11 +1304,11 @@ */ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){ int mem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0); testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0); - assert( testAddr>0 || sqlite3ThreadDataReadOnly()->mallocFailed ); + assert( testAddr>0 || sqlite3MallocFailed() ); sqlite3VdbeAddOp(v, OP_MemInt, 1, mem); } switch( pExpr->op ){ case TK_IN: { @@ -2083,14 +2080,12 @@ ** Do a deep comparison of two expression trees. Return TRUE (non-zero) ** if they are identical and return FALSE if they differ in any way. */ int sqlite3ExprCompare(Expr *pA, Expr *pB){ int i; - if( pA==0 ){ - return pB==0; - }else if( pB==0 ){ - return 0; + if( pA==0||pB==0 ){ + return pB==pA; } if( pA->op!=pB->op ) return 0; if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0; if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0; if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0; Index: SQLite.Interop/src/func.c ================================================================== --- SQLite.Interop/src/func.c +++ SQLite.Interop/src/func.c @@ -14,11 +14,11 @@ ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.17 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: func.c,v 1.18 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* #include */ #include @@ -1022,11 +1022,11 @@ void *pArg = 0; switch( aFuncs[i].argType ){ case 1: pArg = db; break; case 2: pArg = (void *)(-1); break; } - sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg, + sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg, aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0); if( aFuncs[i].needCollSeq ){ FuncDef *pFunc = sqlite3FindFunction(db, aFuncs[i].zName, strlen(aFuncs[i].zName), aFuncs[i].nArg, aFuncs[i].eTextRep, 0); if( pFunc && aFuncs[i].needCollSeq ){ @@ -1044,11 +1044,11 @@ void *pArg = 0; switch( aAggs[i].argType ){ case 1: pArg = db; break; case 2: pArg = (void *)(-1); break; } - sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8, + sqlite3CreateFunc(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8, pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize); if( aAggs[i].needCollSeq ){ FuncDef *pFunc = sqlite3FindFunction( db, aAggs[i].zName, strlen(aAggs[i].zName), aAggs[i].nArg, SQLITE_UTF8, 0); if( pFunc && aAggs[i].needCollSeq ){ @@ -1088,13 +1088,13 @@ if( caseSensitive ){ pInfo = (struct compareInfo*)&likeInfoAlt; }else{ pInfo = (struct compareInfo*)&likeInfoNorm; } - sqlite3_create_function(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0); - sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0); - sqlite3_create_function(db, "glob", 2, SQLITE_UTF8, + sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0); + sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0); + sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, (struct compareInfo*)&globInfo, likeFunc, 0,0); setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE); setLikeOptFlag(db, "like", caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE); } Index: SQLite.Interop/src/hash.c ================================================================== --- SQLite.Interop/src/hash.c +++ SQLite.Interop/src/hash.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This is the implementation of generic hash-tables ** used in SQLite. ** -** $Id: hash.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: hash.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* Turn bulk memory into a hash table object by initializing the Index: SQLite.Interop/src/hash.h ================================================================== --- SQLite.Interop/src/hash.h +++ SQLite.Interop/src/hash.h @@ -10,11 +10,11 @@ ** ************************************************************************* ** This is the header file for the generic hash-table implemenation ** used in SQLite. ** -** $Id: hash.h,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: hash.h,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #ifndef _SQLITE_HASH_H_ #define _SQLITE_HASH_H_ /* Forward declarations of structures. */ Index: SQLite.Interop/src/insert.c ================================================================== --- SQLite.Interop/src/insert.c +++ SQLite.Interop/src/insert.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: insert.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" /* ** Set P3 of the most recently inserted opcode to a column affinity @@ -220,14 +220,14 @@ int isView; /* True if attempting to insert into a view */ int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */ #endif #ifndef SQLITE_OMIT_AUTOINCREMENT - int counterRowid; /* Memory cell holding rowid of autoinc counter */ + int counterRowid = 0; /* Memory cell holding rowid of autoinc counter */ #endif - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( pParse->nErr || sqlite3MallocFailed() ){ goto insert_cleanup; } db = pParse->db; /* Locate the table into which we will be inserting new information. @@ -331,11 +331,11 @@ iSelectLoop = sqlite3VdbeCurrentAddr(v); iInsertBlock = sqlite3VdbeMakeLabel(v); /* 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 || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( rc || pParse->nErr || sqlite3MallocFailed() ){ goto insert_cleanup; } iCleanup = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup); Index: SQLite.Interop/src/legacy.c ================================================================== --- SQLite.Interop/src/legacy.c +++ SQLite.Interop/src/legacy.c @@ -12,11 +12,11 @@ ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: legacy.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: legacy.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -66,12 +66,12 @@ db->nChange += nChange; nCallback = 0; nCol = sqlite3_column_count(pStmt); - azCols = sqliteMalloc(2*nCol*sizeof(const char *)); - if( nCol && !azCols ){ + azCols = sqliteMalloc(2*nCol*sizeof(const char *) + 1); + if( azCols==0 ){ goto exec_out; } while( 1 ){ int i; @@ -119,15 +119,11 @@ exec_out: if( pStmt ) sqlite3_finalize(pStmt); if( azCols ) sqliteFree(azCols); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ - rc = SQLITE_NOMEM; - sqlite3MallocClearFailed(); - } - + rc = sqlite3ApiExit(0, rc); if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){ *pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db))); if( *pzErrMsg ){ strcpy(*pzErrMsg, sqlite3_errmsg(db)); } Index: SQLite.Interop/src/main.c ================================================================== --- SQLite.Interop/src/main.c +++ SQLite.Interop/src/main.c @@ -12,11 +12,11 @@ ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: main.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -384,13 +384,16 @@ ** Note that we need to call free() not sqliteFree() here. */ void sqlite3_free(char *p){ free(p); } /* -** Create new user functions. +** This function is exactly the same as sqlite3_create_function(), except +** that it is designed to be called by internal code. The difference is +** that if a malloc() fails in sqlite3_create_function(), an error code +** is returned and the mallocFailed flag cleared. */ -int sqlite3_create_function( +int sqlite3CreateFunc( sqlite3 *db, const char *zFunctionName, int nArg, int enc, void *pUserData, @@ -423,14 +426,14 @@ */ if( enc==SQLITE_UTF16 ){ enc = SQLITE_UTF16NATIVE; }else if( enc==SQLITE_ANY ){ int rc; - rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF8, + rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8, pUserData, xFunc, xStep, xFinal); if( rc!=SQLITE_OK ) return rc; - rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF16LE, + rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE, pUserData, xFunc, xStep, xFinal); if( rc!=SQLITE_OK ) return rc; enc = SQLITE_UTF16BE; } #else @@ -445,50 +448,68 @@ p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 0); if( p && p->iPrefEnc==enc && p->nArg==nArg ){ if( db->activeVdbeCnt ){ sqlite3Error(db, SQLITE_BUSY, "Unable to delete/modify user-function due to active statements"); + assert( !sqlite3MallocFailed() ); return SQLITE_BUSY; }else{ sqlite3ExpirePreparedStatements(db); } } p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1); - if( p==0 ) return SQLITE_NOMEM; - p->flags = 0; - p->xFunc = xFunc; - p->xStep = xStep; - p->xFinalize = xFinal; - p->pUserData = pUserData; + if( p ){ + p->flags = 0; + p->xFunc = xFunc; + p->xStep = xStep; + p->xFinalize = xFinal; + p->pUserData = pUserData; + } return SQLITE_OK; } + +/* +** Create new user functions. +*/ +int sqlite3_create_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int enc, + void *p, + void (*xFunc)(sqlite3_context*,int,sqlite3_value **), + void (*xStep)(sqlite3_context*,int,sqlite3_value **), + void (*xFinal)(sqlite3_context*) +){ + int rc; + assert( !sqlite3MallocFailed() ); + rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal); + + return sqlite3ApiExit(db, rc); +} + #ifndef SQLITE_OMIT_UTF16 int sqlite3_create_function16( sqlite3 *db, const void *zFunctionName, int nArg, int eTextRep, - void *pUserData, + void *p, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ){ int rc; char *zFunc8; + assert( !sqlite3MallocFailed() ); - if( sqlite3SafetyCheck(db) ){ - return SQLITE_MISUSE; - } zFunc8 = sqlite3utf16to8(zFunctionName, -1); - if( !zFunc8 ){ - return SQLITE_NOMEM; - } - rc = sqlite3_create_function(db, zFunc8, nArg, eTextRep, - pUserData, xFunc, xStep, xFinal); + rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal); sqliteFree(zFunc8); - return rc; + + return sqlite3ApiExit(db, rc); } #endif #ifndef SQLITE_OMIT_TRACE /* @@ -643,11 +664,11 @@ ** Return UTF-8 encoded English language explanation of the most recent ** error. */ const char *sqlite3_errmsg(sqlite3 *db){ const char *z; - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( !db || sqlite3MallocFailed() ){ return sqlite3ErrStr(SQLITE_NOMEM); } if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ return sqlite3ErrStr(SQLITE_MISUSE); } @@ -682,11 +703,11 @@ 0, 'o', 0, 'f', 0, ' ', 0, 's', 0, 'e', 0, 'q', 0, 'u', 0, 'e', 0, 'n', 0, 'c', 0, 'e', 0, 0, 0 }; const void *z; - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ 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]); } @@ -694,27 +715,82 @@ if( z==0 ){ sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode), SQLITE_UTF8, SQLITE_STATIC); z = sqlite3_value_text16(db->pErr); } + sqlite3ApiExit(0, 0); return z; } #endif /* SQLITE_OMIT_UTF16 */ /* ** Return the most recent error code generated by an SQLite routine. If NULL is ** passed to this function, we assume a malloc() failed during sqlite3_open(). */ int sqlite3_errcode(sqlite3 *db){ - if( !db || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( !db || sqlite3MallocFailed() ){ return SQLITE_NOMEM; } if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } return db->errCode; } + +static int createCollation( + sqlite3* db, + const char *zName, + int enc, + void* pCtx, + int(*xCompare)(void*,int,const void*,int,const void*) +){ + CollSeq *pColl; + + if( sqlite3SafetyCheck(db) ){ + return SQLITE_MISUSE; + } + + /* If SQLITE_UTF16 is specified as the encoding type, transform this + ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the + ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. + */ + if( enc==SQLITE_UTF16 ){ + enc = SQLITE_UTF16NATIVE; + } + + if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){ + sqlite3Error(db, SQLITE_ERROR, + "Param 3 to sqlite3_create_collation() must be one of " + "SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE" + ); + return SQLITE_ERROR; + } + + /* Check if this call is removing or replacing an existing collation + ** sequence. If so, and there are active VMs, return busy. If there + ** are no active VMs, invalidate any pre-compiled statements. + */ + pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0); + if( pColl && pColl->xCmp ){ + if( db->activeVdbeCnt ){ + sqlite3Error(db, SQLITE_BUSY, + "Unable to delete/modify collation sequence due to active statements"); + return SQLITE_BUSY; + } + sqlite3ExpirePreparedStatements(db); + } + + pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1); + if( pColl ){ + pColl->xCmp = xCompare; + pColl->pUser = pCtx; + pColl->enc = enc; + } + sqlite3Error(db, SQLITE_OK, 0); + return SQLITE_OK; +} + /* ** This routine does the work of opening a database on behalf of ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" ** is UTF-8 encoded. @@ -725,11 +801,11 @@ ){ sqlite3 *db; int rc; CollSeq *pColl; - assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); + assert( !sqlite3MallocFailed() ); /* Allocate the sqlite data structure */ db = sqliteMalloc( sizeof(sqlite3) ); if( db==0 ) goto opendb_out; db->priorNewRowid = 0; @@ -739,37 +815,25 @@ db->autoCommit = 1; db->flags |= SQLITE_ShortColNames; sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); -#if 0 - for(i=0; inDb; i++){ - sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0); - sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0); - sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0); - sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1); - } -#endif - /* 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. */ - if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) || - sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) || + if( createCollation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) || + createCollation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) || (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0 ){ - /* sqlite3_create_collation() is an external API. So the mallocFailed flag - ** will have been cleared before returning. So set it explicitly here. - */ - sqlite3ThreadData()->mallocFailed = 1; + assert( sqlite3MallocFailed() ); db->magic = SQLITE_MAGIC_CLOSED; goto opendb_out; } /* Also add a UTF-8 case-insensitive collation sequence. */ - sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc); + createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc); /* Set flags on the built-in collating sequences */ db->pDfltColl->type = SQLITE_COLL_BINARY; pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "NOCASE", 6, 0); if( pColl ){ @@ -804,22 +868,23 @@ /* Register all built-in functions, but do not attempt to read the ** database schema yet. This is delayed until the first time the database ** is accessed. */ - sqlite3RegisterBuiltinFunctions(db); - sqlite3Error(db, SQLITE_OK, 0); + if( !sqlite3MallocFailed() ){ + sqlite3RegisterBuiltinFunctions(db); + sqlite3Error(db, SQLITE_OK, 0); + } db->magic = SQLITE_MAGIC_OPEN; opendb_out: if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){ sqlite3_close(db); db = 0; } *ppDb = db; - sqlite3MallocClearFailed(); - return rc; + return sqlite3ApiExit(0, rc); } /* ** Open a new database handle. */ @@ -837,11 +902,11 @@ int sqlite3_open16( const void *zFilename, sqlite3 **ppDb ){ char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */ - int rc = SQLITE_NOMEM; + int rc = SQLITE_OK; sqlite3_value *pVal; assert( zFilename ); assert( ppDb ); *ppDb = 0; @@ -850,18 +915,19 @@ zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zFilename8 ){ rc = openDatabase(zFilename8, ppDb); if( rc==SQLITE_OK && *ppDb ){ rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); + if( rc!=SQLITE_OK ){ + sqlite3_close(*ppDb); + *ppDb = 0; + } } - }else{ - assert( sqlite3ThreadDataReadOnly()->mallocFailed ); - sqlite3MallocClearFailed(); } sqlite3ValueFree(pVal); - return rc; + return sqlite3ApiExit(0, rc); } #endif /* SQLITE_OMIT_UTF16 */ /* ** The following routine destroys a virtual machine that is created by @@ -909,57 +975,14 @@ const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ - CollSeq *pColl; - int rc = SQLITE_OK; - - if( sqlite3SafetyCheck(db) ){ - return SQLITE_MISUSE; - } - - /* If SQLITE_UTF16 is specified as the encoding type, transform this - ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the - ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. - */ - if( enc==SQLITE_UTF16 ){ - enc = SQLITE_UTF16NATIVE; - } - - if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){ - sqlite3Error(db, SQLITE_ERROR, - "Param 3 to sqlite3_create_collation() must be one of " - "SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE" - ); - return SQLITE_ERROR; - } - - /* Check if this call is removing or replacing an existing collation - ** sequence. If so, and there are active VMs, return busy. If there - ** are no active VMs, invalidate any pre-compiled statements. - */ - pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0); - if( pColl && pColl->xCmp ){ - if( db->activeVdbeCnt ){ - sqlite3Error(db, SQLITE_BUSY, - "Unable to delete/modify collation sequence due to active statements"); - return SQLITE_BUSY; - } - sqlite3ExpirePreparedStatements(db); - } - - pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1); - if( 0==pColl ){ - rc = SQLITE_NOMEM; - }else{ - pColl->xCmp = xCompare; - pColl->pUser = pCtx; - pColl->enc = enc; - } - sqlite3Error(db, rc, 0); - return rc; + int rc; + assert( !sqlite3MallocFailed() ); + rc = createCollation(db, zName, enc, pCtx, xCompare); + return sqlite3ApiExit(db, rc); } #ifndef SQLITE_OMIT_UTF16 /* ** Register a new collation sequence with the database handle db. @@ -969,19 +992,19 @@ const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ - char *zName8; - int rc; - if( sqlite3SafetyCheck(db) ){ - return SQLITE_MISUSE; - } - zName8 = sqlite3utf16to8(zName, -1); - rc = sqlite3_create_collation(db, zName8, enc, pCtx, xCompare); - sqliteFree(zName8); - return rc; + int rc = SQLITE_OK; + char *zName8; + assert( !sqlite3MallocFailed() ); + zName8 = sqlite3utf16to8(zName, -1); + if( zName8 ){ + rc = createCollation(db, zName8, enc, pCtx, xCompare); + sqliteFree(zName8); + } + return sqlite3ApiExit(db, rc); } #endif /* SQLITE_OMIT_UTF16 */ /* ** Register a collation sequence factory callback with the database handle @@ -1063,10 +1086,13 @@ ** 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 ){ + return SQLITE_NOMEM; + } /* 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). @@ -1085,9 +1111,11 @@ /* ** This is a convenience routine that makes sure that all thread-specific ** data for this thread has been deallocated. */ void sqlite3_thread_cleanup(void){ - ThreadData *pTd = sqlite3ThreadData(); - memset(pTd, 0, sizeof(*pTd)); - sqlite3ReleaseThreadData(); + ThreadData *pTd = sqlite3OsThreadSpecificData(0); + if( pTd ){ + memset(pTd, 0, sizeof(*pTd)); + sqlite3OsThreadSpecificData(-1); + } } Index: SQLite.Interop/src/os.h ================================================================== --- SQLite.Interop/src/os.h +++ SQLite.Interop/src/os.h @@ -289,11 +289,11 @@ int sqlite3OsRandomSeed(char*); int sqlite3OsSleep(int ms); int sqlite3OsCurrentTime(double*); void sqlite3OsEnterMutex(void); void sqlite3OsLeaveMutex(void); -int sqlite3OsInMutex(void); +int sqlite3OsInMutex(int); ThreadData *sqlite3OsThreadSpecificData(int); void *sqlite3OsMalloc(int); void *sqlite3OsRealloc(void *, int); void sqlite3OsFree(void *); int sqlite3OsAllocationSize(void *); @@ -332,11 +332,11 @@ int (*xSleep)(int ms); int (*xCurrentTime)(double*); void (*xEnterMutex)(void); void (*xLeaveMutex)(void); - int (*xInMutex)(void); + int (*xInMutex)(int); ThreadData *(*xThreadSpecificData)(int); void *(*xMalloc)(int); void *(*xRealloc)(void *, int); void (*xFree)(void *); Index: SQLite.Interop/src/os_common.h ================================================================== --- SQLite.Interop/src/os_common.h +++ SQLite.Interop/src/os_common.h @@ -181,11 +181,8 @@ } void sqlite3GenericFree(void *p){ assert(p); free(p); } -#if 0 /* Never actually invoked */ -int sqlite3GenericAllocationSize(void *p){ - assert(0); -} -#endif +/* Never actually used, but needed for the linker */ +int sqlite3GenericAllocationSize(void *p){ return 0; } #endif Index: SQLite.Interop/src/os_unix.c ================================================================== --- SQLite.Interop/src/os_unix.c +++ SQLite.Interop/src/os_unix.c @@ -476,11 +476,11 @@ /* ** Release a lockInfo structure previously allocated by findLockInfo(). */ static void releaseLockInfo(struct lockInfo *pLock){ - assert( sqlite3OsInMutex() ); + assert( sqlite3OsInMutex(1) ); pLock->nRef--; if( pLock->nRef==0 ){ sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0); sqliteFree(pLock); } @@ -488,11 +488,11 @@ /* ** Release a openCnt structure previously allocated by findLockInfo(). */ static void releaseOpenCnt(struct openCnt *pOpen){ - assert( sqlite3OsInMutex() ); + assert( sqlite3OsInMutex(1) ); pOpen->nRef--; if( pOpen->nRef==0 ){ sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0); free(pOpen->aPending); sqliteFree(pOpen); @@ -518,11 +518,11 @@ struct lockInfo *pLock; struct openCnt *pOpen; rc = fstat(fd, &statbuf); if( rc!=0 ) return 1; - assert( sqlite3OsInMutex() ); + assert( sqlite3OsInMutex(1) ); memset(&key1, 0, sizeof(key1)); key1.dev = statbuf.st_dev; key1.ino = statbuf.st_ino; #ifdef SQLITE_UNIX_THREADS if( threadsOverrideEachOthersLocks<0 ){ @@ -691,12 +691,10 @@ int rc; unixFile f; CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly); assert( 0==*pId ); - f.dirfd = -1; - SET_THREADID(&f); f.h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, SQLITE_DEFAULT_FILE_PERMISSIONS); if( f.h<0 ){ #ifdef EISDIR if( errno==EISDIR ){ @@ -716,11 +714,10 @@ sqlite3OsLeaveMutex(); if( rc ){ close(f.h); return SQLITE_NOMEM; } - f.locktype = 0; TRACE3("OPEN %-3d %s\n", f.h, zFilename); return allocateUnixFile(&f, pId); } @@ -745,12 +742,10 @@ CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag); assert( 0==*pId ); if( access(zFilename, 0)==0 ){ return SQLITE_CANTOPEN; } - SET_THREADID(&f); - f.dirfd = -1; f.h = open(zFilename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, SQLITE_DEFAULT_FILE_PERMISSIONS); if( f.h<0 ){ return SQLITE_CANTOPEN; @@ -761,11 +756,10 @@ if( rc ){ close(f.h); unlink(zFilename); return SQLITE_NOMEM; } - f.locktype = 0; if( delFlag ){ unlink(zFilename); } TRACE3("OPEN-EX %-3d %s\n", f.h, zFilename); return allocateUnixFile(&f, pId); @@ -782,12 +776,10 @@ int rc; unixFile f; CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0); assert( 0==*pId ); - SET_THREADID(&f); - f.dirfd = -1; f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( f.h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); @@ -795,13 +787,11 @@ sqlite3OsLeaveMutex(); if( rc ){ close(f.h); return SQLITE_NOMEM; } - f.locktype = 0; TRACE3("OPEN-RO %-3d %s\n", f.h, zFilename); - return allocateUnixFile(&f, pId); } /* ** Attempt to open a file descriptor for the directory that contains a @@ -1469,11 +1459,10 @@ /* ** Close a file. */ static int unixClose(OsFile **pId){ unixFile *id = (unixFile*)*pId; - int rc; if( !id ) return SQLITE_OK; unixUnlock(*pId, NO_LOCK); if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; @@ -1506,11 +1495,11 @@ id->isOpen = 0; TRACE2("CLOSE %-3d\n", id->h); OpenCounter(-1); sqliteFree(id); *pId = 0; - return rc; + return SQLITE_OK; } /* ** Turn a relative pathname into a full pathname. Return a pointer ** to the full pathname stored in space obtained from sqliteMalloc(). @@ -1582,10 +1571,14 @@ ** 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. */ static int allocateUnixFile(unixFile *pInit, OsFile **pId){ unixFile *pNew; + pInit->dirfd = -1; + pInit->fullSync = 0; + pInit->locktype = 0; + SET_THREADID(pInit); pNew = sqliteMalloc( sizeof(unixFile) ); if( pNew==0 ){ close(pInit->h); sqlite3OsEnterMutex(); releaseLockInfo(pInit->pLock); @@ -1665,11 +1658,13 @@ /* ** Static variables used for thread synchronization */ static int inMutex = 0; #ifdef SQLITE_UNIX_THREADS -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_t mutexOwner; +static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; #endif /* ** The following pair of routine implement mutual exclusion for ** multi-threaded processes. Only a single thread is allowed to @@ -1676,32 +1671,52 @@ ** 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. ** -** This mutex is not recursive. +** As of version 3.3.2, this mutex must be recursive. */ void sqlite3UnixEnterMutex(){ #ifdef SQLITE_UNIX_THREADS - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&mutex1); + if( inMutex==0 ){ + pthread_mutex_lock(&mutex2); + mutexOwner = pthread_self(); + } + pthread_mutex_unlock(&mutex1); #endif - assert( !inMutex ); - inMutex = 1; + inMutex++; } void sqlite3UnixLeaveMutex(){ - assert( inMutex ); - inMutex = 0; + assert( inMutex>0 ); #ifdef SQLITE_UNIX_THREADS - pthread_mutex_unlock(&mutex); + assert( pthread_equal(mutexOwner, pthread_self()) ); + pthread_mutex_lock(&mutex1); + inMutex--; + if( inMutex==0 ){ + pthread_mutex_unlock(&mutex2); + } + pthread_mutex_unlock(&mutex1); +#else + inMutex--; #endif } /* -** Return TRUE if we are currently within the mutex and FALSE if not. +** Return TRUE if the mutex is currently held. +** +** If the thisThreadOnly 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(){ - return inMutex; +int sqlite3UnixInMutex(int thisThreadOnly){ +#ifdef SQLITE_UNIX_THREADS + return inMutex>0 && + (thisThreadOnly==0 || pthread_equal(mutexOwner, pthread_self())); +#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. @@ -1719,11 +1734,10 @@ # 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. @@ -1759,19 +1773,24 @@ } pTsd = pthread_getspecific(key); if( allocateFlag>0 ){ if( pTsd==0 ){ - pTsd = sqlite3OsMalloc(sizeof(zeroData)); + 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(zeroData))==0 ){ + && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ sqlite3OsFree(pTsd); pthread_setspecific(key, 0); TSD_COUNTER(-1); pTsd = 0; } @@ -1778,18 +1797,23 @@ return pTsd; #else static ThreadData *pTsd = 0; if( allocateFlag>0 ){ if( pTsd==0 ){ - pTsd = sqlite3OsMalloc( sizeof(zeroData) ); + 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(zeroData))==0 ){ + && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ sqlite3OsFree(pTsd); TSD_COUNTER(-1); pTsd = 0; } return pTsd; Index: SQLite.Interop/src/os_win.c ================================================================== --- SQLite.Interop/src/os_win.c +++ SQLite.Interop/src/os_win.c @@ -601,12 +601,10 @@ *pReadonly = 0; } #endif /* OS_WINCE */ } f.h = h; - f.locktype = NO_LOCK; - f.sharedLockByte = 0; #if OS_WINCE f.zDeleteOnClose = 0; #endif TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename); return allocateWinFile(&f, pId); @@ -665,15 +663,12 @@ } if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } f.h = h; - f.locktype = NO_LOCK; - f.sharedLockByte = 0; #if OS_WINCE f.zDeleteOnClose = delFlag ? utf8ToUnicode(zFilename) : 0; - f.hMutex = NULL; #endif TRACE3("OPEN EX %d \"%s\"\n", h, zFilename); return allocateWinFile(&f, pId); } @@ -715,15 +710,12 @@ } if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } f.h = h; - f.locktype = NO_LOCK; - f.sharedLockByte = 0; #if OS_WINCE f.zDeleteOnClose = 0; - f.hMutex = NULL; #endif TRACE3("OPEN RO %d \"%s\"\n", h, zFilename); return allocateWinFile(&f, pId); } @@ -1306,11 +1298,17 @@ *pId = 0; return SQLITE_NOMEM; }else{ *pNew = *pInit; pNew->pMethod = &sqlite3WinIoMethod; + pNew->locktype = NO_LOCK; + pNew->sharedLockByte = 0; +#if OS_WINCE + pNew->hMutex = NULL; +#endif *pId = (OsFile*)pNew; + OpenCounter(+1); return SQLITE_OK; } } @@ -1354,20 +1352,24 @@ /* ** 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 routine implement mutual exclusion for +** 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 ){ @@ -1378,27 +1380,36 @@ }else{ Sleep(1); } } EnterCriticalSection(&cs); + mutexOwner = GetCurrentThreadId(); #endif - assert( !inMutex ); - inMutex = 1; + inMutex++; } void sqlite3WinLeaveMutex(){ assert( inMutex ); - inMutex = 0; + inMutex--; #ifdef SQLITE_W32_THREADS + assert( mutexOwner==GetCurrentThreadId() ); LeaveCriticalSection(&cs); #endif } /* -** Return TRUE if we are currently within the mutex and FALSE if not. +** 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(){ - return inMutex; +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 @@ -1493,14 +1504,14 @@ TlsSetValue(key, pTsd); TSD_COUNTER_INCR; } } }else if( pTsd!=0 && allocateFlag<0 - && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){ + && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ sqlite3OsFree(pTsd); TlsSetValue(key, 0); TSD_COUNTER_DECR; pTsd = 0; } return pTsd; } #endif /* OS_WIN */ Index: SQLite.Interop/src/pager.c ================================================================== --- SQLite.Interop/src/pager.c +++ SQLite.Interop/src/pager.c @@ -16,11 +16,11 @@ ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.17 2006/01/16 15:51:47 rmsimpson Exp $ +** @(#) $Id: pager.c,v 1.18 2006/01/23 19:45:55 rmsimpson Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "os.h" #include "pager.h" @@ -427,22 +427,22 @@ /* ** 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){ - unsigned char ac[4]; + char ac[4]; put32bits(ac, val); return sqlite3OsWrite(fd, ac, 4); } /* ** Write the 32-bit integer 'val' into the page identified by page header ** 'p' at offset 'offset'. */ static void store32bits(u32 val, PgHdr *p, int offset){ - unsigned char *ac; - ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset]; + char *ac; + ac = &((char*)PGHDR_TO_DATA(p))[offset]; put32bits(ac, val); } /* ** Read a 32-bit integer at offset 'offset' from the page identified by @@ -466,12 +466,12 @@ ** will immediately return the same error code. */ static int pager_error(Pager *pPager, int rc){ assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK ); if( - rc==SQLITE_FULL || - rc==SQLITE_IOERR || + rc==SQLITE_FULL || + rc==SQLITE_IOERR || rc==SQLITE_CORRUPT || rc==SQLITE_PROTOCOL ){ pPager->errCode = rc; } @@ -907,10 +907,12 @@ } rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; pPager->origDbSize = 0; pPager->setMaster = 0; + pPager->needSync = 0; + pPager->pFirstSynced = pPager->pFirst; return rc; } /* ** Compute and return a checksum for the page of data. @@ -1460,13 +1462,11 @@ } pPager->journalOff = szJ; end_stmt_playback: - if( rc!=SQLITE_OK ){ - rc = pager_error(pPager, SQLITE_CORRUPT); - }else{ + if( rc==SQLITE_OK) { pPager->journalOff = szJ; /* pager_reload_cache(pPager); */ } return rc; } @@ -1564,11 +1564,11 @@ int nExtra, /* Extra bytes append to each in-memory page */ int flags /* flags controlling this file */ ){ Pager *pPager = 0; char *zFullPathname = 0; - int nameLen; + int nameLen; /* Compiler is wrong. This is always initialized before use */ OsFile *fd; int rc = SQLITE_OK; int i; int tempFile = 0; int memDb = 0; @@ -1575,19 +1575,27 @@ 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 - const ThreadData *pTsdro = sqlite3ThreadDataReadOnly(); + /* 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 /* If malloc() has already failed return SQLITE_NOMEM. Before even ** testing for this, set *ppPager to NULL so the caller knows the pager ** structure was never allocated. */ *ppPager = 0; - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ return SQLITE_NOMEM; } memset(&fd, 0, sizeof(fd)); /* Open the pager file and set zFullPathname to point at malloc()ed @@ -1678,15 +1686,12 @@ pPager->sectorSize = PAGER_SECTOR_SIZE; /* pPager->pBusyHandler = 0; */ /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ *ppPager = pPager; #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - if( pTsdro->useMemoryManagement ){ - ThreadData *pTsd = sqlite3ThreadData(); - pPager->pNext = pTsd->pPager; - pTsd->pPager = pPager; - } + pPager->pNext = pTsd->pPager; + pTsd->pPager = pPager; #endif return SQLITE_OK; } /* @@ -1986,11 +1991,18 @@ ** to the caller. */ int sqlite3pager_close(Pager *pPager){ PgHdr *pPg, *pNext; #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - const ThreadData *pTsd = sqlite3ThreadDataReadOnly(); + /* 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 ); #endif switch( pPager->state ){ case PAGER_RESERVED: case PAGER_SYNCED: @@ -2049,18 +2061,16 @@ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* Remove the pager from the linked list of pagers starting at ** ThreadData.pPager if memory-management is enabled. */ - if( pTsd->useMemoryManagement ){ - 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; - } + 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 #ifdef SQLITE_HAS_CODEC sqlite3pager_free_codecarg(pPager->pCodecArg); @@ -2429,11 +2439,11 @@ /* 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. */ - if( sqlite3OsInMutex() ){ + if( sqlite3OsInMutex(0) ){ return 0; } /* Outermost loop runs for at most two iterations. First iteration we ** try to find memory that can be released without calling fsync(). Second @@ -2631,11 +2641,11 @@ pPager->nMaxPage++; } }else{ rc = pager_recycle(pPager, 1, &pPg); if( rc!=SQLITE_OK ){ - return pager_error(pPager, rc); + return rc; } assert(pPg) ; } pPg->pgno = pgno; if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ @@ -2654,26 +2664,24 @@ page_remove_from_stmt_list(pPg); } pPg->dirty = 0; pPg->nRef = 1; REFINFO(pPg); + pPager->nRef++; - h = pager_hash(pgno); - pPg->pNextHash = pPager->aHash[h]; - pPager->aHash[h] = pPg; - if( pPg->pNextHash ){ - assert( pPg->pNextHash->pPrevHash==0 ); - pPg->pNextHash->pPrevHash = pPg; - } if( pPager->nExtra>0 ){ memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra); } if( pPager->errCode ){ sqlite3pager_unref(PGHDR_TO_DATA(pPg)); rc = pPager->errCode; return rc; } + + /* Populate the page with data, either by reading from the database + ** file, or by setting the entire page to zero. + */ if( sqlite3pager_pagecount(pPager)<(int)pgno ){ memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); }else{ int rc; assert( MEMDB==0 ); @@ -2684,22 +2692,35 @@ } TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno); CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3); if( rc!=SQLITE_OK ){ i64 fileSize; - if( sqlite3OsFileSize(pPager->fd,&fileSize)!=SQLITE_OK - || fileSize>=pgno*pPager->pageSize ){ + int rc2 = sqlite3OsFileSize(pPager->fd, &fileSize); + if( rc2!=SQLITE_OK || fileSize>=pgno*pPager->pageSize ){ + /* An IO error occured in one of the the sqlite3OsSeek() or + ** sqlite3OsRead() calls above. */ + pPg->pgno = 0; sqlite3pager_unref(PGHDR_TO_DATA(pPg)); - return pager_error(pPager, rc); + return rc; }else{ clear_simulated_io_error(); memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); } }else{ TEST_INCR(pPager->nRead); } } + + /* Link the page into the page hash table */ + h = pager_hash(pgno); + pPg->pNextHash = pPager->aHash[h]; + pPager->aHash[h] = pPg; + if( pPg->pNextHash ){ + assert( pPg->pNextHash->pPrevHash==0 ); + pPg->pNextHash->pPrevHash = pPg; + } + #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif }else{ /* The requested page is in the page cache. */ @@ -3008,23 +3029,25 @@ cksum = pager_cksum(pPager, pPg->pgno, pData); saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager); store32bits(cksum, pPg, pPager->pageSize); szPg = pPager->pageSize+8; store32bits(pPg->pgno, pPg, -4); + rc = sqlite3OsWrite(pPager->jfd, &((char*)pData)[-4], szPg); pPager->journalOff += szPg; TRACE4("JOURNAL %d page %d needSync=%d\n", PAGERID(pPager), pPg->pgno, pPg->needSync); CODEC(pPager, pData, pPg->pgno, 0); *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved; + + /* An error has occured writing to the journal file. The + ** transaction will be rolled back by the layer above. + */ if( rc!=SQLITE_OK ){ - sqlite3pager_rollback(pPager); - if( !pPager->errCode ){ - pager_error(pPager, SQLITE_FULL); - } return rc; } + pPager->nRec++; assert( pPager->aInJournal!=0 ); pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); pPg->needSync = !pPager->noSync; if( pPager->stmtInUse ){ @@ -3064,14 +3087,10 @@ rc = sqlite3OsWrite(pPager->stfd,((char*)pData)-4, pPager->pageSize+4); TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); CODEC(pPager, pData, pPg->pgno, 0); if( rc!=SQLITE_OK ){ - sqlite3pager_rollback(pPager); - if( !pPager->errCode ){ - pager_error(pPager, SQLITE_FULL); - } return rc; } pPager->stmtNRec++; assert( pPager->aInStmt!=0 ); pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); @@ -3094,14 +3113,16 @@ /* ** Return TRUE if the page given in the argument was previously passed ** to sqlite3pager_write(). In other words, return TRUE if it is ok ** to change the content of the page. */ +#ifndef NDEBUG int sqlite3pager_iswriteable(void *pData){ PgHdr *pPg = DATA_TO_PGHDR(pData); return pPg->dirty; } +#endif #ifndef SQLITE_OMIT_VACUUM /* ** Replace the content of a single page with the information in the third ** argument. @@ -3227,20 +3248,12 @@ */ int sqlite3pager_commit(Pager *pPager){ int rc; PgHdr *pPg; - if( pPager->errCode==SQLITE_FULL ){ - rc = sqlite3pager_rollback(pPager); - if( rc==SQLITE_OK ){ - rc = SQLITE_FULL; - } - return rc; - } if( pPager->errCode ){ - rc = pPager->errCode; - return rc; + return pPager->errCode; } if( pPager->statedbSize = -1; return rc; } assert( pPager->journalOpen ); rc = sqlite3pager_sync(pPager, 0, 0); - if( rc!=SQLITE_OK ){ - goto commit_abort; - } - rc = pager_unwritelock(pPager); - pPager->dbSize = -1; - return rc; - - /* Jump here if anything goes wrong during the commit process. - */ -commit_abort: - sqlite3pager_rollback(pPager); + if( rc==SQLITE_OK ){ + rc = pager_unwritelock(pPager); + pPager->dbSize = -1; + } return rc; } /* ** Rollback all changes. The database falls back to PAGER_SHARED mode. @@ -3362,16 +3368,17 @@ rc = rc2; } }else{ rc = pager_playback(pPager); } - if( rc!=SQLITE_OK ){ - rc = SQLITE_CORRUPT_BKPT; - pager_error(pPager, SQLITE_CORRUPT); - } pPager->dbSize = -1; - return rc; + + /* If an error occurs during a ROLLBACK, we can no longer trust the pager + ** cache. So call pager_error() on the way out to make any error + ** persistent. + */ + return pager_error(pPager, rc); } /* ** Return TRUE if the database file is opened read-only. Return FALSE ** if the database is (in theory) writable. Index: SQLite.Interop/src/pager.h ================================================================== --- SQLite.Interop/src/pager.h +++ SQLite.Interop/src/pager.h @@ -11,11 +11,11 @@ ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** -** @(#) $Id: pager.h,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** @(#) $Id: pager.h,v 1.17 2006/01/23 19:45:55 rmsimpson Exp $ */ #ifndef _PAGER_H_ #define _PAGER_H_ Index: SQLite.Interop/src/parse.c ================================================================== --- SQLite.Interop/src/parse.c +++ SQLite.Interop/src/parse.c @@ -21,11 +21,11 @@ /* ** An instance of this structure is used to store the LIKE, ** GLOB, NOT LIKE, and NOT GLOB operators. */ struct LikeOp { - Token operator; /* "like" or "glob" or "regexp" */ + Token eOperator; /* "like" or "glob" or "regexp" */ int not; /* True if the NOT keyword is present */ }; /* ** An instance of the following structure describes the event of a @@ -2585,16 +2585,16 @@ {yygotominor.yy178 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy178, yymsp[0].minor.yy178, 0);} #line 2588 "parse.c" break; case 198: #line 685 "parse.y" -{yygotominor.yy440.operator = yymsp[0].minor.yy0; yygotominor.yy440.not = 0;} +{yygotominor.yy440.eOperator = yymsp[0].minor.yy0; yygotominor.yy440.not = 0;} #line 2593 "parse.c" break; case 199: #line 686 "parse.y" -{yygotominor.yy440.operator = yymsp[0].minor.yy0; yygotominor.yy440.not = 1;} +{yygotominor.yy440.eOperator = yymsp[0].minor.yy0; yygotominor.yy440.not = 1;} #line 2598 "parse.c" break; case 202: #line 691 "parse.y" { @@ -2601,11 +2601,11 @@ ExprList *pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy178, 0); pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy178, 0); if( yymsp[0].minor.yy178 ){ pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy178, 0); } - yygotominor.yy178 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy440.operator); + yygotominor.yy178 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy440.eOperator); if( yymsp[-2].minor.yy440.not ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); sqlite3ExprSpan(yygotominor.yy178, &yymsp[-3].minor.yy178->span, &yymsp[-1].minor.yy178->span); } #line 2612 "parse.c" break; Index: SQLite.Interop/src/pragma.c ================================================================== --- SQLite.Interop/src/pragma.c +++ SQLite.Interop/src/pragma.c @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: pragma.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include Index: SQLite.Interop/src/prepare.c ================================================================== --- SQLite.Interop/src/prepare.c +++ SQLite.Interop/src/prepare.c @@ -11,11 +11,11 @@ ************************************************************************* ** This file contains the implementation of the sqlite3_prepare() ** interface, and routines that contribute to loading the database schema ** from disk. ** -** $Id: prepare.c,v 1.11 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: prepare.c,v 1.12 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -22,11 +22,11 @@ /* ** Fill the InitData structure with an error message that indicates ** that the database is corrupt. */ static void corruptSchema(InitData *pData, const char *zExtra){ - if( !sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( !sqlite3MallocFailed() ){ sqlite3SetString(pData->pzErrMsg, "malformed database schema", zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); } } @@ -47,11 +47,11 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ InitData *pData = (InitData*)pInit; sqlite3 *db = pData->db; int iDb; - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ return SQLITE_NOMEM; } assert( argc==4 ); if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ @@ -74,13 +74,13 @@ db->init.newTnum = atoi(argv[1]); rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); db->init.iDb = 0; if( SQLITE_OK!=rc ){ if( rc==SQLITE_NOMEM ){ - sqlite3ThreadData()->mallocFailed = 1; + sqlite3FailedMalloc(); }else{ - corruptSchema(pData, zErr); + corruptSchema(pData, zErr); } sqlite3_free(zErr); return rc; } }else{ @@ -301,12 +301,12 @@ sqlite3AnalysisLoad(db, iDb); } #endif sqlite3BtreeCloseCursor(curMain); } - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ - sqlite3SetString(pzErrMsg, "out of memory", (char*)0); + if( sqlite3MallocFailed() ){ + /* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */ rc = SQLITE_NOMEM; sqlite3ResetInternalSchema(db, 0); } if( rc==SQLITE_OK ){ DbSetProperty(db, iDb, DB_SchemaLoaded); @@ -494,11 +494,11 @@ char *zErrMsg = 0; int rc = SQLITE_OK; int i; /* Assert that malloc() has not failed */ - assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); + assert( !sqlite3MallocFailed() ); assert( ppStmt ); *ppStmt = 0; if( sqlite3SafetyOn(db) ){ return SQLITE_MISUSE; @@ -517,15 +517,13 @@ } } memset(&sParse, 0, sizeof(sParse)); sParse.db = db; - sParse.pTsd = sqlite3ThreadData(); - sParse.pTsd->nRef++; sqlite3RunParser(&sParse, zSql, &zErrMsg); - if( sParse.pTsd->mallocFailed ){ + if( sqlite3MallocFailed() ){ sParse.rc = SQLITE_NOMEM; } if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; if( sParse.checkSchema && !schemaIsValid(db) ){ sParse.rc = SQLITE_SCHEMA; @@ -568,20 +566,11 @@ sqliteFree(zErrMsg); }else{ sqlite3Error(db, rc, 0); } - /* We must check for malloc failure last of all, in case malloc() failed - ** inside of the sqlite3Error() call above or something. - */ - if( sParse.pTsd->mallocFailed ){ - rc = SQLITE_NOMEM; - sqlite3Error(db, rc, 0); - } - - sParse.pTsd->nRef--; - sqlite3MallocClearFailed(); + rc = sqlite3ApiExit(db, rc); sqlite3ReleaseThreadData(); return rc; } #ifndef SQLITE_OMIT_UTF16 @@ -597,23 +586,21 @@ ){ /* This function currently works by first transforming the UTF-16 ** encoded string to UTF-8, then invoking sqlite3_prepare(). The ** tricky bit is figuring out the pointer to return in *pzTail. */ - char *zSql8 = 0; + char *zSql8; const char *zTail8 = 0; - int rc; + int rc = SQLITE_OK; if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } zSql8 = sqlite3utf16to8(zSql, nBytes); - if( !zSql8 ){ - sqlite3Error(db, SQLITE_NOMEM, 0); - return SQLITE_NOMEM; + if( zSql8 ){ + rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8); } - rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8); if( zTail8 && pzTail ){ /* If sqlite3_prepare returns a tail pointer, we calculate the ** equivalent pointer into the UTF-16 string by counting the unicode ** characters between zSql8 and zTail8, and then returning a pointer @@ -621,8 +608,8 @@ */ int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8); *pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed); } sqliteFree(zSql8); - return rc; + return sqlite3ApiExit(db, rc); } #endif /* SQLITE_OMIT_UTF16 */ Index: SQLite.Interop/src/random.c ================================================================== --- SQLite.Interop/src/random.c +++ SQLite.Interop/src/random.c @@ -13,11 +13,11 @@ ** generator (PRNG) for SQLite. ** ** Random numbers are used by some of the database backends in order ** to generate random integer keys for tables or random filenames. ** -** $Id: random.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: random.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" Index: SQLite.Interop/src/select.c ================================================================== --- SQLite.Interop/src/select.c +++ SQLite.Interop/src/select.c @@ -10,14 +10,31 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: select.c,v 1.17 2006/01/23 19:45:55 rmsimpson Exp $ */ #include "sqliteInt.h" + +/* +** Delete all the content of a Select structure but do not deallocate +** the select structure itself. +*/ +void clearSelect(Select *p){ + sqlite3ExprListDelete(p->pEList); + sqlite3SrcListDelete(p->pSrc); + sqlite3ExprDelete(p->pWhere); + sqlite3ExprListDelete(p->pGroupBy); + sqlite3ExprDelete(p->pHaving); + sqlite3ExprListDelete(p->pOrderBy); + sqlite3SelectDelete(p->pPrior); + sqlite3ExprDelete(p->pLimit); + sqlite3ExprDelete(p->pOffset); +} + /* ** Allocate a new Select structure and return a pointer to that ** structure. */ @@ -31,43 +48,51 @@ int isDistinct, /* true if the DISTINCT keyword is present */ Expr *pLimit, /* LIMIT value. NULL means not used */ Expr *pOffset /* OFFSET value. NULL means no offset */ ){ Select *pNew; + Select standin; pNew = sqliteMalloc( sizeof(*pNew) ); assert( !pOffset || pLimit ); /* Can't have OFFSET without LIMIT. */ if( pNew==0 ){ - sqlite3ExprListDelete(pEList); - sqlite3SrcListDelete(pSrc); - sqlite3ExprDelete(pWhere); - sqlite3ExprListDelete(pGroupBy); - sqlite3ExprDelete(pHaving); - sqlite3ExprListDelete(pOrderBy); - sqlite3ExprDelete(pLimit); - sqlite3ExprDelete(pOffset); - }else{ - if( pEList==0 ){ - pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0); - } - pNew->pEList = pEList; - pNew->pSrc = pSrc; - pNew->pWhere = pWhere; - pNew->pGroupBy = pGroupBy; - pNew->pHaving = pHaving; - pNew->pOrderBy = pOrderBy; - pNew->isDistinct = isDistinct; - pNew->op = TK_SELECT; - pNew->pLimit = pLimit; - pNew->pOffset = pOffset; - pNew->iLimit = -1; - pNew->iOffset = -1; - pNew->addrOpenVirt[0] = -1; - pNew->addrOpenVirt[1] = -1; - pNew->addrOpenVirt[2] = -1; + pNew = &standin; + memset(pNew, 0, sizeof(*pNew)); + } + if( pEList==0 ){ + pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0); + } + pNew->pEList = pEList; + pNew->pSrc = pSrc; + pNew->pWhere = pWhere; + pNew->pGroupBy = pGroupBy; + pNew->pHaving = pHaving; + pNew->pOrderBy = pOrderBy; + pNew->isDistinct = isDistinct; + pNew->op = TK_SELECT; + pNew->pLimit = pLimit; + pNew->pOffset = pOffset; + pNew->iLimit = -1; + pNew->iOffset = -1; + pNew->addrOpenVirt[0] = -1; + pNew->addrOpenVirt[1] = -1; + pNew->addrOpenVirt[2] = -1; + if( pNew==&standin) { + clearSelect(pNew); + pNew = 0; } return pNew; } + +/* +** Delete the given Select structure and all of its substructures. +*/ +void sqlite3SelectDelete(Select *p){ + if( p ){ + clearSelect(p); + sqliteFree(p); + } +} /* ** Given 1 to 3 identifiers preceeding the JOIN keyword, determine the ** type of join. Return an integer constant that expresses that type ** in terms of the following bit values: @@ -328,27 +353,10 @@ } } return 0; } -/* -** Delete the given Select structure and all of its substructures. -*/ -void sqlite3SelectDelete(Select *p){ - if( p==0 ) return; - sqlite3ExprListDelete(p->pEList); - sqlite3SrcListDelete(p->pSrc); - sqlite3ExprDelete(p->pWhere); - sqlite3ExprListDelete(p->pGroupBy); - sqlite3ExprDelete(p->pHaving); - sqlite3ExprListDelete(p->pOrderBy); - sqlite3SelectDelete(p->pPrior); - sqlite3ExprDelete(p->pLimit); - sqlite3ExprDelete(p->pOffset); - sqliteFree(p); -} - /* ** Insert code into "v" that will push the record on the top of the ** stack into the sorter. */ static void pushOntoSorter( @@ -456,11 +464,11 @@ assert( pEList!=0 ); /* If there was a LIMIT clause on the SELECT statement, then do the check ** to see if this row should be output. */ - hasDistinct = distinct>=0 && pEList && pEList->nExpr>0; + hasDistinct = distinct>=0 && pEList->nExpr>0; if( pOrderBy==0 && !hasDistinct ){ codeOffset(v, p, iContinue, 0); } /* Pull the requested columns. @@ -556,11 +564,11 @@ } sqlite3VdbeJumpHere(v, addr2); break; } - /* If any row exists in the result set, record that fact and abort. + /* If any row exist in the result set, record that fact and abort. */ case SRT_Exists: { sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm); sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); /* The LIMIT clause will terminate the loop for us */ @@ -870,12 +878,11 @@ return; } #endif assert( v!=0 ); - if( pParse->colNamesSet || v==0 - || sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( pParse->colNamesSet || v==0 || sqlite3MallocFailed() ) return; pParse->colNamesSet = 1; fullNames = (db->flags & SQLITE_FullColNames)!=0; shortNames = (db->flags & SQLITE_ShortColNames)!=0; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; inExpr; i++){ @@ -1000,11 +1007,11 @@ }else{ /* If all else fails, make up a name */ zName = sqlite3MPrintf("column%d", i+1); } sqlite3Dequote(zName); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ sqliteFree(zName); sqlite3DeleteTable(0, pTab); return 0; } @@ -1072,11 +1079,11 @@ SrcList *pTabList; ExprList *pEList; Table *pTab; struct SrcList_item *pFrom; - if( p==0 || p->pSrc==0 || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( p==0 || p->pSrc==0 || sqlite3MallocFailed() ){ return 1; } pTabList = p->pSrc; pEList = p->pEList; @@ -1387,12 +1394,12 @@ ** redefined. The UNION ALL operator uses this property to force ** the reuse of the same limit and offset registers across multiple ** SELECT statements. */ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ - Vdbe *v; - int iLimit; + Vdbe *v = 0; + int iLimit = 0; int iOffset; int addr1, addr2; /* ** "LIMIT -1" always shows all rows. There is some @@ -1860,11 +1867,11 @@ struct ExprList_item *pOTerm = pOrderBy->a; int nOrderByExpr = pOrderBy->nExpr; int addr; u8 *pSortOrder; - aCopy = (CollSeq**)&pKeyInfo[1]; + aCopy = &pKeyInfo->aColl[nCol]; pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol]; memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*)); apColl = pKeyInfo->aColl; for(i=0; ipExpr; @@ -2018,10 +2025,14 @@ ** ** (11) The subquery and the outer query do not both have ORDER BY clauses. ** ** (12) The subquery is not the right term of a LEFT OUTER JOIN or the ** subquery has no WHERE clause. (added by ticket #350) +** +** (13) The subquery and outer query do not both use LIMIT +** +** (14) The subquery does not use OFFSET ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates. ** @@ -2053,22 +2064,30 @@ pSrc = p->pSrc; assert( pSrc && iFrom>=0 && iFromnSrc ); pSubitem = &pSrc->a[iFrom]; pSub = pSubitem->pSelect; assert( pSub!=0 ); - if( isAgg && subqueryIsAgg ) return 0; - if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; + if( isAgg && subqueryIsAgg ) return 0; /* Restriction (1) */ + if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; /* Restriction (2) */ pSubSrc = pSub->pSrc; assert( pSubSrc ); - if( (pSub->pLimit && p->pLimit) || pSub->pOffset || - (pSub->pLimit && isAgg) ) return 0; - if( pSubSrc->nSrc==0 ) return 0; - if( pSub->isDistinct && (pSrc->nSrc>1 || isAgg) ){ - return 0; - } - if( p->isDistinct && subqueryIsAgg ) return 0; - if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ) return 0; + /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, + ** not arbitrary expresssions, we allowed some combining of LIMIT and OFFSET + ** because they could be computed at compile-time. But when LIMIT and OFFSET + ** became arbitrary expressions, we were forced to add restrictions (13) + ** and (14). */ + if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */ + if( pSub->pOffset ) return 0; /* Restriction (14) */ + if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */ + if( (pSub->isDistinct || pSub->pLimit) + && (pSrc->nSrc>1 || isAgg) ){ /* Restrictions (4)(5)(8)(9) */ + return 0; + } + if( p->isDistinct && subqueryIsAgg ) return 0; /* Restriction (6) */ + if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ){ + return 0; /* Restriction (11) */ + } /* Restriction 3: If the subquery is a join, make sure the subquery is ** not used as the right operand of an outer join. Examples of why this ** is not allowed: ** @@ -2194,10 +2213,13 @@ */ p->isDistinct = p->isDistinct || pSub->isDistinct; /* ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y; + ** + ** One is tempted to try to add a and b to combine the limits. But this + ** does not work if either limit is negative. */ if( pSub->pLimit ){ p->pLimit = pSub->pLimit; pSub->pLimit = 0; } @@ -2691,11 +2713,11 @@ int rc = 1; /* Value to return from this function */ int addrSortIndex; /* Address of an OP_OpenVirtual instruction */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ - if( p==0 || sqlite3ThreadDataReadOnly()->mallocFailed || pParse->nErr ){ + if( p==0 || sqlite3MallocFailed() || pParse->nErr ){ return 1; } if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); @@ -2947,11 +2969,11 @@ for(i=0; ipList) ){ goto select_end; } } - if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto select_end; + if( sqlite3MallocFailed() ) goto select_end; /* Processing for aggregates with GROUP BY is very different and ** much more complex tha aggregates without a GROUP BY. */ if( pGroupBy ){ Index: SQLite.Interop/src/shell.c ================================================================== --- SQLite.Interop/src/shell.c +++ SQLite.Interop/src/shell.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains code to implement the "sqlite" command line ** utility for accessing SQLite databases. ** -** $Id: shell.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: shell.c,v 1.16 2006/01/23 19:45:55 rmsimpson Exp $ */ #include #include #include #include Index: SQLite.Interop/src/sqlite3.h ================================================================== --- SQLite.Interop/src/sqlite3.h +++ SQLite.Interop/src/sqlite3.h @@ -10,11 +10,11 @@ ** ************************************************************************* ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite3.h,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** @(#) $Id: sqlite3.h,v 1.17 2006/01/23 19:45:55 rmsimpson Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ #include /* Needed for the definition of va_list */ @@ -29,11 +29,11 @@ ** The version of the SQLite library. */ #ifdef SQLITE_VERSION # undef SQLITE_VERSION #endif -#define SQLITE_VERSION "3.3.1" +#define SQLITE_VERSION "3.3.2" /* ** The format of the version string is "X.Y.Z", where ** X is the major version number, Y is the minor version number and Z ** is the release number. The trailing string is often "alpha" or "beta". @@ -46,11 +46,11 @@ ** (SQLITE_VERSION_NUMBER>=3001001). */ #ifdef SQLITE_VERSION_NUMBER # undef SQLITE_VERSION_NUMBER #endif -#define SQLITE_VERSION_NUMBER 3003001 +#define SQLITE_VERSION_NUMBER 3003002 /* ** The version string is also compiled into the library so that a program ** can check to make sure that the lib*.a file and the *.h file are from ** the same version. The sqlite3_libversion() function returns a pointer Index: SQLite.Interop/src/sqliteInt.h ================================================================== --- SQLite.Interop/src/sqliteInt.h +++ SQLite.Interop/src/sqliteInt.h @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** @(#) $Id: sqliteInt.h,v 1.16 2006/01/23 19:45:56 rmsimpson Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* @@ -28,11 +28,11 @@ ** Setting NDEBUG makes the code smaller and run faster. So the following ** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1 ** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out ** feature. */ -#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif /* ** These #defines should enable >2GB file support on Posix if the @@ -71,14 +71,19 @@ ** substitute integer for floating-point */ #ifdef SQLITE_OMIT_FLOATING_POINT # define double sqlite_int64 # define LONGDOUBLE_TYPE sqlite_int64 -# define SQLITE_BIG_DBL (0x7fffffffffffffff) +# ifndef SQLITE_BIG_DBL +# define SQLITE_BIG_DBL (0x7fffffffffffffff) +# endif # define SQLITE_OMIT_DATETIME_FUNCS 1 # define SQLITE_OMIT_TRACE 1 #endif +#ifndef SQLITE_BIG_DBL +# define SQLITE_BIG_DBL (1e99) +#endif /* ** The maximum number of in-memory pages to use for the main database ** table and for temporary tables. Internally, the MAX_PAGES and ** TEMP_PAGES macros are used. To override the default values at @@ -259,13 +264,20 @@ */ 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 */ -#define ENTER_MALLOC (\ - sqlite3ThreadData()->zFile = __FILE__, sqlite3ThreadData()->iLine = __LINE__ \ -) + + +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)) #define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x)) #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)) @@ -287,18 +299,13 @@ /* ** An instance of this structure might be allocated to store information ** specific to a single thread. -** -** To avoid a memory leak on windows, the content of this structure is -** checked at the conclusion of each API call. If it is all zero, it -** is deallocated. */ struct ThreadData { - int mallocFailed; /* True after a malloc() has failed */ - int nRef; /* Number of users */ + 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 */ @@ -306,19 +313,10 @@ #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 - -#ifdef SQLITE_MEMDEBUG - int nMaxAlloc; /* High water mark of ThreadData.nAlloc */ - int mallocDisallowed; /* assert() in sqlite3Malloc() if set */ - int isFail; /* True if all malloc() calls should fail */ - const char *zFile; /* Filename to associate debugging info with */ - int iLine; /* Line number to associate debugging info with */ - void *pFirst; /* Pointer to linked list of allocations */ -#endif }; /* ** Name of the master database table. The master database table ** is a special table that holds the names and attributes of all @@ -698,11 +696,10 @@ int iPKey; /* If not less then 0, use aCol[iPKey] as the primary key */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Root BTree node for this table (see note above) */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ u8 readOnly; /* True if this table should not be written by the user */ -// u8 iDb; /* Index into sqlite.aDb[] of the backend for this table */ u8 isTransient; /* True if automatically deleted when VDBE finishes */ u8 hasPrimKey; /* True if there exists a primary key */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ u8 autoInc; /* True if the integer primary key is autoincrement */ int nRef; /* Number of pointers to this Table */ @@ -962,11 +959,10 @@ ** corresponding table definition. */ struct Expr { u8 op; /* Operation performed by this node */ char affinity; /* The affinity of the column or 0 if not a column */ -//u8 iDb; /* Database referenced by this expression */ u8 flags; /* Various flags. See below */ CollSeq *pColl; /* The collation type of the column or 0 */ Expr *pLeft, *pRight; /* Left and right subnodes */ ExprList *pList; /* A list of expressions used as function arguments ** or in " IN (zTrace is executed. */ static void DbTraceHandler(void *cd, const char *zSql){ @@ -269,11 +270,13 @@ Tcl_DStringAppendElement(&str, zSql); Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); Tcl_ResetResult(pDb->interp); } +#endif +#ifndef SQLITE_OMIT_TRACE /* ** This routine is called by the SQLite profile handler after a statement ** SQL has executed. The TCL script in pDb->zProfile is evaluated. */ static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){ @@ -288,10 +291,11 @@ Tcl_DStringAppendElement(&str, zTm); Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); Tcl_ResetResult(pDb->interp); } +#endif /* ** This routine is called when a transaction is committed. The ** TCL script in pDb->zCommit is executed. If it returns non-zero or ** if it throws an exception, the transaction is rolled back instead Index: SQLite.Interop/src/tokenize.c ================================================================== --- SQLite.Interop/src/tokenize.c +++ SQLite.Interop/src/tokenize.c @@ -13,11 +13,11 @@ ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.19 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: tokenize.c,v 1.20 2006/01/23 19:45:56 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include #include @@ -338,11 +338,10 @@ int i; void *pEngine; int tokenType; int lastTokenParsed = -1; sqlite3 *db = pParse->db; - ThreadData *pTsd = pParse->pTsd; extern void *sqlite3ParserAlloc(void*(*)(int)); extern void sqlite3ParserFree(void*, void(*)(void*)); extern int sqlite3Parser(void*, int, Token, Parse*); db->flags &= ~SQLITE_Interrupt; @@ -358,11 +357,11 @@ assert( pParse->nVar==0 ); assert( pParse->nVarExpr==0 ); assert( pParse->nVarExprAlloc==0 ); assert( pParse->apVarExpr==0 ); pParse->zTail = pParse->zSql = zSql; - while( pTsd->mallocFailed==0 && zSql[i]!=0 ){ + while( !sqlite3MallocFailed() && zSql[i]!=0 ){ assert( i>=0 ); pParse->sLastToken.z = (u8*)&zSql[i]; assert( pParse->sLastToken.dyn==0 ); pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType); i += pParse->sLastToken.n; @@ -406,11 +405,11 @@ pParse->zTail = &zSql[i]; } sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); } sqlite3ParserFree(pEngine, sqlite3FreeX); - if( pTsd->mallocFailed ){ + if( sqlite3MallocFailed() ){ pParse->rc = SQLITE_NOMEM; } if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){ sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc), (char*)0); } Index: SQLite.Interop/src/trigger.c ================================================================== --- SQLite.Interop/src/trigger.c +++ SQLite.Interop/src/trigger.c @@ -79,20 +79,20 @@ /* If the trigger name was unqualified, and the table is a temp table, ** then set iDb to 1 to create the trigger in the temporary database. ** If sqlite3SrcListLookup() returns 0, indicating the table does not ** exist, the error is caught by the block below. */ - if( !pTableName || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( !pTableName || sqlite3MallocFailed() ){ goto trigger_cleanup; } pTab = sqlite3SrcListLookup(pParse, pTableName); if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ iDb = 1; } /* Ensure the table name matches database name and that the table exists */ - if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto trigger_cleanup; + if( sqlite3MallocFailed() ) goto trigger_cleanup; assert( pTableName->nSrc==1 ); if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) && sqlite3FixSrcList(&sFix, pTableName) ){ goto trigger_cleanup; } @@ -255,11 +255,11 @@ Table *pTab; Trigger *pDel; pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash, pTrig->name, strlen(pTrig->name)+1, pTrig); if( pDel ){ - assert( sqlite3ThreadDataReadOnly()->mallocFailed && pDel==pTrig ); + assert( sqlite3MallocFailed() && pDel==pTrig ); goto triggerfinish_cleanup; } n = strlen(pTrig->table) + 1; pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n); assert( pTab!=0 ); @@ -439,11 +439,11 @@ const char *zDb; const char *zName; int nName; sqlite3 *db = pParse->db; - if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto drop_trigger_cleanup; + if( sqlite3MallocFailed() ) goto drop_trigger_cleanup; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto drop_trigger_cleanup; } assert( pName->nSrc==1 ); Index: SQLite.Interop/src/update.c ================================================================== --- SQLite.Interop/src/update.c +++ SQLite.Interop/src/update.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: update.c,v 1.16 2006/01/23 19:45:56 rmsimpson Exp $ */ #include "sqliteInt.h" /* ** The most recently coded instruction was an OP_Column to retrieve the @@ -98,11 +98,11 @@ int newIdx = -1; /* index of trigger "new" temp table */ int oldIdx = -1; /* index of trigger "old" temp table */ sContext.pParse = 0; - if( pParse->nErr || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( pParse->nErr || sqlite3MallocFailed() ){ goto update_cleanup; } db = pParse->db; assert( pTabList->nSrc==1 ); Index: SQLite.Interop/src/utf.c ================================================================== --- SQLite.Interop/src/utf.c +++ SQLite.Interop/src/utf.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains routines used to translate between UTF-8, ** UTF-16, UTF-16BE, and UTF-16LE. ** -** $Id: utf.c,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: utf.c,v 1.16 2006/01/23 19:45:56 rmsimpson Exp $ ** ** Notes on UTF-8: ** ** Byte-0 Byte-1 Byte-2 Byte-3 Value ** 0xxxxxxx 00000000 00000000 0xxxxxxx Index: SQLite.Interop/src/util.c ================================================================== --- SQLite.Interop/src/util.c +++ SQLite.Interop/src/util.c @@ -12,11 +12,11 @@ ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: util.c,v 1.17 2006/01/23 19:45:56 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include #include @@ -23,11 +23,11 @@ /* ** MALLOC WRAPPER ARCHITECTURE ** ** The sqlite code accesses dynamic memory allocation/deallocation by invoking -** the following four APIs (which may be implemented as macros). +** the following six APIs (which may be implemented as macros). ** ** sqlite3Malloc() ** sqlite3MallocRaw() ** sqlite3Realloc() ** sqlite3ReallocOrFree() @@ -35,12 +35,12 @@ ** 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 at the Os -** level (not in this file). The Os level interface is never accessed directly +** 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() @@ -53,11 +53,11 @@ ** 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) +** 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. @@ -70,11 +70,14 @@ /* ** Set the soft heap-size limit for the current thread. Passing a negative ** value indicates no limit. */ void sqlite3_soft_heap_limit(int n){ - sqlite3ThreadData()->nSoftHeapLimit = n; + ThreadData *pTd = sqlite3ThreadData(); + if( pTd ){ + pTd->nSoftHeapLimit = n; + } sqlite3ReleaseThreadData(); } /* ** Release memory held by SQLite instances created by the current thread. @@ -194,24 +197,30 @@ 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 */ + /* ** Check for a simulated memory allocation failure. Return true if ** the failure should be simulated. Return false to proceed as normal. */ -static int failMalloc(){ - ThreadData *pTsd = sqlite3ThreadData(); - if( pTsd->isFail ){ +int sqlite3TestMallocFail(){ + if( sqlite3_isFail ){ return 1; } if( sqlite3_iMallocFail>=0 ){ sqlite3_iMallocFail--; if( sqlite3_iMallocFail==0 ){ sqlite3_iMallocFail = sqlite3_iMallocReset; - pTsd->isFail = 1; + sqlite3_isFail = 1; return 1; } } return 0; } @@ -267,15 +276,15 @@ } /* Line number */ z = &((char *)z)[TESTALLOC_NGUARD*sizeof(u32)]; /* Guard words */ z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)]; - memcpy(z, &sqlite3ThreadData()->iLine, sizeof(u32)); + memcpy(z, &sqlite3_iLine, sizeof(u32)); /* File name */ z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)]; - strncpy(z, sqlite3ThreadData()->zFile, TESTALLOC_FILESIZE); + strncpy(z, sqlite3_zFile, TESTALLOC_FILESIZE); z[TESTALLOC_FILESIZE - 1] = '\0'; /* User string */ z = &zAlloc[TESTALLOC_OFFSET_USER(p)]; z[0] = 0; @@ -307,34 +316,32 @@ /* ** The argument points to an Os level allocation. Link it into the threads list ** of allocations. */ static void linkAlloc(void *p){ - ThreadData *pTsd = sqlite3ThreadData(); void **pp = (void **)p; pp[0] = 0; - pp[1] = pTsd->pFirst; - if( pTsd->pFirst ){ - ((void **)pTsd->pFirst)[0] = p; + pp[1] = sqlite3_pFirst; + if( sqlite3_pFirst ){ + ((void **)sqlite3_pFirst)[0] = p; } - pTsd->pFirst = 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) { - ThreadData *pTsd = sqlite3ThreadData(); void **pp = (void **)p; - if( p==pTsd->pFirst ){ + if( p==sqlite3_pFirst ){ assert(!pp[0]); assert(!pp[1] || ((void **)(pp[1]))[0]==p); - pTsd->pFirst = pp[1]; - if( pTsd->pFirst ){ - ((void **)pTsd->pFirst)[0] = 0; + sqlite3_pFirst = pp[1]; + if( sqlite3_pFirst ){ + ((void **)sqlite3_pFirst)[0] = 0; } }else{ void **pprev = pp[0]; void **pnext = pp[1]; assert(pprev); @@ -356,12 +363,11 @@ { void **pp = (void **)p; if( pp[0] ){ ((void **)(pp[0]))[1] = p; }else{ - ThreadData *pTsd = sqlite3ThreadData(); - pTsd->pFirst = p; + sqlite3_pFirst = p; } if( pp[1] ){ ((void **)(pp[1]))[0] = p; } } @@ -384,19 +390,19 @@ ** * 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. */ -#ifdef TCLSH +#if defined(TCLSH) && defined(SQLITE_DEBUG) && SQLITE_MEMDEBUG>1 #include int sqlite3OutstandingMallocs(Tcl_Interp *interp){ void *p; - ThreadData *pTsd = sqlite3ThreadData(); Tcl_Obj *pRes = Tcl_NewObj(); Tcl_IncrRefCount(pRes); - for(p=pTsd->pFirst; p; p=((void **)p)[1]){ + + 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; @@ -436,15 +442,15 @@ /* ** This is the test layer's wrapper around sqlite3OsMalloc(). */ static void * OSMALLOC(int n){ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - ThreadData *pTsd = sqlite3ThreadData(); - pTsd->nMaxAlloc = MAX(pTsd->nMaxAlloc, pTsd->nAlloc); + sqlite3_nMaxAlloc = + MAX(sqlite3_nMaxAlloc, sqlite3ThreadDataReadOnly()->nAlloc); #endif - assert( !sqlite3ThreadData()->mallocDisallowed ); - if( !failMalloc() ){ + assert( !sqlite3_mallocDisallowed ); + if( !sqlite3TestMallocFail() ){ u32 *p; p = (u32 *)sqlite3OsMalloc(n + TESTALLOC_OVERHEAD); assert(p); sqlite3_nMalloc++; applyGuards(p); @@ -478,15 +484,15 @@ /* ** This is the test layer's wrapper around sqlite3OsRealloc(). */ static void * OSREALLOC(void *pRealloc, int n){ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - ThreadData *pTsd = sqlite3ThreadData(); - pTsd->nMaxAlloc = MAX(pTsd->nMaxAlloc, pTsd->nAlloc); + sqlite3_nMaxAlloc = + MAX(sqlite3_nMaxAlloc, sqlite3ThreadDataReadOnly()->nAlloc); #endif - assert( !sqlite3ThreadData()->mallocDisallowed ); - if( !failMalloc() ){ + assert( !sqlite3_mallocDisallowed ); + if( !sqlite3TestMallocFail() ){ u32 *p = (u32 *)getOsPointer(pRealloc); checkGuards(p); p = sqlite3OsRealloc(p, n + TESTALLOC_OVERHEAD); applyGuards(p); relinkAlloc(p); @@ -494,11 +500,11 @@ } return 0; } static void OSMALLOC_FAILED(){ - sqlite3ThreadData()->isFail = 0; + sqlite3_isFail = 0; } #else /* Define macros to call the sqlite3OsXXX interface directly if ** the SQLITE_MEMDEBUG macro is not defined. @@ -526,42 +532,44 @@ ** ** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is ** a no-op */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT -static void handleSoftLimit(int n){ +static int handleSoftLimit(int n){ ThreadData *pTsd = sqlite3ThreadData(); - pTsd->nAlloc += n; - assert( pTsd->nAlloc>=0 ); - if( n>0 && pTsd->nSoftHeapLimit>0 ){ - while( pTsd->nAlloc>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) ); - }else if( pTsd->nAlloc==0 && pTsd->nSoftHeapLimit==0 ){ - sqlite3ReleaseThreadData(); + if( pTsd ){ + pTsd->nAlloc += n; + assert( pTsd->nAlloc>=0 ); + if( n>0 && pTsd->nSoftHeapLimit>0 ){ + while( pTsd->nAlloc>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) ); + }else if( pTsd->nAlloc==0 && pTsd->nSoftHeapLimit==0 ){ + sqlite3ReleaseThreadData(); + } } + return (pTsd ? 0 : 1); } #else -#define handleSoftLimit(x) +#define handleSoftLimit(x) 0 #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){ void *p = 0; - if( n>0 && !sqlite3ThreadDataReadOnly()->mallocFailed ){ - handleSoftLimit(n); - while( !(p = OSMALLOC(n)) && sqlite3_release_memory(n) ); + if( n>0 && !sqlite3MallocFailed() && !handleSoftLimit(n) ){ + while( (p = OSMALLOC(n))==0 && sqlite3_release_memory(n) ); if( !p ){ /* If the allocation failed, call handleSoftLimit() again, this time ** with the additive inverse of the argument passed to ** handleSoftLimit() above. This is so the ThreadData.nAlloc variable is ** still correct after a malloc() failure. */ - handleSoftLimit(n * -1); - sqlite3ThreadData()->mallocFailed = 1; + (void)handleSoftLimit(n * -1); + sqlite3FailedMalloc(); OSMALLOC_FAILED(); } } return p; } @@ -570,29 +578,30 @@ ** 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( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ return 0; } if( !p ){ return sqlite3Malloc(n); }else{ void *np = 0; - handleSoftLimit(n - OSSIZEOF(p)); - while( !(np = OSREALLOC(p, n)) && sqlite3_release_memory(n) ); - if( !np ){ - /* If the allocation failed, call handleSoftLimit() again, this time - ** with the additive inverse of the argument passed to - ** handleSoftLimit() above. This is so the ThreadData.nAlloc variable is - ** still correct after a malloc() failure. - */ - handleSoftLimit(OSSIZEOF(p) - n); - sqlite3ThreadData()->mallocFailed = 1; - OSMALLOC_FAILED(); + if( !handleSoftLimit(n - OSSIZEOF(p)) ){ + while( (np = OSREALLOC(p, n))==0 && sqlite3_release_memory(n) ); + if( !np ){ + /* If the allocation failed, call handleSoftLimit() again, this time + ** with the additive inverse of the argument passed to + ** handleSoftLimit() above. This is so the ThreadData.nAlloc variable is + ** still correct after a malloc() failure. + */ + (void)handleSoftLimit(OSSIZEOF(p) - n); + sqlite3FailedMalloc(); + OSMALLOC_FAILED(); + } } return np; } } @@ -599,11 +608,11 @@ /* ** 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){ - handleSoftLimit(0 - OSSIZEOF(p)); + (void)handleSoftLimit(0 - OSSIZEOF(p)); if( p ){ OSFREE(p); } } @@ -645,11 +654,11 @@ ** 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. */ -#if 0 /* This is never actually used */ +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT int sqlite3AllocSize(void *p){ return OSSIZEOF(p); } #endif @@ -732,11 +741,11 @@ ** To clear the most recent error for sqlite handle "db", sqlite3Error ** should be called with err_code set to SQLITE_OK and zFormat set ** to NULL. */ void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){ - if( db && (db->pErr || (db->pErr = sqlite3ValueNew()))!=0 ){ + if( db && (db->pErr || (db->pErr = sqlite3ValueNew())!=0) ){ db->errCode = err_code; if( zFormat ){ char *z; va_list ap; va_start(ap, zFormat); @@ -1313,20 +1322,25 @@ /* ** Return a pointer to the ThreadData associated with the calling thread. */ ThreadData *sqlite3ThreadData(){ - return (ThreadData*)sqlite3OsThreadSpecificData(1); + ThreadData *p = (ThreadData*)sqlite3OsThreadSpecificData(1); + if( !p ){ + sqlite3FailedMalloc(); + } + return p; } /* ** Return a pointer to the ThreadData associated with the calling thread. ** If no ThreadData has been allocated to this thread yet, return a pointer ** to a substitute ThreadData structure that is all zeros. */ const ThreadData *sqlite3ThreadDataReadOnly(){ - static const ThreadData zeroData; + static const ThreadData zeroData = {0}; /* Initializer to silence warnings + ** from broken compilers */ const ThreadData *pTd = sqlite3OsThreadSpecificData(0); return pTd ? pTd : &zeroData; } /* @@ -1336,35 +1350,64 @@ void sqlite3ReleaseThreadData(){ sqlite3OsThreadSpecificData(-1); } /* -** Clear the "mallocFailed" flag. This should be invoked before exiting any -** entry points that may have called sqliteMalloc(). -*/ -void sqlite3MallocClearFailed(){ - ThreadData *pTd = sqlite3OsThreadSpecificData(0); - if( pTd && pTd->mallocFailed ){ - pTd->mallocFailed = 0; - sqlite3OsThreadSpecificData(0); - } +** This function must be called before exiting any API function (i.e. +** returning control to the user) that has called sqlite3Malloc or +** sqlite3Realloc. +** +** The returned value is normally a copy of the second argument to this +** function. However, if a malloc() failure has occured since the previous +** invocation SQLITE_NOMEM is returned instead. +** +** If the first argument, db, is not NULL and a malloc() error has occured, +** then the connection error-code (the value returned by sqlite3_errcode()) +** is set to SQLITE_NOMEM. +*/ +static int mallocHasFailed = 0; +int sqlite3ApiExit(sqlite3* db, int rc){ + if( sqlite3MallocFailed() ){ + mallocHasFailed = 0; + sqlite3OsLeaveMutex(); + sqlite3Error(db, SQLITE_NOMEM, 0); + rc = SQLITE_NOMEM; + } + return rc; +} + +/* +** Return true is a malloc has failed in this thread since the last call +** to sqlite3ApiExit(), or false otherwise. +*/ +int sqlite3MallocFailed(){ + return (mallocHasFailed && sqlite3OsInMutex(1)); +} + +/* +** Set the "malloc has failed" condition to true for this thread. +*/ +void sqlite3FailedMalloc(){ + sqlite3OsEnterMutex(); + assert( mallocHasFailed==0 ); + mallocHasFailed = 1; } -#ifndef NDEBUG +#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( sqlite3ThreadData()->mallocDisallowed>=0 ); - sqlite3ThreadData()->mallocDisallowed++; + assert( sqlite3_mallocDisallowed>=0 ); + sqlite3_mallocDisallowed++; } /* ** This function clears the flag set in the thread-specific-data structure set ** by sqlite3MallocDisallow(). */ void sqlite3MallocAllow(){ - assert( sqlite3ThreadData()->mallocDisallowed>0 ); - sqlite3ThreadData()->mallocDisallowed--; + assert( sqlite3_mallocDisallowed>0 ); + sqlite3_mallocDisallowed--; } #endif Index: SQLite.Interop/src/vacuum.c ================================================================== --- SQLite.Interop/src/vacuum.c +++ SQLite.Interop/src/vacuum.c @@ -12,11 +12,11 @@ ** This file contains code used to implement the VACUUM command. ** ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. ** -** $Id: vacuum.c,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: vacuum.c,v 1.17 2006/01/23 19:45:56 rmsimpson Exp $ */ #include "sqliteInt.h" #include "vdbeInt.h" #include "os.h" @@ -312,11 +312,11 @@ /* If one of the execSql() calls above returned SQLITE_NOMEM, then the ** mallocFailed flag will be clear (because execSql() calls sqlite3_exec()). ** Fix this so the flag and return code match. */ if( rc==SQLITE_NOMEM ){ - sqlite3ThreadData()->mallocFailed = 1; + sqlite3MallocFailed(); } if( zTemp ){ sqlite3OsDelete(zTemp); sqliteFree(zTemp); Index: SQLite.Interop/src/vdbe.c ================================================================== --- SQLite.Interop/src/vdbe.c +++ SQLite.Interop/src/vdbe.c @@ -41,11 +41,11 @@ ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.16 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: vdbe.c,v 1.17 2006/01/23 19:45:56 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include #include "vdbeInt.h" @@ -405,14 +405,12 @@ int nProgressOps = 0; /* Opcodes executed since progress callback. */ #endif #ifndef NDEBUG Mem *pStackLimit; #endif - ThreadData *pTsd = sqlite3ThreadData(); if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE; - pTsd->nRef++; assert( db->magic==SQLITE_MAGIC_BUSY ); pTos = p->pTos; if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ @@ -429,11 +427,11 @@ db->busyHandler.nBusy = 0; CHECK_FOR_INTERRUPT; for(pc=p->pc; rc==SQLITE_OK; pc++){ assert( pc>=0 && pcnOp ); assert( pTos<=&p->aStack[pc] ); - if( pTsd->mallocFailed ) goto no_mem; + if( sqlite3MallocFailed() ) goto no_mem; #ifdef VDBE_PROFILE origPc = pc; start = hwtime(); #endif pOp = &p->aOp[pc]; @@ -609,11 +607,10 @@ if( pOp->p3 ){ sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK ); - pTsd->nRef--; if( rc==SQLITE_BUSY ){ p->rc = SQLITE_BUSY; return SQLITE_BUSY; } return p->rc ? SQLITE_ERROR : SQLITE_DONE; @@ -916,11 +913,10 @@ p->resOnStack = 1; p->nCallback++; p->popStack = pOp->p1; p->pc = pc + 1; p->pTos = pTos; - pTsd->nRef--; return SQLITE_ROW; } /* Opcode: Concat P1 P2 * ** @@ -1185,11 +1181,11 @@ ctx.pColl = (CollSeq *)pOp[-1].p3; } if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; (*ctx.pFunc->xFunc)(&ctx, n, apVal); if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; - if( pTsd->mallocFailed ) goto no_mem; + if( sqlite3MallocFailed() ) goto no_mem; popStack(&pTos, n); /* If any auxilary data functions have been called by this user function, ** immediately call the destructor for any non-static values. */ @@ -1196,27 +1192,22 @@ if( ctx.pVdbeFunc ){ sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1); pOp->p3 = (char *)ctx.pVdbeFunc; pOp->p3type = P3_VDBEFUNC; } + + /* If the function returned an error, throw an exception */ + if( ctx.isError ){ + sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0); + rc = SQLITE_ERROR; + } /* Copy the result of the function to the top of the stack */ sqlite3VdbeChangeEncoding(&ctx.s, encoding); pTos++; pTos->flags = 0; sqlite3VdbeMemMove(pTos, &ctx.s); - - /* If the function returned an error, throw an exception */ - if( ctx.isError ){ - if( !(pTos->flags&MEM_Str) ){ - sqlite3SetString(&p->zErrMsg, "user function error", (char*)0); - }else{ - sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pTos), (char*)0); - sqlite3VdbeChangeEncoding(pTos, encoding); - } - rc = SQLITE_ERROR; - } break; } /* Opcode: BitAnd * * * ** @@ -2020,11 +2011,11 @@ goto op_column_out; } zData = sMem.z; } zEndHdr = (u8 *)zData + offset; - zIdx = zData + (int)zIdx; + zIdx = (u8 *)zData + (int)zIdx; /* Scan the header and use it to fill in the aType[] and aOffset[] ** arrays. aType[i] will contain the type integer for the i-th ** column and aOffset[i] will contain the offset from the beginning ** of the record to the start of the data for the i-th column @@ -2341,11 +2332,10 @@ */ sqlite3SetString(&p->zErrMsg, "cannot ", rollback?"rollback":"commit", " transaction - SQL statements in progress", (char*)0); rc = SQLITE_ERROR; }else if( i!=db->autoCommit ){ - pTsd->nRef--; if( pOp->p2 ){ assert( i==1 ); sqlite3RollbackAll(db); db->autoCommit = 1; }else{ @@ -2401,11 +2391,10 @@ rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); if( rc==SQLITE_BUSY ){ p->pc = pc; p->rc = SQLITE_BUSY; p->pTos = pTos; - pTsd->nRef--; return SQLITE_BUSY; } if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){ goto abort_due_to_error; } @@ -2609,11 +2598,10 @@ switch( rc ){ case SQLITE_BUSY: { p->pc = pc; p->rc = SQLITE_BUSY; p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */ - pTsd->nRef--; return SQLITE_BUSY; } case SQLITE_OK: { int flags = sqlite3BtreeFlags(pCur->pCursor); /* Sanity checking. Only the lower four bits of the flags byte should @@ -3290,11 +3278,11 @@ assert( pC->isTable ); iKey = intToKey(pNos->i); if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->i; - if( pC->nextRowidValid && pTos->i>=pC->nextRowid ){ + if( pC->nextRowidValid && pNos->i>=pC->nextRowid ){ pC->nextRowidValid = 0; } if( pTos->flags & MEM_Null ){ pTos->z = 0; pTos->n = 0; @@ -3715,13 +3703,13 @@ assert( pTos>=p->aStack ); assert( pTos->flags & MEM_Blob ); assert( i>=0 && inCursor ); assert( p->apCsr[i]!=0 ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ - int rx, res; - rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res); - if( rx==SQLITE_OK && res==0 ){ + int res; + rc = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res); + if( rc==SQLITE_OK && res==0 ){ rc = sqlite3BtreeDelete(pCrsr); } assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; } @@ -4038,17 +4026,17 @@ pOp->p1, db->aDb[iDb].zName, zMaster, pOp->p3); if( zSql==0 ) goto no_mem; sqlite3SafetyOff(db); assert( db->init.busy==0 ); db->init.busy = 1; - assert(0==pTsd->mallocFailed); + assert( !sqlite3MallocFailed() ); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); sqliteFree(zSql); db->init.busy = 0; sqlite3SafetyOn(db); if( rc==SQLITE_NOMEM ){ - pTsd->mallocFailed = 1; + sqlite3FailedMalloc(); goto no_mem; } break; } @@ -4432,10 +4420,13 @@ } ctx.pFunc = (FuncDef*)pOp->p3; assert( pOp->p1>=0 && pOp->p1nMem ); ctx.pMem = pMem = &p->aMem[pOp->p1]; pMem->n++; + ctx.s.flags = MEM_Null; + ctx.s.z = 0; + ctx.s.xDel = 0; ctx.isError = 0; ctx.pColl = 0; if( ctx.pFunc->needCollSeq ){ assert( pOp>p->aOp ); assert( pOp[-1].p3type==P3_COLLSEQ ); @@ -4443,12 +4434,14 @@ ctx.pColl = (CollSeq *)pOp[-1].p3; } (ctx.pFunc->xStep)(&ctx, n, apVal); popStack(&pTos, n); if( ctx.isError ){ + sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0); rc = SQLITE_ERROR; } + sqlite3VdbeMemRelease(&ctx.s); break; } /* Opcode: AggFinal P1 P2 P3 ** @@ -4465,11 +4458,14 @@ case OP_AggFinal: { /* no-push */ Mem *pMem; assert( pOp->p1>=0 && pOp->p1nMem ); pMem = &p->aMem[pOp->p1]; assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); - sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3); + rc = sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3); + if( rc==SQLITE_ERROR ){ + sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pMem), (char*)0); + } break; } /* Opcode: Vacuum * * * @@ -4613,11 +4609,10 @@ }else{ rc = SQLITE_DONE; } sqlite3VdbeHalt(p); p->pTos = pTos; - pTsd->nRef--; return rc; /* Jump to here if a malloc() fails. It's hard to get a malloc() ** to fail on a modern VM computer, so this code is untested. */ @@ -4635,11 +4630,11 @@ /* Jump to here for any other kind of fatal error. The "rc" variable ** should hold the error number. */ abort_due_to_error: if( p->zErrMsg==0 ){ - if( pTsd->mallocFailed ) rc = SQLITE_NOMEM; + if( sqlite3MallocFailed() ) rc = SQLITE_NOMEM; sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0); } goto vdbe_halt; /* Jump to here if the sqlite3_interrupt() API sets the interrupt Index: SQLite.Interop/src/vdbe.h ================================================================== --- SQLite.Interop/src/vdbe.h +++ SQLite.Interop/src/vdbe.h @@ -13,11 +13,11 @@ ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.15 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: vdbe.h,v 1.16 2006/01/23 19:45:56 rmsimpson Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include Index: SQLite.Interop/src/vdbeInt.h ================================================================== --- SQLite.Interop/src/vdbeInt.h +++ SQLite.Interop/src/vdbeInt.h @@ -372,11 +372,11 @@ void sqlite3VdbeIntegerAffinity(Mem*); int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemNumerify(Mem*); int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); void sqlite3VdbeMemRelease(Mem *p); -void sqlite3VdbeMemFinalize(Mem*, FuncDef*); +int sqlite3VdbeMemFinalize(Mem*, FuncDef*); #ifndef NDEBUG void sqlite3VdbeMemSanity(Mem*, u8); int sqlite3VdbeOpcodeNoPush(u8); #endif int sqlite3VdbeMemTranslate(Mem*, u8); Index: SQLite.Interop/src/vdbeapi.c ================================================================== --- SQLite.Interop/src/vdbeapi.c +++ SQLite.Interop/src/vdbeapi.c @@ -93,14 +93,16 @@ } void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ pCtx->isError = 1; sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); } +#ifndef SQLITE_OMIT_UTF16 void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ pCtx->isError = 1; sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); } +#endif void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal); } void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ sqlite3VdbeMemSetInt64(&pCtx->s, iVal); @@ -155,11 +157,11 @@ Vdbe *p = (Vdbe*)pStmt; sqlite3 *db; int rc; /* Assert that malloc() has not failed */ - assert( !sqlite3ThreadDataReadOnly()->mallocFailed ); + assert( !sqlite3MallocFailed() ); if( p==0 || p->magic!=VDBE_MAGIC_RUN ){ return SQLITE_MISUSE; } if( p->aborted ){ @@ -239,12 +241,12 @@ assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC ); db->xProfile(db->pProfileArg, p->aOp[p->nOp-1].p3, elapseTime); } #endif - sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); - sqlite3MallocClearFailed(); + sqlite3Error(p->db, rc, 0); + p->rc = sqlite3ApiExit(p->db, p->rc); return rc; } /* ** Extract the user data from a sqlite3_context structure and return a @@ -403,14 +405,12 @@ /* If malloc() failed during an encoding conversion within an ** sqlite3_column_XXX API, then set the return code of the statement to ** SQLITE_NOMEM. The next call to _step() (if any) will return SQLITE_ERROR ** and _finalize() will return NOMEM. */ - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ - ((Vdbe *)pStmt)->rc = SQLITE_NOMEM; - sqlite3MallocClearFailed(); - } + Vdbe *p = (Vdbe *)pStmt; + p->rc = sqlite3ApiExit(0, p->rc); } /**************************** sqlite3_column_ ******************************* ** The following routines are used to access elements of the current row ** in the result set. @@ -501,11 +501,11 @@ ret = xFunc(&p->aColName[N]); /* A malloc may have failed inside of the xFunc() call. If this is the case, ** clear the mallocFailed flag and return NULL. */ - sqlite3MallocClearFailed(); + sqlite3ApiExit(0, 0); return ret; } /* ** Return the name of the Nth column of the result set returned by SQL @@ -629,17 +629,16 @@ if( rc || zData==0 ){ return rc; } pVar = &p->aVar[i-1]; rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); - if( rc ){ - return rc; - } if( rc==SQLITE_OK && encoding!=0 ){ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); } - return rc; + + sqlite3Error(((Vdbe *)pStmt)->db, rc, 0); + return sqlite3ApiExit(((Vdbe *)pStmt)->db, rc); } /* ** Bind a blob value to an SQL statement variable. @@ -779,11 +778,13 @@ } if( pFrom->nVar!=pTo->nVar ){ return SQLITE_ERROR; } for(i=0; rc==SQLITE_OK && inVar; i++){ + sqlite3MallocDisallow(); rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]); + sqlite3MallocAllow(); } return rc; } /* Index: SQLite.Interop/src/vdbeaux.c ================================================================== --- SQLite.Interop/src/vdbeaux.c +++ SQLite.Interop/src/vdbeaux.c @@ -299,11 +299,11 @@ */ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ int addr; assert( p->magic==VDBE_MAGIC_INIT ); resizeOpArray(p, p->nOp + nOp); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ return 0; } addr = p->nOp; if( nOp>0 ){ int i; @@ -413,11 +413,11 @@ ** If addr<0 then change P3 on the most recently inserted instruction. */ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){ Op *pOp; assert( p->magic==VDBE_MAGIC_INIT ); - if( p==0 || p->aOp==0 || sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( p==0 || p->aOp==0 || sqlite3MallocFailed() ){ if (n != P3_KEYINFO) { freeP3(n, (void*)*(char**)&zP3); } return; } @@ -438,15 +438,15 @@ nField = ((KeyInfo*)zP3)->nField; nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField; pKeyInfo = sqliteMallocRaw( nByte ); pOp->p3 = (char*)pKeyInfo; if( pKeyInfo ){ - char *aSortOrder; + unsigned char *aSortOrder; memcpy(pKeyInfo, zP3, nByte); aSortOrder = pKeyInfo->aSortOrder; if( aSortOrder ){ - pKeyInfo->aSortOrder = (char*)&pKeyInfo->aColl[nField]; + pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField]; memcpy(pKeyInfo->aSortOrder, aSortOrder, nField); } pOp->p3type = P3_KEYINFO; }else{ pOp->p3type = P3_NOTUSED; @@ -471,11 +471,11 @@ */ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ va_list ap; assert( p->nOp>0 ); assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 - || sqlite3ThreadDataReadOnly()->mallocFailed ); + || sqlite3MallocFailed() ); va_start(ap, zFormat); sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC); va_end(ap); } #endif @@ -737,11 +737,11 @@ + nVar*sizeof(Mem) /* aVar */ + nVar*sizeof(char*) /* azVar */ + nMem*sizeof(Mem) /* aMem */ + nCursor*sizeof(Cursor*) /* apCsr */ ); - if( !sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( !sqlite3MallocFailed() ){ p->aMem = &p->aStack[nStack]; p->nMem = nMem; p->aVar = &p->aMem[nMem]; p->nVar = nVar; p->okVar = 0; @@ -889,11 +889,11 @@ */ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){ int rc; Mem *pColName; assert( idx<(2*p->nResColumn) ); - if( sqlite3ThreadDataReadOnly()->mallocFailed ) return SQLITE_NOMEM; + if( sqlite3MallocFailed() ) return SQLITE_NOMEM; assert( p->aColName!=0 ); pColName = &(p->aColName[idx]); if( N==P3_DYNAMIC || N==P3_STATIC ){ rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC); }else{ @@ -1151,60 +1151,69 @@ */ int sqlite3VdbeHalt(Vdbe *p){ sqlite3 *db = p->db; int i; int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */ + int isSpecialError; /* Set to true if SQLITE_NOMEM or IOERR */ + + /* This function contains the logic that determines if a statement or + ** transaction will be committed or rolled back as a result of the + ** execution of this virtual machine. + ** + ** Special errors: + ** + ** If an SQLITE_NOMEM error has occured in a statement that writes to + ** the database, then either a statement or transaction must be rolled + ** back to ensure the tree-structures are in a consistent state. A + ** statement transaction is rolled back if one is open, otherwise the + ** entire transaction must be rolled back. + ** + ** If an SQLITE_IOERR error has occured in a statement that writes to + ** the database, then the entire transaction must be rolled back. The + ** I/O error may have caused garbage to be written to the journal + ** file. Were the transaction to continue and eventually be rolled + ** back that garbage might end up in the database file. + ** + ** In both of the above cases, the Vdbe.errorAction variable is + ** ignored. If the sqlite3.autoCommit flag is false and a transaction + ** is rolled back, it will be set to true. + ** + ** Other errors: + ** + ** No error: + ** + */ - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ p->rc = SQLITE_NOMEM; } - if( p->magic!=VDBE_MAGIC_RUN ){ /* Already halted. Nothing to do. */ assert( p->magic==VDBE_MAGIC_HALT ); return SQLITE_OK; } closeAllCursors(p); checkActiveVdbeCnt(db); - if( p->pc<0 ){ - /* No commit or rollback needed if the program never started */ - }else if( db->autoCommit && db->activeVdbeCnt==1 ){ - - if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && p->rc!=SQLITE_NOMEM)){ - /* The auto-commit flag is true, there are no other active queries - ** using this handle and the vdbe program was successful or hit an - ** 'OR FAIL' constraint. This means a commit is required. - */ - int rc = vdbeCommit(db); - if( rc==SQLITE_BUSY ){ - return SQLITE_BUSY; - }else if( rc!=SQLITE_OK ){ - p->rc = rc; - sqlite3RollbackAll(db); - }else{ - sqlite3CommitInternalChanges(db); - } - }else{ - sqlite3RollbackAll(db); - } - }else{ - - if( p->rc==SQLITE_NOMEM ){ + + /* No commit or rollback needed if the program never started */ + if( p->pc>=0 ){ + + /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */ + isSpecialError = ((p->rc==SQLITE_NOMEM || p->rc==SQLITE_IOERR)?1:0); + if( isSpecialError ){ /* This loop does static analysis of the query to see which of the ** following three categories it falls into: ** ** Read-only - ** Query with statement journal -> rollback statement - ** Query without statement journal -> rollback transaction + ** Query with statement journal + ** Query without statement journal ** ** We could do something more elegant than this static analysis (i.e. ** store the type of query as part of the compliation phase), but - ** handling malloc() failure is a fairly obscure edge case so this is - ** probably easier. - ** - ** Todo: This means we always override the p->errorAction value for a - ** malloc() failure. Is there any other choice here though? + ** handling malloc() or IO failure is a fairly obscure edge case so + ** this is probably easier. Todo: Might be an opportunity to reduce + ** code size a very small amount though... */ int isReadOnly = 1; int isStatement = 0; assert(p->aOp || p->nOp==0); for(i=0; inOp; i++){ @@ -1215,60 +1224,102 @@ case OP_Statement: isStatement = 1; break; } } - if( (isReadOnly||isStatement) && p->errorAction!=OE_Rollback ){ - p->errorAction = OE_Abort; - }else{ - p->errorAction = OE_Rollback; - } - } - - if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ - xFunc = sqlite3BtreeCommitStmt; - }else if( p->errorAction==OE_Abort ){ - xFunc = sqlite3BtreeRollbackStmt; - }else{ - abortOtherActiveVdbes(p); - sqlite3RollbackAll(db); - db->autoCommit = 1; - } - } - - /* If xFunc is not NULL, then it is one of - ** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on - ** each backend. If an error occurs and the return code is still - ** SQLITE_OK, set the return code to the new error value. - */ - assert(!xFunc || - xFunc==sqlite3BtreeCommitStmt || - xFunc==sqlite3BtreeRollbackStmt - ); - for(i=0; xFunc && inDb; i++){ - int rc; - Btree *pBt = db->aDb[i].pBt; - if( pBt ){ - rc = xFunc(pBt); - if( p->rc==SQLITE_OK ) p->rc = rc; - } - } - - /* If this was an INSERT, UPDATE or DELETE, set the change counter. */ - if( p->changeCntOn && p->pc>=0 ){ - if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){ - sqlite3VdbeSetChanges(db, p->nChange); - }else{ - sqlite3VdbeSetChanges(db, 0); - } - p->nChange = 0; - } - - /* Rollback or commit any schema changes that occurred. */ - if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){ - sqlite3ResetInternalSchema(db, 0); - db->flags = (db->flags | SQLITE_InternChanges); + + /* If the query was read-only, we need do no rollback at all. Otherwise, + ** proceed with the special handling. + */ + if( !isReadOnly ){ + if( p->rc==SQLITE_NOMEM && isStatement ){ + xFunc = sqlite3BtreeRollbackStmt; + }else{ + /* We are forced to roll back the active transaction. Before doing + ** so, abort any other statements this handle currently has active. + */ + abortOtherActiveVdbes(p); + sqlite3RollbackAll(db); + db->autoCommit = 1; + } + } + } + + /* If the auto-commit flag is set and this is the only active vdbe, then + ** we do either a commit or rollback of the current transaction. + ** + ** Note: This block also runs if one of the special errors handled + ** above has occured. + */ + if( db->autoCommit && db->activeVdbeCnt==1 ){ + if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ + /* The auto-commit flag is true, and the vdbe program was + ** successful or hit an 'OR FAIL' constraint. This means a commit + ** is required. + */ + int rc = vdbeCommit(db); + if( rc==SQLITE_BUSY ){ + return SQLITE_BUSY; + }else if( rc!=SQLITE_OK ){ + p->rc = rc; + sqlite3RollbackAll(db); + }else{ + sqlite3CommitInternalChanges(db); + } + }else{ + sqlite3RollbackAll(db); + } + }else if( !xFunc ){ + if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ + xFunc = sqlite3BtreeCommitStmt; + }else if( p->errorAction==OE_Abort ){ + xFunc = sqlite3BtreeRollbackStmt; + }else{ + abortOtherActiveVdbes(p); + sqlite3RollbackAll(db); + db->autoCommit = 1; + } + } + + /* If xFunc is not NULL, then it is one of sqlite3BtreeRollbackStmt or + ** sqlite3BtreeCommitStmt. Call it once on each backend. If an error occurs + ** and the return code is still SQLITE_OK, set the return code to the new + ** error value. + */ + assert(!xFunc || + xFunc==sqlite3BtreeCommitStmt || + xFunc==sqlite3BtreeRollbackStmt + ); + for(i=0; xFunc && inDb; i++){ + int rc; + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + rc = xFunc(pBt); + if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){ + p->rc = rc; + sqlite3SetString(&p->zErrMsg, 0); + } + } + } + + /* If this was an INSERT, UPDATE or DELETE and the statement was committed, + ** set the change counter. + */ + if( p->changeCntOn && p->pc>=0 ){ + if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){ + sqlite3VdbeSetChanges(db, p->nChange); + }else{ + sqlite3VdbeSetChanges(db, 0); + } + p->nChange = 0; + } + + /* Rollback or commit any schema changes that occurred. */ + if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){ + sqlite3ResetInternalSchema(db, 0); + db->flags = (db->flags | SQLITE_InternChanges); + } } /* We have successfully halted and closed the VM. Record this fact. */ if( p->pc>=0 ){ db->activeVdbeCnt--; @@ -1307,12 +1358,13 @@ ** if the VDBE has just been set to run but has not actually executed any ** instructions yet, leave the main database error information unchanged. */ if( p->pc>=0 ){ if( p->zErrMsg ){ - sqlite3Error(p->db, p->rc, "%s", p->zErrMsg); - sqliteFree(p->zErrMsg); + sqlite3* db = p->db; + sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3FreeX); + db->errCode = p->rc; p->zErrMsg = 0; }else if( p->rc ){ sqlite3Error(p->db, p->rc, 0); }else{ sqlite3Error(p->db, SQLITE_OK, 0); Index: SQLite.Interop/src/vdbemem.c ================================================================== --- SQLite.Interop/src/vdbemem.c +++ SQLite.Interop/src/vdbemem.c @@ -199,28 +199,37 @@ /* ** Memory cell pMem contains the context of an aggregate function. ** This routine calls the finalize method for that function. The ** result of the aggregate is stored back into pMem. +** +** Return SQLITE_ERROR if the finalizer reports an error. SQLITE_OK +** otherwise. */ -void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ +int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ + int rc = SQLITE_OK; if( pFunc && pFunc->xFinalize ){ sqlite3_context ctx; assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i ); ctx.s.flags = MEM_Null; ctx.s.z = pMem->zShort; ctx.pMem = pMem; ctx.pFunc = pFunc; + ctx.isError = 0; pFunc->xFinalize(&ctx); if( pMem->z && pMem->z!=pMem->zShort ){ sqliteFree( pMem->z ); } *pMem = ctx.s; if( pMem->flags & MEM_Short ){ pMem->z = pMem->zShort; } + if( ctx.isError ){ + rc = SQLITE_ERROR; + } } + return rc; } /* ** Release any memory held by the Mem. This may leave the Mem in an ** inconsistent state, for example with (Mem.z==0) and @@ -756,11 +765,11 @@ if( pVal->flags&MEM_Str ){ sqlite3VdbeChangeEncoding(pVal, enc); }else if( !(pVal->flags&MEM_Blob) ){ sqlite3VdbeMemStringify(pVal, enc); } - assert(pVal->enc==enc || sqlite3ThreadDataReadOnly()->mallocFailed); + assert(pVal->enc==enc || sqlite3MallocFailed() ); return (const void *)(pVal->enc==enc ? (pVal->z) : 0); } /* ** Create a new sqlite3_value object. Index: SQLite.Interop/src/where.c ================================================================== --- SQLite.Interop/src/where.c +++ SQLite.Interop/src/where.c @@ -14,11 +14,11 @@ ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.17 2006/01/16 15:51:47 rmsimpson Exp $ +** $Id: where.c,v 1.18 2006/01/23 19:45:56 rmsimpson Exp $ */ #include "sqliteInt.h" /* ** The number of bits in a Bitmask. "BMS" means "BitMask Size". @@ -38,20 +38,10 @@ # define TRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X #else # define TRACE(X) #endif -/* -** A large value which is the maximum cost of using an index. -** By default this is a large floating point value. When compiling -** SQLite for a processor that lacks floating point support, simply -** redefine this constant to a large integer. -*/ -#ifndef SQLITE_BIG_DBL -# define SQLITE_BIG_DBL (1.0e+99) -#endif - /* Forward reference */ typedef struct WhereClause WhereClause; /* @@ -91,11 +81,11 @@ struct WhereTerm { Expr *pExpr; /* Pointer to the subexpression */ i16 iParent; /* Disable pWC->a[iParent] when this term disabled */ i16 leftCursor; /* Cursor number of X in "X " */ i16 leftColumn; /* Column number of X in "X " */ - u16 operator; /* A WO_xx value describing */ + u16 eOperator; /* A WO_xx value describing */ u8 flags; /* Bit flags. See below */ u8 nChild; /* Number of children that must disable us */ WhereClause *pWC; /* The clause this term is part of */ Bitmask prereqRight; /* Bitmask of tables used by pRight */ Bitmask prereqAll; /* Bitmask of tables referenced by p */ @@ -426,11 +416,11 @@ int k; for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ if( pTerm->leftCursor==iCur && (pTerm->prereqRight & notReady)==0 && pTerm->leftColumn==iColumn - && (pTerm->operator & op)!=0 + && (pTerm->eOperator & op)!=0 ){ if( iCur>=0 && pIdx ){ Expr *pX = pTerm->pExpr; CollSeq *pColl; char idxaff; @@ -565,11 +555,11 @@ Bitmask prereqLeft; Bitmask prereqAll; int nPattern; int isComplete; - if( sqlite3ThreadDataReadOnly()->mallocFailed ) return; + if( sqlite3MallocFailed() ) return; prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); if( pExpr->op==TK_IN ){ assert( pExpr->pRight==0 ); pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList) | exprSelectTableUsage(pMaskSet, pExpr->pSelect); @@ -581,18 +571,18 @@ prereqAll |= getMask(pMaskSet, pExpr->iRightJoinTable); } pTerm->prereqAll = prereqAll; pTerm->leftCursor = -1; pTerm->iParent = -1; - pTerm->operator = 0; + pTerm->eOperator = 0; if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){ Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; if( pLeft->op==TK_COLUMN ){ pTerm->leftCursor = pLeft->iTable; pTerm->leftColumn = pLeft->iColumn; - pTerm->operator = operatorMask(pExpr->op); + pTerm->eOperator = operatorMask(pExpr->op); } if( pRight && pRight->op==TK_COLUMN ){ WhereTerm *pNew; Expr *pDup; if( pTerm->leftCursor>=0 ){ @@ -613,11 +603,11 @@ pLeft = pDup->pLeft; pNew->leftCursor = pLeft->iTable; pNew->leftColumn = pLeft->iColumn; pNew->prereqRight = prereqLeft; pNew->prereqAll = prereqAll; - pNew->operator = operatorMask(pDup->op); + pNew->eOperator = operatorMask(pDup->op); } } #ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION /* If a term is the BETWEEN operator, create two new virtual terms @@ -672,11 +662,11 @@ do{ iColumn = sOr.a[j].leftColumn; iCursor = sOr.a[j].leftCursor; ok = iCursor>=0; for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){ - if( pOrTerm->operator!=WO_EQ ){ + if( pOrTerm->eOperator!=WO_EQ ){ goto or_not_possible; } if( pOrTerm->leftCursor==iCursor && pOrTerm->leftColumn==iColumn ){ pOrTerm->flags |= TERM_OR_OK; }else if( (pOrTerm->flags & TERM_COPIED)!=0 || @@ -943,11 +933,11 @@ pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); if( pTerm ){ Expr *pExpr; *ppIndex = 0; bestFlags = WHERE_ROWID_EQ; - if( pTerm->operator & WO_EQ ){ + if( pTerm->eOperator & WO_EQ ){ /* Rowid== is always the best pick. Look no further. Because only ** a single row is generated, output is always in sorted order */ *pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE; *pnEq = 1; TRACE(("... best is rowid\n")); @@ -1024,11 +1014,11 @@ for(i=0; inColumn; i++){ int j = pProbe->aiColumn[i]; pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe); if( pTerm==0 ) break; flags |= WHERE_COLUMN_EQ; - if( pTerm->operator & WO_IN ){ + if( pTerm->eOperator & WO_IN ){ Expr *pExpr = pTerm->pExpr; flags |= WHERE_COLUMN_IN; if( pExpr->pSelect!=0 ){ inMultiplier *= 100; }else if( pExpr->pList!=0 ){ @@ -1449,11 +1439,11 @@ /* Allocate and initialize the WhereInfo structure that will become the ** return value. */ pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel)); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ goto whereBeginNoMem; } pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->iBreak = sqlite3VdbeMakeLabel(v); @@ -1473,11 +1463,11 @@ */ for(i=0; inSrc; i++){ createMask(&maskSet, pTabList->a[i].iCursor); } exprAnalyzeAll(pTabList, &maskSet, &wc); - if( sqlite3ThreadDataReadOnly()->mallocFailed ){ + if( sqlite3MallocFailed() ){ goto whereBeginNoMem; } /* Chose the best index to use for each table in the FROM clause. ** @@ -1506,11 +1496,11 @@ int j; /* For looping over FROM tables */ Index *pBest = 0; /* The best index seen so far */ int bestFlags = 0; /* Flags associated with pBest */ int bestNEq = 0; /* nEq associated with pBest */ double lowestCost; /* Cost of the pBest */ - int bestJ; /* The value of j */ + int bestJ = 0; /* The value of j */ Bitmask m; /* Bitmask value for j or bestJ */ lowestCost = SQLITE_BIG_DBL; for(j=iFrom, pTabItem=&pTabList->a[j]; jnSrc; j++, pTabItem++){ m = getMask(&maskSet, pTabItem->iCursor); @@ -1791,11 +1781,11 @@ pTerm = findTerm(&wc, iCur, k, notReady, topOp, pIdx); assert( pTerm!=0 ); pX = pTerm->pExpr; assert( (pTerm->flags & TERM_CODED)==0 ); sqlite3ExprCode(pParse, pX->pRight); - topEq = pTerm->operator & (WO_LE|WO_GE); + topEq = pTerm->eOperator & (WO_LE|WO_GE); disableTerm(pLevel, pTerm); testOp = OP_IdxGE; }else{ testOp = nEq>0 ? OP_IdxGE : OP_Noop; topEq = 1; @@ -1829,11 +1819,11 @@ pTerm = findTerm(&wc, iCur, k, notReady, btmOp, pIdx); assert( pTerm!=0 ); pX = pTerm->pExpr; assert( (pTerm->flags & TERM_CODED)==0 ); sqlite3ExprCode(pParse, pX->pRight); - btmEq = pTerm->operator & (WO_LE|WO_GE); + btmEq = pTerm->eOperator & (WO_LE|WO_GE); disableTerm(pLevel, pTerm); }else{ btmEq = 1; } if( nEq>0 || btmLimit ){ Index: SQLite.NET.sln ================================================================== --- SQLite.NET.sln +++ SQLite.NET.sln @@ -3,13 +3,13 @@ # Visual Studio 2005 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Data.SQLite - Compact", "System.Data.SQLite\System.Data.SQLite - Compact.csproj", "{AC139951-261A-4463-B6FA-AEBC25283A66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj", "{E27B1B1E-19C0-45E8-AA74-B6E1C041A130}" ProjectSection(ProjectDependencies) = postProject - {10B51CE8-A838-44DE-BD82-B658F0296F80} = {10B51CE8-A838-44DE-BD82-B658F0296F80} + {AC139951-261A-4463-B6FA-AEBC25283A66} = {AC139951-261A-4463-B6FA-AEBC25283A66} {AC139952-261A-4463-B6FA-AEBC25283A66} = {AC139952-261A-4463-B6FA-AEBC25283A66} - {AC139951-261A-4463-B6FA-AEBC25283A66} = {AC139951-261A-4463-B6FA-AEBC25283A66} + {10B51CE8-A838-44DE-BD82-B658F0296F80} = {10B51CE8-A838-44DE-BD82-B658F0296F80} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39A3B743-1EBD-4CC0-8E37-ACE3DD38B1C0}" ProjectSection(SolutionItems) = preProject readme.htm = readme.htm @@ -152,15 +152,18 @@ {AC139952-261A-4463-B6FA-AEBC25283A66}.Debug|Win32.ActiveCfg = Debug|Any CPU {AC139952-261A-4463-B6FA-AEBC25283A66}.Debug|Win32.Build.0 = Debug|Any CPU {AC139952-261A-4463-B6FA-AEBC25283A66}.Debug|x64.ActiveCfg = Debug|Any CPU {AC139952-261A-4463-B6FA-AEBC25283A66}.Debug|x64.Build.0 = Debug|Any CPU {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|Compact Framework.ActiveCfg = Debug|Any CPU - {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|Itanium.ActiveCfg = Debug|Any CPU + {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|Itanium.ActiveCfg = Release|Any CPU + {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|Itanium.Build.0 = Release|Any CPU {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|Mixed Platforms.ActiveCfg = Debug|Any CPU {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|Mixed Platforms.Build.0 = Debug|Any CPU - {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|Win32.ActiveCfg = Debug|Any CPU - {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|x64.ActiveCfg = Debug|Any CPU + {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|Win32.ActiveCfg = Release|Any CPU + {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|Win32.Build.0 = Release|Any CPU + {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|x64.ActiveCfg = Release|Any CPU + {AC139952-261A-4463-B6FA-AEBC25283A66}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal Index: SQLite.NET.suo ================================================================== --- SQLite.NET.suo +++ SQLite.NET.suo cannot compute difference between binary files Index: System.Data.SQLite/System.Data.SQLite ================================================================== --- System.Data.SQLite/System.Data.SQLite +++ System.Data.SQLite/System.Data.SQLite @@ -26,15 +26,15 @@ off 512 - true + false bin\ - full + none AnyCPU C:\Program Files\Microsoft Visual Studio 8\Team Tools\Static Analysis Tools\FxCop\\rules true GlobalSuppressions.cs Off Index: bin/tools/mergebin.exe ================================================================== --- bin/tools/mergebin.exe +++ bin/tools/mergebin.exe cannot compute difference between binary files