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