diff --git a/manifest b/manifest index cf862a931a..d35fbb58c9 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 9a134cbc63..61176bde88 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a62129af99b4a576a48eb4931f417af257f510c7 \ No newline at end of file +b56afe640f7f3f2837120e3dd923c529c4a3123a \ No newline at end of file diff --git a/src/main.c b/src/main.c index 2bb38862b6..def984a291 100644 --- a/src/main.c +++ b/src/main.c @@ -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; } /* diff --git a/src/parse.y b/src/parse.y index efb242045d..085a702bc6 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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 ::= . diff --git a/src/shell.c b/src/shell.c index 164cb36501..03a8081a79 100644 --- a/src/shell.c +++ b/src/shell.c @@ -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 #include @@ -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,"\n"); break; } + case MODE_Tcl: { + if( p->cnt++==0 && p->showHeader ){ + for(i=0; iout,azCol[i]); + fprintf(p->out, "%s", p->separator); + } + fprintf(p->out,"\n"); + } + if( azArg==0 ) break; + for(i=0; iout, 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; idb, 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( idb, "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 ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index d3f314a25d..f4bf1ed988 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -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 /* diff --git a/src/vdbeapi.c b/src/vdbeapi.c index ced6437d4b..8c8c27816f 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -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];