]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix the handling of -init option to the sqlite shell. Ticket #568.
authordrh <drh@noemail.net>
Sun, 1 Feb 2004 01:22:50 +0000 (01:22 +0000)
committerdrh <drh@noemail.net>
Sun, 1 Feb 2004 01:22:50 +0000 (01:22 +0000)
Also add hooks for encrypting the database. (CVS 1206)

FossilOrigin-Name: 3c796de8d1af55944f396f08feaa9e69c1652896

manifest
manifest.uuid
src/shell.c
src/sqlite.h.in
src/tclsqlite.c
test/tclsqlite.test

index ece5381fde9a0fd7f1a2a45da62f928f1a16a959..050dbc593551a263bf750386c00e5123b2635205 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\sbug\sintroduced\sby\sthe\sprevious\scheck-in.\s(CVS\s1205)
-D 2004-01-31T20:40:42
+C Fix\sthe\shandling\sof\s-init\soption\sto\sthe\ssqlite\sshell.\sTicket\s#568.\nAlso\sadd\shooks\sfor\sencrypting\sthe\sdatabase.\s(CVS\s1206)
+D 2004-02-01T01:22:51
 F Makefile.in 0515ff9218ad8d5a8f6220f0494b8ef94c67013b
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -47,11 +47,11 @@ F src/pragma.c 89d62c31c6f0a43376fe8d20549b87a6d30c467a
 F src/printf.c 292a7bfc5a815cb6465e32b2d5c9fe9bd43b27f0
 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
 F src/select.c b7694067df8d57fd0c85ddcc0840532d181552ad
-F src/shell.c 3b067edc098c45caca164bcad1fa79192c3ec5ae
-F src/sqlite.h.in c70d8533cd5a5ae8af580597dbc726693ef82de9
+F src/shell.c a069d35277983d54348105aa3c73be3c45eb9c38
+F src/sqlite.h.in 1798588cab21ebf9fac3aad7fc1539b396c1f91d
 F src/sqliteInt.h c5b727d5d07b88654c204c0fc1ae79c9f635a008
 F src/table.c d845cb101b5afc1f7fea083c99e3d2fa7998d895
-F src/tclsqlite.c 85810fc4a850e2178d71aa5efe576dcd331db596
+F src/tclsqlite.c 30afbb2e446d193d867e49fb0ca5ed84f1e0867f
 F src/test1.c e8652055d04d241d4fb437b5c33ff07d9f13b4b4
 F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700
 F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5
@@ -127,7 +127,7 @@ F test/sort.test ba07b107c16070208e6aab3cadea66ba079d85ba
 F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
 F test/table.test 371a1fc1c470982b2f68f9732f903a5d96f949c4
 F test/tableapi.test d881e787779a175238b72f55b5e50d3a85ab47a6
-F test/tclsqlite.test 6921477a25aa630fd8d89b1ad231f80ef0dea88e
+F test/tclsqlite.test 97233f45db35a76ceae9e56d244af68fc8061ceb
 F test/temptable.test c82bd6f800f10e8cf96921af6315e5f1c21e2692
 F test/tester.tcl 2671536d3650c29e7c105219f277568b0884cb58
 F test/thread1.test 0c1fcc2f9bdd887225e56f48db8ddfbb3d0794ba
@@ -182,7 +182,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 06e7ff4cb8c73fd690c6d5b5f530a30d83f4f10c
-R ff7fd92d976b4f09b582d8f23eb657e9
+P 04cf22785e68fcd4098e6c10a89386108cd0bf07
+R 6b544ab7468b55cbc9dfec6b7298d72d
 U drh
-Z 2fd2d1288462765557d2cdab9570e192
+Z e87a644a943e033216fc69c960947b44
index baaf37f24aeb50d7ab53d7bcf229e225cb038ae4..985787fcb02613e36acfeb6aa42504b170d0ef18 100644 (file)
@@ -1 +1 @@
-04cf22785e68fcd4098e6c10a89386108cd0bf07
\ No newline at end of file
+3c796de8d1af55944f396f08feaa9e69c1652896
\ No newline at end of file
index 0fe82be3bce18ef6760ef3255850f05db0f06edc..1cf0da0a105c8800c34a5c68bd16709579a4c052 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains code to implement the "sqlite" command line
 ** utility for accessing SQLite databases.
 **
