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