| 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)
 | 
| 
 |