Upgraded bunbled SQLite lib to 3.3.7

This commit is contained in:
Ilia Alshanetsky 2006-08-14 16:15:29 +00:00
parent 0091c7e1b3
commit e8f30d4502
83 changed files with 17306 additions and 7930 deletions

View file

@ -23,6 +23,15 @@
#include <assert.h>
#include <ctype.h>
/*
* Windows needs to know which symbols to export. Unix does not.
* BUILD_sqlite should be undefined for Unix.
*/
#ifdef BUILD_sqlite
#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLEXPORT
#endif /* BUILD_sqlite */
#define NUM_PREPARED_STMTS 10
#define MAX_PREPARED_STMTS 100
@ -79,7 +88,7 @@ struct SqlPreparedStmt {
*/
typedef struct SqliteDb SqliteDb;
struct SqliteDb {
sqlite3 *db; /* The "real" database structure */
sqlite3 *db; /* The "real" database structure. MUST BE FIRST */
Tcl_Interp *interp; /* The interpreter used for this database */
char *zBusy; /* The busy callback routine */
char *zCommit; /* The commit hook callback routine */
@ -89,6 +98,8 @@ struct SqliteDb {
char *zAuth; /* The authorization callback routine */
char *zNull; /* Text to substitute for an SQL NULL value */
SqlFunc *pFunc; /* List of SQL functions */
Tcl_Obj *pUpdateHook; /* Update hook script (if any) */
Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */
SqlCollate *pCollate; /* List of SQL collation functions */
int rc; /* Return code of most recent sqlite3_exec() */
Tcl_Obj *pCollateNeeded; /* Collation needed script */
@ -200,6 +211,15 @@ static void DbDeleteCmd(void *db){
if( pDb->zNull ){
Tcl_Free(pDb->zNull);
}
if( pDb->pUpdateHook ){
Tcl_DecrRefCount(pDb->pUpdateHook);
}
if( pDb->pRollbackHook ){
Tcl_DecrRefCount(pDb->pRollbackHook);
}
if( pDb->pCollateNeeded ){
Tcl_DecrRefCount(pDb->pCollateNeeded);
}
Tcl_Free((char*)pDb);
}
@ -235,6 +255,7 @@ static int DbProgressHandler(void *cd){
return 0;
}
#ifndef SQLITE_OMIT_TRACE
/*
** This routine is called by the SQLite trace handler whenever a new
** block of SQL is executed. The TCL script in pDb->zTrace is executed.
@ -250,7 +271,9 @@ static void DbTraceHandler(void *cd, const char *zSql){
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.
@ -269,6 +292,7 @@ static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){
Tcl_DStringFree(&str);
Tcl_ResetResult(pDb->interp);
}
#endif
/*
** This routine is called when a transaction is committed. The
@ -287,6 +311,37 @@ static int DbCommitHandler(void *cd){
return 0;
}
static void DbRollbackHandler(void *clientData){
SqliteDb *pDb = (SqliteDb*)clientData;
assert(pDb->pRollbackHook);
if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){
Tcl_BackgroundError(pDb->interp);
}
}
static void DbUpdateHandler(
void *p,
int op,
const char *zDb,
const char *zTbl,
sqlite_int64 rowid
){
SqliteDb *pDb = (SqliteDb *)p;
Tcl_Obj *pCmd;
assert( pDb->pUpdateHook );
assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
pCmd = Tcl_DuplicateObj(pDb->pUpdateHook);
Tcl_IncrRefCount(pCmd);
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(
( (op==SQLITE_INSERT)?"INSERT":(op==SQLITE_UPDATE)?"UPDATE":"DELETE"), -1));
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1));
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1));
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid));
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
}
static void tclCollateNeeded(
void *pCtx,
sqlite3 *db,
@ -392,7 +447,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
}
default: {
int bytes = sqlite3_value_bytes(pIn);
pVal = Tcl_NewStringObj(sqlite3_value_text(pIn), bytes);
pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes);
break;
}
}
@ -439,8 +494,8 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
Tcl_GetWideIntFromObj(0, pVar, &v);
sqlite3_result_int64(context, v);
}else{
data = Tcl_GetStringFromObj(pVar, &n);
sqlite3_result_text(context, data, n, SQLITE_TRANSIENT);
data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT);
}
}
}
@ -496,6 +551,8 @@ static int auth_callback(
case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break;
case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break;
case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break;
case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break;
case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break;
default : zCode="????"; break;
}
Tcl_DStringInit(&str);
@ -610,22 +667,25 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"authorizer", "busy", "cache",
"changes", "close", "collate",
"collation_needed", "commit_hook", "complete",
"copy", "errorcode", "eval",
"function", "last_insert_rowid", "nullvalue",
"copy", "enable_load_extension","errorcode",
"eval", "exists", "function",
"interrupt", "last_insert_rowid", "nullvalue",
"onecolumn", "profile", "progress",
"rekey", "timeout", "total_changes",
"trace", "transaction", "version",
0
"rekey", "rollback_hook", "timeout",
"total_changes", "trace", "transaction",
"update_hook", "version", 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CACHE,
DB_CHANGES, DB_CLOSE, DB_COLLATE,
DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE,
DB_COPY, DB_ERRORCODE, DB_EVAL,
DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_NULLVALUE,
DB_COPY, DB_ENABLE_LOAD_EXTENSION,DB_ERRORCODE,
DB_EVAL, DB_EXISTS, DB_FUNCTION,
DB_INTERRUPT, DB_LAST_INSERT_ROWID,DB_NULLVALUE,
DB_ONECOLUMN, DB_PROFILE, DB_PROGRESS,
DB_REKEY, DB_TIMEOUT, DB_TOTAL_CHANGES,
DB_TRACE, DB_TRANSACTION, DB_VERSION
DB_REKEY, DB_ROLLBACK_HOOK, DB_TIMEOUT,
DB_TOTAL_CHANGES, DB_TRACE, DB_TRANSACTION,
DB_UPDATE_HOOK, DB_VERSION,
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@ -1036,9 +1096,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
if( azCol==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
fclose(in);
return TCL_ERROR;
}
sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
(void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
zCommit = "COMMIT";
while( (zLine = local_getline(0, in))!=0 ){
char *z;
@ -1058,10 +1119,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
if( i+1!=nCol ){
char *zErr;
zErr = malloc(200 + strlen(zFile));
sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d",
zFile, lineno, nCol, i+1);
Tcl_AppendResult(interp, zErr, 0);
free(zErr);
if( zErr ){
sprintf(zErr,
"Error: %s line %d: expected %d columns of data but found %d",
zFile, lineno, nCol, i+1);
Tcl_AppendResult(interp, zErr, 0);
free(zErr);
}
zCommit = "ROLLBACK";
break;
}
@ -1085,7 +1149,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
free(azCol);
fclose(in);
sqlite3_finalize(pStmt);
sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
(void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
if( zCommit[0] == 'C' ){
/* success, set result as number of lines processed */
@ -1101,6 +1165,25 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
/*
** $db enable_load_extension BOOLEAN
**
** Turn the extension loading feature on or off. It if off by
** default.
*/
case DB_ENABLE_LOAD_EXTENSION: {
int onoff;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN");
return TCL_ERROR;
}
if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){
return TCL_ERROR;
}
sqlite3_enable_load_extension(pDb->db, onoff);
break;
}
/*
** $db errorcode
**
@ -1126,7 +1209,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** lindex [$db eval $sql] 0
*/
case DB_ONECOLUMN:
case DB_EVAL: {
case DB_EVAL:
case DB_EXISTS: {
char const *zSql; /* Next SQL statement to execute */
char const *zLeft; /* What is left after first stmt in zSql */
sqlite3_stmt *pStmt; /* Compiled SQL statment */
@ -1139,19 +1223,24 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
SqlPreparedStmt *pPreStmt; /* Pointer to a prepared statement */
int rc2;
if( choice==DB_ONECOLUMN ){
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "SQL");
return TCL_ERROR;
}
pRet = 0;
}else{
if( choice==DB_EVAL ){
if( objc<3 || objc>5 ){
Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?");
return TCL_ERROR;
}
pRet = Tcl_NewObj();
Tcl_IncrRefCount(pRet);
}else{
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "SQL");
return TCL_ERROR;
}
if( choice==DB_EXISTS ){
pRet = Tcl_NewBooleanObj(0);
Tcl_IncrRefCount(pRet);
}else{
pRet = 0;
}
}
if( objc==3 ){
pArray = pScript = 0;
@ -1275,8 +1364,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_GetWideIntFromObj(interp, pVar, &v);
sqlite3_bind_int64(pStmt, i, v);
}else{
data = Tcl_GetStringFromObj(pVar, &n);
sqlite3_bind_text(pStmt, i, data, n, SQLITE_STATIC);
data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC);
Tcl_IncrRefCount(pVar);
apParm[nParm++] = pVar;
}
@ -1344,7 +1433,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
default: {
pVal = dbTextToObj(sqlite3_column_text(pStmt, i));
pVal = dbTextToObj((char *)sqlite3_column_text(pStmt, i));
break;
}
}
@ -1356,11 +1445,19 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0);
}
}else if( choice==DB_ONECOLUMN ){
assert( pRet==0 );
if( pRet==0 ){
pRet = pVal;
Tcl_IncrRefCount(pRet);
}
rc = TCL_BREAK;
i = nCol;
}else if( choice==DB_EXISTS ){
Tcl_DecrRefCount(pRet);
pRet = Tcl_NewBooleanObj(1);
Tcl_IncrRefCount(pRet);
rc = TCL_BREAK;
i = nCol;
}else{
Tcl_ListObjAppendElement(interp, pRet, pVal);
}
@ -1471,6 +1568,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_SetObjResult(interp, pRet);
}
Tcl_DecrRefCount(pRet);
}else if( rc==TCL_OK ){
Tcl_ResetResult(interp);
}
break;
}
@ -1511,6 +1610,17 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
/*
** $db interrupt
**
** Interrupt the execution of the inner-most SQL interpreter. This
** causes the SQL statement to return an error of SQLITE_INTERRUPT.
*/
case DB_INTERRUPT: {
sqlite3_interrupt(pDb->db);
break;
}
/*
** $db nullvalue ?STRING?
**
@ -1549,14 +1659,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
*/
case DB_LAST_INSERT_ROWID: {
Tcl_Obj *pResult;
int rowid;
Tcl_WideInt rowid;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 2, objv, "");
return TCL_ERROR;
}
rowid = sqlite3_last_insert_rowid(pDb->db);
pResult = Tcl_GetObjResult(interp);
Tcl_SetIntObj(pResult, rowid);
Tcl_SetWideIntObj(pResult, rowid);
break;
}
@ -1782,7 +1892,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
inTrans = !sqlite3_get_autocommit(pDb->db);
if( !inTrans ){
sqlite3_exec(pDb->db, zBegin, 0, 0, 0);
(void)sqlite3_exec(pDb->db, zBegin, 0, 0, 0);
}
rc = Tcl_EvalObjEx(interp, pScript, 0);
if( !inTrans ){
@ -1792,11 +1902,53 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
} else {
zEnd = "COMMIT";
}
sqlite3_exec(pDb->db, zEnd, 0, 0, 0);
(void)sqlite3_exec(pDb->db, zEnd, 0, 0, 0);
}
break;
}
/*
** $db update_hook ?script?
** $db rollback_hook ?script?
*/
case DB_UPDATE_HOOK:
case DB_ROLLBACK_HOOK: {
/* set ppHook to point at pUpdateHook or pRollbackHook, depending on
** whether [$db update_hook] or [$db rollback_hook] was invoked.
*/
Tcl_Obj **ppHook;
if( choice==DB_UPDATE_HOOK ){
ppHook = &pDb->pUpdateHook;
}else{
ppHook = &pDb->pRollbackHook;
}
if( objc!=2 && objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
return TCL_ERROR;
}
if( *ppHook ){
Tcl_SetObjResult(interp, *ppHook);
if( objc==3 ){
Tcl_DecrRefCount(*ppHook);
*ppHook = 0;
}
}
if( objc==3 ){
assert( !(*ppHook) );
if( Tcl_GetCharLength(objv[2])>0 ){
*ppHook = objv[2];
Tcl_IncrRefCount(*ppHook);
}
}
sqlite3_update_hook(pDb->db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb);
sqlite3_rollback_hook(pDb->db,(pDb->pRollbackHook?DbRollbackHandler:0),pDb);
break;
}
/* $db version
**
** Return the version string for this database.
@ -1849,7 +2001,6 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
const char *zArg;
char *zErrMsg;
const char *zFile;
char zBuf[80];
if( objc==2 ){
zArg = Tcl_GetStringFromObj(objv[1], 0);
if( strcmp(zArg,"-version")==0 ){
@ -1917,14 +2068,6 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
zArg = Tcl_GetStringFromObj(objv[1], 0);
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
/* The return value is the value of the sqlite* pointer
*/
sprintf(zBuf, "%p", p->db);
if( strncmp(zBuf,"0x",2) ){
sprintf(zBuf, "0x%p", p->db);
}
Tcl_AppendResult(interp, zBuf, 0);
/* If compiled with SQLITE_TEST turned on, then register the "md5sum"
** SQL function.
*/
@ -1939,7 +2082,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
#ifdef SQLITE_MEMDEBUG
sqlite3_iMallocFail = mallocfail;
#endif
}
}
#endif
p->interp = interp;
return TCL_OK;
@ -1954,6 +2097,15 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
# define Tcl_InitStubs(a,b,c)
#endif
/*
** Make sure we have a PACKAGE_VERSION macro defined. This will be
** defined automatically by the TEA makefile. But other makefiles
** do not define it.
*/
#ifndef PACKAGE_VERSION
# define PACKAGE_VERSION SQLITE_VERSION
#endif
/*
** Initialize this module.
**
@ -1963,23 +2115,23 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** used to open a new SQLite database. See the DbMain() routine above
** for additional information.
*/
int Sqlite3_Init(Tcl_Interp *interp){
EXTERN int Sqlite3_Init(Tcl_Interp *interp){
Tcl_InitStubs(interp, "8.4", 0);
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
Tcl_PkgProvide(interp, "sqlite3", "3.0");
Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION);
Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
Tcl_PkgProvide(interp, "sqlite", "3.0");
Tcl_PkgProvide(interp, "sqlite", PACKAGE_VERSION);
return TCL_OK;
}
int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
EXTERN int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
#ifndef SQLITE_3_SUFFIX_ONLY
int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
EXTERN int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
EXTERN int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
EXTERN int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
#endif
#ifdef TCLSH
@ -2040,14 +2192,26 @@ int TCLSH_MAIN(int argc, char **argv){
extern int Sqlitetest3_Init(Tcl_Interp*);
extern int Sqlitetest4_Init(Tcl_Interp*);
extern int Sqlitetest5_Init(Tcl_Interp*);
extern int Sqlitetest6_Init(Tcl_Interp*);
extern int Sqlitetest7_Init(Tcl_Interp*);
extern int Sqlitetest8_Init(Tcl_Interp*);
extern int Md5_Init(Tcl_Interp*);
extern int Sqlitetestsse_Init(Tcl_Interp*);
extern int Sqlitetestasync_Init(Tcl_Interp*);
extern int Sqlitetesttclvar_Init(Tcl_Interp*);
extern int Sqlitetestschema_Init(Tcl_Interp*);
Sqlitetest1_Init(interp);
Sqlitetest2_Init(interp);
Sqlitetest3_Init(interp);
Sqlitetest4_Init(interp);
Sqlitetest5_Init(interp);
Sqlitetest6_Init(interp);
Sqlitetest7_Init(interp);
Sqlitetest8_Init(interp);
Sqlitetestasync_Init(interp);
Sqlitetesttclvar_Init(interp);
Sqlitetestschema_Init(interp);
Md5_Init(interp);
#ifdef SQLITE_SSE
Sqlitetestsse_Init(interp);