]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Work on the ".archive" command.
authordrh <drh@noemail.net>
Wed, 10 Jan 2018 13:11:51 +0000 (13:11 +0000)
committerdrh <drh@noemail.net>
Wed, 10 Jan 2018 13:11:51 +0000 (13:11 +0000)
(1) Add the --dryrun option.
(2) Do not require --file when open on a ZIP archive.
(3) Miscellaneous code simplifications.
This is an incremental check-in of work in progress.

FossilOrigin-Name: a2baada429e84dc4b7243173a056e3c8bc042682f7efb01fdf8d2cc452c97e04

manifest
manifest.uuid
src/shell.c.in

index 73254e8c8852a3414b67e0a6d148cd5fa0a4efe9..2b380e8b603d4731142ee36f0006503400c5cc60 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Rearrange\ssome\sroutines\sin\sshell.c\sto\savoid\sthe\sneed\sto\sforward\sreference\sa\nstatic\sfunction.
-D 2018-01-10T00:53:55.338
+C Work\son\sthe\s".archive"\scommand.\n(1)\sAdd\sthe\s--dryrun\soption.\n(2)\sDo\snot\srequire\s--file\swhen\sopen\son\sa\sZIP\sarchive.\n(3)\sMiscellaneous\scode\ssimplifications.\nThis\sis\san\sincremental\scheck-in\sof\swork\sin\sprogress.
+D 2018-01-10T13:11:51.661
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in 12b6daa4bdb03fa87da27cbc205ff88ace645475b5be79414a3038b68ade14cb
@@ -484,7 +484,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
 F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730
 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
 F src/select.c 8b22abe193e4d8243befa2038e4ae2405802fed1c446e5e502d11f652e09ba74
-F src/shell.c.in 1e50d66dc88bcc61d6300a5b8fb71d2d3821ec2d1418aee69337e391061514dd
+F src/shell.c.in f86200b08a8201fab1c775edbff4a81cb7b07e5926b1ed1ad7c043453fdfa7b3
 F src/sqlite.h.in 1f1a2da222ec57465794e8984d77f32d0bd0da80cdc136beadda461a0be9d80c
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
@@ -1697,7 +1697,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 36b89d728ff13d395fe0e1db8e7c01263f73dccb278b3ece27f6ef78e909b492
-R c0e5b3be89f9671131b70568ccd2de3b
+P fd7f51a107806666d5c3a3a7a62528ec3e1fb71c4256f49d57b4dcdac4bf8680
+R da66d185dcc66f20b0c30262a6b67fe7
+T *branch * archive-improvements
+T *sym-archive-improvements *
+T -sym-trunk *
 U drh
