In the command-line shell, and the ".binary" command and additional
C-style backslash escapes. FossilOrigin-Name: 850c11866686a7b39d7b163fb60898c11283688e
This commit is contained in:
commit
d1055b1bd5
20
manifest
20
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
e7529705903a9d4d410801658a47fb43a4f2de2f
|
||||
850c11866686a7b39d7b163fb60898c11283688e
|
49
src/shell.c
49
src/shell.c
@ -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().
|
||||
*/
|
||||
|
102
test/shell1.test
102
test/shell1.test
@ -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
|
||||
|
@ -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"} {
|
||||
|
Loading…
Reference in New Issue
Block a user