xref: /sqlite-3.40.0/test/shell5.test (revision 636bf9f7)
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 STRING}}
59do_test shell5-1.2.2 {
60  catchcmd "test.db" ".separator FOO"
61} {0 {}}
62do_test shell5-1.2.3 {
63  # too many arguments
64  catchcmd "test.db" ".separator FOO BAD"
65} {1 {Usage: .separator STRING}}
66
67# column separator should default to "|"
68do_test shell5-1.3.1.1 {
69  set res [catchcmd "test.db" ".show"]
70  list [regexp {colseparator: \"\|\"} $res]
71} {1}
72
73# row separator should default to "\n"
74do_test shell5-1.3.1.2 {
75  set res [catchcmd "test.db" ".show"]
76  list [regexp {rowseparator: \"\\n\"} $res]
77} {1}
78
79# set separator to different value.
80# check that .show reports new value
81do_test shell5-1.3.2 {
82  set res [catchcmd "test.db" {.separator ,
83.show}]
84  list [regexp {separator: \",\"} $res]
85} {1}
86
87# import file doesn't exist
88do_test shell5-1.4.1 {
89  forcedelete FOO
90  set res [catchcmd "test.db" {CREATE TABLE t1(a, b);
91.import FOO t1}]
92} {1 {Error: cannot open "FOO"}}
93
94# empty import file
95do_test shell5-1.4.2 {
96  forcedelete shell5.csv
97  set in [open shell5.csv w]
98  close $in
99  set res [catchcmd "test.db" {.import shell5.csv t1
100SELECT COUNT(*) FROM t1;}]
101} {0 0}
102
103# import file with 1 row, 1 column (expecting 2 cols)
104do_test shell5-1.4.3 {
105  set in [open shell5.csv w]
106  puts $in "1"
107  close $in
108  set res [catchcmd "test.db" {.import shell5.csv t1}]
109} {1 {shell5.csv:1: expected 2 columns but found 1 - filling the rest with NULL}}
110
111# import file with 1 row, 3 columns (expecting 2 cols)
112do_test shell5-1.4.4 {
113  set in [open shell5.csv w]
114  puts $in "1|2|3"
115  close $in
116  set res [catchcmd "test.db" {.import shell5.csv t1}]
117} {1 {shell5.csv:1: expected 2 columns but found 3 - extras ignored}}
118
119# import file with 1 row, 2 columns
120do_test shell5-1.4.5 {
121  set in [open shell5.csv w]
122  puts $in "1|2"
123  close $in
124  set res [catchcmd "test.db" {DELETE FROM t1;
125.import shell5.csv t1
126SELECT COUNT(*) FROM t1;}]
127} {0 1}
128
129# import file with 2 rows, 2 columns
130# note we end up with 3 rows because of the 1 row
131# imported above.
132do_test shell5-1.4.6 {
133  set in [open shell5.csv w]
134  puts $in "2|3"
135  puts $in "3|4"
136  close $in
137  set res [catchcmd "test.db" {.import shell5.csv t1
138SELECT COUNT(*) FROM t1;}]
139} {0 3}
140
141# import file with 1 row, 2 columns, using a comma
142do_test shell5-1.4.7 {
143  set in [open shell5.csv w]
144  puts $in "4,5"
145  close $in
146  set res [catchcmd "test.db" {.separator ,
147.import shell5.csv t1
148SELECT COUNT(*) FROM t1;}]
149} {0 4}
150
151# import file with 1 row, 2 columns, text data
152do_test shell5-1.4.8.1 {
153  set in [open shell5.csv w]
154  puts $in "5|Now is the time for all good men to come to the aid of their country."
155  close $in
156  set res [catchcmd "test.db" {.import shell5.csv t1
157SELECT COUNT(*) FROM t1;}]
158} {0 5}
159
160do_test shell5-1.4.8.2 {
161  catchcmd "test.db" {SELECT b FROM t1 WHERE a='5';}
162} {0 {Now is the time for all good men to come to the aid of their country.}}
163
164# import file with 1 row, 2 columns, quoted text data
165# note that currently sqlite doesn't support quoted fields, and
166# imports the entire field, quotes and all.
167do_test shell5-1.4.9.1 {
168  set in [open shell5.csv w]
169  puts $in "6|'Now is the time for all good men to come to the aid of their country.'"
170  close $in
171  set res [catchcmd "test.db" {.import shell5.csv t1
172SELECT COUNT(*) FROM t1;}]
173} {0 6}
174
175do_test shell5-1.4.9.2 {
176  catchcmd "test.db" {SELECT b FROM t1 WHERE a='6';}
177} {0 {'Now is the time for all good men to come to the aid of their country.'}}
178
179# import file with 1 row, 2 columns, quoted text data
180do_test shell5-1.4.10.1 {
181  set in [open shell5.csv w]
182  puts $in "7|\"Now is the time for all good men to come to the aid of their country.\""
183  close $in
184  set res [catchcmd "test.db" {.import shell5.csv t1
185SELECT COUNT(*) FROM t1;}]
186} {0 7}
187
188do_test shell5-1.4.10.2 {
189  catchcmd "test.db" {SELECT b FROM t1 WHERE a='7';}
190} {0 {Now is the time for all good men to come to the aid of their country.}}
191
192# check importing very long field
193do_test shell5-1.5.1 {
194  set str [string repeat X 999]
195  set in [open shell5.csv w]
196  puts $in "8|$str"
197  close $in
198  set res [catchcmd "test.db" {.import shell5.csv t1
199SELECT length(b) FROM t1 WHERE a='8';}]
200} {0 999}
201
202# try importing into a table with a large number of columns.
203# This is limited by SQLITE_MAX_VARIABLE_NUMBER, which defaults to 999.
204set cols 999
205do_test shell5-1.6.1 {
206  set data {}
207  for {set i 1} {$i<$cols} {incr i} {
208    append data "c$i|"
209  }
210  append data "c$cols\n";
211  for {set i 1} {$i<$cols} {incr i} {
212    append data "$i|"
213  }
214  append data "$cols"
215  set in [open shell5.csv w]
216  puts $in $data
217  close $in
218  set res [catchcmd "test.db" {.import shell5.csv t2
219SELECT COUNT(*) FROM t2;}]
220} {0 1}
221
222# try importing a large number of rows
223set rows 9999
224do_test shell5-1.7.1 {
225  set in [open shell5.csv w]
226  puts $in a
227  for {set i 1} {$i<=$rows} {incr i} {
228    puts $in $i
229  }
230  close $in
231  set res [catchcmd "test.db" {.mode csv
232.import shell5.csv t3
233SELECT COUNT(*) FROM t3;}]
234} [list 0 $rows]
235
236# Inport from a pipe.  (Unix only, as it requires "awk")
237if {$tcl_platform(platform)=="unix"} {
238  do_test shell5-1.8 {
239    forcedelete test.db
240    catchcmd test.db {.mode csv
241.import "|awk 'END{print \"x,y\";for(i=1;i<=5;i++){print i \",this is \" i}}'" t1
242SELECT * FROM t1;}
243  } {0 {1,"this is 1"
2442,"this is 2"
2453,"this is 3"
2464,"this is 4"
2475,"this is 5"}}
248}
249
250# Import columns containing quoted strings
251do_test shell5-1.9 {
252  set out [open shell5.csv w]
253  fconfigure $out -translation lf
254  puts $out {1,"",11}
255  puts $out {2,"x",22}
256  puts $out {3,"""",33}
257  puts $out {4,"hello",44}
258  puts $out "5,55,\"\"\r"
259  puts $out {6,66,"x"}
260  puts $out {7,77,""""}
261  puts $out {8,88,"hello"}
262  puts $out {"",9,99}
263  puts $out {"x",10,110}
264  puts $out {"""",11,121}
265  puts $out {"hello",12,132}
266  close $out
267  forcedelete test.db
268  catchcmd test.db {.mode csv
269    CREATE TABLE t1(a,b,c);
270.import shell5.csv t1
271  }
272  sqlite3 db test.db
273  db eval {SELECT *, '|' FROM t1 ORDER BY rowid}
274} {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 |}
275db close
276
277# Import columns containing quoted strings
278do_test shell5-1.10 {
279  set out [open shell5.csv w]
280  fconfigure $out -translation lf
281  puts $out {column1,column2,column3,column4}
282  puts $out "field1,field2,\"x3 \"\"\r\ndata\"\" 3\",field4"
283  puts $out "x1,x2,\"x3 \"\"\ndata\"\" 3\",x4"
284  close $out
285  forcedelete test.db
286  catchcmd test.db {.mode csv
287    CREATE TABLE t1(a,b,c,d);
288.import shell5.csv t1
289  }
290  sqlite3 db test.db
291  db eval {SELECT hex(c) FROM t1 ORDER BY rowid}
292} {636F6C756D6E33 783320220D0A64617461222033 783320220A64617461222033}
293
294# Blank last column with \r\n line endings.
295do_test shell5-1.11 {
296  set out [open shell5.csv w]
297  fconfigure $out -translation binary
298  puts $out "column1,column2,column3\r"
299  puts $out "a,b, \r"
300  puts $out "x,y,\r"
301  puts $out "p,q,r\r"
302  close $out
303  catch {db close}
304  forcedelete test.db
305  catchcmd test.db {.mode csv
306.import shell5.csv t1
307  }
308  sqlite3 db test.db
309  db eval {SELECT *, '|' FROM t1}
310} {a b { } | x y {} | p q r |}
311db close
312
313#----------------------------------------------------------------------------
314#
315reset_db
316sqlite3 db test.db
317do_test shell5-2.1 {
318  set fd [open shell5.csv w]
319  puts $fd ",hello"
320  close $fd
321  catchcmd test.db [string trim {
322.mode csv
323CREATE TABLE t1(a, b);
324.import shell5.csv t1
325  }]
326  db eval { SELECT * FROM t1 }
327} {{} hello}
328
329do_test shell5-2.2 {
330  set fd [open shell5.csv w]
331  puts $fd {"",hello}
332  close $fd
333  catchcmd test.db [string trim {
334.mode csv
335CREATE TABLE t2(a, b);
336.import shell5.csv t2
337  }]
338  db eval { SELECT * FROM t2 }
339} {{} hello}
340
341do_test shell5-2.3 {
342  set fd [open shell5.csv w]
343  puts $fd {"x""y",hello}
344  close $fd
345  catchcmd test.db [string trim {
346.mode csv
347CREATE TABLE t3(a, b);
348.import shell5.csv t3
349  }]
350  db eval { SELECT * FROM t3 }
351} {x\"y hello}
352
353do_test shell5-2.4 {
354  set fd [open shell5.csv w]
355  puts $fd {"xy""",hello}
356  close $fd
357  catchcmd test.db [string trim {
358.mode csv
359CREATE TABLE t4(a, b);
360.import shell5.csv t4
361  }]
362  db eval { SELECT * FROM t4 }
363} {xy\" hello}
364
365do_test shell5-2.5 {
366  set fd [open shell5.csv w]
367  puts $fd {"one","2"}
368  puts $fd {}
369  close $fd
370  catchcmd test.db [string trim {
371.mode csv
372CREATE TABLE t4(a, b);
373.import shell5.csv t4
374  }]
375  db eval { SELECT * FROM t4 }
376} {xy\" hello one 2 {} {}}
377
378#----------------------------------------------------------------------------
379# Tests for the shell "ascii" import/export mode.
380#
381do_test shell5-3.1 {
382  set fd [open shell5.csv w]
383  fconfigure $fd -encoding binary -translation binary
384  puts -nonewline $fd "\"test 1\"\x1F,test 2\r\n\x1E"
385  puts -nonewline $fd "test 3\x1Ftest 4\n"
386  close $fd
387  catchcmd test.db {
388.mode ascii
389CREATE TABLE t5(a, b);
390.import shell5.csv t5
391  }
392  db eval { SELECT * FROM t5 }
393} "\{\"test 1\"} \{,test 2\r\n\} \{test 3\} \{test 4\n\}"
394
395#
396# NOTE: This test ends up converting the "\r\n" to "\n\n" due
397#       to end-of-line translation on the "stdout" channel.
398#
399do_test shell5-3.2 {
400  catchcmd test.db {
401.mode ascii
402SELECT * FROM t5;
403  }
404} "0 \{\"test 1\"\x1F,test 2\n\n\x1Etest 3\x1Ftest 4\n\x1E\}"
405
406finish_test
407