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) 631f28e070Smistachkin # include <unistd.h> 641f28e070Smistachkin # define GETPID getpid 651f28e070Smistachkin #elif !defined(_WIN32_WCE) 661f28e070Smistachkin # ifndef SQLITE_AMALGAMATION 67176b3a09Smistachkin # ifndef WIN32_LEAN_AND_MEAN 681f28e070Smistachkin # define WIN32_LEAN_AND_MEAN 69176b3a09Smistachkin # endif 701f28e070Smistachkin # include <windows.h> 711f28e070Smistachkin # endif 721f28e070Smistachkin # define GETPID (int)GetCurrentProcessId 731f28e070Smistachkin #endif 741f28e070Smistachkin 75ad6e1370Sdrh /* 76ad6e1370Sdrh * Windows needs to know which symbols to export. Unix does not. 77ad6e1370Sdrh * BUILD_sqlite should be undefined for Unix. 78ad6e1370Sdrh */ 79ad6e1370Sdrh #ifdef BUILD_sqlite 80ad6e1370Sdrh #undef TCL_STORAGE_CLASS 81ad6e1370Sdrh #define TCL_STORAGE_CLASS DLLEXPORT 82ad6e1370Sdrh #endif /* BUILD_sqlite */ 8329bc4615Sdrh 84a21c6b6fSdanielk1977 #define NUM_PREPARED_STMTS 10 85fb7e7651Sdrh #define MAX_PREPARED_STMTS 100 86fb7e7651Sdrh 87c45e6716Sdrh /* Forward declaration */ 88c45e6716Sdrh typedef struct SqliteDb SqliteDb; 8998808babSdrh 9098808babSdrh /* 91cabb0819Sdrh ** New SQL functions can be created as TCL scripts. Each such function 92cabb0819Sdrh ** is described by an instance of the following structure. 93cabb0819Sdrh */ 94cabb0819Sdrh typedef struct SqlFunc SqlFunc; 95cabb0819Sdrh struct SqlFunc { 96cabb0819Sdrh Tcl_Interp *interp; /* The TCL interpret to execute the function */ 97d1e4733dSdrh Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */ 98c45e6716Sdrh SqliteDb *pDb; /* Database connection that owns this function */ 99d1e4733dSdrh int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */ 100d1e4733dSdrh char *zName; /* Name of this function */ 101cabb0819Sdrh SqlFunc *pNext; /* Next function on the list of them all */ 102cabb0819Sdrh }; 103cabb0819Sdrh 104cabb0819Sdrh /* 1050202b29eSdanielk1977 ** New collation sequences function can be created as TCL scripts. Each such 1060202b29eSdanielk1977 ** function is described by an instance of the following structure. 1070202b29eSdanielk1977 */ 1080202b29eSdanielk1977 typedef struct SqlCollate SqlCollate; 1090202b29eSdanielk1977 struct SqlCollate { 1100202b29eSdanielk1977 Tcl_Interp *interp; /* The TCL interpret to execute the function */ 1110202b29eSdanielk1977 char *zScript; /* The script to be run */ 1120202b29eSdanielk1977 SqlCollate *pNext; /* Next function on the list of them all */ 1130202b29eSdanielk1977 }; 1140202b29eSdanielk1977 1150202b29eSdanielk1977 /* 116fb7e7651Sdrh ** Prepared statements are cached for faster execution. Each prepared 117fb7e7651Sdrh ** statement is described by an instance of the following structure. 118fb7e7651Sdrh */ 119fb7e7651Sdrh typedef struct SqlPreparedStmt SqlPreparedStmt; 120fb7e7651Sdrh struct SqlPreparedStmt { 121fb7e7651Sdrh SqlPreparedStmt *pNext; /* Next in linked list */ 122fb7e7651Sdrh SqlPreparedStmt *pPrev; /* Previous on the list */ 123fb7e7651Sdrh sqlite3_stmt *pStmt; /* The prepared statement */ 124fb7e7651Sdrh int nSql; /* chars in zSql[] */ 125d0e2a854Sdanielk1977 const char *zSql; /* Text of the SQL statement */ 1264a4c11aaSdan int nParm; /* Size of apParm array */ 1274a4c11aaSdan Tcl_Obj **apParm; /* Array of referenced object pointers */ 128fb7e7651Sdrh }; 129fb7e7651Sdrh 130d0441796Sdanielk1977 typedef struct IncrblobChannel IncrblobChannel; 131d0441796Sdanielk1977 132fb7e7651Sdrh /* 133bec3f402Sdrh ** There is one instance of this structure for each SQLite database 134bec3f402Sdrh ** that has been opened by the SQLite TCL interface. 135c431fd55Sdan ** 136c431fd55Sdan ** If this module is built with SQLITE_TEST defined (to create the SQLite 137c431fd55Sdan ** testfixture executable), then it may be configured to use either 138c431fd55Sdan ** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements. 139c431fd55Sdan ** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used. 140bec3f402Sdrh */ 141bec3f402Sdrh struct SqliteDb { 142dddca286Sdrh sqlite3 *db; /* The "real" database structure. MUST BE FIRST */ 143bec3f402Sdrh Tcl_Interp *interp; /* The interpreter used for this database */ 1446d31316cSdrh char *zBusy; /* The busy callback routine */ 145aa940eacSdrh char *zCommit; /* The commit hook callback routine */ 146b5a20d3cSdrh char *zTrace; /* The trace callback routine */ 147b56660f5Smistachkin char *zTraceV2; /* The trace_v2 callback routine */ 14819e2d37fSdrh char *zProfile; /* The profile callback routine */ 149348bb5d6Sdanielk1977 char *zProgress; /* The progress callback routine */ 150e22a334bSdrh char *zAuth; /* The authorization callback routine */ 1511f1549f8Sdrh int disableAuth; /* Disable the authorizer if it exists */ 15255c45f2eSdanielk1977 char *zNull; /* Text to substitute for an SQL NULL value */ 153cabb0819Sdrh SqlFunc *pFunc; /* List of SQL functions */ 15494eb6a14Sdanielk1977 Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ 15546c47d46Sdan Tcl_Obj *pPreUpdateHook; /* Pre-update hook script (if any) */ 15671fd80bfSdanielk1977 Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ 1575def0843Sdrh Tcl_Obj *pWalHook; /* WAL hook script (if any) */ 158404ca075Sdanielk1977 Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */ 1590202b29eSdanielk1977 SqlCollate *pCollate; /* List of SQL collation functions */ 1606f8a503dSdanielk1977 int rc; /* Return code of most recent sqlite3_exec() */ 1617cedc8d4Sdanielk1977 Tcl_Obj *pCollateNeeded; /* Collation needed script */ 162fb7e7651Sdrh SqlPreparedStmt *stmtList; /* List of prepared statements*/ 163fb7e7651Sdrh SqlPreparedStmt *stmtLast; /* Last statement in the list */ 164fb7e7651Sdrh int maxStmt; /* The next maximum number of stmtList */ 165fb7e7651Sdrh int nStmt; /* Number of statements in stmtList */ 166d0441796Sdanielk1977 IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ 1673c379b01Sdrh int nStep, nSort, nIndex; /* Statistics for most recent operation */ 168c456a76fSdan int nVMStep; /* Another statistic for most recent operation */ 169cd38d520Sdanielk1977 int nTransaction; /* Number of nested [transaction] methods */ 170147ef394Sdrh int openFlags; /* Flags used to open. (SQLITE_OPEN_URI) */ 171c431fd55Sdan #ifdef SQLITE_TEST 172c431fd55Sdan int bLegacyPrepare; /* True to use sqlite3_prepare() */ 173c431fd55Sdan #endif 17498808babSdrh }; 175297ecf14Sdrh 176b4e9af9fSdanielk1977 struct IncrblobChannel { 177d0441796Sdanielk1977 sqlite3_blob *pBlob; /* sqlite3 blob handle */ 178dcbb5d3fSdanielk1977 SqliteDb *pDb; /* Associated database connection */ 179b4e9af9fSdanielk1977 int iSeek; /* Current seek offset */ 180d0441796Sdanielk1977 Tcl_Channel channel; /* Channel identifier */ 181d0441796Sdanielk1977 IncrblobChannel *pNext; /* Linked list of all open incrblob channels */ 182d0441796Sdanielk1977 IncrblobChannel *pPrev; /* Linked list of all open incrblob channels */ 183b4e9af9fSdanielk1977 }; 184b4e9af9fSdanielk1977 185ea678832Sdrh /* 186ea678832Sdrh ** Compute a string length that is limited to what can be stored in 187ea678832Sdrh ** lower 30 bits of a 32-bit signed integer. 188ea678832Sdrh */ 1894f21c4afSdrh static int strlen30(const char *z){ 190ea678832Sdrh const char *z2 = z; 191ea678832Sdrh while( *z2 ){ z2++; } 192ea678832Sdrh return 0x3fffffff & (int)(z2 - z); 193ea678832Sdrh } 194ea678832Sdrh 195ea678832Sdrh 19632a0d8bbSdanielk1977 #ifndef SQLITE_OMIT_INCRBLOB 197b4e9af9fSdanielk1977 /* 198d0441796Sdanielk1977 ** Close all incrblob channels opened using database connection pDb. 199d0441796Sdanielk1977 ** This is called when shutting down the database connection. 200d0441796Sdanielk1977 */ 201d0441796Sdanielk1977 static void closeIncrblobChannels(SqliteDb *pDb){ 202d0441796Sdanielk1977 IncrblobChannel *p; 203d0441796Sdanielk1977 IncrblobChannel *pNext; 204d0441796Sdanielk1977 205d0441796Sdanielk1977 for(p=pDb->pIncrblob; p; p=pNext){ 206d0441796Sdanielk1977 pNext = p->pNext; 207d0441796Sdanielk1977 208d0441796Sdanielk1977 /* Note: Calling unregister here call Tcl_Close on the incrblob channel, 209d0441796Sdanielk1977 ** which deletes the IncrblobChannel structure at *p. So do not 210d0441796Sdanielk1977 ** call Tcl_Free() here. 211d0441796Sdanielk1977 */ 212d0441796Sdanielk1977 Tcl_UnregisterChannel(pDb->interp, p->channel); 213d0441796Sdanielk1977 } 214d0441796Sdanielk1977 } 215d0441796Sdanielk1977 216d0441796Sdanielk1977 /* 217b4e9af9fSdanielk1977 ** Close an incremental blob channel. 218b4e9af9fSdanielk1977 */ 2197617e4a8Smistachkin static int SQLITE_TCLAPI incrblobClose( 2207617e4a8Smistachkin ClientData instanceData, 2217617e4a8Smistachkin Tcl_Interp *interp 2227617e4a8Smistachkin ){ 223b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 22492d4d7a9Sdanielk1977 int rc = sqlite3_blob_close(p->pBlob); 22592d4d7a9Sdanielk1977 sqlite3 *db = p->pDb->db; 226d0441796Sdanielk1977 227d0441796Sdanielk1977 /* Remove the channel from the SqliteDb.pIncrblob list. */ 228d0441796Sdanielk1977 if( p->pNext ){ 229d0441796Sdanielk1977 p->pNext->pPrev = p->pPrev; 230d0441796Sdanielk1977 } 231d0441796Sdanielk1977 if( p->pPrev ){ 232d0441796Sdanielk1977 p->pPrev->pNext = p->pNext; 233d0441796Sdanielk1977 } 234d0441796Sdanielk1977 if( p->pDb->pIncrblob==p ){ 235d0441796Sdanielk1977 p->pDb->pIncrblob = p->pNext; 236d0441796Sdanielk1977 } 237d0441796Sdanielk1977 23892d4d7a9Sdanielk1977 /* Free the IncrblobChannel structure */ 239b4e9af9fSdanielk1977 Tcl_Free((char *)p); 24092d4d7a9Sdanielk1977 24192d4d7a9Sdanielk1977 if( rc!=SQLITE_OK ){ 24292d4d7a9Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE); 24392d4d7a9Sdanielk1977 return TCL_ERROR; 24492d4d7a9Sdanielk1977 } 245b4e9af9fSdanielk1977 return TCL_OK; 246b4e9af9fSdanielk1977 } 247b4e9af9fSdanielk1977 248b4e9af9fSdanielk1977 /* 249b4e9af9fSdanielk1977 ** Read data from an incremental blob channel. 250b4e9af9fSdanielk1977 */ 2517617e4a8Smistachkin static int SQLITE_TCLAPI incrblobInput( 252b4e9af9fSdanielk1977 ClientData instanceData, 253b4e9af9fSdanielk1977 char *buf, 254b4e9af9fSdanielk1977 int bufSize, 255b4e9af9fSdanielk1977 int *errorCodePtr 256b4e9af9fSdanielk1977 ){ 257b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 258b4e9af9fSdanielk1977 int nRead = bufSize; /* Number of bytes to read */ 259b4e9af9fSdanielk1977 int nBlob; /* Total size of the blob */ 260b4e9af9fSdanielk1977 int rc; /* sqlite error code */ 261b4e9af9fSdanielk1977 262b4e9af9fSdanielk1977 nBlob = sqlite3_blob_bytes(p->pBlob); 263b4e9af9fSdanielk1977 if( (p->iSeek+nRead)>nBlob ){ 264b4e9af9fSdanielk1977 nRead = nBlob-p->iSeek; 265b4e9af9fSdanielk1977 } 266b4e9af9fSdanielk1977 if( nRead<=0 ){ 267b4e9af9fSdanielk1977 return 0; 268b4e9af9fSdanielk1977 } 269b4e9af9fSdanielk1977 270b4e9af9fSdanielk1977 rc = sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek); 271b4e9af9fSdanielk1977 if( rc!=SQLITE_OK ){ 272b4e9af9fSdanielk1977 *errorCodePtr = rc; 273b4e9af9fSdanielk1977 return -1; 274b4e9af9fSdanielk1977 } 275b4e9af9fSdanielk1977 276b4e9af9fSdanielk1977 p->iSeek += nRead; 277b4e9af9fSdanielk1977 return nRead; 278b4e9af9fSdanielk1977 } 279b4e9af9fSdanielk1977 280d0441796Sdanielk1977 /* 281d0441796Sdanielk1977 ** Write data to an incremental blob channel. 282d0441796Sdanielk1977 */ 2837617e4a8Smistachkin static int SQLITE_TCLAPI incrblobOutput( 284b4e9af9fSdanielk1977 ClientData instanceData, 285b4e9af9fSdanielk1977 CONST char *buf, 286b4e9af9fSdanielk1977 int toWrite, 287b4e9af9fSdanielk1977 int *errorCodePtr 288b4e9af9fSdanielk1977 ){ 289b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 290b4e9af9fSdanielk1977 int nWrite = toWrite; /* Number of bytes to write */ 291b4e9af9fSdanielk1977 int nBlob; /* Total size of the blob */ 292b4e9af9fSdanielk1977 int rc; /* sqlite error code */ 293b4e9af9fSdanielk1977 294b4e9af9fSdanielk1977 nBlob = sqlite3_blob_bytes(p->pBlob); 295b4e9af9fSdanielk1977 if( (p->iSeek+nWrite)>nBlob ){ 296b4e9af9fSdanielk1977 *errorCodePtr = EINVAL; 297b4e9af9fSdanielk1977 return -1; 298b4e9af9fSdanielk1977 } 299b4e9af9fSdanielk1977 if( nWrite<=0 ){ 300b4e9af9fSdanielk1977 return 0; 301b4e9af9fSdanielk1977 } 302b4e9af9fSdanielk1977 303b4e9af9fSdanielk1977 rc = sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek); 304b4e9af9fSdanielk1977 if( rc!=SQLITE_OK ){ 305b4e9af9fSdanielk1977 *errorCodePtr = EIO; 306b4e9af9fSdanielk1977 return -1; 307b4e9af9fSdanielk1977 } 308b4e9af9fSdanielk1977 309b4e9af9fSdanielk1977 p->iSeek += nWrite; 310b4e9af9fSdanielk1977 return nWrite; 311b4e9af9fSdanielk1977 } 312b4e9af9fSdanielk1977 313b4e9af9fSdanielk1977 /* 314b4e9af9fSdanielk1977 ** Seek an incremental blob channel. 315b4e9af9fSdanielk1977 */ 3167617e4a8Smistachkin static int SQLITE_TCLAPI incrblobSeek( 317b4e9af9fSdanielk1977 ClientData instanceData, 318b4e9af9fSdanielk1977 long offset, 319b4e9af9fSdanielk1977 int seekMode, 320b4e9af9fSdanielk1977 int *errorCodePtr 321b4e9af9fSdanielk1977 ){ 322b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 323b4e9af9fSdanielk1977 324b4e9af9fSdanielk1977 switch( seekMode ){ 325b4e9af9fSdanielk1977 case SEEK_SET: 326b4e9af9fSdanielk1977 p->iSeek = offset; 327b4e9af9fSdanielk1977 break; 328b4e9af9fSdanielk1977 case SEEK_CUR: 329b4e9af9fSdanielk1977 p->iSeek += offset; 330b4e9af9fSdanielk1977 break; 331b4e9af9fSdanielk1977 case SEEK_END: 332b4e9af9fSdanielk1977 p->iSeek = sqlite3_blob_bytes(p->pBlob) + offset; 333b4e9af9fSdanielk1977 break; 334b4e9af9fSdanielk1977 335b4e9af9fSdanielk1977 default: assert(!"Bad seekMode"); 336b4e9af9fSdanielk1977 } 337b4e9af9fSdanielk1977 338b4e9af9fSdanielk1977 return p->iSeek; 339b4e9af9fSdanielk1977 } 340b4e9af9fSdanielk1977 341b4e9af9fSdanielk1977 3427617e4a8Smistachkin static void SQLITE_TCLAPI incrblobWatch( 3437617e4a8Smistachkin ClientData instanceData, 3447617e4a8Smistachkin int mode 3457617e4a8Smistachkin ){ 346b4e9af9fSdanielk1977 /* NO-OP */ 347b4e9af9fSdanielk1977 } 3487617e4a8Smistachkin static int SQLITE_TCLAPI incrblobHandle( 3497617e4a8Smistachkin ClientData instanceData, 3507617e4a8Smistachkin int dir, 3517617e4a8Smistachkin ClientData *hPtr 3527617e4a8Smistachkin ){ 353b4e9af9fSdanielk1977 return TCL_ERROR; 354b4e9af9fSdanielk1977 } 355b4e9af9fSdanielk1977 356b4e9af9fSdanielk1977 static Tcl_ChannelType IncrblobChannelType = { 357b4e9af9fSdanielk1977 "incrblob", /* typeName */ 358b4e9af9fSdanielk1977 TCL_CHANNEL_VERSION_2, /* version */ 359b4e9af9fSdanielk1977 incrblobClose, /* closeProc */ 360b4e9af9fSdanielk1977 incrblobInput, /* inputProc */ 361b4e9af9fSdanielk1977 incrblobOutput, /* outputProc */ 362b4e9af9fSdanielk1977 incrblobSeek, /* seekProc */ 363b4e9af9fSdanielk1977 0, /* setOptionProc */ 364b4e9af9fSdanielk1977 0, /* getOptionProc */ 365b4e9af9fSdanielk1977 incrblobWatch, /* watchProc (this is a no-op) */ 366b4e9af9fSdanielk1977 incrblobHandle, /* getHandleProc (always returns error) */ 367b4e9af9fSdanielk1977 0, /* close2Proc */ 368b4e9af9fSdanielk1977 0, /* blockModeProc */ 369b4e9af9fSdanielk1977 0, /* flushProc */ 370b4e9af9fSdanielk1977 0, /* handlerProc */ 371b4e9af9fSdanielk1977 0, /* wideSeekProc */ 372b4e9af9fSdanielk1977 }; 373b4e9af9fSdanielk1977 374b4e9af9fSdanielk1977 /* 375b4e9af9fSdanielk1977 ** Create a new incrblob channel. 376b4e9af9fSdanielk1977 */ 377b4e9af9fSdanielk1977 static int createIncrblobChannel( 378b4e9af9fSdanielk1977 Tcl_Interp *interp, 379b4e9af9fSdanielk1977 SqliteDb *pDb, 380b4e9af9fSdanielk1977 const char *zDb, 381b4e9af9fSdanielk1977 const char *zTable, 382b4e9af9fSdanielk1977 const char *zColumn, 3838cbadb02Sdanielk1977 sqlite_int64 iRow, 3848cbadb02Sdanielk1977 int isReadonly 385b4e9af9fSdanielk1977 ){ 386b4e9af9fSdanielk1977 IncrblobChannel *p; 3878cbadb02Sdanielk1977 sqlite3 *db = pDb->db; 388b4e9af9fSdanielk1977 sqlite3_blob *pBlob; 389b4e9af9fSdanielk1977 int rc; 3908cbadb02Sdanielk1977 int flags = TCL_READABLE|(isReadonly ? 0 : TCL_WRITABLE); 391b4e9af9fSdanielk1977 392b4e9af9fSdanielk1977 /* This variable is used to name the channels: "incrblob_[incr count]" */ 393b4e9af9fSdanielk1977 static int count = 0; 394b4e9af9fSdanielk1977 char zChannel[64]; 395b4e9af9fSdanielk1977 3968cbadb02Sdanielk1977 rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob); 397b4e9af9fSdanielk1977 if( rc!=SQLITE_OK ){ 398b4e9af9fSdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 399b4e9af9fSdanielk1977 return TCL_ERROR; 400b4e9af9fSdanielk1977 } 401b4e9af9fSdanielk1977 402b4e9af9fSdanielk1977 p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel)); 403b4e9af9fSdanielk1977 p->iSeek = 0; 404b4e9af9fSdanielk1977 p->pBlob = pBlob; 405b4e9af9fSdanielk1977 4065bb3eb9bSdrh sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count); 407d0441796Sdanielk1977 p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags); 408d0441796Sdanielk1977 Tcl_RegisterChannel(interp, p->channel); 409b4e9af9fSdanielk1977 410d0441796Sdanielk1977 /* Link the new channel into the SqliteDb.pIncrblob list. */ 411d0441796Sdanielk1977 p->pNext = pDb->pIncrblob; 412d0441796Sdanielk1977 p->pPrev = 0; 413d0441796Sdanielk1977 if( p->pNext ){ 414d0441796Sdanielk1977 p->pNext->pPrev = p; 415d0441796Sdanielk1977 } 416d0441796Sdanielk1977 pDb->pIncrblob = p; 417d0441796Sdanielk1977 p->pDb = pDb; 418d0441796Sdanielk1977 419d0441796Sdanielk1977 Tcl_SetResult(interp, (char *)Tcl_GetChannelName(p->channel), TCL_VOLATILE); 420b4e9af9fSdanielk1977 return TCL_OK; 421b4e9af9fSdanielk1977 } 42232a0d8bbSdanielk1977 #else /* else clause for "#ifndef SQLITE_OMIT_INCRBLOB" */ 42332a0d8bbSdanielk1977 #define closeIncrblobChannels(pDb) 42432a0d8bbSdanielk1977 #endif 425b4e9af9fSdanielk1977 4266d31316cSdrh /* 427d1e4733dSdrh ** Look at the script prefix in pCmd. We will be executing this script 428d1e4733dSdrh ** after first appending one or more arguments. This routine analyzes 429d1e4733dSdrh ** the script to see if it is safe to use Tcl_EvalObjv() on the script 430d1e4733dSdrh ** rather than the more general Tcl_EvalEx(). Tcl_EvalObjv() is much 431d1e4733dSdrh ** faster. 432d1e4733dSdrh ** 433d1e4733dSdrh ** Scripts that are safe to use with Tcl_EvalObjv() consists of a 434d1e4733dSdrh ** command name followed by zero or more arguments with no [...] or $ 435d1e4733dSdrh ** or {...} or ; to be seen anywhere. Most callback scripts consist 436d1e4733dSdrh ** of just a single procedure name and they meet this requirement. 437d1e4733dSdrh */ 438d1e4733dSdrh static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){ 439d1e4733dSdrh /* We could try to do something with Tcl_Parse(). But we will instead 440d1e4733dSdrh ** just do a search for forbidden characters. If any of the forbidden 441d1e4733dSdrh ** characters appear in pCmd, we will report the string as unsafe. 442d1e4733dSdrh */ 443d1e4733dSdrh const char *z; 444d1e4733dSdrh int n; 445d1e4733dSdrh z = Tcl_GetStringFromObj(pCmd, &n); 446d1e4733dSdrh while( n-- > 0 ){ 447d1e4733dSdrh int c = *(z++); 448d1e4733dSdrh if( c=='$' || c=='[' || c==';' ) return 0; 449d1e4733dSdrh } 450d1e4733dSdrh return 1; 451d1e4733dSdrh } 452d1e4733dSdrh 453d1e4733dSdrh /* 454d1e4733dSdrh ** Find an SqlFunc structure with the given name. Or create a new 455d1e4733dSdrh ** one if an existing one cannot be found. Return a pointer to the 456d1e4733dSdrh ** structure. 457d1e4733dSdrh */ 458d1e4733dSdrh static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ 459d1e4733dSdrh SqlFunc *p, *pNew; 4600425f189Sdrh int nName = strlen30(zName); 4610425f189Sdrh pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 ); 462d1e4733dSdrh pNew->zName = (char*)&pNew[1]; 4630425f189Sdrh memcpy(pNew->zName, zName, nName+1); 464d1e4733dSdrh for(p=pDb->pFunc; p; p=p->pNext){ 4650425f189Sdrh if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){ 466d1e4733dSdrh Tcl_Free((char*)pNew); 467d1e4733dSdrh return p; 468d1e4733dSdrh } 469d1e4733dSdrh } 470d1e4733dSdrh pNew->interp = pDb->interp; 471c45e6716Sdrh pNew->pDb = pDb; 472d1e4733dSdrh pNew->pScript = 0; 473d1e4733dSdrh pNew->pNext = pDb->pFunc; 474d1e4733dSdrh pDb->pFunc = pNew; 475d1e4733dSdrh return pNew; 476d1e4733dSdrh } 477d1e4733dSdrh 478d1e4733dSdrh /* 479c431fd55Sdan ** Free a single SqlPreparedStmt object. 480c431fd55Sdan */ 481c431fd55Sdan static void dbFreeStmt(SqlPreparedStmt *pStmt){ 482c431fd55Sdan #ifdef SQLITE_TEST 483c431fd55Sdan if( sqlite3_sql(pStmt->pStmt)==0 ){ 484c431fd55Sdan Tcl_Free((char *)pStmt->zSql); 485c431fd55Sdan } 486c431fd55Sdan #endif 487c431fd55Sdan sqlite3_finalize(pStmt->pStmt); 488c431fd55Sdan Tcl_Free((char *)pStmt); 489c431fd55Sdan } 490c431fd55Sdan 491c431fd55Sdan /* 492fb7e7651Sdrh ** Finalize and free a list of prepared statements 493fb7e7651Sdrh */ 494fb7e7651Sdrh static void flushStmtCache(SqliteDb *pDb){ 495fb7e7651Sdrh SqlPreparedStmt *pPreStmt; 496c431fd55Sdan SqlPreparedStmt *pNext; 497fb7e7651Sdrh 498c431fd55Sdan for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pNext){ 499c431fd55Sdan pNext = pPreStmt->pNext; 500c431fd55Sdan dbFreeStmt(pPreStmt); 501fb7e7651Sdrh } 502fb7e7651Sdrh pDb->nStmt = 0; 503fb7e7651Sdrh pDb->stmtLast = 0; 504c431fd55Sdan pDb->stmtList = 0; 505fb7e7651Sdrh } 506fb7e7651Sdrh 507fb7e7651Sdrh /* 508895d7472Sdrh ** TCL calls this procedure when an sqlite3 database command is 509895d7472Sdrh ** deleted. 51075897234Sdrh */ 5117617e4a8Smistachkin static void SQLITE_TCLAPI DbDeleteCmd(void *db){ 512bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)db; 513fb7e7651Sdrh flushStmtCache(pDb); 514d0441796Sdanielk1977 closeIncrblobChannels(pDb); 5156f8a503dSdanielk1977 sqlite3_close(pDb->db); 516cabb0819Sdrh while( pDb->pFunc ){ 517cabb0819Sdrh SqlFunc *pFunc = pDb->pFunc; 518cabb0819Sdrh pDb->pFunc = pFunc->pNext; 519c45e6716Sdrh assert( pFunc->pDb==pDb ); 520d1e4733dSdrh Tcl_DecrRefCount(pFunc->pScript); 521cabb0819Sdrh Tcl_Free((char*)pFunc); 522cabb0819Sdrh } 5230202b29eSdanielk1977 while( pDb->pCollate ){ 5240202b29eSdanielk1977 SqlCollate *pCollate = pDb->pCollate; 5250202b29eSdanielk1977 pDb->pCollate = pCollate->pNext; 5260202b29eSdanielk1977 Tcl_Free((char*)pCollate); 5270202b29eSdanielk1977 } 528bec3f402Sdrh if( pDb->zBusy ){ 529bec3f402Sdrh Tcl_Free(pDb->zBusy); 530bec3f402Sdrh } 531b5a20d3cSdrh if( pDb->zTrace ){ 532b5a20d3cSdrh Tcl_Free(pDb->zTrace); 5330d1a643aSdrh } 534b56660f5Smistachkin if( pDb->zTraceV2 ){ 535b56660f5Smistachkin Tcl_Free(pDb->zTraceV2); 536b56660f5Smistachkin } 53719e2d37fSdrh if( pDb->zProfile ){ 53819e2d37fSdrh Tcl_Free(pDb->zProfile); 53919e2d37fSdrh } 540e22a334bSdrh if( pDb->zAuth ){ 541e22a334bSdrh Tcl_Free(pDb->zAuth); 542e22a334bSdrh } 54355c45f2eSdanielk1977 if( pDb->zNull ){ 54455c45f2eSdanielk1977 Tcl_Free(pDb->zNull); 54555c45f2eSdanielk1977 } 54694eb6a14Sdanielk1977 if( pDb->pUpdateHook ){ 54794eb6a14Sdanielk1977 Tcl_DecrRefCount(pDb->pUpdateHook); 54894eb6a14Sdanielk1977 } 54946c47d46Sdan if( pDb->pPreUpdateHook ){ 55046c47d46Sdan Tcl_DecrRefCount(pDb->pPreUpdateHook); 55146c47d46Sdan } 55271fd80bfSdanielk1977 if( pDb->pRollbackHook ){ 55371fd80bfSdanielk1977 Tcl_DecrRefCount(pDb->pRollbackHook); 55471fd80bfSdanielk1977 } 5555def0843Sdrh if( pDb->pWalHook ){ 5565def0843Sdrh Tcl_DecrRefCount(pDb->pWalHook); 5578d22a174Sdan } 55894eb6a14Sdanielk1977 if( pDb->pCollateNeeded ){ 55994eb6a14Sdanielk1977 Tcl_DecrRefCount(pDb->pCollateNeeded); 56094eb6a14Sdanielk1977 } 561bec3f402Sdrh Tcl_Free((char*)pDb); 562bec3f402Sdrh } 563bec3f402Sdrh 564bec3f402Sdrh /* 565bec3f402Sdrh ** This routine is called when a database file is locked while trying 566bec3f402Sdrh ** to execute SQL. 567bec3f402Sdrh */ 5682a764eb0Sdanielk1977 static int DbBusyHandler(void *cd, int nTries){ 569bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 570bec3f402Sdrh int rc; 571bec3f402Sdrh char zVal[30]; 572bec3f402Sdrh 5735bb3eb9bSdrh sqlite3_snprintf(sizeof(zVal), zVal, "%d", nTries); 574d1e4733dSdrh rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0); 575bec3f402Sdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 576bec3f402Sdrh return 0; 577bec3f402Sdrh } 578bec3f402Sdrh return 1; 57975897234Sdrh } 58075897234Sdrh 58126e4a8b1Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK 58275897234Sdrh /* 583348bb5d6Sdanielk1977 ** This routine is invoked as the 'progress callback' for the database. 584348bb5d6Sdanielk1977 */ 585348bb5d6Sdanielk1977 static int DbProgressHandler(void *cd){ 586348bb5d6Sdanielk1977 SqliteDb *pDb = (SqliteDb*)cd; 587348bb5d6Sdanielk1977 int rc; 588348bb5d6Sdanielk1977 589348bb5d6Sdanielk1977 assert( pDb->zProgress ); 590348bb5d6Sdanielk1977 rc = Tcl_Eval(pDb->interp, pDb->zProgress); 591348bb5d6Sdanielk1977 if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 592348bb5d6Sdanielk1977 return 1; 593348bb5d6Sdanielk1977 } 594348bb5d6Sdanielk1977 return 0; 595348bb5d6Sdanielk1977 } 59626e4a8b1Sdrh #endif 597348bb5d6Sdanielk1977 5982eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 5992eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 600348bb5d6Sdanielk1977 /* 601b5a20d3cSdrh ** This routine is called by the SQLite trace handler whenever a new 602b5a20d3cSdrh ** block of SQL is executed. The TCL script in pDb->zTrace is executed. 6030d1a643aSdrh */ 604b5a20d3cSdrh static void DbTraceHandler(void *cd, const char *zSql){ 6050d1a643aSdrh SqliteDb *pDb = (SqliteDb*)cd; 606b5a20d3cSdrh Tcl_DString str; 6070d1a643aSdrh 608b5a20d3cSdrh Tcl_DStringInit(&str); 609b5a20d3cSdrh Tcl_DStringAppend(&str, pDb->zTrace, -1); 610b5a20d3cSdrh Tcl_DStringAppendElement(&str, zSql); 611b5a20d3cSdrh Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); 612b5a20d3cSdrh Tcl_DStringFree(&str); 613b5a20d3cSdrh Tcl_ResetResult(pDb->interp); 6140d1a643aSdrh } 615d1167393Sdrh #endif 6160d1a643aSdrh 617d1167393Sdrh #ifndef SQLITE_OMIT_TRACE 6180d1a643aSdrh /* 619b56660f5Smistachkin ** This routine is called by the SQLite trace_v2 handler whenever a new 620b56660f5Smistachkin ** supported event is generated. Unsupported event types are ignored. 621b56660f5Smistachkin ** The TCL script in pDb->zTraceV2 is executed, with the arguments for 622b56660f5Smistachkin ** the event appended to it (as list elements). 623b56660f5Smistachkin */ 624b56660f5Smistachkin static int DbTraceV2Handler( 625b56660f5Smistachkin unsigned type, /* One of the SQLITE_TRACE_* event types. */ 626b56660f5Smistachkin void *cd, /* The original context data pointer. */ 627b56660f5Smistachkin void *pd, /* Primary event data, depends on event type. */ 628b56660f5Smistachkin void *xd /* Extra event data, depends on event type. */ 629b56660f5Smistachkin ){ 630b56660f5Smistachkin SqliteDb *pDb = (SqliteDb*)cd; 631b56660f5Smistachkin Tcl_Obj *pCmd; 632b56660f5Smistachkin 633b56660f5Smistachkin switch( type ){ 634b56660f5Smistachkin case SQLITE_TRACE_STMT: { 635b56660f5Smistachkin sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; 636b56660f5Smistachkin char *zSql = (char *)xd; 637b56660f5Smistachkin 638b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 639b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 640b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 641b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); 642b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 643b56660f5Smistachkin Tcl_NewStringObj(zSql, -1)); 644b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 645b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 646b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 647b56660f5Smistachkin break; 648b56660f5Smistachkin } 649b56660f5Smistachkin case SQLITE_TRACE_PROFILE: { 650b56660f5Smistachkin sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; 651b56660f5Smistachkin sqlite3_int64 ns = (sqlite3_int64)xd; 652b56660f5Smistachkin 653b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 654b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 655b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 656b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); 657b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 658b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)ns)); 659b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 660b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 661b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 662b56660f5Smistachkin break; 663b56660f5Smistachkin } 664b56660f5Smistachkin case SQLITE_TRACE_ROW: { 665b56660f5Smistachkin sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; 666b56660f5Smistachkin 667b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 668b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 669b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 670b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); 671b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 672b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 673b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 674b56660f5Smistachkin break; 675b56660f5Smistachkin } 676b56660f5Smistachkin case SQLITE_TRACE_CLOSE: { 677b56660f5Smistachkin sqlite3 *db = (sqlite3 *)pd; 678b56660f5Smistachkin 679b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 680b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 681b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 682b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)db)); 683b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 684b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 685b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 686b56660f5Smistachkin break; 687b56660f5Smistachkin } 688b56660f5Smistachkin } 689b56660f5Smistachkin return SQLITE_OK; 690b56660f5Smistachkin } 691b56660f5Smistachkin #endif 692b56660f5Smistachkin 6932eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 6942eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 695b56660f5Smistachkin /* 69619e2d37fSdrh ** This routine is called by the SQLite profile handler after a statement 69719e2d37fSdrh ** SQL has executed. The TCL script in pDb->zProfile is evaluated. 69819e2d37fSdrh */ 69919e2d37fSdrh static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){ 70019e2d37fSdrh SqliteDb *pDb = (SqliteDb*)cd; 70119e2d37fSdrh Tcl_DString str; 70219e2d37fSdrh char zTm[100]; 70319e2d37fSdrh 70419e2d37fSdrh sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm); 70519e2d37fSdrh Tcl_DStringInit(&str); 70619e2d37fSdrh Tcl_DStringAppend(&str, pDb->zProfile, -1); 70719e2d37fSdrh Tcl_DStringAppendElement(&str, zSql); 70819e2d37fSdrh Tcl_DStringAppendElement(&str, zTm); 70919e2d37fSdrh Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); 71019e2d37fSdrh Tcl_DStringFree(&str); 71119e2d37fSdrh Tcl_ResetResult(pDb->interp); 71219e2d37fSdrh } 713d1167393Sdrh #endif 71419e2d37fSdrh 71519e2d37fSdrh /* 716aa940eacSdrh ** This routine is called when a transaction is committed. The 717aa940eacSdrh ** TCL script in pDb->zCommit is executed. If it returns non-zero or 718aa940eacSdrh ** if it throws an exception, the transaction is rolled back instead 719aa940eacSdrh ** of being committed. 720aa940eacSdrh */ 721aa940eacSdrh static int DbCommitHandler(void *cd){ 722aa940eacSdrh SqliteDb *pDb = (SqliteDb*)cd; 723aa940eacSdrh int rc; 724aa940eacSdrh 725aa940eacSdrh rc = Tcl_Eval(pDb->interp, pDb->zCommit); 726aa940eacSdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 727aa940eacSdrh return 1; 728aa940eacSdrh } 729aa940eacSdrh return 0; 730aa940eacSdrh } 731aa940eacSdrh 73271fd80bfSdanielk1977 static void DbRollbackHandler(void *clientData){ 73371fd80bfSdanielk1977 SqliteDb *pDb = (SqliteDb*)clientData; 73471fd80bfSdanielk1977 assert(pDb->pRollbackHook); 73571fd80bfSdanielk1977 if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){ 73671fd80bfSdanielk1977 Tcl_BackgroundError(pDb->interp); 73771fd80bfSdanielk1977 } 73871fd80bfSdanielk1977 } 73971fd80bfSdanielk1977 7405def0843Sdrh /* 7415def0843Sdrh ** This procedure handles wal_hook callbacks. 7425def0843Sdrh */ 7435def0843Sdrh static int DbWalHandler( 7448d22a174Sdan void *clientData, 7458d22a174Sdan sqlite3 *db, 7468d22a174Sdan const char *zDb, 7478d22a174Sdan int nEntry 7488d22a174Sdan ){ 7495def0843Sdrh int ret = SQLITE_OK; 7508d22a174Sdan Tcl_Obj *p; 7518d22a174Sdan SqliteDb *pDb = (SqliteDb*)clientData; 7528d22a174Sdan Tcl_Interp *interp = pDb->interp; 7535def0843Sdrh assert(pDb->pWalHook); 7548d22a174Sdan 7556e45e0c8Sdan assert( db==pDb->db ); 7565def0843Sdrh p = Tcl_DuplicateObj(pDb->pWalHook); 7578d22a174Sdan Tcl_IncrRefCount(p); 7588d22a174Sdan Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1)); 7598d22a174Sdan Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry)); 7608d22a174Sdan if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0) 7618d22a174Sdan || TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret) 7628d22a174Sdan ){ 7638d22a174Sdan Tcl_BackgroundError(interp); 7648d22a174Sdan } 7658d22a174Sdan Tcl_DecrRefCount(p); 7668d22a174Sdan 7678d22a174Sdan return ret; 7688d22a174Sdan } 7698d22a174Sdan 770bcf4f484Sdrh #if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) 771404ca075Sdanielk1977 static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){ 772404ca075Sdanielk1977 char zBuf[64]; 77365545b59Sdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iArg); 774404ca075Sdanielk1977 Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY); 77565545b59Sdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nArg); 776404ca075Sdanielk1977 Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY); 777404ca075Sdanielk1977 } 778404ca075Sdanielk1977 #else 779404ca075Sdanielk1977 # define setTestUnlockNotifyVars(x,y,z) 780404ca075Sdanielk1977 #endif 781404ca075Sdanielk1977 78269910da9Sdrh #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY 783404ca075Sdanielk1977 static void DbUnlockNotify(void **apArg, int nArg){ 784404ca075Sdanielk1977 int i; 785404ca075Sdanielk1977 for(i=0; i<nArg; i++){ 786404ca075Sdanielk1977 const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); 787404ca075Sdanielk1977 SqliteDb *pDb = (SqliteDb *)apArg[i]; 788404ca075Sdanielk1977 setTestUnlockNotifyVars(pDb->interp, i, nArg); 789404ca075Sdanielk1977 assert( pDb->pUnlockNotify); 790404ca075Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pDb->pUnlockNotify, flags); 791404ca075Sdanielk1977 Tcl_DecrRefCount(pDb->pUnlockNotify); 792404ca075Sdanielk1977 pDb->pUnlockNotify = 0; 793404ca075Sdanielk1977 } 794404ca075Sdanielk1977 } 79569910da9Sdrh #endif 796404ca075Sdanielk1977 7979b1c62d4Sdrh #ifdef SQLITE_ENABLE_PREUPDATE_HOOK 79846c47d46Sdan /* 79946c47d46Sdan ** Pre-update hook callback. 80046c47d46Sdan */ 80146c47d46Sdan static void DbPreUpdateHandler( 80246c47d46Sdan void *p, 80346c47d46Sdan sqlite3 *db, 80446c47d46Sdan int op, 80546c47d46Sdan const char *zDb, 80646c47d46Sdan const char *zTbl, 80746c47d46Sdan sqlite_int64 iKey1, 80846c47d46Sdan sqlite_int64 iKey2 80946c47d46Sdan ){ 81046c47d46Sdan SqliteDb *pDb = (SqliteDb *)p; 81146c47d46Sdan Tcl_Obj *pCmd; 81246c47d46Sdan static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"}; 81346c47d46Sdan 81446c47d46Sdan assert( (SQLITE_DELETE-1)/9 == 0 ); 81546c47d46Sdan assert( (SQLITE_INSERT-1)/9 == 1 ); 81646c47d46Sdan assert( (SQLITE_UPDATE-1)/9 == 2 ); 81746c47d46Sdan assert( pDb->pPreUpdateHook ); 81846c47d46Sdan assert( db==pDb->db ); 81946c47d46Sdan assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); 82046c47d46Sdan 82146c47d46Sdan pCmd = Tcl_DuplicateObj(pDb->pPreUpdateHook); 82246c47d46Sdan Tcl_IncrRefCount(pCmd); 82346c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(azStr[(op-1)/9], -1)); 82446c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1)); 82546c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1)); 82646c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey1)); 82746c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey2)); 82846c47d46Sdan Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 82946c47d46Sdan Tcl_DecrRefCount(pCmd); 83046c47d46Sdan } 8319b1c62d4Sdrh #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ 83246c47d46Sdan 83394eb6a14Sdanielk1977 static void DbUpdateHandler( 83494eb6a14Sdanielk1977 void *p, 83594eb6a14Sdanielk1977 int op, 83694eb6a14Sdanielk1977 const char *zDb, 83794eb6a14Sdanielk1977 const char *zTbl, 83894eb6a14Sdanielk1977 sqlite_int64 rowid 83994eb6a14Sdanielk1977 ){ 84094eb6a14Sdanielk1977 SqliteDb *pDb = (SqliteDb *)p; 84194eb6a14Sdanielk1977 Tcl_Obj *pCmd; 84246c47d46Sdan static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"}; 84346c47d46Sdan 84446c47d46Sdan assert( (SQLITE_DELETE-1)/9 == 0 ); 84546c47d46Sdan assert( (SQLITE_INSERT-1)/9 == 1 ); 84646c47d46Sdan assert( (SQLITE_UPDATE-1)/9 == 2 ); 84794eb6a14Sdanielk1977 84894eb6a14Sdanielk1977 assert( pDb->pUpdateHook ); 84994eb6a14Sdanielk1977 assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); 85094eb6a14Sdanielk1977 85194eb6a14Sdanielk1977 pCmd = Tcl_DuplicateObj(pDb->pUpdateHook); 85294eb6a14Sdanielk1977 Tcl_IncrRefCount(pCmd); 85346c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(azStr[(op-1)/9], -1)); 85494eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1)); 85594eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1)); 85694eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid)); 85794eb6a14Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 858efdde169Sdrh Tcl_DecrRefCount(pCmd); 85994eb6a14Sdanielk1977 } 86094eb6a14Sdanielk1977 8617cedc8d4Sdanielk1977 static void tclCollateNeeded( 8627cedc8d4Sdanielk1977 void *pCtx, 8639bb575fdSdrh sqlite3 *db, 8647cedc8d4Sdanielk1977 int enc, 8657cedc8d4Sdanielk1977 const char *zName 8667cedc8d4Sdanielk1977 ){ 8677cedc8d4Sdanielk1977 SqliteDb *pDb = (SqliteDb *)pCtx; 8687cedc8d4Sdanielk1977 Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded); 8697cedc8d4Sdanielk1977 Tcl_IncrRefCount(pScript); 8707cedc8d4Sdanielk1977 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1)); 8717cedc8d4Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pScript, 0); 8727cedc8d4Sdanielk1977 Tcl_DecrRefCount(pScript); 8737cedc8d4Sdanielk1977 } 8747cedc8d4Sdanielk1977 875aa940eacSdrh /* 8760202b29eSdanielk1977 ** This routine is called to evaluate an SQL collation function implemented 8770202b29eSdanielk1977 ** using TCL script. 8780202b29eSdanielk1977 */ 8790202b29eSdanielk1977 static int tclSqlCollate( 8800202b29eSdanielk1977 void *pCtx, 8810202b29eSdanielk1977 int nA, 8820202b29eSdanielk1977 const void *zA, 8830202b29eSdanielk1977 int nB, 8840202b29eSdanielk1977 const void *zB 8850202b29eSdanielk1977 ){ 8860202b29eSdanielk1977 SqlCollate *p = (SqlCollate *)pCtx; 8870202b29eSdanielk1977 Tcl_Obj *pCmd; 8880202b29eSdanielk1977 8890202b29eSdanielk1977 pCmd = Tcl_NewStringObj(p->zScript, -1); 8900202b29eSdanielk1977 Tcl_IncrRefCount(pCmd); 8910202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA)); 8920202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB)); 893d1e4733dSdrh Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); 8940202b29eSdanielk1977 Tcl_DecrRefCount(pCmd); 8950202b29eSdanielk1977 return (atoi(Tcl_GetStringResult(p->interp))); 8960202b29eSdanielk1977 } 8970202b29eSdanielk1977 8980202b29eSdanielk1977 /* 899cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented 900cabb0819Sdrh ** using TCL script. 901cabb0819Sdrh */ 9020ae8b831Sdanielk1977 static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ 9036f8a503dSdanielk1977 SqlFunc *p = sqlite3_user_data(context); 904d1e4733dSdrh Tcl_Obj *pCmd; 905cabb0819Sdrh int i; 906cabb0819Sdrh int rc; 907cabb0819Sdrh 908d1e4733dSdrh if( argc==0 ){ 909d1e4733dSdrh /* If there are no arguments to the function, call Tcl_EvalObjEx on the 910d1e4733dSdrh ** script object directly. This allows the TCL compiler to generate 911d1e4733dSdrh ** bytecode for the command on the first invocation and thus make 912d1e4733dSdrh ** subsequent invocations much faster. */ 913d1e4733dSdrh pCmd = p->pScript; 914d1e4733dSdrh Tcl_IncrRefCount(pCmd); 915d1e4733dSdrh rc = Tcl_EvalObjEx(p->interp, pCmd, 0); 916d1e4733dSdrh Tcl_DecrRefCount(pCmd); 91751ad0ecdSdanielk1977 }else{ 918d1e4733dSdrh /* If there are arguments to the function, make a shallow copy of the 919d1e4733dSdrh ** script object, lappend the arguments, then evaluate the copy. 920d1e4733dSdrh ** 92160ec914cSpeter.d.reid ** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated. 922d1e4733dSdrh ** The new Tcl_Obj contains pointers to the original list elements. 923d1e4733dSdrh ** That way, when Tcl_EvalObjv() is run and shimmers the first element 924d1e4733dSdrh ** of the list to tclCmdNameType, that alternate representation will 925d1e4733dSdrh ** be preserved and reused on the next invocation. 926d1e4733dSdrh */ 927d1e4733dSdrh Tcl_Obj **aArg; 928d1e4733dSdrh int nArg; 929d1e4733dSdrh if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){ 930d1e4733dSdrh sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 931d1e4733dSdrh return; 932d1e4733dSdrh } 933d1e4733dSdrh pCmd = Tcl_NewListObj(nArg, aArg); 934d1e4733dSdrh Tcl_IncrRefCount(pCmd); 935d1e4733dSdrh for(i=0; i<argc; i++){ 936d1e4733dSdrh sqlite3_value *pIn = argv[i]; 937d1e4733dSdrh Tcl_Obj *pVal; 938d1e4733dSdrh 939d1e4733dSdrh /* Set pVal to contain the i'th column of this row. */ 940d1e4733dSdrh switch( sqlite3_value_type(pIn) ){ 941d1e4733dSdrh case SQLITE_BLOB: { 942d1e4733dSdrh int bytes = sqlite3_value_bytes(pIn); 943d1e4733dSdrh pVal = Tcl_NewByteArrayObj(sqlite3_value_blob(pIn), bytes); 944d1e4733dSdrh break; 945d1e4733dSdrh } 946d1e4733dSdrh case SQLITE_INTEGER: { 947d1e4733dSdrh sqlite_int64 v = sqlite3_value_int64(pIn); 948d1e4733dSdrh if( v>=-2147483647 && v<=2147483647 ){ 9497fd33929Sdrh pVal = Tcl_NewIntObj((int)v); 950d1e4733dSdrh }else{ 951d1e4733dSdrh pVal = Tcl_NewWideIntObj(v); 952d1e4733dSdrh } 953d1e4733dSdrh break; 954d1e4733dSdrh } 955d1e4733dSdrh case SQLITE_FLOAT: { 956d1e4733dSdrh double r = sqlite3_value_double(pIn); 957d1e4733dSdrh pVal = Tcl_NewDoubleObj(r); 958d1e4733dSdrh break; 959d1e4733dSdrh } 960d1e4733dSdrh case SQLITE_NULL: { 961c45e6716Sdrh pVal = Tcl_NewStringObj(p->pDb->zNull, -1); 962d1e4733dSdrh break; 963d1e4733dSdrh } 964d1e4733dSdrh default: { 965d1e4733dSdrh int bytes = sqlite3_value_bytes(pIn); 96600fd957bSdanielk1977 pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes); 967d1e4733dSdrh break; 96851ad0ecdSdanielk1977 } 969cabb0819Sdrh } 970d1e4733dSdrh rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal); 971d1e4733dSdrh if( rc ){ 972d1e4733dSdrh Tcl_DecrRefCount(pCmd); 973d1e4733dSdrh sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 974d1e4733dSdrh return; 975d1e4733dSdrh } 976d1e4733dSdrh } 977d1e4733dSdrh if( !p->useEvalObjv ){ 978d1e4733dSdrh /* Tcl_EvalObjEx() will automatically call Tcl_EvalObjv() if pCmd 979d1e4733dSdrh ** is a list without a string representation. To prevent this from 980d1e4733dSdrh ** happening, make sure pCmd has a valid string representation */ 981d1e4733dSdrh Tcl_GetString(pCmd); 982d1e4733dSdrh } 983d1e4733dSdrh rc = Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); 984d1e4733dSdrh Tcl_DecrRefCount(pCmd); 985d1e4733dSdrh } 986562e8d3cSdanielk1977 987c7f269d5Sdrh if( rc && rc!=TCL_RETURN ){ 9887e18c259Sdanielk1977 sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 989cabb0819Sdrh }else{ 990c7f269d5Sdrh Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); 991c7f269d5Sdrh int n; 992c7f269d5Sdrh u8 *data; 9934a4c11aaSdan const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); 994c7f269d5Sdrh char c = zType[0]; 995df0bddaeSdrh if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ 996d1e4733dSdrh /* Only return a BLOB type if the Tcl variable is a bytearray and 997df0bddaeSdrh ** has no string representation. */ 998c7f269d5Sdrh data = Tcl_GetByteArrayFromObj(pVar, &n); 999c7f269d5Sdrh sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT); 1000985e0c63Sdrh }else if( c=='b' && strcmp(zType,"boolean")==0 ){ 1001c7f269d5Sdrh Tcl_GetIntFromObj(0, pVar, &n); 1002c7f269d5Sdrh sqlite3_result_int(context, n); 1003c7f269d5Sdrh }else if( c=='d' && strcmp(zType,"double")==0 ){ 1004c7f269d5Sdrh double r; 1005c7f269d5Sdrh Tcl_GetDoubleFromObj(0, pVar, &r); 1006c7f269d5Sdrh sqlite3_result_double(context, r); 1007985e0c63Sdrh }else if( (c=='w' && strcmp(zType,"wideInt")==0) || 1008985e0c63Sdrh (c=='i' && strcmp(zType,"int")==0) ){ 1009df0bddaeSdrh Tcl_WideInt v; 1010df0bddaeSdrh Tcl_GetWideIntFromObj(0, pVar, &v); 1011df0bddaeSdrh sqlite3_result_int64(context, v); 1012c7f269d5Sdrh }else{ 101300fd957bSdanielk1977 data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); 101400fd957bSdanielk1977 sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT); 1015c7f269d5Sdrh } 1016cabb0819Sdrh } 1017cabb0819Sdrh } 1018895d7472Sdrh 1019e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION 1020e22a334bSdrh /* 1021e22a334bSdrh ** This is the authentication function. It appends the authentication 1022e22a334bSdrh ** type code and the two arguments to zCmd[] then invokes the result 1023e22a334bSdrh ** on the interpreter. The reply is examined to determine if the 1024e22a334bSdrh ** authentication fails or succeeds. 1025e22a334bSdrh */ 1026e22a334bSdrh static int auth_callback( 1027e22a334bSdrh void *pArg, 1028e22a334bSdrh int code, 1029e22a334bSdrh const char *zArg1, 1030e22a334bSdrh const char *zArg2, 1031e22a334bSdrh const char *zArg3, 1032e22a334bSdrh const char *zArg4 103332c6a48bSdrh #ifdef SQLITE_USER_AUTHENTICATION 103432c6a48bSdrh ,const char *zArg5 103532c6a48bSdrh #endif 1036e22a334bSdrh ){ 10376ef5e12eSmistachkin const char *zCode; 1038e22a334bSdrh Tcl_DString str; 1039e22a334bSdrh int rc; 1040e22a334bSdrh const char *zReply; 10419418921cSdrh /* EVIDENCE-OF: R-38590-62769 The first parameter to the authorizer 10429418921cSdrh ** callback is a copy of the third parameter to the 10439418921cSdrh ** sqlite3_set_authorizer() interface. 10449418921cSdrh */ 1045e22a334bSdrh SqliteDb *pDb = (SqliteDb*)pArg; 10461f1549f8Sdrh if( pDb->disableAuth ) return SQLITE_OK; 1047e22a334bSdrh 10489418921cSdrh /* EVIDENCE-OF: R-56518-44310 The second parameter to the callback is an 10499418921cSdrh ** integer action code that specifies the particular action to be 10509418921cSdrh ** authorized. */ 1051e22a334bSdrh switch( code ){ 1052e22a334bSdrh case SQLITE_COPY : zCode="SQLITE_COPY"; break; 1053e22a334bSdrh case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; 1054e22a334bSdrh case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; 1055e22a334bSdrh case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; 1056e22a334bSdrh case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; 1057e22a334bSdrh case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; 1058e22a334bSdrh case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; 1059e22a334bSdrh case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; 1060e22a334bSdrh case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; 1061e22a334bSdrh case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; 1062e22a334bSdrh case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; 1063e22a334bSdrh case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; 1064e22a334bSdrh case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; 1065e22a334bSdrh case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; 1066e22a334bSdrh case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; 1067e22a334bSdrh case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; 1068e22a334bSdrh case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; 1069e22a334bSdrh case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; 1070e22a334bSdrh case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; 1071e22a334bSdrh case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; 1072e22a334bSdrh case SQLITE_READ : zCode="SQLITE_READ"; break; 1073e22a334bSdrh case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; 1074e22a334bSdrh case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; 1075e22a334bSdrh case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; 107681e293b4Sdrh case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break; 107781e293b4Sdrh case SQLITE_DETACH : zCode="SQLITE_DETACH"; break; 10781c8c23ccSdanielk1977 case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; 10791d54df88Sdanielk1977 case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; 1080e6e04969Sdrh case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break; 1081f1a381e7Sdanielk1977 case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break; 1082f1a381e7Sdanielk1977 case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break; 10835169bbc6Sdrh case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break; 1084ab9b703fSdanielk1977 case SQLITE_SAVEPOINT : zCode="SQLITE_SAVEPOINT"; break; 108565a2aaa6Sdrh case SQLITE_RECURSIVE : zCode="SQLITE_RECURSIVE"; break; 1086e22a334bSdrh default : zCode="????"; break; 1087e22a334bSdrh } 1088e22a334bSdrh Tcl_DStringInit(&str); 1089e22a334bSdrh Tcl_DStringAppend(&str, pDb->zAuth, -1); 1090e22a334bSdrh Tcl_DStringAppendElement(&str, zCode); 1091e22a334bSdrh Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); 1092e22a334bSdrh Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); 1093e22a334bSdrh Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); 1094e22a334bSdrh Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); 109532c6a48bSdrh #ifdef SQLITE_USER_AUTHENTICATION 109632c6a48bSdrh Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : ""); 109732c6a48bSdrh #endif 1098e22a334bSdrh rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); 1099e22a334bSdrh Tcl_DStringFree(&str); 1100b07028f7Sdrh zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY"; 1101e22a334bSdrh if( strcmp(zReply,"SQLITE_OK")==0 ){ 1102e22a334bSdrh rc = SQLITE_OK; 1103e22a334bSdrh }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ 1104e22a334bSdrh rc = SQLITE_DENY; 1105e22a334bSdrh }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ 1106e22a334bSdrh rc = SQLITE_IGNORE; 1107e22a334bSdrh }else{ 1108e22a334bSdrh rc = 999; 1109e22a334bSdrh } 1110e22a334bSdrh return rc; 1111e22a334bSdrh } 1112e22a334bSdrh #endif /* SQLITE_OMIT_AUTHORIZATION */ 1113cabb0819Sdrh 1114cabb0819Sdrh /* 11151067fe11Stpoindex ** This routine reads a line of text from FILE in, stores 11161067fe11Stpoindex ** the text in memory obtained from malloc() and returns a pointer 11171067fe11Stpoindex ** to the text. NULL is returned at end of file, or if malloc() 11181067fe11Stpoindex ** fails. 11191067fe11Stpoindex ** 11201067fe11Stpoindex ** The interface is like "readline" but no command-line editing 11211067fe11Stpoindex ** is done. 11221067fe11Stpoindex ** 11231067fe11Stpoindex ** copied from shell.c from '.import' command 11241067fe11Stpoindex */ 11251067fe11Stpoindex static char *local_getline(char *zPrompt, FILE *in){ 11261067fe11Stpoindex char *zLine; 11271067fe11Stpoindex int nLine; 11281067fe11Stpoindex int n; 11291067fe11Stpoindex 11301067fe11Stpoindex nLine = 100; 11311067fe11Stpoindex zLine = malloc( nLine ); 11321067fe11Stpoindex if( zLine==0 ) return 0; 11331067fe11Stpoindex n = 0; 1134b07028f7Sdrh while( 1 ){ 11351067fe11Stpoindex if( n+100>nLine ){ 11361067fe11Stpoindex nLine = nLine*2 + 100; 11371067fe11Stpoindex zLine = realloc(zLine, nLine); 11381067fe11Stpoindex if( zLine==0 ) return 0; 11391067fe11Stpoindex } 11401067fe11Stpoindex if( fgets(&zLine[n], nLine - n, in)==0 ){ 11411067fe11Stpoindex if( n==0 ){ 11421067fe11Stpoindex free(zLine); 11431067fe11Stpoindex return 0; 11441067fe11Stpoindex } 11451067fe11Stpoindex zLine[n] = 0; 11461067fe11Stpoindex break; 11471067fe11Stpoindex } 11481067fe11Stpoindex while( zLine[n] ){ n++; } 11491067fe11Stpoindex if( n>0 && zLine[n-1]=='\n' ){ 11501067fe11Stpoindex n--; 11511067fe11Stpoindex zLine[n] = 0; 1152b07028f7Sdrh break; 11531067fe11Stpoindex } 11541067fe11Stpoindex } 11551067fe11Stpoindex zLine = realloc( zLine, n+1 ); 11561067fe11Stpoindex return zLine; 11571067fe11Stpoindex } 11581067fe11Stpoindex 11598e556520Sdanielk1977 11608e556520Sdanielk1977 /* 11614a4c11aaSdan ** This function is part of the implementation of the command: 11628e556520Sdanielk1977 ** 11634a4c11aaSdan ** $db transaction [-deferred|-immediate|-exclusive] SCRIPT 11648e556520Sdanielk1977 ** 11654a4c11aaSdan ** It is invoked after evaluating the script SCRIPT to commit or rollback 11664a4c11aaSdan ** the transaction or savepoint opened by the [transaction] command. 11674a4c11aaSdan */ 1168a121cc7cSmistachkin static int SQLITE_TCLAPI DbTransPostCmd( 11694a4c11aaSdan ClientData data[], /* data[0] is the Sqlite3Db* for $db */ 11704a4c11aaSdan Tcl_Interp *interp, /* Tcl interpreter */ 11714a4c11aaSdan int result /* Result of evaluating SCRIPT */ 11724a4c11aaSdan ){ 11736ef5e12eSmistachkin static const char *const azEnd[] = { 11744a4c11aaSdan "RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */ 11754a4c11aaSdan "COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */ 11764a4c11aaSdan "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction", 11774a4c11aaSdan "ROLLBACK" /* rc==TCL_ERROR, nTransaction==0 */ 11784a4c11aaSdan }; 11794a4c11aaSdan SqliteDb *pDb = (SqliteDb*)data[0]; 11804a4c11aaSdan int rc = result; 11814a4c11aaSdan const char *zEnd; 11824a4c11aaSdan 11834a4c11aaSdan pDb->nTransaction--; 11844a4c11aaSdan zEnd = azEnd[(rc==TCL_ERROR)*2 + (pDb->nTransaction==0)]; 11854a4c11aaSdan 11864a4c11aaSdan pDb->disableAuth++; 11874a4c11aaSdan if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){ 11884a4c11aaSdan /* This is a tricky scenario to handle. The most likely cause of an 11894a4c11aaSdan ** error is that the exec() above was an attempt to commit the 11904a4c11aaSdan ** top-level transaction that returned SQLITE_BUSY. Or, less likely, 119148864df9Smistachkin ** that an IO-error has occurred. In either case, throw a Tcl exception 11924a4c11aaSdan ** and try to rollback the transaction. 11934a4c11aaSdan ** 11944a4c11aaSdan ** But it could also be that the user executed one or more BEGIN, 11954a4c11aaSdan ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing 11964a4c11aaSdan ** this method's logic. Not clear how this would be best handled. 11974a4c11aaSdan */ 11984a4c11aaSdan if( rc!=TCL_ERROR ){ 1199a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 12004a4c11aaSdan rc = TCL_ERROR; 12014a4c11aaSdan } 12024a4c11aaSdan sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); 12034a4c11aaSdan } 12044a4c11aaSdan pDb->disableAuth--; 12054a4c11aaSdan 12064a4c11aaSdan return rc; 12074a4c11aaSdan } 12084a4c11aaSdan 12094a4c11aaSdan /* 1210c431fd55Sdan ** Unless SQLITE_TEST is defined, this function is a simple wrapper around 1211c431fd55Sdan ** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either 1212c431fd55Sdan ** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending 1213c431fd55Sdan ** on whether or not the [db_use_legacy_prepare] command has been used to 1214c431fd55Sdan ** configure the connection. 1215c431fd55Sdan */ 1216c431fd55Sdan static int dbPrepare( 1217c431fd55Sdan SqliteDb *pDb, /* Database object */ 1218c431fd55Sdan const char *zSql, /* SQL to compile */ 1219c431fd55Sdan sqlite3_stmt **ppStmt, /* OUT: Prepared statement */ 1220c431fd55Sdan const char **pzOut /* OUT: Pointer to next SQL statement */ 1221c431fd55Sdan ){ 12222c2f392dSdrh unsigned int prepFlags = 0; 1223c431fd55Sdan #ifdef SQLITE_TEST 1224c431fd55Sdan if( pDb->bLegacyPrepare ){ 1225c431fd55Sdan return sqlite3_prepare(pDb->db, zSql, -1, ppStmt, pzOut); 1226c431fd55Sdan } 1227c431fd55Sdan #endif 12282c2f392dSdrh /* If the statement cache is large, use the SQLITE_PREPARE_PERSISTENT 12292c2f392dSdrh ** flags, which uses less lookaside memory. But if the cache is small, 12302c2f392dSdrh ** omit that flag to make full use of lookaside */ 12312c2f392dSdrh if( pDb->maxStmt>5 ) prepFlags = SQLITE_PREPARE_PERSISTENT; 12322c2f392dSdrh 12332c2f392dSdrh return sqlite3_prepare_v3(pDb->db, zSql, -1, prepFlags, ppStmt, pzOut); 1234c431fd55Sdan } 1235c431fd55Sdan 1236c431fd55Sdan /* 12374a4c11aaSdan ** Search the cache for a prepared-statement object that implements the 12384a4c11aaSdan ** first SQL statement in the buffer pointed to by parameter zIn. If 12394a4c11aaSdan ** no such prepared-statement can be found, allocate and prepare a new 12404a4c11aaSdan ** one. In either case, bind the current values of the relevant Tcl 12414a4c11aaSdan ** variables to any $var, :var or @var variables in the statement. Before 12424a4c11aaSdan ** returning, set *ppPreStmt to point to the prepared-statement object. 12434a4c11aaSdan ** 12444a4c11aaSdan ** Output parameter *pzOut is set to point to the next SQL statement in 12454a4c11aaSdan ** buffer zIn, or to the '\0' byte at the end of zIn if there is no 12464a4c11aaSdan ** next statement. 12474a4c11aaSdan ** 12484a4c11aaSdan ** If successful, TCL_OK is returned. Otherwise, TCL_ERROR is returned 12494a4c11aaSdan ** and an error message loaded into interpreter pDb->interp. 12504a4c11aaSdan */ 12514a4c11aaSdan static int dbPrepareAndBind( 12524a4c11aaSdan SqliteDb *pDb, /* Database object */ 12534a4c11aaSdan char const *zIn, /* SQL to compile */ 12544a4c11aaSdan char const **pzOut, /* OUT: Pointer to next SQL statement */ 12554a4c11aaSdan SqlPreparedStmt **ppPreStmt /* OUT: Object used to cache statement */ 12564a4c11aaSdan ){ 12574a4c11aaSdan const char *zSql = zIn; /* Pointer to first SQL statement in zIn */ 12587bb22ac7Smistachkin sqlite3_stmt *pStmt = 0; /* Prepared statement object */ 12594a4c11aaSdan SqlPreparedStmt *pPreStmt; /* Pointer to cached statement */ 12604a4c11aaSdan int nSql; /* Length of zSql in bytes */ 12617bb22ac7Smistachkin int nVar = 0; /* Number of variables in statement */ 12624a4c11aaSdan int iParm = 0; /* Next free entry in apParm */ 12630425f189Sdrh char c; 12644a4c11aaSdan int i; 12654a4c11aaSdan Tcl_Interp *interp = pDb->interp; 12664a4c11aaSdan 12674a4c11aaSdan *ppPreStmt = 0; 12684a4c11aaSdan 12694a4c11aaSdan /* Trim spaces from the start of zSql and calculate the remaining length. */ 12700425f189Sdrh while( (c = zSql[0])==' ' || c=='\t' || c=='\r' || c=='\n' ){ zSql++; } 12714a4c11aaSdan nSql = strlen30(zSql); 12724a4c11aaSdan 12734a4c11aaSdan for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){ 12744a4c11aaSdan int n = pPreStmt->nSql; 12754a4c11aaSdan if( nSql>=n 12764a4c11aaSdan && memcmp(pPreStmt->zSql, zSql, n)==0 12774a4c11aaSdan && (zSql[n]==0 || zSql[n-1]==';') 12784a4c11aaSdan ){ 12794a4c11aaSdan pStmt = pPreStmt->pStmt; 12804a4c11aaSdan *pzOut = &zSql[pPreStmt->nSql]; 12814a4c11aaSdan 12824a4c11aaSdan /* When a prepared statement is found, unlink it from the 12834a4c11aaSdan ** cache list. It will later be added back to the beginning 12844a4c11aaSdan ** of the cache list in order to implement LRU replacement. 12854a4c11aaSdan */ 12864a4c11aaSdan if( pPreStmt->pPrev ){ 12874a4c11aaSdan pPreStmt->pPrev->pNext = pPreStmt->pNext; 12884a4c11aaSdan }else{ 12894a4c11aaSdan pDb->stmtList = pPreStmt->pNext; 12904a4c11aaSdan } 12914a4c11aaSdan if( pPreStmt->pNext ){ 12924a4c11aaSdan pPreStmt->pNext->pPrev = pPreStmt->pPrev; 12934a4c11aaSdan }else{ 12944a4c11aaSdan pDb->stmtLast = pPreStmt->pPrev; 12954a4c11aaSdan } 12964a4c11aaSdan pDb->nStmt--; 12974a4c11aaSdan nVar = sqlite3_bind_parameter_count(pStmt); 12984a4c11aaSdan break; 12994a4c11aaSdan } 13004a4c11aaSdan } 13014a4c11aaSdan 13024a4c11aaSdan /* If no prepared statement was found. Compile the SQL text. Also allocate 13034a4c11aaSdan ** a new SqlPreparedStmt structure. */ 13044a4c11aaSdan if( pPreStmt==0 ){ 13054a4c11aaSdan int nByte; 13064a4c11aaSdan 1307c431fd55Sdan if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){ 1308c45e6716Sdrh Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); 13094a4c11aaSdan return TCL_ERROR; 13104a4c11aaSdan } 13114a4c11aaSdan if( pStmt==0 ){ 13124a4c11aaSdan if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){ 13134a4c11aaSdan /* A compile-time error in the statement. */ 1314c45e6716Sdrh Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); 13154a4c11aaSdan return TCL_ERROR; 13164a4c11aaSdan }else{ 13174a4c11aaSdan /* The statement was a no-op. Continue to the next statement 13184a4c11aaSdan ** in the SQL string. 13194a4c11aaSdan */ 13204a4c11aaSdan return TCL_OK; 13214a4c11aaSdan } 13224a4c11aaSdan } 13234a4c11aaSdan 13244a4c11aaSdan assert( pPreStmt==0 ); 13254a4c11aaSdan nVar = sqlite3_bind_parameter_count(pStmt); 13264a4c11aaSdan nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj *); 13274a4c11aaSdan pPreStmt = (SqlPreparedStmt*)Tcl_Alloc(nByte); 13284a4c11aaSdan memset(pPreStmt, 0, nByte); 13294a4c11aaSdan 13304a4c11aaSdan pPreStmt->pStmt = pStmt; 13317ed243b7Sdrh pPreStmt->nSql = (int)(*pzOut - zSql); 13324a4c11aaSdan pPreStmt->zSql = sqlite3_sql(pStmt); 13334a4c11aaSdan pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1]; 1334c431fd55Sdan #ifdef SQLITE_TEST 1335c431fd55Sdan if( pPreStmt->zSql==0 ){ 1336c431fd55Sdan char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1); 1337c431fd55Sdan memcpy(zCopy, zSql, pPreStmt->nSql); 1338c431fd55Sdan zCopy[pPreStmt->nSql] = '\0'; 1339c431fd55Sdan pPreStmt->zSql = zCopy; 1340c431fd55Sdan } 1341c431fd55Sdan #endif 13424a4c11aaSdan } 13434a4c11aaSdan assert( pPreStmt ); 13444a4c11aaSdan assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql ); 13454a4c11aaSdan assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) ); 13464a4c11aaSdan 13474a4c11aaSdan /* Bind values to parameters that begin with $ or : */ 13484a4c11aaSdan for(i=1; i<=nVar; i++){ 13494a4c11aaSdan const char *zVar = sqlite3_bind_parameter_name(pStmt, i); 13504a4c11aaSdan if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){ 13514a4c11aaSdan Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); 13524a4c11aaSdan if( pVar ){ 13534a4c11aaSdan int n; 13544a4c11aaSdan u8 *data; 13554a4c11aaSdan const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); 13568e18922fSmistachkin c = zType[0]; 13574a4c11aaSdan if( zVar[0]=='@' || 13584a4c11aaSdan (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){ 13594a4c11aaSdan /* Load a BLOB type if the Tcl variable is a bytearray and 13604a4c11aaSdan ** it has no string representation or the host 13614a4c11aaSdan ** parameter name begins with "@". */ 13624a4c11aaSdan data = Tcl_GetByteArrayFromObj(pVar, &n); 13634a4c11aaSdan sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC); 13644a4c11aaSdan Tcl_IncrRefCount(pVar); 13654a4c11aaSdan pPreStmt->apParm[iParm++] = pVar; 13664a4c11aaSdan }else if( c=='b' && strcmp(zType,"boolean")==0 ){ 13674a4c11aaSdan Tcl_GetIntFromObj(interp, pVar, &n); 13684a4c11aaSdan sqlite3_bind_int(pStmt, i, n); 13694a4c11aaSdan }else if( c=='d' && strcmp(zType,"double")==0 ){ 13704a4c11aaSdan double r; 13714a4c11aaSdan Tcl_GetDoubleFromObj(interp, pVar, &r); 13724a4c11aaSdan sqlite3_bind_double(pStmt, i, r); 13734a4c11aaSdan }else if( (c=='w' && strcmp(zType,"wideInt")==0) || 13744a4c11aaSdan (c=='i' && strcmp(zType,"int")==0) ){ 13754a4c11aaSdan Tcl_WideInt v; 13764a4c11aaSdan Tcl_GetWideIntFromObj(interp, pVar, &v); 13774a4c11aaSdan sqlite3_bind_int64(pStmt, i, v); 13784a4c11aaSdan }else{ 13794a4c11aaSdan data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); 13804a4c11aaSdan sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC); 13814a4c11aaSdan Tcl_IncrRefCount(pVar); 13824a4c11aaSdan pPreStmt->apParm[iParm++] = pVar; 13834a4c11aaSdan } 13844a4c11aaSdan }else{ 13854a4c11aaSdan sqlite3_bind_null(pStmt, i); 13864a4c11aaSdan } 13874a4c11aaSdan } 13884a4c11aaSdan } 13894a4c11aaSdan pPreStmt->nParm = iParm; 13904a4c11aaSdan *ppPreStmt = pPreStmt; 1391937d0deaSdan 13924a4c11aaSdan return TCL_OK; 13934a4c11aaSdan } 13944a4c11aaSdan 13954a4c11aaSdan /* 13964a4c11aaSdan ** Release a statement reference obtained by calling dbPrepareAndBind(). 13974a4c11aaSdan ** There should be exactly one call to this function for each call to 13984a4c11aaSdan ** dbPrepareAndBind(). 13994a4c11aaSdan ** 14004a4c11aaSdan ** If the discard parameter is non-zero, then the statement is deleted 14014a4c11aaSdan ** immediately. Otherwise it is added to the LRU list and may be returned 14024a4c11aaSdan ** by a subsequent call to dbPrepareAndBind(). 14034a4c11aaSdan */ 14044a4c11aaSdan static void dbReleaseStmt( 14054a4c11aaSdan SqliteDb *pDb, /* Database handle */ 14064a4c11aaSdan SqlPreparedStmt *pPreStmt, /* Prepared statement handle to release */ 14074a4c11aaSdan int discard /* True to delete (not cache) the pPreStmt */ 14084a4c11aaSdan ){ 14094a4c11aaSdan int i; 14104a4c11aaSdan 14114a4c11aaSdan /* Free the bound string and blob parameters */ 14124a4c11aaSdan for(i=0; i<pPreStmt->nParm; i++){ 14134a4c11aaSdan Tcl_DecrRefCount(pPreStmt->apParm[i]); 14144a4c11aaSdan } 14154a4c11aaSdan pPreStmt->nParm = 0; 14164a4c11aaSdan 14174a4c11aaSdan if( pDb->maxStmt<=0 || discard ){ 14184a4c11aaSdan /* If the cache is turned off, deallocated the statement */ 1419c431fd55Sdan dbFreeStmt(pPreStmt); 14204a4c11aaSdan }else{ 14214a4c11aaSdan /* Add the prepared statement to the beginning of the cache list. */ 14224a4c11aaSdan pPreStmt->pNext = pDb->stmtList; 14234a4c11aaSdan pPreStmt->pPrev = 0; 14244a4c11aaSdan if( pDb->stmtList ){ 14254a4c11aaSdan pDb->stmtList->pPrev = pPreStmt; 14264a4c11aaSdan } 14274a4c11aaSdan pDb->stmtList = pPreStmt; 14284a4c11aaSdan if( pDb->stmtLast==0 ){ 14294a4c11aaSdan assert( pDb->nStmt==0 ); 14304a4c11aaSdan pDb->stmtLast = pPreStmt; 14314a4c11aaSdan }else{ 14324a4c11aaSdan assert( pDb->nStmt>0 ); 14334a4c11aaSdan } 14344a4c11aaSdan pDb->nStmt++; 14354a4c11aaSdan 14364a4c11aaSdan /* If we have too many statement in cache, remove the surplus from 14374a4c11aaSdan ** the end of the cache list. */ 14384a4c11aaSdan while( pDb->nStmt>pDb->maxStmt ){ 1439c431fd55Sdan SqlPreparedStmt *pLast = pDb->stmtLast; 1440c431fd55Sdan pDb->stmtLast = pLast->pPrev; 14414a4c11aaSdan pDb->stmtLast->pNext = 0; 14424a4c11aaSdan pDb->nStmt--; 1443c431fd55Sdan dbFreeStmt(pLast); 14444a4c11aaSdan } 14454a4c11aaSdan } 14464a4c11aaSdan } 14474a4c11aaSdan 14484a4c11aaSdan /* 14494a4c11aaSdan ** Structure used with dbEvalXXX() functions: 14504a4c11aaSdan ** 14514a4c11aaSdan ** dbEvalInit() 14524a4c11aaSdan ** dbEvalStep() 14534a4c11aaSdan ** dbEvalFinalize() 14544a4c11aaSdan ** dbEvalRowInfo() 14554a4c11aaSdan ** dbEvalColumnValue() 14564a4c11aaSdan */ 14574a4c11aaSdan typedef struct DbEvalContext DbEvalContext; 14584a4c11aaSdan struct DbEvalContext { 14594a4c11aaSdan SqliteDb *pDb; /* Database handle */ 14604a4c11aaSdan Tcl_Obj *pSql; /* Object holding string zSql */ 14614a4c11aaSdan const char *zSql; /* Remaining SQL to execute */ 14624a4c11aaSdan SqlPreparedStmt *pPreStmt; /* Current statement */ 14634a4c11aaSdan int nCol; /* Number of columns returned by pStmt */ 1464af38cdbcSdrh int evalFlags; /* Flags used */ 14654a4c11aaSdan Tcl_Obj *pArray; /* Name of array variable */ 14664a4c11aaSdan Tcl_Obj **apColName; /* Array of column names */ 14674a4c11aaSdan }; 14684a4c11aaSdan 1469af38cdbcSdrh #define SQLITE_EVAL_WITHOUTNULLS 0x00001 /* Unset array(*) for NULL */ 1470af38cdbcSdrh 14714a4c11aaSdan /* 14724a4c11aaSdan ** Release any cache of column names currently held as part of 14734a4c11aaSdan ** the DbEvalContext structure passed as the first argument. 14744a4c11aaSdan */ 14754a4c11aaSdan static void dbReleaseColumnNames(DbEvalContext *p){ 14764a4c11aaSdan if( p->apColName ){ 14774a4c11aaSdan int i; 14784a4c11aaSdan for(i=0; i<p->nCol; i++){ 14794a4c11aaSdan Tcl_DecrRefCount(p->apColName[i]); 14804a4c11aaSdan } 14814a4c11aaSdan Tcl_Free((char *)p->apColName); 14824a4c11aaSdan p->apColName = 0; 14834a4c11aaSdan } 14844a4c11aaSdan p->nCol = 0; 14854a4c11aaSdan } 14864a4c11aaSdan 14874a4c11aaSdan /* 14884a4c11aaSdan ** Initialize a DbEvalContext structure. 14898e556520Sdanielk1977 ** 14908e556520Sdanielk1977 ** If pArray is not NULL, then it contains the name of a Tcl array 14918e556520Sdanielk1977 ** variable. The "*" member of this array is set to a list containing 14924a4c11aaSdan ** the names of the columns returned by the statement as part of each 14934a4c11aaSdan ** call to dbEvalStep(), in order from left to right. e.g. if the names 14944a4c11aaSdan ** of the returned columns are a, b and c, it does the equivalent of the 14954a4c11aaSdan ** tcl command: 14968e556520Sdanielk1977 ** 14978e556520Sdanielk1977 ** set ${pArray}(*) {a b c} 14988e556520Sdanielk1977 */ 14994a4c11aaSdan static void dbEvalInit( 15004a4c11aaSdan DbEvalContext *p, /* Pointer to structure to initialize */ 15014a4c11aaSdan SqliteDb *pDb, /* Database handle */ 15024a4c11aaSdan Tcl_Obj *pSql, /* Object containing SQL script */ 1503af38cdbcSdrh Tcl_Obj *pArray, /* Name of Tcl array to set (*) element of */ 1504af38cdbcSdrh int evalFlags /* Flags controlling evaluation */ 15058e556520Sdanielk1977 ){ 15064a4c11aaSdan memset(p, 0, sizeof(DbEvalContext)); 15074a4c11aaSdan p->pDb = pDb; 15084a4c11aaSdan p->zSql = Tcl_GetString(pSql); 15094a4c11aaSdan p->pSql = pSql; 15104a4c11aaSdan Tcl_IncrRefCount(pSql); 15114a4c11aaSdan if( pArray ){ 15124a4c11aaSdan p->pArray = pArray; 15134a4c11aaSdan Tcl_IncrRefCount(pArray); 15144a4c11aaSdan } 1515af38cdbcSdrh p->evalFlags = evalFlags; 15164a4c11aaSdan } 15178e556520Sdanielk1977 15184a4c11aaSdan /* 15194a4c11aaSdan ** Obtain information about the row that the DbEvalContext passed as the 15204a4c11aaSdan ** first argument currently points to. 15214a4c11aaSdan */ 15224a4c11aaSdan static void dbEvalRowInfo( 15234a4c11aaSdan DbEvalContext *p, /* Evaluation context */ 15244a4c11aaSdan int *pnCol, /* OUT: Number of column names */ 15254a4c11aaSdan Tcl_Obj ***papColName /* OUT: Array of column names */ 15264a4c11aaSdan ){ 15278e556520Sdanielk1977 /* Compute column names */ 15284a4c11aaSdan if( 0==p->apColName ){ 15294a4c11aaSdan sqlite3_stmt *pStmt = p->pPreStmt->pStmt; 15304a4c11aaSdan int i; /* Iterator variable */ 15314a4c11aaSdan int nCol; /* Number of columns returned by pStmt */ 15324a4c11aaSdan Tcl_Obj **apColName = 0; /* Array of column names */ 15334a4c11aaSdan 15344a4c11aaSdan p->nCol = nCol = sqlite3_column_count(pStmt); 15354a4c11aaSdan if( nCol>0 && (papColName || p->pArray) ){ 15364a4c11aaSdan apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol ); 15378e556520Sdanielk1977 for(i=0; i<nCol; i++){ 1538c45e6716Sdrh apColName[i] = Tcl_NewStringObj(sqlite3_column_name(pStmt,i), -1); 15398e556520Sdanielk1977 Tcl_IncrRefCount(apColName[i]); 15408e556520Sdanielk1977 } 15414a4c11aaSdan p->apColName = apColName; 15424a4c11aaSdan } 15438e556520Sdanielk1977 15448e556520Sdanielk1977 /* If results are being stored in an array variable, then create 15458e556520Sdanielk1977 ** the array(*) entry for that array 15468e556520Sdanielk1977 */ 15474a4c11aaSdan if( p->pArray ){ 15484a4c11aaSdan Tcl_Interp *interp = p->pDb->interp; 15498e556520Sdanielk1977 Tcl_Obj *pColList = Tcl_NewObj(); 15508e556520Sdanielk1977 Tcl_Obj *pStar = Tcl_NewStringObj("*", -1); 15514a4c11aaSdan 15528e556520Sdanielk1977 for(i=0; i<nCol; i++){ 15538e556520Sdanielk1977 Tcl_ListObjAppendElement(interp, pColList, apColName[i]); 15548e556520Sdanielk1977 } 15558e556520Sdanielk1977 Tcl_IncrRefCount(pStar); 15564a4c11aaSdan Tcl_ObjSetVar2(interp, p->pArray, pStar, pColList, 0); 15578e556520Sdanielk1977 Tcl_DecrRefCount(pStar); 15588e556520Sdanielk1977 } 15598e556520Sdanielk1977 } 15608e556520Sdanielk1977 15614a4c11aaSdan if( papColName ){ 15624a4c11aaSdan *papColName = p->apColName; 15634a4c11aaSdan } 15644a4c11aaSdan if( pnCol ){ 15654a4c11aaSdan *pnCol = p->nCol; 15664a4c11aaSdan } 15674a4c11aaSdan } 15684a4c11aaSdan 15694a4c11aaSdan /* 15704a4c11aaSdan ** Return one of TCL_OK, TCL_BREAK or TCL_ERROR. If TCL_ERROR is 15714a4c11aaSdan ** returned, then an error message is stored in the interpreter before 15724a4c11aaSdan ** returning. 15734a4c11aaSdan ** 15744a4c11aaSdan ** A return value of TCL_OK means there is a row of data available. The 15754a4c11aaSdan ** data may be accessed using dbEvalRowInfo() and dbEvalColumnValue(). This 15764a4c11aaSdan ** is analogous to a return of SQLITE_ROW from sqlite3_step(). If TCL_BREAK 15774a4c11aaSdan ** is returned, then the SQL script has finished executing and there are 15784a4c11aaSdan ** no further rows available. This is similar to SQLITE_DONE. 15794a4c11aaSdan */ 15804a4c11aaSdan static int dbEvalStep(DbEvalContext *p){ 1581c431fd55Sdan const char *zPrevSql = 0; /* Previous value of p->zSql */ 1582c431fd55Sdan 15834a4c11aaSdan while( p->zSql[0] || p->pPreStmt ){ 15844a4c11aaSdan int rc; 15854a4c11aaSdan if( p->pPreStmt==0 ){ 1586c431fd55Sdan zPrevSql = (p->zSql==zPrevSql ? 0 : p->zSql); 15874a4c11aaSdan rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt); 15884a4c11aaSdan if( rc!=TCL_OK ) return rc; 15894a4c11aaSdan }else{ 15904a4c11aaSdan int rcs; 15914a4c11aaSdan SqliteDb *pDb = p->pDb; 15924a4c11aaSdan SqlPreparedStmt *pPreStmt = p->pPreStmt; 15934a4c11aaSdan sqlite3_stmt *pStmt = pPreStmt->pStmt; 15944a4c11aaSdan 15954a4c11aaSdan rcs = sqlite3_step(pStmt); 15964a4c11aaSdan if( rcs==SQLITE_ROW ){ 15974a4c11aaSdan return TCL_OK; 15984a4c11aaSdan } 15994a4c11aaSdan if( p->pArray ){ 16004a4c11aaSdan dbEvalRowInfo(p, 0, 0); 16014a4c11aaSdan } 16024a4c11aaSdan rcs = sqlite3_reset(pStmt); 16034a4c11aaSdan 16044a4c11aaSdan pDb->nStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_FULLSCAN_STEP,1); 16054a4c11aaSdan pDb->nSort = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_SORT,1); 16063c379b01Sdrh pDb->nIndex = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_AUTOINDEX,1); 1607c456a76fSdan pDb->nVMStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_VM_STEP,1); 16084a4c11aaSdan dbReleaseColumnNames(p); 16094a4c11aaSdan p->pPreStmt = 0; 16104a4c11aaSdan 16114a4c11aaSdan if( rcs!=SQLITE_OK ){ 16124a4c11aaSdan /* If a run-time error occurs, report the error and stop reading 16134a4c11aaSdan ** the SQL. */ 16144a4c11aaSdan dbReleaseStmt(pDb, pPreStmt, 1); 1615c431fd55Sdan #if SQLITE_TEST 1616c431fd55Sdan if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){ 1617c431fd55Sdan /* If the runtime error was an SQLITE_SCHEMA, and the database 1618c431fd55Sdan ** handle is configured to use the legacy sqlite3_prepare() 1619c431fd55Sdan ** interface, retry prepare()/step() on the same SQL statement. 1620c431fd55Sdan ** This only happens once. If there is a second SQLITE_SCHEMA 1621c431fd55Sdan ** error, the error will be returned to the caller. */ 1622c431fd55Sdan p->zSql = zPrevSql; 1623c431fd55Sdan continue; 1624c431fd55Sdan } 1625c431fd55Sdan #endif 1626c45e6716Sdrh Tcl_SetObjResult(pDb->interp, 1627c45e6716Sdrh Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); 16284a4c11aaSdan return TCL_ERROR; 16294a4c11aaSdan }else{ 16304a4c11aaSdan dbReleaseStmt(pDb, pPreStmt, 0); 16314a4c11aaSdan } 16324a4c11aaSdan } 16334a4c11aaSdan } 16344a4c11aaSdan 16354a4c11aaSdan /* Finished */ 16364a4c11aaSdan return TCL_BREAK; 16374a4c11aaSdan } 16384a4c11aaSdan 16394a4c11aaSdan /* 16404a4c11aaSdan ** Free all resources currently held by the DbEvalContext structure passed 16414a4c11aaSdan ** as the first argument. There should be exactly one call to this function 16424a4c11aaSdan ** for each call to dbEvalInit(). 16434a4c11aaSdan */ 16444a4c11aaSdan static void dbEvalFinalize(DbEvalContext *p){ 16454a4c11aaSdan if( p->pPreStmt ){ 16464a4c11aaSdan sqlite3_reset(p->pPreStmt->pStmt); 16474a4c11aaSdan dbReleaseStmt(p->pDb, p->pPreStmt, 0); 16484a4c11aaSdan p->pPreStmt = 0; 16494a4c11aaSdan } 16504a4c11aaSdan if( p->pArray ){ 16514a4c11aaSdan Tcl_DecrRefCount(p->pArray); 16524a4c11aaSdan p->pArray = 0; 16534a4c11aaSdan } 16544a4c11aaSdan Tcl_DecrRefCount(p->pSql); 16554a4c11aaSdan dbReleaseColumnNames(p); 16564a4c11aaSdan } 16574a4c11aaSdan 16584a4c11aaSdan /* 16594a4c11aaSdan ** Return a pointer to a Tcl_Obj structure with ref-count 0 that contains 16604a4c11aaSdan ** the value for the iCol'th column of the row currently pointed to by 16614a4c11aaSdan ** the DbEvalContext structure passed as the first argument. 16624a4c11aaSdan */ 16634a4c11aaSdan static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){ 16644a4c11aaSdan sqlite3_stmt *pStmt = p->pPreStmt->pStmt; 16654a4c11aaSdan switch( sqlite3_column_type(pStmt, iCol) ){ 16664a4c11aaSdan case SQLITE_BLOB: { 16674a4c11aaSdan int bytes = sqlite3_column_bytes(pStmt, iCol); 16684a4c11aaSdan const char *zBlob = sqlite3_column_blob(pStmt, iCol); 16694a4c11aaSdan if( !zBlob ) bytes = 0; 16704a4c11aaSdan return Tcl_NewByteArrayObj((u8*)zBlob, bytes); 16714a4c11aaSdan } 16724a4c11aaSdan case SQLITE_INTEGER: { 16734a4c11aaSdan sqlite_int64 v = sqlite3_column_int64(pStmt, iCol); 16744a4c11aaSdan if( v>=-2147483647 && v<=2147483647 ){ 16757fd33929Sdrh return Tcl_NewIntObj((int)v); 16764a4c11aaSdan }else{ 16774a4c11aaSdan return Tcl_NewWideIntObj(v); 16784a4c11aaSdan } 16794a4c11aaSdan } 16804a4c11aaSdan case SQLITE_FLOAT: { 16814a4c11aaSdan return Tcl_NewDoubleObj(sqlite3_column_double(pStmt, iCol)); 16824a4c11aaSdan } 16834a4c11aaSdan case SQLITE_NULL: { 1684c45e6716Sdrh return Tcl_NewStringObj(p->pDb->zNull, -1); 16854a4c11aaSdan } 16864a4c11aaSdan } 16874a4c11aaSdan 1688325eff58Sdrh return Tcl_NewStringObj((char*)sqlite3_column_text(pStmt, iCol), -1); 16894a4c11aaSdan } 16904a4c11aaSdan 16914a4c11aaSdan /* 16924a4c11aaSdan ** If using Tcl version 8.6 or greater, use the NR functions to avoid 16934a4c11aaSdan ** recursive evalution of scripts by the [db eval] and [db trans] 16944a4c11aaSdan ** commands. Even if the headers used while compiling the extension 16954a4c11aaSdan ** are 8.6 or newer, the code still tests the Tcl version at runtime. 16964a4c11aaSdan ** This allows stubs-enabled builds to be used with older Tcl libraries. 16974a4c11aaSdan */ 16984a4c11aaSdan #if TCL_MAJOR_VERSION>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6) 1699a2c8a95bSdrh # define SQLITE_TCL_NRE 1 17004a4c11aaSdan static int DbUseNre(void){ 17014a4c11aaSdan int major, minor; 17024a4c11aaSdan Tcl_GetVersion(&major, &minor, 0, 0); 17034a4c11aaSdan return( (major==8 && minor>=6) || major>8 ); 17044a4c11aaSdan } 17054a4c11aaSdan #else 17064a4c11aaSdan /* 17074a4c11aaSdan ** Compiling using headers earlier than 8.6. In this case NR cannot be 17084a4c11aaSdan ** used, so DbUseNre() to always return zero. Add #defines for the other 17094a4c11aaSdan ** Tcl_NRxxx() functions to prevent them from causing compilation errors, 17104a4c11aaSdan ** even though the only invocations of them are within conditional blocks 17114a4c11aaSdan ** of the form: 17124a4c11aaSdan ** 17134a4c11aaSdan ** if( DbUseNre() ) { ... } 17144a4c11aaSdan */ 1715a2c8a95bSdrh # define SQLITE_TCL_NRE 0 17164a4c11aaSdan # define DbUseNre() 0 1717a47941feSdrh # define Tcl_NRAddCallback(a,b,c,d,e,f) (void)0 17184a4c11aaSdan # define Tcl_NREvalObj(a,b,c) 0 1719a47941feSdrh # define Tcl_NRCreateCommand(a,b,c,d,e,f) (void)0 17204a4c11aaSdan #endif 17214a4c11aaSdan 17224a4c11aaSdan /* 17234a4c11aaSdan ** This function is part of the implementation of the command: 17244a4c11aaSdan ** 17254a4c11aaSdan ** $db eval SQL ?ARRAYNAME? SCRIPT 17264a4c11aaSdan */ 1727a121cc7cSmistachkin static int SQLITE_TCLAPI DbEvalNextCmd( 17284a4c11aaSdan ClientData data[], /* data[0] is the (DbEvalContext*) */ 17294a4c11aaSdan Tcl_Interp *interp, /* Tcl interpreter */ 17304a4c11aaSdan int result /* Result so far */ 17314a4c11aaSdan ){ 17324a4c11aaSdan int rc = result; /* Return code */ 17334a4c11aaSdan 17344a4c11aaSdan /* The first element of the data[] array is a pointer to a DbEvalContext 17354a4c11aaSdan ** structure allocated using Tcl_Alloc(). The second element of data[] 17364a4c11aaSdan ** is a pointer to a Tcl_Obj containing the script to run for each row 17374a4c11aaSdan ** returned by the queries encapsulated in data[0]. */ 17384a4c11aaSdan DbEvalContext *p = (DbEvalContext *)data[0]; 17394a4c11aaSdan Tcl_Obj *pScript = (Tcl_Obj *)data[1]; 17404a4c11aaSdan Tcl_Obj *pArray = p->pArray; 17414a4c11aaSdan 17424a4c11aaSdan while( (rc==TCL_OK || rc==TCL_CONTINUE) && TCL_OK==(rc = dbEvalStep(p)) ){ 17434a4c11aaSdan int i; 17444a4c11aaSdan int nCol; 17454a4c11aaSdan Tcl_Obj **apColName; 17464a4c11aaSdan dbEvalRowInfo(p, &nCol, &apColName); 17474a4c11aaSdan for(i=0; i<nCol; i++){ 17484a4c11aaSdan if( pArray==0 ){ 1749af38cdbcSdrh Tcl_ObjSetVar2(interp, apColName[i], 0, dbEvalColumnValue(p,i), 0); 1750af38cdbcSdrh }else if( (p->evalFlags & SQLITE_EVAL_WITHOUTNULLS)!=0 1751af38cdbcSdrh && sqlite3_column_type(p->pPreStmt->pStmt, i)==SQLITE_NULL 1752af38cdbcSdrh ){ 1753af38cdbcSdrh Tcl_UnsetVar2(interp, Tcl_GetString(pArray), 1754af38cdbcSdrh Tcl_GetString(apColName[i]), 0); 17554a4c11aaSdan }else{ 1756af38cdbcSdrh Tcl_ObjSetVar2(interp, pArray, apColName[i], dbEvalColumnValue(p,i), 0); 17574a4c11aaSdan } 17584a4c11aaSdan } 17594a4c11aaSdan 17604a4c11aaSdan /* The required interpreter variables are now populated with the data 17614a4c11aaSdan ** from the current row. If using NRE, schedule callbacks to evaluate 17624a4c11aaSdan ** script pScript, then to invoke this function again to fetch the next 17634a4c11aaSdan ** row (or clean up if there is no next row or the script throws an 17644a4c11aaSdan ** exception). After scheduling the callbacks, return control to the 17654a4c11aaSdan ** caller. 17664a4c11aaSdan ** 17674a4c11aaSdan ** If not using NRE, evaluate pScript directly and continue with the 17684a4c11aaSdan ** next iteration of this while(...) loop. */ 17694a4c11aaSdan if( DbUseNre() ){ 17704a4c11aaSdan Tcl_NRAddCallback(interp, DbEvalNextCmd, (void*)p, (void*)pScript, 0, 0); 17714a4c11aaSdan return Tcl_NREvalObj(interp, pScript, 0); 17724a4c11aaSdan }else{ 17734a4c11aaSdan rc = Tcl_EvalObjEx(interp, pScript, 0); 17744a4c11aaSdan } 17754a4c11aaSdan } 17764a4c11aaSdan 17774a4c11aaSdan Tcl_DecrRefCount(pScript); 17784a4c11aaSdan dbEvalFinalize(p); 17794a4c11aaSdan Tcl_Free((char *)p); 17804a4c11aaSdan 17814a4c11aaSdan if( rc==TCL_OK || rc==TCL_BREAK ){ 17824a4c11aaSdan Tcl_ResetResult(interp); 17834a4c11aaSdan rc = TCL_OK; 17844a4c11aaSdan } 17854a4c11aaSdan return rc; 17868e556520Sdanielk1977 } 17878e556520Sdanielk1977 17881067fe11Stpoindex /* 178946c47d46Sdan ** This function is used by the implementations of the following database 179046c47d46Sdan ** handle sub-commands: 179146c47d46Sdan ** 179246c47d46Sdan ** $db update_hook ?SCRIPT? 179346c47d46Sdan ** $db wal_hook ?SCRIPT? 179446c47d46Sdan ** $db commit_hook ?SCRIPT? 179546c47d46Sdan ** $db preupdate hook ?SCRIPT? 179646c47d46Sdan */ 179746c47d46Sdan static void DbHookCmd( 179846c47d46Sdan Tcl_Interp *interp, /* Tcl interpreter */ 179946c47d46Sdan SqliteDb *pDb, /* Database handle */ 180046c47d46Sdan Tcl_Obj *pArg, /* SCRIPT argument (or NULL) */ 180146c47d46Sdan Tcl_Obj **ppHook /* Pointer to member of SqliteDb */ 180246c47d46Sdan ){ 180346c47d46Sdan sqlite3 *db = pDb->db; 180446c47d46Sdan 180546c47d46Sdan if( *ppHook ){ 180646c47d46Sdan Tcl_SetObjResult(interp, *ppHook); 180746c47d46Sdan if( pArg ){ 180846c47d46Sdan Tcl_DecrRefCount(*ppHook); 180946c47d46Sdan *ppHook = 0; 181046c47d46Sdan } 181146c47d46Sdan } 181246c47d46Sdan if( pArg ){ 181346c47d46Sdan assert( !(*ppHook) ); 181446c47d46Sdan if( Tcl_GetCharLength(pArg)>0 ){ 181546c47d46Sdan *ppHook = pArg; 181646c47d46Sdan Tcl_IncrRefCount(*ppHook); 181746c47d46Sdan } 181846c47d46Sdan } 181946c47d46Sdan 18209b1c62d4Sdrh #ifdef SQLITE_ENABLE_PREUPDATE_HOOK 182146c47d46Sdan sqlite3_preupdate_hook(db, (pDb->pPreUpdateHook?DbPreUpdateHandler:0), pDb); 18229b1c62d4Sdrh #endif 182346c47d46Sdan sqlite3_update_hook(db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb); 182446c47d46Sdan sqlite3_rollback_hook(db, (pDb->pRollbackHook?DbRollbackHandler:0), pDb); 182546c47d46Sdan sqlite3_wal_hook(db, (pDb->pWalHook?DbWalHandler:0), pDb); 182646c47d46Sdan } 182746c47d46Sdan 182846c47d46Sdan /* 182975897234Sdrh ** The "sqlite" command below creates a new Tcl command for each 183075897234Sdrh ** connection it opens to an SQLite database. This routine is invoked 183175897234Sdrh ** whenever one of those connection-specific commands is executed 183275897234Sdrh ** in Tcl. For example, if you run Tcl code like this: 183375897234Sdrh ** 18349bb575fdSdrh ** sqlite3 db1 "my_database" 183575897234Sdrh ** db1 close 183675897234Sdrh ** 183775897234Sdrh ** The first command opens a connection to the "my_database" database 183875897234Sdrh ** and calls that connection "db1". The second command causes this 183975897234Sdrh ** subroutine to be invoked. 184075897234Sdrh */ 18417617e4a8Smistachkin static int SQLITE_TCLAPI DbObjCmd( 18427617e4a8Smistachkin void *cd, 18437617e4a8Smistachkin Tcl_Interp *interp, 18447617e4a8Smistachkin int objc, 18457617e4a8Smistachkin Tcl_Obj *const*objv 18467617e4a8Smistachkin ){ 1847bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 18486d31316cSdrh int choice; 184922fbcb8dSdrh int rc = TCL_OK; 18500de8c112Sdrh static const char *DB_strs[] = { 1851dc2c4915Sdrh "authorizer", "backup", "busy", 1852dc2c4915Sdrh "cache", "changes", "close", 1853dc2c4915Sdrh "collate", "collation_needed", "commit_hook", 1854cb7d541dSdrh "complete", "copy", "deserialize", 1855cb7d541dSdrh "enable_load_extension", "errorcode", "eval", 1856cb7d541dSdrh "exists", "function", "incrblob", 18573ec8665eSdrh "interrupt", "last_insert_rowid", "nullvalue", 18583ec8665eSdrh "onecolumn", "preupdate", "profile", 18593ec8665eSdrh "progress", "rekey", "restore", 18603ec8665eSdrh "rollback_hook", "serialize", "status", 18613ec8665eSdrh "timeout", "total_changes", "trace", 18623ec8665eSdrh "trace_v2", "transaction", "unlock_notify", 18633ec8665eSdrh "update_hook", "version", "wal_hook", 18643ec8665eSdrh 0 18656d31316cSdrh }; 1866411995dcSdrh enum DB_enum { 1867dc2c4915Sdrh DB_AUTHORIZER, DB_BACKUP, DB_BUSY, 1868dc2c4915Sdrh DB_CACHE, DB_CHANGES, DB_CLOSE, 1869dc2c4915Sdrh DB_COLLATE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK, 1870cb7d541dSdrh DB_COMPLETE, DB_COPY, DB_DESERIALIZE, 1871cb7d541dSdrh DB_ENABLE_LOAD_EXTENSION, DB_ERRORCODE, DB_EVAL, 1872cb7d541dSdrh DB_EXISTS, DB_FUNCTION, DB_INCRBLOB, 18733ec8665eSdrh DB_INTERRUPT, DB_LAST_INSERT_ROWID, DB_NULLVALUE, 18743ec8665eSdrh DB_ONECOLUMN, DB_PREUPDATE, DB_PROFILE, 18753ec8665eSdrh DB_PROGRESS, DB_REKEY, DB_RESTORE, 18763ec8665eSdrh DB_ROLLBACK_HOOK, DB_SERIALIZE, DB_STATUS, 18773ec8665eSdrh DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, 18783ec8665eSdrh DB_TRACE_V2, DB_TRANSACTION, DB_UNLOCK_NOTIFY, 18793ec8665eSdrh DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK 18806d31316cSdrh }; 18811067fe11Stpoindex /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ 18826d31316cSdrh 18836d31316cSdrh if( objc<2 ){ 18846d31316cSdrh Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); 188575897234Sdrh return TCL_ERROR; 188675897234Sdrh } 1887411995dcSdrh if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){ 18886d31316cSdrh return TCL_ERROR; 18896d31316cSdrh } 18906d31316cSdrh 1891411995dcSdrh switch( (enum DB_enum)choice ){ 189275897234Sdrh 1893e22a334bSdrh /* $db authorizer ?CALLBACK? 1894e22a334bSdrh ** 1895e22a334bSdrh ** Invoke the given callback to authorize each SQL operation as it is 1896e22a334bSdrh ** compiled. 5 arguments are appended to the callback before it is 1897e22a334bSdrh ** invoked: 1898e22a334bSdrh ** 1899e22a334bSdrh ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...) 1900e22a334bSdrh ** (2) First descriptive name (depends on authorization type) 1901e22a334bSdrh ** (3) Second descriptive name 1902e22a334bSdrh ** (4) Name of the database (ex: "main", "temp") 1903e22a334bSdrh ** (5) Name of trigger that is doing the access 1904e22a334bSdrh ** 1905e22a334bSdrh ** The callback should return on of the following strings: SQLITE_OK, 1906e22a334bSdrh ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error. 1907e22a334bSdrh ** 1908e22a334bSdrh ** If this method is invoked with no arguments, the current authorization 1909e22a334bSdrh ** callback string is returned. 1910e22a334bSdrh */ 1911e22a334bSdrh case DB_AUTHORIZER: { 19121211de37Sdrh #ifdef SQLITE_OMIT_AUTHORIZATION 1913a198f2b5Sdrh Tcl_AppendResult(interp, "authorization not available in this build", 1914a198f2b5Sdrh (char*)0); 19151211de37Sdrh return TCL_ERROR; 19161211de37Sdrh #else 1917e22a334bSdrh if( objc>3 ){ 1918e22a334bSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 19190f14e2ebSdrh return TCL_ERROR; 1920e22a334bSdrh }else if( objc==2 ){ 1921b5a20d3cSdrh if( pDb->zAuth ){ 1922a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zAuth, (char*)0); 1923e22a334bSdrh } 1924e22a334bSdrh }else{ 1925e22a334bSdrh char *zAuth; 1926e22a334bSdrh int len; 1927e22a334bSdrh if( pDb->zAuth ){ 1928e22a334bSdrh Tcl_Free(pDb->zAuth); 1929e22a334bSdrh } 1930e22a334bSdrh zAuth = Tcl_GetStringFromObj(objv[2], &len); 1931e22a334bSdrh if( zAuth && len>0 ){ 1932e22a334bSdrh pDb->zAuth = Tcl_Alloc( len + 1 ); 19335bb3eb9bSdrh memcpy(pDb->zAuth, zAuth, len+1); 1934e22a334bSdrh }else{ 1935e22a334bSdrh pDb->zAuth = 0; 1936e22a334bSdrh } 1937e22a334bSdrh if( pDb->zAuth ){ 193832c6a48bSdrh typedef int (*sqlite3_auth_cb)( 193932c6a48bSdrh void*,int,const char*,const char*, 194032c6a48bSdrh const char*,const char*); 1941e22a334bSdrh pDb->interp = interp; 194232c6a48bSdrh sqlite3_set_authorizer(pDb->db,(sqlite3_auth_cb)auth_callback,pDb); 1943e22a334bSdrh }else{ 19446f8a503dSdanielk1977 sqlite3_set_authorizer(pDb->db, 0, 0); 1945e22a334bSdrh } 1946e22a334bSdrh } 19471211de37Sdrh #endif 1948e22a334bSdrh break; 1949e22a334bSdrh } 1950e22a334bSdrh 1951dc2c4915Sdrh /* $db backup ?DATABASE? FILENAME 1952dc2c4915Sdrh ** 1953dc2c4915Sdrh ** Open or create a database file named FILENAME. Transfer the 1954dc2c4915Sdrh ** content of local database DATABASE (default: "main") into the 1955dc2c4915Sdrh ** FILENAME database. 1956dc2c4915Sdrh */ 1957dc2c4915Sdrh case DB_BACKUP: { 1958dc2c4915Sdrh const char *zDestFile; 1959dc2c4915Sdrh const char *zSrcDb; 1960dc2c4915Sdrh sqlite3 *pDest; 1961dc2c4915Sdrh sqlite3_backup *pBackup; 1962dc2c4915Sdrh 1963dc2c4915Sdrh if( objc==3 ){ 1964dc2c4915Sdrh zSrcDb = "main"; 1965dc2c4915Sdrh zDestFile = Tcl_GetString(objv[2]); 1966dc2c4915Sdrh }else if( objc==4 ){ 1967dc2c4915Sdrh zSrcDb = Tcl_GetString(objv[2]); 1968dc2c4915Sdrh zDestFile = Tcl_GetString(objv[3]); 1969dc2c4915Sdrh }else{ 1970dc2c4915Sdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME"); 1971dc2c4915Sdrh return TCL_ERROR; 1972dc2c4915Sdrh } 1973147ef394Sdrh rc = sqlite3_open_v2(zDestFile, &pDest, 1974147ef394Sdrh SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE| pDb->openFlags, 0); 1975dc2c4915Sdrh if( rc!=SQLITE_OK ){ 1976dc2c4915Sdrh Tcl_AppendResult(interp, "cannot open target database: ", 1977dc2c4915Sdrh sqlite3_errmsg(pDest), (char*)0); 1978dc2c4915Sdrh sqlite3_close(pDest); 1979dc2c4915Sdrh return TCL_ERROR; 1980dc2c4915Sdrh } 1981dc2c4915Sdrh pBackup = sqlite3_backup_init(pDest, "main", pDb->db, zSrcDb); 1982dc2c4915Sdrh if( pBackup==0 ){ 1983dc2c4915Sdrh Tcl_AppendResult(interp, "backup failed: ", 1984dc2c4915Sdrh sqlite3_errmsg(pDest), (char*)0); 1985dc2c4915Sdrh sqlite3_close(pDest); 1986dc2c4915Sdrh return TCL_ERROR; 1987dc2c4915Sdrh } 1988dc2c4915Sdrh while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} 1989dc2c4915Sdrh sqlite3_backup_finish(pBackup); 1990dc2c4915Sdrh if( rc==SQLITE_DONE ){ 1991dc2c4915Sdrh rc = TCL_OK; 1992dc2c4915Sdrh }else{ 1993dc2c4915Sdrh Tcl_AppendResult(interp, "backup failed: ", 1994dc2c4915Sdrh sqlite3_errmsg(pDest), (char*)0); 1995dc2c4915Sdrh rc = TCL_ERROR; 1996dc2c4915Sdrh } 1997dc2c4915Sdrh sqlite3_close(pDest); 1998dc2c4915Sdrh break; 1999dc2c4915Sdrh } 2000dc2c4915Sdrh 2001bec3f402Sdrh /* $db busy ?CALLBACK? 2002bec3f402Sdrh ** 2003bec3f402Sdrh ** Invoke the given callback if an SQL statement attempts to open 2004bec3f402Sdrh ** a locked database file. 2005bec3f402Sdrh */ 20066d31316cSdrh case DB_BUSY: { 20076d31316cSdrh if( objc>3 ){ 20086d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK"); 2009bec3f402Sdrh return TCL_ERROR; 20106d31316cSdrh }else if( objc==2 ){ 2011bec3f402Sdrh if( pDb->zBusy ){ 2012a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zBusy, (char*)0); 2013bec3f402Sdrh } 2014bec3f402Sdrh }else{ 20156d31316cSdrh char *zBusy; 20166d31316cSdrh int len; 2017bec3f402Sdrh if( pDb->zBusy ){ 2018bec3f402Sdrh Tcl_Free(pDb->zBusy); 20196d31316cSdrh } 20206d31316cSdrh zBusy = Tcl_GetStringFromObj(objv[2], &len); 20216d31316cSdrh if( zBusy && len>0 ){ 20226d31316cSdrh pDb->zBusy = Tcl_Alloc( len + 1 ); 20235bb3eb9bSdrh memcpy(pDb->zBusy, zBusy, len+1); 20246d31316cSdrh }else{ 2025bec3f402Sdrh pDb->zBusy = 0; 2026bec3f402Sdrh } 2027bec3f402Sdrh if( pDb->zBusy ){ 2028bec3f402Sdrh pDb->interp = interp; 20296f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb); 20306d31316cSdrh }else{ 20316f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, 0, 0); 2032bec3f402Sdrh } 2033bec3f402Sdrh } 20346d31316cSdrh break; 20356d31316cSdrh } 2036bec3f402Sdrh 2037fb7e7651Sdrh /* $db cache flush 2038fb7e7651Sdrh ** $db cache size n 2039fb7e7651Sdrh ** 2040fb7e7651Sdrh ** Flush the prepared statement cache, or set the maximum number of 2041fb7e7651Sdrh ** cached statements. 2042fb7e7651Sdrh */ 2043fb7e7651Sdrh case DB_CACHE: { 2044fb7e7651Sdrh char *subCmd; 2045fb7e7651Sdrh int n; 2046fb7e7651Sdrh 2047fb7e7651Sdrh if( objc<=2 ){ 2048fb7e7651Sdrh Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?"); 2049fb7e7651Sdrh return TCL_ERROR; 2050fb7e7651Sdrh } 2051fb7e7651Sdrh subCmd = Tcl_GetStringFromObj( objv[2], 0 ); 2052fb7e7651Sdrh if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){ 2053fb7e7651Sdrh if( objc!=3 ){ 2054fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "flush"); 2055fb7e7651Sdrh return TCL_ERROR; 2056fb7e7651Sdrh }else{ 2057fb7e7651Sdrh flushStmtCache( pDb ); 2058fb7e7651Sdrh } 2059fb7e7651Sdrh }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){ 2060fb7e7651Sdrh if( objc!=4 ){ 2061fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "size n"); 2062fb7e7651Sdrh return TCL_ERROR; 2063fb7e7651Sdrh }else{ 2064fb7e7651Sdrh if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ 2065fb7e7651Sdrh Tcl_AppendResult( interp, "cannot convert \"", 2066a198f2b5Sdrh Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0); 2067fb7e7651Sdrh return TCL_ERROR; 2068fb7e7651Sdrh }else{ 2069fb7e7651Sdrh if( n<0 ){ 2070fb7e7651Sdrh flushStmtCache( pDb ); 2071fb7e7651Sdrh n = 0; 2072fb7e7651Sdrh }else if( n>MAX_PREPARED_STMTS ){ 2073fb7e7651Sdrh n = MAX_PREPARED_STMTS; 2074fb7e7651Sdrh } 2075fb7e7651Sdrh pDb->maxStmt = n; 2076fb7e7651Sdrh } 2077fb7e7651Sdrh } 2078fb7e7651Sdrh }else{ 2079fb7e7651Sdrh Tcl_AppendResult( interp, "bad option \"", 2080a198f2b5Sdrh Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", 2081a198f2b5Sdrh (char*)0); 2082fb7e7651Sdrh return TCL_ERROR; 2083fb7e7651Sdrh } 2084fb7e7651Sdrh break; 2085fb7e7651Sdrh } 2086fb7e7651Sdrh 2087b28af71aSdanielk1977 /* $db changes 2088c8d30ac1Sdrh ** 2089c8d30ac1Sdrh ** Return the number of rows that were modified, inserted, or deleted by 2090b28af71aSdanielk1977 ** the most recent INSERT, UPDATE or DELETE statement, not including 2091b28af71aSdanielk1977 ** any changes made by trigger programs. 2092c8d30ac1Sdrh */ 2093c8d30ac1Sdrh case DB_CHANGES: { 2094c8d30ac1Sdrh Tcl_Obj *pResult; 2095c8d30ac1Sdrh if( objc!=2 ){ 2096c8d30ac1Sdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 2097c8d30ac1Sdrh return TCL_ERROR; 2098c8d30ac1Sdrh } 2099c8d30ac1Sdrh pResult = Tcl_GetObjResult(interp); 2100b28af71aSdanielk1977 Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db)); 2101f146a776Srdc break; 2102f146a776Srdc } 2103f146a776Srdc 210475897234Sdrh /* $db close 210575897234Sdrh ** 210675897234Sdrh ** Shutdown the database 210775897234Sdrh */ 21086d31316cSdrh case DB_CLOSE: { 21096d31316cSdrh Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0)); 21106d31316cSdrh break; 21116d31316cSdrh } 211275897234Sdrh 21130f14e2ebSdrh /* 21140f14e2ebSdrh ** $db collate NAME SCRIPT 21150f14e2ebSdrh ** 21160f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 21170f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 21180f14e2ebSdrh */ 21190f14e2ebSdrh case DB_COLLATE: { 21200f14e2ebSdrh SqlCollate *pCollate; 21210f14e2ebSdrh char *zName; 21220f14e2ebSdrh char *zScript; 21230f14e2ebSdrh int nScript; 21240f14e2ebSdrh if( objc!=4 ){ 21250f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 21260f14e2ebSdrh return TCL_ERROR; 21270f14e2ebSdrh } 21280f14e2ebSdrh zName = Tcl_GetStringFromObj(objv[2], 0); 21290f14e2ebSdrh zScript = Tcl_GetStringFromObj(objv[3], &nScript); 21300f14e2ebSdrh pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 ); 21310f14e2ebSdrh if( pCollate==0 ) return TCL_ERROR; 21320f14e2ebSdrh pCollate->interp = interp; 21330f14e2ebSdrh pCollate->pNext = pDb->pCollate; 21340f14e2ebSdrh pCollate->zScript = (char*)&pCollate[1]; 21350f14e2ebSdrh pDb->pCollate = pCollate; 21365bb3eb9bSdrh memcpy(pCollate->zScript, zScript, nScript+1); 21370f14e2ebSdrh if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8, 21380f14e2ebSdrh pCollate, tclSqlCollate) ){ 21399636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 21400f14e2ebSdrh return TCL_ERROR; 21410f14e2ebSdrh } 21420f14e2ebSdrh break; 21430f14e2ebSdrh } 21440f14e2ebSdrh 21450f14e2ebSdrh /* 21460f14e2ebSdrh ** $db collation_needed SCRIPT 21470f14e2ebSdrh ** 21480f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 21490f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 21500f14e2ebSdrh */ 21510f14e2ebSdrh case DB_COLLATION_NEEDED: { 21520f14e2ebSdrh if( objc!=3 ){ 21530f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT"); 21540f14e2ebSdrh return TCL_ERROR; 21550f14e2ebSdrh } 21560f14e2ebSdrh if( pDb->pCollateNeeded ){ 21570f14e2ebSdrh Tcl_DecrRefCount(pDb->pCollateNeeded); 21580f14e2ebSdrh } 21590f14e2ebSdrh pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]); 21600f14e2ebSdrh Tcl_IncrRefCount(pDb->pCollateNeeded); 21610f14e2ebSdrh sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded); 21620f14e2ebSdrh break; 21630f14e2ebSdrh } 21640f14e2ebSdrh 216519e2d37fSdrh /* $db commit_hook ?CALLBACK? 216619e2d37fSdrh ** 216719e2d37fSdrh ** Invoke the given callback just before committing every SQL transaction. 216819e2d37fSdrh ** If the callback throws an exception or returns non-zero, then the 216919e2d37fSdrh ** transaction is aborted. If CALLBACK is an empty string, the callback 217019e2d37fSdrh ** is disabled. 217119e2d37fSdrh */ 217219e2d37fSdrh case DB_COMMIT_HOOK: { 217319e2d37fSdrh if( objc>3 ){ 217419e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 217519e2d37fSdrh return TCL_ERROR; 217619e2d37fSdrh }else if( objc==2 ){ 217719e2d37fSdrh if( pDb->zCommit ){ 2178a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zCommit, (char*)0); 217919e2d37fSdrh } 218019e2d37fSdrh }else{ 21816ef5e12eSmistachkin const char *zCommit; 218219e2d37fSdrh int len; 218319e2d37fSdrh if( pDb->zCommit ){ 218419e2d37fSdrh Tcl_Free(pDb->zCommit); 218519e2d37fSdrh } 218619e2d37fSdrh zCommit = Tcl_GetStringFromObj(objv[2], &len); 218719e2d37fSdrh if( zCommit && len>0 ){ 218819e2d37fSdrh pDb->zCommit = Tcl_Alloc( len + 1 ); 21895bb3eb9bSdrh memcpy(pDb->zCommit, zCommit, len+1); 219019e2d37fSdrh }else{ 219119e2d37fSdrh pDb->zCommit = 0; 219219e2d37fSdrh } 219319e2d37fSdrh if( pDb->zCommit ){ 219419e2d37fSdrh pDb->interp = interp; 219519e2d37fSdrh sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb); 219619e2d37fSdrh }else{ 219719e2d37fSdrh sqlite3_commit_hook(pDb->db, 0, 0); 219819e2d37fSdrh } 219919e2d37fSdrh } 220019e2d37fSdrh break; 220119e2d37fSdrh } 220219e2d37fSdrh 220375897234Sdrh /* $db complete SQL 220475897234Sdrh ** 220575897234Sdrh ** Return TRUE if SQL is a complete SQL statement. Return FALSE if 220675897234Sdrh ** additional lines of input are needed. This is similar to the 220775897234Sdrh ** built-in "info complete" command of Tcl. 220875897234Sdrh */ 22096d31316cSdrh case DB_COMPLETE: { 2210ccae6026Sdrh #ifndef SQLITE_OMIT_COMPLETE 22116d31316cSdrh Tcl_Obj *pResult; 22126d31316cSdrh int isComplete; 22136d31316cSdrh if( objc!=3 ){ 22146d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 221575897234Sdrh return TCL_ERROR; 221675897234Sdrh } 22176f8a503dSdanielk1977 isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); 22186d31316cSdrh pResult = Tcl_GetObjResult(interp); 22196d31316cSdrh Tcl_SetBooleanObj(pResult, isComplete); 2220ccae6026Sdrh #endif 22216d31316cSdrh break; 22226d31316cSdrh } 222375897234Sdrh 222419e2d37fSdrh /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR? 222519e2d37fSdrh ** 222619e2d37fSdrh ** Copy data into table from filename, optionally using SEPARATOR 222719e2d37fSdrh ** as column separators. If a column contains a null string, or the 222819e2d37fSdrh ** value of NULLINDICATOR, a NULL is inserted for the column. 222919e2d37fSdrh ** conflict-algorithm is one of the sqlite conflict algorithms: 223019e2d37fSdrh ** rollback, abort, fail, ignore, replace 223119e2d37fSdrh ** On success, return the number of lines processed, not necessarily same 223219e2d37fSdrh ** as 'db changes' due to conflict-algorithm selected. 223319e2d37fSdrh ** 223419e2d37fSdrh ** This code is basically an implementation/enhancement of 223519e2d37fSdrh ** the sqlite3 shell.c ".import" command. 223619e2d37fSdrh ** 223719e2d37fSdrh ** This command usage is equivalent to the sqlite2.x COPY statement, 223819e2d37fSdrh ** which imports file data into a table using the PostgreSQL COPY file format: 223919e2d37fSdrh ** $db copy $conflit_algo $table_name $filename \t \\N 224019e2d37fSdrh */ 224119e2d37fSdrh case DB_COPY: { 224219e2d37fSdrh char *zTable; /* Insert data into this table */ 224319e2d37fSdrh char *zFile; /* The file from which to extract data */ 224419e2d37fSdrh char *zConflict; /* The conflict algorithm to use */ 224519e2d37fSdrh sqlite3_stmt *pStmt; /* A statement */ 224619e2d37fSdrh int nCol; /* Number of columns in the table */ 224719e2d37fSdrh int nByte; /* Number of bytes in an SQL string */ 224819e2d37fSdrh int i, j; /* Loop counters */ 224919e2d37fSdrh int nSep; /* Number of bytes in zSep[] */ 225019e2d37fSdrh int nNull; /* Number of bytes in zNull[] */ 225119e2d37fSdrh char *zSql; /* An SQL statement */ 225219e2d37fSdrh char *zLine; /* A single line of input from the file */ 225319e2d37fSdrh char **azCol; /* zLine[] broken up into columns */ 22546ef5e12eSmistachkin const char *zCommit; /* How to commit changes */ 225519e2d37fSdrh FILE *in; /* The input file */ 225619e2d37fSdrh int lineno = 0; /* Line number of input file */ 225719e2d37fSdrh char zLineNum[80]; /* Line number print buffer */ 225819e2d37fSdrh Tcl_Obj *pResult; /* interp result */ 225919e2d37fSdrh 22606ef5e12eSmistachkin const char *zSep; 22616ef5e12eSmistachkin const char *zNull; 226219e2d37fSdrh if( objc<5 || objc>7 ){ 226319e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, 226419e2d37fSdrh "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"); 226519e2d37fSdrh return TCL_ERROR; 226619e2d37fSdrh } 226719e2d37fSdrh if( objc>=6 ){ 226819e2d37fSdrh zSep = Tcl_GetStringFromObj(objv[5], 0); 226919e2d37fSdrh }else{ 227019e2d37fSdrh zSep = "\t"; 227119e2d37fSdrh } 227219e2d37fSdrh if( objc>=7 ){ 227319e2d37fSdrh zNull = Tcl_GetStringFromObj(objv[6], 0); 227419e2d37fSdrh }else{ 227519e2d37fSdrh zNull = ""; 227619e2d37fSdrh } 227719e2d37fSdrh zConflict = Tcl_GetStringFromObj(objv[2], 0); 227819e2d37fSdrh zTable = Tcl_GetStringFromObj(objv[3], 0); 227919e2d37fSdrh zFile = Tcl_GetStringFromObj(objv[4], 0); 22804f21c4afSdrh nSep = strlen30(zSep); 22814f21c4afSdrh nNull = strlen30(zNull); 228219e2d37fSdrh if( nSep==0 ){ 2283a198f2b5Sdrh Tcl_AppendResult(interp,"Error: non-null separator required for copy", 2284a198f2b5Sdrh (char*)0); 228519e2d37fSdrh return TCL_ERROR; 228619e2d37fSdrh } 22873e59c012Sdrh if(strcmp(zConflict, "rollback") != 0 && 22883e59c012Sdrh strcmp(zConflict, "abort" ) != 0 && 22893e59c012Sdrh strcmp(zConflict, "fail" ) != 0 && 22903e59c012Sdrh strcmp(zConflict, "ignore" ) != 0 && 22913e59c012Sdrh strcmp(zConflict, "replace" ) != 0 ) { 229219e2d37fSdrh Tcl_AppendResult(interp, "Error: \"", zConflict, 229319e2d37fSdrh "\", conflict-algorithm must be one of: rollback, " 2294a198f2b5Sdrh "abort, fail, ignore, or replace", (char*)0); 229519e2d37fSdrh return TCL_ERROR; 229619e2d37fSdrh } 229719e2d37fSdrh zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); 229819e2d37fSdrh if( zSql==0 ){ 2299a198f2b5Sdrh Tcl_AppendResult(interp, "Error: no such table: ", zTable, (char*)0); 230019e2d37fSdrh return TCL_ERROR; 230119e2d37fSdrh } 23024f21c4afSdrh nByte = strlen30(zSql); 23033e701a18Sdrh rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); 230419e2d37fSdrh sqlite3_free(zSql); 230519e2d37fSdrh if( rc ){ 2306a198f2b5Sdrh Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0); 230719e2d37fSdrh nCol = 0; 230819e2d37fSdrh }else{ 230919e2d37fSdrh nCol = sqlite3_column_count(pStmt); 231019e2d37fSdrh } 231119e2d37fSdrh sqlite3_finalize(pStmt); 231219e2d37fSdrh if( nCol==0 ) { 231319e2d37fSdrh return TCL_ERROR; 231419e2d37fSdrh } 231519e2d37fSdrh zSql = malloc( nByte + 50 + nCol*2 ); 231619e2d37fSdrh if( zSql==0 ) { 2317a198f2b5Sdrh Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0); 231819e2d37fSdrh return TCL_ERROR; 231919e2d37fSdrh } 232019e2d37fSdrh sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?", 232119e2d37fSdrh zConflict, zTable); 23224f21c4afSdrh j = strlen30(zSql); 232319e2d37fSdrh for(i=1; i<nCol; i++){ 232419e2d37fSdrh zSql[j++] = ','; 232519e2d37fSdrh zSql[j++] = '?'; 232619e2d37fSdrh } 232719e2d37fSdrh zSql[j++] = ')'; 232819e2d37fSdrh zSql[j] = 0; 23293e701a18Sdrh rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); 233019e2d37fSdrh free(zSql); 233119e2d37fSdrh if( rc ){ 2332a198f2b5Sdrh Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0); 233319e2d37fSdrh sqlite3_finalize(pStmt); 233419e2d37fSdrh return TCL_ERROR; 233519e2d37fSdrh } 233619e2d37fSdrh in = fopen(zFile, "rb"); 233719e2d37fSdrh if( in==0 ){ 2338ea8f0a15Sdrh Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, (char*)0); 233919e2d37fSdrh sqlite3_finalize(pStmt); 234019e2d37fSdrh return TCL_ERROR; 234119e2d37fSdrh } 234219e2d37fSdrh azCol = malloc( sizeof(azCol[0])*(nCol+1) ); 234319e2d37fSdrh if( azCol==0 ) { 2344a198f2b5Sdrh Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0); 234543617e9aSdrh fclose(in); 234619e2d37fSdrh return TCL_ERROR; 234719e2d37fSdrh } 23483752785fSdrh (void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0); 234919e2d37fSdrh zCommit = "COMMIT"; 235019e2d37fSdrh while( (zLine = local_getline(0, in))!=0 ){ 235119e2d37fSdrh char *z; 235219e2d37fSdrh lineno++; 235319e2d37fSdrh azCol[0] = zLine; 235419e2d37fSdrh for(i=0, z=zLine; *z; z++){ 235519e2d37fSdrh if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){ 235619e2d37fSdrh *z = 0; 235719e2d37fSdrh i++; 235819e2d37fSdrh if( i<nCol ){ 235919e2d37fSdrh azCol[i] = &z[nSep]; 236019e2d37fSdrh z += nSep-1; 236119e2d37fSdrh } 236219e2d37fSdrh } 236319e2d37fSdrh } 236419e2d37fSdrh if( i+1!=nCol ){ 236519e2d37fSdrh char *zErr; 23664f21c4afSdrh int nErr = strlen30(zFile) + 200; 23675bb3eb9bSdrh zErr = malloc(nErr); 2368c1f4494eSdrh if( zErr ){ 23695bb3eb9bSdrh sqlite3_snprintf(nErr, zErr, 2370955de52cSdanielk1977 "Error: %s line %d: expected %d columns of data but found %d", 237119e2d37fSdrh zFile, lineno, nCol, i+1); 2372a198f2b5Sdrh Tcl_AppendResult(interp, zErr, (char*)0); 237319e2d37fSdrh free(zErr); 2374c1f4494eSdrh } 237519e2d37fSdrh zCommit = "ROLLBACK"; 237619e2d37fSdrh break; 237719e2d37fSdrh } 237819e2d37fSdrh for(i=0; i<nCol; i++){ 237919e2d37fSdrh /* check for null data, if so, bind as null */ 2380ea678832Sdrh if( (nNull>0 && strcmp(azCol[i], zNull)==0) 23814f21c4afSdrh || strlen30(azCol[i])==0 2382ea678832Sdrh ){ 238319e2d37fSdrh sqlite3_bind_null(pStmt, i+1); 238419e2d37fSdrh }else{ 238519e2d37fSdrh sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); 238619e2d37fSdrh } 238719e2d37fSdrh } 238819e2d37fSdrh sqlite3_step(pStmt); 238919e2d37fSdrh rc = sqlite3_reset(pStmt); 239019e2d37fSdrh free(zLine); 239119e2d37fSdrh if( rc!=SQLITE_OK ){ 2392a198f2b5Sdrh Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), (char*)0); 239319e2d37fSdrh zCommit = "ROLLBACK"; 239419e2d37fSdrh break; 239519e2d37fSdrh } 239619e2d37fSdrh } 239719e2d37fSdrh free(azCol); 239819e2d37fSdrh fclose(in); 239919e2d37fSdrh sqlite3_finalize(pStmt); 24003752785fSdrh (void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0); 240119e2d37fSdrh 240219e2d37fSdrh if( zCommit[0] == 'C' ){ 240319e2d37fSdrh /* success, set result as number of lines processed */ 240419e2d37fSdrh pResult = Tcl_GetObjResult(interp); 240519e2d37fSdrh Tcl_SetIntObj(pResult, lineno); 240619e2d37fSdrh rc = TCL_OK; 240719e2d37fSdrh }else{ 240819e2d37fSdrh /* failure, append lineno where failed */ 24095bb3eb9bSdrh sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno); 2410a198f2b5Sdrh Tcl_AppendResult(interp,", failed while processing line: ",zLineNum, 2411a198f2b5Sdrh (char*)0); 241219e2d37fSdrh rc = TCL_ERROR; 241319e2d37fSdrh } 241419e2d37fSdrh break; 241519e2d37fSdrh } 241619e2d37fSdrh 241775897234Sdrh /* 2418cb7d541dSdrh ** $db deserialize ?DATABASE? VALUE 2419cb7d541dSdrh ** 2420cb7d541dSdrh ** Reopen DATABASE (default "main") using the content in $VALUE 2421cb7d541dSdrh */ 2422cb7d541dSdrh case DB_DESERIALIZE: { 2423*9c6396ecSdrh #ifndef SQLITE_ENABLE_DESERIALIZE 24243ec8665eSdrh Tcl_AppendResult(interp, "MEMDB not available in this build", 24253ec8665eSdrh (char*)0); 24263ec8665eSdrh rc = TCL_ERROR; 24273ec8665eSdrh #else 24283ec8665eSdrh const char *zSchema; 24293ec8665eSdrh Tcl_Obj *pValue; 24303ec8665eSdrh unsigned char *pBA; 24313ec8665eSdrh unsigned char *pData; 24323ec8665eSdrh int len, xrc; 24333ec8665eSdrh 24343ec8665eSdrh if( objc==3 ){ 24353ec8665eSdrh zSchema = 0; 24363ec8665eSdrh pValue = objv[2]; 24373ec8665eSdrh }else if( objc==4 ){ 24383ec8665eSdrh zSchema = Tcl_GetString(objv[2]); 24393ec8665eSdrh pValue = objv[3]; 24403ec8665eSdrh }else{ 24413ec8665eSdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? VALUE"); 24423ec8665eSdrh rc = TCL_ERROR; 24433ec8665eSdrh break; 24443ec8665eSdrh } 24453ec8665eSdrh pBA = Tcl_GetByteArrayFromObj(pValue, &len); 24463ec8665eSdrh pData = sqlite3_malloc64( len ); 2447a5bb4351Sdrh if( pData==0 && len>0 ){ 24483ec8665eSdrh Tcl_AppendResult(interp, "out of memory", (char*)0); 24493ec8665eSdrh rc = TCL_ERROR; 24503ec8665eSdrh }else{ 2451a5bb4351Sdrh if( len>0 ) memcpy(pData, pBA, len); 24523ec8665eSdrh xrc = sqlite3_deserialize(pDb->db, zSchema, pData, len, len, 24533ec8665eSdrh SQLITE_DESERIALIZE_FREEONCLOSE | 24543ec8665eSdrh SQLITE_DESERIALIZE_RESIZEABLE); 24553ec8665eSdrh if( xrc ){ 24563ec8665eSdrh Tcl_AppendResult(interp, "unable to set MEMDB content", (char*)0); 24573ec8665eSdrh rc = TCL_ERROR; 24583ec8665eSdrh } 24593ec8665eSdrh } 24603ec8665eSdrh #endif 2461cb7d541dSdrh break; 2462cb7d541dSdrh } 2463cb7d541dSdrh 2464cb7d541dSdrh /* 24654144905bSdrh ** $db enable_load_extension BOOLEAN 24664144905bSdrh ** 24674144905bSdrh ** Turn the extension loading feature on or off. It if off by 24684144905bSdrh ** default. 24694144905bSdrh */ 24704144905bSdrh case DB_ENABLE_LOAD_EXTENSION: { 2471f533acc0Sdrh #ifndef SQLITE_OMIT_LOAD_EXTENSION 24724144905bSdrh int onoff; 24734144905bSdrh if( objc!=3 ){ 24744144905bSdrh Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN"); 24754144905bSdrh return TCL_ERROR; 24764144905bSdrh } 24774144905bSdrh if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){ 24784144905bSdrh return TCL_ERROR; 24794144905bSdrh } 24804144905bSdrh sqlite3_enable_load_extension(pDb->db, onoff); 24814144905bSdrh break; 2482f533acc0Sdrh #else 2483f533acc0Sdrh Tcl_AppendResult(interp, "extension loading is turned off at compile-time", 2484a198f2b5Sdrh (char*)0); 2485f533acc0Sdrh return TCL_ERROR; 2486f533acc0Sdrh #endif 24874144905bSdrh } 24884144905bSdrh 24894144905bSdrh /* 2490dcd997eaSdrh ** $db errorcode 2491dcd997eaSdrh ** 2492dcd997eaSdrh ** Return the numeric error code that was returned by the most recent 24936f8a503dSdanielk1977 ** call to sqlite3_exec(). 2494dcd997eaSdrh */ 2495dcd997eaSdrh case DB_ERRORCODE: { 2496f3ce83f5Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); 2497dcd997eaSdrh break; 2498dcd997eaSdrh } 2499dcd997eaSdrh 2500dcd997eaSdrh /* 25014a4c11aaSdan ** $db exists $sql 25021807ce37Sdrh ** $db onecolumn $sql 250375897234Sdrh ** 25044a4c11aaSdan ** The onecolumn method is the equivalent of: 25054a4c11aaSdan ** lindex [$db eval $sql] 0 25064a4c11aaSdan */ 25074a4c11aaSdan case DB_EXISTS: 25084a4c11aaSdan case DB_ONECOLUMN: { 2509edc4024bSdrh Tcl_Obj *pResult = 0; 25104a4c11aaSdan DbEvalContext sEval; 25114a4c11aaSdan if( objc!=3 ){ 25124a4c11aaSdan Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 25134a4c11aaSdan return TCL_ERROR; 25144a4c11aaSdan } 25154a4c11aaSdan 2516af38cdbcSdrh dbEvalInit(&sEval, pDb, objv[2], 0, 0); 25174a4c11aaSdan rc = dbEvalStep(&sEval); 25184a4c11aaSdan if( choice==DB_ONECOLUMN ){ 25194a4c11aaSdan if( rc==TCL_OK ){ 2520edc4024bSdrh pResult = dbEvalColumnValue(&sEval, 0); 2521d5f12cd5Sdan }else if( rc==TCL_BREAK ){ 2522d5f12cd5Sdan Tcl_ResetResult(interp); 25234a4c11aaSdan } 25244a4c11aaSdan }else if( rc==TCL_BREAK || rc==TCL_OK ){ 2525edc4024bSdrh pResult = Tcl_NewBooleanObj(rc==TCL_OK); 25264a4c11aaSdan } 25274a4c11aaSdan dbEvalFinalize(&sEval); 2528edc4024bSdrh if( pResult ) Tcl_SetObjResult(interp, pResult); 25294a4c11aaSdan 25304a4c11aaSdan if( rc==TCL_BREAK ){ 25314a4c11aaSdan rc = TCL_OK; 25324a4c11aaSdan } 25334a4c11aaSdan break; 25344a4c11aaSdan } 25354a4c11aaSdan 25364a4c11aaSdan /* 2537af38cdbcSdrh ** $db eval ?options? $sql ?array? ?{ ...code... }? 25384a4c11aaSdan ** 253975897234Sdrh ** The SQL statement in $sql is evaluated. For each row, the values are 2540bec3f402Sdrh ** placed in elements of the array named "array" and ...code... is executed. 254175897234Sdrh ** If "array" and "code" are omitted, then no callback is every invoked. 254275897234Sdrh ** If "array" is an empty string, then the values are placed in variables 254375897234Sdrh ** that have the same name as the fields extracted by the query. 254475897234Sdrh */ 25454a4c11aaSdan case DB_EVAL: { 2546af38cdbcSdrh int evalFlags = 0; 2547af38cdbcSdrh const char *zOpt; 2548af38cdbcSdrh while( objc>3 && (zOpt = Tcl_GetString(objv[2]))!=0 && zOpt[0]=='-' ){ 2549af38cdbcSdrh if( strcmp(zOpt, "-withoutnulls")==0 ){ 2550af38cdbcSdrh evalFlags |= SQLITE_EVAL_WITHOUTNULLS; 2551af38cdbcSdrh } 2552af38cdbcSdrh else{ 2553af38cdbcSdrh Tcl_AppendResult(interp, "unknown option: \"", zOpt, "\"", (void*)0); 2554af38cdbcSdrh return TCL_ERROR; 2555af38cdbcSdrh } 2556af38cdbcSdrh objc--; 2557af38cdbcSdrh objv++; 2558af38cdbcSdrh } 255992febd92Sdrh if( objc<3 || objc>5 ){ 2560af38cdbcSdrh Tcl_WrongNumArgs(interp, 2, objv, 2561af38cdbcSdrh "?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?"); 256230ccda10Sdanielk1977 return TCL_ERROR; 256330ccda10Sdanielk1977 } 25644a4c11aaSdan 256592febd92Sdrh if( objc==3 ){ 25664a4c11aaSdan DbEvalContext sEval; 25674a4c11aaSdan Tcl_Obj *pRet = Tcl_NewObj(); 25684a4c11aaSdan Tcl_IncrRefCount(pRet); 2569af38cdbcSdrh dbEvalInit(&sEval, pDb, objv[2], 0, 0); 25704a4c11aaSdan while( TCL_OK==(rc = dbEvalStep(&sEval)) ){ 25714a4c11aaSdan int i; 25724a4c11aaSdan int nCol; 25734a4c11aaSdan dbEvalRowInfo(&sEval, &nCol, 0); 257492febd92Sdrh for(i=0; i<nCol; i++){ 25754a4c11aaSdan Tcl_ListObjAppendElement(interp, pRet, dbEvalColumnValue(&sEval, i)); 257692febd92Sdrh } 257730ccda10Sdanielk1977 } 25784a4c11aaSdan dbEvalFinalize(&sEval); 257990b6bb19Sdrh if( rc==TCL_BREAK ){ 25804a4c11aaSdan Tcl_SetObjResult(interp, pRet); 258190b6bb19Sdrh rc = TCL_OK; 258290b6bb19Sdrh } 2583ef2cb63eSdanielk1977 Tcl_DecrRefCount(pRet); 25844a4c11aaSdan }else{ 25858e18922fSmistachkin ClientData cd2[2]; 25864a4c11aaSdan DbEvalContext *p; 25874a4c11aaSdan Tcl_Obj *pArray = 0; 25884a4c11aaSdan Tcl_Obj *pScript; 25894a4c11aaSdan 2590af38cdbcSdrh if( objc>=5 && *(char *)Tcl_GetString(objv[3]) ){ 25914a4c11aaSdan pArray = objv[3]; 25924a4c11aaSdan } 25934a4c11aaSdan pScript = objv[objc-1]; 25944a4c11aaSdan Tcl_IncrRefCount(pScript); 25954a4c11aaSdan 25964a4c11aaSdan p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext)); 2597af38cdbcSdrh dbEvalInit(p, pDb, objv[2], pArray, evalFlags); 25984a4c11aaSdan 25998e18922fSmistachkin cd2[0] = (void *)p; 26008e18922fSmistachkin cd2[1] = (void *)pScript; 26018e18922fSmistachkin rc = DbEvalNextCmd(cd2, interp, TCL_OK); 26021807ce37Sdrh } 260330ccda10Sdanielk1977 break; 260430ccda10Sdanielk1977 } 2605bec3f402Sdrh 2606bec3f402Sdrh /* 26073df30592Sdan ** $db function NAME [-argcount N] [-deterministic] SCRIPT 2608cabb0819Sdrh ** 2609cabb0819Sdrh ** Create a new SQL function called NAME. Whenever that function is 2610cabb0819Sdrh ** called, invoke SCRIPT to evaluate the function. 2611cabb0819Sdrh */ 2612cabb0819Sdrh case DB_FUNCTION: { 26133df30592Sdan int flags = SQLITE_UTF8; 2614cabb0819Sdrh SqlFunc *pFunc; 2615d1e4733dSdrh Tcl_Obj *pScript; 2616cabb0819Sdrh char *zName; 2617e3602be8Sdrh int nArg = -1; 26183df30592Sdan int i; 26193df30592Sdan if( objc<4 ){ 26203df30592Sdan Tcl_WrongNumArgs(interp, 2, objv, "NAME ?SWITCHES? SCRIPT"); 26213df30592Sdan return TCL_ERROR; 26223df30592Sdan } 26233df30592Sdan for(i=3; i<(objc-1); i++){ 26243df30592Sdan const char *z = Tcl_GetString(objv[i]); 26254f21c4afSdrh int n = strlen30(z); 2626e3602be8Sdrh if( n>2 && strncmp(z, "-argcount",n)==0 ){ 26273df30592Sdan if( i==(objc-2) ){ 2628ea8f0a15Sdrh Tcl_AppendResult(interp, "option requires an argument: ", z,(char*)0); 26293df30592Sdan return TCL_ERROR; 26303df30592Sdan } 26313df30592Sdan if( Tcl_GetIntFromObj(interp, objv[i+1], &nArg) ) return TCL_ERROR; 2632e3602be8Sdrh if( nArg<0 ){ 2633e3602be8Sdrh Tcl_AppendResult(interp, "number of arguments must be non-negative", 2634e3602be8Sdrh (char*)0); 2635cabb0819Sdrh return TCL_ERROR; 2636cabb0819Sdrh } 26373df30592Sdan i++; 26383df30592Sdan }else 26393df30592Sdan if( n>2 && strncmp(z, "-deterministic",n)==0 ){ 26403df30592Sdan flags |= SQLITE_DETERMINISTIC; 2641e3602be8Sdrh }else{ 26423df30592Sdan Tcl_AppendResult(interp, "bad option \"", z, 2643ea8f0a15Sdrh "\": must be -argcount or -deterministic", (char*)0 26443df30592Sdan ); 26453df30592Sdan return TCL_ERROR; 2646e3602be8Sdrh } 26473df30592Sdan } 26483df30592Sdan 26493df30592Sdan pScript = objv[objc-1]; 2650e3602be8Sdrh zName = Tcl_GetStringFromObj(objv[2], 0); 2651d1e4733dSdrh pFunc = findSqlFunc(pDb, zName); 2652cabb0819Sdrh if( pFunc==0 ) return TCL_ERROR; 2653d1e4733dSdrh if( pFunc->pScript ){ 2654d1e4733dSdrh Tcl_DecrRefCount(pFunc->pScript); 2655d1e4733dSdrh } 2656d1e4733dSdrh pFunc->pScript = pScript; 2657d1e4733dSdrh Tcl_IncrRefCount(pScript); 2658d1e4733dSdrh pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript); 26593df30592Sdan rc = sqlite3_create_function(pDb->db, zName, nArg, flags, 2660d8123366Sdanielk1977 pFunc, tclSqlFunc, 0, 0); 2661fb7e7651Sdrh if( rc!=SQLITE_OK ){ 2662fb7e7651Sdrh rc = TCL_ERROR; 26639636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 2664fb7e7651Sdrh } 2665cabb0819Sdrh break; 2666cabb0819Sdrh } 2667cabb0819Sdrh 2668cabb0819Sdrh /* 26698cbadb02Sdanielk1977 ** $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID 2670b4e9af9fSdanielk1977 */ 2671b4e9af9fSdanielk1977 case DB_INCRBLOB: { 267232a0d8bbSdanielk1977 #ifdef SQLITE_OMIT_INCRBLOB 2673a198f2b5Sdrh Tcl_AppendResult(interp, "incrblob not available in this build", (char*)0); 267432a0d8bbSdanielk1977 return TCL_ERROR; 267532a0d8bbSdanielk1977 #else 26768cbadb02Sdanielk1977 int isReadonly = 0; 2677b4e9af9fSdanielk1977 const char *zDb = "main"; 2678b4e9af9fSdanielk1977 const char *zTable; 2679b4e9af9fSdanielk1977 const char *zColumn; 2680b3f787f4Sdrh Tcl_WideInt iRow; 2681b4e9af9fSdanielk1977 26828cbadb02Sdanielk1977 /* Check for the -readonly option */ 26838cbadb02Sdanielk1977 if( objc>3 && strcmp(Tcl_GetString(objv[2]), "-readonly")==0 ){ 26848cbadb02Sdanielk1977 isReadonly = 1; 26858cbadb02Sdanielk1977 } 26868cbadb02Sdanielk1977 26878cbadb02Sdanielk1977 if( objc!=(5+isReadonly) && objc!=(6+isReadonly) ){ 26888cbadb02Sdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID"); 2689b4e9af9fSdanielk1977 return TCL_ERROR; 2690b4e9af9fSdanielk1977 } 2691b4e9af9fSdanielk1977 26928cbadb02Sdanielk1977 if( objc==(6+isReadonly) ){ 2693b4e9af9fSdanielk1977 zDb = Tcl_GetString(objv[2]); 2694b4e9af9fSdanielk1977 } 2695b4e9af9fSdanielk1977 zTable = Tcl_GetString(objv[objc-3]); 2696b4e9af9fSdanielk1977 zColumn = Tcl_GetString(objv[objc-2]); 2697b4e9af9fSdanielk1977 rc = Tcl_GetWideIntFromObj(interp, objv[objc-1], &iRow); 2698b4e9af9fSdanielk1977 2699b4e9af9fSdanielk1977 if( rc==TCL_OK ){ 27008cbadb02Sdanielk1977 rc = createIncrblobChannel( 2701edf5b165Sdan interp, pDb, zDb, zTable, zColumn, (sqlite3_int64)iRow, isReadonly 27028cbadb02Sdanielk1977 ); 2703b4e9af9fSdanielk1977 } 270432a0d8bbSdanielk1977 #endif 2705b4e9af9fSdanielk1977 break; 2706b4e9af9fSdanielk1977 } 2707b4e9af9fSdanielk1977 2708b4e9af9fSdanielk1977 /* 2709f11bded5Sdrh ** $db interrupt 2710f11bded5Sdrh ** 2711f11bded5Sdrh ** Interrupt the execution of the inner-most SQL interpreter. This 2712f11bded5Sdrh ** causes the SQL statement to return an error of SQLITE_INTERRUPT. 2713f11bded5Sdrh */ 2714f11bded5Sdrh case DB_INTERRUPT: { 2715f11bded5Sdrh sqlite3_interrupt(pDb->db); 2716f11bded5Sdrh break; 2717f11bded5Sdrh } 2718f11bded5Sdrh 2719f11bded5Sdrh /* 272019e2d37fSdrh ** $db nullvalue ?STRING? 272119e2d37fSdrh ** 272219e2d37fSdrh ** Change text used when a NULL comes back from the database. If ?STRING? 272319e2d37fSdrh ** is not present, then the current string used for NULL is returned. 272419e2d37fSdrh ** If STRING is present, then STRING is returned. 272519e2d37fSdrh ** 272619e2d37fSdrh */ 272719e2d37fSdrh case DB_NULLVALUE: { 272819e2d37fSdrh if( objc!=2 && objc!=3 ){ 272919e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE"); 273019e2d37fSdrh return TCL_ERROR; 273119e2d37fSdrh } 273219e2d37fSdrh if( objc==3 ){ 273319e2d37fSdrh int len; 273419e2d37fSdrh char *zNull = Tcl_GetStringFromObj(objv[2], &len); 273519e2d37fSdrh if( pDb->zNull ){ 273619e2d37fSdrh Tcl_Free(pDb->zNull); 273719e2d37fSdrh } 273819e2d37fSdrh if( zNull && len>0 ){ 273919e2d37fSdrh pDb->zNull = Tcl_Alloc( len + 1 ); 27407fd33929Sdrh memcpy(pDb->zNull, zNull, len); 274119e2d37fSdrh pDb->zNull[len] = '\0'; 274219e2d37fSdrh }else{ 274319e2d37fSdrh pDb->zNull = 0; 274419e2d37fSdrh } 274519e2d37fSdrh } 2746c45e6716Sdrh Tcl_SetObjResult(interp, Tcl_NewStringObj(pDb->zNull, -1)); 274719e2d37fSdrh break; 274819e2d37fSdrh } 274919e2d37fSdrh 275019e2d37fSdrh /* 2751af9ff33aSdrh ** $db last_insert_rowid 2752af9ff33aSdrh ** 2753af9ff33aSdrh ** Return an integer which is the ROWID for the most recent insert. 2754af9ff33aSdrh */ 2755af9ff33aSdrh case DB_LAST_INSERT_ROWID: { 2756af9ff33aSdrh Tcl_Obj *pResult; 2757f7e678d6Sdrh Tcl_WideInt rowid; 2758af9ff33aSdrh if( objc!=2 ){ 2759af9ff33aSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 2760af9ff33aSdrh return TCL_ERROR; 2761af9ff33aSdrh } 27626f8a503dSdanielk1977 rowid = sqlite3_last_insert_rowid(pDb->db); 2763af9ff33aSdrh pResult = Tcl_GetObjResult(interp); 2764f7e678d6Sdrh Tcl_SetWideIntObj(pResult, rowid); 2765af9ff33aSdrh break; 2766af9ff33aSdrh } 2767af9ff33aSdrh 2768af9ff33aSdrh /* 27694a4c11aaSdan ** The DB_ONECOLUMN method is implemented together with DB_EXISTS. 27705d9d7576Sdrh */ 27711807ce37Sdrh 27721807ce37Sdrh /* $db progress ?N CALLBACK? 27731807ce37Sdrh ** 27741807ce37Sdrh ** Invoke the given callback every N virtual machine opcodes while executing 27751807ce37Sdrh ** queries. 27761807ce37Sdrh */ 27771807ce37Sdrh case DB_PROGRESS: { 27781807ce37Sdrh if( objc==2 ){ 27791807ce37Sdrh if( pDb->zProgress ){ 2780a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zProgress, (char*)0); 27815d9d7576Sdrh } 27821807ce37Sdrh }else if( objc==4 ){ 27831807ce37Sdrh char *zProgress; 27841807ce37Sdrh int len; 27851807ce37Sdrh int N; 27861807ce37Sdrh if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ 27871807ce37Sdrh return TCL_ERROR; 27881807ce37Sdrh }; 27891807ce37Sdrh if( pDb->zProgress ){ 27901807ce37Sdrh Tcl_Free(pDb->zProgress); 27911807ce37Sdrh } 27921807ce37Sdrh zProgress = Tcl_GetStringFromObj(objv[3], &len); 27931807ce37Sdrh if( zProgress && len>0 ){ 27941807ce37Sdrh pDb->zProgress = Tcl_Alloc( len + 1 ); 27955bb3eb9bSdrh memcpy(pDb->zProgress, zProgress, len+1); 27961807ce37Sdrh }else{ 27971807ce37Sdrh pDb->zProgress = 0; 27981807ce37Sdrh } 27991807ce37Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK 28001807ce37Sdrh if( pDb->zProgress ){ 28011807ce37Sdrh pDb->interp = interp; 28021807ce37Sdrh sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb); 28031807ce37Sdrh }else{ 28041807ce37Sdrh sqlite3_progress_handler(pDb->db, 0, 0, 0); 28051807ce37Sdrh } 28061807ce37Sdrh #endif 28071807ce37Sdrh }else{ 28081807ce37Sdrh Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK"); 28091807ce37Sdrh return TCL_ERROR; 28105d9d7576Sdrh } 28115d9d7576Sdrh break; 28125d9d7576Sdrh } 28135d9d7576Sdrh 281419e2d37fSdrh /* $db profile ?CALLBACK? 281519e2d37fSdrh ** 281619e2d37fSdrh ** Make arrangements to invoke the CALLBACK routine after each SQL statement 281719e2d37fSdrh ** that has run. The text of the SQL and the amount of elapse time are 281819e2d37fSdrh ** appended to CALLBACK before the script is run. 281919e2d37fSdrh */ 282019e2d37fSdrh case DB_PROFILE: { 282119e2d37fSdrh if( objc>3 ){ 282219e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 282319e2d37fSdrh return TCL_ERROR; 282419e2d37fSdrh }else if( objc==2 ){ 282519e2d37fSdrh if( pDb->zProfile ){ 2826a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zProfile, (char*)0); 282719e2d37fSdrh } 282819e2d37fSdrh }else{ 282919e2d37fSdrh char *zProfile; 283019e2d37fSdrh int len; 283119e2d37fSdrh if( pDb->zProfile ){ 283219e2d37fSdrh Tcl_Free(pDb->zProfile); 283319e2d37fSdrh } 283419e2d37fSdrh zProfile = Tcl_GetStringFromObj(objv[2], &len); 283519e2d37fSdrh if( zProfile && len>0 ){ 283619e2d37fSdrh pDb->zProfile = Tcl_Alloc( len + 1 ); 28375bb3eb9bSdrh memcpy(pDb->zProfile, zProfile, len+1); 283819e2d37fSdrh }else{ 283919e2d37fSdrh pDb->zProfile = 0; 284019e2d37fSdrh } 28412eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 28422eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 284319e2d37fSdrh if( pDb->zProfile ){ 284419e2d37fSdrh pDb->interp = interp; 284519e2d37fSdrh sqlite3_profile(pDb->db, DbProfileHandler, pDb); 284619e2d37fSdrh }else{ 284719e2d37fSdrh sqlite3_profile(pDb->db, 0, 0); 284819e2d37fSdrh } 284919e2d37fSdrh #endif 285019e2d37fSdrh } 285119e2d37fSdrh break; 285219e2d37fSdrh } 285319e2d37fSdrh 28545d9d7576Sdrh /* 285522fbcb8dSdrh ** $db rekey KEY 285622fbcb8dSdrh ** 285722fbcb8dSdrh ** Change the encryption key on the currently open database. 285822fbcb8dSdrh */ 285922fbcb8dSdrh case DB_REKEY: { 286032f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 286122fbcb8dSdrh int nKey; 286222fbcb8dSdrh void *pKey; 2863b07028f7Sdrh #endif 286422fbcb8dSdrh if( objc!=3 ){ 286522fbcb8dSdrh Tcl_WrongNumArgs(interp, 2, objv, "KEY"); 286622fbcb8dSdrh return TCL_ERROR; 286722fbcb8dSdrh } 286832f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 2869b07028f7Sdrh pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); 28702011d5f5Sdrh rc = sqlite3_rekey(pDb->db, pKey, nKey); 287122fbcb8dSdrh if( rc ){ 2872a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0); 287322fbcb8dSdrh rc = TCL_ERROR; 287422fbcb8dSdrh } 287522fbcb8dSdrh #endif 287622fbcb8dSdrh break; 287722fbcb8dSdrh } 287822fbcb8dSdrh 2879dc2c4915Sdrh /* $db restore ?DATABASE? FILENAME 2880dc2c4915Sdrh ** 2881dc2c4915Sdrh ** Open a database file named FILENAME. Transfer the content 2882dc2c4915Sdrh ** of FILENAME into the local database DATABASE (default: "main"). 2883dc2c4915Sdrh */ 2884dc2c4915Sdrh case DB_RESTORE: { 2885dc2c4915Sdrh const char *zSrcFile; 2886dc2c4915Sdrh const char *zDestDb; 2887dc2c4915Sdrh sqlite3 *pSrc; 2888dc2c4915Sdrh sqlite3_backup *pBackup; 2889dc2c4915Sdrh int nTimeout = 0; 2890dc2c4915Sdrh 2891dc2c4915Sdrh if( objc==3 ){ 2892dc2c4915Sdrh zDestDb = "main"; 2893dc2c4915Sdrh zSrcFile = Tcl_GetString(objv[2]); 2894dc2c4915Sdrh }else if( objc==4 ){ 2895dc2c4915Sdrh zDestDb = Tcl_GetString(objv[2]); 2896dc2c4915Sdrh zSrcFile = Tcl_GetString(objv[3]); 2897dc2c4915Sdrh }else{ 2898dc2c4915Sdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME"); 2899dc2c4915Sdrh return TCL_ERROR; 2900dc2c4915Sdrh } 2901147ef394Sdrh rc = sqlite3_open_v2(zSrcFile, &pSrc, 2902147ef394Sdrh SQLITE_OPEN_READONLY | pDb->openFlags, 0); 2903dc2c4915Sdrh if( rc!=SQLITE_OK ){ 2904dc2c4915Sdrh Tcl_AppendResult(interp, "cannot open source database: ", 2905dc2c4915Sdrh sqlite3_errmsg(pSrc), (char*)0); 2906dc2c4915Sdrh sqlite3_close(pSrc); 2907dc2c4915Sdrh return TCL_ERROR; 2908dc2c4915Sdrh } 2909dc2c4915Sdrh pBackup = sqlite3_backup_init(pDb->db, zDestDb, pSrc, "main"); 2910dc2c4915Sdrh if( pBackup==0 ){ 2911dc2c4915Sdrh Tcl_AppendResult(interp, "restore failed: ", 2912dc2c4915Sdrh sqlite3_errmsg(pDb->db), (char*)0); 2913dc2c4915Sdrh sqlite3_close(pSrc); 2914dc2c4915Sdrh return TCL_ERROR; 2915dc2c4915Sdrh } 2916dc2c4915Sdrh while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK 2917dc2c4915Sdrh || rc==SQLITE_BUSY ){ 2918dc2c4915Sdrh if( rc==SQLITE_BUSY ){ 2919dc2c4915Sdrh if( nTimeout++ >= 3 ) break; 2920dc2c4915Sdrh sqlite3_sleep(100); 2921dc2c4915Sdrh } 2922dc2c4915Sdrh } 2923dc2c4915Sdrh sqlite3_backup_finish(pBackup); 2924dc2c4915Sdrh if( rc==SQLITE_DONE ){ 2925dc2c4915Sdrh rc = TCL_OK; 2926dc2c4915Sdrh }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ 2927dc2c4915Sdrh Tcl_AppendResult(interp, "restore failed: source database busy", 2928dc2c4915Sdrh (char*)0); 2929dc2c4915Sdrh rc = TCL_ERROR; 2930dc2c4915Sdrh }else{ 2931dc2c4915Sdrh Tcl_AppendResult(interp, "restore failed: ", 2932dc2c4915Sdrh sqlite3_errmsg(pDb->db), (char*)0); 2933dc2c4915Sdrh rc = TCL_ERROR; 2934dc2c4915Sdrh } 2935dc2c4915Sdrh sqlite3_close(pSrc); 2936dc2c4915Sdrh break; 2937dc2c4915Sdrh } 2938dc2c4915Sdrh 293922fbcb8dSdrh /* 2940cb7d541dSdrh ** $db serialize ?DATABASE? 2941cb7d541dSdrh ** 2942cb7d541dSdrh ** Return a serialization of a database. 2943cb7d541dSdrh */ 2944cb7d541dSdrh case DB_SERIALIZE: { 2945*9c6396ecSdrh #ifndef SQLITE_ENABLE_DESERIALIZE 2946cb7d541dSdrh Tcl_AppendResult(interp, "MEMDB not available in this build", 2947cb7d541dSdrh (char*)0); 2948cb7d541dSdrh rc = TCL_ERROR; 2949cb7d541dSdrh #else 2950cb7d541dSdrh const char *zSchema = objc>=3 ? Tcl_GetString(objv[2]) : "main"; 2951cb7d541dSdrh sqlite3_int64 sz = 0; 2952cb7d541dSdrh unsigned char *pData; 2953cb7d541dSdrh if( objc!=2 && objc!=3 ){ 2954cb7d541dSdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE?"); 2955cb7d541dSdrh rc = TCL_ERROR; 2956cb7d541dSdrh }else{ 2957cb7d541dSdrh int needFree; 2958cb7d541dSdrh pData = sqlite3_serialize(pDb->db, zSchema, &sz, SQLITE_SERIALIZE_NOCOPY); 2959cb7d541dSdrh if( pData ){ 2960cb7d541dSdrh needFree = 0; 2961cb7d541dSdrh }else{ 2962cb7d541dSdrh pData = sqlite3_serialize(pDb->db, zSchema, &sz, 0); 2963cb7d541dSdrh needFree = 1; 2964cb7d541dSdrh } 2965cb7d541dSdrh Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pData,sz)); 2966cb7d541dSdrh if( needFree ) sqlite3_free(pData); 2967cb7d541dSdrh } 2968cb7d541dSdrh #endif 2969cb7d541dSdrh break; 2970cb7d541dSdrh } 2971cb7d541dSdrh 2972cb7d541dSdrh /* 2973c456a76fSdan ** $db status (step|sort|autoindex|vmstep) 2974d1d38488Sdrh ** 2975d1d38488Sdrh ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or 2976d1d38488Sdrh ** SQLITE_STMTSTATUS_SORT for the most recent eval. 2977d1d38488Sdrh */ 2978d1d38488Sdrh case DB_STATUS: { 2979d1d38488Sdrh int v; 2980d1d38488Sdrh const char *zOp; 2981d1d38488Sdrh if( objc!=3 ){ 29821c320a43Sdrh Tcl_WrongNumArgs(interp, 2, objv, "(step|sort|autoindex)"); 2983d1d38488Sdrh return TCL_ERROR; 2984d1d38488Sdrh } 2985d1d38488Sdrh zOp = Tcl_GetString(objv[2]); 2986d1d38488Sdrh if( strcmp(zOp, "step")==0 ){ 2987d1d38488Sdrh v = pDb->nStep; 2988d1d38488Sdrh }else if( strcmp(zOp, "sort")==0 ){ 2989d1d38488Sdrh v = pDb->nSort; 29903c379b01Sdrh }else if( strcmp(zOp, "autoindex")==0 ){ 29913c379b01Sdrh v = pDb->nIndex; 2992c456a76fSdan }else if( strcmp(zOp, "vmstep")==0 ){ 2993c456a76fSdan v = pDb->nVMStep; 2994d1d38488Sdrh }else{ 29953c379b01Sdrh Tcl_AppendResult(interp, 2996c456a76fSdan "bad argument: should be autoindex, step, sort or vmstep", 2997d1d38488Sdrh (char*)0); 2998d1d38488Sdrh return TCL_ERROR; 2999d1d38488Sdrh } 3000d1d38488Sdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(v)); 3001d1d38488Sdrh break; 3002d1d38488Sdrh } 3003d1d38488Sdrh 3004d1d38488Sdrh /* 3005bec3f402Sdrh ** $db timeout MILLESECONDS 3006bec3f402Sdrh ** 3007bec3f402Sdrh ** Delay for the number of milliseconds specified when a file is locked. 3008bec3f402Sdrh */ 30096d31316cSdrh case DB_TIMEOUT: { 3010bec3f402Sdrh int ms; 30116d31316cSdrh if( objc!=3 ){ 30126d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS"); 3013bec3f402Sdrh return TCL_ERROR; 301475897234Sdrh } 30156d31316cSdrh if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR; 30166f8a503dSdanielk1977 sqlite3_busy_timeout(pDb->db, ms); 30176d31316cSdrh break; 301875897234Sdrh } 3019b5a20d3cSdrh 30200f14e2ebSdrh /* 30210f14e2ebSdrh ** $db total_changes 30220f14e2ebSdrh ** 30230f14e2ebSdrh ** Return the number of rows that were modified, inserted, or deleted 30240f14e2ebSdrh ** since the database handle was created. 30250f14e2ebSdrh */ 30260f14e2ebSdrh case DB_TOTAL_CHANGES: { 30270f14e2ebSdrh Tcl_Obj *pResult; 30280f14e2ebSdrh if( objc!=2 ){ 30290f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 30300f14e2ebSdrh return TCL_ERROR; 30310f14e2ebSdrh } 30320f14e2ebSdrh pResult = Tcl_GetObjResult(interp); 30330f14e2ebSdrh Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db)); 30340f14e2ebSdrh break; 30350f14e2ebSdrh } 30360f14e2ebSdrh 3037b5a20d3cSdrh /* $db trace ?CALLBACK? 3038b5a20d3cSdrh ** 3039b5a20d3cSdrh ** Make arrangements to invoke the CALLBACK routine for each SQL statement 3040b5a20d3cSdrh ** that is executed. The text of the SQL is appended to CALLBACK before 3041b5a20d3cSdrh ** it is executed. 3042b5a20d3cSdrh */ 3043b5a20d3cSdrh case DB_TRACE: { 3044b5a20d3cSdrh if( objc>3 ){ 3045b5a20d3cSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 3046b97759edSdrh return TCL_ERROR; 3047b5a20d3cSdrh }else if( objc==2 ){ 3048b5a20d3cSdrh if( pDb->zTrace ){ 3049a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zTrace, (char*)0); 3050b5a20d3cSdrh } 3051b5a20d3cSdrh }else{ 3052b5a20d3cSdrh char *zTrace; 3053b5a20d3cSdrh int len; 3054b5a20d3cSdrh if( pDb->zTrace ){ 3055b5a20d3cSdrh Tcl_Free(pDb->zTrace); 3056b5a20d3cSdrh } 3057b5a20d3cSdrh zTrace = Tcl_GetStringFromObj(objv[2], &len); 3058b5a20d3cSdrh if( zTrace && len>0 ){ 3059b5a20d3cSdrh pDb->zTrace = Tcl_Alloc( len + 1 ); 30605bb3eb9bSdrh memcpy(pDb->zTrace, zTrace, len+1); 3061b5a20d3cSdrh }else{ 3062b5a20d3cSdrh pDb->zTrace = 0; 3063b5a20d3cSdrh } 30642eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 30652eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 3066b5a20d3cSdrh if( pDb->zTrace ){ 3067b5a20d3cSdrh pDb->interp = interp; 30686f8a503dSdanielk1977 sqlite3_trace(pDb->db, DbTraceHandler, pDb); 3069b5a20d3cSdrh }else{ 30706f8a503dSdanielk1977 sqlite3_trace(pDb->db, 0, 0); 3071b5a20d3cSdrh } 307219e2d37fSdrh #endif 3073b5a20d3cSdrh } 3074b5a20d3cSdrh break; 3075b5a20d3cSdrh } 3076b5a20d3cSdrh 3077b56660f5Smistachkin /* $db trace_v2 ?CALLBACK? ?MASK? 3078b56660f5Smistachkin ** 3079b56660f5Smistachkin ** Make arrangements to invoke the CALLBACK routine for each trace event 3080b56660f5Smistachkin ** matching the mask that is generated. The parameters are appended to 3081b56660f5Smistachkin ** CALLBACK before it is executed. 3082b56660f5Smistachkin */ 3083b56660f5Smistachkin case DB_TRACE_V2: { 3084b56660f5Smistachkin if( objc>4 ){ 3085b56660f5Smistachkin Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK? ?MASK?"); 3086b56660f5Smistachkin return TCL_ERROR; 3087b56660f5Smistachkin }else if( objc==2 ){ 3088b56660f5Smistachkin if( pDb->zTraceV2 ){ 3089b56660f5Smistachkin Tcl_AppendResult(interp, pDb->zTraceV2, (char*)0); 3090b56660f5Smistachkin } 3091b56660f5Smistachkin }else{ 3092b56660f5Smistachkin char *zTraceV2; 3093b56660f5Smistachkin int len; 3094b52dcd89Smistachkin Tcl_WideInt wMask = 0; 3095b56660f5Smistachkin if( objc==4 ){ 3096b52dcd89Smistachkin static const char *TTYPE_strs[] = { 3097b52dcd89Smistachkin "statement", "profile", "row", "close", 0 3098b52dcd89Smistachkin }; 3099b52dcd89Smistachkin enum TTYPE_enum { 3100b52dcd89Smistachkin TTYPE_STMT, TTYPE_PROFILE, TTYPE_ROW, TTYPE_CLOSE 3101b52dcd89Smistachkin }; 3102b52dcd89Smistachkin int i; 3103b52dcd89Smistachkin if( TCL_OK!=Tcl_ListObjLength(interp, objv[3], &len) ){ 3104b52dcd89Smistachkin return TCL_ERROR; 3105b52dcd89Smistachkin } 3106b52dcd89Smistachkin for(i=0; i<len; i++){ 3107b52dcd89Smistachkin Tcl_Obj *pObj; 3108b52dcd89Smistachkin int ttype; 3109b52dcd89Smistachkin if( TCL_OK!=Tcl_ListObjIndex(interp, objv[3], i, &pObj) ){ 3110b52dcd89Smistachkin return TCL_ERROR; 3111b52dcd89Smistachkin } 3112b52dcd89Smistachkin if( Tcl_GetIndexFromObj(interp, pObj, TTYPE_strs, "trace type", 3113b52dcd89Smistachkin 0, &ttype)!=TCL_OK ){ 3114b52dcd89Smistachkin Tcl_WideInt wType; 3115b52dcd89Smistachkin Tcl_Obj *pError = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); 3116b52dcd89Smistachkin Tcl_IncrRefCount(pError); 3117b52dcd89Smistachkin if( TCL_OK==Tcl_GetWideIntFromObj(interp, pObj, &wType) ){ 3118b52dcd89Smistachkin Tcl_DecrRefCount(pError); 3119b52dcd89Smistachkin wMask |= wType; 3120b52dcd89Smistachkin }else{ 3121b52dcd89Smistachkin Tcl_SetObjResult(interp, pError); 3122b52dcd89Smistachkin Tcl_DecrRefCount(pError); 3123b56660f5Smistachkin return TCL_ERROR; 3124b56660f5Smistachkin } 3125b56660f5Smistachkin }else{ 3126b52dcd89Smistachkin switch( (enum TTYPE_enum)ttype ){ 3127b52dcd89Smistachkin case TTYPE_STMT: wMask |= SQLITE_TRACE_STMT; break; 3128b52dcd89Smistachkin case TTYPE_PROFILE: wMask |= SQLITE_TRACE_PROFILE; break; 3129b52dcd89Smistachkin case TTYPE_ROW: wMask |= SQLITE_TRACE_ROW; break; 3130b52dcd89Smistachkin case TTYPE_CLOSE: wMask |= SQLITE_TRACE_CLOSE; break; 3131b52dcd89Smistachkin } 3132b52dcd89Smistachkin } 3133b52dcd89Smistachkin } 3134b52dcd89Smistachkin }else{ 3135b52dcd89Smistachkin wMask = SQLITE_TRACE_STMT; /* use the "legacy" default */ 3136b56660f5Smistachkin } 3137b56660f5Smistachkin if( pDb->zTraceV2 ){ 3138b56660f5Smistachkin Tcl_Free(pDb->zTraceV2); 3139b56660f5Smistachkin } 3140b56660f5Smistachkin zTraceV2 = Tcl_GetStringFromObj(objv[2], &len); 3141b56660f5Smistachkin if( zTraceV2 && len>0 ){ 3142b56660f5Smistachkin pDb->zTraceV2 = Tcl_Alloc( len + 1 ); 3143b56660f5Smistachkin memcpy(pDb->zTraceV2, zTraceV2, len+1); 3144b56660f5Smistachkin }else{ 3145b56660f5Smistachkin pDb->zTraceV2 = 0; 3146b56660f5Smistachkin } 3147b56660f5Smistachkin #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) 3148b56660f5Smistachkin if( pDb->zTraceV2 ){ 3149b56660f5Smistachkin pDb->interp = interp; 3150b56660f5Smistachkin sqlite3_trace_v2(pDb->db, (unsigned)wMask, DbTraceV2Handler, pDb); 3151b56660f5Smistachkin }else{ 3152b56660f5Smistachkin sqlite3_trace_v2(pDb->db, 0, 0, 0); 3153b56660f5Smistachkin } 3154b56660f5Smistachkin #endif 3155b56660f5Smistachkin } 3156b56660f5Smistachkin break; 3157b56660f5Smistachkin } 3158b56660f5Smistachkin 31593d21423cSdrh /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT 31603d21423cSdrh ** 31613d21423cSdrh ** Start a new transaction (if we are not already in the midst of a 31623d21423cSdrh ** transaction) and execute the TCL script SCRIPT. After SCRIPT 31633d21423cSdrh ** completes, either commit the transaction or roll it back if SCRIPT 31643d21423cSdrh ** throws an exception. Or if no new transation was started, do nothing. 31653d21423cSdrh ** pass the exception on up the stack. 31663d21423cSdrh ** 31673d21423cSdrh ** This command was inspired by Dave Thomas's talk on Ruby at the 31683d21423cSdrh ** 2005 O'Reilly Open Source Convention (OSCON). 31693d21423cSdrh */ 31703d21423cSdrh case DB_TRANSACTION: { 31713d21423cSdrh Tcl_Obj *pScript; 3172cd38d520Sdanielk1977 const char *zBegin = "SAVEPOINT _tcl_transaction"; 31733d21423cSdrh if( objc!=3 && objc!=4 ){ 31743d21423cSdrh Tcl_WrongNumArgs(interp, 2, objv, "[TYPE] SCRIPT"); 31753d21423cSdrh return TCL_ERROR; 31763d21423cSdrh } 3177cd38d520Sdanielk1977 31784a4c11aaSdan if( pDb->nTransaction==0 && objc==4 ){ 31793d21423cSdrh static const char *TTYPE_strs[] = { 3180ce604012Sdrh "deferred", "exclusive", "immediate", 0 31813d21423cSdrh }; 31823d21423cSdrh enum TTYPE_enum { 31833d21423cSdrh TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE 31843d21423cSdrh }; 31853d21423cSdrh int ttype; 3186b5555e7eSdrh if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type", 31873d21423cSdrh 0, &ttype) ){ 31883d21423cSdrh return TCL_ERROR; 31893d21423cSdrh } 31903d21423cSdrh switch( (enum TTYPE_enum)ttype ){ 31913d21423cSdrh case TTYPE_DEFERRED: /* no-op */; break; 31923d21423cSdrh case TTYPE_EXCLUSIVE: zBegin = "BEGIN EXCLUSIVE"; break; 31933d21423cSdrh case TTYPE_IMMEDIATE: zBegin = "BEGIN IMMEDIATE"; break; 31943d21423cSdrh } 31953d21423cSdrh } 3196cd38d520Sdanielk1977 pScript = objv[objc-1]; 3197cd38d520Sdanielk1977 31984a4c11aaSdan /* Run the SQLite BEGIN command to open a transaction or savepoint. */ 31991f1549f8Sdrh pDb->disableAuth++; 3200cd38d520Sdanielk1977 rc = sqlite3_exec(pDb->db, zBegin, 0, 0, 0); 32011f1549f8Sdrh pDb->disableAuth--; 3202cd38d520Sdanielk1977 if( rc!=SQLITE_OK ){ 3203a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 3204cd38d520Sdanielk1977 return TCL_ERROR; 32053d21423cSdrh } 3206cd38d520Sdanielk1977 pDb->nTransaction++; 3207cd38d520Sdanielk1977 32084a4c11aaSdan /* If using NRE, schedule a callback to invoke the script pScript, then 32094a4c11aaSdan ** a second callback to commit (or rollback) the transaction or savepoint 32104a4c11aaSdan ** opened above. If not using NRE, evaluate the script directly, then 32114a4c11aaSdan ** call function DbTransPostCmd() to commit (or rollback) the transaction 32124a4c11aaSdan ** or savepoint. */ 32134a4c11aaSdan if( DbUseNre() ){ 32144a4c11aaSdan Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0); 3215a47941feSdrh (void)Tcl_NREvalObj(interp, pScript, 0); 32163d21423cSdrh }else{ 32174a4c11aaSdan rc = DbTransPostCmd(&cd, interp, Tcl_EvalObjEx(interp, pScript, 0)); 32183d21423cSdrh } 32193d21423cSdrh break; 32203d21423cSdrh } 32213d21423cSdrh 322294eb6a14Sdanielk1977 /* 3223404ca075Sdanielk1977 ** $db unlock_notify ?script? 3224404ca075Sdanielk1977 */ 3225404ca075Sdanielk1977 case DB_UNLOCK_NOTIFY: { 3226404ca075Sdanielk1977 #ifndef SQLITE_ENABLE_UNLOCK_NOTIFY 3227a198f2b5Sdrh Tcl_AppendResult(interp, "unlock_notify not available in this build", 3228a198f2b5Sdrh (char*)0); 3229404ca075Sdanielk1977 rc = TCL_ERROR; 3230404ca075Sdanielk1977 #else 3231404ca075Sdanielk1977 if( objc!=2 && objc!=3 ){ 3232404ca075Sdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); 3233404ca075Sdanielk1977 rc = TCL_ERROR; 3234404ca075Sdanielk1977 }else{ 3235404ca075Sdanielk1977 void (*xNotify)(void **, int) = 0; 3236404ca075Sdanielk1977 void *pNotifyArg = 0; 3237404ca075Sdanielk1977 3238404ca075Sdanielk1977 if( pDb->pUnlockNotify ){ 3239404ca075Sdanielk1977 Tcl_DecrRefCount(pDb->pUnlockNotify); 3240404ca075Sdanielk1977 pDb->pUnlockNotify = 0; 3241404ca075Sdanielk1977 } 3242404ca075Sdanielk1977 3243404ca075Sdanielk1977 if( objc==3 ){ 3244404ca075Sdanielk1977 xNotify = DbUnlockNotify; 3245404ca075Sdanielk1977 pNotifyArg = (void *)pDb; 3246404ca075Sdanielk1977 pDb->pUnlockNotify = objv[2]; 3247404ca075Sdanielk1977 Tcl_IncrRefCount(pDb->pUnlockNotify); 3248404ca075Sdanielk1977 } 3249404ca075Sdanielk1977 3250404ca075Sdanielk1977 if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){ 3251a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 3252404ca075Sdanielk1977 rc = TCL_ERROR; 3253404ca075Sdanielk1977 } 3254404ca075Sdanielk1977 } 3255404ca075Sdanielk1977 #endif 3256404ca075Sdanielk1977 break; 3257404ca075Sdanielk1977 } 3258404ca075Sdanielk1977 3259304637c0Sdrh /* 3260304637c0Sdrh ** $db preupdate_hook count 3261304637c0Sdrh ** $db preupdate_hook hook ?SCRIPT? 3262304637c0Sdrh ** $db preupdate_hook new INDEX 3263304637c0Sdrh ** $db preupdate_hook old INDEX 3264304637c0Sdrh */ 326546c47d46Sdan case DB_PREUPDATE: { 32669b1c62d4Sdrh #ifndef SQLITE_ENABLE_PREUPDATE_HOOK 32672b519ab0Sdan Tcl_AppendResult(interp, "preupdate_hook was omitted at compile-time", 32682b519ab0Sdan (char*)0); 32699b1c62d4Sdrh rc = TCL_ERROR; 32709b1c62d4Sdrh #else 32711e7a2d43Sdan static const char *azSub[] = {"count", "depth", "hook", "new", "old", 0}; 327246c47d46Sdan enum DbPreupdateSubCmd { 32731e7a2d43Sdan PRE_COUNT, PRE_DEPTH, PRE_HOOK, PRE_NEW, PRE_OLD 327446c47d46Sdan }; 327546c47d46Sdan int iSub; 327646c47d46Sdan 327746c47d46Sdan if( objc<3 ){ 327846c47d46Sdan Tcl_WrongNumArgs(interp, 2, objv, "SUB-COMMAND ?ARGS?"); 327946c47d46Sdan } 328046c47d46Sdan if( Tcl_GetIndexFromObj(interp, objv[2], azSub, "sub-command", 0, &iSub) ){ 328146c47d46Sdan return TCL_ERROR; 328246c47d46Sdan } 328346c47d46Sdan 328446c47d46Sdan switch( (enum DbPreupdateSubCmd)iSub ){ 328546c47d46Sdan case PRE_COUNT: { 328646c47d46Sdan int nCol = sqlite3_preupdate_count(pDb->db); 328746c47d46Sdan Tcl_SetObjResult(interp, Tcl_NewIntObj(nCol)); 328846c47d46Sdan break; 328946c47d46Sdan } 329046c47d46Sdan 329146c47d46Sdan case PRE_HOOK: { 329246c47d46Sdan if( objc>4 ){ 329346c47d46Sdan Tcl_WrongNumArgs(interp, 2, objv, "hook ?SCRIPT?"); 329446c47d46Sdan return TCL_ERROR; 329546c47d46Sdan } 329646c47d46Sdan DbHookCmd(interp, pDb, (objc==4 ? objv[3] : 0), &pDb->pPreUpdateHook); 329746c47d46Sdan break; 329846c47d46Sdan } 329946c47d46Sdan 33001e7a2d43Sdan case PRE_DEPTH: { 33011e7a2d43Sdan Tcl_Obj *pRet; 33021e7a2d43Sdan if( objc!=3 ){ 33031e7a2d43Sdan Tcl_WrongNumArgs(interp, 3, objv, ""); 33041e7a2d43Sdan return TCL_ERROR; 33051e7a2d43Sdan } 33061e7a2d43Sdan pRet = Tcl_NewIntObj(sqlite3_preupdate_depth(pDb->db)); 33071e7a2d43Sdan Tcl_SetObjResult(interp, pRet); 33081e7a2d43Sdan break; 33091e7a2d43Sdan } 33101e7a2d43Sdan 331137db03bfSdan case PRE_NEW: 331246c47d46Sdan case PRE_OLD: { 331346c47d46Sdan int iIdx; 331437db03bfSdan sqlite3_value *pValue; 331546c47d46Sdan if( objc!=4 ){ 331646c47d46Sdan Tcl_WrongNumArgs(interp, 3, objv, "INDEX"); 331746c47d46Sdan return TCL_ERROR; 331846c47d46Sdan } 331946c47d46Sdan if( Tcl_GetIntFromObj(interp, objv[3], &iIdx) ){ 332046c47d46Sdan return TCL_ERROR; 332146c47d46Sdan } 332246c47d46Sdan 332337db03bfSdan if( iSub==PRE_OLD ){ 332446c47d46Sdan rc = sqlite3_preupdate_old(pDb->db, iIdx, &pValue); 332537db03bfSdan }else{ 332637db03bfSdan assert( iSub==PRE_NEW ); 332737db03bfSdan rc = sqlite3_preupdate_new(pDb->db, iIdx, &pValue); 332837db03bfSdan } 332937db03bfSdan 333046c47d46Sdan if( rc==SQLITE_OK ){ 3331304637c0Sdrh Tcl_Obj *pObj; 3332304637c0Sdrh pObj = Tcl_NewStringObj((char*)sqlite3_value_text(pValue), -1); 333346c47d46Sdan Tcl_SetObjResult(interp, pObj); 333437db03bfSdan }else{ 3335ea8f0a15Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 333646c47d46Sdan return TCL_ERROR; 333746c47d46Sdan } 333846c47d46Sdan } 333946c47d46Sdan } 33409b1c62d4Sdrh #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ 334146c47d46Sdan break; 334246c47d46Sdan } 334346c47d46Sdan 3344404ca075Sdanielk1977 /* 3345833bf968Sdrh ** $db wal_hook ?script? 334694eb6a14Sdanielk1977 ** $db update_hook ?script? 334771fd80bfSdanielk1977 ** $db rollback_hook ?script? 334894eb6a14Sdanielk1977 */ 3349833bf968Sdrh case DB_WAL_HOOK: 335071fd80bfSdanielk1977 case DB_UPDATE_HOOK: 33516566ebe1Sdan case DB_ROLLBACK_HOOK: { 335271fd80bfSdanielk1977 /* set ppHook to point at pUpdateHook or pRollbackHook, depending on 335371fd80bfSdanielk1977 ** whether [$db update_hook] or [$db rollback_hook] was invoked. 335471fd80bfSdanielk1977 */ 3355c5896b5cSmistachkin Tcl_Obj **ppHook = 0; 335646c47d46Sdan if( choice==DB_WAL_HOOK ) ppHook = &pDb->pWalHook; 335746c47d46Sdan if( choice==DB_UPDATE_HOOK ) ppHook = &pDb->pUpdateHook; 335846c47d46Sdan if( choice==DB_ROLLBACK_HOOK ) ppHook = &pDb->pRollbackHook; 335946c47d46Sdan if( objc>3 ){ 336094eb6a14Sdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); 336194eb6a14Sdanielk1977 return TCL_ERROR; 336294eb6a14Sdanielk1977 } 336371fd80bfSdanielk1977 336446c47d46Sdan DbHookCmd(interp, pDb, (objc==3 ? objv[2] : 0), ppHook); 336594eb6a14Sdanielk1977 break; 336694eb6a14Sdanielk1977 } 336794eb6a14Sdanielk1977 33684397de57Sdanielk1977 /* $db version 33694397de57Sdanielk1977 ** 33704397de57Sdanielk1977 ** Return the version string for this database. 33714397de57Sdanielk1977 */ 33724397de57Sdanielk1977 case DB_VERSION: { 33731df6470dSdrh int i; 33741df6470dSdrh for(i=2; i<objc; i++){ 33751df6470dSdrh const char *zArg = Tcl_GetString(objv[i]); 33761df6470dSdrh /* Optional arguments to $db version are used for testing purpose */ 33771df6470dSdrh #ifdef SQLITE_TEST 33781df6470dSdrh /* $db version -use-legacy-prepare BOOLEAN 33791df6470dSdrh ** 33801df6470dSdrh ** Turn the use of legacy sqlite3_prepare() on or off. 33811df6470dSdrh */ 33821df6470dSdrh if( strcmp(zArg, "-use-legacy-prepare")==0 && i+1<objc ){ 33831df6470dSdrh i++; 33841df6470dSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &pDb->bLegacyPrepare) ){ 33851df6470dSdrh return TCL_ERROR; 33861df6470dSdrh } 33871df6470dSdrh }else 33881df6470dSdrh 33891df6470dSdrh /* $db version -last-stmt-ptr 33901df6470dSdrh ** 33911df6470dSdrh ** Return a string which is a hex encoding of the pointer to the 33921df6470dSdrh ** most recent sqlite3_stmt in the statement cache. 33931df6470dSdrh */ 33941df6470dSdrh if( strcmp(zArg, "-last-stmt-ptr")==0 ){ 33951df6470dSdrh char zBuf[100]; 33961df6470dSdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", 33971df6470dSdrh pDb->stmtList ? pDb->stmtList->pStmt: 0); 33981df6470dSdrh Tcl_SetResult(interp, zBuf, TCL_VOLATILE); 33991df6470dSdrh }else 34001df6470dSdrh #endif /* SQLITE_TEST */ 34011df6470dSdrh { 34021df6470dSdrh Tcl_AppendResult(interp, "unknown argument: ", zArg, (char*)0); 34031df6470dSdrh return TCL_ERROR; 34041df6470dSdrh } 34051df6470dSdrh } 34061df6470dSdrh if( i==2 ){ 34074397de57Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC); 34081df6470dSdrh } 34094397de57Sdanielk1977 break; 34104397de57Sdanielk1977 } 34114397de57Sdanielk1977 34121067fe11Stpoindex 34136d31316cSdrh } /* End of the SWITCH statement */ 341422fbcb8dSdrh return rc; 341575897234Sdrh } 341675897234Sdrh 3417a2c8a95bSdrh #if SQLITE_TCL_NRE 3418a2c8a95bSdrh /* 3419a2c8a95bSdrh ** Adaptor that provides an objCmd interface to the NRE-enabled 3420a2c8a95bSdrh ** interface implementation. 3421a2c8a95bSdrh */ 3422a121cc7cSmistachkin static int SQLITE_TCLAPI DbObjCmdAdaptor( 3423a2c8a95bSdrh void *cd, 3424a2c8a95bSdrh Tcl_Interp *interp, 3425a2c8a95bSdrh int objc, 3426a2c8a95bSdrh Tcl_Obj *const*objv 3427a2c8a95bSdrh ){ 3428a2c8a95bSdrh return Tcl_NRCallObjProc(interp, DbObjCmd, cd, objc, objv); 3429a2c8a95bSdrh } 3430a2c8a95bSdrh #endif /* SQLITE_TCL_NRE */ 3431a2c8a95bSdrh 343275897234Sdrh /* 34334dcac40eSdrh ** Issue the usage message when the "sqlite3" command arguments are 34344dcac40eSdrh ** incorrect. 34354dcac40eSdrh */ 34364dcac40eSdrh static int sqliteCmdUsage( 34374dcac40eSdrh Tcl_Interp *interp, 34384dcac40eSdrh Tcl_Obj *const*objv 34394dcac40eSdrh ){ 34404dcac40eSdrh Tcl_WrongNumArgs(interp, 1, objv, 34414dcac40eSdrh "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" 34424dcac40eSdrh " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" 34434dcac40eSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 34444dcac40eSdrh " ?-key CODECKEY?" 34454dcac40eSdrh #endif 34464dcac40eSdrh ); 34474dcac40eSdrh return TCL_ERROR; 34484dcac40eSdrh } 34494dcac40eSdrh 34504dcac40eSdrh /* 34513570ad93Sdrh ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN? 34529a6284c1Sdanielk1977 ** ?-create BOOLEAN? ?-nomutex BOOLEAN? 345375897234Sdrh ** 345475897234Sdrh ** This is the main Tcl command. When the "sqlite" Tcl command is 345575897234Sdrh ** invoked, this routine runs to process that command. 345675897234Sdrh ** 345775897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new 345875897234Sdrh ** database connection. This command creates a new command named 345975897234Sdrh ** DBNAME that is used to control that connection. The database 346075897234Sdrh ** connection is deleted when the DBNAME command is deleted. 346175897234Sdrh ** 34623570ad93Sdrh ** The second argument is the name of the database file. 3463fbc3eab8Sdrh ** 346475897234Sdrh */ 34657617e4a8Smistachkin static int SQLITE_TCLAPI DbMain( 34667617e4a8Smistachkin void *cd, 34677617e4a8Smistachkin Tcl_Interp *interp, 34687617e4a8Smistachkin int objc, 34697617e4a8Smistachkin Tcl_Obj *const*objv 34707617e4a8Smistachkin ){ 3471bec3f402Sdrh SqliteDb *p; 347222fbcb8dSdrh const char *zArg; 347375897234Sdrh char *zErrMsg; 34743570ad93Sdrh int i; 34754dcac40eSdrh const char *zFile = 0; 34763570ad93Sdrh const char *zVfs = 0; 3477d9da78a2Sdrh int flags; 3478882e8e4dSdrh Tcl_DString translatedFilename; 347932f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 3480b07028f7Sdrh void *pKey = 0; 3481b07028f7Sdrh int nKey = 0; 3482b07028f7Sdrh #endif 3483540ebf82Smistachkin int rc; 3484d9da78a2Sdrh 3485d9da78a2Sdrh /* In normal use, each TCL interpreter runs in a single thread. So 34864dcac40eSdrh ** by default, we can turn off mutexing on SQLite database connections. 3487d9da78a2Sdrh ** However, for testing purposes it is useful to have mutexes turned 3488d9da78a2Sdrh ** on. So, by default, mutexes default off. But if compiled with 3489d9da78a2Sdrh ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on. 3490d9da78a2Sdrh */ 3491d9da78a2Sdrh #ifdef SQLITE_TCL_DEFAULT_FULLMUTEX 3492d9da78a2Sdrh flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX; 3493d9da78a2Sdrh #else 3494d9da78a2Sdrh flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX; 3495d9da78a2Sdrh #endif 3496d9da78a2Sdrh 349722fbcb8dSdrh if( objc==2 ){ 349822fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 349922fbcb8dSdrh if( strcmp(zArg,"-version")==0 ){ 3500a198f2b5Sdrh Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0); 3501647cb0e1Sdrh return TCL_OK; 3502647cb0e1Sdrh } 350372bf6a3eSdrh if( strcmp(zArg,"-sourceid")==0 ){ 350472bf6a3eSdrh Tcl_AppendResult(interp,sqlite3_sourceid(), (char*)0); 350572bf6a3eSdrh return TCL_OK; 350672bf6a3eSdrh } 35079eb9e26bSdrh if( strcmp(zArg,"-has-codec")==0 ){ 350832f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 3509a198f2b5Sdrh Tcl_AppendResult(interp,"1",(char*)0); 351022fbcb8dSdrh #else 3511a198f2b5Sdrh Tcl_AppendResult(interp,"0",(char*)0); 351222fbcb8dSdrh #endif 351322fbcb8dSdrh return TCL_OK; 351422fbcb8dSdrh } 35154dcac40eSdrh if( zArg[0]=='-' ) return sqliteCmdUsage(interp, objv); 3516fbc3eab8Sdrh } 35174dcac40eSdrh for(i=2; i<objc; i++){ 35183570ad93Sdrh zArg = Tcl_GetString(objv[i]); 35194dcac40eSdrh if( zArg[0]!='-' ){ 35204dcac40eSdrh if( zFile!=0 ) return sqliteCmdUsage(interp, objv); 35214dcac40eSdrh zFile = zArg; 35224dcac40eSdrh continue; 35234dcac40eSdrh } 35244dcac40eSdrh if( i==objc-1 ) return sqliteCmdUsage(interp, objv); 35254dcac40eSdrh i++; 352622fbcb8dSdrh if( strcmp(zArg,"-key")==0 ){ 352732f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 35284dcac40eSdrh pKey = Tcl_GetByteArrayFromObj(objv[i], &nKey); 3529b07028f7Sdrh #endif 35303570ad93Sdrh }else if( strcmp(zArg, "-vfs")==0 ){ 35314dcac40eSdrh zVfs = Tcl_GetString(objv[i]); 35323570ad93Sdrh }else if( strcmp(zArg, "-readonly")==0 ){ 35333570ad93Sdrh int b; 35344dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 35353570ad93Sdrh if( b ){ 353633f4e02aSdrh flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); 35373570ad93Sdrh flags |= SQLITE_OPEN_READONLY; 35383570ad93Sdrh }else{ 35393570ad93Sdrh flags &= ~SQLITE_OPEN_READONLY; 35403570ad93Sdrh flags |= SQLITE_OPEN_READWRITE; 35413570ad93Sdrh } 35423570ad93Sdrh }else if( strcmp(zArg, "-create")==0 ){ 35433570ad93Sdrh int b; 35444dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 354533f4e02aSdrh if( b && (flags & SQLITE_OPEN_READONLY)==0 ){ 35463570ad93Sdrh flags |= SQLITE_OPEN_CREATE; 35473570ad93Sdrh }else{ 35483570ad93Sdrh flags &= ~SQLITE_OPEN_CREATE; 35493570ad93Sdrh } 35509a6284c1Sdanielk1977 }else if( strcmp(zArg, "-nomutex")==0 ){ 35519a6284c1Sdanielk1977 int b; 35524dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 35539a6284c1Sdanielk1977 if( b ){ 35549a6284c1Sdanielk1977 flags |= SQLITE_OPEN_NOMUTEX; 3555039963adSdrh flags &= ~SQLITE_OPEN_FULLMUTEX; 35569a6284c1Sdanielk1977 }else{ 35579a6284c1Sdanielk1977 flags &= ~SQLITE_OPEN_NOMUTEX; 35589a6284c1Sdanielk1977 } 3559039963adSdrh }else if( strcmp(zArg, "-fullmutex")==0 ){ 3560039963adSdrh int b; 35614dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 3562039963adSdrh if( b ){ 3563039963adSdrh flags |= SQLITE_OPEN_FULLMUTEX; 3564039963adSdrh flags &= ~SQLITE_OPEN_NOMUTEX; 3565039963adSdrh }else{ 3566039963adSdrh flags &= ~SQLITE_OPEN_FULLMUTEX; 3567039963adSdrh } 3568f12b3f60Sdrh }else if( strcmp(zArg, "-uri")==0 ){ 3569f12b3f60Sdrh int b; 35704dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 3571f12b3f60Sdrh if( b ){ 3572f12b3f60Sdrh flags |= SQLITE_OPEN_URI; 3573f12b3f60Sdrh }else{ 3574f12b3f60Sdrh flags &= ~SQLITE_OPEN_URI; 3575f12b3f60Sdrh } 35763570ad93Sdrh }else{ 35773570ad93Sdrh Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); 35783570ad93Sdrh return TCL_ERROR; 357922fbcb8dSdrh } 358022fbcb8dSdrh } 358175897234Sdrh zErrMsg = 0; 35824cdc9e84Sdrh p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); 3583bec3f402Sdrh memset(p, 0, sizeof(*p)); 35843ec8665eSdrh if( zFile==0 ) zFile = ""; 3585882e8e4dSdrh zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename); 3586540ebf82Smistachkin rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs); 3587882e8e4dSdrh Tcl_DStringFree(&translatedFilename); 3588540ebf82Smistachkin if( p->db ){ 358980290863Sdanielk1977 if( SQLITE_OK!=sqlite3_errcode(p->db) ){ 35909404d50eSdrh zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db)); 359180290863Sdanielk1977 sqlite3_close(p->db); 359280290863Sdanielk1977 p->db = 0; 359380290863Sdanielk1977 } 3594540ebf82Smistachkin }else{ 35955dac8432Smistachkin zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc)); 3596540ebf82Smistachkin } 359732f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 3598f3a65f7eSdrh if( p->db ){ 35992011d5f5Sdrh sqlite3_key(p->db, pKey, nKey); 3600f3a65f7eSdrh } 3601eb8ed70dSdrh #endif 3602bec3f402Sdrh if( p->db==0 ){ 360375897234Sdrh Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); 3604bec3f402Sdrh Tcl_Free((char*)p); 36059404d50eSdrh sqlite3_free(zErrMsg); 360675897234Sdrh return TCL_ERROR; 360775897234Sdrh } 3608fb7e7651Sdrh p->maxStmt = NUM_PREPARED_STMTS; 3609147ef394Sdrh p->openFlags = flags & SQLITE_OPEN_URI; 36105169bbc6Sdrh p->interp = interp; 361122fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 36124a4c11aaSdan if( DbUseNre() ){ 3613a2c8a95bSdrh Tcl_NRCreateCommand(interp, zArg, DbObjCmdAdaptor, DbObjCmd, 3614a2c8a95bSdrh (char*)p, DbDeleteCmd); 36154a4c11aaSdan }else{ 361622fbcb8dSdrh Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); 36174a4c11aaSdan } 361875897234Sdrh return TCL_OK; 361975897234Sdrh } 362075897234Sdrh 362175897234Sdrh /* 362290ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static 362390ca9753Sdrh ** library. 362490ca9753Sdrh */ 362590ca9753Sdrh #ifndef USE_TCL_STUBS 362690ca9753Sdrh # undef Tcl_InitStubs 36270e85ccfcSdrh # define Tcl_InitStubs(a,b,c) TCL_VERSION 362890ca9753Sdrh #endif 362990ca9753Sdrh 363090ca9753Sdrh /* 363129bc4615Sdrh ** Make sure we have a PACKAGE_VERSION macro defined. This will be 363229bc4615Sdrh ** defined automatically by the TEA makefile. But other makefiles 363329bc4615Sdrh ** do not define it. 363429bc4615Sdrh */ 363529bc4615Sdrh #ifndef PACKAGE_VERSION 363629bc4615Sdrh # define PACKAGE_VERSION SQLITE_VERSION 363729bc4615Sdrh #endif 363829bc4615Sdrh 363929bc4615Sdrh /* 364075897234Sdrh ** Initialize this module. 364175897234Sdrh ** 364275897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite". 364375897234Sdrh ** (Hence there is no namespace. There is no point in using a namespace 364475897234Sdrh ** if the extension only supplies one new name!) The "sqlite" command is 364575897234Sdrh ** used to open a new SQLite database. See the DbMain() routine above 364675897234Sdrh ** for additional information. 3647b652f432Sdrh ** 3648b652f432Sdrh ** The EXTERN macros are required by TCL in order to work on windows. 364975897234Sdrh */ 3650b652f432Sdrh EXTERN int Sqlite3_Init(Tcl_Interp *interp){ 365127b2f053Smistachkin int rc = Tcl_InitStubs(interp, "8.4", 0) ? TCL_OK : TCL_ERROR; 36526dc8cbe0Sdrh if( rc==TCL_OK ){ 3653ef4ac8f9Sdrh Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); 36541cca0d22Sdrh #ifndef SQLITE_3_SUFFIX_ONLY 36551cca0d22Sdrh /* The "sqlite" alias is undocumented. It is here only to support 36561cca0d22Sdrh ** legacy scripts. All new scripts should use only the "sqlite3" 36576dc8cbe0Sdrh ** command. */ 365849766d6cSdrh Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); 36594c0f1649Sdrh #endif 36606dc8cbe0Sdrh rc = Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION); 36616dc8cbe0Sdrh } 36626dc8cbe0Sdrh return rc; 366390ca9753Sdrh } 3664b652f432Sdrh EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 3665b652f432Sdrh EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 3666b652f432Sdrh EXTERN int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 3667e2c3a659Sdrh 3668d878cab5Sdrh /* Because it accesses the file-system and uses persistent state, SQLite 3669e75a9eb9Sdrh ** is not considered appropriate for safe interpreters. Hence, we cause 3670e75a9eb9Sdrh ** the _SafeInit() interfaces return TCL_ERROR. 3671d878cab5Sdrh */ 3672e75a9eb9Sdrh EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; } 3673e75a9eb9Sdrh EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;} 3674e75a9eb9Sdrh 3675e75a9eb9Sdrh 367649766d6cSdrh 367749766d6cSdrh #ifndef SQLITE_3_SUFFIX_ONLY 3678a3e63c4aSdan int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 3679a3e63c4aSdan int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 3680a3e63c4aSdan int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 3681a3e63c4aSdan int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 368249766d6cSdrh #endif 368375897234Sdrh 3684c318f730Sdrh /* 368596a206faSdrh ** If the TCLSH macro is defined, add code to make a stand-alone program. 3686c318f730Sdrh */ 368796a206faSdrh #if defined(TCLSH) 368857a0227fSdrh 368996a206faSdrh /* This is the main routine for an ordinary TCL shell. If there are 369096a206faSdrh ** are arguments, run the first argument as a script. Otherwise, 369196a206faSdrh ** read TCL commands from standard input 3692348784efSdrh */ 36930ae479dfSdan static const char *tclsh_main_loop(void){ 36940ae479dfSdan static const char zMainloop[] = 369596a206faSdrh "if {[llength $argv]>=1} {\n" 369696a206faSdrh "set argv0 [lindex $argv 0]\n" 369796a206faSdrh "set argv [lrange $argv 1 end]\n" 369896a206faSdrh "source $argv0\n" 369996a206faSdrh "} else {\n" 3700348784efSdrh "set line {}\n" 3701348784efSdrh "while {![eof stdin]} {\n" 3702348784efSdrh "if {$line!=\"\"} {\n" 3703348784efSdrh "puts -nonewline \"> \"\n" 3704348784efSdrh "} else {\n" 3705348784efSdrh "puts -nonewline \"% \"\n" 3706348784efSdrh "}\n" 3707348784efSdrh "flush stdout\n" 3708348784efSdrh "append line [gets stdin]\n" 3709348784efSdrh "if {[info complete $line]} {\n" 3710348784efSdrh "if {[catch {uplevel #0 $line} result]} {\n" 3711348784efSdrh "puts stderr \"Error: $result\"\n" 3712348784efSdrh "} elseif {$result!=\"\"} {\n" 3713348784efSdrh "puts $result\n" 3714348784efSdrh "}\n" 3715348784efSdrh "set line {}\n" 3716348784efSdrh "} else {\n" 3717348784efSdrh "append line \\n\n" 3718348784efSdrh "}\n" 3719348784efSdrh "}\n" 372096a206faSdrh "}\n" 3721348784efSdrh ; 37220ae479dfSdan return zMainloop; 37230ae479dfSdan } 37243e27c026Sdrh 3725c1a60c51Sdan #define TCLSH_MAIN main /* Needed to fake out mktclapp */ 372669def7ffSmistachkin int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){ 3727c1a60c51Sdan Tcl_Interp *interp; 372896a206faSdrh int i; 372996a206faSdrh const char *zScript = 0; 373096a206faSdrh char zArgc[32]; 373196a206faSdrh #if defined(TCLSH_INIT_PROC) 373296a206faSdrh extern const char *TCLSH_INIT_PROC(Tcl_Interp*); 373396a206faSdrh #endif 3734c1a60c51Sdan 37351f28e070Smistachkin #if !defined(_WIN32_WCE) 37361f28e070Smistachkin if( getenv("BREAK") ){ 37371f28e070Smistachkin fprintf(stderr, 37381f28e070Smistachkin "attach debugger to process %d and press any key to continue.\n", 37391f28e070Smistachkin GETPID()); 37401f28e070Smistachkin fgetc(stdin); 37411f28e070Smistachkin } 37421f28e070Smistachkin #endif 37431f28e070Smistachkin 3744c1a60c51Sdan /* Call sqlite3_shutdown() once before doing anything else. This is to 3745c1a60c51Sdan ** test that sqlite3_shutdown() can be safely called by a process before 3746c1a60c51Sdan ** sqlite3_initialize() is. */ 3747c1a60c51Sdan sqlite3_shutdown(); 3748c1a60c51Sdan 37490ae479dfSdan Tcl_FindExecutable(argv[0]); 37502953ba9eSmistachkin Tcl_SetSystemEncoding(NULL, "utf-8"); 37510ae479dfSdan interp = Tcl_CreateInterp(); 3752c318f730Sdrh Sqlite3_Init(interp); 375396a206faSdrh 375496a206faSdrh sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-1); 3755ad42c3a3Sshess Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY); 375696a206faSdrh Tcl_SetVar(interp,"argv0",argv[0],TCL_GLOBAL_ONLY); 3757348784efSdrh Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); 375896a206faSdrh for(i=1; i<argc; i++){ 3759348784efSdrh Tcl_SetVar(interp, "argv", argv[i], 3760348784efSdrh TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); 3761348784efSdrh } 376296a206faSdrh #if defined(TCLSH_INIT_PROC) 376396a206faSdrh zScript = TCLSH_INIT_PROC(interp); 376496a206faSdrh #endif 376596a206faSdrh if( zScript==0 ){ 376696a206faSdrh zScript = tclsh_main_loop(); 376796a206faSdrh } 376896a206faSdrh if( Tcl_GlobalEval(interp, zScript)!=TCL_OK ){ 37690de8c112Sdrh const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); 3770a81c64a2Sdrh if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp); 3771c61053b7Sdrh fprintf(stderr,"%s: %s\n", *argv, zInfo); 3772348784efSdrh return 1; 3773348784efSdrh } 3774348784efSdrh return 0; 3775348784efSdrh } 3776348784efSdrh #endif /* TCLSH */ 3777