In the command-line shell, and the ".binary" command and additional

C-style backslash escapes.

FossilOrigin-Name: 850c11866686a7b39d7b163fb60898c11283688e
This commit is contained in:
drh 2015-05-04 19:13:25 +00:00
commit d1055b1bd5
5 changed files with 190 additions and 16 deletions

View File

@ -1,5 +1,5 @@
C Add\sthe\s"dbstat"\svirtual\stable\sas\sa\sstandard\scomponent\sin\sthe\sSQLite\namalgamation,\sthough\sturned\soff\sunless\scompiled\swith\sSQLITE_ENABLE_DBSTAT_VTAB.
D 2015-05-04T19:06:09.589
C In\sthe\scommand-line\sshell,\sand\sthe\s".binary"\scommand\sand\sadditional\nC-style\sbackslash\sescapes.
D 2015-05-04T19:13:25.970
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 382b774885a3f0ac5207b1835e92c96b641c85e5
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -181,7 +181,7 @@ F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575
F src/ctime.c 98f89724adc891a1a4c655bee04e33e716e05887
F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac
F src/dbstat.c ae435cf8c8ec8d2438835f245ed2e7f3c1996cc9 w src/test_stat.c
F src/dbstat.c ae435cf8c8ec8d2438835f245ed2e7f3c1996cc9
F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e
F src/expr.c 4c05a28eebe63b288fda1db0e8de556a82ca2ec6
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
@ -232,7 +232,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c 13109bc3b5ab404446296efa17039640de5bc35d
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c 1b0bfc7d59e48c26b895a6b719157111a617d9e3
F src/shell.c 4ef9436ea7d1016584421067b16ba8a41c506dc4
F src/shell.c ad4c91f89eaced670f5c0d57531dda3fef3a4afe
F src/sqlite.h.in ca27603a36fcacdaac5a19d8ee35aaff8ce8516f
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
@ -869,7 +869,7 @@ F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test ca88b14a8fc8b1f3543a24e519d019585ac9c903
F test/shell1.test ce5e744870387164703bf2dee2cc9753e4a71513
F test/shell2.test 12b8bf901b0e3a8ac58cf5c0c63a0a388d4d1862
F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
F test/shell4.test ddf0a99044e2245a87fc17423e3aaa1445b3243b
@ -920,7 +920,7 @@ F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
F test/tester.tcl ed77454e6c7b40eb501db7e79d1c6fbfd3eebbff
F test/tester.tcl 51211254f2ee2340d3e4fa0a83bd5381b9e1a227
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@ -1256,8 +1256,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 1421c8ffba179d6aafa2643012f80a2738779117 a24480a474993f82ff58edbe12d2093c59b1a2dc
R 320890eb90a509d549c3b65f61bb2b7a
T +closed a24480a474993f82ff58edbe12d2093c59b1a2dc
P e7529705903a9d4d410801658a47fb43a4f2de2f 22827542a5c7aeac4385ba647f45bd500e787fe6
R c2304b3b31b242f903f6a4281630c0d1
T +closed 22827542a5c7aeac4385ba647f45bd500e787fe6
U drh
Z 2cb33eb36021c827866f2a0db467007d
Z 33af9893538436935c8227ae916eb9bb

View File

@ -1 +1 @@
e7529705903a9d4d410801658a47fb43a4f2de2f
850c11866686a7b39d7b163fb60898c11283688e

View File

