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 ":memory:" {ATTACH 'test.db' AS test;
92 .import -schema test shell5.csv t1
93 SELECT COUNT(*) FROM test.t1;}]
96 # import file with 1 row, 1 column (expecting 2 cols)
97 do_test shell5-1.4.3 {
98 set in [open shell5.csv w]
101 set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
102 .import -schema test shell5.csv t1}]
103 } {1 {shell5.csv:1: expected 2 columns but found 1 - filling the rest with NULL}}
105 # import file with 1 row, 3 columns (expecting 2 cols)
106 do_test shell5-1.4.4 {
107 set in [open shell5.csv w]
110 set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
111 .import --schema test shell5.csv t1}]
112 } {1 {shell5.csv:1: expected 2 columns but found 3 - extras ignored}}
114 # import file with 1 row, 2 columns
115 do_test shell5-1.4.5 {
116 set in [open shell5.csv w]
119 set res [catchcmd "test.db" {DELETE FROM t1;
120 .import shell5.csv t1
121 SELECT COUNT(*) FROM t1;}]
124 # import file with 2 rows, 2 columns
125 # note we end up with 3 rows because of the 1 row
127 do_test shell5-1.4.6 {
128 set in [open shell5.csv w]
132 set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
133 .import -schema test shell5.csv t1
134 SELECT COUNT(*) FROM test.t1;}]
137 # import file with 1 row, 2 columns, using a comma
138 do_test shell5-1.4.7 {
139 set in [open shell5.csv w]
142 set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
144 .import --schema test shell5.csv t1
145 SELECT COUNT(*) FROM test.t1;}]
148 # import file with 1 row, 2 columns, text data
149 do_test shell5-1.4.8.1 {
150 set in [open shell5.csv w]
151 puts $in "5|Now is the time for all good men to come to the aid of their country."
153 set res [catchcmd "test.db" {.import shell5.csv t1
154 SELECT COUNT(*) FROM t1;}]
157 do_test shell5-1.4.8.2 {
158 catchcmd "test.db" {SELECT b FROM t1 WHERE a='5';}
159 } {0 {Now is the time for all good men to come to the aid of their country.}}
161 # import file with 1 row, 2 columns, quoted text data
162 # note that currently sqlite doesn't support quoted fields, and
163 # imports the entire field, quotes and all.
164 do_test shell5-1.4.9.1 {
165 set in [open shell5.csv w]
166 puts $in "6|'Now is the time for all good men to come to the aid of their country.'"
168 set res [catchcmd "test.db" {.import shell5.csv t1
169 SELECT COUNT(*) FROM t1;}]
172 do_test shell5-1.4.9.2 {
173 catchcmd "test.db" {SELECT b FROM t1 WHERE a='6';}
174 } {0 {'Now is the time for all good men to come to the aid of their country.'}}
176 # import file with 1 row, 2 columns, quoted text data
177 do_test shell5-1.4.10.1 {
178 set in [open shell5.csv w]
179 puts $in "7|\"Now is the time for all good men to come to the aid of their country.\""
181 set res [catchcmd "test.db" {.import shell5.csv t1
182 SELECT COUNT(*) FROM t1;}]
185 do_test shell5-1.4.10.2 {
186 catchcmd "test.db" {SELECT b FROM t1 WHERE a='7';}
187 } {0 {Now is the time for all good men to come to the aid of their country.}}
189 # import file with 2 rows, 2 columns and an initial BOM
191 do_test shell5-1.4.11 {
192 set in [open shell5.csv wb]
193 puts -nonewline $in "\xef\xbb\xbf"
197 set res [catchcmd "test.db" {CREATE TABLE t2(x INT, y INT);
198 .import shell5.csv t2
202 string map {\n | \n\r |} $res
203 } {0 {'x','y'|2,3|4,5}}
205 # import file with 2 rows, 2 columns or text with an initial BOM
207 do_test shell5-1.4.12 {
208 set in [open shell5.csv wb]
209 puts $in "\xef\xbb\xbf\"two\"|3"
212 set res [catchcmd "test.db" {DELETE FROM t2;
213 .import shell5.csv t2
217 string map {\n | \n\r |} $res
218 } {0 {'x','y'|'two',3|4,5}}
220 # check importing very long field
221 do_test shell5-1.5.1 {
222 set str [string repeat X 999]
223 set in [open shell5.csv w]
226 set res [catchcmd "test.db" {.import shell5.csv t1
227 SELECT length(b) FROM t1 WHERE a='8';}]
230 # try importing into a table with a large number of columns.
231 # This is limited by SQLITE_MAX_VARIABLE_NUMBER, which defaults to 999.
233 do_test shell5-1.6.1 {
235 for {set i 1} {$i<$cols} {incr i} {
238 append data "c$cols\n";
239 for {set i 1} {$i<$cols} {incr i} {
243 set in [open shell5.csv w]
246 set res [catchcmd "test.db" {DROP TABLE IF EXISTS t2;
247 .import shell5.csv t2
248 SELECT COUNT(*) FROM t2;}]
251 # try importing a large number of rows
253 do_test shell5-1.7.1 {
254 set in [open shell5.csv w]
256 for {set i 1} {$i<=$rows} {incr i} {
260 set res [catchcmd "test.db" {.mode csv
261 .import shell5.csv t3
262 SELECT COUNT(*) FROM t3;}]
265 # Import from a pipe. (Unix only, as it requires "awk")
266 if {$tcl_platform(platform)=="unix"} {
269 catchcmd test.db {.mode csv
270 .import "|awk 'END{print \"x,y\";for(i=1;i<=5;i++){print i \",this is \" i}}'" t1
279 # Import columns containing quoted strings
281 set out [open shell5.csv w]
282 fconfigure $out -translation lf
285 puts $out {3,"""",33}
286 puts $out {4,"hello",44}
287 puts $out "5,55,\"\"\r"
289 puts $out {7,77,""""}
290 puts $out {8,88,"hello"}
292 puts $out {"x",10,110}
293 puts $out {"""",11,121}
294 puts $out {"hello",12,132}
297 catchcmd test.db {.mode csv
298 CREATE TABLE t1(a,b,c);
299 .import shell5.csv t1
302 db eval {SELECT *, '|' FROM t1 ORDER BY rowid}
303 } {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 |}
306 # Import columns containing quoted strings
307 do_test shell5-1.10 {
308 set out [open shell5.csv w]
309 fconfigure $out -translation lf
310 puts $out {column1,column2,column3,column4}
311 puts $out "field1,field2,\"x3 \"\"\r\ndata\"\" 3\",field4"
312 puts $out "x1,x2,\"x3 \"\"\ndata\"\" 3\",x4"
315 catchcmd test.db {.mode csv
316 CREATE TABLE t1(a,b,c,d);
317 .import shell5.csv t1
320 db eval {SELECT hex(c) FROM t1 ORDER BY rowid}
321 } {636F6C756D6E33 783320220D0A64617461222033 783320220A64617461222033}
323 # Blank last column with \r\n line endings.
324 do_test shell5-1.11 {
325 set out [open shell5.csv w]
326 fconfigure $out -translation binary
327 puts $out "column1,column2,column3\r"
334 catchcmd test.db {.mode csv
335 .import shell5.csv t1
338 db eval {SELECT *, '|' FROM t1}
339 } {a b { } | x y {} | p q r |}
342 #----------------------------------------------------------------------------
347 set fd [open shell5.csv w]
350 catchcmd test.db [string trim {
352 CREATE TABLE t1(a, b);
353 .import shell5.csv t1
355 db eval { SELECT * FROM t1 }
359 set fd [open shell5.csv w]
362 catchcmd test.db [string trim {
364 CREATE TABLE t2(a, b);
365 .import shell5.csv t2
367 db eval { SELECT * FROM t2 }
371 set fd [open shell5.csv w]
372 puts $fd {"x""y",hello}
374 catchcmd test.db [string trim {
376 CREATE TABLE t3(a, b);
377 .import shell5.csv t3
379 db eval { SELECT * FROM t3 }
383 set fd [open shell5.csv w]
384 puts $fd {"xy""",hello}
386 catchcmd test.db [string trim {
388 CREATE TABLE t4(a, b);
389 .import shell5.csv t4
391 db eval { SELECT * FROM t4 }
395 set fd [open shell5.csv w]
399 catchcmd test.db [string trim {
401 CREATE TABLE t4(a, b);
402 .import shell5.csv t4
404 db eval { SELECT * FROM t4 }
405 } {xy\" hello one 2 {} {}}
407 #----------------------------------------------------------------------------
408 # Tests for the shell "ascii" import/export mode.
411 set fd [open shell5.csv w]
412 fconfigure $fd -encoding binary -translation binary
413 puts -nonewline $fd "\"test 1\"\x1F,test 2\r\n\x1E"
414 puts -nonewline $fd "test 3\x1Ftest 4\n"
418 CREATE TABLE t5(a, b);
419 .import shell5.csv t5
421 db eval { SELECT * FROM t5 }
422 } "\{\"test 1\"} \{,test 2\r\n\} \{test 3\} \{test 4\n\}"
425 set x [catchcmd test.db {
429 # Handle platform end-of-line differences
430 regsub -all {[\n\r]?\n} $x <EOL> x
432 } "0 \{\"test 1\"\x1F,test 2<EOL>\x1Etest 3\x1Ftest 4<EOL>\x1E\}"
435 forcedelete shell5.csv
436 set fd [open shell5.csv w]
441 catchcmd test.db [string trim {
443 CREATE TABLE t6(a, b, c);
444 .import shell5.csv t6
446 db eval { SELECT * FROM t6 ORDER BY a }
447 } {1 2 3 4 5 {} 6 7 8}
450 forcedelete shell5.csv
451 set fd [open shell5.csv w]
456 catchcmd test.db [string trim {
458 CREATE TABLE t7(a, b, c);
459 .import shell5.csv t7
461 db eval { SELECT * FROM t7 ORDER BY a }
462 } {1 2 3 4 5 {} 6 7 8}
465 forcedelete shell5.csv
466 set fd [open shell5.csv w]
470 catchcmd test.db [string trim {
472 CREATE TABLE t8(a, b, c);
473 .import -skip 1 shell5.csv t8
476 db eval { SELECT * FROM t8 }
480 forcedelete shell5.csv
481 set fd [open shell5.csv w]
484 catchcmd test.db [string trim {
486 CREATE TEMP TABLE t8(a, b, c);
487 .import shell5.csv t8
489 SELECT * FROM temp.t8
493 #----------------------------------------------------------------------------
494 # Tests for the shell automatic column rename.
498 # Import columns containing duplicates
500 set out [open shell5.csv w]
501 fconfigure $out -translation lf
502 puts $out {"","x","x","y","z","z_0","z_5","z"}
503 puts $out {0,"x2","x3","y4","z5","z6","z7","z8"}
506 catchcmd test.db {.import -csv shell5.csv t1
517 Columns renamed during .import shell5.csv due to duplicates:
524 set out [open shell5.csv w]
525 fconfigure $out -translation lf
526 puts $out {"COW","cow","CoW","cOw"}
527 puts $out {"uuu","lll","ulu","lul"}
530 catchcmd test.db {.import -csv shell5.csv t1
537 Columns renamed during .import shell5.csv due to duplicates: