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