/ Check-in [47398ae7]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Simplify the "sqlite3" command in the TCL interface. The filename is now optional. There is a new --memdb option with an argument that is the blob to which the database content should be initialized.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | memdb
Files: files | file ages | folders
SHA3-256: 47398ae77236a92f6b9345aa397361b6df127a9a2895c0771d506b0be10822b9
User & Date: drh 2018-01-03 13:20:02
Context
2018-01-03
16:49
Replace the sqlite3_memdb_ptr() interface with the more general sqlite3_serialize() interface. check-in: 8cf2ed4e user: drh tags: memdb
13:20
Simplify the "sqlite3" command in the TCL interface. The filename is now optional. There is a new --memdb option with an argument that is the blob to which the database content should be initialized. check-in: 47398ae7 user: drh tags: memdb
12:39
Fix typo in the Makefile for MSVC. check-in: e5c6ade8 user: mistachkin tags: memdb
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/memdb.c.

   471    471     const char *zSchema,
   472    472     void *aData,
   473    473     sqlite3_int64 sz,
   474    474     sqlite3_int64 szMax,
   475    475     unsigned int mFlags
   476    476   ){
   477    477     MemFile *p = memdbFromDbSchema(db, zSchema);
   478         -  if( p==0 ) return SQLITE_ERROR;
   479         -  if( p->eLock!=SQLITE_LOCK_NONE || p->nMmap>0 ) return SQLITE_BUSY;
   480         -  if( p->mFlags & SQLITE_MEMDB_FREEONCLOSE ) sqlite3_free(p->aData);
   481         -  p->aData = aData;
   482         -  p->sz = sz;
   483         -  p->szMax = szMax;
   484         -  p->mFlags = mFlags;
          478  +  int rc;
          479  +  if( p==0 ){
          480  +    rc = SQLITE_ERROR;
          481  +  }else if( p->eLock!=SQLITE_LOCK_NONE || p->nMmap>0 ){
          482  +    rc = SQLITE_BUSY;
          483  +  }else{
          484  +    if( p->mFlags & SQLITE_MEMDB_FREEONCLOSE ) sqlite3_free(p->aData);
          485  +    p->aData = aData;
          486  +    p->sz = sz;
          487  +    p->szMax = szMax;
          488  +    p->mFlags = mFlags;
          489  +    rc = SQLITE_OK;
          490  +  }
          491  +  if( rc!=SQLITE_OK && (mFlags & SQLITE_MEMDB_FREEONCLOSE)!=0 ){
          492  +    sqlite3_free(aData);
          493  +  }
   485    494     return SQLITE_OK;
   486    495   }
   487    496   
   488    497   /* 
   489    498   ** This routine is called when the extension is loaded.
   490    499   ** Register the new VFS.
   491    500   */
   492    501   int sqlite3MemdbInit(void){
   493    502     memdb_vfs.pAppData = sqlite3_vfs_find(0);
   494    503     memdb_vfs.szOsFile = sizeof(MemFile);
   495    504     return sqlite3_vfs_register(&memdb_vfs, 0);
   496    505   }
   497    506   #endif /* SQLITE_ENABLE_MEMDB */

