1# 2009 Nov 11 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# 14# 15 16# Test plan: 17# 18# shell1-1.*: Basic command line option handling. 19# shell1-2.*: Basic "dot" command token parsing. 20# shell1-3.*: Basic test that "dot" command can be called. 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 27sqlite3 db test.db 28 29#---------------------------------------------------------------------------- 30# Test cases shell1-1.*: Basic command line option handling. 31# 32 33# invalid option 34do_test shell1-1.1.1 { 35 set res [catchcmd "-bad test.db" ""] 36 set rc [lindex $res 0] 37 list $rc \ 38 [regexp {Error: unknown option: -bad} $res] 39} {1 1} 40do_test shell1-1.1.1b { 41 set res [catchcmd "test.db -bad" ""] 42 set rc [lindex $res 0] 43 list $rc \ 44 [regexp {Error: unknown option: -bad} $res] 45} {1 1} 46# error on extra options 47do_test shell1-1.1.2 { 48 catchcmd "test.db \"select+3\" \"select+4\"" "" 49} {0 {3 504}} 51# error on extra options 52do_test shell1-1.1.3 { 53 catchcmd "test.db FOO test.db BAD" ".quit" 54} {1 {Error: near "FOO": syntax error}} 55 56# -help 57do_test shell1-1.2.1 { 58 set res [catchcmd "-help test.db" ""] 59 set rc [lindex $res 0] 60 list $rc \ 61 [regexp {Usage} $res] \ 62 [regexp {\-init} $res] \ 63 [regexp {\-version} $res] 64} {1 1 1 1} 65 66# -init filename read/process named file 67do_test shell1-1.3.1 { 68 catchcmd "-init FOO test.db" "" 69} {0 {}} 70do_test shell1-1.3.2 { 71 catchcmd "-init FOO test.db .quit BAD" "" 72} {0 {}} 73do_test shell1-1.3.3 { 74 catchcmd "-init FOO test.db BAD .quit" "" 75} {1 {Error: near "BAD": syntax error}} 76 77# -echo print commands before execution 78do_test shell1-1.4.1 { 79 catchcmd "-echo test.db" "" 80} {0 {}} 81 82# -[no]header turn headers on or off 83do_test shell1-1.5.1 { 84 catchcmd "-header test.db" "" 85} {0 {}} 86do_test shell1-1.5.2 { 87 catchcmd "-noheader test.db" "" 88} {0 {}} 89 90# -bail stop after hitting an error 91do_test shell1-1.6.1 { 92 catchcmd "-bail test.db" "" 93} {0 {}} 94 95# -interactive force interactive I/O 96do_test shell1-1.7.1 { 97 set res [catchcmd "-interactive test.db" ".quit"] 98 set rc [lindex $res 0] 99 list $rc \ 100 [regexp {SQLite version} $res] \ 101 [regexp {Enter ".help" for usage hints} $res] 102} {0 1 1} 103 104# -batch force batch I/O 105do_test shell1-1.8.1 { 106 catchcmd "-batch test.db" "" 107} {0 {}} 108 109# -column set output mode to 'column' 110do_test shell1-1.9.1 { 111 catchcmd "-column test.db" "" 112} {0 {}} 113 114# -csv set output mode to 'csv' 115do_test shell1-1.10.1 { 116 catchcmd "-csv test.db" "" 117} {0 {}} 118 119# -html set output mode to HTML 120do_test shell1-1.11.1 { 121 catchcmd "-html test.db" "" 122} {0 {}} 123 124# -line set output mode to 'line' 125do_test shell1-1.12.1 { 126 catchcmd "-line test.db" "" 127} {0 {}} 128 129# -list set output mode to 'list' 130do_test shell1-1.13.1 { 131 catchcmd "-list test.db" "" 132} {0 {}} 133 134# -separator 'x' set output field separator (|) 135do_test shell1-1.14.1 { 136 catchcmd "-separator 'x' test.db" "" 137} {0 {}} 138do_test shell1-1.14.2 { 139 catchcmd "-separator x test.db" "" 140} {0 {}} 141do_test shell1-1.14.3 { 142 set res [catchcmd "-separator" ""] 143 set rc [lindex $res 0] 144 list $rc \ 145 [regexp {Error: missing argument to -separator} $res] 146} {1 1} 147 148# -stats print memory stats before each finalize 149do_test shell1-1.14b.1 { 150 catchcmd "-stats test.db" "" 151} {0 {}} 152 153# -nullvalue 'text' set text string for NULL values 154do_test shell1-1.15.1 { 155 catchcmd "-nullvalue 'x' test.db" "" 156} {0 {}} 157do_test shell1-1.15.2 { 158 catchcmd "-nullvalue x test.db" "" 159} {0 {}} 160do_test shell1-1.15.3 { 161 set res [catchcmd "-nullvalue" ""] 162 set rc [lindex $res 0] 163 list $rc \ 164 [regexp {Error: missing argument to -nullvalue} $res] 165} {1 1} 166 167# -version show SQLite version 168do_test shell1-1.16.1 { 169 set x [catchcmd "-version test.db" ""] 170} {/3.[0-9.]+ 20\d\d-[01]\d-\d\d \d\d:\d\d:\d\d [0-9a-f]+/} 171 172#---------------------------------------------------------------------------- 173# Test cases shell1-2.*: Basic "dot" command token parsing. 174# 175 176# check first token handling 177do_test shell1-2.1.1 { 178 catchcmd "test.db" ".foo" 179} {1 {Error: unknown command or invalid arguments: "foo". Enter ".help" for help}} 180do_test shell1-2.1.2 { 181 catchcmd "test.db" ".\"foo OFF\"" 182} {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} 183do_test shell1-2.1.3 { 184 catchcmd "test.db" ".\'foo OFF\'" 185} {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} 186 187# unbalanced quotes 188do_test shell1-2.2.1 { 189 catchcmd "test.db" ".\"foo OFF" 190} {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} 191do_test shell1-2.2.2 { 192 catchcmd "test.db" ".\'foo OFF" 193} {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} 194do_test shell1-2.2.3 { 195 catchcmd "test.db" ".explain \"OFF" 196} {0 {}} 197do_test shell1-2.2.4 { 198 catchcmd "test.db" ".explain \'OFF" 199} {0 {}} 200do_test shell1-2.2.5 { 201 catchcmd "test.db" ".mode \"insert FOO" 202} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}} 203do_test shell1-2.2.6 { 204 catchcmd "test.db" ".mode \'insert FOO" 205} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}} 206 207# check multiple tokens, and quoted tokens 208do_test shell1-2.3.1 { 209 catchcmd "test.db" ".explain 1" 210} {0 {}} 211do_test shell1-2.3.2 { 212 catchcmd "test.db" ".explain on" 213} {0 {}} 214do_test shell1-2.3.3 { 215 catchcmd "test.db" ".explain \"1 2 3\"" 216} {1 {ERROR: Not a boolean value: "1 2 3". Assuming "no".}} 217do_test shell1-2.3.4 { 218 catchcmd "test.db" ".explain \"OFF\"" 219} {0 {}} 220do_test shell1-2.3.5 { 221 catchcmd "test.db" ".\'explain\' \'OFF\'" 222} {0 {}} 223do_test shell1-2.3.6 { 224 catchcmd "test.db" ".explain \'OFF\'" 225} {0 {}} 226do_test shell1-2.3.7 { 227 catchcmd "test.db" ".\'explain\' \'OFF\'" 228} {0 {}} 229 230# check quoted args are unquoted 231do_test shell1-2.4.1 { 232 catchcmd "test.db" ".mode FOO" 233} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}} 234do_test shell1-2.4.2 { 235 catchcmd "test.db" ".mode csv" 236} {0 {}} 237do_test shell1-2.4.2 { 238 catchcmd "test.db" ".mode \"csv\"" 239} {0 {}} 240 241 242#---------------------------------------------------------------------------- 243# Test cases shell1-3.*: Basic test that "dot" command can be called. 244# 245 246# .backup ?DB? FILE Backup DB (default "main") to FILE 247do_test shell1-3.1.1 { 248 catchcmd "test.db" ".backup" 249} {1 {missing FILENAME argument on .backup}} 250do_test shell1-3.1.2 { 251 catchcmd "test.db" ".backup FOO" 252} {0 {}} 253do_test shell1-3.1.3 { 254 catchcmd "test.db" ".backup FOO BAR" 255} {1 {Error: unknown database FOO}} 256do_test shell1-3.1.4 { 257 # too many arguments 258 catchcmd "test.db" ".backup FOO BAR BAD" 259} {1 {too many arguments to .backup}} 260 261# .bail ON|OFF Stop after hitting an error. Default OFF 262do_test shell1-3.2.1 { 263 catchcmd "test.db" ".bail" 264} {1 {Usage: .bail on|off}} 265do_test shell1-3.2.2 { 266 catchcmd "test.db" ".bail ON" 267} {0 {}} 268do_test shell1-3.2.3 { 269 catchcmd "test.db" ".bail OFF" 270} {0 {}} 271do_test shell1-3.2.4 { 272 # too many arguments 273 catchcmd "test.db" ".bail OFF BAD" 274} {1 {Usage: .bail on|off}} 275 276ifcapable vtab { 277# .databases List names and files of attached databases 278do_test shell1-3.3.1 { 279 catchcmd "-csv test.db" ".databases" 280} "/0.+main.+[string map {/ ".{1,2}"} [string range [get_pwd] 0 10]].*/" 281do_test shell1-3.3.2 { 282 # extra arguments ignored 283 catchcmd "test.db" ".databases BAD" 284} "/0.+main.+[string map {/ ".{1,2}"} [string range [get_pwd] 0 10]].*/" 285} 286 287# .dump ?TABLE? ... Dump the database in an SQL text format 288# If TABLE specified, only dump tables matching 289# LIKE pattern TABLE. 290do_test shell1-3.4.1 { 291 set res [catchcmd "test.db" ".dump"] 292 list [regexp {BEGIN TRANSACTION;} $res] \ 293 [regexp {COMMIT;} $res] 294} {1 1} 295do_test shell1-3.4.2 { 296 set res [catchcmd "test.db" ".dump FOO"] 297 list [regexp {BEGIN TRANSACTION;} $res] \ 298 [regexp {COMMIT;} $res] 299} {1 1} 300do_test shell1-3.4.3 { 301 # too many arguments 302 catchcmd "test.db" ".dump FOO BAD" 303} {1 {Usage: .dump ?--preserve-rowids? ?LIKE-PATTERN?}} 304 305# .echo ON|OFF Turn command echo on or off 306do_test shell1-3.5.1 { 307 catchcmd "test.db" ".echo" 308} {1 {Usage: .echo on|off}} 309do_test shell1-3.5.2 { 310 catchcmd "test.db" ".echo ON" 311} {0 {}} 312do_test shell1-3.5.3 { 313 catchcmd "test.db" ".echo OFF" 314} {0 {}} 315do_test shell1-3.5.4 { 316 # too many arguments 317 catchcmd "test.db" ".echo OFF BAD" 318} {1 {Usage: .echo on|off}} 319 320# .exit Exit this program 321do_test shell1-3.6.1 { 322 catchcmd "test.db" ".exit" 323} {0 {}} 324 325# .explain ON|OFF Turn output mode suitable for EXPLAIN on or off. 326do_test shell1-3.7.1 { 327 catchcmd "test.db" ".explain" 328 # explain is the exception to the booleans. without an option, it turns it on. 329} {0 {}} 330do_test shell1-3.7.2 { 331 catchcmd "test.db" ".explain ON" 332} {0 {}} 333do_test shell1-3.7.3 { 334 catchcmd "test.db" ".explain OFF" 335} {0 {}} 336do_test shell1-3.7.4 { 337 # extra arguments ignored 338 catchcmd "test.db" ".explain OFF BAD" 339} {0 {}} 340 341 342# .header(s) ON|OFF Turn display of headers on or off 343do_test shell1-3.9.1 { 344 catchcmd "test.db" ".header" 345} {1 {Usage: .headers on|off}} 346do_test shell1-3.9.2 { 347 catchcmd "test.db" ".header ON" 348} {0 {}} 349do_test shell1-3.9.3 { 350 catchcmd "test.db" ".header OFF" 351} {0 {}} 352do_test shell1-3.9.4 { 353 # too many arguments 354 catchcmd "test.db" ".header OFF BAD" 355} {1 {Usage: .headers on|off}} 356 357do_test shell1-3.9.5 { 358 catchcmd "test.db" ".headers" 359} {1 {Usage: .headers on|off}} 360do_test shell1-3.9.6 { 361 catchcmd "test.db" ".headers ON" 362} {0 {}} 363do_test shell1-3.9.7 { 364 catchcmd "test.db" ".headers OFF" 365} {0 {}} 366do_test shell1-3.9.8 { 367 # too many arguments 368 catchcmd "test.db" ".headers OFF BAD" 369} {1 {Usage: .headers on|off}} 370 371# .help Show this message 372do_test shell1-3.10.1 { 373 set res [catchcmd "test.db" ".help"] 374 # look for a few of the possible help commands 375 list [regexp {.help} $res] \ 376 [regexp {.quit} $res] \ 377 [regexp {.show} $res] 378} {1 1 1} 379do_test shell1-3.10.2 { 380 # we allow .help to take extra args (it is help after all) 381 set res [catchcmd "test.db" ".help BAD"] 382 # look for a few of the possible help commands 383 list [regexp {.help} $res] \ 384 [regexp {.quit} $res] \ 385 [regexp {.show} $res] 386} {1 1 1} 387 388# .import FILE TABLE Import data from FILE into TABLE 389do_test shell1-3.11.1 { 390 catchcmd "test.db" ".import" 391} {1 {Usage: .import FILE TABLE}} 392do_test shell1-3.11.2 { 393 catchcmd "test.db" ".import FOO" 394} {1 {Usage: .import FILE TABLE}} 395#do_test shell1-3.11.2 { 396# catchcmd "test.db" ".import FOO BAR" 397#} {1 {Error: no such table: BAR}} 398do_test shell1-3.11.3 { 399 # too many arguments 400 catchcmd "test.db" ".import FOO BAR BAD" 401} {1 {Usage: .import FILE TABLE}} 402 403# .indexes ?TABLE? Show names of all indexes 404# If TABLE specified, only show indexes for tables 405# matching LIKE pattern TABLE. 406do_test shell1-3.12.1 { 407 catchcmd "test.db" ".indexes" 408} {0 {}} 409do_test shell1-3.12.2 { 410 catchcmd "test.db" ".indexes FOO" 411} {0 {}} 412do_test shell1-3.12.2-legacy { 413 catchcmd "test.db" ".indices FOO" 414} {0 {}} 415do_test shell1-3.12.3 { 416 # too many arguments 417 catchcmd "test.db" ".indexes FOO BAD" 418} {1 {Usage: .indexes ?LIKE-PATTERN?}} 419 420# .mode MODE ?TABLE? Set output mode where MODE is one of: 421# ascii Columns/rows delimited by 0x1F and 0x1E 422# csv Comma-separated values 423# column Left-aligned columns. (See .width) 424# html HTML <table> code 425# insert SQL insert statements for TABLE 426# line One value per line 427# list Values delimited by .separator strings 428# tabs Tab-separated values 429# tcl TCL list elements 430do_test shell1-3.13.1 { 431 catchcmd "test.db" ".mode" 432} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}} 433do_test shell1-3.13.2 { 434 catchcmd "test.db" ".mode FOO" 435} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}} 436do_test shell1-3.13.3 { 437 catchcmd "test.db" ".mode csv" 438} {0 {}} 439do_test shell1-3.13.4 { 440 catchcmd "test.db" ".mode column" 441} {0 {}} 442do_test shell1-3.13.5 { 443 catchcmd "test.db" ".mode html" 444} {0 {}} 445do_test shell1-3.13.6 { 446 catchcmd "test.db" ".mode insert" 447} {0 {}} 448do_test shell1-3.13.7 { 449 catchcmd "test.db" ".mode line" 450} {0 {}} 451do_test shell1-3.13.8 { 452 catchcmd "test.db" ".mode list" 453} {0 {}} 454do_test shell1-3.13.9 { 455 catchcmd "test.db" ".mode tabs" 456} {0 {}} 457do_test shell1-3.13.10 { 458 catchcmd "test.db" ".mode tcl" 459} {0 {}} 460do_test shell1-3.13.11 { 461 # extra arguments ignored 462 catchcmd "test.db" ".mode tcl BAD" 463} {0 {}} 464 465# don't allow partial mode type matches 466do_test shell1-3.13.12 { 467 catchcmd "test.db" ".mode l" 468} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}} 469do_test shell1-3.13.13 { 470 catchcmd "test.db" ".mode li" 471} {1 {Error: mode should be one of: ascii column csv html insert line list quote tabs tcl}} 472do_test shell1-3.13.14 { 473 catchcmd "test.db" ".mode lin" 474} {0 {}} 475 476# .nullvalue STRING Print STRING in place of NULL values 477do_test shell1-3.14.1 { 478 catchcmd "test.db" ".nullvalue" 479} {1 {Usage: .nullvalue STRING}} 480do_test shell1-3.14.2 { 481 catchcmd "test.db" ".nullvalue FOO" 482} {0 {}} 483do_test shell1-3.14.3 { 484 # too many arguments 485 catchcmd "test.db" ".nullvalue FOO BAD" 486} {1 {Usage: .nullvalue STRING}} 487 488# .output FILENAME Send output to FILENAME 489do_test shell1-3.15.1 { 490 catchcmd "test.db" ".output" 491} {0 {}} 492do_test shell1-3.15.2 { 493 catchcmd "test.db" ".output FOO" 494} {0 {}} 495do_test shell1-3.15.3 { 496 # too many arguments 497 catchcmd "test.db" ".output FOO BAD" 498} {1 {Usage: .output FILE}} 499 500# .output stdout Send output to the screen 501do_test shell1-3.16.1 { 502 catchcmd "test.db" ".output stdout" 503} {0 {}} 504do_test shell1-3.16.2 { 505 # too many arguments 506 catchcmd "test.db" ".output stdout BAD" 507} {1 {Usage: .output FILE}} 508 509# .prompt MAIN CONTINUE Replace the standard prompts 510do_test shell1-3.17.1 { 511 catchcmd "test.db" ".prompt" 512} {0 {}} 513do_test shell1-3.17.2 { 514 catchcmd "test.db" ".prompt FOO" 515} {0 {}} 516do_test shell1-3.17.3 { 517 catchcmd "test.db" ".prompt FOO BAR" 518} {0 {}} 519do_test shell1-3.17.4 { 520 # too many arguments 521 catchcmd "test.db" ".prompt FOO BAR BAD" 522} {0 {}} 523 524# .quit Exit this program 525do_test shell1-3.18.1 { 526 catchcmd "test.db" ".quit" 527} {0 {}} 528do_test shell1-3.18.2 { 529 # too many arguments 530 catchcmd "test.db" ".quit BAD" 531} {0 {}} 532 533# .read FILENAME Execute SQL in FILENAME 534do_test shell1-3.19.1 { 535 catchcmd "test.db" ".read" 536} {1 {Usage: .read FILE}} 537do_test shell1-3.19.2 { 538 forcedelete FOO 539 catchcmd "test.db" ".read FOO" 540} {1 {Error: cannot open "FOO"}} 541do_test shell1-3.19.3 { 542 # too many arguments 543 catchcmd "test.db" ".read FOO BAD" 544} {1 {Usage: .read FILE}} 545 546# .restore ?DB? FILE Restore content of DB (default "main") from FILE 547do_test shell1-3.20.1 { 548 catchcmd "test.db" ".restore" 549} {1 {Usage: .restore ?DB? FILE}} 550do_test shell1-3.20.2 { 551 catchcmd "test.db" ".restore FOO" 552} {0 {}} 553do_test shell1-3.20.3 { 554 catchcmd "test.db" ".restore FOO BAR" 555} {1 {Error: unknown database FOO}} 556do_test shell1-3.20.4 { 557 # too many arguments 558 catchcmd "test.db" ".restore FOO BAR BAD" 559} {1 {Usage: .restore ?DB? FILE}} 560 561# .schema ?TABLE? Show the CREATE statements 562# If TABLE specified, only show tables matching 563# LIKE pattern TABLE. 564do_test shell1-3.21.1 { 565 catchcmd "test.db" ".schema" 566} {0 {}} 567do_test shell1-3.21.2 { 568 catchcmd "test.db" ".schema FOO" 569} {0 {}} 570do_test shell1-3.21.3 { 571 # too many arguments 572 catchcmd "test.db" ".schema FOO BAD" 573} {1 {Usage: .schema ?--indent? ?LIKE-PATTERN?}} 574 575do_test shell1-3.21.4 { 576 catchcmd "test.db" { 577 CREATE TABLE t1(x); 578 CREATE VIEW v2 AS SELECT x+1 AS y FROM t1; 579 CREATE VIEW v1 AS SELECT y+1 FROM v2; 580 } 581 catchcmd "test.db" ".schema" 582} {0 {CREATE TABLE t1(x); 583CREATE VIEW v2 AS SELECT x+1 AS y FROM t1; 584CREATE VIEW v1 AS SELECT y+1 FROM v2;}} 585db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;} 586 587# .separator STRING Change column separator used by output and .import 588do_test shell1-3.22.1 { 589 catchcmd "test.db" ".separator" 590} {1 {Usage: .separator COL ?ROW?}} 591do_test shell1-3.22.2 { 592 catchcmd "test.db" ".separator FOO" 593} {0 {}} 594do_test shell1-3.22.3 { 595 catchcmd "test.db" ".separator ABC XYZ" 596} {0 {}} 597do_test shell1-3.22.4 { 598 # too many arguments 599 catchcmd "test.db" ".separator FOO BAD BAD2" 600} {1 {Usage: .separator COL ?ROW?}} 601 602# .show Show the current values for various settings 603do_test shell1-3.23.1 { 604 set res [catchcmd "test.db" ".show"] 605 list [regexp {echo:} $res] \ 606 [regexp {explain:} $res] \ 607 [regexp {headers:} $res] \ 608 [regexp {mode:} $res] \ 609 [regexp {nullvalue:} $res] \ 610 [regexp {output:} $res] \ 611 [regexp {colseparator:} $res] \ 612 [regexp {rowseparator:} $res] \ 613 [regexp {stats:} $res] \ 614 [regexp {width:} $res] 615} {1 1 1 1 1 1 1 1 1 1} 616do_test shell1-3.23.2 { 617 # too many arguments 618 catchcmd "test.db" ".show BAD" 619} {1 {Usage: .show}} 620 621# .stats ON|OFF Turn stats on or off 622#do_test shell1-3.23b.1 { 623# catchcmd "test.db" ".stats" 624#} {1 {Usage: .stats on|off}} 625do_test shell1-3.23b.2 { 626 catchcmd "test.db" ".stats ON" 627} {0 {}} 628do_test shell1-3.23b.3 { 629 catchcmd "test.db" ".stats OFF" 630} {0 {}} 631do_test shell1-3.23b.4 { 632 # too many arguments 633 catchcmd "test.db" ".stats OFF BAD" 634} {1 {Usage: .stats ?on|off?}} 635 636# .tables ?TABLE? List names of tables 637# If TABLE specified, only list tables matching 638# LIKE pattern TABLE. 639do_test shell1-3.24.1 { 640 catchcmd "test.db" ".tables" 641} {0 {}} 642do_test shell1-3.24.2 { 643 catchcmd "test.db" ".tables FOO" 644} {0 {}} 645do_test shell1-3.24.3 { 646 # too many arguments 647 catchcmd "test.db" ".tables FOO BAD" 648} {0 {}} 649 650# .timeout MS Try opening locked tables for MS milliseconds 651do_test shell1-3.25.1 { 652 catchcmd "test.db" ".timeout" 653} {0 {}} 654do_test shell1-3.25.2 { 655 catchcmd "test.db" ".timeout zzz" 656 # this should be treated the same as a '0' timeout 657} {0 {}} 658do_test shell1-3.25.3 { 659 catchcmd "test.db" ".timeout 1" 660} {0 {}} 661do_test shell1-3.25.4 { 662 # too many arguments 663 catchcmd "test.db" ".timeout 1 BAD" 664} {0 {}} 665 666# .width NUM NUM ... Set column widths for "column" mode 667do_test shell1-3.26.1 { 668 catchcmd "test.db" ".width" 669} {0 {}} 670do_test shell1-3.26.2 { 671 catchcmd "test.db" ".width xxx" 672 # this should be treated the same as a '0' width for col 1 673} {0 {}} 674do_test shell1-3.26.3 { 675 catchcmd "test.db" ".width xxx yyy" 676 # this should be treated the same as a '0' width for col 1 and 2 677} {0 {}} 678do_test shell1-3.26.4 { 679 catchcmd "test.db" ".width 1 1" 680 # this should be treated the same as a '1' width for col 1 and 2 681} {0 {}} 682do_test shell1-3.26.5 { 683 catchcmd "test.db" ".mode column\n.width 10 -10\nSELECT 'abcdefg', 123456;" 684 # this should be treated the same as a '1' width for col 1 and 2 685} {0 {abcdefg 123456}} 686do_test shell1-3.26.6 { 687 catchcmd "test.db" ".mode column\n.width -10 10\nSELECT 'abcdefg', 123456;" 688 # this should be treated the same as a '1' width for col 1 and 2 689} {0 { abcdefg 123456 }} 690 691 692# .timer ON|OFF Turn the CPU timer measurement on or off 693do_test shell1-3.27.1 { 694 catchcmd "test.db" ".timer" 695} {1 {Usage: .timer on|off}} 696do_test shell1-3.27.2 { 697 catchcmd "test.db" ".timer ON" 698} {0 {}} 699do_test shell1-3.27.3 { 700 catchcmd "test.db" ".timer OFF" 701} {0 {}} 702do_test shell1-3.27.4 { 703 # too many arguments 704 catchcmd "test.db" ".timer OFF BAD" 705} {1 {Usage: .timer on|off}} 706 707do_test shell1-3-28.1 { 708 catchcmd test.db \ 709 ".log stdout\nSELECT coalesce(sqlite_log(123,'hello'),'456');" 710} "0 {(123) hello\n456}" 711 712do_test shell1-3-29.1 { 713 catchcmd "test.db" ".print this is a test" 714} {0 {this is a test}} 715 716# dot-command argument quoting 717do_test shell1-3-30.1 { 718 catchcmd {test.db} {.print "this\"is'a\055test" 'this\"is\\a\055test'} 719} {0 {this"is'a-test this\"is\\a\055test}} 720do_test shell1-3-31.1 { 721 catchcmd {test.db} {.print "this\nis\ta\\test" 'this\nis\ta\\test'} 722} [list 0 "this\nis\ta\\test this\\nis\\ta\\\\test"] 723 724 725# Test the output of the ".dump" command 726# 727do_test shell1-4.1 { 728 db close 729 forcedelete test.db 730 sqlite3 db test.db 731 db eval { 732 PRAGMA encoding=UTF16; 733 CREATE TABLE t1(x); 734 INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f'); 735 CREATE TABLE t3(x,y); 736 INSERT INTO t3 VALUES(1,null), (2,''), (3,1), 737 (4,2.25), (5,'hello'), (6,x'807f'); 738 } 739 catchcmd test.db {.dump} 740} {0 {PRAGMA foreign_keys=OFF; 741BEGIN TRANSACTION; 742CREATE TABLE t1(x); 743INSERT INTO t1 VALUES(NULL); 744INSERT INTO t1 VALUES(''); 745INSERT INTO t1 VALUES(1); 746INSERT INTO t1 VALUES(2.25); 747INSERT INTO t1 VALUES('hello'); 748INSERT INTO t1 VALUES(X'807f'); 749CREATE TABLE t3(x,y); 750INSERT INTO t3 VALUES(1,NULL); 751INSERT INTO t3 VALUES(2,''); 752INSERT INTO t3 VALUES(3,1); 753INSERT INTO t3 VALUES(4,2.25); 754INSERT INTO t3 VALUES(5,'hello'); 755INSERT INTO t3 VALUES(6,X'807f'); 756COMMIT;}} 757 758 759ifcapable vtab { 760 761# The --preserve-rowids option to .dump 762# 763do_test shell1-4.1.1 { 764 catchcmd test.db {.dump --preserve-rowids} 765} {0 {PRAGMA foreign_keys=OFF; 766BEGIN TRANSACTION; 767CREATE TABLE t1(x); 768INSERT INTO t1(rowid,x) VALUES(1,NULL); 769INSERT INTO t1(rowid,x) VALUES(2,''); 770INSERT INTO t1(rowid,x) VALUES(3,1); 771INSERT INTO t1(rowid,x) VALUES(4,2.25); 772INSERT INTO t1(rowid,x) VALUES(5,'hello'); 773INSERT INTO t1(rowid,x) VALUES(6,X'807f'); 774CREATE TABLE t3(x,y); 775INSERT INTO t3(rowid,x,y) VALUES(1,1,NULL); 776INSERT INTO t3(rowid,x,y) VALUES(2,2,''); 777INSERT INTO t3(rowid,x,y) VALUES(3,3,1); 778INSERT INTO t3(rowid,x,y) VALUES(4,4,2.25); 779INSERT INTO t3(rowid,x,y) VALUES(5,5,'hello'); 780INSERT INTO t3(rowid,x,y) VALUES(6,6,X'807f'); 781COMMIT;}} 782 783# If the table contains an INTEGER PRIMARY KEY, do not record a separate 784# rowid column in the output. 785# 786do_test shell1-4.1.2 { 787 db close 788 forcedelete test2.db 789 sqlite3 db test2.db 790 db eval { 791 CREATE TABLE t1(x INTEGER PRIMARY KEY, y); 792 INSERT INTO t1 VALUES(1,null), (2,''), (3,1), 793 (4,2.25), (5,'hello'), (6,x'807f'); 794 } 795 catchcmd test2.db {.dump --preserve-rowids} 796} {0 {PRAGMA foreign_keys=OFF; 797BEGIN TRANSACTION; 798CREATE TABLE t1(x INTEGER PRIMARY KEY, y); 799INSERT INTO t1 VALUES(1,NULL); 800INSERT INTO t1 VALUES(2,''); 801INSERT INTO t1 VALUES(3,1); 802INSERT INTO t1 VALUES(4,2.25); 803INSERT INTO t1 VALUES(5,'hello'); 804INSERT INTO t1 VALUES(6,X'807f'); 805COMMIT;}} 806 807# Verify that the table named [table] is correctly quoted and that 808# an INTEGER PRIMARY KEY DESC is not an alias for the rowid. 809# 810do_test shell1-4.1.3 { 811 db close 812 forcedelete test2.db 813 sqlite3 db test2.db 814 db eval { 815 CREATE TABLE [table](x INTEGER PRIMARY KEY DESC, y); 816 INSERT INTO [table] VALUES(1,null), (12,''), (23,1), 817 (34,2.25), (45,'hello'), (56,x'807f'); 818 } 819 catchcmd test2.db {.dump --preserve-rowids} 820} {0 {PRAGMA foreign_keys=OFF; 821BEGIN TRANSACTION; 822CREATE TABLE [table](x INTEGER PRIMARY KEY DESC, y); 823INSERT INTO "table"(rowid,x,y) VALUES(1,1,NULL); 824INSERT INTO "table"(rowid,x,y) VALUES(2,12,''); 825INSERT INTO "table"(rowid,x,y) VALUES(3,23,1); 826INSERT INTO "table"(rowid,x,y) VALUES(4,34,2.25); 827INSERT INTO "table"(rowid,x,y) VALUES(5,45,'hello'); 828INSERT INTO "table"(rowid,x,y) VALUES(6,56,X'807f'); 829COMMIT;}} 830 831# Do not record rowids for a WITHOUT ROWID table. Also check correct quoting 832# of table names that contain odd characters. 833# 834do_test shell1-4.1.4 { 835 db close 836 forcedelete test2.db 837 sqlite3 db test2.db 838 db eval { 839 CREATE TABLE [ta<>ble](x INTEGER PRIMARY KEY, y) WITHOUT ROWID; 840 INSERT INTO [ta<>ble] VALUES(1,null), (12,''), (23,1), 841 (34,2.25), (45,'hello'), (56,x'807f'); 842 } 843 catchcmd test2.db {.dump --preserve-rowids} 844} {0 {PRAGMA foreign_keys=OFF; 845BEGIN TRANSACTION; 846CREATE TABLE [ta<>ble](x INTEGER PRIMARY KEY, y) WITHOUT ROWID; 847INSERT INTO "ta<>ble" VALUES(1,NULL); 848INSERT INTO "ta<>ble" VALUES(12,''); 849INSERT INTO "ta<>ble" VALUES(23,1); 850INSERT INTO "ta<>ble" VALUES(34,2.25); 851INSERT INTO "ta<>ble" VALUES(45,'hello'); 852INSERT INTO "ta<>ble" VALUES(56,X'807f'); 853COMMIT;}} 854 855# Do not record rowids if the rowid is inaccessible 856# 857do_test shell1-4.1.5 { 858 db close 859 forcedelete test2.db 860 sqlite3 db test2.db 861 db eval { 862 CREATE TABLE t1(_ROWID_,rowid,oid); 863 INSERT INTO t1 VALUES(1,null,'alpha'), (12,'',99), (23,1,x'b0b1b2'); 864 } 865 catchcmd test2.db {.dump --preserve-rowids} 866} {0 {PRAGMA foreign_keys=OFF; 867BEGIN TRANSACTION; 868CREATE TABLE t1(_ROWID_,rowid,oid); 869INSERT INTO t1 VALUES(1,NULL,'alpha'); 870INSERT INTO t1 VALUES(12,'',99); 871INSERT INTO t1 VALUES(23,1,X'b0b1b2'); 872COMMIT;}} 873 874} else { 875 876do_test shell1-4.1.6 { 877 db close 878 forcedelete test2.db 879 sqlite3 db test2.db 880 db eval { 881 CREATE TABLE t1(x INTEGER PRIMARY KEY, y); 882 INSERT INTO t1 VALUES(1,null), (2,''), (3,1), 883 (4,2.25), (5,'hello'), (6,x'807f'); 884 } 885 catchcmd test2.db {.dump --preserve-rowids} 886} {1 {The --preserve-rowids option is not compatible with SQLITE_OMIT_VIRTUALTABLE}} 887 888} 889 890 891# Test the output of ".mode insert" 892# 893do_test shell1-4.2.1 { 894 catchcmd test.db ".mode insert t1\nselect * from t1;" 895} {0 {INSERT INTO t1 VALUES(NULL); 896INSERT INTO t1 VALUES(''); 897INSERT INTO t1 VALUES(1); 898INSERT INTO t1 VALUES(2.25); 899INSERT INTO t1 VALUES('hello'); 900INSERT INTO t1 VALUES(X'807f');}} 901 902# Test the output of ".mode insert" with headers 903# 904do_test shell1-4.2.2 { 905 catchcmd test.db ".mode insert t1\n.headers on\nselect * from t1;" 906} {0 {INSERT INTO t1(x) VALUES(NULL); 907INSERT INTO t1(x) VALUES(''); 908INSERT INTO t1(x) VALUES(1); 909INSERT INTO t1(x) VALUES(2.25); 910INSERT INTO t1(x) VALUES('hello'); 911INSERT INTO t1(x) VALUES(X'807f');}} 912 913# Test the output of ".mode insert" 914# 915do_test shell1-4.2.3 { 916 catchcmd test.db ".mode insert t3\nselect * from t3;" 917} {0 {INSERT INTO t3 VALUES(1,NULL); 918INSERT INTO t3 VALUES(2,''); 919INSERT INTO t3 VALUES(3,1); 920INSERT INTO t3 VALUES(4,2.25); 921INSERT INTO t3 VALUES(5,'hello'); 922INSERT INTO t3 VALUES(6,X'807f');}} 923 924# Test the output of ".mode insert" with headers 925# 926do_test shell1-4.2.4 { 927 catchcmd test.db ".mode insert t3\n.headers on\nselect * from t3;" 928} {0 {INSERT INTO t3(x,y) VALUES(1,NULL); 929INSERT INTO t3(x,y) VALUES(2,''); 930INSERT INTO t3(x,y) VALUES(3,1); 931INSERT INTO t3(x,y) VALUES(4,2.25); 932INSERT INTO t3(x,y) VALUES(5,'hello'); 933INSERT INTO t3(x,y) VALUES(6,X'807f');}} 934 935# Test the output of ".mode tcl" 936# 937do_test shell1-4.3 { 938 db close 939 forcedelete test.db 940 sqlite3 db test.db 941 db eval { 942 PRAGMA encoding=UTF8; 943 CREATE TABLE t1(x); 944 INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f'); 945 } 946 catchcmd test.db ".mode tcl\nselect * from t1;" 947} {0 {"" 948"" 949"1" 950"2.25" 951"hello" 952"\200\177"}} 953 954# Test the output of ".mode tcl" with multiple columns 955# 956do_test shell1-4.4 { 957 db eval { 958 CREATE TABLE t2(x,y); 959 INSERT INTO t2 VALUES(null, ''), (1, 2.25), ('hello', x'807f'); 960 } 961 catchcmd test.db ".mode tcl\nselect * from t2;" 962} {0 {"" "" 963"1" "2.25" 964"hello" "\200\177"}} 965 966# Test the output of ".mode tcl" with ".nullvalue" 967# 968do_test shell1-4.5 { 969 catchcmd test.db ".mode tcl\n.nullvalue NULL\nselect * from t2;" 970} {0 {"NULL" "" 971"1" "2.25" 972"hello" "\200\177"}} 973 974# Test the output of ".mode tcl" with Tcl reserved characters 975# 976do_test shell1-4.6 { 977 db eval { 978 CREATE TABLE tcl1(x); 979 INSERT INTO tcl1 VALUES('"'), ('['), (']'), ('\{'), ('\}'), (';'), ('$'); 980 } 981 foreach {x y} [catchcmd test.db ".mode tcl\nselect * from tcl1;"] break 982 list $x $y [llength $y] 983} {0 {"\"" 984"[" 985"]" 986"\\{" 987"\\}" 988";" 989"$"} 7} 990 991# Test using arbitrary byte data with the shell via standard input/output. 992# 993do_test shell1-5.0 { 994 # 995 # NOTE: Skip NUL byte because it appears to be incompatible with command 996 # shell argument parsing. 997 # 998 for {set i 1} {$i < 256} {incr i} { 999 # 1000 # NOTE: Due to how the Tcl [exec] command works (i.e. where it treats 1001 # command channels opened for it as textual ones), the carriage 1002 # return character (and on Windows, the end-of-file character) 1003 # cannot be used here. 1004 # 1005 if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} { 1006 continue 1007 } 1008 if {$i>=0xE0 && $tcl_platform(os)=="OpenBSD"} continue 1009 if {$i>=0xE0 && $i<=0xEF && $tcl_platform(os)=="Linux"} continue 1010 set hex [format %02X $i] 1011 set char [subst \\x$hex]; set oldChar $char 1012 set escapes [list] 1013 if {$tcl_platform(platform)=="windows"} { 1014 # 1015 # NOTE: On Windows, we need to escape all the whitespace characters, 1016 # the alarm (\a) character, and those with special meaning to 1017 # the SQLite shell itself. 1018 # 1019 set escapes [list \ 1020 \a \\a \b \\b \t \\t \n \\n \v \\v \f \\f \r \\r \ 1021 " " "\" \"" \" \\\" ' \"'\" \\ \\\\] 1022 } else { 1023 # 1024 # NOTE: On Unix, we need to escape most of the whitespace characters 1025 # and those with special meaning to the SQLite shell itself. 1026 # The alarm (\a), backspace (\b), and carriage-return (\r) 1027 # characters do not appear to require escaping on Unix. For 1028 # the alarm and backspace characters, this is probably due to 1029 # differences in the command shell. For the carriage-return, 1030 # it is probably due to differences in how Tcl handles command 1031 # channel end-of-line translations. 1032 # 1033 set escapes [list \ 1034 \t \\t \n \\n \v \\v \f \\f \ 1035 " " "\" \"" \" \\\" ' \"'\" \\ \\\\] 1036 } 1037 set char [string map $escapes $char] 1038 set x [catchcmdex test.db ".print $char\n"] 1039 set code [lindex $x 0] 1040 set res [lindex $x 1] 1041 if {$code ne "0"} { 1042 error "failed with error: $res" 1043 } 1044 if {$res ne "$oldChar\n"} { 1045 if {[llength $res] > 0} { 1046 set got [format %02X [scan $res %c]] 1047 } else { 1048 set got <empty> 1049 } 1050 error "failed with byte $hex mismatch, got $got" 1051 } 1052 } 1053} {} 1054 1055# These test cases do not work on MinGW 1056if 0 { 1057 1058# The string used here is the word "test" in Chinese. 1059# In UTF-8, it is encoded as: \xE6\xB5\x8B\xE8\xAF\x95 1060set test \u6D4B\u8BD5 1061 1062do_test shell1-6.0 { 1063 set fileName $test; append fileName .db 1064 catch {forcedelete $fileName} 1065 set x [catchcmdex $fileName "CREATE TABLE t1(x);\n.schema\n"] 1066 set code [lindex $x 0] 1067 set res [string trim [lindex $x 1]] 1068 if {$code ne "0"} { 1069 error "failed with error: $res" 1070 } 1071 if {$res ne "CREATE TABLE t1(x);"} { 1072 error "failed with mismatch: $res" 1073 } 1074 if {![file exists $fileName]} { 1075 error "file \"$fileName\" (Unicode) does not exist" 1076 } 1077 forcedelete $fileName 1078} {} 1079 1080do_test shell1-6.1 { 1081 catch {forcedelete test3.db} 1082 set x [catchcmdex test3.db \ 1083 "CREATE TABLE [encoding convertto utf-8 $test](x);\n.schema\n"] 1084 set code [lindex $x 0] 1085 set res [string trim [lindex $x 1]] 1086 if {$code ne "0"} { 1087 error "failed with error: $res" 1088 } 1089 if {$res ne "CREATE TABLE ${test}(x);"} { 1090 error "failed with mismatch: $res" 1091 } 1092 forcedelete test3.db 1093} {} 1094} 1095 1096finish_test 1097