xref: /sqlite-3.40.0/test/shell5.test (revision cc285c5a)
1# 2010 August 4
2#
3# The author disclaims copyright to this source code.  In place of
4# a legal notice, here is a blessing:
5#
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.
9#
10#***********************************************************************
11#
12# The focus of this file is testing the CLI shell tool.
13# These tests are specific to the .import command.
14#
15# $Id: shell5.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $
16#
17
18# Test plan:
19#
20#   shell5-1.*: Basic tests specific to the ".import" command.
21#
22set testdir [file dirname $argv0]
23source $testdir/tester.tcl
24if {$tcl_platform(platform)=="windows"} {
25  set CLI "sqlite3.exe"
26} else {
27  set CLI "./sqlite3"
28}
29if {![file executable $CLI]} {
30  finish_test
31  return
32}
33db close
34forcedelete test.db test.db-journal test.db-wal
35
36#----------------------------------------------------------------------------
37# Test cases shell5-1.*: Basic handling of the .import and .separator commands.
38#
39
40# .import FILE TABLE     Import data from FILE into TABLE
41do_test shell5-1.1.1 {
42  catchcmd "test.db" ".import"
43} {1 {Usage: .import FILE TABLE}}
44do_test shell5-1.1.2 {
45  catchcmd "test.db" ".import FOO"
46} {1 {Usage: .import FILE TABLE}}
47#do_test shell5-1.1.2 {
48#  catchcmd "test.db" ".import FOO BAR"
49#} {1 {Error: no such table: BAR}}
50do_test shell5-1.1.3 {
51  # too many arguments
52  catchcmd "test.db" ".import FOO BAR BAD"
53} {1 {Usage: .import FILE TABLE}}
54
55# .separator STRING      Change separator used by output mode and .import
56do_test shell5-1.2.1 {
57  catchcmd "test.db" ".separator"
58} {1 {Usage: .separator COL ?ROW?}}
59do_test shell5-1.2.2 {
60  catchcmd "test.db" ".separator ONE"
61} {0 {}}
62do_test shell5-1.2.3 {
63  catchcmd "test.db" ".separator ONE TWO"
64} {0 {}}
65do_test shell5-1.2.4 {
66  # too many arguments
67  catchcmd "test.db" ".separator ONE TWO THREE"
68} {1 {Usage: .separator COL ?ROW?}}
69
70# column separator should default to "|"
71do_test shell5-1.3.1.1 {
72  set res [catchcmd "test.db" ".show"]
73  list [regexp {colseparator: \"\|\"} $res]
74} {1}
75
76# row separator should default to "\n"
77do_test shell5-1.3.1.2 {
78  set res [catchcmd "test.db" ".show"]
79  list [regexp {rowseparator: \"\\n\"} $res]
80} {1}
81
82# set separator to different value.
83# check that .show reports new value
84do_test shell5-1.3.2 {
85  set res [catchcmd "test.db" {.separator ,
86.show}]
87  list [regexp {separator: \",\"} $res]
88} {1}
89
90# import file doesn't exist
91do_test shell5-1.4.1 {
92  forcedelete FOO
93  set res [catchcmd "test.db" {CREATE TABLE t1(a, b);
94.import FOO t1}]
95} {1 {Error: cannot open "FOO"}}
96
97# empty import file
98do_test shell5-1.4.2 {
99  forcedelete shell5.csv
100  set in [open shell5.csv w]
101  close $in
102  set res [catchcmd "test.db" {.import shell5.csv t1
103SELECT COUNT(*) FROM t1;}]
104} {0 0}
105
106# import file with 1 row, 1 column (expecting 2 cols)
107do_test shell5-1.4.3 {
108  set in [open shell5.csv w]
109  puts $in "1"
110  close $in
111  set res [catchcmd "test.db" {.import shell5.csv t1}]
112} {1 {shell5.csv:1: expected 2 columns but found 1 - filling the rest with NULL}}
113
114# import file with 1 row, 3 columns (expecting 2 cols)
115do_test shell5-1.4.4 {
116  set in [open shell5.csv w]
117  puts $in "1|2|3"
118  close $in
119  set res [catchcmd "test.db" {.import shell5.csv t1}]
120} {1 {shell5.csv:1: expected 2 columns but found 3 - extras ignored}}
121
122# import file with 1 row, 2 columns
123do_test shell5-1.4.5 {
124  set in [open shell5.csv w]
125  puts $in "1|2"
126  close $in
127  set res [catchcmd "test.db" {DELETE FROM t1;
128.import shell5.csv t1
129SELECT COUNT(*) FROM t1;}]
130} {0 1}
131
132# import file with 2 rows, 2 columns
133# note we end up with 3 rows because of the 1 row
134# imported above.
135do_test shell5-1.4.6 {
136  set in [open shell5.csv w]
137  puts $in "2|3"
138  puts $in "3|4"
139  close $in
140  set res [catchcmd "test.db" {.import shell5.csv t1
141SELECT COUNT(*) FROM t1;}]
142} {0 3}
143
144# import file with 1 row, 2 columns, using a comma
145do_test shell5-1.4.7 {
146  set in [open shell5.csv w]
147  puts $in "4,5"
148  close $in
149  set res [catchcmd "test.db" {.separator ,
150.import shell5.csv t1
151SELECT COUNT(*) FROM t1;}]
152} {0 4}
153
154# import file with 1 row, 2 columns, text data
155do_test shell5-1.4.8.1 {
156  set in [open shell5.csv w]
157  puts $in "5|Now is the time for all good men to come to the aid of their country."
158  close $in
159  set res [catchcmd "test.db" {.import shell5.csv t1
160SELECT COUNT(*) FROM t1;}]
161} {0 5}
162
163do_test shell5-1.4.8.2 {
164  catchcmd "test.db" {SELECT b FROM t1 WHERE a='5';}
165} {0 {Now is the time for all good men to come to the aid of their country.}}
166
167# import file with 1 row, 2 columns, quoted text data
168# note that currently sqlite doesn't support quoted fields, and
169# imports the entire field, quotes and all.
170do_test shell5-1.4.9.1 {
171  set in [open shell5.csv w]
172  puts $in "6|'Now is the time for all good men to come to the aid of their country.'"
173  close $in
174  set res [catchcmd "test.db" {.import shell5.csv t1
175SELECT COUNT(*) FROM t1;}]
176} {0 6}
177
178do_test shell5-1.4.9.2 {
179  catchcmd "test.db" {SELECT b FROM t1 WHERE a='6';}
180} {0 {'Now is the time for all good men to come to the aid of their country.'}}
181
182# import file with 1 row, 2 columns, quoted text data
183do_test shell5-1.4.10.1 {
184  set in [open shell5.csv w]
185  puts $in "7|\"Now is the time for all good men to come to the aid of their country.\""
186  close $in
187  set res [catchcmd "test.db" {.import shell5.csv t1
188SELECT COUNT(*) FROM t1;}]
189} {0 7}
190
191do_test shell5-1.4.10.2 {
192  catchcmd "test.db" {SELECT b FROM t1 WHERE a='7';}
193} {0 {Now is the time for all good men to come to the aid of their country.}}
194
195# check importing very long field
196do_test shell5-1.5.1 {
197  set str [string repeat X 999]
198  set in [open shell5.csv w]
199  puts $in "8|$str"
200  close $in
201  set res [catchcmd "test.db" {.import shell5.csv t1
202SELECT length(b) FROM t1 WHERE a='8';}]
203} {0 999}
204
205# try importing into a table with a large number of columns.
206# This is limited by SQLITE_MAX_VARIABLE_NUMBER, which defaults to 999.
207set cols 999
208do_test shell5-1.6.1 {
209  set data {}
210  for {set i 1} {$i<$cols} {incr i} {
211    append data "c$i|"
212  }
213  append data "c$cols\n";
214  for {set i 1} {$i<$cols} {incr i} {
215    append data "$i|"
216  }
217  append data "$cols"
218  set in [open shell5.csv w]
219  puts $in $data
220  close $in
221  set res [catchcmd "test.db" {.import shell5.csv t2
222SELECT COUNT(*) FROM t2;}]
223} {0 1}
224
225# try importing a large number of rows
226set rows 9999
227do_test shell5-1.7.1 {
228  set in [open shell5.csv w]
229  puts $in a
230  for {set i 1} {$i<=$rows} {incr i} {
231    puts $in $i
232  }
233  close $in
234  set res [catchcmd "test.db" {.mode csv
235.import shell5.csv t3
236SELECT COUNT(*) FROM t3;}]
237} [list 0 $rows]
238
239# Inport from a pipe.  (Unix only, as it requires "awk")
240if {$tcl_platform(platform)=="unix"} {
241  do_test shell5-1.8 {
242    forcedelete test.db
243    catchcmd test.db {.mode csv
244.import "|awk 'END{print \"x,y\";for(i=1;i<=5;i++){print i \",this is \" i}}'" t1
245SELECT * FROM t1;}
246  } {0 {1,"this is 1"
2472,"this is 2"
2483,"this is 3"
2494,"this is 4"
2505,"this is 5"}}
251}
252
253# Import columns containing quoted strings
254do_test shell5-1.9 {
255  set out [open shell5.csv w]
256  fconfigure $out -translation lf
257  puts $out {1,"",11}
258  puts $out {2,"x",22}
259  puts $out {3,"""",33}
260  puts $out {4,"hello",44}
261  puts $out "5,55,\"\"\r"
262  puts $out {6,66,"x"}
263  puts $out {7,77,""""}
264  puts $out {8,88,"hello"}
265  puts $out {"",9,99}
266  puts $out {"x",10,110}
267  puts $out {"""",11,121}
268  puts $out {"hello",12,132}
269  close $out
270  forcedelete test.db
271  catchcmd test.db {.mode csv
272    CREATE TABLE t1(a,b,c);
273.import shell5.csv t1
274  }
275  sqlite3 db test.db
276  db eval {SELECT *, '|' FROM t1 ORDER BY rowid}
277} {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 |}
278db close
279
280# Import columns containing quoted strings
281do_test shell5-1.10 {
282  set out [open shell5.csv w]
283  fconfigure $out -translation lf
284  puts $out {column1,column2,column3,column4}
285  puts $out "field1,field2,\"x3 \"\"\r\ndata\"\" 3\",field4"
286  puts $out "x1,x2,\"x3 \"\"\ndata\"\" 3\",x4"
287  close $out
288  forcedelete test.db
289  catchcmd test.db {.mode csv
290    CREATE TABLE t1(a,b,c,d);
291.import shell5.csv t1
292  }
293  sqlite3 db test.db
294  db eval {SELECT hex(c) FROM t1 ORDER BY rowid}
295} {636F6C756D6E33 783320220D0A64617461222033 783320220A64617461222033}
296
297# Blank last column with \r\n line endings.
298do_test shell5-1.11 {
299  set out [open shell5.csv w]
300  fconfigure $out -translation binary
301  puts $out "column1,column2,column3\r"
302  puts $out "a,b, \r"
303  puts $out "x,y,\r"
304  puts $out "p,q,r\r"
305  close $out
306  catch {db close}
307  forcedelete test.db
308  catchcmd test.db {.mode csv
309.import shell5.csv t1
310  }
311  sqlite3 db test.db
312  db eval {SELECT *, '|' FROM t1}
313} {a b { } | x y {} | p q r |}
314db close
315
316#----------------------------------------------------------------------------
317#
318reset_db
319sqlite3 db test.db
320do_test shell5-2.1 {
321  set fd [open shell5.csv w]
322  puts $fd ",hello"
323  close $fd
324  catchcmd test.db [string trim {
325.mode csv
326CREATE TABLE t1(a, b);
327.import shell5.csv t1
328  }]
329  db eval { SELECT * FROM t1 }
330} {{} hello}
331
332do_test shell5-2.2 {
333  set fd [open shell5.csv w]
334  puts $fd {"",hello}
335  close $fd
336  catchcmd test.db [string trim {
337.mode csv
338CREATE TABLE t2(a, b);
339.import shell5.csv t2
340  }]
341  db eval { SELECT * FROM t2 }
342} {{} hello}
343
344do_test shell5-2.3 {
345  set fd [open shell5.csv w]
346  puts $fd {"x""y",hello}
347  close $fd
348  catchcmd test.db [string trim {
349.mode csv
350CREATE TABLE t3(a, b);
351.import shell5.csv t3
352  }]
353  db eval { SELECT * FROM t3 }
354} {x\"y hello}
355
356do_test shell5-2.4 {
357  set fd [open shell5.csv w]
358  puts $fd {"xy""",hello}
359  close $fd
360  catchcmd test.db [string trim {
361.mode csv
362CREATE TABLE t4(a, b);
363.import shell5.csv t4
364  }]
365  db eval { SELECT * FROM t4 }
366} {xy\" hello}
367
368do_test shell5-2.5 {
369  set fd [open shell5.csv w]
370  puts $fd {"one","2"}
371  puts $fd {}
372  close $fd
373  catchcmd test.db [string trim {
374.mode csv
375CREATE TABLE t4(a, b);
376.import shell5.csv t4
377  }]
378  db eval { SELECT * FROM t4 }
379} {xy\" hello one 2 {} {}}
380
381#----------------------------------------------------------------------------
382# Tests for the shell "ascii" import/export mode.
383#
384do_test shell5-3.1 {
385  set fd [open shell5.csv w]
386  fconfigure $fd -encoding binary -translation binary
387  puts -nonewline $fd "\"test 1\"\x1F,test 2\r\n\x1E"
388  puts -nonewline $fd "test 3\x1Ftest 4\n"
389  close $fd
390  catchcmd test.db {
391.mode ascii
392CREATE TABLE t5(a, b);
393.import shell5.csv t5
394  }
395  db eval { SELECT * FROM t5 }
396} "\{\"test 1\"} \{,test 2\r\n\} \{test 3\} \{test 4\n\}"
397
398do_test shell5-3.2 {
399  set x [catchcmd test.db {
400.mode ascii
401SELECT * FROM t5;
402  }]
403  # Handle platform end-of-line differences
404  regsub -all {[\n\r]?\n} $x <EOL> x
405  set x
406} "0 \{\"test 1\"\x1F,test 2<EOL>\x1Etest 3\x1Ftest 4<EOL>\x1E\}"
407
408do_test shell5-4.1 {
409  forcedelete shell5.csv
410  set fd [open shell5.csv w]
411  puts $fd "1,2,3"
412  puts $fd "4,5"
413  puts $fd "6,7,8"
414  close $fd
415  catchcmd test.db [string trim {
416.mode csv
417CREATE TABLE t6(a, b, c);
418.import shell5.csv t6
419  }]
420  db eval { SELECT * FROM t6 ORDER BY a }
421} {1 2 3 4 5 {} 6 7 8}
422
423do_test shell5-4.2 {
424  forcedelete shell5.csv
425  set fd [open shell5.csv w]
426  puts $fd "1,2,3"
427  puts $fd "4,5"
428  puts $fd "6,7,8,9"
429  close $fd
430  catchcmd test.db [string trim {
431.mode csv
432CREATE TABLE t7(a, b, c);
433.import shell5.csv t7
434  }]
435  db eval { SELECT * FROM t7 ORDER BY a }
436} {1 2 3 4 5 {} 6 7 8}
437
438finish_test
439