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 ************************************************************************* 1275897234Sdrh ** A TCL Interface to SQLite 1375897234Sdrh ** 14*954ce99cSdanielk1977 ** $Id: tclsqlite.c,v 1.159 2006/06/15 15:59:20 danielk1977 Exp $ 1575897234Sdrh */ 166d31316cSdrh #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ 176d31316cSdrh 1806b2718aSdrh #include "sqliteInt.h" 19895d7472Sdrh #include "hash.h" 2017a68934Sdrh #include "tcl.h" 2175897234Sdrh #include <stdlib.h> 2275897234Sdrh #include <string.h> 23ce927065Sdrh #include <assert.h> 24d1e4733dSdrh #include <ctype.h> 2575897234Sdrh 2629bc4615Sdrh 27a21c6b6fSdanielk1977 #define NUM_PREPARED_STMTS 10 28fb7e7651Sdrh #define MAX_PREPARED_STMTS 100 29fb7e7651Sdrh 3075897234Sdrh /* 3198808babSdrh ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we 3298808babSdrh ** have to do a translation when going between the two. Set the 3398808babSdrh ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do 3498808babSdrh ** this translation. 3598808babSdrh */ 3698808babSdrh #if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8) 3798808babSdrh # define UTF_TRANSLATION_NEEDED 1 3898808babSdrh #endif 3998808babSdrh 4098808babSdrh /* 41cabb0819Sdrh ** New SQL functions can be created as TCL scripts. Each such function 42cabb0819Sdrh ** is described by an instance of the following structure. 43cabb0819Sdrh */ 44cabb0819Sdrh typedef struct SqlFunc SqlFunc; 45cabb0819Sdrh struct SqlFunc { 46cabb0819Sdrh Tcl_Interp *interp; /* The TCL interpret to execute the function */ 47d1e4733dSdrh Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */ 48d1e4733dSdrh int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */ 49d1e4733dSdrh char *zName; /* Name of this function */ 50cabb0819Sdrh SqlFunc *pNext; /* Next function on the list of them all */ 51cabb0819Sdrh }; 52cabb0819Sdrh 53cabb0819Sdrh /* 540202b29eSdanielk1977 ** New collation sequences function can be created as TCL scripts. Each such 550202b29eSdanielk1977 ** function is described by an instance of the following structure. 560202b29eSdanielk1977 */ 570202b29eSdanielk1977 typedef struct SqlCollate SqlCollate; 580202b29eSdanielk1977 struct SqlCollate { 590202b29eSdanielk1977 Tcl_Interp *interp; /* The TCL interpret to execute the function */ 600202b29eSdanielk1977 char *zScript; /* The script to be run */ 610202b29eSdanielk1977 SqlCollate *pNext; /* Next function on the list of them all */ 620202b29eSdanielk1977 }; 630202b29eSdanielk1977 640202b29eSdanielk1977 /* 65fb7e7651Sdrh ** Prepared statements are cached for faster execution. Each prepared 66fb7e7651Sdrh ** statement is described by an instance of the following structure. 67fb7e7651Sdrh */ 68fb7e7651Sdrh typedef struct SqlPreparedStmt SqlPreparedStmt; 69fb7e7651Sdrh struct SqlPreparedStmt { 70fb7e7651Sdrh SqlPreparedStmt *pNext; /* Next in linked list */ 71fb7e7651Sdrh SqlPreparedStmt *pPrev; /* Previous on the list */ 72fb7e7651Sdrh sqlite3_stmt *pStmt; /* The prepared statement */ 73fb7e7651Sdrh int nSql; /* chars in zSql[] */ 74fb7e7651Sdrh char zSql[1]; /* Text of the SQL statement */ 75fb7e7651Sdrh }; 76fb7e7651Sdrh 77fb7e7651Sdrh /* 78bec3f402Sdrh ** There is one instance of this structure for each SQLite database 79bec3f402Sdrh ** that has been opened by the SQLite TCL interface. 80bec3f402Sdrh */ 81bec3f402Sdrh typedef struct SqliteDb SqliteDb; 82bec3f402Sdrh struct SqliteDb { 83dddca286Sdrh sqlite3 *db; /* The "real" database structure. MUST BE FIRST */ 84bec3f402Sdrh Tcl_Interp *interp; /* The interpreter used for this database */ 856d31316cSdrh char *zBusy; /* The busy callback routine */ 86aa940eacSdrh char *zCommit; /* The commit hook callback routine */ 87b5a20d3cSdrh char *zTrace; /* The trace callback routine */ 8819e2d37fSdrh char *zProfile; /* The profile callback routine */ 89348bb5d6Sdanielk1977 char *zProgress; /* The progress callback routine */ 90e22a334bSdrh char *zAuth; /* The authorization callback routine */ 9155c45f2eSdanielk1977 char *zNull; /* Text to substitute for an SQL NULL value */ 92cabb0819Sdrh SqlFunc *pFunc; /* List of SQL functions */ 9394eb6a14Sdanielk1977 Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ 9471fd80bfSdanielk1977 Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ 950202b29eSdanielk1977 SqlCollate *pCollate; /* List of SQL collation functions */ 966f8a503dSdanielk1977 int rc; /* Return code of most recent sqlite3_exec() */ 977cedc8d4Sdanielk1977 Tcl_Obj *pCollateNeeded; /* Collation needed script */ 98fb7e7651Sdrh SqlPreparedStmt *stmtList; /* List of prepared statements*/ 99fb7e7651Sdrh SqlPreparedStmt *stmtLast; /* Last statement in the list */ 100fb7e7651Sdrh int maxStmt; /* The next maximum number of stmtList */ 101fb7e7651Sdrh int nStmt; /* Number of statements in stmtList */ 10298808babSdrh }; 103297ecf14Sdrh 1046d31316cSdrh /* 105d1e4733dSdrh ** Look at the script prefix in pCmd. We will be executing this script 106d1e4733dSdrh ** after first appending one or more arguments. This routine analyzes 107d1e4733dSdrh ** the script to see if it is safe to use Tcl_EvalObjv() on the script 108d1e4733dSdrh ** rather than the more general Tcl_EvalEx(). Tcl_EvalObjv() is much 109d1e4733dSdrh ** faster. 110d1e4733dSdrh ** 111d1e4733dSdrh ** Scripts that are safe to use with Tcl_EvalObjv() consists of a 112d1e4733dSdrh ** command name followed by zero or more arguments with no [...] or $ 113d1e4733dSdrh ** or {...} or ; to be seen anywhere. Most callback scripts consist 114d1e4733dSdrh ** of just a single procedure name and they meet this requirement. 115d1e4733dSdrh */ 116d1e4733dSdrh static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){ 117d1e4733dSdrh /* We could try to do something with Tcl_Parse(). But we will instead 118d1e4733dSdrh ** just do a search for forbidden characters. If any of the forbidden 119d1e4733dSdrh ** characters appear in pCmd, we will report the string as unsafe. 120d1e4733dSdrh */ 121d1e4733dSdrh const char *z; 122d1e4733dSdrh int n; 123d1e4733dSdrh z = Tcl_GetStringFromObj(pCmd, &n); 124d1e4733dSdrh while( n-- > 0 ){ 125d1e4733dSdrh int c = *(z++); 126d1e4733dSdrh if( c=='$' || c=='[' || c==';' ) return 0; 127d1e4733dSdrh } 128d1e4733dSdrh return 1; 129d1e4733dSdrh } 130d1e4733dSdrh 131d1e4733dSdrh /* 132d1e4733dSdrh ** Find an SqlFunc structure with the given name. Or create a new 133d1e4733dSdrh ** one if an existing one cannot be found. Return a pointer to the 134d1e4733dSdrh ** structure. 135d1e4733dSdrh */ 136d1e4733dSdrh static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ 137d1e4733dSdrh SqlFunc *p, *pNew; 138d1e4733dSdrh int i; 139d1e4733dSdrh pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + strlen(zName) + 1 ); 140d1e4733dSdrh pNew->zName = (char*)&pNew[1]; 141d1e4733dSdrh for(i=0; zName[i]; i++){ pNew->zName[i] = tolower(zName[i]); } 142d1e4733dSdrh pNew->zName[i] = 0; 143d1e4733dSdrh for(p=pDb->pFunc; p; p=p->pNext){ 144d1e4733dSdrh if( strcmp(p->zName, pNew->zName)==0 ){ 145d1e4733dSdrh Tcl_Free((char*)pNew); 146d1e4733dSdrh return p; 147d1e4733dSdrh } 148d1e4733dSdrh } 149d1e4733dSdrh pNew->interp = pDb->interp; 150d1e4733dSdrh pNew->pScript = 0; 151d1e4733dSdrh pNew->pNext = pDb->pFunc; 152d1e4733dSdrh pDb->pFunc = pNew; 153d1e4733dSdrh return pNew; 154d1e4733dSdrh } 155d1e4733dSdrh 156d1e4733dSdrh /* 157fb7e7651Sdrh ** Finalize and free a list of prepared statements 158fb7e7651Sdrh */ 159fb7e7651Sdrh static void flushStmtCache( SqliteDb *pDb ){ 160fb7e7651Sdrh SqlPreparedStmt *pPreStmt; 161fb7e7651Sdrh 162fb7e7651Sdrh while( pDb->stmtList ){ 163fb7e7651Sdrh sqlite3_finalize( pDb->stmtList->pStmt ); 164fb7e7651Sdrh pPreStmt = pDb->stmtList; 165fb7e7651Sdrh pDb->stmtList = pDb->stmtList->pNext; 166fb7e7651Sdrh Tcl_Free( (char*)pPreStmt ); 167fb7e7651Sdrh } 168fb7e7651Sdrh pDb->nStmt = 0; 169fb7e7651Sdrh pDb->stmtLast = 0; 170fb7e7651Sdrh } 171fb7e7651Sdrh 172fb7e7651Sdrh /* 173895d7472Sdrh ** TCL calls this procedure when an sqlite3 database command is 174895d7472Sdrh ** deleted. 17575897234Sdrh */ 17675897234Sdrh static void DbDeleteCmd(void *db){ 177bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)db; 178fb7e7651Sdrh flushStmtCache(pDb); 1796f8a503dSdanielk1977 sqlite3_close(pDb->db); 180cabb0819Sdrh while( pDb->pFunc ){ 181cabb0819Sdrh SqlFunc *pFunc = pDb->pFunc; 182cabb0819Sdrh pDb->pFunc = pFunc->pNext; 183d1e4733dSdrh Tcl_DecrRefCount(pFunc->pScript); 184cabb0819Sdrh Tcl_Free((char*)pFunc); 185cabb0819Sdrh } 1860202b29eSdanielk1977 while( pDb->pCollate ){ 1870202b29eSdanielk1977 SqlCollate *pCollate = pDb->pCollate; 1880202b29eSdanielk1977 pDb->pCollate = pCollate->pNext; 1890202b29eSdanielk1977 Tcl_Free((char*)pCollate); 1900202b29eSdanielk1977 } 191bec3f402Sdrh if( pDb->zBusy ){ 192bec3f402Sdrh Tcl_Free(pDb->zBusy); 193bec3f402Sdrh } 194b5a20d3cSdrh if( pDb->zTrace ){ 195b5a20d3cSdrh Tcl_Free(pDb->zTrace); 1960d1a643aSdrh } 19719e2d37fSdrh if( pDb->zProfile ){ 19819e2d37fSdrh Tcl_Free(pDb->zProfile); 19919e2d37fSdrh } 200e22a334bSdrh if( pDb->zAuth ){ 201e22a334bSdrh Tcl_Free(pDb->zAuth); 202e22a334bSdrh } 20355c45f2eSdanielk1977 if( pDb->zNull ){ 20455c45f2eSdanielk1977 Tcl_Free(pDb->zNull); 20555c45f2eSdanielk1977 } 20694eb6a14Sdanielk1977 if( pDb->pUpdateHook ){ 20794eb6a14Sdanielk1977 Tcl_DecrRefCount(pDb->pUpdateHook); 20894eb6a14Sdanielk1977 } 20971fd80bfSdanielk1977 if( pDb->pRollbackHook ){ 21071fd80bfSdanielk1977 Tcl_DecrRefCount(pDb->pRollbackHook); 21171fd80bfSdanielk1977 } 21294eb6a14Sdanielk1977 if( pDb->pCollateNeeded ){ 21394eb6a14Sdanielk1977 Tcl_DecrRefCount(pDb->pCollateNeeded); 21494eb6a14Sdanielk1977 } 215bec3f402Sdrh Tcl_Free((char*)pDb); 216bec3f402Sdrh } 217bec3f402Sdrh 218bec3f402Sdrh /* 219bec3f402Sdrh ** This routine is called when a database file is locked while trying 220bec3f402Sdrh ** to execute SQL. 221bec3f402Sdrh */ 2222a764eb0Sdanielk1977 static int DbBusyHandler(void *cd, int nTries){ 223bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 224bec3f402Sdrh int rc; 225bec3f402Sdrh char zVal[30]; 226bec3f402Sdrh 227bec3f402Sdrh sprintf(zVal, "%d", nTries); 228d1e4733dSdrh rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0); 229bec3f402Sdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 230bec3f402Sdrh return 0; 231bec3f402Sdrh } 232bec3f402Sdrh return 1; 23375897234Sdrh } 23475897234Sdrh 23575897234Sdrh /* 236348bb5d6Sdanielk1977 ** This routine is invoked as the 'progress callback' for the database. 237348bb5d6Sdanielk1977 */ 238348bb5d6Sdanielk1977 static int DbProgressHandler(void *cd){ 239348bb5d6Sdanielk1977 SqliteDb *pDb = (SqliteDb*)cd; 240348bb5d6Sdanielk1977 int rc; 241348bb5d6Sdanielk1977 242348bb5d6Sdanielk1977 assert( pDb->zProgress ); 243348bb5d6Sdanielk1977 rc = Tcl_Eval(pDb->interp, pDb->zProgress); 244348bb5d6Sdanielk1977 if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 245348bb5d6Sdanielk1977 return 1; 246348bb5d6Sdanielk1977 } 247348bb5d6Sdanielk1977 return 0; 248348bb5d6Sdanielk1977 } 249348bb5d6Sdanielk1977 250d1167393Sdrh #ifndef SQLITE_OMIT_TRACE 251348bb5d6Sdanielk1977 /* 252b5a20d3cSdrh ** This routine is called by the SQLite trace handler whenever a new 253b5a20d3cSdrh ** block of SQL is executed. The TCL script in pDb->zTrace is executed. 2540d1a643aSdrh */ 255b5a20d3cSdrh static void DbTraceHandler(void *cd, const char *zSql){ 2560d1a643aSdrh SqliteDb *pDb = (SqliteDb*)cd; 257b5a20d3cSdrh Tcl_DString str; 2580d1a643aSdrh 259b5a20d3cSdrh Tcl_DStringInit(&str); 260b5a20d3cSdrh Tcl_DStringAppend(&str, pDb->zTrace, -1); 261b5a20d3cSdrh Tcl_DStringAppendElement(&str, zSql); 262b5a20d3cSdrh Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); 263b5a20d3cSdrh Tcl_DStringFree(&str); 264b5a20d3cSdrh Tcl_ResetResult(pDb->interp); 2650d1a643aSdrh } 266d1167393Sdrh #endif 2670d1a643aSdrh 268d1167393Sdrh #ifndef SQLITE_OMIT_TRACE 2690d1a643aSdrh /* 27019e2d37fSdrh ** This routine is called by the SQLite profile handler after a statement 27119e2d37fSdrh ** SQL has executed. The TCL script in pDb->zProfile is evaluated. 27219e2d37fSdrh */ 27319e2d37fSdrh static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){ 27419e2d37fSdrh SqliteDb *pDb = (SqliteDb*)cd; 27519e2d37fSdrh Tcl_DString str; 27619e2d37fSdrh char zTm[100]; 27719e2d37fSdrh 27819e2d37fSdrh sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm); 27919e2d37fSdrh Tcl_DStringInit(&str); 28019e2d37fSdrh Tcl_DStringAppend(&str, pDb->zProfile, -1); 28119e2d37fSdrh Tcl_DStringAppendElement(&str, zSql); 28219e2d37fSdrh Tcl_DStringAppendElement(&str, zTm); 28319e2d37fSdrh Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); 28419e2d37fSdrh Tcl_DStringFree(&str); 28519e2d37fSdrh Tcl_ResetResult(pDb->interp); 28619e2d37fSdrh } 287d1167393Sdrh #endif 28819e2d37fSdrh 28919e2d37fSdrh /* 290aa940eacSdrh ** This routine is called when a transaction is committed. The 291aa940eacSdrh ** TCL script in pDb->zCommit is executed. If it returns non-zero or 292aa940eacSdrh ** if it throws an exception, the transaction is rolled back instead 293aa940eacSdrh ** of being committed. 294aa940eacSdrh */ 295aa940eacSdrh static int DbCommitHandler(void *cd){ 296aa940eacSdrh SqliteDb *pDb = (SqliteDb*)cd; 297aa940eacSdrh int rc; 298aa940eacSdrh 299aa940eacSdrh rc = Tcl_Eval(pDb->interp, pDb->zCommit); 300aa940eacSdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 301aa940eacSdrh return 1; 302aa940eacSdrh } 303aa940eacSdrh return 0; 304aa940eacSdrh } 305aa940eacSdrh 30671fd80bfSdanielk1977 static void DbRollbackHandler(void *clientData){ 30771fd80bfSdanielk1977 SqliteDb *pDb = (SqliteDb*)clientData; 30871fd80bfSdanielk1977 assert(pDb->pRollbackHook); 30971fd80bfSdanielk1977 if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){ 31071fd80bfSdanielk1977 Tcl_BackgroundError(pDb->interp); 31171fd80bfSdanielk1977 } 31271fd80bfSdanielk1977 } 31371fd80bfSdanielk1977 31494eb6a14Sdanielk1977 static void DbUpdateHandler( 31594eb6a14Sdanielk1977 void *p, 31694eb6a14Sdanielk1977 int op, 31794eb6a14Sdanielk1977 const char *zDb, 31894eb6a14Sdanielk1977 const char *zTbl, 31994eb6a14Sdanielk1977 sqlite_int64 rowid 32094eb6a14Sdanielk1977 ){ 32194eb6a14Sdanielk1977 SqliteDb *pDb = (SqliteDb *)p; 32294eb6a14Sdanielk1977 Tcl_Obj *pCmd; 32394eb6a14Sdanielk1977 32494eb6a14Sdanielk1977 assert( pDb->pUpdateHook ); 32594eb6a14Sdanielk1977 assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); 32694eb6a14Sdanielk1977 32794eb6a14Sdanielk1977 pCmd = Tcl_DuplicateObj(pDb->pUpdateHook); 32894eb6a14Sdanielk1977 Tcl_IncrRefCount(pCmd); 32994eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj( 33094eb6a14Sdanielk1977 ( (op==SQLITE_INSERT)?"INSERT":(op==SQLITE_UPDATE)?"UPDATE":"DELETE"), -1)); 33194eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1)); 33294eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1)); 33394eb6a14Sdanielk1977 Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid)); 33494eb6a14Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); 33594eb6a14Sdanielk1977 } 33694eb6a14Sdanielk1977 3377cedc8d4Sdanielk1977 static void tclCollateNeeded( 3387cedc8d4Sdanielk1977 void *pCtx, 3399bb575fdSdrh sqlite3 *db, 3407cedc8d4Sdanielk1977 int enc, 3417cedc8d4Sdanielk1977 const char *zName 3427cedc8d4Sdanielk1977 ){ 3437cedc8d4Sdanielk1977 SqliteDb *pDb = (SqliteDb *)pCtx; 3447cedc8d4Sdanielk1977 Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded); 3457cedc8d4Sdanielk1977 Tcl_IncrRefCount(pScript); 3467cedc8d4Sdanielk1977 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1)); 3477cedc8d4Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pScript, 0); 3487cedc8d4Sdanielk1977 Tcl_DecrRefCount(pScript); 3497cedc8d4Sdanielk1977 } 3507cedc8d4Sdanielk1977 351aa940eacSdrh /* 3520202b29eSdanielk1977 ** This routine is called to evaluate an SQL collation function implemented 3530202b29eSdanielk1977 ** using TCL script. 3540202b29eSdanielk1977 */ 3550202b29eSdanielk1977 static int tclSqlCollate( 3560202b29eSdanielk1977 void *pCtx, 3570202b29eSdanielk1977 int nA, 3580202b29eSdanielk1977 const void *zA, 3590202b29eSdanielk1977 int nB, 3600202b29eSdanielk1977 const void *zB 3610202b29eSdanielk1977 ){ 3620202b29eSdanielk1977 SqlCollate *p = (SqlCollate *)pCtx; 3630202b29eSdanielk1977 Tcl_Obj *pCmd; 3640202b29eSdanielk1977 3650202b29eSdanielk1977 pCmd = Tcl_NewStringObj(p->zScript, -1); 3660202b29eSdanielk1977 Tcl_IncrRefCount(pCmd); 3670202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA)); 3680202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB)); 369d1e4733dSdrh Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); 3700202b29eSdanielk1977 Tcl_DecrRefCount(pCmd); 3710202b29eSdanielk1977 return (atoi(Tcl_GetStringResult(p->interp))); 3720202b29eSdanielk1977 } 3730202b29eSdanielk1977 3740202b29eSdanielk1977 /* 375cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented 376cabb0819Sdrh ** using TCL script. 377cabb0819Sdrh */ 3780ae8b831Sdanielk1977 static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ 3796f8a503dSdanielk1977 SqlFunc *p = sqlite3_user_data(context); 380d1e4733dSdrh Tcl_Obj *pCmd; 381cabb0819Sdrh int i; 382cabb0819Sdrh int rc; 383cabb0819Sdrh 384d1e4733dSdrh if( argc==0 ){ 385d1e4733dSdrh /* If there are no arguments to the function, call Tcl_EvalObjEx on the 386d1e4733dSdrh ** script object directly. This allows the TCL compiler to generate 387d1e4733dSdrh ** bytecode for the command on the first invocation and thus make 388d1e4733dSdrh ** subsequent invocations much faster. */ 389d1e4733dSdrh pCmd = p->pScript; 390d1e4733dSdrh Tcl_IncrRefCount(pCmd); 391d1e4733dSdrh rc = Tcl_EvalObjEx(p->interp, pCmd, 0); 392d1e4733dSdrh Tcl_DecrRefCount(pCmd); 39351ad0ecdSdanielk1977 }else{ 394d1e4733dSdrh /* If there are arguments to the function, make a shallow copy of the 395d1e4733dSdrh ** script object, lappend the arguments, then evaluate the copy. 396d1e4733dSdrh ** 397d1e4733dSdrh ** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated. 398d1e4733dSdrh ** The new Tcl_Obj contains pointers to the original list elements. 399d1e4733dSdrh ** That way, when Tcl_EvalObjv() is run and shimmers the first element 400d1e4733dSdrh ** of the list to tclCmdNameType, that alternate representation will 401d1e4733dSdrh ** be preserved and reused on the next invocation. 402d1e4733dSdrh */ 403d1e4733dSdrh Tcl_Obj **aArg; 404d1e4733dSdrh int nArg; 405d1e4733dSdrh if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){ 406d1e4733dSdrh sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 407d1e4733dSdrh return; 408d1e4733dSdrh } 409d1e4733dSdrh pCmd = Tcl_NewListObj(nArg, aArg); 410d1e4733dSdrh Tcl_IncrRefCount(pCmd); 411d1e4733dSdrh for(i=0; i<argc; i++){ 412d1e4733dSdrh sqlite3_value *pIn = argv[i]; 413d1e4733dSdrh Tcl_Obj *pVal; 414d1e4733dSdrh 415d1e4733dSdrh /* Set pVal to contain the i'th column of this row. */ 416d1e4733dSdrh switch( sqlite3_value_type(pIn) ){ 417d1e4733dSdrh case SQLITE_BLOB: { 418d1e4733dSdrh int bytes = sqlite3_value_bytes(pIn); 419d1e4733dSdrh pVal = Tcl_NewByteArrayObj(sqlite3_value_blob(pIn), bytes); 420d1e4733dSdrh break; 421d1e4733dSdrh } 422d1e4733dSdrh case SQLITE_INTEGER: { 423d1e4733dSdrh sqlite_int64 v = sqlite3_value_int64(pIn); 424d1e4733dSdrh if( v>=-2147483647 && v<=2147483647 ){ 425d1e4733dSdrh pVal = Tcl_NewIntObj(v); 426d1e4733dSdrh }else{ 427d1e4733dSdrh pVal = Tcl_NewWideIntObj(v); 428d1e4733dSdrh } 429d1e4733dSdrh break; 430d1e4733dSdrh } 431d1e4733dSdrh case SQLITE_FLOAT: { 432d1e4733dSdrh double r = sqlite3_value_double(pIn); 433d1e4733dSdrh pVal = Tcl_NewDoubleObj(r); 434d1e4733dSdrh break; 435d1e4733dSdrh } 436d1e4733dSdrh case SQLITE_NULL: { 437d1e4733dSdrh pVal = Tcl_NewStringObj("", 0); 438d1e4733dSdrh break; 439d1e4733dSdrh } 440d1e4733dSdrh default: { 441d1e4733dSdrh int bytes = sqlite3_value_bytes(pIn); 44200fd957bSdanielk1977 pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes); 443d1e4733dSdrh break; 44451ad0ecdSdanielk1977 } 445cabb0819Sdrh } 446d1e4733dSdrh rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal); 447d1e4733dSdrh if( rc ){ 448d1e4733dSdrh Tcl_DecrRefCount(pCmd); 449d1e4733dSdrh sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 450d1e4733dSdrh return; 451d1e4733dSdrh } 452d1e4733dSdrh } 453d1e4733dSdrh if( !p->useEvalObjv ){ 454d1e4733dSdrh /* Tcl_EvalObjEx() will automatically call Tcl_EvalObjv() if pCmd 455d1e4733dSdrh ** is a list without a string representation. To prevent this from 456d1e4733dSdrh ** happening, make sure pCmd has a valid string representation */ 457d1e4733dSdrh Tcl_GetString(pCmd); 458d1e4733dSdrh } 459d1e4733dSdrh rc = Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); 460d1e4733dSdrh Tcl_DecrRefCount(pCmd); 461d1e4733dSdrh } 462562e8d3cSdanielk1977 463c7f269d5Sdrh if( rc && rc!=TCL_RETURN ){ 4647e18c259Sdanielk1977 sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 465cabb0819Sdrh }else{ 466c7f269d5Sdrh Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); 467c7f269d5Sdrh int n; 468c7f269d5Sdrh u8 *data; 469c7f269d5Sdrh char *zType = pVar->typePtr ? pVar->typePtr->name : ""; 470c7f269d5Sdrh char c = zType[0]; 471df0bddaeSdrh if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ 472d1e4733dSdrh /* Only return a BLOB type if the Tcl variable is a bytearray and 473df0bddaeSdrh ** has no string representation. */ 474c7f269d5Sdrh data = Tcl_GetByteArrayFromObj(pVar, &n); 475c7f269d5Sdrh sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT); 476c7f269d5Sdrh }else if( (c=='b' && strcmp(zType,"boolean")==0) || 477c7f269d5Sdrh (c=='i' && strcmp(zType,"int")==0) ){ 478c7f269d5Sdrh Tcl_GetIntFromObj(0, pVar, &n); 479c7f269d5Sdrh sqlite3_result_int(context, n); 480c7f269d5Sdrh }else if( c=='d' && strcmp(zType,"double")==0 ){ 481c7f269d5Sdrh double r; 482c7f269d5Sdrh Tcl_GetDoubleFromObj(0, pVar, &r); 483c7f269d5Sdrh sqlite3_result_double(context, r); 484df0bddaeSdrh }else if( c=='w' && strcmp(zType,"wideInt")==0 ){ 485df0bddaeSdrh Tcl_WideInt v; 486df0bddaeSdrh Tcl_GetWideIntFromObj(0, pVar, &v); 487df0bddaeSdrh sqlite3_result_int64(context, v); 488c7f269d5Sdrh }else{ 48900fd957bSdanielk1977 data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); 49000fd957bSdanielk1977 sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT); 491c7f269d5Sdrh } 492cabb0819Sdrh } 493cabb0819Sdrh } 494895d7472Sdrh 495e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION 496e22a334bSdrh /* 497e22a334bSdrh ** This is the authentication function. It appends the authentication 498e22a334bSdrh ** type code and the two arguments to zCmd[] then invokes the result 499e22a334bSdrh ** on the interpreter. The reply is examined to determine if the 500e22a334bSdrh ** authentication fails or succeeds. 501e22a334bSdrh */ 502e22a334bSdrh static int auth_callback( 503e22a334bSdrh void *pArg, 504e22a334bSdrh int code, 505e22a334bSdrh const char *zArg1, 506e22a334bSdrh const char *zArg2, 507e22a334bSdrh const char *zArg3, 508e22a334bSdrh const char *zArg4 509e22a334bSdrh ){ 510e22a334bSdrh char *zCode; 511e22a334bSdrh Tcl_DString str; 512e22a334bSdrh int rc; 513e22a334bSdrh const char *zReply; 514e22a334bSdrh SqliteDb *pDb = (SqliteDb*)pArg; 515e22a334bSdrh 516e22a334bSdrh switch( code ){ 517e22a334bSdrh case SQLITE_COPY : zCode="SQLITE_COPY"; break; 518e22a334bSdrh case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; 519e22a334bSdrh case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; 520e22a334bSdrh case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; 521e22a334bSdrh case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; 522e22a334bSdrh case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; 523e22a334bSdrh case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; 524e22a334bSdrh case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; 525e22a334bSdrh case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; 526e22a334bSdrh case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; 527e22a334bSdrh case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; 528e22a334bSdrh case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; 529e22a334bSdrh case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; 530e22a334bSdrh case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; 531e22a334bSdrh case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; 532e22a334bSdrh case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; 533e22a334bSdrh case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; 534e22a334bSdrh case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; 535e22a334bSdrh case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; 536e22a334bSdrh case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; 537e22a334bSdrh case SQLITE_READ : zCode="SQLITE_READ"; break; 538e22a334bSdrh case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; 539e22a334bSdrh case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; 540e22a334bSdrh case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; 54181e293b4Sdrh case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break; 54281e293b4Sdrh case SQLITE_DETACH : zCode="SQLITE_DETACH"; break; 5431c8c23ccSdanielk1977 case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; 5441d54df88Sdanielk1977 case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; 545e6e04969Sdrh case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break; 546e22a334bSdrh default : zCode="????"; break; 547e22a334bSdrh } 548e22a334bSdrh Tcl_DStringInit(&str); 549e22a334bSdrh Tcl_DStringAppend(&str, pDb->zAuth, -1); 550e22a334bSdrh Tcl_DStringAppendElement(&str, zCode); 551e22a334bSdrh Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); 552e22a334bSdrh Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); 553e22a334bSdrh Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); 554e22a334bSdrh Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); 555e22a334bSdrh rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); 556e22a334bSdrh Tcl_DStringFree(&str); 557e22a334bSdrh zReply = Tcl_GetStringResult(pDb->interp); 558e22a334bSdrh if( strcmp(zReply,"SQLITE_OK")==0 ){ 559e22a334bSdrh rc = SQLITE_OK; 560e22a334bSdrh }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ 561e22a334bSdrh rc = SQLITE_DENY; 562e22a334bSdrh }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ 563e22a334bSdrh rc = SQLITE_IGNORE; 564e22a334bSdrh }else{ 565e22a334bSdrh rc = 999; 566e22a334bSdrh } 567e22a334bSdrh return rc; 568e22a334bSdrh } 569e22a334bSdrh #endif /* SQLITE_OMIT_AUTHORIZATION */ 570cabb0819Sdrh 571cabb0819Sdrh /* 572ef2cb63eSdanielk1977 ** zText is a pointer to text obtained via an sqlite3_result_text() 573ef2cb63eSdanielk1977 ** or similar interface. This routine returns a Tcl string object, 574ef2cb63eSdanielk1977 ** reference count set to 0, containing the text. If a translation 575ef2cb63eSdanielk1977 ** between iso8859 and UTF-8 is required, it is preformed. 576ef2cb63eSdanielk1977 */ 577ef2cb63eSdanielk1977 static Tcl_Obj *dbTextToObj(char const *zText){ 578ef2cb63eSdanielk1977 Tcl_Obj *pVal; 579ef2cb63eSdanielk1977 #ifdef UTF_TRANSLATION_NEEDED 580ef2cb63eSdanielk1977 Tcl_DString dCol; 581ef2cb63eSdanielk1977 Tcl_DStringInit(&dCol); 582ef2cb63eSdanielk1977 Tcl_ExternalToUtfDString(NULL, zText, -1, &dCol); 583ef2cb63eSdanielk1977 pVal = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1); 584ef2cb63eSdanielk1977 Tcl_DStringFree(&dCol); 585ef2cb63eSdanielk1977 #else 586ef2cb63eSdanielk1977 pVal = Tcl_NewStringObj(zText, -1); 587ef2cb63eSdanielk1977 #endif 588ef2cb63eSdanielk1977 return pVal; 589ef2cb63eSdanielk1977 } 590ef2cb63eSdanielk1977 591ef2cb63eSdanielk1977 /* 5921067fe11Stpoindex ** This routine reads a line of text from FILE in, stores 5931067fe11Stpoindex ** the text in memory obtained from malloc() and returns a pointer 5941067fe11Stpoindex ** to the text. NULL is returned at end of file, or if malloc() 5951067fe11Stpoindex ** fails. 5961067fe11Stpoindex ** 5971067fe11Stpoindex ** The interface is like "readline" but no command-line editing 5981067fe11Stpoindex ** is done. 5991067fe11Stpoindex ** 6001067fe11Stpoindex ** copied from shell.c from '.import' command 6011067fe11Stpoindex */ 6021067fe11Stpoindex static char *local_getline(char *zPrompt, FILE *in){ 6031067fe11Stpoindex char *zLine; 6041067fe11Stpoindex int nLine; 6051067fe11Stpoindex int n; 6061067fe11Stpoindex int eol; 6071067fe11Stpoindex 6081067fe11Stpoindex nLine = 100; 6091067fe11Stpoindex zLine = malloc( nLine ); 6101067fe11Stpoindex if( zLine==0 ) return 0; 6111067fe11Stpoindex n = 0; 6121067fe11Stpoindex eol = 0; 6131067fe11Stpoindex while( !eol ){ 6141067fe11Stpoindex if( n+100>nLine ){ 6151067fe11Stpoindex nLine = nLine*2 + 100; 6161067fe11Stpoindex zLine = realloc(zLine, nLine); 6171067fe11Stpoindex if( zLine==0 ) return 0; 6181067fe11Stpoindex } 6191067fe11Stpoindex if( fgets(&zLine[n], nLine - n, in)==0 ){ 6201067fe11Stpoindex if( n==0 ){ 6211067fe11Stpoindex free(zLine); 6221067fe11Stpoindex return 0; 6231067fe11Stpoindex } 6241067fe11Stpoindex zLine[n] = 0; 6251067fe11Stpoindex eol = 1; 6261067fe11Stpoindex break; 6271067fe11Stpoindex } 6281067fe11Stpoindex while( zLine[n] ){ n++; } 6291067fe11Stpoindex if( n>0 && zLine[n-1]=='\n' ){ 6301067fe11Stpoindex n--; 6311067fe11Stpoindex zLine[n] = 0; 6321067fe11Stpoindex eol = 1; 6331067fe11Stpoindex } 6341067fe11Stpoindex } 6351067fe11Stpoindex zLine = realloc( zLine, n+1 ); 6361067fe11Stpoindex return zLine; 6371067fe11Stpoindex } 6381067fe11Stpoindex 6391067fe11Stpoindex /* 64075897234Sdrh ** The "sqlite" command below creates a new Tcl command for each 64175897234Sdrh ** connection it opens to an SQLite database. This routine is invoked 64275897234Sdrh ** whenever one of those connection-specific commands is executed 64375897234Sdrh ** in Tcl. For example, if you run Tcl code like this: 64475897234Sdrh ** 6459bb575fdSdrh ** sqlite3 db1 "my_database" 64675897234Sdrh ** db1 close 64775897234Sdrh ** 64875897234Sdrh ** The first command opens a connection to the "my_database" database 64975897234Sdrh ** and calls that connection "db1". The second command causes this 65075897234Sdrh ** subroutine to be invoked. 65175897234Sdrh */ 6526d31316cSdrh static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ 653bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 6546d31316cSdrh int choice; 65522fbcb8dSdrh int rc = TCL_OK; 6560de8c112Sdrh static const char *DB_strs[] = { 657fb7e7651Sdrh "authorizer", "busy", "cache", 658fb7e7651Sdrh "changes", "close", "collate", 659fb7e7651Sdrh "collation_needed", "commit_hook", "complete", 660fb7e7651Sdrh "copy", "errorcode", "eval", 66197f2ebc1Sdrh "exists", "function", "last_insert_rowid", 66297f2ebc1Sdrh "nullvalue", "onecolumn", "profile", 66371fd80bfSdanielk1977 "progress", "rekey", "rollback_hook", 6646aafc29bSdrh "timeout", "total_changes", "trace", 6656aafc29bSdrh "transaction", "update_hook", "version", 6666aafc29bSdrh 0 6676d31316cSdrh }; 668411995dcSdrh enum DB_enum { 669fb7e7651Sdrh DB_AUTHORIZER, DB_BUSY, DB_CACHE, 670fb7e7651Sdrh DB_CHANGES, DB_CLOSE, DB_COLLATE, 671fb7e7651Sdrh DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, 672fb7e7651Sdrh DB_COPY, DB_ERRORCODE, DB_EVAL, 67397f2ebc1Sdrh DB_EXISTS, DB_FUNCTION, DB_LAST_INSERT_ROWID, 67497f2ebc1Sdrh DB_NULLVALUE, DB_ONECOLUMN, DB_PROFILE, 67571fd80bfSdanielk1977 DB_PROGRESS, DB_REKEY, DB_ROLLBACK_HOOK, 6766aafc29bSdrh DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, 6776aafc29bSdrh DB_TRANSACTION, DB_UPDATE_HOOK, DB_VERSION 6786d31316cSdrh }; 6791067fe11Stpoindex /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ 6806d31316cSdrh 6816d31316cSdrh if( objc<2 ){ 6826d31316cSdrh Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); 68375897234Sdrh return TCL_ERROR; 68475897234Sdrh } 685411995dcSdrh if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){ 6866d31316cSdrh return TCL_ERROR; 6876d31316cSdrh } 6886d31316cSdrh 689411995dcSdrh switch( (enum DB_enum)choice ){ 69075897234Sdrh 691e22a334bSdrh /* $db authorizer ?CALLBACK? 692e22a334bSdrh ** 693e22a334bSdrh ** Invoke the given callback to authorize each SQL operation as it is 694e22a334bSdrh ** compiled. 5 arguments are appended to the callback before it is 695e22a334bSdrh ** invoked: 696e22a334bSdrh ** 697e22a334bSdrh ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...) 698e22a334bSdrh ** (2) First descriptive name (depends on authorization type) 699e22a334bSdrh ** (3) Second descriptive name 700e22a334bSdrh ** (4) Name of the database (ex: "main", "temp") 701e22a334bSdrh ** (5) Name of trigger that is doing the access 702e22a334bSdrh ** 703e22a334bSdrh ** The callback should return on of the following strings: SQLITE_OK, 704e22a334bSdrh ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error. 705e22a334bSdrh ** 706e22a334bSdrh ** If this method is invoked with no arguments, the current authorization 707e22a334bSdrh ** callback string is returned. 708e22a334bSdrh */ 709e22a334bSdrh case DB_AUTHORIZER: { 7101211de37Sdrh #ifdef SQLITE_OMIT_AUTHORIZATION 7111211de37Sdrh Tcl_AppendResult(interp, "authorization not available in this build", 0); 7121211de37Sdrh return TCL_ERROR; 7131211de37Sdrh #else 714e22a334bSdrh if( objc>3 ){ 715e22a334bSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 7160f14e2ebSdrh return TCL_ERROR; 717e22a334bSdrh }else if( objc==2 ){ 718b5a20d3cSdrh if( pDb->zAuth ){ 719e22a334bSdrh Tcl_AppendResult(interp, pDb->zAuth, 0); 720e22a334bSdrh } 721e22a334bSdrh }else{ 722e22a334bSdrh char *zAuth; 723e22a334bSdrh int len; 724e22a334bSdrh if( pDb->zAuth ){ 725e22a334bSdrh Tcl_Free(pDb->zAuth); 726e22a334bSdrh } 727e22a334bSdrh zAuth = Tcl_GetStringFromObj(objv[2], &len); 728e22a334bSdrh if( zAuth && len>0 ){ 729e22a334bSdrh pDb->zAuth = Tcl_Alloc( len + 1 ); 730e22a334bSdrh strcpy(pDb->zAuth, zAuth); 731e22a334bSdrh }else{ 732e22a334bSdrh pDb->zAuth = 0; 733e22a334bSdrh } 734e22a334bSdrh if( pDb->zAuth ){ 735e22a334bSdrh pDb->interp = interp; 7366f8a503dSdanielk1977 sqlite3_set_authorizer(pDb->db, auth_callback, pDb); 737e22a334bSdrh }else{ 7386f8a503dSdanielk1977 sqlite3_set_authorizer(pDb->db, 0, 0); 739e22a334bSdrh } 740e22a334bSdrh } 7411211de37Sdrh #endif 742e22a334bSdrh break; 743e22a334bSdrh } 744e22a334bSdrh 745bec3f402Sdrh /* $db busy ?CALLBACK? 746bec3f402Sdrh ** 747bec3f402Sdrh ** Invoke the given callback if an SQL statement attempts to open 748bec3f402Sdrh ** a locked database file. 749bec3f402Sdrh */ 7506d31316cSdrh case DB_BUSY: { 7516d31316cSdrh if( objc>3 ){ 7526d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK"); 753bec3f402Sdrh return TCL_ERROR; 7546d31316cSdrh }else if( objc==2 ){ 755bec3f402Sdrh if( pDb->zBusy ){ 756bec3f402Sdrh Tcl_AppendResult(interp, pDb->zBusy, 0); 757bec3f402Sdrh } 758bec3f402Sdrh }else{ 7596d31316cSdrh char *zBusy; 7606d31316cSdrh int len; 761bec3f402Sdrh if( pDb->zBusy ){ 762bec3f402Sdrh Tcl_Free(pDb->zBusy); 7636d31316cSdrh } 7646d31316cSdrh zBusy = Tcl_GetStringFromObj(objv[2], &len); 7656d31316cSdrh if( zBusy && len>0 ){ 7666d31316cSdrh pDb->zBusy = Tcl_Alloc( len + 1 ); 7676d31316cSdrh strcpy(pDb->zBusy, zBusy); 7686d31316cSdrh }else{ 769bec3f402Sdrh pDb->zBusy = 0; 770bec3f402Sdrh } 771bec3f402Sdrh if( pDb->zBusy ){ 772bec3f402Sdrh pDb->interp = interp; 7736f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb); 7746d31316cSdrh }else{ 7756f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, 0, 0); 776bec3f402Sdrh } 777bec3f402Sdrh } 7786d31316cSdrh break; 7796d31316cSdrh } 780bec3f402Sdrh 781fb7e7651Sdrh /* $db cache flush 782fb7e7651Sdrh ** $db cache size n 783fb7e7651Sdrh ** 784fb7e7651Sdrh ** Flush the prepared statement cache, or set the maximum number of 785fb7e7651Sdrh ** cached statements. 786fb7e7651Sdrh */ 787fb7e7651Sdrh case DB_CACHE: { 788fb7e7651Sdrh char *subCmd; 789fb7e7651Sdrh int n; 790fb7e7651Sdrh 791fb7e7651Sdrh if( objc<=2 ){ 792fb7e7651Sdrh Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?"); 793fb7e7651Sdrh return TCL_ERROR; 794fb7e7651Sdrh } 795fb7e7651Sdrh subCmd = Tcl_GetStringFromObj( objv[2], 0 ); 796fb7e7651Sdrh if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){ 797fb7e7651Sdrh if( objc!=3 ){ 798fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "flush"); 799fb7e7651Sdrh return TCL_ERROR; 800fb7e7651Sdrh }else{ 801fb7e7651Sdrh flushStmtCache( pDb ); 802fb7e7651Sdrh } 803fb7e7651Sdrh }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){ 804fb7e7651Sdrh if( objc!=4 ){ 805fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "size n"); 806fb7e7651Sdrh return TCL_ERROR; 807fb7e7651Sdrh }else{ 808fb7e7651Sdrh if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ 809fb7e7651Sdrh Tcl_AppendResult( interp, "cannot convert \"", 810fb7e7651Sdrh Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0); 811fb7e7651Sdrh return TCL_ERROR; 812fb7e7651Sdrh }else{ 813fb7e7651Sdrh if( n<0 ){ 814fb7e7651Sdrh flushStmtCache( pDb ); 815fb7e7651Sdrh n = 0; 816fb7e7651Sdrh }else if( n>MAX_PREPARED_STMTS ){ 817fb7e7651Sdrh n = MAX_PREPARED_STMTS; 818fb7e7651Sdrh } 819fb7e7651Sdrh pDb->maxStmt = n; 820fb7e7651Sdrh } 821fb7e7651Sdrh } 822fb7e7651Sdrh }else{ 823fb7e7651Sdrh Tcl_AppendResult( interp, "bad option \"", 824fb7e7651Sdrh Tcl_GetStringFromObj(objv[0],0), "\": must be flush or size", 0); 825fb7e7651Sdrh return TCL_ERROR; 826fb7e7651Sdrh } 827fb7e7651Sdrh break; 828fb7e7651Sdrh } 829fb7e7651Sdrh 830b28af71aSdanielk1977 /* $db changes 831c8d30ac1Sdrh ** 832c8d30ac1Sdrh ** Return the number of rows that were modified, inserted, or deleted by 833b28af71aSdanielk1977 ** the most recent INSERT, UPDATE or DELETE statement, not including 834b28af71aSdanielk1977 ** any changes made by trigger programs. 835c8d30ac1Sdrh */ 836c8d30ac1Sdrh case DB_CHANGES: { 837c8d30ac1Sdrh Tcl_Obj *pResult; 838c8d30ac1Sdrh if( objc!=2 ){ 839c8d30ac1Sdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 840c8d30ac1Sdrh return TCL_ERROR; 841c8d30ac1Sdrh } 842c8d30ac1Sdrh pResult = Tcl_GetObjResult(interp); 843b28af71aSdanielk1977 Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db)); 844f146a776Srdc break; 845f146a776Srdc } 846f146a776Srdc 84775897234Sdrh /* $db close 84875897234Sdrh ** 84975897234Sdrh ** Shutdown the database 85075897234Sdrh */ 8516d31316cSdrh case DB_CLOSE: { 8526d31316cSdrh Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0)); 8536d31316cSdrh break; 8546d31316cSdrh } 85575897234Sdrh 8560f14e2ebSdrh /* 8570f14e2ebSdrh ** $db collate NAME SCRIPT 8580f14e2ebSdrh ** 8590f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 8600f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 8610f14e2ebSdrh */ 8620f14e2ebSdrh case DB_COLLATE: { 8630f14e2ebSdrh SqlCollate *pCollate; 8640f14e2ebSdrh char *zName; 8650f14e2ebSdrh char *zScript; 8660f14e2ebSdrh int nScript; 8670f14e2ebSdrh if( objc!=4 ){ 8680f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 8690f14e2ebSdrh return TCL_ERROR; 8700f14e2ebSdrh } 8710f14e2ebSdrh zName = Tcl_GetStringFromObj(objv[2], 0); 8720f14e2ebSdrh zScript = Tcl_GetStringFromObj(objv[3], &nScript); 8730f14e2ebSdrh pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 ); 8740f14e2ebSdrh if( pCollate==0 ) return TCL_ERROR; 8750f14e2ebSdrh pCollate->interp = interp; 8760f14e2ebSdrh pCollate->pNext = pDb->pCollate; 8770f14e2ebSdrh pCollate->zScript = (char*)&pCollate[1]; 8780f14e2ebSdrh pDb->pCollate = pCollate; 8790f14e2ebSdrh strcpy(pCollate->zScript, zScript); 8800f14e2ebSdrh if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8, 8810f14e2ebSdrh pCollate, tclSqlCollate) ){ 8829636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 8830f14e2ebSdrh return TCL_ERROR; 8840f14e2ebSdrh } 8850f14e2ebSdrh break; 8860f14e2ebSdrh } 8870f14e2ebSdrh 8880f14e2ebSdrh /* 8890f14e2ebSdrh ** $db collation_needed SCRIPT 8900f14e2ebSdrh ** 8910f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 8920f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 8930f14e2ebSdrh */ 8940f14e2ebSdrh case DB_COLLATION_NEEDED: { 8950f14e2ebSdrh if( objc!=3 ){ 8960f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT"); 8970f14e2ebSdrh return TCL_ERROR; 8980f14e2ebSdrh } 8990f14e2ebSdrh if( pDb->pCollateNeeded ){ 9000f14e2ebSdrh Tcl_DecrRefCount(pDb->pCollateNeeded); 9010f14e2ebSdrh } 9020f14e2ebSdrh pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]); 9030f14e2ebSdrh Tcl_IncrRefCount(pDb->pCollateNeeded); 9040f14e2ebSdrh sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded); 9050f14e2ebSdrh break; 9060f14e2ebSdrh } 9070f14e2ebSdrh 90819e2d37fSdrh /* $db commit_hook ?CALLBACK? 90919e2d37fSdrh ** 91019e2d37fSdrh ** Invoke the given callback just before committing every SQL transaction. 91119e2d37fSdrh ** If the callback throws an exception or returns non-zero, then the 91219e2d37fSdrh ** transaction is aborted. If CALLBACK is an empty string, the callback 91319e2d37fSdrh ** is disabled. 91419e2d37fSdrh */ 91519e2d37fSdrh case DB_COMMIT_HOOK: { 91619e2d37fSdrh if( objc>3 ){ 91719e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 91819e2d37fSdrh return TCL_ERROR; 91919e2d37fSdrh }else if( objc==2 ){ 92019e2d37fSdrh if( pDb->zCommit ){ 92119e2d37fSdrh Tcl_AppendResult(interp, pDb->zCommit, 0); 92219e2d37fSdrh } 92319e2d37fSdrh }else{ 92419e2d37fSdrh char *zCommit; 92519e2d37fSdrh int len; 92619e2d37fSdrh if( pDb->zCommit ){ 92719e2d37fSdrh Tcl_Free(pDb->zCommit); 92819e2d37fSdrh } 92919e2d37fSdrh zCommit = Tcl_GetStringFromObj(objv[2], &len); 93019e2d37fSdrh if( zCommit && len>0 ){ 93119e2d37fSdrh pDb->zCommit = Tcl_Alloc( len + 1 ); 93219e2d37fSdrh strcpy(pDb->zCommit, zCommit); 93319e2d37fSdrh }else{ 93419e2d37fSdrh pDb->zCommit = 0; 93519e2d37fSdrh } 93619e2d37fSdrh if( pDb->zCommit ){ 93719e2d37fSdrh pDb->interp = interp; 93819e2d37fSdrh sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb); 93919e2d37fSdrh }else{ 94019e2d37fSdrh sqlite3_commit_hook(pDb->db, 0, 0); 94119e2d37fSdrh } 94219e2d37fSdrh } 94319e2d37fSdrh break; 94419e2d37fSdrh } 94519e2d37fSdrh 94675897234Sdrh /* $db complete SQL 94775897234Sdrh ** 94875897234Sdrh ** Return TRUE if SQL is a complete SQL statement. Return FALSE if 94975897234Sdrh ** additional lines of input are needed. This is similar to the 95075897234Sdrh ** built-in "info complete" command of Tcl. 95175897234Sdrh */ 9526d31316cSdrh case DB_COMPLETE: { 953ccae6026Sdrh #ifndef SQLITE_OMIT_COMPLETE 9546d31316cSdrh Tcl_Obj *pResult; 9556d31316cSdrh int isComplete; 9566d31316cSdrh if( objc!=3 ){ 9576d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 95875897234Sdrh return TCL_ERROR; 95975897234Sdrh } 9606f8a503dSdanielk1977 isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); 9616d31316cSdrh pResult = Tcl_GetObjResult(interp); 9626d31316cSdrh Tcl_SetBooleanObj(pResult, isComplete); 963ccae6026Sdrh #endif 9646d31316cSdrh break; 9656d31316cSdrh } 96675897234Sdrh 96719e2d37fSdrh /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR? 96819e2d37fSdrh ** 96919e2d37fSdrh ** Copy data into table from filename, optionally using SEPARATOR 97019e2d37fSdrh ** as column separators. If a column contains a null string, or the 97119e2d37fSdrh ** value of NULLINDICATOR, a NULL is inserted for the column. 97219e2d37fSdrh ** conflict-algorithm is one of the sqlite conflict algorithms: 97319e2d37fSdrh ** rollback, abort, fail, ignore, replace 97419e2d37fSdrh ** On success, return the number of lines processed, not necessarily same 97519e2d37fSdrh ** as 'db changes' due to conflict-algorithm selected. 97619e2d37fSdrh ** 97719e2d37fSdrh ** This code is basically an implementation/enhancement of 97819e2d37fSdrh ** the sqlite3 shell.c ".import" command. 97919e2d37fSdrh ** 98019e2d37fSdrh ** This command usage is equivalent to the sqlite2.x COPY statement, 98119e2d37fSdrh ** which imports file data into a table using the PostgreSQL COPY file format: 98219e2d37fSdrh ** $db copy $conflit_algo $table_name $filename \t \\N 98319e2d37fSdrh */ 98419e2d37fSdrh case DB_COPY: { 98519e2d37fSdrh char *zTable; /* Insert data into this table */ 98619e2d37fSdrh char *zFile; /* The file from which to extract data */ 98719e2d37fSdrh char *zConflict; /* The conflict algorithm to use */ 98819e2d37fSdrh sqlite3_stmt *pStmt; /* A statement */ 98919e2d37fSdrh int rc; /* Result code */ 99019e2d37fSdrh int nCol; /* Number of columns in the table */ 99119e2d37fSdrh int nByte; /* Number of bytes in an SQL string */ 99219e2d37fSdrh int i, j; /* Loop counters */ 99319e2d37fSdrh int nSep; /* Number of bytes in zSep[] */ 99419e2d37fSdrh int nNull; /* Number of bytes in zNull[] */ 99519e2d37fSdrh char *zSql; /* An SQL statement */ 99619e2d37fSdrh char *zLine; /* A single line of input from the file */ 99719e2d37fSdrh char **azCol; /* zLine[] broken up into columns */ 99819e2d37fSdrh char *zCommit; /* How to commit changes */ 99919e2d37fSdrh FILE *in; /* The input file */ 100019e2d37fSdrh int lineno = 0; /* Line number of input file */ 100119e2d37fSdrh char zLineNum[80]; /* Line number print buffer */ 100219e2d37fSdrh Tcl_Obj *pResult; /* interp result */ 100319e2d37fSdrh 100419e2d37fSdrh char *zSep; 100519e2d37fSdrh char *zNull; 100619e2d37fSdrh if( objc<5 || objc>7 ){ 100719e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, 100819e2d37fSdrh "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"); 100919e2d37fSdrh return TCL_ERROR; 101019e2d37fSdrh } 101119e2d37fSdrh if( objc>=6 ){ 101219e2d37fSdrh zSep = Tcl_GetStringFromObj(objv[5], 0); 101319e2d37fSdrh }else{ 101419e2d37fSdrh zSep = "\t"; 101519e2d37fSdrh } 101619e2d37fSdrh if( objc>=7 ){ 101719e2d37fSdrh zNull = Tcl_GetStringFromObj(objv[6], 0); 101819e2d37fSdrh }else{ 101919e2d37fSdrh zNull = ""; 102019e2d37fSdrh } 102119e2d37fSdrh zConflict = Tcl_GetStringFromObj(objv[2], 0); 102219e2d37fSdrh zTable = Tcl_GetStringFromObj(objv[3], 0); 102319e2d37fSdrh zFile = Tcl_GetStringFromObj(objv[4], 0); 102419e2d37fSdrh nSep = strlen(zSep); 102519e2d37fSdrh nNull = strlen(zNull); 102619e2d37fSdrh if( nSep==0 ){ 102719e2d37fSdrh Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0); 102819e2d37fSdrh return TCL_ERROR; 102919e2d37fSdrh } 103019e2d37fSdrh if(sqlite3StrICmp(zConflict, "rollback") != 0 && 103119e2d37fSdrh sqlite3StrICmp(zConflict, "abort" ) != 0 && 103219e2d37fSdrh sqlite3StrICmp(zConflict, "fail" ) != 0 && 103319e2d37fSdrh sqlite3StrICmp(zConflict, "ignore" ) != 0 && 103419e2d37fSdrh sqlite3StrICmp(zConflict, "replace" ) != 0 ) { 103519e2d37fSdrh Tcl_AppendResult(interp, "Error: \"", zConflict, 103619e2d37fSdrh "\", conflict-algorithm must be one of: rollback, " 103719e2d37fSdrh "abort, fail, ignore, or replace", 0); 103819e2d37fSdrh return TCL_ERROR; 103919e2d37fSdrh } 104019e2d37fSdrh zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); 104119e2d37fSdrh if( zSql==0 ){ 104219e2d37fSdrh Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0); 104319e2d37fSdrh return TCL_ERROR; 104419e2d37fSdrh } 104519e2d37fSdrh nByte = strlen(zSql); 104619e2d37fSdrh rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0); 104719e2d37fSdrh sqlite3_free(zSql); 104819e2d37fSdrh if( rc ){ 104919e2d37fSdrh Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); 105019e2d37fSdrh nCol = 0; 105119e2d37fSdrh }else{ 105219e2d37fSdrh nCol = sqlite3_column_count(pStmt); 105319e2d37fSdrh } 105419e2d37fSdrh sqlite3_finalize(pStmt); 105519e2d37fSdrh if( nCol==0 ) { 105619e2d37fSdrh return TCL_ERROR; 105719e2d37fSdrh } 105819e2d37fSdrh zSql = malloc( nByte + 50 + nCol*2 ); 105919e2d37fSdrh if( zSql==0 ) { 106019e2d37fSdrh Tcl_AppendResult(interp, "Error: can't malloc()", 0); 106119e2d37fSdrh return TCL_ERROR; 106219e2d37fSdrh } 106319e2d37fSdrh sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?", 106419e2d37fSdrh zConflict, zTable); 106519e2d37fSdrh j = strlen(zSql); 106619e2d37fSdrh for(i=1; i<nCol; i++){ 106719e2d37fSdrh zSql[j++] = ','; 106819e2d37fSdrh zSql[j++] = '?'; 106919e2d37fSdrh } 107019e2d37fSdrh zSql[j++] = ')'; 107119e2d37fSdrh zSql[j] = 0; 107219e2d37fSdrh rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0); 107319e2d37fSdrh free(zSql); 107419e2d37fSdrh if( rc ){ 107519e2d37fSdrh Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); 107619e2d37fSdrh sqlite3_finalize(pStmt); 107719e2d37fSdrh return TCL_ERROR; 107819e2d37fSdrh } 107919e2d37fSdrh in = fopen(zFile, "rb"); 108019e2d37fSdrh if( in==0 ){ 108119e2d37fSdrh Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL); 108219e2d37fSdrh sqlite3_finalize(pStmt); 108319e2d37fSdrh return TCL_ERROR; 108419e2d37fSdrh } 108519e2d37fSdrh azCol = malloc( sizeof(azCol[0])*(nCol+1) ); 108619e2d37fSdrh if( azCol==0 ) { 108719e2d37fSdrh Tcl_AppendResult(interp, "Error: can't malloc()", 0); 108843617e9aSdrh fclose(in); 108919e2d37fSdrh return TCL_ERROR; 109019e2d37fSdrh } 10913752785fSdrh (void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0); 109219e2d37fSdrh zCommit = "COMMIT"; 109319e2d37fSdrh while( (zLine = local_getline(0, in))!=0 ){ 109419e2d37fSdrh char *z; 109519e2d37fSdrh i = 0; 109619e2d37fSdrh lineno++; 109719e2d37fSdrh azCol[0] = zLine; 109819e2d37fSdrh for(i=0, z=zLine; *z; z++){ 109919e2d37fSdrh if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){ 110019e2d37fSdrh *z = 0; 110119e2d37fSdrh i++; 110219e2d37fSdrh if( i<nCol ){ 110319e2d37fSdrh azCol[i] = &z[nSep]; 110419e2d37fSdrh z += nSep-1; 110519e2d37fSdrh } 110619e2d37fSdrh } 110719e2d37fSdrh } 110819e2d37fSdrh if( i+1!=nCol ){ 110919e2d37fSdrh char *zErr; 111019e2d37fSdrh zErr = malloc(200 + strlen(zFile)); 1111c1f4494eSdrh if( zErr ){ 1112955de52cSdanielk1977 sprintf(zErr, 1113955de52cSdanielk1977 "Error: %s line %d: expected %d columns of data but found %d", 111419e2d37fSdrh zFile, lineno, nCol, i+1); 111519e2d37fSdrh Tcl_AppendResult(interp, zErr, 0); 111619e2d37fSdrh free(zErr); 1117c1f4494eSdrh } 111819e2d37fSdrh zCommit = "ROLLBACK"; 111919e2d37fSdrh break; 112019e2d37fSdrh } 112119e2d37fSdrh for(i=0; i<nCol; i++){ 112219e2d37fSdrh /* check for null data, if so, bind as null */ 112319e2d37fSdrh if ((nNull>0 && strcmp(azCol[i], zNull)==0) || strlen(azCol[i])==0) { 112419e2d37fSdrh sqlite3_bind_null(pStmt, i+1); 112519e2d37fSdrh }else{ 112619e2d37fSdrh sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); 112719e2d37fSdrh } 112819e2d37fSdrh } 112919e2d37fSdrh sqlite3_step(pStmt); 113019e2d37fSdrh rc = sqlite3_reset(pStmt); 113119e2d37fSdrh free(zLine); 113219e2d37fSdrh if( rc!=SQLITE_OK ){ 113319e2d37fSdrh Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0); 113419e2d37fSdrh zCommit = "ROLLBACK"; 113519e2d37fSdrh break; 113619e2d37fSdrh } 113719e2d37fSdrh } 113819e2d37fSdrh free(azCol); 113919e2d37fSdrh fclose(in); 114019e2d37fSdrh sqlite3_finalize(pStmt); 11413752785fSdrh (void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0); 114219e2d37fSdrh 114319e2d37fSdrh if( zCommit[0] == 'C' ){ 114419e2d37fSdrh /* success, set result as number of lines processed */ 114519e2d37fSdrh pResult = Tcl_GetObjResult(interp); 114619e2d37fSdrh Tcl_SetIntObj(pResult, lineno); 114719e2d37fSdrh rc = TCL_OK; 114819e2d37fSdrh }else{ 114919e2d37fSdrh /* failure, append lineno where failed */ 115019e2d37fSdrh sprintf(zLineNum,"%d",lineno); 115119e2d37fSdrh Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0); 115219e2d37fSdrh rc = TCL_ERROR; 115319e2d37fSdrh } 115419e2d37fSdrh break; 115519e2d37fSdrh } 115619e2d37fSdrh 115775897234Sdrh /* 1158dcd997eaSdrh ** $db errorcode 1159dcd997eaSdrh ** 1160dcd997eaSdrh ** Return the numeric error code that was returned by the most recent 11616f8a503dSdanielk1977 ** call to sqlite3_exec(). 1162dcd997eaSdrh */ 1163dcd997eaSdrh case DB_ERRORCODE: { 1164f3ce83f5Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); 1165dcd997eaSdrh break; 1166dcd997eaSdrh } 1167dcd997eaSdrh 1168dcd997eaSdrh /* 1169895d7472Sdrh ** $db eval $sql ?array? ?{ ...code... }? 11701807ce37Sdrh ** $db onecolumn $sql 117175897234Sdrh ** 117275897234Sdrh ** The SQL statement in $sql is evaluated. For each row, the values are 1173bec3f402Sdrh ** placed in elements of the array named "array" and ...code... is executed. 117475897234Sdrh ** If "array" and "code" are omitted, then no callback is every invoked. 117575897234Sdrh ** If "array" is an empty string, then the values are placed in variables 117675897234Sdrh ** that have the same name as the fields extracted by the query. 11771807ce37Sdrh ** 11781807ce37Sdrh ** The onecolumn method is the equivalent of: 11791807ce37Sdrh ** lindex [$db eval $sql] 0 118075897234Sdrh */ 11811807ce37Sdrh case DB_ONECOLUMN: 118297f2ebc1Sdrh case DB_EVAL: 118397f2ebc1Sdrh case DB_EXISTS: { 11849d74b4c5Sdrh char const *zSql; /* Next SQL statement to execute */ 11859d74b4c5Sdrh char const *zLeft; /* What is left after first stmt in zSql */ 11869d74b4c5Sdrh sqlite3_stmt *pStmt; /* Compiled SQL statment */ 118792febd92Sdrh Tcl_Obj *pArray; /* Name of array into which results are written */ 118892febd92Sdrh Tcl_Obj *pScript; /* Script to run for each result set */ 11891d895039Sdrh Tcl_Obj **apParm; /* Parameters that need a Tcl_DecrRefCount() */ 11901d895039Sdrh int nParm; /* Number of entries used in apParm[] */ 11911d895039Sdrh Tcl_Obj *aParm[10]; /* Static space for apParm[] in the common case */ 11921807ce37Sdrh Tcl_Obj *pRet; /* Value to be returned */ 1193fb7e7651Sdrh SqlPreparedStmt *pPreStmt; /* Pointer to a prepared statement */ 1194fb7e7651Sdrh int rc2; 1195ef2cb63eSdanielk1977 119697f2ebc1Sdrh if( choice==DB_EVAL ){ 119792febd92Sdrh if( objc<3 || objc>5 ){ 1198895d7472Sdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?"); 119930ccda10Sdanielk1977 return TCL_ERROR; 120030ccda10Sdanielk1977 } 12011807ce37Sdrh pRet = Tcl_NewObj(); 12021807ce37Sdrh Tcl_IncrRefCount(pRet); 120397f2ebc1Sdrh }else{ 120497f2ebc1Sdrh if( objc!=3 ){ 120597f2ebc1Sdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 120697f2ebc1Sdrh return TCL_ERROR; 120797f2ebc1Sdrh } 120897f2ebc1Sdrh if( choice==DB_EXISTS ){ 1209446a9b82Sdrh pRet = Tcl_NewBooleanObj(0); 1210446a9b82Sdrh Tcl_IncrRefCount(pRet); 1211446a9b82Sdrh }else{ 1212446a9b82Sdrh pRet = 0; 121397f2ebc1Sdrh } 12141807ce37Sdrh } 121592febd92Sdrh if( objc==3 ){ 121692febd92Sdrh pArray = pScript = 0; 121792febd92Sdrh }else if( objc==4 ){ 121892febd92Sdrh pArray = 0; 121992febd92Sdrh pScript = objv[3]; 122092febd92Sdrh }else{ 122192febd92Sdrh pArray = objv[3]; 122292febd92Sdrh if( Tcl_GetString(pArray)[0]==0 ) pArray = 0; 122392febd92Sdrh pScript = objv[4]; 122492febd92Sdrh } 122530ccda10Sdanielk1977 12261d895039Sdrh Tcl_IncrRefCount(objv[2]); 122730ccda10Sdanielk1977 zSql = Tcl_GetStringFromObj(objv[2], 0); 122890b6bb19Sdrh while( rc==TCL_OK && zSql[0] ){ 122992febd92Sdrh int i; /* Loop counter */ 1230fb7e7651Sdrh int nVar; /* Number of bind parameters in the pStmt */ 123192febd92Sdrh int nCol; /* Number of columns in the result set */ 123292febd92Sdrh Tcl_Obj **apColName = 0; /* Array of column names */ 1233fb7e7651Sdrh int len; /* String length of zSql */ 123430ccda10Sdanielk1977 1235fb7e7651Sdrh /* Try to find a SQL statement that has already been compiled and 1236fb7e7651Sdrh ** which matches the next sequence of SQL. 1237fb7e7651Sdrh */ 1238fb7e7651Sdrh pStmt = 0; 1239fb7e7651Sdrh pPreStmt = pDb->stmtList; 1240fb7e7651Sdrh len = strlen(zSql); 1241fb7e7651Sdrh if( pPreStmt && sqlite3_expired(pPreStmt->pStmt) ){ 1242fb7e7651Sdrh flushStmtCache(pDb); 1243fb7e7651Sdrh pPreStmt = 0; 1244fb7e7651Sdrh } 1245fb7e7651Sdrh for(; pPreStmt; pPreStmt=pPreStmt->pNext){ 1246fb7e7651Sdrh int n = pPreStmt->nSql; 1247fb7e7651Sdrh if( len>=n 1248fb7e7651Sdrh && memcmp(pPreStmt->zSql, zSql, n)==0 1249fb7e7651Sdrh && (zSql[n]==0 || zSql[n-1]==';') 1250fb7e7651Sdrh ){ 1251fb7e7651Sdrh pStmt = pPreStmt->pStmt; 1252fb7e7651Sdrh zLeft = &zSql[pPreStmt->nSql]; 1253fb7e7651Sdrh 1254fb7e7651Sdrh /* When a prepared statement is found, unlink it from the 1255fb7e7651Sdrh ** cache list. It will later be added back to the beginning 1256fb7e7651Sdrh ** of the cache list in order to implement LRU replacement. 1257fb7e7651Sdrh */ 1258fb7e7651Sdrh if( pPreStmt->pPrev ){ 1259fb7e7651Sdrh pPreStmt->pPrev->pNext = pPreStmt->pNext; 1260fb7e7651Sdrh }else{ 1261fb7e7651Sdrh pDb->stmtList = pPreStmt->pNext; 1262fb7e7651Sdrh } 1263fb7e7651Sdrh if( pPreStmt->pNext ){ 1264fb7e7651Sdrh pPreStmt->pNext->pPrev = pPreStmt->pPrev; 1265fb7e7651Sdrh }else{ 1266fb7e7651Sdrh pDb->stmtLast = pPreStmt->pPrev; 1267fb7e7651Sdrh } 1268fb7e7651Sdrh pDb->nStmt--; 1269fb7e7651Sdrh break; 1270fb7e7651Sdrh } 1271fb7e7651Sdrh } 1272fb7e7651Sdrh 1273fb7e7651Sdrh /* If no prepared statement was found. Compile the SQL text 1274fb7e7651Sdrh */ 1275fb7e7651Sdrh if( pStmt==0 ){ 127630ccda10Sdanielk1977 if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){ 1277ef2cb63eSdanielk1977 Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); 127830ccda10Sdanielk1977 rc = TCL_ERROR; 127930ccda10Sdanielk1977 break; 128030ccda10Sdanielk1977 } 128192febd92Sdrh if( pStmt==0 ){ 128292febd92Sdrh if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){ 1283fb7e7651Sdrh /* A compile-time error in the statement 1284fb7e7651Sdrh */ 128592febd92Sdrh Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); 128692febd92Sdrh rc = TCL_ERROR; 128792febd92Sdrh break; 128892febd92Sdrh }else{ 1289fb7e7651Sdrh /* The statement was a no-op. Continue to the next statement 1290fb7e7651Sdrh ** in the SQL string. 1291fb7e7651Sdrh */ 129292febd92Sdrh zSql = zLeft; 129392febd92Sdrh continue; 129492febd92Sdrh } 129592febd92Sdrh } 1296fb7e7651Sdrh assert( pPreStmt==0 ); 1297fb7e7651Sdrh } 129830ccda10Sdanielk1977 1299fb7e7651Sdrh /* Bind values to parameters that begin with $ or : 1300fb7e7651Sdrh */ 130192febd92Sdrh nVar = sqlite3_bind_parameter_count(pStmt); 13021d895039Sdrh nParm = 0; 13031d895039Sdrh if( nVar>sizeof(aParm)/sizeof(aParm[0]) ){ 13041d895039Sdrh apParm = (Tcl_Obj**)Tcl_Alloc(nVar*sizeof(apParm[0])); 13051d895039Sdrh }else{ 13061d895039Sdrh apParm = aParm; 13071d895039Sdrh } 130892febd92Sdrh for(i=1; i<=nVar; i++){ 130992febd92Sdrh const char *zVar = sqlite3_bind_parameter_name(pStmt, i); 1310c8f9079cSdrh if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':') ){ 131192febd92Sdrh Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); 131292febd92Sdrh if( pVar ){ 131392febd92Sdrh int n; 131492febd92Sdrh u8 *data; 131592febd92Sdrh char *zType = pVar->typePtr ? pVar->typePtr->name : ""; 131692febd92Sdrh char c = zType[0]; 1317df0bddaeSdrh if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ 1318df0bddaeSdrh /* Only load a BLOB type if the Tcl variable is a bytearray and 1319df0bddaeSdrh ** has no string representation. */ 132092febd92Sdrh data = Tcl_GetByteArrayFromObj(pVar, &n); 132192febd92Sdrh sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC); 13221d895039Sdrh Tcl_IncrRefCount(pVar); 13231d895039Sdrh apParm[nParm++] = pVar; 132492febd92Sdrh }else if( (c=='b' && strcmp(zType,"boolean")==0) || 132592febd92Sdrh (c=='i' && strcmp(zType,"int")==0) ){ 132692febd92Sdrh Tcl_GetIntFromObj(interp, pVar, &n); 132792febd92Sdrh sqlite3_bind_int(pStmt, i, n); 132892febd92Sdrh }else if( c=='d' && strcmp(zType,"double")==0 ){ 132992febd92Sdrh double r; 133092febd92Sdrh Tcl_GetDoubleFromObj(interp, pVar, &r); 133192febd92Sdrh sqlite3_bind_double(pStmt, i, r); 1332df0bddaeSdrh }else if( c=='w' && strcmp(zType,"wideInt")==0 ){ 1333df0bddaeSdrh Tcl_WideInt v; 1334df0bddaeSdrh Tcl_GetWideIntFromObj(interp, pVar, &v); 1335df0bddaeSdrh sqlite3_bind_int64(pStmt, i, v); 133692febd92Sdrh }else{ 133700fd957bSdanielk1977 data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); 133800fd957bSdanielk1977 sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC); 13391d895039Sdrh Tcl_IncrRefCount(pVar); 13401d895039Sdrh apParm[nParm++] = pVar; 134192febd92Sdrh } 1342fb7e7651Sdrh }else{ 1343fb7e7651Sdrh sqlite3_bind_null( pStmt, i ); 134492febd92Sdrh } 134592febd92Sdrh } 134692febd92Sdrh } 134792febd92Sdrh 134892febd92Sdrh /* Compute column names */ 134992febd92Sdrh nCol = sqlite3_column_count(pStmt); 135092febd92Sdrh if( pScript ){ 135192febd92Sdrh apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol ); 135292febd92Sdrh if( apColName==0 ) break; 135392febd92Sdrh for(i=0; i<nCol; i++){ 135492febd92Sdrh apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i)); 135592febd92Sdrh Tcl_IncrRefCount(apColName[i]); 135692febd92Sdrh } 135792febd92Sdrh } 135892febd92Sdrh 135992febd92Sdrh /* If results are being stored in an array variable, then create 136092febd92Sdrh ** the array(*) entry for that array 136192febd92Sdrh */ 136292febd92Sdrh if( pArray ){ 136330ccda10Sdanielk1977 Tcl_Obj *pColList = Tcl_NewObj(); 13643ced14a6Sdrh Tcl_Obj *pStar = Tcl_NewStringObj("*", -1); 136530ccda10Sdanielk1977 Tcl_IncrRefCount(pColList); 136692febd92Sdrh for(i=0; i<nCol; i++){ 136792febd92Sdrh Tcl_ListObjAppendElement(interp, pColList, apColName[i]); 136830ccda10Sdanielk1977 } 13693ced14a6Sdrh Tcl_ObjSetVar2(interp, pArray, pStar, pColList,0); 13703ced14a6Sdrh Tcl_DecrRefCount(pColList); 13713ced14a6Sdrh Tcl_DecrRefCount(pStar); 137230ccda10Sdanielk1977 } 137330ccda10Sdanielk1977 137492febd92Sdrh /* Execute the SQL 137592febd92Sdrh */ 137690b6bb19Sdrh while( rc==TCL_OK && pStmt && SQLITE_ROW==sqlite3_step(pStmt) ){ 137792febd92Sdrh for(i=0; i<nCol; i++){ 137830ccda10Sdanielk1977 Tcl_Obj *pVal; 137930ccda10Sdanielk1977 138030ccda10Sdanielk1977 /* Set pVal to contain the i'th column of this row. */ 138192febd92Sdrh switch( sqlite3_column_type(pStmt, i) ){ 138292febd92Sdrh case SQLITE_BLOB: { 13833fd0a736Sdanielk1977 int bytes = sqlite3_column_bytes(pStmt, i); 13843fd0a736Sdanielk1977 pVal = Tcl_NewByteArrayObj(sqlite3_column_blob(pStmt, i), bytes); 138592febd92Sdrh break; 138692febd92Sdrh } 138792febd92Sdrh case SQLITE_INTEGER: { 138892febd92Sdrh sqlite_int64 v = sqlite3_column_int64(pStmt, i); 138992febd92Sdrh if( v>=-2147483647 && v<=2147483647 ){ 139092febd92Sdrh pVal = Tcl_NewIntObj(v); 139192febd92Sdrh }else{ 139292febd92Sdrh pVal = Tcl_NewWideIntObj(v); 139392febd92Sdrh } 139492febd92Sdrh break; 139592febd92Sdrh } 139692febd92Sdrh case SQLITE_FLOAT: { 139792febd92Sdrh double r = sqlite3_column_double(pStmt, i); 139892febd92Sdrh pVal = Tcl_NewDoubleObj(r); 139992febd92Sdrh break; 140092febd92Sdrh } 140155c45f2eSdanielk1977 case SQLITE_NULL: { 140255c45f2eSdanielk1977 pVal = dbTextToObj(pDb->zNull); 140355c45f2eSdanielk1977 break; 140455c45f2eSdanielk1977 } 140592febd92Sdrh default: { 140600fd957bSdanielk1977 pVal = dbTextToObj((char *)sqlite3_column_text(pStmt, i)); 140792febd92Sdrh break; 140892febd92Sdrh } 140930ccda10Sdanielk1977 } 141030ccda10Sdanielk1977 141192febd92Sdrh if( pScript ){ 141292febd92Sdrh if( pArray==0 ){ 141392febd92Sdrh Tcl_ObjSetVar2(interp, apColName[i], 0, pVal, 0); 141430ccda10Sdanielk1977 }else{ 141592febd92Sdrh Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0); 141630ccda10Sdanielk1977 } 14171807ce37Sdrh }else if( choice==DB_ONECOLUMN ){ 141897f2ebc1Sdrh assert( pRet==0 ); 14191807ce37Sdrh if( pRet==0 ){ 14201807ce37Sdrh pRet = pVal; 14211807ce37Sdrh Tcl_IncrRefCount(pRet); 14221807ce37Sdrh } 142390b6bb19Sdrh rc = TCL_BREAK; 142497f2ebc1Sdrh i = nCol; 142597f2ebc1Sdrh }else if( choice==DB_EXISTS ){ 1426446a9b82Sdrh Tcl_DecrRefCount(pRet); 1427446a9b82Sdrh pRet = Tcl_NewBooleanObj(1); 1428446a9b82Sdrh Tcl_IncrRefCount(pRet); 142997f2ebc1Sdrh rc = TCL_BREAK; 143097f2ebc1Sdrh i = nCol; 143130ccda10Sdanielk1977 }else{ 143230ccda10Sdanielk1977 Tcl_ListObjAppendElement(interp, pRet, pVal); 143330ccda10Sdanielk1977 } 143430ccda10Sdanielk1977 } 143530ccda10Sdanielk1977 143692febd92Sdrh if( pScript ){ 143792febd92Sdrh rc = Tcl_EvalObjEx(interp, pScript, 0); 143890b6bb19Sdrh if( rc==TCL_CONTINUE ){ 143990b6bb19Sdrh rc = TCL_OK; 144030ccda10Sdanielk1977 } 144130ccda10Sdanielk1977 } 144290b6bb19Sdrh } 144390b6bb19Sdrh if( rc==TCL_BREAK ){ 144490b6bb19Sdrh rc = TCL_OK; 144590b6bb19Sdrh } 144630ccda10Sdanielk1977 144792febd92Sdrh /* Free the column name objects */ 144892febd92Sdrh if( pScript ){ 144992febd92Sdrh for(i=0; i<nCol; i++){ 145092febd92Sdrh Tcl_DecrRefCount(apColName[i]); 145192febd92Sdrh } 145292febd92Sdrh Tcl_Free((char*)apColName); 145392febd92Sdrh } 145492febd92Sdrh 14551d895039Sdrh /* Free the bound string and blob parameters */ 14561d895039Sdrh for(i=0; i<nParm; i++){ 14571d895039Sdrh Tcl_DecrRefCount(apParm[i]); 14581d895039Sdrh } 14591d895039Sdrh if( apParm!=aParm ){ 14601d895039Sdrh Tcl_Free((char*)apParm); 14611d895039Sdrh } 14621d895039Sdrh 1463fb7e7651Sdrh /* Reset the statement. If the result code is SQLITE_SCHEMA, then 1464fb7e7651Sdrh ** flush the statement cache and try the statement again. 146592febd92Sdrh */ 1466fb7e7651Sdrh rc2 = sqlite3_reset(pStmt); 1467fb7e7651Sdrh if( SQLITE_SCHEMA==rc2 ){ 1468fb7e7651Sdrh /* After a schema change, flush the cache and try to run the 1469fb7e7651Sdrh ** statement again 1470fb7e7651Sdrh */ 1471fb7e7651Sdrh flushStmtCache( pDb ); 1472fb7e7651Sdrh sqlite3_finalize(pStmt); 1473fb7e7651Sdrh if( pPreStmt ) Tcl_Free((char*)pPreStmt); 147430ccda10Sdanielk1977 continue; 1475fb7e7651Sdrh }else if( SQLITE_OK!=rc2 ){ 1476fb7e7651Sdrh /* If a run-time error occurs, report the error and stop reading 1477fb7e7651Sdrh ** the SQL 1478fb7e7651Sdrh */ 1479ef2cb63eSdanielk1977 Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); 1480fb7e7651Sdrh sqlite3_finalize(pStmt); 148130ccda10Sdanielk1977 rc = TCL_ERROR; 1482fb7e7651Sdrh if( pPreStmt ) Tcl_Free((char*)pPreStmt); 148330ccda10Sdanielk1977 break; 1484fb7e7651Sdrh }else if( pDb->maxStmt<=0 ){ 1485fb7e7651Sdrh /* If the cache is turned off, deallocated the statement */ 1486fb7e7651Sdrh if( pPreStmt ) Tcl_Free((char*)pPreStmt); 1487fb7e7651Sdrh sqlite3_finalize(pStmt); 1488fb7e7651Sdrh }else{ 1489fb7e7651Sdrh /* Everything worked and the cache is operational. 1490fb7e7651Sdrh ** Create a new SqlPreparedStmt structure if we need one. 1491fb7e7651Sdrh ** (If we already have one we can just reuse it.) 1492fb7e7651Sdrh */ 1493fb7e7651Sdrh if( pPreStmt==0 ){ 1494fb7e7651Sdrh len = zLeft - zSql; 1495fb7e7651Sdrh pPreStmt = (SqlPreparedStmt*)Tcl_Alloc( sizeof(*pPreStmt) + len ); 1496fb7e7651Sdrh if( pPreStmt==0 ) return TCL_ERROR; 1497fb7e7651Sdrh pPreStmt->pStmt = pStmt; 1498fb7e7651Sdrh pPreStmt->nSql = len; 1499fb7e7651Sdrh memcpy(pPreStmt->zSql, zSql, len); 1500fb7e7651Sdrh pPreStmt->zSql[len] = 0; 150130ccda10Sdanielk1977 } 150230ccda10Sdanielk1977 1503fb7e7651Sdrh /* Add the prepared statement to the beginning of the cache list 1504fb7e7651Sdrh */ 1505fb7e7651Sdrh pPreStmt->pNext = pDb->stmtList; 1506fb7e7651Sdrh pPreStmt->pPrev = 0; 1507fb7e7651Sdrh if( pDb->stmtList ){ 1508fb7e7651Sdrh pDb->stmtList->pPrev = pPreStmt; 1509fb7e7651Sdrh } 1510fb7e7651Sdrh pDb->stmtList = pPreStmt; 1511fb7e7651Sdrh if( pDb->stmtLast==0 ){ 1512fb7e7651Sdrh assert( pDb->nStmt==0 ); 1513fb7e7651Sdrh pDb->stmtLast = pPreStmt; 1514fb7e7651Sdrh }else{ 1515fb7e7651Sdrh assert( pDb->nStmt>0 ); 1516fb7e7651Sdrh } 1517fb7e7651Sdrh pDb->nStmt++; 1518fb7e7651Sdrh 1519fb7e7651Sdrh /* If we have too many statement in cache, remove the surplus from the 1520fb7e7651Sdrh ** end of the cache list. 1521fb7e7651Sdrh */ 1522fb7e7651Sdrh while( pDb->nStmt>pDb->maxStmt ){ 1523fb7e7651Sdrh sqlite3_finalize(pDb->stmtLast->pStmt); 1524fb7e7651Sdrh pDb->stmtLast = pDb->stmtLast->pPrev; 1525fb7e7651Sdrh Tcl_Free((char*)pDb->stmtLast->pNext); 1526fb7e7651Sdrh pDb->stmtLast->pNext = 0; 1527fb7e7651Sdrh pDb->nStmt--; 1528fb7e7651Sdrh } 1529fb7e7651Sdrh } 1530fb7e7651Sdrh 1531fb7e7651Sdrh /* Proceed to the next statement */ 153230ccda10Sdanielk1977 zSql = zLeft; 153330ccda10Sdanielk1977 } 15341d895039Sdrh Tcl_DecrRefCount(objv[2]); 153530ccda10Sdanielk1977 15361807ce37Sdrh if( pRet ){ 1537ef2cb63eSdanielk1977 if( rc==TCL_OK ){ 153830ccda10Sdanielk1977 Tcl_SetObjResult(interp, pRet); 153930ccda10Sdanielk1977 } 1540ef2cb63eSdanielk1977 Tcl_DecrRefCount(pRet); 15411807ce37Sdrh } 154230ccda10Sdanielk1977 break; 154330ccda10Sdanielk1977 } 1544bec3f402Sdrh 1545bec3f402Sdrh /* 1546cabb0819Sdrh ** $db function NAME SCRIPT 1547cabb0819Sdrh ** 1548cabb0819Sdrh ** Create a new SQL function called NAME. Whenever that function is 1549cabb0819Sdrh ** called, invoke SCRIPT to evaluate the function. 1550cabb0819Sdrh */ 1551cabb0819Sdrh case DB_FUNCTION: { 1552cabb0819Sdrh SqlFunc *pFunc; 1553d1e4733dSdrh Tcl_Obj *pScript; 1554cabb0819Sdrh char *zName; 1555cabb0819Sdrh if( objc!=4 ){ 1556cabb0819Sdrh Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 1557cabb0819Sdrh return TCL_ERROR; 1558cabb0819Sdrh } 1559cabb0819Sdrh zName = Tcl_GetStringFromObj(objv[2], 0); 1560d1e4733dSdrh pScript = objv[3]; 1561d1e4733dSdrh pFunc = findSqlFunc(pDb, zName); 1562cabb0819Sdrh if( pFunc==0 ) return TCL_ERROR; 1563d1e4733dSdrh if( pFunc->pScript ){ 1564d1e4733dSdrh Tcl_DecrRefCount(pFunc->pScript); 1565d1e4733dSdrh } 1566d1e4733dSdrh pFunc->pScript = pScript; 1567d1e4733dSdrh Tcl_IncrRefCount(pScript); 1568d1e4733dSdrh pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript); 1569c8c1158bSdanielk1977 rc = sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8, 1570d8123366Sdanielk1977 pFunc, tclSqlFunc, 0, 0); 1571fb7e7651Sdrh if( rc!=SQLITE_OK ){ 1572fb7e7651Sdrh rc = TCL_ERROR; 15739636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 1574fb7e7651Sdrh }else{ 1575fb7e7651Sdrh /* Must flush any cached statements */ 1576fb7e7651Sdrh flushStmtCache( pDb ); 1577fb7e7651Sdrh } 1578cabb0819Sdrh break; 1579cabb0819Sdrh } 1580cabb0819Sdrh 1581cabb0819Sdrh /* 158219e2d37fSdrh ** $db nullvalue ?STRING? 158319e2d37fSdrh ** 158419e2d37fSdrh ** Change text used when a NULL comes back from the database. If ?STRING? 158519e2d37fSdrh ** is not present, then the current string used for NULL is returned. 158619e2d37fSdrh ** If STRING is present, then STRING is returned. 158719e2d37fSdrh ** 158819e2d37fSdrh */ 158919e2d37fSdrh case DB_NULLVALUE: { 159019e2d37fSdrh if( objc!=2 && objc!=3 ){ 159119e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE"); 159219e2d37fSdrh return TCL_ERROR; 159319e2d37fSdrh } 159419e2d37fSdrh if( objc==3 ){ 159519e2d37fSdrh int len; 159619e2d37fSdrh char *zNull = Tcl_GetStringFromObj(objv[2], &len); 159719e2d37fSdrh if( pDb->zNull ){ 159819e2d37fSdrh Tcl_Free(pDb->zNull); 159919e2d37fSdrh } 160019e2d37fSdrh if( zNull && len>0 ){ 160119e2d37fSdrh pDb->zNull = Tcl_Alloc( len + 1 ); 160219e2d37fSdrh strncpy(pDb->zNull, zNull, len); 160319e2d37fSdrh pDb->zNull[len] = '\0'; 160419e2d37fSdrh }else{ 160519e2d37fSdrh pDb->zNull = 0; 160619e2d37fSdrh } 160719e2d37fSdrh } 160819e2d37fSdrh Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull)); 160919e2d37fSdrh break; 161019e2d37fSdrh } 161119e2d37fSdrh 161219e2d37fSdrh /* 1613af9ff33aSdrh ** $db last_insert_rowid 1614af9ff33aSdrh ** 1615af9ff33aSdrh ** Return an integer which is the ROWID for the most recent insert. 1616af9ff33aSdrh */ 1617af9ff33aSdrh case DB_LAST_INSERT_ROWID: { 1618af9ff33aSdrh Tcl_Obj *pResult; 1619af9ff33aSdrh int rowid; 1620af9ff33aSdrh if( objc!=2 ){ 1621af9ff33aSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 1622af9ff33aSdrh return TCL_ERROR; 1623af9ff33aSdrh } 16246f8a503dSdanielk1977 rowid = sqlite3_last_insert_rowid(pDb->db); 1625af9ff33aSdrh pResult = Tcl_GetObjResult(interp); 1626af9ff33aSdrh Tcl_SetIntObj(pResult, rowid); 1627af9ff33aSdrh break; 1628af9ff33aSdrh } 1629af9ff33aSdrh 1630af9ff33aSdrh /* 16311807ce37Sdrh ** The DB_ONECOLUMN method is implemented together with DB_EVAL. 16325d9d7576Sdrh */ 16331807ce37Sdrh 16341807ce37Sdrh /* $db progress ?N CALLBACK? 16351807ce37Sdrh ** 16361807ce37Sdrh ** Invoke the given callback every N virtual machine opcodes while executing 16371807ce37Sdrh ** queries. 16381807ce37Sdrh */ 16391807ce37Sdrh case DB_PROGRESS: { 16401807ce37Sdrh if( objc==2 ){ 16411807ce37Sdrh if( pDb->zProgress ){ 16421807ce37Sdrh Tcl_AppendResult(interp, pDb->zProgress, 0); 16435d9d7576Sdrh } 16441807ce37Sdrh }else if( objc==4 ){ 16451807ce37Sdrh char *zProgress; 16461807ce37Sdrh int len; 16471807ce37Sdrh int N; 16481807ce37Sdrh if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ 16491807ce37Sdrh return TCL_ERROR; 16501807ce37Sdrh }; 16511807ce37Sdrh if( pDb->zProgress ){ 16521807ce37Sdrh Tcl_Free(pDb->zProgress); 16531807ce37Sdrh } 16541807ce37Sdrh zProgress = Tcl_GetStringFromObj(objv[3], &len); 16551807ce37Sdrh if( zProgress && len>0 ){ 16561807ce37Sdrh pDb->zProgress = Tcl_Alloc( len + 1 ); 16571807ce37Sdrh strcpy(pDb->zProgress, zProgress); 16581807ce37Sdrh }else{ 16591807ce37Sdrh pDb->zProgress = 0; 16601807ce37Sdrh } 16611807ce37Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK 16621807ce37Sdrh if( pDb->zProgress ){ 16631807ce37Sdrh pDb->interp = interp; 16641807ce37Sdrh sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb); 16651807ce37Sdrh }else{ 16661807ce37Sdrh sqlite3_progress_handler(pDb->db, 0, 0, 0); 16671807ce37Sdrh } 16681807ce37Sdrh #endif 16691807ce37Sdrh }else{ 16701807ce37Sdrh Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK"); 16711807ce37Sdrh return TCL_ERROR; 16725d9d7576Sdrh } 16735d9d7576Sdrh break; 16745d9d7576Sdrh } 16755d9d7576Sdrh 167619e2d37fSdrh /* $db profile ?CALLBACK? 167719e2d37fSdrh ** 167819e2d37fSdrh ** Make arrangements to invoke the CALLBACK routine after each SQL statement 167919e2d37fSdrh ** that has run. The text of the SQL and the amount of elapse time are 168019e2d37fSdrh ** appended to CALLBACK before the script is run. 168119e2d37fSdrh */ 168219e2d37fSdrh case DB_PROFILE: { 168319e2d37fSdrh if( objc>3 ){ 168419e2d37fSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 168519e2d37fSdrh return TCL_ERROR; 168619e2d37fSdrh }else if( objc==2 ){ 168719e2d37fSdrh if( pDb->zProfile ){ 168819e2d37fSdrh Tcl_AppendResult(interp, pDb->zProfile, 0); 168919e2d37fSdrh } 169019e2d37fSdrh }else{ 169119e2d37fSdrh char *zProfile; 169219e2d37fSdrh int len; 169319e2d37fSdrh if( pDb->zProfile ){ 169419e2d37fSdrh Tcl_Free(pDb->zProfile); 169519e2d37fSdrh } 169619e2d37fSdrh zProfile = Tcl_GetStringFromObj(objv[2], &len); 169719e2d37fSdrh if( zProfile && len>0 ){ 169819e2d37fSdrh pDb->zProfile = Tcl_Alloc( len + 1 ); 169919e2d37fSdrh strcpy(pDb->zProfile, zProfile); 170019e2d37fSdrh }else{ 170119e2d37fSdrh pDb->zProfile = 0; 170219e2d37fSdrh } 170319e2d37fSdrh #ifndef SQLITE_OMIT_TRACE 170419e2d37fSdrh if( pDb->zProfile ){ 170519e2d37fSdrh pDb->interp = interp; 170619e2d37fSdrh sqlite3_profile(pDb->db, DbProfileHandler, pDb); 170719e2d37fSdrh }else{ 170819e2d37fSdrh sqlite3_profile(pDb->db, 0, 0); 170919e2d37fSdrh } 171019e2d37fSdrh #endif 171119e2d37fSdrh } 171219e2d37fSdrh break; 171319e2d37fSdrh } 171419e2d37fSdrh 17155d9d7576Sdrh /* 171622fbcb8dSdrh ** $db rekey KEY 171722fbcb8dSdrh ** 171822fbcb8dSdrh ** Change the encryption key on the currently open database. 171922fbcb8dSdrh */ 172022fbcb8dSdrh case DB_REKEY: { 172122fbcb8dSdrh int nKey; 172222fbcb8dSdrh void *pKey; 172322fbcb8dSdrh if( objc!=3 ){ 172422fbcb8dSdrh Tcl_WrongNumArgs(interp, 2, objv, "KEY"); 172522fbcb8dSdrh return TCL_ERROR; 172622fbcb8dSdrh } 172722fbcb8dSdrh pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); 17289eb9e26bSdrh #ifdef SQLITE_HAS_CODEC 17292011d5f5Sdrh rc = sqlite3_rekey(pDb->db, pKey, nKey); 173022fbcb8dSdrh if( rc ){ 1731f20b21c8Sdanielk1977 Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); 173222fbcb8dSdrh rc = TCL_ERROR; 173322fbcb8dSdrh } 173422fbcb8dSdrh #endif 173522fbcb8dSdrh break; 173622fbcb8dSdrh } 173722fbcb8dSdrh 173822fbcb8dSdrh /* 1739bec3f402Sdrh ** $db timeout MILLESECONDS 1740bec3f402Sdrh ** 1741bec3f402Sdrh ** Delay for the number of milliseconds specified when a file is locked. 1742bec3f402Sdrh */ 17436d31316cSdrh case DB_TIMEOUT: { 1744bec3f402Sdrh int ms; 17456d31316cSdrh if( objc!=3 ){ 17466d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS"); 1747bec3f402Sdrh return TCL_ERROR; 174875897234Sdrh } 17496d31316cSdrh if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR; 17506f8a503dSdanielk1977 sqlite3_busy_timeout(pDb->db, ms); 17516d31316cSdrh break; 175275897234Sdrh } 1753b5a20d3cSdrh 17540f14e2ebSdrh /* 17550f14e2ebSdrh ** $db total_changes 17560f14e2ebSdrh ** 17570f14e2ebSdrh ** Return the number of rows that were modified, inserted, or deleted 17580f14e2ebSdrh ** since the database handle was created. 17590f14e2ebSdrh */ 17600f14e2ebSdrh case DB_TOTAL_CHANGES: { 17610f14e2ebSdrh Tcl_Obj *pResult; 17620f14e2ebSdrh if( objc!=2 ){ 17630f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 17640f14e2ebSdrh return TCL_ERROR; 17650f14e2ebSdrh } 17660f14e2ebSdrh pResult = Tcl_GetObjResult(interp); 17670f14e2ebSdrh Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db)); 17680f14e2ebSdrh break; 17690f14e2ebSdrh } 17700f14e2ebSdrh 1771b5a20d3cSdrh /* $db trace ?CALLBACK? 1772b5a20d3cSdrh ** 1773b5a20d3cSdrh ** Make arrangements to invoke the CALLBACK routine for each SQL statement 1774b5a20d3cSdrh ** that is executed. The text of the SQL is appended to CALLBACK before 1775b5a20d3cSdrh ** it is executed. 1776b5a20d3cSdrh */ 1777b5a20d3cSdrh case DB_TRACE: { 1778b5a20d3cSdrh if( objc>3 ){ 1779b5a20d3cSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 1780b97759edSdrh return TCL_ERROR; 1781b5a20d3cSdrh }else if( objc==2 ){ 1782b5a20d3cSdrh if( pDb->zTrace ){ 1783b5a20d3cSdrh Tcl_AppendResult(interp, pDb->zTrace, 0); 1784b5a20d3cSdrh } 1785b5a20d3cSdrh }else{ 1786b5a20d3cSdrh char *zTrace; 1787b5a20d3cSdrh int len; 1788b5a20d3cSdrh if( pDb->zTrace ){ 1789b5a20d3cSdrh Tcl_Free(pDb->zTrace); 1790b5a20d3cSdrh } 1791b5a20d3cSdrh zTrace = Tcl_GetStringFromObj(objv[2], &len); 1792b5a20d3cSdrh if( zTrace && len>0 ){ 1793b5a20d3cSdrh pDb->zTrace = Tcl_Alloc( len + 1 ); 1794b5a20d3cSdrh strcpy(pDb->zTrace, zTrace); 1795b5a20d3cSdrh }else{ 1796b5a20d3cSdrh pDb->zTrace = 0; 1797b5a20d3cSdrh } 179819e2d37fSdrh #ifndef SQLITE_OMIT_TRACE 1799b5a20d3cSdrh if( pDb->zTrace ){ 1800b5a20d3cSdrh pDb->interp = interp; 18016f8a503dSdanielk1977 sqlite3_trace(pDb->db, DbTraceHandler, pDb); 1802b5a20d3cSdrh }else{ 18036f8a503dSdanielk1977 sqlite3_trace(pDb->db, 0, 0); 1804b5a20d3cSdrh } 180519e2d37fSdrh #endif 1806b5a20d3cSdrh } 1807b5a20d3cSdrh break; 1808b5a20d3cSdrh } 1809b5a20d3cSdrh 18103d21423cSdrh /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT 18113d21423cSdrh ** 18123d21423cSdrh ** Start a new transaction (if we are not already in the midst of a 18133d21423cSdrh ** transaction) and execute the TCL script SCRIPT. After SCRIPT 18143d21423cSdrh ** completes, either commit the transaction or roll it back if SCRIPT 18153d21423cSdrh ** throws an exception. Or if no new transation was started, do nothing. 18163d21423cSdrh ** pass the exception on up the stack. 18173d21423cSdrh ** 18183d21423cSdrh ** This command was inspired by Dave Thomas's talk on Ruby at the 18193d21423cSdrh ** 2005 O'Reilly Open Source Convention (OSCON). 18203d21423cSdrh */ 18213d21423cSdrh case DB_TRANSACTION: { 18223d21423cSdrh int inTrans; 18233d21423cSdrh Tcl_Obj *pScript; 18243d21423cSdrh const char *zBegin = "BEGIN"; 18253d21423cSdrh if( objc!=3 && objc!=4 ){ 18263d21423cSdrh Tcl_WrongNumArgs(interp, 2, objv, "[TYPE] SCRIPT"); 18273d21423cSdrh return TCL_ERROR; 18283d21423cSdrh } 18293d21423cSdrh if( objc==3 ){ 18303d21423cSdrh pScript = objv[2]; 18313d21423cSdrh } else { 18323d21423cSdrh static const char *TTYPE_strs[] = { 1833ce604012Sdrh "deferred", "exclusive", "immediate", 0 18343d21423cSdrh }; 18353d21423cSdrh enum TTYPE_enum { 18363d21423cSdrh TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE 18373d21423cSdrh }; 18383d21423cSdrh int ttype; 1839b5555e7eSdrh if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type", 18403d21423cSdrh 0, &ttype) ){ 18413d21423cSdrh return TCL_ERROR; 18423d21423cSdrh } 18433d21423cSdrh switch( (enum TTYPE_enum)ttype ){ 18443d21423cSdrh case TTYPE_DEFERRED: /* no-op */; break; 18453d21423cSdrh case TTYPE_EXCLUSIVE: zBegin = "BEGIN EXCLUSIVE"; break; 18463d21423cSdrh case TTYPE_IMMEDIATE: zBegin = "BEGIN IMMEDIATE"; break; 18473d21423cSdrh } 18483d21423cSdrh pScript = objv[3]; 18493d21423cSdrh } 18503d21423cSdrh inTrans = !sqlite3_get_autocommit(pDb->db); 18513d21423cSdrh if( !inTrans ){ 18523752785fSdrh (void)sqlite3_exec(pDb->db, zBegin, 0, 0, 0); 18533d21423cSdrh } 18543d21423cSdrh rc = Tcl_EvalObjEx(interp, pScript, 0); 18553d21423cSdrh if( !inTrans ){ 18563d21423cSdrh const char *zEnd; 18573d21423cSdrh if( rc==TCL_ERROR ){ 18583d21423cSdrh zEnd = "ROLLBACK"; 18593d21423cSdrh } else { 18603d21423cSdrh zEnd = "COMMIT"; 18613d21423cSdrh } 18623752785fSdrh (void)sqlite3_exec(pDb->db, zEnd, 0, 0, 0); 18633d21423cSdrh } 18643d21423cSdrh break; 18653d21423cSdrh } 18663d21423cSdrh 186794eb6a14Sdanielk1977 /* 186894eb6a14Sdanielk1977 ** $db update_hook ?script? 186971fd80bfSdanielk1977 ** $db rollback_hook ?script? 187094eb6a14Sdanielk1977 */ 187171fd80bfSdanielk1977 case DB_UPDATE_HOOK: 187271fd80bfSdanielk1977 case DB_ROLLBACK_HOOK: { 187371fd80bfSdanielk1977 187471fd80bfSdanielk1977 /* set ppHook to point at pUpdateHook or pRollbackHook, depending on 187571fd80bfSdanielk1977 ** whether [$db update_hook] or [$db rollback_hook] was invoked. 187671fd80bfSdanielk1977 */ 187771fd80bfSdanielk1977 Tcl_Obj **ppHook; 187871fd80bfSdanielk1977 if( choice==DB_UPDATE_HOOK ){ 187971fd80bfSdanielk1977 ppHook = &pDb->pUpdateHook; 188071fd80bfSdanielk1977 }else{ 188171fd80bfSdanielk1977 ppHook = &pDb->pRollbackHook; 188271fd80bfSdanielk1977 } 188371fd80bfSdanielk1977 188494eb6a14Sdanielk1977 if( objc!=2 && objc!=3 ){ 188594eb6a14Sdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); 188694eb6a14Sdanielk1977 return TCL_ERROR; 188794eb6a14Sdanielk1977 } 188871fd80bfSdanielk1977 if( *ppHook ){ 188971fd80bfSdanielk1977 Tcl_SetObjResult(interp, *ppHook); 189094eb6a14Sdanielk1977 if( objc==3 ){ 189171fd80bfSdanielk1977 Tcl_DecrRefCount(*ppHook); 189271fd80bfSdanielk1977 *ppHook = 0; 189394eb6a14Sdanielk1977 } 189494eb6a14Sdanielk1977 } 189594eb6a14Sdanielk1977 if( objc==3 ){ 189671fd80bfSdanielk1977 assert( !(*ppHook) ); 189794eb6a14Sdanielk1977 if( Tcl_GetCharLength(objv[2])>0 ){ 189871fd80bfSdanielk1977 *ppHook = objv[2]; 189971fd80bfSdanielk1977 Tcl_IncrRefCount(*ppHook); 190094eb6a14Sdanielk1977 } 190194eb6a14Sdanielk1977 } 190271fd80bfSdanielk1977 190371fd80bfSdanielk1977 sqlite3_update_hook(pDb->db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb); 190471fd80bfSdanielk1977 sqlite3_rollback_hook(pDb->db,(pDb->pRollbackHook?DbRollbackHandler:0),pDb); 190571fd80bfSdanielk1977 190694eb6a14Sdanielk1977 break; 190794eb6a14Sdanielk1977 } 190894eb6a14Sdanielk1977 19094397de57Sdanielk1977 /* $db version 19104397de57Sdanielk1977 ** 19114397de57Sdanielk1977 ** Return the version string for this database. 19124397de57Sdanielk1977 */ 19134397de57Sdanielk1977 case DB_VERSION: { 19144397de57Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC); 19154397de57Sdanielk1977 break; 19164397de57Sdanielk1977 } 19174397de57Sdanielk1977 19181067fe11Stpoindex 19196d31316cSdrh } /* End of the SWITCH statement */ 192022fbcb8dSdrh return rc; 192175897234Sdrh } 192275897234Sdrh 192375897234Sdrh /* 19249bb575fdSdrh ** sqlite3 DBNAME FILENAME ?MODE? ?-key KEY? 192575897234Sdrh ** 192675897234Sdrh ** This is the main Tcl command. When the "sqlite" Tcl command is 192775897234Sdrh ** invoked, this routine runs to process that command. 192875897234Sdrh ** 192975897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new 193075897234Sdrh ** database connection. This command creates a new command named 193175897234Sdrh ** DBNAME that is used to control that connection. The database 193275897234Sdrh ** connection is deleted when the DBNAME command is deleted. 193375897234Sdrh ** 193475897234Sdrh ** The second argument is the name of the directory that contains 193575897234Sdrh ** the sqlite database that is to be accessed. 1936fbc3eab8Sdrh ** 1937fbc3eab8Sdrh ** For testing purposes, we also support the following: 1938fbc3eab8Sdrh ** 19399bb575fdSdrh ** sqlite3 -encoding 1940fbc3eab8Sdrh ** 1941fbc3eab8Sdrh ** Return the encoding used by LIKE and GLOB operators. Choices 1942fbc3eab8Sdrh ** are UTF-8 and iso8859. 1943fbc3eab8Sdrh ** 19449bb575fdSdrh ** sqlite3 -version 1945647cb0e1Sdrh ** 1946647cb0e1Sdrh ** Return the version number of the SQLite library. 1947647cb0e1Sdrh ** 19489bb575fdSdrh ** sqlite3 -tcl-uses-utf 1949fbc3eab8Sdrh ** 1950fbc3eab8Sdrh ** Return "1" if compiled with a Tcl uses UTF-8. Return "0" if 1951fbc3eab8Sdrh ** not. Used by tests to make sure the library was compiled 1952fbc3eab8Sdrh ** correctly. 195375897234Sdrh */ 195422fbcb8dSdrh static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ 1955bec3f402Sdrh SqliteDb *p; 195622fbcb8dSdrh void *pKey = 0; 195722fbcb8dSdrh int nKey = 0; 195822fbcb8dSdrh const char *zArg; 195975897234Sdrh char *zErrMsg; 196022fbcb8dSdrh const char *zFile; 196122fbcb8dSdrh if( objc==2 ){ 196222fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 196322fbcb8dSdrh if( strcmp(zArg,"-version")==0 ){ 19646f8a503dSdanielk1977 Tcl_AppendResult(interp,sqlite3_version,0); 1965647cb0e1Sdrh return TCL_OK; 1966647cb0e1Sdrh } 19679eb9e26bSdrh if( strcmp(zArg,"-has-codec")==0 ){ 19689eb9e26bSdrh #ifdef SQLITE_HAS_CODEC 196922fbcb8dSdrh Tcl_AppendResult(interp,"1",0); 197022fbcb8dSdrh #else 197122fbcb8dSdrh Tcl_AppendResult(interp,"0",0); 197222fbcb8dSdrh #endif 197322fbcb8dSdrh return TCL_OK; 197422fbcb8dSdrh } 197522fbcb8dSdrh if( strcmp(zArg,"-tcl-uses-utf")==0 ){ 1976fbc3eab8Sdrh #ifdef TCL_UTF_MAX 1977fbc3eab8Sdrh Tcl_AppendResult(interp,"1",0); 1978fbc3eab8Sdrh #else 1979fbc3eab8Sdrh Tcl_AppendResult(interp,"0",0); 1980fbc3eab8Sdrh #endif 1981fbc3eab8Sdrh return TCL_OK; 1982fbc3eab8Sdrh } 1983fbc3eab8Sdrh } 198422fbcb8dSdrh if( objc==5 || objc==6 ){ 198522fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[objc-2], 0); 198622fbcb8dSdrh if( strcmp(zArg,"-key")==0 ){ 198722fbcb8dSdrh pKey = Tcl_GetByteArrayFromObj(objv[objc-1], &nKey); 198822fbcb8dSdrh objc -= 2; 198922fbcb8dSdrh } 199022fbcb8dSdrh } 199122fbcb8dSdrh if( objc!=3 && objc!=4 ){ 199222fbcb8dSdrh Tcl_WrongNumArgs(interp, 1, objv, 19939eb9e26bSdrh #ifdef SQLITE_HAS_CODEC 19949eb9e26bSdrh "HANDLE FILENAME ?-key CODEC-KEY?" 199522fbcb8dSdrh #else 199622fbcb8dSdrh "HANDLE FILENAME ?MODE?" 199722fbcb8dSdrh #endif 199822fbcb8dSdrh ); 199975897234Sdrh return TCL_ERROR; 200075897234Sdrh } 200175897234Sdrh zErrMsg = 0; 20024cdc9e84Sdrh p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); 200375897234Sdrh if( p==0 ){ 2004bec3f402Sdrh Tcl_SetResult(interp, "malloc failed", TCL_STATIC); 2005bec3f402Sdrh return TCL_ERROR; 2006bec3f402Sdrh } 2007bec3f402Sdrh memset(p, 0, sizeof(*p)); 200822fbcb8dSdrh zFile = Tcl_GetStringFromObj(objv[2], 0); 20094f057f90Sdanielk1977 sqlite3_open(zFile, &p->db); 201080290863Sdanielk1977 if( SQLITE_OK!=sqlite3_errcode(p->db) ){ 201180290863Sdanielk1977 zErrMsg = strdup(sqlite3_errmsg(p->db)); 201280290863Sdanielk1977 sqlite3_close(p->db); 201380290863Sdanielk1977 p->db = 0; 201480290863Sdanielk1977 } 20152011d5f5Sdrh #ifdef SQLITE_HAS_CODEC 20162011d5f5Sdrh sqlite3_key(p->db, pKey, nKey); 2017eb8ed70dSdrh #endif 2018bec3f402Sdrh if( p->db==0 ){ 201975897234Sdrh Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); 2020bec3f402Sdrh Tcl_Free((char*)p); 202175897234Sdrh free(zErrMsg); 202275897234Sdrh return TCL_ERROR; 202375897234Sdrh } 2024fb7e7651Sdrh p->maxStmt = NUM_PREPARED_STMTS; 202522fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 202622fbcb8dSdrh Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); 2027c22bd47dSdrh 2028c22bd47dSdrh /* If compiled with SQLITE_TEST turned on, then register the "md5sum" 202906b2718aSdrh ** SQL function. 2030c22bd47dSdrh */ 203128b4e489Sdrh #ifdef SQLITE_TEST 203228b4e489Sdrh { 20339bb575fdSdrh extern void Md5_Register(sqlite3*); 20343b93bc8cSdrh #ifdef SQLITE_MEMDEBUG 203513073931Sdanielk1977 int mallocfail = sqlite3_iMallocFail; 203613073931Sdanielk1977 sqlite3_iMallocFail = 0; 20375b59af85Sdanielk1977 #endif 203828b4e489Sdrh Md5_Register(p->db); 20393b93bc8cSdrh #ifdef SQLITE_MEMDEBUG 204013073931Sdanielk1977 sqlite3_iMallocFail = mallocfail; 20415b59af85Sdanielk1977 #endif 204228b4e489Sdrh } 204328b4e489Sdrh #endif 20447cedc8d4Sdanielk1977 p->interp = interp; 204575897234Sdrh return TCL_OK; 204675897234Sdrh } 204775897234Sdrh 204875897234Sdrh /* 204990ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static 205090ca9753Sdrh ** library. 205190ca9753Sdrh */ 205290ca9753Sdrh #ifndef USE_TCL_STUBS 205390ca9753Sdrh # undef Tcl_InitStubs 205490ca9753Sdrh # define Tcl_InitStubs(a,b,c) 205590ca9753Sdrh #endif 205690ca9753Sdrh 205790ca9753Sdrh /* 205829bc4615Sdrh ** Make sure we have a PACKAGE_VERSION macro defined. This will be 205929bc4615Sdrh ** defined automatically by the TEA makefile. But other makefiles 206029bc4615Sdrh ** do not define it. 206129bc4615Sdrh */ 206229bc4615Sdrh #ifndef PACKAGE_VERSION 206329bc4615Sdrh # define PACKAGE_VERSION SQLITE_VERSION 206429bc4615Sdrh #endif 206529bc4615Sdrh 206629bc4615Sdrh /* 206775897234Sdrh ** Initialize this module. 206875897234Sdrh ** 206975897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite". 207075897234Sdrh ** (Hence there is no namespace. There is no point in using a namespace 207175897234Sdrh ** if the extension only supplies one new name!) The "sqlite" command is 207275897234Sdrh ** used to open a new SQLite database. See the DbMain() routine above 207375897234Sdrh ** for additional information. 207475897234Sdrh */ 207586b7f575Sdrh extern int Sqlite3_Init(Tcl_Interp *interp){ 207692febd92Sdrh Tcl_InitStubs(interp, "8.4", 0); 2077ef4ac8f9Sdrh Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); 207829bc4615Sdrh Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION); 207949766d6cSdrh Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); 208029bc4615Sdrh Tcl_PkgProvide(interp, "sqlite", PACKAGE_VERSION); 208190ca9753Sdrh return TCL_OK; 208290ca9753Sdrh } 208386b7f575Sdrh extern int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 208486b7f575Sdrh extern int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 208586b7f575Sdrh extern int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 208649766d6cSdrh 208749766d6cSdrh #ifndef SQLITE_3_SUFFIX_ONLY 208886b7f575Sdrh extern int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 208986b7f575Sdrh extern int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 209086b7f575Sdrh extern int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 209186b7f575Sdrh extern int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 209249766d6cSdrh #endif 209375897234Sdrh 20943e27c026Sdrh #ifdef TCLSH 20953e27c026Sdrh /***************************************************************************** 20963e27c026Sdrh ** The code that follows is used to build standalone TCL interpreters 209775897234Sdrh */ 2098348784efSdrh 2099348784efSdrh /* 21003e27c026Sdrh ** If the macro TCLSH is one, then put in code this for the 21013e27c026Sdrh ** "main" routine that will initialize Tcl and take input from 21023e27c026Sdrh ** standard input. 2103348784efSdrh */ 21043e27c026Sdrh #if TCLSH==1 2105348784efSdrh static char zMainloop[] = 2106348784efSdrh "set line {}\n" 2107348784efSdrh "while {![eof stdin]} {\n" 2108348784efSdrh "if {$line!=\"\"} {\n" 2109348784efSdrh "puts -nonewline \"> \"\n" 2110348784efSdrh "} else {\n" 2111348784efSdrh "puts -nonewline \"% \"\n" 2112348784efSdrh "}\n" 2113348784efSdrh "flush stdout\n" 2114348784efSdrh "append line [gets stdin]\n" 2115348784efSdrh "if {[info complete $line]} {\n" 2116348784efSdrh "if {[catch {uplevel #0 $line} result]} {\n" 2117348784efSdrh "puts stderr \"Error: $result\"\n" 2118348784efSdrh "} elseif {$result!=\"\"} {\n" 2119348784efSdrh "puts $result\n" 2120348784efSdrh "}\n" 2121348784efSdrh "set line {}\n" 2122348784efSdrh "} else {\n" 2123348784efSdrh "append line \\n\n" 2124348784efSdrh "}\n" 2125348784efSdrh "}\n" 2126348784efSdrh ; 21273e27c026Sdrh #endif 21283e27c026Sdrh 21293e27c026Sdrh /* 21303e27c026Sdrh ** If the macro TCLSH is two, then get the main loop code out of 21313e27c026Sdrh ** the separate file "spaceanal_tcl.h". 21323e27c026Sdrh */ 21333e27c026Sdrh #if TCLSH==2 21343e27c026Sdrh static char zMainloop[] = 21353e27c026Sdrh #include "spaceanal_tcl.h" 21363e27c026Sdrh ; 21373e27c026Sdrh #endif 2138348784efSdrh 2139348784efSdrh #define TCLSH_MAIN main /* Needed to fake out mktclapp */ 2140348784efSdrh int TCLSH_MAIN(int argc, char **argv){ 2141348784efSdrh Tcl_Interp *interp; 2142297ecf14Sdrh Tcl_FindExecutable(argv[0]); 2143348784efSdrh interp = Tcl_CreateInterp(); 214438f8271fSdrh Sqlite3_Init(interp); 2145d9b0257aSdrh #ifdef SQLITE_TEST 2146d1bf3512Sdrh { 2147d1bf3512Sdrh extern int Sqlitetest1_Init(Tcl_Interp*); 21485c4d9703Sdrh extern int Sqlitetest2_Init(Tcl_Interp*); 21495c4d9703Sdrh extern int Sqlitetest3_Init(Tcl_Interp*); 2150a6064dcfSdrh extern int Sqlitetest4_Init(Tcl_Interp*); 2151998b56c3Sdanielk1977 extern int Sqlitetest5_Init(Tcl_Interp*); 21529c06c953Sdrh extern int Sqlitetest6_Init(Tcl_Interp*); 215329c636bcSdrh extern int Sqlitetest7_Init(Tcl_Interp*); 2154b9bb7c18Sdrh extern int Sqlitetest8_Init(Tcl_Interp*); 2155efc251daSdrh extern int Md5_Init(Tcl_Interp*); 21562e66f0b9Sdrh extern int Sqlitetestsse_Init(Tcl_Interp*); 21572366940dSdrh extern int Sqlitetestasync_Init(Tcl_Interp*); 21584be8b51eSdrh extern int Sqlitetesttclvar_Init(Tcl_Interp*); 2159*954ce99cSdanielk1977 extern int Sqlitetestschema_Init(Tcl_Interp*); 21602e66f0b9Sdrh 21616490bebdSdanielk1977 Sqlitetest1_Init(interp); 21625c4d9703Sdrh Sqlitetest2_Init(interp); 2163de647130Sdrh Sqlitetest3_Init(interp); 2164fc57d7bfSdanielk1977 Sqlitetest4_Init(interp); 2165998b56c3Sdanielk1977 Sqlitetest5_Init(interp); 21669c06c953Sdrh Sqlitetest6_Init(interp); 216729c636bcSdrh Sqlitetest7_Init(interp); 2168b9bb7c18Sdrh Sqlitetest8_Init(interp); 21692366940dSdrh Sqlitetestasync_Init(interp); 21704be8b51eSdrh Sqlitetesttclvar_Init(interp); 2171*954ce99cSdanielk1977 Sqlitetestschema_Init(interp); 2172efc251daSdrh Md5_Init(interp); 217389dec819Sdrh #ifdef SQLITE_SSE 21742e66f0b9Sdrh Sqlitetestsse_Init(interp); 21752e66f0b9Sdrh #endif 2176d1bf3512Sdrh } 2177d1bf3512Sdrh #endif 21783e27c026Sdrh if( argc>=2 || TCLSH==2 ){ 2179348784efSdrh int i; 2180348784efSdrh Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY); 2181348784efSdrh Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); 218261212b69Sdrh for(i=3-TCLSH; i<argc; i++){ 2183348784efSdrh Tcl_SetVar(interp, "argv", argv[i], 2184348784efSdrh TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); 2185348784efSdrh } 21863e27c026Sdrh if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){ 21870de8c112Sdrh const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); 2188c61053b7Sdrh if( zInfo==0 ) zInfo = interp->result; 2189c61053b7Sdrh fprintf(stderr,"%s: %s\n", *argv, zInfo); 2190348784efSdrh return 1; 2191348784efSdrh } 21923e27c026Sdrh } 21933e27c026Sdrh if( argc<=1 || TCLSH==2 ){ 2194348784efSdrh Tcl_GlobalEval(interp, zMainloop); 2195348784efSdrh } 2196348784efSdrh return 0; 2197348784efSdrh } 2198348784efSdrh #endif /* TCLSH */ 21996d31316cSdrh 22006d31316cSdrh #endif /* !defined(NO_TCL) */ 2201