175897234Sdrh /* 2b19a2bc6Sdrh ** 2001 September 15 375897234Sdrh ** 4b19a2bc6Sdrh ** The author disclaims copyright to this source code. In place of 5b19a2bc6Sdrh ** a legal notice, here is a blessing: 675897234Sdrh ** 7b19a2bc6Sdrh ** May you do good and not evil. 8b19a2bc6Sdrh ** May you find forgiveness for yourself and forgive others. 9b19a2bc6Sdrh ** May you share freely, never taking more than you give. 1075897234Sdrh ** 1175897234Sdrh ************************************************************************* 12bd08af48Sdrh ** A TCL Interface to SQLite. Append this file to sqlite3.c and 13bd08af48Sdrh ** compile the whole thing to build a TCL-enabled version of SQLite. 1457a0227fSdrh ** 1557a0227fSdrh ** Compile-time options: 1657a0227fSdrh ** 1796a206faSdrh ** -DTCLSH Add a "main()" routine that works as a tclsh. 1857a0227fSdrh ** 1996a206faSdrh ** -DTCLSH_INIT_PROC=name 2057a0227fSdrh ** 2196a206faSdrh ** Invoke name(interp) to initialize the Tcl interpreter. 2296a206faSdrh ** If name(interp) returns a non-NULL string, then run 2396a206faSdrh ** that string as a Tcl script to launch the application. 2496a206faSdrh ** If name(interp) returns NULL, then run the regular 2596a206faSdrh ** tclsh-emulator code. 2675897234Sdrh */ 2796a206faSdrh #ifdef TCLSH_INIT_PROC 2896a206faSdrh # define TCLSH 1 2996a206faSdrh #endif 3027b2f053Smistachkin 3127b2f053Smistachkin /* 3227b2f053Smistachkin ** If requested, include the SQLite compiler options file for MSVC. 3327b2f053Smistachkin */ 3427b2f053Smistachkin #if defined(INCLUDE_MSVC_H) 3527b2f053Smistachkin # include "msvc.h" 3627b2f053Smistachkin #endif 3727b2f053Smistachkin 3852b1dbb5Smistachkin #if defined(INCLUDE_SQLITE_TCL_H) 3952b1dbb5Smistachkin # include "sqlite_tcl.h" 4052b1dbb5Smistachkin #else 41bd08af48Sdrh # include "tcl.h" 427617e4a8Smistachkin # ifndef SQLITE_TCLAPI 437617e4a8Smistachkin # define SQLITE_TCLAPI 447617e4a8Smistachkin # endif 4552b1dbb5Smistachkin #endif 46b4e9af9fSdanielk1977 #include <errno.h> 476d31316cSdrh 48bd08af48Sdrh /* 49bd08af48Sdrh ** Some additional include files are needed if this file is not 50bd08af48Sdrh ** appended to the amalgamation. 51bd08af48Sdrh */ 52bd08af48Sdrh #ifndef SQLITE_AMALGAMATION 5365e8c82eSdrh # include "sqlite3.h" 5475897234Sdrh # include <stdlib.h> 5575897234Sdrh # include <string.h> 56ce927065Sdrh # include <assert.h> 5765e8c82eSdrh typedef unsigned char u8; 58bd08af48Sdrh #endif 59eb206381Sdrh #include <ctype.h> 6075897234Sdrh 611f28e070Smistachkin /* Used to get the current process ID */ 621f28e070Smistachkin #if !defined(_WIN32) 631e8487dbSmistachkin # include <signal.h> 641f28e070Smistachkin # include <unistd.h> 651f28e070Smistachkin # define GETPID getpid 661f28e070Smistachkin #elif !defined(_WIN32_WCE) 671f28e070Smistachkin # ifndef SQLITE_AMALGAMATION 68176b3a09Smistachkin # ifndef WIN32_LEAN_AND_MEAN 691f28e070Smistachkin # define WIN32_LEAN_AND_MEAN 70176b3a09Smistachkin # endif 711f28e070Smistachkin # include <windows.h> 721f28e070Smistachkin # endif 731e8487dbSmistachkin # include <io.h> 741e8487dbSmistachkin # define isatty(h) _isatty(h) 751f28e070Smistachkin # define GETPID (int)GetCurrentProcessId 761f28e070Smistachkin #endif 771f28e070Smistachkin 78ad6e1370Sdrh /* 79ad6e1370Sdrh * Windows needs to know which symbols to export. Unix does not. 80ad6e1370Sdrh * BUILD_sqlite should be undefined for Unix. 81ad6e1370Sdrh */ 82ad6e1370Sdrh #ifdef BUILD_sqlite 83ad6e1370Sdrh #undef TCL_STORAGE_CLASS 84ad6e1370Sdrh #define TCL_STORAGE_CLASS DLLEXPORT 85ad6e1370Sdrh #endif /* BUILD_sqlite */ 8629bc4615Sdrh 87a21c6b6fSdanielk1977 #define NUM_PREPARED_STMTS 10 88fb7e7651Sdrh #define MAX_PREPARED_STMTS 100 89fb7e7651Sdrh 90c45e6716Sdrh /* Forward declaration */ 91c45e6716Sdrh typedef struct SqliteDb SqliteDb; 9298808babSdrh 9398808babSdrh /* 94cabb0819Sdrh ** New SQL functions can be created as TCL scripts. Each such function 95cabb0819Sdrh ** is described by an instance of the following structure. 96cabb0819Sdrh */ 97cabb0819Sdrh typedef struct SqlFunc SqlFunc; 98cabb0819Sdrh struct SqlFunc { 99cabb0819Sdrh Tcl_Interp *interp; /* The TCL interpret to execute the function */ 100d1e4733dSdrh Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */ 101c45e6716Sdrh SqliteDb *pDb; /* Database connection that owns this function */ 102d1e4733dSdrh int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */ 103d1e4733dSdrh char *zName; /* Name of this function */ 104cabb0819Sdrh SqlFunc *pNext; /* Next function on the list of them all */ 105cabb0819Sdrh }; 106cabb0819Sdrh 107cabb0819Sdrh /* 1080202b29eSdanielk1977 ** New collation sequences function can be created as TCL scripts. Each such 1090202b29eSdanielk1977 ** function is described by an instance of the following structure. 1100202b29eSdanielk1977 */ 1110202b29eSdanielk1977 typedef struct SqlCollate SqlCollate; 1120202b29eSdanielk1977 struct SqlCollate { 1130202b29eSdanielk1977 Tcl_Interp *interp; /* The TCL interpret to execute the function */ 1140202b29eSdanielk1977 char *zScript; /* The script to be run */ 1150202b29eSdanielk1977 SqlCollate *pNext; /* Next function on the list of them all */ 1160202b29eSdanielk1977 }; 1170202b29eSdanielk1977 1180202b29eSdanielk1977 /* 119fb7e7651Sdrh ** Prepared statements are cached for faster execution. Each prepared 120fb7e7651Sdrh ** statement is described by an instance of the following structure. 121fb7e7651Sdrh */ 122fb7e7651Sdrh typedef struct SqlPreparedStmt SqlPreparedStmt; 123fb7e7651Sdrh struct SqlPreparedStmt { 124fb7e7651Sdrh SqlPreparedStmt *pNext; /* Next in linked list */ 125fb7e7651Sdrh SqlPreparedStmt *pPrev; /* Previous on the list */ 126fb7e7651Sdrh sqlite3_stmt *pStmt; /* The prepared statement */ 127fb7e7651Sdrh int nSql; /* chars in zSql[] */ 128d0e2a854Sdanielk1977 const char *zSql; /* Text of the SQL statement */ 1294a4c11aaSdan int nParm; /* Size of apParm array */ 1304a4c11aaSdan Tcl_Obj **apParm; /* Array of referenced object pointers */ 131fb7e7651Sdrh }; 132fb7e7651Sdrh 133d0441796Sdanielk1977 typedef struct IncrblobChannel IncrblobChannel; 134d0441796Sdanielk1977 135fb7e7651Sdrh /* 136bec3f402Sdrh ** There is one instance of this structure for each SQLite database 137bec3f402Sdrh ** that has been opened by the SQLite TCL interface. 138c431fd55Sdan ** 139c431fd55Sdan ** If this module is built with SQLITE_TEST defined (to create the SQLite 140c431fd55Sdan ** testfixture executable), then it may be configured to use either 141c431fd55Sdan ** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements. 142c431fd55Sdan ** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used. 143bec3f402Sdrh */ 144bec3f402Sdrh struct SqliteDb { 145dddca286Sdrh sqlite3 *db; /* The "real" database structure. MUST BE FIRST */ 146bec3f402Sdrh Tcl_Interp *interp; /* The interpreter used for this database */ 1476d31316cSdrh char *zBusy; /* The busy callback routine */ 148aa940eacSdrh char *zCommit; /* The commit hook callback routine */ 149b5a20d3cSdrh char *zTrace; /* The trace callback routine */ 150b56660f5Smistachkin char *zTraceV2; /* The trace_v2 callback routine */ 15119e2d37fSdrh char *zProfile; /* The profile callback routine */ 152348bb5d6Sdanielk1977 char *zProgress; /* The progress callback routine */ 153e22a334bSdrh char *zAuth; /* The authorization callback routine */ 1541f1549f8Sdrh int disableAuth; /* Disable the authorizer if it exists */ 15555c45f2eSdanielk1977 char *zNull; /* Text to substitute for an SQL NULL value */ 156cabb0819Sdrh SqlFunc *pFunc; /* List of SQL functions */ 15794eb6a14Sdanielk1977 Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ 15846c47d46Sdan Tcl_Obj *pPreUpdateHook; /* Pre-update hook script (if any) */ 15971fd80bfSdanielk1977 Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ 1605def0843Sdrh Tcl_Obj *pWalHook; /* WAL hook script (if any) */ 161404ca075Sdanielk1977 Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */ 1620202b29eSdanielk1977 SqlCollate *pCollate; /* List of SQL collation functions */ 1636f8a503dSdanielk1977 int rc; /* Return code of most recent sqlite3_exec() */ 1647cedc8d4Sdanielk1977 Tcl_Obj *pCollateNeeded; /* Collation needed script */ 165fb7e7651Sdrh SqlPreparedStmt *stmtList; /* List of prepared statements*/ 166fb7e7651Sdrh SqlPreparedStmt *stmtLast; /* Last statement in the list */ 167fb7e7651Sdrh int maxStmt; /* The next maximum number of stmtList */ 168fb7e7651Sdrh int nStmt; /* Number of statements in stmtList */ 169d0441796Sdanielk1977 IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ 1703c379b01Sdrh int nStep, nSort, nIndex; /* Statistics for most recent operation */ 171c456a76fSdan int nVMStep; /* Another statistic for most recent operation */ 172cd38d520Sdanielk1977 int nTransaction; /* Number of nested [transaction] methods */ 173147ef394Sdrh int openFlags; /* Flags used to open. (SQLITE_OPEN_URI) */ 174c431fd55Sdan #ifdef SQLITE_TEST 175c431fd55Sdan int bLegacyPrepare; /* True to use sqlite3_prepare() */ 176c431fd55Sdan #endif 17798808babSdrh }; 178297ecf14Sdrh 179b4e9af9fSdanielk1977 struct IncrblobChannel { 180d0441796Sdanielk1977 sqlite3_blob *pBlob; /* sqlite3 blob handle */ 181dcbb5d3fSdanielk1977 SqliteDb *pDb; /* Associated database connection */ 182b4e9af9fSdanielk1977 int iSeek; /* Current seek offset */ 183d0441796Sdanielk1977 Tcl_Channel channel; /* Channel identifier */ 184d0441796Sdanielk1977 IncrblobChannel *pNext; /* Linked list of all open incrblob channels */ 185d0441796Sdanielk1977 IncrblobChannel *pPrev; /* Linked list of all open incrblob channels */ 186b4e9af9fSdanielk1977 }; 187b4e9af9fSdanielk1977 188ea678832Sdrh /* 189ea678832Sdrh ** Compute a string length that is limited to what can be stored in 190ea678832Sdrh ** lower 30 bits of a 32-bit signed integer. 191ea678832Sdrh */ 1924f21c4afSdrh static int strlen30(const char *z){ 193ea678832Sdrh const char *z2 = z; 194ea678832Sdrh while( *z2 ){ z2++; } 195ea678832Sdrh return 0x3fffffff & (int)(z2 - z); 196ea678832Sdrh } 197ea678832Sdrh 198ea678832Sdrh 19932a0d8bbSdanielk1977 #ifndef SQLITE_OMIT_INCRBLOB 200b4e9af9fSdanielk1977 /* 201d0441796Sdanielk1977 ** Close all incrblob channels opened using database connection pDb. 202d0441796Sdanielk1977 ** This is called when shutting down the database connection. 203d0441796Sdanielk1977 */ 204d0441796Sdanielk1977 static void closeIncrblobChannels(SqliteDb *pDb){ 205d0441796Sdanielk1977 IncrblobChannel *p; 206d0441796Sdanielk1977 IncrblobChannel *pNext; 207d0441796Sdanielk1977 208d0441796Sdanielk1977 for(p=pDb->pIncrblob; p; p=pNext){ 209d0441796Sdanielk1977 pNext = p->pNext; 210d0441796Sdanielk1977 211d0441796Sdanielk1977 /* Note: Calling unregister here call Tcl_Close on the incrblob channel, 212d0441796Sdanielk1977 ** which deletes the IncrblobChannel structure at *p. So do not 213d0441796Sdanielk1977 ** call Tcl_Free() here. 214d0441796Sdanielk1977 */ 215d0441796Sdanielk1977 Tcl_UnregisterChannel(pDb->interp, p->channel); 216d0441796Sdanielk1977 } 217d0441796Sdanielk1977 } 218d0441796Sdanielk1977 219d0441796Sdanielk1977 /* 220b4e9af9fSdanielk1977 ** Close an incremental blob channel. 221b4e9af9fSdanielk1977 */ 2227617e4a8Smistachkin static int SQLITE_TCLAPI incrblobClose( 2237617e4a8Smistachkin ClientData instanceData, 2247617e4a8Smistachkin Tcl_Interp *interp 2257617e4a8Smistachkin ){ 226b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 22792d4d7a9Sdanielk1977 int rc = sqlite3_blob_close(p->pBlob); 22892d4d7a9Sdanielk1977 sqlite3 *db = p->pDb->db; 229d0441796Sdanielk1977 230d0441796Sdanielk1977 /* Remove the channel from the SqliteDb.pIncrblob list. */ 231d0441796Sdanielk1977 if( p->pNext ){ 232d0441796Sdanielk1977 p->pNext->pPrev = p->pPrev; 233d0441796Sdanielk1977 } 234d0441796Sdanielk1977 if( p->pPrev ){ 235d0441796Sdanielk1977 p->pPrev->pNext = p->pNext; 236d0441796Sdanielk1977 } 237d0441796Sdanielk1977 if( p->pDb->pIncrblob==p ){ 238d0441796Sdanielk1977 p->pDb->pIncrblob = p->pNext; 239d0441796Sdanielk1977 } 240d0441796Sdanielk1977 24192d4d7a9Sdanielk1977 /* Free the IncrblobChannel structure */ 242b4e9af9fSdanielk1977 Tcl_Free((char *)p); 24392d4d7a9Sdanielk1977 24492d4d7a9Sdanielk1977 if( rc!=SQLITE_OK ){ 24592d4d7a9Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE); 24692d4d7a9Sdanielk1977 return TCL_ERROR; 24792d4d7a9Sdanielk1977 } 248b4e9af9fSdanielk1977 return TCL_OK; 249b4e9af9fSdanielk1977 } 250b4e9af9fSdanielk1977 251b4e9af9fSdanielk1977 /* 252b4e9af9fSdanielk1977 ** Read data from an incremental blob channel. 253b4e9af9fSdanielk1977 */ 2547617e4a8Smistachkin static int SQLITE_TCLAPI incrblobInput( 255b4e9af9fSdanielk1977 ClientData instanceData, 256b4e9af9fSdanielk1977 char *buf, 257b4e9af9fSdanielk1977 int bufSize, 258b4e9af9fSdanielk1977 int *errorCodePtr 259b4e9af9fSdanielk1977 ){ 260b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 261b4e9af9fSdanielk1977 int nRead = bufSize; /* Number of bytes to read */ 262b4e9af9fSdanielk1977 int nBlob; /* Total size of the blob */ 263b4e9af9fSdanielk1977 int rc; /* sqlite error code */ 264b4e9af9fSdanielk1977 265b4e9af9fSdanielk1977 nBlob = sqlite3_blob_bytes(p->pBlob); 266b4e9af9fSdanielk1977 if( (p->iSeek+nRead)>nBlob ){ 267b4e9af9fSdanielk1977 nRead = nBlob-p->iSeek; 268b4e9af9fSdanielk1977 } 269b4e9af9fSdanielk1977 if( nRead<=0 ){ 270b4e9af9fSdanielk1977 return 0; 271b4e9af9fSdanielk1977 } 272b4e9af9fSdanielk1977 273b4e9af9fSdanielk1977 rc = sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek); 274b4e9af9fSdanielk1977 if( rc!=SQLITE_OK ){ 275b4e9af9fSdanielk1977 *errorCodePtr = rc; 276b4e9af9fSdanielk1977 return -1; 277b4e9af9fSdanielk1977 } 278b4e9af9fSdanielk1977 279b4e9af9fSdanielk1977 p->iSeek += nRead; 280b4e9af9fSdanielk1977 return nRead; 281b4e9af9fSdanielk1977 } 282b4e9af9fSdanielk1977 283d0441796Sdanielk1977 /* 284d0441796Sdanielk1977 ** Write data to an incremental blob channel. 285d0441796Sdanielk1977 */ 2867617e4a8Smistachkin static int SQLITE_TCLAPI incrblobOutput( 287b4e9af9fSdanielk1977 ClientData instanceData, 288b4e9af9fSdanielk1977 CONST char *buf, 289b4e9af9fSdanielk1977 int toWrite, 290b4e9af9fSdanielk1977 int *errorCodePtr 291b4e9af9fSdanielk1977 ){ 292b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 293b4e9af9fSdanielk1977 int nWrite = toWrite; /* Number of bytes to write */ 294b4e9af9fSdanielk1977 int nBlob; /* Total size of the blob */ 295b4e9af9fSdanielk1977 int rc; /* sqlite error code */ 296b4e9af9fSdanielk1977 297b4e9af9fSdanielk1977 nBlob = sqlite3_blob_bytes(p->pBlob); 298b4e9af9fSdanielk1977 if( (p->iSeek+nWrite)>nBlob ){ 299b4e9af9fSdanielk1977 *errorCodePtr = EINVAL; 300b4e9af9fSdanielk1977 return -1; 301b4e9af9fSdanielk1977 } 302b4e9af9fSdanielk1977 if( nWrite<=0 ){ 303b4e9af9fSdanielk1977 return 0; 304b4e9af9fSdanielk1977 } 305b4e9af9fSdanielk1977 306b4e9af9fSdanielk1977 rc = sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek); 307b4e9af9fSdanielk1977 if( rc!=SQLITE_OK ){ 308b4e9af9fSdanielk1977 *errorCodePtr = EIO; 309b4e9af9fSdanielk1977 return -1; 310b4e9af9fSdanielk1977 } 311b4e9af9fSdanielk1977 312b4e9af9fSdanielk1977 p->iSeek += nWrite; 313b4e9af9fSdanielk1977 return nWrite; 314b4e9af9fSdanielk1977 } 315b4e9af9fSdanielk1977 316b4e9af9fSdanielk1977 /* 317b4e9af9fSdanielk1977 ** Seek an incremental blob channel. 318b4e9af9fSdanielk1977 */ 3197617e4a8Smistachkin static int SQLITE_TCLAPI incrblobSeek( 320b4e9af9fSdanielk1977 ClientData instanceData, 321b4e9af9fSdanielk1977 long offset, 322b4e9af9fSdanielk1977 int seekMode, 323b4e9af9fSdanielk1977 int *errorCodePtr 324b4e9af9fSdanielk1977 ){ 325b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 326b4e9af9fSdanielk1977 327b4e9af9fSdanielk1977 switch( seekMode ){ 328b4e9af9fSdanielk1977 case SEEK_SET: 329b4e9af9fSdanielk1977 p->iSeek = offset; 330b4e9af9fSdanielk1977 break; 331b4e9af9fSdanielk1977 case SEEK_CUR: 332b4e9af9fSdanielk1977 p->iSeek += offset; 333b4e9af9fSdanielk1977 break; 334b4e9af9fSdanielk1977 case SEEK_END: 335b4e9af9fSdanielk1977 p->iSeek = sqlite3_blob_bytes(p->pBlob) + offset; 336b4e9af9fSdanielk1977 break; 337b4e9af9fSdanielk1977 338b4e9af9fSdanielk1977 default: assert(!"Bad seekMode"); 339b4e9af9fSdanielk1977 } 340b4e9af9fSdanielk1977 341b4e9af9fSdanielk1977 return p->iSeek; 342b4e9af9fSdanielk1977 } 343b4e9af9fSdanielk1977 344b4e9af9fSdanielk1977 3457617e4a8Smistachkin static void SQLITE_TCLAPI incrblobWatch( 3467617e4a8Smistachkin ClientData instanceData, 3477617e4a8Smistachkin int mode 3487617e4a8Smistachkin ){ 349b4e9af9fSdanielk1977 /* NO-OP */ 350b4e9af9fSdanielk1977 } 3517617e4a8Smistachkin static int SQLITE_TCLAPI incrblobHandle( 3527617e4a8Smistachkin ClientData instanceData, 3537617e4a8Smistachkin int dir, 3547617e4a8Smistachkin ClientData *hPtr 3557617e4a8Smistachkin ){ 356b4e9af9fSdanielk1977 return TCL_ERROR; 357b4e9af9fSdanielk1977 } 358b4e9af9fSdanielk1977 359b4e9af9fSdanielk1977 static Tcl_ChannelType IncrblobChannelType = { 360b4e9af9fSdanielk1977 "incrblob", /* typeName */ 361b4e9af9fSdanielk1977 TCL_CHANNEL_VERSION_2, /* version */ 362b4e9af9fSdanielk1977 incrblobClose, /* closeProc */ 363b4e9af9fSdanielk1977 incrblobInput, /* inputProc */ 364b4e9af9fSdanielk1977 incrblobOutput, /* outputProc */ 365b4e9af9fSdanielk1977 incrblobSeek, /* seekProc */ 366b4e9af9fSdanielk1977 0, /* setOptionProc */ 367b4e9af9fSdanielk1977 0, /* getOptionProc */ 368b4e9af9fSdanielk1977 incrblobWatch, /* watchProc (this is a no-op) */ 369b4e9af9fSdanielk1977 incrblobHandle, /* getHandleProc (always returns error) */ 370b4e9af9fSdanielk1977 0, /* close2Proc */ 371b4e9af9fSdanielk1977 0, /* blockModeProc */ 372b4e9af9fSdanielk1977 0, /* flushProc */ 373b4e9af9fSdanielk1977 0, /* handlerProc */ 374b4e9af9fSdanielk1977 0, /* wideSeekProc */ 375b4e9af9fSdanielk1977 }; 376b4e9af9fSdanielk1977 377b4e9af9fSdanielk1977 /* 378b4e9af9fSdanielk1977 ** Create a new incrblob channel. 379b4e9af9fSdanielk1977 */ 380b4e9af9fSdanielk1977 static int createIncrblobChannel( 381b4e9af9fSdanielk1977 Tcl_Interp *interp, 382b4e9af9fSdanielk1977 SqliteDb *pDb, 383b4e9af9fSdanielk1977 const char *zDb, 384b4e9af9fSdanielk1977 const char *zTable, 385b4e9af9fSdanielk1977 const char *zColumn, 3868cbadb02Sdanielk1977 sqlite_int64 iRow, 3878cbadb02Sdanielk1977 int isReadonly 388b4e9af9fSdanielk1977 ){ 389b4e9af9fSdanielk1977 IncrblobChannel *p; 3908cbadb02Sdanielk1977 sqlite3 *db = pDb->db; 391b4e9af9fSdanielk1977 sqlite3_blob *pBlob; 392b4e9af9fSdanielk1977 int rc; 3938cbadb02Sdanielk1977 int flags = TCL_READABLE|(isReadonly ? 0 : TCL_WRITABLE); 394b4e9af9fSdanielk1977 395b4e9af9fSdanielk1977 /* This variable is used to name the channels: "incrblob_[incr count]" */ 396b4e9af9fSdanielk1977 static int count = 0; 397b4e9af9fSdanielk1977 char zChannel[64]; 398b4e9af9fSdanielk1977 3998cbadb02Sdanielk1977 rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob); 400b4e9af9fSdanielk1977 if( rc!=SQLITE_OK ){ 401b4e9af9fSdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 402b4e9af9fSdanielk1977 return TCL_ERROR; 403b4e9af9fSdanielk1977 } 404b4e9af9fSdanielk1977 405b4e9af9fSdanielk1977 p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel)); 406b4e9af9fSdanielk1977 p->iSeek = 0; 407b4e9af9fSdanielk1977 p->pBlob = pBlob; 408b4e9af9fSdanielk1977 4095bb3eb9bSdrh sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count); 410d0441796Sdanielk1977 p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags); 411d0441796Sdanielk1977 Tcl_RegisterChannel(interp, p->channel); 412b4e9af9fSdanielk1977 413d0441796Sdanielk1977 /* Link the new channel into the SqliteDb.pIncrblob list. */ 414d0441796Sdanielk1977 p->pNext = pDb->pIncrblob; 415d0441796Sdanielk1977 p->pPrev = 0; 416d0441796Sdanielk1977 if( p->pNext ){ 417d0441796Sdanielk1977 p->pNext->pPrev = p; 418d0441796Sdanielk1977 } 419d0441796Sdanielk1977 pDb->pIncrblob = p; 420d0441796Sdanielk1977 p->pDb = pDb; 421d0441796Sdanielk1977 422d0441796Sdanielk1977 Tcl_SetResult(interp, (char *)Tcl_GetChannelName(p->channel), TCL_VOLATILE); 423b4e9af9fSdanielk1977 return TCL_OK; 424b4e9af9fSdanielk1977 } 42532a0d8bbSdanielk1977 #else /* else clause for "#ifndef SQLITE_OMIT_INCRBLOB" */ 42632a0d8bbSdanielk1977 #define closeIncrblobChannels(pDb) 42732a0d8bbSdanielk1977 #endif 428b4e9af9fSdanielk1977 4296d31316cSdrh /* 430d1e4733dSdrh ** Look at the script prefix in pCmd. We will be executing this script 431d1e4733dSdrh ** after first appending one or more arguments. This routine analyzes 432d1e4733dSdrh ** the script to see if it is safe to use Tcl_EvalObjv() on the script 433d1e4733dSdrh ** rather than the more general Tcl_EvalEx(). Tcl_EvalObjv() is much 434d1e4733dSdrh ** faster. 435d1e4733dSdrh ** 436d1e4733dSdrh ** Scripts that are safe to use with Tcl_EvalObjv() consists of a 437d1e4733dSdrh ** command name followed by zero or more arguments with no [...] or $ 438d1e4733dSdrh ** or {...} or ; to be seen anywhere. Most callback scripts consist 439d1e4733dSdrh ** of just a single procedure name and they meet this requirement. 440d1e4733dSdrh */ 441d1e4733dSdrh static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){ 442d1e4733dSdrh /* We could try to do something with Tcl_Parse(). But we will instead 443d1e4733dSdrh ** just do a search for forbidden characters. If any of the forbidden 444d1e4733dSdrh ** characters appear in pCmd, we will report the string as unsafe. 445d1e4733dSdrh */ 446d1e4733dSdrh const char *z; 447d1e4733dSdrh int n; 448d1e4733dSdrh z = Tcl_GetStringFromObj(pCmd, &n); 449d1e4733dSdrh while( n-- > 0 ){ 450d1e4733dSdrh int c = *(z++); 451d1e4733dSdrh if( c=='$' || c=='[' || c==';' ) return 0; 452d1e4733dSdrh } 453d1e4733dSdrh return 1; 454d1e4733dSdrh } 455d1e4733dSdrh 456d1e4733dSdrh /* 457d1e4733dSdrh ** Find an SqlFunc structure with the given name. Or create a new 458d1e4733dSdrh ** one if an existing one cannot be found. Return a pointer to the 459d1e4733dSdrh ** structure. 460d1e4733dSdrh */ 461d1e4733dSdrh static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ 462d1e4733dSdrh SqlFunc *p, *pNew; 4630425f189Sdrh int nName = strlen30(zName); 4640425f189Sdrh pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 ); 465d1e4733dSdrh pNew->zName = (char*)&pNew[1]; 4660425f189Sdrh memcpy(pNew->zName, zName, nName+1); 467d1e4733dSdrh for(p=pDb->pFunc; p; p=p->pNext){ 4680425f189Sdrh if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){ 469d1e4733dSdrh Tcl_Free((char*)pNew); 470d1e4733dSdrh return p; 471d1e4733dSdrh } 472d1e4733dSdrh } 473d1e4733dSdrh pNew->interp = pDb->interp; 474c45e6716Sdrh pNew->pDb = pDb; 475d1e4733dSdrh pNew->pScript = 0; 476d1e4733dSdrh pNew->pNext = pDb->pFunc; 477d1e4733dSdrh pDb->pFunc = pNew; 478d1e4733dSdrh return pNew; 479d1e4733dSdrh } 480d1e4733dSdrh 481d1e4733dSdrh /* 482c431fd55Sdan ** Free a single SqlPreparedStmt object. 483c431fd55Sdan */ 484c431fd55Sdan static void dbFreeStmt(SqlPreparedStmt *pStmt){ 485c431fd55Sdan #ifdef SQLITE_TEST 486c431fd55Sdan if( sqlite3_sql(pStmt->pStmt)==0 ){ 487c431fd55Sdan Tcl_Free((char *)pStmt->zSql); 488c431fd55Sdan } 489c431fd55Sdan #endif 490c431fd55Sdan sqlite3_finalize(pStmt->pStmt); 491c431fd55Sdan Tcl_Free((char *)pStmt); 492c431fd55Sdan } 493c431fd55Sdan 494c431fd55Sdan /* 495fb7e7651Sdrh ** Finalize and free a list of prepared statements 496fb7e7651Sdrh */ 497fb7e7651Sdrh static void flushStmtCache(SqliteDb *pDb){ 498fb7e7651Sdrh SqlPreparedStmt *pPreStmt; 499c431fd55Sdan SqlPreparedStmt *pNext; 500fb7e7651Sdrh 501c431fd55Sdan for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pNext){ 502c431fd55Sdan pNext = pPreStmt->pNext; 503c431fd55Sdan dbFreeStmt(pPreStmt); 504fb7e7651Sdrh } 505fb7e7651Sdrh pDb->nStmt = 0; 506fb7e7651Sdrh pDb->stmtLast = 0; 507c431fd55Sdan pDb->stmtList = 0; 508fb7e7651Sdrh } 509fb7e7651Sdrh 510fb7e7651Sdrh /* 511895d7472Sdrh ** TCL calls this procedure when an sqlite3 database command is 512895d7472Sdrh ** deleted. 51375897234Sdrh */ 5147617e4a8Smistachkin static void SQLITE_TCLAPI DbDeleteCmd(void *db){ 515bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)db; 516fb7e7651Sdrh flushStmtCache(pDb); 517d0441796Sdanielk1977 closeIncrblobChannels(pDb); 5186f8a503dSdanielk1977 sqlite3_close(pDb->db); 519cabb0819Sdrh while( pDb->pFunc ){ 520cabb0819Sdrh SqlFunc *pFunc = pDb->pFunc; 521cabb0819Sdrh pDb->pFunc = pFunc->pNext; 522c45e6716Sdrh assert( pFunc->pDb==pDb ); 523d1e4733dSdrh Tcl_DecrRefCount(pFunc->pScript); 524cabb0819Sdrh Tcl_Free((char*)pFunc); 525cabb0819Sdrh } 5260202b29eSdanielk1977 while( pDb->pCollate ){ 5270202b29eSdanielk1977 SqlCollate *pCollate = pDb->pCollate; 5280202b29eSdanielk1977 pDb->pCollate = pCollate->pNext; 5290202b29eSdanielk1977 Tcl_Free((char*)pCollate); 5300202b29eSdanielk1977 } 531bec3f402Sdrh if( pDb->zBusy ){ 532bec3f402Sdrh Tcl_Free(pDb->zBusy); 533bec3f402Sdrh } 534b5a20d3cSdrh if( pDb->zTrace ){ 535b5a20d3cSdrh Tcl_Free(pDb->zTrace); 5360d1a643aSdrh } 537b56660f5Smistachkin if( pDb->zTraceV2 ){ 538b56660f5Smistachkin Tcl_Free(pDb->zTraceV2); 539b56660f5Smistachkin } 54019e2d37fSdrh if( pDb->zProfile ){ 54119e2d37fSdrh Tcl_Free(pDb->zProfile); 54219e2d37fSdrh } 543e22a334bSdrh if( pDb->zAuth ){ 544e22a334bSdrh Tcl_Free(pDb->zAuth); 545e22a334bSdrh } 54655c45f2eSdanielk1977 if( pDb->zNull ){ 54755c45f2eSdanielk1977 Tcl_Free(pDb->zNull); 54855c45f2eSdanielk1977 } 54994eb6a14Sdanielk1977 if( pDb->pUpdateHook ){ 55094eb6a14Sdanielk1977 Tcl_DecrRefCount(pDb->pUpdateHook); 55194eb6a14Sdanielk1977 } 55246c47d46Sdan if( pDb->pPreUpdateHook ){ 55346c47d46Sdan Tcl_DecrRefCount(pDb->pPreUpdateHook); 55446c47d46Sdan } 55571fd80bfSdanielk1977 if( pDb->pRollbackHook ){ 55671fd80bfSdanielk1977 Tcl_DecrRefCount(pDb->pRollbackHook); 55771fd80bfSdanielk1977 } 5585def0843Sdrh if( pDb->pWalHook ){ 5595def0843Sdrh Tcl_DecrRefCount(pDb->pWalHook); 5608d22a174Sdan } 56194eb6a14Sdanielk1977 if( pDb->pCollateNeeded ){ 56294eb6a14Sdanielk1977 Tcl_DecrRefCount(pDb->pCollateNeeded); 56394eb6a14Sdanielk1977 } 564bec3f402Sdrh Tcl_Free((char*)pDb); 565bec3f402Sdrh } 566bec3f402Sdrh 567bec3f402Sdrh /* 568bec3f402Sdrh ** This routine is called when a database file is locked while trying 569bec3f402Sdrh ** to execute SQL. 570bec3f402Sdrh */ 5712a764eb0Sdanielk1977 static int DbBusyHandler(void *cd, int nTries){ 572bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 573bec3f402Sdrh int rc; 574bec3f402Sdrh char zVal[30]; 575bec3f402Sdrh 5765bb3eb9bSdrh sqlite3_snprintf(sizeof(zVal), zVal, "%d", nTries); 577d1e4733dSdrh rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0); 578bec3f402Sdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 579bec3f402Sdrh return 0; 580bec3f402Sdrh } 581bec3f402Sdrh return 1; 58275897234Sdrh } 58375897234Sdrh 58426e4a8b1Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK 58575897234Sdrh /* 586348bb5d6Sdanielk1977 ** This routine is invoked as the 'progress callback' for the database. 587348bb5d6Sdanielk1977 */ 588348bb5d6Sdanielk1977 static int DbProgressHandler(void *cd){ 589348bb5d6Sdanielk1977 SqliteDb *pDb = (SqliteDb*)cd; 590348bb5d6Sdanielk1977 int rc; 591348bb5d6Sdanielk1977 592348bb5d6Sdanielk1977 assert( pDb->zProgress ); 593348bb5d6Sdanielk1977 rc = Tcl_Eval(pDb->interp, pDb->zProgress); 594348bb5d6Sdanielk1977 if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 595348bb5d6Sdanielk1977 return 1; 596348bb5d6Sdanielk1977 } 597348bb5d6Sdanielk1977 return 0; 598348bb5d6Sdanielk1977 } 59926e4a8b1Sdrh #endif 600348bb5d6Sdanielk1977 6012eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 6022eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 603348bb5d6Sdanielk1977 /* 604b5a20d3cSdrh ** This routine is called by the SQLite trace handler whenever a new 605b5a20d3cSdrh ** block of SQL is executed. The TCL script in pDb->zTrace is executed. 6060d1a643aSdrh */ 607b5a20d3cSdrh static void DbTraceHandler(void *cd, const char *zSql){ 6080d1a643aSdrh SqliteDb *pDb = (SqliteDb*)cd; 609b5a20d3cSdrh Tcl_DString str; 6100d1a643aSdrh 611b5a20d3cSdrh Tcl_DStringInit(&str); 612b5a20d3cSdrh Tcl_DStringAppend(&str, pDb->zTrace, -1); 613b5a20d3cSdrh Tcl_DStringAppendElement(&str, zSql); 614b5a20d3cSdrh Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); 615b5a20d3cSdrh Tcl_DStringFree(&str); 616b5a20d3cSdrh Tcl_ResetResult(pDb->interp); 6170d1a643aSdrh } 618d1167393Sdrh #endif 6190d1a643aSdrh 620d1167393Sdrh #ifndef SQLITE_OMIT_TRACE 6210d1a643aSdrh /* 622b56660f5Smistachkin ** This routine is called by the SQLite trace_v2 handler whenever a new 623b56660f5Smistachkin ** supported event is generated. Unsupported event types are ignored. 624b56660f5Smistachkin ** The TCL script in pDb->zTraceV2 is executed, with the arguments for 625b56660f5Smistachkin ** the event appended to it (as list elements). 626b56660f5Smistachkin */ 627b56660f5Smistachkin static int DbTraceV2Handler( 628b56660f5Smistachkin unsigned type, /* One of the SQLITE_TRACE_* event types. */ 629b56660f5Smistachkin void *cd, /* The original context data pointer. */ 630b56660f5Smistachkin void *pd, /* Primary event data, depends on event type. */ 631b56660f5Smistachkin void *xd /* Extra event data, depends on event type. */ 632b56660f5Smistachkin ){ 633b56660f5Smistachkin SqliteDb *pDb = (SqliteDb*)cd; 634b56660f5Smistachkin Tcl_Obj *pCmd; 635b56660f5Smistachkin 636b56660f5Smistachkin switch( type ){ 637b56660f5Smistachkin case SQLITE_TRACE_STMT: { 638b56660f5Smistachkin sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; 639b56660f5Smistachkin char *zSql = (char *)xd; 640b56660f5Smistachkin 641b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 642b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 643b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 644b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); 645b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 646b56660f5Smistachkin Tcl_NewStringObj(zSql, -1)); 647b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 648b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 649b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 650b56660f5Smistachkin break; 651b56660f5Smistachkin } 652b56660f5Smistachkin case SQLITE_TRACE_PROFILE: { 653b56660f5Smistachkin sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; 654ffdab721Sdrh sqlite3_int64 ns = *(sqlite3_int64*)xd; 655b56660f5Smistachkin 656b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 657b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 658b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 659b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); 660b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 661b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)ns)); 662b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 663b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 664b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 665b56660f5Smistachkin break; 666b56660f5Smistachkin } 667b56660f5Smistachkin case SQLITE_TRACE_ROW: { 668b56660f5Smistachkin sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; 669b56660f5Smistachkin 670b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 671b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 672b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 673b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); 674b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 675b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 676b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 677b56660f5Smistachkin break; 678b56660f5Smistachkin } 679b56660f5Smistachkin case SQLITE_TRACE_CLOSE: { 680b56660f5Smistachkin sqlite3 *db = (sqlite3 *)pd; 681b56660f5Smistachkin 682b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 683b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 684b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 685b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)db)); 686b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 687b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 688b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 689b56660f5Smistachkin break; 690b56660f5Smistachkin } 691b56660f5Smistachkin } 692b56660f5Smistachkin return SQLITE_OK; 693b56660f5Smistachkin } 694b56660f5Smistachkin #endif 695b56660f5Smistachkin 6962eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 6972eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 698b56660f5Smistachkin /* 69919e2d37fSdrh ** This routine is called by the SQLite profile handler after a statement 70019e2d37fSdrh ** SQL has executed. The TCL script in pDb->zProfile is evaluated. 70119e2d37fSdrh */ 70219e2d37fSdrh static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){ 70319e2d37fSdrh SqliteDb *pDb = (SqliteDb*)cd; 70419e2d37fSdrh Tcl_DString str; 70519e2d37fSdrh char zTm[100]; 70619e2d37fSdrh 70719e2d37fSdrh sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm); 70819e2d37fSdrh Tcl_DStringInit(&str); 70919e2d37fSdrh Tcl_DStringAppend(&str, pDb->zProfile, -1); 71019e2d37fSdrh Tcl_DStringAppendElement(&str, zSql); 71119e2d37fSdrh Tcl_DStringAppendElement(&str, zTm); 71219e2d37fSdrh Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); 71319e2d37fSdrh Tcl_DStringFree(&str); 71419e2d37fSdrh Tcl_ResetResult(pDb->interp); 71519e2d37fSdrh } 716d1167393Sdrh #endif 71719e2d37fSdrh 71819e2d37fSdrh /* 719aa940eacSdrh ** This routine is called when a transaction is committed. The 720aa940eacSdrh ** TCL script in pDb->zCommit is executed. If it returns non-zero or 721aa940eacSdrh ** if it throws an exception, the transaction is rolled back instead 722aa940eacSdrh ** of being committed. 723aa940eacSdrh */ 724aa940eacSdrh static int DbCommitHandler(void *cd){ 725aa940eacSdrh SqliteDb *pDb = (SqliteDb*)cd; 726aa940eacSdrh int rc; 727aa940eacSdrh 728aa940eacSdrh rc = Tcl_Eval(pDb->interp, pDb->zCommit); 729aa940eacSdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 730aa940eacSdrh return 1; 731aa940eacSdrh } 732aa940eacSdrh return 0; 733aa940eacSdrh } 734aa940eacSdrh 73571fd80bfSdanielk1977 static void DbRollbackHandler(void *clientData){ 73671fd80bfSdanielk1977 SqliteDb *pDb = (SqliteDb*)clientData; 73771fd80bfSdanielk1977 assert(pDb->pRollbackHook); 73871fd80bfSdanielk1977 if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){ 73971fd80bfSdanielk1977 Tcl_BackgroundError(pDb->interp); 74071fd80bfSdanielk1977 } 74171fd80bfSdanielk1977 } 74271fd80bfSdanielk1977 7435def0843Sdrh /* 7445def0843Sdrh ** This procedure handles wal_hook callbacks. 7455def0843Sdrh */ 7465def0843Sdrh static int DbWalHandler( 7478d22a174Sdan void *clientData, 7488d22a174Sdan sqlite3 *db, 7498d22a174Sdan const char *zDb, 7508d22a174Sdan int nEntry 7518d22a174Sdan ){ 7525def0843Sdrh int ret = SQLITE_OK; 7538d22a174Sdan Tcl_Obj *p; 7548d22a174Sdan SqliteDb *pDb = (SqliteDb*)clientData; 7558d22a174Sdan Tcl_Interp *interp = pDb->interp; 7565def0843Sdrh assert(pDb->pWalHook); 7578d22a174Sdan 7586e45e0c8Sdan assert( db==pDb->db ); 7595def0843Sdrh p = Tcl_DuplicateObj(pDb->pWalHook); 7608d22a174Sdan Tcl_IncrRefCount(p); 7618d22a174Sdan Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1)); 7628d22a174Sdan Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry)); 7638d22a174Sdan if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0) 7648d22a174Sdan || TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret) 7658d22a174Sdan ){ 7668d22a174Sdan Tcl_BackgroundError(interp); 7678d22a174Sdan } 7688d22a174Sdan Tcl_DecrRefCount(p); 7698d22a174Sdan 7708d22a174Sdan return ret; 7718d22a174Sdan } 7728d22a174Sdan 773bcf4f484Sdrh #if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) 774404ca075Sdanielk1977 static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){ 775404ca075Sdanielk1977 char zBuf[64]; 77665545b59Sdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iArg); 777404ca075Sdanielk1977 Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY); 77865545b59Sdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nArg); 779404ca075Sdanielk1977 Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY); 780404ca075Sdanielk1977 } 781404ca075Sdanielk1977 #else 782404ca075Sdanielk1977 # define setTestUnlockNotifyVars(x,y,z) 783404ca075Sdanielk1977 #endif 784404ca075Sdanielk1977 78569910da9Sdrh #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY 786404ca075Sdanielk1977 static void DbUnlockNotify(void **apArg, int nArg){ 787404ca075Sdanielk1977 int i; 788404ca075Sdanielk1977 for(i=0; i<nArg; i++){ 789404ca075Sdanielk1977 const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); 790404ca075Sdanielk1977 SqliteDb *pDb = (SqliteDb *)apArg[i]; 791404ca075Sdanielk1977 setTestUnlockNotifyVars(pDb->interp, i, nArg); 792404ca075Sdanielk1977 assert( pDb->pUnlockNotify); 793404ca075Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pDb->pUnlockNotify, flags); 794404ca075Sdanielk1977 Tcl_DecrRefCount(pDb->pUnlockNotify); 795404ca075Sdanielk1977 pDb->pUnlockNotify = 0; 796404ca075Sdanielk1977 } 797404ca075Sdanielk1977 } 79869910da9Sdrh #endif 799404ca075Sdanielk1977 8009b1c62d4Sdrh #ifdef SQLITE_ENABLE_PREUPDATE_HOOK 80146c47d46Sdan /* 80246c47d46Sdan ** Pre-update hook callback. 80346c47d46Sdan */ 80446c47d46Sdan static void DbPreUpdateHandler( 80546c47d46Sdan void *p, 80646c47d46Sdan sqlite3 *db, 80746c47d46Sdan int op, 80846c47d46Sdan const char *zDb, 80946c47d46Sdan const char *zTbl, 81046c47d46Sdan sqlite_int64 iKey1, 81146c47d46Sdan sqlite_int64 iKey2 81246c47d46Sdan ){ 81346c47d46Sdan SqliteDb *pDb = (SqliteDb *)p; 81446c47d46Sdan Tcl_Obj *pCmd; 81546c47d46Sdan static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"}; 81646c47d46Sdan 81746c47d46Sdan assert( (SQLITE_DELETE-1)/9 == 0 ); 81846c47d46Sdan assert( (SQLITE_INSERT-1)/9 == 1 ); 81946c47d46Sdan assert( (SQLITE_UPDATE-1)/9 == 2 ); 82046c47d46Sdan assert( pDb->pPreUpdateHook ); 82146c47d46Sdan assert( db==pDb->db ); 82246c47d46Sdan assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); 82346c47d46Sdan 82446c47d46Sdan pCmd = Tcl_DuplicateObj(pDb->pPreUpdateHook); 82546c47d46Sdan Tcl_IncrRefCount(pCmd); 82646c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(azStr[(op-1)/9], -1)); 82746c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1)); 82846c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1)); 82946c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey1)); 83046c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey2)); 83146c47d46Sdan Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 83246c47d46Sdan Tcl_DecrRefCount(pCmd); 83346c47d46Sdan } 8349b1c62d4Sdrh #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ 83546c47d46Sdan 83694eb6a14Sdanielk1977 static void DbUpdateHandler( 83794eb6a14Sdanielk1977 void *p, 83894eb6a14Sdanielk1977 int op, 83994eb6a14Sdanielk1977 const char *zDb, 84094eb6a14Sdanielk1977 const char *zTbl, 84194eb6a14Sdanielk1977 sqlite_int64 rowid 84294eb6a14Sdanielk1977 ){ 84394eb6a14Sdanielk1977 SqliteDb *pDb = (SqliteDb *)p; 84494eb6a14Sdanielk1977 Tcl_Obj *pCmd; 84546c47d46Sdan static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"}; 84646c47d46Sdan 84746c47d46Sdan assert( (SQLITE_DELETE-1)/9 == 0 ); 84846c47d46Sdan assert( (SQLITE_INSERT-1)/9 == 1 ); 84946c47d46Sdan assert( (SQLITE_UPDATE-1)/9 == 2 ); 85094eb6a14Sdanielk1977 85194eb6a14Sdanielk1977 assert( pDb->pUpdateHook ); 85294eb6a14Sdanielk1977 assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); 85394eb6a14Sdanielk1977 85494eb6a14Sdanielk1977 pCmd = Tcl_DuplicateObj(pDb->pUpdateHook); 85594eb6a14Sdanielk1977 Tcl_IncrRefCount(pCmd); 85646c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(azStr[(op-1)/9], -1)); 85794eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1)); 85894eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1)); 85994eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid)); 86094eb6a14Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 861efdde169Sdrh Tcl_DecrRefCount(pCmd); 86294eb6a14Sdanielk1977 } 86394eb6a14Sdanielk1977 8647cedc8d4Sdanielk1977 static void tclCollateNeeded( 8657cedc8d4Sdanielk1977 void *pCtx, 8669bb575fdSdrh sqlite3 *db, 8677cedc8d4Sdanielk1977 int enc, 8687cedc8d4Sdanielk1977 const char *zName 8697cedc8d4Sdanielk1977 ){ 8707cedc8d4Sdanielk1977 SqliteDb *pDb = (SqliteDb *)pCtx; 8717cedc8d4Sdanielk1977 Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded); 8727cedc8d4Sdanielk1977 Tcl_IncrRefCount(pScript); 8737cedc8d4Sdanielk1977 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1)); 8747cedc8d4Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pScript, 0); 8757cedc8d4Sdanielk1977 Tcl_DecrRefCount(pScript); 8767cedc8d4Sdanielk1977 } 8777cedc8d4Sdanielk1977 878aa940eacSdrh /* 8790202b29eSdanielk1977 ** This routine is called to evaluate an SQL collation function implemented 8800202b29eSdanielk1977 ** using TCL script. 8810202b29eSdanielk1977 */ 8820202b29eSdanielk1977 static int tclSqlCollate( 8830202b29eSdanielk1977 void *pCtx, 8840202b29eSdanielk1977 int nA, 8850202b29eSdanielk1977 const void *zA, 8860202b29eSdanielk1977 int nB, 8870202b29eSdanielk1977 const void *zB 8880202b29eSdanielk1977 ){ 8890202b29eSdanielk1977 SqlCollate *p = (SqlCollate *)pCtx; 8900202b29eSdanielk1977 Tcl_Obj *pCmd; 8910202b29eSdanielk1977 8920202b29eSdanielk1977 pCmd = Tcl_NewStringObj(p->zScript, -1); 8930202b29eSdanielk1977 Tcl_IncrRefCount(pCmd); 8940202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA)); 8950202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB)); 896d1e4733dSdrh Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); 8970202b29eSdanielk1977 Tcl_DecrRefCount(pCmd); 8980202b29eSdanielk1977 return (atoi(Tcl_GetStringResult(p->interp))); 8990202b29eSdanielk1977 } 9000202b29eSdanielk1977 9010202b29eSdanielk1977 /* 902cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented 903cabb0819Sdrh ** using TCL script. 904cabb0819Sdrh */ 9050ae8b831Sdanielk1977 static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ 9066f8a503dSdanielk1977 SqlFunc *p = sqlite3_user_data(context); 907d1e4733dSdrh Tcl_Obj *pCmd; 908cabb0819Sdrh int i; 909cabb0819Sdrh int rc; 910cabb0819Sdrh 911d1e4733dSdrh if( argc==0 ){ 912d1e4733dSdrh /* If there are no arguments to the function, call Tcl_EvalObjEx on the 913d1e4733dSdrh ** script object directly. This allows the TCL compiler to generate 914d1e4733dSdrh ** bytecode for the command on the first invocation and thus make 915d1e4733dSdrh ** subsequent invocations much faster. */ 916d1e4733dSdrh pCmd = p->pScript; 917d1e4733dSdrh Tcl_IncrRefCount(pCmd); 918d1e4733dSdrh rc = Tcl_EvalObjEx(p->interp, pCmd, 0); 919d1e4733dSdrh Tcl_DecrRefCount(pCmd); 92051ad0ecdSdanielk1977 }else{ 921d1e4733dSdrh /* If there are arguments to the function, make a shallow copy of the 922d1e4733dSdrh ** script object, lappend the arguments, then evaluate the copy. 923d1e4733dSdrh ** 92460ec914cSpeter.d.reid ** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated. 925d1e4733dSdrh ** The new Tcl_Obj contains pointers to the original list elements. 926d1e4733dSdrh ** That way, when Tcl_EvalObjv() is run and shimmers the first element 927d1e4733dSdrh ** of the list to tclCmdNameType, that alternate representation will 928d1e4733dSdrh ** be preserved and reused on the next invocation. 929d1e4733dSdrh */ 930d1e4733dSdrh Tcl_Obj **aArg; 931d1e4733dSdrh int nArg; 932d1e4733dSdrh if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){ 933d1e4733dSdrh sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 934d1e4733dSdrh return; 935d1e4733dSdrh } 936d1e4733dSdrh pCmd = Tcl_NewListObj(nArg, aArg); 937d1e4733dSdrh Tcl_IncrRefCount(pCmd); 938d1e4733dSdrh for(i=0; i<argc; i++){ 939d1e4733dSdrh sqlite3_value *pIn = argv[i]; 940d1e4733dSdrh Tcl_Obj *pVal; 941d1e4733dSdrh 942d1e4733dSdrh /* Set pVal to contain the i'th column of this row. */ 943d1e4733dSdrh switch( sqlite3_value_type(pIn) ){ 944d1e4733dSdrh case SQLITE_BLOB: { 945d1e4733dSdrh int bytes = sqlite3_value_bytes(pIn); 946d1e4733dSdrh pVal = Tcl_NewByteArrayObj(sqlite3_value_blob(pIn), bytes); 947d1e4733dSdrh break; 948d1e4733dSdrh } 949d1e4733dSdrh case SQLITE_INTEGER: { 950d1e4733dSdrh sqlite_int64 v = sqlite3_value_int64(pIn); 951d1e4733dSdrh if( v>=-2147483647 && v<=2147483647 ){ 9527fd33929Sdrh pVal = Tcl_NewIntObj((int)v); 953d1e4733dSdrh }else{ 954d1e4733dSdrh pVal = Tcl_NewWideIntObj(v); 955d1e4733dSdrh } 956d1e4733dSdrh break; 957d1e4733dSdrh } 958d1e4733dSdrh case SQLITE_FLOAT: { 959d1e4733dSdrh double r = sqlite3_value_double(pIn); 960d1e4733dSdrh pVal = Tcl_NewDoubleObj(r); 961d1e4733dSdrh break; 962d1e4733dSdrh } 963d1e4733dSdrh case SQLITE_NULL: { 964c45e6716Sdrh pVal = Tcl_NewStringObj(p->pDb->zNull, -1); 965d1e4733dSdrh break; 966d1e4733dSdrh } 967d1e4733dSdrh default: { 968d1e4733dSdrh int bytes = sqlite3_value_bytes(pIn); 96900fd957bSdanielk1977 pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes); 970d1e4733dSdrh break; 97151ad0ecdSdanielk1977 } 972cabb0819Sdrh } 973d1e4733dSdrh rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal); 974d1e4733dSdrh if( rc ){ 975d1e4733dSdrh Tcl_DecrRefCount(pCmd); 976d1e4733dSdrh sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 977d1e4733dSdrh return; 978d1e4733dSdrh } 979d1e4733dSdrh } 980d1e4733dSdrh if( !p->useEvalObjv ){ 981d1e4733dSdrh /* Tcl_EvalObjEx() will automatically call Tcl_EvalObjv() if pCmd 982d1e4733dSdrh ** is a list without a string representation. To prevent this from 983d1e4733dSdrh ** happening, make sure pCmd has a valid string representation */ 984d1e4733dSdrh Tcl_GetString(pCmd); 985d1e4733dSdrh } 986d1e4733dSdrh rc = Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); 987d1e4733dSdrh Tcl_DecrRefCount(pCmd); 988d1e4733dSdrh } 989562e8d3cSdanielk1977 990c7f269d5Sdrh if( rc && rc!=TCL_RETURN ){ 9917e18c259Sdanielk1977 sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 992cabb0819Sdrh }else{ 993c7f269d5Sdrh Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); 994c7f269d5Sdrh int n; 995c7f269d5Sdrh u8 *data; 9964a4c11aaSdan const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); 997c7f269d5Sdrh char c = zType[0]; 998df0bddaeSdrh if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ 999d1e4733dSdrh /* Only return a BLOB type if the Tcl variable is a bytearray and 1000df0bddaeSdrh ** has no string representation. */ 1001c7f269d5Sdrh data = Tcl_GetByteArrayFromObj(pVar, &n); 1002c7f269d5Sdrh sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT); 1003985e0c63Sdrh }else if( c=='b' && strcmp(zType,"boolean")==0 ){ 1004c7f269d5Sdrh Tcl_GetIntFromObj(0, pVar, &n); 1005c7f269d5Sdrh sqlite3_result_int(context, n); 1006c7f269d5Sdrh }else if( c=='d' && strcmp(zType,"double")==0 ){ 1007c7f269d5Sdrh double r; 1008c7f269d5Sdrh Tcl_GetDoubleFromObj(0, pVar, &r); 1009c7f269d5Sdrh sqlite3_result_double(context, r); 1010985e0c63Sdrh }else if( (c=='w' && strcmp(zType,"wideInt")==0) || 1011985e0c63Sdrh (c=='i' && strcmp(zType,"int")==0) ){ 1012df0bddaeSdrh Tcl_WideInt v; 1013df0bddaeSdrh Tcl_GetWideIntFromObj(0, pVar, &v); 1014df0bddaeSdrh sqlite3_result_int64(context, v); 1015c7f269d5Sdrh }else{ 101600fd957bSdanielk1977 data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); 101700fd957bSdanielk1977 sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT); 1018c7f269d5Sdrh } 1019cabb0819Sdrh } 1020cabb0819Sdrh } 1021895d7472Sdrh 1022e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION 1023e22a334bSdrh /* 1024e22a334bSdrh ** This is the authentication function. It appends the authentication 1025e22a334bSdrh ** type code and the two arguments to zCmd[] then invokes the result 1026e22a334bSdrh ** on the interpreter. The reply is examined to determine if the 1027e22a334bSdrh ** authentication fails or succeeds. 1028e22a334bSdrh */ 1029e22a334bSdrh static int auth_callback( 1030e22a334bSdrh void *pArg, 1031e22a334bSdrh int code, 1032e22a334bSdrh const char *zArg1, 1033e22a334bSdrh const char *zArg2, 1034e22a334bSdrh const char *zArg3, 1035e22a334bSdrh const char *zArg4 103632c6a48bSdrh #ifdef SQLITE_USER_AUTHENTICATION 103732c6a48bSdrh ,const char *zArg5 103832c6a48bSdrh #endif 1039e22a334bSdrh ){ 10406ef5e12eSmistachkin const char *zCode; 1041e22a334bSdrh Tcl_DString str; 1042e22a334bSdrh int rc; 1043e22a334bSdrh const char *zReply; 10449418921cSdrh /* EVIDENCE-OF: R-38590-62769 The first parameter to the authorizer 10459418921cSdrh ** callback is a copy of the third parameter to the 10469418921cSdrh ** sqlite3_set_authorizer() interface. 10479418921cSdrh */ 1048e22a334bSdrh SqliteDb *pDb = (SqliteDb*)pArg; 10491f1549f8Sdrh if( pDb->disableAuth ) return SQLITE_OK; 1050e22a334bSdrh 10519418921cSdrh /* EVIDENCE-OF: R-56518-44310 The second parameter to the callback is an 10529418921cSdrh ** integer action code that specifies the particular action to be 10539418921cSdrh ** authorized. */ 1054e22a334bSdrh switch( code ){ 1055e22a334bSdrh case SQLITE_COPY : zCode="SQLITE_COPY"; break; 1056e22a334bSdrh case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; 1057e22a334bSdrh case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; 1058e22a334bSdrh case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; 1059e22a334bSdrh case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; 1060e22a334bSdrh case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; 1061e22a334bSdrh case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; 1062e22a334bSdrh case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; 1063e22a334bSdrh case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; 1064e22a334bSdrh case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; 1065e22a334bSdrh case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; 1066e22a334bSdrh case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; 1067e22a334bSdrh case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; 1068e22a334bSdrh case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; 1069e22a334bSdrh case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; 1070e22a334bSdrh case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; 1071e22a334bSdrh case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; 1072e22a334bSdrh case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; 1073e22a334bSdrh case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; 1074e22a334bSdrh case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; 1075e22a334bSdrh case SQLITE_READ : zCode="SQLITE_READ"; break; 1076e22a334bSdrh case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; 1077e22a334bSdrh case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; 1078e22a334bSdrh case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; 107981e293b4Sdrh case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break; 108081e293b4Sdrh case SQLITE_DETACH : zCode="SQLITE_DETACH"; break; 10811c8c23ccSdanielk1977 case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; 10821d54df88Sdanielk1977 case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; 1083e6e04969Sdrh case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break; 1084f1a381e7Sdanielk1977 case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break; 1085f1a381e7Sdanielk1977 case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break; 10865169bbc6Sdrh case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break; 1087ab9b703fSdanielk1977 case SQLITE_SAVEPOINT : zCode="SQLITE_SAVEPOINT"; break; 108865a2aaa6Sdrh case SQLITE_RECURSIVE : zCode="SQLITE_RECURSIVE"; break; 1089e22a334bSdrh default : zCode="????"; break; 1090e22a334bSdrh } 1091e22a334bSdrh Tcl_DStringInit(&str); 1092e22a334bSdrh Tcl_DStringAppend(&str, pDb->zAuth, -1); 1093e22a334bSdrh Tcl_DStringAppendElement(&str, zCode); 1094e22a334bSdrh Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); 1095e22a334bSdrh Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); 1096e22a334bSdrh Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); 1097e22a334bSdrh Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); 109832c6a48bSdrh #ifdef SQLITE_USER_AUTHENTICATION 109932c6a48bSdrh Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : ""); 110032c6a48bSdrh #endif 1101e22a334bSdrh rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); 1102e22a334bSdrh Tcl_DStringFree(&str); 1103b07028f7Sdrh zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY"; 1104e22a334bSdrh if( strcmp(zReply,"SQLITE_OK")==0 ){ 1105e22a334bSdrh rc = SQLITE_OK; 1106e22a334bSdrh }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ 1107e22a334bSdrh rc = SQLITE_DENY; 1108e22a334bSdrh }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ 1109e22a334bSdrh rc = SQLITE_IGNORE; 1110e22a334bSdrh }else{ 1111e22a334bSdrh rc = 999; 1112e22a334bSdrh } 1113e22a334bSdrh return rc; 1114e22a334bSdrh } 1115e22a334bSdrh #endif /* SQLITE_OMIT_AUTHORIZATION */ 1116cabb0819Sdrh 1117cabb0819Sdrh /* 11181067fe11Stpoindex ** This routine reads a line of text from FILE in, stores 11191067fe11Stpoindex ** the text in memory obtained from malloc() and returns a pointer 11201067fe11Stpoindex ** to the text. NULL is returned at end of file, or if malloc() 11211067fe11Stpoindex ** fails. 11221067fe11Stpoindex ** 11231067fe11Stpoindex ** The interface is like "readline" but no command-line editing 11241067fe11Stpoindex ** is done. 11251067fe11Stpoindex ** 11261067fe11Stpoindex ** copied from shell.c from '.import' command 11271067fe11Stpoindex */ 11281067fe11Stpoindex static char *local_getline(char *zPrompt, FILE *in){ 11291067fe11Stpoindex char *zLine; 11301067fe11Stpoindex int nLine; 11311067fe11Stpoindex int n; 11321067fe11Stpoindex 11331067fe11Stpoindex nLine = 100; 11341067fe11Stpoindex zLine = malloc( nLine ); 11351067fe11Stpoindex if( zLine==0 ) return 0; 11361067fe11Stpoindex n = 0; 1137b07028f7Sdrh while( 1 ){ 11381067fe11Stpoindex if( n+100>nLine ){ 11391067fe11Stpoindex nLine = nLine*2 + 100; 11401067fe11Stpoindex zLine = realloc(zLine, nLine); 11411067fe11Stpoindex if( zLine==0 ) return 0; 11421067fe11Stpoindex } 11431067fe11Stpoindex if( fgets(&zLine[n], nLine - n, in)==0 ){ 11441067fe11Stpoindex if( n==0 ){ 11451067fe11Stpoindex free(zLine); 11461067fe11Stpoindex return 0; 11471067fe11Stpoindex } 11481067fe11Stpoindex zLine[n] = 0; 11491067fe11Stpoindex break; 11501067fe11Stpoindex } 11511067fe11Stpoindex while( zLine[n] ){ n++; } 11521067fe11Stpoindex if( n>0 && zLine[n-1]=='\n' ){ 11531067fe11Stpoindex n--; 11541067fe11Stpoindex zLine[n] = 0; 1155b07028f7Sdrh break; 11561067fe11Stpoindex } 11571067fe11Stpoindex } 11581067fe11Stpoindex zLine = realloc( zLine, n+1 ); 11591067fe11Stpoindex return zLine; 11601067fe11Stpoindex } 11611067fe11Stpoindex 11628e556520Sdanielk1977 11638e556520Sdanielk1977 /* 11644a4c11aaSdan ** This function is part of the implementation of the command: 11658e556520Sdanielk1977 ** 11664a4c11aaSdan ** $db transaction [-deferred|-immediate|-exclusive] SCRIPT 11678e556520Sdanielk1977 ** 11684a4c11aaSdan ** It is invoked after evaluating the script SCRIPT to commit or rollback 11694a4c11aaSdan ** the transaction or savepoint opened by the [transaction] command. 11704a4c11aaSdan */ 1171a121cc7cSmistachkin static int SQLITE_TCLAPI DbTransPostCmd( 11724a4c11aaSdan ClientData data[], /* data[0] is the Sqlite3Db* for $db */ 11734a4c11aaSdan Tcl_Interp *interp, /* Tcl interpreter */ 11744a4c11aaSdan int result /* Result of evaluating SCRIPT */ 11754a4c11aaSdan ){ 11766ef5e12eSmistachkin static const char *const azEnd[] = { 11774a4c11aaSdan "RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */ 11784a4c11aaSdan "COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */ 11794a4c11aaSdan "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction", 11804a4c11aaSdan "ROLLBACK" /* rc==TCL_ERROR, nTransaction==0 */ 11814a4c11aaSdan }; 11824a4c11aaSdan SqliteDb *pDb = (SqliteDb*)data[0]; 11834a4c11aaSdan int rc = result; 11844a4c11aaSdan const char *zEnd; 11854a4c11aaSdan 11864a4c11aaSdan pDb->nTransaction--; 11874a4c11aaSdan zEnd = azEnd[(rc==TCL_ERROR)*2 + (pDb->nTransaction==0)]; 11884a4c11aaSdan 11894a4c11aaSdan pDb->disableAuth++; 11904a4c11aaSdan if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){ 11914a4c11aaSdan /* This is a tricky scenario to handle. The most likely cause of an 11924a4c11aaSdan ** error is that the exec() above was an attempt to commit the 11934a4c11aaSdan ** top-level transaction that returned SQLITE_BUSY. Or, less likely, 119448864df9Smistachkin ** that an IO-error has occurred. In either case, throw a Tcl exception 11954a4c11aaSdan ** and try to rollback the transaction. 11964a4c11aaSdan ** 11974a4c11aaSdan ** But it could also be that the user executed one or more BEGIN, 11984a4c11aaSdan ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing 11994a4c11aaSdan ** this method's logic. Not clear how this would be best handled. 12004a4c11aaSdan */ 12014a4c11aaSdan if( rc!=TCL_ERROR ){ 1202a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 12034a4c11aaSdan rc = TCL_ERROR; 12044a4c11aaSdan } 12054a4c11aaSdan sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); 12064a4c11aaSdan } 12074a4c11aaSdan pDb->disableAuth--; 12084a4c11aaSdan 12094a4c11aaSdan return rc; 12104a4c11aaSdan } 12114a4c11aaSdan 12124a4c11aaSdan /* 1213c431fd55Sdan ** Unless SQLITE_TEST is defined, this function is a simple wrapper around 1214c431fd55Sdan ** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either 1215c431fd55Sdan ** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending 1216c431fd55Sdan ** on whether or not the [db_use_legacy_prepare] command has been used to 1217c431fd55Sdan ** configure the connection. 1218c431fd55Sdan */ 1219c431fd55Sdan static int dbPrepare( 1220c431fd55Sdan SqliteDb *pDb, /* Database object */ 1221c431fd55Sdan const char *zSql, /* SQL to compile */ 1222c431fd55Sdan sqlite3_stmt **ppStmt, /* OUT: Prepared statement */ 1223c431fd55Sdan const char **pzOut /* OUT: Pointer to next SQL statement */ 1224c431fd55Sdan ){ 12252c2f392dSdrh unsigned int prepFlags = 0; 1226c431fd55Sdan #ifdef SQLITE_TEST 1227c431fd55Sdan if( pDb->bLegacyPrepare ){ 1228c431fd55Sdan return sqlite3_prepare(pDb->db, zSql, -1, ppStmt, pzOut); 1229c431fd55Sdan } 1230c431fd55Sdan #endif 12312c2f392dSdrh /* If the statement cache is large, use the SQLITE_PREPARE_PERSISTENT 12322c2f392dSdrh ** flags, which uses less lookaside memory. But if the cache is small, 12332c2f392dSdrh ** omit that flag to make full use of lookaside */ 12342c2f392dSdrh if( pDb->maxStmt>5 ) prepFlags = SQLITE_PREPARE_PERSISTENT; 12352c2f392dSdrh 12362c2f392dSdrh return sqlite3_prepare_v3(pDb->db, zSql, -1, prepFlags, ppStmt, pzOut); 1237c431fd55Sdan } 1238c431fd55Sdan 1239c431fd55Sdan /* 12404a4c11aaSdan ** Search the cache for a prepared-statement object that implements the 12414a4c11aaSdan ** first SQL statement in the buffer pointed to by parameter zIn. If 12424a4c11aaSdan ** no such prepared-statement can be found, allocate and prepare a new 12434a4c11aaSdan ** one. In either case, bind the current values of the relevant Tcl 12444a4c11aaSdan ** variables to any $var, :var or @var variables in the statement. Before 12454a4c11aaSdan ** returning, set *ppPreStmt to point to the prepared-statement object. 12464a4c11aaSdan ** 12474a4c11aaSdan ** Output parameter *pzOut is set to point to the next SQL statement in 12484a4c11aaSdan ** buffer zIn, or to the '\0' byte at the end of zIn if there is no 12494a4c11aaSdan ** next statement. 12504a4c11aaSdan ** 12514a4c11aaSdan ** If successful, TCL_OK is returned. Otherwise, TCL_ERROR is returned 12524a4c11aaSdan ** and an error message loaded into interpreter pDb->interp. 12534a4c11aaSdan */ 12544a4c11aaSdan static int dbPrepareAndBind( 12554a4c11aaSdan SqliteDb *pDb, /* Database object */ 12564a4c11aaSdan char const *zIn, /* SQL to compile */ 12574a4c11aaSdan char const **pzOut, /* OUT: Pointer to next SQL statement */ 12584a4c11aaSdan SqlPreparedStmt **ppPreStmt /* OUT: Object used to cache statement */ 12594a4c11aaSdan ){ 12604a4c11aaSdan const char *zSql = zIn; /* Pointer to first SQL statement in zIn */ 12617bb22ac7Smistachkin sqlite3_stmt *pStmt = 0; /* Prepared statement object */ 12624a4c11aaSdan SqlPreparedStmt *pPreStmt; /* Pointer to cached statement */ 12634a4c11aaSdan int nSql; /* Length of zSql in bytes */ 12647bb22ac7Smistachkin int nVar = 0; /* Number of variables in statement */ 12654a4c11aaSdan int iParm = 0; /* Next free entry in apParm */ 12660425f189Sdrh char c; 12674a4c11aaSdan int i; 12684a4c11aaSdan Tcl_Interp *interp = pDb->interp; 12694a4c11aaSdan 12704a4c11aaSdan *ppPreStmt = 0; 12714a4c11aaSdan 12724a4c11aaSdan /* Trim spaces from the start of zSql and calculate the remaining length. */ 12730425f189Sdrh while( (c = zSql[0])==' ' || c=='\t' || c=='\r' || c=='\n' ){ zSql++; } 12744a4c11aaSdan nSql = strlen30(zSql); 12754a4c11aaSdan 12764a4c11aaSdan for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){ 12774a4c11aaSdan int n = pPreStmt->nSql; 12784a4c11aaSdan if( nSql>=n 12794a4c11aaSdan && memcmp(pPreStmt->zSql, zSql, n)==0 12804a4c11aaSdan && (zSql[n]==0 || zSql[n-1]==';') 12814a4c11aaSdan ){ 12824a4c11aaSdan pStmt = pPreStmt->pStmt; 12834a4c11aaSdan *pzOut = &zSql[pPreStmt->nSql]; 12844a4c11aaSdan 12854a4c11aaSdan /* When a prepared statement is found, unlink it from the 12864a4c11aaSdan ** cache list. It will later be added back to the beginning 12874a4c11aaSdan ** of the cache list in order to implement LRU replacement. 12884a4c11aaSdan */ 12894a4c11aaSdan if( pPreStmt->pPrev ){ 12904a4c11aaSdan pPreStmt->pPrev->pNext = pPreStmt->pNext; 12914a4c11aaSdan }else{ 12924a4c11aaSdan pDb->stmtList = pPreStmt->pNext; 12934a4c11aaSdan } 12944a4c11aaSdan if( pPreStmt->pNext ){ 12954a4c11aaSdan pPreStmt->pNext->pPrev = pPreStmt->pPrev; 12964a4c11aaSdan }else{ 12974a4c11aaSdan pDb->stmtLast = pPreStmt->pPrev; 12984a4c11aaSdan } 12994a4c11aaSdan pDb->nStmt--; 13004a4c11aaSdan nVar = sqlite3_bind_parameter_count(pStmt); 13014a4c11aaSdan break; 13024a4c11aaSdan } 13034a4c11aaSdan } 13044a4c11aaSdan 13054a4c11aaSdan /* If no prepared statement was found. Compile the SQL text. Also allocate 13064a4c11aaSdan ** a new SqlPreparedStmt structure. */ 13074a4c11aaSdan if( pPreStmt==0 ){ 13084a4c11aaSdan int nByte; 13094a4c11aaSdan 1310c431fd55Sdan if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){ 1311c45e6716Sdrh Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); 13124a4c11aaSdan return TCL_ERROR; 13134a4c11aaSdan } 13144a4c11aaSdan if( pStmt==0 ){ 13154a4c11aaSdan if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){ 13164a4c11aaSdan /* A compile-time error in the statement. */ 1317c45e6716Sdrh Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); 13184a4c11aaSdan return TCL_ERROR; 13194a4c11aaSdan }else{ 13204a4c11aaSdan /* The statement was a no-op. Continue to the next statement 13214a4c11aaSdan ** in the SQL string. 13224a4c11aaSdan */ 13234a4c11aaSdan return TCL_OK; 13244a4c11aaSdan } 13254a4c11aaSdan } 13264a4c11aaSdan 13274a4c11aaSdan assert( pPreStmt==0 ); 13284a4c11aaSdan nVar = sqlite3_bind_parameter_count(pStmt); 13294a4c11aaSdan nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj *); 13304a4c11aaSdan pPreStmt = (SqlPreparedStmt*)Tcl_Alloc(nByte); 13314a4c11aaSdan memset(pPreStmt, 0, nByte); 13324a4c11aaSdan 13334a4c11aaSdan pPreStmt->pStmt = pStmt; 13347ed243b7Sdrh pPreStmt->nSql = (int)(*pzOut - zSql); 13354a4c11aaSdan pPreStmt->zSql = sqlite3_sql(pStmt); 13364a4c11aaSdan pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1]; 1337c431fd55Sdan #ifdef SQLITE_TEST 1338c431fd55Sdan if( pPreStmt->zSql==0 ){ 1339c431fd55Sdan char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1); 1340c431fd55Sdan memcpy(zCopy, zSql, pPreStmt->nSql); 1341c431fd55Sdan zCopy[pPreStmt->nSql] = '\0'; 1342c431fd55Sdan pPreStmt->zSql = zCopy; 1343c431fd55Sdan } 1344c431fd55Sdan #endif 13454a4c11aaSdan } 13464a4c11aaSdan assert( pPreStmt ); 13474a4c11aaSdan assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql ); 13484a4c11aaSdan assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) ); 13494a4c11aaSdan 13504a4c11aaSdan /* Bind values to parameters that begin with $ or : */ 13514a4c11aaSdan for(i=1; i<=nVar; i++){ 13524a4c11aaSdan const char *zVar = sqlite3_bind_parameter_name(pStmt, i); 13534a4c11aaSdan if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){ 13544a4c11aaSdan Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); 13554a4c11aaSdan if( pVar ){ 13564a4c11aaSdan int n; 13574a4c11aaSdan u8 *data; 13584a4c11aaSdan const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); 13598e18922fSmistachkin c = zType[0]; 13604a4c11aaSdan if( zVar[0]=='@' || 13614a4c11aaSdan (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){ 13624a4c11aaSdan /* Load a BLOB type if the Tcl variable is a bytearray and 13634a4c11aaSdan ** it has no string representation or the host 13644a4c11aaSdan ** parameter name begins with "@". */ 13654a4c11aaSdan data = Tcl_GetByteArrayFromObj(pVar, &n); 13664a4c11aaSdan sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC); 13674a4c11aaSdan Tcl_IncrRefCount(pVar); 13684a4c11aaSdan pPreStmt->apParm[iParm++] = pVar; 13694a4c11aaSdan }else if( c=='b' && strcmp(zType,"boolean")==0 ){ 13704a4c11aaSdan Tcl_GetIntFromObj(interp, pVar, &n); 13714a4c11aaSdan sqlite3_bind_int(pStmt, i, n); 13724a4c11aaSdan }else if( c=='d' && strcmp(zType,"double")==0 ){ 13734a4c11aaSdan double r; 13744a4c11aaSdan Tcl_GetDoubleFromObj(interp, pVar, &r); 13754a4c11aaSdan sqlite3_bind_double(pStmt, i, r); 13764a4c11aaSdan }else if( (c=='w' && strcmp(zType,"wideInt")==0) || 13774a4c11aaSdan (c=='i' && strcmp(zType,"int")==0) ){ 13784a4c11aaSdan Tcl_WideInt v; 13794a4c11aaSdan Tcl_GetWideIntFromObj(interp, pVar, &v); 13804a4c11aaSdan sqlite3_bind_int64(pStmt, i, v); 13814a4c11aaSdan }else{ 13824a4c11aaSdan data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); 13834a4c11aaSdan sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC); 13844a4c11aaSdan Tcl_IncrRefCount(pVar); 13854a4c11aaSdan pPreStmt->apParm[iParm++] = pVar; 13864a4c11aaSdan } 13874a4c11aaSdan }else{ 13884a4c11aaSdan sqlite3_bind_null(pStmt, i); 13894a4c11aaSdan } 13904a4c11aaSdan } 13914a4c11aaSdan } 13924a4c11aaSdan pPreStmt->nParm = iParm; 13934a4c11aaSdan *ppPreStmt = pPreStmt; 1394937d0deaSdan 13954a4c11aaSdan return TCL_OK; 13964a4c11aaSdan } 13974a4c11aaSdan 13984a4c11aaSdan /* 13994a4c11aaSdan ** Release a statement reference obtained by calling dbPrepareAndBind(). 14004a4c11aaSdan ** There should be exactly one call to this function for each call to 14014a4c11aaSdan ** dbPrepareAndBind(). 14024a4c11aaSdan ** 14034a4c11aaSdan ** If the discard parameter is non-zero, then the statement is deleted 14044a4c11aaSdan ** immediately. Otherwise it is added to the LRU list and may be returned 14054a4c11aaSdan ** by a subsequent call to dbPrepareAndBind(). 14064a4c11aaSdan */ 14074a4c11aaSdan static void dbReleaseStmt( 14084a4c11aaSdan SqliteDb *pDb, /* Database handle */ 14094a4c11aaSdan SqlPreparedStmt *pPreStmt, /* Prepared statement handle to release */ 14104a4c11aaSdan int discard /* True to delete (not cache) the pPreStmt */ 14114a4c11aaSdan ){ 14124a4c11aaSdan int i; 14134a4c11aaSdan 14144a4c11aaSdan /* Free the bound string and blob parameters */ 14154a4c11aaSdan for(i=0; i<pPreStmt->nParm; i++){ 14164a4c11aaSdan Tcl_DecrRefCount(pPreStmt->apParm[i]); 14174a4c11aaSdan } 14184a4c11aaSdan pPreStmt->nParm = 0; 14194a4c11aaSdan 14204a4c11aaSdan if( pDb->maxStmt<=0 || discard ){ 14214a4c11aaSdan /* If the cache is turned off, deallocated the statement */ 1422c431fd55Sdan dbFreeStmt(pPreStmt); 14234a4c11aaSdan }else{ 14244a4c11aaSdan /* Add the prepared statement to the beginning of the cache list. */ 14254a4c11aaSdan pPreStmt->pNext = pDb->stmtList; 14264a4c11aaSdan pPreStmt->pPrev = 0; 14274a4c11aaSdan if( pDb->stmtList ){ 14284a4c11aaSdan pDb->stmtList->pPrev = pPreStmt; 14294a4c11aaSdan } 14304a4c11aaSdan pDb->stmtList = pPreStmt; 14314a4c11aaSdan if( pDb->stmtLast==0 ){ 14324a4c11aaSdan assert( pDb->nStmt==0 ); 14334a4c11aaSdan pDb->stmtLast = pPreStmt; 14344a4c11aaSdan }else{ 14354a4c11aaSdan assert( pDb->nStmt>0 ); 14364a4c11aaSdan } 14374a4c11aaSdan pDb->nStmt++; 14384a4c11aaSdan 14394a4c11aaSdan /* If we have too many statement in cache, remove the surplus from 14404a4c11aaSdan ** the end of the cache list. */ 14414a4c11aaSdan while( pDb->nStmt>pDb->maxStmt ){ 1442c431fd55Sdan SqlPreparedStmt *pLast = pDb->stmtLast; 1443c431fd55Sdan pDb->stmtLast = pLast->pPrev; 14444a4c11aaSdan pDb->stmtLast->pNext = 0; 14454a4c11aaSdan pDb->nStmt--; 1446c431fd55Sdan dbFreeStmt(pLast); 14474a4c11aaSdan } 14484a4c11aaSdan } 14494a4c11aaSdan } 14504a4c11aaSdan 14514a4c11aaSdan /* 14524a4c11aaSdan ** Structure used with dbEvalXXX() functions: 14534a4c11aaSdan ** 14544a4c11aaSdan ** dbEvalInit() 14554a4c11aaSdan ** dbEvalStep() 14564a4c11aaSdan ** dbEvalFinalize() 14574a4c11aaSdan ** dbEvalRowInfo() 14584a4c11aaSdan ** dbEvalColumnValue() 14594a4c11aaSdan */ 14604a4c11aaSdan typedef struct DbEvalContext DbEvalContext; 14614a4c11aaSdan struct DbEvalContext { 14624a4c11aaSdan SqliteDb *pDb; /* Database handle */ 14634a4c11aaSdan Tcl_Obj *pSql; /* Object holding string zSql */ 14644a4c11aaSdan const char *zSql; /* Remaining SQL to execute */ 14654a4c11aaSdan SqlPreparedStmt *pPreStmt; /* Current statement */ 14664a4c11aaSdan int nCol; /* Number of columns returned by pStmt */ 1467af38cdbcSdrh int evalFlags; /* Flags used */ 14684a4c11aaSdan Tcl_Obj *pArray; /* Name of array variable */ 14694a4c11aaSdan Tcl_Obj **apColName; /* Array of column names */ 14704a4c11aaSdan }; 14714a4c11aaSdan 1472af38cdbcSdrh #define SQLITE_EVAL_WITHOUTNULLS 0x00001 /* Unset array(*) for NULL */ 1473af38cdbcSdrh 14744a4c11aaSdan /* 14754a4c11aaSdan ** Release any cache of column names currently held as part of 14764a4c11aaSdan ** the DbEvalContext structure passed as the first argument. 14774a4c11aaSdan */ 14784a4c11aaSdan static void dbReleaseColumnNames(DbEvalContext *p){ 14794a4c11aaSdan if( p->apColName ){ 14804a4c11aaSdan int i; 14814a4c11aaSdan for(i=0; i<p->nCol; i++){ 14824a4c11aaSdan Tcl_DecrRefCount(p->apColName[i]); 14834a4c11aaSdan } 14844a4c11aaSdan Tcl_Free((char *)p->apColName); 14854a4c11aaSdan p->apColName = 0; 14864a4c11aaSdan } 14874a4c11aaSdan p->nCol = 0; 14884a4c11aaSdan } 14894a4c11aaSdan 14904a4c11aaSdan /* 14914a4c11aaSdan ** Initialize a DbEvalContext structure. 14928e556520Sdanielk1977 ** 14938e556520Sdanielk1977 ** If pArray is not NULL, then it contains the name of a Tcl array 14948e556520Sdanielk1977 ** variable. The "*" member of this array is set to a list containing 14954a4c11aaSdan ** the names of the columns returned by the statement as part of each 14964a4c11aaSdan ** call to dbEvalStep(), in order from left to right. e.g. if the names 14974a4c11aaSdan ** of the returned columns are a, b and c, it does the equivalent of the 14984a4c11aaSdan ** tcl command: 14998e556520Sdanielk1977 ** 15008e556520Sdanielk1977 ** set ${pArray}(*) {a b c} 15018e556520Sdanielk1977 */ 15024a4c11aaSdan static void dbEvalInit( 15034a4c11aaSdan DbEvalContext *p, /* Pointer to structure to initialize */ 15044a4c11aaSdan SqliteDb *pDb, /* Database handle */ 15054a4c11aaSdan Tcl_Obj *pSql, /* Object containing SQL script */ 1506af38cdbcSdrh Tcl_Obj *pArray, /* Name of Tcl array to set (*) element of */ 1507af38cdbcSdrh int evalFlags /* Flags controlling evaluation */ 15088e556520Sdanielk1977 ){ 15094a4c11aaSdan memset(p, 0, sizeof(DbEvalContext)); 15104a4c11aaSdan p->pDb = pDb; 15114a4c11aaSdan p->zSql = Tcl_GetString(pSql); 15124a4c11aaSdan p->pSql = pSql; 15134a4c11aaSdan Tcl_IncrRefCount(pSql); 15144a4c11aaSdan if( pArray ){ 15154a4c11aaSdan p->pArray = pArray; 15164a4c11aaSdan Tcl_IncrRefCount(pArray); 15174a4c11aaSdan } 1518af38cdbcSdrh p->evalFlags = evalFlags; 15194a4c11aaSdan } 15208e556520Sdanielk1977 15214a4c11aaSdan /* 15224a4c11aaSdan ** Obtain information about the row that the DbEvalContext passed as the 15234a4c11aaSdan ** first argument currently points to. 15244a4c11aaSdan */ 15254a4c11aaSdan static void dbEvalRowInfo( 15264a4c11aaSdan DbEvalContext *p, /* Evaluation context */ 15274a4c11aaSdan int *pnCol, /* OUT: Number of column names */ 15284a4c11aaSdan Tcl_Obj ***papColName /* OUT: Array of column names */ 15294a4c11aaSdan ){ 15308e556520Sdanielk1977 /* Compute column names */ 15314a4c11aaSdan if( 0==p->apColName ){ 15324a4c11aaSdan sqlite3_stmt *pStmt = p->pPreStmt->pStmt; 15334a4c11aaSdan int i; /* Iterator variable */ 15344a4c11aaSdan int nCol; /* Number of columns returned by pStmt */ 15354a4c11aaSdan Tcl_Obj **apColName = 0; /* Array of column names */ 15364a4c11aaSdan 15374a4c11aaSdan p->nCol = nCol = sqlite3_column_count(pStmt); 15384a4c11aaSdan if( nCol>0 && (papColName || p->pArray) ){ 15394a4c11aaSdan apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol ); 15408e556520Sdanielk1977 for(i=0; i<nCol; i++){ 1541c45e6716Sdrh apColName[i] = Tcl_NewStringObj(sqlite3_column_name(pStmt,i), -1); 15428e556520Sdanielk1977 Tcl_IncrRefCount(apColName[i]); 15438e556520Sdanielk1977 } 15444a4c11aaSdan p->apColName = apColName; 15454a4c11aaSdan } 15468e556520Sdanielk1977 15478e556520Sdanielk1977 /* If results are being stored in an array variable, then create 15488e556520Sdanielk1977 ** the array(*) entry for that array 15498e556520Sdanielk1977 */ 15504a4c11aaSdan if( p->pArray ){ 15514a4c11aaSdan Tcl_Interp *interp = p->pDb->interp; 15528e556520Sdanielk1977 Tcl_Obj *pColList = Tcl_NewObj(); 15538e556520Sdanielk1977 Tcl_Obj *pStar = Tcl_NewStringObj("*", -1); 15544a4c11aaSdan 15558e556520Sdanielk1977 for(i=0; i<nCol; i++){ 15568e556520Sdanielk1977 Tcl_ListObjAppendElement(interp, pColList, apColName[i]); 15578e556520Sdanielk1977 } 15588e556520Sdanielk1977 Tcl_IncrRefCount(pStar); 15594a4c11aaSdan Tcl_ObjSetVar2(interp, p->pArray, pStar, pColList, 0); 15608e556520Sdanielk1977 Tcl_DecrRefCount(pStar); 15618e556520Sdanielk1977 } 15628e556520Sdanielk1977 } 15638e556520Sdanielk1977 15644a4c11aaSdan if( papColName ){ 15654a4c11aaSdan *papColName = p->apColName; 15664a4c11aaSdan } 15674a4c11aaSdan if( pnCol ){ 15684a4c11aaSdan *pnCol = p->nCol; 15694a4c11aaSdan } 15704a4c11aaSdan } 15714a4c11aaSdan 15724a4c11aaSdan /* 15734a4c11aaSdan ** Return one of TCL_OK, TCL_BREAK or TCL_ERROR. If TCL_ERROR is 15744a4c11aaSdan ** returned, then an error message is stored in the interpreter before 15754a4c11aaSdan ** returning. 15764a4c11aaSdan ** 15774a4c11aaSdan ** A return value of TCL_OK means there is a row of data available. The 15784a4c11aaSdan ** data may be accessed using dbEvalRowInfo() and dbEvalColumnValue(). This 15794a4c11aaSdan ** is analogous to a return of SQLITE_ROW from sqlite3_step(). If TCL_BREAK 15804a4c11aaSdan ** is returned, then the SQL script has finished executing and there are 15814a4c11aaSdan ** no further rows available. This is similar to SQLITE_DONE. 15824a4c11aaSdan */ 15834a4c11aaSdan static int dbEvalStep(DbEvalContext *p){ 1584c431fd55Sdan const char *zPrevSql = 0; /* Previous value of p->zSql */ 1585c431fd55Sdan 15864a4c11aaSdan while( p->zSql[0] || p->pPreStmt ){ 15874a4c11aaSdan int rc; 15884a4c11aaSdan if( p->pPreStmt==0 ){ 1589c431fd55Sdan zPrevSql = (p->zSql==zPrevSql ? 0 : p->zSql); 15904a4c11aaSdan rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt); 15914a4c11aaSdan if( rc!=TCL_OK ) return rc; 15924a4c11aaSdan }else{ 15934a4c11aaSdan int rcs; 15944a4c11aaSdan SqliteDb *pDb = p->pDb; 15954a4c11aaSdan SqlPreparedStmt *pPreStmt = p->pPreStmt; 15964a4c11aaSdan sqlite3_stmt *pStmt = pPreStmt->pStmt; 15974a4c11aaSdan 15984a4c11aaSdan rcs = sqlite3_step(pStmt); 15994a4c11aaSdan if( rcs==SQLITE_ROW ){ 16004a4c11aaSdan return TCL_OK; 16014a4c11aaSdan } 16024a4c11aaSdan if( p->pArray ){ 16034a4c11aaSdan dbEvalRowInfo(p, 0, 0); 16044a4c11aaSdan } 16054a4c11aaSdan rcs = sqlite3_reset(pStmt); 16064a4c11aaSdan 16074a4c11aaSdan pDb->nStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_FULLSCAN_STEP,1); 16084a4c11aaSdan pDb->nSort = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_SORT,1); 16093c379b01Sdrh pDb->nIndex = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_AUTOINDEX,1); 1610c456a76fSdan pDb->nVMStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_VM_STEP,1); 16114a4c11aaSdan dbReleaseColumnNames(p); 16124a4c11aaSdan p->pPreStmt = 0; 16134a4c11aaSdan 16144a4c11aaSdan if( rcs!=SQLITE_OK ){ 16154a4c11aaSdan /* If a run-time error occurs, report the error and stop reading 16164a4c11aaSdan ** the SQL. */ 16174a4c11aaSdan dbReleaseStmt(pDb, pPreStmt, 1); 1618c431fd55Sdan #if SQLITE_TEST 1619c431fd55Sdan if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){ 1620c431fd55Sdan /* If the runtime error was an SQLITE_SCHEMA, and the database 1621c431fd55Sdan ** handle is configured to use the legacy sqlite3_prepare() 1622c431fd55Sdan ** interface, retry prepare()/step() on the same SQL statement. 1623c431fd55Sdan ** This only happens once. If there is a second SQLITE_SCHEMA 1624c431fd55Sdan ** error, the error will be returned to the caller. */ 1625c431fd55Sdan p->zSql = zPrevSql; 1626c431fd55Sdan continue; 1627c431fd55Sdan } 1628c431fd55Sdan #endif 1629c45e6716Sdrh Tcl_SetObjResult(pDb->interp, 1630c45e6716Sdrh Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); 16314a4c11aaSdan return TCL_ERROR; 16324a4c11aaSdan }else{ 16334a4c11aaSdan dbReleaseStmt(pDb, pPreStmt, 0); 16344a4c11aaSdan } 16354a4c11aaSdan } 16364a4c11aaSdan } 16374a4c11aaSdan 16384a4c11aaSdan /* Finished */ 16394a4c11aaSdan return TCL_BREAK; 16404a4c11aaSdan } 16414a4c11aaSdan 16424a4c11aaSdan /* 16434a4c11aaSdan ** Free all resources currently held by the DbEvalContext structure passed 16444a4c11aaSdan ** as the first argument. There should be exactly one call to this function 16454a4c11aaSdan ** for each call to dbEvalInit(). 16464a4c11aaSdan */ 16474a4c11aaSdan static void dbEvalFinalize(DbEvalContext *p){ 16484a4c11aaSdan if( p->pPreStmt ){ 16494a4c11aaSdan sqlite3_reset(p->pPreStmt->pStmt); 16504a4c11aaSdan dbReleaseStmt(p->pDb, p->pPreStmt, 0); 16514a4c11aaSdan p->pPreStmt = 0; 16524a4c11aaSdan } 16534a4c11aaSdan if( p->pArray ){ 16544a4c11aaSdan Tcl_DecrRefCount(p->pArray); 16554a4c11aaSdan p->pArray = 0; 16564a4c11aaSdan } 16574a4c11aaSdan Tcl_DecrRefCount(p->pSql); 16584a4c11aaSdan dbReleaseColumnNames(p); 16594a4c11aaSdan } 16604a4c11aaSdan 16614a4c11aaSdan /* 16624a4c11aaSdan ** Return a pointer to a Tcl_Obj structure with ref-count 0 that contains 16634a4c11aaSdan ** the value for the iCol'th column of the row currently pointed to by 16644a4c11aaSdan ** the DbEvalContext structure passed as the first argument. 16654a4c11aaSdan */ 16664a4c11aaSdan static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){ 16674a4c11aaSdan sqlite3_stmt *pStmt = p->pPreStmt->pStmt; 16684a4c11aaSdan switch( sqlite3_column_type(pStmt, iCol) ){ 16694a4c11aaSdan case SQLITE_BLOB: { 16704a4c11aaSdan int bytes = sqlite3_column_bytes(pStmt, iCol); 16714a4c11aaSdan const char *zBlob = sqlite3_column_blob(pStmt, iCol); 16724a4c11aaSdan if( !zBlob ) bytes = 0; 16734a4c11aaSdan return Tcl_NewByteArrayObj((u8*)zBlob, bytes); 16744a4c11aaSdan } 16754a4c11aaSdan case SQLITE_INTEGER: { 16764a4c11aaSdan sqlite_int64 v = sqlite3_column_int64(pStmt, iCol); 16774a4c11aaSdan if( v>=-2147483647 && v<=2147483647 ){ 16787fd33929Sdrh return Tcl_NewIntObj((int)v); 16794a4c11aaSdan }else{ 16804a4c11aaSdan return Tcl_NewWideIntObj(v); 16814a4c11aaSdan } 16824a4c11aaSdan } 16834a4c11aaSdan case SQLITE_FLOAT: { 16844a4c11aaSdan return Tcl_NewDoubleObj(sqlite3_column_double(pStmt, iCol)); 16854a4c11aaSdan } 16864a4c11aaSdan case SQLITE_NULL: { 1687c45e6716Sdrh return Tcl_NewStringObj(p->pDb->zNull, -1); 16884a4c11aaSdan } 16894a4c11aaSdan } 16904a4c11aaSdan 1691325eff58Sdrh return Tcl_NewStringObj((char*)sqlite3_column_text(pStmt, iCol), -1); 16924a4c11aaSdan } 16934a4c11aaSdan 16944a4c11aaSdan /* 16954a4c11aaSdan ** If using Tcl version 8.6 or greater, use the NR functions to avoid 16964a4c11aaSdan ** recursive evalution of scripts by the [db eval] and [db trans] 16974a4c11aaSdan ** commands. Even if the headers used while compiling the extension 16984a4c11aaSdan ** are 8.6 or newer, the code still tests the Tcl version at runtime. 16994a4c11aaSdan ** This allows stubs-enabled builds to be used with older Tcl libraries. 17004a4c11aaSdan */ 17014a4c11aaSdan #if TCL_MAJOR_VERSION>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6) 1702a2c8a95bSdrh # define SQLITE_TCL_NRE 1 17034a4c11aaSdan static int DbUseNre(void){ 17044a4c11aaSdan int major, minor; 17054a4c11aaSdan Tcl_GetVersion(&major, &minor, 0, 0); 17064a4c11aaSdan return( (major==8 && minor>=6) || major>8 ); 17074a4c11aaSdan } 17084a4c11aaSdan #else 17094a4c11aaSdan /* 17104a4c11aaSdan ** Compiling using headers earlier than 8.6. In this case NR cannot be 17114a4c11aaSdan ** used, so DbUseNre() to always return zero. Add #defines for the other 17124a4c11aaSdan ** Tcl_NRxxx() functions to prevent them from causing compilation errors, 17134a4c11aaSdan ** even though the only invocations of them are within conditional blocks 17144a4c11aaSdan ** of the form: 17154a4c11aaSdan ** 17164a4c11aaSdan ** if( DbUseNre() ) { ... } 17174a4c11aaSdan */ 1718a2c8a95bSdrh # define SQLITE_TCL_NRE 0 17194a4c11aaSdan # define DbUseNre() 0 1720a47941feSdrh # define Tcl_NRAddCallback(a,b,c,d,e,f) (void)0 17214a4c11aaSdan # define Tcl_NREvalObj(a,b,c) 0 1722a47941feSdrh # define Tcl_NRCreateCommand(a,b,c,d,e,f) (void)0 17234a4c11aaSdan #endif 17244a4c11aaSdan 17254a4c11aaSdan /* 17264a4c11aaSdan ** This function is part of the implementation of the command: 17274a4c11aaSdan ** 17284a4c11aaSdan ** $db eval SQL ?ARRAYNAME? SCRIPT 17294a4c11aaSdan */ 1730a121cc7cSmistachkin static int SQLITE_TCLAPI DbEvalNextCmd( 17314a4c11aaSdan ClientData data[], /* data[0] is the (DbEvalContext*) */ 17324a4c11aaSdan Tcl_Interp *interp, /* Tcl interpreter */ 17334a4c11aaSdan int result /* Result so far */ 17344a4c11aaSdan ){ 17354a4c11aaSdan int rc = result; /* Return code */ 17364a4c11aaSdan 17374a4c11aaSdan /* The first element of the data[] array is a pointer to a DbEvalContext 17384a4c11aaSdan ** structure allocated using Tcl_Alloc(). The second element of data[] 17394a4c11aaSdan ** is a pointer to a Tcl_Obj containing the script to run for each row 17404a4c11aaSdan ** returned by the queries encapsulated in data[0]. */ 17414a4c11aaSdan DbEvalContext *p = (DbEvalContext *)data[0]; 17424a4c11aaSdan Tcl_Obj *pScript = (Tcl_Obj *)data[1]; 17434a4c11aaSdan Tcl_Obj *pArray = p->pArray; 17444a4c11aaSdan 17454a4c11aaSdan while( (rc==TCL_OK || rc==TCL_CONTINUE) && TCL_OK==(rc = dbEvalStep(p)) ){ 17464a4c11aaSdan int i; 17474a4c11aaSdan int nCol; 17484a4c11aaSdan Tcl_Obj **apColName; 17494a4c11aaSdan dbEvalRowInfo(p, &nCol, &apColName); 17504a4c11aaSdan for(i=0; i<nCol; i++){ 17514a4c11aaSdan if( pArray==0 ){ 1752af38cdbcSdrh Tcl_ObjSetVar2(interp, apColName[i], 0, dbEvalColumnValue(p,i), 0); 1753af38cdbcSdrh }else if( (p->evalFlags & SQLITE_EVAL_WITHOUTNULLS)!=0 1754af38cdbcSdrh && sqlite3_column_type(p->pPreStmt->pStmt, i)==SQLITE_NULL 1755af38cdbcSdrh ){ 1756af38cdbcSdrh Tcl_UnsetVar2(interp, Tcl_GetString(pArray), 1757af38cdbcSdrh Tcl_GetString(apColName[i]), 0); 17584a4c11aaSdan }else{ 1759af38cdbcSdrh Tcl_ObjSetVar2(interp, pArray, apColName[i], dbEvalColumnValue(p,i), 0); 17604a4c11aaSdan } 17614a4c11aaSdan } 17624a4c11aaSdan 17634a4c11aaSdan /* The required interpreter variables are now populated with the data 17644a4c11aaSdan ** from the current row. If using NRE, schedule callbacks to evaluate 17654a4c11aaSdan ** script pScript, then to invoke this function again to fetch the next 17664a4c11aaSdan ** row (or clean up if there is no next row or the script throws an 17674a4c11aaSdan ** exception). After scheduling the callbacks, return control to the 17684a4c11aaSdan ** caller. 17694a4c11aaSdan ** 17704a4c11aaSdan ** If not using NRE, evaluate pScript directly and continue with the 17714a4c11aaSdan ** next iteration of this while(...) loop. */ 17724a4c11aaSdan if( DbUseNre() ){ 17734a4c11aaSdan Tcl_NRAddCallback(interp, DbEvalNextCmd, (void*)p, (void*)pScript, 0, 0); 17744a4c11aaSdan return Tcl_NREvalObj(interp, pScript, 0); 17754a4c11aaSdan }else{ 17764a4c11aaSdan rc = Tcl_EvalObjEx(interp, pScript, 0); 17774a4c11aaSdan } 17784a4c11aaSdan } 17794a4c11aaSdan 17804a4c11aaSdan Tcl_DecrRefCount(pScript); 17814a4c11aaSdan dbEvalFinalize(p); 17824a4c11aaSdan Tcl_Free((char *)p); 17834a4c11aaSdan 17844a4c11aaSdan if( rc==TCL_OK || rc==TCL_BREAK ){ 17854a4c11aaSdan Tcl_ResetResult(interp); 17864a4c11aaSdan rc = TCL_OK; 17874a4c11aaSdan } 17884a4c11aaSdan return rc; 17898e556520Sdanielk1977 } 17908e556520Sdanielk1977 17911067fe11Stpoindex /* 179246c47d46Sdan ** This function is used by the implementations of the following database 179346c47d46Sdan ** handle sub-commands: 179446c47d46Sdan ** 179546c47d46Sdan ** $db update_hook ?SCRIPT? 179646c47d46Sdan ** $db wal_hook ?SCRIPT? 179746c47d46Sdan ** $db commit_hook ?SCRIPT? 179846c47d46Sdan ** $db preupdate hook ?SCRIPT? 179946c47d46Sdan */ 180046c47d46Sdan static void DbHookCmd( 180146c47d46Sdan Tcl_Interp *interp, /* Tcl interpreter */ 180246c47d46Sdan SqliteDb *pDb, /* Database handle */ 180346c47d46Sdan Tcl_Obj *pArg, /* SCRIPT argument (or NULL) */ 180446c47d46Sdan Tcl_Obj **ppHook /* Pointer to member of SqliteDb */ 180546c47d46Sdan ){ 180646c47d46Sdan sqlite3 *db = pDb->db; 180746c47d46Sdan 180846c47d46Sdan if( *ppHook ){ 180946c47d46Sdan Tcl_SetObjResult(interp, *ppHook); 181046c47d46Sdan if( pArg ){ 181146c47d46Sdan Tcl_DecrRefCount(*ppHook); 181246c47d46Sdan *ppHook = 0; 181346c47d46Sdan } 181446c47d46Sdan } 181546c47d46Sdan if( pArg ){ 181646c47d46Sdan assert( !(*ppHook) ); 181746c47d46Sdan if( Tcl_GetCharLength(pArg)>0 ){ 181846c47d46Sdan *ppHook = pArg; 181946c47d46Sdan Tcl_IncrRefCount(*ppHook); 182046c47d46Sdan } 182146c47d46Sdan } 182246c47d46Sdan 18239b1c62d4Sdrh #ifdef SQLITE_ENABLE_PREUPDATE_HOOK 182446c47d46Sdan sqlite3_preupdate_hook(db, (pDb->pPreUpdateHook?DbPreUpdateHandler:0), pDb); 18259b1c62d4Sdrh #endif 182646c47d46Sdan sqlite3_update_hook(db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb); 182746c47d46Sdan sqlite3_rollback_hook(db, (pDb->pRollbackHook?DbRollbackHandler:0), pDb); 182846c47d46Sdan sqlite3_wal_hook(db, (pDb->pWalHook?DbWalHandler:0), pDb); 182946c47d46Sdan } 183046c47d46Sdan 183146c47d46Sdan /* 183275897234Sdrh ** The "sqlite" command below creates a new Tcl command for each 183375897234Sdrh ** connection it opens to an SQLite database. This routine is invoked 183475897234Sdrh ** whenever one of those connection-specific commands is executed 183575897234Sdrh ** in Tcl. For example, if you run Tcl code like this: 183675897234Sdrh ** 18379bb575fdSdrh ** sqlite3 db1 "my_database" 183875897234Sdrh ** db1 close 183975897234Sdrh ** 184075897234Sdrh ** The first command opens a connection to the "my_database" database 184175897234Sdrh ** and calls that connection "db1". The second command causes this 184275897234Sdrh ** subroutine to be invoked. 184375897234Sdrh */ 18447617e4a8Smistachkin static int SQLITE_TCLAPI DbObjCmd( 18457617e4a8Smistachkin void *cd, 18467617e4a8Smistachkin Tcl_Interp *interp, 18477617e4a8Smistachkin int objc, 18487617e4a8Smistachkin Tcl_Obj *const*objv 18497617e4a8Smistachkin ){ 1850bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 18516d31316cSdrh int choice; 185222fbcb8dSdrh int rc = TCL_OK; 18530de8c112Sdrh static const char *DB_strs[] = { 1854dc2c4915Sdrh "authorizer", "backup", "busy", 1855dc2c4915Sdrh "cache", "changes", "close", 1856dc2c4915Sdrh "collate", "collation_needed", "commit_hook", 1857cb7d541dSdrh "complete", "copy", "deserialize", 1858cb7d541dSdrh "enable_load_extension", "errorcode", "eval", 1859cb7d541dSdrh "exists", "function", "incrblob", 18603ec8665eSdrh "interrupt", "last_insert_rowid", "nullvalue", 18613ec8665eSdrh "onecolumn", "preupdate", "profile", 18623ec8665eSdrh "progress", "rekey", "restore", 18633ec8665eSdrh "rollback_hook", "serialize", "status", 18643ec8665eSdrh "timeout", "total_changes", "trace", 18653ec8665eSdrh "trace_v2", "transaction", "unlock_notify", 18663ec8665eSdrh "update_hook", "version", "wal_hook", 18673ec8665eSdrh 0 18686d31316cSdrh }; 1869411995dcSdrh enum DB_enum { 1870dc2c4915Sdrh DB_AUTHORIZER, DB_BACKUP, DB_BUSY, 1871dc2c4915Sdrh DB_CACHE, DB_CHANGES, DB_CLOSE, 1872dc2c4915Sdrh DB_COLLATE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK, 1873cb7d541dSdrh DB_COMPLETE, DB_COPY, DB_DESERIALIZE, 1874cb7d541dSdrh DB_ENABLE_LOAD_EXTENSION, DB_ERRORCODE, DB_EVAL, 1875cb7d541dSdrh DB_EXISTS, DB_FUNCTION, DB_INCRBLOB, 18763ec8665eSdrh DB_INTERRUPT, DB_LAST_INSERT_ROWID, DB_NULLVALUE, 18773ec8665eSdrh DB_ONECOLUMN, DB_PREUPDATE, DB_PROFILE, 18783ec8665eSdrh DB_PROGRESS, DB_REKEY, DB_RESTORE, 18793ec8665eSdrh DB_ROLLBACK_HOOK, DB_SERIALIZE, DB_STATUS, 18803ec8665eSdrh DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, 18813ec8665eSdrh DB_TRACE_V2, DB_TRANSACTION, DB_UNLOCK_NOTIFY, 18823ec8665eSdrh DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK 18836d31316cSdrh }; 18841067fe11Stpoindex /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ 18856d31316cSdrh 18866d31316cSdrh if( objc<2 ){ 18876d31316cSdrh Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); 188875897234Sdrh return TCL_ERROR; 188975897234Sdrh } 1890411995dcSdrh if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){ 18916d31316cSdrh return TCL_ERROR; 18926d31316cSdrh } 18936d31316cSdrh 1894411995dcSdrh switch( (enum DB_enum)choice ){ 189575897234Sdrh 1896e22a334bSdrh /* $db authorizer ?CALLBACK? 1897e22a334bSdrh ** 1898e22a334bSdrh ** Invoke the given callback to authorize each SQL operation as it is 1899e22a334bSdrh ** compiled. 5 arguments are appended to the callback before it is 1900e22a334bSdrh ** invoked: 1901e22a334bSdrh ** 1902e22a334bSdrh ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...) 1903e22a334bSdrh ** (2) First descriptive name (depends on authorization type) 1904e22a334bSdrh ** (3) Second descriptive name 1905e22a334bSdrh ** (4) Name of the database (ex: "main", "temp") 1906e22a334bSdrh ** (5) Name of trigger that is doing the access 1907e22a334bSdrh ** 1908e22a334bSdrh ** The callback should return on of the following strings: SQLITE_OK, 1909e22a334bSdrh ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error. 1910e22a334bSdrh ** 1911e22a334bSdrh ** If this method is invoked with no arguments, the current authorization 1912e22a334bSdrh ** callback string is returned. 1913e22a334bSdrh */ 1914e22a334bSdrh case DB_AUTHORIZER: { 19151211de37Sdrh #ifdef SQLITE_OMIT_AUTHORIZATION 1916a198f2b5Sdrh Tcl_AppendResult(interp, "authorization not available in this build", 1917a198f2b5Sdrh (char*)0); 19181211de37Sdrh return TCL_ERROR; 19191211de37Sdrh #else 1920e22a334bSdrh if( objc>3 ){ 1921e22a334bSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 19220f14e2ebSdrh return TCL_ERROR; 1923e22a334bSdrh }else if( objc==2 ){ 1924b5a20d3cSdrh if( pDb->zAuth ){ 1925a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zAuth, (char*)0); 1926e22a334bSdrh } 1927e22a334bSdrh }else{ 1928e22a334bSdrh char *zAuth; 1929e22a334bSdrh int len; 1930e22a334bSdrh if( pDb->zAuth ){ 1931e22a334bSdrh Tcl_Free(pDb->zAuth); 1932e22a334bSdrh } 1933e22a334bSdrh zAuth = Tcl_GetStringFromObj(objv[2], &len); 1934e22a334bSdrh if( zAuth && len>0 ){ 1935e22a334bSdrh pDb->zAuth = Tcl_Alloc( len + 1 ); 19365bb3eb9bSdrh memcpy(pDb->zAuth, zAuth, len+1); 1937e22a334bSdrh }else{ 1938e22a334bSdrh pDb->zAuth = 0; 1939e22a334bSdrh } 1940e22a334bSdrh if( pDb->zAuth ){ 194132c6a48bSdrh typedef int (*sqlite3_auth_cb)( 194232c6a48bSdrh void*,int,const char*,const char*, 194332c6a48bSdrh const char*,const char*); 1944e22a334bSdrh pDb->interp = interp; 194532c6a48bSdrh sqlite3_set_authorizer(pDb->db,(sqlite3_auth_cb)auth_callback,pDb); 1946e22a334bSdrh }else{ 19476f8a503dSdanielk1977 sqlite3_set_authorizer(pDb->db, 0, 0); 1948e22a334bSdrh } 1949e22a334bSdrh } 19501211de37Sdrh #endif 1951e22a334bSdrh break; 1952e22a334bSdrh } 1953e22a334bSdrh 1954dc2c4915Sdrh /* $db backup ?DATABASE? FILENAME 1955dc2c4915Sdrh ** 1956dc2c4915Sdrh ** Open or create a database file named FILENAME. Transfer the 1957dc2c4915Sdrh ** content of local database DATABASE (default: "main") into the 1958dc2c4915Sdrh ** FILENAME database. 1959dc2c4915Sdrh */ 1960dc2c4915Sdrh case DB_BACKUP: { 1961dc2c4915Sdrh const char *zDestFile; 1962dc2c4915Sdrh const char *zSrcDb; 1963dc2c4915Sdrh sqlite3 *pDest; 1964dc2c4915Sdrh sqlite3_backup *pBackup; 1965dc2c4915Sdrh 1966dc2c4915Sdrh if( objc==3 ){ 1967dc2c4915Sdrh zSrcDb = "main"; 1968dc2c4915Sdrh zDestFile = Tcl_GetString(objv[2]); 1969dc2c4915Sdrh }else if( objc==4 ){ 1970dc2c4915Sdrh zSrcDb = Tcl_GetString(objv[2]); 1971dc2c4915Sdrh zDestFile = Tcl_GetString(objv[3]); 1972dc2c4915Sdrh }else{ 1973dc2c4915Sdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME"); 1974dc2c4915Sdrh return TCL_ERROR; 1975dc2c4915Sdrh } 1976147ef394Sdrh rc = sqlite3_open_v2(zDestFile, &pDest, 1977147ef394Sdrh SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE| pDb->openFlags, 0); 1978dc2c4915Sdrh if( rc!=SQLITE_OK ){ 1979dc2c4915Sdrh Tcl_AppendResult(interp, "cannot open target database: ", 1980dc2c4915Sdrh sqlite3_errmsg(pDest), (char*)0); 1981dc2c4915Sdrh sqlite3_close(pDest); 1982dc2c4915Sdrh return TCL_ERROR; 1983dc2c4915Sdrh } 1984dc2c4915Sdrh pBackup = sqlite3_backup_init(pDest, "main", pDb->db, zSrcDb); 1985dc2c4915Sdrh if( pBackup==0 ){ 1986dc2c4915Sdrh Tcl_AppendResult(interp, "backup failed: ", 1987dc2c4915Sdrh sqlite3_errmsg(pDest), (char*)0); 1988dc2c4915Sdrh sqlite3_close(pDest); 1989dc2c4915Sdrh return TCL_ERROR; 1990dc2c4915Sdrh } 1991dc2c4915Sdrh while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} 1992dc2c4915Sdrh sqlite3_backup_finish(pBackup); 1993dc2c4915Sdrh if( rc==SQLITE_DONE ){ 1994dc2c4915Sdrh rc = TCL_OK; 1995dc2c4915Sdrh }else{ 1996dc2c4915Sdrh Tcl_AppendResult(interp, "backup failed: ", 1997dc2c4915Sdrh sqlite3_errmsg(pDest), (char*)0); 1998dc2c4915Sdrh rc = TCL_ERROR; 1999dc2c4915Sdrh } 2000dc2c4915Sdrh sqlite3_close(pDest); 2001dc2c4915Sdrh break; 2002dc2c4915Sdrh } 2003dc2c4915Sdrh 2004bec3f402Sdrh /* $db busy ?CALLBACK? 2005bec3f402Sdrh ** 2006bec3f402Sdrh ** Invoke the given callback if an SQL statement attempts to open 2007bec3f402Sdrh ** a locked database file. 2008bec3f402Sdrh */ 20096d31316cSdrh case DB_BUSY: { 20106d31316cSdrh if( objc>3 ){ 20116d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK"); 2012bec3f402Sdrh return TCL_ERROR; 20136d31316cSdrh }else if( objc==2 ){ 2014bec3f402Sdrh if( pDb->zBusy ){ 2015a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zBusy, (char*)0); 2016bec3f402Sdrh } 2017bec3f402Sdrh }else{ 20186d31316cSdrh char *zBusy; 20196d31316cSdrh int len; 2020bec3f402Sdrh if( pDb->zBusy ){ 2021bec3f402Sdrh Tcl_Free(pDb->zBusy); 20226d31316cSdrh } 20236d31316cSdrh zBusy = Tcl_GetStringFromObj(objv[2], &len); 20246d31316cSdrh if( zBusy && len>0 ){ 20256d31316cSdrh pDb->zBusy = Tcl_Alloc( len + 1 ); 20265bb3eb9bSdrh memcpy(pDb->zBusy, zBusy, len+1); 20276d31316cSdrh }else{ 2028bec3f402Sdrh pDb->zBusy = 0; 2029bec3f402Sdrh } 2030bec3f402Sdrh if( pDb->zBusy ){ 2031bec3f402Sdrh pDb->interp = interp; 20326f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb); 20336d31316cSdrh }else{ 20346f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, 0, 0); 2035bec3f402Sdrh } 2036bec3f402Sdrh } 20376d31316cSdrh break; 20386d31316cSdrh } 2039bec3f402Sdrh 2040fb7e7651Sdrh /* $db cache flush 2041fb7e7651Sdrh ** $db cache size n 2042fb7e7651Sdrh ** 2043fb7e7651Sdrh ** Flush the prepared statement cache, or set the maximum number of 2044fb7e7651Sdrh ** cached statements. 2045fb7e7651Sdrh */ 2046fb7e7651Sdrh case DB_CACHE: { 2047fb7e7651Sdrh char *subCmd; 2048fb7e7651Sdrh int n; 2049fb7e7651Sdrh 2050fb7e7651Sdrh if( objc<=2 ){ 2051fb7e7651Sdrh Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?"); 2052fb7e7651Sdrh return TCL_ERROR; 2053fb7e7651Sdrh } 2054fb7e7651Sdrh subCmd = Tcl_GetStringFromObj( objv[2], 0 ); 2055fb7e7651Sdrh if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){ 2056fb7e7651Sdrh if( objc!=3 ){ 2057fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "flush"); 2058fb7e7651Sdrh return TCL_ERROR; 2059fb7e7651Sdrh }else{ 2060fb7e7651Sdrh flushStmtCache( pDb ); 2061fb7e7651Sdrh } 2062fb7e7651Sdrh }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){ 2063fb7e7651Sdrh if( objc!=4 ){ 2064fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "size n"); 2065fb7e7651Sdrh return TCL_ERROR; 2066fb7e7651Sdrh }else{ 2067fb7e7651Sdrh if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ 2068fb7e7651Sdrh Tcl_AppendResult( interp, "cannot convert \"", 2069a198f2b5Sdrh Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0); 2070fb7e7651Sdrh return TCL_ERROR; 2071fb7e7651Sdrh }else{ 2072fb7e7651Sdrh if( n<0 ){ 2073fb7e7651Sdrh flushStmtCache( pDb ); 2074fb7e7651Sdrh n = 0; 2075fb7e7651Sdrh }else if( n>MAX_PREPARED_STMTS ){ 2076fb7e7651Sdrh n = MAX_PREPARED_STMTS; 2077fb7e7651Sdrh } 2078fb7e7651Sdrh pDb->maxStmt = n; 2079fb7e7651Sdrh } 2080fb7e7651Sdrh } 2081fb7e7651Sdrh }else{ 2082fb7e7651Sdrh Tcl_AppendResult( interp, "bad option \"", 2083a198f2b5Sdrh Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", 2084a198f2b5Sdrh (char*)0); 2085fb7e7651Sdrh return TCL_ERROR; 2086fb7e7651Sdrh } 2087fb7e7651Sdrh break; 2088fb7e7651Sdrh } 2089fb7e7651Sdrh 2090b28af71aSdanielk1977 /* $db changes 2091c8d30ac1Sdrh ** 2092c8d30ac1Sdrh ** Return the number of rows that were modified, inserted, or deleted by 2093b28af71aSdanielk1977 ** the most recent INSERT, UPDATE or DELETE statement, not including 2094b28af71aSdanielk1977 ** any changes made by trigger programs. 2095c8d30ac1Sdrh */ 2096c8d30ac1Sdrh case DB_CHANGES: { 2097c8d30ac1Sdrh Tcl_Obj *pResult; 2098c8d30ac1Sdrh if( objc!=2 ){ 2099c8d30ac1Sdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 2100c8d30ac1Sdrh return TCL_ERROR; 2101c8d30ac1Sdrh } 2102c8d30ac1Sdrh pResult = Tcl_GetObjResult(interp); 2103b28af71aSdanielk1977 Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db)); 2104f146a776Srdc break; 2105f146a776Srdc } 2106f146a776Srdc 210775897234Sdrh /* $db close 210875897234Sdrh ** 210975897234Sdrh ** Shutdown the database 211075897234Sdrh */ 21116d31316cSdrh case DB_CLOSE: { 21126d31316cSdrh Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0)); 21136d31316cSdrh break; 21146d31316cSdrh } 211575897234Sdrh 21160f14e2ebSdrh /* 21170f14e2ebSdrh ** $db collate NAME SCRIPT 21180f14e2ebSdrh ** 21190f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 21200f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 21210f14e2ebSdrh */ 21220f14e2ebSdrh case DB_COLLATE: { 21230f14e2ebSdrh SqlCollate *pCollate; 21240f14e2ebSdrh char *zName; 21250f14e2ebSdrh char *zScript; 21260f14e2ebSdrh int nScript; 21270f14e2ebSdrh if( objc!=4 ){ 21280f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 21290f14e2ebSdrh return TCL_ERROR; 21300f14e2ebSdrh } 21310f14e2ebSdrh zName = Tcl_GetStringFromObj(objv[2], 0); 21320f14e2ebSdrh zScript = Tcl_GetStringFromObj(objv[3], &nScript); 21330f14e2ebSdrh pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 ); 21340f14e2ebSdrh if( pCollate==0 ) return TCL_ERROR; 21350f14e2ebSdrh pCollate->interp = interp; 21360f14e2ebSdrh pCollate->pNext = pDb->pCollate; 21370f14e2ebSdrh pCollate->zScript = (char*)&pCollate[1]; 21380f14e2ebSdrh pDb->pCollate = pCollate; 21395bb3eb9bSdrh memcpy(pCollate->zScript, zScript, nScript+1); 21400f14e2ebSdrh if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8, 21410f14e2ebSdrh pCollate, tclSqlCollate) ){ 21429636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 21430f14e2ebSdrh return TCL_ERROR; 21440f14e2ebSdrh } 21450f14e2ebSdrh break; 21460f14e2ebSdrh } 21470f14e2ebSdrh 21480f14e2ebSdrh /* 21490f14e2ebSdrh ** $db collation_needed SCRIPT 21500f14e2ebSdrh ** 21510f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 21520f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 21530f14e2ebSdrh */ 21540f14e2ebSdrh case DB_COLLATION_NEEDED: { 21550f14e2ebSdrh if( objc!=3 ){ 21560f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT"); 21570f14e2ebSdrh return TCL_ERROR; 21580f14e2ebSdrh } 21590f14e2ebSdrh if( pDb->pCollateNeeded ){ 21600f14e2ebSdrh Tcl_DecrRefCount(pDb->pCollateNeeded); 21610f14e2ebSdrh } 21620f14e2ebSdrh pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]); 21630f14e2ebSdrh Tcl_IncrRefCount(pDb->pCollateNeeded); 21640f14e2ebSdrh sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded); 21650f14e2ebSdrh break; 21660f14e2ebSdrh } 21670f14e2ebSdrh 216819e2d37fSdrh /* $db commit_hook ?CALLBACK? 216919e2d37fSdrh ** 217019e2d37fSdrh ** Invoke the given callback just before committing every SQL transaction. 217119e2d37fSdrh ** If the callback throws an exception or returns non-zero, then the 217219e2d37fSdrh ** transaction is aborted. If CALLBACK is an empty string, the callback 217319e2d37fSdrh ** is disabled. 217419e2d37fSdrh */ 217519e2d37fSdrh case DB_COMMIT_HOOK: { 217619e2d37fSdrh if( objc>3 ){ 217719e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 217819e2d37fSdrh return TCL_ERROR; 217919e2d37fSdrh }else if( objc==2 ){ 218019e2d37fSdrh if( pDb->zCommit ){ 2181a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zCommit, (char*)0); 218219e2d37fSdrh } 218319e2d37fSdrh }else{ 21846ef5e12eSmistachkin const char *zCommit; 218519e2d37fSdrh int len; 218619e2d37fSdrh if( pDb->zCommit ){ 218719e2d37fSdrh Tcl_Free(pDb->zCommit); 218819e2d37fSdrh } 218919e2d37fSdrh zCommit = Tcl_GetStringFromObj(objv[2], &len); 219019e2d37fSdrh if( zCommit && len>0 ){ 219119e2d37fSdrh pDb->zCommit = Tcl_Alloc( len + 1 ); 21925bb3eb9bSdrh memcpy(pDb->zCommit, zCommit, len+1); 219319e2d37fSdrh }else{ 219419e2d37fSdrh pDb->zCommit = 0; 219519e2d37fSdrh } 219619e2d37fSdrh if( pDb->zCommit ){ 219719e2d37fSdrh pDb->interp = interp; 219819e2d37fSdrh sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb); 219919e2d37fSdrh }else{ 220019e2d37fSdrh sqlite3_commit_hook(pDb->db, 0, 0); 220119e2d37fSdrh } 220219e2d37fSdrh } 220319e2d37fSdrh break; 220419e2d37fSdrh } 220519e2d37fSdrh 220675897234Sdrh /* $db complete SQL 220775897234Sdrh ** 220875897234Sdrh ** Return TRUE if SQL is a complete SQL statement. Return FALSE if 220975897234Sdrh ** additional lines of input are needed. This is similar to the 221075897234Sdrh ** built-in "info complete" command of Tcl. 221175897234Sdrh */ 22126d31316cSdrh case DB_COMPLETE: { 2213ccae6026Sdrh #ifndef SQLITE_OMIT_COMPLETE 22146d31316cSdrh Tcl_Obj *pResult; 22156d31316cSdrh int isComplete; 22166d31316cSdrh if( objc!=3 ){ 22176d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 221875897234Sdrh return TCL_ERROR; 221975897234Sdrh } 22206f8a503dSdanielk1977 isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); 22216d31316cSdrh pResult = Tcl_GetObjResult(interp); 22226d31316cSdrh Tcl_SetBooleanObj(pResult, isComplete); 2223ccae6026Sdrh #endif 22246d31316cSdrh break; 22256d31316cSdrh } 222675897234Sdrh 222719e2d37fSdrh /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR? 222819e2d37fSdrh ** 222919e2d37fSdrh ** Copy data into table from filename, optionally using SEPARATOR 223019e2d37fSdrh ** as column separators. If a column contains a null string, or the 223119e2d37fSdrh ** value of NULLINDICATOR, a NULL is inserted for the column. 223219e2d37fSdrh ** conflict-algorithm is one of the sqlite conflict algorithms: 223319e2d37fSdrh ** rollback, abort, fail, ignore, replace 223419e2d37fSdrh ** On success, return the number of lines processed, not necessarily same 223519e2d37fSdrh ** as 'db changes' due to conflict-algorithm selected. 223619e2d37fSdrh ** 223719e2d37fSdrh ** This code is basically an implementation/enhancement of 223819e2d37fSdrh ** the sqlite3 shell.c ".import" command. 223919e2d37fSdrh ** 224019e2d37fSdrh ** This command usage is equivalent to the sqlite2.x COPY statement, 224119e2d37fSdrh ** which imports file data into a table using the PostgreSQL COPY file format: 224219e2d37fSdrh ** $db copy $conflit_algo $table_name $filename \t \\N 224319e2d37fSdrh */ 224419e2d37fSdrh case DB_COPY: { 224519e2d37fSdrh char *zTable; /* Insert data into this table */ 224619e2d37fSdrh char *zFile; /* The file from which to extract data */ 224719e2d37fSdrh char *zConflict; /* The conflict algorithm to use */ 224819e2d37fSdrh sqlite3_stmt *pStmt; /* A statement */ 224919e2d37fSdrh int nCol; /* Number of columns in the table */ 225019e2d37fSdrh int nByte; /* Number of bytes in an SQL string */ 225119e2d37fSdrh int i, j; /* Loop counters */ 225219e2d37fSdrh int nSep; /* Number of bytes in zSep[] */ 225319e2d37fSdrh int nNull; /* Number of bytes in zNull[] */ 225419e2d37fSdrh char *zSql; /* An SQL statement */ 225519e2d37fSdrh char *zLine; /* A single line of input from the file */ 225619e2d37fSdrh char **azCol; /* zLine[] broken up into columns */ 22576ef5e12eSmistachkin const char *zCommit; /* How to commit changes */ 225819e2d37fSdrh FILE *in; /* The input file */ 225919e2d37fSdrh int lineno = 0; /* Line number of input file */ 226019e2d37fSdrh char zLineNum[80]; /* Line number print buffer */ 226119e2d37fSdrh Tcl_Obj *pResult; /* interp result */ 226219e2d37fSdrh 22636ef5e12eSmistachkin const char *zSep; 22646ef5e12eSmistachkin const char *zNull; 226519e2d37fSdrh if( objc<5 || objc>7 ){ 226619e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, 226719e2d37fSdrh "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"); 226819e2d37fSdrh return TCL_ERROR; 226919e2d37fSdrh } 227019e2d37fSdrh if( objc>=6 ){ 227119e2d37fSdrh zSep = Tcl_GetStringFromObj(objv[5], 0); 227219e2d37fSdrh }else{ 227319e2d37fSdrh zSep = "\t"; 227419e2d37fSdrh } 227519e2d37fSdrh if( objc>=7 ){ 227619e2d37fSdrh zNull = Tcl_GetStringFromObj(objv[6], 0); 227719e2d37fSdrh }else{ 227819e2d37fSdrh zNull = ""; 227919e2d37fSdrh } 228019e2d37fSdrh zConflict = Tcl_GetStringFromObj(objv[2], 0); 228119e2d37fSdrh zTable = Tcl_GetStringFromObj(objv[3], 0); 228219e2d37fSdrh zFile = Tcl_GetStringFromObj(objv[4], 0); 22834f21c4afSdrh nSep = strlen30(zSep); 22844f21c4afSdrh nNull = strlen30(zNull); 228519e2d37fSdrh if( nSep==0 ){ 2286a198f2b5Sdrh Tcl_AppendResult(interp,"Error: non-null separator required for copy", 2287a198f2b5Sdrh (char*)0); 228819e2d37fSdrh return TCL_ERROR; 228919e2d37fSdrh } 22903e59c012Sdrh if(strcmp(zConflict, "rollback") != 0 && 22913e59c012Sdrh strcmp(zConflict, "abort" ) != 0 && 22923e59c012Sdrh strcmp(zConflict, "fail" ) != 0 && 22933e59c012Sdrh strcmp(zConflict, "ignore" ) != 0 && 22943e59c012Sdrh strcmp(zConflict, "replace" ) != 0 ) { 229519e2d37fSdrh Tcl_AppendResult(interp, "Error: \"", zConflict, 229619e2d37fSdrh "\", conflict-algorithm must be one of: rollback, " 2297a198f2b5Sdrh "abort, fail, ignore, or replace", (char*)0); 229819e2d37fSdrh return TCL_ERROR; 229919e2d37fSdrh } 230019e2d37fSdrh zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); 230119e2d37fSdrh if( zSql==0 ){ 2302a198f2b5Sdrh Tcl_AppendResult(interp, "Error: no such table: ", zTable, (char*)0); 230319e2d37fSdrh return TCL_ERROR; 230419e2d37fSdrh } 23054f21c4afSdrh nByte = strlen30(zSql); 23063e701a18Sdrh rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); 230719e2d37fSdrh sqlite3_free(zSql); 230819e2d37fSdrh if( rc ){ 2309a198f2b5Sdrh Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0); 231019e2d37fSdrh nCol = 0; 231119e2d37fSdrh }else{ 231219e2d37fSdrh nCol = sqlite3_column_count(pStmt); 231319e2d37fSdrh } 231419e2d37fSdrh sqlite3_finalize(pStmt); 231519e2d37fSdrh if( nCol==0 ) { 231619e2d37fSdrh return TCL_ERROR; 231719e2d37fSdrh } 231819e2d37fSdrh zSql = malloc( nByte + 50 + nCol*2 ); 231919e2d37fSdrh if( zSql==0 ) { 2320a198f2b5Sdrh Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0); 232119e2d37fSdrh return TCL_ERROR; 232219e2d37fSdrh } 232319e2d37fSdrh sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?", 232419e2d37fSdrh zConflict, zTable); 23254f21c4afSdrh j = strlen30(zSql); 232619e2d37fSdrh for(i=1; i<nCol; i++){ 232719e2d37fSdrh zSql[j++] = ','; 232819e2d37fSdrh zSql[j++] = '?'; 232919e2d37fSdrh } 233019e2d37fSdrh zSql[j++] = ')'; 233119e2d37fSdrh zSql[j] = 0; 23323e701a18Sdrh rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); 233319e2d37fSdrh free(zSql); 233419e2d37fSdrh if( rc ){ 2335a198f2b5Sdrh Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0); 233619e2d37fSdrh sqlite3_finalize(pStmt); 233719e2d37fSdrh return TCL_ERROR; 233819e2d37fSdrh } 233919e2d37fSdrh in = fopen(zFile, "rb"); 234019e2d37fSdrh if( in==0 ){ 2341ea8f0a15Sdrh Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, (char*)0); 234219e2d37fSdrh sqlite3_finalize(pStmt); 234319e2d37fSdrh return TCL_ERROR; 234419e2d37fSdrh } 234519e2d37fSdrh azCol = malloc( sizeof(azCol[0])*(nCol+1) ); 234619e2d37fSdrh if( azCol==0 ) { 2347a198f2b5Sdrh Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0); 234843617e9aSdrh fclose(in); 234919e2d37fSdrh return TCL_ERROR; 235019e2d37fSdrh } 23513752785fSdrh (void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0); 235219e2d37fSdrh zCommit = "COMMIT"; 235319e2d37fSdrh while( (zLine = local_getline(0, in))!=0 ){ 235419e2d37fSdrh char *z; 235519e2d37fSdrh lineno++; 235619e2d37fSdrh azCol[0] = zLine; 235719e2d37fSdrh for(i=0, z=zLine; *z; z++){ 235819e2d37fSdrh if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){ 235919e2d37fSdrh *z = 0; 236019e2d37fSdrh i++; 236119e2d37fSdrh if( i<nCol ){ 236219e2d37fSdrh azCol[i] = &z[nSep]; 236319e2d37fSdrh z += nSep-1; 236419e2d37fSdrh } 236519e2d37fSdrh } 236619e2d37fSdrh } 236719e2d37fSdrh if( i+1!=nCol ){ 236819e2d37fSdrh char *zErr; 23694f21c4afSdrh int nErr = strlen30(zFile) + 200; 23705bb3eb9bSdrh zErr = malloc(nErr); 2371c1f4494eSdrh if( zErr ){ 23725bb3eb9bSdrh sqlite3_snprintf(nErr, zErr, 2373955de52cSdanielk1977 "Error: %s line %d: expected %d columns of data but found %d", 237419e2d37fSdrh zFile, lineno, nCol, i+1); 2375a198f2b5Sdrh Tcl_AppendResult(interp, zErr, (char*)0); 237619e2d37fSdrh free(zErr); 2377c1f4494eSdrh } 237819e2d37fSdrh zCommit = "ROLLBACK"; 237919e2d37fSdrh break; 238019e2d37fSdrh } 238119e2d37fSdrh for(i=0; i<nCol; i++){ 238219e2d37fSdrh /* check for null data, if so, bind as null */ 2383ea678832Sdrh if( (nNull>0 && strcmp(azCol[i], zNull)==0) 23844f21c4afSdrh || strlen30(azCol[i])==0 2385ea678832Sdrh ){ 238619e2d37fSdrh sqlite3_bind_null(pStmt, i+1); 238719e2d37fSdrh }else{ 238819e2d37fSdrh sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); 238919e2d37fSdrh } 239019e2d37fSdrh } 239119e2d37fSdrh sqlite3_step(pStmt); 239219e2d37fSdrh rc = sqlite3_reset(pStmt); 239319e2d37fSdrh free(zLine); 239419e2d37fSdrh if( rc!=SQLITE_OK ){ 2395a198f2b5Sdrh Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), (char*)0); 239619e2d37fSdrh zCommit = "ROLLBACK"; 239719e2d37fSdrh break; 239819e2d37fSdrh } 239919e2d37fSdrh } 240019e2d37fSdrh free(azCol); 240119e2d37fSdrh fclose(in); 240219e2d37fSdrh sqlite3_finalize(pStmt); 24033752785fSdrh (void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0); 240419e2d37fSdrh 240519e2d37fSdrh if( zCommit[0] == 'C' ){ 240619e2d37fSdrh /* success, set result as number of lines processed */ 240719e2d37fSdrh pResult = Tcl_GetObjResult(interp); 240819e2d37fSdrh Tcl_SetIntObj(pResult, lineno); 240919e2d37fSdrh rc = TCL_OK; 241019e2d37fSdrh }else{ 241119e2d37fSdrh /* failure, append lineno where failed */ 24125bb3eb9bSdrh sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno); 2413a198f2b5Sdrh Tcl_AppendResult(interp,", failed while processing line: ",zLineNum, 2414a198f2b5Sdrh (char*)0); 241519e2d37fSdrh rc = TCL_ERROR; 241619e2d37fSdrh } 241719e2d37fSdrh break; 241819e2d37fSdrh } 241919e2d37fSdrh 242075897234Sdrh /* 2421*6ca64481Sdrh ** $db deserialize ?-maxsize N? ?-readonly BOOL? ?DATABASE? VALUE 2422cb7d541dSdrh ** 2423cb7d541dSdrh ** Reopen DATABASE (default "main") using the content in $VALUE 2424cb7d541dSdrh */ 2425cb7d541dSdrh case DB_DESERIALIZE: { 24269c6396ecSdrh #ifndef SQLITE_ENABLE_DESERIALIZE 24273ec8665eSdrh Tcl_AppendResult(interp, "MEMDB not available in this build", 24283ec8665eSdrh (char*)0); 24293ec8665eSdrh rc = TCL_ERROR; 24303ec8665eSdrh #else 2431*6ca64481Sdrh const char *zSchema = 0; 2432*6ca64481Sdrh Tcl_Obj *pValue = 0; 24333ec8665eSdrh unsigned char *pBA; 24343ec8665eSdrh unsigned char *pData; 24353ec8665eSdrh int len, xrc; 2436*6ca64481Sdrh sqlite3_int64 mxSize = 0; 2437*6ca64481Sdrh int i; 2438*6ca64481Sdrh int isReadonly = 0; 24393ec8665eSdrh 2440*6ca64481Sdrh 2441*6ca64481Sdrh if( objc<3 ){ 24423ec8665eSdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? VALUE"); 24433ec8665eSdrh rc = TCL_ERROR; 24443ec8665eSdrh break; 24453ec8665eSdrh } 2446*6ca64481Sdrh for(i=2; i<objc-1; i++){ 2447*6ca64481Sdrh const char *z = Tcl_GetString(objv[i]); 2448*6ca64481Sdrh if( strcmp(z,"-maxsize")==0 && i<objc-2 ){ 2449*6ca64481Sdrh rc = Tcl_GetWideIntFromObj(interp, objv[++i], &mxSize); 2450*6ca64481Sdrh if( rc ) goto deserialize_error; 2451*6ca64481Sdrh continue; 2452*6ca64481Sdrh } 2453*6ca64481Sdrh if( strcmp(z,"-readonly")==0 && i<objc-2 ){ 2454*6ca64481Sdrh rc = Tcl_GetBooleanFromObj(interp, objv[++i], &isReadonly); 2455*6ca64481Sdrh if( rc ) goto deserialize_error; 2456*6ca64481Sdrh continue; 2457*6ca64481Sdrh } 2458*6ca64481Sdrh if( zSchema==0 && i==objc-2 && z[0]!='-' ){ 2459*6ca64481Sdrh zSchema = z; 2460*6ca64481Sdrh continue; 2461*6ca64481Sdrh } 2462*6ca64481Sdrh Tcl_AppendResult(interp, "unknown option: ", z, (char*)0); 2463*6ca64481Sdrh rc = TCL_ERROR; 2464*6ca64481Sdrh goto deserialize_error; 2465*6ca64481Sdrh } 2466*6ca64481Sdrh pValue = objv[objc-1]; 24673ec8665eSdrh pBA = Tcl_GetByteArrayFromObj(pValue, &len); 24683ec8665eSdrh pData = sqlite3_malloc64( len ); 2469a5bb4351Sdrh if( pData==0 && len>0 ){ 24703ec8665eSdrh Tcl_AppendResult(interp, "out of memory", (char*)0); 24713ec8665eSdrh rc = TCL_ERROR; 24723ec8665eSdrh }else{ 2473*6ca64481Sdrh int flags; 2474a5bb4351Sdrh if( len>0 ) memcpy(pData, pBA, len); 2475*6ca64481Sdrh if( isReadonly ){ 2476*6ca64481Sdrh flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_READONLY; 2477*6ca64481Sdrh }else{ 2478*6ca64481Sdrh flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE; 2479*6ca64481Sdrh } 2480*6ca64481Sdrh xrc = sqlite3_deserialize(pDb->db, zSchema, pData, len, len, flags); 24813ec8665eSdrh if( xrc ){ 24823ec8665eSdrh Tcl_AppendResult(interp, "unable to set MEMDB content", (char*)0); 24833ec8665eSdrh rc = TCL_ERROR; 24843ec8665eSdrh } 2485*6ca64481Sdrh if( mxSize>0 ){ 2486*6ca64481Sdrh sqlite3_file_control(pDb->db, zSchema,SQLITE_FCNTL_SIZE_LIMIT,&mxSize); 24873ec8665eSdrh } 2488*6ca64481Sdrh } 2489*6ca64481Sdrh deserialize_error: 24903ec8665eSdrh #endif 2491cb7d541dSdrh break; 2492cb7d541dSdrh } 2493cb7d541dSdrh 2494cb7d541dSdrh /* 24954144905bSdrh ** $db enable_load_extension BOOLEAN 24964144905bSdrh ** 24974144905bSdrh ** Turn the extension loading feature on or off. It if off by 24984144905bSdrh ** default. 24994144905bSdrh */ 25004144905bSdrh case DB_ENABLE_LOAD_EXTENSION: { 2501f533acc0Sdrh #ifndef SQLITE_OMIT_LOAD_EXTENSION 25024144905bSdrh int onoff; 25034144905bSdrh if( objc!=3 ){ 25044144905bSdrh Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN"); 25054144905bSdrh return TCL_ERROR; 25064144905bSdrh } 25074144905bSdrh if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){ 25084144905bSdrh return TCL_ERROR; 25094144905bSdrh } 25104144905bSdrh sqlite3_enable_load_extension(pDb->db, onoff); 25114144905bSdrh break; 2512f533acc0Sdrh #else 2513f533acc0Sdrh Tcl_AppendResult(interp, "extension loading is turned off at compile-time", 2514a198f2b5Sdrh (char*)0); 2515f533acc0Sdrh return TCL_ERROR; 2516f533acc0Sdrh #endif 25174144905bSdrh } 25184144905bSdrh 25194144905bSdrh /* 2520dcd997eaSdrh ** $db errorcode 2521dcd997eaSdrh ** 2522dcd997eaSdrh ** Return the numeric error code that was returned by the most recent 25236f8a503dSdanielk1977 ** call to sqlite3_exec(). 2524dcd997eaSdrh */ 2525dcd997eaSdrh case DB_ERRORCODE: { 2526f3ce83f5Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); 2527dcd997eaSdrh break; 2528dcd997eaSdrh } 2529dcd997eaSdrh 2530dcd997eaSdrh /* 25314a4c11aaSdan ** $db exists $sql 25321807ce37Sdrh ** $db onecolumn $sql 253375897234Sdrh ** 25344a4c11aaSdan ** The onecolumn method is the equivalent of: 25354a4c11aaSdan ** lindex [$db eval $sql] 0 25364a4c11aaSdan */ 25374a4c11aaSdan case DB_EXISTS: 25384a4c11aaSdan case DB_ONECOLUMN: { 2539edc4024bSdrh Tcl_Obj *pResult = 0; 25404a4c11aaSdan DbEvalContext sEval; 25414a4c11aaSdan if( objc!=3 ){ 25424a4c11aaSdan Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 25434a4c11aaSdan return TCL_ERROR; 25444a4c11aaSdan } 25454a4c11aaSdan 2546af38cdbcSdrh dbEvalInit(&sEval, pDb, objv[2], 0, 0); 25474a4c11aaSdan rc = dbEvalStep(&sEval); 25484a4c11aaSdan if( choice==DB_ONECOLUMN ){ 25494a4c11aaSdan if( rc==TCL_OK ){ 2550edc4024bSdrh pResult = dbEvalColumnValue(&sEval, 0); 2551d5f12cd5Sdan }else if( rc==TCL_BREAK ){ 2552d5f12cd5Sdan Tcl_ResetResult(interp); 25534a4c11aaSdan } 25544a4c11aaSdan }else if( rc==TCL_BREAK || rc==TCL_OK ){ 2555edc4024bSdrh pResult = Tcl_NewBooleanObj(rc==TCL_OK); 25564a4c11aaSdan } 25574a4c11aaSdan dbEvalFinalize(&sEval); 2558edc4024bSdrh if( pResult ) Tcl_SetObjResult(interp, pResult); 25594a4c11aaSdan 25604a4c11aaSdan if( rc==TCL_BREAK ){ 25614a4c11aaSdan rc = TCL_OK; 25624a4c11aaSdan } 25634a4c11aaSdan break; 25644a4c11aaSdan } 25654a4c11aaSdan 25664a4c11aaSdan /* 2567af38cdbcSdrh ** $db eval ?options? $sql ?array? ?{ ...code... }? 25684a4c11aaSdan ** 256975897234Sdrh ** The SQL statement in $sql is evaluated. For each row, the values are 2570bec3f402Sdrh ** placed in elements of the array named "array" and ...code... is executed. 257175897234Sdrh ** If "array" and "code" are omitted, then no callback is every invoked. 257275897234Sdrh ** If "array" is an empty string, then the values are placed in variables 257375897234Sdrh ** that have the same name as the fields extracted by the query. 257475897234Sdrh */ 25754a4c11aaSdan case DB_EVAL: { 2576af38cdbcSdrh int evalFlags = 0; 2577af38cdbcSdrh const char *zOpt; 2578af38cdbcSdrh while( objc>3 && (zOpt = Tcl_GetString(objv[2]))!=0 && zOpt[0]=='-' ){ 2579af38cdbcSdrh if( strcmp(zOpt, "-withoutnulls")==0 ){ 2580af38cdbcSdrh evalFlags |= SQLITE_EVAL_WITHOUTNULLS; 2581af38cdbcSdrh } 2582af38cdbcSdrh else{ 2583af38cdbcSdrh Tcl_AppendResult(interp, "unknown option: \"", zOpt, "\"", (void*)0); 2584af38cdbcSdrh return TCL_ERROR; 2585af38cdbcSdrh } 2586af38cdbcSdrh objc--; 2587af38cdbcSdrh objv++; 2588af38cdbcSdrh } 258992febd92Sdrh if( objc<3 || objc>5 ){ 2590af38cdbcSdrh Tcl_WrongNumArgs(interp, 2, objv, 2591af38cdbcSdrh "?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?"); 259230ccda10Sdanielk1977 return TCL_ERROR; 259330ccda10Sdanielk1977 } 25944a4c11aaSdan 259592febd92Sdrh if( objc==3 ){ 25964a4c11aaSdan DbEvalContext sEval; 25974a4c11aaSdan Tcl_Obj *pRet = Tcl_NewObj(); 25984a4c11aaSdan Tcl_IncrRefCount(pRet); 2599af38cdbcSdrh dbEvalInit(&sEval, pDb, objv[2], 0, 0); 26004a4c11aaSdan while( TCL_OK==(rc = dbEvalStep(&sEval)) ){ 26014a4c11aaSdan int i; 26024a4c11aaSdan int nCol; 26034a4c11aaSdan dbEvalRowInfo(&sEval, &nCol, 0); 260492febd92Sdrh for(i=0; i<nCol; i++){ 26054a4c11aaSdan Tcl_ListObjAppendElement(interp, pRet, dbEvalColumnValue(&sEval, i)); 260692febd92Sdrh } 260730ccda10Sdanielk1977 } 26084a4c11aaSdan dbEvalFinalize(&sEval); 260990b6bb19Sdrh if( rc==TCL_BREAK ){ 26104a4c11aaSdan Tcl_SetObjResult(interp, pRet); 261190b6bb19Sdrh rc = TCL_OK; 261290b6bb19Sdrh } 2613ef2cb63eSdanielk1977 Tcl_DecrRefCount(pRet); 26144a4c11aaSdan }else{ 26158e18922fSmistachkin ClientData cd2[2]; 26164a4c11aaSdan DbEvalContext *p; 26174a4c11aaSdan Tcl_Obj *pArray = 0; 26184a4c11aaSdan Tcl_Obj *pScript; 26194a4c11aaSdan 2620af38cdbcSdrh if( objc>=5 && *(char *)Tcl_GetString(objv[3]) ){ 26214a4c11aaSdan pArray = objv[3]; 26224a4c11aaSdan } 26234a4c11aaSdan pScript = objv[objc-1]; 26244a4c11aaSdan Tcl_IncrRefCount(pScript); 26254a4c11aaSdan 26264a4c11aaSdan p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext)); 2627af38cdbcSdrh dbEvalInit(p, pDb, objv[2], pArray, evalFlags); 26284a4c11aaSdan 26298e18922fSmistachkin cd2[0] = (void *)p; 26308e18922fSmistachkin cd2[1] = (void *)pScript; 26318e18922fSmistachkin rc = DbEvalNextCmd(cd2, interp, TCL_OK); 26321807ce37Sdrh } 263330ccda10Sdanielk1977 break; 263430ccda10Sdanielk1977 } 2635bec3f402Sdrh 2636bec3f402Sdrh /* 26373df30592Sdan ** $db function NAME [-argcount N] [-deterministic] SCRIPT 2638cabb0819Sdrh ** 2639cabb0819Sdrh ** Create a new SQL function called NAME. Whenever that function is 2640cabb0819Sdrh ** called, invoke SCRIPT to evaluate the function. 2641cabb0819Sdrh */ 2642cabb0819Sdrh case DB_FUNCTION: { 26433df30592Sdan int flags = SQLITE_UTF8; 2644cabb0819Sdrh SqlFunc *pFunc; 2645d1e4733dSdrh Tcl_Obj *pScript; 2646cabb0819Sdrh char *zName; 2647e3602be8Sdrh int nArg = -1; 26483df30592Sdan int i; 26493df30592Sdan if( objc<4 ){ 26503df30592Sdan Tcl_WrongNumArgs(interp, 2, objv, "NAME ?SWITCHES? SCRIPT"); 26513df30592Sdan return TCL_ERROR; 26523df30592Sdan } 26533df30592Sdan for(i=3; i<(objc-1); i++){ 26543df30592Sdan const char *z = Tcl_GetString(objv[i]); 26554f21c4afSdrh int n = strlen30(z); 2656e3602be8Sdrh if( n>2 && strncmp(z, "-argcount",n)==0 ){ 26573df30592Sdan if( i==(objc-2) ){ 2658ea8f0a15Sdrh Tcl_AppendResult(interp, "option requires an argument: ", z,(char*)0); 26593df30592Sdan return TCL_ERROR; 26603df30592Sdan } 26613df30592Sdan if( Tcl_GetIntFromObj(interp, objv[i+1], &nArg) ) return TCL_ERROR; 2662e3602be8Sdrh if( nArg<0 ){ 2663e3602be8Sdrh Tcl_AppendResult(interp, "number of arguments must be non-negative", 2664e3602be8Sdrh (char*)0); 2665cabb0819Sdrh return TCL_ERROR; 2666cabb0819Sdrh } 26673df30592Sdan i++; 26683df30592Sdan }else 26693df30592Sdan if( n>2 && strncmp(z, "-deterministic",n)==0 ){ 26703df30592Sdan flags |= SQLITE_DETERMINISTIC; 2671e3602be8Sdrh }else{ 26723df30592Sdan Tcl_AppendResult(interp, "bad option \"", z, 2673ea8f0a15Sdrh "\": must be -argcount or -deterministic", (char*)0 26743df30592Sdan ); 26753df30592Sdan return TCL_ERROR; 2676e3602be8Sdrh } 26773df30592Sdan } 26783df30592Sdan 26793df30592Sdan pScript = objv[objc-1]; 2680e3602be8Sdrh zName = Tcl_GetStringFromObj(objv[2], 0); 2681d1e4733dSdrh pFunc = findSqlFunc(pDb, zName); 2682cabb0819Sdrh if( pFunc==0 ) return TCL_ERROR; 2683d1e4733dSdrh if( pFunc->pScript ){ 2684d1e4733dSdrh Tcl_DecrRefCount(pFunc->pScript); 2685d1e4733dSdrh } 2686d1e4733dSdrh pFunc->pScript = pScript; 2687d1e4733dSdrh Tcl_IncrRefCount(pScript); 2688d1e4733dSdrh pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript); 26893df30592Sdan rc = sqlite3_create_function(pDb->db, zName, nArg, flags, 2690d8123366Sdanielk1977 pFunc, tclSqlFunc, 0, 0); 2691fb7e7651Sdrh if( rc!=SQLITE_OK ){ 2692fb7e7651Sdrh rc = TCL_ERROR; 26939636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 2694fb7e7651Sdrh } 2695cabb0819Sdrh break; 2696cabb0819Sdrh } 2697cabb0819Sdrh 2698cabb0819Sdrh /* 26998cbadb02Sdanielk1977 ** $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID 2700b4e9af9fSdanielk1977 */ 2701b4e9af9fSdanielk1977 case DB_INCRBLOB: { 270232a0d8bbSdanielk1977 #ifdef SQLITE_OMIT_INCRBLOB 2703a198f2b5Sdrh Tcl_AppendResult(interp, "incrblob not available in this build", (char*)0); 270432a0d8bbSdanielk1977 return TCL_ERROR; 270532a0d8bbSdanielk1977 #else 27068cbadb02Sdanielk1977 int isReadonly = 0; 2707b4e9af9fSdanielk1977 const char *zDb = "main"; 2708b4e9af9fSdanielk1977 const char *zTable; 2709b4e9af9fSdanielk1977 const char *zColumn; 2710b3f787f4Sdrh Tcl_WideInt iRow; 2711b4e9af9fSdanielk1977 27128cbadb02Sdanielk1977 /* Check for the -readonly option */ 27138cbadb02Sdanielk1977 if( objc>3 && strcmp(Tcl_GetString(objv[2]), "-readonly")==0 ){ 27148cbadb02Sdanielk1977 isReadonly = 1; 27158cbadb02Sdanielk1977 } 27168cbadb02Sdanielk1977 27178cbadb02Sdanielk1977 if( objc!=(5+isReadonly) && objc!=(6+isReadonly) ){ 27188cbadb02Sdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID"); 2719b4e9af9fSdanielk1977 return TCL_ERROR; 2720b4e9af9fSdanielk1977 } 2721b4e9af9fSdanielk1977 27228cbadb02Sdanielk1977 if( objc==(6+isReadonly) ){ 2723b4e9af9fSdanielk1977 zDb = Tcl_GetString(objv[2]); 2724b4e9af9fSdanielk1977 } 2725b4e9af9fSdanielk1977 zTable = Tcl_GetString(objv[objc-3]); 2726b4e9af9fSdanielk1977 zColumn = Tcl_GetString(objv[objc-2]); 2727b4e9af9fSdanielk1977 rc = Tcl_GetWideIntFromObj(interp, objv[objc-1], &iRow); 2728b4e9af9fSdanielk1977 2729b4e9af9fSdanielk1977 if( rc==TCL_OK ){ 27308cbadb02Sdanielk1977 rc = createIncrblobChannel( 2731edf5b165Sdan interp, pDb, zDb, zTable, zColumn, (sqlite3_int64)iRow, isReadonly 27328cbadb02Sdanielk1977 ); 2733b4e9af9fSdanielk1977 } 273432a0d8bbSdanielk1977 #endif 2735b4e9af9fSdanielk1977 break; 2736b4e9af9fSdanielk1977 } 2737b4e9af9fSdanielk1977 2738b4e9af9fSdanielk1977 /* 2739f11bded5Sdrh ** $db interrupt 2740f11bded5Sdrh ** 2741f11bded5Sdrh ** Interrupt the execution of the inner-most SQL interpreter. This 2742f11bded5Sdrh ** causes the SQL statement to return an error of SQLITE_INTERRUPT. 2743f11bded5Sdrh */ 2744f11bded5Sdrh case DB_INTERRUPT: { 2745f11bded5Sdrh sqlite3_interrupt(pDb->db); 2746f11bded5Sdrh break; 2747f11bded5Sdrh } 2748f11bded5Sdrh 2749f11bded5Sdrh /* 275019e2d37fSdrh ** $db nullvalue ?STRING? 275119e2d37fSdrh ** 275219e2d37fSdrh ** Change text used when a NULL comes back from the database. If ?STRING? 275319e2d37fSdrh ** is not present, then the current string used for NULL is returned. 275419e2d37fSdrh ** If STRING is present, then STRING is returned. 275519e2d37fSdrh ** 275619e2d37fSdrh */ 275719e2d37fSdrh case DB_NULLVALUE: { 275819e2d37fSdrh if( objc!=2 && objc!=3 ){ 275919e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE"); 276019e2d37fSdrh return TCL_ERROR; 276119e2d37fSdrh } 276219e2d37fSdrh if( objc==3 ){ 276319e2d37fSdrh int len; 276419e2d37fSdrh char *zNull = Tcl_GetStringFromObj(objv[2], &len); 276519e2d37fSdrh if( pDb->zNull ){ 276619e2d37fSdrh Tcl_Free(pDb->zNull); 276719e2d37fSdrh } 276819e2d37fSdrh if( zNull && len>0 ){ 276919e2d37fSdrh pDb->zNull = Tcl_Alloc( len + 1 ); 27707fd33929Sdrh memcpy(pDb->zNull, zNull, len); 277119e2d37fSdrh pDb->zNull[len] = '\0'; 277219e2d37fSdrh }else{ 277319e2d37fSdrh pDb->zNull = 0; 277419e2d37fSdrh } 277519e2d37fSdrh } 2776c45e6716Sdrh Tcl_SetObjResult(interp, Tcl_NewStringObj(pDb->zNull, -1)); 277719e2d37fSdrh break; 277819e2d37fSdrh } 277919e2d37fSdrh 278019e2d37fSdrh /* 2781af9ff33aSdrh ** $db last_insert_rowid 2782af9ff33aSdrh ** 2783af9ff33aSdrh ** Return an integer which is the ROWID for the most recent insert. 2784af9ff33aSdrh */ 2785af9ff33aSdrh case DB_LAST_INSERT_ROWID: { 2786af9ff33aSdrh Tcl_Obj *pResult; 2787f7e678d6Sdrh Tcl_WideInt rowid; 2788af9ff33aSdrh if( objc!=2 ){ 2789af9ff33aSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 2790af9ff33aSdrh return TCL_ERROR; 2791af9ff33aSdrh } 27926f8a503dSdanielk1977 rowid = sqlite3_last_insert_rowid(pDb->db); 2793af9ff33aSdrh pResult = Tcl_GetObjResult(interp); 2794f7e678d6Sdrh Tcl_SetWideIntObj(pResult, rowid); 2795af9ff33aSdrh break; 2796af9ff33aSdrh } 2797af9ff33aSdrh 2798af9ff33aSdrh /* 27994a4c11aaSdan ** The DB_ONECOLUMN method is implemented together with DB_EXISTS. 28005d9d7576Sdrh */ 28011807ce37Sdrh 28021807ce37Sdrh /* $db progress ?N CALLBACK? 28031807ce37Sdrh ** 28041807ce37Sdrh ** Invoke the given callback every N virtual machine opcodes while executing 28051807ce37Sdrh ** queries. 28061807ce37Sdrh */ 28071807ce37Sdrh case DB_PROGRESS: { 28081807ce37Sdrh if( objc==2 ){ 28091807ce37Sdrh if( pDb->zProgress ){ 2810a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zProgress, (char*)0); 28115d9d7576Sdrh } 28121807ce37Sdrh }else if( objc==4 ){ 28131807ce37Sdrh char *zProgress; 28141807ce37Sdrh int len; 28151807ce37Sdrh int N; 28161807ce37Sdrh if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ 28171807ce37Sdrh return TCL_ERROR; 28181807ce37Sdrh }; 28191807ce37Sdrh if( pDb->zProgress ){ 28201807ce37Sdrh Tcl_Free(pDb->zProgress); 28211807ce37Sdrh } 28221807ce37Sdrh zProgress = Tcl_GetStringFromObj(objv[3], &len); 28231807ce37Sdrh if( zProgress && len>0 ){ 28241807ce37Sdrh pDb->zProgress = Tcl_Alloc( len + 1 ); 28255bb3eb9bSdrh memcpy(pDb->zProgress, zProgress, len+1); 28261807ce37Sdrh }else{ 28271807ce37Sdrh pDb->zProgress = 0; 28281807ce37Sdrh } 28291807ce37Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK 28301807ce37Sdrh if( pDb->zProgress ){ 28311807ce37Sdrh pDb->interp = interp; 28321807ce37Sdrh sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb); 28331807ce37Sdrh }else{ 28341807ce37Sdrh sqlite3_progress_handler(pDb->db, 0, 0, 0); 28351807ce37Sdrh } 28361807ce37Sdrh #endif 28371807ce37Sdrh }else{ 28381807ce37Sdrh Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK"); 28391807ce37Sdrh return TCL_ERROR; 28405d9d7576Sdrh } 28415d9d7576Sdrh break; 28425d9d7576Sdrh } 28435d9d7576Sdrh 284419e2d37fSdrh /* $db profile ?CALLBACK? 284519e2d37fSdrh ** 284619e2d37fSdrh ** Make arrangements to invoke the CALLBACK routine after each SQL statement 284719e2d37fSdrh ** that has run. The text of the SQL and the amount of elapse time are 284819e2d37fSdrh ** appended to CALLBACK before the script is run. 284919e2d37fSdrh */ 285019e2d37fSdrh case DB_PROFILE: { 285119e2d37fSdrh if( objc>3 ){ 285219e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 285319e2d37fSdrh return TCL_ERROR; 285419e2d37fSdrh }else if( objc==2 ){ 285519e2d37fSdrh if( pDb->zProfile ){ 2856a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zProfile, (char*)0); 285719e2d37fSdrh } 285819e2d37fSdrh }else{ 285919e2d37fSdrh char *zProfile; 286019e2d37fSdrh int len; 286119e2d37fSdrh if( pDb->zProfile ){ 286219e2d37fSdrh Tcl_Free(pDb->zProfile); 286319e2d37fSdrh } 286419e2d37fSdrh zProfile = Tcl_GetStringFromObj(objv[2], &len); 286519e2d37fSdrh if( zProfile && len>0 ){ 286619e2d37fSdrh pDb->zProfile = Tcl_Alloc( len + 1 ); 28675bb3eb9bSdrh memcpy(pDb->zProfile, zProfile, len+1); 286819e2d37fSdrh }else{ 286919e2d37fSdrh pDb->zProfile = 0; 287019e2d37fSdrh } 28712eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 28722eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 287319e2d37fSdrh if( pDb->zProfile ){ 287419e2d37fSdrh pDb->interp = interp; 287519e2d37fSdrh sqlite3_profile(pDb->db, DbProfileHandler, pDb); 287619e2d37fSdrh }else{ 287719e2d37fSdrh sqlite3_profile(pDb->db, 0, 0); 287819e2d37fSdrh } 287919e2d37fSdrh #endif 288019e2d37fSdrh } 288119e2d37fSdrh break; 288219e2d37fSdrh } 288319e2d37fSdrh 28845d9d7576Sdrh /* 288522fbcb8dSdrh ** $db rekey KEY 288622fbcb8dSdrh ** 288722fbcb8dSdrh ** Change the encryption key on the currently open database. 288822fbcb8dSdrh */ 288922fbcb8dSdrh case DB_REKEY: { 289032f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 289122fbcb8dSdrh int nKey; 289222fbcb8dSdrh void *pKey; 2893b07028f7Sdrh #endif 289422fbcb8dSdrh if( objc!=3 ){ 289522fbcb8dSdrh Tcl_WrongNumArgs(interp, 2, objv, "KEY"); 289622fbcb8dSdrh return TCL_ERROR; 289722fbcb8dSdrh } 289832f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 2899b07028f7Sdrh pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); 29002011d5f5Sdrh rc = sqlite3_rekey(pDb->db, pKey, nKey); 290122fbcb8dSdrh if( rc ){ 2902a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0); 290322fbcb8dSdrh rc = TCL_ERROR; 290422fbcb8dSdrh } 290522fbcb8dSdrh #endif 290622fbcb8dSdrh break; 290722fbcb8dSdrh } 290822fbcb8dSdrh 2909dc2c4915Sdrh /* $db restore ?DATABASE? FILENAME 2910dc2c4915Sdrh ** 2911dc2c4915Sdrh ** Open a database file named FILENAME. Transfer the content 2912dc2c4915Sdrh ** of FILENAME into the local database DATABASE (default: "main"). 2913dc2c4915Sdrh */ 2914dc2c4915Sdrh case DB_RESTORE: { 2915dc2c4915Sdrh const char *zSrcFile; 2916dc2c4915Sdrh const char *zDestDb; 2917dc2c4915Sdrh sqlite3 *pSrc; 2918dc2c4915Sdrh sqlite3_backup *pBackup; 2919dc2c4915Sdrh int nTimeout = 0; 2920dc2c4915Sdrh 2921dc2c4915Sdrh if( objc==3 ){ 2922dc2c4915Sdrh zDestDb = "main"; 2923dc2c4915Sdrh zSrcFile = Tcl_GetString(objv[2]); 2924dc2c4915Sdrh }else if( objc==4 ){ 2925dc2c4915Sdrh zDestDb = Tcl_GetString(objv[2]); 2926dc2c4915Sdrh zSrcFile = Tcl_GetString(objv[3]); 2927dc2c4915Sdrh }else{ 2928dc2c4915Sdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME"); 2929dc2c4915Sdrh return TCL_ERROR; 2930dc2c4915Sdrh } 2931147ef394Sdrh rc = sqlite3_open_v2(zSrcFile, &pSrc, 2932147ef394Sdrh SQLITE_OPEN_READONLY | pDb->openFlags, 0); 2933dc2c4915Sdrh if( rc!=SQLITE_OK ){ 2934dc2c4915Sdrh Tcl_AppendResult(interp, "cannot open source database: ", 2935dc2c4915Sdrh sqlite3_errmsg(pSrc), (char*)0); 2936dc2c4915Sdrh sqlite3_close(pSrc); 2937dc2c4915Sdrh return TCL_ERROR; 2938dc2c4915Sdrh } 2939dc2c4915Sdrh pBackup = sqlite3_backup_init(pDb->db, zDestDb, pSrc, "main"); 2940dc2c4915Sdrh if( pBackup==0 ){ 2941dc2c4915Sdrh Tcl_AppendResult(interp, "restore failed: ", 2942dc2c4915Sdrh sqlite3_errmsg(pDb->db), (char*)0); 2943dc2c4915Sdrh sqlite3_close(pSrc); 2944dc2c4915Sdrh return TCL_ERROR; 2945dc2c4915Sdrh } 2946dc2c4915Sdrh while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK 2947dc2c4915Sdrh || rc==SQLITE_BUSY ){ 2948dc2c4915Sdrh if( rc==SQLITE_BUSY ){ 2949dc2c4915Sdrh if( nTimeout++ >= 3 ) break; 2950dc2c4915Sdrh sqlite3_sleep(100); 2951dc2c4915Sdrh } 2952dc2c4915Sdrh } 2953dc2c4915Sdrh sqlite3_backup_finish(pBackup); 2954dc2c4915Sdrh if( rc==SQLITE_DONE ){ 2955dc2c4915Sdrh rc = TCL_OK; 2956dc2c4915Sdrh }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ 2957dc2c4915Sdrh Tcl_AppendResult(interp, "restore failed: source database busy", 2958dc2c4915Sdrh (char*)0); 2959dc2c4915Sdrh rc = TCL_ERROR; 2960dc2c4915Sdrh }else{ 2961dc2c4915Sdrh Tcl_AppendResult(interp, "restore failed: ", 2962dc2c4915Sdrh sqlite3_errmsg(pDb->db), (char*)0); 2963dc2c4915Sdrh rc = TCL_ERROR; 2964dc2c4915Sdrh } 2965dc2c4915Sdrh sqlite3_close(pSrc); 2966dc2c4915Sdrh break; 2967dc2c4915Sdrh } 2968dc2c4915Sdrh 296922fbcb8dSdrh /* 2970cb7d541dSdrh ** $db serialize ?DATABASE? 2971cb7d541dSdrh ** 2972cb7d541dSdrh ** Return a serialization of a database. 2973cb7d541dSdrh */ 2974cb7d541dSdrh case DB_SERIALIZE: { 29759c6396ecSdrh #ifndef SQLITE_ENABLE_DESERIALIZE 2976cb7d541dSdrh Tcl_AppendResult(interp, "MEMDB not available in this build", 2977cb7d541dSdrh (char*)0); 2978cb7d541dSdrh rc = TCL_ERROR; 2979cb7d541dSdrh #else 2980cb7d541dSdrh const char *zSchema = objc>=3 ? Tcl_GetString(objv[2]) : "main"; 2981cb7d541dSdrh sqlite3_int64 sz = 0; 2982cb7d541dSdrh unsigned char *pData; 2983cb7d541dSdrh if( objc!=2 && objc!=3 ){ 2984cb7d541dSdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE?"); 2985cb7d541dSdrh rc = TCL_ERROR; 2986cb7d541dSdrh }else{ 2987cb7d541dSdrh int needFree; 2988cb7d541dSdrh pData = sqlite3_serialize(pDb->db, zSchema, &sz, SQLITE_SERIALIZE_NOCOPY); 2989cb7d541dSdrh if( pData ){ 2990cb7d541dSdrh needFree = 0; 2991cb7d541dSdrh }else{ 2992cb7d541dSdrh pData = sqlite3_serialize(pDb->db, zSchema, &sz, 0); 2993cb7d541dSdrh needFree = 1; 2994cb7d541dSdrh } 2995cb7d541dSdrh Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pData,sz)); 2996cb7d541dSdrh if( needFree ) sqlite3_free(pData); 2997cb7d541dSdrh } 2998cb7d541dSdrh #endif 2999cb7d541dSdrh break; 3000cb7d541dSdrh } 3001cb7d541dSdrh 3002cb7d541dSdrh /* 3003c456a76fSdan ** $db status (step|sort|autoindex|vmstep) 3004d1d38488Sdrh ** 3005d1d38488Sdrh ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or 3006d1d38488Sdrh ** SQLITE_STMTSTATUS_SORT for the most recent eval. 3007d1d38488Sdrh */ 3008d1d38488Sdrh case DB_STATUS: { 3009d1d38488Sdrh int v; 3010d1d38488Sdrh const char *zOp; 3011d1d38488Sdrh if( objc!=3 ){ 30121c320a43Sdrh Tcl_WrongNumArgs(interp, 2, objv, "(step|sort|autoindex)"); 3013d1d38488Sdrh return TCL_ERROR; 3014d1d38488Sdrh } 3015d1d38488Sdrh zOp = Tcl_GetString(objv[2]); 3016d1d38488Sdrh if( strcmp(zOp, "step")==0 ){ 3017d1d38488Sdrh v = pDb->nStep; 3018d1d38488Sdrh }else if( strcmp(zOp, "sort")==0 ){ 3019d1d38488Sdrh v = pDb->nSort; 30203c379b01Sdrh }else if( strcmp(zOp, "autoindex")==0 ){ 30213c379b01Sdrh v = pDb->nIndex; 3022c456a76fSdan }else if( strcmp(zOp, "vmstep")==0 ){ 3023c456a76fSdan v = pDb->nVMStep; 3024d1d38488Sdrh }else{ 30253c379b01Sdrh Tcl_AppendResult(interp, 3026c456a76fSdan "bad argument: should be autoindex, step, sort or vmstep", 3027d1d38488Sdrh (char*)0); 3028d1d38488Sdrh return TCL_ERROR; 3029d1d38488Sdrh } 3030d1d38488Sdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(v)); 3031d1d38488Sdrh break; 3032d1d38488Sdrh } 3033d1d38488Sdrh 3034d1d38488Sdrh /* 3035bec3f402Sdrh ** $db timeout MILLESECONDS 3036bec3f402Sdrh ** 3037bec3f402Sdrh ** Delay for the number of milliseconds specified when a file is locked. 3038bec3f402Sdrh */ 30396d31316cSdrh case DB_TIMEOUT: { 3040bec3f402Sdrh int ms; 30416d31316cSdrh if( objc!=3 ){ 30426d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS"); 3043bec3f402Sdrh return TCL_ERROR; 304475897234Sdrh } 30456d31316cSdrh if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR; 30466f8a503dSdanielk1977 sqlite3_busy_timeout(pDb->db, ms); 30476d31316cSdrh break; 304875897234Sdrh } 3049b5a20d3cSdrh 30500f14e2ebSdrh /* 30510f14e2ebSdrh ** $db total_changes 30520f14e2ebSdrh ** 30530f14e2ebSdrh ** Return the number of rows that were modified, inserted, or deleted 30540f14e2ebSdrh ** since the database handle was created. 30550f14e2ebSdrh */ 30560f14e2ebSdrh case DB_TOTAL_CHANGES: { 30570f14e2ebSdrh Tcl_Obj *pResult; 30580f14e2ebSdrh if( objc!=2 ){ 30590f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 30600f14e2ebSdrh return TCL_ERROR; 30610f14e2ebSdrh } 30620f14e2ebSdrh pResult = Tcl_GetObjResult(interp); 30630f14e2ebSdrh Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db)); 30640f14e2ebSdrh break; 30650f14e2ebSdrh } 30660f14e2ebSdrh 3067b5a20d3cSdrh /* $db trace ?CALLBACK? 3068b5a20d3cSdrh ** 3069b5a20d3cSdrh ** Make arrangements to invoke the CALLBACK routine for each SQL statement 3070b5a20d3cSdrh ** that is executed. The text of the SQL is appended to CALLBACK before 3071b5a20d3cSdrh ** it is executed. 3072b5a20d3cSdrh */ 3073b5a20d3cSdrh case DB_TRACE: { 3074b5a20d3cSdrh if( objc>3 ){ 3075b5a20d3cSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 3076b97759edSdrh return TCL_ERROR; 3077b5a20d3cSdrh }else if( objc==2 ){ 3078b5a20d3cSdrh if( pDb->zTrace ){ 3079a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zTrace, (char*)0); 3080b5a20d3cSdrh } 3081b5a20d3cSdrh }else{ 3082b5a20d3cSdrh char *zTrace; 3083b5a20d3cSdrh int len; 3084b5a20d3cSdrh if( pDb->zTrace ){ 3085b5a20d3cSdrh Tcl_Free(pDb->zTrace); 3086b5a20d3cSdrh } 3087b5a20d3cSdrh zTrace = Tcl_GetStringFromObj(objv[2], &len); 3088b5a20d3cSdrh if( zTrace && len>0 ){ 3089b5a20d3cSdrh pDb->zTrace = Tcl_Alloc( len + 1 ); 30905bb3eb9bSdrh memcpy(pDb->zTrace, zTrace, len+1); 3091b5a20d3cSdrh }else{ 3092b5a20d3cSdrh pDb->zTrace = 0; 3093b5a20d3cSdrh } 30942eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 30952eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 3096b5a20d3cSdrh if( pDb->zTrace ){ 3097b5a20d3cSdrh pDb->interp = interp; 30986f8a503dSdanielk1977 sqlite3_trace(pDb->db, DbTraceHandler, pDb); 3099b5a20d3cSdrh }else{ 31006f8a503dSdanielk1977 sqlite3_trace(pDb->db, 0, 0); 3101b5a20d3cSdrh } 310219e2d37fSdrh #endif 3103b5a20d3cSdrh } 3104b5a20d3cSdrh break; 3105b5a20d3cSdrh } 3106b5a20d3cSdrh 3107b56660f5Smistachkin /* $db trace_v2 ?CALLBACK? ?MASK? 3108b56660f5Smistachkin ** 3109b56660f5Smistachkin ** Make arrangements to invoke the CALLBACK routine for each trace event 3110b56660f5Smistachkin ** matching the mask that is generated. The parameters are appended to 3111b56660f5Smistachkin ** CALLBACK before it is executed. 3112b56660f5Smistachkin */ 3113b56660f5Smistachkin case DB_TRACE_V2: { 3114b56660f5Smistachkin if( objc>4 ){ 3115b56660f5Smistachkin Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK? ?MASK?"); 3116b56660f5Smistachkin return TCL_ERROR; 3117b56660f5Smistachkin }else if( objc==2 ){ 3118b56660f5Smistachkin if( pDb->zTraceV2 ){ 3119b56660f5Smistachkin Tcl_AppendResult(interp, pDb->zTraceV2, (char*)0); 3120b56660f5Smistachkin } 3121b56660f5Smistachkin }else{ 3122b56660f5Smistachkin char *zTraceV2; 3123b56660f5Smistachkin int len; 3124b52dcd89Smistachkin Tcl_WideInt wMask = 0; 3125b56660f5Smistachkin if( objc==4 ){ 3126b52dcd89Smistachkin static const char *TTYPE_strs[] = { 3127b52dcd89Smistachkin "statement", "profile", "row", "close", 0 3128b52dcd89Smistachkin }; 3129b52dcd89Smistachkin enum TTYPE_enum { 3130b52dcd89Smistachkin TTYPE_STMT, TTYPE_PROFILE, TTYPE_ROW, TTYPE_CLOSE 3131b52dcd89Smistachkin }; 3132b52dcd89Smistachkin int i; 3133b52dcd89Smistachkin if( TCL_OK!=Tcl_ListObjLength(interp, objv[3], &len) ){ 3134b52dcd89Smistachkin return TCL_ERROR; 3135b52dcd89Smistachkin } 3136b52dcd89Smistachkin for(i=0; i<len; i++){ 3137b52dcd89Smistachkin Tcl_Obj *pObj; 3138b52dcd89Smistachkin int ttype; 3139b52dcd89Smistachkin if( TCL_OK!=Tcl_ListObjIndex(interp, objv[3], i, &pObj) ){ 3140b52dcd89Smistachkin return TCL_ERROR; 3141b52dcd89Smistachkin } 3142b52dcd89Smistachkin if( Tcl_GetIndexFromObj(interp, pObj, TTYPE_strs, "trace type", 3143b52dcd89Smistachkin 0, &ttype)!=TCL_OK ){ 3144b52dcd89Smistachkin Tcl_WideInt wType; 3145b52dcd89Smistachkin Tcl_Obj *pError = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); 3146b52dcd89Smistachkin Tcl_IncrRefCount(pError); 3147b52dcd89Smistachkin if( TCL_OK==Tcl_GetWideIntFromObj(interp, pObj, &wType) ){ 3148b52dcd89Smistachkin Tcl_DecrRefCount(pError); 3149b52dcd89Smistachkin wMask |= wType; 3150b52dcd89Smistachkin }else{ 3151b52dcd89Smistachkin Tcl_SetObjResult(interp, pError); 3152b52dcd89Smistachkin Tcl_DecrRefCount(pError); 3153b56660f5Smistachkin return TCL_ERROR; 3154b56660f5Smistachkin } 3155b56660f5Smistachkin }else{ 3156b52dcd89Smistachkin switch( (enum TTYPE_enum)ttype ){ 3157b52dcd89Smistachkin case TTYPE_STMT: wMask |= SQLITE_TRACE_STMT; break; 3158b52dcd89Smistachkin case TTYPE_PROFILE: wMask |= SQLITE_TRACE_PROFILE; break; 3159b52dcd89Smistachkin case TTYPE_ROW: wMask |= SQLITE_TRACE_ROW; break; 3160b52dcd89Smistachkin case TTYPE_CLOSE: wMask |= SQLITE_TRACE_CLOSE; break; 3161b52dcd89Smistachkin } 3162b52dcd89Smistachkin } 3163b52dcd89Smistachkin } 3164b52dcd89Smistachkin }else{ 3165b52dcd89Smistachkin wMask = SQLITE_TRACE_STMT; /* use the "legacy" default */ 3166b56660f5Smistachkin } 3167b56660f5Smistachkin if( pDb->zTraceV2 ){ 3168b56660f5Smistachkin Tcl_Free(pDb->zTraceV2); 3169b56660f5Smistachkin } 3170b56660f5Smistachkin zTraceV2 = Tcl_GetStringFromObj(objv[2], &len); 3171b56660f5Smistachkin if( zTraceV2 && len>0 ){ 3172b56660f5Smistachkin pDb->zTraceV2 = Tcl_Alloc( len + 1 ); 3173b56660f5Smistachkin memcpy(pDb->zTraceV2, zTraceV2, len+1); 3174b56660f5Smistachkin }else{ 3175b56660f5Smistachkin pDb->zTraceV2 = 0; 3176b56660f5Smistachkin } 3177b56660f5Smistachkin #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) 3178b56660f5Smistachkin if( pDb->zTraceV2 ){ 3179b56660f5Smistachkin pDb->interp = interp; 3180b56660f5Smistachkin sqlite3_trace_v2(pDb->db, (unsigned)wMask, DbTraceV2Handler, pDb); 3181b56660f5Smistachkin }else{ 3182b56660f5Smistachkin sqlite3_trace_v2(pDb->db, 0, 0, 0); 3183b56660f5Smistachkin } 3184b56660f5Smistachkin #endif 3185b56660f5Smistachkin } 3186b56660f5Smistachkin break; 3187b56660f5Smistachkin } 3188b56660f5Smistachkin 31893d21423cSdrh /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT 31903d21423cSdrh ** 31913d21423cSdrh ** Start a new transaction (if we are not already in the midst of a 31923d21423cSdrh ** transaction) and execute the TCL script SCRIPT. After SCRIPT 31933d21423cSdrh ** completes, either commit the transaction or roll it back if SCRIPT 31943d21423cSdrh ** throws an exception. Or if no new transation was started, do nothing. 31953d21423cSdrh ** pass the exception on up the stack. 31963d21423cSdrh ** 31973d21423cSdrh ** This command was inspired by Dave Thomas's talk on Ruby at the 31983d21423cSdrh ** 2005 O'Reilly Open Source Convention (OSCON). 31993d21423cSdrh */ 32003d21423cSdrh case DB_TRANSACTION: { 32013d21423cSdrh Tcl_Obj *pScript; 3202cd38d520Sdanielk1977 const char *zBegin = "SAVEPOINT _tcl_transaction"; 32033d21423cSdrh if( objc!=3 && objc!=4 ){ 32043d21423cSdrh Tcl_WrongNumArgs(interp, 2, objv, "[TYPE] SCRIPT"); 32053d21423cSdrh return TCL_ERROR; 32063d21423cSdrh } 3207cd38d520Sdanielk1977 32084a4c11aaSdan if( pDb->nTransaction==0 && objc==4 ){ 32093d21423cSdrh static const char *TTYPE_strs[] = { 3210ce604012Sdrh "deferred", "exclusive", "immediate", 0 32113d21423cSdrh }; 32123d21423cSdrh enum TTYPE_enum { 32133d21423cSdrh TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE 32143d21423cSdrh }; 32153d21423cSdrh int ttype; 3216b5555e7eSdrh if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type", 32173d21423cSdrh 0, &ttype) ){ 32183d21423cSdrh return TCL_ERROR; 32193d21423cSdrh } 32203d21423cSdrh switch( (enum TTYPE_enum)ttype ){ 32213d21423cSdrh case TTYPE_DEFERRED: /* no-op */; break; 32223d21423cSdrh case TTYPE_EXCLUSIVE: zBegin = "BEGIN EXCLUSIVE"; break; 32233d21423cSdrh case TTYPE_IMMEDIATE: zBegin = "BEGIN IMMEDIATE"; break; 32243d21423cSdrh } 32253d21423cSdrh } 3226cd38d520Sdanielk1977 pScript = objv[objc-1]; 3227cd38d520Sdanielk1977 32284a4c11aaSdan /* Run the SQLite BEGIN command to open a transaction or savepoint. */ 32291f1549f8Sdrh pDb->disableAuth++; 3230cd38d520Sdanielk1977 rc = sqlite3_exec(pDb->db, zBegin, 0, 0, 0); 32311f1549f8Sdrh pDb->disableAuth--; 3232cd38d520Sdanielk1977 if( rc!=SQLITE_OK ){ 3233a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 3234cd38d520Sdanielk1977 return TCL_ERROR; 32353d21423cSdrh } 3236cd38d520Sdanielk1977 pDb->nTransaction++; 3237cd38d520Sdanielk1977 32384a4c11aaSdan /* If using NRE, schedule a callback to invoke the script pScript, then 32394a4c11aaSdan ** a second callback to commit (or rollback) the transaction or savepoint 32404a4c11aaSdan ** opened above. If not using NRE, evaluate the script directly, then 32414a4c11aaSdan ** call function DbTransPostCmd() to commit (or rollback) the transaction 32424a4c11aaSdan ** or savepoint. */ 32434a4c11aaSdan if( DbUseNre() ){ 32444a4c11aaSdan Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0); 3245a47941feSdrh (void)Tcl_NREvalObj(interp, pScript, 0); 32463d21423cSdrh }else{ 32474a4c11aaSdan rc = DbTransPostCmd(&cd, interp, Tcl_EvalObjEx(interp, pScript, 0)); 32483d21423cSdrh } 32493d21423cSdrh break; 32503d21423cSdrh } 32513d21423cSdrh 325294eb6a14Sdanielk1977 /* 3253404ca075Sdanielk1977 ** $db unlock_notify ?script? 3254404ca075Sdanielk1977 */ 3255404ca075Sdanielk1977 case DB_UNLOCK_NOTIFY: { 3256404ca075Sdanielk1977 #ifndef SQLITE_ENABLE_UNLOCK_NOTIFY 3257a198f2b5Sdrh Tcl_AppendResult(interp, "unlock_notify not available in this build", 3258a198f2b5Sdrh (char*)0); 3259404ca075Sdanielk1977 rc = TCL_ERROR; 3260404ca075Sdanielk1977 #else 3261404ca075Sdanielk1977 if( objc!=2 && objc!=3 ){ 3262404ca075Sdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); 3263404ca075Sdanielk1977 rc = TCL_ERROR; 3264404ca075Sdanielk1977 }else{ 3265404ca075Sdanielk1977 void (*xNotify)(void **, int) = 0; 3266404ca075Sdanielk1977 void *pNotifyArg = 0; 3267404ca075Sdanielk1977 3268404ca075Sdanielk1977 if( pDb->pUnlockNotify ){ 3269404ca075Sdanielk1977 Tcl_DecrRefCount(pDb->pUnlockNotify); 3270404ca075Sdanielk1977 pDb->pUnlockNotify = 0; 3271404ca075Sdanielk1977 } 3272404ca075Sdanielk1977 3273404ca075Sdanielk1977 if( objc==3 ){ 3274404ca075Sdanielk1977 xNotify = DbUnlockNotify; 3275404ca075Sdanielk1977 pNotifyArg = (void *)pDb; 3276404ca075Sdanielk1977 pDb->pUnlockNotify = objv[2]; 3277404ca075Sdanielk1977 Tcl_IncrRefCount(pDb->pUnlockNotify); 3278404ca075Sdanielk1977 } 3279404ca075Sdanielk1977 3280404ca075Sdanielk1977 if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){ 3281a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 3282404ca075Sdanielk1977 rc = TCL_ERROR; 3283404ca075Sdanielk1977 } 3284404ca075Sdanielk1977 } 3285404ca075Sdanielk1977 #endif 3286404ca075Sdanielk1977 break; 3287404ca075Sdanielk1977 } 3288404ca075Sdanielk1977 3289304637c0Sdrh /* 3290304637c0Sdrh ** $db preupdate_hook count 3291304637c0Sdrh ** $db preupdate_hook hook ?SCRIPT? 3292304637c0Sdrh ** $db preupdate_hook new INDEX 3293304637c0Sdrh ** $db preupdate_hook old INDEX 3294304637c0Sdrh */ 329546c47d46Sdan case DB_PREUPDATE: { 32969b1c62d4Sdrh #ifndef SQLITE_ENABLE_PREUPDATE_HOOK 32972b519ab0Sdan Tcl_AppendResult(interp, "preupdate_hook was omitted at compile-time", 32982b519ab0Sdan (char*)0); 32999b1c62d4Sdrh rc = TCL_ERROR; 33009b1c62d4Sdrh #else 33011e7a2d43Sdan static const char *azSub[] = {"count", "depth", "hook", "new", "old", 0}; 330246c47d46Sdan enum DbPreupdateSubCmd { 33031e7a2d43Sdan PRE_COUNT, PRE_DEPTH, PRE_HOOK, PRE_NEW, PRE_OLD 330446c47d46Sdan }; 330546c47d46Sdan int iSub; 330646c47d46Sdan 330746c47d46Sdan if( objc<3 ){ 330846c47d46Sdan Tcl_WrongNumArgs(interp, 2, objv, "SUB-COMMAND ?ARGS?"); 330946c47d46Sdan } 331046c47d46Sdan if( Tcl_GetIndexFromObj(interp, objv[2], azSub, "sub-command", 0, &iSub) ){ 331146c47d46Sdan return TCL_ERROR; 331246c47d46Sdan } 331346c47d46Sdan 331446c47d46Sdan switch( (enum DbPreupdateSubCmd)iSub ){ 331546c47d46Sdan case PRE_COUNT: { 331646c47d46Sdan int nCol = sqlite3_preupdate_count(pDb->db); 331746c47d46Sdan Tcl_SetObjResult(interp, Tcl_NewIntObj(nCol)); 331846c47d46Sdan break; 331946c47d46Sdan } 332046c47d46Sdan 332146c47d46Sdan case PRE_HOOK: { 332246c47d46Sdan if( objc>4 ){ 332346c47d46Sdan Tcl_WrongNumArgs(interp, 2, objv, "hook ?SCRIPT?"); 332446c47d46Sdan return TCL_ERROR; 332546c47d46Sdan } 332646c47d46Sdan DbHookCmd(interp, pDb, (objc==4 ? objv[3] : 0), &pDb->pPreUpdateHook); 332746c47d46Sdan break; 332846c47d46Sdan } 332946c47d46Sdan 33301e7a2d43Sdan case PRE_DEPTH: { 33311e7a2d43Sdan Tcl_Obj *pRet; 33321e7a2d43Sdan if( objc!=3 ){ 33331e7a2d43Sdan Tcl_WrongNumArgs(interp, 3, objv, ""); 33341e7a2d43Sdan return TCL_ERROR; 33351e7a2d43Sdan } 33361e7a2d43Sdan pRet = Tcl_NewIntObj(sqlite3_preupdate_depth(pDb->db)); 33371e7a2d43Sdan Tcl_SetObjResult(interp, pRet); 33381e7a2d43Sdan break; 33391e7a2d43Sdan } 33401e7a2d43Sdan 334137db03bfSdan case PRE_NEW: 334246c47d46Sdan case PRE_OLD: { 334346c47d46Sdan int iIdx; 334437db03bfSdan sqlite3_value *pValue; 334546c47d46Sdan if( objc!=4 ){ 334646c47d46Sdan Tcl_WrongNumArgs(interp, 3, objv, "INDEX"); 334746c47d46Sdan return TCL_ERROR; 334846c47d46Sdan } 334946c47d46Sdan if( Tcl_GetIntFromObj(interp, objv[3], &iIdx) ){ 335046c47d46Sdan return TCL_ERROR; 335146c47d46Sdan } 335246c47d46Sdan 335337db03bfSdan if( iSub==PRE_OLD ){ 335446c47d46Sdan rc = sqlite3_preupdate_old(pDb->db, iIdx, &pValue); 335537db03bfSdan }else{ 335637db03bfSdan assert( iSub==PRE_NEW ); 335737db03bfSdan rc = sqlite3_preupdate_new(pDb->db, iIdx, &pValue); 335837db03bfSdan } 335937db03bfSdan 336046c47d46Sdan if( rc==SQLITE_OK ){ 3361304637c0Sdrh Tcl_Obj *pObj; 3362304637c0Sdrh pObj = Tcl_NewStringObj((char*)sqlite3_value_text(pValue), -1); 336346c47d46Sdan Tcl_SetObjResult(interp, pObj); 336437db03bfSdan }else{ 3365ea8f0a15Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 336646c47d46Sdan return TCL_ERROR; 336746c47d46Sdan } 336846c47d46Sdan } 336946c47d46Sdan } 33709b1c62d4Sdrh #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ 337146c47d46Sdan break; 337246c47d46Sdan } 337346c47d46Sdan 3374404ca075Sdanielk1977 /* 3375833bf968Sdrh ** $db wal_hook ?script? 337694eb6a14Sdanielk1977 ** $db update_hook ?script? 337771fd80bfSdanielk1977 ** $db rollback_hook ?script? 337894eb6a14Sdanielk1977 */ 3379833bf968Sdrh case DB_WAL_HOOK: 338071fd80bfSdanielk1977 case DB_UPDATE_HOOK: 33816566ebe1Sdan case DB_ROLLBACK_HOOK: { 338271fd80bfSdanielk1977 /* set ppHook to point at pUpdateHook or pRollbackHook, depending on 338371fd80bfSdanielk1977 ** whether [$db update_hook] or [$db rollback_hook] was invoked. 338471fd80bfSdanielk1977 */ 3385c5896b5cSmistachkin Tcl_Obj **ppHook = 0; 338646c47d46Sdan if( choice==DB_WAL_HOOK ) ppHook = &pDb->pWalHook; 338746c47d46Sdan if( choice==DB_UPDATE_HOOK ) ppHook = &pDb->pUpdateHook; 338846c47d46Sdan if( choice==DB_ROLLBACK_HOOK ) ppHook = &pDb->pRollbackHook; 338946c47d46Sdan if( objc>3 ){ 339094eb6a14Sdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); 339194eb6a14Sdanielk1977 return TCL_ERROR; 339294eb6a14Sdanielk1977 } 339371fd80bfSdanielk1977 339446c47d46Sdan DbHookCmd(interp, pDb, (objc==3 ? objv[2] : 0), ppHook); 339594eb6a14Sdanielk1977 break; 339694eb6a14Sdanielk1977 } 339794eb6a14Sdanielk1977 33984397de57Sdanielk1977 /* $db version 33994397de57Sdanielk1977 ** 34004397de57Sdanielk1977 ** Return the version string for this database. 34014397de57Sdanielk1977 */ 34024397de57Sdanielk1977 case DB_VERSION: { 34031df6470dSdrh int i; 34041df6470dSdrh for(i=2; i<objc; i++){ 34051df6470dSdrh const char *zArg = Tcl_GetString(objv[i]); 34061df6470dSdrh /* Optional arguments to $db version are used for testing purpose */ 34071df6470dSdrh #ifdef SQLITE_TEST 34081df6470dSdrh /* $db version -use-legacy-prepare BOOLEAN 34091df6470dSdrh ** 34101df6470dSdrh ** Turn the use of legacy sqlite3_prepare() on or off. 34111df6470dSdrh */ 34121df6470dSdrh if( strcmp(zArg, "-use-legacy-prepare")==0 && i+1<objc ){ 34131df6470dSdrh i++; 34141df6470dSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &pDb->bLegacyPrepare) ){ 34151df6470dSdrh return TCL_ERROR; 34161df6470dSdrh } 34171df6470dSdrh }else 34181df6470dSdrh 34191df6470dSdrh /* $db version -last-stmt-ptr 34201df6470dSdrh ** 34211df6470dSdrh ** Return a string which is a hex encoding of the pointer to the 34221df6470dSdrh ** most recent sqlite3_stmt in the statement cache. 34231df6470dSdrh */ 34241df6470dSdrh if( strcmp(zArg, "-last-stmt-ptr")==0 ){ 34251df6470dSdrh char zBuf[100]; 34261df6470dSdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", 34271df6470dSdrh pDb->stmtList ? pDb->stmtList->pStmt: 0); 34281df6470dSdrh Tcl_SetResult(interp, zBuf, TCL_VOLATILE); 34291df6470dSdrh }else 34301df6470dSdrh #endif /* SQLITE_TEST */ 34311df6470dSdrh { 34321df6470dSdrh Tcl_AppendResult(interp, "unknown argument: ", zArg, (char*)0); 34331df6470dSdrh return TCL_ERROR; 34341df6470dSdrh } 34351df6470dSdrh } 34361df6470dSdrh if( i==2 ){ 34374397de57Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC); 34381df6470dSdrh } 34394397de57Sdanielk1977 break; 34404397de57Sdanielk1977 } 34414397de57Sdanielk1977 34421067fe11Stpoindex 34436d31316cSdrh } /* End of the SWITCH statement */ 344422fbcb8dSdrh return rc; 344575897234Sdrh } 344675897234Sdrh 3447a2c8a95bSdrh #if SQLITE_TCL_NRE 3448a2c8a95bSdrh /* 3449a2c8a95bSdrh ** Adaptor that provides an objCmd interface to the NRE-enabled 3450a2c8a95bSdrh ** interface implementation. 3451a2c8a95bSdrh */ 3452a121cc7cSmistachkin static int SQLITE_TCLAPI DbObjCmdAdaptor( 3453a2c8a95bSdrh void *cd, 3454a2c8a95bSdrh Tcl_Interp *interp, 3455a2c8a95bSdrh int objc, 3456a2c8a95bSdrh Tcl_Obj *const*objv 3457a2c8a95bSdrh ){ 3458a2c8a95bSdrh return Tcl_NRCallObjProc(interp, DbObjCmd, cd, objc, objv); 3459a2c8a95bSdrh } 3460a2c8a95bSdrh #endif /* SQLITE_TCL_NRE */ 3461a2c8a95bSdrh 346275897234Sdrh /* 34634dcac40eSdrh ** Issue the usage message when the "sqlite3" command arguments are 34644dcac40eSdrh ** incorrect. 34654dcac40eSdrh */ 34664dcac40eSdrh static int sqliteCmdUsage( 34674dcac40eSdrh Tcl_Interp *interp, 34684dcac40eSdrh Tcl_Obj *const*objv 34694dcac40eSdrh ){ 34704dcac40eSdrh Tcl_WrongNumArgs(interp, 1, objv, 34714dcac40eSdrh "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" 34724dcac40eSdrh " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" 34734dcac40eSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 34744dcac40eSdrh " ?-key CODECKEY?" 34754dcac40eSdrh #endif 34764dcac40eSdrh ); 34774dcac40eSdrh return TCL_ERROR; 34784dcac40eSdrh } 34794dcac40eSdrh 34804dcac40eSdrh /* 34813570ad93Sdrh ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN? 34829a6284c1Sdanielk1977 ** ?-create BOOLEAN? ?-nomutex BOOLEAN? 348375897234Sdrh ** 348475897234Sdrh ** This is the main Tcl command. When the "sqlite" Tcl command is 348575897234Sdrh ** invoked, this routine runs to process that command. 348675897234Sdrh ** 348775897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new 348875897234Sdrh ** database connection. This command creates a new command named 348975897234Sdrh ** DBNAME that is used to control that connection. The database 349075897234Sdrh ** connection is deleted when the DBNAME command is deleted. 349175897234Sdrh ** 34923570ad93Sdrh ** The second argument is the name of the database file. 3493fbc3eab8Sdrh ** 349475897234Sdrh */ 34957617e4a8Smistachkin static int SQLITE_TCLAPI DbMain( 34967617e4a8Smistachkin void *cd, 34977617e4a8Smistachkin Tcl_Interp *interp, 34987617e4a8Smistachkin int objc, 34997617e4a8Smistachkin Tcl_Obj *const*objv 35007617e4a8Smistachkin ){ 3501bec3f402Sdrh SqliteDb *p; 350222fbcb8dSdrh const char *zArg; 350375897234Sdrh char *zErrMsg; 35043570ad93Sdrh int i; 35054dcac40eSdrh const char *zFile = 0; 35063570ad93Sdrh const char *zVfs = 0; 3507d9da78a2Sdrh int flags; 3508882e8e4dSdrh Tcl_DString translatedFilename; 350932f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 3510b07028f7Sdrh void *pKey = 0; 3511b07028f7Sdrh int nKey = 0; 3512b07028f7Sdrh #endif 3513540ebf82Smistachkin int rc; 3514d9da78a2Sdrh 3515d9da78a2Sdrh /* In normal use, each TCL interpreter runs in a single thread. So 35164dcac40eSdrh ** by default, we can turn off mutexing on SQLite database connections. 3517d9da78a2Sdrh ** However, for testing purposes it is useful to have mutexes turned 3518d9da78a2Sdrh ** on. So, by default, mutexes default off. But if compiled with 3519d9da78a2Sdrh ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on. 3520d9da78a2Sdrh */ 3521d9da78a2Sdrh #ifdef SQLITE_TCL_DEFAULT_FULLMUTEX 3522d9da78a2Sdrh flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX; 3523d9da78a2Sdrh #else 3524d9da78a2Sdrh flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX; 3525d9da78a2Sdrh #endif 3526d9da78a2Sdrh 3527c6727c83Sdrh if( objc==1 ) return sqliteCmdUsage(interp, objv); 352822fbcb8dSdrh if( objc==2 ){ 352922fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 353022fbcb8dSdrh if( strcmp(zArg,"-version")==0 ){ 3531a198f2b5Sdrh Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0); 3532647cb0e1Sdrh return TCL_OK; 3533647cb0e1Sdrh } 353472bf6a3eSdrh if( strcmp(zArg,"-sourceid")==0 ){ 353572bf6a3eSdrh Tcl_AppendResult(interp,sqlite3_sourceid(), (char*)0); 353672bf6a3eSdrh return TCL_OK; 353772bf6a3eSdrh } 35389eb9e26bSdrh if( strcmp(zArg,"-has-codec")==0 ){ 353932f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 3540a198f2b5Sdrh Tcl_AppendResult(interp,"1",(char*)0); 354122fbcb8dSdrh #else 3542a198f2b5Sdrh Tcl_AppendResult(interp,"0",(char*)0); 354322fbcb8dSdrh #endif 354422fbcb8dSdrh return TCL_OK; 354522fbcb8dSdrh } 35464dcac40eSdrh if( zArg[0]=='-' ) return sqliteCmdUsage(interp, objv); 3547fbc3eab8Sdrh } 35484dcac40eSdrh for(i=2; i<objc; i++){ 35493570ad93Sdrh zArg = Tcl_GetString(objv[i]); 35504dcac40eSdrh if( zArg[0]!='-' ){ 35514dcac40eSdrh if( zFile!=0 ) return sqliteCmdUsage(interp, objv); 35524dcac40eSdrh zFile = zArg; 35534dcac40eSdrh continue; 35544dcac40eSdrh } 35554dcac40eSdrh if( i==objc-1 ) return sqliteCmdUsage(interp, objv); 35564dcac40eSdrh i++; 355722fbcb8dSdrh if( strcmp(zArg,"-key")==0 ){ 355832f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 35594dcac40eSdrh pKey = Tcl_GetByteArrayFromObj(objv[i], &nKey); 3560b07028f7Sdrh #endif 35613570ad93Sdrh }else if( strcmp(zArg, "-vfs")==0 ){ 35624dcac40eSdrh zVfs = Tcl_GetString(objv[i]); 35633570ad93Sdrh }else if( strcmp(zArg, "-readonly")==0 ){ 35643570ad93Sdrh int b; 35654dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 35663570ad93Sdrh if( b ){ 356733f4e02aSdrh flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); 35683570ad93Sdrh flags |= SQLITE_OPEN_READONLY; 35693570ad93Sdrh }else{ 35703570ad93Sdrh flags &= ~SQLITE_OPEN_READONLY; 35713570ad93Sdrh flags |= SQLITE_OPEN_READWRITE; 35723570ad93Sdrh } 35733570ad93Sdrh }else if( strcmp(zArg, "-create")==0 ){ 35743570ad93Sdrh int b; 35754dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 357633f4e02aSdrh if( b && (flags & SQLITE_OPEN_READONLY)==0 ){ 35773570ad93Sdrh flags |= SQLITE_OPEN_CREATE; 35783570ad93Sdrh }else{ 35793570ad93Sdrh flags &= ~SQLITE_OPEN_CREATE; 35803570ad93Sdrh } 35819a6284c1Sdanielk1977 }else if( strcmp(zArg, "-nomutex")==0 ){ 35829a6284c1Sdanielk1977 int b; 35834dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 35849a6284c1Sdanielk1977 if( b ){ 35859a6284c1Sdanielk1977 flags |= SQLITE_OPEN_NOMUTEX; 3586039963adSdrh flags &= ~SQLITE_OPEN_FULLMUTEX; 35879a6284c1Sdanielk1977 }else{ 35889a6284c1Sdanielk1977 flags &= ~SQLITE_OPEN_NOMUTEX; 35899a6284c1Sdanielk1977 } 3590039963adSdrh }else if( strcmp(zArg, "-fullmutex")==0 ){ 3591039963adSdrh int b; 35924dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 3593039963adSdrh if( b ){ 3594039963adSdrh flags |= SQLITE_OPEN_FULLMUTEX; 3595039963adSdrh flags &= ~SQLITE_OPEN_NOMUTEX; 3596039963adSdrh }else{ 3597039963adSdrh flags &= ~SQLITE_OPEN_FULLMUTEX; 3598039963adSdrh } 3599f12b3f60Sdrh }else if( strcmp(zArg, "-uri")==0 ){ 3600f12b3f60Sdrh int b; 36014dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 3602f12b3f60Sdrh if( b ){ 3603f12b3f60Sdrh flags |= SQLITE_OPEN_URI; 3604f12b3f60Sdrh }else{ 3605f12b3f60Sdrh flags &= ~SQLITE_OPEN_URI; 3606f12b3f60Sdrh } 36073570ad93Sdrh }else{ 36083570ad93Sdrh Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); 36093570ad93Sdrh return TCL_ERROR; 361022fbcb8dSdrh } 361122fbcb8dSdrh } 361275897234Sdrh zErrMsg = 0; 36134cdc9e84Sdrh p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); 3614bec3f402Sdrh memset(p, 0, sizeof(*p)); 36153ec8665eSdrh if( zFile==0 ) zFile = ""; 3616882e8e4dSdrh zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename); 3617540ebf82Smistachkin rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs); 3618882e8e4dSdrh Tcl_DStringFree(&translatedFilename); 3619540ebf82Smistachkin if( p->db ){ 362080290863Sdanielk1977 if( SQLITE_OK!=sqlite3_errcode(p->db) ){ 36219404d50eSdrh zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db)); 362280290863Sdanielk1977 sqlite3_close(p->db); 362380290863Sdanielk1977 p->db = 0; 362480290863Sdanielk1977 } 3625540ebf82Smistachkin }else{ 36265dac8432Smistachkin zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc)); 3627540ebf82Smistachkin } 362832f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 3629f3a65f7eSdrh if( p->db ){ 36302011d5f5Sdrh sqlite3_key(p->db, pKey, nKey); 3631f3a65f7eSdrh } 3632eb8ed70dSdrh #endif 3633bec3f402Sdrh if( p->db==0 ){ 363475897234Sdrh Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); 3635bec3f402Sdrh Tcl_Free((char*)p); 36369404d50eSdrh sqlite3_free(zErrMsg); 363775897234Sdrh return TCL_ERROR; 363875897234Sdrh } 3639fb7e7651Sdrh p->maxStmt = NUM_PREPARED_STMTS; 3640147ef394Sdrh p->openFlags = flags & SQLITE_OPEN_URI; 36415169bbc6Sdrh p->interp = interp; 364222fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 36434a4c11aaSdan if( DbUseNre() ){ 3644a2c8a95bSdrh Tcl_NRCreateCommand(interp, zArg, DbObjCmdAdaptor, DbObjCmd, 3645a2c8a95bSdrh (char*)p, DbDeleteCmd); 36464a4c11aaSdan }else{ 364722fbcb8dSdrh Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); 36484a4c11aaSdan } 364975897234Sdrh return TCL_OK; 365075897234Sdrh } 365175897234Sdrh 365275897234Sdrh /* 365390ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static 365490ca9753Sdrh ** library. 365590ca9753Sdrh */ 365690ca9753Sdrh #ifndef USE_TCL_STUBS 365790ca9753Sdrh # undef Tcl_InitStubs 36580e85ccfcSdrh # define Tcl_InitStubs(a,b,c) TCL_VERSION 365990ca9753Sdrh #endif 366090ca9753Sdrh 366190ca9753Sdrh /* 366229bc4615Sdrh ** Make sure we have a PACKAGE_VERSION macro defined. This will be 366329bc4615Sdrh ** defined automatically by the TEA makefile. But other makefiles 366429bc4615Sdrh ** do not define it. 366529bc4615Sdrh */ 366629bc4615Sdrh #ifndef PACKAGE_VERSION 366729bc4615Sdrh # define PACKAGE_VERSION SQLITE_VERSION 366829bc4615Sdrh #endif 366929bc4615Sdrh 367029bc4615Sdrh /* 367175897234Sdrh ** Initialize this module. 367275897234Sdrh ** 367375897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite". 367475897234Sdrh ** (Hence there is no namespace. There is no point in using a namespace 367575897234Sdrh ** if the extension only supplies one new name!) The "sqlite" command is 367675897234Sdrh ** used to open a new SQLite database. See the DbMain() routine above 367775897234Sdrh ** for additional information. 3678b652f432Sdrh ** 3679b652f432Sdrh ** The EXTERN macros are required by TCL in order to work on windows. 368075897234Sdrh */ 3681b652f432Sdrh EXTERN int Sqlite3_Init(Tcl_Interp *interp){ 368227b2f053Smistachkin int rc = Tcl_InitStubs(interp, "8.4", 0) ? TCL_OK : TCL_ERROR; 36836dc8cbe0Sdrh if( rc==TCL_OK ){ 3684ef4ac8f9Sdrh Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); 36851cca0d22Sdrh #ifndef SQLITE_3_SUFFIX_ONLY 36861cca0d22Sdrh /* The "sqlite" alias is undocumented. It is here only to support 36871cca0d22Sdrh ** legacy scripts. All new scripts should use only the "sqlite3" 36886dc8cbe0Sdrh ** command. */ 368949766d6cSdrh Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); 36904c0f1649Sdrh #endif 36916dc8cbe0Sdrh rc = Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION); 36926dc8cbe0Sdrh } 36936dc8cbe0Sdrh return rc; 369490ca9753Sdrh } 3695b652f432Sdrh EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 3696b652f432Sdrh EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 3697b652f432Sdrh EXTERN int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 3698e2c3a659Sdrh 3699d878cab5Sdrh /* Because it accesses the file-system and uses persistent state, SQLite 3700e75a9eb9Sdrh ** is not considered appropriate for safe interpreters. Hence, we cause 3701e75a9eb9Sdrh ** the _SafeInit() interfaces return TCL_ERROR. 3702d878cab5Sdrh */ 3703e75a9eb9Sdrh EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; } 3704e75a9eb9Sdrh EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;} 3705e75a9eb9Sdrh 3706e75a9eb9Sdrh 370749766d6cSdrh 370849766d6cSdrh #ifndef SQLITE_3_SUFFIX_ONLY 3709a3e63c4aSdan int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 3710a3e63c4aSdan int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 3711a3e63c4aSdan int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 3712a3e63c4aSdan int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 371349766d6cSdrh #endif 371475897234Sdrh 3715c318f730Sdrh /* 371696a206faSdrh ** If the TCLSH macro is defined, add code to make a stand-alone program. 3717c318f730Sdrh */ 371896a206faSdrh #if defined(TCLSH) 371957a0227fSdrh 372096a206faSdrh /* This is the main routine for an ordinary TCL shell. If there are 372196a206faSdrh ** are arguments, run the first argument as a script. Otherwise, 372296a206faSdrh ** read TCL commands from standard input 3723348784efSdrh */ 37240ae479dfSdan static const char *tclsh_main_loop(void){ 37250ae479dfSdan static const char zMainloop[] = 372696a206faSdrh "if {[llength $argv]>=1} {\n" 372796a206faSdrh "set argv0 [lindex $argv 0]\n" 372896a206faSdrh "set argv [lrange $argv 1 end]\n" 372996a206faSdrh "source $argv0\n" 373096a206faSdrh "} else {\n" 3731348784efSdrh "set line {}\n" 3732348784efSdrh "while {![eof stdin]} {\n" 3733348784efSdrh "if {$line!=\"\"} {\n" 3734348784efSdrh "puts -nonewline \"> \"\n" 3735348784efSdrh "} else {\n" 3736348784efSdrh "puts -nonewline \"% \"\n" 3737348784efSdrh "}\n" 3738348784efSdrh "flush stdout\n" 3739348784efSdrh "append line [gets stdin]\n" 3740348784efSdrh "if {[info complete $line]} {\n" 3741348784efSdrh "if {[catch {uplevel #0 $line} result]} {\n" 3742348784efSdrh "puts stderr \"Error: $result\"\n" 3743348784efSdrh "} elseif {$result!=\"\"} {\n" 3744348784efSdrh "puts $result\n" 3745348784efSdrh "}\n" 3746348784efSdrh "set line {}\n" 3747348784efSdrh "} else {\n" 3748348784efSdrh "append line \\n\n" 3749348784efSdrh "}\n" 3750348784efSdrh "}\n" 375196a206faSdrh "}\n" 3752348784efSdrh ; 37530ae479dfSdan return zMainloop; 37540ae479dfSdan } 37553e27c026Sdrh 3756c1a60c51Sdan #define TCLSH_MAIN main /* Needed to fake out mktclapp */ 375769def7ffSmistachkin int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){ 3758c1a60c51Sdan Tcl_Interp *interp; 375996a206faSdrh int i; 376096a206faSdrh const char *zScript = 0; 376196a206faSdrh char zArgc[32]; 376296a206faSdrh #if defined(TCLSH_INIT_PROC) 376396a206faSdrh extern const char *TCLSH_INIT_PROC(Tcl_Interp*); 376496a206faSdrh #endif 3765c1a60c51Sdan 37661f28e070Smistachkin #if !defined(_WIN32_WCE) 37671e8487dbSmistachkin if( getenv("SQLITE_DEBUG_BREAK") ){ 37681e8487dbSmistachkin if( isatty(0) && isatty(2) ){ 37691f28e070Smistachkin fprintf(stderr, 37701f28e070Smistachkin "attach debugger to process %d and press any key to continue.\n", 37711f28e070Smistachkin GETPID()); 37721f28e070Smistachkin fgetc(stdin); 37731e8487dbSmistachkin }else{ 37741e8487dbSmistachkin #if defined(_WIN32) || defined(WIN32) 37751e8487dbSmistachkin DebugBreak(); 37761e8487dbSmistachkin #elif defined(SIGTRAP) 37771e8487dbSmistachkin raise(SIGTRAP); 37781e8487dbSmistachkin #endif 37791e8487dbSmistachkin } 37801f28e070Smistachkin } 37811f28e070Smistachkin #endif 37821f28e070Smistachkin 3783c1a60c51Sdan /* Call sqlite3_shutdown() once before doing anything else. This is to 3784c1a60c51Sdan ** test that sqlite3_shutdown() can be safely called by a process before 3785c1a60c51Sdan ** sqlite3_initialize() is. */ 3786c1a60c51Sdan sqlite3_shutdown(); 3787c1a60c51Sdan 37880ae479dfSdan Tcl_FindExecutable(argv[0]); 37892953ba9eSmistachkin Tcl_SetSystemEncoding(NULL, "utf-8"); 37900ae479dfSdan interp = Tcl_CreateInterp(); 3791c318f730Sdrh Sqlite3_Init(interp); 379296a206faSdrh 379396a206faSdrh sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-1); 3794ad42c3a3Sshess Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY); 379596a206faSdrh Tcl_SetVar(interp,"argv0",argv[0],TCL_GLOBAL_ONLY); 3796348784efSdrh Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); 379796a206faSdrh for(i=1; i<argc; i++){ 3798348784efSdrh Tcl_SetVar(interp, "argv", argv[i], 3799348784efSdrh TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); 3800348784efSdrh } 380196a206faSdrh #if defined(TCLSH_INIT_PROC) 380296a206faSdrh zScript = TCLSH_INIT_PROC(interp); 380396a206faSdrh #endif 380496a206faSdrh if( zScript==0 ){ 380596a206faSdrh zScript = tclsh_main_loop(); 380696a206faSdrh } 380796a206faSdrh if( Tcl_GlobalEval(interp, zScript)!=TCL_OK ){ 38080de8c112Sdrh const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); 3809a81c64a2Sdrh if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp); 3810c61053b7Sdrh fprintf(stderr,"%s: %s\n", *argv, zInfo); 3811348784efSdrh return 1; 3812348784efSdrh } 3813348784efSdrh return 0; 3814348784efSdrh } 3815348784efSdrh #endif /* TCLSH */ 3816