]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the ".import" command to the command-line shell. (CVS 1873)
authordrh <drh@noemail.net>
Sun, 1 Aug 2004 00:10:45 +0000 (00:10 +0000)
committerdrh <drh@noemail.net>
Sun, 1 Aug 2004 00:10:45 +0000 (00:10 +0000)
FossilOrigin-Name: b56afe640f7f3f2837120e3dd923c529c4a3123a

manifest
manifest.uuid
src/main.c
src/parse.y
src/shell.c
src/sqlite.h.in
src/vdbeapi.c

index cf862a931ad6754a644413c82ec16df643a1cf97..d35fbb58c940715fc65e8151867156793f080495 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Additional\stest\scase\sto\scover\sticket\s#831.\s(CVS\s1872)
-D 2004-07-27T13:38:48
+C Add\sthe\s".import"\scommand\sto\sthe\scommand-line\sshell.\s(CVS\s1873)
+D 2004-08-01T00:10:45
 F Makefile.in 4a5e570a9e2d35b09c31b3cf01b78cea764ade4b
 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -39,7 +39,7 @@ F src/hash.c f0a2f22c2a7052d67053b5f4690ea3010bb3fb9f
 F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
 F src/insert.c bedcba371401395033a1a1c578d8fdc3fec87bec
 F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
-F src/main.c 49ea4a45223a002d06b5a4a5db36327acafc1779
+F src/main.c 41da595846e299b757cc413d18de804f97f68748
 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
 F src/os.h d1780e0db95cad01f213d48da22ab490eb4fd345
 F src/os_common.h fe9604754116bd2f2702d58f82d2d8b89998cb21
@@ -53,13 +53,13 @@ F src/os_win.c 54181eb73cb4783c4241feca9eaa490768b39008
 F src/os_win.h babd4e912967c6b09088cfe38a45e8005a07ba44
 F src/pager.c e0865a9afa64f59c6dc1cc1ab50bc700f67ee28b
 F src/pager.h 67739fe649f33be55dba522ca8a9cc4e42d14f71
-F src/parse.y 0bcc53bba498081a544e50c8845bf4857ebfccb9
+F src/parse.y 589b1a39b23092888adfa9ec1f3ded8a35e8e006
 F src/pragma.c c8be18093f0492f9983406647808781ca0073d8b
 F src/printf.c 17b28a1eedfe8129b05de981719306c18c3f1327
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
 F src/select.c cbed45f4af76ad7fdfc0a0df6878b2b3827ae1d4
-F src/shell.c 93c96c847228c02fb84bb381875d87ee71fbbeb4
-F src/sqlite.h.in d5d542e3cfd25c79f46239d1722d8333f1b16796
+F src/shell.c 7371f0a4b1c1aaed336176dfcc6e6742c138b263
+F src/sqlite.h.in c340a12b4d0521efb474dd000fba3bdfb18d76da
 F src/sqliteInt.h 691d584330cadab3801280caa49eb479fe2446a3
 F src/table.c 4521c278892f60e4d630788c0ea5cf4db1e75c49
 F src/tclsqlite.c cece44ee1d4427185e4ac85ddec79f31ac26965a
@@ -77,7 +77,7 @@ F src/vacuum.c 9978a5760c2c430bc5b5e66505a02dad76f25813
 F src/vdbe.c f40f4ca4d9a7ba7c330e5673419f32dd3512547c
 F src/vdbe.h 75b241c02431b9c0f16eaa9cdbb34146c6287f52
 F src/vdbeInt.h 3d8e08c54dcb5ca2169db8bb3a37b81a12efaecd
-F src/vdbeapi.c c5c6d8f162a9581dde497b1a4034f9a0bf54c355
+F src/vdbeapi.c 3be4ccab4ba6c21d60feffc48e22cf8c1643c6d5
 F src/vdbeaux.c daf40a292ec458ed962845a8d95d5c96bc242e04
 F src/vdbemem.c bbf621377343bee046547712a144a94f387bb1eb
 F src/where.c cf8a54641eea01f1af5d09529ad69166db92f658
