Merge branch 'prerelease' of ssh://git.zetetic.net/sqlcipher into prerelease
[sqlcipher.git] / test / shell5.test
blobdc99a7acea84c0c7192ba7d3d26df648c1847999
1 # 2010 August 4
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 $
18 # Test plan:
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]
25 db close
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 {
40   # too many arguments
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"
50 } {0 {}}
51 do_test shell5-1.2.3 {
52   catchcmd "test.db" ".separator ONE TWO"
53 } {0 {}}
54 do_test shell5-1.2.4 {
55   # too many arguments
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]
63 } {1}
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]
69 } {1}
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 ,
75 .show}]
76   list [regexp {separator: \",\"} $res]
77 } {1}
79 # import file doesn't exist
80 do_test shell5-1.4.1 {
81   forcedelete FOO
82   set res [catchcmd "test.db" {CREATE TABLE t1(a, b);
83 .import FOO t1}]
84 } {1 {Error: cannot open "FOO"}}
86 # empty import file
87 do_test shell5-1.4.2 {
88   forcedelete shell5.csv
89   set in [open shell5.csv w]
90   close $in
91   set res [catchcmd "test.db" {.import shell5.csv t1
92 SELECT COUNT(*) FROM t1;}]
93 } {0 0}
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]
98   puts $in "1"
99   close $in
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]
106   puts $in "1|2|3"
107   close $in
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]
114   puts $in "1|2"
115   close $in
116   set res [catchcmd "test.db" {DELETE FROM t1;
117 .import shell5.csv t1
118 SELECT COUNT(*) FROM t1;}]
119 } {0 1}
121 # import file with 2 rows, 2 columns
122 # note we end up with 3 rows because of the 1 row 
123 # imported above.
124 do_test shell5-1.4.6 {
125   set in [open shell5.csv w]
126   puts $in "2|3"
127   puts $in "3|4"
128   close $in
129   set res [catchcmd "test.db" {.import shell5.csv t1
130 SELECT COUNT(*) FROM t1;}]
131 } {0 3}
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]
136   puts $in "4,5"
137   close $in
138   set res [catchcmd "test.db" {.separator ,
139 .import shell5.csv t1
140 SELECT COUNT(*) FROM t1;}]
141 } {0 4}
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."
147   close $in
148   set res [catchcmd "test.db" {.import shell5.csv t1
149 SELECT COUNT(*) FROM t1;}]
150 } {0 5}
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.'"
162   close $in
163   set res [catchcmd "test.db" {.import shell5.csv t1
164 SELECT COUNT(*) FROM t1;}]
165 } {0 6}
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.\""
175   close $in
176   set res [catchcmd "test.db" {.import shell5.csv t1
177 SELECT COUNT(*) FROM t1;}]
178 } {0 7}
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"
189   puts $in "2|3"
190   puts $in "4|5"
191   close $in
192   set res [catchcmd "test.db" {CREATE TABLE t2(x INT, y INT);
193 .import shell5.csv t2
194 .mode quote
195 .header on
196 SELECT * FROM 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"
205   puts $in "4|5"
206   close $in
207   set res [catchcmd "test.db" {DELETE FROM t2;
208 .import shell5.csv t2
209 .mode quote
210 .header on
211 SELECT * FROM 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]
219   puts $in "8|$str"
220   close $in
221   set res [catchcmd "test.db" {.import shell5.csv t1
222 SELECT length(b) FROM t1 WHERE a='8';}]
223 } {0 999}
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.
227 set cols 999
228 do_test shell5-1.6.1 {
229   set data {}
230   for {set i 1} {$i<$cols} {incr i} {
231     append data "c$i|"
232   }
233   append data "c$cols\n";
234   for {set i 1} {$i<$cols} {incr i} {
235     append data "$i|"
236   }
237   append data "$cols"
238   set in [open shell5.csv w]
239   puts $in $data
240   close $in
241   set res [catchcmd "test.db" {DROP TABLE IF EXISTS t2;
242 .import shell5.csv t2
243 SELECT COUNT(*) FROM t2;}]
244 } {0 1}
246 # try importing a large number of rows
247 set rows 9999
248 do_test shell5-1.7.1 {
249   set in [open shell5.csv w]
250   puts $in a
251   for {set i 1} {$i<=$rows} {incr i} {
252     puts $in $i
253   }
254   close $in
255   set res [catchcmd "test.db" {.mode csv
256 .import shell5.csv t3
257 SELECT COUNT(*) FROM t3;}]
258 } [list 0 $rows]
260 # Inport from a pipe.  (Unix only, as it requires "awk")
261 if {$tcl_platform(platform)=="unix"} {
262   do_test shell5-1.8 {
263     forcedelete test.db
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
266 SELECT * FROM t1;}
267   } {0 {1,"this is 1"
268 2,"this is 2"
269 3,"this is 3"
270 4,"this is 4"
271 5,"this is 5"}}
274 # Import columns containing quoted strings
275 do_test shell5-1.9 {
276   set out [open shell5.csv w]
277   fconfigure $out -translation lf
278   puts $out {1,"",11}
279   puts $out {2,"x",22}
280   puts $out {3,"""",33}
281   puts $out {4,"hello",44}
282   puts $out "5,55,\"\"\r"
283   puts $out {6,66,"x"}
284   puts $out {7,77,""""}
285   puts $out {8,88,"hello"}
286   puts $out {"",9,99}
287   puts $out {"x",10,110}
288   puts $out {"""",11,121}
289   puts $out {"hello",12,132}
290   close $out
291   forcedelete test.db
292   catchcmd test.db {.mode csv
293     CREATE TABLE t1(a,b,c);
294 .import shell5.csv t1
295   }
296   sqlite3 db test.db
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 |}
299 db close
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"
308   close $out
309   forcedelete test.db
310   catchcmd test.db {.mode csv
311     CREATE TABLE t1(a,b,c,d);
312 .import shell5.csv t1
313   }
314   sqlite3 db test.db
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"
323   puts $out "a,b, \r"
324   puts $out "x,y,\r"
325   puts $out "p,q,r\r"
326   close $out
327   catch {db close}
328   forcedelete test.db
329   catchcmd test.db {.mode csv
330 .import shell5.csv t1
331   }
332   sqlite3 db test.db
333   db eval {SELECT *, '|' FROM t1}
334 } {a b { } | x y {} | p q r |}
335 db close
337 #----------------------------------------------------------------------------
339 reset_db
340 sqlite3 db test.db
341 do_test shell5-2.1 {
342   set fd [open shell5.csv w]
343   puts $fd ",hello"
344   close $fd
345   catchcmd test.db [string trim {
346 .mode csv
347 CREATE TABLE t1(a, b);
348 .import shell5.csv t1
349   }]
350   db eval { SELECT * FROM t1 }
351 } {{} hello}
353 do_test shell5-2.2 {
354   set fd [open shell5.csv w]
355   puts $fd {"",hello}
356   close $fd
357   catchcmd test.db [string trim {
358 .mode csv
359 CREATE TABLE t2(a, b);
360 .import shell5.csv t2
361   }]
362   db eval { SELECT * FROM t2 }
363 } {{} hello}
365 do_test shell5-2.3 {
366   set fd [open shell5.csv w]
367   puts $fd {"x""y",hello}
368   close $fd
369   catchcmd test.db [string trim {
370 .mode csv
371 CREATE TABLE t3(a, b);
372 .import shell5.csv t3
373   }]
374   db eval { SELECT * FROM t3 }
375 } {x\"y hello}
377 do_test shell5-2.4 {
378   set fd [open shell5.csv w]
379   puts $fd {"xy""",hello}
380   close $fd
381   catchcmd test.db [string trim {
382 .mode csv
383 CREATE TABLE t4(a, b);
384 .import shell5.csv t4
385   }]
386   db eval { SELECT * FROM t4 }
387 } {xy\" hello}
389 do_test shell5-2.5 {
390   set fd [open shell5.csv w]
391   puts $fd {"one","2"}
392   puts $fd {}
393   close $fd
394   catchcmd test.db [string trim {
395 .mode csv
396 CREATE TABLE t4(a, b);
397 .import shell5.csv t4
398   }]
399   db eval { SELECT * FROM t4 }
400 } {xy\" hello one 2 {} {}}
402 #----------------------------------------------------------------------------
403 # Tests for the shell "ascii" import/export mode.
405 do_test shell5-3.1 {
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"
410   close $fd
411   catchcmd test.db {
412 .mode ascii
413 CREATE TABLE t5(a, b);
414 .import shell5.csv t5
415   }
416   db eval { SELECT * FROM t5 }
417 } "\{\"test 1\"} \{,test 2\r\n\} \{test 3\} \{test 4\n\}"
419 do_test shell5-3.2 {
420   set x [catchcmd test.db {
421 .mode ascii
422 SELECT * FROM t5;
423   }]
424   # Handle platform end-of-line differences
425   regsub -all {[\n\r]?\n} $x <EOL> x
426   set x
427 } "0 \{\"test 1\"\x1F,test 2<EOL>\x1Etest 3\x1Ftest 4<EOL>\x1E\}"
429 do_test shell5-4.1 {
430   forcedelete shell5.csv
431   set fd [open shell5.csv w]
432   puts $fd "1,2,3"
433   puts $fd "4,5"
434   puts $fd "6,7,8"
435   close $fd
436   catchcmd test.db [string trim {
437 .mode csv
438 CREATE TABLE t6(a, b, c);
439 .import shell5.csv t6
440   }]
441   db eval { SELECT * FROM t6 ORDER BY a }
442 } {1 2 3 4 5 {} 6 7 8}
444 do_test shell5-4.2 {
445   forcedelete shell5.csv
446   set fd [open shell5.csv w]
447   puts $fd "1,2,3"
448   puts $fd "4,5"
449   puts $fd "6,7,8,9"
450   close $fd
451   catchcmd test.db [string trim {
452 .mode csv
453 CREATE TABLE t7(a, b, c);
454 .import shell5.csv t7
455   }]
456   db eval { SELECT * FROM t7 ORDER BY a }
457 } {1 2 3 4 5 {} 6 7 8}
459 do_test shell5-4.3 {
460   forcedelete shell5.csv
461   set fd [open shell5.csv w]
462   puts $fd ",,"
463   puts $fd "1,2,3"
464   close $fd
465   catchcmd test.db [string trim {
466 .mode csv
467 CREATE TABLE t8(a, b, c);
468 .import -skip 1 shell5.csv t8
469 .nullvalue #
470   }]
471   db eval { SELECT * FROM t8 }
472 } {1 2 3}
474 finish_test