blob: 8ec9a632bf300610729fb691dc7faa1e3fc018c2 [file] [log] [blame]
shaneh1b8f78c2010-08-18 17:16:26 +00001# 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#
drh8df91852012-04-24 12:46:05 +000022set testdir [file dirname $argv0]
23source $testdir/tester.tcl
dan089555c2016-03-15 09:55:44 +000024set CLI [test_find_cli]
drh8df91852012-04-24 12:46:05 +000025db close
26forcedelete test.db test.db-journal test.db-wal
shaneh1b8f78c2010-08-18 17:16:26 +000027
28#----------------------------------------------------------------------------
29# Test cases shell5-1.*: Basic handling of the .import and .separator commands.
30#
31
32# .import FILE TABLE Import data from FILE into TABLE
33do_test shell5-1.1.1 {
34 catchcmd "test.db" ".import"
drhccb37812020-03-09 15:39:39 +000035} {/1 .ERROR: missing FILE argument.*/}
shaneh1b8f78c2010-08-18 17:16:26 +000036do_test shell5-1.1.2 {
37 catchcmd "test.db" ".import FOO"
drhccb37812020-03-09 15:39:39 +000038} {/1 .ERROR: missing TABLE argument.*/}
shaneh1b8f78c2010-08-18 17:16:26 +000039do_test shell5-1.1.3 {
40 # too many arguments
41 catchcmd "test.db" ".import FOO BAR BAD"
drhccb37812020-03-09 15:39:39 +000042} {/1 .ERROR: extra argument.*/}
shaneh1b8f78c2010-08-18 17:16:26 +000043
44# .separator STRING Change separator used by output mode and .import
drhc2ce0be2014-05-29 12:36:14 +000045do_test shell5-1.2.1 {
shaneh1b8f78c2010-08-18 17:16:26 +000046 catchcmd "test.db" ".separator"
mistachkine0d68852014-12-11 03:12:33 +000047} {1 {Usage: .separator COL ?ROW?}}
drhc2ce0be2014-05-29 12:36:14 +000048do_test shell5-1.2.2 {
drh6976c212014-07-24 12:09:47 +000049 catchcmd "test.db" ".separator ONE"
shaneh1b8f78c2010-08-18 17:16:26 +000050} {0 {}}
drhc2ce0be2014-05-29 12:36:14 +000051do_test shell5-1.2.3 {
drh6976c212014-07-24 12:09:47 +000052 catchcmd "test.db" ".separator ONE TWO"
53} {0 {}}
54do_test shell5-1.2.4 {
shaneh1b8f78c2010-08-18 17:16:26 +000055 # too many arguments
drh6976c212014-07-24 12:09:47 +000056 catchcmd "test.db" ".separator ONE TWO THREE"
mistachkine0d68852014-12-11 03:12:33 +000057} {1 {Usage: .separator COL ?ROW?}}
shaneh1b8f78c2010-08-18 17:16:26 +000058
mistachkin636bf9f2014-07-19 20:15:16 +000059# column separator should default to "|"
60do_test shell5-1.3.1.1 {
shaneh1b8f78c2010-08-18 17:16:26 +000061 set res [catchcmd "test.db" ".show"]
mistachkin636bf9f2014-07-19 20:15:16 +000062 list [regexp {colseparator: \"\|\"} $res]
63} {1}
64
65# row separator should default to "\n"
66do_test shell5-1.3.1.2 {
67 set res [catchcmd "test.db" ".show"]
68 list [regexp {rowseparator: \"\\n\"} $res]
shaneh1b8f78c2010-08-18 17:16:26 +000069} {1}
70
71# set separator to different value.
72# check that .show reports new value
73do_test shell5-1.3.2 {
74 set res [catchcmd "test.db" {.separator ,
75.show}]
76 list [regexp {separator: \",\"} $res]
77} {1}
78
79# import file doesn't exist
80do_test shell5-1.4.1 {
mistachkin9ac99312013-09-13 23:26:47 +000081 forcedelete FOO
shaneh1b8f78c2010-08-18 17:16:26 +000082 set res [catchcmd "test.db" {CREATE TABLE t1(a, b);
83.import FOO t1}]
84} {1 {Error: cannot open "FOO"}}
85
86# empty import file
87do_test shell5-1.4.2 {
mistachkin9ac99312013-09-13 23:26:47 +000088 forcedelete shell5.csv
shaneh1b8f78c2010-08-18 17:16:26 +000089 set in [open shell5.csv w]
90 close $in
91 set res [catchcmd "test.db" {.import shell5.csv t1
92SELECT COUNT(*) FROM t1;}]
93} {0 0}
94
95# import file with 1 row, 1 column (expecting 2 cols)
96do_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}]
drhdb95f682013-06-26 22:46:00 +0000101} {1 {shell5.csv:1: expected 2 columns but found 1 - filling the rest with NULL}}
shaneh1b8f78c2010-08-18 17:16:26 +0000102
103# import file with 1 row, 3 columns (expecting 2 cols)
104do_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}]
drhdb95f682013-06-26 22:46:00 +0000109} {1 {shell5.csv:1: expected 2 columns but found 3 - extras ignored}}
shaneh1b8f78c2010-08-18 17:16:26 +0000110
111# import file with 1 row, 2 columns
112do_test shell5-1.4.5 {
113 set in [open shell5.csv w]
114 puts $in "1|2"
115 close $in
drhdb95f682013-06-26 22:46:00 +0000116 set res [catchcmd "test.db" {DELETE FROM t1;
117.import shell5.csv t1
shaneh1b8f78c2010-08-18 17:16:26 +0000118SELECT COUNT(*) FROM t1;}]
119} {0 1}
120
121# import file with 2 rows, 2 columns
122# note we end up with 3 rows because of the 1 row
123# imported above.
124do_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
130SELECT COUNT(*) FROM t1;}]
131} {0 3}
132
133# import file with 1 row, 2 columns, using a comma
134do_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
140SELECT COUNT(*) FROM t1;}]
141} {0 4}
142
143# import file with 1 row, 2 columns, text data
144do_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
149SELECT COUNT(*) FROM t1;}]
150} {0 5}
151
152do_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.}}
155
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.
159do_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
164SELECT COUNT(*) FROM t1;}]
165} {0 6}
166
167do_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.'}}
170
171# import file with 1 row, 2 columns, quoted text data
172do_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
177SELECT COUNT(*) FROM t1;}]
178} {0 7}
179
180do_test shell5-1.4.10.2 {
181 catchcmd "test.db" {SELECT b FROM t1 WHERE a='7';}
drh18f52e02012-01-16 16:56:31 +0000182} {0 {Now is the time for all good men to come to the aid of their country.}}
shaneh1b8f78c2010-08-18 17:16:26 +0000183
drhd5fbde82017-06-26 18:42:23 +0000184# import file with 2 rows, 2 columns and an initial BOM
185#
186do_test shell5-1.4.11 {
187 set in [open shell5.csv wb]
drha4d770c2017-07-15 13:49:56 +0000188 puts -nonewline $in "\xef\xbb\xbf"
189 puts $in "2|3"
drhd5fbde82017-06-26 18:42:23 +0000190 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
196SELECT * FROM t2;}]
197 string map {\n | \n\r |} $res
198} {0 {'x','y'|2,3|4,5}}
199
200# import file with 2 rows, 2 columns or text with an initial BOM
201#
202do_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
211SELECT * FROM t2;}]
212 string map {\n | \n\r |} $res
213} {0 {'x','y'|'two',3|4,5}}
214
shaneh1b8f78c2010-08-18 17:16:26 +0000215# check importing very long field
216do_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
222SELECT length(b) FROM t1 WHERE a='8';}]
223} {0 999}
224
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.
227set cols 999
228do_test shell5-1.6.1 {
shaneh1b8f78c2010-08-18 17:16:26 +0000229 set data {}
230 for {set i 1} {$i<$cols} {incr i} {
drhdb95f682013-06-26 22:46:00 +0000231 append data "c$i|"
232 }
233 append data "c$cols\n";
234 for {set i 1} {$i<$cols} {incr i} {
shaneh1b8f78c2010-08-18 17:16:26 +0000235 append data "$i|"
236 }
shaneh1b8f78c2010-08-18 17:16:26 +0000237 append data "$cols"
shaneh1b8f78c2010-08-18 17:16:26 +0000238 set in [open shell5.csv w]
239 puts $in $data
240 close $in
drhd5fbde82017-06-26 18:42:23 +0000241 set res [catchcmd "test.db" {DROP TABLE IF EXISTS t2;
242.import shell5.csv t2
shaneh1b8f78c2010-08-18 17:16:26 +0000243SELECT COUNT(*) FROM t2;}]
244} {0 1}
245
246# try importing a large number of rows
drh5bde8162013-06-27 14:07:53 +0000247set rows 9999
shaneh1b8f78c2010-08-18 17:16:26 +0000248do_test shell5-1.7.1 {
249 set in [open shell5.csv w]
drhdb95f682013-06-26 22:46:00 +0000250 puts $in a
shaneh1b8f78c2010-08-18 17:16:26 +0000251 for {set i 1} {$i<=$rows} {incr i} {
252 puts $in $i
253 }
254 close $in
drhdb95f682013-06-26 22:46:00 +0000255 set res [catchcmd "test.db" {.mode csv
shaneh1b8f78c2010-08-18 17:16:26 +0000256.import shell5.csv t3
257SELECT COUNT(*) FROM t3;}]
258} [list 0 $rows]
259
drh5bde8162013-06-27 14:07:53 +0000260# Inport from a pipe. (Unix only, as it requires "awk")
261if {$tcl_platform(platform)=="unix"} {
262 do_test shell5-1.8 {
mistachkin9ac99312013-09-13 23:26:47 +0000263 forcedelete test.db
drh5bde8162013-06-27 14:07:53 +0000264 catchcmd test.db {.mode csv
265.import "|awk 'END{print \"x,y\";for(i=1;i<=5;i++){print i \",this is \" i}}'" t1
266SELECT * FROM t1;}
267 } {0 {1,"this is 1"
2682,"this is 2"
2693,"this is 3"
2704,"this is 4"
2715,"this is 5"}}
272}
273
drhf7f8de52013-08-28 11:57:52 +0000274# Import columns containing quoted strings
275do_test shell5-1.9 {
276 set out [open shell5.csv w]
mistachkin9ac99312013-09-13 23:26:47 +0000277 fconfigure $out -translation lf
drhf7f8de52013-08-28 11:57:52 +0000278 puts $out {1,"",11}
279 puts $out {2,"x",22}
280 puts $out {3,"""",33}
281 puts $out {4,"hello",44}
drh868ccf22013-08-28 13:33:40 +0000282 puts $out "5,55,\"\"\r"
drhf7f8de52013-08-28 11:57:52 +0000283 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
mistachkin9ac99312013-09-13 23:26:47 +0000291 forcedelete test.db
drhf7f8de52013-08-28 11:57:52 +0000292 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 |}
299db close
300
drha81ad172013-12-11 14:00:04 +0000301# Import columns containing quoted strings
302do_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}
317
drh3852b682014-02-26 13:53:34 +0000318# Blank last column with \r\n line endings.
319do_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 |}
drha81ad172013-12-11 14:00:04 +0000335db close
336
dan6a8ac852014-05-26 18:27:12 +0000337#----------------------------------------------------------------------------
338#
339reset_db
340sqlite3 db test.db
341do_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
347CREATE TABLE t1(a, b);
348.import shell5.csv t1
349 }]
350 db eval { SELECT * FROM t1 }
351} {{} hello}
352
353do_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
359CREATE TABLE t2(a, b);
360.import shell5.csv t2
361 }]
362 db eval { SELECT * FROM t2 }
363} {{} hello}
364
365do_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
371CREATE TABLE t3(a, b);
372.import shell5.csv t3
373 }]
374 db eval { SELECT * FROM t3 }
375} {x\"y hello}
376
377do_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
383CREATE TABLE t4(a, b);
384.import shell5.csv t4
385 }]
386 db eval { SELECT * FROM t4 }
387} {xy\" hello}
388
mistachkin6fe03382014-06-16 22:45:28 +0000389do_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
396CREATE TABLE t4(a, b);
397.import shell5.csv t4
398 }]
399 db eval { SELECT * FROM t4 }
400} {xy\" hello one 2 {} {}}
dan6a8ac852014-05-26 18:27:12 +0000401
mistachkin636bf9f2014-07-19 20:15:16 +0000402#----------------------------------------------------------------------------
403# Tests for the shell "ascii" import/export mode.
404#
405do_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
413CREATE 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\}"
418
mistachkin636bf9f2014-07-19 20:15:16 +0000419do_test shell5-3.2 {
drhfa5ed022015-01-09 00:38:06 +0000420 set x [catchcmd test.db {
mistachkin636bf9f2014-07-19 20:15:16 +0000421.mode ascii
422SELECT * FROM t5;
drhfa5ed022015-01-09 00:38:06 +0000423 }]
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\}"
dan6a8ac852014-05-26 18:27:12 +0000428
mistachkina0efb1a2015-02-12 22:45:25 +0000429do_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
438CREATE 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}
443
444do_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
453CREATE 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}
458
drh8df91852012-04-24 12:46:05 +0000459finish_test