@@ -240,7 +240,7 @@ F www/tclsqlite.tcl 06a86cba4d7fc88e2bcd633b57702d3d16abebb5
 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 76fe68cff6ce75dada510544b063dc1069eb2e0e
-R c48658c71737283e3919f2cd9abce5ad
+P a62129af99b4a576a48eb4931f417af257f510c7
+R b813c752399c5314294f809547b48dc6
 U drh
-Z ed9af753dbee169dca4931e23b4b59b8
+Z a47918bb8602f63d1d3008ff249473a1
index 9a134cbc632b1b3a06fe060bdee978174fb2984f..61176bde8802ff977e9d116ff178fddf6ace96ef 100644 (file)
@@ -1 +1 @@
-a62129af99b4a576a48eb4931f417af257f510c7
\ No newline at end of file
+b56afe640f7f3f2837120e3dd923c529c4a3123a
\ No newline at end of file
index 2bb38862b63c5cadcdf26303fd4e90767ca1c82a..def984a291270167facca33b477c1a862d485906 100644 (file)
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.248 2004/07/24 14:35:58 drh Exp $
+** $Id: main.c,v 1.249 2004/08/01 00:10:45 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -1242,7 +1242,7 @@ int sqlite3_open16(
 ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
 */
 int sqlite3_finalize(sqlite3_stmt *pStmt){
-  return sqlite3VdbeFinalize((Vdbe*)pStmt);
+  return pStmt ? sqlite3VdbeFinalize((Vdbe*)pStmt) : SQLITE_OK;
 }
 
 /*
index efb242045d37c199ef8bff3e48758127fdb946ac..085a702bc6709d1df7e2ad6a33edf98fbd39b4f8 100644 (file)
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.131 2004/07/22 15:02:25 drh Exp $
+** @(#) $Id: parse.y,v 1.132 2004/08/01 00:10:45 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -902,10 +902,8 @@ cmd ::= ATTACH database_kw_opt ids(F) AS nm(D) key_opt(K). {
 }
 %type key_opt {struct AttachKey}
 key_opt(A) ::= .                     { A.type = 0; }
-%ifdef SQLITE_HAS_CODEC
 key_opt(A) ::= KEY ids(X).           { A.type=1; A.key = X; }
-key_opt(A) ::= KEY BLOB(X).          { A.type=2; A.Key = X; }
-%endif
+key_opt(A) ::= KEY BLOB(X).          { A.type=2; A.key = X; }
 
 database_kw_opt ::= DATABASE.
 database_kw_opt ::= .
index 164cb365018e82a838fcfb3dba74bdd974244d1c..03a8081a7986db7b381749757803170229fc60a9 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.107 2004/07/22 02:40:38 drh Exp $
+** $Id: shell.c,v 1.108 2004/08/01 00:10:45 drh Exp $
 */
 #include <stdlib.h>
 #include <string.h>
@@ -104,7 +104,7 @@ static void shellstaticFunc(
 
 
 /*
-** This routine reads a line of text from standard input, stores
+** This routine reads a line of text from FILE in, stores
 ** the text in memory obtained from malloc() and returns a pointer
 ** to the text.  NULL is returned at end of file, or if malloc()
 ** fails.
@@ -219,7 +219,8 @@ struct callback_data {
 #define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
 #define MODE_Html     4  /* Generate an XHTML table */
 #define MODE_Insert   5  /* Generate SQL "insert" statements */
-#define MODE_NUM_OF   6  /* The number of modes (not a mode itself) */
+#define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
+#define MODE_NUM_OF   7  /* The number of modes (not a mode itself) */
 
 char *modeDescr[MODE_NUM_OF] = {
   "line",
@@ -227,7 +228,8 @@ char *modeDescr[MODE_NUM_OF] = {
   "list",
   "semi",
   "html",
-  "insert"
+  "insert",
+  "tcl",
 };
 
 /*
@@ -265,6 +267,34 @@ static void output_quoted_string(FILE *out, const char *z){
   }
 }
 
+/*
+** Output the given string as a quoted according to C or TCL quoting rules.
+*/
+static void output_c_string(FILE *out, const char *z){
+  unsigned int c;
+  fputc('"', out);
+  while( (c = *(z++))!=0 ){
+    if( c=='\\' ){
+      fputc(c, out);
+      fputc(c, out);
+    }else if( c=='\t' ){
+      fputc('\\', out);
+      fputc('t', out);
+    }else if( c=='\n' ){
+      fputc('\\', out);
+      fputc('n', out);
+    }else if( c=='\r' ){
+      fputc('\\', out);
+      fputc('r', out);
+    }else if( !isprint(c) ){
+      fprintf(out, "\\%03o", c);
+    }else{
+      fputc(c, out);
+    }
+  }
+  fputc('"', out);
+}
+
 /*
 ** Output the given string with characters that are special to
 ** HTML escaped.
@@ -406,6 +436,22 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
       fprintf(p->out,"</TR>\n");
       break;
     }
+    case MODE_Tcl: {
+      if( p->cnt++==0 && p->showHeader ){
+        for(i=0; i<nArg; i++){
+          output_c_string(p->out,azCol[i]);
+          fprintf(p->out, "%s", p->separator);
+        }
+        fprintf(p->out,"\n");
+      }
+      if( azArg==0 ) break;
+      for(i=0; i<nArg; i++){
+        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
+        fprintf(p->out, "%s", p->separator);
+      }
+      fprintf(p->out,"\n");
+      break;
+    }
     case MODE_Insert: {
       if( azArg==0 ) break;
       fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
@@ -603,9 +649,10 @@ static char zHelp[] =
   ".explain ON|OFF        Turn output mode suitable for EXPLAIN on or off.\n"
   ".header(s) ON|OFF      Turn display of headers on or off\n"
   ".help                  Show this message\n"
+  ".import FILE TABLE     Import data from FILE\n"
   ".indices TABLE         Show names of all indices on TABLE\n"
-  ".mode MODE             Set mode to one of \"line(s)\", \"column(s)\", \n"
-  "                       \"insert\", \"list\", or \"html\"\n"
+  ".mode MODE             Set mode to one of: cvs column html insert line\n"
+  "                       list tabs tcl\n"
   ".mode insert TABLE     Generate SQL insert statements for TABLE\n"
   ".nullvalue STRING      Print STRING instead of nothing for NULL data\n"
   ".output FILENAME       Send output to FILENAME\n"
@@ -617,9 +664,9 @@ static char zHelp[] =
   ".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"
+  ".separator STRING      Change separator string\n"
   ".show                  Show the current values for various settings\n"
-  ".tables ?PATTERN?      List names of tables matching a pattern\n"
+  ".tables ?PATTERN?      List names of tables matching a LIKE pattern\n"
   ".timeout MS            Try opening locked tables for MS milliseconds\n"
   ".width NUM NUM ...     Set column widths for \"column\" mode\n"
 ;
@@ -648,6 +695,43 @@ static void open_db(struct callback_data *p){
   }
 }
 
+/*
+** Do C-language style dequoting.
+**
+**    \t    -> tab
+**    \n    -> newline
+**    \r    -> carriage return
+**    \NNN  -> ascii character NNN in octal
+**    \\    -> backslash
+*/
+static void resolve_backslashes(char *z){
+  int i, j, c;
+  for(i=j=0; (c = z[i])!=0; i++, j++){
+    if( c=='\\' ){
+      c = z[++i];
+      if( c=='n' ){
+        c = '\n';
+      }else if( c=='t' ){
+        c = '\t';
+      }else if( c=='r' ){
+        c = '\r';
+      }else if( c>='0' && c<='7' ){
+        c =- '0';
+        if( z[i+1]>='0' && z[i+1]<='7' ){
+          i++;
+          c = (c<<3) + z[i] - '0';
+          if( z[i+1]>='0' && z[i+1]<='7' ){
+            i++;
+            c = (c<<3) + z[i] - '0';
+          }
+        }
+      }
+    }
+    z[j] = c;
+  }
+  z[j] = 0;
+}
+
 /*
 ** If an input line begins with "." then invoke this routine to
 ** process that line.
@@ -673,10 +757,12 @@ static int do_meta_command(char *zLine, struct callback_data *p){
       if( zLine[i]==delim ){
         zLine[i++] = 0;
       }
+      if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
     }else{
       azArg[nArg++] = &zLine[i];
       while( zLine[i] && !isspace(zLine[i]) ){ i++; }
       if( zLine[i] ) zLine[i++] = 0;
+      resolve_backslashes(azArg[nArg-1]);
     }
   }
 
@@ -816,6 +902,98 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     fprintf(stderr,zHelp);
   }else
 
+  if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg>=3 ){
+    char *zTable = azArg[2];    /* Insert data into this table */
+    char *zFile = azArg[1];     /* The file from which to extract data */
+    sqlite3_stmt *pStmt;        /* A statement */
+    int rc;                     /* Result code */
+    int nCol;                   /* Number of columns in the table */
+    int nByte;                  /* Number of bytes in an SQL string */
+    int i, j;                   /* Loop counters */
+    int nSep;                   /* Number of bytes in p->separator[] */
+    char *zSql;                 /* An SQL statement */
+    char *zLine;                /* A single line of input from the file */
+    char **azCol;               /* zLine[] broken up into columns */
+    char *zCommit;              /* How to commit changes */   
+    FILE *in;                   /* The input file */      
+
+    nSep = strlen(p->separator);
+    if( nSep==0 ){
+      fprintf(stderr, "non-null separator required for import\n");
+      return 0;
+    }
+    zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
+    if( zSql==0 ) return 0;
+    nByte = strlen(zSql);
+    rc = sqlite3_prepare(p->db, zSql, 0, &pStmt, 0);
+    sqlite3_free(zSql);
+    if( rc ){
+      fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
+      nCol = 0;
+    }else{
+      nCol = sqlite3_column_count(pStmt);
+    }
+    sqlite3_finalize(pStmt);
+    if( nCol==0 ) return 0;
+    zSql = malloc( nByte + 20 + nCol*2 );
+    if( zSql==0 ) return 0;
+    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO '%q' VALUES(?", zTable);
+    j = strlen(zSql);
+    for(i=1; i<nCol; i++){
+      zSql[j++] = ',';
+      zSql[j++] = '?';
+    }
+    zSql[j++] = ')';
+    zSql[j] = 0;
+    rc = sqlite3_prepare(p->db, zSql, 0, &pStmt, 0);
+    free(zSql);
+    if( rc ){
+      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
+      sqlite3_finalize(pStmt);
+      return 0;
+    }
+    in = fopen(zFile, "rb");
+    if( in==0 ){
+      fprintf(stderr, "cannot open file: %s\n", zFile);
+      sqlite3_finalize(pStmt);
+      return 0;
+    }
+    azCol = malloc( sizeof(azCol[0])*(nCol+1) );
+    if( azCol==0 ) return 0;
+    sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
+    zCommit = "COMMIT";
+    while( (zLine = local_getline(0, in))!=0 ){
+      char *z;
+      i = 0;
+      azCol[0] = zLine;
+      for(i=0, z=zLine; *z; z++){
+        if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){
+          *z = 0;
+          i++;
+          if( i>=nCol ) break;
+          azCol[i] = &z[nSep];
+          z += nSep-1;
+        }
+      }
+      while( i<nCol ) azCol[i++] = 0;
+      for(i=0; i<nCol; i++){
+        sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
+      }
+      sqlite3_step(pStmt);
+      rc = sqlite3_reset(pStmt);
+      free(zLine);
+      if( rc!=SQLITE_OK ){
+        fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
+        zCommit = "ROLLBACK";
+        break;
+      }
+    }
+    free(azCol);
+    fclose(in);
+    sqlite3_finalize(pStmt);
+    sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
+  }else
+
   if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
     struct callback_data data;
     char *zErrMsg = 0;
@@ -854,6 +1032,14 @@ static int do_meta_command(char *zLine, struct callback_data *p){
       p->mode = MODE_List;
     }else if( strncmp(azArg[1],"html",n2)==0 ){
       p->mode = MODE_Html;
+    }else if( strncmp(azArg[1],"tcl",n2)==0 ){
+      p->mode = MODE_Tcl;
+    }else if( strncmp(azArg[1],"csv",n2)==0 ){
+      p->mode = MODE_List;
+      strcpy(p->separator, ",");
+    }else if( strncmp(azArg[1],"tabs",n2)==0 ){
+      p->mode = MODE_List;
+      strcpy(p->separator, "\t");
     }else if( strncmp(azArg[1],"insert",n2)==0 ){
       p->mode = MODE_Insert;
       if( nArg>=3 ){
@@ -862,7 +1048,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
         set_table_name(p, "table");
       }
     }else {
-      fprintf(stderr,"mode should be on of: column html insert line list\n");
+      fprintf(stderr,"mode should be on of: "
+         "column csv html insert line list tabs tcl\n");
     }
   }else
 
@@ -999,15 +1186,19 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
     fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
     fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
-    fprintf(p->out,"%9.9s: %s\n","nullvalue", p->nullvalue);
+    fprintf(p->out,"%9.9s: ", "nullvalue");
+      output_c_string(p->out, p->nullvalue);
+      fprintf(p->out, "\n");
     fprintf(p->out,"%9.9s: %s\n","output",
                                  strlen(p->outfile) ? p->outfile : "stdout");
-    fprintf(p->out,"%9.9s: %s\n","separator", p->separator);
+    fprintf(p->out,"%9.9s: ", "separator");
+      output_c_string(p->out, p->separator);
+      fprintf(p->out, "\n");
     fprintf(p->out,"%9.9s: ","width");
     for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
-        fprintf(p->out,"%d ",p->colWidth[i]);
+      fprintf(p->out,"%d ",p->colWidth[i]);
     }
