175897234Sdrh /* 2b19a2bc6Sdrh ** 2001 September 15 375897234Sdrh ** 4b19a2bc6Sdrh ** The author disclaims copyright to this source code. In place of 5b19a2bc6Sdrh ** a legal notice, here is a blessing: 675897234Sdrh ** 7b19a2bc6Sdrh ** May you do good and not evil. 8b19a2bc6Sdrh ** May you find forgiveness for yourself and forgive others. 9b19a2bc6Sdrh ** May you share freely, never taking more than you give. 1075897234Sdrh ** 1175897234Sdrh ************************************************************************* 12bd08af48Sdrh ** A TCL Interface to SQLite. Append this file to sqlite3.c and 13bd08af48Sdrh ** compile the whole thing to build a TCL-enabled version of SQLite. 1457a0227fSdrh ** 1557a0227fSdrh ** Compile-time options: 1657a0227fSdrh ** 1796a206faSdrh ** -DTCLSH Add a "main()" routine that works as a tclsh. 1857a0227fSdrh ** 1996a206faSdrh ** -DTCLSH_INIT_PROC=name 2057a0227fSdrh ** 2196a206faSdrh ** Invoke name(interp) to initialize the Tcl interpreter. 2296a206faSdrh ** If name(interp) returns a non-NULL string, then run 2396a206faSdrh ** that string as a Tcl script to launch the application. 2496a206faSdrh ** If name(interp) returns NULL, then run the regular 2596a206faSdrh ** tclsh-emulator code. 2675897234Sdrh */ 2796a206faSdrh #ifdef TCLSH_INIT_PROC 2896a206faSdrh # define TCLSH 1 2996a206faSdrh #endif 3027b2f053Smistachkin 3127b2f053Smistachkin /* 3227b2f053Smistachkin ** If requested, include the SQLite compiler options file for MSVC. 3327b2f053Smistachkin */ 3427b2f053Smistachkin #if defined(INCLUDE_MSVC_H) 3527b2f053Smistachkin # include "msvc.h" 3627b2f053Smistachkin #endif 3727b2f053Smistachkin 3852b1dbb5Smistachkin #if defined(INCLUDE_SQLITE_TCL_H) 3952b1dbb5Smistachkin # include "sqlite_tcl.h" 4052b1dbb5Smistachkin #else 41bd08af48Sdrh # include "tcl.h" 427617e4a8Smistachkin # ifndef SQLITE_TCLAPI 437617e4a8Smistachkin # define SQLITE_TCLAPI 447617e4a8Smistachkin # endif 4552b1dbb5Smistachkin #endif 46b4e9af9fSdanielk1977 #include <errno.h> 476d31316cSdrh 48bd08af48Sdrh /* 49bd08af48Sdrh ** Some additional include files are needed if this file is not 50bd08af48Sdrh ** appended to the amalgamation. 51bd08af48Sdrh */ 52bd08af48Sdrh #ifndef SQLITE_AMALGAMATION 5365e8c82eSdrh # include "sqlite3.h" 5475897234Sdrh # include <stdlib.h> 5575897234Sdrh # include <string.h> 56ce927065Sdrh # include <assert.h> 5765e8c82eSdrh typedef unsigned char u8; 58bd08af48Sdrh #endif 59eb206381Sdrh #include <ctype.h> 6075897234Sdrh 611f28e070Smistachkin /* Used to get the current process ID */ 621f28e070Smistachkin #if !defined(_WIN32) 631e8487dbSmistachkin # include <signal.h> 641f28e070Smistachkin # include <unistd.h> 651f28e070Smistachkin # define GETPID getpid 661f28e070Smistachkin #elif !defined(_WIN32_WCE) 671f28e070Smistachkin # ifndef SQLITE_AMALGAMATION 68176b3a09Smistachkin # ifndef WIN32_LEAN_AND_MEAN 691f28e070Smistachkin # define WIN32_LEAN_AND_MEAN 70176b3a09Smistachkin # endif 711f28e070Smistachkin # include <windows.h> 721f28e070Smistachkin # endif 731e8487dbSmistachkin # include <io.h> 741e8487dbSmistachkin # define isatty(h) _isatty(h) 751f28e070Smistachkin # define GETPID (int)GetCurrentProcessId 761f28e070Smistachkin #endif 771f28e070Smistachkin 78ad6e1370Sdrh /* 79ad6e1370Sdrh * Windows needs to know which symbols to export. Unix does not. 80ad6e1370Sdrh * BUILD_sqlite should be undefined for Unix. 81ad6e1370Sdrh */ 82ad6e1370Sdrh #ifdef BUILD_sqlite 83ad6e1370Sdrh #undef TCL_STORAGE_CLASS 84ad6e1370Sdrh #define TCL_STORAGE_CLASS DLLEXPORT 85ad6e1370Sdrh #endif /* BUILD_sqlite */ 8629bc4615Sdrh 87a21c6b6fSdanielk1977 #define NUM_PREPARED_STMTS 10 88fb7e7651Sdrh #define MAX_PREPARED_STMTS 100 89fb7e7651Sdrh 90c45e6716Sdrh /* Forward declaration */ 91c45e6716Sdrh typedef struct SqliteDb SqliteDb; 9298808babSdrh 9398808babSdrh /* 94cabb0819Sdrh ** New SQL functions can be created as TCL scripts. Each such function 95cabb0819Sdrh ** is described by an instance of the following structure. 9689d24936Sdan ** 9789d24936Sdan ** Variable eType may be set to SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, 9889d24936Sdan ** SQLITE_BLOB or SQLITE_NULL. If it is SQLITE_NULL, then the implementation 9989d24936Sdan ** attempts to determine the type of the result based on the Tcl object. 10089d24936Sdan ** If it is SQLITE_TEXT or SQLITE_BLOB, then a text (sqlite3_result_text()) 10189d24936Sdan ** or blob (sqlite3_result_blob()) is returned. If it is SQLITE_INTEGER 10289d24936Sdan ** or SQLITE_FLOAT, then an attempt is made to return an integer or float 10389d24936Sdan ** value, falling back to float and then text if this is not possible. 104cabb0819Sdrh */ 105cabb0819Sdrh typedef struct SqlFunc SqlFunc; 106cabb0819Sdrh struct SqlFunc { 107cabb0819Sdrh Tcl_Interp *interp; /* The TCL interpret to execute the function */ 108d1e4733dSdrh Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */ 109c45e6716Sdrh SqliteDb *pDb; /* Database connection that owns this function */ 110d1e4733dSdrh int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */ 11189d24936Sdan int eType; /* Type of value to return */ 112d1e4733dSdrh char *zName; /* Name of this function */ 113cabb0819Sdrh SqlFunc *pNext; /* Next function on the list of them all */ 114cabb0819Sdrh }; 115cabb0819Sdrh 116cabb0819Sdrh /* 1170202b29eSdanielk1977 ** New collation sequences function can be created as TCL scripts. Each such 1180202b29eSdanielk1977 ** function is described by an instance of the following structure. 1190202b29eSdanielk1977 */ 1200202b29eSdanielk1977 typedef struct SqlCollate SqlCollate; 1210202b29eSdanielk1977 struct SqlCollate { 1220202b29eSdanielk1977 Tcl_Interp *interp; /* The TCL interpret to execute the function */ 1230202b29eSdanielk1977 char *zScript; /* The script to be run */ 1240202b29eSdanielk1977 SqlCollate *pNext; /* Next function on the list of them all */ 1250202b29eSdanielk1977 }; 1260202b29eSdanielk1977 1270202b29eSdanielk1977 /* 128fb7e7651Sdrh ** Prepared statements are cached for faster execution. Each prepared 129fb7e7651Sdrh ** statement is described by an instance of the following structure. 130fb7e7651Sdrh */ 131fb7e7651Sdrh typedef struct SqlPreparedStmt SqlPreparedStmt; 132fb7e7651Sdrh struct SqlPreparedStmt { 133fb7e7651Sdrh SqlPreparedStmt *pNext; /* Next in linked list */ 134fb7e7651Sdrh SqlPreparedStmt *pPrev; /* Previous on the list */ 135fb7e7651Sdrh sqlite3_stmt *pStmt; /* The prepared statement */ 136fb7e7651Sdrh int nSql; /* chars in zSql[] */ 137d0e2a854Sdanielk1977 const char *zSql; /* Text of the SQL statement */ 1384a4c11aaSdan int nParm; /* Size of apParm array */ 1394a4c11aaSdan Tcl_Obj **apParm; /* Array of referenced object pointers */ 140fb7e7651Sdrh }; 141fb7e7651Sdrh 142d0441796Sdanielk1977 typedef struct IncrblobChannel IncrblobChannel; 143d0441796Sdanielk1977 144fb7e7651Sdrh /* 145bec3f402Sdrh ** There is one instance of this structure for each SQLite database 146bec3f402Sdrh ** that has been opened by the SQLite TCL interface. 147c431fd55Sdan ** 148c431fd55Sdan ** If this module is built with SQLITE_TEST defined (to create the SQLite 149c431fd55Sdan ** testfixture executable), then it may be configured to use either 150c431fd55Sdan ** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements. 151c431fd55Sdan ** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used. 152bec3f402Sdrh */ 153bec3f402Sdrh struct SqliteDb { 154dddca286Sdrh sqlite3 *db; /* The "real" database structure. MUST BE FIRST */ 155bec3f402Sdrh Tcl_Interp *interp; /* The interpreter used for this database */ 1566d31316cSdrh char *zBusy; /* The busy callback routine */ 157aa940eacSdrh char *zCommit; /* The commit hook callback routine */ 158b5a20d3cSdrh char *zTrace; /* The trace callback routine */ 159b56660f5Smistachkin char *zTraceV2; /* The trace_v2 callback routine */ 16019e2d37fSdrh char *zProfile; /* The profile callback routine */ 161348bb5d6Sdanielk1977 char *zProgress; /* The progress callback routine */ 162c06ede10Sdrh char *zBindFallback; /* Callback to invoke on a binding miss */ 163e22a334bSdrh char *zAuth; /* The authorization callback routine */ 1641f1549f8Sdrh int disableAuth; /* Disable the authorizer if it exists */ 16555c45f2eSdanielk1977 char *zNull; /* Text to substitute for an SQL NULL value */ 166cabb0819Sdrh SqlFunc *pFunc; /* List of SQL functions */ 16794eb6a14Sdanielk1977 Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ 16846c47d46Sdan Tcl_Obj *pPreUpdateHook; /* Pre-update hook script (if any) */ 16971fd80bfSdanielk1977 Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ 1705def0843Sdrh Tcl_Obj *pWalHook; /* WAL hook script (if any) */ 171404ca075Sdanielk1977 Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */ 1720202b29eSdanielk1977 SqlCollate *pCollate; /* List of SQL collation functions */ 1736f8a503dSdanielk1977 int rc; /* Return code of most recent sqlite3_exec() */ 1747cedc8d4Sdanielk1977 Tcl_Obj *pCollateNeeded; /* Collation needed script */ 175fb7e7651Sdrh SqlPreparedStmt *stmtList; /* List of prepared statements*/ 176fb7e7651Sdrh SqlPreparedStmt *stmtLast; /* Last statement in the list */ 177fb7e7651Sdrh int maxStmt; /* The next maximum number of stmtList */ 178fb7e7651Sdrh int nStmt; /* Number of statements in stmtList */ 179d0441796Sdanielk1977 IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ 1803c379b01Sdrh int nStep, nSort, nIndex; /* Statistics for most recent operation */ 181c456a76fSdan int nVMStep; /* Another statistic for most recent operation */ 182cd38d520Sdanielk1977 int nTransaction; /* Number of nested [transaction] methods */ 183147ef394Sdrh int openFlags; /* Flags used to open. (SQLITE_OPEN_URI) */ 184c431fd55Sdan #ifdef SQLITE_TEST 185c431fd55Sdan int bLegacyPrepare; /* True to use sqlite3_prepare() */ 186c431fd55Sdan #endif 18798808babSdrh }; 188297ecf14Sdrh 189b4e9af9fSdanielk1977 struct IncrblobChannel { 190d0441796Sdanielk1977 sqlite3_blob *pBlob; /* sqlite3 blob handle */ 191dcbb5d3fSdanielk1977 SqliteDb *pDb; /* Associated database connection */ 192b4e9af9fSdanielk1977 int iSeek; /* Current seek offset */ 193d0441796Sdanielk1977 Tcl_Channel channel; /* Channel identifier */ 194d0441796Sdanielk1977 IncrblobChannel *pNext; /* Linked list of all open incrblob channels */ 195d0441796Sdanielk1977 IncrblobChannel *pPrev; /* Linked list of all open incrblob channels */ 196b4e9af9fSdanielk1977 }; 197b4e9af9fSdanielk1977 198ea678832Sdrh /* 199ea678832Sdrh ** Compute a string length that is limited to what can be stored in 200ea678832Sdrh ** lower 30 bits of a 32-bit signed integer. 201ea678832Sdrh */ 2024f21c4afSdrh static int strlen30(const char *z){ 203ea678832Sdrh const char *z2 = z; 204ea678832Sdrh while( *z2 ){ z2++; } 205ea678832Sdrh return 0x3fffffff & (int)(z2 - z); 206ea678832Sdrh } 207ea678832Sdrh 208ea678832Sdrh 20932a0d8bbSdanielk1977 #ifndef SQLITE_OMIT_INCRBLOB 210b4e9af9fSdanielk1977 /* 211d0441796Sdanielk1977 ** Close all incrblob channels opened using database connection pDb. 212d0441796Sdanielk1977 ** This is called when shutting down the database connection. 213d0441796Sdanielk1977 */ 214d0441796Sdanielk1977 static void closeIncrblobChannels(SqliteDb *pDb){ 215d0441796Sdanielk1977 IncrblobChannel *p; 216d0441796Sdanielk1977 IncrblobChannel *pNext; 217d0441796Sdanielk1977 218d0441796Sdanielk1977 for(p=pDb->pIncrblob; p; p=pNext){ 219d0441796Sdanielk1977 pNext = p->pNext; 220d0441796Sdanielk1977 221d0441796Sdanielk1977 /* Note: Calling unregister here call Tcl_Close on the incrblob channel, 222d0441796Sdanielk1977 ** which deletes the IncrblobChannel structure at *p. So do not 223d0441796Sdanielk1977 ** call Tcl_Free() here. 224d0441796Sdanielk1977 */ 225d0441796Sdanielk1977 Tcl_UnregisterChannel(pDb->interp, p->channel); 226d0441796Sdanielk1977 } 227d0441796Sdanielk1977 } 228d0441796Sdanielk1977 229d0441796Sdanielk1977 /* 230b4e9af9fSdanielk1977 ** Close an incremental blob channel. 231b4e9af9fSdanielk1977 */ 2327617e4a8Smistachkin static int SQLITE_TCLAPI incrblobClose( 2337617e4a8Smistachkin ClientData instanceData, 2347617e4a8Smistachkin Tcl_Interp *interp 2357617e4a8Smistachkin ){ 236b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 23792d4d7a9Sdanielk1977 int rc = sqlite3_blob_close(p->pBlob); 23892d4d7a9Sdanielk1977 sqlite3 *db = p->pDb->db; 239d0441796Sdanielk1977 240d0441796Sdanielk1977 /* Remove the channel from the SqliteDb.pIncrblob list. */ 241d0441796Sdanielk1977 if( p->pNext ){ 242d0441796Sdanielk1977 p->pNext->pPrev = p->pPrev; 243d0441796Sdanielk1977 } 244d0441796Sdanielk1977 if( p->pPrev ){ 245d0441796Sdanielk1977 p->pPrev->pNext = p->pNext; 246d0441796Sdanielk1977 } 247d0441796Sdanielk1977 if( p->pDb->pIncrblob==p ){ 248d0441796Sdanielk1977 p->pDb->pIncrblob = p->pNext; 249d0441796Sdanielk1977 } 250d0441796Sdanielk1977 25192d4d7a9Sdanielk1977 /* Free the IncrblobChannel structure */ 252b4e9af9fSdanielk1977 Tcl_Free((char *)p); 25392d4d7a9Sdanielk1977 25492d4d7a9Sdanielk1977 if( rc!=SQLITE_OK ){ 25592d4d7a9Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE); 25692d4d7a9Sdanielk1977 return TCL_ERROR; 25792d4d7a9Sdanielk1977 } 258b4e9af9fSdanielk1977 return TCL_OK; 259b4e9af9fSdanielk1977 } 260b4e9af9fSdanielk1977 261b4e9af9fSdanielk1977 /* 262b4e9af9fSdanielk1977 ** Read data from an incremental blob channel. 263b4e9af9fSdanielk1977 */ 2647617e4a8Smistachkin static int SQLITE_TCLAPI incrblobInput( 265b4e9af9fSdanielk1977 ClientData instanceData, 266b4e9af9fSdanielk1977 char *buf, 267b4e9af9fSdanielk1977 int bufSize, 268b4e9af9fSdanielk1977 int *errorCodePtr 269b4e9af9fSdanielk1977 ){ 270b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 271b4e9af9fSdanielk1977 int nRead = bufSize; /* Number of bytes to read */ 272b4e9af9fSdanielk1977 int nBlob; /* Total size of the blob */ 273b4e9af9fSdanielk1977 int rc; /* sqlite error code */ 274b4e9af9fSdanielk1977 275b4e9af9fSdanielk1977 nBlob = sqlite3_blob_bytes(p->pBlob); 276b4e9af9fSdanielk1977 if( (p->iSeek+nRead)>nBlob ){ 277b4e9af9fSdanielk1977 nRead = nBlob-p->iSeek; 278b4e9af9fSdanielk1977 } 279b4e9af9fSdanielk1977 if( nRead<=0 ){ 280b4e9af9fSdanielk1977 return 0; 281b4e9af9fSdanielk1977 } 282b4e9af9fSdanielk1977 283b4e9af9fSdanielk1977 rc = sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek); 284b4e9af9fSdanielk1977 if( rc!=SQLITE_OK ){ 285b4e9af9fSdanielk1977 *errorCodePtr = rc; 286b4e9af9fSdanielk1977 return -1; 287b4e9af9fSdanielk1977 } 288b4e9af9fSdanielk1977 289b4e9af9fSdanielk1977 p->iSeek += nRead; 290b4e9af9fSdanielk1977 return nRead; 291b4e9af9fSdanielk1977 } 292b4e9af9fSdanielk1977 293d0441796Sdanielk1977 /* 294d0441796Sdanielk1977 ** Write data to an incremental blob channel. 295d0441796Sdanielk1977 */ 2967617e4a8Smistachkin static int SQLITE_TCLAPI incrblobOutput( 297b4e9af9fSdanielk1977 ClientData instanceData, 298b4e9af9fSdanielk1977 CONST char *buf, 299b4e9af9fSdanielk1977 int toWrite, 300b4e9af9fSdanielk1977 int *errorCodePtr 301b4e9af9fSdanielk1977 ){ 302b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 303b4e9af9fSdanielk1977 int nWrite = toWrite; /* Number of bytes to write */ 304b4e9af9fSdanielk1977 int nBlob; /* Total size of the blob */ 305b4e9af9fSdanielk1977 int rc; /* sqlite error code */ 306b4e9af9fSdanielk1977 307b4e9af9fSdanielk1977 nBlob = sqlite3_blob_bytes(p->pBlob); 308b4e9af9fSdanielk1977 if( (p->iSeek+nWrite)>nBlob ){ 309b4e9af9fSdanielk1977 *errorCodePtr = EINVAL; 310b4e9af9fSdanielk1977 return -1; 311b4e9af9fSdanielk1977 } 312b4e9af9fSdanielk1977 if( nWrite<=0 ){ 313b4e9af9fSdanielk1977 return 0; 314b4e9af9fSdanielk1977 } 315b4e9af9fSdanielk1977 316b4e9af9fSdanielk1977 rc = sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek); 317b4e9af9fSdanielk1977 if( rc!=SQLITE_OK ){ 318b4e9af9fSdanielk1977 *errorCodePtr = EIO; 319b4e9af9fSdanielk1977 return -1; 320b4e9af9fSdanielk1977 } 321b4e9af9fSdanielk1977 322b4e9af9fSdanielk1977 p->iSeek += nWrite; 323b4e9af9fSdanielk1977 return nWrite; 324b4e9af9fSdanielk1977 } 325b4e9af9fSdanielk1977 326b4e9af9fSdanielk1977 /* 327b4e9af9fSdanielk1977 ** Seek an incremental blob channel. 328b4e9af9fSdanielk1977 */ 3297617e4a8Smistachkin static int SQLITE_TCLAPI incrblobSeek( 330b4e9af9fSdanielk1977 ClientData instanceData, 331b4e9af9fSdanielk1977 long offset, 332b4e9af9fSdanielk1977 int seekMode, 333b4e9af9fSdanielk1977 int *errorCodePtr 334b4e9af9fSdanielk1977 ){ 335b4e9af9fSdanielk1977 IncrblobChannel *p = (IncrblobChannel *)instanceData; 336b4e9af9fSdanielk1977 337b4e9af9fSdanielk1977 switch( seekMode ){ 338b4e9af9fSdanielk1977 case SEEK_SET: 339b4e9af9fSdanielk1977 p->iSeek = offset; 340b4e9af9fSdanielk1977 break; 341b4e9af9fSdanielk1977 case SEEK_CUR: 342b4e9af9fSdanielk1977 p->iSeek += offset; 343b4e9af9fSdanielk1977 break; 344b4e9af9fSdanielk1977 case SEEK_END: 345b4e9af9fSdanielk1977 p->iSeek = sqlite3_blob_bytes(p->pBlob) + offset; 346b4e9af9fSdanielk1977 break; 347b4e9af9fSdanielk1977 348b4e9af9fSdanielk1977 default: assert(!"Bad seekMode"); 349b4e9af9fSdanielk1977 } 350b4e9af9fSdanielk1977 351b4e9af9fSdanielk1977 return p->iSeek; 352b4e9af9fSdanielk1977 } 353b4e9af9fSdanielk1977 354b4e9af9fSdanielk1977 3557617e4a8Smistachkin static void SQLITE_TCLAPI incrblobWatch( 3567617e4a8Smistachkin ClientData instanceData, 3577617e4a8Smistachkin int mode 3587617e4a8Smistachkin ){ 359b4e9af9fSdanielk1977 /* NO-OP */ 360b4e9af9fSdanielk1977 } 3617617e4a8Smistachkin static int SQLITE_TCLAPI incrblobHandle( 3627617e4a8Smistachkin ClientData instanceData, 3637617e4a8Smistachkin int dir, 3647617e4a8Smistachkin ClientData *hPtr 3657617e4a8Smistachkin ){ 366b4e9af9fSdanielk1977 return TCL_ERROR; 367b4e9af9fSdanielk1977 } 368b4e9af9fSdanielk1977 369b4e9af9fSdanielk1977 static Tcl_ChannelType IncrblobChannelType = { 370b4e9af9fSdanielk1977 "incrblob", /* typeName */ 371b4e9af9fSdanielk1977 TCL_CHANNEL_VERSION_2, /* version */ 372b4e9af9fSdanielk1977 incrblobClose, /* closeProc */ 373b4e9af9fSdanielk1977 incrblobInput, /* inputProc */ 374b4e9af9fSdanielk1977 incrblobOutput, /* outputProc */ 375b4e9af9fSdanielk1977 incrblobSeek, /* seekProc */ 376b4e9af9fSdanielk1977 0, /* setOptionProc */ 377b4e9af9fSdanielk1977 0, /* getOptionProc */ 378b4e9af9fSdanielk1977 incrblobWatch, /* watchProc (this is a no-op) */ 379b4e9af9fSdanielk1977 incrblobHandle, /* getHandleProc (always returns error) */ 380b4e9af9fSdanielk1977 0, /* close2Proc */ 381b4e9af9fSdanielk1977 0, /* blockModeProc */ 382b4e9af9fSdanielk1977 0, /* flushProc */ 383b4e9af9fSdanielk1977 0, /* handlerProc */ 384b4e9af9fSdanielk1977 0, /* wideSeekProc */ 385b4e9af9fSdanielk1977 }; 386b4e9af9fSdanielk1977 387b4e9af9fSdanielk1977 /* 388b4e9af9fSdanielk1977 ** Create a new incrblob channel. 389b4e9af9fSdanielk1977 */ 390b4e9af9fSdanielk1977 static int createIncrblobChannel( 391b4e9af9fSdanielk1977 Tcl_Interp *interp, 392b4e9af9fSdanielk1977 SqliteDb *pDb, 393b4e9af9fSdanielk1977 const char *zDb, 394b4e9af9fSdanielk1977 const char *zTable, 395b4e9af9fSdanielk1977 const char *zColumn, 3968cbadb02Sdanielk1977 sqlite_int64 iRow, 3978cbadb02Sdanielk1977 int isReadonly 398b4e9af9fSdanielk1977 ){ 399b4e9af9fSdanielk1977 IncrblobChannel *p; 4008cbadb02Sdanielk1977 sqlite3 *db = pDb->db; 401b4e9af9fSdanielk1977 sqlite3_blob *pBlob; 402b4e9af9fSdanielk1977 int rc; 4038cbadb02Sdanielk1977 int flags = TCL_READABLE|(isReadonly ? 0 : TCL_WRITABLE); 404b4e9af9fSdanielk1977 405b4e9af9fSdanielk1977 /* This variable is used to name the channels: "incrblob_[incr count]" */ 406b4e9af9fSdanielk1977 static int count = 0; 407b4e9af9fSdanielk1977 char zChannel[64]; 408b4e9af9fSdanielk1977 4098cbadb02Sdanielk1977 rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob); 410b4e9af9fSdanielk1977 if( rc!=SQLITE_OK ){ 411b4e9af9fSdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 412b4e9af9fSdanielk1977 return TCL_ERROR; 413b4e9af9fSdanielk1977 } 414b4e9af9fSdanielk1977 415b4e9af9fSdanielk1977 p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel)); 416b4e9af9fSdanielk1977 p->iSeek = 0; 417b4e9af9fSdanielk1977 p->pBlob = pBlob; 418b4e9af9fSdanielk1977 4195bb3eb9bSdrh sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count); 420d0441796Sdanielk1977 p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags); 421d0441796Sdanielk1977 Tcl_RegisterChannel(interp, p->channel); 422b4e9af9fSdanielk1977 423d0441796Sdanielk1977 /* Link the new channel into the SqliteDb.pIncrblob list. */ 424d0441796Sdanielk1977 p->pNext = pDb->pIncrblob; 425d0441796Sdanielk1977 p->pPrev = 0; 426d0441796Sdanielk1977 if( p->pNext ){ 427d0441796Sdanielk1977 p->pNext->pPrev = p; 428d0441796Sdanielk1977 } 429d0441796Sdanielk1977 pDb->pIncrblob = p; 430d0441796Sdanielk1977 p->pDb = pDb; 431d0441796Sdanielk1977 432d0441796Sdanielk1977 Tcl_SetResult(interp, (char *)Tcl_GetChannelName(p->channel), TCL_VOLATILE); 433b4e9af9fSdanielk1977 return TCL_OK; 434b4e9af9fSdanielk1977 } 43532a0d8bbSdanielk1977 #else /* else clause for "#ifndef SQLITE_OMIT_INCRBLOB" */ 43632a0d8bbSdanielk1977 #define closeIncrblobChannels(pDb) 43732a0d8bbSdanielk1977 #endif 438b4e9af9fSdanielk1977 4396d31316cSdrh /* 440d1e4733dSdrh ** Look at the script prefix in pCmd. We will be executing this script 441d1e4733dSdrh ** after first appending one or more arguments. This routine analyzes 442d1e4733dSdrh ** the script to see if it is safe to use Tcl_EvalObjv() on the script 443d1e4733dSdrh ** rather than the more general Tcl_EvalEx(). Tcl_EvalObjv() is much 444d1e4733dSdrh ** faster. 445d1e4733dSdrh ** 446d1e4733dSdrh ** Scripts that are safe to use with Tcl_EvalObjv() consists of a 447d1e4733dSdrh ** command name followed by zero or more arguments with no [...] or $ 448d1e4733dSdrh ** or {...} or ; to be seen anywhere. Most callback scripts consist 449d1e4733dSdrh ** of just a single procedure name and they meet this requirement. 450d1e4733dSdrh */ 451d1e4733dSdrh static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){ 452d1e4733dSdrh /* We could try to do something with Tcl_Parse(). But we will instead 453d1e4733dSdrh ** just do a search for forbidden characters. If any of the forbidden 454d1e4733dSdrh ** characters appear in pCmd, we will report the string as unsafe. 455d1e4733dSdrh */ 456d1e4733dSdrh const char *z; 457d1e4733dSdrh int n; 458d1e4733dSdrh z = Tcl_GetStringFromObj(pCmd, &n); 459d1e4733dSdrh while( n-- > 0 ){ 460d1e4733dSdrh int c = *(z++); 461d1e4733dSdrh if( c=='$' || c=='[' || c==';' ) return 0; 462d1e4733dSdrh } 463d1e4733dSdrh return 1; 464d1e4733dSdrh } 465d1e4733dSdrh 466d1e4733dSdrh /* 467d1e4733dSdrh ** Find an SqlFunc structure with the given name. Or create a new 468d1e4733dSdrh ** one if an existing one cannot be found. Return a pointer to the 469d1e4733dSdrh ** structure. 470d1e4733dSdrh */ 471d1e4733dSdrh static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ 472d1e4733dSdrh SqlFunc *p, *pNew; 4730425f189Sdrh int nName = strlen30(zName); 4740425f189Sdrh pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 ); 475d1e4733dSdrh pNew->zName = (char*)&pNew[1]; 4760425f189Sdrh memcpy(pNew->zName, zName, nName+1); 477d1e4733dSdrh for(p=pDb->pFunc; p; p=p->pNext){ 4780425f189Sdrh if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){ 479d1e4733dSdrh Tcl_Free((char*)pNew); 480d1e4733dSdrh return p; 481d1e4733dSdrh } 482d1e4733dSdrh } 483d1e4733dSdrh pNew->interp = pDb->interp; 484c45e6716Sdrh pNew->pDb = pDb; 485d1e4733dSdrh pNew->pScript = 0; 486d1e4733dSdrh pNew->pNext = pDb->pFunc; 487d1e4733dSdrh pDb->pFunc = pNew; 488d1e4733dSdrh return pNew; 489d1e4733dSdrh } 490d1e4733dSdrh 491d1e4733dSdrh /* 492c431fd55Sdan ** Free a single SqlPreparedStmt object. 493c431fd55Sdan */ 494c431fd55Sdan static void dbFreeStmt(SqlPreparedStmt *pStmt){ 495c431fd55Sdan #ifdef SQLITE_TEST 496c431fd55Sdan if( sqlite3_sql(pStmt->pStmt)==0 ){ 497c431fd55Sdan Tcl_Free((char *)pStmt->zSql); 498c431fd55Sdan } 499c431fd55Sdan #endif 500c431fd55Sdan sqlite3_finalize(pStmt->pStmt); 501c431fd55Sdan Tcl_Free((char *)pStmt); 502c431fd55Sdan } 503c431fd55Sdan 504c431fd55Sdan /* 505fb7e7651Sdrh ** Finalize and free a list of prepared statements 506fb7e7651Sdrh */ 507fb7e7651Sdrh static void flushStmtCache(SqliteDb *pDb){ 508fb7e7651Sdrh SqlPreparedStmt *pPreStmt; 509c431fd55Sdan SqlPreparedStmt *pNext; 510fb7e7651Sdrh 511c431fd55Sdan for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pNext){ 512c431fd55Sdan pNext = pPreStmt->pNext; 513c431fd55Sdan dbFreeStmt(pPreStmt); 514fb7e7651Sdrh } 515fb7e7651Sdrh pDb->nStmt = 0; 516fb7e7651Sdrh pDb->stmtLast = 0; 517c431fd55Sdan pDb->stmtList = 0; 518fb7e7651Sdrh } 519fb7e7651Sdrh 520fb7e7651Sdrh /* 521895d7472Sdrh ** TCL calls this procedure when an sqlite3 database command is 522895d7472Sdrh ** deleted. 52375897234Sdrh */ 5247617e4a8Smistachkin static void SQLITE_TCLAPI DbDeleteCmd(void *db){ 525bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)db; 526fb7e7651Sdrh flushStmtCache(pDb); 527d0441796Sdanielk1977 closeIncrblobChannels(pDb); 5286f8a503dSdanielk1977 sqlite3_close(pDb->db); 529cabb0819Sdrh while( pDb->pFunc ){ 530cabb0819Sdrh SqlFunc *pFunc = pDb->pFunc; 531cabb0819Sdrh pDb->pFunc = pFunc->pNext; 532c45e6716Sdrh assert( pFunc->pDb==pDb ); 533d1e4733dSdrh Tcl_DecrRefCount(pFunc->pScript); 534cabb0819Sdrh Tcl_Free((char*)pFunc); 535cabb0819Sdrh } 5360202b29eSdanielk1977 while( pDb->pCollate ){ 5370202b29eSdanielk1977 SqlCollate *pCollate = pDb->pCollate; 5380202b29eSdanielk1977 pDb->pCollate = pCollate->pNext; 5390202b29eSdanielk1977 Tcl_Free((char*)pCollate); 5400202b29eSdanielk1977 } 541bec3f402Sdrh if( pDb->zBusy ){ 542bec3f402Sdrh Tcl_Free(pDb->zBusy); 543bec3f402Sdrh } 544b5a20d3cSdrh if( pDb->zTrace ){ 545b5a20d3cSdrh Tcl_Free(pDb->zTrace); 5460d1a643aSdrh } 547b56660f5Smistachkin if( pDb->zTraceV2 ){ 548b56660f5Smistachkin Tcl_Free(pDb->zTraceV2); 549b56660f5Smistachkin } 55019e2d37fSdrh if( pDb->zProfile ){ 55119e2d37fSdrh Tcl_Free(pDb->zProfile); 55219e2d37fSdrh } 553c06ede10Sdrh if( pDb->zBindFallback ){ 554c06ede10Sdrh Tcl_Free(pDb->zBindFallback); 555c06ede10Sdrh } 556e22a334bSdrh if( pDb->zAuth ){ 557e22a334bSdrh Tcl_Free(pDb->zAuth); 558e22a334bSdrh } 55955c45f2eSdanielk1977 if( pDb->zNull ){ 56055c45f2eSdanielk1977 Tcl_Free(pDb->zNull); 56155c45f2eSdanielk1977 } 56294eb6a14Sdanielk1977 if( pDb->pUpdateHook ){ 56394eb6a14Sdanielk1977 Tcl_DecrRefCount(pDb->pUpdateHook); 56494eb6a14Sdanielk1977 } 56546c47d46Sdan if( pDb->pPreUpdateHook ){ 56646c47d46Sdan Tcl_DecrRefCount(pDb->pPreUpdateHook); 56746c47d46Sdan } 56871fd80bfSdanielk1977 if( pDb->pRollbackHook ){ 56971fd80bfSdanielk1977 Tcl_DecrRefCount(pDb->pRollbackHook); 57071fd80bfSdanielk1977 } 5715def0843Sdrh if( pDb->pWalHook ){ 5725def0843Sdrh Tcl_DecrRefCount(pDb->pWalHook); 5738d22a174Sdan } 57494eb6a14Sdanielk1977 if( pDb->pCollateNeeded ){ 57594eb6a14Sdanielk1977 Tcl_DecrRefCount(pDb->pCollateNeeded); 57694eb6a14Sdanielk1977 } 577bec3f402Sdrh Tcl_Free((char*)pDb); 578bec3f402Sdrh } 579bec3f402Sdrh 580bec3f402Sdrh /* 581bec3f402Sdrh ** This routine is called when a database file is locked while trying 582bec3f402Sdrh ** to execute SQL. 583bec3f402Sdrh */ 5842a764eb0Sdanielk1977 static int DbBusyHandler(void *cd, int nTries){ 585bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 586bec3f402Sdrh int rc; 587bec3f402Sdrh char zVal[30]; 588bec3f402Sdrh 5895bb3eb9bSdrh sqlite3_snprintf(sizeof(zVal), zVal, "%d", nTries); 590d1e4733dSdrh rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0); 591bec3f402Sdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 592bec3f402Sdrh return 0; 593bec3f402Sdrh } 594bec3f402Sdrh return 1; 59575897234Sdrh } 59675897234Sdrh 59726e4a8b1Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK 59875897234Sdrh /* 599348bb5d6Sdanielk1977 ** This routine is invoked as the 'progress callback' for the database. 600348bb5d6Sdanielk1977 */ 601348bb5d6Sdanielk1977 static int DbProgressHandler(void *cd){ 602348bb5d6Sdanielk1977 SqliteDb *pDb = (SqliteDb*)cd; 603348bb5d6Sdanielk1977 int rc; 604348bb5d6Sdanielk1977 605348bb5d6Sdanielk1977 assert( pDb->zProgress ); 606348bb5d6Sdanielk1977 rc = Tcl_Eval(pDb->interp, pDb->zProgress); 607348bb5d6Sdanielk1977 if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 608348bb5d6Sdanielk1977 return 1; 609348bb5d6Sdanielk1977 } 610348bb5d6Sdanielk1977 return 0; 611348bb5d6Sdanielk1977 } 61226e4a8b1Sdrh #endif 613348bb5d6Sdanielk1977 6142eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 6152eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 616348bb5d6Sdanielk1977 /* 617b5a20d3cSdrh ** This routine is called by the SQLite trace handler whenever a new 618b5a20d3cSdrh ** block of SQL is executed. The TCL script in pDb->zTrace is executed. 6190d1a643aSdrh */ 620b5a20d3cSdrh static void DbTraceHandler(void *cd, const char *zSql){ 6210d1a643aSdrh SqliteDb *pDb = (SqliteDb*)cd; 622b5a20d3cSdrh Tcl_DString str; 6230d1a643aSdrh 624b5a20d3cSdrh Tcl_DStringInit(&str); 625b5a20d3cSdrh Tcl_DStringAppend(&str, pDb->zTrace, -1); 626b5a20d3cSdrh Tcl_DStringAppendElement(&str, zSql); 627b5a20d3cSdrh Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); 628b5a20d3cSdrh Tcl_DStringFree(&str); 629b5a20d3cSdrh Tcl_ResetResult(pDb->interp); 6300d1a643aSdrh } 631d1167393Sdrh #endif 6320d1a643aSdrh 633d1167393Sdrh #ifndef SQLITE_OMIT_TRACE 6340d1a643aSdrh /* 635b56660f5Smistachkin ** This routine is called by the SQLite trace_v2 handler whenever a new 636b56660f5Smistachkin ** supported event is generated. Unsupported event types are ignored. 637b56660f5Smistachkin ** The TCL script in pDb->zTraceV2 is executed, with the arguments for 638b56660f5Smistachkin ** the event appended to it (as list elements). 639b56660f5Smistachkin */ 640b56660f5Smistachkin static int DbTraceV2Handler( 641b56660f5Smistachkin unsigned type, /* One of the SQLITE_TRACE_* event types. */ 642b56660f5Smistachkin void *cd, /* The original context data pointer. */ 643b56660f5Smistachkin void *pd, /* Primary event data, depends on event type. */ 644b56660f5Smistachkin void *xd /* Extra event data, depends on event type. */ 645b56660f5Smistachkin ){ 646b56660f5Smistachkin SqliteDb *pDb = (SqliteDb*)cd; 647b56660f5Smistachkin Tcl_Obj *pCmd; 648b56660f5Smistachkin 649b56660f5Smistachkin switch( type ){ 650b56660f5Smistachkin case SQLITE_TRACE_STMT: { 651b56660f5Smistachkin sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; 652b56660f5Smistachkin char *zSql = (char *)xd; 653b56660f5Smistachkin 654b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 655b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 656b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 657b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); 658b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 659b56660f5Smistachkin Tcl_NewStringObj(zSql, -1)); 660b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 661b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 662b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 663b56660f5Smistachkin break; 664b56660f5Smistachkin } 665b56660f5Smistachkin case SQLITE_TRACE_PROFILE: { 666b56660f5Smistachkin sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; 667ffdab721Sdrh sqlite3_int64 ns = *(sqlite3_int64*)xd; 668b56660f5Smistachkin 669b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 670b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 671b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 672b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); 673b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 674b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)ns)); 675b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 676b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 677b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 678b56660f5Smistachkin break; 679b56660f5Smistachkin } 680b56660f5Smistachkin case SQLITE_TRACE_ROW: { 681b56660f5Smistachkin sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; 682b56660f5Smistachkin 683b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 684b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 685b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 686b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); 687b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 688b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 689b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 690b56660f5Smistachkin break; 691b56660f5Smistachkin } 692b56660f5Smistachkin case SQLITE_TRACE_CLOSE: { 693b56660f5Smistachkin sqlite3 *db = (sqlite3 *)pd; 694b56660f5Smistachkin 695b56660f5Smistachkin pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); 696b56660f5Smistachkin Tcl_IncrRefCount(pCmd); 697b56660f5Smistachkin Tcl_ListObjAppendElement(pDb->interp, pCmd, 698b56660f5Smistachkin Tcl_NewWideIntObj((Tcl_WideInt)db)); 699b56660f5Smistachkin Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 700b56660f5Smistachkin Tcl_DecrRefCount(pCmd); 701b56660f5Smistachkin Tcl_ResetResult(pDb->interp); 702b56660f5Smistachkin break; 703b56660f5Smistachkin } 704b56660f5Smistachkin } 705b56660f5Smistachkin return SQLITE_OK; 706b56660f5Smistachkin } 707b56660f5Smistachkin #endif 708b56660f5Smistachkin 7092eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 7102eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 711b56660f5Smistachkin /* 71219e2d37fSdrh ** This routine is called by the SQLite profile handler after a statement 71319e2d37fSdrh ** SQL has executed. The TCL script in pDb->zProfile is evaluated. 71419e2d37fSdrh */ 71519e2d37fSdrh static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){ 71619e2d37fSdrh SqliteDb *pDb = (SqliteDb*)cd; 71719e2d37fSdrh Tcl_DString str; 71819e2d37fSdrh char zTm[100]; 71919e2d37fSdrh 72019e2d37fSdrh sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm); 72119e2d37fSdrh Tcl_DStringInit(&str); 72219e2d37fSdrh Tcl_DStringAppend(&str, pDb->zProfile, -1); 72319e2d37fSdrh Tcl_DStringAppendElement(&str, zSql); 72419e2d37fSdrh Tcl_DStringAppendElement(&str, zTm); 72519e2d37fSdrh Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); 72619e2d37fSdrh Tcl_DStringFree(&str); 72719e2d37fSdrh Tcl_ResetResult(pDb->interp); 72819e2d37fSdrh } 729d1167393Sdrh #endif 73019e2d37fSdrh 73119e2d37fSdrh /* 732aa940eacSdrh ** This routine is called when a transaction is committed. The 733aa940eacSdrh ** TCL script in pDb->zCommit is executed. If it returns non-zero or 734aa940eacSdrh ** if it throws an exception, the transaction is rolled back instead 735aa940eacSdrh ** of being committed. 736aa940eacSdrh */ 737aa940eacSdrh static int DbCommitHandler(void *cd){ 738aa940eacSdrh SqliteDb *pDb = (SqliteDb*)cd; 739aa940eacSdrh int rc; 740aa940eacSdrh 741aa940eacSdrh rc = Tcl_Eval(pDb->interp, pDb->zCommit); 742aa940eacSdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 743aa940eacSdrh return 1; 744aa940eacSdrh } 745aa940eacSdrh return 0; 746aa940eacSdrh } 747aa940eacSdrh 74871fd80bfSdanielk1977 static void DbRollbackHandler(void *clientData){ 74971fd80bfSdanielk1977 SqliteDb *pDb = (SqliteDb*)clientData; 75071fd80bfSdanielk1977 assert(pDb->pRollbackHook); 75171fd80bfSdanielk1977 if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){ 75271fd80bfSdanielk1977 Tcl_BackgroundError(pDb->interp); 75371fd80bfSdanielk1977 } 75471fd80bfSdanielk1977 } 75571fd80bfSdanielk1977 7565def0843Sdrh /* 7575def0843Sdrh ** This procedure handles wal_hook callbacks. 7585def0843Sdrh */ 7595def0843Sdrh static int DbWalHandler( 7608d22a174Sdan void *clientData, 7618d22a174Sdan sqlite3 *db, 7628d22a174Sdan const char *zDb, 7638d22a174Sdan int nEntry 7648d22a174Sdan ){ 7655def0843Sdrh int ret = SQLITE_OK; 7668d22a174Sdan Tcl_Obj *p; 7678d22a174Sdan SqliteDb *pDb = (SqliteDb*)clientData; 7688d22a174Sdan Tcl_Interp *interp = pDb->interp; 7695def0843Sdrh assert(pDb->pWalHook); 7708d22a174Sdan 7716e45e0c8Sdan assert( db==pDb->db ); 7725def0843Sdrh p = Tcl_DuplicateObj(pDb->pWalHook); 7738d22a174Sdan Tcl_IncrRefCount(p); 7748d22a174Sdan Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1)); 7758d22a174Sdan Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry)); 7768d22a174Sdan if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0) 7778d22a174Sdan || TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret) 7788d22a174Sdan ){ 7798d22a174Sdan Tcl_BackgroundError(interp); 7808d22a174Sdan } 7818d22a174Sdan Tcl_DecrRefCount(p); 7828d22a174Sdan 7838d22a174Sdan return ret; 7848d22a174Sdan } 7858d22a174Sdan 786bcf4f484Sdrh #if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) 787404ca075Sdanielk1977 static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){ 788404ca075Sdanielk1977 char zBuf[64]; 78965545b59Sdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iArg); 790404ca075Sdanielk1977 Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY); 79165545b59Sdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nArg); 792404ca075Sdanielk1977 Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY); 793404ca075Sdanielk1977 } 794404ca075Sdanielk1977 #else 795404ca075Sdanielk1977 # define setTestUnlockNotifyVars(x,y,z) 796404ca075Sdanielk1977 #endif 797404ca075Sdanielk1977 79869910da9Sdrh #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY 799404ca075Sdanielk1977 static void DbUnlockNotify(void **apArg, int nArg){ 800404ca075Sdanielk1977 int i; 801404ca075Sdanielk1977 for(i=0; i<nArg; i++){ 802404ca075Sdanielk1977 const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); 803404ca075Sdanielk1977 SqliteDb *pDb = (SqliteDb *)apArg[i]; 804404ca075Sdanielk1977 setTestUnlockNotifyVars(pDb->interp, i, nArg); 805404ca075Sdanielk1977 assert( pDb->pUnlockNotify); 806404ca075Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pDb->pUnlockNotify, flags); 807404ca075Sdanielk1977 Tcl_DecrRefCount(pDb->pUnlockNotify); 808404ca075Sdanielk1977 pDb->pUnlockNotify = 0; 809404ca075Sdanielk1977 } 810404ca075Sdanielk1977 } 81169910da9Sdrh #endif 812404ca075Sdanielk1977 8139b1c62d4Sdrh #ifdef SQLITE_ENABLE_PREUPDATE_HOOK 81446c47d46Sdan /* 81546c47d46Sdan ** Pre-update hook callback. 81646c47d46Sdan */ 81746c47d46Sdan static void DbPreUpdateHandler( 81846c47d46Sdan void *p, 81946c47d46Sdan sqlite3 *db, 82046c47d46Sdan int op, 82146c47d46Sdan const char *zDb, 82246c47d46Sdan const char *zTbl, 82346c47d46Sdan sqlite_int64 iKey1, 82446c47d46Sdan sqlite_int64 iKey2 82546c47d46Sdan ){ 82646c47d46Sdan SqliteDb *pDb = (SqliteDb *)p; 82746c47d46Sdan Tcl_Obj *pCmd; 82846c47d46Sdan static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"}; 82946c47d46Sdan 83046c47d46Sdan assert( (SQLITE_DELETE-1)/9 == 0 ); 83146c47d46Sdan assert( (SQLITE_INSERT-1)/9 == 1 ); 83246c47d46Sdan assert( (SQLITE_UPDATE-1)/9 == 2 ); 83346c47d46Sdan assert( pDb->pPreUpdateHook ); 83446c47d46Sdan assert( db==pDb->db ); 83546c47d46Sdan assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); 83646c47d46Sdan 83746c47d46Sdan pCmd = Tcl_DuplicateObj(pDb->pPreUpdateHook); 83846c47d46Sdan Tcl_IncrRefCount(pCmd); 83946c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(azStr[(op-1)/9], -1)); 84046c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1)); 84146c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1)); 84246c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey1)); 84346c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey2)); 84446c47d46Sdan Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 84546c47d46Sdan Tcl_DecrRefCount(pCmd); 84646c47d46Sdan } 8479b1c62d4Sdrh #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ 84846c47d46Sdan 84994eb6a14Sdanielk1977 static void DbUpdateHandler( 85094eb6a14Sdanielk1977 void *p, 85194eb6a14Sdanielk1977 int op, 85294eb6a14Sdanielk1977 const char *zDb, 85394eb6a14Sdanielk1977 const char *zTbl, 85494eb6a14Sdanielk1977 sqlite_int64 rowid 85594eb6a14Sdanielk1977 ){ 85694eb6a14Sdanielk1977 SqliteDb *pDb = (SqliteDb *)p; 85794eb6a14Sdanielk1977 Tcl_Obj *pCmd; 85846c47d46Sdan static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"}; 85946c47d46Sdan 86046c47d46Sdan assert( (SQLITE_DELETE-1)/9 == 0 ); 86146c47d46Sdan assert( (SQLITE_INSERT-1)/9 == 1 ); 86246c47d46Sdan assert( (SQLITE_UPDATE-1)/9 == 2 ); 86394eb6a14Sdanielk1977 86494eb6a14Sdanielk1977 assert( pDb->pUpdateHook ); 86594eb6a14Sdanielk1977 assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); 86694eb6a14Sdanielk1977 86794eb6a14Sdanielk1977 pCmd = Tcl_DuplicateObj(pDb->pUpdateHook); 86894eb6a14Sdanielk1977 Tcl_IncrRefCount(pCmd); 86946c47d46Sdan Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(azStr[(op-1)/9], -1)); 87094eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1)); 87194eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1)); 87294eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid)); 87394eb6a14Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 874efdde169Sdrh Tcl_DecrRefCount(pCmd); 87594eb6a14Sdanielk1977 } 87694eb6a14Sdanielk1977 8777cedc8d4Sdanielk1977 static void tclCollateNeeded( 8787cedc8d4Sdanielk1977 void *pCtx, 8799bb575fdSdrh sqlite3 *db, 8807cedc8d4Sdanielk1977 int enc, 8817cedc8d4Sdanielk1977 const char *zName 8827cedc8d4Sdanielk1977 ){ 8837cedc8d4Sdanielk1977 SqliteDb *pDb = (SqliteDb *)pCtx; 8847cedc8d4Sdanielk1977 Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded); 8857cedc8d4Sdanielk1977 Tcl_IncrRefCount(pScript); 8867cedc8d4Sdanielk1977 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1)); 8877cedc8d4Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pScript, 0); 8887cedc8d4Sdanielk1977 Tcl_DecrRefCount(pScript); 8897cedc8d4Sdanielk1977 } 8907cedc8d4Sdanielk1977 891aa940eacSdrh /* 8920202b29eSdanielk1977 ** This routine is called to evaluate an SQL collation function implemented 8930202b29eSdanielk1977 ** using TCL script. 8940202b29eSdanielk1977 */ 8950202b29eSdanielk1977 static int tclSqlCollate( 8960202b29eSdanielk1977 void *pCtx, 8970202b29eSdanielk1977 int nA, 8980202b29eSdanielk1977 const void *zA, 8990202b29eSdanielk1977 int nB, 9000202b29eSdanielk1977 const void *zB 9010202b29eSdanielk1977 ){ 9020202b29eSdanielk1977 SqlCollate *p = (SqlCollate *)pCtx; 9030202b29eSdanielk1977 Tcl_Obj *pCmd; 9040202b29eSdanielk1977 9050202b29eSdanielk1977 pCmd = Tcl_NewStringObj(p->zScript, -1); 9060202b29eSdanielk1977 Tcl_IncrRefCount(pCmd); 9070202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA)); 9080202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB)); 909d1e4733dSdrh Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); 9100202b29eSdanielk1977 Tcl_DecrRefCount(pCmd); 9110202b29eSdanielk1977 return (atoi(Tcl_GetStringResult(p->interp))); 9120202b29eSdanielk1977 } 9130202b29eSdanielk1977 9140202b29eSdanielk1977 /* 915cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented 916cabb0819Sdrh ** using TCL script. 917cabb0819Sdrh */ 9180ae8b831Sdanielk1977 static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ 9196f8a503dSdanielk1977 SqlFunc *p = sqlite3_user_data(context); 920d1e4733dSdrh Tcl_Obj *pCmd; 921cabb0819Sdrh int i; 922cabb0819Sdrh int rc; 923cabb0819Sdrh 924d1e4733dSdrh if( argc==0 ){ 925d1e4733dSdrh /* If there are no arguments to the function, call Tcl_EvalObjEx on the 926d1e4733dSdrh ** script object directly. This allows the TCL compiler to generate 927d1e4733dSdrh ** bytecode for the command on the first invocation and thus make 928d1e4733dSdrh ** subsequent invocations much faster. */ 929d1e4733dSdrh pCmd = p->pScript; 930d1e4733dSdrh Tcl_IncrRefCount(pCmd); 931d1e4733dSdrh rc = Tcl_EvalObjEx(p->interp, pCmd, 0); 932d1e4733dSdrh Tcl_DecrRefCount(pCmd); 93351ad0ecdSdanielk1977 }else{ 934d1e4733dSdrh /* If there are arguments to the function, make a shallow copy of the 935d1e4733dSdrh ** script object, lappend the arguments, then evaluate the copy. 936d1e4733dSdrh ** 93760ec914cSpeter.d.reid ** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated. 938d1e4733dSdrh ** The new Tcl_Obj contains pointers to the original list elements. 939d1e4733dSdrh ** That way, when Tcl_EvalObjv() is run and shimmers the first element 940d1e4733dSdrh ** of the list to tclCmdNameType, that alternate representation will 941d1e4733dSdrh ** be preserved and reused on the next invocation. 942d1e4733dSdrh */ 943d1e4733dSdrh Tcl_Obj **aArg; 944d1e4733dSdrh int nArg; 945d1e4733dSdrh if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){ 946d1e4733dSdrh sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 947d1e4733dSdrh return; 948d1e4733dSdrh } 949d1e4733dSdrh pCmd = Tcl_NewListObj(nArg, aArg); 950d1e4733dSdrh Tcl_IncrRefCount(pCmd); 951d1e4733dSdrh for(i=0; i<argc; i++){ 952d1e4733dSdrh sqlite3_value *pIn = argv[i]; 953d1e4733dSdrh Tcl_Obj *pVal; 954d1e4733dSdrh 955d1e4733dSdrh /* Set pVal to contain the i'th column of this row. */ 956d1e4733dSdrh switch( sqlite3_value_type(pIn) ){ 957d1e4733dSdrh case SQLITE_BLOB: { 958d1e4733dSdrh int bytes = sqlite3_value_bytes(pIn); 959d1e4733dSdrh pVal = Tcl_NewByteArrayObj(sqlite3_value_blob(pIn), bytes); 960d1e4733dSdrh break; 961d1e4733dSdrh } 962d1e4733dSdrh case SQLITE_INTEGER: { 963d1e4733dSdrh sqlite_int64 v = sqlite3_value_int64(pIn); 964d1e4733dSdrh if( v>=-2147483647 && v<=2147483647 ){ 9657fd33929Sdrh pVal = Tcl_NewIntObj((int)v); 966d1e4733dSdrh }else{ 967d1e4733dSdrh pVal = Tcl_NewWideIntObj(v); 968d1e4733dSdrh } 969d1e4733dSdrh break; 970d1e4733dSdrh } 971d1e4733dSdrh case SQLITE_FLOAT: { 972d1e4733dSdrh double r = sqlite3_value_double(pIn); 973d1e4733dSdrh pVal = Tcl_NewDoubleObj(r); 974d1e4733dSdrh break; 975d1e4733dSdrh } 976d1e4733dSdrh case SQLITE_NULL: { 977c45e6716Sdrh pVal = Tcl_NewStringObj(p->pDb->zNull, -1); 978d1e4733dSdrh break; 979d1e4733dSdrh } 980d1e4733dSdrh default: { 981d1e4733dSdrh int bytes = sqlite3_value_bytes(pIn); 98200fd957bSdanielk1977 pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes); 983d1e4733dSdrh break; 98451ad0ecdSdanielk1977 } 985cabb0819Sdrh } 986d1e4733dSdrh rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal); 987d1e4733dSdrh if( rc ){ 988d1e4733dSdrh Tcl_DecrRefCount(pCmd); 989d1e4733dSdrh sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 990d1e4733dSdrh return; 991d1e4733dSdrh } 992d1e4733dSdrh } 993d1e4733dSdrh if( !p->useEvalObjv ){ 994d1e4733dSdrh /* Tcl_EvalObjEx() will automatically call Tcl_EvalObjv() if pCmd 995d1e4733dSdrh ** is a list without a string representation. To prevent this from 996d1e4733dSdrh ** happening, make sure pCmd has a valid string representation */ 997d1e4733dSdrh Tcl_GetString(pCmd); 998d1e4733dSdrh } 999d1e4733dSdrh rc = Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); 1000d1e4733dSdrh Tcl_DecrRefCount(pCmd); 1001d1e4733dSdrh } 1002562e8d3cSdanielk1977 1003c7f269d5Sdrh if( rc && rc!=TCL_RETURN ){ 10047e18c259Sdanielk1977 sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 1005cabb0819Sdrh }else{ 1006c7f269d5Sdrh Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); 1007c7f269d5Sdrh int n; 1008c7f269d5Sdrh u8 *data; 10094a4c11aaSdan const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); 1010c7f269d5Sdrh char c = zType[0]; 101189d24936Sdan int eType = p->eType; 101289d24936Sdan 101389d24936Sdan if( eType==SQLITE_NULL ){ 1014df0bddaeSdrh if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ 1015d1e4733dSdrh /* Only return a BLOB type if the Tcl variable is a bytearray and 1016df0bddaeSdrh ** has no string representation. */ 101789d24936Sdan eType = SQLITE_BLOB; 101889d24936Sdan }else if( (c=='b' && strcmp(zType,"boolean")==0) 101989d24936Sdan || (c=='w' && strcmp(zType,"wideInt")==0) 102089d24936Sdan || (c=='i' && strcmp(zType,"int")==0) 102189d24936Sdan ){ 102289d24936Sdan eType = SQLITE_INTEGER; 102389d24936Sdan }else if( c=='d' && strcmp(zType,"double")==0 ){ 102489d24936Sdan eType = SQLITE_FLOAT; 102589d24936Sdan }else{ 102689d24936Sdan eType = SQLITE_TEXT; 102789d24936Sdan } 102889d24936Sdan } 102989d24936Sdan 103089d24936Sdan switch( eType ){ 103189d24936Sdan case SQLITE_BLOB: { 1032c7f269d5Sdrh data = Tcl_GetByteArrayFromObj(pVar, &n); 1033c7f269d5Sdrh sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT); 103489d24936Sdan break; 103589d24936Sdan } 103689d24936Sdan case SQLITE_INTEGER: { 1037df0bddaeSdrh Tcl_WideInt v; 103889d24936Sdan if( TCL_OK==Tcl_GetWideIntFromObj(0, pVar, &v) ){ 1039df0bddaeSdrh sqlite3_result_int64(context, v); 104089d24936Sdan break; 104189d24936Sdan } 104289d24936Sdan /* fall-through */ 104389d24936Sdan } 104489d24936Sdan case SQLITE_FLOAT: { 104589d24936Sdan double r; 104689d24936Sdan if( TCL_OK==Tcl_GetDoubleFromObj(0, pVar, &r) ){ 104789d24936Sdan sqlite3_result_double(context, r); 104889d24936Sdan break; 104989d24936Sdan } 105089d24936Sdan /* fall-through */ 105189d24936Sdan } 105289d24936Sdan default: { 105300fd957bSdanielk1977 data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); 105400fd957bSdanielk1977 sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT); 105589d24936Sdan break; 1056c7f269d5Sdrh } 1057cabb0819Sdrh } 105889d24936Sdan 105989d24936Sdan } 1060cabb0819Sdrh } 1061895d7472Sdrh 1062e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION 1063e22a334bSdrh /* 1064e22a334bSdrh ** This is the authentication function. It appends the authentication 1065e22a334bSdrh ** type code and the two arguments to zCmd[] then invokes the result 1066e22a334bSdrh ** on the interpreter. The reply is examined to determine if the 1067e22a334bSdrh ** authentication fails or succeeds. 1068e22a334bSdrh */ 1069e22a334bSdrh static int auth_callback( 1070e22a334bSdrh void *pArg, 1071e22a334bSdrh int code, 1072e22a334bSdrh const char *zArg1, 1073e22a334bSdrh const char *zArg2, 1074e22a334bSdrh const char *zArg3, 1075e22a334bSdrh const char *zArg4 107632c6a48bSdrh #ifdef SQLITE_USER_AUTHENTICATION 107732c6a48bSdrh ,const char *zArg5 107832c6a48bSdrh #endif 1079e22a334bSdrh ){ 10806ef5e12eSmistachkin const char *zCode; 1081e22a334bSdrh Tcl_DString str; 1082e22a334bSdrh int rc; 1083e22a334bSdrh const char *zReply; 10849418921cSdrh /* EVIDENCE-OF: R-38590-62769 The first parameter to the authorizer 10859418921cSdrh ** callback is a copy of the third parameter to the 10869418921cSdrh ** sqlite3_set_authorizer() interface. 10879418921cSdrh */ 1088e22a334bSdrh SqliteDb *pDb = (SqliteDb*)pArg; 10891f1549f8Sdrh if( pDb->disableAuth ) return SQLITE_OK; 1090e22a334bSdrh 10919418921cSdrh /* EVIDENCE-OF: R-56518-44310 The second parameter to the callback is an 10929418921cSdrh ** integer action code that specifies the particular action to be 10939418921cSdrh ** authorized. */ 1094e22a334bSdrh switch( code ){ 1095e22a334bSdrh case SQLITE_COPY : zCode="SQLITE_COPY"; break; 1096e22a334bSdrh case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; 1097e22a334bSdrh case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; 1098e22a334bSdrh case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; 1099e22a334bSdrh case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; 1100e22a334bSdrh case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; 1101e22a334bSdrh case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; 1102e22a334bSdrh case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; 1103e22a334bSdrh case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; 1104e22a334bSdrh case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; 1105e22a334bSdrh case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; 1106e22a334bSdrh case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; 1107e22a334bSdrh case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; 1108e22a334bSdrh case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; 1109e22a334bSdrh case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; 1110e22a334bSdrh case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; 1111e22a334bSdrh case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; 1112e22a334bSdrh case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; 1113e22a334bSdrh case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; 1114e22a334bSdrh case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; 1115e22a334bSdrh case SQLITE_READ : zCode="SQLITE_READ"; break; 1116e22a334bSdrh case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; 1117e22a334bSdrh case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; 1118e22a334bSdrh case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; 111981e293b4Sdrh case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break; 112081e293b4Sdrh case SQLITE_DETACH : zCode="SQLITE_DETACH"; break; 11211c8c23ccSdanielk1977 case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; 11221d54df88Sdanielk1977 case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; 1123e6e04969Sdrh case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break; 1124f1a381e7Sdanielk1977 case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break; 1125f1a381e7Sdanielk1977 case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break; 11265169bbc6Sdrh case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break; 1127ab9b703fSdanielk1977 case SQLITE_SAVEPOINT : zCode="SQLITE_SAVEPOINT"; break; 112865a2aaa6Sdrh case SQLITE_RECURSIVE : zCode="SQLITE_RECURSIVE"; break; 1129e22a334bSdrh default : zCode="????"; break; 1130e22a334bSdrh } 1131e22a334bSdrh Tcl_DStringInit(&str); 1132e22a334bSdrh Tcl_DStringAppend(&str, pDb->zAuth, -1); 1133e22a334bSdrh Tcl_DStringAppendElement(&str, zCode); 1134e22a334bSdrh Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); 1135e22a334bSdrh Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); 1136e22a334bSdrh Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); 1137e22a334bSdrh Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); 113832c6a48bSdrh #ifdef SQLITE_USER_AUTHENTICATION 113932c6a48bSdrh Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : ""); 114032c6a48bSdrh #endif 1141e22a334bSdrh rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); 1142e22a334bSdrh Tcl_DStringFree(&str); 1143b07028f7Sdrh zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY"; 1144e22a334bSdrh if( strcmp(zReply,"SQLITE_OK")==0 ){ 1145e22a334bSdrh rc = SQLITE_OK; 1146e22a334bSdrh }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ 1147e22a334bSdrh rc = SQLITE_DENY; 1148e22a334bSdrh }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ 1149e22a334bSdrh rc = SQLITE_IGNORE; 1150e22a334bSdrh }else{ 1151e22a334bSdrh rc = 999; 1152e22a334bSdrh } 1153e22a334bSdrh return rc; 1154e22a334bSdrh } 1155e22a334bSdrh #endif /* SQLITE_OMIT_AUTHORIZATION */ 1156cabb0819Sdrh 1157cabb0819Sdrh /* 11581067fe11Stpoindex ** This routine reads a line of text from FILE in, stores 11591067fe11Stpoindex ** the text in memory obtained from malloc() and returns a pointer 11601067fe11Stpoindex ** to the text. NULL is returned at end of file, or if malloc() 11611067fe11Stpoindex ** fails. 11621067fe11Stpoindex ** 11631067fe11Stpoindex ** The interface is like "readline" but no command-line editing 11641067fe11Stpoindex ** is done. 11651067fe11Stpoindex ** 11661067fe11Stpoindex ** copied from shell.c from '.import' command 11671067fe11Stpoindex */ 11681067fe11Stpoindex static char *local_getline(char *zPrompt, FILE *in){ 11691067fe11Stpoindex char *zLine; 11701067fe11Stpoindex int nLine; 11711067fe11Stpoindex int n; 11721067fe11Stpoindex 11731067fe11Stpoindex nLine = 100; 11741067fe11Stpoindex zLine = malloc( nLine ); 11751067fe11Stpoindex if( zLine==0 ) return 0; 11761067fe11Stpoindex n = 0; 1177b07028f7Sdrh while( 1 ){ 11781067fe11Stpoindex if( n+100>nLine ){ 11791067fe11Stpoindex nLine = nLine*2 + 100; 11801067fe11Stpoindex zLine = realloc(zLine, nLine); 11811067fe11Stpoindex if( zLine==0 ) return 0; 11821067fe11Stpoindex } 11831067fe11Stpoindex if( fgets(&zLine[n], nLine - n, in)==0 ){ 11841067fe11Stpoindex if( n==0 ){ 11851067fe11Stpoindex free(zLine); 11861067fe11Stpoindex return 0; 11871067fe11Stpoindex } 11881067fe11Stpoindex zLine[n] = 0; 11891067fe11Stpoindex break; 11901067fe11Stpoindex } 11911067fe11Stpoindex while( zLine[n] ){ n++; } 11921067fe11Stpoindex if( n>0 && zLine[n-1]=='\n' ){ 11931067fe11Stpoindex n--; 11941067fe11Stpoindex zLine[n] = 0; 1195b07028f7Sdrh break; 11961067fe11Stpoindex } 11971067fe11Stpoindex } 11981067fe11Stpoindex zLine = realloc( zLine, n+1 ); 11991067fe11Stpoindex return zLine; 12001067fe11Stpoindex } 12011067fe11Stpoindex 12028e556520Sdanielk1977 12038e556520Sdanielk1977 /* 12044a4c11aaSdan ** This function is part of the implementation of the command: 12058e556520Sdanielk1977 ** 12064a4c11aaSdan ** $db transaction [-deferred|-immediate|-exclusive] SCRIPT 12078e556520Sdanielk1977 ** 12084a4c11aaSdan ** It is invoked after evaluating the script SCRIPT to commit or rollback 12094a4c11aaSdan ** the transaction or savepoint opened by the [transaction] command. 12104a4c11aaSdan */ 1211a121cc7cSmistachkin static int SQLITE_TCLAPI DbTransPostCmd( 12124a4c11aaSdan ClientData data[], /* data[0] is the Sqlite3Db* for $db */ 12134a4c11aaSdan Tcl_Interp *interp, /* Tcl interpreter */ 12144a4c11aaSdan int result /* Result of evaluating SCRIPT */ 12154a4c11aaSdan ){ 12166ef5e12eSmistachkin static const char *const azEnd[] = { 12174a4c11aaSdan "RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */ 12184a4c11aaSdan "COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */ 12194a4c11aaSdan "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction", 12204a4c11aaSdan "ROLLBACK" /* rc==TCL_ERROR, nTransaction==0 */ 12214a4c11aaSdan }; 12224a4c11aaSdan SqliteDb *pDb = (SqliteDb*)data[0]; 12234a4c11aaSdan int rc = result; 12244a4c11aaSdan const char *zEnd; 12254a4c11aaSdan 12264a4c11aaSdan pDb->nTransaction--; 12274a4c11aaSdan zEnd = azEnd[(rc==TCL_ERROR)*2 + (pDb->nTransaction==0)]; 12284a4c11aaSdan 12294a4c11aaSdan pDb->disableAuth++; 12304a4c11aaSdan if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){ 12314a4c11aaSdan /* This is a tricky scenario to handle. The most likely cause of an 12324a4c11aaSdan ** error is that the exec() above was an attempt to commit the 12334a4c11aaSdan ** top-level transaction that returned SQLITE_BUSY. Or, less likely, 123448864df9Smistachkin ** that an IO-error has occurred. In either case, throw a Tcl exception 12354a4c11aaSdan ** and try to rollback the transaction. 12364a4c11aaSdan ** 12374a4c11aaSdan ** But it could also be that the user executed one or more BEGIN, 12384a4c11aaSdan ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing 12394a4c11aaSdan ** this method's logic. Not clear how this would be best handled. 12404a4c11aaSdan */ 12414a4c11aaSdan if( rc!=TCL_ERROR ){ 1242a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 12434a4c11aaSdan rc = TCL_ERROR; 12444a4c11aaSdan } 12454a4c11aaSdan sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); 12464a4c11aaSdan } 12474a4c11aaSdan pDb->disableAuth--; 12484a4c11aaSdan 12494a4c11aaSdan return rc; 12504a4c11aaSdan } 12514a4c11aaSdan 12524a4c11aaSdan /* 1253c431fd55Sdan ** Unless SQLITE_TEST is defined, this function is a simple wrapper around 1254c431fd55Sdan ** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either 1255c431fd55Sdan ** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending 1256c431fd55Sdan ** on whether or not the [db_use_legacy_prepare] command has been used to 1257c431fd55Sdan ** configure the connection. 1258c431fd55Sdan */ 1259c431fd55Sdan static int dbPrepare( 1260c431fd55Sdan SqliteDb *pDb, /* Database object */ 1261c431fd55Sdan const char *zSql, /* SQL to compile */ 1262c431fd55Sdan sqlite3_stmt **ppStmt, /* OUT: Prepared statement */ 1263c431fd55Sdan const char **pzOut /* OUT: Pointer to next SQL statement */ 1264c431fd55Sdan ){ 12652c2f392dSdrh unsigned int prepFlags = 0; 1266c431fd55Sdan #ifdef SQLITE_TEST 1267c431fd55Sdan if( pDb->bLegacyPrepare ){ 1268c431fd55Sdan return sqlite3_prepare(pDb->db, zSql, -1, ppStmt, pzOut); 1269c431fd55Sdan } 1270c431fd55Sdan #endif 12712c2f392dSdrh /* If the statement cache is large, use the SQLITE_PREPARE_PERSISTENT 12722c2f392dSdrh ** flags, which uses less lookaside memory. But if the cache is small, 12732c2f392dSdrh ** omit that flag to make full use of lookaside */ 12742c2f392dSdrh if( pDb->maxStmt>5 ) prepFlags = SQLITE_PREPARE_PERSISTENT; 12752c2f392dSdrh 12762c2f392dSdrh return sqlite3_prepare_v3(pDb->db, zSql, -1, prepFlags, ppStmt, pzOut); 1277c431fd55Sdan } 1278c431fd55Sdan 1279c431fd55Sdan /* 12804a4c11aaSdan ** Search the cache for a prepared-statement object that implements the 12814a4c11aaSdan ** first SQL statement in the buffer pointed to by parameter zIn. If 12824a4c11aaSdan ** no such prepared-statement can be found, allocate and prepare a new 12834a4c11aaSdan ** one. In either case, bind the current values of the relevant Tcl 12844a4c11aaSdan ** variables to any $var, :var or @var variables in the statement. Before 12854a4c11aaSdan ** returning, set *ppPreStmt to point to the prepared-statement object. 12864a4c11aaSdan ** 12874a4c11aaSdan ** Output parameter *pzOut is set to point to the next SQL statement in 12884a4c11aaSdan ** buffer zIn, or to the '\0' byte at the end of zIn if there is no 12894a4c11aaSdan ** next statement. 12904a4c11aaSdan ** 12914a4c11aaSdan ** If successful, TCL_OK is returned. Otherwise, TCL_ERROR is returned 12924a4c11aaSdan ** and an error message loaded into interpreter pDb->interp. 12934a4c11aaSdan */ 12944a4c11aaSdan static int dbPrepareAndBind( 12954a4c11aaSdan SqliteDb *pDb, /* Database object */ 12964a4c11aaSdan char const *zIn, /* SQL to compile */ 12974a4c11aaSdan char const **pzOut, /* OUT: Pointer to next SQL statement */ 12984a4c11aaSdan SqlPreparedStmt **ppPreStmt /* OUT: Object used to cache statement */ 12994a4c11aaSdan ){ 13004a4c11aaSdan const char *zSql = zIn; /* Pointer to first SQL statement in zIn */ 13017bb22ac7Smistachkin sqlite3_stmt *pStmt = 0; /* Prepared statement object */ 13024a4c11aaSdan SqlPreparedStmt *pPreStmt; /* Pointer to cached statement */ 13034a4c11aaSdan int nSql; /* Length of zSql in bytes */ 13047bb22ac7Smistachkin int nVar = 0; /* Number of variables in statement */ 13054a4c11aaSdan int iParm = 0; /* Next free entry in apParm */ 13060425f189Sdrh char c; 13074a4c11aaSdan int i; 1308c06ede10Sdrh int needResultReset = 0; /* Need to invoke Tcl_ResetResult() */ 1309c06ede10Sdrh int rc = SQLITE_OK; /* Value to return */ 13104a4c11aaSdan Tcl_Interp *interp = pDb->interp; 13114a4c11aaSdan 13124a4c11aaSdan *ppPreStmt = 0; 13134a4c11aaSdan 13144a4c11aaSdan /* Trim spaces from the start of zSql and calculate the remaining length. */ 13150425f189Sdrh while( (c = zSql[0])==' ' || c=='\t' || c=='\r' || c=='\n' ){ zSql++; } 13164a4c11aaSdan nSql = strlen30(zSql); 13174a4c11aaSdan 13184a4c11aaSdan for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){ 13194a4c11aaSdan int n = pPreStmt->nSql; 13204a4c11aaSdan if( nSql>=n 13214a4c11aaSdan && memcmp(pPreStmt->zSql, zSql, n)==0 13224a4c11aaSdan && (zSql[n]==0 || zSql[n-1]==';') 13234a4c11aaSdan ){ 13244a4c11aaSdan pStmt = pPreStmt->pStmt; 13254a4c11aaSdan *pzOut = &zSql[pPreStmt->nSql]; 13264a4c11aaSdan 13274a4c11aaSdan /* When a prepared statement is found, unlink it from the 13284a4c11aaSdan ** cache list. It will later be added back to the beginning 13294a4c11aaSdan ** of the cache list in order to implement LRU replacement. 13304a4c11aaSdan */ 13314a4c11aaSdan if( pPreStmt->pPrev ){ 13324a4c11aaSdan pPreStmt->pPrev->pNext = pPreStmt->pNext; 13334a4c11aaSdan }else{ 13344a4c11aaSdan pDb->stmtList = pPreStmt->pNext; 13354a4c11aaSdan } 13364a4c11aaSdan if( pPreStmt->pNext ){ 13374a4c11aaSdan pPreStmt->pNext->pPrev = pPreStmt->pPrev; 13384a4c11aaSdan }else{ 13394a4c11aaSdan pDb->stmtLast = pPreStmt->pPrev; 13404a4c11aaSdan } 13414a4c11aaSdan pDb->nStmt--; 13424a4c11aaSdan nVar = sqlite3_bind_parameter_count(pStmt); 13434a4c11aaSdan break; 13444a4c11aaSdan } 13454a4c11aaSdan } 13464a4c11aaSdan 13474a4c11aaSdan /* If no prepared statement was found. Compile the SQL text. Also allocate 13484a4c11aaSdan ** a new SqlPreparedStmt structure. */ 13494a4c11aaSdan if( pPreStmt==0 ){ 13504a4c11aaSdan int nByte; 13514a4c11aaSdan 1352c431fd55Sdan if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){ 1353c45e6716Sdrh Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); 13544a4c11aaSdan return TCL_ERROR; 13554a4c11aaSdan } 13564a4c11aaSdan if( pStmt==0 ){ 13574a4c11aaSdan if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){ 13584a4c11aaSdan /* A compile-time error in the statement. */ 1359c45e6716Sdrh Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); 13604a4c11aaSdan return TCL_ERROR; 13614a4c11aaSdan }else{ 13624a4c11aaSdan /* The statement was a no-op. Continue to the next statement 13634a4c11aaSdan ** in the SQL string. 13644a4c11aaSdan */ 13654a4c11aaSdan return TCL_OK; 13664a4c11aaSdan } 13674a4c11aaSdan } 13684a4c11aaSdan 13694a4c11aaSdan assert( pPreStmt==0 ); 13704a4c11aaSdan nVar = sqlite3_bind_parameter_count(pStmt); 13714a4c11aaSdan nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj *); 13724a4c11aaSdan pPreStmt = (SqlPreparedStmt*)Tcl_Alloc(nByte); 13734a4c11aaSdan memset(pPreStmt, 0, nByte); 13744a4c11aaSdan 13754a4c11aaSdan pPreStmt->pStmt = pStmt; 13767ed243b7Sdrh pPreStmt->nSql = (int)(*pzOut - zSql); 13774a4c11aaSdan pPreStmt->zSql = sqlite3_sql(pStmt); 13784a4c11aaSdan pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1]; 1379c431fd55Sdan #ifdef SQLITE_TEST 1380c431fd55Sdan if( pPreStmt->zSql==0 ){ 1381c431fd55Sdan char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1); 1382c431fd55Sdan memcpy(zCopy, zSql, pPreStmt->nSql); 1383c431fd55Sdan zCopy[pPreStmt->nSql] = '\0'; 1384c431fd55Sdan pPreStmt->zSql = zCopy; 1385c431fd55Sdan } 1386c431fd55Sdan #endif 13874a4c11aaSdan } 13884a4c11aaSdan assert( pPreStmt ); 13894a4c11aaSdan assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql ); 13904a4c11aaSdan assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) ); 13914a4c11aaSdan 13924a4c11aaSdan /* Bind values to parameters that begin with $ or : */ 13934a4c11aaSdan for(i=1; i<=nVar; i++){ 13944a4c11aaSdan const char *zVar = sqlite3_bind_parameter_name(pStmt, i); 13954a4c11aaSdan if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){ 13964a4c11aaSdan Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); 1397c06ede10Sdrh if( pVar==0 && pDb->zBindFallback!=0 ){ 1398c06ede10Sdrh Tcl_Obj *pCmd; 1399c06ede10Sdrh int rx; 1400c06ede10Sdrh pCmd = Tcl_NewStringObj(pDb->zBindFallback, -1); 1401c06ede10Sdrh Tcl_IncrRefCount(pCmd); 1402c06ede10Sdrh Tcl_ListObjAppendElement(interp, pCmd, Tcl_NewStringObj(zVar,-1)); 1403c06ede10Sdrh if( needResultReset ) Tcl_ResetResult(interp); 1404c06ede10Sdrh needResultReset = 1; 1405c06ede10Sdrh rx = Tcl_EvalObjEx(interp, pCmd, TCL_EVAL_DIRECT); 1406c06ede10Sdrh Tcl_DecrRefCount(pCmd); 1407c06ede10Sdrh if( rx==TCL_OK ){ 1408c06ede10Sdrh pVar = Tcl_GetObjResult(interp); 1409c06ede10Sdrh }else if( rx==TCL_ERROR ){ 1410c06ede10Sdrh rc = TCL_ERROR; 1411c06ede10Sdrh break; 1412c06ede10Sdrh }else{ 1413c06ede10Sdrh pVar = 0; 1414c06ede10Sdrh } 1415c06ede10Sdrh } 14164a4c11aaSdan if( pVar ){ 14174a4c11aaSdan int n; 14184a4c11aaSdan u8 *data; 14194a4c11aaSdan const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); 14208e18922fSmistachkin c = zType[0]; 14214a4c11aaSdan if( zVar[0]=='@' || 14224a4c11aaSdan (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){ 14234a4c11aaSdan /* Load a BLOB type if the Tcl variable is a bytearray and 14244a4c11aaSdan ** it has no string representation or the host 14254a4c11aaSdan ** parameter name begins with "@". */ 14264a4c11aaSdan data = Tcl_GetByteArrayFromObj(pVar, &n); 14274a4c11aaSdan sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC); 14284a4c11aaSdan Tcl_IncrRefCount(pVar); 14294a4c11aaSdan pPreStmt->apParm[iParm++] = pVar; 14304a4c11aaSdan }else if( c=='b' && strcmp(zType,"boolean")==0 ){ 14314a4c11aaSdan Tcl_GetIntFromObj(interp, pVar, &n); 14324a4c11aaSdan sqlite3_bind_int(pStmt, i, n); 14334a4c11aaSdan }else if( c=='d' && strcmp(zType,"double")==0 ){ 14344a4c11aaSdan double r; 14354a4c11aaSdan Tcl_GetDoubleFromObj(interp, pVar, &r); 14364a4c11aaSdan sqlite3_bind_double(pStmt, i, r); 14374a4c11aaSdan }else if( (c=='w' && strcmp(zType,"wideInt")==0) || 14384a4c11aaSdan (c=='i' && strcmp(zType,"int")==0) ){ 14394a4c11aaSdan Tcl_WideInt v; 14404a4c11aaSdan Tcl_GetWideIntFromObj(interp, pVar, &v); 14414a4c11aaSdan sqlite3_bind_int64(pStmt, i, v); 14424a4c11aaSdan }else{ 14434a4c11aaSdan data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); 14444a4c11aaSdan sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC); 14454a4c11aaSdan Tcl_IncrRefCount(pVar); 14464a4c11aaSdan pPreStmt->apParm[iParm++] = pVar; 14474a4c11aaSdan } 14484a4c11aaSdan }else{ 14494a4c11aaSdan sqlite3_bind_null(pStmt, i); 14504a4c11aaSdan } 1451c06ede10Sdrh if( needResultReset ) Tcl_ResetResult(pDb->interp); 14524a4c11aaSdan } 14534a4c11aaSdan } 14544a4c11aaSdan pPreStmt->nParm = iParm; 14554a4c11aaSdan *ppPreStmt = pPreStmt; 1456c06ede10Sdrh if( needResultReset && rc==TCL_OK ) Tcl_ResetResult(pDb->interp); 1457937d0deaSdan 1458c06ede10Sdrh return rc; 14594a4c11aaSdan } 14604a4c11aaSdan 14614a4c11aaSdan /* 14624a4c11aaSdan ** Release a statement reference obtained by calling dbPrepareAndBind(). 14634a4c11aaSdan ** There should be exactly one call to this function for each call to 14644a4c11aaSdan ** dbPrepareAndBind(). 14654a4c11aaSdan ** 14664a4c11aaSdan ** If the discard parameter is non-zero, then the statement is deleted 14674a4c11aaSdan ** immediately. Otherwise it is added to the LRU list and may be returned 14684a4c11aaSdan ** by a subsequent call to dbPrepareAndBind(). 14694a4c11aaSdan */ 14704a4c11aaSdan static void dbReleaseStmt( 14714a4c11aaSdan SqliteDb *pDb, /* Database handle */ 14724a4c11aaSdan SqlPreparedStmt *pPreStmt, /* Prepared statement handle to release */ 14734a4c11aaSdan int discard /* True to delete (not cache) the pPreStmt */ 14744a4c11aaSdan ){ 14754a4c11aaSdan int i; 14764a4c11aaSdan 14774a4c11aaSdan /* Free the bound string and blob parameters */ 14784a4c11aaSdan for(i=0; i<pPreStmt->nParm; i++){ 14794a4c11aaSdan Tcl_DecrRefCount(pPreStmt->apParm[i]); 14804a4c11aaSdan } 14814a4c11aaSdan pPreStmt->nParm = 0; 14824a4c11aaSdan 14834a4c11aaSdan if( pDb->maxStmt<=0 || discard ){ 14844a4c11aaSdan /* If the cache is turned off, deallocated the statement */ 1485c431fd55Sdan dbFreeStmt(pPreStmt); 14864a4c11aaSdan }else{ 14874a4c11aaSdan /* Add the prepared statement to the beginning of the cache list. */ 14884a4c11aaSdan pPreStmt->pNext = pDb->stmtList; 14894a4c11aaSdan pPreStmt->pPrev = 0; 14904a4c11aaSdan if( pDb->stmtList ){ 14914a4c11aaSdan pDb->stmtList->pPrev = pPreStmt; 14924a4c11aaSdan } 14934a4c11aaSdan pDb->stmtList = pPreStmt; 14944a4c11aaSdan if( pDb->stmtLast==0 ){ 14954a4c11aaSdan assert( pDb->nStmt==0 ); 14964a4c11aaSdan pDb->stmtLast = pPreStmt; 14974a4c11aaSdan }else{ 14984a4c11aaSdan assert( pDb->nStmt>0 ); 14994a4c11aaSdan } 15004a4c11aaSdan pDb->nStmt++; 15014a4c11aaSdan 15024a4c11aaSdan /* If we have too many statement in cache, remove the surplus from 15034a4c11aaSdan ** the end of the cache list. */ 15044a4c11aaSdan while( pDb->nStmt>pDb->maxStmt ){ 1505c431fd55Sdan SqlPreparedStmt *pLast = pDb->stmtLast; 1506c431fd55Sdan pDb->stmtLast = pLast->pPrev; 15074a4c11aaSdan pDb->stmtLast->pNext = 0; 15084a4c11aaSdan pDb->nStmt--; 1509c431fd55Sdan dbFreeStmt(pLast); 15104a4c11aaSdan } 15114a4c11aaSdan } 15124a4c11aaSdan } 15134a4c11aaSdan 15144a4c11aaSdan /* 15154a4c11aaSdan ** Structure used with dbEvalXXX() functions: 15164a4c11aaSdan ** 15174a4c11aaSdan ** dbEvalInit() 15184a4c11aaSdan ** dbEvalStep() 15194a4c11aaSdan ** dbEvalFinalize() 15204a4c11aaSdan ** dbEvalRowInfo() 15214a4c11aaSdan ** dbEvalColumnValue() 15224a4c11aaSdan */ 15234a4c11aaSdan typedef struct DbEvalContext DbEvalContext; 15244a4c11aaSdan struct DbEvalContext { 15254a4c11aaSdan SqliteDb *pDb; /* Database handle */ 15264a4c11aaSdan Tcl_Obj *pSql; /* Object holding string zSql */ 15274a4c11aaSdan const char *zSql; /* Remaining SQL to execute */ 15284a4c11aaSdan SqlPreparedStmt *pPreStmt; /* Current statement */ 15294a4c11aaSdan int nCol; /* Number of columns returned by pStmt */ 1530af38cdbcSdrh int evalFlags; /* Flags used */ 15314a4c11aaSdan Tcl_Obj *pArray; /* Name of array variable */ 15324a4c11aaSdan Tcl_Obj **apColName; /* Array of column names */ 15334a4c11aaSdan }; 15344a4c11aaSdan 1535af38cdbcSdrh #define SQLITE_EVAL_WITHOUTNULLS 0x00001 /* Unset array(*) for NULL */ 1536af38cdbcSdrh 15374a4c11aaSdan /* 15384a4c11aaSdan ** Release any cache of column names currently held as part of 15394a4c11aaSdan ** the DbEvalContext structure passed as the first argument. 15404a4c11aaSdan */ 15414a4c11aaSdan static void dbReleaseColumnNames(DbEvalContext *p){ 15424a4c11aaSdan if( p->apColName ){ 15434a4c11aaSdan int i; 15444a4c11aaSdan for(i=0; i<p->nCol; i++){ 15454a4c11aaSdan Tcl_DecrRefCount(p->apColName[i]); 15464a4c11aaSdan } 15474a4c11aaSdan Tcl_Free((char *)p->apColName); 15484a4c11aaSdan p->apColName = 0; 15494a4c11aaSdan } 15504a4c11aaSdan p->nCol = 0; 15514a4c11aaSdan } 15524a4c11aaSdan 15534a4c11aaSdan /* 15544a4c11aaSdan ** Initialize a DbEvalContext structure. 15558e556520Sdanielk1977 ** 15568e556520Sdanielk1977 ** If pArray is not NULL, then it contains the name of a Tcl array 15578e556520Sdanielk1977 ** variable. The "*" member of this array is set to a list containing 15584a4c11aaSdan ** the names of the columns returned by the statement as part of each 15594a4c11aaSdan ** call to dbEvalStep(), in order from left to right. e.g. if the names 15604a4c11aaSdan ** of the returned columns are a, b and c, it does the equivalent of the 15614a4c11aaSdan ** tcl command: 15628e556520Sdanielk1977 ** 15638e556520Sdanielk1977 ** set ${pArray}(*) {a b c} 15648e556520Sdanielk1977 */ 15654a4c11aaSdan static void dbEvalInit( 15664a4c11aaSdan DbEvalContext *p, /* Pointer to structure to initialize */ 15674a4c11aaSdan SqliteDb *pDb, /* Database handle */ 15684a4c11aaSdan Tcl_Obj *pSql, /* Object containing SQL script */ 1569af38cdbcSdrh Tcl_Obj *pArray, /* Name of Tcl array to set (*) element of */ 1570af38cdbcSdrh int evalFlags /* Flags controlling evaluation */ 15718e556520Sdanielk1977 ){ 15724a4c11aaSdan memset(p, 0, sizeof(DbEvalContext)); 15734a4c11aaSdan p->pDb = pDb; 15744a4c11aaSdan p->zSql = Tcl_GetString(pSql); 15754a4c11aaSdan p->pSql = pSql; 15764a4c11aaSdan Tcl_IncrRefCount(pSql); 15774a4c11aaSdan if( pArray ){ 15784a4c11aaSdan p->pArray = pArray; 15794a4c11aaSdan Tcl_IncrRefCount(pArray); 15804a4c11aaSdan } 1581af38cdbcSdrh p->evalFlags = evalFlags; 15824a4c11aaSdan } 15838e556520Sdanielk1977 15844a4c11aaSdan /* 15854a4c11aaSdan ** Obtain information about the row that the DbEvalContext passed as the 15864a4c11aaSdan ** first argument currently points to. 15874a4c11aaSdan */ 15884a4c11aaSdan static void dbEvalRowInfo( 15894a4c11aaSdan DbEvalContext *p, /* Evaluation context */ 15904a4c11aaSdan int *pnCol, /* OUT: Number of column names */ 15914a4c11aaSdan Tcl_Obj ***papColName /* OUT: Array of column names */ 15924a4c11aaSdan ){ 15938e556520Sdanielk1977 /* Compute column names */ 15944a4c11aaSdan if( 0==p->apColName ){ 15954a4c11aaSdan sqlite3_stmt *pStmt = p->pPreStmt->pStmt; 15964a4c11aaSdan int i; /* Iterator variable */ 15974a4c11aaSdan int nCol; /* Number of columns returned by pStmt */ 15984a4c11aaSdan Tcl_Obj **apColName = 0; /* Array of column names */ 15994a4c11aaSdan 16004a4c11aaSdan p->nCol = nCol = sqlite3_column_count(pStmt); 16014a4c11aaSdan if( nCol>0 && (papColName || p->pArray) ){ 16024a4c11aaSdan apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol ); 16038e556520Sdanielk1977 for(i=0; i<nCol; i++){ 1604c45e6716Sdrh apColName[i] = Tcl_NewStringObj(sqlite3_column_name(pStmt,i), -1); 16058e556520Sdanielk1977 Tcl_IncrRefCount(apColName[i]); 16068e556520Sdanielk1977 } 16074a4c11aaSdan p->apColName = apColName; 16084a4c11aaSdan } 16098e556520Sdanielk1977 16108e556520Sdanielk1977 /* If results are being stored in an array variable, then create 16118e556520Sdanielk1977 ** the array(*) entry for that array 16128e556520Sdanielk1977 */ 16134a4c11aaSdan if( p->pArray ){ 16144a4c11aaSdan Tcl_Interp *interp = p->pDb->interp; 16158e556520Sdanielk1977 Tcl_Obj *pColList = Tcl_NewObj(); 16168e556520Sdanielk1977 Tcl_Obj *pStar = Tcl_NewStringObj("*", -1); 16174a4c11aaSdan 16188e556520Sdanielk1977 for(i=0; i<nCol; i++){ 16198e556520Sdanielk1977 Tcl_ListObjAppendElement(interp, pColList, apColName[i]); 16208e556520Sdanielk1977 } 16218e556520Sdanielk1977 Tcl_IncrRefCount(pStar); 16224a4c11aaSdan Tcl_ObjSetVar2(interp, p->pArray, pStar, pColList, 0); 16238e556520Sdanielk1977 Tcl_DecrRefCount(pStar); 16248e556520Sdanielk1977 } 16258e556520Sdanielk1977 } 16268e556520Sdanielk1977 16274a4c11aaSdan if( papColName ){ 16284a4c11aaSdan *papColName = p->apColName; 16294a4c11aaSdan } 16304a4c11aaSdan if( pnCol ){ 16314a4c11aaSdan *pnCol = p->nCol; 16324a4c11aaSdan } 16334a4c11aaSdan } 16344a4c11aaSdan 16354a4c11aaSdan /* 16364a4c11aaSdan ** Return one of TCL_OK, TCL_BREAK or TCL_ERROR. If TCL_ERROR is 16374a4c11aaSdan ** returned, then an error message is stored in the interpreter before 16384a4c11aaSdan ** returning. 16394a4c11aaSdan ** 16404a4c11aaSdan ** A return value of TCL_OK means there is a row of data available. The 16414a4c11aaSdan ** data may be accessed using dbEvalRowInfo() and dbEvalColumnValue(). This 16424a4c11aaSdan ** is analogous to a return of SQLITE_ROW from sqlite3_step(). If TCL_BREAK 16434a4c11aaSdan ** is returned, then the SQL script has finished executing and there are 16444a4c11aaSdan ** no further rows available. This is similar to SQLITE_DONE. 16454a4c11aaSdan */ 16464a4c11aaSdan static int dbEvalStep(DbEvalContext *p){ 1647c431fd55Sdan const char *zPrevSql = 0; /* Previous value of p->zSql */ 1648c431fd55Sdan 16494a4c11aaSdan while( p->zSql[0] || p->pPreStmt ){ 16504a4c11aaSdan int rc; 16514a4c11aaSdan if( p->pPreStmt==0 ){ 1652c431fd55Sdan zPrevSql = (p->zSql==zPrevSql ? 0 : p->zSql); 16534a4c11aaSdan rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt); 16544a4c11aaSdan if( rc!=TCL_OK ) return rc; 16554a4c11aaSdan }else{ 16564a4c11aaSdan int rcs; 16574a4c11aaSdan SqliteDb *pDb = p->pDb; 16584a4c11aaSdan SqlPreparedStmt *pPreStmt = p->pPreStmt; 16594a4c11aaSdan sqlite3_stmt *pStmt = pPreStmt->pStmt; 16604a4c11aaSdan 16614a4c11aaSdan rcs = sqlite3_step(pStmt); 16624a4c11aaSdan if( rcs==SQLITE_ROW ){ 16634a4c11aaSdan return TCL_OK; 16644a4c11aaSdan } 16654a4c11aaSdan if( p->pArray ){ 16664a4c11aaSdan dbEvalRowInfo(p, 0, 0); 16674a4c11aaSdan } 16684a4c11aaSdan rcs = sqlite3_reset(pStmt); 16694a4c11aaSdan 16704a4c11aaSdan pDb->nStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_FULLSCAN_STEP,1); 16714a4c11aaSdan pDb->nSort = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_SORT,1); 16723c379b01Sdrh pDb->nIndex = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_AUTOINDEX,1); 1673c456a76fSdan pDb->nVMStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_VM_STEP,1); 16744a4c11aaSdan dbReleaseColumnNames(p); 16754a4c11aaSdan p->pPreStmt = 0; 16764a4c11aaSdan 16774a4c11aaSdan if( rcs!=SQLITE_OK ){ 16784a4c11aaSdan /* If a run-time error occurs, report the error and stop reading 16794a4c11aaSdan ** the SQL. */ 16804a4c11aaSdan dbReleaseStmt(pDb, pPreStmt, 1); 1681c431fd55Sdan #if SQLITE_TEST 1682c431fd55Sdan if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){ 1683c431fd55Sdan /* If the runtime error was an SQLITE_SCHEMA, and the database 1684c431fd55Sdan ** handle is configured to use the legacy sqlite3_prepare() 1685c431fd55Sdan ** interface, retry prepare()/step() on the same SQL statement. 1686c431fd55Sdan ** This only happens once. If there is a second SQLITE_SCHEMA 1687c431fd55Sdan ** error, the error will be returned to the caller. */ 1688c431fd55Sdan p->zSql = zPrevSql; 1689c431fd55Sdan continue; 1690c431fd55Sdan } 1691c431fd55Sdan #endif 1692c45e6716Sdrh Tcl_SetObjResult(pDb->interp, 1693c45e6716Sdrh Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); 16944a4c11aaSdan return TCL_ERROR; 16954a4c11aaSdan }else{ 16964a4c11aaSdan dbReleaseStmt(pDb, pPreStmt, 0); 16974a4c11aaSdan } 16984a4c11aaSdan } 16994a4c11aaSdan } 17004a4c11aaSdan 17014a4c11aaSdan /* Finished */ 17024a4c11aaSdan return TCL_BREAK; 17034a4c11aaSdan } 17044a4c11aaSdan 17054a4c11aaSdan /* 17064a4c11aaSdan ** Free all resources currently held by the DbEvalContext structure passed 17074a4c11aaSdan ** as the first argument. There should be exactly one call to this function 17084a4c11aaSdan ** for each call to dbEvalInit(). 17094a4c11aaSdan */ 17104a4c11aaSdan static void dbEvalFinalize(DbEvalContext *p){ 17114a4c11aaSdan if( p->pPreStmt ){ 17124a4c11aaSdan sqlite3_reset(p->pPreStmt->pStmt); 17134a4c11aaSdan dbReleaseStmt(p->pDb, p->pPreStmt, 0); 17144a4c11aaSdan p->pPreStmt = 0; 17154a4c11aaSdan } 17164a4c11aaSdan if( p->pArray ){ 17174a4c11aaSdan Tcl_DecrRefCount(p->pArray); 17184a4c11aaSdan p->pArray = 0; 17194a4c11aaSdan } 17204a4c11aaSdan Tcl_DecrRefCount(p->pSql); 17214a4c11aaSdan dbReleaseColumnNames(p); 17224a4c11aaSdan } 17234a4c11aaSdan 17244a4c11aaSdan /* 17254a4c11aaSdan ** Return a pointer to a Tcl_Obj structure with ref-count 0 that contains 17264a4c11aaSdan ** the value for the iCol'th column of the row currently pointed to by 17274a4c11aaSdan ** the DbEvalContext structure passed as the first argument. 17284a4c11aaSdan */ 17294a4c11aaSdan static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){ 17304a4c11aaSdan sqlite3_stmt *pStmt = p->pPreStmt->pStmt; 17314a4c11aaSdan switch( sqlite3_column_type(pStmt, iCol) ){ 17324a4c11aaSdan case SQLITE_BLOB: { 17334a4c11aaSdan int bytes = sqlite3_column_bytes(pStmt, iCol); 17344a4c11aaSdan const char *zBlob = sqlite3_column_blob(pStmt, iCol); 17354a4c11aaSdan if( !zBlob ) bytes = 0; 17364a4c11aaSdan return Tcl_NewByteArrayObj((u8*)zBlob, bytes); 17374a4c11aaSdan } 17384a4c11aaSdan case SQLITE_INTEGER: { 17394a4c11aaSdan sqlite_int64 v = sqlite3_column_int64(pStmt, iCol); 17404a4c11aaSdan if( v>=-2147483647 && v<=2147483647 ){ 17417fd33929Sdrh return Tcl_NewIntObj((int)v); 17424a4c11aaSdan }else{ 17434a4c11aaSdan return Tcl_NewWideIntObj(v); 17444a4c11aaSdan } 17454a4c11aaSdan } 17464a4c11aaSdan case SQLITE_FLOAT: { 17474a4c11aaSdan return Tcl_NewDoubleObj(sqlite3_column_double(pStmt, iCol)); 17484a4c11aaSdan } 17494a4c11aaSdan case SQLITE_NULL: { 1750c45e6716Sdrh return Tcl_NewStringObj(p->pDb->zNull, -1); 17514a4c11aaSdan } 17524a4c11aaSdan } 17534a4c11aaSdan 1754325eff58Sdrh return Tcl_NewStringObj((char*)sqlite3_column_text(pStmt, iCol), -1); 17554a4c11aaSdan } 17564a4c11aaSdan 17574a4c11aaSdan /* 17584a4c11aaSdan ** If using Tcl version 8.6 or greater, use the NR functions to avoid 17594a4c11aaSdan ** recursive evalution of scripts by the [db eval] and [db trans] 17604a4c11aaSdan ** commands. Even if the headers used while compiling the extension 17614a4c11aaSdan ** are 8.6 or newer, the code still tests the Tcl version at runtime. 17624a4c11aaSdan ** This allows stubs-enabled builds to be used with older Tcl libraries. 17634a4c11aaSdan */ 17644a4c11aaSdan #if TCL_MAJOR_VERSION>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6) 1765a2c8a95bSdrh # define SQLITE_TCL_NRE 1 17664a4c11aaSdan static int DbUseNre(void){ 17674a4c11aaSdan int major, minor; 17684a4c11aaSdan Tcl_GetVersion(&major, &minor, 0, 0); 17694a4c11aaSdan return( (major==8 && minor>=6) || major>8 ); 17704a4c11aaSdan } 17714a4c11aaSdan #else 17724a4c11aaSdan /* 17734a4c11aaSdan ** Compiling using headers earlier than 8.6. In this case NR cannot be 17744a4c11aaSdan ** used, so DbUseNre() to always return zero. Add #defines for the other 17754a4c11aaSdan ** Tcl_NRxxx() functions to prevent them from causing compilation errors, 17764a4c11aaSdan ** even though the only invocations of them are within conditional blocks 17774a4c11aaSdan ** of the form: 17784a4c11aaSdan ** 17794a4c11aaSdan ** if( DbUseNre() ) { ... } 17804a4c11aaSdan */ 1781a2c8a95bSdrh # define SQLITE_TCL_NRE 0 17824a4c11aaSdan # define DbUseNre() 0 1783a47941feSdrh # define Tcl_NRAddCallback(a,b,c,d,e,f) (void)0 17844a4c11aaSdan # define Tcl_NREvalObj(a,b,c) 0 1785a47941feSdrh # define Tcl_NRCreateCommand(a,b,c,d,e,f) (void)0 17864a4c11aaSdan #endif 17874a4c11aaSdan 17884a4c11aaSdan /* 17894a4c11aaSdan ** This function is part of the implementation of the command: 17904a4c11aaSdan ** 17914a4c11aaSdan ** $db eval SQL ?ARRAYNAME? SCRIPT 17924a4c11aaSdan */ 1793a121cc7cSmistachkin static int SQLITE_TCLAPI DbEvalNextCmd( 17944a4c11aaSdan ClientData data[], /* data[0] is the (DbEvalContext*) */ 17954a4c11aaSdan Tcl_Interp *interp, /* Tcl interpreter */ 17964a4c11aaSdan int result /* Result so far */ 17974a4c11aaSdan ){ 17984a4c11aaSdan int rc = result; /* Return code */ 17994a4c11aaSdan 18004a4c11aaSdan /* The first element of the data[] array is a pointer to a DbEvalContext 18014a4c11aaSdan ** structure allocated using Tcl_Alloc(). The second element of data[] 18024a4c11aaSdan ** is a pointer to a Tcl_Obj containing the script to run for each row 18034a4c11aaSdan ** returned by the queries encapsulated in data[0]. */ 18044a4c11aaSdan DbEvalContext *p = (DbEvalContext *)data[0]; 18054a4c11aaSdan Tcl_Obj *pScript = (Tcl_Obj *)data[1]; 18064a4c11aaSdan Tcl_Obj *pArray = p->pArray; 18074a4c11aaSdan 18084a4c11aaSdan while( (rc==TCL_OK || rc==TCL_CONTINUE) && TCL_OK==(rc = dbEvalStep(p)) ){ 18094a4c11aaSdan int i; 18104a4c11aaSdan int nCol; 18114a4c11aaSdan Tcl_Obj **apColName; 18124a4c11aaSdan dbEvalRowInfo(p, &nCol, &apColName); 18134a4c11aaSdan for(i=0; i<nCol; i++){ 18144a4c11aaSdan if( pArray==0 ){ 1815af38cdbcSdrh Tcl_ObjSetVar2(interp, apColName[i], 0, dbEvalColumnValue(p,i), 0); 1816af38cdbcSdrh }else if( (p->evalFlags & SQLITE_EVAL_WITHOUTNULLS)!=0 1817af38cdbcSdrh && sqlite3_column_type(p->pPreStmt->pStmt, i)==SQLITE_NULL 1818af38cdbcSdrh ){ 1819af38cdbcSdrh Tcl_UnsetVar2(interp, Tcl_GetString(pArray), 1820af38cdbcSdrh Tcl_GetString(apColName[i]), 0); 18214a4c11aaSdan }else{ 1822af38cdbcSdrh Tcl_ObjSetVar2(interp, pArray, apColName[i], dbEvalColumnValue(p,i), 0); 18234a4c11aaSdan } 18244a4c11aaSdan } 18254a4c11aaSdan 18264a4c11aaSdan /* The required interpreter variables are now populated with the data 18274a4c11aaSdan ** from the current row. If using NRE, schedule callbacks to evaluate 18284a4c11aaSdan ** script pScript, then to invoke this function again to fetch the next 18294a4c11aaSdan ** row (or clean up if there is no next row or the script throws an 18304a4c11aaSdan ** exception). After scheduling the callbacks, return control to the 18314a4c11aaSdan ** caller. 18324a4c11aaSdan ** 18334a4c11aaSdan ** If not using NRE, evaluate pScript directly and continue with the 18344a4c11aaSdan ** next iteration of this while(...) loop. */ 18354a4c11aaSdan if( DbUseNre() ){ 18364a4c11aaSdan Tcl_NRAddCallback(interp, DbEvalNextCmd, (void*)p, (void*)pScript, 0, 0); 18374a4c11aaSdan return Tcl_NREvalObj(interp, pScript, 0); 18384a4c11aaSdan }else{ 18394a4c11aaSdan rc = Tcl_EvalObjEx(interp, pScript, 0); 18404a4c11aaSdan } 18414a4c11aaSdan } 18424a4c11aaSdan 18434a4c11aaSdan Tcl_DecrRefCount(pScript); 18444a4c11aaSdan dbEvalFinalize(p); 18454a4c11aaSdan Tcl_Free((char *)p); 18464a4c11aaSdan 18474a4c11aaSdan if( rc==TCL_OK || rc==TCL_BREAK ){ 18484a4c11aaSdan Tcl_ResetResult(interp); 18494a4c11aaSdan rc = TCL_OK; 18504a4c11aaSdan } 18514a4c11aaSdan return rc; 18528e556520Sdanielk1977 } 18538e556520Sdanielk1977 18541067fe11Stpoindex /* 185546c47d46Sdan ** This function is used by the implementations of the following database 185646c47d46Sdan ** handle sub-commands: 185746c47d46Sdan ** 185846c47d46Sdan ** $db update_hook ?SCRIPT? 185946c47d46Sdan ** $db wal_hook ?SCRIPT? 186046c47d46Sdan ** $db commit_hook ?SCRIPT? 186146c47d46Sdan ** $db preupdate hook ?SCRIPT? 186246c47d46Sdan */ 186346c47d46Sdan static void DbHookCmd( 186446c47d46Sdan Tcl_Interp *interp, /* Tcl interpreter */ 186546c47d46Sdan SqliteDb *pDb, /* Database handle */ 186646c47d46Sdan Tcl_Obj *pArg, /* SCRIPT argument (or NULL) */ 186746c47d46Sdan Tcl_Obj **ppHook /* Pointer to member of SqliteDb */ 186846c47d46Sdan ){ 186946c47d46Sdan sqlite3 *db = pDb->db; 187046c47d46Sdan 187146c47d46Sdan if( *ppHook ){ 187246c47d46Sdan Tcl_SetObjResult(interp, *ppHook); 187346c47d46Sdan if( pArg ){ 187446c47d46Sdan Tcl_DecrRefCount(*ppHook); 187546c47d46Sdan *ppHook = 0; 187646c47d46Sdan } 187746c47d46Sdan } 187846c47d46Sdan if( pArg ){ 187946c47d46Sdan assert( !(*ppHook) ); 188046c47d46Sdan if( Tcl_GetCharLength(pArg)>0 ){ 188146c47d46Sdan *ppHook = pArg; 188246c47d46Sdan Tcl_IncrRefCount(*ppHook); 188346c47d46Sdan } 188446c47d46Sdan } 188546c47d46Sdan 18869b1c62d4Sdrh #ifdef SQLITE_ENABLE_PREUPDATE_HOOK 188746c47d46Sdan sqlite3_preupdate_hook(db, (pDb->pPreUpdateHook?DbPreUpdateHandler:0), pDb); 18889b1c62d4Sdrh #endif 188946c47d46Sdan sqlite3_update_hook(db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb); 189046c47d46Sdan sqlite3_rollback_hook(db, (pDb->pRollbackHook?DbRollbackHandler:0), pDb); 189146c47d46Sdan sqlite3_wal_hook(db, (pDb->pWalHook?DbWalHandler:0), pDb); 189246c47d46Sdan } 189346c47d46Sdan 189446c47d46Sdan /* 189575897234Sdrh ** The "sqlite" command below creates a new Tcl command for each 189675897234Sdrh ** connection it opens to an SQLite database. This routine is invoked 189775897234Sdrh ** whenever one of those connection-specific commands is executed 189875897234Sdrh ** in Tcl. For example, if you run Tcl code like this: 189975897234Sdrh ** 19009bb575fdSdrh ** sqlite3 db1 "my_database" 190175897234Sdrh ** db1 close 190275897234Sdrh ** 190375897234Sdrh ** The first command opens a connection to the "my_database" database 190475897234Sdrh ** and calls that connection "db1". The second command causes this 190575897234Sdrh ** subroutine to be invoked. 190675897234Sdrh */ 19077617e4a8Smistachkin static int SQLITE_TCLAPI DbObjCmd( 19087617e4a8Smistachkin void *cd, 19097617e4a8Smistachkin Tcl_Interp *interp, 19107617e4a8Smistachkin int objc, 19117617e4a8Smistachkin Tcl_Obj *const*objv 19127617e4a8Smistachkin ){ 1913bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 19146d31316cSdrh int choice; 191522fbcb8dSdrh int rc = TCL_OK; 19160de8c112Sdrh static const char *DB_strs[] = { 1917c06ede10Sdrh "authorizer", "backup", "bind_fallback", 1918c06ede10Sdrh "busy", "cache", "changes", 1919c06ede10Sdrh "close", "collate", "collation_needed", 192011d88e68Sdrh "commit_hook", "complete", "config", 192111d88e68Sdrh "copy", "deserialize", "enable_load_extension", 192211d88e68Sdrh "errorcode", "eval", "exists", 192311d88e68Sdrh "function", "incrblob", "interrupt", 192411d88e68Sdrh "last_insert_rowid", "nullvalue", "onecolumn", 192511d88e68Sdrh "preupdate", "profile", "progress", 192611d88e68Sdrh "rekey", "restore", "rollback_hook", 192711d88e68Sdrh "serialize", "status", "timeout", 192811d88e68Sdrh "total_changes", "trace", "trace_v2", 192911d88e68Sdrh "transaction", "unlock_notify", "update_hook", 193011d88e68Sdrh "version", "wal_hook", 0 19316d31316cSdrh }; 1932411995dcSdrh enum DB_enum { 1933c06ede10Sdrh DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK, 1934c06ede10Sdrh DB_BUSY, DB_CACHE, DB_CHANGES, 1935c06ede10Sdrh DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED, 193611d88e68Sdrh DB_COMMIT_HOOK, DB_COMPLETE, DB_CONFIG, 193711d88e68Sdrh DB_COPY, DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION, 193811d88e68Sdrh DB_ERRORCODE, DB_EVAL, DB_EXISTS, 193911d88e68Sdrh DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT, 194011d88e68Sdrh DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN, 194111d88e68Sdrh DB_PREUPDATE, DB_PROFILE, DB_PROGRESS, 194211d88e68Sdrh DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK, 194311d88e68Sdrh DB_SERIALIZE, DB_STATUS, DB_TIMEOUT, 194411d88e68Sdrh DB_TOTAL_CHANGES, DB_TRACE, DB_TRACE_V2, 194511d88e68Sdrh DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, 194611d88e68Sdrh DB_VERSION, DB_WAL_HOOK 19476d31316cSdrh }; 19481067fe11Stpoindex /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ 19496d31316cSdrh 19506d31316cSdrh if( objc<2 ){ 19516d31316cSdrh Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); 195275897234Sdrh return TCL_ERROR; 195375897234Sdrh } 1954411995dcSdrh if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){ 19556d31316cSdrh return TCL_ERROR; 19566d31316cSdrh } 19576d31316cSdrh 1958411995dcSdrh switch( (enum DB_enum)choice ){ 195975897234Sdrh 1960e22a334bSdrh /* $db authorizer ?CALLBACK? 1961e22a334bSdrh ** 1962e22a334bSdrh ** Invoke the given callback to authorize each SQL operation as it is 1963e22a334bSdrh ** compiled. 5 arguments are appended to the callback before it is 1964e22a334bSdrh ** invoked: 1965e22a334bSdrh ** 1966e22a334bSdrh ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...) 1967e22a334bSdrh ** (2) First descriptive name (depends on authorization type) 1968e22a334bSdrh ** (3) Second descriptive name 1969e22a334bSdrh ** (4) Name of the database (ex: "main", "temp") 1970e22a334bSdrh ** (5) Name of trigger that is doing the access 1971e22a334bSdrh ** 1972e22a334bSdrh ** The callback should return on of the following strings: SQLITE_OK, 1973e22a334bSdrh ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error. 1974e22a334bSdrh ** 1975e22a334bSdrh ** If this method is invoked with no arguments, the current authorization 1976e22a334bSdrh ** callback string is returned. 1977e22a334bSdrh */ 1978e22a334bSdrh case DB_AUTHORIZER: { 19791211de37Sdrh #ifdef SQLITE_OMIT_AUTHORIZATION 1980a198f2b5Sdrh Tcl_AppendResult(interp, "authorization not available in this build", 1981a198f2b5Sdrh (char*)0); 19821211de37Sdrh return TCL_ERROR; 19831211de37Sdrh #else 1984e22a334bSdrh if( objc>3 ){ 1985e22a334bSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 19860f14e2ebSdrh return TCL_ERROR; 1987e22a334bSdrh }else if( objc==2 ){ 1988b5a20d3cSdrh if( pDb->zAuth ){ 1989a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zAuth, (char*)0); 1990e22a334bSdrh } 1991e22a334bSdrh }else{ 1992e22a334bSdrh char *zAuth; 1993e22a334bSdrh int len; 1994e22a334bSdrh if( pDb->zAuth ){ 1995e22a334bSdrh Tcl_Free(pDb->zAuth); 1996e22a334bSdrh } 1997e22a334bSdrh zAuth = Tcl_GetStringFromObj(objv[2], &len); 1998e22a334bSdrh if( zAuth && len>0 ){ 1999e22a334bSdrh pDb->zAuth = Tcl_Alloc( len + 1 ); 20005bb3eb9bSdrh memcpy(pDb->zAuth, zAuth, len+1); 2001e22a334bSdrh }else{ 2002e22a334bSdrh pDb->zAuth = 0; 2003e22a334bSdrh } 2004e22a334bSdrh if( pDb->zAuth ){ 200532c6a48bSdrh typedef int (*sqlite3_auth_cb)( 200632c6a48bSdrh void*,int,const char*,const char*, 200732c6a48bSdrh const char*,const char*); 2008e22a334bSdrh pDb->interp = interp; 200932c6a48bSdrh sqlite3_set_authorizer(pDb->db,(sqlite3_auth_cb)auth_callback,pDb); 2010e22a334bSdrh }else{ 20116f8a503dSdanielk1977 sqlite3_set_authorizer(pDb->db, 0, 0); 2012e22a334bSdrh } 2013e22a334bSdrh } 20141211de37Sdrh #endif 2015e22a334bSdrh break; 2016e22a334bSdrh } 2017e22a334bSdrh 2018dc2c4915Sdrh /* $db backup ?DATABASE? FILENAME 2019dc2c4915Sdrh ** 2020dc2c4915Sdrh ** Open or create a database file named FILENAME. Transfer the 2021dc2c4915Sdrh ** content of local database DATABASE (default: "main") into the 2022dc2c4915Sdrh ** FILENAME database. 2023dc2c4915Sdrh */ 2024dc2c4915Sdrh case DB_BACKUP: { 2025dc2c4915Sdrh const char *zDestFile; 2026dc2c4915Sdrh const char *zSrcDb; 2027dc2c4915Sdrh sqlite3 *pDest; 2028dc2c4915Sdrh sqlite3_backup *pBackup; 2029dc2c4915Sdrh 2030dc2c4915Sdrh if( objc==3 ){ 2031dc2c4915Sdrh zSrcDb = "main"; 2032dc2c4915Sdrh zDestFile = Tcl_GetString(objv[2]); 2033dc2c4915Sdrh }else if( objc==4 ){ 2034dc2c4915Sdrh zSrcDb = Tcl_GetString(objv[2]); 2035dc2c4915Sdrh zDestFile = Tcl_GetString(objv[3]); 2036dc2c4915Sdrh }else{ 2037dc2c4915Sdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME"); 2038dc2c4915Sdrh return TCL_ERROR; 2039dc2c4915Sdrh } 2040147ef394Sdrh rc = sqlite3_open_v2(zDestFile, &pDest, 2041147ef394Sdrh SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE| pDb->openFlags, 0); 2042dc2c4915Sdrh if( rc!=SQLITE_OK ){ 2043dc2c4915Sdrh Tcl_AppendResult(interp, "cannot open target database: ", 2044dc2c4915Sdrh sqlite3_errmsg(pDest), (char*)0); 2045dc2c4915Sdrh sqlite3_close(pDest); 2046dc2c4915Sdrh return TCL_ERROR; 2047dc2c4915Sdrh } 2048dc2c4915Sdrh pBackup = sqlite3_backup_init(pDest, "main", pDb->db, zSrcDb); 2049dc2c4915Sdrh if( pBackup==0 ){ 2050dc2c4915Sdrh Tcl_AppendResult(interp, "backup failed: ", 2051dc2c4915Sdrh sqlite3_errmsg(pDest), (char*)0); 2052dc2c4915Sdrh sqlite3_close(pDest); 2053dc2c4915Sdrh return TCL_ERROR; 2054dc2c4915Sdrh } 2055dc2c4915Sdrh while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} 2056dc2c4915Sdrh sqlite3_backup_finish(pBackup); 2057dc2c4915Sdrh if( rc==SQLITE_DONE ){ 2058dc2c4915Sdrh rc = TCL_OK; 2059dc2c4915Sdrh }else{ 2060dc2c4915Sdrh Tcl_AppendResult(interp, "backup failed: ", 2061dc2c4915Sdrh sqlite3_errmsg(pDest), (char*)0); 2062dc2c4915Sdrh rc = TCL_ERROR; 2063dc2c4915Sdrh } 2064dc2c4915Sdrh sqlite3_close(pDest); 2065dc2c4915Sdrh break; 2066dc2c4915Sdrh } 2067dc2c4915Sdrh 2068c06ede10Sdrh /* $db bind_fallback ?CALLBACK? 2069c06ede10Sdrh ** 2070c06ede10Sdrh ** When resolving bind parameters in an SQL statement, if the parameter 2071c06ede10Sdrh ** cannot be associated with a TCL variable then invoke CALLBACK with a 2072c06ede10Sdrh ** single argument that is the name of the parameter and use the return 2073c06ede10Sdrh ** value of the CALLBACK as the binding. If CALLBACK returns something 2074c06ede10Sdrh ** other than TCL_OK or TCL_ERROR then bind a NULL. 2075c06ede10Sdrh ** 2076c06ede10Sdrh ** If CALLBACK is an empty string, then revert to the default behavior 2077c06ede10Sdrh ** which is to set the binding to NULL. 2078c06ede10Sdrh ** 2079c06ede10Sdrh ** If CALLBACK returns an error, that causes the statement execution to 2080c06ede10Sdrh ** abort. Hence, to configure a connection so that it throws an error 2081c06ede10Sdrh ** on an attempt to bind an unknown variable, do something like this: 2082c06ede10Sdrh ** 2083c06ede10Sdrh ** proc bind_error {name} {error "no such variable: $name"} 2084c06ede10Sdrh ** db bind_fallback bind_error 2085c06ede10Sdrh */ 2086c06ede10Sdrh case DB_BIND_FALLBACK: { 2087c06ede10Sdrh if( objc>3 ){ 2088c06ede10Sdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 2089c06ede10Sdrh return TCL_ERROR; 2090c06ede10Sdrh }else if( objc==2 ){ 2091c06ede10Sdrh if( pDb->zBindFallback ){ 2092c06ede10Sdrh Tcl_AppendResult(interp, pDb->zBindFallback, (char*)0); 2093c06ede10Sdrh } 2094c06ede10Sdrh }else{ 2095c06ede10Sdrh char *zCallback; 2096c06ede10Sdrh int len; 2097c06ede10Sdrh if( pDb->zBindFallback ){ 2098c06ede10Sdrh Tcl_Free(pDb->zBindFallback); 2099c06ede10Sdrh } 2100c06ede10Sdrh zCallback = Tcl_GetStringFromObj(objv[2], &len); 2101c06ede10Sdrh if( zCallback && len>0 ){ 2102c06ede10Sdrh pDb->zBindFallback = Tcl_Alloc( len + 1 ); 2103c06ede10Sdrh memcpy(pDb->zBindFallback, zCallback, len+1); 2104c06ede10Sdrh }else{ 2105c06ede10Sdrh pDb->zBindFallback = 0; 2106c06ede10Sdrh } 2107c06ede10Sdrh } 2108c06ede10Sdrh break; 2109c06ede10Sdrh } 2110c06ede10Sdrh 2111bec3f402Sdrh /* $db busy ?CALLBACK? 2112bec3f402Sdrh ** 2113bec3f402Sdrh ** Invoke the given callback if an SQL statement attempts to open 2114bec3f402Sdrh ** a locked database file. 2115bec3f402Sdrh */ 21166d31316cSdrh case DB_BUSY: { 21176d31316cSdrh if( objc>3 ){ 21186d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK"); 2119bec3f402Sdrh return TCL_ERROR; 21206d31316cSdrh }else if( objc==2 ){ 2121bec3f402Sdrh if( pDb->zBusy ){ 2122a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zBusy, (char*)0); 2123bec3f402Sdrh } 2124bec3f402Sdrh }else{ 21256d31316cSdrh char *zBusy; 21266d31316cSdrh int len; 2127bec3f402Sdrh if( pDb->zBusy ){ 2128bec3f402Sdrh Tcl_Free(pDb->zBusy); 21296d31316cSdrh } 21306d31316cSdrh zBusy = Tcl_GetStringFromObj(objv[2], &len); 21316d31316cSdrh if( zBusy && len>0 ){ 21326d31316cSdrh pDb->zBusy = Tcl_Alloc( len + 1 ); 21335bb3eb9bSdrh memcpy(pDb->zBusy, zBusy, len+1); 21346d31316cSdrh }else{ 2135bec3f402Sdrh pDb->zBusy = 0; 2136bec3f402Sdrh } 2137bec3f402Sdrh if( pDb->zBusy ){ 2138bec3f402Sdrh pDb->interp = interp; 21396f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb); 21406d31316cSdrh }else{ 21416f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, 0, 0); 2142bec3f402Sdrh } 2143bec3f402Sdrh } 21446d31316cSdrh break; 21456d31316cSdrh } 2146bec3f402Sdrh 2147fb7e7651Sdrh /* $db cache flush 2148fb7e7651Sdrh ** $db cache size n 2149fb7e7651Sdrh ** 2150fb7e7651Sdrh ** Flush the prepared statement cache, or set the maximum number of 2151fb7e7651Sdrh ** cached statements. 2152fb7e7651Sdrh */ 2153fb7e7651Sdrh case DB_CACHE: { 2154fb7e7651Sdrh char *subCmd; 2155fb7e7651Sdrh int n; 2156fb7e7651Sdrh 2157fb7e7651Sdrh if( objc<=2 ){ 2158fb7e7651Sdrh Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?"); 2159fb7e7651Sdrh return TCL_ERROR; 2160fb7e7651Sdrh } 2161fb7e7651Sdrh subCmd = Tcl_GetStringFromObj( objv[2], 0 ); 2162fb7e7651Sdrh if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){ 2163fb7e7651Sdrh if( objc!=3 ){ 2164fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "flush"); 2165fb7e7651Sdrh return TCL_ERROR; 2166fb7e7651Sdrh }else{ 2167fb7e7651Sdrh flushStmtCache( pDb ); 2168fb7e7651Sdrh } 2169fb7e7651Sdrh }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){ 2170fb7e7651Sdrh if( objc!=4 ){ 2171fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "size n"); 2172fb7e7651Sdrh return TCL_ERROR; 2173fb7e7651Sdrh }else{ 2174fb7e7651Sdrh if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ 2175fb7e7651Sdrh Tcl_AppendResult( interp, "cannot convert \"", 2176a198f2b5Sdrh Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0); 2177fb7e7651Sdrh return TCL_ERROR; 2178fb7e7651Sdrh }else{ 2179fb7e7651Sdrh if( n<0 ){ 2180fb7e7651Sdrh flushStmtCache( pDb ); 2181fb7e7651Sdrh n = 0; 2182fb7e7651Sdrh }else if( n>MAX_PREPARED_STMTS ){ 2183fb7e7651Sdrh n = MAX_PREPARED_STMTS; 2184fb7e7651Sdrh } 2185fb7e7651Sdrh pDb->maxStmt = n; 2186fb7e7651Sdrh } 2187fb7e7651Sdrh } 2188fb7e7651Sdrh }else{ 2189fb7e7651Sdrh Tcl_AppendResult( interp, "bad option \"", 2190a198f2b5Sdrh Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", 2191a198f2b5Sdrh (char*)0); 2192fb7e7651Sdrh return TCL_ERROR; 2193fb7e7651Sdrh } 2194fb7e7651Sdrh break; 2195fb7e7651Sdrh } 2196fb7e7651Sdrh 2197b28af71aSdanielk1977 /* $db changes 2198c8d30ac1Sdrh ** 2199c8d30ac1Sdrh ** Return the number of rows that were modified, inserted, or deleted by 2200b28af71aSdanielk1977 ** the most recent INSERT, UPDATE or DELETE statement, not including 2201b28af71aSdanielk1977 ** any changes made by trigger programs. 2202c8d30ac1Sdrh */ 2203c8d30ac1Sdrh case DB_CHANGES: { 2204c8d30ac1Sdrh Tcl_Obj *pResult; 2205c8d30ac1Sdrh if( objc!=2 ){ 2206c8d30ac1Sdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 2207c8d30ac1Sdrh return TCL_ERROR; 2208c8d30ac1Sdrh } 2209c8d30ac1Sdrh pResult = Tcl_GetObjResult(interp); 2210b28af71aSdanielk1977 Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db)); 2211f146a776Srdc break; 2212f146a776Srdc } 2213f146a776Srdc 221475897234Sdrh /* $db close 221575897234Sdrh ** 221675897234Sdrh ** Shutdown the database 221775897234Sdrh */ 22186d31316cSdrh case DB_CLOSE: { 22196d31316cSdrh Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0)); 22206d31316cSdrh break; 22216d31316cSdrh } 222275897234Sdrh 22230f14e2ebSdrh /* 22240f14e2ebSdrh ** $db collate NAME SCRIPT 22250f14e2ebSdrh ** 22260f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 22270f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 22280f14e2ebSdrh */ 22290f14e2ebSdrh case DB_COLLATE: { 22300f14e2ebSdrh SqlCollate *pCollate; 22310f14e2ebSdrh char *zName; 22320f14e2ebSdrh char *zScript; 22330f14e2ebSdrh int nScript; 22340f14e2ebSdrh if( objc!=4 ){ 22350f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 22360f14e2ebSdrh return TCL_ERROR; 22370f14e2ebSdrh } 22380f14e2ebSdrh zName = Tcl_GetStringFromObj(objv[2], 0); 22390f14e2ebSdrh zScript = Tcl_GetStringFromObj(objv[3], &nScript); 22400f14e2ebSdrh pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 ); 22410f14e2ebSdrh if( pCollate==0 ) return TCL_ERROR; 22420f14e2ebSdrh pCollate->interp = interp; 22430f14e2ebSdrh pCollate->pNext = pDb->pCollate; 22440f14e2ebSdrh pCollate->zScript = (char*)&pCollate[1]; 22450f14e2ebSdrh pDb->pCollate = pCollate; 22465bb3eb9bSdrh memcpy(pCollate->zScript, zScript, nScript+1); 22470f14e2ebSdrh if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8, 22480f14e2ebSdrh pCollate, tclSqlCollate) ){ 22499636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 22500f14e2ebSdrh return TCL_ERROR; 22510f14e2ebSdrh } 22520f14e2ebSdrh break; 22530f14e2ebSdrh } 22540f14e2ebSdrh 22550f14e2ebSdrh /* 22560f14e2ebSdrh ** $db collation_needed SCRIPT 22570f14e2ebSdrh ** 22580f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 22590f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 22600f14e2ebSdrh */ 22610f14e2ebSdrh case DB_COLLATION_NEEDED: { 22620f14e2ebSdrh if( objc!=3 ){ 22630f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT"); 22640f14e2ebSdrh return TCL_ERROR; 22650f14e2ebSdrh } 22660f14e2ebSdrh if( pDb->pCollateNeeded ){ 22670f14e2ebSdrh Tcl_DecrRefCount(pDb->pCollateNeeded); 22680f14e2ebSdrh } 22690f14e2ebSdrh pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]); 22700f14e2ebSdrh Tcl_IncrRefCount(pDb->pCollateNeeded); 22710f14e2ebSdrh sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded); 22720f14e2ebSdrh break; 22730f14e2ebSdrh } 22740f14e2ebSdrh 227519e2d37fSdrh /* $db commit_hook ?CALLBACK? 227619e2d37fSdrh ** 227719e2d37fSdrh ** Invoke the given callback just before committing every SQL transaction. 227819e2d37fSdrh ** If the callback throws an exception or returns non-zero, then the 227919e2d37fSdrh ** transaction is aborted. If CALLBACK is an empty string, the callback 228019e2d37fSdrh ** is disabled. 228119e2d37fSdrh */ 228219e2d37fSdrh case DB_COMMIT_HOOK: { 228319e2d37fSdrh if( objc>3 ){ 228419e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 228519e2d37fSdrh return TCL_ERROR; 228619e2d37fSdrh }else if( objc==2 ){ 228719e2d37fSdrh if( pDb->zCommit ){ 2288a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zCommit, (char*)0); 228919e2d37fSdrh } 229019e2d37fSdrh }else{ 22916ef5e12eSmistachkin const char *zCommit; 229219e2d37fSdrh int len; 229319e2d37fSdrh if( pDb->zCommit ){ 229419e2d37fSdrh Tcl_Free(pDb->zCommit); 229519e2d37fSdrh } 229619e2d37fSdrh zCommit = Tcl_GetStringFromObj(objv[2], &len); 229719e2d37fSdrh if( zCommit && len>0 ){ 229819e2d37fSdrh pDb->zCommit = Tcl_Alloc( len + 1 ); 22995bb3eb9bSdrh memcpy(pDb->zCommit, zCommit, len+1); 230019e2d37fSdrh }else{ 230119e2d37fSdrh pDb->zCommit = 0; 230219e2d37fSdrh } 230319e2d37fSdrh if( pDb->zCommit ){ 230419e2d37fSdrh pDb->interp = interp; 230519e2d37fSdrh sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb); 230619e2d37fSdrh }else{ 230719e2d37fSdrh sqlite3_commit_hook(pDb->db, 0, 0); 230819e2d37fSdrh } 230919e2d37fSdrh } 231019e2d37fSdrh break; 231119e2d37fSdrh } 231219e2d37fSdrh 231375897234Sdrh /* $db complete SQL 231475897234Sdrh ** 231575897234Sdrh ** Return TRUE if SQL is a complete SQL statement. Return FALSE if 231675897234Sdrh ** additional lines of input are needed. This is similar to the 231775897234Sdrh ** built-in "info complete" command of Tcl. 231875897234Sdrh */ 23196d31316cSdrh case DB_COMPLETE: { 2320ccae6026Sdrh #ifndef SQLITE_OMIT_COMPLETE 23216d31316cSdrh Tcl_Obj *pResult; 23226d31316cSdrh int isComplete; 23236d31316cSdrh if( objc!=3 ){ 23246d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 232575897234Sdrh return TCL_ERROR; 232675897234Sdrh } 23276f8a503dSdanielk1977 isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); 23286d31316cSdrh pResult = Tcl_GetObjResult(interp); 23296d31316cSdrh Tcl_SetBooleanObj(pResult, isComplete); 2330ccae6026Sdrh #endif 23316d31316cSdrh break; 23326d31316cSdrh } 233375897234Sdrh 233411d88e68Sdrh /* $db config ?OPTION? ?BOOLEAN? 233511d88e68Sdrh ** 233611d88e68Sdrh ** Configure the database connection using the sqlite3_db_config() 233711d88e68Sdrh ** interface. 233811d88e68Sdrh */ 233911d88e68Sdrh case DB_CONFIG: { 234011d88e68Sdrh static const struct DbConfigChoices { 234111d88e68Sdrh const char *zName; 234211d88e68Sdrh int op; 234311d88e68Sdrh } aDbConfig[] = { 234411d88e68Sdrh { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY }, 234511d88e68Sdrh { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER }, 234611d88e68Sdrh { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW }, 234711d88e68Sdrh { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER }, 234811d88e68Sdrh { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION }, 234911d88e68Sdrh { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE }, 235011d88e68Sdrh { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG }, 235111d88e68Sdrh { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP }, 235211d88e68Sdrh { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE }, 235311d88e68Sdrh { "defensive", SQLITE_DBCONFIG_DEFENSIVE }, 235411d88e68Sdrh { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA }, 235511d88e68Sdrh { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE }, 235611d88e68Sdrh { "dqs_dml", SQLITE_DBCONFIG_DQS_DML }, 235711d88e68Sdrh { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL }, 235811d88e68Sdrh }; 235911d88e68Sdrh Tcl_Obj *pResult; 236011d88e68Sdrh int ii; 236111d88e68Sdrh if( objc>4 ){ 236211d88e68Sdrh Tcl_WrongNumArgs(interp, 2, objv, "?OPTION? ?BOOLEAN?"); 236311d88e68Sdrh return TCL_ERROR; 236411d88e68Sdrh } 236511d88e68Sdrh if( objc==2 ){ 236611d88e68Sdrh /* With no arguments, list all configuration options and with the 236711d88e68Sdrh ** current value */ 236811d88e68Sdrh pResult = Tcl_NewListObj(0,0); 236911d88e68Sdrh for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){ 237011d88e68Sdrh int v = 0; 2371*4043cfefSdrh sqlite3_db_config(pDb->db, aDbConfig[ii].op, -1, &v); 237211d88e68Sdrh Tcl_ListObjAppendElement(interp, pResult, 237311d88e68Sdrh Tcl_NewStringObj(aDbConfig[ii].zName,-1)); 237411d88e68Sdrh Tcl_ListObjAppendElement(interp, pResult, 237511d88e68Sdrh Tcl_NewIntObj(v)); 237611d88e68Sdrh } 237711d88e68Sdrh }else{ 237811d88e68Sdrh const char *zOpt = Tcl_GetString(objv[2]); 237911d88e68Sdrh int onoff = -1; 238011d88e68Sdrh int v = 0; 238111d88e68Sdrh if( zOpt[0]=='-' ) zOpt++; 238211d88e68Sdrh for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){ 238311d88e68Sdrh if( strcmp(aDbConfig[ii].zName, zOpt)==0 ) break; 238411d88e68Sdrh } 238511d88e68Sdrh if( ii>=sizeof(aDbConfig)/sizeof(aDbConfig[0]) ){ 238611d88e68Sdrh Tcl_AppendResult(interp, "unknown config option: \"", zOpt, 238711d88e68Sdrh "\"", (void*)0); 238811d88e68Sdrh return TCL_ERROR; 238911d88e68Sdrh } 239011d88e68Sdrh if( objc==4 ){ 239111d88e68Sdrh if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ){ 239211d88e68Sdrh return TCL_ERROR; 239311d88e68Sdrh } 239411d88e68Sdrh } 2395*4043cfefSdrh sqlite3_db_config(pDb->db, aDbConfig[ii].op, onoff, &v); 239611d88e68Sdrh pResult = Tcl_NewIntObj(v); 239711d88e68Sdrh } 239811d88e68Sdrh Tcl_SetObjResult(interp, pResult); 239911d88e68Sdrh break; 240011d88e68Sdrh } 240111d88e68Sdrh 240219e2d37fSdrh /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR? 240319e2d37fSdrh ** 240419e2d37fSdrh ** Copy data into table from filename, optionally using SEPARATOR 240519e2d37fSdrh ** as column separators. If a column contains a null string, or the 240619e2d37fSdrh ** value of NULLINDICATOR, a NULL is inserted for the column. 240719e2d37fSdrh ** conflict-algorithm is one of the sqlite conflict algorithms: 240819e2d37fSdrh ** rollback, abort, fail, ignore, replace 240919e2d37fSdrh ** On success, return the number of lines processed, not necessarily same 241019e2d37fSdrh ** as 'db changes' due to conflict-algorithm selected. 241119e2d37fSdrh ** 241219e2d37fSdrh ** This code is basically an implementation/enhancement of 241319e2d37fSdrh ** the sqlite3 shell.c ".import" command. 241419e2d37fSdrh ** 241519e2d37fSdrh ** This command usage is equivalent to the sqlite2.x COPY statement, 241619e2d37fSdrh ** which imports file data into a table using the PostgreSQL COPY file format: 241719e2d37fSdrh ** $db copy $conflit_algo $table_name $filename \t \\N 241819e2d37fSdrh */ 241919e2d37fSdrh case DB_COPY: { 242019e2d37fSdrh char *zTable; /* Insert data into this table */ 242119e2d37fSdrh char *zFile; /* The file from which to extract data */ 242219e2d37fSdrh char *zConflict; /* The conflict algorithm to use */ 242319e2d37fSdrh sqlite3_stmt *pStmt; /* A statement */ 242419e2d37fSdrh int nCol; /* Number of columns in the table */ 242519e2d37fSdrh int nByte; /* Number of bytes in an SQL string */ 242619e2d37fSdrh int i, j; /* Loop counters */ 242719e2d37fSdrh int nSep; /* Number of bytes in zSep[] */ 242819e2d37fSdrh int nNull; /* Number of bytes in zNull[] */ 242919e2d37fSdrh char *zSql; /* An SQL statement */ 243019e2d37fSdrh char *zLine; /* A single line of input from the file */ 243119e2d37fSdrh char **azCol; /* zLine[] broken up into columns */ 24326ef5e12eSmistachkin const char *zCommit; /* How to commit changes */ 243319e2d37fSdrh FILE *in; /* The input file */ 243419e2d37fSdrh int lineno = 0; /* Line number of input file */ 243519e2d37fSdrh char zLineNum[80]; /* Line number print buffer */ 243619e2d37fSdrh Tcl_Obj *pResult; /* interp result */ 243719e2d37fSdrh 24386ef5e12eSmistachkin const char *zSep; 24396ef5e12eSmistachkin const char *zNull; 244019e2d37fSdrh if( objc<5 || objc>7 ){ 244119e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, 244219e2d37fSdrh "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"); 244319e2d37fSdrh return TCL_ERROR; 244419e2d37fSdrh } 244519e2d37fSdrh if( objc>=6 ){ 244619e2d37fSdrh zSep = Tcl_GetStringFromObj(objv[5], 0); 244719e2d37fSdrh }else{ 244819e2d37fSdrh zSep = "\t"; 244919e2d37fSdrh } 245019e2d37fSdrh if( objc>=7 ){ 245119e2d37fSdrh zNull = Tcl_GetStringFromObj(objv[6], 0); 245219e2d37fSdrh }else{ 245319e2d37fSdrh zNull = ""; 245419e2d37fSdrh } 245519e2d37fSdrh zConflict = Tcl_GetStringFromObj(objv[2], 0); 245619e2d37fSdrh zTable = Tcl_GetStringFromObj(objv[3], 0); 245719e2d37fSdrh zFile = Tcl_GetStringFromObj(objv[4], 0); 24584f21c4afSdrh nSep = strlen30(zSep); 24594f21c4afSdrh nNull = strlen30(zNull); 246019e2d37fSdrh if( nSep==0 ){ 2461a198f2b5Sdrh Tcl_AppendResult(interp,"Error: non-null separator required for copy", 2462a198f2b5Sdrh (char*)0); 246319e2d37fSdrh return TCL_ERROR; 246419e2d37fSdrh } 24653e59c012Sdrh if(strcmp(zConflict, "rollback") != 0 && 24663e59c012Sdrh strcmp(zConflict, "abort" ) != 0 && 24673e59c012Sdrh strcmp(zConflict, "fail" ) != 0 && 24683e59c012Sdrh strcmp(zConflict, "ignore" ) != 0 && 24693e59c012Sdrh strcmp(zConflict, "replace" ) != 0 ) { 247019e2d37fSdrh Tcl_AppendResult(interp, "Error: \"", zConflict, 247119e2d37fSdrh "\", conflict-algorithm must be one of: rollback, " 2472a198f2b5Sdrh "abort, fail, ignore, or replace", (char*)0); 247319e2d37fSdrh return TCL_ERROR; 247419e2d37fSdrh } 247519e2d37fSdrh zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); 247619e2d37fSdrh if( zSql==0 ){ 2477a198f2b5Sdrh Tcl_AppendResult(interp, "Error: no such table: ", zTable, (char*)0); 247819e2d37fSdrh return TCL_ERROR; 247919e2d37fSdrh } 24804f21c4afSdrh nByte = strlen30(zSql); 24813e701a18Sdrh rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); 248219e2d37fSdrh sqlite3_free(zSql); 248319e2d37fSdrh if( rc ){ 2484a198f2b5Sdrh Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0); 248519e2d37fSdrh nCol = 0; 248619e2d37fSdrh }else{ 248719e2d37fSdrh nCol = sqlite3_column_count(pStmt); 248819e2d37fSdrh } 248919e2d37fSdrh sqlite3_finalize(pStmt); 249019e2d37fSdrh if( nCol==0 ) { 249119e2d37fSdrh return TCL_ERROR; 249219e2d37fSdrh } 249319e2d37fSdrh zSql = malloc( nByte + 50 + nCol*2 ); 249419e2d37fSdrh if( zSql==0 ) { 2495a198f2b5Sdrh Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0); 249619e2d37fSdrh return TCL_ERROR; 249719e2d37fSdrh } 249819e2d37fSdrh sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?", 249919e2d37fSdrh zConflict, zTable); 25004f21c4afSdrh j = strlen30(zSql); 250119e2d37fSdrh for(i=1; i<nCol; i++){ 250219e2d37fSdrh zSql[j++] = ','; 250319e2d37fSdrh zSql[j++] = '?'; 250419e2d37fSdrh } 250519e2d37fSdrh zSql[j++] = ')'; 250619e2d37fSdrh zSql[j] = 0; 25073e701a18Sdrh rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0); 250819e2d37fSdrh free(zSql); 250919e2d37fSdrh if( rc ){ 2510a198f2b5Sdrh Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0); 251119e2d37fSdrh sqlite3_finalize(pStmt); 251219e2d37fSdrh return TCL_ERROR; 251319e2d37fSdrh } 251419e2d37fSdrh in = fopen(zFile, "rb"); 251519e2d37fSdrh if( in==0 ){ 2516ea8f0a15Sdrh Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, (char*)0); 251719e2d37fSdrh sqlite3_finalize(pStmt); 251819e2d37fSdrh return TCL_ERROR; 251919e2d37fSdrh } 252019e2d37fSdrh azCol = malloc( sizeof(azCol[0])*(nCol+1) ); 252119e2d37fSdrh if( azCol==0 ) { 2522a198f2b5Sdrh Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0); 252343617e9aSdrh fclose(in); 252419e2d37fSdrh return TCL_ERROR; 252519e2d37fSdrh } 25263752785fSdrh (void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0); 252719e2d37fSdrh zCommit = "COMMIT"; 252819e2d37fSdrh while( (zLine = local_getline(0, in))!=0 ){ 252919e2d37fSdrh char *z; 253019e2d37fSdrh lineno++; 253119e2d37fSdrh azCol[0] = zLine; 253219e2d37fSdrh for(i=0, z=zLine; *z; z++){ 253319e2d37fSdrh if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){ 253419e2d37fSdrh *z = 0; 253519e2d37fSdrh i++; 253619e2d37fSdrh if( i<nCol ){ 253719e2d37fSdrh azCol[i] = &z[nSep]; 253819e2d37fSdrh z += nSep-1; 253919e2d37fSdrh } 254019e2d37fSdrh } 254119e2d37fSdrh } 254219e2d37fSdrh if( i+1!=nCol ){ 254319e2d37fSdrh char *zErr; 25444f21c4afSdrh int nErr = strlen30(zFile) + 200; 25455bb3eb9bSdrh zErr = malloc(nErr); 2546c1f4494eSdrh if( zErr ){ 25475bb3eb9bSdrh sqlite3_snprintf(nErr, zErr, 2548955de52cSdanielk1977 "Error: %s line %d: expected %d columns of data but found %d", 254919e2d37fSdrh zFile, lineno, nCol, i+1); 2550a198f2b5Sdrh Tcl_AppendResult(interp, zErr, (char*)0); 255119e2d37fSdrh free(zErr); 2552c1f4494eSdrh } 255319e2d37fSdrh zCommit = "ROLLBACK"; 255419e2d37fSdrh break; 255519e2d37fSdrh } 255619e2d37fSdrh for(i=0; i<nCol; i++){ 255719e2d37fSdrh /* check for null data, if so, bind as null */ 2558ea678832Sdrh if( (nNull>0 && strcmp(azCol[i], zNull)==0) 25594f21c4afSdrh || strlen30(azCol[i])==0 2560ea678832Sdrh ){ 256119e2d37fSdrh sqlite3_bind_null(pStmt, i+1); 256219e2d37fSdrh }else{ 256319e2d37fSdrh sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); 256419e2d37fSdrh } 256519e2d37fSdrh } 256619e2d37fSdrh sqlite3_step(pStmt); 256719e2d37fSdrh rc = sqlite3_reset(pStmt); 256819e2d37fSdrh free(zLine); 256919e2d37fSdrh if( rc!=SQLITE_OK ){ 2570a198f2b5Sdrh Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), (char*)0); 257119e2d37fSdrh zCommit = "ROLLBACK"; 257219e2d37fSdrh break; 257319e2d37fSdrh } 257419e2d37fSdrh } 257519e2d37fSdrh free(azCol); 257619e2d37fSdrh fclose(in); 257719e2d37fSdrh sqlite3_finalize(pStmt); 25783752785fSdrh (void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0); 257919e2d37fSdrh 258019e2d37fSdrh if( zCommit[0] == 'C' ){ 258119e2d37fSdrh /* success, set result as number of lines processed */ 258219e2d37fSdrh pResult = Tcl_GetObjResult(interp); 258319e2d37fSdrh Tcl_SetIntObj(pResult, lineno); 258419e2d37fSdrh rc = TCL_OK; 258519e2d37fSdrh }else{ 258619e2d37fSdrh /* failure, append lineno where failed */ 25875bb3eb9bSdrh sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno); 2588a198f2b5Sdrh Tcl_AppendResult(interp,", failed while processing line: ",zLineNum, 2589a198f2b5Sdrh (char*)0); 259019e2d37fSdrh rc = TCL_ERROR; 259119e2d37fSdrh } 259219e2d37fSdrh break; 259319e2d37fSdrh } 259419e2d37fSdrh 259575897234Sdrh /* 25966ca64481Sdrh ** $db deserialize ?-maxsize N? ?-readonly BOOL? ?DATABASE? VALUE 2597cb7d541dSdrh ** 2598cb7d541dSdrh ** Reopen DATABASE (default "main") using the content in $VALUE 2599cb7d541dSdrh */ 2600cb7d541dSdrh case DB_DESERIALIZE: { 26019c6396ecSdrh #ifndef SQLITE_ENABLE_DESERIALIZE 26023ec8665eSdrh Tcl_AppendResult(interp, "MEMDB not available in this build", 26033ec8665eSdrh (char*)0); 26043ec8665eSdrh rc = TCL_ERROR; 26053ec8665eSdrh #else 26066ca64481Sdrh const char *zSchema = 0; 26076ca64481Sdrh Tcl_Obj *pValue = 0; 26083ec8665eSdrh unsigned char *pBA; 26093ec8665eSdrh unsigned char *pData; 26103ec8665eSdrh int len, xrc; 26116ca64481Sdrh sqlite3_int64 mxSize = 0; 26126ca64481Sdrh int i; 26136ca64481Sdrh int isReadonly = 0; 26143ec8665eSdrh 26156ca64481Sdrh 26166ca64481Sdrh if( objc<3 ){ 26173ec8665eSdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? VALUE"); 26183ec8665eSdrh rc = TCL_ERROR; 26193ec8665eSdrh break; 26203ec8665eSdrh } 26216ca64481Sdrh for(i=2; i<objc-1; i++){ 26226ca64481Sdrh const char *z = Tcl_GetString(objv[i]); 26236ca64481Sdrh if( strcmp(z,"-maxsize")==0 && i<objc-2 ){ 26246ca64481Sdrh rc = Tcl_GetWideIntFromObj(interp, objv[++i], &mxSize); 26256ca64481Sdrh if( rc ) goto deserialize_error; 26266ca64481Sdrh continue; 26276ca64481Sdrh } 26286ca64481Sdrh if( strcmp(z,"-readonly")==0 && i<objc-2 ){ 26296ca64481Sdrh rc = Tcl_GetBooleanFromObj(interp, objv[++i], &isReadonly); 26306ca64481Sdrh if( rc ) goto deserialize_error; 26316ca64481Sdrh continue; 26326ca64481Sdrh } 26336ca64481Sdrh if( zSchema==0 && i==objc-2 && z[0]!='-' ){ 26346ca64481Sdrh zSchema = z; 26356ca64481Sdrh continue; 26366ca64481Sdrh } 26376ca64481Sdrh Tcl_AppendResult(interp, "unknown option: ", z, (char*)0); 26386ca64481Sdrh rc = TCL_ERROR; 26396ca64481Sdrh goto deserialize_error; 26406ca64481Sdrh } 26416ca64481Sdrh pValue = objv[objc-1]; 26423ec8665eSdrh pBA = Tcl_GetByteArrayFromObj(pValue, &len); 26433ec8665eSdrh pData = sqlite3_malloc64( len ); 2644a5bb4351Sdrh if( pData==0 && len>0 ){ 26453ec8665eSdrh Tcl_AppendResult(interp, "out of memory", (char*)0); 26463ec8665eSdrh rc = TCL_ERROR; 26473ec8665eSdrh }else{ 26486ca64481Sdrh int flags; 2649a5bb4351Sdrh if( len>0 ) memcpy(pData, pBA, len); 26506ca64481Sdrh if( isReadonly ){ 26516ca64481Sdrh flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_READONLY; 26526ca64481Sdrh }else{ 26536ca64481Sdrh flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE; 26546ca64481Sdrh } 26556ca64481Sdrh xrc = sqlite3_deserialize(pDb->db, zSchema, pData, len, len, flags); 26563ec8665eSdrh if( xrc ){ 26573ec8665eSdrh Tcl_AppendResult(interp, "unable to set MEMDB content", (char*)0); 26583ec8665eSdrh rc = TCL_ERROR; 26593ec8665eSdrh } 26606ca64481Sdrh if( mxSize>0 ){ 26616ca64481Sdrh sqlite3_file_control(pDb->db, zSchema,SQLITE_FCNTL_SIZE_LIMIT,&mxSize); 26623ec8665eSdrh } 26636ca64481Sdrh } 26646ca64481Sdrh deserialize_error: 26653ec8665eSdrh #endif 2666cb7d541dSdrh break; 2667cb7d541dSdrh } 2668cb7d541dSdrh 2669cb7d541dSdrh /* 26704144905bSdrh ** $db enable_load_extension BOOLEAN 26714144905bSdrh ** 26724144905bSdrh ** Turn the extension loading feature on or off. It if off by 26734144905bSdrh ** default. 26744144905bSdrh */ 26754144905bSdrh case DB_ENABLE_LOAD_EXTENSION: { 2676f533acc0Sdrh #ifndef SQLITE_OMIT_LOAD_EXTENSION 26774144905bSdrh int onoff; 26784144905bSdrh if( objc!=3 ){ 26794144905bSdrh Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN"); 26804144905bSdrh return TCL_ERROR; 26814144905bSdrh } 26824144905bSdrh if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){ 26834144905bSdrh return TCL_ERROR; 26844144905bSdrh } 26854144905bSdrh sqlite3_enable_load_extension(pDb->db, onoff); 26864144905bSdrh break; 2687f533acc0Sdrh #else 2688f533acc0Sdrh Tcl_AppendResult(interp, "extension loading is turned off at compile-time", 2689a198f2b5Sdrh (char*)0); 2690f533acc0Sdrh return TCL_ERROR; 2691f533acc0Sdrh #endif 26924144905bSdrh } 26934144905bSdrh 26944144905bSdrh /* 2695dcd997eaSdrh ** $db errorcode 2696dcd997eaSdrh ** 2697dcd997eaSdrh ** Return the numeric error code that was returned by the most recent 26986f8a503dSdanielk1977 ** call to sqlite3_exec(). 2699dcd997eaSdrh */ 2700dcd997eaSdrh case DB_ERRORCODE: { 2701f3ce83f5Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); 2702dcd997eaSdrh break; 2703dcd997eaSdrh } 2704dcd997eaSdrh 2705dcd997eaSdrh /* 27064a4c11aaSdan ** $db exists $sql 27071807ce37Sdrh ** $db onecolumn $sql 270875897234Sdrh ** 27094a4c11aaSdan ** The onecolumn method is the equivalent of: 27104a4c11aaSdan ** lindex [$db eval $sql] 0 27114a4c11aaSdan */ 27124a4c11aaSdan case DB_EXISTS: 27134a4c11aaSdan case DB_ONECOLUMN: { 2714edc4024bSdrh Tcl_Obj *pResult = 0; 27154a4c11aaSdan DbEvalContext sEval; 27164a4c11aaSdan if( objc!=3 ){ 27174a4c11aaSdan Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 27184a4c11aaSdan return TCL_ERROR; 27194a4c11aaSdan } 27204a4c11aaSdan 2721af38cdbcSdrh dbEvalInit(&sEval, pDb, objv[2], 0, 0); 27224a4c11aaSdan rc = dbEvalStep(&sEval); 27234a4c11aaSdan if( choice==DB_ONECOLUMN ){ 27244a4c11aaSdan if( rc==TCL_OK ){ 2725edc4024bSdrh pResult = dbEvalColumnValue(&sEval, 0); 2726d5f12cd5Sdan }else if( rc==TCL_BREAK ){ 2727d5f12cd5Sdan Tcl_ResetResult(interp); 27284a4c11aaSdan } 27294a4c11aaSdan }else if( rc==TCL_BREAK || rc==TCL_OK ){ 2730edc4024bSdrh pResult = Tcl_NewBooleanObj(rc==TCL_OK); 27314a4c11aaSdan } 27324a4c11aaSdan dbEvalFinalize(&sEval); 2733edc4024bSdrh if( pResult ) Tcl_SetObjResult(interp, pResult); 27344a4c11aaSdan 27354a4c11aaSdan if( rc==TCL_BREAK ){ 27364a4c11aaSdan rc = TCL_OK; 27374a4c11aaSdan } 27384a4c11aaSdan break; 27394a4c11aaSdan } 27404a4c11aaSdan 27414a4c11aaSdan /* 2742af38cdbcSdrh ** $db eval ?options? $sql ?array? ?{ ...code... }? 27434a4c11aaSdan ** 274475897234Sdrh ** The SQL statement in $sql is evaluated. For each row, the values are 2745bec3f402Sdrh ** placed in elements of the array named "array" and ...code... is executed. 274675897234Sdrh ** If "array" and "code" are omitted, then no callback is every invoked. 274775897234Sdrh ** If "array" is an empty string, then the values are placed in variables 274875897234Sdrh ** that have the same name as the fields extracted by the query. 274975897234Sdrh */ 27504a4c11aaSdan case DB_EVAL: { 2751af38cdbcSdrh int evalFlags = 0; 2752af38cdbcSdrh const char *zOpt; 2753af38cdbcSdrh while( objc>3 && (zOpt = Tcl_GetString(objv[2]))!=0 && zOpt[0]=='-' ){ 2754af38cdbcSdrh if( strcmp(zOpt, "-withoutnulls")==0 ){ 2755af38cdbcSdrh evalFlags |= SQLITE_EVAL_WITHOUTNULLS; 2756af38cdbcSdrh } 2757af38cdbcSdrh else{ 2758af38cdbcSdrh Tcl_AppendResult(interp, "unknown option: \"", zOpt, "\"", (void*)0); 2759af38cdbcSdrh return TCL_ERROR; 2760af38cdbcSdrh } 2761af38cdbcSdrh objc--; 2762af38cdbcSdrh objv++; 2763af38cdbcSdrh } 276492febd92Sdrh if( objc<3 || objc>5 ){ 2765af38cdbcSdrh Tcl_WrongNumArgs(interp, 2, objv, 2766af38cdbcSdrh "?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?"); 276730ccda10Sdanielk1977 return TCL_ERROR; 276830ccda10Sdanielk1977 } 27694a4c11aaSdan 277092febd92Sdrh if( objc==3 ){ 27714a4c11aaSdan DbEvalContext sEval; 27724a4c11aaSdan Tcl_Obj *pRet = Tcl_NewObj(); 27734a4c11aaSdan Tcl_IncrRefCount(pRet); 2774af38cdbcSdrh dbEvalInit(&sEval, pDb, objv[2], 0, 0); 27754a4c11aaSdan while( TCL_OK==(rc = dbEvalStep(&sEval)) ){ 27764a4c11aaSdan int i; 27774a4c11aaSdan int nCol; 27784a4c11aaSdan dbEvalRowInfo(&sEval, &nCol, 0); 277992febd92Sdrh for(i=0; i<nCol; i++){ 27804a4c11aaSdan Tcl_ListObjAppendElement(interp, pRet, dbEvalColumnValue(&sEval, i)); 278192febd92Sdrh } 278230ccda10Sdanielk1977 } 27834a4c11aaSdan dbEvalFinalize(&sEval); 278490b6bb19Sdrh if( rc==TCL_BREAK ){ 27854a4c11aaSdan Tcl_SetObjResult(interp, pRet); 278690b6bb19Sdrh rc = TCL_OK; 278790b6bb19Sdrh } 2788ef2cb63eSdanielk1977 Tcl_DecrRefCount(pRet); 27894a4c11aaSdan }else{ 27908e18922fSmistachkin ClientData cd2[2]; 27914a4c11aaSdan DbEvalContext *p; 27924a4c11aaSdan Tcl_Obj *pArray = 0; 27934a4c11aaSdan Tcl_Obj *pScript; 27944a4c11aaSdan 2795af38cdbcSdrh if( objc>=5 && *(char *)Tcl_GetString(objv[3]) ){ 27964a4c11aaSdan pArray = objv[3]; 27974a4c11aaSdan } 27984a4c11aaSdan pScript = objv[objc-1]; 27994a4c11aaSdan Tcl_IncrRefCount(pScript); 28004a4c11aaSdan 28014a4c11aaSdan p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext)); 2802af38cdbcSdrh dbEvalInit(p, pDb, objv[2], pArray, evalFlags); 28034a4c11aaSdan 28048e18922fSmistachkin cd2[0] = (void *)p; 28058e18922fSmistachkin cd2[1] = (void *)pScript; 28068e18922fSmistachkin rc = DbEvalNextCmd(cd2, interp, TCL_OK); 28071807ce37Sdrh } 280830ccda10Sdanielk1977 break; 280930ccda10Sdanielk1977 } 2810bec3f402Sdrh 2811bec3f402Sdrh /* 28123df30592Sdan ** $db function NAME [-argcount N] [-deterministic] SCRIPT 2813cabb0819Sdrh ** 2814cabb0819Sdrh ** Create a new SQL function called NAME. Whenever that function is 2815cabb0819Sdrh ** called, invoke SCRIPT to evaluate the function. 2816cabb0819Sdrh */ 2817cabb0819Sdrh case DB_FUNCTION: { 28183df30592Sdan int flags = SQLITE_UTF8; 2819cabb0819Sdrh SqlFunc *pFunc; 2820d1e4733dSdrh Tcl_Obj *pScript; 2821cabb0819Sdrh char *zName; 2822e3602be8Sdrh int nArg = -1; 28233df30592Sdan int i; 282489d24936Sdan int eType = SQLITE_NULL; 28253df30592Sdan if( objc<4 ){ 28263df30592Sdan Tcl_WrongNumArgs(interp, 2, objv, "NAME ?SWITCHES? SCRIPT"); 28273df30592Sdan return TCL_ERROR; 28283df30592Sdan } 28293df30592Sdan for(i=3; i<(objc-1); i++){ 28303df30592Sdan const char *z = Tcl_GetString(objv[i]); 28314f21c4afSdrh int n = strlen30(z); 283289d24936Sdan if( n>1 && strncmp(z, "-argcount",n)==0 ){ 28333df30592Sdan if( i==(objc-2) ){ 2834ea8f0a15Sdrh Tcl_AppendResult(interp, "option requires an argument: ", z,(char*)0); 28353df30592Sdan return TCL_ERROR; 28363df30592Sdan } 28373df30592Sdan if( Tcl_GetIntFromObj(interp, objv[i+1], &nArg) ) return TCL_ERROR; 2838e3602be8Sdrh if( nArg<0 ){ 2839e3602be8Sdrh Tcl_AppendResult(interp, "number of arguments must be non-negative", 2840e3602be8Sdrh (char*)0); 2841cabb0819Sdrh return TCL_ERROR; 2842cabb0819Sdrh } 28433df30592Sdan i++; 28443df30592Sdan }else 284589d24936Sdan if( n>1 && strncmp(z, "-deterministic",n)==0 ){ 28463df30592Sdan flags |= SQLITE_DETERMINISTIC; 284789d24936Sdan }else 284889d24936Sdan if( n>1 && strncmp(z, "-returntype", n)==0 ){ 284989d24936Sdan const char *azType[] = {"integer", "real", "text", "blob", "any", 0}; 285089d24936Sdan assert( SQLITE_INTEGER==1 && SQLITE_FLOAT==2 && SQLITE_TEXT==3 ); 285189d24936Sdan assert( SQLITE_BLOB==4 && SQLITE_NULL==5 ); 285289d24936Sdan if( i==(objc-2) ){ 285389d24936Sdan Tcl_AppendResult(interp, "option requires an argument: ", z,(char*)0); 285489d24936Sdan return TCL_ERROR; 285589d24936Sdan } 285689d24936Sdan i++; 285789d24936Sdan if( Tcl_GetIndexFromObj(interp, objv[i], azType, "type", 0, &eType) ){ 285889d24936Sdan return TCL_ERROR; 285989d24936Sdan } 286089d24936Sdan eType++; 2861e3602be8Sdrh }else{ 28623df30592Sdan Tcl_AppendResult(interp, "bad option \"", z, 286389d24936Sdan "\": must be -argcount, -deterministic or -returntype", (char*)0 28643df30592Sdan ); 28653df30592Sdan return TCL_ERROR; 2866e3602be8Sdrh } 28673df30592Sdan } 28683df30592Sdan 28693df30592Sdan pScript = objv[objc-1]; 2870e3602be8Sdrh zName = Tcl_GetStringFromObj(objv[2], 0); 2871d1e4733dSdrh pFunc = findSqlFunc(pDb, zName); 2872cabb0819Sdrh if( pFunc==0 ) return TCL_ERROR; 2873d1e4733dSdrh if( pFunc->pScript ){ 2874d1e4733dSdrh Tcl_DecrRefCount(pFunc->pScript); 2875d1e4733dSdrh } 2876d1e4733dSdrh pFunc->pScript = pScript; 2877d1e4733dSdrh Tcl_IncrRefCount(pScript); 2878d1e4733dSdrh pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript); 287989d24936Sdan pFunc->eType = eType; 28803df30592Sdan rc = sqlite3_create_function(pDb->db, zName, nArg, flags, 2881d8123366Sdanielk1977 pFunc, tclSqlFunc, 0, 0); 2882fb7e7651Sdrh if( rc!=SQLITE_OK ){ 2883fb7e7651Sdrh rc = TCL_ERROR; 28849636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 2885fb7e7651Sdrh } 2886cabb0819Sdrh break; 2887cabb0819Sdrh } 2888cabb0819Sdrh 2889cabb0819Sdrh /* 28908cbadb02Sdanielk1977 ** $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID 2891b4e9af9fSdanielk1977 */ 2892b4e9af9fSdanielk1977 case DB_INCRBLOB: { 289332a0d8bbSdanielk1977 #ifdef SQLITE_OMIT_INCRBLOB 2894a198f2b5Sdrh Tcl_AppendResult(interp, "incrblob not available in this build", (char*)0); 289532a0d8bbSdanielk1977 return TCL_ERROR; 289632a0d8bbSdanielk1977 #else 28978cbadb02Sdanielk1977 int isReadonly = 0; 2898b4e9af9fSdanielk1977 const char *zDb = "main"; 2899b4e9af9fSdanielk1977 const char *zTable; 2900b4e9af9fSdanielk1977 const char *zColumn; 2901b3f787f4Sdrh Tcl_WideInt iRow; 2902b4e9af9fSdanielk1977 29038cbadb02Sdanielk1977 /* Check for the -readonly option */ 29048cbadb02Sdanielk1977 if( objc>3 && strcmp(Tcl_GetString(objv[2]), "-readonly")==0 ){ 29058cbadb02Sdanielk1977 isReadonly = 1; 29068cbadb02Sdanielk1977 } 29078cbadb02Sdanielk1977 29088cbadb02Sdanielk1977 if( objc!=(5+isReadonly) && objc!=(6+isReadonly) ){ 29098cbadb02Sdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID"); 2910b4e9af9fSdanielk1977 return TCL_ERROR; 2911b4e9af9fSdanielk1977 } 2912b4e9af9fSdanielk1977 29138cbadb02Sdanielk1977 if( objc==(6+isReadonly) ){ 2914b4e9af9fSdanielk1977 zDb = Tcl_GetString(objv[2]); 2915b4e9af9fSdanielk1977 } 2916b4e9af9fSdanielk1977 zTable = Tcl_GetString(objv[objc-3]); 2917b4e9af9fSdanielk1977 zColumn = Tcl_GetString(objv[objc-2]); 2918b4e9af9fSdanielk1977 rc = Tcl_GetWideIntFromObj(interp, objv[objc-1], &iRow); 2919b4e9af9fSdanielk1977 2920b4e9af9fSdanielk1977 if( rc==TCL_OK ){ 29218cbadb02Sdanielk1977 rc = createIncrblobChannel( 2922edf5b165Sdan interp, pDb, zDb, zTable, zColumn, (sqlite3_int64)iRow, isReadonly 29238cbadb02Sdanielk1977 ); 2924b4e9af9fSdanielk1977 } 292532a0d8bbSdanielk1977 #endif 2926b4e9af9fSdanielk1977 break; 2927b4e9af9fSdanielk1977 } 2928b4e9af9fSdanielk1977 2929b4e9af9fSdanielk1977 /* 2930f11bded5Sdrh ** $db interrupt 2931f11bded5Sdrh ** 2932f11bded5Sdrh ** Interrupt the execution of the inner-most SQL interpreter. This 2933f11bded5Sdrh ** causes the SQL statement to return an error of SQLITE_INTERRUPT. 2934f11bded5Sdrh */ 2935f11bded5Sdrh case DB_INTERRUPT: { 2936f11bded5Sdrh sqlite3_interrupt(pDb->db); 2937f11bded5Sdrh break; 2938f11bded5Sdrh } 2939f11bded5Sdrh 2940f11bded5Sdrh /* 294119e2d37fSdrh ** $db nullvalue ?STRING? 294219e2d37fSdrh ** 294319e2d37fSdrh ** Change text used when a NULL comes back from the database. If ?STRING? 294419e2d37fSdrh ** is not present, then the current string used for NULL is returned. 294519e2d37fSdrh ** If STRING is present, then STRING is returned. 294619e2d37fSdrh ** 294719e2d37fSdrh */ 294819e2d37fSdrh case DB_NULLVALUE: { 294919e2d37fSdrh if( objc!=2 && objc!=3 ){ 295019e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE"); 295119e2d37fSdrh return TCL_ERROR; 295219e2d37fSdrh } 295319e2d37fSdrh if( objc==3 ){ 295419e2d37fSdrh int len; 295519e2d37fSdrh char *zNull = Tcl_GetStringFromObj(objv[2], &len); 295619e2d37fSdrh if( pDb->zNull ){ 295719e2d37fSdrh Tcl_Free(pDb->zNull); 295819e2d37fSdrh } 295919e2d37fSdrh if( zNull && len>0 ){ 296019e2d37fSdrh pDb->zNull = Tcl_Alloc( len + 1 ); 29617fd33929Sdrh memcpy(pDb->zNull, zNull, len); 296219e2d37fSdrh pDb->zNull[len] = '\0'; 296319e2d37fSdrh }else{ 296419e2d37fSdrh pDb->zNull = 0; 296519e2d37fSdrh } 296619e2d37fSdrh } 2967c45e6716Sdrh Tcl_SetObjResult(interp, Tcl_NewStringObj(pDb->zNull, -1)); 296819e2d37fSdrh break; 296919e2d37fSdrh } 297019e2d37fSdrh 297119e2d37fSdrh /* 2972af9ff33aSdrh ** $db last_insert_rowid 2973af9ff33aSdrh ** 2974af9ff33aSdrh ** Return an integer which is the ROWID for the most recent insert. 2975af9ff33aSdrh */ 2976af9ff33aSdrh case DB_LAST_INSERT_ROWID: { 2977af9ff33aSdrh Tcl_Obj *pResult; 2978f7e678d6Sdrh Tcl_WideInt rowid; 2979af9ff33aSdrh if( objc!=2 ){ 2980af9ff33aSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 2981af9ff33aSdrh return TCL_ERROR; 2982af9ff33aSdrh } 29836f8a503dSdanielk1977 rowid = sqlite3_last_insert_rowid(pDb->db); 2984af9ff33aSdrh pResult = Tcl_GetObjResult(interp); 2985f7e678d6Sdrh Tcl_SetWideIntObj(pResult, rowid); 2986af9ff33aSdrh break; 2987af9ff33aSdrh } 2988af9ff33aSdrh 2989af9ff33aSdrh /* 29904a4c11aaSdan ** The DB_ONECOLUMN method is implemented together with DB_EXISTS. 29915d9d7576Sdrh */ 29921807ce37Sdrh 29931807ce37Sdrh /* $db progress ?N CALLBACK? 29941807ce37Sdrh ** 29951807ce37Sdrh ** Invoke the given callback every N virtual machine opcodes while executing 29961807ce37Sdrh ** queries. 29971807ce37Sdrh */ 29981807ce37Sdrh case DB_PROGRESS: { 29991807ce37Sdrh if( objc==2 ){ 30001807ce37Sdrh if( pDb->zProgress ){ 3001a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zProgress, (char*)0); 30025d9d7576Sdrh } 30031807ce37Sdrh }else if( objc==4 ){ 30041807ce37Sdrh char *zProgress; 30051807ce37Sdrh int len; 30061807ce37Sdrh int N; 30071807ce37Sdrh if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ 30081807ce37Sdrh return TCL_ERROR; 30091807ce37Sdrh }; 30101807ce37Sdrh if( pDb->zProgress ){ 30111807ce37Sdrh Tcl_Free(pDb->zProgress); 30121807ce37Sdrh } 30131807ce37Sdrh zProgress = Tcl_GetStringFromObj(objv[3], &len); 30141807ce37Sdrh if( zProgress && len>0 ){ 30151807ce37Sdrh pDb->zProgress = Tcl_Alloc( len + 1 ); 30165bb3eb9bSdrh memcpy(pDb->zProgress, zProgress, len+1); 30171807ce37Sdrh }else{ 30181807ce37Sdrh pDb->zProgress = 0; 30191807ce37Sdrh } 30201807ce37Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK 30211807ce37Sdrh if( pDb->zProgress ){ 30221807ce37Sdrh pDb->interp = interp; 30231807ce37Sdrh sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb); 30241807ce37Sdrh }else{ 30251807ce37Sdrh sqlite3_progress_handler(pDb->db, 0, 0, 0); 30261807ce37Sdrh } 30271807ce37Sdrh #endif 30281807ce37Sdrh }else{ 30291807ce37Sdrh Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK"); 30301807ce37Sdrh return TCL_ERROR; 30315d9d7576Sdrh } 30325d9d7576Sdrh break; 30335d9d7576Sdrh } 30345d9d7576Sdrh 303519e2d37fSdrh /* $db profile ?CALLBACK? 303619e2d37fSdrh ** 303719e2d37fSdrh ** Make arrangements to invoke the CALLBACK routine after each SQL statement 303819e2d37fSdrh ** that has run. The text of the SQL and the amount of elapse time are 303919e2d37fSdrh ** appended to CALLBACK before the script is run. 304019e2d37fSdrh */ 304119e2d37fSdrh case DB_PROFILE: { 304219e2d37fSdrh if( objc>3 ){ 304319e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 304419e2d37fSdrh return TCL_ERROR; 304519e2d37fSdrh }else if( objc==2 ){ 304619e2d37fSdrh if( pDb->zProfile ){ 3047a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zProfile, (char*)0); 304819e2d37fSdrh } 304919e2d37fSdrh }else{ 305019e2d37fSdrh char *zProfile; 305119e2d37fSdrh int len; 305219e2d37fSdrh if( pDb->zProfile ){ 305319e2d37fSdrh Tcl_Free(pDb->zProfile); 305419e2d37fSdrh } 305519e2d37fSdrh zProfile = Tcl_GetStringFromObj(objv[2], &len); 305619e2d37fSdrh if( zProfile && len>0 ){ 305719e2d37fSdrh pDb->zProfile = Tcl_Alloc( len + 1 ); 30585bb3eb9bSdrh memcpy(pDb->zProfile, zProfile, len+1); 305919e2d37fSdrh }else{ 306019e2d37fSdrh pDb->zProfile = 0; 306119e2d37fSdrh } 30622eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 30632eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 306419e2d37fSdrh if( pDb->zProfile ){ 306519e2d37fSdrh pDb->interp = interp; 306619e2d37fSdrh sqlite3_profile(pDb->db, DbProfileHandler, pDb); 306719e2d37fSdrh }else{ 306819e2d37fSdrh sqlite3_profile(pDb->db, 0, 0); 306919e2d37fSdrh } 307019e2d37fSdrh #endif 307119e2d37fSdrh } 307219e2d37fSdrh break; 307319e2d37fSdrh } 307419e2d37fSdrh 30755d9d7576Sdrh /* 307622fbcb8dSdrh ** $db rekey KEY 307722fbcb8dSdrh ** 307822fbcb8dSdrh ** Change the encryption key on the currently open database. 307922fbcb8dSdrh */ 308022fbcb8dSdrh case DB_REKEY: { 308132f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 308222fbcb8dSdrh int nKey; 308322fbcb8dSdrh void *pKey; 3084b07028f7Sdrh #endif 308522fbcb8dSdrh if( objc!=3 ){ 308622fbcb8dSdrh Tcl_WrongNumArgs(interp, 2, objv, "KEY"); 308722fbcb8dSdrh return TCL_ERROR; 308822fbcb8dSdrh } 308932f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 3090b07028f7Sdrh pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); 30912011d5f5Sdrh rc = sqlite3_rekey(pDb->db, pKey, nKey); 309222fbcb8dSdrh if( rc ){ 3093a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0); 309422fbcb8dSdrh rc = TCL_ERROR; 309522fbcb8dSdrh } 309622fbcb8dSdrh #endif 309722fbcb8dSdrh break; 309822fbcb8dSdrh } 309922fbcb8dSdrh 3100dc2c4915Sdrh /* $db restore ?DATABASE? FILENAME 3101dc2c4915Sdrh ** 3102dc2c4915Sdrh ** Open a database file named FILENAME. Transfer the content 3103dc2c4915Sdrh ** of FILENAME into the local database DATABASE (default: "main"). 3104dc2c4915Sdrh */ 3105dc2c4915Sdrh case DB_RESTORE: { 3106dc2c4915Sdrh const char *zSrcFile; 3107dc2c4915Sdrh const char *zDestDb; 3108dc2c4915Sdrh sqlite3 *pSrc; 3109dc2c4915Sdrh sqlite3_backup *pBackup; 3110dc2c4915Sdrh int nTimeout = 0; 3111dc2c4915Sdrh 3112dc2c4915Sdrh if( objc==3 ){ 3113dc2c4915Sdrh zDestDb = "main"; 3114dc2c4915Sdrh zSrcFile = Tcl_GetString(objv[2]); 3115dc2c4915Sdrh }else if( objc==4 ){ 3116dc2c4915Sdrh zDestDb = Tcl_GetString(objv[2]); 3117dc2c4915Sdrh zSrcFile = Tcl_GetString(objv[3]); 3118dc2c4915Sdrh }else{ 3119dc2c4915Sdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME"); 3120dc2c4915Sdrh return TCL_ERROR; 3121dc2c4915Sdrh } 3122147ef394Sdrh rc = sqlite3_open_v2(zSrcFile, &pSrc, 3123147ef394Sdrh SQLITE_OPEN_READONLY | pDb->openFlags, 0); 3124dc2c4915Sdrh if( rc!=SQLITE_OK ){ 3125dc2c4915Sdrh Tcl_AppendResult(interp, "cannot open source database: ", 3126dc2c4915Sdrh sqlite3_errmsg(pSrc), (char*)0); 3127dc2c4915Sdrh sqlite3_close(pSrc); 3128dc2c4915Sdrh return TCL_ERROR; 3129dc2c4915Sdrh } 3130dc2c4915Sdrh pBackup = sqlite3_backup_init(pDb->db, zDestDb, pSrc, "main"); 3131dc2c4915Sdrh if( pBackup==0 ){ 3132dc2c4915Sdrh Tcl_AppendResult(interp, "restore failed: ", 3133dc2c4915Sdrh sqlite3_errmsg(pDb->db), (char*)0); 3134dc2c4915Sdrh sqlite3_close(pSrc); 3135dc2c4915Sdrh return TCL_ERROR; 3136dc2c4915Sdrh } 3137dc2c4915Sdrh while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK 3138dc2c4915Sdrh || rc==SQLITE_BUSY ){ 3139dc2c4915Sdrh if( rc==SQLITE_BUSY ){ 3140dc2c4915Sdrh if( nTimeout++ >= 3 ) break; 3141dc2c4915Sdrh sqlite3_sleep(100); 3142dc2c4915Sdrh } 3143dc2c4915Sdrh } 3144dc2c4915Sdrh sqlite3_backup_finish(pBackup); 3145dc2c4915Sdrh if( rc==SQLITE_DONE ){ 3146dc2c4915Sdrh rc = TCL_OK; 3147dc2c4915Sdrh }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ 3148dc2c4915Sdrh Tcl_AppendResult(interp, "restore failed: source database busy", 3149dc2c4915Sdrh (char*)0); 3150dc2c4915Sdrh rc = TCL_ERROR; 3151dc2c4915Sdrh }else{ 3152dc2c4915Sdrh Tcl_AppendResult(interp, "restore failed: ", 3153dc2c4915Sdrh sqlite3_errmsg(pDb->db), (char*)0); 3154dc2c4915Sdrh rc = TCL_ERROR; 3155dc2c4915Sdrh } 3156dc2c4915Sdrh sqlite3_close(pSrc); 3157dc2c4915Sdrh break; 3158dc2c4915Sdrh } 3159dc2c4915Sdrh 316022fbcb8dSdrh /* 3161cb7d541dSdrh ** $db serialize ?DATABASE? 3162cb7d541dSdrh ** 3163cb7d541dSdrh ** Return a serialization of a database. 3164cb7d541dSdrh */ 3165cb7d541dSdrh case DB_SERIALIZE: { 31669c6396ecSdrh #ifndef SQLITE_ENABLE_DESERIALIZE 3167cb7d541dSdrh Tcl_AppendResult(interp, "MEMDB not available in this build", 3168cb7d541dSdrh (char*)0); 3169cb7d541dSdrh rc = TCL_ERROR; 3170cb7d541dSdrh #else 3171cb7d541dSdrh const char *zSchema = objc>=3 ? Tcl_GetString(objv[2]) : "main"; 3172cb7d541dSdrh sqlite3_int64 sz = 0; 3173cb7d541dSdrh unsigned char *pData; 3174cb7d541dSdrh if( objc!=2 && objc!=3 ){ 3175cb7d541dSdrh Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE?"); 3176cb7d541dSdrh rc = TCL_ERROR; 3177cb7d541dSdrh }else{ 3178cb7d541dSdrh int needFree; 3179cb7d541dSdrh pData = sqlite3_serialize(pDb->db, zSchema, &sz, SQLITE_SERIALIZE_NOCOPY); 3180cb7d541dSdrh if( pData ){ 3181cb7d541dSdrh needFree = 0; 3182cb7d541dSdrh }else{ 3183cb7d541dSdrh pData = sqlite3_serialize(pDb->db, zSchema, &sz, 0); 3184cb7d541dSdrh needFree = 1; 3185cb7d541dSdrh } 3186cb7d541dSdrh Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pData,sz)); 3187cb7d541dSdrh if( needFree ) sqlite3_free(pData); 3188cb7d541dSdrh } 3189cb7d541dSdrh #endif 3190cb7d541dSdrh break; 3191cb7d541dSdrh } 3192cb7d541dSdrh 3193cb7d541dSdrh /* 3194c456a76fSdan ** $db status (step|sort|autoindex|vmstep) 3195d1d38488Sdrh ** 3196d1d38488Sdrh ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or 3197d1d38488Sdrh ** SQLITE_STMTSTATUS_SORT for the most recent eval. 3198d1d38488Sdrh */ 3199d1d38488Sdrh case DB_STATUS: { 3200d1d38488Sdrh int v; 3201d1d38488Sdrh const char *zOp; 3202d1d38488Sdrh if( objc!=3 ){ 32031c320a43Sdrh Tcl_WrongNumArgs(interp, 2, objv, "(step|sort|autoindex)"); 3204d1d38488Sdrh return TCL_ERROR; 3205d1d38488Sdrh } 3206d1d38488Sdrh zOp = Tcl_GetString(objv[2]); 3207d1d38488Sdrh if( strcmp(zOp, "step")==0 ){ 3208d1d38488Sdrh v = pDb->nStep; 3209d1d38488Sdrh }else if( strcmp(zOp, "sort")==0 ){ 3210d1d38488Sdrh v = pDb->nSort; 32113c379b01Sdrh }else if( strcmp(zOp, "autoindex")==0 ){ 32123c379b01Sdrh v = pDb->nIndex; 3213c456a76fSdan }else if( strcmp(zOp, "vmstep")==0 ){ 3214c456a76fSdan v = pDb->nVMStep; 3215d1d38488Sdrh }else{ 32163c379b01Sdrh Tcl_AppendResult(interp, 3217c456a76fSdan "bad argument: should be autoindex, step, sort or vmstep", 3218d1d38488Sdrh (char*)0); 3219d1d38488Sdrh return TCL_ERROR; 3220d1d38488Sdrh } 3221d1d38488Sdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(v)); 3222d1d38488Sdrh break; 3223d1d38488Sdrh } 3224d1d38488Sdrh 3225d1d38488Sdrh /* 3226bec3f402Sdrh ** $db timeout MILLESECONDS 3227bec3f402Sdrh ** 3228bec3f402Sdrh ** Delay for the number of milliseconds specified when a file is locked. 3229bec3f402Sdrh */ 32306d31316cSdrh case DB_TIMEOUT: { 3231bec3f402Sdrh int ms; 32326d31316cSdrh if( objc!=3 ){ 32336d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS"); 3234bec3f402Sdrh return TCL_ERROR; 323575897234Sdrh } 32366d31316cSdrh if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR; 32376f8a503dSdanielk1977 sqlite3_busy_timeout(pDb->db, ms); 32386d31316cSdrh break; 323975897234Sdrh } 3240b5a20d3cSdrh 32410f14e2ebSdrh /* 32420f14e2ebSdrh ** $db total_changes 32430f14e2ebSdrh ** 32440f14e2ebSdrh ** Return the number of rows that were modified, inserted, or deleted 32450f14e2ebSdrh ** since the database handle was created. 32460f14e2ebSdrh */ 32470f14e2ebSdrh case DB_TOTAL_CHANGES: { 32480f14e2ebSdrh Tcl_Obj *pResult; 32490f14e2ebSdrh if( objc!=2 ){ 32500f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 32510f14e2ebSdrh return TCL_ERROR; 32520f14e2ebSdrh } 32530f14e2ebSdrh pResult = Tcl_GetObjResult(interp); 32540f14e2ebSdrh Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db)); 32550f14e2ebSdrh break; 32560f14e2ebSdrh } 32570f14e2ebSdrh 3258b5a20d3cSdrh /* $db trace ?CALLBACK? 3259b5a20d3cSdrh ** 3260b5a20d3cSdrh ** Make arrangements to invoke the CALLBACK routine for each SQL statement 3261b5a20d3cSdrh ** that is executed. The text of the SQL is appended to CALLBACK before 3262b5a20d3cSdrh ** it is executed. 3263b5a20d3cSdrh */ 3264b5a20d3cSdrh case DB_TRACE: { 3265b5a20d3cSdrh if( objc>3 ){ 3266b5a20d3cSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 3267b97759edSdrh return TCL_ERROR; 3268b5a20d3cSdrh }else if( objc==2 ){ 3269b5a20d3cSdrh if( pDb->zTrace ){ 3270a198f2b5Sdrh Tcl_AppendResult(interp, pDb->zTrace, (char*)0); 3271b5a20d3cSdrh } 3272b5a20d3cSdrh }else{ 3273b5a20d3cSdrh char *zTrace; 3274b5a20d3cSdrh int len; 3275b5a20d3cSdrh if( pDb->zTrace ){ 3276b5a20d3cSdrh Tcl_Free(pDb->zTrace); 3277b5a20d3cSdrh } 3278b5a20d3cSdrh zTrace = Tcl_GetStringFromObj(objv[2], &len); 3279b5a20d3cSdrh if( zTrace && len>0 ){ 3280b5a20d3cSdrh pDb->zTrace = Tcl_Alloc( len + 1 ); 32815bb3eb9bSdrh memcpy(pDb->zTrace, zTrace, len+1); 3282b5a20d3cSdrh }else{ 3283b5a20d3cSdrh pDb->zTrace = 0; 3284b5a20d3cSdrh } 32852eb22af0Sdrh #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) && \ 32862eb22af0Sdrh !defined(SQLITE_OMIT_DEPRECATED) 3287b5a20d3cSdrh if( pDb->zTrace ){ 3288b5a20d3cSdrh pDb->interp = interp; 32896f8a503dSdanielk1977 sqlite3_trace(pDb->db, DbTraceHandler, pDb); 3290b5a20d3cSdrh }else{ 32916f8a503dSdanielk1977 sqlite3_trace(pDb->db, 0, 0); 3292b5a20d3cSdrh } 329319e2d37fSdrh #endif 3294b5a20d3cSdrh } 3295b5a20d3cSdrh break; 3296b5a20d3cSdrh } 3297b5a20d3cSdrh 3298b56660f5Smistachkin /* $db trace_v2 ?CALLBACK? ?MASK? 3299b56660f5Smistachkin ** 3300b56660f5Smistachkin ** Make arrangements to invoke the CALLBACK routine for each trace event 3301b56660f5Smistachkin ** matching the mask that is generated. The parameters are appended to 3302b56660f5Smistachkin ** CALLBACK before it is executed. 3303b56660f5Smistachkin */ 3304b56660f5Smistachkin case DB_TRACE_V2: { 3305b56660f5Smistachkin if( objc>4 ){ 3306b56660f5Smistachkin Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK? ?MASK?"); 3307b56660f5Smistachkin return TCL_ERROR; 3308b56660f5Smistachkin }else if( objc==2 ){ 3309b56660f5Smistachkin if( pDb->zTraceV2 ){ 3310b56660f5Smistachkin Tcl_AppendResult(interp, pDb->zTraceV2, (char*)0); 3311b56660f5Smistachkin } 3312b56660f5Smistachkin }else{ 3313b56660f5Smistachkin char *zTraceV2; 3314b56660f5Smistachkin int len; 3315b52dcd89Smistachkin Tcl_WideInt wMask = 0; 3316b56660f5Smistachkin if( objc==4 ){ 3317b52dcd89Smistachkin static const char *TTYPE_strs[] = { 3318b52dcd89Smistachkin "statement", "profile", "row", "close", 0 3319b52dcd89Smistachkin }; 3320b52dcd89Smistachkin enum TTYPE_enum { 3321b52dcd89Smistachkin TTYPE_STMT, TTYPE_PROFILE, TTYPE_ROW, TTYPE_CLOSE 3322b52dcd89Smistachkin }; 3323b52dcd89Smistachkin int i; 3324b52dcd89Smistachkin if( TCL_OK!=Tcl_ListObjLength(interp, objv[3], &len) ){ 3325b52dcd89Smistachkin return TCL_ERROR; 3326b52dcd89Smistachkin } 3327b52dcd89Smistachkin for(i=0; i<len; i++){ 3328b52dcd89Smistachkin Tcl_Obj *pObj; 3329b52dcd89Smistachkin int ttype; 3330b52dcd89Smistachkin if( TCL_OK!=Tcl_ListObjIndex(interp, objv[3], i, &pObj) ){ 3331b52dcd89Smistachkin return TCL_ERROR; 3332b52dcd89Smistachkin } 3333b52dcd89Smistachkin if( Tcl_GetIndexFromObj(interp, pObj, TTYPE_strs, "trace type", 3334b52dcd89Smistachkin 0, &ttype)!=TCL_OK ){ 3335b52dcd89Smistachkin Tcl_WideInt wType; 3336b52dcd89Smistachkin Tcl_Obj *pError = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); 3337b52dcd89Smistachkin Tcl_IncrRefCount(pError); 3338b52dcd89Smistachkin if( TCL_OK==Tcl_GetWideIntFromObj(interp, pObj, &wType) ){ 3339b52dcd89Smistachkin Tcl_DecrRefCount(pError); 3340b52dcd89Smistachkin wMask |= wType; 3341b52dcd89Smistachkin }else{ 3342b52dcd89Smistachkin Tcl_SetObjResult(interp, pError); 3343b52dcd89Smistachkin Tcl_DecrRefCount(pError); 3344b56660f5Smistachkin return TCL_ERROR; 3345b56660f5Smistachkin } 3346b56660f5Smistachkin }else{ 3347b52dcd89Smistachkin switch( (enum TTYPE_enum)ttype ){ 3348b52dcd89Smistachkin case TTYPE_STMT: wMask |= SQLITE_TRACE_STMT; break; 3349b52dcd89Smistachkin case TTYPE_PROFILE: wMask |= SQLITE_TRACE_PROFILE; break; 3350b52dcd89Smistachkin case TTYPE_ROW: wMask |= SQLITE_TRACE_ROW; break; 3351b52dcd89Smistachkin case TTYPE_CLOSE: wMask |= SQLITE_TRACE_CLOSE; break; 3352b52dcd89Smistachkin } 3353b52dcd89Smistachkin } 3354b52dcd89Smistachkin } 3355b52dcd89Smistachkin }else{ 3356b52dcd89Smistachkin wMask = SQLITE_TRACE_STMT; /* use the "legacy" default */ 3357b56660f5Smistachkin } 3358b56660f5Smistachkin if( pDb->zTraceV2 ){ 3359b56660f5Smistachkin Tcl_Free(pDb->zTraceV2); 3360b56660f5Smistachkin } 3361b56660f5Smistachkin zTraceV2 = Tcl_GetStringFromObj(objv[2], &len); 3362b56660f5Smistachkin if( zTraceV2 && len>0 ){ 3363b56660f5Smistachkin pDb->zTraceV2 = Tcl_Alloc( len + 1 ); 3364b56660f5Smistachkin memcpy(pDb->zTraceV2, zTraceV2, len+1); 3365b56660f5Smistachkin }else{ 3366b56660f5Smistachkin pDb->zTraceV2 = 0; 3367b56660f5Smistachkin } 3368b56660f5Smistachkin #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) 3369b56660f5Smistachkin if( pDb->zTraceV2 ){ 3370b56660f5Smistachkin pDb->interp = interp; 3371b56660f5Smistachkin sqlite3_trace_v2(pDb->db, (unsigned)wMask, DbTraceV2Handler, pDb); 3372b56660f5Smistachkin }else{ 3373b56660f5Smistachkin sqlite3_trace_v2(pDb->db, 0, 0, 0); 3374b56660f5Smistachkin } 3375b56660f5Smistachkin #endif 3376b56660f5Smistachkin } 3377b56660f5Smistachkin break; 3378b56660f5Smistachkin } 3379b56660f5Smistachkin 33803d21423cSdrh /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT 33813d21423cSdrh ** 33823d21423cSdrh ** Start a new transaction (if we are not already in the midst of a 33833d21423cSdrh ** transaction) and execute the TCL script SCRIPT. After SCRIPT 33843d21423cSdrh ** completes, either commit the transaction or roll it back if SCRIPT 33853d21423cSdrh ** throws an exception. Or if no new transation was started, do nothing. 33863d21423cSdrh ** pass the exception on up the stack. 33873d21423cSdrh ** 33883d21423cSdrh ** This command was inspired by Dave Thomas's talk on Ruby at the 33893d21423cSdrh ** 2005 O'Reilly Open Source Convention (OSCON). 33903d21423cSdrh */ 33913d21423cSdrh case DB_TRANSACTION: { 33923d21423cSdrh Tcl_Obj *pScript; 3393cd38d520Sdanielk1977 const char *zBegin = "SAVEPOINT _tcl_transaction"; 33943d21423cSdrh if( objc!=3 && objc!=4 ){ 33953d21423cSdrh Tcl_WrongNumArgs(interp, 2, objv, "[TYPE] SCRIPT"); 33963d21423cSdrh return TCL_ERROR; 33973d21423cSdrh } 3398cd38d520Sdanielk1977 33994a4c11aaSdan if( pDb->nTransaction==0 && objc==4 ){ 34003d21423cSdrh static const char *TTYPE_strs[] = { 3401ce604012Sdrh "deferred", "exclusive", "immediate", 0 34023d21423cSdrh }; 34033d21423cSdrh enum TTYPE_enum { 34043d21423cSdrh TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE 34053d21423cSdrh }; 34063d21423cSdrh int ttype; 3407b5555e7eSdrh if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type", 34083d21423cSdrh 0, &ttype) ){ 34093d21423cSdrh return TCL_ERROR; 34103d21423cSdrh } 34113d21423cSdrh switch( (enum TTYPE_enum)ttype ){ 34123d21423cSdrh case TTYPE_DEFERRED: /* no-op */; break; 34133d21423cSdrh case TTYPE_EXCLUSIVE: zBegin = "BEGIN EXCLUSIVE"; break; 34143d21423cSdrh case TTYPE_IMMEDIATE: zBegin = "BEGIN IMMEDIATE"; break; 34153d21423cSdrh } 34163d21423cSdrh } 3417cd38d520Sdanielk1977 pScript = objv[objc-1]; 3418cd38d520Sdanielk1977 34194a4c11aaSdan /* Run the SQLite BEGIN command to open a transaction or savepoint. */ 34201f1549f8Sdrh pDb->disableAuth++; 3421cd38d520Sdanielk1977 rc = sqlite3_exec(pDb->db, zBegin, 0, 0, 0); 34221f1549f8Sdrh pDb->disableAuth--; 3423cd38d520Sdanielk1977 if( rc!=SQLITE_OK ){ 3424a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 3425cd38d520Sdanielk1977 return TCL_ERROR; 34263d21423cSdrh } 3427cd38d520Sdanielk1977 pDb->nTransaction++; 3428cd38d520Sdanielk1977 34294a4c11aaSdan /* If using NRE, schedule a callback to invoke the script pScript, then 34304a4c11aaSdan ** a second callback to commit (or rollback) the transaction or savepoint 34314a4c11aaSdan ** opened above. If not using NRE, evaluate the script directly, then 34324a4c11aaSdan ** call function DbTransPostCmd() to commit (or rollback) the transaction 34334a4c11aaSdan ** or savepoint. */ 34344a4c11aaSdan if( DbUseNre() ){ 34354a4c11aaSdan Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0); 3436a47941feSdrh (void)Tcl_NREvalObj(interp, pScript, 0); 34373d21423cSdrh }else{ 34384a4c11aaSdan rc = DbTransPostCmd(&cd, interp, Tcl_EvalObjEx(interp, pScript, 0)); 34393d21423cSdrh } 34403d21423cSdrh break; 34413d21423cSdrh } 34423d21423cSdrh 344394eb6a14Sdanielk1977 /* 3444404ca075Sdanielk1977 ** $db unlock_notify ?script? 3445404ca075Sdanielk1977 */ 3446404ca075Sdanielk1977 case DB_UNLOCK_NOTIFY: { 3447404ca075Sdanielk1977 #ifndef SQLITE_ENABLE_UNLOCK_NOTIFY 3448a198f2b5Sdrh Tcl_AppendResult(interp, "unlock_notify not available in this build", 3449a198f2b5Sdrh (char*)0); 3450404ca075Sdanielk1977 rc = TCL_ERROR; 3451404ca075Sdanielk1977 #else 3452404ca075Sdanielk1977 if( objc!=2 && objc!=3 ){ 3453404ca075Sdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); 3454404ca075Sdanielk1977 rc = TCL_ERROR; 3455404ca075Sdanielk1977 }else{ 3456404ca075Sdanielk1977 void (*xNotify)(void **, int) = 0; 3457404ca075Sdanielk1977 void *pNotifyArg = 0; 3458404ca075Sdanielk1977 3459404ca075Sdanielk1977 if( pDb->pUnlockNotify ){ 3460404ca075Sdanielk1977 Tcl_DecrRefCount(pDb->pUnlockNotify); 3461404ca075Sdanielk1977 pDb->pUnlockNotify = 0; 3462404ca075Sdanielk1977 } 3463404ca075Sdanielk1977 3464404ca075Sdanielk1977 if( objc==3 ){ 3465404ca075Sdanielk1977 xNotify = DbUnlockNotify; 3466404ca075Sdanielk1977 pNotifyArg = (void *)pDb; 3467404ca075Sdanielk1977 pDb->pUnlockNotify = objv[2]; 3468404ca075Sdanielk1977 Tcl_IncrRefCount(pDb->pUnlockNotify); 3469404ca075Sdanielk1977 } 3470404ca075Sdanielk1977 3471404ca075Sdanielk1977 if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){ 3472a198f2b5Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 3473404ca075Sdanielk1977 rc = TCL_ERROR; 3474404ca075Sdanielk1977 } 3475404ca075Sdanielk1977 } 3476404ca075Sdanielk1977 #endif 3477404ca075Sdanielk1977 break; 3478404ca075Sdanielk1977 } 3479404ca075Sdanielk1977 3480304637c0Sdrh /* 3481304637c0Sdrh ** $db preupdate_hook count 3482304637c0Sdrh ** $db preupdate_hook hook ?SCRIPT? 3483304637c0Sdrh ** $db preupdate_hook new INDEX 3484304637c0Sdrh ** $db preupdate_hook old INDEX 3485304637c0Sdrh */ 348646c47d46Sdan case DB_PREUPDATE: { 34879b1c62d4Sdrh #ifndef SQLITE_ENABLE_PREUPDATE_HOOK 34882b519ab0Sdan Tcl_AppendResult(interp, "preupdate_hook was omitted at compile-time", 34892b519ab0Sdan (char*)0); 34909b1c62d4Sdrh rc = TCL_ERROR; 34919b1c62d4Sdrh #else 34921e7a2d43Sdan static const char *azSub[] = {"count", "depth", "hook", "new", "old", 0}; 349346c47d46Sdan enum DbPreupdateSubCmd { 34941e7a2d43Sdan PRE_COUNT, PRE_DEPTH, PRE_HOOK, PRE_NEW, PRE_OLD 349546c47d46Sdan }; 349646c47d46Sdan int iSub; 349746c47d46Sdan 349846c47d46Sdan if( objc<3 ){ 349946c47d46Sdan Tcl_WrongNumArgs(interp, 2, objv, "SUB-COMMAND ?ARGS?"); 350046c47d46Sdan } 350146c47d46Sdan if( Tcl_GetIndexFromObj(interp, objv[2], azSub, "sub-command", 0, &iSub) ){ 350246c47d46Sdan return TCL_ERROR; 350346c47d46Sdan } 350446c47d46Sdan 350546c47d46Sdan switch( (enum DbPreupdateSubCmd)iSub ){ 350646c47d46Sdan case PRE_COUNT: { 350746c47d46Sdan int nCol = sqlite3_preupdate_count(pDb->db); 350846c47d46Sdan Tcl_SetObjResult(interp, Tcl_NewIntObj(nCol)); 350946c47d46Sdan break; 351046c47d46Sdan } 351146c47d46Sdan 351246c47d46Sdan case PRE_HOOK: { 351346c47d46Sdan if( objc>4 ){ 351446c47d46Sdan Tcl_WrongNumArgs(interp, 2, objv, "hook ?SCRIPT?"); 351546c47d46Sdan return TCL_ERROR; 351646c47d46Sdan } 351746c47d46Sdan DbHookCmd(interp, pDb, (objc==4 ? objv[3] : 0), &pDb->pPreUpdateHook); 351846c47d46Sdan break; 351946c47d46Sdan } 352046c47d46Sdan 35211e7a2d43Sdan case PRE_DEPTH: { 35221e7a2d43Sdan Tcl_Obj *pRet; 35231e7a2d43Sdan if( objc!=3 ){ 35241e7a2d43Sdan Tcl_WrongNumArgs(interp, 3, objv, ""); 35251e7a2d43Sdan return TCL_ERROR; 35261e7a2d43Sdan } 35271e7a2d43Sdan pRet = Tcl_NewIntObj(sqlite3_preupdate_depth(pDb->db)); 35281e7a2d43Sdan Tcl_SetObjResult(interp, pRet); 35291e7a2d43Sdan break; 35301e7a2d43Sdan } 35311e7a2d43Sdan 353237db03bfSdan case PRE_NEW: 353346c47d46Sdan case PRE_OLD: { 353446c47d46Sdan int iIdx; 353537db03bfSdan sqlite3_value *pValue; 353646c47d46Sdan if( objc!=4 ){ 353746c47d46Sdan Tcl_WrongNumArgs(interp, 3, objv, "INDEX"); 353846c47d46Sdan return TCL_ERROR; 353946c47d46Sdan } 354046c47d46Sdan if( Tcl_GetIntFromObj(interp, objv[3], &iIdx) ){ 354146c47d46Sdan return TCL_ERROR; 354246c47d46Sdan } 354346c47d46Sdan 354437db03bfSdan if( iSub==PRE_OLD ){ 354546c47d46Sdan rc = sqlite3_preupdate_old(pDb->db, iIdx, &pValue); 354637db03bfSdan }else{ 354737db03bfSdan assert( iSub==PRE_NEW ); 354837db03bfSdan rc = sqlite3_preupdate_new(pDb->db, iIdx, &pValue); 354937db03bfSdan } 355037db03bfSdan 355146c47d46Sdan if( rc==SQLITE_OK ){ 3552304637c0Sdrh Tcl_Obj *pObj; 3553304637c0Sdrh pObj = Tcl_NewStringObj((char*)sqlite3_value_text(pValue), -1); 355446c47d46Sdan Tcl_SetObjResult(interp, pObj); 355537db03bfSdan }else{ 3556ea8f0a15Sdrh Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); 355746c47d46Sdan return TCL_ERROR; 355846c47d46Sdan } 355946c47d46Sdan } 356046c47d46Sdan } 35619b1c62d4Sdrh #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ 356246c47d46Sdan break; 356346c47d46Sdan } 356446c47d46Sdan 3565404ca075Sdanielk1977 /* 3566833bf968Sdrh ** $db wal_hook ?script? 356794eb6a14Sdanielk1977 ** $db update_hook ?script? 356871fd80bfSdanielk1977 ** $db rollback_hook ?script? 356994eb6a14Sdanielk1977 */ 3570833bf968Sdrh case DB_WAL_HOOK: 357171fd80bfSdanielk1977 case DB_UPDATE_HOOK: 35726566ebe1Sdan case DB_ROLLBACK_HOOK: { 357371fd80bfSdanielk1977 /* set ppHook to point at pUpdateHook or pRollbackHook, depending on 357471fd80bfSdanielk1977 ** whether [$db update_hook] or [$db rollback_hook] was invoked. 357571fd80bfSdanielk1977 */ 3576c5896b5cSmistachkin Tcl_Obj **ppHook = 0; 357746c47d46Sdan if( choice==DB_WAL_HOOK ) ppHook = &pDb->pWalHook; 357846c47d46Sdan if( choice==DB_UPDATE_HOOK ) ppHook = &pDb->pUpdateHook; 357946c47d46Sdan if( choice==DB_ROLLBACK_HOOK ) ppHook = &pDb->pRollbackHook; 358046c47d46Sdan if( objc>3 ){ 358194eb6a14Sdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); 358294eb6a14Sdanielk1977 return TCL_ERROR; 358394eb6a14Sdanielk1977 } 358471fd80bfSdanielk1977 358546c47d46Sdan DbHookCmd(interp, pDb, (objc==3 ? objv[2] : 0), ppHook); 358694eb6a14Sdanielk1977 break; 358794eb6a14Sdanielk1977 } 358894eb6a14Sdanielk1977 35894397de57Sdanielk1977 /* $db version 35904397de57Sdanielk1977 ** 35914397de57Sdanielk1977 ** Return the version string for this database. 35924397de57Sdanielk1977 */ 35934397de57Sdanielk1977 case DB_VERSION: { 35941df6470dSdrh int i; 35951df6470dSdrh for(i=2; i<objc; i++){ 35961df6470dSdrh const char *zArg = Tcl_GetString(objv[i]); 35971df6470dSdrh /* Optional arguments to $db version are used for testing purpose */ 35981df6470dSdrh #ifdef SQLITE_TEST 35991df6470dSdrh /* $db version -use-legacy-prepare BOOLEAN 36001df6470dSdrh ** 36011df6470dSdrh ** Turn the use of legacy sqlite3_prepare() on or off. 36021df6470dSdrh */ 36031df6470dSdrh if( strcmp(zArg, "-use-legacy-prepare")==0 && i+1<objc ){ 36041df6470dSdrh i++; 36051df6470dSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &pDb->bLegacyPrepare) ){ 36061df6470dSdrh return TCL_ERROR; 36071df6470dSdrh } 36081df6470dSdrh }else 36091df6470dSdrh 36101df6470dSdrh /* $db version -last-stmt-ptr 36111df6470dSdrh ** 36121df6470dSdrh ** Return a string which is a hex encoding of the pointer to the 36131df6470dSdrh ** most recent sqlite3_stmt in the statement cache. 36141df6470dSdrh */ 36151df6470dSdrh if( strcmp(zArg, "-last-stmt-ptr")==0 ){ 36161df6470dSdrh char zBuf[100]; 36171df6470dSdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", 36181df6470dSdrh pDb->stmtList ? pDb->stmtList->pStmt: 0); 36191df6470dSdrh Tcl_SetResult(interp, zBuf, TCL_VOLATILE); 36201df6470dSdrh }else 36211df6470dSdrh #endif /* SQLITE_TEST */ 36221df6470dSdrh { 36231df6470dSdrh Tcl_AppendResult(interp, "unknown argument: ", zArg, (char*)0); 36241df6470dSdrh return TCL_ERROR; 36251df6470dSdrh } 36261df6470dSdrh } 36271df6470dSdrh if( i==2 ){ 36284397de57Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC); 36291df6470dSdrh } 36304397de57Sdanielk1977 break; 36314397de57Sdanielk1977 } 36324397de57Sdanielk1977 36331067fe11Stpoindex 36346d31316cSdrh } /* End of the SWITCH statement */ 363522fbcb8dSdrh return rc; 363675897234Sdrh } 363775897234Sdrh 3638a2c8a95bSdrh #if SQLITE_TCL_NRE 3639a2c8a95bSdrh /* 3640a2c8a95bSdrh ** Adaptor that provides an objCmd interface to the NRE-enabled 3641a2c8a95bSdrh ** interface implementation. 3642a2c8a95bSdrh */ 3643a121cc7cSmistachkin static int SQLITE_TCLAPI DbObjCmdAdaptor( 3644a2c8a95bSdrh void *cd, 3645a2c8a95bSdrh Tcl_Interp *interp, 3646a2c8a95bSdrh int objc, 3647a2c8a95bSdrh Tcl_Obj *const*objv 3648a2c8a95bSdrh ){ 3649a2c8a95bSdrh return Tcl_NRCallObjProc(interp, DbObjCmd, cd, objc, objv); 3650a2c8a95bSdrh } 3651a2c8a95bSdrh #endif /* SQLITE_TCL_NRE */ 3652a2c8a95bSdrh 365375897234Sdrh /* 36544dcac40eSdrh ** Issue the usage message when the "sqlite3" command arguments are 36554dcac40eSdrh ** incorrect. 36564dcac40eSdrh */ 36574dcac40eSdrh static int sqliteCmdUsage( 36584dcac40eSdrh Tcl_Interp *interp, 36594dcac40eSdrh Tcl_Obj *const*objv 36604dcac40eSdrh ){ 36614dcac40eSdrh Tcl_WrongNumArgs(interp, 1, objv, 36624dcac40eSdrh "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" 36634dcac40eSdrh " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" 36644dcac40eSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 36654dcac40eSdrh " ?-key CODECKEY?" 36664dcac40eSdrh #endif 36674dcac40eSdrh ); 36684dcac40eSdrh return TCL_ERROR; 36694dcac40eSdrh } 36704dcac40eSdrh 36714dcac40eSdrh /* 36723570ad93Sdrh ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN? 36739a6284c1Sdanielk1977 ** ?-create BOOLEAN? ?-nomutex BOOLEAN? 367475897234Sdrh ** 367575897234Sdrh ** This is the main Tcl command. When the "sqlite" Tcl command is 367675897234Sdrh ** invoked, this routine runs to process that command. 367775897234Sdrh ** 367875897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new 367975897234Sdrh ** database connection. This command creates a new command named 368075897234Sdrh ** DBNAME that is used to control that connection. The database 368175897234Sdrh ** connection is deleted when the DBNAME command is deleted. 368275897234Sdrh ** 36833570ad93Sdrh ** The second argument is the name of the database file. 3684fbc3eab8Sdrh ** 368575897234Sdrh */ 36867617e4a8Smistachkin static int SQLITE_TCLAPI DbMain( 36877617e4a8Smistachkin void *cd, 36887617e4a8Smistachkin Tcl_Interp *interp, 36897617e4a8Smistachkin int objc, 36907617e4a8Smistachkin Tcl_Obj *const*objv 36917617e4a8Smistachkin ){ 3692bec3f402Sdrh SqliteDb *p; 369322fbcb8dSdrh const char *zArg; 369475897234Sdrh char *zErrMsg; 36953570ad93Sdrh int i; 36964dcac40eSdrh const char *zFile = 0; 36973570ad93Sdrh const char *zVfs = 0; 3698d9da78a2Sdrh int flags; 3699882e8e4dSdrh Tcl_DString translatedFilename; 370032f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 3701b07028f7Sdrh void *pKey = 0; 3702b07028f7Sdrh int nKey = 0; 3703b07028f7Sdrh #endif 3704540ebf82Smistachkin int rc; 3705d9da78a2Sdrh 3706d9da78a2Sdrh /* In normal use, each TCL interpreter runs in a single thread. So 37074dcac40eSdrh ** by default, we can turn off mutexing on SQLite database connections. 3708d9da78a2Sdrh ** However, for testing purposes it is useful to have mutexes turned 3709d9da78a2Sdrh ** on. So, by default, mutexes default off. But if compiled with 3710d9da78a2Sdrh ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on. 3711d9da78a2Sdrh */ 3712d9da78a2Sdrh #ifdef SQLITE_TCL_DEFAULT_FULLMUTEX 3713d9da78a2Sdrh flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX; 3714d9da78a2Sdrh #else 3715d9da78a2Sdrh flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX; 3716d9da78a2Sdrh #endif 3717d9da78a2Sdrh 3718c6727c83Sdrh if( objc==1 ) return sqliteCmdUsage(interp, objv); 371922fbcb8dSdrh if( objc==2 ){ 372022fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 372122fbcb8dSdrh if( strcmp(zArg,"-version")==0 ){ 3722a198f2b5Sdrh Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0); 3723647cb0e1Sdrh return TCL_OK; 3724647cb0e1Sdrh } 372572bf6a3eSdrh if( strcmp(zArg,"-sourceid")==0 ){ 372672bf6a3eSdrh Tcl_AppendResult(interp,sqlite3_sourceid(), (char*)0); 372772bf6a3eSdrh return TCL_OK; 372872bf6a3eSdrh } 37299eb9e26bSdrh if( strcmp(zArg,"-has-codec")==0 ){ 373032f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 3731a198f2b5Sdrh Tcl_AppendResult(interp,"1",(char*)0); 373222fbcb8dSdrh #else 3733a198f2b5Sdrh Tcl_AppendResult(interp,"0",(char*)0); 373422fbcb8dSdrh #endif 373522fbcb8dSdrh return TCL_OK; 373622fbcb8dSdrh } 37374dcac40eSdrh if( zArg[0]=='-' ) return sqliteCmdUsage(interp, objv); 3738fbc3eab8Sdrh } 37394dcac40eSdrh for(i=2; i<objc; i++){ 37403570ad93Sdrh zArg = Tcl_GetString(objv[i]); 37414dcac40eSdrh if( zArg[0]!='-' ){ 37424dcac40eSdrh if( zFile!=0 ) return sqliteCmdUsage(interp, objv); 37434dcac40eSdrh zFile = zArg; 37444dcac40eSdrh continue; 37454dcac40eSdrh } 37464dcac40eSdrh if( i==objc-1 ) return sqliteCmdUsage(interp, objv); 37474dcac40eSdrh i++; 374822fbcb8dSdrh if( strcmp(zArg,"-key")==0 ){ 374932f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 37504dcac40eSdrh pKey = Tcl_GetByteArrayFromObj(objv[i], &nKey); 3751b07028f7Sdrh #endif 37523570ad93Sdrh }else if( strcmp(zArg, "-vfs")==0 ){ 37534dcac40eSdrh zVfs = Tcl_GetString(objv[i]); 37543570ad93Sdrh }else if( strcmp(zArg, "-readonly")==0 ){ 37553570ad93Sdrh int b; 37564dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 37573570ad93Sdrh if( b ){ 375833f4e02aSdrh flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); 37593570ad93Sdrh flags |= SQLITE_OPEN_READONLY; 37603570ad93Sdrh }else{ 37613570ad93Sdrh flags &= ~SQLITE_OPEN_READONLY; 37623570ad93Sdrh flags |= SQLITE_OPEN_READWRITE; 37633570ad93Sdrh } 37643570ad93Sdrh }else if( strcmp(zArg, "-create")==0 ){ 37653570ad93Sdrh int b; 37664dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 376733f4e02aSdrh if( b && (flags & SQLITE_OPEN_READONLY)==0 ){ 37683570ad93Sdrh flags |= SQLITE_OPEN_CREATE; 37693570ad93Sdrh }else{ 37703570ad93Sdrh flags &= ~SQLITE_OPEN_CREATE; 37713570ad93Sdrh } 37729a6284c1Sdanielk1977 }else if( strcmp(zArg, "-nomutex")==0 ){ 37739a6284c1Sdanielk1977 int b; 37744dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 37759a6284c1Sdanielk1977 if( b ){ 37769a6284c1Sdanielk1977 flags |= SQLITE_OPEN_NOMUTEX; 3777039963adSdrh flags &= ~SQLITE_OPEN_FULLMUTEX; 37789a6284c1Sdanielk1977 }else{ 37799a6284c1Sdanielk1977 flags &= ~SQLITE_OPEN_NOMUTEX; 37809a6284c1Sdanielk1977 } 3781039963adSdrh }else if( strcmp(zArg, "-fullmutex")==0 ){ 3782039963adSdrh int b; 37834dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 3784039963adSdrh if( b ){ 3785039963adSdrh flags |= SQLITE_OPEN_FULLMUTEX; 3786039963adSdrh flags &= ~SQLITE_OPEN_NOMUTEX; 3787039963adSdrh }else{ 3788039963adSdrh flags &= ~SQLITE_OPEN_FULLMUTEX; 3789039963adSdrh } 3790f12b3f60Sdrh }else if( strcmp(zArg, "-uri")==0 ){ 3791f12b3f60Sdrh int b; 37924dcac40eSdrh if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; 3793f12b3f60Sdrh if( b ){ 3794f12b3f60Sdrh flags |= SQLITE_OPEN_URI; 3795f12b3f60Sdrh }else{ 3796f12b3f60Sdrh flags &= ~SQLITE_OPEN_URI; 3797f12b3f60Sdrh } 37983570ad93Sdrh }else{ 37993570ad93Sdrh Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); 38003570ad93Sdrh return TCL_ERROR; 380122fbcb8dSdrh } 380222fbcb8dSdrh } 380375897234Sdrh zErrMsg = 0; 38044cdc9e84Sdrh p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); 3805bec3f402Sdrh memset(p, 0, sizeof(*p)); 38063ec8665eSdrh if( zFile==0 ) zFile = ""; 3807882e8e4dSdrh zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename); 3808540ebf82Smistachkin rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs); 3809882e8e4dSdrh Tcl_DStringFree(&translatedFilename); 3810540ebf82Smistachkin if( p->db ){ 381180290863Sdanielk1977 if( SQLITE_OK!=sqlite3_errcode(p->db) ){ 38129404d50eSdrh zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db)); 381380290863Sdanielk1977 sqlite3_close(p->db); 381480290863Sdanielk1977 p->db = 0; 381580290863Sdanielk1977 } 3816540ebf82Smistachkin }else{ 38175dac8432Smistachkin zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc)); 3818540ebf82Smistachkin } 381932f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) 3820f3a65f7eSdrh if( p->db ){ 38212011d5f5Sdrh sqlite3_key(p->db, pKey, nKey); 3822f3a65f7eSdrh } 3823eb8ed70dSdrh #endif 3824bec3f402Sdrh if( p->db==0 ){ 382575897234Sdrh Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); 3826bec3f402Sdrh Tcl_Free((char*)p); 38279404d50eSdrh sqlite3_free(zErrMsg); 382875897234Sdrh return TCL_ERROR; 382975897234Sdrh } 3830fb7e7651Sdrh p->maxStmt = NUM_PREPARED_STMTS; 3831147ef394Sdrh p->openFlags = flags & SQLITE_OPEN_URI; 38325169bbc6Sdrh p->interp = interp; 383322fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 38344a4c11aaSdan if( DbUseNre() ){ 3835a2c8a95bSdrh Tcl_NRCreateCommand(interp, zArg, DbObjCmdAdaptor, DbObjCmd, 3836a2c8a95bSdrh (char*)p, DbDeleteCmd); 38374a4c11aaSdan }else{ 383822fbcb8dSdrh Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); 38394a4c11aaSdan } 384075897234Sdrh return TCL_OK; 384175897234Sdrh } 384275897234Sdrh 384375897234Sdrh /* 384490ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static 384590ca9753Sdrh ** library. 384690ca9753Sdrh */ 384790ca9753Sdrh #ifndef USE_TCL_STUBS 384890ca9753Sdrh # undef Tcl_InitStubs 38490e85ccfcSdrh # define Tcl_InitStubs(a,b,c) TCL_VERSION 385090ca9753Sdrh #endif 385190ca9753Sdrh 385290ca9753Sdrh /* 385329bc4615Sdrh ** Make sure we have a PACKAGE_VERSION macro defined. This will be 385429bc4615Sdrh ** defined automatically by the TEA makefile. But other makefiles 385529bc4615Sdrh ** do not define it. 385629bc4615Sdrh */ 385729bc4615Sdrh #ifndef PACKAGE_VERSION 385829bc4615Sdrh # define PACKAGE_VERSION SQLITE_VERSION 385929bc4615Sdrh #endif 386029bc4615Sdrh 386129bc4615Sdrh /* 386275897234Sdrh ** Initialize this module. 386375897234Sdrh ** 386475897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite". 386575897234Sdrh ** (Hence there is no namespace. There is no point in using a namespace 386675897234Sdrh ** if the extension only supplies one new name!) The "sqlite" command is 386775897234Sdrh ** used to open a new SQLite database. See the DbMain() routine above 386875897234Sdrh ** for additional information. 3869b652f432Sdrh ** 3870b652f432Sdrh ** The EXTERN macros are required by TCL in order to work on windows. 387175897234Sdrh */ 3872b652f432Sdrh EXTERN int Sqlite3_Init(Tcl_Interp *interp){ 387327b2f053Smistachkin int rc = Tcl_InitStubs(interp, "8.4", 0) ? TCL_OK : TCL_ERROR; 38746dc8cbe0Sdrh if( rc==TCL_OK ){ 3875ef4ac8f9Sdrh Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); 38761cca0d22Sdrh #ifndef SQLITE_3_SUFFIX_ONLY 38771cca0d22Sdrh /* The "sqlite" alias is undocumented. It is here only to support 38781cca0d22Sdrh ** legacy scripts. All new scripts should use only the "sqlite3" 38796dc8cbe0Sdrh ** command. */ 388049766d6cSdrh Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); 38814c0f1649Sdrh #endif 38826dc8cbe0Sdrh rc = Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION); 38836dc8cbe0Sdrh } 38846dc8cbe0Sdrh return rc; 388590ca9753Sdrh } 3886b652f432Sdrh EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 3887b652f432Sdrh EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 3888b652f432Sdrh EXTERN int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 3889e2c3a659Sdrh 3890d878cab5Sdrh /* Because it accesses the file-system and uses persistent state, SQLite 3891e75a9eb9Sdrh ** is not considered appropriate for safe interpreters. Hence, we cause 3892e75a9eb9Sdrh ** the _SafeInit() interfaces return TCL_ERROR. 3893d878cab5Sdrh */ 3894e75a9eb9Sdrh EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; } 3895e75a9eb9Sdrh EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;} 3896e75a9eb9Sdrh 3897e75a9eb9Sdrh 389849766d6cSdrh 389949766d6cSdrh #ifndef SQLITE_3_SUFFIX_ONLY 3900a3e63c4aSdan int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 3901a3e63c4aSdan int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 3902a3e63c4aSdan int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 3903a3e63c4aSdan int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } 390449766d6cSdrh #endif 390575897234Sdrh 3906c318f730Sdrh /* 390796a206faSdrh ** If the TCLSH macro is defined, add code to make a stand-alone program. 3908c318f730Sdrh */ 390996a206faSdrh #if defined(TCLSH) 391057a0227fSdrh 391196a206faSdrh /* This is the main routine for an ordinary TCL shell. If there are 391296a206faSdrh ** are arguments, run the first argument as a script. Otherwise, 391396a206faSdrh ** read TCL commands from standard input 3914348784efSdrh */ 39150ae479dfSdan static const char *tclsh_main_loop(void){ 39160ae479dfSdan static const char zMainloop[] = 391796a206faSdrh "if {[llength $argv]>=1} {\n" 391896a206faSdrh "set argv0 [lindex $argv 0]\n" 391996a206faSdrh "set argv [lrange $argv 1 end]\n" 392096a206faSdrh "source $argv0\n" 392196a206faSdrh "} else {\n" 3922348784efSdrh "set line {}\n" 3923348784efSdrh "while {![eof stdin]} {\n" 3924348784efSdrh "if {$line!=\"\"} {\n" 3925348784efSdrh "puts -nonewline \"> \"\n" 3926348784efSdrh "} else {\n" 3927348784efSdrh "puts -nonewline \"% \"\n" 3928348784efSdrh "}\n" 3929348784efSdrh "flush stdout\n" 3930348784efSdrh "append line [gets stdin]\n" 3931348784efSdrh "if {[info complete $line]} {\n" 3932348784efSdrh "if {[catch {uplevel #0 $line} result]} {\n" 3933348784efSdrh "puts stderr \"Error: $result\"\n" 3934348784efSdrh "} elseif {$result!=\"\"} {\n" 3935348784efSdrh "puts $result\n" 3936348784efSdrh "}\n" 3937348784efSdrh "set line {}\n" 3938348784efSdrh "} else {\n" 3939348784efSdrh "append line \\n\n" 3940348784efSdrh "}\n" 3941348784efSdrh "}\n" 394296a206faSdrh "}\n" 3943348784efSdrh ; 39440ae479dfSdan return zMainloop; 39450ae479dfSdan } 39463e27c026Sdrh 3947c1a60c51Sdan #define TCLSH_MAIN main /* Needed to fake out mktclapp */ 394869def7ffSmistachkin int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){ 3949c1a60c51Sdan Tcl_Interp *interp; 395096a206faSdrh int i; 395196a206faSdrh const char *zScript = 0; 395296a206faSdrh char zArgc[32]; 395396a206faSdrh #if defined(TCLSH_INIT_PROC) 395496a206faSdrh extern const char *TCLSH_INIT_PROC(Tcl_Interp*); 395596a206faSdrh #endif 3956c1a60c51Sdan 39571f28e070Smistachkin #if !defined(_WIN32_WCE) 39581e8487dbSmistachkin if( getenv("SQLITE_DEBUG_BREAK") ){ 39591e8487dbSmistachkin if( isatty(0) && isatty(2) ){ 39601f28e070Smistachkin fprintf(stderr, 39611f28e070Smistachkin "attach debugger to process %d and press any key to continue.\n", 39621f28e070Smistachkin GETPID()); 39631f28e070Smistachkin fgetc(stdin); 39641e8487dbSmistachkin }else{ 39651e8487dbSmistachkin #if defined(_WIN32) || defined(WIN32) 39661e8487dbSmistachkin DebugBreak(); 39671e8487dbSmistachkin #elif defined(SIGTRAP) 39681e8487dbSmistachkin raise(SIGTRAP); 39691e8487dbSmistachkin #endif 39701e8487dbSmistachkin } 39711f28e070Smistachkin } 39721f28e070Smistachkin #endif 39731f28e070Smistachkin 3974c1a60c51Sdan /* Call sqlite3_shutdown() once before doing anything else. This is to 3975c1a60c51Sdan ** test that sqlite3_shutdown() can be safely called by a process before 3976c1a60c51Sdan ** sqlite3_initialize() is. */ 3977c1a60c51Sdan sqlite3_shutdown(); 3978c1a60c51Sdan 39790ae479dfSdan Tcl_FindExecutable(argv[0]); 39802953ba9eSmistachkin Tcl_SetSystemEncoding(NULL, "utf-8"); 39810ae479dfSdan interp = Tcl_CreateInterp(); 3982c318f730Sdrh Sqlite3_Init(interp); 398396a206faSdrh 398496a206faSdrh sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-1); 3985ad42c3a3Sshess Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY); 398696a206faSdrh Tcl_SetVar(interp,"argv0",argv[0],TCL_GLOBAL_ONLY); 3987348784efSdrh Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); 398896a206faSdrh for(i=1; i<argc; i++){ 3989348784efSdrh Tcl_SetVar(interp, "argv", argv[i], 3990348784efSdrh TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); 3991348784efSdrh } 399296a206faSdrh #if defined(TCLSH_INIT_PROC) 399396a206faSdrh zScript = TCLSH_INIT_PROC(interp); 399496a206faSdrh #endif 399596a206faSdrh if( zScript==0 ){ 399696a206faSdrh zScript = tclsh_main_loop(); 399796a206faSdrh } 399896a206faSdrh if( Tcl_GlobalEval(interp, zScript)!=TCL_OK ){ 39990de8c112Sdrh const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); 4000a81c64a2Sdrh if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp); 4001c61053b7Sdrh fprintf(stderr,"%s: %s\n", *argv, zInfo); 4002348784efSdrh return 1; 4003348784efSdrh } 4004348784efSdrh return 0; 4005348784efSdrh } 4006348784efSdrh #endif /* TCLSH */ 4007