-** $Id: shell.c,v 1.83 2003/12/04 20:51:41 drh Exp $
+** $Id: shell.c,v 1.84 2004/02/01 01:22:51 drh Exp $
 */
 #include <stdlib.h>
 #include <string.h>
@@ -186,6 +186,7 @@ struct callback_data {
                          ** .explain ON */
   char outfile[FILENAME_MAX]; /* Filename for *out */
   const char *zDbFilename;    /* name of the database file */
+  char *zKey;                 /* Encryption key */
 };
 
 /*
@@ -489,6 +490,9 @@ static char zHelp[] =
   ".prompt MAIN CONTINUE  Replace the standard prompts\n"
   ".quit                  Exit this program\n"
   ".read FILENAME         Execute SQL in FILENAME\n"
+#ifdef SQLITE_HAS_CRYPTO
+  ".rekey OLD NEW NEW     Change the encryption key\n"
+#endif
   ".schema ?TABLE?        Show the CREATE statements\n"
   ".separator STRING      Change separator string for \"list\" mode\n"
   ".show                  Show the current values for various settings\n"
@@ -507,20 +511,21 @@ static void process_input(struct callback_data *p, FILE *in);
 static void open_db(struct callback_data *p){
   if( p->db==0 ){
     char *zErrMsg = 0;
-    p->db = db = sqlite_open(p->zDbFilename, 0666, &zErrMsg);
-    if( db==0 ){
-      p->db = db = sqlite_open(p->zDbFilename, 0444, &zErrMsg);
-      if( db==0 ){
-        if( zErrMsg ){
-          fprintf(stderr,"Unable to open database \"%s\": %s\n", 
-             p->zDbFilename, zErrMsg);
-        }else{
-          fprintf(stderr,"Unable to open database %s\n", p->zDbFilename);
-        }
-        exit(1);
+#ifdef SQLITE_HAS_CRYPTO
+    if( p->zKey && p->zKey[0] ){
+      int n = strlen(p->zKey);
+      p->db = sqlite_open_encrypted(p->zDbFilename, p->zKey, n, &zErrMsg);
+    }else
+#endif
+    p->db = sqlite_open(p->zDbFilename, 0, &zErrMsg);
+    if( p->db==0 ){
+      if( zErrMsg ){
+        fprintf(stderr,"Unable to open database \"%s\": %s\n", 
+           p->zDbFilename, zErrMsg);
       }else{
-        fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", p->zDbFilename);
+        fprintf(stderr,"Unable to open database %s\n", p->zDbFilename);
       }
+      exit(1);
     }
   }
 }
@@ -781,6 +786,22 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     }
   }else
 
+#ifdef SQLITE_HAS_CRYPTO
+  if( c=='r' && strncmp(azArg[0],"rekey", n)==0 && nArg==4 ){
+    char *zOld = p->zKey;
+    if( zOld==0 ) zOld = "";
+    if( strcmp(azArg[1],zOld) ){
+      fprintf(stderr,"old key is incorrect\n");
+    }else if( strcmp(azArg[2], azArg[3]) ){
+      fprintf(stderr,"2nd copy of new key does not match the 1st\n");
+    }else{
+      sqlite_freemem(p->zKey);
+      p->zKey = sqlite_mprintf("%s", azArg[2]);
+      sqlite_rekey(p->db, p->zKey, strlen(p->zKey));
+    }
+  }else
+#endif
+
   if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
     struct callback_data data;
     char *zErrMsg = 0;
@@ -1105,9 +1126,13 @@ static char *find_home_dir(void){
 ** Read input from the file given by sqliterc_override.  Or if that
 ** parameter is NULL, take input from ~/.sqliterc
 */