-    fprintf(p->out,"\n\n");
+    fprintf(p->out,"\n");
   }else
 
   if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
index d3f314a25d2e9a15e3c30e632a71829b09eff902..f4bf1ed9880f02275b5910560cf3c1eed1753079 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.111 2004/07/26 12:24:23 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.112 2004/08/01 00:10:45 drh Exp $
 */
 #ifndef _SQLITE_H_
 #define _SQLITE_H_
@@ -364,6 +364,7 @@ void sqlite3_free_table(char **result);
 char *sqlite3_mprintf(const char*,...);
 char *sqlite3_vmprintf(const char*, va_list);
 void sqlite3_free(char *z);
+char *sqlite3_snprintf(int,char*,const char*, ...);
 
 #ifndef SQLITE_OMIT_AUTHORIZATION
 /*
index ced6437d4b266491f42a49506cf4aa9006258221..8c8c27816f14f7deec90e3ba968a9dfc4fd55a68 100644 (file)
@@ -436,7 +436,7 @@ int sqlite3_bind_blob(
   int rc;
 
   rc = vdbeUnbind(p, i);
-  if( rc ){
+  if( rc || zData==0 ){
     return rc;
   }
   pVar = &p->apVar[i-1];
@@ -479,7 +479,7 @@ int sqlite3_bind_text(
   int rc;
 
   rc = vdbeUnbind(p, i);
-  if( rc ){
+  if( rc || zData==0 ){
     return rc;
   }
   pVar = &p->apVar[i-1];
@@ -502,7 +502,7 @@ int sqlite3_bind_text16(
   int rc;
 
   rc = vdbeUnbind(p, i);
-  if( rc ){
+  if( rc || zData==0 ){
     return rc;
   }
   pVar = &p->apVar[i-1];