3 # The author disclaims copyright to this source code. In place of
4 # a legal notice, here is a blessing:
6 # May you do good and not evil.
7 # May you find forgiveness for yourself and forgive others.
8 # May you share freely, never taking more than you give.
10 #***********************************************************************
12 # The focus of this file is testing the CLI shell tool.
13 # These tests are specific to the .import command.
15 # $Id: shell5.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $
20 # shell5-1.*: Basic tests specific to the ".import" command.
22 set testdir [file dirname $argv0]
23 source $testdir/tester.tcl
24 set CLI [test_find_cli]
26 forcedelete test.db test.db-journal test.db-wal
28 #----------------------------------------------------------------------------
29 # Test cases shell5-1.*: Basic handling of the .import and .separator commands.
32 # .import FILE TABLE Import data from FILE into TABLE
33 do_test shell5-1.1.1 {
34 catchcmd "test.db" ".import"
35 } {/1 .ERROR: missing FILE argument.*/}
36 do_test shell5-1.1.2 {
37 catchcmd "test.db" ".import FOO"
38 } {/1 .ERROR: missing TABLE argument.*/}
39 do_test shell5-1.1.3 {
41 catchcmd "test.db" ".import FOO BAR BAD"
42 } {/1 .ERROR: extra argument.*/}
44 # .separator STRING Change separator used by output mode and .import
45 do_test shell5-1.2.1 {
46 catchcmd "test.db" ".separator"
47 } {1 {Usage: .separator COL ?ROW?}}
48 do_test shell5-1.2.2 {
49 catchcmd "test.db" ".separator ONE"
51 do_test shell5-1.2.3 {
52 catchcmd "test.db" ".separator ONE TWO"
54 do_test shell5-1.2.4 {
56 catchcmd "test.db" ".separator ONE TWO THREE"
57 } {1 {Usage: .separator COL ?ROW?}}
59 # column separator should default to "|"
60 do_test shell5-1.3.1.1 {
61 set res [catchcmd "test.db" ".show"]
62 list [regexp {colseparator: \"\|\"} $res]
65 # row separator should default to "\n"
66 do_test shell5-1.3.1.2 {
67 set res [catchcmd "test.db" ".show"]
68 list [regexp {rowseparator: \"\\n\"} $res]
71 # set separator to different value.
72 # check that .show reports new value
73 do_test shell5-1.3.2 {
74 set res [catchcmd "test.db" {.separator ,
76 list [regexp {separator: \",\"} $res]
79 # import file doesn't exist
80 do_test shell5-1.4.1 {
82 set res [catchcmd "test.db" {CREATE TABLE t1(a, b);
84 } {1 {Error: cannot open "FOO"}}
87 do_test shell5-1.4.2 {
88 forcedelete shell5.csv
89 set in [open shell5.csv w]
91 set res [catchcmd "test.db" {.import shell5.csv t1
92 SELECT COUNT(*) FROM t1;}]
95 # import file with 1 row, 1 column (expecting 2 cols)
96 do_test shell5-1.4.3 {
97 set in [open shell5.csv w]
100 set res [catchcmd "test.db" {.import shell5.csv t1}]
101 } {1 {shell5.csv:1: expected 2 columns but found 1 - filling the rest with NULL}}
103 # import file with 1 row, 3 columns (expecting 2 cols)
104 do_test shell5-1.4.4 {
105 set in [open shell5.csv w]
108 set res [catchcmd "test.db" {.import shell5.csv t1}]
109 } {1 {shell5.csv:1: expected 2 columns but found 3 - extras ignored}}
111 # import file with 1 row, 2 columns
112 do_test shell5-1.4.5 {
113 set in [open shell5.csv w]
116 set res [catchcmd "test.db" {DELETE FROM t1;
117 .import shell5.csv t1
118 SELECT COUNT(*) FROM t1;}]
121 # import file with 2 rows, 2 columns
122 # note we end up with 3 rows because of the 1 row
124 do_test shell5-1.4.6 {
125 set in [open shell5.csv w]
129 set res [catchcmd "test.db" {.import shell5.csv t1
130 SELECT COUNT(*) FROM t1;}]
133 # import file with 1 row, 2 columns, using a comma
134 do_test shell5-1.4.7 {
135 set in [open shell5.csv w]
138 set res [catchcmd "test.db" {.separator ,
139 .import shell5.csv t1
140 SELECT COUNT(*) FROM t1;}]
143 # import file with 1 row, 2 columns, text data
144 do_test shell5-1.4.8.1 {
145 set in [open shell5.csv w]
146 puts $in "5|Now is the time for all good men to come to the aid of their country."
148 set res [catchcmd "test.db" {.import shell5.csv t1
149 SELECT COUNT(*) FROM t1;}]
152 do_test shell5-1.4.8.2 {
153 catchcmd "test.db" {SELECT b FROM t1 WHERE a='5';}
154 } {0 {Now is the time for all good men to come to the aid of their country.}}
156 # import file with 1 row, 2 columns, quoted text data
157 # note that currently sqlite doesn't support quoted fields, and
158 # imports the entire field, quotes and all.
159 do_test shell5-1.4.9.1 {
160 set in [open shell5.csv w]
161 puts $in "6|'Now is the time for all good men to come to the aid of their country.'"
163 set res [catchcmd "test.db" {.import shell5.csv t1
164 SELECT COUNT(*) FROM t1;}]
167 do_test shell5-1.4.9.2 {
168 catchcmd "test.db" {SELECT b FROM t1 WHERE a='6';}
169 } {0 {'Now is the time for all good men to come to the aid of their country.'}}
171 # import file with 1 row, 2 columns, quoted text data
172 do_test shell5-1.4.10.1 {
173 set in [open shell5.csv w]
174 puts $in "7|\"Now is the time for all good men to come to the aid of their country.\""
176 set res [catchcmd "test.db" {.import shell5.csv t1
177 SELECT COUNT(*) FROM t1;}]
180 do_test shell5-1.4.10.2 {
181 catchcmd "test.db" {SELECT b FROM t1 WHERE a='7';}
182 } {0 {Now is the time for all good men to come to the aid of their country.}}
184 # import file with 2 rows, 2 columns and an initial BOM
186 do_test shell5-1.4.11 {
187 set in [open shell5.csv wb]
188 puts -nonewline $in "\xef\xbb\xbf"
192 set res [catchcmd "test.db" {CREATE TABLE t2(x INT, y INT);
193 .import shell5.csv t2
197 string map {\n | \n\r |} $res
198 } {0 {'x','y'|2,3|4,5}}
200 # import file with 2 rows, 2 columns or text with an initial BOM
202 do_test shell5-1.4.12 {
203 set in [open shell5.csv wb]
204 puts $in "\xef\xbb\xbf\"two\"|3"
207 set res [catchcmd "test.db" {DELETE FROM t2;
208 .import shell5.csv t2
212 string map {\n | \n\r |} $res
213 } {0 {'x','y'|'two',3|4,5}}
215 # check importing very long field
216 do_test shell5-1.5.1 {
217 set str [string repeat X 999]
218 set in [open shell5.csv w]
221 set res [catchcmd "test.db" {.import shell5.csv t1
222 SELECT length(b) FROM t1 WHERE a='8';}]
225 # try importing into a table with a large number of columns.
226 # This is limited by SQLITE_MAX_VARIABLE_NUMBER, which defaults to 999.
228 do_test shell5-1.6.1 {
230 for {set i 1} {$i<$cols} {incr i} {
233 append data "c$cols\n";
234 for {set i 1} {$i<$cols} {incr i} {
238 set in [open shell5.csv w]
241 set res [catchcmd "test.db" {DROP TABLE IF EXISTS t2;
242 .import shell5.csv t2
243 SELECT COUNT(*) FROM t2;}]
246 # try importing a large number of rows
248 do_test shell5-1.7.1 {
249 set in [open shell5.csv w]
251 for {set i 1} {$i<=$rows} {incr i} {
255 set res [catchcmd "test.db" {.mode csv
256 .import shell5.csv t3
257 SELECT COUNT(*) FROM t3;}]
260 # Inport from a pipe. (Unix only, as it requires "awk")
261 if {$tcl_platform(platform)=="unix"} {
264 catchcmd test.db {.mode csv
265 .import "|awk 'END{print \"x,y\";for(i=1;i<=5;i++){print i \",this is \" i}}'" t1
274 # Import columns containing quoted strings
276 set out [open shell5.csv w]
277 fconfigure $out -translation lf
280 puts $out {3,"""",33}
281 puts $out {4,"hello",44}
282 puts $out "5,55,\"\"\r"
284 puts $out {7,77,""""}
285 puts $out {8,88,"hello"}
287 puts $out {"x",10,110}
288 puts $out {"""",11,121}
289 puts $out {"hello",12,132}
292 catchcmd test.db {.mode csv
293 CREATE TABLE t1(a,b,c);
294 .import shell5.csv t1
297 db eval {SELECT *, '|' FROM t1 ORDER BY rowid}
298 } {1 {} 11 | 2 x 22 | 3 {"} 33 | 4 hello 44 | 5 55 {} | 6 66 x | 7 77 {"} | 8 88 hello | {} 9 99 | x 10 110 | {"} 11 121 | hello 12 132 |}
301 # Import columns containing quoted strings
302 do_test shell5-1.10 {
303 set out [open shell5.csv w]
304 fconfigure $out -translation lf
305 puts $out {column1,column2,column3,column4}
306 puts $out "field1,field2,\"x3 \"\"\r\ndata\"\" 3\",field4"
307 puts $out "x1,x2,\"x3 \"\"\ndata\"\" 3\",x4"
310 catchcmd test.db {.mode csv
311 CREATE TABLE t1(a,b,c,d);
312 .import shell5.csv t1
315 db eval {SELECT hex(c) FROM t1 ORDER BY rowid}
316 } {636F6C756D6E33 783320220D0A64617461222033 783320220A64617461222033}
318 # Blank last column with \r\n line endings.
319 do_test shell5-1.11 {
320 set out [open shell5.csv w]
321 fconfigure $out -translation binary
322 puts $out "column1,column2,column3\r"
329 catchcmd test.db {.mode csv
330 .import shell5.csv t1
333 db eval {SELECT *, '|' FROM t1}
334 } {a b { } | x y {} | p q r |}
337 #----------------------------------------------------------------------------
342 set fd [open shell5.csv w]
345 catchcmd test.db [string trim {
347 CREATE TABLE t1(a, b);
348 .import shell5.csv t1
350 db eval { SELECT * FROM t1 }
354 set fd [open shell5.csv w]
357 catchcmd test.db [string trim {
359 CREATE TABLE t2(a, b);
360 .import shell5.csv t2
362 db eval { SELECT * FROM t2 }
366 set fd [open shell5.csv w]
367 puts $fd {"x""y",hello}
369 catchcmd test.db [string trim {
371 CREATE TABLE t3(a, b);
372 .import shell5.csv t3
374 db eval { SELECT * FROM t3 }
378 set fd [open shell5.csv w]
379 puts $fd {"xy""",hello}
381 catchcmd test.db [string trim {
383 CREATE TABLE t4(a, b);
384 .import shell5.csv t4
386 db eval { SELECT * FROM t4 }
390 set fd [open shell5.csv w]
394 catchcmd test.db [string trim {
396 CREATE TABLE t4(a, b);
397 .import shell5.csv t4
399 db eval { SELECT * FROM t4 }
400 } {xy\" hello one 2 {} {}}
402 #----------------------------------------------------------------------------
403 # Tests for the shell "ascii" import/export mode.
406 set fd [open shell5.csv w]
407 fconfigure $fd -encoding binary -translation binary
408 puts -nonewline $fd "\"test 1\"\x1F,test 2\r\n\x1E"
409 puts -nonewline $fd "test 3\x1Ftest 4\n"
413 CREATE TABLE t5(a, b);
414 .import shell5.csv t5
416 db eval { SELECT * FROM t5 }
417 } "\{\"test 1\"} \{,test 2\r\n\} \{test 3\} \{test 4\n\}"
420 set x [catchcmd test.db {
424 # Handle platform end-of-line differences
425 regsub -all {[\n\r]?\n} $x <EOL> x
427 } "0 \{\"test 1\"\x1F,test 2<EOL>\x1Etest 3\x1Ftest 4<EOL>\x1E\}"
430 forcedelete shell5.csv
431 set fd [open shell5.csv w]
436 catchcmd test.db [string trim {
438 CREATE TABLE t6(a, b, c);
439 .import shell5.csv t6
441 db eval { SELECT * FROM t6 ORDER BY a }
442 } {1 2 3 4 5 {} 6 7 8}
445 forcedelete shell5.csv
446 set fd [open shell5.csv w]
451 catchcmd test.db [string trim {
453 CREATE TABLE t7(a, b, c);
454 .import shell5.csv t7
456 db eval { SELECT * FROM t7 ORDER BY a }
457 } {1 2 3 4 5 {} 6 7 8}
460 forcedelete shell5.csv
461 set fd [open shell5.csv w]
465 catchcmd test.db [string trim {
467 CREATE TABLE t8(a, b, c);
468 .import -skip 1 shell5.csv t8
471 db eval { SELECT * FROM t8 }