Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Unified Diff: third_party/sqlite/src/src/tclsqlite.c

Issue 2751253002: [sql] Import SQLite 3.17.0. (Closed)
Patch Set: also clang on Linux i386 Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/sqlite/src/src/table.c ('k') | third_party/sqlite/src/src/test1.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 f024317e9098399b31d96e723cab0719959a1cf1..5b52bf0c91ca14652974173a6e6d66d22bb2ee07 100644
--- a/third_party/sqlite/src/src/tclsqlite.c
+++ b/third_party/sqlite/src/src/tclsqlite.c
@@ -30,10 +30,17 @@
** If requested, include the SQLite compiler options file for MSVC.
*/
#if defined(INCLUDE_MSVC_H)
-#include "msvc.h"
+# include "msvc.h"
#endif
-#include "tcl.h"
+#if defined(INCLUDE_SQLITE_TCL_H)
+# include "sqlite_tcl.h"
+#else
+# include "tcl.h"
+# ifndef SQLITE_TCLAPI
+# define SQLITE_TCLAPI
+# endif
+#endif
#include <errno.h>
/*
@@ -133,6 +140,7 @@ struct SqliteDb {
char *zBusy; /* The busy callback routine */
char *zCommit; /* The commit hook callback routine */
char *zTrace; /* The trace callback routine */
+ char *zTraceV2; /* The trace_v2 callback routine */
char *zProfile; /* The profile callback routine */
char *zProgress; /* The progress callback routine */
char *zAuth; /* The authorization callback routine */
@@ -140,6 +148,7 @@ struct SqliteDb {
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 *pPreUpdateHook; /* Pre-update hook script (if any) */
Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */
Tcl_Obj *pWalHook; /* WAL hook script (if any) */
Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */
@@ -153,6 +162,7 @@ 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 */
+ int openFlags; /* Flags used to open. (SQLITE_OPEN_URI) */
#ifdef SQLITE_TEST
int bLegacyPrepare; /* True to use sqlite3_prepare() */
#endif
@@ -190,7 +200,7 @@ static void closeIncrblobChannels(SqliteDb *pDb){
for(p=pDb->pIncrblob; p; p=pNext){
pNext = p->pNext;
- /* Note: Calling unregister here call Tcl_Close on the incrblob channel,
+ /* Note: Calling unregister here call Tcl_Close on the incrblob channel,
** which deletes the IncrblobChannel structure at *p. So do not
** call Tcl_Free() here.
*/
@@ -201,7 +211,10 @@ static void closeIncrblobChannels(SqliteDb *pDb){
/*
** Close an incremental blob channel.
*/
-static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){
+static int SQLITE_TCLAPI incrblobClose(
+ ClientData instanceData,
+ Tcl_Interp *interp
+){
IncrblobChannel *p = (IncrblobChannel *)instanceData;
int rc = sqlite3_blob_close(p->pBlob);
sqlite3 *db = p->pDb->db;
@@ -230,9 +243,9 @@ static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){
/*
** Read data from an incremental blob channel.
*/
-static int incrblobInput(
- ClientData instanceData,
- char *buf,
+static int SQLITE_TCLAPI incrblobInput(
+ ClientData instanceData,
+ char *buf,
int bufSize,
int *errorCodePtr
){
@@ -262,9 +275,9 @@ static int incrblobInput(
/*
** Write data to an incremental blob channel.
*/
-static int incrblobOutput(
- ClientData instanceData,
- CONST char *buf,
+static int SQLITE_TCLAPI incrblobOutput(
+ ClientData instanceData,
+ CONST char *buf,
int toWrite,
int *errorCodePtr
){
@@ -295,8 +308,8 @@ static int incrblobOutput(
/*
** Seek an incremental blob channel.
*/
-static int incrblobSeek(
- ClientData instanceData,
+static int SQLITE_TCLAPI incrblobSeek(
+ ClientData instanceData,
long offset,
int seekMode,
int *errorCodePtr
@@ -321,10 +334,17 @@ static int incrblobSeek(
}
-static void incrblobWatch(ClientData instanceData, int mode){
- /* NO-OP */
+static void SQLITE_TCLAPI incrblobWatch(
+ ClientData instanceData,
+ int mode
+){
+ /* NO-OP */
}
-static int incrblobHandle(ClientData instanceData, int dir, ClientData *hPtr){
+static int SQLITE_TCLAPI incrblobHandle(
+ ClientData instanceData,
+ int dir,
+ ClientData *hPtr
+){
return TCL_ERROR;
}
@@ -350,11 +370,11 @@ static Tcl_ChannelType IncrblobChannelType = {
** Create a new incrblob channel.
*/
static int createIncrblobChannel(
- Tcl_Interp *interp,
- SqliteDb *pDb,
+ Tcl_Interp *interp,
+ SqliteDb *pDb,
const char *zDb,
- const char *zTable,
- const char *zColumn,
+ const char *zTable,
+ const char *zColumn,
sqlite_int64 iRow,
int isReadonly
){
@@ -436,7 +456,7 @@ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){
pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 );
pNew->zName = (char*)&pNew[1];
memcpy(pNew->zName, zName, nName+1);
- for(p=pDb->pFunc; p; p=p->pNext){
+ for(p=pDb->pFunc; p; p=p->pNext){
if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){
Tcl_Free((char*)pNew);
return p;
@@ -483,7 +503,7 @@ static void flushStmtCache(SqliteDb *pDb){
** TCL calls this procedure when an sqlite3 database command is
** deleted.
*/
-static void DbDeleteCmd(void *db){
+static void SQLITE_TCLAPI DbDeleteCmd(void *db){
SqliteDb *pDb = (SqliteDb*)db;
flushStmtCache(pDb);
closeIncrblobChannels(pDb);
@@ -506,6 +526,9 @@ static void DbDeleteCmd(void *db){
if( pDb->zTrace ){
Tcl_Free(pDb->zTrace);
}
+ if( pDb->zTraceV2 ){
+ Tcl_Free(pDb->zTraceV2);
+ }
if( pDb->zProfile ){
Tcl_Free(pDb->zProfile);
}
@@ -518,6 +541,9 @@ static void DbDeleteCmd(void *db){
if( pDb->pUpdateHook ){
Tcl_DecrRefCount(pDb->pUpdateHook);
}
+ if( pDb->pPreUpdateHook ){
+ Tcl_DecrRefCount(pDb->pPreUpdateHook);
+ }
if( pDb->pRollbackHook ){
Tcl_DecrRefCount(pDb->pRollbackHook);
}
@@ -564,7 +590,8 @@ static int DbProgressHandler(void *cd){
}
#endif
-#ifndef SQLITE_OMIT_TRACE
+#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \
+ !defined(SQLITE_OMIT_DEPRECATED)
/*
** 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.
@@ -584,6 +611,83 @@ static void DbTraceHandler(void *cd, const char *zSql){
#ifndef SQLITE_OMIT_TRACE
/*
+** This routine is called by the SQLite trace_v2 handler whenever a new
+** supported event is generated. Unsupported event types are ignored.
+** The TCL script in pDb->zTraceV2 is executed, with the arguments for
+** the event appended to it (as list elements).
+*/
+static int DbTraceV2Handler(
+ unsigned type, /* One of the SQLITE_TRACE_* event types. */
+ void *cd, /* The original context data pointer. */
+ void *pd, /* Primary event data, depends on event type. */
+ void *xd /* Extra event data, depends on event type. */
+){
+ SqliteDb *pDb = (SqliteDb*)cd;
+ Tcl_Obj *pCmd;
+
+ switch( type ){
+ case SQLITE_TRACE_STMT: {
+ sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
+ char *zSql = (char *)xd;
+
+ pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
+ Tcl_IncrRefCount(pCmd);
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewStringObj(zSql, -1));
+ Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
+ Tcl_DecrRefCount(pCmd);
+ Tcl_ResetResult(pDb->interp);
+ break;
+ }
+ case SQLITE_TRACE_PROFILE: {
+ sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
+ sqlite3_int64 ns = (sqlite3_int64)xd;
+
+ pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
+ Tcl_IncrRefCount(pCmd);
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewWideIntObj((Tcl_WideInt)ns));
+ Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
+ Tcl_DecrRefCount(pCmd);
+ Tcl_ResetResult(pDb->interp);
+ break;
+ }
+ case SQLITE_TRACE_ROW: {
+ sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
+
+ pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
+ Tcl_IncrRefCount(pCmd);
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
+ Tcl_DecrRefCount(pCmd);
+ Tcl_ResetResult(pDb->interp);
+ break;
+ }
+ case SQLITE_TRACE_CLOSE: {
+ sqlite3 *db = (sqlite3 *)pd;
+
+ pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
+ Tcl_IncrRefCount(pCmd);
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewWideIntObj((Tcl_WideInt)db));
+ Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
+ Tcl_DecrRefCount(pCmd);
+ Tcl_ResetResult(pDb->interp);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+#endif
+
+#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \
+ !defined(SQLITE_OMIT_DEPRECATED)
+/*
** This routine is called by the SQLite profile handler after a statement
** SQL has executed. The TCL script in pDb->zProfile is evaluated.
*/
@@ -632,9 +736,9 @@ static void DbRollbackHandler(void *clientData){
** This procedure handles wal_hook callbacks.
*/
static int DbWalHandler(
- void *clientData,
- sqlite3 *db,
- const char *zDb,
+ void *clientData,
+ sqlite3 *db,
+ const char *zDb,
int nEntry
){
int ret = SQLITE_OK;
@@ -648,7 +752,7 @@ static int DbWalHandler(
Tcl_IncrRefCount(p);
Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));
Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));
- if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
+ if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
|| TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)
){
Tcl_BackgroundError(interp);
@@ -685,23 +789,63 @@ static void DbUnlockNotify(void **apArg, int nArg){
}
#endif
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+/*
+** Pre-update hook callback.
+*/
+static void DbPreUpdateHandler(
+ void *p,
+ sqlite3 *db,
+ int op,
+ const char *zDb,
+ const char *zTbl,
+ sqlite_int64 iKey1,
+ sqlite_int64 iKey2
+){
+ SqliteDb *pDb = (SqliteDb *)p;
+ Tcl_Obj *pCmd;
+ static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"};
+
+ assert( (SQLITE_DELETE-1)/9 == 0 );
+ assert( (SQLITE_INSERT-1)/9 == 1 );
+ assert( (SQLITE_UPDATE-1)/9 == 2 );
+ assert( pDb->pPreUpdateHook );
+ assert( db==pDb->db );
+ assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
+
+ pCmd = Tcl_DuplicateObj(pDb->pPreUpdateHook);
+ Tcl_IncrRefCount(pCmd);
+ Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(azStr[(op-1)/9], -1));
+ Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1));
+ Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1));
+ Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey1));
+ Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey2));
+ Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
+ Tcl_DecrRefCount(pCmd);
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
static void DbUpdateHandler(
- void *p,
+ void *p,
int op,
- const char *zDb,
- const char *zTbl,
+ const char *zDb,
+ const char *zTbl,
sqlite_int64 rowid
){
SqliteDb *pDb = (SqliteDb *)p;
Tcl_Obj *pCmd;
+ static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"};
+
+ assert( (SQLITE_DELETE-1)/9 == 0 );
+ assert( (SQLITE_INSERT-1)/9 == 1 );
+ assert( (SQLITE_UPDATE-1)/9 == 2 );
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(azStr[(op-1)/9], -1));
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1));
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1));
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid));
@@ -770,7 +914,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
** script object, lappend the arguments, then evaluate the copy.
**
** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated.
- ** The new Tcl_Obj contains pointers to the original list elements.
+ ** 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
** be preserved and reused on the next invocation.
@@ -778,15 +922,15 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
Tcl_Obj **aArg;
int nArg;
if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
- sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
+ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
return;
- }
+ }
pCmd = Tcl_NewListObj(nArg, aArg);
Tcl_IncrRefCount(pCmd);
for(i=0; i<argc; i++){
sqlite3_value *pIn = argv[i];
Tcl_Obj *pVal;
-
+
/* Set pVal to contain the i'th column of this row. */
switch( sqlite3_value_type(pIn) ){
case SQLITE_BLOB: {
@@ -821,7 +965,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal);
if( rc ){
Tcl_DecrRefCount(pCmd);
- sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
+ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
return;
}
}
@@ -836,7 +980,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
}
if( rc && rc!=TCL_RETURN ){
- sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
+ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
}else{
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
int n;
@@ -938,7 +1082,7 @@ static int auth_callback(
Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
#ifdef SQLITE_USER_AUTHENTICATION
Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : "");
-#endif
+#endif
rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
Tcl_DStringFree(&str);
zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY";
@@ -1009,7 +1153,7 @@ static char *local_getline(char *zPrompt, FILE *in){
** It is invoked after evaluating the script SCRIPT to commit or rollback
** the transaction or savepoint opened by the [transaction] command.
*/
-static int DbTransPostCmd(
+static int SQLITE_TCLAPI DbTransPostCmd(
ClientData data[], /* data[0] is the Sqlite3Db* for $db */
Tcl_Interp *interp, /* Tcl interpreter */
int result /* Result of evaluating SCRIPT */
@@ -1030,12 +1174,12 @@ static int DbTransPostCmd(
pDb->disableAuth++;
if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){
/* 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
+ ** 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 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,
+ ** But it could also be that the user executed one or more BEGIN,
** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing
** this method's logic. Not clear how this would be best handled.
*/
@@ -1054,7 +1198,7 @@ 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
+** on whether or not the [db_use_legacy_prepare] command has been used to
** configure the connection.
*/
static int dbPrepare(
@@ -1110,7 +1254,7 @@ static int dbPrepareAndBind(
for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){
int n = pPreStmt->nSql;
- if( nSql>=n
+ if( nSql>=n
&& memcmp(pPreStmt->zSql, zSql, n)==0
&& (zSql[n]==0 || zSql[n-1]==';')
){
@@ -1136,7 +1280,7 @@ static int dbPrepareAndBind(
break;
}
}
-
+
/* If no prepared statement was found. Compile the SQL text. Also allocate
** a new SqlPreparedStmt structure. */
if( pPreStmt==0 ){
@@ -1182,7 +1326,7 @@ static int dbPrepareAndBind(
assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql );
assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) );
- /* Bind values to parameters that begin with $ or : */
+ /* Bind values to parameters that begin with $ or : */
for(i=1; i<=nVar; i++){
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){
@@ -1270,8 +1414,8 @@ static void dbReleaseStmt(
assert( pDb->nStmt>0 );
}
pDb->nStmt++;
-
- /* If we have too many statement in cache, remove the surplus from
+
+ /* If we have too many statement in cache, remove the surplus from
** the end of the cache list. */
while( pDb->nStmt>pDb->maxStmt ){
SqlPreparedStmt *pLast = pDb->stmtLast;
@@ -1325,8 +1469,8 @@ static void dbReleaseColumnNames(DbEvalContext *p){
** If pArray is not NULL, then it contains the name of a Tcl array
** variable. The "*" member of this array is set to a list containing
** the names of the columns returned by the statement as part of each
-** call to dbEvalStep(), in order from left to right. e.g. if the names
-** of the returned columns are a, b and c, it does the equivalent of the
+** call to dbEvalStep(), in order from left to right. e.g. if the names
+** of the returned columns are a, b and c, it does the equivalent of the
** tcl command:
**
** set ${pArray}(*) {a b c}
@@ -1447,7 +1591,7 @@ static int dbEvalStep(DbEvalContext *p){
#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()
+ ** 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. */
@@ -1535,11 +1679,11 @@ static int DbUseNre(void){
return( (major==8 && minor>=6) || major>8 );
}
#else
-/*
+/*
** Compiling using headers earlier than 8.6. In this case NR cannot be
** used, so DbUseNre() to always return zero. Add #defines for the other
** Tcl_NRxxx() functions to prevent them from causing compilation errors,
-** even though the only invocations of them are within conditional blocks
+** even though the only invocations of them are within conditional blocks
** of the form:
**
** if( DbUseNre() ) { ... }
@@ -1556,7 +1700,7 @@ static int DbUseNre(void){
**
** $db eval SQL ?ARRAYNAME? SCRIPT
*/
-static int DbEvalNextCmd(
+static int SQLITE_TCLAPI DbEvalNextCmd(
ClientData data[], /* data[0] is the (DbEvalContext*) */
Tcl_Interp *interp, /* Tcl interpreter */
int result /* Result so far */
@@ -1585,11 +1729,11 @@ static int DbEvalNextCmd(
}
}
- /* The required interpreter variables are now populated with the data
+ /* The required interpreter variables are now populated with the data
** from the current row. If using NRE, schedule callbacks to evaluate
** script pScript, then to invoke this function again to fetch the next
** row (or clean up if there is no next row or the script throws an
- ** exception). After scheduling the callbacks, return control to the
+ ** exception). After scheduling the callbacks, return control to the
** caller.
**
** If not using NRE, evaluate pScript directly and continue with the
@@ -1614,6 +1758,46 @@ static int DbEvalNextCmd(
}
/*
+** This function is used by the implementations of the following database
+** handle sub-commands:
+**
+** $db update_hook ?SCRIPT?
+** $db wal_hook ?SCRIPT?
+** $db commit_hook ?SCRIPT?
+** $db preupdate hook ?SCRIPT?
+*/
+static void DbHookCmd(
+ Tcl_Interp *interp, /* Tcl interpreter */
+ SqliteDb *pDb, /* Database handle */
+ Tcl_Obj *pArg, /* SCRIPT argument (or NULL) */
+ Tcl_Obj **ppHook /* Pointer to member of SqliteDb */
+){
+ sqlite3 *db = pDb->db;
+
+ if( *ppHook ){
+ Tcl_SetObjResult(interp, *ppHook);
+ if( pArg ){
+ Tcl_DecrRefCount(*ppHook);
+ *ppHook = 0;
+ }
+ }
+ if( pArg ){
+ assert( !(*ppHook) );
+ if( Tcl_GetCharLength(pArg)>0 ){
+ *ppHook = pArg;
+ Tcl_IncrRefCount(*ppHook);
+ }
+ }
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ sqlite3_preupdate_hook(db, (pDb->pPreUpdateHook?DbPreUpdateHandler:0), pDb);
+#endif
+ sqlite3_update_hook(db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb);
+ sqlite3_rollback_hook(db, (pDb->pRollbackHook?DbRollbackHandler:0), pDb);
+ sqlite3_wal_hook(db, (pDb->pWalHook?DbWalHandler:0), pDb);
+}
+
+/*
** The "sqlite" command below creates a new Tcl command for each
** connection it opens to an SQLite database. This routine is invoked
** whenever one of those connection-specific commands is executed
@@ -1626,7 +1810,12 @@ static int DbEvalNextCmd(
** and calls that connection "db1". The second command causes this
** subroutine to be invoked.
*/
-static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
+static int SQLITE_TCLAPI DbObjCmd(
+ void *cd,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *const*objv
+){
SqliteDb *pDb = (SqliteDb*)cd;
int choice;
int rc = TCL_OK;
@@ -1638,11 +1827,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"errorcode", "eval", "exists",
"function", "incrblob", "interrupt",
"last_insert_rowid", "nullvalue", "onecolumn",
- "profile", "progress", "rekey",
- "restore", "rollback_hook", "status",
- "timeout", "total_changes", "trace",
- "transaction", "unlock_notify", "update_hook",
- "version", "wal_hook", 0
+ "preupdate", "profile", "progress",
+ "rekey", "restore", "rollback_hook",
+ "status", "timeout", "total_changes",
+ "trace", "trace_v2", "transaction",
+ "unlock_notify", "update_hook", "version",
+ "wal_hook",
+ 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BUSY,
@@ -1652,11 +1843,12 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
DB_ERRORCODE, DB_EVAL, DB_EXISTS,
DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT,
DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN,
- DB_PROFILE, DB_PROGRESS, DB_REKEY,
- DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS,
- DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
- DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK,
- DB_VERSION, DB_WAL_HOOK
+ DB_PREUPDATE, DB_PROFILE, DB_PROGRESS,
+ DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK,
+ DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
+ DB_TRACE, DB_TRACE_V2, DB_TRANSACTION,
+ DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION,
+ DB_WAL_HOOK,
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@@ -1750,7 +1942,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME");
return TCL_ERROR;
}
- rc = sqlite3_open(zDestFile, &pDest);
+ rc = sqlite3_open_v2(zDestFile, &pDest,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE| pDb->openFlags, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "cannot open target database: ",
sqlite3_errmsg(pDest), (char*)0);
@@ -1841,7 +2034,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
return TCL_ERROR;
}else{
if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
- Tcl_AppendResult( interp, "cannot convert \"",
+ Tcl_AppendResult( interp, "cannot convert \"",
Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0);
return TCL_ERROR;
}else{
@@ -1855,7 +2048,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
}
}else{
- Tcl_AppendResult( interp, "bad option \"",
+ Tcl_AppendResult( interp, "bad option \"",
Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size",
(char*)0);
return TCL_ERROR;
@@ -1866,7 +2059,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/* $db changes
**
** Return the number of rows that were modified, inserted, or deleted by
- ** the most recent INSERT, UPDATE or DELETE statement, not including
+ ** the most recent INSERT, UPDATE or DELETE statement, not including
** any changes made by trigger programs.
*/
case DB_CHANGES: {
@@ -1913,7 +2106,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
pCollate->zScript = (char*)&pCollate[1];
pDb->pCollate = pCollate;
memcpy(pCollate->zScript, zScript, nScript+1);
- if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
+ if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
pCollate, tclSqlCollate) ){
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
return TCL_ERROR;
@@ -2039,7 +2232,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
const char *zSep;
const char *zNull;
if( objc<5 || objc>7 ){
- Tcl_WrongNumArgs(interp, 2, objv,
+ Tcl_WrongNumArgs(interp, 2, objv,
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
return TCL_ERROR;
}
@@ -2068,7 +2261,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
strcmp(zConflict, "fail" ) != 0 &&
strcmp(zConflict, "ignore" ) != 0 &&
strcmp(zConflict, "replace" ) != 0 ) {
- Tcl_AppendResult(interp, "Error: \"", zConflict,
+ Tcl_AppendResult(interp, "Error: \"", zConflict,
"\", conflict-algorithm must be one of: rollback, "
"abort, fail, ignore, or replace", (char*)0);
return TCL_ERROR;
@@ -2114,7 +2307,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
in = fopen(zFile, "rb");
if( in==0 ){
- Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL);
+ Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, (char*)0);
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
@@ -2157,7 +2350,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
for(i=0; i<nCol; i++){
/* check for null data, if so, bind as null */
if( (nNull>0 && strcmp(azCol[i], zNull)==0)
- || strlen30(azCol[i])==0
+ || strlen30(azCol[i])==0
){
sqlite3_bind_null(pStmt, i+1);
}else{
@@ -2236,8 +2429,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** The onecolumn method is the equivalent of:
** lindex [$db eval $sql] 0
*/
- case DB_EXISTS:
+ case DB_EXISTS:
case DB_ONECOLUMN: {
+ Tcl_Obj *pResult = 0;
DbEvalContext sEval;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "SQL");
@@ -2248,21 +2442,22 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
rc = dbEvalStep(&sEval);
if( choice==DB_ONECOLUMN ){
if( rc==TCL_OK ){
- Tcl_SetObjResult(interp, dbEvalColumnValue(&sEval, 0));
+ pResult = 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));
+ pResult = Tcl_NewBooleanObj(rc==TCL_OK);
}
dbEvalFinalize(&sEval);
+ if( pResult ) Tcl_SetObjResult(interp, pResult);
if( rc==TCL_BREAK ){
rc = TCL_OK;
}
break;
}
-
+
/*
** $db eval $sql ?array? ?{ ...code... }?
**
@@ -2308,7 +2503,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
pScript = objv[objc-1];
Tcl_IncrRefCount(pScript);
-
+
p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext));
dbEvalInit(p, pDb, objv[2], pArray);
@@ -2341,7 +2536,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
int n = strlen30(z);
if( n>2 && strncmp(z, "-argcount",n)==0 ){
if( i==(objc-2) ){
- Tcl_AppendResult(interp, "option requires an argument: ", z, 0);
+ Tcl_AppendResult(interp, "option requires an argument: ", z,(char*)0);
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[i+1], &nArg) ) return TCL_ERROR;
@@ -2355,8 +2550,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
if( n>2 && strncmp(z, "-deterministic",n)==0 ){
flags |= SQLITE_DETERMINISTIC;
}else{
- Tcl_AppendResult(interp, "bad option \"", z,
- "\": must be -argcount or -deterministic", 0
+ Tcl_AppendResult(interp, "bad option \"", z,
+ "\": must be -argcount or -deterministic", (char*)0
);
return TCL_ERROR;
}
@@ -2464,7 +2659,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
/*
- ** $db last_insert_rowid
+ ** $db last_insert_rowid
**
** Return an integer which is the ROWID for the most recent insert.
*/
@@ -2486,7 +2681,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
*/
/* $db progress ?N CALLBACK?
- **
+ **
** Invoke the given callback every N virtual machine opcodes while executing
** queries.
*/
@@ -2554,7 +2749,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else{
pDb->zProfile = 0;
}
-#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
+#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \
+ !defined(SQLITE_OMIT_DEPRECATED)
if( pDb->zProfile ){
pDb->interp = interp;
sqlite3_profile(pDb->db, DbProfileHandler, pDb);
@@ -2572,7 +2768,7 @@ 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
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
int nKey;
void *pKey;
#endif
@@ -2580,7 +2776,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_WrongNumArgs(interp, 2, objv, "KEY");
return TCL_ERROR;
}
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
rc = sqlite3_rekey(pDb->db, pKey, nKey);
if( rc ){
@@ -2593,7 +2789,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/* $db restore ?DATABASE? FILENAME
**
- ** Open a database file named FILENAME. Transfer the content
+ ** Open a database file named FILENAME. Transfer the content
** of FILENAME into the local database DATABASE (default: "main").
*/
case DB_RESTORE: {
@@ -2613,7 +2809,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME");
return TCL_ERROR;
}
- rc = sqlite3_open_v2(zSrcFile, &pSrc, SQLITE_OPEN_READONLY, 0);
+ rc = sqlite3_open_v2(zSrcFile, &pSrc,
+ SQLITE_OPEN_READONLY | pDb->openFlags, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "cannot open source database: ",
sqlite3_errmsg(pSrc), (char*)0);
@@ -2653,7 +2850,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/*
** $db status (step|sort|autoindex)
**
- ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
+ ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
** SQLITE_STMTSTATUS_SORT for the most recent eval.
*/
case DB_STATUS: {
@@ -2671,15 +2868,15 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else if( strcmp(zOp, "autoindex")==0 ){
v = pDb->nIndex;
}else{
- Tcl_AppendResult(interp,
- "bad argument: should be autoindex, step, or sort",
+ Tcl_AppendResult(interp,
+ "bad argument: should be autoindex, step, or sort",
(char*)0);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
break;
}
-
+
/*
** $db timeout MILLESECONDS
**
@@ -2695,11 +2892,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
sqlite3_busy_timeout(pDb->db, ms);
break;
}
-
+
/*
** $db total_changes
**
- ** Return the number of rows that were modified, inserted, or deleted
+ ** Return the number of rows that were modified, inserted, or deleted
** since the database handle was created.
*/
case DB_TOTAL_CHANGES: {
@@ -2740,7 +2937,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else{
pDb->zTrace = 0;
}
-#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
+#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \
+ !defined(SQLITE_OMIT_DEPRECATED)
if( pDb->zTrace ){
pDb->interp = interp;
sqlite3_trace(pDb->db, DbTraceHandler, pDb);
@@ -2752,6 +2950,88 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
+ /* $db trace_v2 ?CALLBACK? ?MASK?
+ **
+ ** Make arrangements to invoke the CALLBACK routine for each trace event
+ ** matching the mask that is generated. The parameters are appended to
+ ** CALLBACK before it is executed.
+ */
+ case DB_TRACE_V2: {
+ if( objc>4 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK? ?MASK?");
+ return TCL_ERROR;
+ }else if( objc==2 ){
+ if( pDb->zTraceV2 ){
+ Tcl_AppendResult(interp, pDb->zTraceV2, (char*)0);
+ }
+ }else{
+ char *zTraceV2;
+ int len;
+ Tcl_WideInt wMask = 0;
+ if( objc==4 ){
+ static const char *TTYPE_strs[] = {
+ "statement", "profile", "row", "close", 0
+ };
+ enum TTYPE_enum {
+ TTYPE_STMT, TTYPE_PROFILE, TTYPE_ROW, TTYPE_CLOSE
+ };
+ int i;
+ if( TCL_OK!=Tcl_ListObjLength(interp, objv[3], &len) ){
+ return TCL_ERROR;
+ }
+ for(i=0; i<len; i++){
+ Tcl_Obj *pObj;
+ int ttype;
+ if( TCL_OK!=Tcl_ListObjIndex(interp, objv[3], i, &pObj) ){
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIndexFromObj(interp, pObj, TTYPE_strs, "trace type",
+ 0, &ttype)!=TCL_OK ){
+ Tcl_WideInt wType;
+ Tcl_Obj *pError = Tcl_DuplicateObj(Tcl_GetObjResult(interp));
+ Tcl_IncrRefCount(pError);
+ if( TCL_OK==Tcl_GetWideIntFromObj(interp, pObj, &wType) ){
+ Tcl_DecrRefCount(pError);
+ wMask |= wType;
+ }else{
+ Tcl_SetObjResult(interp, pError);
+ Tcl_DecrRefCount(pError);
+ return TCL_ERROR;
+ }
+ }else{
+ switch( (enum TTYPE_enum)ttype ){
+ case TTYPE_STMT: wMask |= SQLITE_TRACE_STMT; break;
+ case TTYPE_PROFILE: wMask |= SQLITE_TRACE_PROFILE; break;
+ case TTYPE_ROW: wMask |= SQLITE_TRACE_ROW; break;
+ case TTYPE_CLOSE: wMask |= SQLITE_TRACE_CLOSE; break;
+ }
+ }
+ }
+ }else{
+ wMask = SQLITE_TRACE_STMT; /* use the "legacy" default */
+ }
+ if( pDb->zTraceV2 ){
+ Tcl_Free(pDb->zTraceV2);
+ }
+ zTraceV2 = Tcl_GetStringFromObj(objv[2], &len);
+ if( zTraceV2 && len>0 ){
+ pDb->zTraceV2 = Tcl_Alloc( len + 1 );
+ memcpy(pDb->zTraceV2, zTraceV2, len+1);
+ }else{
+ pDb->zTraceV2 = 0;
+ }
+#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
+ if( pDb->zTraceV2 ){
+ pDb->interp = interp;
+ sqlite3_trace_v2(pDb->db, (unsigned)wMask, DbTraceV2Handler, pDb);
+ }else{
+ sqlite3_trace_v2(pDb->db, 0, 0, 0);
+ }
+#endif
+ }
+ break;
+ }
+
/* $db transaction [-deferred|-immediate|-exclusive] SCRIPT
**
** Start a new transaction (if we are not already in the midst of a
@@ -2804,7 +3084,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/* If using NRE, schedule a callback to invoke the script pScript, then
** a second callback to commit (or rollback) the transaction or savepoint
** opened above. If not using NRE, evaluate the script directly, then
- ** call function DbTransPostCmd() to commit (or rollback) the transaction
+ ** call function DbTransPostCmd() to commit (or rollback) the transaction
** or savepoint. */
if( DbUseNre() ){
Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0);
@@ -2835,14 +3115,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_DecrRefCount(pDb->pUnlockNotify);
pDb->pUnlockNotify = 0;
}
-
+
if( objc==3 ){
xNotify = DbUnlockNotify;
pNotifyArg = (void *)pDb;
pDb->pUnlockNotify = objv[2];
Tcl_IncrRefCount(pDb->pUnlockNotify);
}
-
+
if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
rc = TCL_ERROR;
@@ -2853,49 +3133,111 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
/*
+ ** $db preupdate_hook count
+ ** $db preupdate_hook hook ?SCRIPT?
+ ** $db preupdate_hook new INDEX
+ ** $db preupdate_hook old INDEX
+ */
+ case DB_PREUPDATE: {
+#ifndef SQLITE_ENABLE_PREUPDATE_HOOK
+ Tcl_AppendResult(interp, "preupdate_hook was omitted at compile-time",
+ (char*)0);
+ rc = TCL_ERROR;
+#else
+ static const char *azSub[] = {"count", "depth", "hook", "new", "old", 0};
+ enum DbPreupdateSubCmd {
+ PRE_COUNT, PRE_DEPTH, PRE_HOOK, PRE_NEW, PRE_OLD
+ };
+ int iSub;
+
+ if( objc<3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "SUB-COMMAND ?ARGS?");
+ }
+ if( Tcl_GetIndexFromObj(interp, objv[2], azSub, "sub-command", 0, &iSub) ){
+ return TCL_ERROR;
+ }
+
+ switch( (enum DbPreupdateSubCmd)iSub ){
+ case PRE_COUNT: {
+ int nCol = sqlite3_preupdate_count(pDb->db);
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(nCol));
+ break;
+ }
+
+ case PRE_HOOK: {
+ if( objc>4 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "hook ?SCRIPT?");
+ return TCL_ERROR;
+ }
+ DbHookCmd(interp, pDb, (objc==4 ? objv[3] : 0), &pDb->pPreUpdateHook);
+ break;
+ }
+
+ case PRE_DEPTH: {
+ Tcl_Obj *pRet;
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 3, objv, "");
+ return TCL_ERROR;
+ }
+ pRet = Tcl_NewIntObj(sqlite3_preupdate_depth(pDb->db));
+ Tcl_SetObjResult(interp, pRet);
+ break;
+ }
+
+ case PRE_NEW:
+ case PRE_OLD: {
+ int iIdx;
+ sqlite3_value *pValue;
+ if( objc!=4 ){
+ Tcl_WrongNumArgs(interp, 3, objv, "INDEX");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIntFromObj(interp, objv[3], &iIdx) ){
+ return TCL_ERROR;
+ }
+
+ if( iSub==PRE_OLD ){
+ rc = sqlite3_preupdate_old(pDb->db, iIdx, &pValue);
+ }else{
+ assert( iSub==PRE_NEW );
+ rc = sqlite3_preupdate_new(pDb->db, iIdx, &pValue);
+ }
+
+ if( rc==SQLITE_OK ){
+ Tcl_Obj *pObj;
+ pObj = Tcl_NewStringObj((char*)sqlite3_value_text(pValue), -1);
+ Tcl_SetObjResult(interp, pObj);
+ }else{
+ Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
+ return TCL_ERROR;
+ }
+ }
+ }
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+ break;
+ }
+
+ /*
** $db wal_hook ?script?
** $db update_hook ?script?
** $db rollback_hook ?script?
*/
- case DB_WAL_HOOK:
- case DB_UPDATE_HOOK:
+ case DB_WAL_HOOK:
+ case DB_UPDATE_HOOK:
case DB_ROLLBACK_HOOK: {
-
- /* set ppHook to point at pUpdateHook or pRollbackHook, depending on
+ /* 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 if( choice==DB_WAL_HOOK ){
- ppHook = &pDb->pWalHook;
- }else{
- ppHook = &pDb->pRollbackHook;
- }
-
- if( objc!=2 && objc!=3 ){
+ Tcl_Obj **ppHook = 0;
+ if( choice==DB_WAL_HOOK ) ppHook = &pDb->pWalHook;
+ if( choice==DB_UPDATE_HOOK ) ppHook = &pDb->pUpdateHook;
+ if( choice==DB_ROLLBACK_HOOK ) ppHook = &pDb->pRollbackHook;
+ if( 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);
- sqlite3_wal_hook(pDb->db,(pDb->pWalHook?DbWalHandler:0),pDb);
+ DbHookCmd(interp, pDb, (objc==3 ? objv[2] : 0), ppHook);
break;
}
@@ -2918,7 +3260,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** Adaptor that provides an objCmd interface to the NRE-enabled
** interface implementation.
*/
-static int DbObjCmdAdaptor(
+static int SQLITE_TCLAPI DbObjCmdAdaptor(
void *cd,
Tcl_Interp *interp,
int objc,
@@ -2943,7 +3285,12 @@ static int DbObjCmdAdaptor(
** The second argument is the name of the database file.
**
*/
-static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
+static int SQLITE_TCLAPI DbMain(
+ void *cd,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *const*objv
+){
SqliteDb *p;
const char *zArg;
char *zErrMsg;
@@ -2952,7 +3299,7 @@ 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
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
void *pKey = 0;
int nKey = 0;
#endif
@@ -2976,8 +3323,12 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0);
return TCL_OK;
}
+ if( strcmp(zArg,"-sourceid")==0 ){
+ Tcl_AppendResult(interp,sqlite3_sourceid(), (char*)0);
+ return TCL_OK;
+ }
if( strcmp(zArg,"-has-codec")==0 ){
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
Tcl_AppendResult(interp,"1",(char*)0);
#else
Tcl_AppendResult(interp,"0",(char*)0);
@@ -2988,7 +3339,7 @@ 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
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey);
#endif
}else if( strcmp(zArg, "-vfs")==0 ){
@@ -3043,10 +3394,10 @@ 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,
+ Tcl_WrongNumArgs(interp, 1, objv,
"HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
" ?-key CODECKEY?"
#endif
);
@@ -3072,7 +3423,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else{
zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc));
}
-#ifdef SQLITE_HAS_CODEC
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
if( p->db ){
sqlite3_key(p->db, pKey, nKey);
}
@@ -3084,6 +3435,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
return TCL_ERROR;
}
p->maxStmt = NUM_PREPARED_STMTS;
+ p->openFlags = flags & SQLITE_OPEN_URI;
p->interp = interp;
zArg = Tcl_GetStringFromObj(objv[1], 0);
if( DbUseNre() ){
@@ -3143,9 +3495,13 @@ EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
EXTERN int Tclsqlite3_Unload(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.
+** is not considered appropriate for safe interpreters. Hence, we cause
+** the _SafeInit() interfaces return TCL_ERROR.
*/
+EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
+EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}
+
+
#ifndef SQLITE_3_SUFFIX_ONLY
int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
@@ -3330,7 +3686,7 @@ static void MD5Init(MD5Context *ctx){
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
-static
+static
void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
uint32 t;
@@ -3376,7 +3732,7 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
}
/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
static void MD5Final(unsigned char digest[16], MD5Context *ctx){
@@ -3452,16 +3808,21 @@ static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
/*
** A TCL command for md5. The argument is the text to be hashed. The
-** Result is the hash in base64.
+** Result is the hash in base64.
*/
-static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
+static int SQLITE_TCLAPI md5_cmd(
+ void*cd,
+ Tcl_Interp *interp,
+ int argc,
+ const char **argv
+){
MD5Context ctx;
unsigned char digest[16];
char zBuf[50];
void (*converter)(unsigned char*, char*);
if( argc!=2 ){
- Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
" TEXT\"", (char*)0);
return TCL_ERROR;
}
@@ -3478,7 +3839,12 @@ static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
** A TCL command to take the md5 hash of a file. The argument is the
** name of the file.
*/
-static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
+static int SQLITE_TCLAPI md5file_cmd(
+ void*cd,
+ Tcl_Interp *interp,
+ int argc,
+ const char **argv
+){
FILE *in;
MD5Context ctx;
void (*converter)(unsigned char*, char*);
@@ -3486,13 +3852,13 @@ static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
char zBuf[10240];
if( argc!=2 ){
- Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
" FILENAME\"", (char*)0);
return TCL_ERROR;
}
in = fopen(argv[1],"rb");
if( in==0 ){
- Tcl_AppendResult(interp,"unable to open file \"", argv[1],
+ Tcl_AppendResult(interp,"unable to open file \"", argv[1],
"\" for reading", (char*)0);
return TCL_ERROR;
}
@@ -3558,8 +3924,12 @@ static void md5finalize(sqlite3_context *context){
MD5DigestToBase16(digest, zBuf);
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
-int Md5_Register(sqlite3 *db){
- int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
+int Md5_Register(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pThunk
+){
+ int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
md5step, md5finalize);
sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
return rc;
@@ -3606,7 +3976,7 @@ static const char *tclsh_main_loop(void);
#ifdef SQLITE_TEST
static void init_all(Tcl_Interp *);
-static int init_all_cmd(
+static int SQLITE_TCLAPI init_all_cmd(
ClientData cd,
Tcl_Interp *interp,
int objc,
@@ -3636,7 +4006,7 @@ static int init_all_cmd(
** to use the sqlite3_prepare_v2() function to prepare statements. If it
** is false, sqlite3_prepare().
*/
-static int db_use_legacy_prepare_cmd(
+static int SQLITE_TCLAPI db_use_legacy_prepare_cmd(
ClientData cd,
Tcl_Interp *interp,
int objc,
@@ -3673,7 +4043,7 @@ static int db_use_legacy_prepare_cmd(
** return the text representation of the most recently used statement
** handle.
*/
-static int db_last_stmt_ptr(
+static int SQLITE_TCLAPI db_last_stmt_ptr(
ClientData cd,
Tcl_Interp *interp,
int objc,
@@ -3710,7 +4080,7 @@ static int db_last_stmt_ptr(
** Configure the interpreter passed as the first argument to have access
** to the commands and linked variables that make up:
**
-** * the [sqlite3] extension itself,
+** * the [sqlite3] extension itself,
**
** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
**
@@ -3760,8 +4130,12 @@ 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*);
+#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
+ extern int TestSession_Init(Tcl_Interp*);
+#endif
extern int Fts5tcl_Init(Tcl_Interp *);
extern int SqliteRbu_Init(Tcl_Interp*);
+ extern int Sqlitetesttcl_Init(Tcl_Interp*);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
#endif
@@ -3794,7 +4168,7 @@ static void init_all(Tcl_Interp *interp){
Sqlitetesttclvar_Init(interp);
Sqlitetestfs_Init(interp);
SqlitetestThread_Init(interp);
- SqlitetestOnefile_Init(interp);
+ SqlitetestOnefile_Init();
SqlitetestOsinst_Init(interp);
Sqlitetestbackup_Init(interp);
Sqlitetestintarray_Init(interp);
@@ -3804,8 +4178,12 @@ static void init_all(Tcl_Interp *interp){
Sqlitemultiplex_Init(interp);
SqliteSuperlock_Init(interp);
SqlitetestSyscall_Init(interp);
+#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
+ TestSession_Init(interp);
+#endif
Fts5tcl_Init(interp);
SqliteRbu_Init(interp);
+ Sqlitetesttcl_Init(interp);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
Sqlitetestfts3_Init(interp);
@@ -3834,7 +4212,7 @@ static void init_all(Tcl_Interp *interp){
#endif
#define TCLSH_MAIN main /* Needed to fake out mktclapp */
-int TCLSH_MAIN(int argc, char **argv){
+int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){
Tcl_Interp *interp;
#if !defined(_WIN32_WCE)
« no previous file with comments | « third_party/sqlite/src/src/table.c ('k') | third_party/sqlite/src/src/test1.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698