diff options
Diffstat (limited to 'tea/generic/tclsqlite3.c')
-rw-r--r-- | tea/generic/tclsqlite3.c | 320 |
1 files changed, 201 insertions, 119 deletions
diff --git a/tea/generic/tclsqlite3.c b/tea/generic/tclsqlite3.c index 37cef47..26b4e47 100644 --- a/tea/generic/tclsqlite3.c +++ b/tea/generic/tclsqlite3.c @@ -1,7 +1,7 @@ #ifdef USE_SYSTEM_SQLITE # include <sqlite3.h> #else -#include "../../sqlite3.c" +#include "sqlite3.c" #endif /* ** 2001 September 15 @@ -30,6 +30,14 @@ ** hundreds of new commands used for testing ** SQLite. This option implies -DSQLITE_TCLMD5. */ + +/* +** If requested, include the SQLite compiler options file for MSVC. +*/ +#if defined(INCLUDE_MSVC_H) +#include "msvc.h" +#endif + #include "tcl.h" #include <errno.h> @@ -46,6 +54,18 @@ #endif #include <ctype.h> +/* Used to get the current process ID */ +#if !defined(_WIN32) +# include <unistd.h> +# define GETPID getpid +#elif !defined(_WIN32_WCE) +# ifndef SQLITE_AMALGAMATION +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# endif +# define GETPID (int)GetCurrentProcessId +#endif + /* * Windows needs to know which symbols to export. Unix does not. * BUILD_sqlite should be undefined for Unix. @@ -58,15 +78,8 @@ #define NUM_PREPARED_STMTS 10 #define MAX_PREPARED_STMTS 100 -/* -** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we -** have to do a translation when going between the two. Set the -** UTF_TRANSLATION_NEEDED macro to indicate that we need to do -** this translation. -*/ -#if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8) -# define UTF_TRANSLATION_NEEDED 1 -#endif +/* Forward declaration */ +typedef struct SqliteDb SqliteDb; /* ** New SQL functions can be created as TCL scripts. Each such function @@ -76,6 +89,7 @@ typedef struct SqlFunc SqlFunc; struct SqlFunc { Tcl_Interp *interp; /* The TCL interpret to execute the function */ Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */ + SqliteDb *pDb; /* Database connection that owns this function */ int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */ char *zName; /* Name of this function */ SqlFunc *pNext; /* Next function on the list of them all */ @@ -118,7 +132,6 @@ typedef struct IncrblobChannel IncrblobChannel; ** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements. ** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used. */ -typedef struct SqliteDb SqliteDb; struct SqliteDb { sqlite3 *db; /* The "real" database structure. MUST BE FIRST */ Tcl_Interp *interp; /* The interpreter used for this database */ @@ -424,18 +437,18 @@ static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){ */ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ SqlFunc *p, *pNew; - int i; - pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + strlen30(zName) + 1 ); + int nName = strlen30(zName); + pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 ); pNew->zName = (char*)&pNew[1]; - for(i=0; zName[i]; i++){ pNew->zName[i] = tolower(zName[i]); } - pNew->zName[i] = 0; + memcpy(pNew->zName, zName, nName+1); for(p=pDb->pFunc; p; p=p->pNext){ - if( strcmp(p->zName, pNew->zName)==0 ){ + if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){ Tcl_Free((char*)pNew); return p; } } pNew->interp = pDb->interp; + pNew->pDb = pDb; pNew->pScript = 0; pNew->pNext = pDb->pFunc; pDb->pFunc = pNew; @@ -483,6 +496,7 @@ static void DbDeleteCmd(void *db){ while( pDb->pFunc ){ SqlFunc *pFunc = pDb->pFunc; pDb->pFunc = pFunc->pNext; + assert( pFunc->pDb==pDb ); Tcl_DecrRefCount(pFunc->pScript); Tcl_Free((char*)pFunc); } @@ -634,6 +648,7 @@ static int DbWalHandler( Tcl_Interp *interp = pDb->interp; assert(pDb->pWalHook); + assert( db==pDb->db ); p = Tcl_DuplicateObj(pDb->pWalHook); Tcl_IncrRefCount(p); Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1)); @@ -759,7 +774,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ /* If there are arguments to the function, make a shallow copy of the ** script object, lappend the arguments, then evaluate the copy. ** - ** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated. + ** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated. ** The new Tcl_Obj contains pointers to the original list elements. ** That way, when Tcl_EvalObjv() is run and shimmers the first element ** of the list to tclCmdNameType, that alternate representation will @@ -799,7 +814,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ break; } case SQLITE_NULL: { - pVal = Tcl_NewStringObj("", 0); + pVal = Tcl_NewStringObj(p->pDb->zNull, -1); break; } default: { @@ -871,8 +886,11 @@ static int auth_callback( const char *zArg2, const char *zArg3, const char *zArg4 +#ifdef SQLITE_USER_AUTHENTICATION + ,const char *zArg5 +#endif ){ - char *zCode; + const char *zCode; Tcl_DString str; int rc; const char *zReply; @@ -913,6 +931,7 @@ static int auth_callback( case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break; case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break; case SQLITE_SAVEPOINT : zCode="SQLITE_SAVEPOINT"; break; + case SQLITE_RECURSIVE : zCode="SQLITE_RECURSIVE"; break; default : zCode="????"; break; } Tcl_DStringInit(&str); @@ -922,6 +941,9 @@ static int auth_callback( Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); +#ifdef SQLITE_USER_AUTHENTICATION + Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : ""); +#endif rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY"; @@ -939,26 +961,6 @@ static int auth_callback( #endif /* SQLITE_OMIT_AUTHORIZATION */ /* -** zText is a pointer to text obtained via an sqlite3_result_text() -** or similar interface. This routine returns a Tcl string object, -** reference count set to 0, containing the text. If a translation -** between iso8859 and UTF-8 is required, it is preformed. -*/ -static Tcl_Obj *dbTextToObj(char const *zText){ - Tcl_Obj *pVal; -#ifdef UTF_TRANSLATION_NEEDED - Tcl_DString dCol; - Tcl_DStringInit(&dCol); - Tcl_ExternalToUtfDString(NULL, zText, -1, &dCol); - pVal = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1); - Tcl_DStringFree(&dCol); -#else - pVal = Tcl_NewStringObj(zText, -1); -#endif - return pVal; -} - -/* ** This routine reads a line of text from FILE in, stores ** the text in memory obtained from malloc() and returns a pointer ** to the text. NULL is returned at end of file, or if malloc() @@ -1017,7 +1019,7 @@ static int DbTransPostCmd( Tcl_Interp *interp, /* Tcl interpreter */ int result /* Result of evaluating SCRIPT */ ){ - static const char *azEnd[] = { + static const char *const azEnd[] = { "RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */ "COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */ "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction", @@ -1035,7 +1037,7 @@ static int DbTransPostCmd( /* This is a tricky scenario to handle. The most likely cause of an ** error is that the exec() above was an attempt to commit the ** top-level transaction that returned SQLITE_BUSY. Or, less likely, - ** that an IO-error has occured. In either case, throw a Tcl exception + ** that an IO-error has occurred. In either case, throw a Tcl exception ** and try to rollback the transaction. ** ** But it could also be that the user executed one or more BEGIN, @@ -1043,7 +1045,7 @@ static int DbTransPostCmd( ** this method's logic. Not clear how this would be best handled. */ if( rc!=TCL_ERROR ){ - Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); + Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); rc = TCL_ERROR; } sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); @@ -1096,18 +1098,19 @@ static int dbPrepareAndBind( SqlPreparedStmt **ppPreStmt /* OUT: Object used to cache statement */ ){ const char *zSql = zIn; /* Pointer to first SQL statement in zIn */ - sqlite3_stmt *pStmt; /* Prepared statement object */ + sqlite3_stmt *pStmt = 0; /* Prepared statement object */ SqlPreparedStmt *pPreStmt; /* Pointer to cached statement */ int nSql; /* Length of zSql in bytes */ - int nVar; /* Number of variables in statement */ + int nVar = 0; /* Number of variables in statement */ int iParm = 0; /* Next free entry in apParm */ + char c; int i; Tcl_Interp *interp = pDb->interp; *ppPreStmt = 0; /* Trim spaces from the start of zSql and calculate the remaining length. */ - while( isspace(zSql[0]) ){ zSql++; } + while( (c = zSql[0])==' ' || c=='\t' || c=='\r' || c=='\n' ){ zSql++; } nSql = strlen30(zSql); for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){ @@ -1145,13 +1148,13 @@ static int dbPrepareAndBind( int nByte; if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){ - Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); + Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); return TCL_ERROR; } if( pStmt==0 ){ if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){ /* A compile-time error in the statement. */ - Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); + Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); return TCL_ERROR; }else{ /* The statement was a no-op. Continue to the next statement @@ -1370,7 +1373,7 @@ static void dbEvalRowInfo( if( nCol>0 && (papColName || p->pArray) ){ apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol ); for(i=0; i<nCol; i++){ - apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i)); + apColName[i] = Tcl_NewStringObj(sqlite3_column_name(pStmt,i), -1); Tcl_IncrRefCount(apColName[i]); } p->apColName = apColName; @@ -1457,7 +1460,8 @@ static int dbEvalStep(DbEvalContext *p){ continue; } #endif - Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db))); + Tcl_SetObjResult(pDb->interp, + Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); return TCL_ERROR; }else{ dbReleaseStmt(pDb, pPreStmt, 0); @@ -1514,11 +1518,11 @@ static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){ return Tcl_NewDoubleObj(sqlite3_column_double(pStmt, iCol)); } case SQLITE_NULL: { - return dbTextToObj(p->pDb->zNull); + return Tcl_NewStringObj(p->pDb->zNull, -1); } } - return dbTextToObj((char *)sqlite3_column_text(pStmt, iCol)); + return Tcl_NewStringObj((char*)sqlite3_column_text(pStmt, iCol), -1); } /* @@ -1547,9 +1551,9 @@ static int DbUseNre(void){ */ # define SQLITE_TCL_NRE 0 # define DbUseNre() 0 -# define Tcl_NRAddCallback(a,b,c,d,e,f) 0 +# define Tcl_NRAddCallback(a,b,c,d,e,f) (void)0 # define Tcl_NREvalObj(a,b,c) 0 -# define Tcl_NRCreateCommand(a,b,c,d,e,f) 0 +# define Tcl_NRCreateCommand(a,b,c,d,e,f) (void)0 #endif /* @@ -1691,7 +1695,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ */ case DB_AUTHORIZER: { #ifdef SQLITE_OMIT_AUTHORIZATION - Tcl_AppendResult(interp, "authorization not available in this build", 0); + Tcl_AppendResult(interp, "authorization not available in this build", + (char*)0); return TCL_ERROR; #else if( objc>3 ){ @@ -1699,7 +1704,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ return TCL_ERROR; }else if( objc==2 ){ if( pDb->zAuth ){ - Tcl_AppendResult(interp, pDb->zAuth, 0); + Tcl_AppendResult(interp, pDb->zAuth, (char*)0); } }else{ char *zAuth; @@ -1715,8 +1720,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ pDb->zAuth = 0; } if( pDb->zAuth ){ + typedef int (*sqlite3_auth_cb)( + void*,int,const char*,const char*, + const char*,const char*); pDb->interp = interp; - sqlite3_set_authorizer(pDb->db, auth_callback, pDb); + sqlite3_set_authorizer(pDb->db,(sqlite3_auth_cb)auth_callback,pDb); }else{ sqlite3_set_authorizer(pDb->db, 0, 0); } @@ -1785,7 +1793,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ return TCL_ERROR; }else if( objc==2 ){ if( pDb->zBusy ){ - Tcl_AppendResult(interp, pDb->zBusy, 0); + Tcl_AppendResult(interp, pDb->zBusy, (char*)0); } }else{ char *zBusy; @@ -1839,7 +1847,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ }else{ if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ Tcl_AppendResult( interp, "cannot convert \"", - Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0); + Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0); return TCL_ERROR; }else{ if( n<0 ){ @@ -1853,7 +1861,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ } }else{ Tcl_AppendResult( interp, "bad option \"", - Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", 0); + Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", + (char*)0); return TCL_ERROR; } break; @@ -1950,10 +1959,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ return TCL_ERROR; }else if( objc==2 ){ if( pDb->zCommit ){ - Tcl_AppendResult(interp, pDb->zCommit, 0); + Tcl_AppendResult(interp, pDb->zCommit, (char*)0); } }else{ - char *zCommit; + const char *zCommit; int len; if( pDb->zCommit ){ Tcl_Free(pDb->zCommit); @@ -2026,14 +2035,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ char *zSql; /* An SQL statement */ char *zLine; /* A single line of input from the file */ char **azCol; /* zLine[] broken up into columns */ - char *zCommit; /* How to commit changes */ + const char *zCommit; /* How to commit changes */ FILE *in; /* The input file */ int lineno = 0; /* Line number of input file */ char zLineNum[80]; /* Line number print buffer */ Tcl_Obj *pResult; /* interp result */ - char *zSep; - char *zNull; + const char *zSep; + const char *zNull; if( objc<5 || objc>7 ){ Tcl_WrongNumArgs(interp, 2, objv, "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"); @@ -2055,7 +2064,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ nSep = strlen30(zSep); nNull = strlen30(zNull); if( nSep==0 ){ - Tcl_AppendResult(interp,"Error: non-null separator required for copy",0); + Tcl_AppendResult(interp,"Error: non-null separator required for copy", + (char*)0); return TCL_ERROR; } if(strcmp(zConflict, "rollback") != 0 && @@ -2065,19 +2075,19 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ strcmp(zConflict, "replace" ) != 0 ) { Tcl_AppendResult(interp, "Error: \"", zConflict, "\", conflict-algorithm must be one of: rollback, " - "abort, fail, ignore, or replace", 0); + "abort, fail, ignore, or replace", (char*)0); return TCL_ERROR; } zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); if( zSql==0 ){ - Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0); + Tcl_AppendResult(interp, "Error: no such table: ", zTable, (char*)0); return TCL_ERROR; } nByte = strlen30(zSql); rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ){ - Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); + Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0); nCol = 0; }else{ nCol = sqlite3_column_count(pStmt); @@ -2088,7 +2098,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ } zSql = malloc( nByte + 50 + nCol*2 ); if( zSql==0 ) { - Tcl_AppendResult(interp, "Error: can't malloc()", 0); + Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0); return TCL_ERROR; } sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?", @@ -2103,7 +2113,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); free(zSql); if( rc ){ - Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); + Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0); sqlite3_finalize(pStmt); return TCL_ERROR; } @@ -2115,7 +2125,7 @@ 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); + Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0); fclose(in); return TCL_ERROR; } @@ -2143,7 +2153,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ sqlite3_snprintf(nErr, zErr, "Error: %s line %d: expected %d columns of data but found %d", zFile, lineno, nCol, i+1); - Tcl_AppendResult(interp, zErr, 0); + Tcl_AppendResult(interp, zErr, (char*)0); free(zErr); } zCommit = "ROLLBACK"; @@ -2163,7 +2173,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ rc = sqlite3_reset(pStmt); free(zLine); if( rc!=SQLITE_OK ){ - Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0); + Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), (char*)0); zCommit = "ROLLBACK"; break; } @@ -2181,7 +2191,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ }else{ /* failure, append lineno where failed */ sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno); - Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0); + Tcl_AppendResult(interp,", failed while processing line: ",zLineNum, + (char*)0); rc = TCL_ERROR; } break; @@ -2207,7 +2218,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ break; #else Tcl_AppendResult(interp, "extension loading is turned off at compile-time", - 0); + (char*)0); return TCL_ERROR; #endif } @@ -2365,14 +2376,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ */ case DB_INCRBLOB: { #ifdef SQLITE_OMIT_INCRBLOB - Tcl_AppendResult(interp, "incrblob not available in this build", 0); + Tcl_AppendResult(interp, "incrblob not available in this build", (char*)0); return TCL_ERROR; #else int isReadonly = 0; const char *zDb = "main"; const char *zTable; const char *zColumn; - sqlite_int64 iRow; + Tcl_WideInt iRow; /* Check for the -readonly option */ if( objc>3 && strcmp(Tcl_GetString(objv[2]), "-readonly")==0 ){ @@ -2393,7 +2404,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ if( rc==TCL_OK ){ rc = createIncrblobChannel( - interp, pDb, zDb, zTable, zColumn, iRow, isReadonly + interp, pDb, zDb, zTable, zColumn, (sqlite3_int64)iRow, isReadonly ); } #endif @@ -2438,7 +2449,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ pDb->zNull = 0; } } - Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull)); + Tcl_SetObjResult(interp, Tcl_NewStringObj(pDb->zNull, -1)); break; } @@ -2472,7 +2483,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ case DB_PROGRESS: { if( objc==2 ){ if( pDb->zProgress ){ - Tcl_AppendResult(interp, pDb->zProgress, 0); + Tcl_AppendResult(interp, pDb->zProgress, (char*)0); } }else if( objc==4 ){ char *zProgress; @@ -2518,7 +2529,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ return TCL_ERROR; }else if( objc==2 ){ if( pDb->zProfile ){ - Tcl_AppendResult(interp, pDb->zProfile, 0); + Tcl_AppendResult(interp, pDb->zProfile, (char*)0); } }else{ char *zProfile; @@ -2563,7 +2574,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); rc = sqlite3_rekey(pDb->db, pKey, nKey); if( rc ){ - Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); + Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0); rc = TCL_ERROR; } #endif @@ -2704,7 +2715,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ return TCL_ERROR; }else if( objc==2 ){ if( pDb->zTrace ){ - Tcl_AppendResult(interp, pDb->zTrace, 0); + Tcl_AppendResult(interp, pDb->zTrace, (char*)0); } }else{ char *zTrace; @@ -2775,7 +2786,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ rc = sqlite3_exec(pDb->db, zBegin, 0, 0, 0); pDb->disableAuth--; if( rc!=SQLITE_OK ){ - Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); + Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); return TCL_ERROR; } pDb->nTransaction++; @@ -2787,7 +2798,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ ** or savepoint. */ if( DbUseNre() ){ Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0); - Tcl_NREvalObj(interp, pScript, 0); + (void)Tcl_NREvalObj(interp, pScript, 0); }else{ rc = DbTransPostCmd(&cd, interp, Tcl_EvalObjEx(interp, pScript, 0)); } @@ -2799,7 +2810,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ */ case DB_UNLOCK_NOTIFY: { #ifndef SQLITE_ENABLE_UNLOCK_NOTIFY - Tcl_AppendResult(interp, "unlock_notify not available in this build", 0); + Tcl_AppendResult(interp, "unlock_notify not available in this build", + (char*)0); rc = TCL_ERROR; #else if( objc!=2 && objc!=3 ){ @@ -2822,7 +2834,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ } if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){ - Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); + Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); rc = TCL_ERROR; } } @@ -2934,6 +2946,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ void *pKey = 0; int nKey = 0; #endif + int rc; /* In normal use, each TCL interpreter runs in a single thread. So ** by default, we can turn of mutexing on SQLite database connections. @@ -2950,14 +2963,14 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ if( objc==2 ){ zArg = Tcl_GetStringFromObj(objv[1], 0); if( strcmp(zArg,"-version")==0 ){ - Tcl_AppendResult(interp,sqlite3_version,0); + Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0); return TCL_OK; } if( strcmp(zArg,"-has-codec")==0 ){ #ifdef SQLITE_HAS_CODEC - Tcl_AppendResult(interp,"1",0); + Tcl_AppendResult(interp,"1",(char*)0); #else - Tcl_AppendResult(interp,"0",0); + Tcl_AppendResult(interp,"0",(char*)0); #endif return TCL_OK; } @@ -3032,18 +3045,22 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ zErrMsg = 0; p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); if( p==0 ){ - Tcl_SetResult(interp, "malloc failed", TCL_STATIC); + Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC); return TCL_ERROR; } memset(p, 0, sizeof(*p)); zFile = Tcl_GetStringFromObj(objv[2], 0); zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename); - sqlite3_open_v2(zFile, &p->db, flags, zVfs); + rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs); Tcl_DStringFree(&translatedFilename); - if( SQLITE_OK!=sqlite3_errcode(p->db) ){ - zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db)); - sqlite3_close(p->db); - p->db = 0; + if( p->db ){ + if( SQLITE_OK!=sqlite3_errcode(p->db) ){ + zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db)); + sqlite3_close(p->db); + p->db = 0; + } + }else{ + zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc)); } #ifdef SQLITE_HAS_CODEC if( p->db ){ @@ -3074,7 +3091,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ */ #ifndef USE_TCL_STUBS # undef Tcl_InitStubs -# define Tcl_InitStubs(a,b,c) +# define Tcl_InitStubs(a,b,c) TCL_VERSION #endif /* @@ -3098,19 +3115,18 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ ** The EXTERN macros are required by TCL in order to work on windows. */ 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", PACKAGE_VERSION); - + int rc = Tcl_InitStubs(interp, "8.4", 0) ? TCL_OK : TCL_ERROR; + if( rc==TCL_OK ){ + Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); #ifndef SQLITE_3_SUFFIX_ONLY - /* The "sqlite" alias is undocumented. It is here only to support - ** legacy scripts. All new scripts should use only the "sqlite3" - ** command. - */ - Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); + /* The "sqlite" alias is undocumented. It is here only to support + ** legacy scripts. All new scripts should use only the "sqlite3" + ** command. */ + Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); #endif - - return TCL_OK; + rc = Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION); + } + return rc; } EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } @@ -3384,13 +3400,11 @@ static void MD5Final(unsigned char digest[16], MD5Context *ctx){ byteReverse(ctx->in, 14); /* Append length in bits and transform */ - ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; - ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; + memcpy(ctx->in + 14*4, ctx->bits, 8); MD5Transform(ctx->buf, (uint32 *)ctx->in); byteReverse((unsigned char *)ctx->buf, 4); memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */ } /* @@ -3438,7 +3452,7 @@ static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){ if( argc!=2 ){ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], - " TEXT\"", 0); + " TEXT\"", (char*)0); return TCL_ERROR; } MD5Init(&ctx); @@ -3463,13 +3477,13 @@ static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){ if( argc!=2 ){ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], - " FILENAME\"", 0); + " FILENAME\"", (char*)0); return TCL_ERROR; } in = fopen(argv[1],"rb"); if( in==0 ){ Tcl_AppendResult(interp,"unable to open file \"", argv[1], - "\" for reading", 0); + "\" for reading", (char*)0); return TCL_ERROR; } MD5Init(&ctx); @@ -3641,6 +3655,45 @@ static int db_use_legacy_prepare_cmd( Tcl_ResetResult(interp); return TCL_OK; } + +/* +** Tclcmd: db_last_stmt_ptr DB +** +** If the statement cache associated with database DB is not empty, +** return the text representation of the most recently used statement +** handle. +*/ +static int db_last_stmt_ptr( + ClientData cd, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*); + Tcl_CmdInfo cmdInfo; + SqliteDb *pDb; + sqlite3_stmt *pStmt = 0; + char zBuf[100]; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; + } + + if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){ + Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0); + return TCL_ERROR; + } + pDb = (SqliteDb*)cmdInfo.objClientData; + + if( pDb->stmtList ) pStmt = pDb->stmtList->pStmt; + if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ){ + return TCL_ERROR; + } + Tcl_SetResult(interp, zBuf, TCL_VOLATILE); + + return TCL_OK; +} #endif /* @@ -3686,6 +3739,7 @@ static void init_all(Tcl_Interp *interp){ extern int Sqlitetest9_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetest_autoext_Init(Tcl_Interp*); + extern int Sqlitetest_blob_Init(Tcl_Interp*); extern int Sqlitetest_demovfs_Init(Tcl_Interp *); extern int Sqlitetest_func_Init(Tcl_Interp*); extern int Sqlitetest_hexio_Init(Tcl_Interp*); @@ -3695,6 +3749,7 @@ static void init_all(Tcl_Interp *interp){ extern int Sqlitetestschema_Init(Tcl_Interp*); extern int Sqlitetestsse_Init(Tcl_Interp*); extern int Sqlitetesttclvar_Init(Tcl_Interp*); + extern int Sqlitetestfs_Init(Tcl_Interp*); extern int SqlitetestThread_Init(Tcl_Interp*); extern int SqlitetestOnefile_Init(); extern int SqlitetestOsinst_Init(Tcl_Interp*); @@ -3706,8 +3761,6 @@ static void init_all(Tcl_Interp *interp){ extern int Sqlitemultiplex_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*); extern int SqlitetestSyscall_Init(Tcl_Interp*); - extern int Sqlitetestfuzzer_Init(Tcl_Interp*); - extern int Sqlitetestwholenumber_Init(Tcl_Interp*); #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) extern int Sqlitetestfts3_Init(Tcl_Interp *interp); @@ -3730,6 +3783,7 @@ static void init_all(Tcl_Interp *interp){ Sqlitetest9_Init(interp); Sqlitetestasync_Init(interp); Sqlitetest_autoext_Init(interp); + Sqlitetest_blob_Init(interp); Sqlitetest_demovfs_Init(interp); Sqlitetest_func_Init(interp); Sqlitetest_hexio_Init(interp); @@ -3738,6 +3792,7 @@ static void init_all(Tcl_Interp *interp){ Sqlitetest_mutex_Init(interp); Sqlitetestschema_Init(interp); Sqlitetesttclvar_Init(interp); + Sqlitetestfs_Init(interp); SqlitetestThread_Init(interp); SqlitetestOnefile_Init(interp); SqlitetestOsinst_Init(interp); @@ -3749,8 +3804,6 @@ static void init_all(Tcl_Interp *interp){ Sqlitemultiplex_Init(interp); SqliteSuperlock_Init(interp); SqlitetestSyscall_Init(interp); - Sqlitetestfuzzer_Init(interp); - Sqlitetestwholenumber_Init(interp); #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) Sqlitetestfts3_Init(interp); @@ -3762,6 +3815,9 @@ static void init_all(Tcl_Interp *interp){ Tcl_CreateObjCommand( interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0 ); + Tcl_CreateObjCommand( + interp, "db_last_stmt_ptr", db_last_stmt_ptr, 0, 0 + ); #ifdef SQLITE_SSE Sqlitetestsse_Init(interp); @@ -3770,16 +3826,42 @@ static void init_all(Tcl_Interp *interp){ #endif } +/* Needed for the setrlimit() system call on unix */ +#if defined(unix) +#include <sys/resource.h> +#endif + #define TCLSH_MAIN main /* Needed to fake out mktclapp */ int TCLSH_MAIN(int argc, char **argv){ Tcl_Interp *interp; - + +#if !defined(_WIN32_WCE) + if( getenv("BREAK") ){ + fprintf(stderr, + "attach debugger to process %d and press any key to continue.\n", + GETPID()); + fgetc(stdin); + } +#endif + + /* Since the primary use case for this binary is testing of SQLite, + ** be sure to generate core files if we crash */ +#if defined(SQLITE_TEST) && defined(unix) + { struct rlimit x; + getrlimit(RLIMIT_CORE, &x); + x.rlim_cur = x.rlim_max; + setrlimit(RLIMIT_CORE, &x); + } +#endif /* SQLITE_TEST && unix */ + + /* Call sqlite3_shutdown() once before doing anything else. This is to ** test that sqlite3_shutdown() can be safely called by a process before ** sqlite3_initialize() is. */ sqlite3_shutdown(); Tcl_FindExecutable(argv[0]); + Tcl_SetSystemEncoding(NULL, "utf-8"); interp = Tcl_CreateInterp(); #if TCLSH==2 |