diff options
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/tclsqlite.c')
-rw-r--r-- | ext/pdo_sqlite/sqlite/src/tclsqlite.c | 272 |
1 files changed, 218 insertions, 54 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/tclsqlite.c b/ext/pdo_sqlite/sqlite/src/tclsqlite.c index 9a8b823b7e..8572b7cf65 100644 --- a/ext/pdo_sqlite/sqlite/src/tclsqlite.c +++ b/ext/pdo_sqlite/sqlite/src/tclsqlite.c @@ -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 */ @@ -1102,6 +1166,25 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ } /* + ** $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 ** ** Return the numeric error code that was returned by the most recent @@ -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; } @@ -1512,6 +1611,17 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ } /* + ** $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? ** ** Change text used when a NULL comes back from the database. If ?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,8 +1902,50 @@ 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; } @@ -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; @@ -1955,6 +2098,15 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ #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. ** ** This Tcl module contains only a single new Tcl command named "sqlite". @@ -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); |