@ -990,7 +990,16 @@ static int shell_callback(
case MODE_Insert: {
p->cnt++;
if( azArg==0 ) break;
fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
fprintf(p->out,"INSERT INTO %s",p->zDestTable);
if( p->showHeader ){
fprintf(p->out,"(");
for(i=0; i<nArg; i++){
char *zSep = i>0 ? ",": "";
fprintf(p->out, "%s%s", zSep, azCol[i]);
}
fprintf(p->out,")");
}
fprintf(p->out," VALUES(");
for(i=0; i<nArg; i++){
char *zSep = i>0 ? ",": "";
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
@ -1772,6 +1781,7 @@ static int run_schema_dump_query(
static char zHelp[] =
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
".bail on|off Stop after hitting an error. Default OFF\n"
".binary on|off Turn binary output on or off. Default OFF\n"
".clone NEWDB Clone data into NEWDB from the existing database\n"
".databases List names and files of attached databases\n"
".dbinfo ?DB? Show status information about the database\n"
@ -1940,12 +1950,18 @@ static void open_db(ShellState *p, int keepAlive){
/*
** Do C-language style dequoting.
**
** \a -> alarm
** \b -> backspace
** \t -> tab
** \n -> newline
** \v -> vertical tab
** \f -> form feed
** \r -> carriage return
** \s -> space
** \" -> "
** \NNN -> ascii character NNN in octal
** \' -> '
** \\ -> backslash
** \NNN -> ascii character NNN in octal
*/
static void resolve_backslashes(char *z){
int i, j;
@ -1954,12 +1970,24 @@ static void resolve_backslashes(char *z){
for(i=j=0; (c = z[i])!=0; i++, j++){
if( c=='\\' && z[i+1]!=0 ){
c = z[++i];
if( c=='n' ){
c = '\n';
if( c=='a' ){
c = '\a';
}else if( c=='b' ){
c = '\b';
}else if( c=='t' ){
c = '\t';
}else if( c=='n' ){
c = '\n';
}else if( c=='v' ){
c = '\v';
}else if( c=='f' ){
c = '\f';
}else if( c=='r' ){
c = '\r';
}else if( c=='"' ){
c = '"';
}else if( c=='\'' ){
c = '\'';
}else if( c=='\\' ){
c = '\\';
}else if( c>='0' && c<='7' ){
@ -2693,6 +2721,19 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){
if( nArg==2 ){
if( booleanValue(azArg[1]) ){
setBinaryMode(p->out);
}else{
setTextMode(p->out);
}
}else{
fprintf(stderr, "Usage: .binary on|off\n");
rc = 1;
}
}else
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/

View File

@ -738,6 +738,9 @@ do_test shell1-4.1 {
PRAGMA encoding=UTF16;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f');
CREATE TABLE t3(x,y);
INSERT INTO t3 VALUES(1,null), (2,''), (3,1),
(4,2.25), (5,'hello'), (6,x'807f');
}
catchcmd test.db {.dump}
} {0 {PRAGMA foreign_keys=OFF;
@ -749,11 +752,18 @@ INSERT INTO "t1" VALUES(1);
INSERT INTO "t1" VALUES(2.25);
INSERT INTO "t1" VALUES('hello');
INSERT INTO "t1" VALUES(X'807F');
CREATE TABLE t3(x,y);
INSERT INTO "t3" VALUES(1,NULL);
INSERT INTO "t3" VALUES(2,'');
INSERT INTO "t3" VALUES(3,1);
INSERT INTO "t3" VALUES(4,2.25);
INSERT INTO "t3" VALUES(5,'hello');
INSERT INTO "t3" VALUES(6,X'807F');
COMMIT;}}
# Test the output of ".mode insert"
#
do_test shell1-4.2 {
do_test shell1-4.2.1 {
catchcmd test.db ".mode insert t1\nselect * from t1;"
} {0 {INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES('');
@ -762,6 +772,39 @@ INSERT INTO t1 VALUES(2.25);
INSERT INTO t1 VALUES('hello');
INSERT INTO t1 VALUES(X'807f');}}
# Test the output of ".mode insert" with headers
#
do_test shell1-4.2.2 {
catchcmd test.db ".mode insert t1\n.headers on\nselect * from t1;"
} {0 {INSERT INTO t1(x) VALUES(NULL);
INSERT INTO t1(x) VALUES('');
INSERT INTO t1(x) VALUES(1);
INSERT INTO t1(x) VALUES(2.25);
INSERT INTO t1(x) VALUES('hello');
INSERT INTO t1(x) VALUES(X'807f');}}
# Test the output of ".mode insert"
#
do_test shell1-4.2.3 {
catchcmd test.db ".mode insert t3\nselect * from t3;"
} {0 {INSERT INTO t3 VALUES(1,NULL);
INSERT INTO t3 VALUES(2,'');
INSERT INTO t3 VALUES(3,1);
INSERT INTO t3 VALUES(4,2.25);
INSERT INTO t3 VALUES(5,'hello');
INSERT INTO t3 VALUES(6,X'807f');}}
# Test the output of ".mode insert" with headers
#
do_test shell1-4.2.4 {
catchcmd test.db ".mode insert t3\n.headers on\nselect * from t3;"
} {0 {INSERT INTO t3(x,y) VALUES(1,NULL);
INSERT INTO t3(x,y) VALUES(2,'');
INSERT INTO t3(x,y) VALUES(3,1);
INSERT INTO t3(x,y) VALUES(4,2.25);
INSERT INTO t3(x,y) VALUES(5,'hello');
INSERT INTO t3(x,y) VALUES(6,X'807f');}}
# Test the output of ".mode tcl"
#
do_test shell1-4.3 {
@ -818,4 +861,61 @@ do_test shell1-4.6 {
";"
"$"} 7}
# Test using arbitrary byte data with the shell via standard input/output.
#
do_test shell1-5.0 {
#
# NOTE: Skip NUL byte because it appears to be incompatible with command
# shell argument parsing.
#
for {set i 1} {$i < 256} {incr i} {
#
# NOTE: Due to how the Tcl [exec] command works (i.e. where it treats
# command channels opened for it as textual ones), the carriage
# return character (and on Windows, the end-of-file character)
# cannot be used here.
#
if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} {
continue
}
set hex [format %02X $i]
set char [subst \\x$hex]; set oldChar $char
set escapes [list]
if {$tcl_platform(platform)=="windows"} {
#
# NOTE: On Windows, we need to escape all the whitespace characters,
# the alarm (\a) character, and those with special meaning to
# the SQLite shell itself.
#
set escapes [list \
\a \\a \b \\b \t \\t \n \\n \v \\v \f \\f \r \\r \
" " "\" \"" \" \\\" ' \"'\" \\ \\\\]
} else {
#
# NOTE: On Unix, we need to escape most of the whitespace characters
# and those with special meaning to the SQLite shell itself.
# The alarm (\a), backspace (\b), and carriage-return (\r)
# characters do not appear to require escaping on Unix. For
# the alarm and backspace characters, this is probably due to
# differences in the command shell. For the carriage-return,
# it is probably due to differences in how Tcl handles command
# channel end-of-line translations.
#
set escapes [list \
\t \\t \n \\n \v \\v \f \\f \
" " "\" \"" \" \\\" ' \"'\" \\ \\\\]
}
set char [string map $escapes $char]
set x [catchcmdex test.db ".print $char\n"]
set code [lindex $x 0]
set res [lindex $x 1]
if {$code ne "0"} {
error "failed with error: $res"
}
if {$res ne "$oldChar\n"} {
error "failed with byte $hex mismatch"
}
}
} {}
finish_test

View File

@ -666,6 +666,15 @@ proc do_test {name cmd expected} {
flush stdout
}
proc dumpbytes {s} {
set r ""
for {set i 0} {$i < [string length $s]} {incr i} {
if {$i > 0} {append r " "}
append r [format %02X [scan [string index $s $i] %c]]
}
return $r
}
proc catchcmd {db {cmd ""}} {
global CLI
set out [open cmds.txt w]
@ -676,6 +685,30 @@ proc catchcmd {db {cmd ""}} {
list $rc $msg
}
proc catchcmdex {db {cmd ""}} {
global CLI
set out [open cmds.txt w]
fconfigure $out -encoding binary -translation binary
puts -nonewline $out $cmd
close $out
set line "exec -keepnewline -- $CLI $db < cmds.txt"
set chans [list stdin stdout stderr]
foreach chan $chans {
catch {
set modes($chan) [fconfigure $chan]
fconfigure $chan -encoding binary -translation binary -buffering none
}
}
set rc [catch { eval $line } msg]
foreach chan $chans {
catch {
eval fconfigure [list $chan] $modes($chan)
}
}
# puts [dumpbytes $msg]
list $rc $msg
}
proc filepath_normalize {p} {
# test cases should be written to assume "unix"-like file paths
if {$::tcl_platform(platform)!="unix"} {