Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tclsqlite.c4600 linesDownload Raw Back to src
1/*2** 2001 September 153**4** The author disclaims copyright to this source code.  In place of5** a legal notice, here is a blessing:6**7**    May you do good and not evil.8**    May you find forgiveness for yourself and forgive others.9**    May you share freely, never taking more than you give.10**11*************************************************************************12** A TCL Interface to SQLite.  Append this file to sqlite3.c and13** compile the whole thing to build a TCL-enabled version of SQLite.14**15** Compile-time options:16**17**  -DTCLSH         Add a "main()" routine that works as a tclsh.18**19**  -DTCLSH_INIT_PROC=name20**21**                  Invoke name(interp) to initialize the Tcl interpreter.22**                  If name(interp) returns a non-NULL string, then run23**                  that string as a Tcl script to launch the application.24**                  If name(interp) returns NULL, then run the regular25**                  tclsh-emulator code.26*/27#ifdef TCLSH_INIT_PROC28# define TCLSH 129#endif30 31/*32** If requested, include the SQLite compiler options file for MSVC.33*/34#if defined(INCLUDE_MSVC_H)35# include "msvc.h"36#endif37 38/****** Copy of tclsqlite.h ******/39#if defined(INCLUDE_SQLITE_TCL_H)40# include "sqlite_tcl.h"   /* Special case for Windows using STDCALL */41#else42# include <tcl.h>          /* All normal cases */43# ifndef SQLITE_TCLAPI44#   define SQLITE_TCLAPI45# endif46#endif47/* Compatability between Tcl8.6 and Tcl9.0 */48#if TCL_MAJOR_VERSION==949# define CONST const50#elif !defined(Tcl_Size)51  typedef int Tcl_Size;52# ifndef Tcl_BounceRefCount53#  define Tcl_BounceRefCount(X) Tcl_IncrRefCount(X); Tcl_DecrRefCount(X)54   /* https://www.tcl-lang.org/man/tcl9.0/TclLib/Object.html */55# endif56#endif57/**** End copy of tclsqlite.h ****/58 59#include <errno.h>60 61/*62** Some additional include files are needed if this file is not63** appended to the amalgamation.64*/65#ifndef SQLITE_AMALGAMATION66# include "sqlite3.h"67# include <stdlib.h>68# include <string.h>69# include <assert.h>70  typedef unsigned char u8;71# ifndef SQLITE_PTRSIZE72#   if defined(__SIZEOF_POINTER__)73#     define SQLITE_PTRSIZE __SIZEOF_POINTER__74#   elif defined(i386)     || defined(__i386__)   || defined(_M_IX86) ||    \75         defined(_M_ARM)   || defined(__arm__)    || defined(__x86)   ||    \76        (defined(__APPLE__) && defined(__POWERPC__)) ||                     \77        (defined(__TOS_AIX__) && !defined(__64BIT__))78#     define SQLITE_PTRSIZE 479#   else80#     define SQLITE_PTRSIZE 881#   endif82# endif /* SQLITE_PTRSIZE */83# if defined(HAVE_STDINT_H) || (defined(__STDC_VERSION__) &&  \84                                (__STDC_VERSION__ >= 199901L))85#   include <stdint.h>86    typedef uintptr_t uptr;87# elif SQLITE_PTRSIZE==488    typedef unsigned int uptr;89# else90    typedef sqlite3_uint64 uptr;91# endif92#endif93#include <ctype.h>94 95/* Used to get the current process ID */96#if !defined(_WIN32)97# include <signal.h>98# include <unistd.h>99# define GETPID getpid100#elif !defined(_WIN32_WCE)101# ifndef SQLITE_AMALGAMATION102#  ifndef WIN32_LEAN_AND_MEAN103#   define WIN32_LEAN_AND_MEAN104#  endif105#  include <windows.h>106# endif107# include <io.h>108# define isatty(h) _isatty(h)109# define GETPID (int)GetCurrentProcessId110#endif111 112/*113 * Windows needs to know which symbols to export.  Unix does not.114 * BUILD_sqlite should be undefined for Unix.115 */116#ifdef BUILD_sqlite117#undef TCL_STORAGE_CLASS118#define TCL_STORAGE_CLASS DLLEXPORT119#endif /* BUILD_sqlite */120 121#define NUM_PREPARED_STMTS 10122#define MAX_PREPARED_STMTS 100123 124/* Forward declaration */125typedef struct SqliteDb SqliteDb;126 127/* Add -DSQLITE_ENABLE_QRF_IN_TCL to add the Query Result Formatter (QRF)128** into the build of the TCL extension, when building using separate129** source files.  The QRF is included automatically when building from130** the tclsqlite3.c amalgamation.131*/132#if defined(SQLITE_ENABLE_QRF_IN_TCL)133#include "qrf.h"134#endif135 136/*137** New SQL functions can be created as TCL scripts.  Each such function138** is described by an instance of the following structure.139**140** Variable eType may be set to SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT,141** SQLITE_BLOB or SQLITE_NULL. If it is SQLITE_NULL, then the implementation142** attempts to determine the type of the result based on the Tcl object.143** If it is SQLITE_TEXT or SQLITE_BLOB, then a text (sqlite3_result_text())144** or blob (sqlite3_result_blob()) is returned. If it is SQLITE_INTEGER145** or SQLITE_FLOAT, then an attempt is made to return an integer or float146** value, falling back to float and then text if this is not possible.147*/148typedef struct SqlFunc SqlFunc;149struct SqlFunc {150  Tcl_Interp *interp;   /* The TCL interpret to execute the function */151  Tcl_Obj *pScript;     /* The Tcl_Obj representation of the script */152  SqliteDb *pDb;        /* Database connection that owns this function */153  int useEvalObjv;      /* True if it is safe to use Tcl_EvalObjv */154  int eType;            /* Type of value to return */155  char *zName;          /* Name of this function */156  SqlFunc *pNext;       /* Next function on the list of them all */157};158 159/*160** New collation sequences function can be created as TCL scripts.  Each such161** function is described by an instance of the following structure.162*/163typedef struct SqlCollate SqlCollate;164struct SqlCollate {165  Tcl_Interp *interp;   /* The TCL interpret to execute the function */166  char *zScript;        /* The script to be run */167  SqlCollate *pNext;    /* Next function on the list of them all */168};169 170/*171** Prepared statements are cached for faster execution.  Each prepared172** statement is described by an instance of the following structure.173*/174typedef struct SqlPreparedStmt SqlPreparedStmt;175struct SqlPreparedStmt {176  SqlPreparedStmt *pNext;  /* Next in linked list */177  SqlPreparedStmt *pPrev;  /* Previous on the list */178  sqlite3_stmt *pStmt;     /* The prepared statement */179  int nSql;                /* chars in zSql[] */180  const char *zSql;        /* Text of the SQL statement */181  int nParm;               /* Size of apParm array */182  Tcl_Obj **apParm;        /* Array of referenced object pointers */183};184 185typedef struct IncrblobChannel IncrblobChannel;186 187/*188** There is one instance of this structure for each SQLite database189** that has been opened by the SQLite TCL interface.190**191** If this module is built with SQLITE_TEST defined (to create the SQLite192** testfixture executable), then it may be configured to use either193** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements.194** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used.195*/196struct SqliteDb {197  sqlite3 *db;               /* The "real" database structure. MUST BE FIRST */198  Tcl_Interp *interp;        /* The interpreter used for this database */199  char *zBusy;               /* The busy callback routine */200  char *zCommit;             /* The commit hook callback routine */201  char *zTrace;              /* The trace callback routine */202  char *zTraceV2;            /* The trace_v2 callback routine */203  char *zProfile;            /* The profile callback routine */204  char *zProgress;           /* The progress callback routine */205  char *zBindFallback;       /* Callback to invoke on a binding miss */206  char *zAuth;               /* The authorization callback routine */207  int disableAuth;           /* Disable the authorizer if it exists */208  char *zNull;               /* Text to substitute for an SQL NULL value */209  SqlFunc *pFunc;            /* List of SQL functions */210  Tcl_Obj *pUpdateHook;      /* Update hook script (if any) */211  Tcl_Obj *pPreUpdateHook;   /* Pre-update hook script (if any) */212  Tcl_Obj *pRollbackHook;    /* Rollback hook script (if any) */213  Tcl_Obj *pWalHook;         /* WAL hook script (if any) */214  Tcl_Obj *pUnlockNotify;    /* Unlock notify script (if any) */215  SqlCollate *pCollate;      /* List of SQL collation functions */216  int rc;                    /* Return code of most recent sqlite3_exec() */217  Tcl_Obj *pCollateNeeded;   /* Collation needed script */218  SqlPreparedStmt *stmtList; /* List of prepared statements*/219  SqlPreparedStmt *stmtLast; /* Last statement in the list */220  int maxStmt;               /* The next maximum number of stmtList */221  int nStmt;                 /* Number of statements in stmtList */222  IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */223  int nStep, nSort, nIndex;  /* Statistics for most recent operation */224  int nVMStep;               /* Another statistic for most recent operation */225  int nTransaction;          /* Number of nested [transaction] methods */226  int openFlags;             /* Flags used to open.  (SQLITE_OPEN_URI) */227  int nRef;                  /* Delete object when this reaches 0 */228#ifdef SQLITE_TEST229  int bLegacyPrepare;        /* True to use sqlite3_prepare() */230#endif231};232 233struct IncrblobChannel {234  sqlite3_blob *pBlob;      /* sqlite3 blob handle */235  SqliteDb *pDb;            /* Associated database connection */236  sqlite3_int64 iSeek;      /* Current seek offset */237  unsigned int isClosed;    /* TCL_CLOSE_READ or TCL_CLOSE_WRITE */238  Tcl_Channel channel;      /* Channel identifier */239  IncrblobChannel *pNext;   /* Linked list of all open incrblob channels */240  IncrblobChannel *pPrev;   /* Linked list of all open incrblob channels */241};242 243/*244** Compute a string length that is limited to what can be stored in245** lower 30 bits of a 32-bit signed integer.246*/247static int strlen30(const char *z){248  const char *z2 = z;249  while( *z2 ){ z2++; }250  return 0x3fffffff & (int)(z2 - z);251}252 253 254#ifndef SQLITE_OMIT_INCRBLOB255/*256** Close all incrblob channels opened using database connection pDb.257** This is called when shutting down the database connection.258*/259static void closeIncrblobChannels(SqliteDb *pDb){260  IncrblobChannel *p;261  IncrblobChannel *pNext;262 263  for(p=pDb->pIncrblob; p; p=pNext){264    pNext = p->pNext;265 266    /* Note: Calling unregister here call Tcl_Close on the incrblob channel,267    ** which deletes the IncrblobChannel structure at *p. So do not268    ** call Tcl_Free() here.269    */270    Tcl_UnregisterChannel(pDb->interp, p->channel);271  }272}273 274/*275** Close an incremental blob channel.276*/277static int SQLITE_TCLAPI incrblobClose2(278  ClientData instanceData,279  Tcl_Interp *interp,280  int flags281){282  IncrblobChannel *p = (IncrblobChannel *)instanceData;283  int  rc;284  sqlite3 *db = p->pDb->db;285 286  if( flags ){287    p->isClosed |= flags;288    return TCL_OK;289  }290 291  /* If we reach this point, then we really do need to close the channel */292  rc = sqlite3_blob_close(p->pBlob);293 294  /* Remove the channel from the SqliteDb.pIncrblob list. */295  if( p->pNext ){296    p->pNext->pPrev = p->pPrev;297  }298  if( p->pPrev ){299    p->pPrev->pNext = p->pNext;300  }301  if( p->pDb->pIncrblob==p ){302    p->pDb->pIncrblob = p->pNext;303  }304 305  /* Free the IncrblobChannel structure */306  Tcl_Free((char *)p);307 308  if( rc!=SQLITE_OK ){309    Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);310    return TCL_ERROR;311  }312  return TCL_OK;313}314static int SQLITE_TCLAPI incrblobClose(315  ClientData instanceData,316  Tcl_Interp *interp317){318  return incrblobClose2(instanceData, interp, 0);319}320 321 322/*323** Read data from an incremental blob channel.324*/325static int SQLITE_TCLAPI incrblobInput(326  ClientData instanceData,327  char *buf,328  int bufSize,329  int *errorCodePtr330){331  IncrblobChannel *p = (IncrblobChannel *)instanceData;332  sqlite3_int64 nRead = bufSize;   /* Number of bytes to read */333  sqlite3_int64 nBlob;             /* Total size of the blob */334  int rc;                          /* sqlite error code */335 336  nBlob = sqlite3_blob_bytes(p->pBlob);337  if( (p->iSeek+nRead)>nBlob ){338    nRead = nBlob-p->iSeek;339  }340  if( nRead<=0 ){341    return 0;342  }343 344  rc = sqlite3_blob_read(p->pBlob, (void *)buf, (int)nRead, (int)p->iSeek);345  if( rc!=SQLITE_OK ){346    *errorCodePtr = rc;347    return -1;348  }349 350  p->iSeek += nRead;351  return nRead;352}353 354/*355** Write data to an incremental blob channel.356*/357static int SQLITE_TCLAPI incrblobOutput(358  ClientData instanceData,359  const char *buf,360  int toWrite,361  int *errorCodePtr362){363  IncrblobChannel *p = (IncrblobChannel *)instanceData;364  sqlite3_int64 nWrite = toWrite;   /* Number of bytes to write */365  sqlite3_int64 nBlob;              /* Total size of the blob */366  int rc;                           /* sqlite error code */367 368  nBlob = sqlite3_blob_bytes(p->pBlob);369  if( (p->iSeek+nWrite)>nBlob ){370    *errorCodePtr = EINVAL;371    return -1;372  }373  if( nWrite<=0 ){374    return 0;375  }376 377  rc = sqlite3_blob_write(p->pBlob, (void*)buf,(int)nWrite, (int)p->iSeek);378  if( rc!=SQLITE_OK ){379    *errorCodePtr = EIO;380    return -1;381  }382 383  p->iSeek += nWrite;384  return nWrite;385}386 387/* The datatype of Tcl_DriverWideSeekProc changes between tcl8.6 and tcl9.0 */388#if TCL_MAJOR_VERSION==9389# define WideSeekProcType long long390#else391# define WideSeekProcType Tcl_WideInt392#endif393 394/*395** Seek an incremental blob channel.396*/397static WideSeekProcType SQLITE_TCLAPI incrblobWideSeek(398  ClientData instanceData,399  WideSeekProcType offset,400  int seekMode,401  int *errorCodePtr402){403  IncrblobChannel *p = (IncrblobChannel *)instanceData;404 405  switch( seekMode ){406    case SEEK_SET:407      p->iSeek = offset;408      break;409    case SEEK_CUR:410      p->iSeek += offset;411      break;412    case SEEK_END:413      p->iSeek = sqlite3_blob_bytes(p->pBlob) + offset;414      break;415 416    default: assert(!"Bad seekMode");417  }418 419  return p->iSeek;420}421static int SQLITE_TCLAPI incrblobSeek(422  ClientData instanceData,423  long offset,424  int seekMode,425  int *errorCodePtr426){427  return incrblobWideSeek(instanceData,offset,seekMode,errorCodePtr);428}429 430 431static void SQLITE_TCLAPI incrblobWatch(432  ClientData instanceData,433  int mode434){435  /* NO-OP */436}437static int SQLITE_TCLAPI incrblobHandle(438  ClientData instanceData,439  int dir,440  ClientData *hPtr441){442  return TCL_ERROR;443}444 445static Tcl_ChannelType IncrblobChannelType = {446  "incrblob",                        /* typeName                             */447  TCL_CHANNEL_VERSION_5,             /* version                              */448  incrblobClose,                     /* closeProc                            */449  incrblobInput,                     /* inputProc                            */450  incrblobOutput,                    /* outputProc                           */451  incrblobSeek,                      /* seekProc                             */452  0,                                 /* setOptionProc                        */453  0,                                 /* getOptionProc                        */454  incrblobWatch,                     /* watchProc (this is a no-op)          */455  incrblobHandle,                    /* getHandleProc (always returns error) */456  incrblobClose2,                    /* close2Proc                           */457  0,                                 /* blockModeProc                        */458  0,                                 /* flushProc                            */459  0,                                 /* handlerProc                          */460  incrblobWideSeek,                  /* wideSeekProc                         */461};462 463/*464** Create a new incrblob channel.465*/466static int createIncrblobChannel(467  Tcl_Interp *interp,468  SqliteDb *pDb,469  const char *zDb,470  const char *zTable,471  const char *zColumn,472  sqlite_int64 iRow,473  int isReadonly474){475  IncrblobChannel *p;476  sqlite3 *db = pDb->db;477  sqlite3_blob *pBlob;478  int rc;479  int flags = TCL_READABLE|(isReadonly ? 0 : TCL_WRITABLE);480 481  /* This variable is used to name the channels: "incrblob_[incr count]" */482  static int count = 0;483  char zChannel[64];484 485  rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob);486  if( rc!=SQLITE_OK ){487    Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);488    return TCL_ERROR;489  }490 491  p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel));492  memset(p, 0, sizeof(*p));493  p->pBlob = pBlob;494  if( (flags & TCL_WRITABLE)==0 ) p->isClosed |= TCL_CLOSE_WRITE;495 496  sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count);497  p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags);498  Tcl_RegisterChannel(interp, p->channel);499 500  /* Link the new channel into the SqliteDb.pIncrblob list. */501  p->pNext = pDb->pIncrblob;502  p->pPrev = 0;503  if( p->pNext ){504    p->pNext->pPrev = p;505  }506  pDb->pIncrblob = p;507  p->pDb = pDb;508 509  Tcl_SetResult(interp, (char *)Tcl_GetChannelName(p->channel), TCL_VOLATILE);510  return TCL_OK;511}512#else  /* else clause for "#ifndef SQLITE_OMIT_INCRBLOB" */513  #define closeIncrblobChannels(pDb)514#endif515 516/*517** Look at the script prefix in pCmd.  We will be executing this script518** after first appending one or more arguments.  This routine analyzes519** the script to see if it is safe to use Tcl_EvalObjv() on the script520** rather than the more general Tcl_EvalEx().  Tcl_EvalObjv() is much521** faster.522**523** Scripts that are safe to use with Tcl_EvalObjv() consists of a524** command name followed by zero or more arguments with no [...] or $525** or {...} or ; to be seen anywhere.  Most callback scripts consist526** of just a single procedure name and they meet this requirement.527*/528static int safeToUseEvalObjv(Tcl_Obj *pCmd){529  /* We could try to do something with Tcl_Parse().  But we will instead530  ** just do a search for forbidden characters.  If any of the forbidden531  ** characters appear in pCmd, we will report the string as unsafe.532  */533  const char *z;534  Tcl_Size n;535  z = Tcl_GetStringFromObj(pCmd, &n);536  while( n-- > 0 ){537    int c = *(z++);538    if( c=='$' || c=='[' || c==';' ) return 0;539  }540  return 1;541}542 543/*544** Find an SqlFunc structure with the given name.  Or create a new545** one if an existing one cannot be found.  Return a pointer to the546** structure.547*/548static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){549  SqlFunc *p, *pNew;550  int nName = strlen30(zName);551  pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 );552  pNew->zName = (char*)&pNew[1];553  memcpy(pNew->zName, zName, nName+1);554  for(p=pDb->pFunc; p; p=p->pNext){555    if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){556      Tcl_Free((char*)pNew);557      return p;558    }559  }560  pNew->interp = pDb->interp;561  pNew->pDb = pDb;562  pNew->pScript = 0;563  pNew->pNext = pDb->pFunc;564  pDb->pFunc = pNew;565  return pNew;566}567 568/*569** Free a single SqlPreparedStmt object.570*/571static void dbFreeStmt(SqlPreparedStmt *pStmt){572#ifdef SQLITE_TEST573  if( sqlite3_sql(pStmt->pStmt)==0 ){574    Tcl_Free((char *)pStmt->zSql);575  }576#endif577  sqlite3_finalize(pStmt->pStmt);578  Tcl_Free((char *)pStmt);579}580 581/*582** Finalize and free a list of prepared statements583*/584static void flushStmtCache(SqliteDb *pDb){585  SqlPreparedStmt *pPreStmt;586  SqlPreparedStmt *pNext;587 588  for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pNext){589    pNext = pPreStmt->pNext;590    dbFreeStmt(pPreStmt);591  }592  pDb->nStmt = 0;593  pDb->stmtLast = 0;594  pDb->stmtList = 0;595}596 597/*598** Increment the reference counter on the SqliteDb object. The reference599** should be released by calling delDatabaseRef().600*/601static void addDatabaseRef(SqliteDb *pDb){602  pDb->nRef++;603}604 605/*606** Decrement the reference counter associated with the SqliteDb object.607** If it reaches zero, delete the object.608*/609static void delDatabaseRef(SqliteDb *pDb){610  assert( pDb->nRef>0 );611  pDb->nRef--;612  if( pDb->nRef==0 ){613    flushStmtCache(pDb);614    closeIncrblobChannels(pDb);615    sqlite3_close(pDb->db);616    while( pDb->pFunc ){617      SqlFunc *pFunc = pDb->pFunc;618      pDb->pFunc = pFunc->pNext;619      assert( pFunc->pDb==pDb );620      Tcl_DecrRefCount(pFunc->pScript);621      Tcl_Free((char*)pFunc);622    }623    while( pDb->pCollate ){624      SqlCollate *pCollate = pDb->pCollate;625      pDb->pCollate = pCollate->pNext;626      Tcl_Free((char*)pCollate);627    }628    if( pDb->zBusy ){629      Tcl_Free(pDb->zBusy);630    }631    if( pDb->zTrace ){632      Tcl_Free(pDb->zTrace);633    }634    if( pDb->zTraceV2 ){635      Tcl_Free(pDb->zTraceV2);636    }637    if( pDb->zProfile ){638      Tcl_Free(pDb->zProfile);639    }640    if( pDb->zBindFallback ){641      Tcl_Free(pDb->zBindFallback);642    }643    if( pDb->zAuth ){644      Tcl_Free(pDb->zAuth);645    }646    if( pDb->zNull ){647      Tcl_Free(pDb->zNull);648    }649    if( pDb->pUpdateHook ){650      Tcl_DecrRefCount(pDb->pUpdateHook);651    }652    if( pDb->pPreUpdateHook ){653      Tcl_DecrRefCount(pDb->pPreUpdateHook);654    }655    if( pDb->pRollbackHook ){656      Tcl_DecrRefCount(pDb->pRollbackHook);657    }658    if( pDb->pWalHook ){659      Tcl_DecrRefCount(pDb->pWalHook);660    }661    if( pDb->pCollateNeeded ){662      Tcl_DecrRefCount(pDb->pCollateNeeded);663    }664    Tcl_Free((char*)pDb);665  }666}667 668/*669** TCL calls this procedure when an sqlite3 database command is670** deleted.671*/672static void SQLITE_TCLAPI DbDeleteCmd(void *db){673  SqliteDb *pDb = (SqliteDb*)db;674  delDatabaseRef(pDb);675}676 677/*678** This routine is called when a database file is locked while trying679** to execute SQL.680*/681static int DbBusyHandler(void *cd, int nTries){682  SqliteDb *pDb = (SqliteDb*)cd;683  int rc;684  char zVal[30];685 686  sqlite3_snprintf(sizeof(zVal), zVal, "%d", nTries);687  rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0);688  if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){689    return 0;690  }691  return 1;692}693 694#ifndef SQLITE_OMIT_PROGRESS_CALLBACK695/*696** This routine is invoked as the 'progress callback' for the database.697*/698static int DbProgressHandler(void *cd){699  SqliteDb *pDb = (SqliteDb*)cd;700  int rc;701 702  assert( pDb->zProgress );703  rc = Tcl_Eval(pDb->interp, pDb->zProgress);704  if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){705    return 1;706  }707  return 0;708}709#endif710 711#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \712    !defined(SQLITE_OMIT_DEPRECATED)713/*714** This routine is called by the SQLite trace handler whenever a new715** block of SQL is executed.  The TCL script in pDb->zTrace is executed.716*/717static void DbTraceHandler(void *cd, const char *zSql){718  SqliteDb *pDb = (SqliteDb*)cd;719  Tcl_DString str;720 721  Tcl_DStringInit(&str);722  Tcl_DStringAppend(&str, pDb->zTrace, -1);723  Tcl_DStringAppendElement(&str, zSql);724  Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));725  Tcl_DStringFree(&str);726  Tcl_ResetResult(pDb->interp);727}728#endif729 730#ifndef SQLITE_OMIT_TRACE731/*732** This routine is called by the SQLite trace_v2 handler whenever a new733** supported event is generated.  Unsupported event types are ignored.734** The TCL script in pDb->zTraceV2 is executed, with the arguments for735** the event appended to it (as list elements).736*/737static int DbTraceV2Handler(738  unsigned type, /* One of the SQLITE_TRACE_* event types. */739  void *cd,      /* The original context data pointer. */740  void *pd,      /* Primary event data, depends on event type. */741  void *xd       /* Extra event data, depends on event type. */742){743  SqliteDb *pDb = (SqliteDb*)cd;744  Tcl_Obj *pCmd;745 746  switch( type ){747    case SQLITE_TRACE_STMT: {748      sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;749      char *zSql = (char *)xd;750 751      pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);752      Tcl_IncrRefCount(pCmd);753      Tcl_ListObjAppendElement(pDb->interp, pCmd,754                               Tcl_NewWideIntObj((Tcl_WideInt)(uptr)pStmt));755      Tcl_ListObjAppendElement(pDb->interp, pCmd,756                               Tcl_NewStringObj(zSql, -1));757      Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);758      Tcl_DecrRefCount(pCmd);759      Tcl_ResetResult(pDb->interp);760      break;761    }762    case SQLITE_TRACE_PROFILE: {763      sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;764      sqlite3_int64 ns = *(sqlite3_int64*)xd;765 766      pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);767      Tcl_IncrRefCount(pCmd);768      Tcl_ListObjAppendElement(pDb->interp, pCmd,769                               Tcl_NewWideIntObj((Tcl_WideInt)(uptr)pStmt));770      Tcl_ListObjAppendElement(pDb->interp, pCmd,771                               Tcl_NewWideIntObj((Tcl_WideInt)ns));772      Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);773      Tcl_DecrRefCount(pCmd);774      Tcl_ResetResult(pDb->interp);775      break;776    }777    case SQLITE_TRACE_ROW: {778      sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;779 780      pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);781      Tcl_IncrRefCount(pCmd);782      Tcl_ListObjAppendElement(pDb->interp, pCmd,783                               Tcl_NewWideIntObj((Tcl_WideInt)(uptr)pStmt));784      Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);785      Tcl_DecrRefCount(pCmd);786      Tcl_ResetResult(pDb->interp);787      break;788    }789    case SQLITE_TRACE_CLOSE: {790      sqlite3 *db = (sqlite3 *)pd;791 792      pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);793      Tcl_IncrRefCount(pCmd);794      Tcl_ListObjAppendElement(pDb->interp, pCmd,795                               Tcl_NewWideIntObj((Tcl_WideInt)(uptr)db));796      Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);797      Tcl_DecrRefCount(pCmd);798      Tcl_ResetResult(pDb->interp);799      break;800    }801  }802  return SQLITE_OK;803}804#endif805 806#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \807    !defined(SQLITE_OMIT_DEPRECATED)808/*809** This routine is called by the SQLite profile handler after a statement810** SQL has executed.  The TCL script in pDb->zProfile is evaluated.811*/812static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){813  SqliteDb *pDb = (SqliteDb*)cd;814  Tcl_DString str;815  char zTm[100];816 817  sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm);818  Tcl_DStringInit(&str);819  Tcl_DStringAppend(&str, pDb->zProfile, -1);820  Tcl_DStringAppendElement(&str, zSql);821  Tcl_DStringAppendElement(&str, zTm);822  Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));823  Tcl_DStringFree(&str);824  Tcl_ResetResult(pDb->interp);825}826#endif827 828/*829** This routine is called when a transaction is committed.  The830** TCL script in pDb->zCommit is executed.  If it returns non-zero or831** if it throws an exception, the transaction is rolled back instead832** of being committed.833*/834static int DbCommitHandler(void *cd){835  SqliteDb *pDb = (SqliteDb*)cd;836  int rc;837 838  rc = Tcl_Eval(pDb->interp, pDb->zCommit);839  if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){840    return 1;841  }842  return 0;843}844 845static void DbRollbackHandler(void *clientData){846  SqliteDb *pDb = (SqliteDb*)clientData;847  assert(pDb->pRollbackHook);848  if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){849    Tcl_BackgroundError(pDb->interp);850  }851}852 853/*854** This procedure handles wal_hook callbacks.855*/856static int DbWalHandler(857  void *clientData,858  sqlite3 *db,859  const char *zDb,860  int nEntry861){862  int ret = SQLITE_OK;863  Tcl_Obj *p;864  SqliteDb *pDb = (SqliteDb*)clientData;865  Tcl_Interp *interp = pDb->interp;866  assert(pDb->pWalHook);867 868  assert( db==pDb->db );869  p = Tcl_DuplicateObj(pDb->pWalHook);870  Tcl_IncrRefCount(p);871  Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));872  Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));873  if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)874   || TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)875  ){876    Tcl_BackgroundError(interp);877  }878  Tcl_DecrRefCount(p);879 880  return ret;881}882 883#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)884static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){885  char zBuf[64];886  sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iArg);887  Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY);888  sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nArg);889  Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY);890}891#else892# define setTestUnlockNotifyVars(x,y,z)893#endif894 895#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY896static void DbUnlockNotify(void **apArg, int nArg){897  int i;898  for(i=0; i<nArg; i++){899    const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);900    SqliteDb *pDb = (SqliteDb *)apArg[i];901    setTestUnlockNotifyVars(pDb->interp, i, nArg);902    assert( pDb->pUnlockNotify);903    Tcl_EvalObjEx(pDb->interp, pDb->pUnlockNotify, flags);904    Tcl_DecrRefCount(pDb->pUnlockNotify);905    pDb->pUnlockNotify = 0;906  }907}908#endif909 910#ifdef SQLITE_ENABLE_PREUPDATE_HOOK911/*912** Pre-update hook callback.913*/914static void DbPreUpdateHandler(915  void *p,916  sqlite3 *db,917  int op,918  const char *zDb,919  const char *zTbl,920  sqlite_int64 iKey1,921  sqlite_int64 iKey2922){923  SqliteDb *pDb = (SqliteDb *)p;924  Tcl_Obj *pCmd;925  static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"};926 927  assert( (SQLITE_DELETE-1)/9 == 0 );928  assert( (SQLITE_INSERT-1)/9 == 1 );929  assert( (SQLITE_UPDATE-1)/9 == 2 );930  assert( pDb->pPreUpdateHook );931  assert( db==pDb->db );932  assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );933 934  pCmd = Tcl_DuplicateObj(pDb->pPreUpdateHook);935  Tcl_IncrRefCount(pCmd);936  Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(azStr[(op-1)/9], -1));937  Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1));938  Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1));939  Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey1));940  Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey2));941  Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);942  Tcl_DecrRefCount(pCmd);943}944#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */945 946static void DbUpdateHandler(947  void *p,948  int op,949  const char *zDb,950  const char *zTbl,951  sqlite_int64 rowid952){953  SqliteDb *pDb = (SqliteDb *)p;954  Tcl_Obj *pCmd;955  static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"};956 957  assert( (SQLITE_DELETE-1)/9 == 0 );958  assert( (SQLITE_INSERT-1)/9 == 1 );959  assert( (SQLITE_UPDATE-1)/9 == 2 );960 961  assert( pDb->pUpdateHook );962  assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );963 964  pCmd = Tcl_DuplicateObj(pDb->pUpdateHook);965  Tcl_IncrRefCount(pCmd);966  Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(azStr[(op-1)/9], -1));967  Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1));968  Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1));969  Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid));970  Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);971  Tcl_DecrRefCount(pCmd);972}973 974static void tclCollateNeeded(975  void *pCtx,976  sqlite3 *db,977  int enc,978  const char *zName979){980  SqliteDb *pDb = (SqliteDb *)pCtx;981  Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded);982  Tcl_IncrRefCount(pScript);983  Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1));984  Tcl_EvalObjEx(pDb->interp, pScript, 0);985  Tcl_DecrRefCount(pScript);986}987 988/*989** This routine is called to evaluate an SQL collation function implemented990** using TCL script.991*/992static int tclSqlCollate(993  void *pCtx,994  int nA,995  const void *zA,996  int nB,997  const void *zB998){999  SqlCollate *p = (SqlCollate *)pCtx;1000  Tcl_Obj *pCmd;1001 1002  pCmd = Tcl_NewStringObj(p->zScript, -1);1003  Tcl_IncrRefCount(pCmd);1004  Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA));1005  Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB));1006  Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT);1007  Tcl_DecrRefCount(pCmd);1008  return (atoi(Tcl_GetStringResult(p->interp)));1009}1010 1011/*1012** This routine is called to evaluate an SQL function implemented1013** using TCL script.1014*/1015static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){1016  SqlFunc *p = sqlite3_user_data(context);1017  Tcl_Obj *pCmd;1018  int i;1019  int rc;1020 1021  if( argc==0 ){1022    /* If there are no arguments to the function, call Tcl_EvalObjEx on the1023    ** script object directly.  This allows the TCL compiler to generate1024    ** bytecode for the command on the first invocation and thus make1025    ** subsequent invocations much faster. */1026    pCmd = p->pScript;1027    Tcl_IncrRefCount(pCmd);1028    rc = Tcl_EvalObjEx(p->interp, pCmd, 0);1029    Tcl_DecrRefCount(pCmd);1030  }else{1031    /* If there are arguments to the function, make a shallow copy of the1032    ** script object, lappend the arguments, then evaluate the copy.1033    **1034    ** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated.1035    ** The new Tcl_Obj contains pointers to the original list elements.1036    ** That way, when Tcl_EvalObjv() is run and shimmers the first element1037    ** of the list to tclCmdNameType, that alternate representation will1038    ** be preserved and reused on the next invocation.1039    */1040    Tcl_Obj **aArg;1041    Tcl_Size nArg;1042    if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){1043      sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);1044      return;1045    }1046    pCmd = Tcl_NewListObj(nArg, aArg);1047    Tcl_IncrRefCount(pCmd);1048    for(i=0; i<argc; i++){1049      sqlite3_value *pIn = argv[i];1050      Tcl_Obj *pVal;1051 1052      /* Set pVal to contain the i'th column of this row. */1053      switch( sqlite3_value_type(pIn) ){1054        case SQLITE_BLOB: {1055          int bytes = sqlite3_value_bytes(pIn);1056          pVal = Tcl_NewByteArrayObj(sqlite3_value_blob(pIn), bytes);1057          break;1058        }1059        case SQLITE_INTEGER: {1060          sqlite_int64 v = sqlite3_value_int64(pIn);1061          if( v>=-2147483647 && v<=2147483647 ){1062            pVal = Tcl_NewIntObj((int)v);1063          }else{1064            pVal = Tcl_NewWideIntObj(v);1065          }1066          break;1067        }1068        case SQLITE_FLOAT: {1069          double r = sqlite3_value_double(pIn);1070          pVal = Tcl_NewDoubleObj(r);1071          break;1072        }1073        case SQLITE_NULL: {1074          pVal = Tcl_NewStringObj(p->pDb->zNull, -1);1075          break;1076        }1077        default: {1078          int bytes = sqlite3_value_bytes(pIn);1079          pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes);1080          break;1081        }1082      }1083      rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal);1084      if( rc ){1085        Tcl_DecrRefCount(pCmd);1086        sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);1087        return;1088      }1089    }1090    if( !p->useEvalObjv ){1091      /* Tcl_EvalObjEx() will automatically call Tcl_EvalObjv() if pCmd1092      ** is a list without a string representation.  To prevent this from1093      ** happening, make sure pCmd has a valid string representation */1094      Tcl_GetString(pCmd);1095    }1096    rc = Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT);1097    Tcl_DecrRefCount(pCmd);1098  }1099 1100  if( TCL_BREAK==rc ){1101    sqlite3_result_null(context);1102  }else if( rc && rc!=TCL_RETURN ){1103    sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);1104  }else{1105    Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);1106    Tcl_Size n;1107    u8 *data;1108    const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");1109    char c = zType[0];1110    int eType = p->eType;1111 1112    if( eType==SQLITE_NULL ){1113      if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){1114        /* Only return a BLOB type if the Tcl variable is a bytearray and1115        ** has no string representation. */1116        eType = SQLITE_BLOB;1117      }else if( (c=='b' && pVar->bytes==0 && strcmp(zType,"boolean")==0 )1118             || (c=='b' && pVar->bytes==0 && strcmp(zType,"booleanString")==0 )1119             || (c=='w' && strcmp(zType,"wideInt")==0)1120             || (c=='i' && strcmp(zType,"int")==0)1121      ){1122        eType = SQLITE_INTEGER;1123      }else if( c=='d' && strcmp(zType,"double")==0 ){1124        eType = SQLITE_FLOAT;1125      }else{1126        eType = SQLITE_TEXT;1127      }1128    }1129 1130    switch( eType ){1131      case SQLITE_BLOB: {1132        data = Tcl_GetByteArrayFromObj(pVar, &n);1133        sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT);1134        break;1135      }1136      case SQLITE_INTEGER: {1137        Tcl_WideInt v;1138        if( TCL_OK==Tcl_GetWideIntFromObj(0, pVar, &v) ){1139          sqlite3_result_int64(context, v);1140          break;1141        }1142        /* fall-through */1143      }1144      case SQLITE_FLOAT: {1145        double r;1146        if( TCL_OK==Tcl_GetDoubleFromObj(0, pVar, &r) ){1147          sqlite3_result_double(context, r);1148          break;1149        }1150        /* fall-through */1151      }1152      default: {1153        data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);1154        sqlite3_result_text64(context, (char *)data, n, SQLITE_TRANSIENT,1155                              SQLITE_UTF8);1156        break;1157      }1158    }1159 1160  }1161}1162 1163#ifndef SQLITE_OMIT_AUTHORIZATION1164/*1165** This is the authentication function.  It appends the authentication1166** type code and the two arguments to zCmd[] then invokes the result1167** on the interpreter.  The reply is examined to determine if the1168** authentication fails or succeeds.1169*/1170static int auth_callback(1171  void *pArg,1172  int code,1173  const char *zArg1,1174  const char *zArg2,1175  const char *zArg3,1176  const char *zArg41177){1178  const char *zCode;1179  Tcl_DString str;1180  int rc;1181  const char *zReply;1182  /* EVIDENCE-OF: R-38590-62769 The first parameter to the authorizer1183  ** callback is a copy of the third parameter to the1184  ** sqlite3_set_authorizer() interface.1185  */1186  SqliteDb *pDb = (SqliteDb*)pArg;1187  if( pDb->disableAuth ) return SQLITE_OK;1188 1189  /* EVIDENCE-OF: R-56518-44310 The second parameter to the callback is an1190  ** integer action code that specifies the particular action to be1191  ** authorized. */1192  switch( code ){1193    case SQLITE_COPY              : zCode="SQLITE_COPY"; break;1194    case SQLITE_CREATE_INDEX      : zCode="SQLITE_CREATE_INDEX"; break;1195    case SQLITE_CREATE_TABLE      : zCode="SQLITE_CREATE_TABLE"; break;1196    case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;1197    case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;1198    case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;1199    case SQLITE_CREATE_TEMP_VIEW  : zCode="SQLITE_CREATE_TEMP_VIEW"; break;1200    case SQLITE_CREATE_TRIGGER    : zCode="SQLITE_CREATE_TRIGGER"; break;

Showing the first 1,200 of 4600 lines. Download the file for the rest.