summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src/main.c
diff options
context:
space:
mode:
authorScott MacVicar <scottmac@php.net>2008-03-07 10:55:14 +0000
committerScott MacVicar <scottmac@php.net>2008-03-07 10:55:14 +0000
commit31dade5280849135b00fd1c5e53d057732a72776 (patch)
tree564b9f0f9d8cf89d7df9a9c12147ba8a5da6506f /ext/pdo_sqlite/sqlite/src/main.c
parent7abf0787ad9fd613ddde880c9bc163161d7bf4ff (diff)
downloadphp-git-31dade5280849135b00fd1c5e53d057732a72776.tar.gz
MFB: Update bundled SQLite to 3.5.6
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/main.c')
-rw-r--r--ext/pdo_sqlite/sqlite/src/main.c700
1 files changed, 461 insertions, 239 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/main.c b/ext/pdo_sqlite/sqlite/src/main.c
index eccf83be69..a6617ead74 100644
--- a/ext/pdo_sqlite/sqlite/src/main.c
+++ b/ext/pdo_sqlite/sqlite/src/main.c
@@ -17,14 +17,10 @@
** $Id$
*/
#include "sqliteInt.h"
-#include "os.h"
#include <ctype.h>
-
-/*
-** The following constant value is used by the SQLITE_BIGENDIAN and
-** SQLITE_LITTLEENDIAN macros.
-*/
-const int sqlite3one = 1;
+#ifdef SQLITE_ENABLE_FTS3
+# include "fts3.h"
+#endif
/*
** The version of the library
@@ -32,13 +28,43 @@ const int sqlite3one = 1;
const char sqlite3_version[] = SQLITE_VERSION;
const char *sqlite3_libversion(void){ return sqlite3_version; }
int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
+int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
+
+/*
+** If the following function pointer is not NULL and if
+** SQLITE_ENABLE_IOTRACE is enabled, then messages describing
+** I/O active are written using this function. These messages
+** are intended for debugging activity only.
+*/
+void (*sqlite3_io_trace)(const char*, ...) = 0;
+
+/*
+** If the following global variable points to a string which is the
+** name of a directory, then that directory will be used to store
+** temporary files.
+**
+** See also the "PRAGMA temp_store_directory" SQL command.
+*/
+char *sqlite3_temp_directory = 0;
+
+
+/*
+** Return true if the buffer z[0..n-1] contains all spaces.
+*/
+static int allSpaces(const char *z, int n){
+ while( n>0 && z[--n]==' ' ){}
+ return n==0;
+}
/*
** This is the default collating function named "BINARY" which is always
** available.
+**
+** If the padFlag argument is not NULL then space padding at the end
+** of strings is ignored. This implements the RTRIM collation.
*/
static int binCollFunc(
- void *NotUsed,
+ void *padFlag,
int nKey1, const void *pKey1,
int nKey2, const void *pKey2
){
@@ -46,7 +72,14 @@ static int binCollFunc(
n = nKey1<nKey2 ? nKey1 : nKey2;
rc = memcmp(pKey1, pKey2, n);
if( rc==0 ){
- rc = nKey1 - nKey2;
+ if( padFlag
+ && allSpaces(((char*)pKey1)+n, nKey1-n)
+ && allSpaces(((char*)pKey2)+n, nKey2-n)
+ ){
+ /* Leave rc unchanged at 0 */
+ }else{
+ rc = nKey1 - nKey2;
+ }
}
return rc;
}
@@ -104,9 +137,10 @@ int sqlite3_close(sqlite3 *db){
if( !db ){
return SQLITE_OK;
}
- if( sqlite3SafetyCheck(db) ){
+ if( !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE;
}
+ sqlite3_mutex_enter(db->mutex);
#ifdef SQLITE_SSE
{
@@ -115,26 +149,25 @@ int sqlite3_close(sqlite3 *db){
}
#endif
- /* If there are any outstanding VMs, return SQLITE_BUSY. */
sqlite3ResetInternalSchema(db, 0);
+
+ /* If a transaction is open, the ResetInternalSchema() call above
+ ** will not have called the xDisconnect() method on any virtual
+ ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback()
+ ** call will do so. We need to do this before the check for active
+ ** SQL statements below, as the v-table implementation may be storing
+ ** some prepared statements internally.
+ */
+ sqlite3VtabRollback(db);
+
+ /* If there are any outstanding VMs, return SQLITE_BUSY. */
if( db->pVdbe ){
sqlite3Error(db, SQLITE_BUSY,
"Unable to close due to unfinalised statements");
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_BUSY;
}
- assert( !sqlite3SafetyCheck(db) );
-
- /* FIX ME: db->magic may be set to SQLITE_MAGIC_CLOSED if the database
- ** cannot be opened for some reason. So this routine needs to run in
- ** that case. But maybe there should be an extra magic value for the
- ** "failed to open" state.
- */
- if( db->magic!=SQLITE_MAGIC_CLOSED && sqlite3SafetyOn(db) ){
- /* printf("DID NOT CLOSE\n"); fflush(stdout); */
- return SQLITE_ERROR;
- }
-
- sqlite3VtabRollback(db);
+ assert( sqlite3SafetyCheckSickOrOk(db) );
for(j=0; j<db->nDb; j++){
struct Db *pDb = &db->aDb[j];
@@ -153,19 +186,28 @@ int sqlite3_close(sqlite3 *db){
FuncDef *pFunc, *pNext;
for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){
pNext = pFunc->pNext;
- sqliteFree(pFunc);
+ sqlite3_free(pFunc);
}
}
for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
CollSeq *pColl = (CollSeq *)sqliteHashData(i);
- sqliteFree(pColl);
+ /* Invoke any destructors registered for collation sequence user data. */
+ for(j=0; j<3; j++){
+ if( pColl[j].xDel ){
+ pColl[j].xDel(pColl[j].pUser);
+ }
+ }
+ sqlite3_free(pColl);
}
sqlite3HashClear(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){
Module *pMod = (Module *)sqliteHashData(i);
- sqliteFree(pMod);
+ if( pMod->xDestroy ){
+ pMod->xDestroy(pMod->pAux);
+ }
+ sqlite3_free(pMod);
}
sqlite3HashClear(&db->aModule);
#endif
@@ -185,9 +227,11 @@ int sqlite3_close(sqlite3 *db){
** the same sqliteMalloc() as the one that allocates the database
** structure?
*/
- sqliteFree(db->aDb[1].pSchema);
- sqliteFree(db);
- sqlite3ReleaseThreadData();
+ sqlite3_free(db->aDb[1].pSchema);
+ sqlite3_mutex_leave(db->mutex);
+ db->magic = SQLITE_MAGIC_CLOSED;
+ sqlite3_mutex_free(db->mutex);
+ sqlite3_free(db);
return SQLITE_OK;
}
@@ -197,6 +241,8 @@ int sqlite3_close(sqlite3 *db){
void sqlite3RollbackAll(sqlite3 *db){
int i;
int inTrans = 0;
+ assert( sqlite3_mutex_held(db->mutex) );
+ sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 1);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt ){
if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
@@ -207,7 +253,10 @@ void sqlite3RollbackAll(sqlite3 *db){
}
}
sqlite3VtabRollback(db);
+ sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0);
+
if( db->flags&SQLITE_InternChanges ){
+ sqlite3ExpirePreparedStatements(db);
sqlite3ResetInternalSchema(db, 0);
}
@@ -223,7 +272,7 @@ void sqlite3RollbackAll(sqlite3 *db){
*/
const char *sqlite3ErrStr(int rc){
const char *z;
- switch( rc ){
+ switch( rc & 0xff ){
case SQLITE_ROW:
case SQLITE_DONE:
case SQLITE_OK: z = "not an error"; break;
@@ -239,9 +288,9 @@ const char *sqlite3ErrStr(int rc){
case SQLITE_CORRUPT: z = "database disk image is malformed"; break;
case SQLITE_FULL: z = "database or disk is full"; break;
case SQLITE_CANTOPEN: z = "unable to open database file"; break;
- case SQLITE_PROTOCOL: z = "database locking protocol failure"; break;
case SQLITE_EMPTY: z = "table contains no data"; break;
case SQLITE_SCHEMA: z = "database schema has changed"; break;
+ case SQLITE_TOOBIG: z = "String or BLOB exceeded size limit"; break;
case SQLITE_CONSTRAINT: z = "constraint failed"; break;
case SQLITE_MISMATCH: z = "datatype mismatch"; break;
case SQLITE_MISUSE: z = "library routine called out of sequence";break;
@@ -271,7 +320,8 @@ static int sqliteDefaultBusyCallback(
static const u8 totals[] =
{ 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 };
# define NDELAY (sizeof(delays)/sizeof(delays[0]))
- int timeout = ((sqlite3 *)ptr)->busyTimeout;
+ sqlite3 *db = (sqlite3 *)ptr;
+ int timeout = db->busyTimeout;
int delay, prior;
assert( count>=0 );
@@ -286,14 +336,15 @@ static int sqliteDefaultBusyCallback(
delay = timeout - prior;
if( delay<=0 ) return 0;
}
- sqlite3OsSleep(delay);
+ sqlite3OsSleep(db->pVfs, delay*1000);
return 1;
#else
+ sqlite3 *db = (sqlite3 *)ptr;
int timeout = ((sqlite3 *)ptr)->busyTimeout;
if( (count+1)*1000 > timeout ){
return 0;
}
- sqlite3OsSleep(1000);
+ sqlite3OsSleep(db->pVfs, 1000000);
return 1;
#endif
}
@@ -326,12 +377,11 @@ int sqlite3_busy_handler(
int (*xBusy)(void*,int),
void *pArg
){
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
+ sqlite3_mutex_enter(db->mutex);
db->busyHandler.xFunc = xBusy;
db->busyHandler.pArg = pArg;
db->busyHandler.nBusy = 0;
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -347,7 +397,8 @@ void sqlite3_progress_handler(
int (*xProgress)(void*),
void *pArg
){
- if( !sqlite3SafetyCheck(db) ){
+ if( sqlite3SafetyCheckOk(db) ){
+ sqlite3_mutex_enter(db->mutex);
if( nOps>0 ){
db->xProgress = xProgress;
db->nProgressOps = nOps;
@@ -357,6 +408,7 @@ void sqlite3_progress_handler(
db->nProgressOps = 0;
db->pProgressArg = 0;
}
+ sqlite3_mutex_leave(db->mutex);
}
}
#endif
@@ -367,9 +419,6 @@ void sqlite3_progress_handler(
** specified number of milliseconds before returning 0.
*/
int sqlite3_busy_timeout(sqlite3 *db, int ms){
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
if( ms>0 ){
db->busyTimeout = ms;
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
@@ -383,35 +432,11 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
** Cause any pending operation to stop at its earliest opportunity.
*/
void sqlite3_interrupt(sqlite3 *db){
- if( db && (db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_BUSY) ){
+ if( sqlite3SafetyCheckOk(db) ){
db->u1.isInterrupted = 1;
}
}
-/*
-** Memory allocation routines that use SQLites internal memory
-** memory allocator. Depending on how SQLite is compiled, the
-** internal memory allocator might be just an alias for the
-** system default malloc/realloc/free. Or the built-in allocator
-** might do extra stuff like put sentinals around buffers to
-** check for overruns or look for memory leaks.
-**
-** Use sqlite3_free() to free memory returned by sqlite3_mprintf().
-*/
-void sqlite3_free(void *p){ if( p ) sqlite3OsFree(p); }
-void *sqlite3_malloc(int nByte){ return nByte>0 ? sqlite3OsMalloc(nByte) : 0; }
-void *sqlite3_realloc(void *pOld, int nByte){
- if( pOld ){
- if( nByte>0 ){
- return sqlite3OsRealloc(pOld, nByte);
- }else{
- sqlite3OsFree(pOld);
- return 0;
- }
- }else{
- return sqlite3_malloc(nByte);
- }
-}
/*
** This function is exactly the same as sqlite3_create_function(), except
@@ -432,9 +457,7 @@ int sqlite3CreateFunc(
FuncDef *p;
int nName;
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
+ assert( sqlite3_mutex_held(db->mutex) );
if( zFunctionName==0 ||
(xFunc && (xFinal || xStep)) ||
(!xFunc && (xFinal && !xStep)) ||
@@ -459,10 +482,13 @@ int sqlite3CreateFunc(
int rc;
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8,
pUserData, xFunc, xStep, xFinal);
- if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
- pUserData, xFunc, xStep, xFinal);
- if( rc!=SQLITE_OK ) return rc;
+ if( rc==SQLITE_OK ){
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
+ pUserData, xFunc, xStep, xFinal);
+ }
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
enc = SQLITE_UTF16BE;
}
#else
@@ -479,7 +505,7 @@ int sqlite3CreateFunc(
if( db->activeVdbeCnt ){
sqlite3Error(db, SQLITE_BUSY,
"Unable to delete/modify user-function due to active statements");
- assert( !sqlite3MallocFailed() );
+ assert( !db->mallocFailed );
return SQLITE_BUSY;
}else{
sqlite3ExpirePreparedStatements(db);
@@ -487,14 +513,16 @@ int sqlite3CreateFunc(
}
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1);
- if( p ){
- p->flags = 0;
- p->xFunc = xFunc;
- p->xStep = xStep;
- p->xFinalize = xFinal;
- p->pUserData = pUserData;
- p->nArg = nArg;
+ assert(p || db->mallocFailed);
+ if( !p ){
+ return SQLITE_NOMEM;
}
+ p->flags = 0;
+ p->xFunc = xFunc;
+ p->xStep = xStep;
+ p->xFinalize = xFinal;
+ p->pUserData = pUserData;
+ p->nArg = nArg;
return SQLITE_OK;
}
@@ -512,10 +540,12 @@ int sqlite3_create_function(
void (*xFinal)(sqlite3_context*)
){
int rc;
- assert( !sqlite3MallocFailed() );
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal);
-
- return sqlite3ApiExit(db, rc);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#ifndef SQLITE_OMIT_UTF16
@@ -531,16 +561,47 @@ int sqlite3_create_function16(
){
int rc;
char *zFunc8;
- assert( !sqlite3MallocFailed() );
-
- zFunc8 = sqlite3utf16to8(zFunctionName, -1);
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
+ zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1);
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
- sqliteFree(zFunc8);
-
- return sqlite3ApiExit(db, rc);
+ sqlite3_free(zFunc8);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#endif
+
+/*
+** Declare that a function has been overloaded by a virtual table.
+**
+** If the function already exists as a regular global function, then
+** this routine is a no-op. If the function does not exist, then create
+** a new one that always throws a run-time error.
+**
+** When virtual tables intend to provide an overloaded function, they
+** should call this routine to make sure the global function exists.
+** A global function must exist in order for name resolution to work
+** properly.
+*/
+int sqlite3_overload_function(
+ sqlite3 *db,
+ const char *zName,
+ int nArg
+){
+ int nName = strlen(zName);
+ int rc;
+ sqlite3_mutex_enter(db->mutex);
+ if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
+ sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
+ 0, sqlite3InvalidFunction, 0, 0);
+ }
+ rc = sqlite3ApiExit(db, SQLITE_OK);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
#ifndef SQLITE_OMIT_TRACE
/*
** Register a trace function. The pArg from the previously registered trace
@@ -551,9 +612,12 @@ int sqlite3_create_function16(
** SQL statement.
*/
void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
- void *pOld = db->pTraceArg;
+ void *pOld;
+ sqlite3_mutex_enter(db->mutex);
+ pOld = db->pTraceArg;
db->xTrace = xTrace;
db->pTraceArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
return pOld;
}
/*
@@ -569,9 +633,12 @@ void *sqlite3_profile(
void (*xProfile)(void*,const char*,sqlite_uint64),
void *pArg
){
- void *pOld = db->pProfileArg;
+ void *pOld;
+ sqlite3_mutex_enter(db->mutex);
+ pOld = db->pProfileArg;
db->xProfile = xProfile;
db->pProfileArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
return pOld;
}
#endif /* SQLITE_OMIT_TRACE */
@@ -587,9 +654,12 @@ void *sqlite3_commit_hook(
int (*xCallback)(void*), /* Function to invoke on each commit */
void *pArg /* Argument to the function */
){
- void *pOld = db->pCommitArg;
+ void *pOld;
+ sqlite3_mutex_enter(db->mutex);
+ pOld = db->pCommitArg;
db->xCommitCallback = xCallback;
db->pCommitArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
return pOld;
}
@@ -602,9 +672,12 @@ void *sqlite3_update_hook(
void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
void *pArg /* Argument to the function */
){
- void *pRet = db->pUpdateArg;
+ void *pRet;
+ sqlite3_mutex_enter(db->mutex);
+ pRet = db->pUpdateArg;
db->xUpdateCallback = xCallback;
db->pUpdateArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
return pRet;
}
@@ -617,9 +690,12 @@ void *sqlite3_rollback_hook(
void (*xCallback)(void*), /* Callback function */
void *pArg /* Argument to the function */
){
- void *pRet = db->pRollbackArg;
+ void *pRet;
+ sqlite3_mutex_enter(db->mutex);
+ pRet = db->pRollbackArg;
db->xRollbackCallback = xCallback;
db->pRollbackArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
return pRet;
}
@@ -653,17 +729,19 @@ int sqlite3BtreeFactory(
const char *zFilename, /* Name of the file containing the BTree database */
int omitJournal, /* if TRUE then do not journal this file */
int nCache, /* How many pages in the page cache */
+ int vfsFlags, /* Flags passed through to vfsOpen */
Btree **ppBtree /* Pointer to new Btree object written here */
){
- int btree_flags = 0;
+ int btFlags = 0;
int rc;
+ assert( sqlite3_mutex_held(db->mutex) );
assert( ppBtree != 0);
if( omitJournal ){
- btree_flags |= BTREE_OMIT_JOURNAL;
+ btFlags |= BTREE_OMIT_JOURNAL;
}
if( db->flags & SQLITE_NoReadlock ){
- btree_flags |= BTREE_NO_READLOCK;
+ btFlags |= BTREE_NO_READLOCK;
}
if( zFilename==0 ){
#if TEMP_STORE==0
@@ -682,9 +760,11 @@ int sqlite3BtreeFactory(
#endif /* SQLITE_OMIT_MEMORYDB */
}
- rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btree_flags);
+ if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (zFilename==0 || *zFilename==0) ){
+ vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
+ }
+ rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btFlags, vfsFlags);
if( rc==SQLITE_OK ){
- sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler);
sqlite3BtreeSetCacheSize(*ppBtree, nCache);
}
return rc;
@@ -696,16 +776,19 @@ int sqlite3BtreeFactory(
*/
const char *sqlite3_errmsg(sqlite3 *db){
const char *z;
- if( !db || sqlite3MallocFailed() ){
+ if( !db ){
return sqlite3ErrStr(SQLITE_NOMEM);
}
- if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
+ if( !sqlite3SafetyCheckSickOrOk(db) || db->errCode==SQLITE_MISUSE ){
return sqlite3ErrStr(SQLITE_MISUSE);
}
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
z = (char*)sqlite3_value_text(db->pErr);
if( z==0 ){
z = sqlite3ErrStr(db->errCode);
}
+ sqlite3_mutex_leave(db->mutex);
return z;
}
@@ -735,12 +818,14 @@ const void *sqlite3_errmsg16(sqlite3 *db){
};
const void *z;
- if( sqlite3MallocFailed() ){
+ if( !db ){
return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
}
- if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
+ if( !sqlite3SafetyCheckSickOrOk(db) || db->errCode==SQLITE_MISUSE ){
return (void *)(&misuseBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
}
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
z = sqlite3_value_text16(db->pErr);
if( z==0 ){
sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode),
@@ -748,6 +833,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
z = sqlite3_value_text16(db->pErr);
}
sqlite3ApiExit(0, 0);
+ sqlite3_mutex_leave(db->mutex);
return z;
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -757,13 +843,13 @@ const void *sqlite3_errmsg16(sqlite3 *db){
** passed to this function, we assume a malloc() failed during sqlite3_open().
*/
int sqlite3_errcode(sqlite3 *db){
- if( !db || sqlite3MallocFailed() ){
- return SQLITE_NOMEM;
- }
- if( sqlite3SafetyCheck(db) ){
+ if( db && !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE;
}
- return db->errCode;
+ if( !db || db->mallocFailed ){
+ return SQLITE_NOMEM;
+ }
+ return db->errCode & db->errMask;
}
/*
@@ -775,14 +861,13 @@ static int createCollation(
const char *zName,
int enc,
void* pCtx,
- int(*xCompare)(void*,int,const void*,int,const void*)
+ int(*xCompare)(void*,int,const void*,int,const void*),
+ void(*xDel)(void*)
){
CollSeq *pColl;
int enc2;
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
+ assert( sqlite3_mutex_held(db->mutex) );
/* If SQLITE_UTF16 is specified as the encoding type, transform this
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
@@ -810,12 +895,33 @@ static int createCollation(
return SQLITE_BUSY;
}
sqlite3ExpirePreparedStatements(db);
+
+ /* If collation sequence pColl was created directly by a call to
+ ** sqlite3_create_collation, and not generated by synthCollSeq(),
+ ** then any copies made by synthCollSeq() need to be invalidated.
+ ** Also, collation destructor - CollSeq.xDel() - function may need
+ ** to be called.
+ */
+ if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){
+ CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName, strlen(zName));
+ int j;
+ for(j=0; j<3; j++){
+ CollSeq *p = &aColl[j];
+ if( p->enc==pColl->enc ){
+ if( p->xDel ){
+ p->xDel(p->pUser);
+ }
+ p->xCmp = 0;
+ }
+ }
+ }
}
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, strlen(zName), 1);
if( pColl ){
pColl->xCmp = xCompare;
pColl->pUser = pCtx;
+ pColl->xDel = xDel;
pColl->enc = enc2 | (enc & SQLITE_UTF16_ALIGNED);
}
sqlite3Error(db, SQLITE_OK, 0);
@@ -830,26 +936,38 @@ static int createCollation(
*/
static int openDatabase(
const char *zFilename, /* Database filename UTF-8 encoded */
- sqlite3 **ppDb /* OUT: Returned database handle */
+ sqlite3 **ppDb, /* OUT: Returned database handle */
+ unsigned flags, /* Operational flags */
+ const char *zVfs /* Name of the VFS to use */
){
sqlite3 *db;
int rc;
CollSeq *pColl;
- assert( !sqlite3MallocFailed() );
-
/* Allocate the sqlite data structure */
- db = sqliteMalloc( sizeof(sqlite3) );
+ db = sqlite3MallocZero( sizeof(sqlite3) );
if( db==0 ) goto opendb_out;
+ db->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
+ if( db->mutex==0 ){
+ sqlite3_free(db);
+ db = 0;
+ goto opendb_out;
+ }
+ sqlite3_mutex_enter(db->mutex);
+ db->errMask = 0xff;
db->priorNewRowid = 0;
- db->magic = SQLITE_MAGIC_BUSY;
db->nDb = 2;
+ db->magic = SQLITE_MAGIC_BUSY;
db->aDb = db->aDbStatic;
db->autoCommit = 1;
+ db->nextAutovac = -1;
db->flags |= SQLITE_ShortColNames
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
+#ifdef SQLITE_ENABLE_LOAD_EXTENSION
+ | SQLITE_LoadExtension
+#endif
;
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
@@ -857,22 +975,31 @@ static int openDatabase(
sqlite3HashInit(&db->aModule, SQLITE_HASH_STRING, 0);
#endif
+ db->pVfs = sqlite3_vfs_find(zVfs);
+ if( !db->pVfs ){
+ rc = SQLITE_ERROR;
+ db->magic = SQLITE_MAGIC_SICK;
+ sqlite3Error(db, rc, "no such vfs: %s", (zVfs?zVfs:"(null)"));
+ goto opendb_out;
+ }
+
/* Add the default collation sequence BINARY. BINARY works for both UTF-8
** and UTF-16, so add a version for each to avoid any unnecessary
** conversions. The only error that can occur here is a malloc() failure.
*/
- if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc) ||
- createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc) ||
- createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc) ||
+ if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0) ||
+ createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0) ||
+ createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0) ||
+ createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0) ||
(db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0
){
- assert( sqlite3MallocFailed() );
- db->magic = SQLITE_MAGIC_CLOSED;
+ assert( db->mallocFailed );
+ db->magic = SQLITE_MAGIC_SICK;
goto opendb_out;
}
/* Also add a UTF-8 case-insensitive collation sequence. */
- createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
+ createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
/* Set flags on the built-in collating sequences */
db->pDfltColl->type = SQLITE_COLL_BINARY;
@@ -882,14 +1009,17 @@ static int openDatabase(
}
/* Open the backend database driver */
- rc = sqlite3BtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
+ db->openFlags = flags;
+ rc = sqlite3BtreeFactory(db, zFilename, 0, SQLITE_DEFAULT_CACHE_SIZE,
+ flags | SQLITE_OPEN_MAIN_DB,
+ &db->aDb[0].pBt);
if( rc!=SQLITE_OK ){
sqlite3Error(db, rc, 0);
- db->magic = SQLITE_MAGIC_CLOSED;
+ db->magic = SQLITE_MAGIC_SICK;
goto opendb_out;
}
- db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt);
- db->aDb[1].pSchema = sqlite3SchemaGet(0);
+ db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
+ db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
/* The default safety_level for the main database is 'full'; for the temp
@@ -902,17 +1032,68 @@ static int openDatabase(
db->aDb[1].safety_level = 1;
#endif
+ db->magic = SQLITE_MAGIC_OPEN;
+ if( db->mallocFailed ){
+ goto opendb_out;
+ }
+
/* 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.
*/
- if( !sqlite3MallocFailed() ){
- sqlite3RegisterBuiltinFunctions(db);
- sqlite3Error(db, SQLITE_OK, 0);
+ sqlite3Error(db, SQLITE_OK, 0);
+ sqlite3RegisterBuiltinFunctions(db);
+
+ /* Load automatic extensions - extensions that have been registered
+ ** using the sqlite3_automatic_extension() API.
+ */
+ (void)sqlite3AutoLoadExtensions(db);
+ if( sqlite3_errcode(db)!=SQLITE_OK ){
+ goto opendb_out;
}
- db->magic = SQLITE_MAGIC_OPEN;
+
+#ifdef SQLITE_ENABLE_FTS1
+ if( !db->mallocFailed ){
+ extern int sqlite3Fts1Init(sqlite3*);
+ rc = sqlite3Fts1Init(db);
+ }
+#endif
+
+#ifdef SQLITE_ENABLE_FTS2
+ if( !db->mallocFailed && rc==SQLITE_OK ){
+ extern int sqlite3Fts2Init(sqlite3*);
+ rc = sqlite3Fts2Init(db);
+ }
+#endif
+
+#ifdef SQLITE_ENABLE_FTS3
+ if( !db->mallocFailed && rc==SQLITE_OK ){
+ rc = sqlite3Fts3Init(db);
+ }
+#endif
+
+#ifdef SQLITE_ENABLE_ICU
+ if( !db->mallocFailed && rc==SQLITE_OK ){
+ extern int sqlite3IcuInit(sqlite3*);
+ rc = sqlite3IcuInit(db);
+ }
+#endif
+ sqlite3Error(db, rc, 0);
+
+ /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
+ ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
+ ** mode. Doing nothing at all also makes NORMAL the default.
+ */
+#ifdef SQLITE_DEFAULT_LOCKING_MODE
+ db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
+ sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
+ SQLITE_DEFAULT_LOCKING_MODE);
+#endif
opendb_out:
+ if( db && db->mutex ){
+ sqlite3_mutex_leave(db->mutex);
+ }
if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
sqlite3_close(db);
db = 0;
@@ -928,7 +1109,16 @@ int sqlite3_open(
const char *zFilename,
sqlite3 **ppDb
){
- return openDatabase(zFilename, ppDb);
+ return openDatabase(zFilename, ppDb,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
+}
+int sqlite3_open_v2(
+ const char *filename, /* Database filename (UTF-8) */
+ sqlite3 **ppDb, /* OUT: SQLite db handle */
+ int flags, /* Flags */
+ const char *zVfs /* Name of VFS module to use */
+){
+ return openDatabase(filename, ppDb, flags, zVfs);
}
#ifndef SQLITE_OMIT_UTF16
@@ -940,17 +1130,18 @@ int sqlite3_open16(
sqlite3 **ppDb
){
char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */
- int rc = SQLITE_OK;
sqlite3_value *pVal;
+ int rc = SQLITE_NOMEM;
assert( zFilename );
assert( ppDb );
*ppDb = 0;
- pVal = sqlite3ValueNew();
+ pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zFilename8 ){
- rc = openDatabase(zFilename8, ppDb);
+ rc = openDatabase(zFilename8, ppDb,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
if( rc==SQLITE_OK && *ppDb ){
rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
if( rc!=SQLITE_OK ){
@@ -966,57 +1157,42 @@ int sqlite3_open16(
#endif /* SQLITE_OMIT_UTF16 */
/*
-** The following routine destroys a virtual machine that is created by
-** the sqlite3_compile() routine. The integer returned is an SQLITE_
-** success/failure code that describes the result of executing the virtual
-** machine.
-**
-** This routine sets the error code and string returned by
-** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
-*/
-int sqlite3_finalize(sqlite3_stmt *pStmt){
- int rc;
- if( pStmt==0 ){
- rc = SQLITE_OK;
- }else{
- rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
- }
- return rc;
-}
-
-/*
-** Terminate the current execution of an SQL statement and reset it
-** back to its starting state so that it can be reused. A success code from
-** the prior execution is returned.
-**
-** This routine sets the error code and string returned by
-** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
+** Register a new collation sequence with the database handle db.
*/
-int sqlite3_reset(sqlite3_stmt *pStmt){
+int sqlite3_create_collation(
+ sqlite3* db,
+ const char *zName,
+ int enc,
+ void* pCtx,
+ int(*xCompare)(void*,int,const void*,int,const void*)
+){
int rc;
- if( pStmt==0 ){
- rc = SQLITE_OK;
- }else{
- rc = sqlite3VdbeReset((Vdbe*)pStmt);
- sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
- }
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
+ rc = createCollation(db, zName, enc, pCtx, xCompare, 0);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
return rc;
}
/*
** Register a new collation sequence with the database handle db.
*/
-int sqlite3_create_collation(
+int sqlite3_create_collation_v2(
sqlite3* db,
const char *zName,
int enc,
void* pCtx,
- int(*xCompare)(void*,int,const void*,int,const void*)
+ int(*xCompare)(void*,int,const void*,int,const void*),
+ void(*xDel)(void*)
){
int rc;
- assert( !sqlite3MallocFailed() );
- rc = createCollation(db, zName, enc, pCtx, xCompare);
- return sqlite3ApiExit(db, rc);
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
+ rc = createCollation(db, zName, enc, pCtx, xCompare, xDel);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#ifndef SQLITE_OMIT_UTF16
@@ -1031,14 +1207,17 @@ int sqlite3_create_collation16(
int(*xCompare)(void*,int,const void*,int,const void*)
){
int rc = SQLITE_OK;
- char *zName8;
- assert( !sqlite3MallocFailed() );
- zName8 = sqlite3utf16to8(zName, -1);
+ char *zName8;
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
+ zName8 = sqlite3Utf16to8(db, zName, -1);
if( zName8 ){
- rc = createCollation(db, zName8, enc, pCtx, xCompare);
- sqliteFree(zName8);
+ rc = createCollation(db, zName8, enc, pCtx, xCompare, 0);
+ sqlite3_free(zName8);
}
- return sqlite3ApiExit(db, rc);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -1051,12 +1230,11 @@ int sqlite3_collation_needed(
void *pCollNeededArg,
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
){
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
+ sqlite3_mutex_enter(db->mutex);
db->xCollNeeded = xCollNeeded;
db->xCollNeeded16 = 0;
db->pCollNeededArg = pCollNeededArg;
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -1070,12 +1248,11 @@ int sqlite3_collation_needed16(
void *pCollNeededArg,
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
){
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
+ sqlite3_mutex_enter(db->mutex);
db->xCollNeeded = 0;
db->xCollNeeded16 = xCollNeeded16;
db->pCollNeededArg = pCollNeededArg;
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -1085,7 +1262,7 @@ int sqlite3_collation_needed16(
** This function is now an anachronism. It used to be used to recover from a
** malloc() failure, but SQLite now does this automatically.
*/
-int sqlite3_global_recover(){
+int sqlite3_global_recover(void){
return SQLITE_OK;
}
#endif
@@ -1113,45 +1290,14 @@ int sqlite3Corrupt(void){
}
#endif
-
-#ifndef SQLITE_OMIT_SHARED_CACHE
-/*
-** Enable or disable the shared pager and schema features for the
-** current thread.
-**
-** This routine should only be called when there are no open
-** database connections.
-*/
-int sqlite3_enable_shared_cache(int enable){
- ThreadData *pTd = sqlite3ThreadData();
- if( pTd ){
- /* It is only legal to call sqlite3_enable_shared_cache() when there
- ** are no currently open b-trees that were opened by the calling thread.
- ** This condition is only easy to detect if the shared-cache were
- ** previously enabled (and is being disabled).
- */
- if( pTd->pBtree && !enable ){
- assert( pTd->useSharedData );
- return SQLITE_MISUSE;
- }
-
- pTd->useSharedData = enable;
- sqlite3ReleaseThreadData();
- }
- return sqlite3ApiExit(0, SQLITE_OK);
-}
-#endif
-
/*
** This is a convenience routine that makes sure that all thread-specific
** data for this thread has been deallocated.
+**
+** SQLite no longer uses thread-specific data so this routine is now a
+** no-op. It is retained for historical compatibility.
*/
void sqlite3_thread_cleanup(void){
- ThreadData *pTd = sqlite3OsThreadSpecificData(0);
- if( pTd ){
- memset(pTd, 0, sizeof(*pTd));
- sqlite3OsThreadSpecificData(-1);
- }
}
/*
@@ -1183,9 +1329,8 @@ int sqlite3_table_column_metadata(
int autoinc = 0;
/* Ensure the database schema has been loaded */
- if( sqlite3SafetyOn(db) ){
- return SQLITE_MISUSE;
- }
+ (void)sqlite3SafetyOn(db);
+ sqlite3_mutex_enter(db->mutex);
rc = sqlite3Init(db, &zErrMsg);
if( SQLITE_OK!=rc ){
goto error_out;
@@ -1242,9 +1387,7 @@ int sqlite3_table_column_metadata(
}
error_out:
- if( sqlite3SafetyOff(db) ){
- rc = SQLITE_MISUSE;
- }
+ (void)sqlite3SafetyOff(db);
/* Whether the function call succeeded or failed, set the output parameters
** to whatever their local counterparts contain. If an error did occur,
@@ -1262,26 +1405,105 @@ error_out:
rc = SQLITE_ERROR;
}
sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg);
- sqliteFree(zErrMsg);
- return sqlite3ApiExit(db, rc);
+ sqlite3_free(zErrMsg);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#endif
/*
-** Set all the parameters in the compiled SQL statement to NULL.
+** Sleep for a little while. Return the amount of time slept.
*/
-int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
- int i;
- int rc = SQLITE_OK;
- for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){
- rc = sqlite3_bind_null(pStmt, i);
- }
+int sqlite3_sleep(int ms){
+ sqlite3_vfs *pVfs;
+ int rc;
+ pVfs = sqlite3_vfs_find(0);
+
+ /* This function works in milliseconds, but the underlying OsSleep()
+ ** API uses microseconds. Hence the 1000's.
+ */
+ rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000);
return rc;
}
/*
-** Sleep for a little while. Return the amount of time slept.
+** Enable or disable the extended result codes.
*/
-int sqlite3_sleep(int ms){
- return sqlite3OsSleep(ms);
+int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
+ sqlite3_mutex_enter(db->mutex);
+ db->errMask = onoff ? 0xffffffff : 0xff;
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+}
+
+/*
+** Invoke the xFileControl method on a particular database.
+*/
+int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
+ int rc = SQLITE_ERROR;
+ int iDb;
+ sqlite3_mutex_enter(db->mutex);
+ if( zDbName==0 ){
+ iDb = 0;
+ }else{
+ for(iDb=0; iDb<db->nDb; iDb++){
+ if( strcmp(db->aDb[iDb].zName, zDbName)==0 ) break;
+ }
+ }
+ if( iDb<db->nDb ){
+ Btree *pBtree = db->aDb[iDb].pBt;
+ if( pBtree ){
+ Pager *pPager;
+ sqlite3_file *fd;
+ sqlite3BtreeEnter(pBtree);
+ pPager = sqlite3BtreePager(pBtree);
+ assert( pPager!=0 );
+ fd = sqlite3PagerFile(pPager);
+ assert( fd!=0 );
+ if( fd->pMethods ){
+ rc = sqlite3OsFileControl(fd, op, pArg);
+ }
+ sqlite3BtreeLeave(pBtree);
+ }
+ }
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
+/*
+** Interface to the testing logic.
+*/
+int sqlite3_test_control(int op, ...){
+ va_list ap;
+ int rc = 0;
+ va_start(ap, op);
+ switch( op ){
+#ifndef SQLITE_OMIT_FAULTINJECTOR
+ case SQLITE_TESTCTRL_FAULT_CONFIG: {
+ int id = va_arg(ap, int);
+ int nDelay = va_arg(ap, int);
+ int nRepeat = va_arg(ap, int);
+ sqlite3FaultConfig(id, nDelay, nRepeat);
+ break;
+ }
+ case SQLITE_TESTCTRL_FAULT_FAILURES: {
+ int id = va_arg(ap, int);
+ rc = sqlite3FaultFailures(id);
+ break;
+ }
+ case SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES: {
+ int id = va_arg(ap, int);
+ rc = sqlite3FaultBenignFailures(id);
+ break;
+ }
+ case SQLITE_TESTCTRL_FAULT_PENDING: {
+ int id = va_arg(ap, int);
+ rc = sqlite3FaultPending(id);
+ break;
+ }
+#endif /* SQLITE_OMIT_FAULTINJECTOR */
+ }
+ va_end(ap);
+ return rc;
}