Changes to src/tclsqlite.c.

  1852   1852       "complete",           "copy",              "enable_load_extension",
  1853   1853       "errorcode",          "eval",              "exists",
  1854   1854       "function",           "incrblob",          "interrupt",
  1855   1855       "last_insert_rowid",  "memdb",             "nullvalue",
  1856   1856       "onecolumn",          "preupdate",         "profile",
  1857   1857       "progress",           "rekey",             "restore",
  1858   1858       "rollback_hook",      "status",            "timeout",
  1859         -    "total_changes",      "trace",             "trace_v",
         1859  +    "total_changes",      "trace",             "trace_v2",
  1860   1860       "transaction",        "unlock_notify",     "update_hook",
  1861   1861       "version",            "wal_hook",          0
  1862   1862     };
  1863   1863     enum DB_enum {
  1864   1864       DB_AUTHORIZER,        DB_BACKUP,           DB_BUSY,
  1865   1865       DB_CACHE,             DB_CHANGES,          DB_CLOSE,
  1866   1866       DB_COLLATE,           DB_COLLATION_NEEDED, DB_COMMIT_HOOK,
................................................................................
  2697   2697           Tcl_AppendResult(interp, "out of memory", (char*)0);
  2698   2698           rc = TCL_ERROR;
  2699   2699         }else{
  2700   2700           memcpy(pData, pBA, len);
  2701   2701           xrc = sqlite3_memdb_config(pDb->db, zSchema, pData, len, len,
  2702   2702                     SQLITE_MEMDB_FREEONCLOSE|SQLITE_MEMDB_RESIZEABLE);
  2703   2703           if( xrc ){
  2704         -          sqlite3_free(pData);
  2705   2704             Tcl_AppendResult(interp, "unable to set MEMDB content", (char*)0);
  2706   2705             rc = TCL_ERROR;
  2707   2706           }
  2708   2707         }
  2709   2708       }else{
  2710   2709         Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
  2711   2710         rc = TCL_ERROR;
................................................................................
  3389   3388     Tcl_Interp *interp,
  3390   3389     int objc,
  3391   3390     Tcl_Obj *const*objv
  3392   3391   ){
  3393   3392     return Tcl_NRCallObjProc(interp, DbObjCmd, cd, objc, objv);
  3394   3393   }
  3395   3394   #endif /* SQLITE_TCL_NRE */
         3395  +
         3396  +/*
         3397  +** Issue the usage message when the "sqlite3" command arguments are
         3398  +** incorrect.
         3399  +*/
         3400  +static int sqliteCmdUsage(
         3401  +  Tcl_Interp *interp,
         3402  +  Tcl_Obj *const*objv
         3403  +){
         3404  +  Tcl_WrongNumArgs(interp, 1, objv,
         3405  +    "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
         3406  +    " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
         3407  +#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
         3408  +    " ?-key CODECKEY?"
         3409  +#endif
         3410  +  );
         3411  +  return TCL_ERROR;
         3412  +}
  3396   3413   
  3397   3414   /*
  3398   3415   **   sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
  3399   3416   **                           ?-create BOOLEAN? ?-nomutex BOOLEAN?
  3400   3417   **
  3401   3418   ** This is the main Tcl command.  When the "sqlite" Tcl command is
  3402   3419   ** invoked, this routine runs to process that command.
................................................................................
  3415   3432     int objc,
  3416   3433     Tcl_Obj *const*objv
  3417   3434   ){
  3418   3435     SqliteDb *p;
  3419   3436     const char *zArg;
  3420   3437     char *zErrMsg;
  3421   3438     int i;
  3422         -  const char *zFile;
         3439  +  const char *zFile = 0;
  3423   3440     const char *zVfs = 0;
  3424   3441     int flags;
  3425   3442     Tcl_DString translatedFilename;
  3426   3443   #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
  3427   3444     void *pKey = 0;
  3428   3445     int nKey = 0;
  3429   3446   #endif
  3430   3447     int rc;
         3448  +#ifdef SQLITE_ENABLE_MEMDB
         3449  +  Tcl_Obj *pDbObj = 0;
         3450  +#endif
  3431   3451   
  3432   3452     /* In normal use, each TCL interpreter runs in a single thread.  So
  3433         -  ** by default, we can turn of mutexing on SQLite database connections.
         3453  +  ** by default, we can turn off mutexing on SQLite database connections.
  3434   3454     ** However, for testing purposes it is useful to have mutexes turned
  3435   3455     ** on.  So, by default, mutexes default off.  But if compiled with
  3436   3456     ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on.
  3437   3457     */
  3438   3458   #ifdef SQLITE_TCL_DEFAULT_FULLMUTEX
  3439   3459     flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
  3440   3460   #else