-Z 058862bc11ed7b27f8f707a776eec676
+Z 75859d5801ea825c715cde8533b487b8
index b802c2b17a661006874966308ab11bc2e8ccd6af..822237285ab6a627d755ad54d8f1fb66ce8e0232 100644 (file)
@@ -1 +1 @@
-fd7f51a107806666d5c3a3a7a62528ec3e1fb71c4256f49d57b4dcdac4bf8680
\ No newline at end of file
+a2baada429e84dc4b7243173a056e3c8bc042682f7efb01fdf8d2cc452c97e04
\ No newline at end of file
index 253b1c764d9d186f5f56414b10344a07d95b2e91..4bfc1c85ccdeb72149323d103a4befe84e00ed68 100644 (file)
@@ -4503,13 +4503,17 @@ static void shellReset(
 */
 typedef struct ArCommand ArCommand;
 struct ArCommand {
-  int eCmd;                       /* An AR_CMD_* value */
+  u8 eCmd;                        /* An AR_CMD_* value */
+  u8 bVerbose;                    /* True if --verbose */
+  u8 bZip;                        /* True if --zip */
+  u8 bDryRun;                     /* True if --dry-run */
+  int nArg;                       /* Number of command arguments */
+  const char *zSrcTable;          /* "sqlar", "zipfile($file)" or "zip" */
   const char *zFile;              /* --file argument, or NULL */
   const char *zDir;               /* --directory argument, or NULL */
-  int bVerbose;                   /* True if --verbose */
-  int bZip;                       /* True if --zip */
-  int nArg;                       /* Number of command arguments */
   char **azArg;                   /* Array of command arguments */
+  ShellState *p;                  /* Shell state */
+  sqlite3 *db;                    /* Database containing the archive */
 };
 
 /*
@@ -4536,6 +4540,8 @@ static int arUsage(FILE *f){
 "  -v, --verbose              Print each filename as it is processed\n"
 "  -f FILE, --file FILE       Operate on archive FILE (default is current db)\n"
 "  -C DIR, --directory DIR    Change to directory DIR to read/extract files\n"
+"  -n, --dryrun               Show the SQL that would have occurred\n"
+"  -z, --zip                  Operate on a ZIP archive instead of an SQLAR\n"
 "\n"
 "See also: http://sqlite.org/cli.html#sqlar_archive_support\n"
 "\n"
@@ -4570,10 +4576,11 @@ static int arErrorMsg(const char *zFmt, ...){
 /*
 ** Other (non-command) switches.
 */
-#define AR_SWITCH_VERBOSE   6
-#define AR_SWITCH_FILE      7
-#define AR_SWITCH_DIRECTORY 8
-#define AR_SWITCH_ZIP       9
+#define AR_SWITCH_VERBOSE     6
+#define AR_SWITCH_FILE        7
+#define AR_SWITCH_DIRECTORY   8
+#define AR_SWITCH_ZIP         9
+#define AR_SWITCH_DRYRUN     10
 
 static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
   switch( eSwitch ){
@@ -4588,6 +4595,9 @@ static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
       pAr->eCmd = eSwitch;
       break;
 
+    case AR_SWITCH_DRYRUN:
+      pAr->bDryRun = 1;
+      break;
     case AR_SWITCH_VERBOSE:
       pAr->bVerbose = 1;
       break;
@@ -4618,20 +4628,21 @@ static int arParseCommand(
   ArCommand *pAr                  /* Populate this object */
 ){
   struct ArSwitch {
-    char cShort;
     const char *zLong;
-    int eSwitch;
-    int bArg;
+    char cShort;
+    u8 eSwitch;
+    u8 bArg;
   } aSwitch[] = {
-    { 'c', "create",    AR_CMD_CREATE, 0 },
-    { 'x', "extract",   AR_CMD_EXTRACT, 0 },
-    { 't', "list",      AR_CMD_LIST, 0 },
-    { 'u', "update",    AR_CMD_UPDATE, 0 },
-    { 'h', "help",      AR_CMD_HELP, 0 },
-    { 'v', "verbose",   AR_SWITCH_VERBOSE, 0 },
-    { 'f', "file",      AR_SWITCH_FILE, 1 },
-    { 'C', "directory", AR_SWITCH_DIRECTORY, 1 },
-    { 'z', "zip",       AR_SWITCH_ZIP, 0 }
+    { "create",    'c', AR_CMD_CREATE,       0 },
+    { "extract",   'x', AR_CMD_EXTRACT,      0 },
+    { "list",      't', AR_CMD_LIST,         0 },
+    { "update",    'u', AR_CMD_UPDATE,       0 },
+    { "help",      'h', AR_CMD_HELP,         0 },
+    { "verbose",   'v', AR_SWITCH_VERBOSE,   0 },
+    { "file",      'f', AR_SWITCH_FILE,      1 },
+    { "directory", 'C', AR_SWITCH_DIRECTORY, 1 },
+    { "zip",       'z', AR_SWITCH_ZIP,       0 },
+    { "dryrun",    'n', AR_SWITCH_DRYRUN,    0 },
   };
   int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
   struct ArSwitch *pEnd = &aSwitch[nSwitch];
@@ -4758,37 +4769,40 @@ static int arParseCommand(
 ** This is consistent with the way the [tar] command seems to work on
 ** Linux.
 */
-static int arCheckEntries(sqlite3 *db, ArCommand *pAr){
+static int arCheckEntries(ArCommand *pAr){
   int rc = SQLITE_OK;
   if( pAr->nArg ){
-    int i;
+    int i, j;
     sqlite3_stmt *pTest = 0;
 
-    shellPreparePrintf(db, &rc, &pTest, "SELECT name FROM %s WHERE name=?1", 
-        pAr->bZip ? "zipfile(?2)" : "sqlar"
+    shellPreparePrintf(pAr->db, &rc, &pTest,
+        "SELECT name FROM %s WHERE name=$name", 
+        pAr->zSrcTable
     );
-    if( rc==SQLITE_OK && pAr->bZip ){
-      sqlite3_bind_text(pTest, 2, pAr->zFile, -1, SQLITE_TRANSIENT);
+    if( rc==SQLITE_OK
+     && (j = sqlite3_bind_parameter_index(pTest, "$archiveFile"))>0
+    ){
+      sqlite3_bind_text(pTest, j, pAr->zFile, -1, SQLITE_TRANSIENT);
     }
+    j = sqlite3_bind_parameter_index(pTest, "$name");
     for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
       char *z = pAr->azArg[i];
       int n = strlen30(z);
       int bOk = 0;
       while( n>0 && z[n-1]=='/' ) n--;
       z[n] = '\0';
-      sqlite3_bind_text(pTest, 1, z, -1, SQLITE_STATIC);
+      sqlite3_bind_text(pTest, j, z, -1, SQLITE_STATIC);
       if( SQLITE_ROW==sqlite3_step(pTest) ){
         bOk = 1;
       }
       shellReset(&rc, pTest);
       if( rc==SQLITE_OK && bOk==0 ){
-        raw_printf(stderr, "not found in archive: %s\n", z);
+        utf8_printf(stderr, "not found in archive: %s\n", z);
         rc = SQLITE_ERROR;
       }
     }
     shellFinalize(&rc, pTest);
   }
-
   return rc;
 }
 
@@ -4814,9 +4828,9 @@ static void arWhereClause(
       for(i=0; i<pAr->nArg; i++){
         const char *z = pAr->azArg[i];
         zWhere = sqlite3_mprintf(
-            "%z%s name = '%q' OR name BETWEEN '%q/' AND '%q0'", 
-            zWhere, zSep, z, z, z
-            );
+          "%z%s name = '%q' OR substr(name,1,%d) = '%q/'", 
+          zWhere, zSep, z, strlen30(z)+1, z
+        );
         if( zWhere==0 ){
           *pRc = SQLITE_NOMEM;
           break;
@@ -4858,9 +4872,8 @@ static void shellModeToString(char *zMode, int mode){
 /*
 ** Implementation of .ar "lisT" command. 
 */
-static int arListCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){
+static int arListCommand(ArCommand *pAr){
   const char *zSql = "SELECT %s FROM %s WHERE %s"; 
-  const char *zTbl = (pAr->bZip ? "zipfile(?)" : "sqlar");
   const char *azCols[] = {
     "name",
     "mode, sz, datetime(mtime, 'unixepoch'), name"
@@ -4869,29 +4882,36 @@ static int arListCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){
   char *zWhere = 0;
   sqlite3_stmt *pSql = 0;
   int rc;
+  int j;
 
-  rc = arCheckEntries(db, pAr);
+  rc = arCheckEntries(pAr);
   arWhereClause(&rc, pAr, &zWhere);
 
-  shellPreparePrintf(db, &rc, &pSql, zSql, azCols[pAr->bVerbose], zTbl, zWhere);
-  if( rc==SQLITE_OK && pAr->bZip ){
-    sqlite3_bind_text(pSql, 1, pAr->zFile, -1, SQLITE_TRANSIENT);
+  shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
+                     pAr->zSrcTable, zWhere);
+  if( rc==SQLITE_OK 
+   && (j = sqlite3_bind_parameter_index(pSql, "$archiveFile"))>0
+  ){
+    sqlite3_bind_text(pSql, j, pAr->zFile, -1, SQLITE_TRANSIENT);
   }
-  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
-    if( pAr->bVerbose ){
-      char zMode[11];
-      shellModeToString(zMode, sqlite3_column_int(pSql, 0));
-
-      raw_printf(p->out, "%s % 10d  %s  %s\n", zMode,
-          sqlite3_column_int(pSql, 1), 
-          sqlite3_column_text(pSql, 2),
-          sqlite3_column_text(pSql, 3)
-      );
-    }else{
-      raw_printf(p->out, "%s\n", sqlite3_column_text(pSql, 0));
+  if( pAr->bDryRun ){
+    utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
+  }else{
+    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
+      if( pAr->bVerbose ){
+        char zMode[11];
+        shellModeToString(zMode, sqlite3_column_int(pSql, 0));
+  
+        utf8_printf(pAr->p->out, "%s % 10d  %s  %s\n", zMode,
+            sqlite3_column_int(pSql, 1), 
+            sqlite3_column_text(pSql, 2),
+            sqlite3_column_text(pSql, 3)
+        );
+      }else{
+        utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
+      }
     }
   }
-
   shellFinalize(&rc, pSql);
   return rc;
 }
@@ -4900,31 +4920,28 @@ static int arListCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){
 /*
 ** Implementation of .ar "eXtract" command. 
 */
-static int arExtractCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){
+static int arExtractCommand(ArCommand *pAr){
   const char *zSql1 = 
     "SELECT "
-    "  :1 || name, "
-    "  writefile(?1 || name, %s, mode, mtime) "
-    "FROM %s WHERE (%s) AND (data IS NULL OR ?2 = 0)";
+    " ($dir || name),"
+    " writefile(($dir || name), %s, mode, mtime) "
+    "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)";
 
   const char *azExtraArg[] = { 
     "sqlar_uncompress(data, sz)",
     "data"
   };
-  const char *azSource[] = {
-    "sqlar", "zipfile(?3)"
-  };
 
   sqlite3_stmt *pSql = 0;
   int rc = SQLITE_OK;
   char *zDir = 0;
   char *zWhere = 0;
-  int i;
+  int i, j;
 
   /* If arguments are specified, check that they actually exist within
   ** the archive before proceeding. And formulate a WHERE clause to
   ** match them.  */
-  rc = arCheckEntries(db, pAr);
+  rc = arCheckEntries(pAr);
   arWhereClause(&rc, pAr, &zWhere);
 
   if( rc==SQLITE_OK ){
@@ -4936,14 +4953,16 @@ static int arExtractCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){
     if( zDir==0 ) rc = SQLITE_NOMEM;
   }
 
-  shellPreparePrintf(db, &rc, &pSql, zSql1, 
-      azExtraArg[pAr->bZip], azSource[pAr->bZip], zWhere
+  shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, 
+      azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere
   );
 
   if( rc==SQLITE_OK ){
-    sqlite3_bind_text(pSql, 1, zDir, -1, SQLITE_STATIC);
-    if( pAr->bZip ){
-      sqlite3_bind_text(pSql, 3, pAr->zFile, -1, SQLITE_STATIC);
+    j = sqlite3_bind_parameter_index(pSql, "$dir");
+    sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC);
+    j = sqlite3_bind_parameter_index(pSql, "$archiveFile");
+    if( j ){
+      sqlite3_bind_text(pSql, j, pAr->zFile, -1, SQLITE_STATIC);
     }
 
     /* Run the SELECT statement twice. The first time, writefile() is called
@@ -4952,10 +4971,15 @@ static int arExtractCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){
     ** extracted directories must be reset after they are populated (as
     ** populating them changes the timestamp).  */
     for(i=0; i<2; i++){
-      sqlite3_bind_int(pSql, 2, i);
-      while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
-        if( i==0 && pAr->bVerbose ){
-          raw_printf(p->out, "%s\n", sqlite3_column_text(pSql, 0));
+      j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
+      sqlite3_bind_int(pSql, j, i);
+      if( pAr->bDryRun ){
+        utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
+      }else{
+        while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
+          if( i==0 && pAr->bVerbose ){
+            utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
+          }
         }
       }
       shellReset(&rc, pSql);
@@ -4968,6 +4992,20 @@ static int arExtractCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){
   return rc;
 }
 
+/*
+** Run the SQL statement in zSql.  Or if doing a --dryrun, merely print it out.
+*/
+static int arExecSql(ArCommand *pAr, const char *zSql){
+  int rc;
+  if( pAr->bDryRun ){
+    utf8_printf(pAr->p->out, "%s\n", zSql);
+    rc = SQLITE_OK;
+  }else{
+    rc = sqlite3_exec(pAr->db, zSql, 0, 0, 0);
+  }
+  return rc;
+}
+
 
 /*
 ** Implementation of .ar "create" and "update" commands.
@@ -4980,11 +5018,9 @@ static int arExtractCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){
 ** The create command is the same as update, except that it drops
 ** any existing "sqlar" table before beginning.
 */
-static int arCreateUpdate(
-  ShellState *p,                  /* Shell state pointer */
-  sqlite3 *db,
+static int arCreateOrUpdateCommand(
   ArCommand *pAr,                 /* Command arguments and options */
-  int bUpdate
+  int bUpdate                     /* true for a --create.  false for --update */
 ){
   const char *zSql = "SELECT name, mode, mtime, data FROM fsdir(?, ?)";
   const char *zCreate = 
@@ -5005,17 +5041,17 @@ static int arCreateUpdate(
 
   assert( pAr->bZip==0 );
 
-  rc = sqlite3_exec(db, "SAVEPOINT ar;", 0, 0, 0);
+  rc = arExecSql(pAr, "SAVEPOINT ar;");
   if( rc!=SQLITE_OK ) return rc;
 
   if( bUpdate==0 ){
-    rc = sqlite3_exec(db, zDrop, 0, 0, 0);
+    rc = arExecSql(pAr, zDrop);
     if( rc!=SQLITE_OK ) return rc;
   }
 
-  rc = sqlite3_exec(db, zCreate, 0, 0, 0);
-  shellPrepare(db, &rc, zInsert, &pInsert);
-  shellPrepare(db, &rc, zSql, &pStmt);
+  rc = arExecSql(pAr, zCreate);
+  shellPrepare(pAr->db, &rc, zInsert, &pInsert);
+  shellPrepare(pAr->db, &rc, zSql, &pStmt);
   sqlite3_bind_text(pStmt, 2, pAr->zDir, -1, SQLITE_STATIC);
 
   for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
@@ -5027,7 +5063,7 @@ static int arCreateUpdate(
       unsigned int mtime = sqlite3_column_int(pStmt, 2);
 
       if( pAr->bVerbose ){
-        raw_printf(p->out, "%s\n", zName);
+        utf8_printf(pAr->p->out, "%s\n", zName);
       }
 
       sqlite3_bind_text(pInsert, 1, zName, -1, SQLITE_STATIC);
@@ -5047,46 +5083,26 @@ static int arCreateUpdate(
       }
 
       sqlite3_bind_int(pInsert, 4, sz);
-      sqlite3_step(pInsert);
+      if( pAr->bDryRun ){
+        utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pInsert));
+      }else{
+        sqlite3_step(pInsert);
+      }
       rc = sqlite3_reset(pInsert);
     }
     shellReset(&rc, pStmt);
   }
 
   if( rc!=SQLITE_OK ){
-    sqlite3_exec(db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0);
+    arExecSql(pAr, "ROLLBACK TO ar; RELEASE ar;");
   }else{
-    rc = sqlite3_exec(db, "RELEASE ar;", 0, 0, 0);
+    rc = arExecSql(pAr, "RELEASE ar;");
   }
   shellFinalize(&rc, pStmt);
   shellFinalize(&rc, pInsert);
   return rc;
 }
 
-/*
-** Implementation of .ar "Create" command. 
-**
-** Create the "sqlar" table in the database if it does not already exist.
-** Then add each file in the azFile[] array to the archive. Directories
-** are added recursively. If argument bVerbose is non-zero, a message is
-** printed on stdout for each file archived.
-*/
-static int arCreateCommand(
-  ShellState *p,                  /* Shell state pointer */
-  sqlite3 *db,
-  ArCommand *pAr                  /* Command arguments and options */
-){
-  return arCreateUpdate(p, db, pAr, 0);
-}
-
-/*
-** Implementation of .ar "Update" command. 
-*/
-static int arUpdateCmd(ShellState *p, sqlite3 *db, ArCommand *pAr){
-  return arCreateUpdate(p, db, pAr, 1);
-}
-
-
 /*
 ** Implementation of ".ar" dot command.
 */
@@ -5099,18 +5115,19 @@ static int arDotCommand(
   int rc;
   rc = arParseCommand(azArg, nArg, &cmd);
   if( rc==SQLITE_OK ){
-    sqlite3 *db = 0;              /* Database handle to use as archive */
-
+    cmd.p = pState;
+    cmd.db = pState->db;
+    cmd.zSrcTable = "sqlar";
     if( cmd.bZip ){
-      if( cmd.zFile==0 ){
-        raw_printf(stderr, "zip format requires a --file switch\n");
-        return SQLITE_ERROR;
-      }else
+      if( pState->openMode==SHELL_OPEN_ZIPFILE ){
+        cmd.zSrcTable = "zip";
+      }else{
+        cmd.zSrcTable = "zipfile($archiveFile)";
+      }
       if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){
-        raw_printf(stderr, "zip archives are read-only\n");
+        utf8_printf(stderr, "zip archives are read-only\n");
         return SQLITE_ERROR;
       }
-      db = pState->db;
     }else if( cmd.zFile ){
       int flags;
       if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){
@@ -5118,33 +5135,31 @@ static int arDotCommand(
       }else{
         flags = SQLITE_OPEN_READONLY;
       }
-      rc = sqlite3_open_v2(cmd.zFile, &db, flags, 0);
+      rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, 0);
       if( rc!=SQLITE_OK ){
-        raw_printf(stderr, "cannot open file: %s (%s)\n", 
-            cmd.zFile, sqlite3_errmsg(db)
+        utf8_printf(stderr, "cannot open file: %s (%s)\n", 
+            cmd.zFile, sqlite3_errmsg(cmd.db)
         );
-        sqlite3_close(db);
+        sqlite3_close(cmd.db);
         return rc;
       }
-      sqlite3_fileio_init(db, 0, 0);
+      sqlite3_fileio_init(cmd.db, 0, 0);
 #ifdef SQLITE_HAVE_ZLIB
-      sqlite3_sqlar_init(db, 0, 0);
+      sqlite3_sqlar_init(cmd.db, 0, 0);
 #endif
-    }else{
-      db = pState->db;
     }
 
     switch( cmd.eCmd ){
       case AR_CMD_CREATE:
-        rc = arCreateCommand(pState, db, &cmd);
+        rc = arCreateOrUpdateCommand(&cmd, 0);
         break;
 
       case AR_CMD_EXTRACT:
-        rc = arExtractCommand(pState, db, &cmd);
+        rc = arExtractCommand(&cmd);
         break;
 
       case AR_CMD_LIST:
-        rc = arListCommand(pState, db, &cmd);
+        rc = arListCommand(&cmd);
         break;
 
       case AR_CMD_HELP:
@@ -5153,12 +5168,12 @@ static int arDotCommand(
 
       default:
         assert( cmd.eCmd==AR_CMD_UPDATE );
-        rc = arUpdateCmd(pState, db, &cmd);
+        rc = arCreateOrUpdateCommand(&cmd, 1);
         break;
     }
 
     if( cmd.zFile ){
-      sqlite3_close(db);
+      sqlite3_close(cmd.db);
     }
   }