summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/main.c')
-rw-r--r--ext/pdo_sqlite/sqlite/src/main.c641
1 files changed, 434 insertions, 207 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/main.c b/ext/pdo_sqlite/sqlite/src/main.c
index c42df158e4..eccf83be69 100644
--- a/ext/pdo_sqlite/sqlite/src/main.c
+++ b/ext/pdo_sqlite/sqlite/src/main.c
@@ -26,32 +26,9 @@
*/
const int sqlite3one = 1;
-#ifndef SQLITE_OMIT_GLOBALRECOVER
-/*
-** Linked list of all open database handles. This is used by the
-** sqlite3_global_recover() function. Entries are added to the list
-** by openDatabase() and removed by sqlite3_close().
-*/
-static sqlite3 *pDbList = 0;
-#endif
-
-#ifndef SQLITE_OMIT_UTF16
-/*
-** Return the transient sqlite3_value object used for encoding conversions
-** during SQL compilation.
-*/
-sqlite3_value *sqlite3GetTransientValue(sqlite3 *db){
- if( !db->pValue ){
- db->pValue = sqlite3ValueNew();
- }
- return db->pValue;
-}
-#endif
-
/*
** The version of the library
*/
-const char rcsid3[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $";
const char sqlite3_version[] = SQLITE_VERSION;
const char *sqlite3_libversion(void){ return sqlite3_version; }
int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
@@ -132,10 +109,14 @@ int sqlite3_close(sqlite3 *db){
}
#ifdef SQLITE_SSE
- sqlite3_finalize(db->pFetch);
+ {
+ extern void sqlite3SseCleanup(sqlite3*);
+ sqlite3SseCleanup(db);
+ }
#endif
/* If there are any outstanding VMs, return SQLITE_BUSY. */
+ sqlite3ResetInternalSchema(db, 0);
if( db->pVdbe ){
sqlite3Error(db, SQLITE_BUSY,
"Unable to close due to unfinalised statements");
@@ -153,11 +134,16 @@ int sqlite3_close(sqlite3 *db){
return SQLITE_ERROR;
}
+ sqlite3VtabRollback(db);
+
for(j=0; j<db->nDb; j++){
struct Db *pDb = &db->aDb[j];
if( pDb->pBt ){
sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0;
+ if( j!=1 ){
+ pDb->pSchema = 0;
+ }
}
}
sqlite3ResetInternalSchema(db, 0);
@@ -176,36 +162,32 @@ int sqlite3_close(sqlite3 *db){
sqliteFree(pColl);
}
sqlite3HashClear(&db->aCollSeq);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){
+ Module *pMod = (Module *)sqliteHashData(i);
+ sqliteFree(pMod);
+ }
+ sqlite3HashClear(&db->aModule);
+#endif
sqlite3HashClear(&db->aFunc);
sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
- if( db->pValue ){
- sqlite3ValueFree(db->pValue);
- }
if( db->pErr ){
sqlite3ValueFree(db->pErr);
}
-
-#ifndef SQLITE_OMIT_GLOBALRECOVER
- {
- sqlite3 *pPrev;
- sqlite3OsEnterMutex();
- pPrev = pDbList;
- while( pPrev && pPrev->pNext!=db ){
- pPrev = pPrev->pNext;
- }
- if( pPrev ){
- pPrev->pNext = db->pNext;
- }else{
- assert( pDbList==db );
- pDbList = db->pNext;
- }
- sqlite3OsLeaveMutex();
- }
-#endif
+ sqlite3CloseExtensions(db);
db->magic = SQLITE_MAGIC_ERROR;
+
+ /* The temp-database schema is allocated differently from the other schema
+ ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
+ ** So it needs to be freed here. Todo: Why not roll the temp schema into
+ ** the same sqliteMalloc() as the one that allocates the database
+ ** structure?
+ */
+ sqliteFree(db->aDb[1].pSchema);
sqliteFree(db);
+ sqlite3ReleaseThreadData();
return SQLITE_OK;
}
@@ -214,13 +196,25 @@ int sqlite3_close(sqlite3 *db){
*/
void sqlite3RollbackAll(sqlite3 *db){
int i;
+ int inTrans = 0;
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt ){
+ if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
+ inTrans = 1;
+ }
sqlite3BtreeRollback(db->aDb[i].pBt);
db->aDb[i].inTrans = 0;
}
}
- sqlite3ResetInternalSchema(db, 0);
+ sqlite3VtabRollback(db);
+ if( db->flags&SQLITE_InternChanges ){
+ sqlite3ResetInternalSchema(db, 0);
+ }
+
+ /* If one has been configured, invoke the rollback-hook callback */
+ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
+ db->xRollbackCallback(db->pRollbackArg);
+ }
}
/*
@@ -271,7 +265,7 @@ static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
){
-#if SQLITE_MIN_SLEEP_MS==1
+#if OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP)
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
@@ -373,6 +367,9 @@ 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);
@@ -386,25 +383,43 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
** Cause any pending operation to stop at its earliest opportunity.
*/
void sqlite3_interrupt(sqlite3 *db){
- if( !sqlite3SafetyCheck(db) ){
- db->flags |= SQLITE_Interrupt;
+ if( db && (db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_BUSY) ){
+ db->u1.isInterrupted = 1;
}
}
/*
-** Windows systems should call this routine to free memory that
-** is returned in the in the errmsg parameter of sqlite3_open() when
-** SQLite is a DLL. For some reason, it does not work to call free()
-** directly.
+** 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.
**
-** Note that we need to call free() not sqliteFree() here.
+** Use sqlite3_free() to free memory returned by sqlite3_mprintf().
*/
-void sqlite3_free(char *p){ free(p); }
+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);
+ }
+}
/*
-** 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,
@@ -426,6 +441,7 @@ int sqlite3_create_function(
(!xFunc && (!xFinal && xStep)) ||
(nArg<-1 || nArg>127) ||
(255<(nName = strlen(zFunctionName))) ){
+ sqlite3Error(db, SQLITE_ERROR, "bad parameters");
return SQLITE_ERROR;
}
@@ -441,10 +457,10 @@ int sqlite3_create_function(
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;
@@ -463,6 +479,7 @@ int sqlite3_create_function(
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);
@@ -470,42 +487,57 @@ int sqlite3_create_function(
}
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;
+ p->nArg = nArg;
+ }
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 const *zFunc8;
- sqlite3_value *pTmp;
+ char *zFunc8;
+ assert( !sqlite3MallocFailed() );
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
- pTmp = sqlite3GetTransientValue(db);
- sqlite3ValueSetStr(pTmp, -1, zFunctionName, SQLITE_UTF16NATIVE,SQLITE_STATIC);
- zFunc8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
+ zFunc8 = sqlite3utf16to8(zFunctionName, -1);
+ rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
+ sqliteFree(zFunc8);
- if( !zFunc8 ){
- return SQLITE_NOMEM;
- }
- rc = sqlite3_create_function(db, zFunc8, nArg, eTextRep,
- pUserData, xFunc, xStep, xFinal);
- return rc;
+ return sqlite3ApiExit(db, rc);
}
#endif
@@ -547,7 +579,7 @@ void *sqlite3_profile(
/*** EXPERIMENTAL ***
**
** Register a function to be invoked when a transaction comments.
-** If either function returns non-zero, then the commit becomes a
+** If the invoked function returns non-zero, then the commit becomes a
** rollback.
*/
void *sqlite3_commit_hook(
@@ -561,6 +593,35 @@ void *sqlite3_commit_hook(
return pOld;
}
+/*
+** Register a callback to be invoked each time a row is updated,
+** inserted or deleted using this database connection.
+*/
+void *sqlite3_update_hook(
+ sqlite3 *db, /* Attach the hook to this database */
+ void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
+ void *pArg /* Argument to the function */
+){
+ void *pRet = db->pUpdateArg;
+ db->xUpdateCallback = xCallback;
+ db->pUpdateArg = pArg;
+ return pRet;
+}
+
+/*
+** Register a callback to be invoked each time a transaction is rolled
+** back by this database connection.
+*/
+void *sqlite3_rollback_hook(
+ sqlite3 *db, /* Attach the hook to this database */
+ void (*xCallback)(void*), /* Callback function */
+ void *pArg /* Argument to the function */
+){
+ void *pRet = db->pRollbackArg;
+ db->xRollbackCallback = xCallback;
+ db->pRollbackArg = pArg;
+ return pRet;
+}
/*
** This routine is called to create a connection to a database BTree
@@ -621,7 +682,7 @@ int sqlite3BtreeFactory(
#endif /* SQLITE_OMIT_MEMORYDB */
}
- rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags);
+ rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btree_flags);
if( rc==SQLITE_OK ){
sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler);
sqlite3BtreeSetCacheSize(*ppBtree, nCache);
@@ -635,13 +696,13 @@ int sqlite3BtreeFactory(
*/
const char *sqlite3_errmsg(sqlite3 *db){
const char *z;
- if( sqlite3_malloc_failed ){
+ if( !db || sqlite3MallocFailed() ){
return sqlite3ErrStr(SQLITE_NOMEM);
}
if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
return sqlite3ErrStr(SQLITE_MISUSE);
}
- z = sqlite3_value_text(db->pErr);
+ z = (char*)sqlite3_value_text(db->pErr);
if( z==0 ){
z = sqlite3ErrStr(db->errCode);
}
@@ -674,7 +735,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
};
const void *z;
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
}
if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
@@ -686,15 +747,17 @@ const void *sqlite3_errmsg16(sqlite3 *db){
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.
+** 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( sqlite3_malloc_failed ){
+ if( !db || sqlite3MallocFailed() ){
return SQLITE_NOMEM;
}
if( sqlite3SafetyCheck(db) ){
@@ -704,6 +767,63 @@ int sqlite3_errcode(sqlite3 *db){
}
/*
+** Create a new collating function for database "db". The name is zName
+** and the encoding is enc.
+*/
+static int createCollation(
+ sqlite3* db,
+ const char *zName,
+ int enc,
+ void* pCtx,
+ int(*xCompare)(void*,int,const void*,int,const void*)
+){
+ CollSeq *pColl;
+ int enc2;
+
+ 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.
+ */
+ enc2 = enc & ~SQLITE_UTF16_ALIGNED;
+ if( enc2==SQLITE_UTF16 ){
+ enc2 = SQLITE_UTF16NATIVE;
+ }
+
+ if( (enc2&~3)!=0 ){
+ sqlite3Error(db, SQLITE_ERROR, "unknown encoding");
+ 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)enc2, 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)enc2, zName, strlen(zName), 1);
+ if( pColl ){
+ pColl->xCmp = xCompare;
+ pColl->pUser = pCtx;
+ pColl->enc = enc2 | (enc & SQLITE_UTF16_ALIGNED);
+ }
+ 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.
@@ -713,9 +833,11 @@ static int openDatabase(
sqlite3 **ppDb /* OUT: Returned database handle */
){
sqlite3 *db;
- int rc, i;
+ int rc;
CollSeq *pColl;
+ assert( !sqlite3MallocFailed() );
+
/* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite3) );
if( db==0 ) goto opendb_out;
@@ -723,33 +845,34 @@ static int openDatabase(
db->magic = SQLITE_MAGIC_BUSY;
db->nDb = 2;
db->aDb = db->aDbStatic;
- db->enc = SQLITE_UTF8;
db->autoCommit = 1;
- db->flags |= SQLITE_ShortColNames;
+ db->flags |= SQLITE_ShortColNames
+#if SQLITE_DEFAULT_FILE_FORMAT<4
+ | SQLITE_LegacyFileFmt
+#endif
+ ;
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
- for(i=0; i<db->nDb; 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);
- }
-
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ sqlite3HashInit(&db->aModule, SQLITE_HASH_STRING, 0);
+#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) ||
- !(db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0)) ){
- rc = db->errCode;
- assert( rc!=SQLITE_OK );
+ if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc) ||
+ createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc) ||
+ createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc) ||
+ (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0
+ ){
+ 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;
@@ -765,6 +888,9 @@ static int openDatabase(
db->magic = SQLITE_MAGIC_CLOSED;
goto opendb_out;
}
+ db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt);
+ db->aDb[1].pSchema = sqlite3SchemaGet(0);
+
/* The default safety_level for the main database is 'full'; for the temp
** database it is 'NONE'. This matches the pager layer defaults.
@@ -776,29 +902,23 @@ static int openDatabase(
db->aDb[1].safety_level = 1;
#endif
-
/* 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( sqlite3_errcode(db)==SQLITE_OK && sqlite3_malloc_failed ){
- sqlite3Error(db, SQLITE_NOMEM, 0);
+ if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
+ sqlite3_close(db);
+ db = 0;
}
*ppDb = db;
-#ifndef SQLITE_OMIT_GLOBALRECOVER
- if( db ){
- sqlite3OsEnterMutex();
- db->pNext = pDbList;
- pDbList = db;
- sqlite3OsLeaveMutex();
- }
-#endif
- return sqlite3_errcode(db);
+ return sqlite3ApiExit(0, rc);
}
/*
@@ -820,9 +940,10 @@ int sqlite3_open16(
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;
pVal = sqlite3ValueNew();
@@ -831,14 +952,16 @@ int sqlite3_open16(
if( zFilename8 ){
rc = openDatabase(zFilename8, ppDb);
if( rc==SQLITE_OK && *ppDb ){
- sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
+ rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
+ if( rc!=SQLITE_OK ){
+ sqlite3_close(*ppDb);
+ *ppDb = 0;
+ }
}
}
- if( pVal ){
- sqlite3ValueFree(pVal);
- }
+ sqlite3ValueFree(pVal);
- return rc;
+ return sqlite3ApiExit(0, rc);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -890,53 +1013,10 @@ int sqlite3_create_collation(
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
@@ -950,15 +1030,15 @@ int sqlite3_create_collation16(
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*)
){
- char const *zName8;
- sqlite3_value *pTmp;
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
+ int rc = SQLITE_OK;
+ char *zName8;
+ assert( !sqlite3MallocFailed() );
+ zName8 = sqlite3utf16to8(zName, -1);
+ if( zName8 ){
+ rc = createCollation(db, zName8, enc, pCtx, xCompare);
+ sqliteFree(zName8);
}
- pTmp = sqlite3GetTransientValue(db);
- sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF16NATIVE, SQLITE_STATIC);
- zName8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
- return sqlite3_create_collation(db, zName8, enc, pCtx, xCompare);
+ return sqlite3ApiExit(db, rc);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -1002,37 +1082,11 @@ int sqlite3_collation_needed16(
#ifndef SQLITE_OMIT_GLOBALRECOVER
/*
-** This function is called to recover from a malloc failure that occured
-** within SQLite.
-**
-** This function is *not* threadsafe. Calling this from within a threaded
-** application when threads other than the caller have used SQLite is
-** dangerous and will almost certainly result in malfunctions.
+** 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 rc = SQLITE_OK;
-
- if( sqlite3_malloc_failed ){
- sqlite3 *db;
- int i;
- sqlite3_malloc_failed = 0;
- for(db=pDbList; db; db=db->pNext ){
- sqlite3ExpirePreparedStatements(db);
- for(i=0; i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt && (rc=sqlite3BtreeReset(pBt)) ){
- goto recover_out;
- }
- }
- db->autoCommit = 1;
- }
- }
-
-recover_out:
- if( rc!=SQLITE_OK ){
- sqlite3_malloc_failed = 1;
- }
- return rc;
+ return SQLITE_OK;
}
#endif
@@ -1058,3 +1112,176 @@ int sqlite3Corrupt(void){
return SQLITE_CORRUPT;
}
#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.
+*/
+void sqlite3_thread_cleanup(void){
+ ThreadData *pTd = sqlite3OsThreadSpecificData(0);
+ if( pTd ){
+ memset(pTd, 0, sizeof(*pTd));
+ sqlite3OsThreadSpecificData(-1);
+ }
+}
+
+/*
+** Return meta information about a specific column of a database table.
+** See comment in sqlite3.h (sqlite.h.in) for details.
+*/
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+int sqlite3_table_column_metadata(
+ sqlite3 *db, /* Connection handle */
+ const char *zDbName, /* Database name or NULL */
+ const char *zTableName, /* Table name */
+ const char *zColumnName, /* Column name */
+ char const **pzDataType, /* OUTPUT: Declared data type */
+ char const **pzCollSeq, /* OUTPUT: Collation sequence name */
+ int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */
+ int *pPrimaryKey, /* OUTPUT: True if column part of PK */
+ int *pAutoinc /* OUTPUT: True if colums is auto-increment */
+){
+ int rc;
+ char *zErrMsg = 0;
+ Table *pTab = 0;
+ Column *pCol = 0;
+ int iCol;
+
+ char const *zDataType = 0;
+ char const *zCollSeq = 0;
+ int notnull = 0;
+ int primarykey = 0;
+ int autoinc = 0;
+
+ /* Ensure the database schema has been loaded */
+ if( sqlite3SafetyOn(db) ){
+ return SQLITE_MISUSE;
+ }
+ rc = sqlite3Init(db, &zErrMsg);
+ if( SQLITE_OK!=rc ){
+ goto error_out;
+ }
+
+ /* Locate the table in question */
+ pTab = sqlite3FindTable(db, zTableName, zDbName);
+ if( !pTab || pTab->pSelect ){
+ pTab = 0;
+ goto error_out;
+ }
+
+ /* Find the column for which info is requested */
+ if( sqlite3IsRowid(zColumnName) ){
+ iCol = pTab->iPKey;
+ if( iCol>=0 ){
+ pCol = &pTab->aCol[iCol];
+ }
+ }else{
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ pCol = &pTab->aCol[iCol];
+ if( 0==sqlite3StrICmp(pCol->zName, zColumnName) ){
+ break;
+ }
+ }
+ if( iCol==pTab->nCol ){
+ pTab = 0;
+ goto error_out;
+ }
+ }
+
+ /* The following block stores the meta information that will be returned
+ ** to the caller in local variables zDataType, zCollSeq, notnull, primarykey
+ ** and autoinc. At this point there are two possibilities:
+ **
+ ** 1. The specified column name was rowid", "oid" or "_rowid_"
+ ** and there is no explicitly declared IPK column.
+ **
+ ** 2. The table is not a view and the column name identified an
+ ** explicitly declared column. Copy meta information from *pCol.
+ */
+ if( pCol ){
+ zDataType = pCol->zType;
+ zCollSeq = pCol->zColl;
+ notnull = (pCol->notNull?1:0);
+ primarykey = (pCol->isPrimKey?1:0);
+ autoinc = ((pTab->iPKey==iCol && pTab->autoInc)?1:0);
+ }else{
+ zDataType = "INTEGER";
+ primarykey = 1;
+ }
+ if( !zCollSeq ){
+ zCollSeq = "BINARY";
+ }
+
+error_out:
+ if( sqlite3SafetyOff(db) ){
+ rc = SQLITE_MISUSE;
+ }
+
+ /* Whether the function call succeeded or failed, set the output parameters
+ ** to whatever their local counterparts contain. If an error did occur,
+ ** this has the effect of zeroing all output parameters.
+ */
+ if( pzDataType ) *pzDataType = zDataType;
+ if( pzCollSeq ) *pzCollSeq = zCollSeq;
+ if( pNotNull ) *pNotNull = notnull;
+ if( pPrimaryKey ) *pPrimaryKey = primarykey;
+ if( pAutoinc ) *pAutoinc = autoinc;
+
+ if( SQLITE_OK==rc && !pTab ){
+ sqlite3SetString(&zErrMsg, "no such table column: ", zTableName, ".",
+ zColumnName, 0);
+ rc = SQLITE_ERROR;
+ }
+ sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg);
+ sqliteFree(zErrMsg);
+ return sqlite3ApiExit(db, rc);
+}
+#endif
+
+/*
+** Set all the parameters in the compiled SQL statement to NULL.
+*/
+int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
+ int i;
+ int rc = SQLITE_OK;
+ for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){
+ rc = sqlite3_bind_null(pStmt, i);
+ }
+ return rc;
+}
+
+/*
+** Sleep for a little while. Return the amount of time slept.
+*/
+int sqlite3_sleep(int ms){
+ return sqlite3OsSleep(ms);
+}