Index: third_party/sqlite/src/src/tclsqlite.c |
diff --git a/third_party/sqlite/src/src/tclsqlite.c b/third_party/sqlite/src/src/tclsqlite.c |
index 575651d7e561d11c8e54280377b72ff6bddd75ec..756d0daa5a914287f55b0faeb431caf6d0a40b03 100644 |
--- a/third_party/sqlite/src/src/tclsqlite.c |
+++ b/third_party/sqlite/src/src/tclsqlite.c |
@@ -41,6 +41,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. |
@@ -53,15 +65,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 |
@@ -71,6 +76,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 */ |
@@ -107,8 +113,12 @@ typedef struct IncrblobChannel IncrblobChannel; |
/* |
** There is one instance of this structure for each SQLite database |
** that has been opened by the SQLite TCL interface. |
+** |
+** If this module is built with SQLITE_TEST defined (to create the SQLite |
+** testfixture executable), then it may be configured to use either |
+** 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 */ |
@@ -135,6 +145,9 @@ struct SqliteDb { |
IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ |
int nStep, nSort, nIndex; /* Statistics for most recent operation */ |
int nTransaction; /* Number of nested [transaction] methods */ |
+#ifdef SQLITE_TEST |
+ int bLegacyPrepare; /* True to use sqlite3_prepare() */ |
+#endif |
}; |
struct IncrblobChannel { |
@@ -411,18 +424,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; |
@@ -430,19 +443,32 @@ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ |
} |
/* |
+** Free a single SqlPreparedStmt object. |
+*/ |
+static void dbFreeStmt(SqlPreparedStmt *pStmt){ |
+#ifdef SQLITE_TEST |
+ if( sqlite3_sql(pStmt->pStmt)==0 ){ |
+ Tcl_Free((char *)pStmt->zSql); |
+ } |
+#endif |
+ sqlite3_finalize(pStmt->pStmt); |
+ Tcl_Free((char *)pStmt); |
+} |
+ |
+/* |
** Finalize and free a list of prepared statements |
*/ |
-static void flushStmtCache( SqliteDb *pDb ){ |
+static void flushStmtCache(SqliteDb *pDb){ |
SqlPreparedStmt *pPreStmt; |
+ SqlPreparedStmt *pNext; |
- while( pDb->stmtList ){ |
- sqlite3_finalize( pDb->stmtList->pStmt ); |
- pPreStmt = pDb->stmtList; |
- pDb->stmtList = pDb->stmtList->pNext; |
- Tcl_Free( (char*)pPreStmt ); |
+ for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pNext){ |
+ pNext = pPreStmt->pNext; |
+ dbFreeStmt(pPreStmt); |
} |
pDb->nStmt = 0; |
pDb->stmtLast = 0; |
+ pDb->stmtList = 0; |
} |
/* |
@@ -457,6 +483,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); |
} |
@@ -733,7 +760,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 |
@@ -761,7 +788,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ |
case SQLITE_INTEGER: { |
sqlite_int64 v = sqlite3_value_int64(pIn); |
if( v>=-2147483647 && v<=2147483647 ){ |
- pVal = Tcl_NewIntObj(v); |
+ pVal = Tcl_NewIntObj((int)v); |
}else{ |
pVal = Tcl_NewWideIntObj(v); |
} |
@@ -773,7 +800,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: { |
@@ -845,8 +872,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; |
@@ -887,6 +917,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); |
@@ -896,9 +927,12 @@ 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 = Tcl_GetStringResult(pDb->interp); |
+ zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY"; |
if( strcmp(zReply,"SQLITE_OK")==0 ){ |
rc = SQLITE_OK; |
}else if( strcmp(zReply,"SQLITE_DENY")==0 ){ |
@@ -913,26 +947,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() |
@@ -947,14 +961,12 @@ static char *local_getline(char *zPrompt, FILE *in){ |
char *zLine; |
int nLine; |
int n; |
- int eol; |
nLine = 100; |
zLine = malloc( nLine ); |
if( zLine==0 ) return 0; |
n = 0; |
- eol = 0; |
- while( !eol ){ |
+ while( 1 ){ |
if( n+100>nLine ){ |
nLine = nLine*2 + 100; |
zLine = realloc(zLine, nLine); |
@@ -966,14 +978,13 @@ static char *local_getline(char *zPrompt, FILE *in){ |
return 0; |
} |
zLine[n] = 0; |
- eol = 1; |
break; |
} |
while( zLine[n] ){ n++; } |
if( n>0 && zLine[n-1]=='\n' ){ |
n--; |
zLine[n] = 0; |
- eol = 1; |
+ break; |
} |
} |
zLine = realloc( zLine, n+1 ); |
@@ -994,7 +1005,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", |
@@ -1012,7 +1023,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, |
@@ -1020,7 +1031,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); |
@@ -1031,6 +1042,27 @@ static int DbTransPostCmd( |
} |
/* |
+** Unless SQLITE_TEST is defined, this function is a simple wrapper around |
+** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either |
+** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending |
+** on whether or not the [db_use_legacy_prepare] command has been used to |
+** configure the connection. |
+*/ |
+static int dbPrepare( |
+ SqliteDb *pDb, /* Database object */ |
+ const char *zSql, /* SQL to compile */ |
+ sqlite3_stmt **ppStmt, /* OUT: Prepared statement */ |
+ const char **pzOut /* OUT: Pointer to next SQL statement */ |
+){ |
+#ifdef SQLITE_TEST |
+ if( pDb->bLegacyPrepare ){ |
+ return sqlite3_prepare(pDb->db, zSql, -1, ppStmt, pzOut); |
+ } |
+#endif |
+ return sqlite3_prepare_v2(pDb->db, zSql, -1, ppStmt, pzOut); |
+} |
+ |
+/* |
** Search the cache for a prepared-statement object that implements the |
** first SQL statement in the buffer pointed to by parameter zIn. If |
** no such prepared-statement can be found, allocate and prepare a new |
@@ -1057,13 +1089,14 @@ static int dbPrepareAndBind( |
int nSql; /* Length of zSql in bytes */ |
int nVar; /* 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){ |
@@ -1100,14 +1133,14 @@ static int dbPrepareAndBind( |
if( pPreStmt==0 ){ |
int nByte; |
- if( SQLITE_OK!=sqlite3_prepare_v2(pDb->db, zSql, -1, &pStmt, pzOut) ){ |
- Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); |
+ if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){ |
+ 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 |
@@ -1124,9 +1157,17 @@ static int dbPrepareAndBind( |
memset(pPreStmt, 0, nByte); |
pPreStmt->pStmt = pStmt; |
- pPreStmt->nSql = (*pzOut - zSql); |
+ pPreStmt->nSql = (int)(*pzOut - zSql); |
pPreStmt->zSql = sqlite3_sql(pStmt); |
pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1]; |
+#ifdef SQLITE_TEST |
+ if( pPreStmt->zSql==0 ){ |
+ char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1); |
+ memcpy(zCopy, zSql, pPreStmt->nSql); |
+ zCopy[pPreStmt->nSql] = '\0'; |
+ pPreStmt->zSql = zCopy; |
+ } |
+#endif |
} |
assert( pPreStmt ); |
assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql ); |
@@ -1180,7 +1221,6 @@ static int dbPrepareAndBind( |
return TCL_OK; |
} |
- |
/* |
** Release a statement reference obtained by calling dbPrepareAndBind(). |
** There should be exactly one call to this function for each call to |
@@ -1205,8 +1245,7 @@ static void dbReleaseStmt( |
if( pDb->maxStmt<=0 || discard ){ |
/* If the cache is turned off, deallocated the statement */ |
- sqlite3_finalize(pPreStmt->pStmt); |
- Tcl_Free((char *)pPreStmt); |
+ dbFreeStmt(pPreStmt); |
}else{ |
/* Add the prepared statement to the beginning of the cache list. */ |
pPreStmt->pNext = pDb->stmtList; |
@@ -1226,11 +1265,11 @@ static void dbReleaseStmt( |
/* If we have too many statement in cache, remove the surplus from |
** the end of the cache list. */ |
while( pDb->nStmt>pDb->maxStmt ){ |
- sqlite3_finalize(pDb->stmtLast->pStmt); |
- pDb->stmtLast = pDb->stmtLast->pPrev; |
- Tcl_Free((char*)pDb->stmtLast->pNext); |
+ SqlPreparedStmt *pLast = pDb->stmtLast; |
+ pDb->stmtLast = pLast->pPrev; |
pDb->stmtLast->pNext = 0; |
pDb->nStmt--; |
+ dbFreeStmt(pLast); |
} |
} |
} |
@@ -1320,7 +1359,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; |
@@ -1363,9 +1402,12 @@ static void dbEvalRowInfo( |
** no further rows available. This is similar to SQLITE_DONE. |
*/ |
static int dbEvalStep(DbEvalContext *p){ |
+ const char *zPrevSql = 0; /* Previous value of p->zSql */ |
+ |
while( p->zSql[0] || p->pPreStmt ){ |
int rc; |
if( p->pPreStmt==0 ){ |
+ zPrevSql = (p->zSql==zPrevSql ? 0 : p->zSql); |
rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt); |
if( rc!=TCL_OK ) return rc; |
}else{ |
@@ -1392,8 +1434,20 @@ static int dbEvalStep(DbEvalContext *p){ |
if( rcs!=SQLITE_OK ){ |
/* If a run-time error occurs, report the error and stop reading |
** the SQL. */ |
- Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db))); |
dbReleaseStmt(pDb, pPreStmt, 1); |
+#if SQLITE_TEST |
+ if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){ |
+ /* If the runtime error was an SQLITE_SCHEMA, and the database |
+ ** handle is configured to use the legacy sqlite3_prepare() |
+ ** interface, retry prepare()/step() on the same SQL statement. |
+ ** This only happens once. If there is a second SQLITE_SCHEMA |
+ ** error, the error will be returned to the caller. */ |
+ p->zSql = zPrevSql; |
+ continue; |
+ } |
+#endif |
+ Tcl_SetObjResult(pDb->interp, |
+ Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); |
return TCL_ERROR; |
}else{ |
dbReleaseStmt(pDb, pPreStmt, 0); |
@@ -1441,7 +1495,7 @@ static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){ |
case SQLITE_INTEGER: { |
sqlite_int64 v = sqlite3_column_int64(pStmt, iCol); |
if( v>=-2147483647 && v<=2147483647 ){ |
- return Tcl_NewIntObj(v); |
+ return Tcl_NewIntObj((int)v); |
}else{ |
return Tcl_NewWideIntObj(v); |
} |
@@ -1450,11 +1504,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); |
} |
/* |
@@ -1483,9 +1537,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 |
/* |
@@ -1627,7 +1681,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 ){ |
@@ -1635,7 +1690,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; |
@@ -1651,8 +1706,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); |
} |
@@ -1721,7 +1779,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; |
@@ -1775,7 +1833,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 ){ |
@@ -1789,7 +1847,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; |
@@ -1886,10 +1945,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); |
@@ -1962,14 +2021,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?"); |
@@ -1991,7 +2050,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 && |
@@ -2001,19 +2061,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); |
@@ -2024,7 +2084,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(?", |
@@ -2039,7 +2099,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; |
} |
@@ -2051,7 +2111,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; |
} |
@@ -2059,7 +2119,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
zCommit = "COMMIT"; |
while( (zLine = local_getline(0, in))!=0 ){ |
char *z; |
- i = 0; |
lineno++; |
azCol[0] = zLine; |
for(i=0, z=zLine; *z; z++){ |
@@ -2080,7 +2139,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"; |
@@ -2100,7 +2159,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; |
} |
@@ -2118,7 +2177,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; |
@@ -2144,7 +2204,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 |
} |
@@ -2180,6 +2240,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
if( choice==DB_ONECOLUMN ){ |
if( rc==TCL_OK ){ |
Tcl_SetObjResult(interp, dbEvalColumnValue(&sEval, 0)); |
+ }else if( rc==TCL_BREAK ){ |
+ Tcl_ResetResult(interp); |
} |
}else if( rc==TCL_BREAK || rc==TCL_OK ){ |
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc==TCL_OK)); |
@@ -2300,14 +2362,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 ){ |
@@ -2328,7 +2390,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 |
@@ -2367,13 +2429,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
} |
if( zNull && len>0 ){ |
pDb->zNull = Tcl_Alloc( len + 1 ); |
- strncpy(pDb->zNull, zNull, len); |
+ memcpy(pDb->zNull, zNull, len); |
pDb->zNull[len] = '\0'; |
}else{ |
pDb->zNull = 0; |
} |
} |
- Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull)); |
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(pDb->zNull, -1)); |
break; |
} |
@@ -2407,7 +2469,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; |
@@ -2453,7 +2515,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; |
@@ -2486,17 +2548,19 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
** Change the encryption key on the currently open database. |
*/ |
case DB_REKEY: { |
+#ifdef SQLITE_HAS_CODEC |
int nKey; |
void *pKey; |
+#endif |
if( objc!=3 ){ |
Tcl_WrongNumArgs(interp, 2, objv, "KEY"); |
return TCL_ERROR; |
} |
- pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); |
#ifdef SQLITE_HAS_CODEC |
+ 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 |
@@ -2637,7 +2701,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; |
@@ -2708,7 +2772,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++; |
@@ -2720,7 +2784,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)); |
} |
@@ -2732,7 +2796,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 ){ |
@@ -2755,7 +2820,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; |
} |
} |
@@ -2856,8 +2921,6 @@ static int DbObjCmdAdaptor( |
*/ |
static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
SqliteDb *p; |
- void *pKey = 0; |
- int nKey = 0; |
const char *zArg; |
char *zErrMsg; |
int i; |
@@ -2865,6 +2928,11 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
const char *zVfs = 0; |
int flags; |
Tcl_DString translatedFilename; |
+#ifdef SQLITE_HAS_CODEC |
+ 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. |
@@ -2881,14 +2949,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; |
} |
@@ -2896,7 +2964,9 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
for(i=3; i+1<objc; i+=2){ |
zArg = Tcl_GetString(objv[i]); |
if( strcmp(zArg,"-key")==0 ){ |
+#ifdef SQLITE_HAS_CODEC |
pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey); |
+#endif |
}else if( strcmp(zArg, "-vfs")==0 ){ |
zVfs = Tcl_GetString(objv[i+1]); |
}else if( strcmp(zArg, "-readonly")==0 ){ |
@@ -2926,7 +2996,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
}else{ |
flags &= ~SQLITE_OPEN_NOMUTEX; |
} |
- }else if( strcmp(zArg, "-fullmutex")==0 ){ |
+ }else if( strcmp(zArg, "-fullmutex")==0 ){ |
int b; |
if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; |
if( b ){ |
@@ -2935,6 +3005,14 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
}else{ |
flags &= ~SQLITE_OPEN_FULLMUTEX; |
} |
+ }else if( strcmp(zArg, "-uri")==0 ){ |
+ int b; |
+ if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; |
+ if( b ){ |
+ flags |= SQLITE_OPEN_URI; |
+ }else{ |
+ flags &= ~SQLITE_OPEN_URI; |
+ } |
}else{ |
Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); |
return TCL_ERROR; |
@@ -2943,7 +3021,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ |
if( objc<3 || (objc&1)!=1 ){ |
Tcl_WrongNumArgs(interp, 1, objv, |
"HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" |
- " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN?" |
+ " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" |
#ifdef SQLITE_HAS_CODEC |
" ?-key CODECKEY?" |
#endif |
@@ -2953,18 +3031,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 ){ |
@@ -2995,7 +3077,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 |
/* |
@@ -3019,38 +3101,33 @@ 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)==0 ? TCL_ERROR : TCL_OK; |
+ 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_SafeInit(Tcl_Interp *interp){ return TCL_OK; } |
-EXTERN int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } |
EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } |
EXTERN int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } |
-EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK; } |
-EXTERN int Tclsqlite3_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK;} |
+/* Because it accesses the file-system and uses persistent state, SQLite |
+** is not considered appropriate for safe interpreters. Hence, we deliberately |
+** omit the _SafeInit() interfaces. |
+*/ |
#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; } |
int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } |
int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } |
-int Sqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK; } |
-int Tclsqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK;} |
#endif |
#ifdef TCLSH |
@@ -3309,13 +3386,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 */ |
} |
/* |
@@ -3363,7 +3438,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); |
@@ -3388,19 +3463,19 @@ 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); |
for(;;){ |
int n; |
- n = fread(zBuf, 1, sizeof(zBuf), in); |
+ n = (int)fread(zBuf, 1, sizeof(zBuf), in); |
if( n<=0 ) break; |
MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n); |
} |
@@ -3446,7 +3521,7 @@ static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){ |
for(i=0; i<argc; i++){ |
const char *zData = (char*)sqlite3_value_text(argv[i]); |
if( zData ){ |
- MD5Update(p, (unsigned char*)zData, strlen(zData)); |
+ MD5Update(p, (unsigned char*)zData, (int)strlen(zData)); |
} |
} |
} |
@@ -3475,33 +3550,34 @@ int Md5_Register(sqlite3 *db){ |
** the TCL interpreter reads and evaluates that file. |
*/ |
#if TCLSH==1 |
-static char zMainloop[] = |
- "set line {}\n" |
- "while {![eof stdin]} {\n" |
- "if {$line!=\"\"} {\n" |
- "puts -nonewline \"> \"\n" |
- "} else {\n" |
- "puts -nonewline \"% \"\n" |
- "}\n" |
- "flush stdout\n" |
- "append line [gets stdin]\n" |
- "if {[info complete $line]} {\n" |
- "if {[catch {uplevel #0 $line} result]} {\n" |
- "puts stderr \"Error: $result\"\n" |
- "} elseif {$result!=\"\"} {\n" |
- "puts $result\n" |
+static const char *tclsh_main_loop(void){ |
+ static const char zMainloop[] = |
+ "set line {}\n" |
+ "while {![eof stdin]} {\n" |
+ "if {$line!=\"\"} {\n" |
+ "puts -nonewline \"> \"\n" |
+ "} else {\n" |
+ "puts -nonewline \"% \"\n" |
+ "}\n" |
+ "flush stdout\n" |
+ "append line [gets stdin]\n" |
+ "if {[info complete $line]} {\n" |
+ "if {[catch {uplevel #0 $line} result]} {\n" |
+ "puts stderr \"Error: $result\"\n" |
+ "} elseif {$result!=\"\"} {\n" |
+ "puts $result\n" |
+ "}\n" |
+ "set line {}\n" |
+ "} else {\n" |
+ "append line \\n\n" |
"}\n" |
- "set line {}\n" |
- "} else {\n" |
- "append line \\n\n" |
"}\n" |
- "}\n" |
-; |
+ ; |
+ return zMainloop; |
+} |
#endif |
#if TCLSH==2 |
-static char zMainloop[] = |
-#include "spaceanal_tcl.h" |
-; |
+static const char *tclsh_main_loop(void); |
#endif |
#ifdef SQLITE_TEST |
@@ -3527,6 +3603,44 @@ static int init_all_cmd( |
init_all(slave); |
return TCL_OK; |
} |
+ |
+/* |
+** Tclcmd: db_use_legacy_prepare DB BOOLEAN |
+** |
+** The first argument to this command must be a database command created by |
+** [sqlite3]. If the second argument is true, then the handle is configured |
+** to use the sqlite3_prepare_v2() function to prepare statements. If it |
+** is false, sqlite3_prepare(). |
+*/ |
+static int db_use_legacy_prepare_cmd( |
+ ClientData cd, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ Tcl_CmdInfo cmdInfo; |
+ SqliteDb *pDb; |
+ int bPrepare; |
+ |
+ if( objc!=3 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN"); |
+ 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( Tcl_GetBooleanFromObj(interp, objv[2], &bPrepare) ){ |
+ return TCL_ERROR; |
+ } |
+ |
+ pDb->bLegacyPrepare = bPrepare; |
+ |
+ Tcl_ResetResult(interp); |
+ return TCL_OK; |
+} |
#endif |
/* |
@@ -3547,6 +3661,17 @@ static void init_all(Tcl_Interp *interp){ |
Md5_Init(interp); |
#endif |
+ /* Install the [register_dbstat_vtab] command to access the implementation |
+ ** of virtual table dbstat (source file test_stat.c). This command is |
+ ** required for testfixture and sqlite3_analyzer, but not by the production |
+ ** Tcl extension. */ |
+#if defined(SQLITE_TEST) || TCLSH==2 |
+ { |
+ extern int SqlitetestStat_Init(Tcl_Interp*); |
+ SqlitetestStat_Init(interp); |
+ } |
+#endif |
+ |
#ifdef SQLITE_TEST |
{ |
extern int Sqliteconfig_Init(Tcl_Interp*); |
@@ -3570,20 +3695,22 @@ 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*); |
extern int Sqlitetestbackup_Init(Tcl_Interp*); |
extern int Sqlitetestintarray_Init(Tcl_Interp*); |
extern int Sqlitetestvfs_Init(Tcl_Interp *); |
- extern int SqlitetestStat_Init(Tcl_Interp*); |
extern int Sqlitetestrtree_Init(Tcl_Interp*); |
extern int Sqlitequota_Init(Tcl_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); |
+#endif |
#ifdef SQLITE_ENABLE_ZIPVFS |
extern int Zipvfs_Init(Tcl_Interp*); |
@@ -3610,22 +3737,29 @@ 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); |
Sqlitetestbackup_Init(interp); |
Sqlitetestintarray_Init(interp); |
Sqlitetestvfs_Init(interp); |
- SqlitetestStat_Init(interp); |
Sqlitetestrtree_Init(interp); |
Sqlitequota_Init(interp); |
Sqlitemultiplex_Init(interp); |
SqliteSuperlock_Init(interp); |
SqlitetestSyscall_Init(interp); |
- Sqlitetestfuzzer_Init(interp); |
- Sqlitetestwholenumber_Init(interp); |
- Tcl_CreateObjCommand(interp,"load_testfixture_extensions",init_all_cmd,0,0); |
+#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) |
+ Sqlitetestfts3_Init(interp); |
+#endif |
+ |
+ Tcl_CreateObjCommand( |
+ interp, "load_testfixture_extensions", init_all_cmd, 0, 0 |
+ ); |
+ Tcl_CreateObjCommand( |
+ interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0 |
+ ); |
#ifdef SQLITE_SSE |
Sqlitetestsse_Init(interp); |
@@ -3637,18 +3771,29 @@ static void init_all(Tcl_Interp *interp){ |
#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 |
+ |
/* 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 |
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
#endif |
- Tcl_FindExecutable(argv[0]); |
- interp = Tcl_CreateInterp(); |
init_all(interp); |
if( argc>=2 ){ |
int i; |
@@ -3669,7 +3814,7 @@ int TCLSH_MAIN(int argc, char **argv){ |
} |
} |
if( TCLSH==2 || argc<=1 ){ |
- Tcl_GlobalEval(interp, zMainloop); |
+ Tcl_GlobalEval(interp, tclsh_main_loop()); |
} |
return 0; |
} |