................................................................................
  3455   3475   #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
  3456   3476         Tcl_AppendResult(interp,"1",(char*)0);
  3457   3477   #else
  3458   3478         Tcl_AppendResult(interp,"0",(char*)0);
  3459   3479   #endif
  3460   3480         return TCL_OK;
  3461   3481       }
         3482  +    if( zArg[0]=='-' ) return sqliteCmdUsage(interp, objv);
  3462   3483     }
  3463         -  for(i=3; i+1<objc; i+=2){
         3484  +  for(i=2; i<objc; i++){
  3464   3485       zArg = Tcl_GetString(objv[i]);
         3486  +    if( zArg[0]!='-' ){
         3487  +      if( zFile!=0 ) return sqliteCmdUsage(interp, objv);
         3488  +      zFile = zArg;
         3489  +      continue;
         3490  +    }
         3491  +    if( i==objc-1 ) return sqliteCmdUsage(interp, objv);
         3492  +    i++;
  3465   3493       if( strcmp(zArg,"-key")==0 ){
  3466   3494   #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
  3467         -      pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey);
         3495  +      pKey = Tcl_GetByteArrayFromObj(objv[i], &nKey);
  3468   3496   #endif
  3469   3497       }else if( strcmp(zArg, "-vfs")==0 ){
  3470         -      zVfs = Tcl_GetString(objv[i+1]);
         3498  +      zVfs = Tcl_GetString(objv[i]);
  3471   3499       }else if( strcmp(zArg, "-readonly")==0 ){
  3472   3500         int b;
  3473         -      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3501  +      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
  3474   3502         if( b ){
  3475   3503           flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
  3476   3504           flags |= SQLITE_OPEN_READONLY;
  3477   3505         }else{
  3478   3506           flags &= ~SQLITE_OPEN_READONLY;
  3479   3507           flags |= SQLITE_OPEN_READWRITE;
  3480   3508         }
  3481   3509       }else if( strcmp(zArg, "-create")==0 ){
  3482   3510         int b;
  3483         -      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3511  +      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
  3484   3512         if( b && (flags & SQLITE_OPEN_READONLY)==0 ){
  3485   3513           flags |= SQLITE_OPEN_CREATE;
  3486   3514         }else{
  3487   3515           flags &= ~SQLITE_OPEN_CREATE;
  3488   3516         }
  3489   3517       }else if( strcmp(zArg, "-nomutex")==0 ){
  3490   3518         int b;
  3491         -      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3519  +      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
  3492   3520         if( b ){
  3493   3521           flags |= SQLITE_OPEN_NOMUTEX;
  3494   3522           flags &= ~SQLITE_OPEN_FULLMUTEX;
  3495   3523         }else{
  3496   3524           flags &= ~SQLITE_OPEN_NOMUTEX;
  3497   3525         }
  3498   3526       }else if( strcmp(zArg, "-fullmutex")==0 ){
  3499   3527         int b;
  3500         -      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3528  +      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
  3501   3529         if( b ){
  3502   3530           flags |= SQLITE_OPEN_FULLMUTEX;
  3503   3531           flags &= ~SQLITE_OPEN_NOMUTEX;
  3504   3532         }else{
  3505   3533           flags &= ~SQLITE_OPEN_FULLMUTEX;
  3506   3534         }
  3507   3535       }else if( strcmp(zArg, "-uri")==0 ){
  3508   3536         int b;
  3509         -      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
         3537  +      if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
  3510   3538         if( b ){
  3511   3539           flags |= SQLITE_OPEN_URI;
  3512   3540         }else{
  3513   3541           flags &= ~SQLITE_OPEN_URI;
  3514   3542         }
         3543  +#ifdef SQLITE_ENABLE_MEMDB
         3544  +    }else if( strcmp(zArg, "-memdb")==0 ){
         3545  +      pDbObj = objv[i];
         3546  +#endif
  3515   3547       }else{
  3516   3548         Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
  3517   3549         return TCL_ERROR;
  3518   3550       }
  3519   3551     }
  3520         -  if( objc<3 || (objc&1)!=1 ){
  3521         -    Tcl_WrongNumArgs(interp, 1, objv,
  3522         -      "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
  3523         -      " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
  3524         -#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
  3525         -      " ?-key CODECKEY?"
  3526         -#endif
  3527         -    );
  3528         -    return TCL_ERROR;
  3529         -  }
  3530   3552     zErrMsg = 0;
  3531   3553     p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
  3532   3554     memset(p, 0, sizeof(*p));
  3533         -  zFile = Tcl_GetStringFromObj(objv[2], 0);
  3534         -  zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
  3535         -  rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs);
  3536         -  Tcl_DStringFree(&translatedFilename);
         3555  +#ifdef SQLITE_ENABLE_MEMDB
         3556  +  if( pDbObj ){
         3557  +    rc = sqlite3_open_v2("x", &p->db, flags, "memdb");
         3558  +    if( rc==SQLITE_OK ){
         3559  +      int len;
         3560  +      unsigned char *aData = Tcl_GetByteArrayFromObj(pDbObj, &len);
         3561  +      unsigned char *a = sqlite3_malloc64( len );
         3562  +      memcpy(a, aData, len);
         3563  +      sqlite3_memdb_config(p->db, "main", a, len, sqlite3_msize(a),
         3564  +           SQLITE_MEMDB_FREEONCLOSE | SQLITE_MEMDB_RESIZEABLE);
         3565  +    }
         3566  +  }else
         3567  +#endif
         3568  +  {
         3569  +    if( zFile==0 ) zFile = ":memory:";
         3570  +    zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
         3571  +    rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs);
         3572  +    Tcl_DStringFree(&translatedFilename);
         3573  +  }
  3537   3574     if( p->db ){
  3538   3575       if( SQLITE_OK!=sqlite3_errcode(p->db) ){
  3539   3576         zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
  3540   3577         sqlite3_close(p->db);
  3541   3578         p->db = 0;
  3542   3579       }
  3543   3580     }else{

Changes to test/memdb1.test.

    43     43     expr {[string length $::db1]==$::sz1}
    44     44   } 1
    45     45   
    46     46   # Create a new MEMDB and initialize it to the content of $::db1
    47     47   # Verify that the content is the same.
    48     48   #
    49     49   db close
    50         -sqlite3 db dummy2 -vfs memdb
    51         -db memdb main $db1
           50  +sqlite3 db -memdb $db1
    52     51   do_execsql_test 110 {
    53     52     SELECT * FROM t1;
    54     53   } {1 2}
    55     54   
    56     55   
    57     56   finish_test