-static void process_sqliterc(struct callback_data *p, char *sqliterc_override){
+static void process_sqliterc(
+  struct callback_data *p,        /* Configuration data */
+  const char *sqliterc_override   /* Name of config file. NULL to use default */
+){
   char *home_dir = NULL;
-  char *sqliterc = sqliterc_override;
+  const char *sqliterc = sqliterc_override;
+  char *zBuf;
   FILE *in = NULL;
 
   if (sqliterc == NULL) {
@@ -1116,17 +1141,20 @@ static void process_sqliterc(struct callback_data *p, char *sqliterc_override){
       fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0);
       return;
     }
-    sqliterc = malloc(strlen(home_dir) + 15);
-    if( sqliterc==0 ){
+    zBuf = malloc(strlen(home_dir) + 15);
+    if( zBuf==0 ){
       fprintf(stderr,"%s: out of memory!\n", Argv0);
       exit(1);
     }
-    sprintf(sqliterc,"%s/.sqliterc",home_dir);
+    sprintf(zBuf,"%s/.sqliterc",home_dir);
     free(home_dir);
+    sqliterc = (const char*)zBuf;
   }
   in = fopen(sqliterc,"r");
-  if(in && isatty(fileno(stdout))) {
-    printf("Loading resources from %s\n",sqliterc);
+  if( in ){
+    if( isatty(fileno(stdout)) ){
+      printf("Loading resources from %s\n",sqliterc);
+    }
     process_input(p,in);
     fclose(in);
   }
@@ -1174,15 +1202,13 @@ void main_init(struct callback_data *data) {
 int main(int argc, char **argv){
   char *zErrMsg = 0;
   struct callback_data data;
-  int origArgc = argc;
-  char **origArgv = argv;
+  const char *zInitFile = 0;
+  char *zFirstCmd = 0;
   int i;
   extern int sqliteOsFileExists(const char*);
 
 #ifdef __MACOS__
   argc = ccommand(&argv);
-  origArgc = argc;
-  origArgv = argv;
 #endif
 
   Argv0 = argv[0];
@@ -1195,15 +1221,30 @@ int main(int argc, char **argv){
   signal(SIGINT, interrupt_handler);
 #endif
 
-  /* Locate the name of the database file
+  /* Do an initial pass through the command-line argument to locate
+  ** the name of the database file, the name of the initialization file,
+  ** and the first command to execute.
   */
-  for(i=1; i<argc; i++){
+  for(i=1; i<argc-1; i++){
     if( argv[i][0]!='-' ) break;
     if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
       i++;
+    }else if( strcmp(argv[i],"-init")==0 ){
+      i++;
+      zInitFile = argv[i];
+    }else if( strcmp(argv[i],"-key")==0 ){
+      i++;
+      data.zKey = sqlite_mprintf("%s",argv[i]);
     }
   }
-  data.zDbFilename = i<argc ? argv[i] : ":memory:";
+  if( i<argc ){
+    data.zDbFilename = argv[i++];
+  }else{
+    data.zDbFilename = ":memory:";
+  }
+  if( i<argc ){
+    zFirstCmd = argv[i++];
+  }
   data.out = stdout;
 
   /* Go ahead and open the database file if it already exists.  If the
@@ -1215,96 +1256,63 @@ int main(int argc, char **argv){
     open_db(&data);
   }
 
-  /* Process the ~/.sqliterc file, if there is one
+  /* Process the initialization file if there is one.  If no -init option
+  ** is given on the command line, look for a file named ~/.sqliterc and
+  ** try to process it.
   */
-  process_sqliterc(&data,NULL);
+  process_sqliterc(&data,zInitFile);
 
-  /* Process command-line options
+  /* Make a second pass through the command-line argument and set
+  ** options.  This second pass is delayed until after the initialization
+  ** file is processed so that the command-line arguments will override
+  ** settings in the initialization file.
   */
-  while( argc>=2 && argv[1][0]=='-' ){
-    if( argc>=3 && strcmp(argv[1],"-init")==0 ){
-      /* If we get a -init to do, we have to pretend that
-      ** it replaced the .sqliterc file. Soooo, in order to
-      ** do that we need to start from scratch...*/
-      main_init(&data);
-
-      /* treat this file as the sqliterc... */
-      process_sqliterc(&data,argv[2]);
-
-      /* fix up the command line so we do not re-read
-      ** the option next time around... */
-      {
-        int i = 1;
-        for(i=1;i<=argc-2;i++) {
-          argv[i] = argv[i+2];
-        }
-      }
-      origArgc-=2;
-
-      /* and reset the command line options to be re-read.*/
-      argv = origArgv;
-      argc = origArgc;
-
-    }else if( strcmp(argv[1],"-html")==0 ){
+  for(i=1; i<argc && argv[i][0]=='-'; i++){
+    char *z = argv[i];
+    if( strcmp(z,"-init")==0 || strcmp(z,"-key")==0 ){
+      i++;
+    }else if( strcmp(z,"-html")==0 ){
       data.mode = MODE_Html;
-      argc--;
-      argv++;
-    }else if( strcmp(argv[1],"-list")==0 ){
+    }else if( strcmp(z,"-list")==0 ){
       data.mode = MODE_List;
-      argc--;
-      argv++;
-    }else if( strcmp(argv[1],"-line")==0 ){
+    }else if( strcmp(z,"-line")==0 ){
       data.mode = MODE_Line;
-      argc--;
-      argv++;
-    }else if( strcmp(argv[1],"-column")==0 ){
+    }else if( strcmp(z,"-column")==0 ){
       data.mode = MODE_Column;
-      argc--;
-      argv++;
-    }else if( argc>=3 && strcmp(argv[1],"-separator")==0 ){
-      sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
-      argc -= 2;
-      argv += 2;
-    }else if( argc>=3 && strcmp(argv[1],"-nullvalue")==0 ){
-      sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[2]);
-      argc -= 2;
-      argv += 2;
-    }else if( strcmp(argv[1],"-header")==0 ){
+    }else if( strcmp(z,"-separator")==0 ){
+      i++;
+      sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[i]);
+    }else if( strcmp(z,"-nullvalue")==0 ){
+      i++;
+      sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
+    }else if( strcmp(z,"-header")==0 ){
       data.showHeader = 1;
-      argc--;
-      argv++;
-    }else if( strcmp(argv[1],"-noheader")==0 ){
+    }else if( strcmp(z,"-noheader")==0 ){
       data.showHeader = 0;
-      argc--;
-      argv++;
-    }else if( strcmp(argv[1],"-echo")==0 ){
+    }else if( strcmp(z,"-echo")==0 ){
       data.echoOn = 1;
-      argc--;
-      argv++;
-    }else if( strcmp(argv[1],"-version")==0 ){
+    }else if( strcmp(z,"-version")==0 ){
       printf("%s\n", sqlite_version);
       return 1;
-    }else if( strcmp(argv[1],"-help")==0 ){
+    }else if( strcmp(z,"-help")==0 ){
       usage(1);
     }else{
-      fprintf(stderr,"%s: unknown option: %s\n", Argv0, argv[1]);
+      fprintf(stderr,"%s: unknown option: %s\n", Argv0, z);
       fprintf(stderr,"Use -help for a list of options.\n");
       return 1;
     }
   }
 
-  if( argc<2 ){
-    usage(0);
-  }else if( argc==3 ){
+  if( zFirstCmd ){
     /* Run just the command that follows the database name
     */
-    if( argv[2][0]=='.' ){
-      do_meta_command(argv[2], &data);
+    if( zFirstCmd[0]=='.' ){
+      do_meta_command(zFirstCmd, &data);
       exit(0);
     }else{
       int rc;
       open_db(&data);
-      rc = sqlite_exec(db, argv[2], callback, &data, &zErrMsg);
+      rc = sqlite_exec(db, zFirstCmd, callback, &data, &zErrMsg);
       if( rc!=0 && zErrMsg!=0 ){
         fprintf(stderr,"SQL error: %s\n", zErrMsg);
         exit(1);
index e493a13fecd45a039bd69d78c1409e1a364c1762..a2c6d1557c6cc7fba0e488f4b5d514d088c4ccbb 100644 (file)
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the SQLite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.54 2004/01/15 02:44:03 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.55 2004/02/01 01:22:52 drh Exp $
 */
 #ifndef _SQLITE_H_
 #define _SQLITE_H_
@@ -773,6 +773,33 @@ void sqlite_progress_handler(sqlite*, int, int(*)(void*), void*);
 */
 void *sqlite_commit_hook(sqlite*, int(*)(void*), void*);
 
+/*
+** Open an encrypted SQLite database.  If pKey==0 or nKey==0, this routine
+** is the same as sqlite_open().
+**
+** The code to implement this API is not available in the public release
+** of SQLite.
+*/
+sqlite *sqlite_open_encrypted(
+  const char *zFilename,   /* Name of the encrypted database */
+  const void *pKey,        /* Pointer to the key */
+  int nKey,                /* Number of bytes in the key */
+  char **pzErrmsg          /* Write error message here */
+);
+
+/*
+** Change the key on an open database.  If the current database is not
+** encrypted, this routine will encrypt it.  If pNew==0 or nNew==0, the
+** database is decrypted.
+**
+** The code to implement this API is not available in the public release
+** of SQLite.
+*/
+int sqlite_rekey(
+  sqlite *db,                    /* Database to be rekeyed */
+  const void *pKey, int nKey     /* The new key */
+);
+
 #ifdef __cplusplus
 }  /* End of the 'extern "C"' block */
 #endif
index 70706306adc9103690e349601b28aff331e15503..6fb3c3addcbe7ce299e00ae385799d16c61f6eff 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** A TCL Interface to SQLite
 **
-** $Id: tclsqlite.c,v 1.54 2004/01/15 02:44:03 drh Exp $
+** $Id: tclsqlite.c,v 1.55 2004/02/01 01:22:52 drh Exp $
 */
 #ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */
 
@@ -486,19 +486,21 @@ static int auth_callback(
 static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
   SqliteDb *pDb = (SqliteDb*)cd;
   int choice;
+  int rc = TCL_OK;
   static const char *DB_strs[] = {
     "authorizer",         "busy",              "changes",
     "close",              "commit_hook",       "complete",
     "errorcode",          "eval",              "function",
     "last_insert_rowid",  "onecolumn",         "progress",
-    "timeout",            "trace",             0
+    "rekey",              "timeout",           "trace",
+    0                    
   };
   enum DB_enum {
     DB_AUTHORIZER,        DB_BUSY,             DB_CHANGES,
     DB_CLOSE,             DB_COMMIT_HOOK,      DB_COMPLETE,
     DB_ERRORCODE,         DB_EVAL,             DB_FUNCTION,
     DB_LAST_INSERT_ROWID, DB_ONECOLUMN,        DB_PROGRESS,
-    DB_TIMEOUT,           DB_TRACE,            
+    DB_REKEY,             DB_TIMEOUT,          DB_TRACE,
   };
 
   if( objc<2 ){
@@ -747,7 +749,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
     CallbackData cbData;
     char *zErrMsg;
     char *zSql;
-    int rc;
 #ifdef UTF_TRANSLATION_NEEDED
     Tcl_DString dSql;
     int i;
@@ -865,7 +866,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
   ** Return a single column from a single row of the given SQL query.
   */
   case DB_ONECOLUMN: {
-    int rc;
     char *zSql;
     char *zErrMsg = 0;
     if( objc!=3 ){
@@ -875,7 +875,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
     zSql = Tcl_GetStringFromObj(objv[2], 0);
     rc = sqlite_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg);
     if( rc==SQLITE_ABORT ){
-      /* Do nothing.  This is normal. */
+      rc = SQLITE_OK;
     }else if( zErrMsg ){
       Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
       free(zErrMsg);
@@ -887,6 +887,29 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
     break;
   }
 
+  /*
+  **     $db rekey KEY
+  **
+  ** Change the encryption key on the currently open database.
+  */
+  case DB_REKEY: {
+    int nKey;
+    void *pKey;
+    if( objc!=3 ){
+      Tcl_WrongNumArgs(interp, 2, objv, "KEY");
+      return TCL_ERROR;
+    }
+    pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
+#ifdef SQLITE_HAS_CRYPTO
+    rc = sqlite_rekey(pDb->db, pKey, nKey);
+    if( rc ){
+      Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
+      rc = TCL_ERROR;
+    }
+#endif
+    break;
+  }
+
   /*
   **     $db timeout MILLESECONDS
   **
@@ -940,11 +963,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
   }
 
   } /* End of the SWITCH statement */
-  return TCL_OK;
+  return rc;
 }
 
 /*
-**   sqlite DBNAME FILENAME ?MODE?
+**   sqlite DBNAME FILENAME ?MODE? ?-key KEY?
 **
 ** This is the main Tcl command.  When the "sqlite" Tcl command is
 ** invoked, this routine runs to process that command.
@@ -974,21 +997,34 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
 **       not.  Used by tests to make sure the library was compiled 
 **       correctly.
 */
-static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
+static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
   int mode;
   SqliteDb *p;
+  void *pKey = 0;
+  int nKey = 0;
+  const char *zArg;
   char *zErrMsg;
+  const char *zFile;
   char zBuf[80];
-  if( argc==2 ){
-    if( strcmp(argv[1],"-encoding")==0 ){
+  if( objc==2 ){
+    zArg = Tcl_GetStringFromObj(objv[1], 0);
+    if( strcmp(zArg,"-encoding")==0 ){
       Tcl_AppendResult(interp,sqlite_encoding,0);
       return TCL_OK;
     }
-    if( strcmp(argv[1],"-version")==0 ){
+    if( strcmp(zArg,"-version")==0 ){
       Tcl_AppendResult(interp,sqlite_version,0);
       return TCL_OK;
     }
-    if( strcmp(argv[1],"-tcl-uses-utf")==0 ){
+    if( strcmp(zArg,"-has-crypto")==0 ){
+#ifdef SQLITE_HAS_CRYPTO
+      Tcl_AppendResult(interp,"1",0);
+#else
+      Tcl_AppendResult(interp,"0",0);
+#endif
+      return TCL_OK;
+    }
+    if( strcmp(zArg,"-tcl-uses-utf")==0 ){
 #ifdef TCL_UTF_MAX
       Tcl_AppendResult(interp,"1",0);
 #else
@@ -997,14 +1033,26 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
       return TCL_OK;
     }
   }
-  if( argc!=3 && argc!=4 ){
-    Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
-       " HANDLE FILENAME ?MODE?\"", 0);
+  if( objc==5 || objc==6 ){
+    zArg = Tcl_GetStringFromObj(objv[objc-2], 0);
+    if( strcmp(zArg,"-key")==0 ){
+      pKey = Tcl_GetByteArrayFromObj(objv[objc-1], &nKey);
+      objc -= 2;
+    }
+  }
+  if( objc!=3 && objc!=4 ){
+    Tcl_WrongNumArgs(interp, 1, objv, 
+#ifdef SQLITE_HAS_CRYPTO
+      "HANDLE FILENAME ?-key CRYPTOKEY?"
+#else
+      "HANDLE FILENAME ?MODE?"
+#endif
+    );
     return TCL_ERROR;
   }
-  if( argc==3 ){
+  if( objc==3 ){
     mode = 0666;
-  }else if( Tcl_GetInt(interp, argv[3], &mode)!=TCL_OK ){
+  }else if( Tcl_GetIntFromObj(interp, objv[3], &mode)!=TCL_OK ){
     return TCL_ERROR;
   }
   zErrMsg = 0;
@@ -1014,14 +1062,21 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
     return TCL_ERROR;
   }
   memset(p, 0, sizeof(*p));
-  p->db = sqlite_open(argv[2], mode, &zErrMsg);
+  zFile = Tcl_GetStringFromObj(objv[2], 0);
+#ifdef SQLITE_HAS_CRYPTO
+  if( nKey>0 ){
+    p->db = sqlite_open_encrypted(zFile, pKey, nKey, &zErrMsg);
+  }else
+#endif
+  p->db = sqlite_open(zFile, mode, &zErrMsg);
   if( p->db==0 ){
     Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
     Tcl_Free((char*)p);
     free(zErrMsg);
     return TCL_ERROR;
   }
-  Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd);
+  zArg = Tcl_GetStringFromObj(objv[1], 0);
+  Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
 
   /* The return value is the value of the sqlite* pointer
   */
@@ -1063,13 +1118,13 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
 */
 int Sqlite_Init(Tcl_Interp *interp){
   Tcl_InitStubs(interp, "8.0", 0);
-  Tcl_CreateCommand(interp, "sqlite", (Tcl_CmdProc*)DbMain, 0, 0);
+  Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
   Tcl_PkgProvide(interp, "sqlite", "2.0");
   return TCL_OK;
 }
 int Tclsqlite_Init(Tcl_Interp *interp){
   Tcl_InitStubs(interp, "8.0", 0);
-  Tcl_CreateCommand(interp, "sqlite", (Tcl_CmdProc*)DbMain, 0, 0);
+  Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
   Tcl_PkgProvide(interp, "sqlite", "2.0");
   return TCL_OK;
 }
index 5b358674dd4e3d3aa3d5ad2f12d797802880fa3c..b8c90dc7b3a96294cb2b60925320c97df827e1c0 100644 (file)
 # interface is pretty well tested.  This file contains some addition
 # tests for fringe issues that the main test suite does not cover.
 #
-# $Id: tclsqlite.test,v 1.17 2004/01/15 02:44:04 drh Exp $
+# $Id: tclsqlite.test,v 1.18 2004/02/01 01:22:52 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
 # Check the error messages generated by tclsqlite
 #
+if {[sqlite -has-crypto]} {
+  set r "sqlite HANDLE FILENAME ?-key CRYPTOKEY?"
+} else {
+  set r "sqlite HANDLE FILENAME ?MODE?"
+}
 do_test tcl-1.1 {
   set v [catch {sqlite bogus} msg]
   lappend v $msg
-} {1 {wrong # args: should be "sqlite HANDLE FILENAME ?MODE?"}}
+} [list 1 "wrong # args: should be \"$r\""]
 do_test tcl-1.2 {
   set v [catch {db bogus} msg]
   lappend v $msg
-} {1 {bad option "bogus": must be authorizer, busy, changes, close, commit_hook, complete, errorcode, eval, function, last_insert_rowid, onecolumn, progress, timeout, or trace}}
+} {1 {bad option "bogus": must be authorizer, busy, changes, close, commit_hook, complete, errorcode, eval, function, last_insert_rowid, onecolumn, progress, rekey, timeout, or trace}}
 do_test tcl-1.3 {
   execsql {CREATE TABLE t1(a int, b int)}
   execsql {INSERT INTO t1 VALUES(10,20)}
@@ -98,8 +103,9 @@ do_test tcl-3.1 {
     INSERT INTO t1 SELECT a*2+1, b*2+1 FROM t1;
     INSERT INTO t1 SELECT a*2+3, b*2+3 FROM t1;
   }
-  db onecolumn {SELECT * FROM t1 ORDER BY a}
-} {10}
+  set rc [catch {db onecolumn {SELECT * FROM t1 ORDER BY a}} msg]
+  lappend rc $msg
+} {0 10}
 do_test tcl-3.2 {
   db onecolumn {SELECT * FROM t1 WHERE a<0}
 } {}