Annotation of embedaddon/sqlite3/src/tclsqlite.c, revision 1.1
1.1 ! misho 1: /*
! 2: ** 2001 September 15
! 3: **
! 4: ** The author disclaims copyright to this source code. In place of
! 5: ** a legal notice, here is a blessing:
! 6: **
! 7: ** May you do good and not evil.
! 8: ** May you find forgiveness for yourself and forgive others.
! 9: ** May you share freely, never taking more than you give.
! 10: **
! 11: *************************************************************************
! 12: ** A TCL Interface to SQLite. Append this file to sqlite3.c and
! 13: ** compile the whole thing to build a TCL-enabled version of SQLite.
! 14: **
! 15: ** Compile-time options:
! 16: **
! 17: ** -DTCLSH=1 Add a "main()" routine that works as a tclsh.
! 18: **
! 19: ** -DSQLITE_TCLMD5 When used in conjuction with -DTCLSH=1, add
! 20: ** four new commands to the TCL interpreter for
! 21: ** generating MD5 checksums: md5, md5file,
! 22: ** md5-10x8, and md5file-10x8.
! 23: **
! 24: ** -DSQLITE_TEST When used in conjuction with -DTCLSH=1, add
! 25: ** hundreds of new commands used for testing
! 26: ** SQLite. This option implies -DSQLITE_TCLMD5.
! 27: */
! 28: #include "tcl.h"
! 29: #include <errno.h>
! 30:
! 31: /*
! 32: ** Some additional include files are needed if this file is not
! 33: ** appended to the amalgamation.
! 34: */
! 35: #ifndef SQLITE_AMALGAMATION
! 36: # include "sqlite3.h"
! 37: # include <stdlib.h>
! 38: # include <string.h>
! 39: # include <assert.h>
! 40: typedef unsigned char u8;
! 41: #endif
! 42: #include <ctype.h>
! 43:
! 44: /*
! 45: * Windows needs to know which symbols to export. Unix does not.
! 46: * BUILD_sqlite should be undefined for Unix.
! 47: */
! 48: #ifdef BUILD_sqlite
! 49: #undef TCL_STORAGE_CLASS
! 50: #define TCL_STORAGE_CLASS DLLEXPORT
! 51: #endif /* BUILD_sqlite */
! 52:
! 53: #define NUM_PREPARED_STMTS 10
! 54: #define MAX_PREPARED_STMTS 100
! 55:
! 56: /*
! 57: ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we
! 58: ** have to do a translation when going between the two. Set the
! 59: ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do
! 60: ** this translation.
! 61: */
! 62: #if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8)
! 63: # define UTF_TRANSLATION_NEEDED 1
! 64: #endif
! 65:
! 66: /*
! 67: ** New SQL functions can be created as TCL scripts. Each such function
! 68: ** is described by an instance of the following structure.
! 69: */
! 70: typedef struct SqlFunc SqlFunc;
! 71: struct SqlFunc {
! 72: Tcl_Interp *interp; /* The TCL interpret to execute the function */
! 73: Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */
! 74: int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */
! 75: char *zName; /* Name of this function */
! 76: SqlFunc *pNext; /* Next function on the list of them all */
! 77: };
! 78:
! 79: /*
! 80: ** New collation sequences function can be created as TCL scripts. Each such
! 81: ** function is described by an instance of the following structure.
! 82: */
! 83: typedef struct SqlCollate SqlCollate;
! 84: struct SqlCollate {
! 85: Tcl_Interp *interp; /* The TCL interpret to execute the function */
! 86: char *zScript; /* The script to be run */
! 87: SqlCollate *pNext; /* Next function on the list of them all */
! 88: };
! 89:
! 90: /*
! 91: ** Prepared statements are cached for faster execution. Each prepared
! 92: ** statement is described by an instance of the following structure.
! 93: */
! 94: typedef struct SqlPreparedStmt SqlPreparedStmt;
! 95: struct SqlPreparedStmt {
! 96: SqlPreparedStmt *pNext; /* Next in linked list */
! 97: SqlPreparedStmt *pPrev; /* Previous on the list */
! 98: sqlite3_stmt *pStmt; /* The prepared statement */
! 99: int nSql; /* chars in zSql[] */
! 100: const char *zSql; /* Text of the SQL statement */
! 101: int nParm; /* Size of apParm array */
! 102: Tcl_Obj **apParm; /* Array of referenced object pointers */
! 103: };
! 104:
! 105: typedef struct IncrblobChannel IncrblobChannel;
! 106:
! 107: /*
! 108: ** There is one instance of this structure for each SQLite database
! 109: ** that has been opened by the SQLite TCL interface.
! 110: **
! 111: ** If this module is built with SQLITE_TEST defined (to create the SQLite
! 112: ** testfixture executable), then it may be configured to use either
! 113: ** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements.
! 114: ** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used.
! 115: */
! 116: typedef struct SqliteDb SqliteDb;
! 117: struct SqliteDb {
! 118: sqlite3 *db; /* The "real" database structure. MUST BE FIRST */
! 119: Tcl_Interp *interp; /* The interpreter used for this database */
! 120: char *zBusy; /* The busy callback routine */
! 121: char *zCommit; /* The commit hook callback routine */
! 122: char *zTrace; /* The trace callback routine */
! 123: char *zProfile; /* The profile callback routine */
! 124: char *zProgress; /* The progress callback routine */
! 125: char *zAuth; /* The authorization callback routine */
! 126: int disableAuth; /* Disable the authorizer if it exists */
! 127: char *zNull; /* Text to substitute for an SQL NULL value */
! 128: SqlFunc *pFunc; /* List of SQL functions */
! 129: Tcl_Obj *pUpdateHook; /* Update hook script (if any) */
! 130: Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */
! 131: Tcl_Obj *pWalHook; /* WAL hook script (if any) */
! 132: Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */
! 133: SqlCollate *pCollate; /* List of SQL collation functions */
! 134: int rc; /* Return code of most recent sqlite3_exec() */
! 135: Tcl_Obj *pCollateNeeded; /* Collation needed script */
! 136: SqlPreparedStmt *stmtList; /* List of prepared statements*/
! 137: SqlPreparedStmt *stmtLast; /* Last statement in the list */
! 138: int maxStmt; /* The next maximum number of stmtList */
! 139: int nStmt; /* Number of statements in stmtList */
! 140: IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */
! 141: int nStep, nSort, nIndex; /* Statistics for most recent operation */
! 142: int nTransaction; /* Number of nested [transaction] methods */
! 143: #ifdef SQLITE_TEST
! 144: int bLegacyPrepare; /* True to use sqlite3_prepare() */
! 145: #endif
! 146: };
! 147:
! 148: struct IncrblobChannel {
! 149: sqlite3_blob *pBlob; /* sqlite3 blob handle */
! 150: SqliteDb *pDb; /* Associated database connection */
! 151: int iSeek; /* Current seek offset */
! 152: Tcl_Channel channel; /* Channel identifier */
! 153: IncrblobChannel *pNext; /* Linked list of all open incrblob channels */
! 154: IncrblobChannel *pPrev; /* Linked list of all open incrblob channels */
! 155: };
! 156:
! 157: /*
! 158: ** Compute a string length that is limited to what can be stored in
! 159: ** lower 30 bits of a 32-bit signed integer.
! 160: */
! 161: static int strlen30(const char *z){
! 162: const char *z2 = z;
! 163: while( *z2 ){ z2++; }
! 164: return 0x3fffffff & (int)(z2 - z);
! 165: }
! 166:
! 167:
! 168: #ifndef SQLITE_OMIT_INCRBLOB
! 169: /*
! 170: ** Close all incrblob channels opened using database connection pDb.
! 171: ** This is called when shutting down the database connection.
! 172: */
! 173: static void closeIncrblobChannels(SqliteDb *pDb){
! 174: IncrblobChannel *p;
! 175: IncrblobChannel *pNext;
! 176:
! 177: for(p=pDb->pIncrblob; p; p=pNext){
! 178: pNext = p->pNext;
! 179:
! 180: /* Note: Calling unregister here call Tcl_Close on the incrblob channel,
! 181: ** which deletes the IncrblobChannel structure at *p. So do not
! 182: ** call Tcl_Free() here.
! 183: */
! 184: Tcl_UnregisterChannel(pDb->interp, p->channel);
! 185: }
! 186: }
! 187:
! 188: /*
! 189: ** Close an incremental blob channel.
! 190: */
! 191: static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){
! 192: IncrblobChannel *p = (IncrblobChannel *)instanceData;
! 193: int rc = sqlite3_blob_close(p->pBlob);
! 194: sqlite3 *db = p->pDb->db;
! 195:
! 196: /* Remove the channel from the SqliteDb.pIncrblob list. */
! 197: if( p->pNext ){
! 198: p->pNext->pPrev = p->pPrev;
! 199: }
! 200: if( p->pPrev ){
! 201: p->pPrev->pNext = p->pNext;
! 202: }
! 203: if( p->pDb->pIncrblob==p ){
! 204: p->pDb->pIncrblob = p->pNext;
! 205: }
! 206:
! 207: /* Free the IncrblobChannel structure */
! 208: Tcl_Free((char *)p);
! 209:
! 210: if( rc!=SQLITE_OK ){
! 211: Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);
! 212: return TCL_ERROR;
! 213: }
! 214: return TCL_OK;
! 215: }
! 216:
! 217: /*
! 218: ** Read data from an incremental blob channel.
! 219: */
! 220: static int incrblobInput(
! 221: ClientData instanceData,
! 222: char *buf,
! 223: int bufSize,
! 224: int *errorCodePtr
! 225: ){
! 226: IncrblobChannel *p = (IncrblobChannel *)instanceData;
! 227: int nRead = bufSize; /* Number of bytes to read */
! 228: int nBlob; /* Total size of the blob */
! 229: int rc; /* sqlite error code */
! 230:
! 231: nBlob = sqlite3_blob_bytes(p->pBlob);
! 232: if( (p->iSeek+nRead)>nBlob ){
! 233: nRead = nBlob-p->iSeek;
! 234: }
! 235: if( nRead<=0 ){
! 236: return 0;
! 237: }
! 238:
! 239: rc = sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek);
! 240: if( rc!=SQLITE_OK ){
! 241: *errorCodePtr = rc;
! 242: return -1;
! 243: }
! 244:
! 245: p->iSeek += nRead;
! 246: return nRead;
! 247: }
! 248:
! 249: /*
! 250: ** Write data to an incremental blob channel.
! 251: */
! 252: static int incrblobOutput(
! 253: ClientData instanceData,
! 254: CONST char *buf,
! 255: int toWrite,
! 256: int *errorCodePtr
! 257: ){
! 258: IncrblobChannel *p = (IncrblobChannel *)instanceData;
! 259: int nWrite = toWrite; /* Number of bytes to write */
! 260: int nBlob; /* Total size of the blob */
! 261: int rc; /* sqlite error code */
! 262:
! 263: nBlob = sqlite3_blob_bytes(p->pBlob);
! 264: if( (p->iSeek+nWrite)>nBlob ){
! 265: *errorCodePtr = EINVAL;
! 266: return -1;
! 267: }
! 268: if( nWrite<=0 ){
! 269: return 0;
! 270: }
! 271:
! 272: rc = sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek);
! 273: if( rc!=SQLITE_OK ){
! 274: *errorCodePtr = EIO;
! 275: return -1;
! 276: }
! 277:
! 278: p->iSeek += nWrite;
! 279: return nWrite;
! 280: }
! 281:
! 282: /*
! 283: ** Seek an incremental blob channel.
! 284: */
! 285: static int incrblobSeek(
! 286: ClientData instanceData,
! 287: long offset,
! 288: int seekMode,
! 289: int *errorCodePtr
! 290: ){
! 291: IncrblobChannel *p = (IncrblobChannel *)instanceData;
! 292:
! 293: switch( seekMode ){
! 294: case SEEK_SET:
! 295: p->iSeek = offset;
! 296: break;
! 297: case SEEK_CUR:
! 298: p->iSeek += offset;
! 299: break;
! 300: case SEEK_END:
! 301: p->iSeek = sqlite3_blob_bytes(p->pBlob) + offset;
! 302: break;
! 303:
! 304: default: assert(!"Bad seekMode");
! 305: }
! 306:
! 307: return p->iSeek;
! 308: }
! 309:
! 310:
! 311: static void incrblobWatch(ClientData instanceData, int mode){
! 312: /* NO-OP */
! 313: }
! 314: static int incrblobHandle(ClientData instanceData, int dir, ClientData *hPtr){
! 315: return TCL_ERROR;
! 316: }
! 317:
! 318: static Tcl_ChannelType IncrblobChannelType = {
! 319: "incrblob", /* typeName */
! 320: TCL_CHANNEL_VERSION_2, /* version */
! 321: incrblobClose, /* closeProc */
! 322: incrblobInput, /* inputProc */
! 323: incrblobOutput, /* outputProc */
! 324: incrblobSeek, /* seekProc */
! 325: 0, /* setOptionProc */
! 326: 0, /* getOptionProc */
! 327: incrblobWatch, /* watchProc (this is a no-op) */
! 328: incrblobHandle, /* getHandleProc (always returns error) */
! 329: 0, /* close2Proc */
! 330: 0, /* blockModeProc */
! 331: 0, /* flushProc */
! 332: 0, /* handlerProc */
! 333: 0, /* wideSeekProc */
! 334: };
! 335:
! 336: /*
! 337: ** Create a new incrblob channel.
! 338: */
! 339: static int createIncrblobChannel(
! 340: Tcl_Interp *interp,
! 341: SqliteDb *pDb,
! 342: const char *zDb,
! 343: const char *zTable,
! 344: const char *zColumn,
! 345: sqlite_int64 iRow,
! 346: int isReadonly
! 347: ){
! 348: IncrblobChannel *p;
! 349: sqlite3 *db = pDb->db;
! 350: sqlite3_blob *pBlob;
! 351: int rc;
! 352: int flags = TCL_READABLE|(isReadonly ? 0 : TCL_WRITABLE);
! 353:
! 354: /* This variable is used to name the channels: "incrblob_[incr count]" */
! 355: static int count = 0;
! 356: char zChannel[64];
! 357:
! 358: rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob);
! 359: if( rc!=SQLITE_OK ){
! 360: Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
! 361: return TCL_ERROR;
! 362: }
! 363:
! 364: p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel));
! 365: p->iSeek = 0;
! 366: p->pBlob = pBlob;
! 367:
! 368: sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count);
! 369: p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags);
! 370: Tcl_RegisterChannel(interp, p->channel);
! 371:
! 372: /* Link the new channel into the SqliteDb.pIncrblob list. */
! 373: p->pNext = pDb->pIncrblob;
! 374: p->pPrev = 0;
! 375: if( p->pNext ){
! 376: p->pNext->pPrev = p;
! 377: }
! 378: pDb->pIncrblob = p;
! 379: p->pDb = pDb;
! 380:
! 381: Tcl_SetResult(interp, (char *)Tcl_GetChannelName(p->channel), TCL_VOLATILE);
! 382: return TCL_OK;
! 383: }
! 384: #else /* else clause for "#ifndef SQLITE_OMIT_INCRBLOB" */
! 385: #define closeIncrblobChannels(pDb)
! 386: #endif
! 387:
! 388: /*
! 389: ** Look at the script prefix in pCmd. We will be executing this script
! 390: ** after first appending one or more arguments. This routine analyzes
! 391: ** the script to see if it is safe to use Tcl_EvalObjv() on the script
! 392: ** rather than the more general Tcl_EvalEx(). Tcl_EvalObjv() is much
! 393: ** faster.
! 394: **
! 395: ** Scripts that are safe to use with Tcl_EvalObjv() consists of a
! 396: ** command name followed by zero or more arguments with no [...] or $
! 397: ** or {...} or ; to be seen anywhere. Most callback scripts consist
! 398: ** of just a single procedure name and they meet this requirement.
! 399: */
! 400: static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){
! 401: /* We could try to do something with Tcl_Parse(). But we will instead
! 402: ** just do a search for forbidden characters. If any of the forbidden
! 403: ** characters appear in pCmd, we will report the string as unsafe.
! 404: */
! 405: const char *z;
! 406: int n;
! 407: z = Tcl_GetStringFromObj(pCmd, &n);
! 408: while( n-- > 0 ){
! 409: int c = *(z++);
! 410: if( c=='$' || c=='[' || c==';' ) return 0;
! 411: }
! 412: return 1;
! 413: }
! 414:
! 415: /*
! 416: ** Find an SqlFunc structure with the given name. Or create a new
! 417: ** one if an existing one cannot be found. Return a pointer to the
! 418: ** structure.
! 419: */
! 420: static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){
! 421: SqlFunc *p, *pNew;
! 422: int i;
! 423: pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + strlen30(zName) + 1 );
! 424: pNew->zName = (char*)&pNew[1];
! 425: for(i=0; zName[i]; i++){ pNew->zName[i] = tolower(zName[i]); }
! 426: pNew->zName[i] = 0;
! 427: for(p=pDb->pFunc; p; p=p->pNext){
! 428: if( strcmp(p->zName, pNew->zName)==0 ){
! 429: Tcl_Free((char*)pNew);
! 430: return p;
! 431: }
! 432: }
! 433: pNew->interp = pDb->interp;
! 434: pNew->pScript = 0;
! 435: pNew->pNext = pDb->pFunc;
! 436: pDb->pFunc = pNew;
! 437: return pNew;
! 438: }
! 439:
! 440: /*
! 441: ** Free a single SqlPreparedStmt object.
! 442: */
! 443: static void dbFreeStmt(SqlPreparedStmt *pStmt){
! 444: #ifdef SQLITE_TEST
! 445: if( sqlite3_sql(pStmt->pStmt)==0 ){
! 446: Tcl_Free((char *)pStmt->zSql);
! 447: }
! 448: #endif
! 449: sqlite3_finalize(pStmt->pStmt);
! 450: Tcl_Free((char *)pStmt);
! 451: }
! 452:
! 453: /*
! 454: ** Finalize and free a list of prepared statements
! 455: */
! 456: static void flushStmtCache(SqliteDb *pDb){
! 457: SqlPreparedStmt *pPreStmt;
! 458: SqlPreparedStmt *pNext;
! 459:
! 460: for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pNext){
! 461: pNext = pPreStmt->pNext;
! 462: dbFreeStmt(pPreStmt);
! 463: }
! 464: pDb->nStmt = 0;
! 465: pDb->stmtLast = 0;
! 466: pDb->stmtList = 0;
! 467: }
! 468:
! 469: /*
! 470: ** TCL calls this procedure when an sqlite3 database command is
! 471: ** deleted.
! 472: */
! 473: static void DbDeleteCmd(void *db){
! 474: SqliteDb *pDb = (SqliteDb*)db;
! 475: flushStmtCache(pDb);
! 476: closeIncrblobChannels(pDb);
! 477: sqlite3_close(pDb->db);
! 478: while( pDb->pFunc ){
! 479: SqlFunc *pFunc = pDb->pFunc;
! 480: pDb->pFunc = pFunc->pNext;
! 481: Tcl_DecrRefCount(pFunc->pScript);
! 482: Tcl_Free((char*)pFunc);
! 483: }
! 484: while( pDb->pCollate ){
! 485: SqlCollate *pCollate = pDb->pCollate;
! 486: pDb->pCollate = pCollate->pNext;
! 487: Tcl_Free((char*)pCollate);
! 488: }
! 489: if( pDb->zBusy ){
! 490: Tcl_Free(pDb->zBusy);
! 491: }
! 492: if( pDb->zTrace ){
! 493: Tcl_Free(pDb->zTrace);
! 494: }
! 495: if( pDb->zProfile ){
! 496: Tcl_Free(pDb->zProfile);
! 497: }
! 498: if( pDb->zAuth ){
! 499: Tcl_Free(pDb->zAuth);
! 500: }
! 501: if( pDb->zNull ){
! 502: Tcl_Free(pDb->zNull);
! 503: }
! 504: if( pDb->pUpdateHook ){
! 505: Tcl_DecrRefCount(pDb->pUpdateHook);
! 506: }
! 507: if( pDb->pRollbackHook ){
! 508: Tcl_DecrRefCount(pDb->pRollbackHook);
! 509: }
! 510: if( pDb->pWalHook ){
! 511: Tcl_DecrRefCount(pDb->pWalHook);
! 512: }
! 513: if( pDb->pCollateNeeded ){
! 514: Tcl_DecrRefCount(pDb->pCollateNeeded);
! 515: }
! 516: Tcl_Free((char*)pDb);
! 517: }
! 518:
! 519: /*
! 520: ** This routine is called when a database file is locked while trying
! 521: ** to execute SQL.
! 522: */
! 523: static int DbBusyHandler(void *cd, int nTries){
! 524: SqliteDb *pDb = (SqliteDb*)cd;
! 525: int rc;
! 526: char zVal[30];
! 527:
! 528: sqlite3_snprintf(sizeof(zVal), zVal, "%d", nTries);
! 529: rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0);
! 530: if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
! 531: return 0;
! 532: }
! 533: return 1;
! 534: }
! 535:
! 536: #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
! 537: /*
! 538: ** This routine is invoked as the 'progress callback' for the database.
! 539: */
! 540: static int DbProgressHandler(void *cd){
! 541: SqliteDb *pDb = (SqliteDb*)cd;
! 542: int rc;
! 543:
! 544: assert( pDb->zProgress );
! 545: rc = Tcl_Eval(pDb->interp, pDb->zProgress);
! 546: if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
! 547: return 1;
! 548: }
! 549: return 0;
! 550: }
! 551: #endif
! 552:
! 553: #ifndef SQLITE_OMIT_TRACE
! 554: /*
! 555: ** This routine is called by the SQLite trace handler whenever a new
! 556: ** block of SQL is executed. The TCL script in pDb->zTrace is executed.
! 557: */
! 558: static void DbTraceHandler(void *cd, const char *zSql){
! 559: SqliteDb *pDb = (SqliteDb*)cd;
! 560: Tcl_DString str;
! 561:
! 562: Tcl_DStringInit(&str);
! 563: Tcl_DStringAppend(&str, pDb->zTrace, -1);
! 564: Tcl_DStringAppendElement(&str, zSql);
! 565: Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
! 566: Tcl_DStringFree(&str);
! 567: Tcl_ResetResult(pDb->interp);
! 568: }
! 569: #endif
! 570:
! 571: #ifndef SQLITE_OMIT_TRACE
! 572: /*
! 573: ** This routine is called by the SQLite profile handler after a statement
! 574: ** SQL has executed. The TCL script in pDb->zProfile is evaluated.
! 575: */
! 576: static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){
! 577: SqliteDb *pDb = (SqliteDb*)cd;
! 578: Tcl_DString str;
! 579: char zTm[100];
! 580:
! 581: sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm);
! 582: Tcl_DStringInit(&str);
! 583: Tcl_DStringAppend(&str, pDb->zProfile, -1);
! 584: Tcl_DStringAppendElement(&str, zSql);
! 585: Tcl_DStringAppendElement(&str, zTm);
! 586: Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
! 587: Tcl_DStringFree(&str);
! 588: Tcl_ResetResult(pDb->interp);
! 589: }
! 590: #endif
! 591:
! 592: /*
! 593: ** This routine is called when a transaction is committed. The
! 594: ** TCL script in pDb->zCommit is executed. If it returns non-zero or
! 595: ** if it throws an exception, the transaction is rolled back instead
! 596: ** of being committed.
! 597: */
! 598: static int DbCommitHandler(void *cd){
! 599: SqliteDb *pDb = (SqliteDb*)cd;
! 600: int rc;
! 601:
! 602: rc = Tcl_Eval(pDb->interp, pDb->zCommit);
! 603: if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
! 604: return 1;
! 605: }
! 606: return 0;
! 607: }
! 608:
! 609: static void DbRollbackHandler(void *clientData){
! 610: SqliteDb *pDb = (SqliteDb*)clientData;
! 611: assert(pDb->pRollbackHook);
! 612: if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){
! 613: Tcl_BackgroundError(pDb->interp);
! 614: }
! 615: }
! 616:
! 617: /*
! 618: ** This procedure handles wal_hook callbacks.
! 619: */
! 620: static int DbWalHandler(
! 621: void *clientData,
! 622: sqlite3 *db,
! 623: const char *zDb,
! 624: int nEntry
! 625: ){
! 626: int ret = SQLITE_OK;
! 627: Tcl_Obj *p;
! 628: SqliteDb *pDb = (SqliteDb*)clientData;
! 629: Tcl_Interp *interp = pDb->interp;
! 630: assert(pDb->pWalHook);
! 631:
! 632: p = Tcl_DuplicateObj(pDb->pWalHook);
! 633: Tcl_IncrRefCount(p);
! 634: Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));
! 635: Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));
! 636: if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
! 637: || TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)
! 638: ){
! 639: Tcl_BackgroundError(interp);
! 640: }
! 641: Tcl_DecrRefCount(p);
! 642:
! 643: return ret;
! 644: }
! 645:
! 646: #if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
! 647: static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){
! 648: char zBuf[64];
! 649: sprintf(zBuf, "%d", iArg);
! 650: Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY);
! 651: sprintf(zBuf, "%d", nArg);
! 652: Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY);
! 653: }
! 654: #else
! 655: # define setTestUnlockNotifyVars(x,y,z)
! 656: #endif
! 657:
! 658: #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
! 659: static void DbUnlockNotify(void **apArg, int nArg){
! 660: int i;
! 661: for(i=0; i<nArg; i++){
! 662: const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
! 663: SqliteDb *pDb = (SqliteDb *)apArg[i];
! 664: setTestUnlockNotifyVars(pDb->interp, i, nArg);
! 665: assert( pDb->pUnlockNotify);
! 666: Tcl_EvalObjEx(pDb->interp, pDb->pUnlockNotify, flags);
! 667: Tcl_DecrRefCount(pDb->pUnlockNotify);
! 668: pDb->pUnlockNotify = 0;
! 669: }
! 670: }
! 671: #endif
! 672:
! 673: static void DbUpdateHandler(
! 674: void *p,
! 675: int op,
! 676: const char *zDb,
! 677: const char *zTbl,
! 678: sqlite_int64 rowid
! 679: ){
! 680: SqliteDb *pDb = (SqliteDb *)p;
! 681: Tcl_Obj *pCmd;
! 682:
! 683: assert( pDb->pUpdateHook );
! 684: assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
! 685:
! 686: pCmd = Tcl_DuplicateObj(pDb->pUpdateHook);
! 687: Tcl_IncrRefCount(pCmd);
! 688: Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(
! 689: ( (op==SQLITE_INSERT)?"INSERT":(op==SQLITE_UPDATE)?"UPDATE":"DELETE"), -1));
! 690: Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1));
! 691: Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1));
! 692: Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid));
! 693: Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
! 694: Tcl_DecrRefCount(pCmd);
! 695: }
! 696:
! 697: static void tclCollateNeeded(
! 698: void *pCtx,
! 699: sqlite3 *db,
! 700: int enc,
! 701: const char *zName
! 702: ){
! 703: SqliteDb *pDb = (SqliteDb *)pCtx;
! 704: Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded);
! 705: Tcl_IncrRefCount(pScript);
! 706: Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1));
! 707: Tcl_EvalObjEx(pDb->interp, pScript, 0);
! 708: Tcl_DecrRefCount(pScript);
! 709: }
! 710:
! 711: /*
! 712: ** This routine is called to evaluate an SQL collation function implemented
! 713: ** using TCL script.
! 714: */
! 715: static int tclSqlCollate(
! 716: void *pCtx,
! 717: int nA,
! 718: const void *zA,
! 719: int nB,
! 720: const void *zB
! 721: ){
! 722: SqlCollate *p = (SqlCollate *)pCtx;
! 723: Tcl_Obj *pCmd;
! 724:
! 725: pCmd = Tcl_NewStringObj(p->zScript, -1);
! 726: Tcl_IncrRefCount(pCmd);
! 727: Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA));
! 728: Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB));
! 729: Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT);
! 730: Tcl_DecrRefCount(pCmd);
! 731: return (atoi(Tcl_GetStringResult(p->interp)));
! 732: }
! 733:
! 734: /*
! 735: ** This routine is called to evaluate an SQL function implemented
! 736: ** using TCL script.
! 737: */
! 738: static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
! 739: SqlFunc *p = sqlite3_user_data(context);
! 740: Tcl_Obj *pCmd;
! 741: int i;
! 742: int rc;
! 743:
! 744: if( argc==0 ){
! 745: /* If there are no arguments to the function, call Tcl_EvalObjEx on the
! 746: ** script object directly. This allows the TCL compiler to generate
! 747: ** bytecode for the command on the first invocation and thus make
! 748: ** subsequent invocations much faster. */
! 749: pCmd = p->pScript;
! 750: Tcl_IncrRefCount(pCmd);
! 751: rc = Tcl_EvalObjEx(p->interp, pCmd, 0);
! 752: Tcl_DecrRefCount(pCmd);
! 753: }else{
! 754: /* If there are arguments to the function, make a shallow copy of the
! 755: ** script object, lappend the arguments, then evaluate the copy.
! 756: **
! 757: ** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated.
! 758: ** The new Tcl_Obj contains pointers to the original list elements.
! 759: ** That way, when Tcl_EvalObjv() is run and shimmers the first element
! 760: ** of the list to tclCmdNameType, that alternate representation will
! 761: ** be preserved and reused on the next invocation.
! 762: */
! 763: Tcl_Obj **aArg;
! 764: int nArg;
! 765: if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
! 766: sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
! 767: return;
! 768: }
! 769: pCmd = Tcl_NewListObj(nArg, aArg);
! 770: Tcl_IncrRefCount(pCmd);
! 771: for(i=0; i<argc; i++){
! 772: sqlite3_value *pIn = argv[i];
! 773: Tcl_Obj *pVal;
! 774:
! 775: /* Set pVal to contain the i'th column of this row. */
! 776: switch( sqlite3_value_type(pIn) ){
! 777: case SQLITE_BLOB: {
! 778: int bytes = sqlite3_value_bytes(pIn);
! 779: pVal = Tcl_NewByteArrayObj(sqlite3_value_blob(pIn), bytes);
! 780: break;
! 781: }
! 782: case SQLITE_INTEGER: {
! 783: sqlite_int64 v = sqlite3_value_int64(pIn);
! 784: if( v>=-2147483647 && v<=2147483647 ){
! 785: pVal = Tcl_NewIntObj((int)v);
! 786: }else{
! 787: pVal = Tcl_NewWideIntObj(v);
! 788: }
! 789: break;
! 790: }
! 791: case SQLITE_FLOAT: {
! 792: double r = sqlite3_value_double(pIn);
! 793: pVal = Tcl_NewDoubleObj(r);
! 794: break;
! 795: }
! 796: case SQLITE_NULL: {
! 797: pVal = Tcl_NewStringObj("", 0);
! 798: break;
! 799: }
! 800: default: {
! 801: int bytes = sqlite3_value_bytes(pIn);
! 802: pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes);
! 803: break;
! 804: }
! 805: }
! 806: rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal);
! 807: if( rc ){
! 808: Tcl_DecrRefCount(pCmd);
! 809: sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
! 810: return;
! 811: }
! 812: }
! 813: if( !p->useEvalObjv ){
! 814: /* Tcl_EvalObjEx() will automatically call Tcl_EvalObjv() if pCmd
! 815: ** is a list without a string representation. To prevent this from
! 816: ** happening, make sure pCmd has a valid string representation */
! 817: Tcl_GetString(pCmd);
! 818: }
! 819: rc = Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT);
! 820: Tcl_DecrRefCount(pCmd);
! 821: }
! 822:
! 823: if( rc && rc!=TCL_RETURN ){
! 824: sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
! 825: }else{
! 826: Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
! 827: int n;
! 828: u8 *data;
! 829: const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
! 830: char c = zType[0];
! 831: if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
! 832: /* Only return a BLOB type if the Tcl variable is a bytearray and
! 833: ** has no string representation. */
! 834: data = Tcl_GetByteArrayFromObj(pVar, &n);
! 835: sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT);
! 836: }else if( c=='b' && strcmp(zType,"boolean")==0 ){
! 837: Tcl_GetIntFromObj(0, pVar, &n);
! 838: sqlite3_result_int(context, n);
! 839: }else if( c=='d' && strcmp(zType,"double")==0 ){
! 840: double r;
! 841: Tcl_GetDoubleFromObj(0, pVar, &r);
! 842: sqlite3_result_double(context, r);
! 843: }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||
! 844: (c=='i' && strcmp(zType,"int")==0) ){
! 845: Tcl_WideInt v;
! 846: Tcl_GetWideIntFromObj(0, pVar, &v);
! 847: sqlite3_result_int64(context, v);
! 848: }else{
! 849: data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
! 850: sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT);
! 851: }
! 852: }
! 853: }
! 854:
! 855: #ifndef SQLITE_OMIT_AUTHORIZATION
! 856: /*
! 857: ** This is the authentication function. It appends the authentication
! 858: ** type code and the two arguments to zCmd[] then invokes the result
! 859: ** on the interpreter. The reply is examined to determine if the
! 860: ** authentication fails or succeeds.
! 861: */
! 862: static int auth_callback(
! 863: void *pArg,
! 864: int code,
! 865: const char *zArg1,
! 866: const char *zArg2,
! 867: const char *zArg3,
! 868: const char *zArg4
! 869: ){
! 870: char *zCode;
! 871: Tcl_DString str;
! 872: int rc;
! 873: const char *zReply;
! 874: SqliteDb *pDb = (SqliteDb*)pArg;
! 875: if( pDb->disableAuth ) return SQLITE_OK;
! 876:
! 877: switch( code ){
! 878: case SQLITE_COPY : zCode="SQLITE_COPY"; break;
! 879: case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break;
! 880: case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break;
! 881: case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;
! 882: case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;
! 883: case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;
! 884: case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break;
! 885: case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break;
! 886: case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break;
! 887: case SQLITE_DELETE : zCode="SQLITE_DELETE"; break;
! 888: case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break;
! 889: case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break;
! 890: case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break;
! 891: case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break;
! 892: case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;
! 893: case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break;
! 894: case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break;
! 895: case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break;
! 896: case SQLITE_INSERT : zCode="SQLITE_INSERT"; break;
! 897: case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break;
! 898: case SQLITE_READ : zCode="SQLITE_READ"; break;
! 899: case SQLITE_SELECT : zCode="SQLITE_SELECT"; break;
! 900: case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break;
! 901: case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break;
! 902: case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break;
! 903: case SQLITE_DETACH : zCode="SQLITE_DETACH"; break;
! 904: case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break;
! 905: case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break;
! 906: case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break;
! 907: case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break;
! 908: case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break;
! 909: case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break;
! 910: case SQLITE_SAVEPOINT : zCode="SQLITE_SAVEPOINT"; break;
! 911: default : zCode="????"; break;
! 912: }
! 913: Tcl_DStringInit(&str);
! 914: Tcl_DStringAppend(&str, pDb->zAuth, -1);
! 915: Tcl_DStringAppendElement(&str, zCode);
! 916: Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
! 917: Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
! 918: Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
! 919: Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
! 920: rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
! 921: Tcl_DStringFree(&str);
! 922: zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY";
! 923: if( strcmp(zReply,"SQLITE_OK")==0 ){
! 924: rc = SQLITE_OK;
! 925: }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
! 926: rc = SQLITE_DENY;
! 927: }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
! 928: rc = SQLITE_IGNORE;
! 929: }else{
! 930: rc = 999;
! 931: }
! 932: return rc;
! 933: }
! 934: #endif /* SQLITE_OMIT_AUTHORIZATION */
! 935:
! 936: /*
! 937: ** zText is a pointer to text obtained via an sqlite3_result_text()
! 938: ** or similar interface. This routine returns a Tcl string object,
! 939: ** reference count set to 0, containing the text. If a translation
! 940: ** between iso8859 and UTF-8 is required, it is preformed.
! 941: */
! 942: static Tcl_Obj *dbTextToObj(char const *zText){
! 943: Tcl_Obj *pVal;
! 944: #ifdef UTF_TRANSLATION_NEEDED
! 945: Tcl_DString dCol;
! 946: Tcl_DStringInit(&dCol);
! 947: Tcl_ExternalToUtfDString(NULL, zText, -1, &dCol);
! 948: pVal = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
! 949: Tcl_DStringFree(&dCol);
! 950: #else
! 951: pVal = Tcl_NewStringObj(zText, -1);
! 952: #endif
! 953: return pVal;
! 954: }
! 955:
! 956: /*
! 957: ** This routine reads a line of text from FILE in, stores
! 958: ** the text in memory obtained from malloc() and returns a pointer
! 959: ** to the text. NULL is returned at end of file, or if malloc()
! 960: ** fails.
! 961: **
! 962: ** The interface is like "readline" but no command-line editing
! 963: ** is done.
! 964: **
! 965: ** copied from shell.c from '.import' command
! 966: */
! 967: static char *local_getline(char *zPrompt, FILE *in){
! 968: char *zLine;
! 969: int nLine;
! 970: int n;
! 971:
! 972: nLine = 100;
! 973: zLine = malloc( nLine );
! 974: if( zLine==0 ) return 0;
! 975: n = 0;
! 976: while( 1 ){
! 977: if( n+100>nLine ){
! 978: nLine = nLine*2 + 100;
! 979: zLine = realloc(zLine, nLine);
! 980: if( zLine==0 ) return 0;
! 981: }
! 982: if( fgets(&zLine[n], nLine - n, in)==0 ){
! 983: if( n==0 ){
! 984: free(zLine);
! 985: return 0;
! 986: }
! 987: zLine[n] = 0;
! 988: break;
! 989: }
! 990: while( zLine[n] ){ n++; }
! 991: if( n>0 && zLine[n-1]=='\n' ){
! 992: n--;
! 993: zLine[n] = 0;
! 994: break;
! 995: }
! 996: }
! 997: zLine = realloc( zLine, n+1 );
! 998: return zLine;
! 999: }
! 1000:
! 1001:
! 1002: /*
! 1003: ** This function is part of the implementation of the command:
! 1004: **
! 1005: ** $db transaction [-deferred|-immediate|-exclusive] SCRIPT
! 1006: **
! 1007: ** It is invoked after evaluating the script SCRIPT to commit or rollback
! 1008: ** the transaction or savepoint opened by the [transaction] command.
! 1009: */
! 1010: static int DbTransPostCmd(
! 1011: ClientData data[], /* data[0] is the Sqlite3Db* for $db */
! 1012: Tcl_Interp *interp, /* Tcl interpreter */
! 1013: int result /* Result of evaluating SCRIPT */
! 1014: ){
! 1015: static const char *azEnd[] = {
! 1016: "RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */
! 1017: "COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */
! 1018: "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction",
! 1019: "ROLLBACK" /* rc==TCL_ERROR, nTransaction==0 */
! 1020: };
! 1021: SqliteDb *pDb = (SqliteDb*)data[0];
! 1022: int rc = result;
! 1023: const char *zEnd;
! 1024:
! 1025: pDb->nTransaction--;
! 1026: zEnd = azEnd[(rc==TCL_ERROR)*2 + (pDb->nTransaction==0)];
! 1027:
! 1028: pDb->disableAuth++;
! 1029: if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){
! 1030: /* This is a tricky scenario to handle. The most likely cause of an
! 1031: ** error is that the exec() above was an attempt to commit the
! 1032: ** top-level transaction that returned SQLITE_BUSY. Or, less likely,
! 1033: ** that an IO-error has occured. In either case, throw a Tcl exception
! 1034: ** and try to rollback the transaction.
! 1035: **
! 1036: ** But it could also be that the user executed one or more BEGIN,
! 1037: ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing
! 1038: ** this method's logic. Not clear how this would be best handled.
! 1039: */
! 1040: if( rc!=TCL_ERROR ){
! 1041: Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
! 1042: rc = TCL_ERROR;
! 1043: }
! 1044: sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0);
! 1045: }
! 1046: pDb->disableAuth--;
! 1047:
! 1048: return rc;
! 1049: }
! 1050:
! 1051: /*
! 1052: ** Unless SQLITE_TEST is defined, this function is a simple wrapper around
! 1053: ** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either
! 1054: ** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending
! 1055: ** on whether or not the [db_use_legacy_prepare] command has been used to
! 1056: ** configure the connection.
! 1057: */
! 1058: static int dbPrepare(
! 1059: SqliteDb *pDb, /* Database object */
! 1060: const char *zSql, /* SQL to compile */
! 1061: sqlite3_stmt **ppStmt, /* OUT: Prepared statement */
! 1062: const char **pzOut /* OUT: Pointer to next SQL statement */
! 1063: ){
! 1064: #ifdef SQLITE_TEST
! 1065: if( pDb->bLegacyPrepare ){
! 1066: return sqlite3_prepare(pDb->db, zSql, -1, ppStmt, pzOut);
! 1067: }
! 1068: #endif
! 1069: return sqlite3_prepare_v2(pDb->db, zSql, -1, ppStmt, pzOut);
! 1070: }
! 1071:
! 1072: /*
! 1073: ** Search the cache for a prepared-statement object that implements the
! 1074: ** first SQL statement in the buffer pointed to by parameter zIn. If
! 1075: ** no such prepared-statement can be found, allocate and prepare a new
! 1076: ** one. In either case, bind the current values of the relevant Tcl
! 1077: ** variables to any $var, :var or @var variables in the statement. Before
! 1078: ** returning, set *ppPreStmt to point to the prepared-statement object.
! 1079: **
! 1080: ** Output parameter *pzOut is set to point to the next SQL statement in
! 1081: ** buffer zIn, or to the '\0' byte at the end of zIn if there is no
! 1082: ** next statement.
! 1083: **
! 1084: ** If successful, TCL_OK is returned. Otherwise, TCL_ERROR is returned
! 1085: ** and an error message loaded into interpreter pDb->interp.
! 1086: */
! 1087: static int dbPrepareAndBind(
! 1088: SqliteDb *pDb, /* Database object */
! 1089: char const *zIn, /* SQL to compile */
! 1090: char const **pzOut, /* OUT: Pointer to next SQL statement */
! 1091: SqlPreparedStmt **ppPreStmt /* OUT: Object used to cache statement */
! 1092: ){
! 1093: const char *zSql = zIn; /* Pointer to first SQL statement in zIn */
! 1094: sqlite3_stmt *pStmt; /* Prepared statement object */
! 1095: SqlPreparedStmt *pPreStmt; /* Pointer to cached statement */
! 1096: int nSql; /* Length of zSql in bytes */
! 1097: int nVar; /* Number of variables in statement */
! 1098: int iParm = 0; /* Next free entry in apParm */
! 1099: int i;
! 1100: Tcl_Interp *interp = pDb->interp;
! 1101:
! 1102: *ppPreStmt = 0;
! 1103:
! 1104: /* Trim spaces from the start of zSql and calculate the remaining length. */
! 1105: while( isspace(zSql[0]) ){ zSql++; }
! 1106: nSql = strlen30(zSql);
! 1107:
! 1108: for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){
! 1109: int n = pPreStmt->nSql;
! 1110: if( nSql>=n
! 1111: && memcmp(pPreStmt->zSql, zSql, n)==0
! 1112: && (zSql[n]==0 || zSql[n-1]==';')
! 1113: ){
! 1114: pStmt = pPreStmt->pStmt;
! 1115: *pzOut = &zSql[pPreStmt->nSql];
! 1116:
! 1117: /* When a prepared statement is found, unlink it from the
! 1118: ** cache list. It will later be added back to the beginning
! 1119: ** of the cache list in order to implement LRU replacement.
! 1120: */
! 1121: if( pPreStmt->pPrev ){
! 1122: pPreStmt->pPrev->pNext = pPreStmt->pNext;
! 1123: }else{
! 1124: pDb->stmtList = pPreStmt->pNext;
! 1125: }
! 1126: if( pPreStmt->pNext ){
! 1127: pPreStmt->pNext->pPrev = pPreStmt->pPrev;
! 1128: }else{
! 1129: pDb->stmtLast = pPreStmt->pPrev;
! 1130: }
! 1131: pDb->nStmt--;
! 1132: nVar = sqlite3_bind_parameter_count(pStmt);
! 1133: break;
! 1134: }
! 1135: }
! 1136:
! 1137: /* If no prepared statement was found. Compile the SQL text. Also allocate
! 1138: ** a new SqlPreparedStmt structure. */
! 1139: if( pPreStmt==0 ){
! 1140: int nByte;
! 1141:
! 1142: if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){
! 1143: Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
! 1144: return TCL_ERROR;
! 1145: }
! 1146: if( pStmt==0 ){
! 1147: if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
! 1148: /* A compile-time error in the statement. */
! 1149: Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
! 1150: return TCL_ERROR;
! 1151: }else{
! 1152: /* The statement was a no-op. Continue to the next statement
! 1153: ** in the SQL string.
! 1154: */
! 1155: return TCL_OK;
! 1156: }
! 1157: }
! 1158:
! 1159: assert( pPreStmt==0 );
! 1160: nVar = sqlite3_bind_parameter_count(pStmt);
! 1161: nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj *);
! 1162: pPreStmt = (SqlPreparedStmt*)Tcl_Alloc(nByte);
! 1163: memset(pPreStmt, 0, nByte);
! 1164:
! 1165: pPreStmt->pStmt = pStmt;
! 1166: pPreStmt->nSql = (*pzOut - zSql);
! 1167: pPreStmt->zSql = sqlite3_sql(pStmt);
! 1168: pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1];
! 1169: #ifdef SQLITE_TEST
! 1170: if( pPreStmt->zSql==0 ){
! 1171: char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1);
! 1172: memcpy(zCopy, zSql, pPreStmt->nSql);
! 1173: zCopy[pPreStmt->nSql] = '\0';
! 1174: pPreStmt->zSql = zCopy;
! 1175: }
! 1176: #endif
! 1177: }
! 1178: assert( pPreStmt );
! 1179: assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql );
! 1180: assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) );
! 1181:
! 1182: /* Bind values to parameters that begin with $ or : */
! 1183: for(i=1; i<=nVar; i++){
! 1184: const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
! 1185: if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){
! 1186: Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0);
! 1187: if( pVar ){
! 1188: int n;
! 1189: u8 *data;
! 1190: const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
! 1191: char c = zType[0];
! 1192: if( zVar[0]=='@' ||
! 1193: (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){
! 1194: /* Load a BLOB type if the Tcl variable is a bytearray and
! 1195: ** it has no string representation or the host
! 1196: ** parameter name begins with "@". */
! 1197: data = Tcl_GetByteArrayFromObj(pVar, &n);
! 1198: sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC);
! 1199: Tcl_IncrRefCount(pVar);
! 1200: pPreStmt->apParm[iParm++] = pVar;
! 1201: }else if( c=='b' && strcmp(zType,"boolean")==0 ){
! 1202: Tcl_GetIntFromObj(interp, pVar, &n);
! 1203: sqlite3_bind_int(pStmt, i, n);
! 1204: }else if( c=='d' && strcmp(zType,"double")==0 ){
! 1205: double r;
! 1206: Tcl_GetDoubleFromObj(interp, pVar, &r);
! 1207: sqlite3_bind_double(pStmt, i, r);
! 1208: }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||
! 1209: (c=='i' && strcmp(zType,"int")==0) ){
! 1210: Tcl_WideInt v;
! 1211: Tcl_GetWideIntFromObj(interp, pVar, &v);
! 1212: sqlite3_bind_int64(pStmt, i, v);
! 1213: }else{
! 1214: data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
! 1215: sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC);
! 1216: Tcl_IncrRefCount(pVar);
! 1217: pPreStmt->apParm[iParm++] = pVar;
! 1218: }
! 1219: }else{
! 1220: sqlite3_bind_null(pStmt, i);
! 1221: }
! 1222: }
! 1223: }
! 1224: pPreStmt->nParm = iParm;
! 1225: *ppPreStmt = pPreStmt;
! 1226:
! 1227: return TCL_OK;
! 1228: }
! 1229:
! 1230: /*
! 1231: ** Release a statement reference obtained by calling dbPrepareAndBind().
! 1232: ** There should be exactly one call to this function for each call to
! 1233: ** dbPrepareAndBind().
! 1234: **
! 1235: ** If the discard parameter is non-zero, then the statement is deleted
! 1236: ** immediately. Otherwise it is added to the LRU list and may be returned
! 1237: ** by a subsequent call to dbPrepareAndBind().
! 1238: */
! 1239: static void dbReleaseStmt(
! 1240: SqliteDb *pDb, /* Database handle */
! 1241: SqlPreparedStmt *pPreStmt, /* Prepared statement handle to release */
! 1242: int discard /* True to delete (not cache) the pPreStmt */
! 1243: ){
! 1244: int i;
! 1245:
! 1246: /* Free the bound string and blob parameters */
! 1247: for(i=0; i<pPreStmt->nParm; i++){
! 1248: Tcl_DecrRefCount(pPreStmt->apParm[i]);
! 1249: }
! 1250: pPreStmt->nParm = 0;
! 1251:
! 1252: if( pDb->maxStmt<=0 || discard ){
! 1253: /* If the cache is turned off, deallocated the statement */
! 1254: dbFreeStmt(pPreStmt);
! 1255: }else{
! 1256: /* Add the prepared statement to the beginning of the cache list. */
! 1257: pPreStmt->pNext = pDb->stmtList;
! 1258: pPreStmt->pPrev = 0;
! 1259: if( pDb->stmtList ){
! 1260: pDb->stmtList->pPrev = pPreStmt;
! 1261: }
! 1262: pDb->stmtList = pPreStmt;
! 1263: if( pDb->stmtLast==0 ){
! 1264: assert( pDb->nStmt==0 );
! 1265: pDb->stmtLast = pPreStmt;
! 1266: }else{
! 1267: assert( pDb->nStmt>0 );
! 1268: }
! 1269: pDb->nStmt++;
! 1270:
! 1271: /* If we have too many statement in cache, remove the surplus from
! 1272: ** the end of the cache list. */
! 1273: while( pDb->nStmt>pDb->maxStmt ){
! 1274: SqlPreparedStmt *pLast = pDb->stmtLast;
! 1275: pDb->stmtLast = pLast->pPrev;
! 1276: pDb->stmtLast->pNext = 0;
! 1277: pDb->nStmt--;
! 1278: dbFreeStmt(pLast);
! 1279: }
! 1280: }
! 1281: }
! 1282:
! 1283: /*
! 1284: ** Structure used with dbEvalXXX() functions:
! 1285: **
! 1286: ** dbEvalInit()
! 1287: ** dbEvalStep()
! 1288: ** dbEvalFinalize()
! 1289: ** dbEvalRowInfo()
! 1290: ** dbEvalColumnValue()
! 1291: */
! 1292: typedef struct DbEvalContext DbEvalContext;
! 1293: struct DbEvalContext {
! 1294: SqliteDb *pDb; /* Database handle */
! 1295: Tcl_Obj *pSql; /* Object holding string zSql */
! 1296: const char *zSql; /* Remaining SQL to execute */
! 1297: SqlPreparedStmt *pPreStmt; /* Current statement */
! 1298: int nCol; /* Number of columns returned by pStmt */
! 1299: Tcl_Obj *pArray; /* Name of array variable */
! 1300: Tcl_Obj **apColName; /* Array of column names */
! 1301: };
! 1302:
! 1303: /*
! 1304: ** Release any cache of column names currently held as part of
! 1305: ** the DbEvalContext structure passed as the first argument.
! 1306: */
! 1307: static void dbReleaseColumnNames(DbEvalContext *p){
! 1308: if( p->apColName ){
! 1309: int i;
! 1310: for(i=0; i<p->nCol; i++){
! 1311: Tcl_DecrRefCount(p->apColName[i]);
! 1312: }
! 1313: Tcl_Free((char *)p->apColName);
! 1314: p->apColName = 0;
! 1315: }
! 1316: p->nCol = 0;
! 1317: }
! 1318:
! 1319: /*
! 1320: ** Initialize a DbEvalContext structure.
! 1321: **
! 1322: ** If pArray is not NULL, then it contains the name of a Tcl array
! 1323: ** variable. The "*" member of this array is set to a list containing
! 1324: ** the names of the columns returned by the statement as part of each
! 1325: ** call to dbEvalStep(), in order from left to right. e.g. if the names
! 1326: ** of the returned columns are a, b and c, it does the equivalent of the
! 1327: ** tcl command:
! 1328: **
! 1329: ** set ${pArray}(*) {a b c}
! 1330: */
! 1331: static void dbEvalInit(
! 1332: DbEvalContext *p, /* Pointer to structure to initialize */
! 1333: SqliteDb *pDb, /* Database handle */
! 1334: Tcl_Obj *pSql, /* Object containing SQL script */
! 1335: Tcl_Obj *pArray /* Name of Tcl array to set (*) element of */
! 1336: ){
! 1337: memset(p, 0, sizeof(DbEvalContext));
! 1338: p->pDb = pDb;
! 1339: p->zSql = Tcl_GetString(pSql);
! 1340: p->pSql = pSql;
! 1341: Tcl_IncrRefCount(pSql);
! 1342: if( pArray ){
! 1343: p->pArray = pArray;
! 1344: Tcl_IncrRefCount(pArray);
! 1345: }
! 1346: }
! 1347:
! 1348: /*
! 1349: ** Obtain information about the row that the DbEvalContext passed as the
! 1350: ** first argument currently points to.
! 1351: */
! 1352: static void dbEvalRowInfo(
! 1353: DbEvalContext *p, /* Evaluation context */
! 1354: int *pnCol, /* OUT: Number of column names */
! 1355: Tcl_Obj ***papColName /* OUT: Array of column names */
! 1356: ){
! 1357: /* Compute column names */
! 1358: if( 0==p->apColName ){
! 1359: sqlite3_stmt *pStmt = p->pPreStmt->pStmt;
! 1360: int i; /* Iterator variable */
! 1361: int nCol; /* Number of columns returned by pStmt */
! 1362: Tcl_Obj **apColName = 0; /* Array of column names */
! 1363:
! 1364: p->nCol = nCol = sqlite3_column_count(pStmt);
! 1365: if( nCol>0 && (papColName || p->pArray) ){
! 1366: apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol );
! 1367: for(i=0; i<nCol; i++){
! 1368: apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i));
! 1369: Tcl_IncrRefCount(apColName[i]);
! 1370: }
! 1371: p->apColName = apColName;
! 1372: }
! 1373:
! 1374: /* If results are being stored in an array variable, then create
! 1375: ** the array(*) entry for that array
! 1376: */
! 1377: if( p->pArray ){
! 1378: Tcl_Interp *interp = p->pDb->interp;
! 1379: Tcl_Obj *pColList = Tcl_NewObj();
! 1380: Tcl_Obj *pStar = Tcl_NewStringObj("*", -1);
! 1381:
! 1382: for(i=0; i<nCol; i++){
! 1383: Tcl_ListObjAppendElement(interp, pColList, apColName[i]);
! 1384: }
! 1385: Tcl_IncrRefCount(pStar);
! 1386: Tcl_ObjSetVar2(interp, p->pArray, pStar, pColList, 0);
! 1387: Tcl_DecrRefCount(pStar);
! 1388: }
! 1389: }
! 1390:
! 1391: if( papColName ){
! 1392: *papColName = p->apColName;
! 1393: }
! 1394: if( pnCol ){
! 1395: *pnCol = p->nCol;
! 1396: }
! 1397: }
! 1398:
! 1399: /*
! 1400: ** Return one of TCL_OK, TCL_BREAK or TCL_ERROR. If TCL_ERROR is
! 1401: ** returned, then an error message is stored in the interpreter before
! 1402: ** returning.
! 1403: **
! 1404: ** A return value of TCL_OK means there is a row of data available. The
! 1405: ** data may be accessed using dbEvalRowInfo() and dbEvalColumnValue(). This
! 1406: ** is analogous to a return of SQLITE_ROW from sqlite3_step(). If TCL_BREAK
! 1407: ** is returned, then the SQL script has finished executing and there are
! 1408: ** no further rows available. This is similar to SQLITE_DONE.
! 1409: */
! 1410: static int dbEvalStep(DbEvalContext *p){
! 1411: const char *zPrevSql = 0; /* Previous value of p->zSql */
! 1412:
! 1413: while( p->zSql[0] || p->pPreStmt ){
! 1414: int rc;
! 1415: if( p->pPreStmt==0 ){
! 1416: zPrevSql = (p->zSql==zPrevSql ? 0 : p->zSql);
! 1417: rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt);
! 1418: if( rc!=TCL_OK ) return rc;
! 1419: }else{
! 1420: int rcs;
! 1421: SqliteDb *pDb = p->pDb;
! 1422: SqlPreparedStmt *pPreStmt = p->pPreStmt;
! 1423: sqlite3_stmt *pStmt = pPreStmt->pStmt;
! 1424:
! 1425: rcs = sqlite3_step(pStmt);
! 1426: if( rcs==SQLITE_ROW ){
! 1427: return TCL_OK;
! 1428: }
! 1429: if( p->pArray ){
! 1430: dbEvalRowInfo(p, 0, 0);
! 1431: }
! 1432: rcs = sqlite3_reset(pStmt);
! 1433:
! 1434: pDb->nStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_FULLSCAN_STEP,1);
! 1435: pDb->nSort = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_SORT,1);
! 1436: pDb->nIndex = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_AUTOINDEX,1);
! 1437: dbReleaseColumnNames(p);
! 1438: p->pPreStmt = 0;
! 1439:
! 1440: if( rcs!=SQLITE_OK ){
! 1441: /* If a run-time error occurs, report the error and stop reading
! 1442: ** the SQL. */
! 1443: dbReleaseStmt(pDb, pPreStmt, 1);
! 1444: #if SQLITE_TEST
! 1445: if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){
! 1446: /* If the runtime error was an SQLITE_SCHEMA, and the database
! 1447: ** handle is configured to use the legacy sqlite3_prepare()
! 1448: ** interface, retry prepare()/step() on the same SQL statement.
! 1449: ** This only happens once. If there is a second SQLITE_SCHEMA
! 1450: ** error, the error will be returned to the caller. */
! 1451: p->zSql = zPrevSql;
! 1452: continue;
! 1453: }
! 1454: #endif
! 1455: Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
! 1456: return TCL_ERROR;
! 1457: }else{
! 1458: dbReleaseStmt(pDb, pPreStmt, 0);
! 1459: }
! 1460: }
! 1461: }
! 1462:
! 1463: /* Finished */
! 1464: return TCL_BREAK;
! 1465: }
! 1466:
! 1467: /*
! 1468: ** Free all resources currently held by the DbEvalContext structure passed
! 1469: ** as the first argument. There should be exactly one call to this function
! 1470: ** for each call to dbEvalInit().
! 1471: */
! 1472: static void dbEvalFinalize(DbEvalContext *p){
! 1473: if( p->pPreStmt ){
! 1474: sqlite3_reset(p->pPreStmt->pStmt);
! 1475: dbReleaseStmt(p->pDb, p->pPreStmt, 0);
! 1476: p->pPreStmt = 0;
! 1477: }
! 1478: if( p->pArray ){
! 1479: Tcl_DecrRefCount(p->pArray);
! 1480: p->pArray = 0;
! 1481: }
! 1482: Tcl_DecrRefCount(p->pSql);
! 1483: dbReleaseColumnNames(p);
! 1484: }
! 1485:
! 1486: /*
! 1487: ** Return a pointer to a Tcl_Obj structure with ref-count 0 that contains
! 1488: ** the value for the iCol'th column of the row currently pointed to by
! 1489: ** the DbEvalContext structure passed as the first argument.
! 1490: */
! 1491: static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){
! 1492: sqlite3_stmt *pStmt = p->pPreStmt->pStmt;
! 1493: switch( sqlite3_column_type(pStmt, iCol) ){
! 1494: case SQLITE_BLOB: {
! 1495: int bytes = sqlite3_column_bytes(pStmt, iCol);
! 1496: const char *zBlob = sqlite3_column_blob(pStmt, iCol);
! 1497: if( !zBlob ) bytes = 0;
! 1498: return Tcl_NewByteArrayObj((u8*)zBlob, bytes);
! 1499: }
! 1500: case SQLITE_INTEGER: {
! 1501: sqlite_int64 v = sqlite3_column_int64(pStmt, iCol);
! 1502: if( v>=-2147483647 && v<=2147483647 ){
! 1503: return Tcl_NewIntObj((int)v);
! 1504: }else{
! 1505: return Tcl_NewWideIntObj(v);
! 1506: }
! 1507: }
! 1508: case SQLITE_FLOAT: {
! 1509: return Tcl_NewDoubleObj(sqlite3_column_double(pStmt, iCol));
! 1510: }
! 1511: case SQLITE_NULL: {
! 1512: return dbTextToObj(p->pDb->zNull);
! 1513: }
! 1514: }
! 1515:
! 1516: return dbTextToObj((char *)sqlite3_column_text(pStmt, iCol));
! 1517: }
! 1518:
! 1519: /*
! 1520: ** If using Tcl version 8.6 or greater, use the NR functions to avoid
! 1521: ** recursive evalution of scripts by the [db eval] and [db trans]
! 1522: ** commands. Even if the headers used while compiling the extension
! 1523: ** are 8.6 or newer, the code still tests the Tcl version at runtime.
! 1524: ** This allows stubs-enabled builds to be used with older Tcl libraries.
! 1525: */
! 1526: #if TCL_MAJOR_VERSION>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6)
! 1527: # define SQLITE_TCL_NRE 1
! 1528: static int DbUseNre(void){
! 1529: int major, minor;
! 1530: Tcl_GetVersion(&major, &minor, 0, 0);
! 1531: return( (major==8 && minor>=6) || major>8 );
! 1532: }
! 1533: #else
! 1534: /*
! 1535: ** Compiling using headers earlier than 8.6. In this case NR cannot be
! 1536: ** used, so DbUseNre() to always return zero. Add #defines for the other
! 1537: ** Tcl_NRxxx() functions to prevent them from causing compilation errors,
! 1538: ** even though the only invocations of them are within conditional blocks
! 1539: ** of the form:
! 1540: **
! 1541: ** if( DbUseNre() ) { ... }
! 1542: */
! 1543: # define SQLITE_TCL_NRE 0
! 1544: # define DbUseNre() 0
! 1545: # define Tcl_NRAddCallback(a,b,c,d,e,f) 0
! 1546: # define Tcl_NREvalObj(a,b,c) 0
! 1547: # define Tcl_NRCreateCommand(a,b,c,d,e,f) 0
! 1548: #endif
! 1549:
! 1550: /*
! 1551: ** This function is part of the implementation of the command:
! 1552: **
! 1553: ** $db eval SQL ?ARRAYNAME? SCRIPT
! 1554: */
! 1555: static int DbEvalNextCmd(
! 1556: ClientData data[], /* data[0] is the (DbEvalContext*) */
! 1557: Tcl_Interp *interp, /* Tcl interpreter */
! 1558: int result /* Result so far */
! 1559: ){
! 1560: int rc = result; /* Return code */
! 1561:
! 1562: /* The first element of the data[] array is a pointer to a DbEvalContext
! 1563: ** structure allocated using Tcl_Alloc(). The second element of data[]
! 1564: ** is a pointer to a Tcl_Obj containing the script to run for each row
! 1565: ** returned by the queries encapsulated in data[0]. */
! 1566: DbEvalContext *p = (DbEvalContext *)data[0];
! 1567: Tcl_Obj *pScript = (Tcl_Obj *)data[1];
! 1568: Tcl_Obj *pArray = p->pArray;
! 1569:
! 1570: while( (rc==TCL_OK || rc==TCL_CONTINUE) && TCL_OK==(rc = dbEvalStep(p)) ){
! 1571: int i;
! 1572: int nCol;
! 1573: Tcl_Obj **apColName;
! 1574: dbEvalRowInfo(p, &nCol, &apColName);
! 1575: for(i=0; i<nCol; i++){
! 1576: Tcl_Obj *pVal = dbEvalColumnValue(p, i);
! 1577: if( pArray==0 ){
! 1578: Tcl_ObjSetVar2(interp, apColName[i], 0, pVal, 0);
! 1579: }else{
! 1580: Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0);
! 1581: }
! 1582: }
! 1583:
! 1584: /* The required interpreter variables are now populated with the data
! 1585: ** from the current row. If using NRE, schedule callbacks to evaluate
! 1586: ** script pScript, then to invoke this function again to fetch the next
! 1587: ** row (or clean up if there is no next row or the script throws an
! 1588: ** exception). After scheduling the callbacks, return control to the
! 1589: ** caller.
! 1590: **
! 1591: ** If not using NRE, evaluate pScript directly and continue with the
! 1592: ** next iteration of this while(...) loop. */
! 1593: if( DbUseNre() ){
! 1594: Tcl_NRAddCallback(interp, DbEvalNextCmd, (void*)p, (void*)pScript, 0, 0);
! 1595: return Tcl_NREvalObj(interp, pScript, 0);
! 1596: }else{
! 1597: rc = Tcl_EvalObjEx(interp, pScript, 0);
! 1598: }
! 1599: }
! 1600:
! 1601: Tcl_DecrRefCount(pScript);
! 1602: dbEvalFinalize(p);
! 1603: Tcl_Free((char *)p);
! 1604:
! 1605: if( rc==TCL_OK || rc==TCL_BREAK ){
! 1606: Tcl_ResetResult(interp);
! 1607: rc = TCL_OK;
! 1608: }
! 1609: return rc;
! 1610: }
! 1611:
! 1612: /*
! 1613: ** The "sqlite" command below creates a new Tcl command for each
! 1614: ** connection it opens to an SQLite database. This routine is invoked
! 1615: ** whenever one of those connection-specific commands is executed
! 1616: ** in Tcl. For example, if you run Tcl code like this:
! 1617: **
! 1618: ** sqlite3 db1 "my_database"
! 1619: ** db1 close
! 1620: **
! 1621: ** The first command opens a connection to the "my_database" database
! 1622: ** and calls that connection "db1". The second command causes this
! 1623: ** subroutine to be invoked.
! 1624: */
! 1625: static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
! 1626: SqliteDb *pDb = (SqliteDb*)cd;
! 1627: int choice;
! 1628: int rc = TCL_OK;
! 1629: static const char *DB_strs[] = {
! 1630: "authorizer", "backup", "busy",
! 1631: "cache", "changes", "close",
! 1632: "collate", "collation_needed", "commit_hook",
! 1633: "complete", "copy", "enable_load_extension",
! 1634: "errorcode", "eval", "exists",
! 1635: "function", "incrblob", "interrupt",
! 1636: "last_insert_rowid", "nullvalue", "onecolumn",
! 1637: "profile", "progress", "rekey",
! 1638: "restore", "rollback_hook", "status",
! 1639: "timeout", "total_changes", "trace",
! 1640: "transaction", "unlock_notify", "update_hook",
! 1641: "version", "wal_hook", 0
! 1642: };
! 1643: enum DB_enum {
! 1644: DB_AUTHORIZER, DB_BACKUP, DB_BUSY,
! 1645: DB_CACHE, DB_CHANGES, DB_CLOSE,
! 1646: DB_COLLATE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK,
! 1647: DB_COMPLETE, DB_COPY, DB_ENABLE_LOAD_EXTENSION,
! 1648: DB_ERRORCODE, DB_EVAL, DB_EXISTS,
! 1649: DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT,
! 1650: DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN,
! 1651: DB_PROFILE, DB_PROGRESS, DB_REKEY,
! 1652: DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS,
! 1653: DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
! 1654: DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK,
! 1655: DB_VERSION, DB_WAL_HOOK
! 1656: };
! 1657: /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
! 1658:
! 1659: if( objc<2 ){
! 1660: Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
! 1661: return TCL_ERROR;
! 1662: }
! 1663: if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
! 1664: return TCL_ERROR;
! 1665: }
! 1666:
! 1667: switch( (enum DB_enum)choice ){
! 1668:
! 1669: /* $db authorizer ?CALLBACK?
! 1670: **
! 1671: ** Invoke the given callback to authorize each SQL operation as it is
! 1672: ** compiled. 5 arguments are appended to the callback before it is
! 1673: ** invoked:
! 1674: **
! 1675: ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...)
! 1676: ** (2) First descriptive name (depends on authorization type)
! 1677: ** (3) Second descriptive name
! 1678: ** (4) Name of the database (ex: "main", "temp")
! 1679: ** (5) Name of trigger that is doing the access
! 1680: **
! 1681: ** The callback should return on of the following strings: SQLITE_OK,
! 1682: ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error.
! 1683: **
! 1684: ** If this method is invoked with no arguments, the current authorization
! 1685: ** callback string is returned.
! 1686: */
! 1687: case DB_AUTHORIZER: {
! 1688: #ifdef SQLITE_OMIT_AUTHORIZATION
! 1689: Tcl_AppendResult(interp, "authorization not available in this build", 0);
! 1690: return TCL_ERROR;
! 1691: #else
! 1692: if( objc>3 ){
! 1693: Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
! 1694: return TCL_ERROR;
! 1695: }else if( objc==2 ){
! 1696: if( pDb->zAuth ){
! 1697: Tcl_AppendResult(interp, pDb->zAuth, 0);
! 1698: }
! 1699: }else{
! 1700: char *zAuth;
! 1701: int len;
! 1702: if( pDb->zAuth ){
! 1703: Tcl_Free(pDb->zAuth);
! 1704: }
! 1705: zAuth = Tcl_GetStringFromObj(objv[2], &len);
! 1706: if( zAuth && len>0 ){
! 1707: pDb->zAuth = Tcl_Alloc( len + 1 );
! 1708: memcpy(pDb->zAuth, zAuth, len+1);
! 1709: }else{
! 1710: pDb->zAuth = 0;
! 1711: }
! 1712: if( pDb->zAuth ){
! 1713: pDb->interp = interp;
! 1714: sqlite3_set_authorizer(pDb->db, auth_callback, pDb);
! 1715: }else{
! 1716: sqlite3_set_authorizer(pDb->db, 0, 0);
! 1717: }
! 1718: }
! 1719: #endif
! 1720: break;
! 1721: }
! 1722:
! 1723: /* $db backup ?DATABASE? FILENAME
! 1724: **
! 1725: ** Open or create a database file named FILENAME. Transfer the
! 1726: ** content of local database DATABASE (default: "main") into the
! 1727: ** FILENAME database.
! 1728: */
! 1729: case DB_BACKUP: {
! 1730: const char *zDestFile;
! 1731: const char *zSrcDb;
! 1732: sqlite3 *pDest;
! 1733: sqlite3_backup *pBackup;
! 1734:
! 1735: if( objc==3 ){
! 1736: zSrcDb = "main";
! 1737: zDestFile = Tcl_GetString(objv[2]);
! 1738: }else if( objc==4 ){
! 1739: zSrcDb = Tcl_GetString(objv[2]);
! 1740: zDestFile = Tcl_GetString(objv[3]);
! 1741: }else{
! 1742: Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME");
! 1743: return TCL_ERROR;
! 1744: }
! 1745: rc = sqlite3_open(zDestFile, &pDest);
! 1746: if( rc!=SQLITE_OK ){
! 1747: Tcl_AppendResult(interp, "cannot open target database: ",
! 1748: sqlite3_errmsg(pDest), (char*)0);
! 1749: sqlite3_close(pDest);
! 1750: return TCL_ERROR;
! 1751: }
! 1752: pBackup = sqlite3_backup_init(pDest, "main", pDb->db, zSrcDb);
! 1753: if( pBackup==0 ){
! 1754: Tcl_AppendResult(interp, "backup failed: ",
! 1755: sqlite3_errmsg(pDest), (char*)0);
! 1756: sqlite3_close(pDest);
! 1757: return TCL_ERROR;
! 1758: }
! 1759: while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
! 1760: sqlite3_backup_finish(pBackup);
! 1761: if( rc==SQLITE_DONE ){
! 1762: rc = TCL_OK;
! 1763: }else{
! 1764: Tcl_AppendResult(interp, "backup failed: ",
! 1765: sqlite3_errmsg(pDest), (char*)0);
! 1766: rc = TCL_ERROR;
! 1767: }
! 1768: sqlite3_close(pDest);
! 1769: break;
! 1770: }
! 1771:
! 1772: /* $db busy ?CALLBACK?
! 1773: **
! 1774: ** Invoke the given callback if an SQL statement attempts to open
! 1775: ** a locked database file.
! 1776: */
! 1777: case DB_BUSY: {
! 1778: if( objc>3 ){
! 1779: Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK");
! 1780: return TCL_ERROR;
! 1781: }else if( objc==2 ){
! 1782: if( pDb->zBusy ){
! 1783: Tcl_AppendResult(interp, pDb->zBusy, 0);
! 1784: }
! 1785: }else{
! 1786: char *zBusy;
! 1787: int len;
! 1788: if( pDb->zBusy ){
! 1789: Tcl_Free(pDb->zBusy);
! 1790: }
! 1791: zBusy = Tcl_GetStringFromObj(objv[2], &len);
! 1792: if( zBusy && len>0 ){
! 1793: pDb->zBusy = Tcl_Alloc( len + 1 );
! 1794: memcpy(pDb->zBusy, zBusy, len+1);
! 1795: }else{
! 1796: pDb->zBusy = 0;
! 1797: }
! 1798: if( pDb->zBusy ){
! 1799: pDb->interp = interp;
! 1800: sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb);
! 1801: }else{
! 1802: sqlite3_busy_handler(pDb->db, 0, 0);
! 1803: }
! 1804: }
! 1805: break;
! 1806: }
! 1807:
! 1808: /* $db cache flush
! 1809: ** $db cache size n
! 1810: **
! 1811: ** Flush the prepared statement cache, or set the maximum number of
! 1812: ** cached statements.
! 1813: */
! 1814: case DB_CACHE: {
! 1815: char *subCmd;
! 1816: int n;
! 1817:
! 1818: if( objc<=2 ){
! 1819: Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?");
! 1820: return TCL_ERROR;
! 1821: }
! 1822: subCmd = Tcl_GetStringFromObj( objv[2], 0 );
! 1823: if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){
! 1824: if( objc!=3 ){
! 1825: Tcl_WrongNumArgs(interp, 2, objv, "flush");
! 1826: return TCL_ERROR;
! 1827: }else{
! 1828: flushStmtCache( pDb );
! 1829: }
! 1830: }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){
! 1831: if( objc!=4 ){
! 1832: Tcl_WrongNumArgs(interp, 2, objv, "size n");
! 1833: return TCL_ERROR;
! 1834: }else{
! 1835: if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
! 1836: Tcl_AppendResult( interp, "cannot convert \"",
! 1837: Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0);
! 1838: return TCL_ERROR;
! 1839: }else{
! 1840: if( n<0 ){
! 1841: flushStmtCache( pDb );
! 1842: n = 0;
! 1843: }else if( n>MAX_PREPARED_STMTS ){
! 1844: n = MAX_PREPARED_STMTS;
! 1845: }
! 1846: pDb->maxStmt = n;
! 1847: }
! 1848: }
! 1849: }else{
! 1850: Tcl_AppendResult( interp, "bad option \"",
! 1851: Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", 0);
! 1852: return TCL_ERROR;
! 1853: }
! 1854: break;
! 1855: }
! 1856:
! 1857: /* $db changes
! 1858: **
! 1859: ** Return the number of rows that were modified, inserted, or deleted by
! 1860: ** the most recent INSERT, UPDATE or DELETE statement, not including
! 1861: ** any changes made by trigger programs.
! 1862: */
! 1863: case DB_CHANGES: {
! 1864: Tcl_Obj *pResult;
! 1865: if( objc!=2 ){
! 1866: Tcl_WrongNumArgs(interp, 2, objv, "");
! 1867: return TCL_ERROR;
! 1868: }
! 1869: pResult = Tcl_GetObjResult(interp);
! 1870: Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db));
! 1871: break;
! 1872: }
! 1873:
! 1874: /* $db close
! 1875: **
! 1876: ** Shutdown the database
! 1877: */
! 1878: case DB_CLOSE: {
! 1879: Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
! 1880: break;
! 1881: }
! 1882:
! 1883: /*
! 1884: ** $db collate NAME SCRIPT
! 1885: **
! 1886: ** Create a new SQL collation function called NAME. Whenever
! 1887: ** that function is called, invoke SCRIPT to evaluate the function.
! 1888: */
! 1889: case DB_COLLATE: {
! 1890: SqlCollate *pCollate;
! 1891: char *zName;
! 1892: char *zScript;
! 1893: int nScript;
! 1894: if( objc!=4 ){
! 1895: Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
! 1896: return TCL_ERROR;
! 1897: }
! 1898: zName = Tcl_GetStringFromObj(objv[2], 0);
! 1899: zScript = Tcl_GetStringFromObj(objv[3], &nScript);
! 1900: pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 );
! 1901: if( pCollate==0 ) return TCL_ERROR;
! 1902: pCollate->interp = interp;
! 1903: pCollate->pNext = pDb->pCollate;
! 1904: pCollate->zScript = (char*)&pCollate[1];
! 1905: pDb->pCollate = pCollate;
! 1906: memcpy(pCollate->zScript, zScript, nScript+1);
! 1907: if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
! 1908: pCollate, tclSqlCollate) ){
! 1909: Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
! 1910: return TCL_ERROR;
! 1911: }
! 1912: break;
! 1913: }
! 1914:
! 1915: /*
! 1916: ** $db collation_needed SCRIPT
! 1917: **
! 1918: ** Create a new SQL collation function called NAME. Whenever
! 1919: ** that function is called, invoke SCRIPT to evaluate the function.
! 1920: */
! 1921: case DB_COLLATION_NEEDED: {
! 1922: if( objc!=3 ){
! 1923: Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT");
! 1924: return TCL_ERROR;
! 1925: }
! 1926: if( pDb->pCollateNeeded ){
! 1927: Tcl_DecrRefCount(pDb->pCollateNeeded);
! 1928: }
! 1929: pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]);
! 1930: Tcl_IncrRefCount(pDb->pCollateNeeded);
! 1931: sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded);
! 1932: break;
! 1933: }
! 1934:
! 1935: /* $db commit_hook ?CALLBACK?
! 1936: **
! 1937: ** Invoke the given callback just before committing every SQL transaction.
! 1938: ** If the callback throws an exception or returns non-zero, then the
! 1939: ** transaction is aborted. If CALLBACK is an empty string, the callback
! 1940: ** is disabled.
! 1941: */
! 1942: case DB_COMMIT_HOOK: {
! 1943: if( objc>3 ){
! 1944: Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
! 1945: return TCL_ERROR;
! 1946: }else if( objc==2 ){
! 1947: if( pDb->zCommit ){
! 1948: Tcl_AppendResult(interp, pDb->zCommit, 0);
! 1949: }
! 1950: }else{
! 1951: char *zCommit;
! 1952: int len;
! 1953: if( pDb->zCommit ){
! 1954: Tcl_Free(pDb->zCommit);
! 1955: }
! 1956: zCommit = Tcl_GetStringFromObj(objv[2], &len);
! 1957: if( zCommit && len>0 ){
! 1958: pDb->zCommit = Tcl_Alloc( len + 1 );
! 1959: memcpy(pDb->zCommit, zCommit, len+1);
! 1960: }else{
! 1961: pDb->zCommit = 0;
! 1962: }
! 1963: if( pDb->zCommit ){
! 1964: pDb->interp = interp;
! 1965: sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb);
! 1966: }else{
! 1967: sqlite3_commit_hook(pDb->db, 0, 0);
! 1968: }
! 1969: }
! 1970: break;
! 1971: }
! 1972:
! 1973: /* $db complete SQL
! 1974: **
! 1975: ** Return TRUE if SQL is a complete SQL statement. Return FALSE if
! 1976: ** additional lines of input are needed. This is similar to the
! 1977: ** built-in "info complete" command of Tcl.
! 1978: */
! 1979: case DB_COMPLETE: {
! 1980: #ifndef SQLITE_OMIT_COMPLETE
! 1981: Tcl_Obj *pResult;
! 1982: int isComplete;
! 1983: if( objc!=3 ){
! 1984: Tcl_WrongNumArgs(interp, 2, objv, "SQL");
! 1985: return TCL_ERROR;
! 1986: }
! 1987: isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) );
! 1988: pResult = Tcl_GetObjResult(interp);
! 1989: Tcl_SetBooleanObj(pResult, isComplete);
! 1990: #endif
! 1991: break;
! 1992: }
! 1993:
! 1994: /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
! 1995: **
! 1996: ** Copy data into table from filename, optionally using SEPARATOR
! 1997: ** as column separators. If a column contains a null string, or the
! 1998: ** value of NULLINDICATOR, a NULL is inserted for the column.
! 1999: ** conflict-algorithm is one of the sqlite conflict algorithms:
! 2000: ** rollback, abort, fail, ignore, replace
! 2001: ** On success, return the number of lines processed, not necessarily same
! 2002: ** as 'db changes' due to conflict-algorithm selected.
! 2003: **
! 2004: ** This code is basically an implementation/enhancement of
! 2005: ** the sqlite3 shell.c ".import" command.
! 2006: **
! 2007: ** This command usage is equivalent to the sqlite2.x COPY statement,
! 2008: ** which imports file data into a table using the PostgreSQL COPY file format:
! 2009: ** $db copy $conflit_algo $table_name $filename \t \\N
! 2010: */
! 2011: case DB_COPY: {
! 2012: char *zTable; /* Insert data into this table */
! 2013: char *zFile; /* The file from which to extract data */
! 2014: char *zConflict; /* The conflict algorithm to use */
! 2015: sqlite3_stmt *pStmt; /* A statement */
! 2016: int nCol; /* Number of columns in the table */
! 2017: int nByte; /* Number of bytes in an SQL string */
! 2018: int i, j; /* Loop counters */
! 2019: int nSep; /* Number of bytes in zSep[] */
! 2020: int nNull; /* Number of bytes in zNull[] */
! 2021: char *zSql; /* An SQL statement */
! 2022: char *zLine; /* A single line of input from the file */
! 2023: char **azCol; /* zLine[] broken up into columns */
! 2024: char *zCommit; /* How to commit changes */
! 2025: FILE *in; /* The input file */
! 2026: int lineno = 0; /* Line number of input file */
! 2027: char zLineNum[80]; /* Line number print buffer */
! 2028: Tcl_Obj *pResult; /* interp result */
! 2029:
! 2030: char *zSep;
! 2031: char *zNull;
! 2032: if( objc<5 || objc>7 ){
! 2033: Tcl_WrongNumArgs(interp, 2, objv,
! 2034: "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
! 2035: return TCL_ERROR;
! 2036: }
! 2037: if( objc>=6 ){
! 2038: zSep = Tcl_GetStringFromObj(objv[5], 0);
! 2039: }else{
! 2040: zSep = "\t";
! 2041: }
! 2042: if( objc>=7 ){
! 2043: zNull = Tcl_GetStringFromObj(objv[6], 0);
! 2044: }else{
! 2045: zNull = "";
! 2046: }
! 2047: zConflict = Tcl_GetStringFromObj(objv[2], 0);
! 2048: zTable = Tcl_GetStringFromObj(objv[3], 0);
! 2049: zFile = Tcl_GetStringFromObj(objv[4], 0);
! 2050: nSep = strlen30(zSep);
! 2051: nNull = strlen30(zNull);
! 2052: if( nSep==0 ){
! 2053: Tcl_AppendResult(interp,"Error: non-null separator required for copy",0);
! 2054: return TCL_ERROR;
! 2055: }
! 2056: if(strcmp(zConflict, "rollback") != 0 &&
! 2057: strcmp(zConflict, "abort" ) != 0 &&
! 2058: strcmp(zConflict, "fail" ) != 0 &&
! 2059: strcmp(zConflict, "ignore" ) != 0 &&
! 2060: strcmp(zConflict, "replace" ) != 0 ) {
! 2061: Tcl_AppendResult(interp, "Error: \"", zConflict,
! 2062: "\", conflict-algorithm must be one of: rollback, "
! 2063: "abort, fail, ignore, or replace", 0);
! 2064: return TCL_ERROR;
! 2065: }
! 2066: zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
! 2067: if( zSql==0 ){
! 2068: Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0);
! 2069: return TCL_ERROR;
! 2070: }
! 2071: nByte = strlen30(zSql);
! 2072: rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
! 2073: sqlite3_free(zSql);
! 2074: if( rc ){
! 2075: Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
! 2076: nCol = 0;
! 2077: }else{
! 2078: nCol = sqlite3_column_count(pStmt);
! 2079: }
! 2080: sqlite3_finalize(pStmt);
! 2081: if( nCol==0 ) {
! 2082: return TCL_ERROR;
! 2083: }
! 2084: zSql = malloc( nByte + 50 + nCol*2 );
! 2085: if( zSql==0 ) {
! 2086: Tcl_AppendResult(interp, "Error: can't malloc()", 0);
! 2087: return TCL_ERROR;
! 2088: }
! 2089: sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
! 2090: zConflict, zTable);
! 2091: j = strlen30(zSql);
! 2092: for(i=1; i<nCol; i++){
! 2093: zSql[j++] = ',';
! 2094: zSql[j++] = '?';
! 2095: }
! 2096: zSql[j++] = ')';
! 2097: zSql[j] = 0;
! 2098: rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
! 2099: free(zSql);
! 2100: if( rc ){
! 2101: Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
! 2102: sqlite3_finalize(pStmt);
! 2103: return TCL_ERROR;
! 2104: }
! 2105: in = fopen(zFile, "rb");
! 2106: if( in==0 ){
! 2107: Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL);
! 2108: sqlite3_finalize(pStmt);
! 2109: return TCL_ERROR;
! 2110: }
! 2111: azCol = malloc( sizeof(azCol[0])*(nCol+1) );
! 2112: if( azCol==0 ) {
! 2113: Tcl_AppendResult(interp, "Error: can't malloc()", 0);
! 2114: fclose(in);
! 2115: return TCL_ERROR;
! 2116: }
! 2117: (void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
! 2118: zCommit = "COMMIT";
! 2119: while( (zLine = local_getline(0, in))!=0 ){
! 2120: char *z;
! 2121: lineno++;
! 2122: azCol[0] = zLine;
! 2123: for(i=0, z=zLine; *z; z++){
! 2124: if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
! 2125: *z = 0;
! 2126: i++;
! 2127: if( i<nCol ){
! 2128: azCol[i] = &z[nSep];
! 2129: z += nSep-1;
! 2130: }
! 2131: }
! 2132: }
! 2133: if( i+1!=nCol ){
! 2134: char *zErr;
! 2135: int nErr = strlen30(zFile) + 200;
! 2136: zErr = malloc(nErr);
! 2137: if( zErr ){
! 2138: sqlite3_snprintf(nErr, zErr,
! 2139: "Error: %s line %d: expected %d columns of data but found %d",
! 2140: zFile, lineno, nCol, i+1);
! 2141: Tcl_AppendResult(interp, zErr, 0);
! 2142: free(zErr);
! 2143: }
! 2144: zCommit = "ROLLBACK";
! 2145: break;
! 2146: }
! 2147: for(i=0; i<nCol; i++){
! 2148: /* check for null data, if so, bind as null */
! 2149: if( (nNull>0 && strcmp(azCol[i], zNull)==0)
! 2150: || strlen30(azCol[i])==0
! 2151: ){
! 2152: sqlite3_bind_null(pStmt, i+1);
! 2153: }else{
! 2154: sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
! 2155: }
! 2156: }
! 2157: sqlite3_step(pStmt);
! 2158: rc = sqlite3_reset(pStmt);
! 2159: free(zLine);
! 2160: if( rc!=SQLITE_OK ){
! 2161: Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0);
! 2162: zCommit = "ROLLBACK";
! 2163: break;
! 2164: }
! 2165: }
! 2166: free(azCol);
! 2167: fclose(in);
! 2168: sqlite3_finalize(pStmt);
! 2169: (void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
! 2170:
! 2171: if( zCommit[0] == 'C' ){
! 2172: /* success, set result as number of lines processed */
! 2173: pResult = Tcl_GetObjResult(interp);
! 2174: Tcl_SetIntObj(pResult, lineno);
! 2175: rc = TCL_OK;
! 2176: }else{
! 2177: /* failure, append lineno where failed */
! 2178: sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno);
! 2179: Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0);
! 2180: rc = TCL_ERROR;
! 2181: }
! 2182: break;
! 2183: }
! 2184:
! 2185: /*
! 2186: ** $db enable_load_extension BOOLEAN
! 2187: **
! 2188: ** Turn the extension loading feature on or off. It if off by
! 2189: ** default.
! 2190: */
! 2191: case DB_ENABLE_LOAD_EXTENSION: {
! 2192: #ifndef SQLITE_OMIT_LOAD_EXTENSION
! 2193: int onoff;
! 2194: if( objc!=3 ){
! 2195: Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN");
! 2196: return TCL_ERROR;
! 2197: }
! 2198: if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){
! 2199: return TCL_ERROR;
! 2200: }
! 2201: sqlite3_enable_load_extension(pDb->db, onoff);
! 2202: break;
! 2203: #else
! 2204: Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
! 2205: 0);
! 2206: return TCL_ERROR;
! 2207: #endif
! 2208: }
! 2209:
! 2210: /*
! 2211: ** $db errorcode
! 2212: **
! 2213: ** Return the numeric error code that was returned by the most recent
! 2214: ** call to sqlite3_exec().
! 2215: */
! 2216: case DB_ERRORCODE: {
! 2217: Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db)));
! 2218: break;
! 2219: }
! 2220:
! 2221: /*
! 2222: ** $db exists $sql
! 2223: ** $db onecolumn $sql
! 2224: **
! 2225: ** The onecolumn method is the equivalent of:
! 2226: ** lindex [$db eval $sql] 0
! 2227: */
! 2228: case DB_EXISTS:
! 2229: case DB_ONECOLUMN: {
! 2230: DbEvalContext sEval;
! 2231: if( objc!=3 ){
! 2232: Tcl_WrongNumArgs(interp, 2, objv, "SQL");
! 2233: return TCL_ERROR;
! 2234: }
! 2235:
! 2236: dbEvalInit(&sEval, pDb, objv[2], 0);
! 2237: rc = dbEvalStep(&sEval);
! 2238: if( choice==DB_ONECOLUMN ){
! 2239: if( rc==TCL_OK ){
! 2240: Tcl_SetObjResult(interp, dbEvalColumnValue(&sEval, 0));
! 2241: }else if( rc==TCL_BREAK ){
! 2242: Tcl_ResetResult(interp);
! 2243: }
! 2244: }else if( rc==TCL_BREAK || rc==TCL_OK ){
! 2245: Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc==TCL_OK));
! 2246: }
! 2247: dbEvalFinalize(&sEval);
! 2248:
! 2249: if( rc==TCL_BREAK ){
! 2250: rc = TCL_OK;
! 2251: }
! 2252: break;
! 2253: }
! 2254:
! 2255: /*
! 2256: ** $db eval $sql ?array? ?{ ...code... }?
! 2257: **
! 2258: ** The SQL statement in $sql is evaluated. For each row, the values are
! 2259: ** placed in elements of the array named "array" and ...code... is executed.
! 2260: ** If "array" and "code" are omitted, then no callback is every invoked.
! 2261: ** If "array" is an empty string, then the values are placed in variables
! 2262: ** that have the same name as the fields extracted by the query.
! 2263: */
! 2264: case DB_EVAL: {
! 2265: if( objc<3 || objc>5 ){
! 2266: Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?");
! 2267: return TCL_ERROR;
! 2268: }
! 2269:
! 2270: if( objc==3 ){
! 2271: DbEvalContext sEval;
! 2272: Tcl_Obj *pRet = Tcl_NewObj();
! 2273: Tcl_IncrRefCount(pRet);
! 2274: dbEvalInit(&sEval, pDb, objv[2], 0);
! 2275: while( TCL_OK==(rc = dbEvalStep(&sEval)) ){
! 2276: int i;
! 2277: int nCol;
! 2278: dbEvalRowInfo(&sEval, &nCol, 0);
! 2279: for(i=0; i<nCol; i++){
! 2280: Tcl_ListObjAppendElement(interp, pRet, dbEvalColumnValue(&sEval, i));
! 2281: }
! 2282: }
! 2283: dbEvalFinalize(&sEval);
! 2284: if( rc==TCL_BREAK ){
! 2285: Tcl_SetObjResult(interp, pRet);
! 2286: rc = TCL_OK;
! 2287: }
! 2288: Tcl_DecrRefCount(pRet);
! 2289: }else{
! 2290: ClientData cd[2];
! 2291: DbEvalContext *p;
! 2292: Tcl_Obj *pArray = 0;
! 2293: Tcl_Obj *pScript;
! 2294:
! 2295: if( objc==5 && *(char *)Tcl_GetString(objv[3]) ){
! 2296: pArray = objv[3];
! 2297: }
! 2298: pScript = objv[objc-1];
! 2299: Tcl_IncrRefCount(pScript);
! 2300:
! 2301: p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext));
! 2302: dbEvalInit(p, pDb, objv[2], pArray);
! 2303:
! 2304: cd[0] = (void *)p;
! 2305: cd[1] = (void *)pScript;
! 2306: rc = DbEvalNextCmd(cd, interp, TCL_OK);
! 2307: }
! 2308: break;
! 2309: }
! 2310:
! 2311: /*
! 2312: ** $db function NAME [-argcount N] SCRIPT
! 2313: **
! 2314: ** Create a new SQL function called NAME. Whenever that function is
! 2315: ** called, invoke SCRIPT to evaluate the function.
! 2316: */
! 2317: case DB_FUNCTION: {
! 2318: SqlFunc *pFunc;
! 2319: Tcl_Obj *pScript;
! 2320: char *zName;
! 2321: int nArg = -1;
! 2322: if( objc==6 ){
! 2323: const char *z = Tcl_GetString(objv[3]);
! 2324: int n = strlen30(z);
! 2325: if( n>2 && strncmp(z, "-argcount",n)==0 ){
! 2326: if( Tcl_GetIntFromObj(interp, objv[4], &nArg) ) return TCL_ERROR;
! 2327: if( nArg<0 ){
! 2328: Tcl_AppendResult(interp, "number of arguments must be non-negative",
! 2329: (char*)0);
! 2330: return TCL_ERROR;
! 2331: }
! 2332: }
! 2333: pScript = objv[5];
! 2334: }else if( objc!=4 ){
! 2335: Tcl_WrongNumArgs(interp, 2, objv, "NAME [-argcount N] SCRIPT");
! 2336: return TCL_ERROR;
! 2337: }else{
! 2338: pScript = objv[3];
! 2339: }
! 2340: zName = Tcl_GetStringFromObj(objv[2], 0);
! 2341: pFunc = findSqlFunc(pDb, zName);
! 2342: if( pFunc==0 ) return TCL_ERROR;
! 2343: if( pFunc->pScript ){
! 2344: Tcl_DecrRefCount(pFunc->pScript);
! 2345: }
! 2346: pFunc->pScript = pScript;
! 2347: Tcl_IncrRefCount(pScript);
! 2348: pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript);
! 2349: rc = sqlite3_create_function(pDb->db, zName, nArg, SQLITE_UTF8,
! 2350: pFunc, tclSqlFunc, 0, 0);
! 2351: if( rc!=SQLITE_OK ){
! 2352: rc = TCL_ERROR;
! 2353: Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
! 2354: }
! 2355: break;
! 2356: }
! 2357:
! 2358: /*
! 2359: ** $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID
! 2360: */
! 2361: case DB_INCRBLOB: {
! 2362: #ifdef SQLITE_OMIT_INCRBLOB
! 2363: Tcl_AppendResult(interp, "incrblob not available in this build", 0);
! 2364: return TCL_ERROR;
! 2365: #else
! 2366: int isReadonly = 0;
! 2367: const char *zDb = "main";
! 2368: const char *zTable;
! 2369: const char *zColumn;
! 2370: sqlite_int64 iRow;
! 2371:
! 2372: /* Check for the -readonly option */
! 2373: if( objc>3 && strcmp(Tcl_GetString(objv[2]), "-readonly")==0 ){
! 2374: isReadonly = 1;
! 2375: }
! 2376:
! 2377: if( objc!=(5+isReadonly) && objc!=(6+isReadonly) ){
! 2378: Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID");
! 2379: return TCL_ERROR;
! 2380: }
! 2381:
! 2382: if( objc==(6+isReadonly) ){
! 2383: zDb = Tcl_GetString(objv[2]);
! 2384: }
! 2385: zTable = Tcl_GetString(objv[objc-3]);
! 2386: zColumn = Tcl_GetString(objv[objc-2]);
! 2387: rc = Tcl_GetWideIntFromObj(interp, objv[objc-1], &iRow);
! 2388:
! 2389: if( rc==TCL_OK ){
! 2390: rc = createIncrblobChannel(
! 2391: interp, pDb, zDb, zTable, zColumn, iRow, isReadonly
! 2392: );
! 2393: }
! 2394: #endif
! 2395: break;
! 2396: }
! 2397:
! 2398: /*
! 2399: ** $db interrupt
! 2400: **
! 2401: ** Interrupt the execution of the inner-most SQL interpreter. This
! 2402: ** causes the SQL statement to return an error of SQLITE_INTERRUPT.
! 2403: */
! 2404: case DB_INTERRUPT: {
! 2405: sqlite3_interrupt(pDb->db);
! 2406: break;
! 2407: }
! 2408:
! 2409: /*
! 2410: ** $db nullvalue ?STRING?
! 2411: **
! 2412: ** Change text used when a NULL comes back from the database. If ?STRING?
! 2413: ** is not present, then the current string used for NULL is returned.
! 2414: ** If STRING is present, then STRING is returned.
! 2415: **
! 2416: */
! 2417: case DB_NULLVALUE: {
! 2418: if( objc!=2 && objc!=3 ){
! 2419: Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE");
! 2420: return TCL_ERROR;
! 2421: }
! 2422: if( objc==3 ){
! 2423: int len;
! 2424: char *zNull = Tcl_GetStringFromObj(objv[2], &len);
! 2425: if( pDb->zNull ){
! 2426: Tcl_Free(pDb->zNull);
! 2427: }
! 2428: if( zNull && len>0 ){
! 2429: pDb->zNull = Tcl_Alloc( len + 1 );
! 2430: memcpy(pDb->zNull, zNull, len);
! 2431: pDb->zNull[len] = '\0';
! 2432: }else{
! 2433: pDb->zNull = 0;
! 2434: }
! 2435: }
! 2436: Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull));
! 2437: break;
! 2438: }
! 2439:
! 2440: /*
! 2441: ** $db last_insert_rowid
! 2442: **
! 2443: ** Return an integer which is the ROWID for the most recent insert.
! 2444: */
! 2445: case DB_LAST_INSERT_ROWID: {
! 2446: Tcl_Obj *pResult;
! 2447: Tcl_WideInt rowid;
! 2448: if( objc!=2 ){
! 2449: Tcl_WrongNumArgs(interp, 2, objv, "");
! 2450: return TCL_ERROR;
! 2451: }
! 2452: rowid = sqlite3_last_insert_rowid(pDb->db);
! 2453: pResult = Tcl_GetObjResult(interp);
! 2454: Tcl_SetWideIntObj(pResult, rowid);
! 2455: break;
! 2456: }
! 2457:
! 2458: /*
! 2459: ** The DB_ONECOLUMN method is implemented together with DB_EXISTS.
! 2460: */
! 2461:
! 2462: /* $db progress ?N CALLBACK?
! 2463: **
! 2464: ** Invoke the given callback every N virtual machine opcodes while executing
! 2465: ** queries.
! 2466: */
! 2467: case DB_PROGRESS: {
! 2468: if( objc==2 ){
! 2469: if( pDb->zProgress ){
! 2470: Tcl_AppendResult(interp, pDb->zProgress, 0);
! 2471: }
! 2472: }else if( objc==4 ){
! 2473: char *zProgress;
! 2474: int len;
! 2475: int N;
! 2476: if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
! 2477: return TCL_ERROR;
! 2478: };
! 2479: if( pDb->zProgress ){
! 2480: Tcl_Free(pDb->zProgress);
! 2481: }
! 2482: zProgress = Tcl_GetStringFromObj(objv[3], &len);
! 2483: if( zProgress && len>0 ){
! 2484: pDb->zProgress = Tcl_Alloc( len + 1 );
! 2485: memcpy(pDb->zProgress, zProgress, len+1);
! 2486: }else{
! 2487: pDb->zProgress = 0;
! 2488: }
! 2489: #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
! 2490: if( pDb->zProgress ){
! 2491: pDb->interp = interp;
! 2492: sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb);
! 2493: }else{
! 2494: sqlite3_progress_handler(pDb->db, 0, 0, 0);
! 2495: }
! 2496: #endif
! 2497: }else{
! 2498: Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK");
! 2499: return TCL_ERROR;
! 2500: }
! 2501: break;
! 2502: }
! 2503:
! 2504: /* $db profile ?CALLBACK?
! 2505: **
! 2506: ** Make arrangements to invoke the CALLBACK routine after each SQL statement
! 2507: ** that has run. The text of the SQL and the amount of elapse time are
! 2508: ** appended to CALLBACK before the script is run.
! 2509: */
! 2510: case DB_PROFILE: {
! 2511: if( objc>3 ){
! 2512: Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
! 2513: return TCL_ERROR;
! 2514: }else if( objc==2 ){
! 2515: if( pDb->zProfile ){
! 2516: Tcl_AppendResult(interp, pDb->zProfile, 0);
! 2517: }
! 2518: }else{
! 2519: char *zProfile;
! 2520: int len;
! 2521: if( pDb->zProfile ){
! 2522: Tcl_Free(pDb->zProfile);
! 2523: }
! 2524: zProfile = Tcl_GetStringFromObj(objv[2], &len);
! 2525: if( zProfile && len>0 ){
! 2526: pDb->zProfile = Tcl_Alloc( len + 1 );
! 2527: memcpy(pDb->zProfile, zProfile, len+1);
! 2528: }else{
! 2529: pDb->zProfile = 0;
! 2530: }
! 2531: #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
! 2532: if( pDb->zProfile ){
! 2533: pDb->interp = interp;
! 2534: sqlite3_profile(pDb->db, DbProfileHandler, pDb);
! 2535: }else{
! 2536: sqlite3_profile(pDb->db, 0, 0);
! 2537: }
! 2538: #endif
! 2539: }
! 2540: break;
! 2541: }
! 2542:
! 2543: /*
! 2544: ** $db rekey KEY
! 2545: **
! 2546: ** Change the encryption key on the currently open database.
! 2547: */
! 2548: case DB_REKEY: {
! 2549: #ifdef SQLITE_HAS_CODEC
! 2550: int nKey;
! 2551: void *pKey;
! 2552: #endif
! 2553: if( objc!=3 ){
! 2554: Tcl_WrongNumArgs(interp, 2, objv, "KEY");
! 2555: return TCL_ERROR;
! 2556: }
! 2557: #ifdef SQLITE_HAS_CODEC
! 2558: pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
! 2559: rc = sqlite3_rekey(pDb->db, pKey, nKey);
! 2560: if( rc ){
! 2561: Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
! 2562: rc = TCL_ERROR;
! 2563: }
! 2564: #endif
! 2565: break;
! 2566: }
! 2567:
! 2568: /* $db restore ?DATABASE? FILENAME
! 2569: **
! 2570: ** Open a database file named FILENAME. Transfer the content
! 2571: ** of FILENAME into the local database DATABASE (default: "main").
! 2572: */
! 2573: case DB_RESTORE: {
! 2574: const char *zSrcFile;
! 2575: const char *zDestDb;
! 2576: sqlite3 *pSrc;
! 2577: sqlite3_backup *pBackup;
! 2578: int nTimeout = 0;
! 2579:
! 2580: if( objc==3 ){
! 2581: zDestDb = "main";
! 2582: zSrcFile = Tcl_GetString(objv[2]);
! 2583: }else if( objc==4 ){
! 2584: zDestDb = Tcl_GetString(objv[2]);
! 2585: zSrcFile = Tcl_GetString(objv[3]);
! 2586: }else{
! 2587: Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? FILENAME");
! 2588: return TCL_ERROR;
! 2589: }
! 2590: rc = sqlite3_open_v2(zSrcFile, &pSrc, SQLITE_OPEN_READONLY, 0);
! 2591: if( rc!=SQLITE_OK ){
! 2592: Tcl_AppendResult(interp, "cannot open source database: ",
! 2593: sqlite3_errmsg(pSrc), (char*)0);
! 2594: sqlite3_close(pSrc);
! 2595: return TCL_ERROR;
! 2596: }
! 2597: pBackup = sqlite3_backup_init(pDb->db, zDestDb, pSrc, "main");
! 2598: if( pBackup==0 ){
! 2599: Tcl_AppendResult(interp, "restore failed: ",
! 2600: sqlite3_errmsg(pDb->db), (char*)0);
! 2601: sqlite3_close(pSrc);
! 2602: return TCL_ERROR;
! 2603: }
! 2604: while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
! 2605: || rc==SQLITE_BUSY ){
! 2606: if( rc==SQLITE_BUSY ){
! 2607: if( nTimeout++ >= 3 ) break;
! 2608: sqlite3_sleep(100);
! 2609: }
! 2610: }
! 2611: sqlite3_backup_finish(pBackup);
! 2612: if( rc==SQLITE_DONE ){
! 2613: rc = TCL_OK;
! 2614: }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
! 2615: Tcl_AppendResult(interp, "restore failed: source database busy",
! 2616: (char*)0);
! 2617: rc = TCL_ERROR;
! 2618: }else{
! 2619: Tcl_AppendResult(interp, "restore failed: ",
! 2620: sqlite3_errmsg(pDb->db), (char*)0);
! 2621: rc = TCL_ERROR;
! 2622: }
! 2623: sqlite3_close(pSrc);
! 2624: break;
! 2625: }
! 2626:
! 2627: /*
! 2628: ** $db status (step|sort|autoindex)
! 2629: **
! 2630: ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
! 2631: ** SQLITE_STMTSTATUS_SORT for the most recent eval.
! 2632: */
! 2633: case DB_STATUS: {
! 2634: int v;
! 2635: const char *zOp;
! 2636: if( objc!=3 ){
! 2637: Tcl_WrongNumArgs(interp, 2, objv, "(step|sort|autoindex)");
! 2638: return TCL_ERROR;
! 2639: }
! 2640: zOp = Tcl_GetString(objv[2]);
! 2641: if( strcmp(zOp, "step")==0 ){
! 2642: v = pDb->nStep;
! 2643: }else if( strcmp(zOp, "sort")==0 ){
! 2644: v = pDb->nSort;
! 2645: }else if( strcmp(zOp, "autoindex")==0 ){
! 2646: v = pDb->nIndex;
! 2647: }else{
! 2648: Tcl_AppendResult(interp,
! 2649: "bad argument: should be autoindex, step, or sort",
! 2650: (char*)0);
! 2651: return TCL_ERROR;
! 2652: }
! 2653: Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
! 2654: break;
! 2655: }
! 2656:
! 2657: /*
! 2658: ** $db timeout MILLESECONDS
! 2659: **
! 2660: ** Delay for the number of milliseconds specified when a file is locked.
! 2661: */
! 2662: case DB_TIMEOUT: {
! 2663: int ms;
! 2664: if( objc!=3 ){
! 2665: Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS");
! 2666: return TCL_ERROR;
! 2667: }
! 2668: if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR;
! 2669: sqlite3_busy_timeout(pDb->db, ms);
! 2670: break;
! 2671: }
! 2672:
! 2673: /*
! 2674: ** $db total_changes
! 2675: **
! 2676: ** Return the number of rows that were modified, inserted, or deleted
! 2677: ** since the database handle was created.
! 2678: */
! 2679: case DB_TOTAL_CHANGES: {
! 2680: Tcl_Obj *pResult;
! 2681: if( objc!=2 ){
! 2682: Tcl_WrongNumArgs(interp, 2, objv, "");
! 2683: return TCL_ERROR;
! 2684: }
! 2685: pResult = Tcl_GetObjResult(interp);
! 2686: Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db));
! 2687: break;
! 2688: }
! 2689:
! 2690: /* $db trace ?CALLBACK?
! 2691: **
! 2692: ** Make arrangements to invoke the CALLBACK routine for each SQL statement
! 2693: ** that is executed. The text of the SQL is appended to CALLBACK before
! 2694: ** it is executed.
! 2695: */
! 2696: case DB_TRACE: {
! 2697: if( objc>3 ){
! 2698: Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
! 2699: return TCL_ERROR;
! 2700: }else if( objc==2 ){
! 2701: if( pDb->zTrace ){
! 2702: Tcl_AppendResult(interp, pDb->zTrace, 0);
! 2703: }
! 2704: }else{
! 2705: char *zTrace;
! 2706: int len;
! 2707: if( pDb->zTrace ){
! 2708: Tcl_Free(pDb->zTrace);
! 2709: }
! 2710: zTrace = Tcl_GetStringFromObj(objv[2], &len);
! 2711: if( zTrace && len>0 ){
! 2712: pDb->zTrace = Tcl_Alloc( len + 1 );
! 2713: memcpy(pDb->zTrace, zTrace, len+1);
! 2714: }else{
! 2715: pDb->zTrace = 0;
! 2716: }
! 2717: #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
! 2718: if( pDb->zTrace ){
! 2719: pDb->interp = interp;
! 2720: sqlite3_trace(pDb->db, DbTraceHandler, pDb);
! 2721: }else{
! 2722: sqlite3_trace(pDb->db, 0, 0);
! 2723: }
! 2724: #endif
! 2725: }
! 2726: break;
! 2727: }
! 2728:
! 2729: /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT
! 2730: **
! 2731: ** Start a new transaction (if we are not already in the midst of a
! 2732: ** transaction) and execute the TCL script SCRIPT. After SCRIPT
! 2733: ** completes, either commit the transaction or roll it back if SCRIPT
! 2734: ** throws an exception. Or if no new transation was started, do nothing.
! 2735: ** pass the exception on up the stack.
! 2736: **
! 2737: ** This command was inspired by Dave Thomas's talk on Ruby at the
! 2738: ** 2005 O'Reilly Open Source Convention (OSCON).
! 2739: */
! 2740: case DB_TRANSACTION: {
! 2741: Tcl_Obj *pScript;
! 2742: const char *zBegin = "SAVEPOINT _tcl_transaction";
! 2743: if( objc!=3 && objc!=4 ){
! 2744: Tcl_WrongNumArgs(interp, 2, objv, "[TYPE] SCRIPT");
! 2745: return TCL_ERROR;
! 2746: }
! 2747:
! 2748: if( pDb->nTransaction==0 && objc==4 ){
! 2749: static const char *TTYPE_strs[] = {
! 2750: "deferred", "exclusive", "immediate", 0
! 2751: };
! 2752: enum TTYPE_enum {
! 2753: TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE
! 2754: };
! 2755: int ttype;
! 2756: if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type",
! 2757: 0, &ttype) ){
! 2758: return TCL_ERROR;
! 2759: }
! 2760: switch( (enum TTYPE_enum)ttype ){
! 2761: case TTYPE_DEFERRED: /* no-op */; break;
! 2762: case TTYPE_EXCLUSIVE: zBegin = "BEGIN EXCLUSIVE"; break;
! 2763: case TTYPE_IMMEDIATE: zBegin = "BEGIN IMMEDIATE"; break;
! 2764: }
! 2765: }
! 2766: pScript = objv[objc-1];
! 2767:
! 2768: /* Run the SQLite BEGIN command to open a transaction or savepoint. */
! 2769: pDb->disableAuth++;
! 2770: rc = sqlite3_exec(pDb->db, zBegin, 0, 0, 0);
! 2771: pDb->disableAuth--;
! 2772: if( rc!=SQLITE_OK ){
! 2773: Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
! 2774: return TCL_ERROR;
! 2775: }
! 2776: pDb->nTransaction++;
! 2777:
! 2778: /* If using NRE, schedule a callback to invoke the script pScript, then
! 2779: ** a second callback to commit (or rollback) the transaction or savepoint
! 2780: ** opened above. If not using NRE, evaluate the script directly, then
! 2781: ** call function DbTransPostCmd() to commit (or rollback) the transaction
! 2782: ** or savepoint. */
! 2783: if( DbUseNre() ){
! 2784: Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0);
! 2785: Tcl_NREvalObj(interp, pScript, 0);
! 2786: }else{
! 2787: rc = DbTransPostCmd(&cd, interp, Tcl_EvalObjEx(interp, pScript, 0));
! 2788: }
! 2789: break;
! 2790: }
! 2791:
! 2792: /*
! 2793: ** $db unlock_notify ?script?
! 2794: */
! 2795: case DB_UNLOCK_NOTIFY: {
! 2796: #ifndef SQLITE_ENABLE_UNLOCK_NOTIFY
! 2797: Tcl_AppendResult(interp, "unlock_notify not available in this build", 0);
! 2798: rc = TCL_ERROR;
! 2799: #else
! 2800: if( objc!=2 && objc!=3 ){
! 2801: Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
! 2802: rc = TCL_ERROR;
! 2803: }else{
! 2804: void (*xNotify)(void **, int) = 0;
! 2805: void *pNotifyArg = 0;
! 2806:
! 2807: if( pDb->pUnlockNotify ){
! 2808: Tcl_DecrRefCount(pDb->pUnlockNotify);
! 2809: pDb->pUnlockNotify = 0;
! 2810: }
! 2811:
! 2812: if( objc==3 ){
! 2813: xNotify = DbUnlockNotify;
! 2814: pNotifyArg = (void *)pDb;
! 2815: pDb->pUnlockNotify = objv[2];
! 2816: Tcl_IncrRefCount(pDb->pUnlockNotify);
! 2817: }
! 2818:
! 2819: if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){
! 2820: Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
! 2821: rc = TCL_ERROR;
! 2822: }
! 2823: }
! 2824: #endif
! 2825: break;
! 2826: }
! 2827:
! 2828: /*
! 2829: ** $db wal_hook ?script?
! 2830: ** $db update_hook ?script?
! 2831: ** $db rollback_hook ?script?
! 2832: */
! 2833: case DB_WAL_HOOK:
! 2834: case DB_UPDATE_HOOK:
! 2835: case DB_ROLLBACK_HOOK: {
! 2836:
! 2837: /* set ppHook to point at pUpdateHook or pRollbackHook, depending on
! 2838: ** whether [$db update_hook] or [$db rollback_hook] was invoked.
! 2839: */
! 2840: Tcl_Obj **ppHook;
! 2841: if( choice==DB_UPDATE_HOOK ){
! 2842: ppHook = &pDb->pUpdateHook;
! 2843: }else if( choice==DB_WAL_HOOK ){
! 2844: ppHook = &pDb->pWalHook;
! 2845: }else{
! 2846: ppHook = &pDb->pRollbackHook;
! 2847: }
! 2848:
! 2849: if( objc!=2 && objc!=3 ){
! 2850: Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
! 2851: return TCL_ERROR;
! 2852: }
! 2853: if( *ppHook ){
! 2854: Tcl_SetObjResult(interp, *ppHook);
! 2855: if( objc==3 ){
! 2856: Tcl_DecrRefCount(*ppHook);
! 2857: *ppHook = 0;
! 2858: }
! 2859: }
! 2860: if( objc==3 ){
! 2861: assert( !(*ppHook) );
! 2862: if( Tcl_GetCharLength(objv[2])>0 ){
! 2863: *ppHook = objv[2];
! 2864: Tcl_IncrRefCount(*ppHook);
! 2865: }
! 2866: }
! 2867:
! 2868: sqlite3_update_hook(pDb->db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb);
! 2869: sqlite3_rollback_hook(pDb->db,(pDb->pRollbackHook?DbRollbackHandler:0),pDb);
! 2870: sqlite3_wal_hook(pDb->db,(pDb->pWalHook?DbWalHandler:0),pDb);
! 2871:
! 2872: break;
! 2873: }
! 2874:
! 2875: /* $db version
! 2876: **
! 2877: ** Return the version string for this database.
! 2878: */
! 2879: case DB_VERSION: {
! 2880: Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC);
! 2881: break;
! 2882: }
! 2883:
! 2884:
! 2885: } /* End of the SWITCH statement */
! 2886: return rc;
! 2887: }
! 2888:
! 2889: #if SQLITE_TCL_NRE
! 2890: /*
! 2891: ** Adaptor that provides an objCmd interface to the NRE-enabled
! 2892: ** interface implementation.
! 2893: */
! 2894: static int DbObjCmdAdaptor(
! 2895: void *cd,
! 2896: Tcl_Interp *interp,
! 2897: int objc,
! 2898: Tcl_Obj *const*objv
! 2899: ){
! 2900: return Tcl_NRCallObjProc(interp, DbObjCmd, cd, objc, objv);
! 2901: }
! 2902: #endif /* SQLITE_TCL_NRE */
! 2903:
! 2904: /*
! 2905: ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
! 2906: ** ?-create BOOLEAN? ?-nomutex BOOLEAN?
! 2907: **
! 2908: ** This is the main Tcl command. When the "sqlite" Tcl command is
! 2909: ** invoked, this routine runs to process that command.
! 2910: **
! 2911: ** The first argument, DBNAME, is an arbitrary name for a new
! 2912: ** database connection. This command creates a new command named
! 2913: ** DBNAME that is used to control that connection. The database
! 2914: ** connection is deleted when the DBNAME command is deleted.
! 2915: **
! 2916: ** The second argument is the name of the database file.
! 2917: **
! 2918: */
! 2919: static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
! 2920: SqliteDb *p;
! 2921: const char *zArg;
! 2922: char *zErrMsg;
! 2923: int i;
! 2924: const char *zFile;
! 2925: const char *zVfs = 0;
! 2926: int flags;
! 2927: Tcl_DString translatedFilename;
! 2928: #ifdef SQLITE_HAS_CODEC
! 2929: void *pKey = 0;
! 2930: int nKey = 0;
! 2931: #endif
! 2932:
! 2933: /* In normal use, each TCL interpreter runs in a single thread. So
! 2934: ** by default, we can turn of mutexing on SQLite database connections.
! 2935: ** However, for testing purposes it is useful to have mutexes turned
! 2936: ** on. So, by default, mutexes default off. But if compiled with
! 2937: ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on.
! 2938: */
! 2939: #ifdef SQLITE_TCL_DEFAULT_FULLMUTEX
! 2940: flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
! 2941: #else
! 2942: flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX;
! 2943: #endif
! 2944:
! 2945: if( objc==2 ){
! 2946: zArg = Tcl_GetStringFromObj(objv[1], 0);
! 2947: if( strcmp(zArg,"-version")==0 ){
! 2948: Tcl_AppendResult(interp,sqlite3_version,0);
! 2949: return TCL_OK;
! 2950: }
! 2951: if( strcmp(zArg,"-has-codec")==0 ){
! 2952: #ifdef SQLITE_HAS_CODEC
! 2953: Tcl_AppendResult(interp,"1",0);
! 2954: #else
! 2955: Tcl_AppendResult(interp,"0",0);
! 2956: #endif
! 2957: return TCL_OK;
! 2958: }
! 2959: }
! 2960: for(i=3; i+1<objc; i+=2){
! 2961: zArg = Tcl_GetString(objv[i]);
! 2962: if( strcmp(zArg,"-key")==0 ){
! 2963: #ifdef SQLITE_HAS_CODEC
! 2964: pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey);
! 2965: #endif
! 2966: }else if( strcmp(zArg, "-vfs")==0 ){
! 2967: zVfs = Tcl_GetString(objv[i+1]);
! 2968: }else if( strcmp(zArg, "-readonly")==0 ){
! 2969: int b;
! 2970: if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
! 2971: if( b ){
! 2972: flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
! 2973: flags |= SQLITE_OPEN_READONLY;
! 2974: }else{
! 2975: flags &= ~SQLITE_OPEN_READONLY;
! 2976: flags |= SQLITE_OPEN_READWRITE;
! 2977: }
! 2978: }else if( strcmp(zArg, "-create")==0 ){
! 2979: int b;
! 2980: if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
! 2981: if( b && (flags & SQLITE_OPEN_READONLY)==0 ){
! 2982: flags |= SQLITE_OPEN_CREATE;
! 2983: }else{
! 2984: flags &= ~SQLITE_OPEN_CREATE;
! 2985: }
! 2986: }else if( strcmp(zArg, "-nomutex")==0 ){
! 2987: int b;
! 2988: if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
! 2989: if( b ){
! 2990: flags |= SQLITE_OPEN_NOMUTEX;
! 2991: flags &= ~SQLITE_OPEN_FULLMUTEX;
! 2992: }else{
! 2993: flags &= ~SQLITE_OPEN_NOMUTEX;
! 2994: }
! 2995: }else if( strcmp(zArg, "-fullmutex")==0 ){
! 2996: int b;
! 2997: if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
! 2998: if( b ){
! 2999: flags |= SQLITE_OPEN_FULLMUTEX;
! 3000: flags &= ~SQLITE_OPEN_NOMUTEX;
! 3001: }else{
! 3002: flags &= ~SQLITE_OPEN_FULLMUTEX;
! 3003: }
! 3004: }else if( strcmp(zArg, "-uri")==0 ){
! 3005: int b;
! 3006: if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
! 3007: if( b ){
! 3008: flags |= SQLITE_OPEN_URI;
! 3009: }else{
! 3010: flags &= ~SQLITE_OPEN_URI;
! 3011: }
! 3012: }else{
! 3013: Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
! 3014: return TCL_ERROR;
! 3015: }
! 3016: }
! 3017: if( objc<3 || (objc&1)!=1 ){
! 3018: Tcl_WrongNumArgs(interp, 1, objv,
! 3019: "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
! 3020: " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
! 3021: #ifdef SQLITE_HAS_CODEC
! 3022: " ?-key CODECKEY?"
! 3023: #endif
! 3024: );
! 3025: return TCL_ERROR;
! 3026: }
! 3027: zErrMsg = 0;
! 3028: p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
! 3029: if( p==0 ){
! 3030: Tcl_SetResult(interp, "malloc failed", TCL_STATIC);
! 3031: return TCL_ERROR;
! 3032: }
! 3033: memset(p, 0, sizeof(*p));
! 3034: zFile = Tcl_GetStringFromObj(objv[2], 0);
! 3035: zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
! 3036: sqlite3_open_v2(zFile, &p->db, flags, zVfs);
! 3037: Tcl_DStringFree(&translatedFilename);
! 3038: if( SQLITE_OK!=sqlite3_errcode(p->db) ){
! 3039: zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
! 3040: sqlite3_close(p->db);
! 3041: p->db = 0;
! 3042: }
! 3043: #ifdef SQLITE_HAS_CODEC
! 3044: if( p->db ){
! 3045: sqlite3_key(p->db, pKey, nKey);
! 3046: }
! 3047: #endif
! 3048: if( p->db==0 ){
! 3049: Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
! 3050: Tcl_Free((char*)p);
! 3051: sqlite3_free(zErrMsg);
! 3052: return TCL_ERROR;
! 3053: }
! 3054: p->maxStmt = NUM_PREPARED_STMTS;
! 3055: p->interp = interp;
! 3056: zArg = Tcl_GetStringFromObj(objv[1], 0);
! 3057: if( DbUseNre() ){
! 3058: Tcl_NRCreateCommand(interp, zArg, DbObjCmdAdaptor, DbObjCmd,
! 3059: (char*)p, DbDeleteCmd);
! 3060: }else{
! 3061: Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
! 3062: }
! 3063: return TCL_OK;
! 3064: }
! 3065:
! 3066: /*
! 3067: ** Provide a dummy Tcl_InitStubs if we are using this as a static
! 3068: ** library.
! 3069: */
! 3070: #ifndef USE_TCL_STUBS
! 3071: # undef Tcl_InitStubs
! 3072: # define Tcl_InitStubs(a,b,c)
! 3073: #endif
! 3074:
! 3075: /*
! 3076: ** Make sure we have a PACKAGE_VERSION macro defined. This will be
! 3077: ** defined automatically by the TEA makefile. But other makefiles
! 3078: ** do not define it.
! 3079: */
! 3080: #ifndef PACKAGE_VERSION
! 3081: # define PACKAGE_VERSION SQLITE_VERSION
! 3082: #endif
! 3083:
! 3084: /*
! 3085: ** Initialize this module.
! 3086: **
! 3087: ** This Tcl module contains only a single new Tcl command named "sqlite".
! 3088: ** (Hence there is no namespace. There is no point in using a namespace
! 3089: ** if the extension only supplies one new name!) The "sqlite" command is
! 3090: ** used to open a new SQLite database. See the DbMain() routine above
! 3091: ** for additional information.
! 3092: **
! 3093: ** The EXTERN macros are required by TCL in order to work on windows.
! 3094: */
! 3095: EXTERN int Sqlite3_Init(Tcl_Interp *interp){
! 3096: Tcl_InitStubs(interp, "8.4", 0);
! 3097: Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
! 3098: Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION);
! 3099:
! 3100: #ifndef SQLITE_3_SUFFIX_ONLY
! 3101: /* The "sqlite" alias is undocumented. It is here only to support
! 3102: ** legacy scripts. All new scripts should use only the "sqlite3"
! 3103: ** command.
! 3104: */
! 3105: Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
! 3106: #endif
! 3107:
! 3108: return TCL_OK;
! 3109: }
! 3110: EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
! 3111: EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
! 3112: EXTERN int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
! 3113: EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
! 3114: EXTERN int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
! 3115: EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK; }
! 3116: EXTERN int Tclsqlite3_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK;}
! 3117:
! 3118:
! 3119: #ifndef SQLITE_3_SUFFIX_ONLY
! 3120: int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
! 3121: int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
! 3122: int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
! 3123: int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
! 3124: int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
! 3125: int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
! 3126: int Sqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK; }
! 3127: int Tclsqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK;}
! 3128: #endif
! 3129:
! 3130: #ifdef TCLSH
! 3131: /*****************************************************************************
! 3132: ** All of the code that follows is used to build standalone TCL interpreters
! 3133: ** that are statically linked with SQLite. Enable these by compiling
! 3134: ** with -DTCLSH=n where n can be 1 or 2. An n of 1 generates a standard
! 3135: ** tclsh but with SQLite built in. An n of 2 generates the SQLite space
! 3136: ** analysis program.
! 3137: */
! 3138:
! 3139: #if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5)
! 3140: /*
! 3141: * This code implements the MD5 message-digest algorithm.
! 3142: * The algorithm is due to Ron Rivest. This code was
! 3143: * written by Colin Plumb in 1993, no copyright is claimed.
! 3144: * This code is in the public domain; do with it what you wish.
! 3145: *
! 3146: * Equivalent code is available from RSA Data Security, Inc.
! 3147: * This code has been tested against that, and is equivalent,
! 3148: * except that you don't need to include two pages of legalese
! 3149: * with every copy.
! 3150: *
! 3151: * To compute the message digest of a chunk of bytes, declare an
! 3152: * MD5Context structure, pass it to MD5Init, call MD5Update as
! 3153: * needed on buffers full of bytes, and then call MD5Final, which
! 3154: * will fill a supplied 16-byte array with the digest.
! 3155: */
! 3156:
! 3157: /*
! 3158: * If compiled on a machine that doesn't have a 32-bit integer,
! 3159: * you just set "uint32" to the appropriate datatype for an
! 3160: * unsigned 32-bit integer. For example:
! 3161: *
! 3162: * cc -Duint32='unsigned long' md5.c
! 3163: *
! 3164: */
! 3165: #ifndef uint32
! 3166: # define uint32 unsigned int
! 3167: #endif
! 3168:
! 3169: struct MD5Context {
! 3170: int isInit;
! 3171: uint32 buf[4];
! 3172: uint32 bits[2];
! 3173: unsigned char in[64];
! 3174: };
! 3175: typedef struct MD5Context MD5Context;
! 3176:
! 3177: /*
! 3178: * Note: this code is harmless on little-endian machines.
! 3179: */
! 3180: static void byteReverse (unsigned char *buf, unsigned longs){
! 3181: uint32 t;
! 3182: do {
! 3183: t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
! 3184: ((unsigned)buf[1]<<8 | buf[0]);
! 3185: *(uint32 *)buf = t;
! 3186: buf += 4;
! 3187: } while (--longs);
! 3188: }
! 3189: /* The four core functions - F1 is optimized somewhat */
! 3190:
! 3191: /* #define F1(x, y, z) (x & y | ~x & z) */
! 3192: #define F1(x, y, z) (z ^ (x & (y ^ z)))
! 3193: #define F2(x, y, z) F1(z, x, y)
! 3194: #define F3(x, y, z) (x ^ y ^ z)
! 3195: #define F4(x, y, z) (y ^ (x | ~z))
! 3196:
! 3197: /* This is the central step in the MD5 algorithm. */
! 3198: #define MD5STEP(f, w, x, y, z, data, s) \
! 3199: ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
! 3200:
! 3201: /*
! 3202: * The core of the MD5 algorithm, this alters an existing MD5 hash to
! 3203: * reflect the addition of 16 longwords of new data. MD5Update blocks
! 3204: * the data and converts bytes into longwords for this routine.
! 3205: */
! 3206: static void MD5Transform(uint32 buf[4], const uint32 in[16]){
! 3207: register uint32 a, b, c, d;
! 3208:
! 3209: a = buf[0];
! 3210: b = buf[1];
! 3211: c = buf[2];
! 3212: d = buf[3];
! 3213:
! 3214: MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
! 3215: MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
! 3216: MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
! 3217: MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
! 3218: MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
! 3219: MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
! 3220: MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
! 3221: MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
! 3222: MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
! 3223: MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
! 3224: MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
! 3225: MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
! 3226: MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
! 3227: MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
! 3228: MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
! 3229: MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
! 3230:
! 3231: MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
! 3232: MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
! 3233: MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
! 3234: MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
! 3235: MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
! 3236: MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
! 3237: MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
! 3238: MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
! 3239: MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
! 3240: MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
! 3241: MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
! 3242: MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
! 3243: MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
! 3244: MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
! 3245: MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
! 3246: MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
! 3247:
! 3248: MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
! 3249: MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
! 3250: MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
! 3251: MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
! 3252: MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
! 3253: MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
! 3254: MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
! 3255: MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
! 3256: MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
! 3257: MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
! 3258: MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
! 3259: MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
! 3260: MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
! 3261: MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
! 3262: MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
! 3263: MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
! 3264:
! 3265: MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
! 3266: MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
! 3267: MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
! 3268: MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
! 3269: MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
! 3270: MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
! 3271: MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
! 3272: MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
! 3273: MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
! 3274: MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
! 3275: MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
! 3276: MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
! 3277: MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
! 3278: MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
! 3279: MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
! 3280: MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
! 3281:
! 3282: buf[0] += a;
! 3283: buf[1] += b;
! 3284: buf[2] += c;
! 3285: buf[3] += d;
! 3286: }
! 3287:
! 3288: /*
! 3289: * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
! 3290: * initialization constants.
! 3291: */
! 3292: static void MD5Init(MD5Context *ctx){
! 3293: ctx->isInit = 1;
! 3294: ctx->buf[0] = 0x67452301;
! 3295: ctx->buf[1] = 0xefcdab89;
! 3296: ctx->buf[2] = 0x98badcfe;
! 3297: ctx->buf[3] = 0x10325476;
! 3298: ctx->bits[0] = 0;
! 3299: ctx->bits[1] = 0;
! 3300: }
! 3301:
! 3302: /*
! 3303: * Update context to reflect the concatenation of another buffer full
! 3304: * of bytes.
! 3305: */
! 3306: static
! 3307: void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
! 3308: uint32 t;
! 3309:
! 3310: /* Update bitcount */
! 3311:
! 3312: t = ctx->bits[0];
! 3313: if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
! 3314: ctx->bits[1]++; /* Carry from low to high */
! 3315: ctx->bits[1] += len >> 29;
! 3316:
! 3317: t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
! 3318:
! 3319: /* Handle any leading odd-sized chunks */
! 3320:
! 3321: if ( t ) {
! 3322: unsigned char *p = (unsigned char *)ctx->in + t;
! 3323:
! 3324: t = 64-t;
! 3325: if (len < t) {
! 3326: memcpy(p, buf, len);
! 3327: return;
! 3328: }
! 3329: memcpy(p, buf, t);
! 3330: byteReverse(ctx->in, 16);
! 3331: MD5Transform(ctx->buf, (uint32 *)ctx->in);
! 3332: buf += t;
! 3333: len -= t;
! 3334: }
! 3335:
! 3336: /* Process data in 64-byte chunks */
! 3337:
! 3338: while (len >= 64) {
! 3339: memcpy(ctx->in, buf, 64);
! 3340: byteReverse(ctx->in, 16);
! 3341: MD5Transform(ctx->buf, (uint32 *)ctx->in);
! 3342: buf += 64;
! 3343: len -= 64;
! 3344: }
! 3345:
! 3346: /* Handle any remaining bytes of data. */
! 3347:
! 3348: memcpy(ctx->in, buf, len);
! 3349: }
! 3350:
! 3351: /*
! 3352: * Final wrapup - pad to 64-byte boundary with the bit pattern
! 3353: * 1 0* (64-bit count of bits processed, MSB-first)
! 3354: */
! 3355: static void MD5Final(unsigned char digest[16], MD5Context *ctx){
! 3356: unsigned count;
! 3357: unsigned char *p;
! 3358:
! 3359: /* Compute number of bytes mod 64 */
! 3360: count = (ctx->bits[0] >> 3) & 0x3F;
! 3361:
! 3362: /* Set the first char of padding to 0x80. This is safe since there is
! 3363: always at least one byte free */
! 3364: p = ctx->in + count;
! 3365: *p++ = 0x80;
! 3366:
! 3367: /* Bytes of padding needed to make 64 bytes */
! 3368: count = 64 - 1 - count;
! 3369:
! 3370: /* Pad out to 56 mod 64 */
! 3371: if (count < 8) {
! 3372: /* Two lots of padding: Pad the first block to 64 bytes */
! 3373: memset(p, 0, count);
! 3374: byteReverse(ctx->in, 16);
! 3375: MD5Transform(ctx->buf, (uint32 *)ctx->in);
! 3376:
! 3377: /* Now fill the next block with 56 bytes */
! 3378: memset(ctx->in, 0, 56);
! 3379: } else {
! 3380: /* Pad block to 56 bytes */
! 3381: memset(p, 0, count-8);
! 3382: }
! 3383: byteReverse(ctx->in, 14);
! 3384:
! 3385: /* Append length in bits and transform */
! 3386: ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
! 3387: ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
! 3388:
! 3389: MD5Transform(ctx->buf, (uint32 *)ctx->in);
! 3390: byteReverse((unsigned char *)ctx->buf, 4);
! 3391: memcpy(digest, ctx->buf, 16);
! 3392: memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */
! 3393: }
! 3394:
! 3395: /*
! 3396: ** Convert a 128-bit MD5 digest into a 32-digit base-16 number.
! 3397: */
! 3398: static void MD5DigestToBase16(unsigned char *digest, char *zBuf){
! 3399: static char const zEncode[] = "0123456789abcdef";
! 3400: int i, j;
! 3401:
! 3402: for(j=i=0; i<16; i++){
! 3403: int a = digest[i];
! 3404: zBuf[j++] = zEncode[(a>>4)&0xf];
! 3405: zBuf[j++] = zEncode[a & 0xf];
! 3406: }
! 3407: zBuf[j] = 0;
! 3408: }
! 3409:
! 3410:
! 3411: /*
! 3412: ** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers
! 3413: ** each representing 16 bits of the digest and separated from each
! 3414: ** other by a "-" character.
! 3415: */
! 3416: static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
! 3417: int i, j;
! 3418: unsigned int x;
! 3419: for(i=j=0; i<16; i+=2){
! 3420: x = digest[i]*256 + digest[i+1];
! 3421: if( i>0 ) zDigest[j++] = '-';
! 3422: sprintf(&zDigest[j], "%05u", x);
! 3423: j += 5;
! 3424: }
! 3425: zDigest[j] = 0;
! 3426: }
! 3427:
! 3428: /*
! 3429: ** A TCL command for md5. The argument is the text to be hashed. The
! 3430: ** Result is the hash in base64.
! 3431: */
! 3432: static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
! 3433: MD5Context ctx;
! 3434: unsigned char digest[16];
! 3435: char zBuf[50];
! 3436: void (*converter)(unsigned char*, char*);
! 3437:
! 3438: if( argc!=2 ){
! 3439: Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
! 3440: " TEXT\"", 0);
! 3441: return TCL_ERROR;
! 3442: }
! 3443: MD5Init(&ctx);
! 3444: MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1]));
! 3445: MD5Final(digest, &ctx);
! 3446: converter = (void(*)(unsigned char*,char*))cd;
! 3447: converter(digest, zBuf);
! 3448: Tcl_AppendResult(interp, zBuf, (char*)0);
! 3449: return TCL_OK;
! 3450: }
! 3451:
! 3452: /*
! 3453: ** A TCL command to take the md5 hash of a file. The argument is the
! 3454: ** name of the file.
! 3455: */
! 3456: static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
! 3457: FILE *in;
! 3458: MD5Context ctx;
! 3459: void (*converter)(unsigned char*, char*);
! 3460: unsigned char digest[16];
! 3461: char zBuf[10240];
! 3462:
! 3463: if( argc!=2 ){
! 3464: Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
! 3465: " FILENAME\"", 0);
! 3466: return TCL_ERROR;
! 3467: }
! 3468: in = fopen(argv[1],"rb");
! 3469: if( in==0 ){
! 3470: Tcl_AppendResult(interp,"unable to open file \"", argv[1],
! 3471: "\" for reading", 0);
! 3472: return TCL_ERROR;
! 3473: }
! 3474: MD5Init(&ctx);
! 3475: for(;;){
! 3476: int n;
! 3477: n = fread(zBuf, 1, sizeof(zBuf), in);
! 3478: if( n<=0 ) break;
! 3479: MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
! 3480: }
! 3481: fclose(in);
! 3482: MD5Final(digest, &ctx);
! 3483: converter = (void(*)(unsigned char*,char*))cd;
! 3484: converter(digest, zBuf);
! 3485: Tcl_AppendResult(interp, zBuf, (char*)0);
! 3486: return TCL_OK;
! 3487: }
! 3488:
! 3489: /*
! 3490: ** Register the four new TCL commands for generating MD5 checksums
! 3491: ** with the TCL interpreter.
! 3492: */
! 3493: int Md5_Init(Tcl_Interp *interp){
! 3494: Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd,
! 3495: MD5DigestToBase16, 0);
! 3496: Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc*)md5_cmd,
! 3497: MD5DigestToBase10x8, 0);
! 3498: Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd,
! 3499: MD5DigestToBase16, 0);
! 3500: Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc*)md5file_cmd,
! 3501: MD5DigestToBase10x8, 0);
! 3502: return TCL_OK;
! 3503: }
! 3504: #endif /* defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) */
! 3505:
! 3506: #if defined(SQLITE_TEST)
! 3507: /*
! 3508: ** During testing, the special md5sum() aggregate function is available.
! 3509: ** inside SQLite. The following routines implement that function.
! 3510: */
! 3511: static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
! 3512: MD5Context *p;
! 3513: int i;
! 3514: if( argc<1 ) return;
! 3515: p = sqlite3_aggregate_context(context, sizeof(*p));
! 3516: if( p==0 ) return;
! 3517: if( !p->isInit ){
! 3518: MD5Init(p);
! 3519: }
! 3520: for(i=0; i<argc; i++){
! 3521: const char *zData = (char*)sqlite3_value_text(argv[i]);
! 3522: if( zData ){
! 3523: MD5Update(p, (unsigned char*)zData, strlen(zData));
! 3524: }
! 3525: }
! 3526: }
! 3527: static void md5finalize(sqlite3_context *context){
! 3528: MD5Context *p;
! 3529: unsigned char digest[16];
! 3530: char zBuf[33];
! 3531: p = sqlite3_aggregate_context(context, sizeof(*p));
! 3532: MD5Final(digest,p);
! 3533: MD5DigestToBase16(digest, zBuf);
! 3534: sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
! 3535: }
! 3536: int Md5_Register(sqlite3 *db){
! 3537: int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
! 3538: md5step, md5finalize);
! 3539: sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
! 3540: return rc;
! 3541: }
! 3542: #endif /* defined(SQLITE_TEST) */
! 3543:
! 3544:
! 3545: /*
! 3546: ** If the macro TCLSH is one, then put in code this for the
! 3547: ** "main" routine that will initialize Tcl and take input from
! 3548: ** standard input, or if a file is named on the command line
! 3549: ** the TCL interpreter reads and evaluates that file.
! 3550: */
! 3551: #if TCLSH==1
! 3552: static const char *tclsh_main_loop(void){
! 3553: static const char zMainloop[] =
! 3554: "set line {}\n"
! 3555: "while {![eof stdin]} {\n"
! 3556: "if {$line!=\"\"} {\n"
! 3557: "puts -nonewline \"> \"\n"
! 3558: "} else {\n"
! 3559: "puts -nonewline \"% \"\n"
! 3560: "}\n"
! 3561: "flush stdout\n"
! 3562: "append line [gets stdin]\n"
! 3563: "if {[info complete $line]} {\n"
! 3564: "if {[catch {uplevel #0 $line} result]} {\n"
! 3565: "puts stderr \"Error: $result\"\n"
! 3566: "} elseif {$result!=\"\"} {\n"
! 3567: "puts $result\n"
! 3568: "}\n"
! 3569: "set line {}\n"
! 3570: "} else {\n"
! 3571: "append line \\n\n"
! 3572: "}\n"
! 3573: "}\n"
! 3574: ;
! 3575: return zMainloop;
! 3576: }
! 3577: #endif
! 3578: #if TCLSH==2
! 3579: static const char *tclsh_main_loop(void);
! 3580: #endif
! 3581:
! 3582: #ifdef SQLITE_TEST
! 3583: static void init_all(Tcl_Interp *);
! 3584: static int init_all_cmd(
! 3585: ClientData cd,
! 3586: Tcl_Interp *interp,
! 3587: int objc,
! 3588: Tcl_Obj *CONST objv[]
! 3589: ){
! 3590:
! 3591: Tcl_Interp *slave;
! 3592: if( objc!=2 ){
! 3593: Tcl_WrongNumArgs(interp, 1, objv, "SLAVE");
! 3594: return TCL_ERROR;
! 3595: }
! 3596:
! 3597: slave = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
! 3598: if( !slave ){
! 3599: return TCL_ERROR;
! 3600: }
! 3601:
! 3602: init_all(slave);
! 3603: return TCL_OK;
! 3604: }
! 3605:
! 3606: /*
! 3607: ** Tclcmd: db_use_legacy_prepare DB BOOLEAN
! 3608: **
! 3609: ** The first argument to this command must be a database command created by
! 3610: ** [sqlite3]. If the second argument is true, then the handle is configured
! 3611: ** to use the sqlite3_prepare_v2() function to prepare statements. If it
! 3612: ** is false, sqlite3_prepare().
! 3613: */
! 3614: static int db_use_legacy_prepare_cmd(
! 3615: ClientData cd,
! 3616: Tcl_Interp *interp,
! 3617: int objc,
! 3618: Tcl_Obj *CONST objv[]
! 3619: ){
! 3620: Tcl_CmdInfo cmdInfo;
! 3621: SqliteDb *pDb;
! 3622: int bPrepare;
! 3623:
! 3624: if( objc!=3 ){
! 3625: Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
! 3626: return TCL_ERROR;
! 3627: }
! 3628:
! 3629: if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
! 3630: Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0);
! 3631: return TCL_ERROR;
! 3632: }
! 3633: pDb = (SqliteDb*)cmdInfo.objClientData;
! 3634: if( Tcl_GetBooleanFromObj(interp, objv[2], &bPrepare) ){
! 3635: return TCL_ERROR;
! 3636: }
! 3637:
! 3638: pDb->bLegacyPrepare = bPrepare;
! 3639:
! 3640: Tcl_ResetResult(interp);
! 3641: return TCL_OK;
! 3642: }
! 3643: #endif
! 3644:
! 3645: /*
! 3646: ** Configure the interpreter passed as the first argument to have access
! 3647: ** to the commands and linked variables that make up:
! 3648: **
! 3649: ** * the [sqlite3] extension itself,
! 3650: **
! 3651: ** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
! 3652: **
! 3653: ** * If SQLITE_TEST is set, the various test interfaces used by the Tcl
! 3654: ** test suite.
! 3655: */
! 3656: static void init_all(Tcl_Interp *interp){
! 3657: Sqlite3_Init(interp);
! 3658:
! 3659: #if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5)
! 3660: Md5_Init(interp);
! 3661: #endif
! 3662:
! 3663: /* Install the [register_dbstat_vtab] command to access the implementation
! 3664: ** of virtual table dbstat (source file test_stat.c). This command is
! 3665: ** required for testfixture and sqlite3_analyzer, but not by the production
! 3666: ** Tcl extension. */
! 3667: #if defined(SQLITE_TEST) || TCLSH==2
! 3668: {
! 3669: extern int SqlitetestStat_Init(Tcl_Interp*);
! 3670: SqlitetestStat_Init(interp);
! 3671: }
! 3672: #endif
! 3673:
! 3674: #ifdef SQLITE_TEST
! 3675: {
! 3676: extern int Sqliteconfig_Init(Tcl_Interp*);
! 3677: extern int Sqlitetest1_Init(Tcl_Interp*);
! 3678: extern int Sqlitetest2_Init(Tcl_Interp*);
! 3679: extern int Sqlitetest3_Init(Tcl_Interp*);
! 3680: extern int Sqlitetest4_Init(Tcl_Interp*);
! 3681: extern int Sqlitetest5_Init(Tcl_Interp*);
! 3682: extern int Sqlitetest6_Init(Tcl_Interp*);
! 3683: extern int Sqlitetest7_Init(Tcl_Interp*);
! 3684: extern int Sqlitetest8_Init(Tcl_Interp*);
! 3685: extern int Sqlitetest9_Init(Tcl_Interp*);
! 3686: extern int Sqlitetestasync_Init(Tcl_Interp*);
! 3687: extern int Sqlitetest_autoext_Init(Tcl_Interp*);
! 3688: extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
! 3689: extern int Sqlitetest_func_Init(Tcl_Interp*);
! 3690: extern int Sqlitetest_hexio_Init(Tcl_Interp*);
! 3691: extern int Sqlitetest_init_Init(Tcl_Interp*);
! 3692: extern int Sqlitetest_malloc_Init(Tcl_Interp*);
! 3693: extern int Sqlitetest_mutex_Init(Tcl_Interp*);
! 3694: extern int Sqlitetestschema_Init(Tcl_Interp*);
! 3695: extern int Sqlitetestsse_Init(Tcl_Interp*);
! 3696: extern int Sqlitetesttclvar_Init(Tcl_Interp*);
! 3697: extern int SqlitetestThread_Init(Tcl_Interp*);
! 3698: extern int SqlitetestOnefile_Init();
! 3699: extern int SqlitetestOsinst_Init(Tcl_Interp*);
! 3700: extern int Sqlitetestbackup_Init(Tcl_Interp*);
! 3701: extern int Sqlitetestintarray_Init(Tcl_Interp*);
! 3702: extern int Sqlitetestvfs_Init(Tcl_Interp *);
! 3703: extern int Sqlitetestrtree_Init(Tcl_Interp*);
! 3704: extern int Sqlitequota_Init(Tcl_Interp*);
! 3705: extern int Sqlitemultiplex_Init(Tcl_Interp*);
! 3706: extern int SqliteSuperlock_Init(Tcl_Interp*);
! 3707: extern int SqlitetestSyscall_Init(Tcl_Interp*);
! 3708: extern int Sqlitetestfuzzer_Init(Tcl_Interp*);
! 3709: extern int Sqlitetestwholenumber_Init(Tcl_Interp*);
! 3710:
! 3711: #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
! 3712: extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
! 3713: #endif
! 3714:
! 3715: #ifdef SQLITE_ENABLE_ZIPVFS
! 3716: extern int Zipvfs_Init(Tcl_Interp*);
! 3717: Zipvfs_Init(interp);
! 3718: #endif
! 3719:
! 3720: Sqliteconfig_Init(interp);
! 3721: Sqlitetest1_Init(interp);
! 3722: Sqlitetest2_Init(interp);
! 3723: Sqlitetest3_Init(interp);
! 3724: Sqlitetest4_Init(interp);
! 3725: Sqlitetest5_Init(interp);
! 3726: Sqlitetest6_Init(interp);
! 3727: Sqlitetest7_Init(interp);
! 3728: Sqlitetest8_Init(interp);
! 3729: Sqlitetest9_Init(interp);
! 3730: Sqlitetestasync_Init(interp);
! 3731: Sqlitetest_autoext_Init(interp);
! 3732: Sqlitetest_demovfs_Init(interp);
! 3733: Sqlitetest_func_Init(interp);
! 3734: Sqlitetest_hexio_Init(interp);
! 3735: Sqlitetest_init_Init(interp);
! 3736: Sqlitetest_malloc_Init(interp);
! 3737: Sqlitetest_mutex_Init(interp);
! 3738: Sqlitetestschema_Init(interp);
! 3739: Sqlitetesttclvar_Init(interp);
! 3740: SqlitetestThread_Init(interp);
! 3741: SqlitetestOnefile_Init(interp);
! 3742: SqlitetestOsinst_Init(interp);
! 3743: Sqlitetestbackup_Init(interp);
! 3744: Sqlitetestintarray_Init(interp);
! 3745: Sqlitetestvfs_Init(interp);
! 3746: Sqlitetestrtree_Init(interp);
! 3747: Sqlitequota_Init(interp);
! 3748: Sqlitemultiplex_Init(interp);
! 3749: SqliteSuperlock_Init(interp);
! 3750: SqlitetestSyscall_Init(interp);
! 3751: Sqlitetestfuzzer_Init(interp);
! 3752: Sqlitetestwholenumber_Init(interp);
! 3753:
! 3754: #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
! 3755: Sqlitetestfts3_Init(interp);
! 3756: #endif
! 3757:
! 3758: Tcl_CreateObjCommand(
! 3759: interp, "load_testfixture_extensions", init_all_cmd, 0, 0
! 3760: );
! 3761: Tcl_CreateObjCommand(
! 3762: interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0
! 3763: );
! 3764:
! 3765: #ifdef SQLITE_SSE
! 3766: Sqlitetestsse_Init(interp);
! 3767: #endif
! 3768: }
! 3769: #endif
! 3770: }
! 3771:
! 3772: #define TCLSH_MAIN main /* Needed to fake out mktclapp */
! 3773: int TCLSH_MAIN(int argc, char **argv){
! 3774: Tcl_Interp *interp;
! 3775:
! 3776: /* Call sqlite3_shutdown() once before doing anything else. This is to
! 3777: ** test that sqlite3_shutdown() can be safely called by a process before
! 3778: ** sqlite3_initialize() is. */
! 3779: sqlite3_shutdown();
! 3780:
! 3781: Tcl_FindExecutable(argv[0]);
! 3782: interp = Tcl_CreateInterp();
! 3783:
! 3784: #if TCLSH==2
! 3785: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
! 3786: #endif
! 3787:
! 3788: init_all(interp);
! 3789: if( argc>=2 ){
! 3790: int i;
! 3791: char zArgc[32];
! 3792: sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH));
! 3793: Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
! 3794: Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
! 3795: Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
! 3796: for(i=3-TCLSH; i<argc; i++){
! 3797: Tcl_SetVar(interp, "argv", argv[i],
! 3798: TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
! 3799: }
! 3800: if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
! 3801: const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
! 3802: if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp);
! 3803: fprintf(stderr,"%s: %s\n", *argv, zInfo);
! 3804: return 1;
! 3805: }
! 3806: }
! 3807: if( TCLSH==2 || argc<=1 ){
! 3808: Tcl_GlobalEval(interp, tclsh_main_loop());
! 3809: }
! 3810: return 0;
! 3811: }
! 3812: #endif /* TCLSH */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>