Changes to test/tclsqlite.test.

    18     18   # $Id: tclsqlite.test,v 1.73 2009/03/16 13:19:36 danielk1977 Exp $
    19     19   
    20     20   set testdir [file dirname $argv0]
    21     21   source $testdir/tester.tcl
    22     22   
    23     23   # Check the error messages generated by tclsqlite
    24     24   #
    25         -set r "sqlite_orig HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
           25  +set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
    26     26   if {[sqlite3 -has-codec]} {
    27     27     append r " ?-key CODECKEY?"
    28     28   }
    29     29   do_test tcl-1.1 {
    30         -  set v [catch {sqlite3 bogus} msg]
           30  +  set v [catch {sqlite3 -bogus} msg]
    31     31     regsub {really_sqlite3} $msg {sqlite3} msg
    32     32     lappend v $msg
    33     33   } [list 1 "wrong # args: should be \"$r\""]
    34     34   do_test tcl-1.2 {
    35     35     set v [catch {db bogus} msg]
    36     36     lappend v $msg
    37         -} {1 {bad option "bogus": must be authorizer, backup, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}}
           37  +} {1 {bad option "bogus": must be authorizer, backup, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, memdb, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}}
    38     38   do_test tcl-1.2.1 {
    39     39     set v [catch {db cache bogus} msg]
    40     40     lappend v $msg
    41     41   } {1 {bad option "bogus": must be flush or size}}
    42     42   do_test tcl-1.2.2 {
    43     43     set v [catch {db cache} msg]
    44     44     lappend v $msg