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*df0bddaeSdrh ** $Id: tclsqlite.c,v 1.126 2005/06/25 19:31:48 drh 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> 2475897234Sdrh 25a21c6b6fSdanielk1977 #define NUM_PREPARED_STMTS 10 26fb7e7651Sdrh #define MAX_PREPARED_STMTS 100 27fb7e7651Sdrh 2875897234Sdrh /* 2998808babSdrh ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we 3098808babSdrh ** have to do a translation when going between the two. Set the 3198808babSdrh ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do 3298808babSdrh ** this translation. 3398808babSdrh */ 3498808babSdrh #if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8) 3598808babSdrh # define UTF_TRANSLATION_NEEDED 1 3698808babSdrh #endif 3798808babSdrh 3898808babSdrh /* 39cabb0819Sdrh ** New SQL functions can be created as TCL scripts. Each such function 40cabb0819Sdrh ** is described by an instance of the following structure. 41cabb0819Sdrh */ 42cabb0819Sdrh typedef struct SqlFunc SqlFunc; 43cabb0819Sdrh struct SqlFunc { 44cabb0819Sdrh Tcl_Interp *interp; /* The TCL interpret to execute the function */ 45cabb0819Sdrh char *zScript; /* The script to be run */ 46cabb0819Sdrh SqlFunc *pNext; /* Next function on the list of them all */ 47cabb0819Sdrh }; 48cabb0819Sdrh 49cabb0819Sdrh /* 500202b29eSdanielk1977 ** New collation sequences function can be created as TCL scripts. Each such 510202b29eSdanielk1977 ** function is described by an instance of the following structure. 520202b29eSdanielk1977 */ 530202b29eSdanielk1977 typedef struct SqlCollate SqlCollate; 540202b29eSdanielk1977 struct SqlCollate { 550202b29eSdanielk1977 Tcl_Interp *interp; /* The TCL interpret to execute the function */ 560202b29eSdanielk1977 char *zScript; /* The script to be run */ 570202b29eSdanielk1977 SqlCollate *pNext; /* Next function on the list of them all */ 580202b29eSdanielk1977 }; 590202b29eSdanielk1977 600202b29eSdanielk1977 /* 61fb7e7651Sdrh ** Prepared statements are cached for faster execution. Each prepared 62fb7e7651Sdrh ** statement is described by an instance of the following structure. 63fb7e7651Sdrh */ 64fb7e7651Sdrh typedef struct SqlPreparedStmt SqlPreparedStmt; 65fb7e7651Sdrh struct SqlPreparedStmt { 66fb7e7651Sdrh SqlPreparedStmt *pNext; /* Next in linked list */ 67fb7e7651Sdrh SqlPreparedStmt *pPrev; /* Previous on the list */ 68fb7e7651Sdrh sqlite3_stmt *pStmt; /* The prepared statement */ 69fb7e7651Sdrh int nSql; /* chars in zSql[] */ 70fb7e7651Sdrh char zSql[1]; /* Text of the SQL statement */ 71fb7e7651Sdrh }; 72fb7e7651Sdrh 73fb7e7651Sdrh /* 74bec3f402Sdrh ** There is one instance of this structure for each SQLite database 75bec3f402Sdrh ** that has been opened by the SQLite TCL interface. 76bec3f402Sdrh */ 77bec3f402Sdrh typedef struct SqliteDb SqliteDb; 78bec3f402Sdrh struct SqliteDb { 79895d7472Sdrh sqlite3 *db; /* The "real" database structure */ 80bec3f402Sdrh Tcl_Interp *interp; /* The interpreter used for this database */ 816d31316cSdrh char *zBusy; /* The busy callback routine */ 82aa940eacSdrh char *zCommit; /* The commit hook callback routine */ 83b5a20d3cSdrh char *zTrace; /* The trace callback routine */ 84348bb5d6Sdanielk1977 char *zProgress; /* The progress callback routine */ 85e22a334bSdrh char *zAuth; /* The authorization callback routine */ 8655c45f2eSdanielk1977 char *zNull; /* Text to substitute for an SQL NULL value */ 87cabb0819Sdrh SqlFunc *pFunc; /* List of SQL functions */ 880202b29eSdanielk1977 SqlCollate *pCollate; /* List of SQL collation functions */ 896f8a503dSdanielk1977 int rc; /* Return code of most recent sqlite3_exec() */ 907cedc8d4Sdanielk1977 Tcl_Obj *pCollateNeeded; /* Collation needed script */ 91fb7e7651Sdrh SqlPreparedStmt *stmtList; /* List of prepared statements*/ 92fb7e7651Sdrh SqlPreparedStmt *stmtLast; /* Last statement in the list */ 93fb7e7651Sdrh int maxStmt; /* The next maximum number of stmtList */ 94fb7e7651Sdrh int nStmt; /* Number of statements in stmtList */ 9598808babSdrh }; 96297ecf14Sdrh 976d31316cSdrh /* 98fb7e7651Sdrh ** Finalize and free a list of prepared statements 99fb7e7651Sdrh */ 100fb7e7651Sdrh static void flushStmtCache( SqliteDb *pDb ){ 101fb7e7651Sdrh SqlPreparedStmt *pPreStmt; 102fb7e7651Sdrh 103fb7e7651Sdrh while( pDb->stmtList ){ 104fb7e7651Sdrh sqlite3_finalize( pDb->stmtList->pStmt ); 105fb7e7651Sdrh pPreStmt = pDb->stmtList; 106fb7e7651Sdrh pDb->stmtList = pDb->stmtList->pNext; 107fb7e7651Sdrh Tcl_Free( (char*)pPreStmt ); 108fb7e7651Sdrh } 109fb7e7651Sdrh pDb->nStmt = 0; 110fb7e7651Sdrh pDb->stmtLast = 0; 111fb7e7651Sdrh } 112fb7e7651Sdrh 113fb7e7651Sdrh /* 114895d7472Sdrh ** TCL calls this procedure when an sqlite3 database command is 115895d7472Sdrh ** deleted. 11675897234Sdrh */ 11775897234Sdrh static void DbDeleteCmd(void *db){ 118bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)db; 119fb7e7651Sdrh flushStmtCache(pDb); 1206f8a503dSdanielk1977 sqlite3_close(pDb->db); 121cabb0819Sdrh while( pDb->pFunc ){ 122cabb0819Sdrh SqlFunc *pFunc = pDb->pFunc; 123cabb0819Sdrh pDb->pFunc = pFunc->pNext; 124cabb0819Sdrh Tcl_Free((char*)pFunc); 125cabb0819Sdrh } 1260202b29eSdanielk1977 while( pDb->pCollate ){ 1270202b29eSdanielk1977 SqlCollate *pCollate = pDb->pCollate; 1280202b29eSdanielk1977 pDb->pCollate = pCollate->pNext; 1290202b29eSdanielk1977 Tcl_Free((char*)pCollate); 1300202b29eSdanielk1977 } 131bec3f402Sdrh if( pDb->zBusy ){ 132bec3f402Sdrh Tcl_Free(pDb->zBusy); 133bec3f402Sdrh } 134b5a20d3cSdrh if( pDb->zTrace ){ 135b5a20d3cSdrh Tcl_Free(pDb->zTrace); 1360d1a643aSdrh } 137e22a334bSdrh if( pDb->zAuth ){ 138e22a334bSdrh Tcl_Free(pDb->zAuth); 139e22a334bSdrh } 14055c45f2eSdanielk1977 if( pDb->zNull ){ 14155c45f2eSdanielk1977 Tcl_Free(pDb->zNull); 14255c45f2eSdanielk1977 } 143bec3f402Sdrh Tcl_Free((char*)pDb); 144bec3f402Sdrh } 145bec3f402Sdrh 146bec3f402Sdrh /* 147bec3f402Sdrh ** This routine is called when a database file is locked while trying 148bec3f402Sdrh ** to execute SQL. 149bec3f402Sdrh */ 1502a764eb0Sdanielk1977 static int DbBusyHandler(void *cd, int nTries){ 151bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 152bec3f402Sdrh int rc; 153bec3f402Sdrh char zVal[30]; 154bec3f402Sdrh char *zCmd; 155bec3f402Sdrh Tcl_DString cmd; 156bec3f402Sdrh 157bec3f402Sdrh Tcl_DStringInit(&cmd); 158bec3f402Sdrh Tcl_DStringAppend(&cmd, pDb->zBusy, -1); 159bec3f402Sdrh sprintf(zVal, "%d", nTries); 1602a764eb0Sdanielk1977 Tcl_DStringAppendElement(&cmd, zVal); 161bec3f402Sdrh zCmd = Tcl_DStringValue(&cmd); 162bec3f402Sdrh rc = Tcl_Eval(pDb->interp, zCmd); 163bec3f402Sdrh Tcl_DStringFree(&cmd); 164bec3f402Sdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 165bec3f402Sdrh return 0; 166bec3f402Sdrh } 167bec3f402Sdrh return 1; 16875897234Sdrh } 16975897234Sdrh 17075897234Sdrh /* 171348bb5d6Sdanielk1977 ** This routine is invoked as the 'progress callback' for the database. 172348bb5d6Sdanielk1977 */ 173348bb5d6Sdanielk1977 static int DbProgressHandler(void *cd){ 174348bb5d6Sdanielk1977 SqliteDb *pDb = (SqliteDb*)cd; 175348bb5d6Sdanielk1977 int rc; 176348bb5d6Sdanielk1977 177348bb5d6Sdanielk1977 assert( pDb->zProgress ); 178348bb5d6Sdanielk1977 rc = Tcl_Eval(pDb->interp, pDb->zProgress); 179348bb5d6Sdanielk1977 if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 180348bb5d6Sdanielk1977 return 1; 181348bb5d6Sdanielk1977 } 182348bb5d6Sdanielk1977 return 0; 183348bb5d6Sdanielk1977 } 184348bb5d6Sdanielk1977 185348bb5d6Sdanielk1977 /* 186b5a20d3cSdrh ** This routine is called by the SQLite trace handler whenever a new 187b5a20d3cSdrh ** block of SQL is executed. The TCL script in pDb->zTrace is executed. 1880d1a643aSdrh */ 189b5a20d3cSdrh static void DbTraceHandler(void *cd, const char *zSql){ 1900d1a643aSdrh SqliteDb *pDb = (SqliteDb*)cd; 191b5a20d3cSdrh Tcl_DString str; 1920d1a643aSdrh 193b5a20d3cSdrh Tcl_DStringInit(&str); 194b5a20d3cSdrh Tcl_DStringAppend(&str, pDb->zTrace, -1); 195b5a20d3cSdrh Tcl_DStringAppendElement(&str, zSql); 196b5a20d3cSdrh Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); 197b5a20d3cSdrh Tcl_DStringFree(&str); 198b5a20d3cSdrh Tcl_ResetResult(pDb->interp); 1990d1a643aSdrh } 2000d1a643aSdrh 2010d1a643aSdrh /* 202aa940eacSdrh ** This routine is called when a transaction is committed. The 203aa940eacSdrh ** TCL script in pDb->zCommit is executed. If it returns non-zero or 204aa940eacSdrh ** if it throws an exception, the transaction is rolled back instead 205aa940eacSdrh ** of being committed. 206aa940eacSdrh */ 207aa940eacSdrh static int DbCommitHandler(void *cd){ 208aa940eacSdrh SqliteDb *pDb = (SqliteDb*)cd; 209aa940eacSdrh int rc; 210aa940eacSdrh 211aa940eacSdrh rc = Tcl_Eval(pDb->interp, pDb->zCommit); 212aa940eacSdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 213aa940eacSdrh return 1; 214aa940eacSdrh } 215aa940eacSdrh return 0; 216aa940eacSdrh } 217aa940eacSdrh 2187cedc8d4Sdanielk1977 static void tclCollateNeeded( 2197cedc8d4Sdanielk1977 void *pCtx, 2209bb575fdSdrh sqlite3 *db, 2217cedc8d4Sdanielk1977 int enc, 2227cedc8d4Sdanielk1977 const char *zName 2237cedc8d4Sdanielk1977 ){ 2247cedc8d4Sdanielk1977 SqliteDb *pDb = (SqliteDb *)pCtx; 2257cedc8d4Sdanielk1977 Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded); 2267cedc8d4Sdanielk1977 Tcl_IncrRefCount(pScript); 2277cedc8d4Sdanielk1977 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1)); 2287cedc8d4Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pScript, 0); 2297cedc8d4Sdanielk1977 Tcl_DecrRefCount(pScript); 2307cedc8d4Sdanielk1977 } 2317cedc8d4Sdanielk1977 232aa940eacSdrh /* 2330202b29eSdanielk1977 ** This routine is called to evaluate an SQL collation function implemented 2340202b29eSdanielk1977 ** using TCL script. 2350202b29eSdanielk1977 */ 2360202b29eSdanielk1977 static int tclSqlCollate( 2370202b29eSdanielk1977 void *pCtx, 2380202b29eSdanielk1977 int nA, 2390202b29eSdanielk1977 const void *zA, 2400202b29eSdanielk1977 int nB, 2410202b29eSdanielk1977 const void *zB 2420202b29eSdanielk1977 ){ 2430202b29eSdanielk1977 SqlCollate *p = (SqlCollate *)pCtx; 2440202b29eSdanielk1977 Tcl_Obj *pCmd; 2450202b29eSdanielk1977 2460202b29eSdanielk1977 pCmd = Tcl_NewStringObj(p->zScript, -1); 2470202b29eSdanielk1977 Tcl_IncrRefCount(pCmd); 2480202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA)); 2490202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB)); 2500202b29eSdanielk1977 Tcl_EvalObjEx(p->interp, pCmd, 0); 2510202b29eSdanielk1977 Tcl_DecrRefCount(pCmd); 2520202b29eSdanielk1977 return (atoi(Tcl_GetStringResult(p->interp))); 2530202b29eSdanielk1977 } 2540202b29eSdanielk1977 2550202b29eSdanielk1977 /* 256cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented 257cabb0819Sdrh ** using TCL script. 258cabb0819Sdrh */ 2590ae8b831Sdanielk1977 static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ 2606f8a503dSdanielk1977 SqlFunc *p = sqlite3_user_data(context); 261cabb0819Sdrh Tcl_DString cmd; 262cabb0819Sdrh int i; 263cabb0819Sdrh int rc; 264cabb0819Sdrh 265cabb0819Sdrh Tcl_DStringInit(&cmd); 266cabb0819Sdrh Tcl_DStringAppend(&cmd, p->zScript, -1); 267cabb0819Sdrh for(i=0; i<argc; i++){ 2689c054830Sdrh if( SQLITE_NULL==sqlite3_value_type(argv[i]) ){ 26951ad0ecdSdanielk1977 Tcl_DStringAppendElement(&cmd, ""); 27051ad0ecdSdanielk1977 }else{ 2714f26d6c4Sdrh Tcl_DStringAppendElement(&cmd, sqlite3_value_text(argv[i])); 27251ad0ecdSdanielk1977 } 273cabb0819Sdrh } 274c7f269d5Sdrh rc = Tcl_EvalEx(p->interp, Tcl_DStringValue(&cmd), Tcl_DStringLength(&cmd), 275c7f269d5Sdrh TCL_EVAL_DIRECT); 276562e8d3cSdanielk1977 Tcl_DStringFree(&cmd); 277562e8d3cSdanielk1977 278c7f269d5Sdrh if( rc && rc!=TCL_RETURN ){ 2797e18c259Sdanielk1977 sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 280cabb0819Sdrh }else{ 281c7f269d5Sdrh Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); 282c7f269d5Sdrh int n; 283c7f269d5Sdrh u8 *data; 284c7f269d5Sdrh char *zType = pVar->typePtr ? pVar->typePtr->name : ""; 285c7f269d5Sdrh char c = zType[0]; 286*df0bddaeSdrh if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ 287*df0bddaeSdrh /* Only load a BLOB type if the Tcl variable is a bytearray and 288*df0bddaeSdrh ** has no string representation. */ 289c7f269d5Sdrh data = Tcl_GetByteArrayFromObj(pVar, &n); 290c7f269d5Sdrh sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT); 291c7f269d5Sdrh }else if( (c=='b' && strcmp(zType,"boolean")==0) || 292c7f269d5Sdrh (c=='i' && strcmp(zType,"int")==0) ){ 293c7f269d5Sdrh Tcl_GetIntFromObj(0, pVar, &n); 294c7f269d5Sdrh sqlite3_result_int(context, n); 295c7f269d5Sdrh }else if( c=='d' && strcmp(zType,"double")==0 ){ 296c7f269d5Sdrh double r; 297c7f269d5Sdrh Tcl_GetDoubleFromObj(0, pVar, &r); 298c7f269d5Sdrh sqlite3_result_double(context, r); 299*df0bddaeSdrh }else if( c=='w' && strcmp(zType,"wideInt")==0 ){ 300*df0bddaeSdrh Tcl_WideInt v; 301*df0bddaeSdrh Tcl_GetWideIntFromObj(0, pVar, &v); 302*df0bddaeSdrh sqlite3_result_int64(context, v); 303c7f269d5Sdrh }else{ 304c7f269d5Sdrh data = Tcl_GetStringFromObj(pVar, &n); 305c7f269d5Sdrh sqlite3_result_text(context, data, n, SQLITE_TRANSIENT); 306c7f269d5Sdrh } 307cabb0819Sdrh } 308cabb0819Sdrh } 309895d7472Sdrh 310e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION 311e22a334bSdrh /* 312e22a334bSdrh ** This is the authentication function. It appends the authentication 313e22a334bSdrh ** type code and the two arguments to zCmd[] then invokes the result 314e22a334bSdrh ** on the interpreter. The reply is examined to determine if the 315e22a334bSdrh ** authentication fails or succeeds. 316e22a334bSdrh */ 317e22a334bSdrh static int auth_callback( 318e22a334bSdrh void *pArg, 319e22a334bSdrh int code, 320e22a334bSdrh const char *zArg1, 321e22a334bSdrh const char *zArg2, 322e22a334bSdrh const char *zArg3, 323e22a334bSdrh const char *zArg4 324e22a334bSdrh ){ 325e22a334bSdrh char *zCode; 326e22a334bSdrh Tcl_DString str; 327e22a334bSdrh int rc; 328e22a334bSdrh const char *zReply; 329e22a334bSdrh SqliteDb *pDb = (SqliteDb*)pArg; 330e22a334bSdrh 331e22a334bSdrh switch( code ){ 332e22a334bSdrh case SQLITE_COPY : zCode="SQLITE_COPY"; break; 333e22a334bSdrh case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; 334e22a334bSdrh case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; 335e22a334bSdrh case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; 336e22a334bSdrh case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; 337e22a334bSdrh case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; 338e22a334bSdrh case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; 339e22a334bSdrh case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; 340e22a334bSdrh case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; 341e22a334bSdrh case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; 342e22a334bSdrh case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; 343e22a334bSdrh case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; 344e22a334bSdrh case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; 345e22a334bSdrh case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; 346e22a334bSdrh case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; 347e22a334bSdrh case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; 348e22a334bSdrh case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; 349e22a334bSdrh case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; 350e22a334bSdrh case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; 351e22a334bSdrh case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; 352e22a334bSdrh case SQLITE_READ : zCode="SQLITE_READ"; break; 353e22a334bSdrh case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; 354e22a334bSdrh case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; 355e22a334bSdrh case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; 35681e293b4Sdrh case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break; 35781e293b4Sdrh case SQLITE_DETACH : zCode="SQLITE_DETACH"; break; 3581c8c23ccSdanielk1977 case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; 3591d54df88Sdanielk1977 case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; 360e22a334bSdrh default : zCode="????"; break; 361e22a334bSdrh } 362e22a334bSdrh Tcl_DStringInit(&str); 363e22a334bSdrh Tcl_DStringAppend(&str, pDb->zAuth, -1); 364e22a334bSdrh Tcl_DStringAppendElement(&str, zCode); 365e22a334bSdrh Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); 366e22a334bSdrh Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); 367e22a334bSdrh Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); 368e22a334bSdrh Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); 369e22a334bSdrh rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); 370e22a334bSdrh Tcl_DStringFree(&str); 371e22a334bSdrh zReply = Tcl_GetStringResult(pDb->interp); 372e22a334bSdrh if( strcmp(zReply,"SQLITE_OK")==0 ){ 373e22a334bSdrh rc = SQLITE_OK; 374e22a334bSdrh }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ 375e22a334bSdrh rc = SQLITE_DENY; 376e22a334bSdrh }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ 377e22a334bSdrh rc = SQLITE_IGNORE; 378e22a334bSdrh }else{ 379e22a334bSdrh rc = 999; 380e22a334bSdrh } 381e22a334bSdrh return rc; 382e22a334bSdrh } 383e22a334bSdrh #endif /* SQLITE_OMIT_AUTHORIZATION */ 384cabb0819Sdrh 385cabb0819Sdrh /* 386ef2cb63eSdanielk1977 ** zText is a pointer to text obtained via an sqlite3_result_text() 387ef2cb63eSdanielk1977 ** or similar interface. This routine returns a Tcl string object, 388ef2cb63eSdanielk1977 ** reference count set to 0, containing the text. If a translation 389ef2cb63eSdanielk1977 ** between iso8859 and UTF-8 is required, it is preformed. 390ef2cb63eSdanielk1977 */ 391ef2cb63eSdanielk1977 static Tcl_Obj *dbTextToObj(char const *zText){ 392ef2cb63eSdanielk1977 Tcl_Obj *pVal; 393ef2cb63eSdanielk1977 #ifdef UTF_TRANSLATION_NEEDED 394ef2cb63eSdanielk1977 Tcl_DString dCol; 395ef2cb63eSdanielk1977 Tcl_DStringInit(&dCol); 396ef2cb63eSdanielk1977 Tcl_ExternalToUtfDString(NULL, zText, -1, &dCol); 397ef2cb63eSdanielk1977 pVal = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1); 398ef2cb63eSdanielk1977 Tcl_DStringFree(&dCol); 399ef2cb63eSdanielk1977 #else 400ef2cb63eSdanielk1977 pVal = Tcl_NewStringObj(zText, -1); 401ef2cb63eSdanielk1977 #endif 402ef2cb63eSdanielk1977 return pVal; 403ef2cb63eSdanielk1977 } 404ef2cb63eSdanielk1977 405ef2cb63eSdanielk1977 /* 4061067fe11Stpoindex ** This routine reads a line of text from FILE in, stores 4071067fe11Stpoindex ** the text in memory obtained from malloc() and returns a pointer 4081067fe11Stpoindex ** to the text. NULL is returned at end of file, or if malloc() 4091067fe11Stpoindex ** fails. 4101067fe11Stpoindex ** 4111067fe11Stpoindex ** The interface is like "readline" but no command-line editing 4121067fe11Stpoindex ** is done. 4131067fe11Stpoindex ** 4141067fe11Stpoindex ** copied from shell.c from '.import' command 4151067fe11Stpoindex */ 4161067fe11Stpoindex static char *local_getline(char *zPrompt, FILE *in){ 4171067fe11Stpoindex char *zLine; 4181067fe11Stpoindex int nLine; 4191067fe11Stpoindex int n; 4201067fe11Stpoindex int eol; 4211067fe11Stpoindex 4221067fe11Stpoindex nLine = 100; 4231067fe11Stpoindex zLine = malloc( nLine ); 4241067fe11Stpoindex if( zLine==0 ) return 0; 4251067fe11Stpoindex n = 0; 4261067fe11Stpoindex eol = 0; 4271067fe11Stpoindex while( !eol ){ 4281067fe11Stpoindex if( n+100>nLine ){ 4291067fe11Stpoindex nLine = nLine*2 + 100; 4301067fe11Stpoindex zLine = realloc(zLine, nLine); 4311067fe11Stpoindex if( zLine==0 ) return 0; 4321067fe11Stpoindex } 4331067fe11Stpoindex if( fgets(&zLine[n], nLine - n, in)==0 ){ 4341067fe11Stpoindex if( n==0 ){ 4351067fe11Stpoindex free(zLine); 4361067fe11Stpoindex return 0; 4371067fe11Stpoindex } 4381067fe11Stpoindex zLine[n] = 0; 4391067fe11Stpoindex eol = 1; 4401067fe11Stpoindex break; 4411067fe11Stpoindex } 4421067fe11Stpoindex while( zLine[n] ){ n++; } 4431067fe11Stpoindex if( n>0 && zLine[n-1]=='\n' ){ 4441067fe11Stpoindex n--; 4451067fe11Stpoindex zLine[n] = 0; 4461067fe11Stpoindex eol = 1; 4471067fe11Stpoindex } 4481067fe11Stpoindex } 4491067fe11Stpoindex zLine = realloc( zLine, n+1 ); 4501067fe11Stpoindex return zLine; 4511067fe11Stpoindex } 4521067fe11Stpoindex 4531067fe11Stpoindex /* 45475897234Sdrh ** The "sqlite" command below creates a new Tcl command for each 45575897234Sdrh ** connection it opens to an SQLite database. This routine is invoked 45675897234Sdrh ** whenever one of those connection-specific commands is executed 45775897234Sdrh ** in Tcl. For example, if you run Tcl code like this: 45875897234Sdrh ** 4599bb575fdSdrh ** sqlite3 db1 "my_database" 46075897234Sdrh ** db1 close 46175897234Sdrh ** 46275897234Sdrh ** The first command opens a connection to the "my_database" database 46375897234Sdrh ** and calls that connection "db1". The second command causes this 46475897234Sdrh ** subroutine to be invoked. 46575897234Sdrh */ 4666d31316cSdrh static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ 467bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 4686d31316cSdrh int choice; 46922fbcb8dSdrh int rc = TCL_OK; 4700de8c112Sdrh static const char *DB_strs[] = { 471fb7e7651Sdrh "authorizer", "busy", "cache", 472fb7e7651Sdrh "changes", "close", "collate", 473fb7e7651Sdrh "collation_needed", "commit_hook", "complete", 474fb7e7651Sdrh "copy", "errorcode", "eval", 47555c45f2eSdanielk1977 "function", "last_insert_rowid", "nullvalue", 47655c45f2eSdanielk1977 "onecolumn", "progress", "rekey", 47755c45f2eSdanielk1977 "timeout", "total_changes", "trace", 47855c45f2eSdanielk1977 "version", 4790f14e2ebSdrh 0 4806d31316cSdrh }; 481411995dcSdrh enum DB_enum { 482fb7e7651Sdrh DB_AUTHORIZER, DB_BUSY, DB_CACHE, 483fb7e7651Sdrh DB_CHANGES, DB_CLOSE, DB_COLLATE, 484fb7e7651Sdrh DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, 485fb7e7651Sdrh DB_COPY, DB_ERRORCODE, DB_EVAL, 48655c45f2eSdanielk1977 DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_NULLVALUE, 48755c45f2eSdanielk1977 DB_ONECOLUMN, DB_PROGRESS, DB_REKEY, 48855c45f2eSdanielk1977 DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, 48955c45f2eSdanielk1977 DB_VERSION 4906d31316cSdrh }; 4911067fe11Stpoindex /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ 4926d31316cSdrh 4936d31316cSdrh if( objc<2 ){ 4946d31316cSdrh Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); 49575897234Sdrh return TCL_ERROR; 49675897234Sdrh } 497411995dcSdrh if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){ 4986d31316cSdrh return TCL_ERROR; 4996d31316cSdrh } 5006d31316cSdrh 501411995dcSdrh switch( (enum DB_enum)choice ){ 50275897234Sdrh 503e22a334bSdrh /* $db authorizer ?CALLBACK? 504e22a334bSdrh ** 505e22a334bSdrh ** Invoke the given callback to authorize each SQL operation as it is 506e22a334bSdrh ** compiled. 5 arguments are appended to the callback before it is 507e22a334bSdrh ** invoked: 508e22a334bSdrh ** 509e22a334bSdrh ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...) 510e22a334bSdrh ** (2) First descriptive name (depends on authorization type) 511e22a334bSdrh ** (3) Second descriptive name 512e22a334bSdrh ** (4) Name of the database (ex: "main", "temp") 513e22a334bSdrh ** (5) Name of trigger that is doing the access 514e22a334bSdrh ** 515e22a334bSdrh ** The callback should return on of the following strings: SQLITE_OK, 516e22a334bSdrh ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error. 517e22a334bSdrh ** 518e22a334bSdrh ** If this method is invoked with no arguments, the current authorization 519e22a334bSdrh ** callback string is returned. 520e22a334bSdrh */ 521e22a334bSdrh case DB_AUTHORIZER: { 5221211de37Sdrh #ifdef SQLITE_OMIT_AUTHORIZATION 5231211de37Sdrh Tcl_AppendResult(interp, "authorization not available in this build", 0); 5241211de37Sdrh return TCL_ERROR; 5251211de37Sdrh #else 526e22a334bSdrh if( objc>3 ){ 527e22a334bSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 5280f14e2ebSdrh return TCL_ERROR; 529e22a334bSdrh }else if( objc==2 ){ 530b5a20d3cSdrh if( pDb->zAuth ){ 531e22a334bSdrh Tcl_AppendResult(interp, pDb->zAuth, 0); 532e22a334bSdrh } 533e22a334bSdrh }else{ 534e22a334bSdrh char *zAuth; 535e22a334bSdrh int len; 536e22a334bSdrh if( pDb->zAuth ){ 537e22a334bSdrh Tcl_Free(pDb->zAuth); 538e22a334bSdrh } 539e22a334bSdrh zAuth = Tcl_GetStringFromObj(objv[2], &len); 540e22a334bSdrh if( zAuth && len>0 ){ 541e22a334bSdrh pDb->zAuth = Tcl_Alloc( len + 1 ); 542e22a334bSdrh strcpy(pDb->zAuth, zAuth); 543e22a334bSdrh }else{ 544e22a334bSdrh pDb->zAuth = 0; 545e22a334bSdrh } 546e22a334bSdrh if( pDb->zAuth ){ 547e22a334bSdrh pDb->interp = interp; 5486f8a503dSdanielk1977 sqlite3_set_authorizer(pDb->db, auth_callback, pDb); 549e22a334bSdrh }else{ 5506f8a503dSdanielk1977 sqlite3_set_authorizer(pDb->db, 0, 0); 551e22a334bSdrh } 552e22a334bSdrh } 5531211de37Sdrh #endif 554e22a334bSdrh break; 555e22a334bSdrh } 556e22a334bSdrh 557bec3f402Sdrh /* $db busy ?CALLBACK? 558bec3f402Sdrh ** 559bec3f402Sdrh ** Invoke the given callback if an SQL statement attempts to open 560bec3f402Sdrh ** a locked database file. 561bec3f402Sdrh */ 5626d31316cSdrh case DB_BUSY: { 5636d31316cSdrh if( objc>3 ){ 5646d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK"); 565bec3f402Sdrh return TCL_ERROR; 5666d31316cSdrh }else if( objc==2 ){ 567bec3f402Sdrh if( pDb->zBusy ){ 568bec3f402Sdrh Tcl_AppendResult(interp, pDb->zBusy, 0); 569bec3f402Sdrh } 570bec3f402Sdrh }else{ 5716d31316cSdrh char *zBusy; 5726d31316cSdrh int len; 573bec3f402Sdrh if( pDb->zBusy ){ 574bec3f402Sdrh Tcl_Free(pDb->zBusy); 5756d31316cSdrh } 5766d31316cSdrh zBusy = Tcl_GetStringFromObj(objv[2], &len); 5776d31316cSdrh if( zBusy && len>0 ){ 5786d31316cSdrh pDb->zBusy = Tcl_Alloc( len + 1 ); 5796d31316cSdrh strcpy(pDb->zBusy, zBusy); 5806d31316cSdrh }else{ 581bec3f402Sdrh pDb->zBusy = 0; 582bec3f402Sdrh } 583bec3f402Sdrh if( pDb->zBusy ){ 584bec3f402Sdrh pDb->interp = interp; 5856f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb); 5866d31316cSdrh }else{ 5876f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, 0, 0); 588bec3f402Sdrh } 589bec3f402Sdrh } 5906d31316cSdrh break; 5916d31316cSdrh } 592bec3f402Sdrh 593fb7e7651Sdrh /* $db cache flush 594fb7e7651Sdrh ** $db cache size n 595fb7e7651Sdrh ** 596fb7e7651Sdrh ** Flush the prepared statement cache, or set the maximum number of 597fb7e7651Sdrh ** cached statements. 598fb7e7651Sdrh */ 599fb7e7651Sdrh case DB_CACHE: { 600fb7e7651Sdrh char *subCmd; 601fb7e7651Sdrh int n; 602fb7e7651Sdrh 603fb7e7651Sdrh if( objc<=2 ){ 604fb7e7651Sdrh Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?"); 605fb7e7651Sdrh return TCL_ERROR; 606fb7e7651Sdrh } 607fb7e7651Sdrh subCmd = Tcl_GetStringFromObj( objv[2], 0 ); 608fb7e7651Sdrh if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){ 609fb7e7651Sdrh if( objc!=3 ){ 610fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "flush"); 611fb7e7651Sdrh return TCL_ERROR; 612fb7e7651Sdrh }else{ 613fb7e7651Sdrh flushStmtCache( pDb ); 614fb7e7651Sdrh } 615fb7e7651Sdrh }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){ 616fb7e7651Sdrh if( objc!=4 ){ 617fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "size n"); 618fb7e7651Sdrh return TCL_ERROR; 619fb7e7651Sdrh }else{ 620fb7e7651Sdrh if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ 621fb7e7651Sdrh Tcl_AppendResult( interp, "cannot convert \"", 622fb7e7651Sdrh Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0); 623fb7e7651Sdrh return TCL_ERROR; 624fb7e7651Sdrh }else{ 625fb7e7651Sdrh if( n<0 ){ 626fb7e7651Sdrh flushStmtCache( pDb ); 627fb7e7651Sdrh n = 0; 628fb7e7651Sdrh }else if( n>MAX_PREPARED_STMTS ){ 629fb7e7651Sdrh n = MAX_PREPARED_STMTS; 630fb7e7651Sdrh } 631fb7e7651Sdrh pDb->maxStmt = n; 632fb7e7651Sdrh } 633fb7e7651Sdrh } 634fb7e7651Sdrh }else{ 635fb7e7651Sdrh Tcl_AppendResult( interp, "bad option \"", 636fb7e7651Sdrh Tcl_GetStringFromObj(objv[0],0), "\": must be flush or size", 0); 637fb7e7651Sdrh return TCL_ERROR; 638fb7e7651Sdrh } 639fb7e7651Sdrh break; 640fb7e7651Sdrh } 641fb7e7651Sdrh 642b28af71aSdanielk1977 /* $db changes 643c8d30ac1Sdrh ** 644c8d30ac1Sdrh ** Return the number of rows that were modified, inserted, or deleted by 645b28af71aSdanielk1977 ** the most recent INSERT, UPDATE or DELETE statement, not including 646b28af71aSdanielk1977 ** any changes made by trigger programs. 647c8d30ac1Sdrh */ 648c8d30ac1Sdrh case DB_CHANGES: { 649c8d30ac1Sdrh Tcl_Obj *pResult; 650c8d30ac1Sdrh if( objc!=2 ){ 651c8d30ac1Sdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 652c8d30ac1Sdrh return TCL_ERROR; 653c8d30ac1Sdrh } 654c8d30ac1Sdrh pResult = Tcl_GetObjResult(interp); 655b28af71aSdanielk1977 Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db)); 656f146a776Srdc break; 657f146a776Srdc } 658f146a776Srdc 65975897234Sdrh /* $db close 66075897234Sdrh ** 66175897234Sdrh ** Shutdown the database 66275897234Sdrh */ 6636d31316cSdrh case DB_CLOSE: { 6646d31316cSdrh Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0)); 6656d31316cSdrh break; 6666d31316cSdrh } 66775897234Sdrh 668aa940eacSdrh /* $db commit_hook ?CALLBACK? 669aa940eacSdrh ** 670aa940eacSdrh ** Invoke the given callback just before committing every SQL transaction. 671aa940eacSdrh ** If the callback throws an exception or returns non-zero, then the 672aa940eacSdrh ** transaction is aborted. If CALLBACK is an empty string, the callback 673aa940eacSdrh ** is disabled. 674aa940eacSdrh */ 675aa940eacSdrh case DB_COMMIT_HOOK: { 676aa940eacSdrh if( objc>3 ){ 677aa940eacSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 6780f14e2ebSdrh return TCL_ERROR; 679aa940eacSdrh }else if( objc==2 ){ 680aa940eacSdrh if( pDb->zCommit ){ 681aa940eacSdrh Tcl_AppendResult(interp, pDb->zCommit, 0); 682aa940eacSdrh } 683aa940eacSdrh }else{ 684aa940eacSdrh char *zCommit; 685aa940eacSdrh int len; 686aa940eacSdrh if( pDb->zCommit ){ 687aa940eacSdrh Tcl_Free(pDb->zCommit); 688aa940eacSdrh } 689aa940eacSdrh zCommit = Tcl_GetStringFromObj(objv[2], &len); 690aa940eacSdrh if( zCommit && len>0 ){ 691aa940eacSdrh pDb->zCommit = Tcl_Alloc( len + 1 ); 692aa940eacSdrh strcpy(pDb->zCommit, zCommit); 693aa940eacSdrh }else{ 694aa940eacSdrh pDb->zCommit = 0; 695aa940eacSdrh } 696aa940eacSdrh if( pDb->zCommit ){ 697aa940eacSdrh pDb->interp = interp; 6986f8a503dSdanielk1977 sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb); 699aa940eacSdrh }else{ 7006f8a503dSdanielk1977 sqlite3_commit_hook(pDb->db, 0, 0); 701aa940eacSdrh } 702aa940eacSdrh } 703aa940eacSdrh break; 704aa940eacSdrh } 705aa940eacSdrh 7060f14e2ebSdrh /* 7070f14e2ebSdrh ** $db collate NAME SCRIPT 7080f14e2ebSdrh ** 7090f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 7100f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 7110f14e2ebSdrh */ 7120f14e2ebSdrh case DB_COLLATE: { 7130f14e2ebSdrh SqlCollate *pCollate; 7140f14e2ebSdrh char *zName; 7150f14e2ebSdrh char *zScript; 7160f14e2ebSdrh int nScript; 7170f14e2ebSdrh if( objc!=4 ){ 7180f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 7190f14e2ebSdrh return TCL_ERROR; 7200f14e2ebSdrh } 7210f14e2ebSdrh zName = Tcl_GetStringFromObj(objv[2], 0); 7220f14e2ebSdrh zScript = Tcl_GetStringFromObj(objv[3], &nScript); 7230f14e2ebSdrh pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 ); 7240f14e2ebSdrh if( pCollate==0 ) return TCL_ERROR; 7250f14e2ebSdrh pCollate->interp = interp; 7260f14e2ebSdrh pCollate->pNext = pDb->pCollate; 7270f14e2ebSdrh pCollate->zScript = (char*)&pCollate[1]; 7280f14e2ebSdrh pDb->pCollate = pCollate; 7290f14e2ebSdrh strcpy(pCollate->zScript, zScript); 7300f14e2ebSdrh if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8, 7310f14e2ebSdrh pCollate, tclSqlCollate) ){ 7329636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 7330f14e2ebSdrh return TCL_ERROR; 7340f14e2ebSdrh } 7350f14e2ebSdrh break; 7360f14e2ebSdrh } 7370f14e2ebSdrh 7380f14e2ebSdrh /* 7390f14e2ebSdrh ** $db collation_needed SCRIPT 7400f14e2ebSdrh ** 7410f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 7420f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 7430f14e2ebSdrh */ 7440f14e2ebSdrh case DB_COLLATION_NEEDED: { 7450f14e2ebSdrh if( objc!=3 ){ 7460f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT"); 7470f14e2ebSdrh return TCL_ERROR; 7480f14e2ebSdrh } 7490f14e2ebSdrh if( pDb->pCollateNeeded ){ 7500f14e2ebSdrh Tcl_DecrRefCount(pDb->pCollateNeeded); 7510f14e2ebSdrh } 7520f14e2ebSdrh pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]); 7530f14e2ebSdrh Tcl_IncrRefCount(pDb->pCollateNeeded); 7540f14e2ebSdrh sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded); 7550f14e2ebSdrh break; 7560f14e2ebSdrh } 7570f14e2ebSdrh 75875897234Sdrh /* $db complete SQL 75975897234Sdrh ** 76075897234Sdrh ** Return TRUE if SQL is a complete SQL statement. Return FALSE if 76175897234Sdrh ** additional lines of input are needed. This is similar to the 76275897234Sdrh ** built-in "info complete" command of Tcl. 76375897234Sdrh */ 7646d31316cSdrh case DB_COMPLETE: { 765ccae6026Sdrh #ifndef SQLITE_OMIT_COMPLETE 7666d31316cSdrh Tcl_Obj *pResult; 7676d31316cSdrh int isComplete; 7686d31316cSdrh if( objc!=3 ){ 7696d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 77075897234Sdrh return TCL_ERROR; 77175897234Sdrh } 7726f8a503dSdanielk1977 isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); 7736d31316cSdrh pResult = Tcl_GetObjResult(interp); 7746d31316cSdrh Tcl_SetBooleanObj(pResult, isComplete); 775ccae6026Sdrh #endif 7766d31316cSdrh break; 7776d31316cSdrh } 77875897234Sdrh 77975897234Sdrh /* 780dcd997eaSdrh ** $db errorcode 781dcd997eaSdrh ** 782dcd997eaSdrh ** Return the numeric error code that was returned by the most recent 7836f8a503dSdanielk1977 ** call to sqlite3_exec(). 784dcd997eaSdrh */ 785dcd997eaSdrh case DB_ERRORCODE: { 786f3ce83f5Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); 787dcd997eaSdrh break; 788dcd997eaSdrh } 789dcd997eaSdrh 790dcd997eaSdrh /* 791895d7472Sdrh ** $db eval $sql ?array? ?{ ...code... }? 7921807ce37Sdrh ** $db onecolumn $sql 79375897234Sdrh ** 79475897234Sdrh ** The SQL statement in $sql is evaluated. For each row, the values are 795bec3f402Sdrh ** placed in elements of the array named "array" and ...code... is executed. 79675897234Sdrh ** If "array" and "code" are omitted, then no callback is every invoked. 79775897234Sdrh ** If "array" is an empty string, then the values are placed in variables 79875897234Sdrh ** that have the same name as the fields extracted by the query. 7991807ce37Sdrh ** 8001807ce37Sdrh ** The onecolumn method is the equivalent of: 8011807ce37Sdrh ** lindex [$db eval $sql] 0 80275897234Sdrh */ 8031807ce37Sdrh case DB_ONECOLUMN: 8046d31316cSdrh case DB_EVAL: { 8059d74b4c5Sdrh char const *zSql; /* Next SQL statement to execute */ 8069d74b4c5Sdrh char const *zLeft; /* What is left after first stmt in zSql */ 8079d74b4c5Sdrh sqlite3_stmt *pStmt; /* Compiled SQL statment */ 80892febd92Sdrh Tcl_Obj *pArray; /* Name of array into which results are written */ 80992febd92Sdrh Tcl_Obj *pScript; /* Script to run for each result set */ 8101d895039Sdrh Tcl_Obj **apParm; /* Parameters that need a Tcl_DecrRefCount() */ 8111d895039Sdrh int nParm; /* Number of entries used in apParm[] */ 8121d895039Sdrh Tcl_Obj *aParm[10]; /* Static space for apParm[] in the common case */ 8131807ce37Sdrh Tcl_Obj *pRet; /* Value to be returned */ 814fb7e7651Sdrh SqlPreparedStmt *pPreStmt; /* Pointer to a prepared statement */ 815fb7e7651Sdrh int rc2; 816ef2cb63eSdanielk1977 8171807ce37Sdrh if( choice==DB_ONECOLUMN ){ 8181807ce37Sdrh if( objc!=3 ){ 8191807ce37Sdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 8201807ce37Sdrh return TCL_ERROR; 8211807ce37Sdrh } 8221807ce37Sdrh pRet = 0; 8231807ce37Sdrh }else{ 82492febd92Sdrh if( objc<3 || objc>5 ){ 825895d7472Sdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?"); 82630ccda10Sdanielk1977 return TCL_ERROR; 82730ccda10Sdanielk1977 } 8281807ce37Sdrh pRet = Tcl_NewObj(); 8291807ce37Sdrh Tcl_IncrRefCount(pRet); 8301807ce37Sdrh } 83192febd92Sdrh if( objc==3 ){ 83292febd92Sdrh pArray = pScript = 0; 83392febd92Sdrh }else if( objc==4 ){ 83492febd92Sdrh pArray = 0; 83592febd92Sdrh pScript = objv[3]; 83692febd92Sdrh }else{ 83792febd92Sdrh pArray = objv[3]; 83892febd92Sdrh if( Tcl_GetString(pArray)[0]==0 ) pArray = 0; 83992febd92Sdrh pScript = objv[4]; 84092febd92Sdrh } 84130ccda10Sdanielk1977 8421d895039Sdrh Tcl_IncrRefCount(objv[2]); 84330ccda10Sdanielk1977 zSql = Tcl_GetStringFromObj(objv[2], 0); 84490b6bb19Sdrh while( rc==TCL_OK && zSql[0] ){ 84592febd92Sdrh int i; /* Loop counter */ 846fb7e7651Sdrh int nVar; /* Number of bind parameters in the pStmt */ 84792febd92Sdrh int nCol; /* Number of columns in the result set */ 84892febd92Sdrh Tcl_Obj **apColName = 0; /* Array of column names */ 849fb7e7651Sdrh int len; /* String length of zSql */ 85030ccda10Sdanielk1977 851fb7e7651Sdrh /* Try to find a SQL statement that has already been compiled and 852fb7e7651Sdrh ** which matches the next sequence of SQL. 853fb7e7651Sdrh */ 854fb7e7651Sdrh pStmt = 0; 855fb7e7651Sdrh pPreStmt = pDb->stmtList; 856fb7e7651Sdrh len = strlen(zSql); 857fb7e7651Sdrh if( pPreStmt && sqlite3_expired(pPreStmt->pStmt) ){ 858fb7e7651Sdrh flushStmtCache(pDb); 859fb7e7651Sdrh pPreStmt = 0; 860fb7e7651Sdrh } 861fb7e7651Sdrh for(; pPreStmt; pPreStmt=pPreStmt->pNext){ 862fb7e7651Sdrh int n = pPreStmt->nSql; 863fb7e7651Sdrh if( len>=n 864fb7e7651Sdrh && memcmp(pPreStmt->zSql, zSql, n)==0 865fb7e7651Sdrh && (zSql[n]==0 || zSql[n-1]==';') 866fb7e7651Sdrh ){ 867fb7e7651Sdrh pStmt = pPreStmt->pStmt; 868fb7e7651Sdrh zLeft = &zSql[pPreStmt->nSql]; 869fb7e7651Sdrh 870fb7e7651Sdrh /* When a prepared statement is found, unlink it from the 871fb7e7651Sdrh ** cache list. It will later be added back to the beginning 872fb7e7651Sdrh ** of the cache list in order to implement LRU replacement. 873fb7e7651Sdrh */ 874fb7e7651Sdrh if( pPreStmt->pPrev ){ 875fb7e7651Sdrh pPreStmt->pPrev->pNext = pPreStmt->pNext; 876fb7e7651Sdrh }else{ 877fb7e7651Sdrh pDb->stmtList = pPreStmt->pNext; 878fb7e7651Sdrh } 879fb7e7651Sdrh if( pPreStmt->pNext ){ 880fb7e7651Sdrh pPreStmt->pNext->pPrev = pPreStmt->pPrev; 881fb7e7651Sdrh }else{ 882fb7e7651Sdrh pDb->stmtLast = pPreStmt->pPrev; 883fb7e7651Sdrh } 884fb7e7651Sdrh pDb->nStmt--; 885fb7e7651Sdrh break; 886fb7e7651Sdrh } 887fb7e7651Sdrh } 888fb7e7651Sdrh 889fb7e7651Sdrh /* If no prepared statement was found. Compile the SQL text 890fb7e7651Sdrh */ 891fb7e7651Sdrh if( pStmt==0 ){ 89230ccda10Sdanielk1977 if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){ 893ef2cb63eSdanielk1977 Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); 89430ccda10Sdanielk1977 rc = TCL_ERROR; 89530ccda10Sdanielk1977 break; 89630ccda10Sdanielk1977 } 89792febd92Sdrh if( pStmt==0 ){ 89892febd92Sdrh if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){ 899fb7e7651Sdrh /* A compile-time error in the statement 900fb7e7651Sdrh */ 90192febd92Sdrh Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); 90292febd92Sdrh rc = TCL_ERROR; 90392febd92Sdrh break; 90492febd92Sdrh }else{ 905fb7e7651Sdrh /* The statement was a no-op. Continue to the next statement 906fb7e7651Sdrh ** in the SQL string. 907fb7e7651Sdrh */ 90892febd92Sdrh zSql = zLeft; 90992febd92Sdrh continue; 91092febd92Sdrh } 91192febd92Sdrh } 912fb7e7651Sdrh assert( pPreStmt==0 ); 913fb7e7651Sdrh } 91430ccda10Sdanielk1977 915fb7e7651Sdrh /* Bind values to parameters that begin with $ or : 916fb7e7651Sdrh */ 91792febd92Sdrh nVar = sqlite3_bind_parameter_count(pStmt); 9181d895039Sdrh nParm = 0; 9191d895039Sdrh if( nVar>sizeof(aParm)/sizeof(aParm[0]) ){ 9201d895039Sdrh apParm = (Tcl_Obj**)Tcl_Alloc(nVar*sizeof(apParm[0])); 9211d895039Sdrh }else{ 9221d895039Sdrh apParm = aParm; 9231d895039Sdrh } 92492febd92Sdrh for(i=1; i<=nVar; i++){ 92592febd92Sdrh const char *zVar = sqlite3_bind_parameter_name(pStmt, i); 926c8f9079cSdrh if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':') ){ 92792febd92Sdrh Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); 92892febd92Sdrh if( pVar ){ 92992febd92Sdrh int n; 93092febd92Sdrh u8 *data; 93192febd92Sdrh char *zType = pVar->typePtr ? pVar->typePtr->name : ""; 93292febd92Sdrh char c = zType[0]; 933*df0bddaeSdrh if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ 934*df0bddaeSdrh /* Only load a BLOB type if the Tcl variable is a bytearray and 935*df0bddaeSdrh ** has no string representation. */ 93692febd92Sdrh data = Tcl_GetByteArrayFromObj(pVar, &n); 93792febd92Sdrh sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC); 9381d895039Sdrh Tcl_IncrRefCount(pVar); 9391d895039Sdrh apParm[nParm++] = pVar; 94092febd92Sdrh }else if( (c=='b' && strcmp(zType,"boolean")==0) || 94192febd92Sdrh (c=='i' && strcmp(zType,"int")==0) ){ 94292febd92Sdrh Tcl_GetIntFromObj(interp, pVar, &n); 94392febd92Sdrh sqlite3_bind_int(pStmt, i, n); 94492febd92Sdrh }else if( c=='d' && strcmp(zType,"double")==0 ){ 94592febd92Sdrh double r; 94692febd92Sdrh Tcl_GetDoubleFromObj(interp, pVar, &r); 94792febd92Sdrh sqlite3_bind_double(pStmt, i, r); 948*df0bddaeSdrh }else if( c=='w' && strcmp(zType,"wideInt")==0 ){ 949*df0bddaeSdrh Tcl_WideInt v; 950*df0bddaeSdrh Tcl_GetWideIntFromObj(interp, pVar, &v); 951*df0bddaeSdrh sqlite3_bind_int64(pStmt, i, v); 95292febd92Sdrh }else{ 95392febd92Sdrh data = Tcl_GetStringFromObj(pVar, &n); 95492febd92Sdrh sqlite3_bind_text(pStmt, i, data, n, SQLITE_STATIC); 9551d895039Sdrh Tcl_IncrRefCount(pVar); 9561d895039Sdrh apParm[nParm++] = pVar; 95792febd92Sdrh } 958fb7e7651Sdrh }else{ 959fb7e7651Sdrh sqlite3_bind_null( pStmt, i ); 96092febd92Sdrh } 96192febd92Sdrh } 96292febd92Sdrh } 96392febd92Sdrh 96492febd92Sdrh /* Compute column names */ 96592febd92Sdrh nCol = sqlite3_column_count(pStmt); 96692febd92Sdrh if( pScript ){ 96792febd92Sdrh apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol ); 96892febd92Sdrh if( apColName==0 ) break; 96992febd92Sdrh for(i=0; i<nCol; i++){ 97092febd92Sdrh apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i)); 97192febd92Sdrh Tcl_IncrRefCount(apColName[i]); 97292febd92Sdrh } 97392febd92Sdrh } 97492febd92Sdrh 97592febd92Sdrh /* If results are being stored in an array variable, then create 97692febd92Sdrh ** the array(*) entry for that array 97792febd92Sdrh */ 97892febd92Sdrh if( pArray ){ 97930ccda10Sdanielk1977 Tcl_Obj *pColList = Tcl_NewObj(); 9803ced14a6Sdrh Tcl_Obj *pStar = Tcl_NewStringObj("*", -1); 98130ccda10Sdanielk1977 Tcl_IncrRefCount(pColList); 98292febd92Sdrh for(i=0; i<nCol; i++){ 98392febd92Sdrh Tcl_ListObjAppendElement(interp, pColList, apColName[i]); 98430ccda10Sdanielk1977 } 9853ced14a6Sdrh Tcl_ObjSetVar2(interp, pArray, pStar, pColList,0); 9863ced14a6Sdrh Tcl_DecrRefCount(pColList); 9873ced14a6Sdrh Tcl_DecrRefCount(pStar); 98830ccda10Sdanielk1977 } 98930ccda10Sdanielk1977 99092febd92Sdrh /* Execute the SQL 99192febd92Sdrh */ 99290b6bb19Sdrh while( rc==TCL_OK && pStmt && SQLITE_ROW==sqlite3_step(pStmt) ){ 99392febd92Sdrh for(i=0; i<nCol; i++){ 99430ccda10Sdanielk1977 Tcl_Obj *pVal; 99530ccda10Sdanielk1977 99630ccda10Sdanielk1977 /* Set pVal to contain the i'th column of this row. */ 99792febd92Sdrh switch( sqlite3_column_type(pStmt, i) ){ 99892febd92Sdrh case SQLITE_BLOB: { 9993fd0a736Sdanielk1977 int bytes = sqlite3_column_bytes(pStmt, i); 10003fd0a736Sdanielk1977 pVal = Tcl_NewByteArrayObj(sqlite3_column_blob(pStmt, i), bytes); 100192febd92Sdrh break; 100292febd92Sdrh } 100392febd92Sdrh case SQLITE_INTEGER: { 100492febd92Sdrh sqlite_int64 v = sqlite3_column_int64(pStmt, i); 100592febd92Sdrh if( v>=-2147483647 && v<=2147483647 ){ 100692febd92Sdrh pVal = Tcl_NewIntObj(v); 100792febd92Sdrh }else{ 100892febd92Sdrh pVal = Tcl_NewWideIntObj(v); 100992febd92Sdrh } 101092febd92Sdrh break; 101192febd92Sdrh } 101292febd92Sdrh case SQLITE_FLOAT: { 101392febd92Sdrh double r = sqlite3_column_double(pStmt, i); 101492febd92Sdrh pVal = Tcl_NewDoubleObj(r); 101592febd92Sdrh break; 101692febd92Sdrh } 101755c45f2eSdanielk1977 case SQLITE_NULL: { 101855c45f2eSdanielk1977 pVal = dbTextToObj(pDb->zNull); 101955c45f2eSdanielk1977 break; 102055c45f2eSdanielk1977 } 102192febd92Sdrh default: { 102292febd92Sdrh pVal = dbTextToObj(sqlite3_column_text(pStmt, i)); 102392febd92Sdrh break; 102492febd92Sdrh } 102530ccda10Sdanielk1977 } 102630ccda10Sdanielk1977 102792febd92Sdrh if( pScript ){ 102892febd92Sdrh if( pArray==0 ){ 102992febd92Sdrh Tcl_ObjSetVar2(interp, apColName[i], 0, pVal, 0); 103030ccda10Sdanielk1977 }else{ 103192febd92Sdrh Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0); 103230ccda10Sdanielk1977 } 10331807ce37Sdrh }else if( choice==DB_ONECOLUMN ){ 10341807ce37Sdrh if( pRet==0 ){ 10351807ce37Sdrh pRet = pVal; 10361807ce37Sdrh Tcl_IncrRefCount(pRet); 10371807ce37Sdrh } 103890b6bb19Sdrh rc = TCL_BREAK; 103930ccda10Sdanielk1977 }else{ 104030ccda10Sdanielk1977 Tcl_ListObjAppendElement(interp, pRet, pVal); 104130ccda10Sdanielk1977 } 104230ccda10Sdanielk1977 } 104330ccda10Sdanielk1977 104492febd92Sdrh if( pScript ){ 104592febd92Sdrh rc = Tcl_EvalObjEx(interp, pScript, 0); 104690b6bb19Sdrh if( rc==TCL_CONTINUE ){ 104790b6bb19Sdrh rc = TCL_OK; 104830ccda10Sdanielk1977 } 104930ccda10Sdanielk1977 } 105090b6bb19Sdrh } 105190b6bb19Sdrh if( rc==TCL_BREAK ){ 105290b6bb19Sdrh rc = TCL_OK; 105390b6bb19Sdrh } 105430ccda10Sdanielk1977 105592febd92Sdrh /* Free the column name objects */ 105692febd92Sdrh if( pScript ){ 105792febd92Sdrh for(i=0; i<nCol; i++){ 105892febd92Sdrh Tcl_DecrRefCount(apColName[i]); 105992febd92Sdrh } 106092febd92Sdrh Tcl_Free((char*)apColName); 106192febd92Sdrh } 106292febd92Sdrh 10631d895039Sdrh /* Free the bound string and blob parameters */ 10641d895039Sdrh for(i=0; i<nParm; i++){ 10651d895039Sdrh Tcl_DecrRefCount(apParm[i]); 10661d895039Sdrh } 10671d895039Sdrh if( apParm!=aParm ){ 10681d895039Sdrh Tcl_Free((char*)apParm); 10691d895039Sdrh } 10701d895039Sdrh 1071fb7e7651Sdrh /* Reset the statement. If the result code is SQLITE_SCHEMA, then 1072fb7e7651Sdrh ** flush the statement cache and try the statement again. 107392febd92Sdrh */ 1074fb7e7651Sdrh rc2 = sqlite3_reset(pStmt); 1075fb7e7651Sdrh if( SQLITE_SCHEMA==rc2 ){ 1076fb7e7651Sdrh /* After a schema change, flush the cache and try to run the 1077fb7e7651Sdrh ** statement again 1078fb7e7651Sdrh */ 1079fb7e7651Sdrh flushStmtCache( pDb ); 1080fb7e7651Sdrh sqlite3_finalize(pStmt); 1081fb7e7651Sdrh if( pPreStmt ) Tcl_Free((char*)pPreStmt); 108230ccda10Sdanielk1977 continue; 1083fb7e7651Sdrh }else if( SQLITE_OK!=rc2 ){ 1084fb7e7651Sdrh /* If a run-time error occurs, report the error and stop reading 1085fb7e7651Sdrh ** the SQL 1086fb7e7651Sdrh */ 1087ef2cb63eSdanielk1977 Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); 1088fb7e7651Sdrh sqlite3_finalize(pStmt); 108930ccda10Sdanielk1977 rc = TCL_ERROR; 1090fb7e7651Sdrh if( pPreStmt ) Tcl_Free((char*)pPreStmt); 109130ccda10Sdanielk1977 break; 1092fb7e7651Sdrh }else if( pDb->maxStmt<=0 ){ 1093fb7e7651Sdrh /* If the cache is turned off, deallocated the statement */ 1094fb7e7651Sdrh if( pPreStmt ) Tcl_Free((char*)pPreStmt); 1095fb7e7651Sdrh sqlite3_finalize(pStmt); 1096fb7e7651Sdrh }else{ 1097fb7e7651Sdrh /* Everything worked and the cache is operational. 1098fb7e7651Sdrh ** Create a new SqlPreparedStmt structure if we need one. 1099fb7e7651Sdrh ** (If we already have one we can just reuse it.) 1100fb7e7651Sdrh */ 1101fb7e7651Sdrh if( pPreStmt==0 ){ 1102fb7e7651Sdrh len = zLeft - zSql; 1103fb7e7651Sdrh pPreStmt = (SqlPreparedStmt*)Tcl_Alloc( sizeof(*pPreStmt) + len ); 1104fb7e7651Sdrh if( pPreStmt==0 ) return TCL_ERROR; 1105fb7e7651Sdrh pPreStmt->pStmt = pStmt; 1106fb7e7651Sdrh pPreStmt->nSql = len; 1107fb7e7651Sdrh memcpy(pPreStmt->zSql, zSql, len); 1108fb7e7651Sdrh pPreStmt->zSql[len] = 0; 110930ccda10Sdanielk1977 } 111030ccda10Sdanielk1977 1111fb7e7651Sdrh /* Add the prepared statement to the beginning of the cache list 1112fb7e7651Sdrh */ 1113fb7e7651Sdrh pPreStmt->pNext = pDb->stmtList; 1114fb7e7651Sdrh pPreStmt->pPrev = 0; 1115fb7e7651Sdrh if( pDb->stmtList ){ 1116fb7e7651Sdrh pDb->stmtList->pPrev = pPreStmt; 1117fb7e7651Sdrh } 1118fb7e7651Sdrh pDb->stmtList = pPreStmt; 1119fb7e7651Sdrh if( pDb->stmtLast==0 ){ 1120fb7e7651Sdrh assert( pDb->nStmt==0 ); 1121fb7e7651Sdrh pDb->stmtLast = pPreStmt; 1122fb7e7651Sdrh }else{ 1123fb7e7651Sdrh assert( pDb->nStmt>0 ); 1124fb7e7651Sdrh } 1125fb7e7651Sdrh pDb->nStmt++; 1126fb7e7651Sdrh 1127fb7e7651Sdrh /* If we have too many statement in cache, remove the surplus from the 1128fb7e7651Sdrh ** end of the cache list. 1129fb7e7651Sdrh */ 1130fb7e7651Sdrh while( pDb->nStmt>pDb->maxStmt ){ 1131fb7e7651Sdrh sqlite3_finalize(pDb->stmtLast->pStmt); 1132fb7e7651Sdrh pDb->stmtLast = pDb->stmtLast->pPrev; 1133fb7e7651Sdrh Tcl_Free((char*)pDb->stmtLast->pNext); 1134fb7e7651Sdrh pDb->stmtLast->pNext = 0; 1135fb7e7651Sdrh pDb->nStmt--; 1136fb7e7651Sdrh } 1137fb7e7651Sdrh } 1138fb7e7651Sdrh 1139fb7e7651Sdrh /* Proceed to the next statement */ 114030ccda10Sdanielk1977 zSql = zLeft; 114130ccda10Sdanielk1977 } 11421d895039Sdrh Tcl_DecrRefCount(objv[2]); 114330ccda10Sdanielk1977 11441807ce37Sdrh if( pRet ){ 1145ef2cb63eSdanielk1977 if( rc==TCL_OK ){ 114630ccda10Sdanielk1977 Tcl_SetObjResult(interp, pRet); 114730ccda10Sdanielk1977 } 1148ef2cb63eSdanielk1977 Tcl_DecrRefCount(pRet); 11491807ce37Sdrh } 115030ccda10Sdanielk1977 break; 115130ccda10Sdanielk1977 } 1152bec3f402Sdrh 1153bec3f402Sdrh /* 1154cabb0819Sdrh ** $db function NAME SCRIPT 1155cabb0819Sdrh ** 1156cabb0819Sdrh ** Create a new SQL function called NAME. Whenever that function is 1157cabb0819Sdrh ** called, invoke SCRIPT to evaluate the function. 1158cabb0819Sdrh */ 1159cabb0819Sdrh case DB_FUNCTION: { 1160cabb0819Sdrh SqlFunc *pFunc; 1161cabb0819Sdrh char *zName; 1162cabb0819Sdrh char *zScript; 1163cabb0819Sdrh int nScript; 1164cabb0819Sdrh if( objc!=4 ){ 1165cabb0819Sdrh Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 1166cabb0819Sdrh return TCL_ERROR; 1167cabb0819Sdrh } 1168cabb0819Sdrh zName = Tcl_GetStringFromObj(objv[2], 0); 1169cabb0819Sdrh zScript = Tcl_GetStringFromObj(objv[3], &nScript); 1170cabb0819Sdrh pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 ); 1171cabb0819Sdrh if( pFunc==0 ) return TCL_ERROR; 1172cabb0819Sdrh pFunc->interp = interp; 1173cabb0819Sdrh pFunc->pNext = pDb->pFunc; 1174cabb0819Sdrh pFunc->zScript = (char*)&pFunc[1]; 11750f14e2ebSdrh pDb->pFunc = pFunc; 1176cabb0819Sdrh strcpy(pFunc->zScript, zScript); 1177c8c1158bSdanielk1977 rc = sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8, 1178d8123366Sdanielk1977 pFunc, tclSqlFunc, 0, 0); 1179fb7e7651Sdrh if( rc!=SQLITE_OK ){ 1180fb7e7651Sdrh rc = TCL_ERROR; 11819636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 1182fb7e7651Sdrh }else{ 1183fb7e7651Sdrh /* Must flush any cached statements */ 1184fb7e7651Sdrh flushStmtCache( pDb ); 1185fb7e7651Sdrh } 1186cabb0819Sdrh break; 1187cabb0819Sdrh } 1188cabb0819Sdrh 1189cabb0819Sdrh /* 1190af9ff33aSdrh ** $db last_insert_rowid 1191af9ff33aSdrh ** 1192af9ff33aSdrh ** Return an integer which is the ROWID for the most recent insert. 1193af9ff33aSdrh */ 1194af9ff33aSdrh case DB_LAST_INSERT_ROWID: { 1195af9ff33aSdrh Tcl_Obj *pResult; 1196af9ff33aSdrh int rowid; 1197af9ff33aSdrh if( objc!=2 ){ 1198af9ff33aSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 1199af9ff33aSdrh return TCL_ERROR; 1200af9ff33aSdrh } 12016f8a503dSdanielk1977 rowid = sqlite3_last_insert_rowid(pDb->db); 1202af9ff33aSdrh pResult = Tcl_GetObjResult(interp); 1203af9ff33aSdrh Tcl_SetIntObj(pResult, rowid); 1204af9ff33aSdrh break; 1205af9ff33aSdrh } 1206af9ff33aSdrh 1207af9ff33aSdrh /* 12081807ce37Sdrh ** The DB_ONECOLUMN method is implemented together with DB_EVAL. 12095d9d7576Sdrh */ 12101807ce37Sdrh 12111807ce37Sdrh /* $db progress ?N CALLBACK? 12121807ce37Sdrh ** 12131807ce37Sdrh ** Invoke the given callback every N virtual machine opcodes while executing 12141807ce37Sdrh ** queries. 12151807ce37Sdrh */ 12161807ce37Sdrh case DB_PROGRESS: { 12171807ce37Sdrh if( objc==2 ){ 12181807ce37Sdrh if( pDb->zProgress ){ 12191807ce37Sdrh Tcl_AppendResult(interp, pDb->zProgress, 0); 12205d9d7576Sdrh } 12211807ce37Sdrh }else if( objc==4 ){ 12221807ce37Sdrh char *zProgress; 12231807ce37Sdrh int len; 12241807ce37Sdrh int N; 12251807ce37Sdrh if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ 12261807ce37Sdrh return TCL_ERROR; 12271807ce37Sdrh }; 12281807ce37Sdrh if( pDb->zProgress ){ 12291807ce37Sdrh Tcl_Free(pDb->zProgress); 12301807ce37Sdrh } 12311807ce37Sdrh zProgress = Tcl_GetStringFromObj(objv[3], &len); 12321807ce37Sdrh if( zProgress && len>0 ){ 12331807ce37Sdrh pDb->zProgress = Tcl_Alloc( len + 1 ); 12341807ce37Sdrh strcpy(pDb->zProgress, zProgress); 12351807ce37Sdrh }else{ 12361807ce37Sdrh pDb->zProgress = 0; 12371807ce37Sdrh } 12381807ce37Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK 12391807ce37Sdrh if( pDb->zProgress ){ 12401807ce37Sdrh pDb->interp = interp; 12411807ce37Sdrh sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb); 12421807ce37Sdrh }else{ 12431807ce37Sdrh sqlite3_progress_handler(pDb->db, 0, 0, 0); 12441807ce37Sdrh } 12451807ce37Sdrh #endif 12461807ce37Sdrh }else{ 12471807ce37Sdrh Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK"); 12481807ce37Sdrh return TCL_ERROR; 12495d9d7576Sdrh } 12505d9d7576Sdrh break; 12515d9d7576Sdrh } 12525d9d7576Sdrh 12535d9d7576Sdrh /* 125422fbcb8dSdrh ** $db rekey KEY 125522fbcb8dSdrh ** 125622fbcb8dSdrh ** Change the encryption key on the currently open database. 125722fbcb8dSdrh */ 125822fbcb8dSdrh case DB_REKEY: { 125922fbcb8dSdrh int nKey; 126022fbcb8dSdrh void *pKey; 126122fbcb8dSdrh if( objc!=3 ){ 126222fbcb8dSdrh Tcl_WrongNumArgs(interp, 2, objv, "KEY"); 126322fbcb8dSdrh return TCL_ERROR; 126422fbcb8dSdrh } 126522fbcb8dSdrh pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); 12669eb9e26bSdrh #ifdef SQLITE_HAS_CODEC 12672011d5f5Sdrh rc = sqlite3_rekey(pDb->db, pKey, nKey); 126822fbcb8dSdrh if( rc ){ 1269f20b21c8Sdanielk1977 Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); 127022fbcb8dSdrh rc = TCL_ERROR; 127122fbcb8dSdrh } 127222fbcb8dSdrh #endif 127322fbcb8dSdrh break; 127422fbcb8dSdrh } 127522fbcb8dSdrh 127622fbcb8dSdrh /* 1277bec3f402Sdrh ** $db timeout MILLESECONDS 1278bec3f402Sdrh ** 1279bec3f402Sdrh ** Delay for the number of milliseconds specified when a file is locked. 1280bec3f402Sdrh */ 12816d31316cSdrh case DB_TIMEOUT: { 1282bec3f402Sdrh int ms; 12836d31316cSdrh if( objc!=3 ){ 12846d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS"); 1285bec3f402Sdrh return TCL_ERROR; 128675897234Sdrh } 12876d31316cSdrh if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR; 12886f8a503dSdanielk1977 sqlite3_busy_timeout(pDb->db, ms); 12896d31316cSdrh break; 129075897234Sdrh } 1291b5a20d3cSdrh 12920f14e2ebSdrh /* 129355c45f2eSdanielk1977 ** $db nullvalue ?STRING? 129455c45f2eSdanielk1977 ** 129555c45f2eSdanielk1977 ** Change text used when a NULL comes back from the database. If ?STRING? 129655c45f2eSdanielk1977 ** is not present, then the current string used for NULL is returned. 129755c45f2eSdanielk1977 ** If STRING is present, then STRING is returned. 129855c45f2eSdanielk1977 ** 129955c45f2eSdanielk1977 */ 130055c45f2eSdanielk1977 case DB_NULLVALUE: { 130155c45f2eSdanielk1977 if( objc!=2 && objc!=3 ){ 130255c45f2eSdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE"); 130355c45f2eSdanielk1977 return TCL_ERROR; 130455c45f2eSdanielk1977 } 130555c45f2eSdanielk1977 if( objc==3 ){ 130655c45f2eSdanielk1977 int len; 130755c45f2eSdanielk1977 char *zNull = Tcl_GetStringFromObj(objv[2], &len); 130855c45f2eSdanielk1977 if( pDb->zNull ){ 130955c45f2eSdanielk1977 Tcl_Free(pDb->zNull); 131055c45f2eSdanielk1977 } 131155c45f2eSdanielk1977 if( zNull && len>0 ){ 131255c45f2eSdanielk1977 pDb->zNull = Tcl_Alloc( len + 1 ); 131355c45f2eSdanielk1977 strncpy(pDb->zNull, zNull, len); 131455c45f2eSdanielk1977 pDb->zNull[len] = '\0'; 131555c45f2eSdanielk1977 }else{ 131655c45f2eSdanielk1977 pDb->zNull = 0; 131755c45f2eSdanielk1977 } 131855c45f2eSdanielk1977 } 131955c45f2eSdanielk1977 Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull)); 132055c45f2eSdanielk1977 break; 132155c45f2eSdanielk1977 } 132255c45f2eSdanielk1977 132355c45f2eSdanielk1977 /* 13240f14e2ebSdrh ** $db total_changes 13250f14e2ebSdrh ** 13260f14e2ebSdrh ** Return the number of rows that were modified, inserted, or deleted 13270f14e2ebSdrh ** since the database handle was created. 13280f14e2ebSdrh */ 13290f14e2ebSdrh case DB_TOTAL_CHANGES: { 13300f14e2ebSdrh Tcl_Obj *pResult; 13310f14e2ebSdrh if( objc!=2 ){ 13320f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 13330f14e2ebSdrh return TCL_ERROR; 13340f14e2ebSdrh } 13350f14e2ebSdrh pResult = Tcl_GetObjResult(interp); 13360f14e2ebSdrh Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db)); 13370f14e2ebSdrh break; 13380f14e2ebSdrh } 13390f14e2ebSdrh 1340b5a20d3cSdrh /* $db trace ?CALLBACK? 1341b5a20d3cSdrh ** 1342b5a20d3cSdrh ** Make arrangements to invoke the CALLBACK routine for each SQL statement 1343b5a20d3cSdrh ** that is executed. The text of the SQL is appended to CALLBACK before 1344b5a20d3cSdrh ** it is executed. 1345b5a20d3cSdrh */ 1346b5a20d3cSdrh case DB_TRACE: { 1347b5a20d3cSdrh if( objc>3 ){ 1348b5a20d3cSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 1349b97759edSdrh return TCL_ERROR; 1350b5a20d3cSdrh }else if( objc==2 ){ 1351b5a20d3cSdrh if( pDb->zTrace ){ 1352b5a20d3cSdrh Tcl_AppendResult(interp, pDb->zTrace, 0); 1353b5a20d3cSdrh } 1354b5a20d3cSdrh }else{ 1355b5a20d3cSdrh char *zTrace; 1356b5a20d3cSdrh int len; 1357b5a20d3cSdrh if( pDb->zTrace ){ 1358b5a20d3cSdrh Tcl_Free(pDb->zTrace); 1359b5a20d3cSdrh } 1360b5a20d3cSdrh zTrace = Tcl_GetStringFromObj(objv[2], &len); 1361b5a20d3cSdrh if( zTrace && len>0 ){ 1362b5a20d3cSdrh pDb->zTrace = Tcl_Alloc( len + 1 ); 1363b5a20d3cSdrh strcpy(pDb->zTrace, zTrace); 1364b5a20d3cSdrh }else{ 1365b5a20d3cSdrh pDb->zTrace = 0; 1366b5a20d3cSdrh } 1367b5a20d3cSdrh if( pDb->zTrace ){ 1368b5a20d3cSdrh pDb->interp = interp; 13696f8a503dSdanielk1977 sqlite3_trace(pDb->db, DbTraceHandler, pDb); 1370b5a20d3cSdrh }else{ 13716f8a503dSdanielk1977 sqlite3_trace(pDb->db, 0, 0); 1372b5a20d3cSdrh } 1373b5a20d3cSdrh } 1374b5a20d3cSdrh break; 1375b5a20d3cSdrh } 1376b5a20d3cSdrh 13771067fe11Stpoindex /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR? 13781067fe11Stpoindex ** 13791067fe11Stpoindex ** Copy data into table from filename, optionally using SEPARATOR 13801067fe11Stpoindex ** as column separators. If a column contains a null string, or the 13811067fe11Stpoindex ** value of NULLINDICATOR, a NULL is inserted for the column. 13821067fe11Stpoindex ** conflict-algorithm is one of the sqlite conflict algorithms: 13831067fe11Stpoindex ** rollback, abort, fail, ignore, replace 13841067fe11Stpoindex ** On success, return the number of lines processed, not necessarily same 13851067fe11Stpoindex ** as 'db changes' due to conflict-algorithm selected. 13861067fe11Stpoindex ** 13871067fe11Stpoindex ** This code is basically an implementation/enhancement of 13881067fe11Stpoindex ** the sqlite3 shell.c ".import" command. 13891067fe11Stpoindex ** 13901067fe11Stpoindex ** This command usage is equivalent to the sqlite2.x COPY statement, 13911067fe11Stpoindex ** which imports file data into a table using the PostgreSQL COPY file format: 13921067fe11Stpoindex ** $db copy $conflit_algo $table_name $filename \t \\N 13931067fe11Stpoindex */ 13941067fe11Stpoindex case DB_COPY: { 13951067fe11Stpoindex char *zTable; /* Insert data into this table */ 13961067fe11Stpoindex char *zFile; /* The file from which to extract data */ 13971067fe11Stpoindex char *zConflict; /* The conflict algorithm to use */ 13981067fe11Stpoindex sqlite3_stmt *pStmt; /* A statement */ 13991067fe11Stpoindex int rc; /* Result code */ 14001067fe11Stpoindex int nCol; /* Number of columns in the table */ 14011067fe11Stpoindex int nByte; /* Number of bytes in an SQL string */ 14021067fe11Stpoindex int i, j; /* Loop counters */ 14031067fe11Stpoindex int nSep; /* Number of bytes in zSep[] */ 14041067fe11Stpoindex int nNull; /* Number of bytes in zNull[] */ 14051067fe11Stpoindex char *zSql; /* An SQL statement */ 14061067fe11Stpoindex char *zLine; /* A single line of input from the file */ 14071067fe11Stpoindex char **azCol; /* zLine[] broken up into columns */ 14081067fe11Stpoindex char *zCommit; /* How to commit changes */ 14091067fe11Stpoindex FILE *in; /* The input file */ 14101067fe11Stpoindex int lineno = 0; /* Line number of input file */ 14111067fe11Stpoindex char zLineNum[80]; /* Line number print buffer */ 14121067fe11Stpoindex Tcl_Obj *pResult; /* interp result */ 14131067fe11Stpoindex 14149ee3cdcbSdrh char *zSep; 14159ee3cdcbSdrh char *zNull; 14169ee3cdcbSdrh if( objc<5 || objc>7 ){ 14179ee3cdcbSdrh Tcl_WrongNumArgs(interp, 2, objv, 14189ee3cdcbSdrh "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"); 14199ee3cdcbSdrh return TCL_ERROR; 14209ee3cdcbSdrh } 14219ee3cdcbSdrh if( objc>=6 ){ 14229ee3cdcbSdrh zSep = Tcl_GetStringFromObj(objv[5], 0); 14239ee3cdcbSdrh }else{ 14249ee3cdcbSdrh zSep = "\t"; 14259ee3cdcbSdrh } 14269ee3cdcbSdrh if( objc>=7 ){ 14279ee3cdcbSdrh zNull = Tcl_GetStringFromObj(objv[6], 0); 14289ee3cdcbSdrh }else{ 14299ee3cdcbSdrh zNull = ""; 14309ee3cdcbSdrh } 14311067fe11Stpoindex zConflict = Tcl_GetStringFromObj(objv[2], 0); 14321067fe11Stpoindex zTable = Tcl_GetStringFromObj(objv[3], 0); 14331067fe11Stpoindex zFile = Tcl_GetStringFromObj(objv[4], 0); 14341067fe11Stpoindex nSep = strlen(zSep); 14351067fe11Stpoindex nNull = strlen(zNull); 14361067fe11Stpoindex if( nSep==0 ){ 14371067fe11Stpoindex Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0); 14381067fe11Stpoindex return TCL_ERROR; 14391067fe11Stpoindex } 14401067fe11Stpoindex if(sqlite3StrICmp(zConflict, "rollback") != 0 && 14411067fe11Stpoindex sqlite3StrICmp(zConflict, "abort" ) != 0 && 14421067fe11Stpoindex sqlite3StrICmp(zConflict, "fail" ) != 0 && 14431067fe11Stpoindex sqlite3StrICmp(zConflict, "ignore" ) != 0 && 14441067fe11Stpoindex sqlite3StrICmp(zConflict, "replace" ) != 0 ) { 14459ee3cdcbSdrh Tcl_AppendResult(interp, "Error: \"", zConflict, 14469ee3cdcbSdrh "\", conflict-algorithm must be one of: rollback, " 14479ee3cdcbSdrh "abort, fail, ignore, or replace", 0); 14481067fe11Stpoindex return TCL_ERROR; 14491067fe11Stpoindex } 14501067fe11Stpoindex zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); 14511067fe11Stpoindex if( zSql==0 ){ 14521067fe11Stpoindex Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0); 14531067fe11Stpoindex return TCL_ERROR; 14541067fe11Stpoindex } 14551067fe11Stpoindex nByte = strlen(zSql); 14561067fe11Stpoindex rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0); 14571067fe11Stpoindex sqlite3_free(zSql); 14581067fe11Stpoindex if( rc ){ 14591067fe11Stpoindex Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); 14601067fe11Stpoindex nCol = 0; 14611067fe11Stpoindex }else{ 14621067fe11Stpoindex nCol = sqlite3_column_count(pStmt); 14631067fe11Stpoindex } 14641067fe11Stpoindex sqlite3_finalize(pStmt); 14651067fe11Stpoindex if( nCol==0 ) { 14661067fe11Stpoindex return TCL_ERROR; 14671067fe11Stpoindex } 14681067fe11Stpoindex zSql = malloc( nByte + 50 + nCol*2 ); 14691067fe11Stpoindex if( zSql==0 ) { 14701067fe11Stpoindex Tcl_AppendResult(interp, "Error: can't malloc()", 0); 14711067fe11Stpoindex return TCL_ERROR; 14721067fe11Stpoindex } 14739ee3cdcbSdrh sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?", 14749ee3cdcbSdrh zConflict, zTable); 14751067fe11Stpoindex j = strlen(zSql); 14761067fe11Stpoindex for(i=1; i<nCol; i++){ 14771067fe11Stpoindex zSql[j++] = ','; 14781067fe11Stpoindex zSql[j++] = '?'; 14791067fe11Stpoindex } 14801067fe11Stpoindex zSql[j++] = ')'; 14811067fe11Stpoindex zSql[j] = 0; 14821067fe11Stpoindex rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0); 14831067fe11Stpoindex free(zSql); 14841067fe11Stpoindex if( rc ){ 14851067fe11Stpoindex Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); 14861067fe11Stpoindex sqlite3_finalize(pStmt); 14871067fe11Stpoindex return TCL_ERROR; 14881067fe11Stpoindex } 14891067fe11Stpoindex in = fopen(zFile, "rb"); 14901067fe11Stpoindex if( in==0 ){ 14911067fe11Stpoindex Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL); 14921067fe11Stpoindex sqlite3_finalize(pStmt); 14931067fe11Stpoindex return TCL_ERROR; 14941067fe11Stpoindex } 14951067fe11Stpoindex azCol = malloc( sizeof(azCol[0])*(nCol+1) ); 14961067fe11Stpoindex if( azCol==0 ) { 14971067fe11Stpoindex Tcl_AppendResult(interp, "Error: can't malloc()", 0); 14981067fe11Stpoindex return TCL_ERROR; 14991067fe11Stpoindex } 15001067fe11Stpoindex sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0); 15011067fe11Stpoindex zCommit = "COMMIT"; 15021067fe11Stpoindex while( (zLine = local_getline(0, in))!=0 ){ 15031067fe11Stpoindex char *z; 15041067fe11Stpoindex i = 0; 15051067fe11Stpoindex lineno++; 15061067fe11Stpoindex azCol[0] = zLine; 15071067fe11Stpoindex for(i=0, z=zLine; *z; z++){ 15081067fe11Stpoindex if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){ 15091067fe11Stpoindex *z = 0; 15101067fe11Stpoindex i++; 15111067fe11Stpoindex if( i<nCol ){ 15121067fe11Stpoindex azCol[i] = &z[nSep]; 15131067fe11Stpoindex z += nSep-1; 15141067fe11Stpoindex } 15151067fe11Stpoindex } 15161067fe11Stpoindex } 15171067fe11Stpoindex if( i+1!=nCol ){ 15181067fe11Stpoindex char *zErr; 15191067fe11Stpoindex zErr = malloc(200 + strlen(zFile)); 15201067fe11Stpoindex sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d", 15211067fe11Stpoindex zFile, lineno, nCol, i+1); 15221067fe11Stpoindex Tcl_AppendResult(interp, zErr, 0); 15231067fe11Stpoindex free(zErr); 15241067fe11Stpoindex zCommit = "ROLLBACK"; 15251067fe11Stpoindex break; 15261067fe11Stpoindex } 15271067fe11Stpoindex for(i=0; i<nCol; i++){ 15281067fe11Stpoindex /* check for null data, if so, bind as null */ 15291067fe11Stpoindex if ((nNull>0 && strcmp(azCol[i], zNull)==0) || strlen(azCol[i])==0) { 15301067fe11Stpoindex sqlite3_bind_null(pStmt, i+1); 15311067fe11Stpoindex }else{ 15321067fe11Stpoindex sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); 15331067fe11Stpoindex } 15341067fe11Stpoindex } 15351067fe11Stpoindex sqlite3_step(pStmt); 15361067fe11Stpoindex rc = sqlite3_reset(pStmt); 15371067fe11Stpoindex free(zLine); 15381067fe11Stpoindex if( rc!=SQLITE_OK ){ 15391067fe11Stpoindex Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0); 15401067fe11Stpoindex zCommit = "ROLLBACK"; 15411067fe11Stpoindex break; 15421067fe11Stpoindex } 15431067fe11Stpoindex } 15441067fe11Stpoindex free(azCol); 15451067fe11Stpoindex fclose(in); 15461067fe11Stpoindex sqlite3_finalize(pStmt); 15471067fe11Stpoindex sqlite3_exec(pDb->db, zCommit, 0, 0, 0); 15481067fe11Stpoindex 15491067fe11Stpoindex if( zCommit[0] == 'C' ){ 15501067fe11Stpoindex /* success, set result as number of lines processed */ 15511067fe11Stpoindex pResult = Tcl_GetObjResult(interp); 15521067fe11Stpoindex Tcl_SetIntObj(pResult, lineno); 15531067fe11Stpoindex rc = TCL_OK; 15541067fe11Stpoindex }else{ 15551067fe11Stpoindex /* failure, append lineno where failed */ 15561067fe11Stpoindex sprintf(zLineNum,"%d",lineno); 15571067fe11Stpoindex Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0); 15581067fe11Stpoindex rc = TCL_ERROR; 15591067fe11Stpoindex } 15601067fe11Stpoindex break; 15611067fe11Stpoindex } 15621067fe11Stpoindex 15634397de57Sdanielk1977 /* $db version 15644397de57Sdanielk1977 ** 15654397de57Sdanielk1977 ** Return the version string for this database. 15664397de57Sdanielk1977 */ 15674397de57Sdanielk1977 case DB_VERSION: { 15684397de57Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC); 15694397de57Sdanielk1977 break; 15704397de57Sdanielk1977 } 15714397de57Sdanielk1977 15721067fe11Stpoindex 15736d31316cSdrh } /* End of the SWITCH statement */ 157422fbcb8dSdrh return rc; 157575897234Sdrh } 157675897234Sdrh 157775897234Sdrh /* 15789bb575fdSdrh ** sqlite3 DBNAME FILENAME ?MODE? ?-key KEY? 157975897234Sdrh ** 158075897234Sdrh ** This is the main Tcl command. When the "sqlite" Tcl command is 158175897234Sdrh ** invoked, this routine runs to process that command. 158275897234Sdrh ** 158375897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new 158475897234Sdrh ** database connection. This command creates a new command named 158575897234Sdrh ** DBNAME that is used to control that connection. The database 158675897234Sdrh ** connection is deleted when the DBNAME command is deleted. 158775897234Sdrh ** 158875897234Sdrh ** The second argument is the name of the directory that contains 158975897234Sdrh ** the sqlite database that is to be accessed. 1590fbc3eab8Sdrh ** 1591fbc3eab8Sdrh ** For testing purposes, we also support the following: 1592fbc3eab8Sdrh ** 15939bb575fdSdrh ** sqlite3 -encoding 1594fbc3eab8Sdrh ** 1595fbc3eab8Sdrh ** Return the encoding used by LIKE and GLOB operators. Choices 1596fbc3eab8Sdrh ** are UTF-8 and iso8859. 1597fbc3eab8Sdrh ** 15989bb575fdSdrh ** sqlite3 -version 1599647cb0e1Sdrh ** 1600647cb0e1Sdrh ** Return the version number of the SQLite library. 1601647cb0e1Sdrh ** 16029bb575fdSdrh ** sqlite3 -tcl-uses-utf 1603fbc3eab8Sdrh ** 1604fbc3eab8Sdrh ** Return "1" if compiled with a Tcl uses UTF-8. Return "0" if 1605fbc3eab8Sdrh ** not. Used by tests to make sure the library was compiled 1606fbc3eab8Sdrh ** correctly. 160775897234Sdrh */ 160822fbcb8dSdrh static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ 1609bec3f402Sdrh SqliteDb *p; 161022fbcb8dSdrh void *pKey = 0; 161122fbcb8dSdrh int nKey = 0; 161222fbcb8dSdrh const char *zArg; 161375897234Sdrh char *zErrMsg; 161422fbcb8dSdrh const char *zFile; 161506b2718aSdrh char zBuf[80]; 161622fbcb8dSdrh if( objc==2 ){ 161722fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 161822fbcb8dSdrh if( strcmp(zArg,"-version")==0 ){ 16196f8a503dSdanielk1977 Tcl_AppendResult(interp,sqlite3_version,0); 1620647cb0e1Sdrh return TCL_OK; 1621647cb0e1Sdrh } 16229eb9e26bSdrh if( strcmp(zArg,"-has-codec")==0 ){ 16239eb9e26bSdrh #ifdef SQLITE_HAS_CODEC 162422fbcb8dSdrh Tcl_AppendResult(interp,"1",0); 162522fbcb8dSdrh #else 162622fbcb8dSdrh Tcl_AppendResult(interp,"0",0); 162722fbcb8dSdrh #endif 162822fbcb8dSdrh return TCL_OK; 162922fbcb8dSdrh } 163022fbcb8dSdrh if( strcmp(zArg,"-tcl-uses-utf")==0 ){ 1631fbc3eab8Sdrh #ifdef TCL_UTF_MAX 1632fbc3eab8Sdrh Tcl_AppendResult(interp,"1",0); 1633fbc3eab8Sdrh #else 1634fbc3eab8Sdrh Tcl_AppendResult(interp,"0",0); 1635fbc3eab8Sdrh #endif 1636fbc3eab8Sdrh return TCL_OK; 1637fbc3eab8Sdrh } 1638fbc3eab8Sdrh } 163922fbcb8dSdrh if( objc==5 || objc==6 ){ 164022fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[objc-2], 0); 164122fbcb8dSdrh if( strcmp(zArg,"-key")==0 ){ 164222fbcb8dSdrh pKey = Tcl_GetByteArrayFromObj(objv[objc-1], &nKey); 164322fbcb8dSdrh objc -= 2; 164422fbcb8dSdrh } 164522fbcb8dSdrh } 164622fbcb8dSdrh if( objc!=3 && objc!=4 ){ 164722fbcb8dSdrh Tcl_WrongNumArgs(interp, 1, objv, 16489eb9e26bSdrh #ifdef SQLITE_HAS_CODEC 16499eb9e26bSdrh "HANDLE FILENAME ?-key CODEC-KEY?" 165022fbcb8dSdrh #else 165122fbcb8dSdrh "HANDLE FILENAME ?MODE?" 165222fbcb8dSdrh #endif 165322fbcb8dSdrh ); 165475897234Sdrh return TCL_ERROR; 165575897234Sdrh } 165675897234Sdrh zErrMsg = 0; 16574cdc9e84Sdrh p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); 165875897234Sdrh if( p==0 ){ 1659bec3f402Sdrh Tcl_SetResult(interp, "malloc failed", TCL_STATIC); 1660bec3f402Sdrh return TCL_ERROR; 1661bec3f402Sdrh } 1662bec3f402Sdrh memset(p, 0, sizeof(*p)); 166322fbcb8dSdrh zFile = Tcl_GetStringFromObj(objv[2], 0); 16644f057f90Sdanielk1977 sqlite3_open(zFile, &p->db); 166580290863Sdanielk1977 if( SQLITE_OK!=sqlite3_errcode(p->db) ){ 166680290863Sdanielk1977 zErrMsg = strdup(sqlite3_errmsg(p->db)); 166780290863Sdanielk1977 sqlite3_close(p->db); 166880290863Sdanielk1977 p->db = 0; 166980290863Sdanielk1977 } 16702011d5f5Sdrh #ifdef SQLITE_HAS_CODEC 16712011d5f5Sdrh sqlite3_key(p->db, pKey, nKey); 1672eb8ed70dSdrh #endif 1673bec3f402Sdrh if( p->db==0 ){ 167475897234Sdrh Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); 1675bec3f402Sdrh Tcl_Free((char*)p); 167675897234Sdrh free(zErrMsg); 167775897234Sdrh return TCL_ERROR; 167875897234Sdrh } 1679fb7e7651Sdrh p->maxStmt = NUM_PREPARED_STMTS; 168022fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 168122fbcb8dSdrh Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); 1682c22bd47dSdrh 168306b2718aSdrh /* The return value is the value of the sqlite* pointer 168406b2718aSdrh */ 168506b2718aSdrh sprintf(zBuf, "%p", p->db); 16865e5377fbSdrh if( strncmp(zBuf,"0x",2) ){ 16875e5377fbSdrh sprintf(zBuf, "0x%p", p->db); 16885e5377fbSdrh } 168906b2718aSdrh Tcl_AppendResult(interp, zBuf, 0); 169006b2718aSdrh 1691c22bd47dSdrh /* If compiled with SQLITE_TEST turned on, then register the "md5sum" 169206b2718aSdrh ** SQL function. 1693c22bd47dSdrh */ 169428b4e489Sdrh #ifdef SQLITE_TEST 169528b4e489Sdrh { 16969bb575fdSdrh extern void Md5_Register(sqlite3*); 16973b93bc8cSdrh #ifdef SQLITE_MEMDEBUG 169813073931Sdanielk1977 int mallocfail = sqlite3_iMallocFail; 169913073931Sdanielk1977 sqlite3_iMallocFail = 0; 17005b59af85Sdanielk1977 #endif 170128b4e489Sdrh Md5_Register(p->db); 17023b93bc8cSdrh #ifdef SQLITE_MEMDEBUG 170313073931Sdanielk1977 sqlite3_iMallocFail = mallocfail; 17045b59af85Sdanielk1977 #endif 170528b4e489Sdrh } 170628b4e489Sdrh #endif 17077cedc8d4Sdanielk1977 p->interp = interp; 170875897234Sdrh return TCL_OK; 170975897234Sdrh } 171075897234Sdrh 171175897234Sdrh /* 171290ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static 171390ca9753Sdrh ** library. 171490ca9753Sdrh */ 171590ca9753Sdrh #ifndef USE_TCL_STUBS 171690ca9753Sdrh # undef Tcl_InitStubs 171790ca9753Sdrh # define Tcl_InitStubs(a,b,c) 171890ca9753Sdrh #endif 171990ca9753Sdrh 172090ca9753Sdrh /* 172175897234Sdrh ** Initialize this module. 172275897234Sdrh ** 172375897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite". 172475897234Sdrh ** (Hence there is no namespace. There is no point in using a namespace 172575897234Sdrh ** if the extension only supplies one new name!) The "sqlite" command is 172675897234Sdrh ** used to open a new SQLite database. See the DbMain() routine above 172775897234Sdrh ** for additional information. 172875897234Sdrh */ 172938f8271fSdrh int Sqlite3_Init(Tcl_Interp *interp){ 173092febd92Sdrh Tcl_InitStubs(interp, "8.4", 0); 1731ef4ac8f9Sdrh Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); 1732ef4ac8f9Sdrh Tcl_PkgProvide(interp, "sqlite3", "3.0"); 173349766d6cSdrh Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); 173449766d6cSdrh Tcl_PkgProvide(interp, "sqlite", "3.0"); 173590ca9753Sdrh return TCL_OK; 173690ca9753Sdrh } 173749766d6cSdrh int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 173849766d6cSdrh int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 173949766d6cSdrh int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 174049766d6cSdrh 174149766d6cSdrh #ifndef SQLITE_3_SUFFIX_ONLY 174249766d6cSdrh int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 174349766d6cSdrh int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 174449766d6cSdrh int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 174549766d6cSdrh int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 174649766d6cSdrh #endif 174775897234Sdrh 17483e27c026Sdrh #ifdef TCLSH 17493e27c026Sdrh /***************************************************************************** 17503e27c026Sdrh ** The code that follows is used to build standalone TCL interpreters 175175897234Sdrh */ 1752348784efSdrh 1753348784efSdrh /* 17543e27c026Sdrh ** If the macro TCLSH is one, then put in code this for the 17553e27c026Sdrh ** "main" routine that will initialize Tcl and take input from 17563e27c026Sdrh ** standard input. 1757348784efSdrh */ 17583e27c026Sdrh #if TCLSH==1 1759348784efSdrh static char zMainloop[] = 1760348784efSdrh "set line {}\n" 1761348784efSdrh "while {![eof stdin]} {\n" 1762348784efSdrh "if {$line!=\"\"} {\n" 1763348784efSdrh "puts -nonewline \"> \"\n" 1764348784efSdrh "} else {\n" 1765348784efSdrh "puts -nonewline \"% \"\n" 1766348784efSdrh "}\n" 1767348784efSdrh "flush stdout\n" 1768348784efSdrh "append line [gets stdin]\n" 1769348784efSdrh "if {[info complete $line]} {\n" 1770348784efSdrh "if {[catch {uplevel #0 $line} result]} {\n" 1771348784efSdrh "puts stderr \"Error: $result\"\n" 1772348784efSdrh "} elseif {$result!=\"\"} {\n" 1773348784efSdrh "puts $result\n" 1774348784efSdrh "}\n" 1775348784efSdrh "set line {}\n" 1776348784efSdrh "} else {\n" 1777348784efSdrh "append line \\n\n" 1778348784efSdrh "}\n" 1779348784efSdrh "}\n" 1780348784efSdrh ; 17813e27c026Sdrh #endif 17823e27c026Sdrh 17833e27c026Sdrh /* 17843e27c026Sdrh ** If the macro TCLSH is two, then get the main loop code out of 17853e27c026Sdrh ** the separate file "spaceanal_tcl.h". 17863e27c026Sdrh */ 17873e27c026Sdrh #if TCLSH==2 17883e27c026Sdrh static char zMainloop[] = 17893e27c026Sdrh #include "spaceanal_tcl.h" 17903e27c026Sdrh ; 17913e27c026Sdrh #endif 1792348784efSdrh 1793348784efSdrh #define TCLSH_MAIN main /* Needed to fake out mktclapp */ 1794348784efSdrh int TCLSH_MAIN(int argc, char **argv){ 1795348784efSdrh Tcl_Interp *interp; 1796297ecf14Sdrh Tcl_FindExecutable(argv[0]); 1797348784efSdrh interp = Tcl_CreateInterp(); 179838f8271fSdrh Sqlite3_Init(interp); 1799d9b0257aSdrh #ifdef SQLITE_TEST 1800d1bf3512Sdrh { 1801d1bf3512Sdrh extern int Sqlitetest1_Init(Tcl_Interp*); 18025c4d9703Sdrh extern int Sqlitetest2_Init(Tcl_Interp*); 18035c4d9703Sdrh extern int Sqlitetest3_Init(Tcl_Interp*); 1804a6064dcfSdrh extern int Sqlitetest4_Init(Tcl_Interp*); 1805998b56c3Sdanielk1977 extern int Sqlitetest5_Init(Tcl_Interp*); 1806efc251daSdrh extern int Md5_Init(Tcl_Interp*); 18072e66f0b9Sdrh extern int Sqlitetestsse_Init(Tcl_Interp*); 18082e66f0b9Sdrh 18096490bebdSdanielk1977 Sqlitetest1_Init(interp); 18105c4d9703Sdrh Sqlitetest2_Init(interp); 1811de647130Sdrh Sqlitetest3_Init(interp); 1812fc57d7bfSdanielk1977 Sqlitetest4_Init(interp); 1813998b56c3Sdanielk1977 Sqlitetest5_Init(interp); 1814efc251daSdrh Md5_Init(interp); 181589dec819Sdrh #ifdef SQLITE_SSE 18162e66f0b9Sdrh Sqlitetestsse_Init(interp); 18172e66f0b9Sdrh #endif 1818d1bf3512Sdrh } 1819d1bf3512Sdrh #endif 18203e27c026Sdrh if( argc>=2 || TCLSH==2 ){ 1821348784efSdrh int i; 1822348784efSdrh Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY); 1823348784efSdrh Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); 182461212b69Sdrh for(i=3-TCLSH; i<argc; i++){ 1825348784efSdrh Tcl_SetVar(interp, "argv", argv[i], 1826348784efSdrh TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); 1827348784efSdrh } 18283e27c026Sdrh if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){ 18290de8c112Sdrh const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); 1830c61053b7Sdrh if( zInfo==0 ) zInfo = interp->result; 1831c61053b7Sdrh fprintf(stderr,"%s: %s\n", *argv, zInfo); 1832348784efSdrh return 1; 1833348784efSdrh } 18343e27c026Sdrh } 18353e27c026Sdrh if( argc<=1 || TCLSH==2 ){ 1836348784efSdrh Tcl_GlobalEval(interp, zMainloop); 1837348784efSdrh } 1838348784efSdrh return 0; 1839348784efSdrh } 1840348784efSdrh #endif /* TCLSH */ 18416d31316cSdrh 18426d31316cSdrh #endif /* !defined(NO_TCL) */ 1843