modernc.org/cc@v1.0.1/v2/testdata/_sqlite/test/shell1.test (about)

     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  #
    22  set testdir [file dirname $argv0]
    23  source $testdir/tester.tcl
    24  set CLI [test_find_cli]
    25  db close
    26  forcedelete test.db test.db-journal test.db-wal
    27  sqlite3 db test.db
    28  
    29  #----------------------------------------------------------------------------
    30  # Test cases shell1-1.*: Basic command line option handling.
    31  #
    32  
    33  # invalid option
    34  do_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}
    40  do_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
    47  do_test shell1-1.1.2 {
    48    catchcmd "test.db \"select+3\" \"select+4\"" ""
    49  } {0 {3
    50  4}}
    51  # error on extra options
    52  do_test shell1-1.1.3 {
    53    catchcmd "test.db FOO test.db BAD" ".quit"
    54  } {1 {Error: near "FOO": syntax error}}
    55  
    56  # -help
    57  do_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
    67  do_test shell1-1.3.1 {
    68    catchcmd "-init FOO test.db" ""
    69  } {0 {}}
    70  do_test shell1-1.3.2 {
    71    catchcmd "-init FOO test.db .quit BAD" ""
    72  } {0 {}}
    73  do_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
    78  do_test shell1-1.4.1 {
    79    catchcmd "-echo test.db" ""
    80  } {0 {}}
    81  
    82  # -[no]header          turn headers on or off
    83  do_test shell1-1.5.1 {
    84    catchcmd "-header test.db" ""
    85  } {0 {}}
    86  do_test shell1-1.5.2 {
    87    catchcmd "-noheader test.db" ""
    88  } {0 {}}
    89  
    90  # -bail                stop after hitting an error
    91  do_test shell1-1.6.1 {
    92    catchcmd "-bail test.db" ""
    93  } {0 {}}
    94  
    95  # -interactive         force interactive I/O
    96  do_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
   105  do_test shell1-1.8.1 {
   106    catchcmd "-batch test.db" ""
   107  } {0 {}}
   108  
   109  # -column              set output mode to 'column'
   110  do_test shell1-1.9.1 {
   111    catchcmd "-column test.db" ""
   112  } {0 {}}
   113  
   114  # -csv                 set output mode to 'csv'
   115  do_test shell1-1.10.1 {
   116    catchcmd "-csv test.db" ""
   117  } {0 {}}
   118  
   119  # -html                set output mode to HTML
   120  do_test shell1-1.11.1 {
   121    catchcmd "-html test.db" ""
   122  } {0 {}}
   123  
   124  # -line                set output mode to 'line'
   125  do_test shell1-1.12.1 {
   126    catchcmd "-line test.db" ""
   127  } {0 {}}
   128  
   129  # -list                set output mode to 'list'
   130  do_test shell1-1.13.1 {
   131    catchcmd "-list test.db" ""
   132  } {0 {}}
   133  
   134  # -separator 'x'       set output field separator (|)
   135  do_test shell1-1.14.1 {
   136    catchcmd "-separator 'x' test.db" ""
   137  } {0 {}}
   138  do_test shell1-1.14.2 {
   139    catchcmd "-separator x test.db" ""
   140  } {0 {}}
   141  do_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
   149  do_test shell1-1.14b.1 {
   150    catchcmd "-stats test.db" ""
   151  } {0 {}}
   152  
   153  # -nullvalue 'text'    set text string for NULL values
   154  do_test shell1-1.15.1 {
   155    catchcmd "-nullvalue 'x' test.db" ""
   156  } {0 {}}
   157  do_test shell1-1.15.2 {
   158    catchcmd "-nullvalue x test.db" ""
   159  } {0 {}}
   160  do_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
   168  do_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
   177  do_test shell1-2.1.1 {
   178    catchcmd "test.db" ".foo"
   179  } {1 {Error: unknown command or invalid arguments:  "foo". Enter ".help" for help}}
   180  do_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}}
   183  do_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
   188  do_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}}
   191  do_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}}
   194  do_test shell1-2.2.3 {
   195    catchcmd "test.db" ".explain \"OFF"
   196  } {0 {}}
   197  do_test shell1-2.2.4 {
   198    catchcmd "test.db" ".explain \'OFF"
   199  } {0 {}}
   200  do_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}}
   203  do_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
   208  do_test shell1-2.3.1 {
   209    catchcmd "test.db" ".explain 1"
   210  } {0 {}}
   211  do_test shell1-2.3.2 {
   212    catchcmd "test.db" ".explain on"
   213  } {0 {}}
   214  do_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".}}
   217  do_test shell1-2.3.4 {
   218    catchcmd "test.db" ".explain \"OFF\""
   219  } {0 {}}
   220  do_test shell1-2.3.5 {
   221    catchcmd "test.db" ".\'explain\' \'OFF\'"
   222  } {0 {}}
   223  do_test shell1-2.3.6 {
   224    catchcmd "test.db" ".explain \'OFF\'"
   225  } {0 {}}
   226  do_test shell1-2.3.7 {
   227    catchcmd "test.db" ".\'explain\' \'OFF\'"
   228  } {0 {}}
   229  
   230  # check quoted args are unquoted
   231  do_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}}
   234  do_test shell1-2.4.2 {
   235    catchcmd "test.db" ".mode csv"
   236  } {0 {}}
   237  do_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
   247  do_test shell1-3.1.1 {
   248    catchcmd "test.db" ".backup"
   249  } {1 {missing FILENAME argument on .backup}}
   250  do_test shell1-3.1.2 {
   251    catchcmd "test.db" ".backup FOO"
   252  } {0 {}}
   253  do_test shell1-3.1.3 {
   254    catchcmd "test.db" ".backup FOO BAR"
   255  } {1 {Error: unknown database FOO}}
   256  do_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
   262  do_test shell1-3.2.1 {
   263    catchcmd "test.db" ".bail"
   264  } {1 {Usage: .bail on|off}}
   265  do_test shell1-3.2.2 {
   266    catchcmd "test.db" ".bail ON"
   267  } {0 {}}
   268  do_test shell1-3.2.3 {
   269    catchcmd "test.db" ".bail OFF"
   270  } {0 {}}
   271  do_test shell1-3.2.4 {
   272    # too many arguments
   273    catchcmd "test.db" ".bail OFF BAD"
   274  } {1 {Usage: .bail on|off}}
   275  
   276  ifcapable vtab {
   277  # .databases             List names and files of attached databases
   278  do_test shell1-3.3.1 {
   279    catchcmd "-csv test.db" ".databases"
   280  } "/0.+main.+[string map {/ ".{1,2}"} [string range [get_pwd] 0 10]].*/"
   281  do_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.
   290  do_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}
   295  do_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}
   300  do_test shell1-3.4.3 {
   301    # too many arguments
   302    catchcmd "test.db" ".dump FOO BAD"
   303  } {1 {Usage: .dump ?--preserve-rowids? ?--newlines? ?LIKE-PATTERN?}}
   304  
   305  # .echo ON|OFF           Turn command echo on or off
   306  do_test shell1-3.5.1 {
   307    catchcmd "test.db" ".echo"
   308  } {1 {Usage: .echo on|off}}
   309  do_test shell1-3.5.2 {
   310    catchcmd "test.db" ".echo ON"
   311  } {0 {}}
   312  do_test shell1-3.5.3 {
   313    catchcmd "test.db" ".echo OFF"
   314  } {0 {}}
   315  do_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
   321  do_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.
   326  do_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 {}}
   330  do_test shell1-3.7.2 {
   331    catchcmd "test.db" ".explain ON"
   332  } {0 {}}
   333  do_test shell1-3.7.3 {
   334    catchcmd "test.db" ".explain OFF"
   335  } {0 {}}
   336  do_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
   343  do_test shell1-3.9.1 {
   344    catchcmd "test.db" ".header"
   345  } {1 {Usage: .headers on|off}}
   346  do_test shell1-3.9.2 {
   347    catchcmd "test.db" ".header ON"
   348  } {0 {}}
   349  do_test shell1-3.9.3 {
   350    catchcmd "test.db" ".header OFF"
   351  } {0 {}}
   352  do_test shell1-3.9.4 {
   353    # too many arguments
   354    catchcmd "test.db" ".header OFF BAD"
   355  } {1 {Usage: .headers on|off}}
   356  
   357  do_test shell1-3.9.5 {
   358    catchcmd "test.db" ".headers"
   359  } {1 {Usage: .headers on|off}}
   360  do_test shell1-3.9.6 {
   361    catchcmd "test.db" ".headers ON"
   362  } {0 {}}
   363  do_test shell1-3.9.7 {
   364    catchcmd "test.db" ".headers OFF"
   365  } {0 {}}
   366  do_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
   372  do_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}
   379  do_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
   389  do_test shell1-3.11.1 {
   390    catchcmd "test.db" ".import"
   391  } {1 {Usage: .import FILE TABLE}}
   392  do_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}}
   398  do_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.
   406  do_test shell1-3.12.1 {
   407    catchcmd "test.db" ".indexes"
   408  } {0 {}}
   409  do_test shell1-3.12.2 {
   410    catchcmd "test.db" ".indexes FOO"
   411  } {0 {}}
   412  do_test shell1-3.12.2-legacy {
   413    catchcmd "test.db" ".indices FOO"
   414  } {0 {}}
   415  do_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
   430  do_test shell1-3.13.1 {
   431    catchcmd "test.db" ".mode"
   432  } {0 {current output mode: list}}
   433  do_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}}
   436  do_test shell1-3.13.3 {
   437    catchcmd "test.db" ".mode csv"
   438  } {0 {}}
   439  do_test shell1-3.13.4 {
   440    catchcmd "test.db" ".mode column"
   441  } {0 {}}
   442  do_test shell1-3.13.5 {
   443    catchcmd "test.db" ".mode html"
   444  } {0 {}}
   445  do_test shell1-3.13.6 {
   446    catchcmd "test.db" ".mode insert"
   447  } {0 {}}
   448  do_test shell1-3.13.7 {
   449    catchcmd "test.db" ".mode line"
   450  } {0 {}}
   451  do_test shell1-3.13.8 {
   452    catchcmd "test.db" ".mode list"
   453  } {0 {}}
   454  do_test shell1-3.13.9 {
   455    catchcmd "test.db" ".mode tabs"
   456  } {0 {}}
   457  do_test shell1-3.13.10 {
   458    catchcmd "test.db" ".mode tcl"
   459  } {0 {}}
   460  do_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
   466  do_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}}
   469  do_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}}
   472  do_test shell1-3.13.14 {
   473    catchcmd "test.db" ".mode lin"
   474  } {0 {}}
   475  
   476  # .nullvalue STRING      Print STRING in place of NULL values
   477  do_test shell1-3.14.1 {
   478    catchcmd "test.db" ".nullvalue"
   479  } {1 {Usage: .nullvalue STRING}}
   480  do_test shell1-3.14.2 {
   481    catchcmd "test.db" ".nullvalue FOO"
   482  } {0 {}}
   483  do_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
   489  do_test shell1-3.15.1 {
   490    catchcmd "test.db" ".output"
   491  } {0 {}}
   492  do_test shell1-3.15.2 {
   493    catchcmd "test.db" ".output FOO"
   494  } {0 {}}
   495  do_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
   501  do_test shell1-3.16.1 {
   502    catchcmd "test.db" ".output stdout"
   503  } {0 {}}
   504  do_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
   510  do_test shell1-3.17.1 {
   511    catchcmd "test.db" ".prompt"
   512  } {0 {}}
   513  do_test shell1-3.17.2 {
   514    catchcmd "test.db" ".prompt FOO"
   515  } {0 {}}
   516  do_test shell1-3.17.3 {
   517    catchcmd "test.db" ".prompt FOO BAR"
   518  } {0 {}}
   519  do_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
   525  do_test shell1-3.18.1 {
   526    catchcmd "test.db" ".quit"
   527  } {0 {}}
   528  do_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
   534  do_test shell1-3.19.1 {
   535    catchcmd "test.db" ".read"
   536  } {1 {Usage: .read FILE}}
   537  do_test shell1-3.19.2 {
   538    forcedelete FOO
   539    catchcmd "test.db" ".read FOO"
   540  } {1 {Error: cannot open "FOO"}}
   541  do_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
   547  do_test shell1-3.20.1 {
   548    catchcmd "test.db" ".restore"
   549  } {1 {Usage: .restore ?DB? FILE}}
   550  do_test shell1-3.20.2 {
   551    catchcmd "test.db" ".restore FOO"
   552  } {0 {}}
   553  do_test shell1-3.20.3 {
   554    catchcmd "test.db" ".restore FOO BAR"
   555  } {1 {Error: unknown database FOO}}
   556  do_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  ifcapable vtab {
   562  # .schema ?TABLE?        Show the CREATE statements
   563  #                          If TABLE specified, only show tables matching
   564  #                          LIKE pattern TABLE.
   565  do_test shell1-3.21.1 {
   566    catchcmd "test.db" ".schema"
   567  } {0 {}}
   568  do_test shell1-3.21.2 {
   569    catchcmd "test.db" ".schema FOO"
   570  } {0 {}}
   571  do_test shell1-3.21.3 {
   572    # too many arguments
   573    catchcmd "test.db" ".schema FOO BAD"
   574  } {1 {Usage: .schema ?--indent? ?LIKE-PATTERN?}}
   575  
   576  do_test shell1-3.21.4 {
   577    catchcmd "test.db" {
   578       CREATE TABLE t1(x);
   579       CREATE VIEW v2 AS SELECT x+1 AS y FROM t1;
   580       CREATE VIEW v1 AS SELECT y+1 FROM v2;
   581    }
   582    catchcmd "test.db" ".schema"
   583  } {0 {CREATE TABLE t1(x);
   584  CREATE VIEW v2 AS SELECT x+1 AS y FROM t1;
   585  CREATE VIEW v1 AS SELECT y+1 FROM v2;}}
   586  db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;}
   587  }
   588  
   589  # .separator STRING  Change column separator used by output and .import
   590  do_test shell1-3.22.1 {
   591    catchcmd "test.db" ".separator"
   592  } {1 {Usage: .separator COL ?ROW?}}
   593  do_test shell1-3.22.2 {
   594    catchcmd "test.db" ".separator FOO"
   595  } {0 {}}
   596  do_test shell1-3.22.3 {
   597    catchcmd "test.db" ".separator ABC XYZ"
   598  } {0 {}}
   599  do_test shell1-3.22.4 {
   600    # too many arguments
   601    catchcmd "test.db" ".separator FOO BAD BAD2"
   602  } {1 {Usage: .separator COL ?ROW?}}
   603  
   604  # .show                  Show the current values for various settings
   605  do_test shell1-3.23.1 {
   606    set res [catchcmd "test.db" ".show"]
   607    list [regexp {echo:} $res] \
   608         [regexp {explain:} $res] \
   609         [regexp {headers:} $res] \
   610         [regexp {mode:} $res] \
   611         [regexp {nullvalue:} $res] \
   612         [regexp {output:} $res] \
   613         [regexp {colseparator:} $res] \
   614         [regexp {rowseparator:} $res] \
   615         [regexp {stats:} $res] \
   616         [regexp {width:} $res]
   617  } {1 1 1 1 1 1 1 1 1 1}
   618  do_test shell1-3.23.2 {
   619    # too many arguments
   620    catchcmd "test.db" ".show BAD"
   621  } {1 {Usage: .show}}
   622  
   623  # .stats ON|OFF          Turn stats on or off
   624  #do_test shell1-3.23b.1 {
   625  #  catchcmd "test.db" ".stats"
   626  #} {1 {Usage: .stats on|off}}
   627  do_test shell1-3.23b.2 {
   628    catchcmd "test.db" ".stats ON"
   629  } {0 {}}
   630  do_test shell1-3.23b.3 {
   631    catchcmd "test.db" ".stats OFF"
   632  } {0 {}}
   633  do_test shell1-3.23b.4 {
   634    # too many arguments
   635    catchcmd "test.db" ".stats OFF BAD"
   636  } {1 {Usage: .stats ?on|off?}}
   637  
   638  # .tables ?TABLE?        List names of tables
   639  #                          If TABLE specified, only list tables matching
   640  #                          LIKE pattern TABLE.
   641  do_test shell1-3.24.1 {
   642    catchcmd "test.db" ".tables"
   643  } {0 {}}
   644  do_test shell1-3.24.2 {
   645    catchcmd "test.db" ".tables FOO"
   646  } {0 {}}
   647  do_test shell1-3.24.3 {
   648    # too many arguments
   649    catchcmd "test.db" ".tables FOO BAD"
   650  } {0 {}}
   651  
   652  # .timeout MS            Try opening locked tables for MS milliseconds
   653  do_test shell1-3.25.1 {
   654    catchcmd "test.db" ".timeout"
   655  } {0 {}}
   656  do_test shell1-3.25.2 {
   657    catchcmd "test.db" ".timeout zzz"
   658    # this should be treated the same as a '0' timeout
   659  } {0 {}}
   660  do_test shell1-3.25.3 {
   661    catchcmd "test.db" ".timeout 1"
   662  } {0 {}}
   663  do_test shell1-3.25.4 {
   664    # too many arguments
   665    catchcmd "test.db" ".timeout 1 BAD"
   666  } {0 {}}
   667  
   668  # .width NUM NUM ...     Set column widths for "column" mode
   669  do_test shell1-3.26.1 {
   670    catchcmd "test.db" ".width"
   671  } {0 {}}
   672  do_test shell1-3.26.2 {
   673    catchcmd "test.db" ".width xxx"
   674    # this should be treated the same as a '0' width for col 1
   675  } {0 {}}
   676  do_test shell1-3.26.3 {
   677    catchcmd "test.db" ".width xxx yyy"
   678    # this should be treated the same as a '0' width for col 1 and 2
   679  } {0 {}}
   680  do_test shell1-3.26.4 {
   681    catchcmd "test.db" ".width 1 1"
   682    # this should be treated the same as a '1' width for col 1 and 2
   683  } {0 {}}
   684  do_test shell1-3.26.5 {
   685    catchcmd "test.db" ".mode column\n.width 10 -10\nSELECT 'abcdefg', 123456;"
   686    # this should be treated the same as a '1' width for col 1 and 2
   687  } {0 {abcdefg         123456}}
   688  do_test shell1-3.26.6 {
   689    catchcmd "test.db" ".mode column\n.width -10 10\nSELECT 'abcdefg', 123456;"
   690    # this should be treated the same as a '1' width for col 1 and 2
   691  } {0 {   abcdefg  123456    }}
   692  
   693  
   694  # .timer ON|OFF          Turn the CPU timer measurement on or off
   695  do_test shell1-3.27.1 {
   696    catchcmd "test.db" ".timer"
   697  } {1 {Usage: .timer on|off}}
   698  do_test shell1-3.27.2 {
   699    catchcmd "test.db" ".timer ON"
   700  } {0 {}}
   701  do_test shell1-3.27.3 {
   702    catchcmd "test.db" ".timer OFF"
   703  } {0 {}}
   704  do_test shell1-3.27.4 {
   705    # too many arguments
   706    catchcmd "test.db" ".timer OFF BAD"
   707  } {1 {Usage: .timer on|off}}
   708  
   709  do_test shell1-3-28.1 {
   710    catchcmd test.db \
   711       ".log stdout\nSELECT coalesce(sqlite_log(123,'hello'),'456');"
   712  } "0 {(123) hello\n456}"
   713  
   714  do_test shell1-3-29.1 {
   715    catchcmd "test.db" ".print this is a test"
   716  } {0 {this is a test}}
   717  
   718  # dot-command argument quoting
   719  do_test shell1-3-30.1 {
   720    catchcmd {test.db} {.print "this\"is'a\055test" 'this\"is\\a\055test'}
   721  } {0 {this"is'a-test this\"is\\a\055test}}
   722  do_test shell1-3-31.1 {
   723    catchcmd {test.db} {.print "this\nis\ta\\test" 'this\nis\ta\\test'}
   724  } [list 0 "this\nis\ta\\test this\\nis\\ta\\\\test"]
   725  
   726  
   727  # Test the output of the ".dump" command
   728  #
   729  do_test shell1-4.1 {
   730    db close
   731    forcedelete test.db
   732    sqlite3 db test.db
   733    db eval {
   734      PRAGMA encoding=UTF16;
   735      CREATE TABLE t1(x);
   736      INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f');
   737      CREATE TABLE t3(x,y);
   738      INSERT INTO t3 VALUES(1,null), (2,''), (3,1),
   739                           (4,2.25), (5,'hello'), (6,x'807f');
   740    }
   741    catchcmd test.db {.dump}
   742  } {0 {PRAGMA foreign_keys=OFF;
   743  BEGIN TRANSACTION;
   744  CREATE TABLE t1(x);
   745  INSERT INTO t1 VALUES(NULL);
   746  INSERT INTO t1 VALUES('');
   747  INSERT INTO t1 VALUES(1);
   748  INSERT INTO t1 VALUES(2.25);
   749  INSERT INTO t1 VALUES('hello');
   750  INSERT INTO t1 VALUES(X'807f');
   751  CREATE TABLE t3(x,y);
   752  INSERT INTO t3 VALUES(1,NULL);
   753  INSERT INTO t3 VALUES(2,'');
   754  INSERT INTO t3 VALUES(3,1);
   755  INSERT INTO t3 VALUES(4,2.25);
   756  INSERT INTO t3 VALUES(5,'hello');
   757  INSERT INTO t3 VALUES(6,X'807f');
   758  COMMIT;}}
   759  
   760  
   761  ifcapable vtab {
   762  
   763  # The --preserve-rowids option to .dump
   764  #
   765  do_test shell1-4.1.1 {
   766    catchcmd test.db {.dump --preserve-rowids}
   767  } {0 {PRAGMA foreign_keys=OFF;
   768  BEGIN TRANSACTION;
   769  CREATE TABLE t1(x);
   770  INSERT INTO t1(rowid,x) VALUES(1,NULL);
   771  INSERT INTO t1(rowid,x) VALUES(2,'');
   772  INSERT INTO t1(rowid,x) VALUES(3,1);
   773  INSERT INTO t1(rowid,x) VALUES(4,2.25);
   774  INSERT INTO t1(rowid,x) VALUES(5,'hello');
   775  INSERT INTO t1(rowid,x) VALUES(6,X'807f');
   776  CREATE TABLE t3(x,y);
   777  INSERT INTO t3(rowid,x,y) VALUES(1,1,NULL);
   778  INSERT INTO t3(rowid,x,y) VALUES(2,2,'');
   779  INSERT INTO t3(rowid,x,y) VALUES(3,3,1);
   780  INSERT INTO t3(rowid,x,y) VALUES(4,4,2.25);
   781  INSERT INTO t3(rowid,x,y) VALUES(5,5,'hello');
   782  INSERT INTO t3(rowid,x,y) VALUES(6,6,X'807f');
   783  COMMIT;}}
   784  
   785  # If the table contains an INTEGER PRIMARY KEY, do not record a separate
   786  # rowid column in the output.
   787  #
   788  do_test shell1-4.1.2 {
   789    db close
   790    forcedelete test2.db
   791    sqlite3 db test2.db
   792    db eval {
   793      CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
   794      INSERT INTO t1 VALUES(1,null), (2,''), (3,1),
   795                           (4,2.25), (5,'hello'), (6,x'807f');
   796    }
   797    catchcmd test2.db {.dump --preserve-rowids}
   798  } {0 {PRAGMA foreign_keys=OFF;
   799  BEGIN TRANSACTION;
   800  CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
   801  INSERT INTO t1 VALUES(1,NULL);
   802  INSERT INTO t1 VALUES(2,'');
   803  INSERT INTO t1 VALUES(3,1);
   804  INSERT INTO t1 VALUES(4,2.25);
   805  INSERT INTO t1 VALUES(5,'hello');
   806  INSERT INTO t1 VALUES(6,X'807f');
   807  COMMIT;}}
   808  
   809  # Verify that the table named [table] is correctly quoted and that
   810  # an INTEGER PRIMARY KEY DESC is not an alias for the rowid.
   811  #
   812  do_test shell1-4.1.3 {
   813    db close
   814    forcedelete test2.db
   815    sqlite3 db test2.db
   816    db eval {
   817      CREATE TABLE [table](x INTEGER PRIMARY KEY DESC, y);
   818      INSERT INTO [table] VALUES(1,null), (12,''), (23,1),
   819                           (34,2.25), (45,'hello'), (56,x'807f');
   820    }
   821    catchcmd test2.db {.dump --preserve-rowids}
   822  } {0 {PRAGMA foreign_keys=OFF;
   823  BEGIN TRANSACTION;
   824  CREATE TABLE [table](x INTEGER PRIMARY KEY DESC, y);
   825  INSERT INTO "table"(rowid,x,y) VALUES(1,1,NULL);
   826  INSERT INTO "table"(rowid,x,y) VALUES(2,12,'');
   827  INSERT INTO "table"(rowid,x,y) VALUES(3,23,1);
   828  INSERT INTO "table"(rowid,x,y) VALUES(4,34,2.25);
   829  INSERT INTO "table"(rowid,x,y) VALUES(5,45,'hello');
   830  INSERT INTO "table"(rowid,x,y) VALUES(6,56,X'807f');
   831  COMMIT;}}
   832  
   833  # Do not record rowids for a WITHOUT ROWID table.  Also check correct quoting
   834  # of table names that contain odd characters.
   835  #
   836  do_test shell1-4.1.4 {
   837    db close
   838    forcedelete test2.db
   839    sqlite3 db test2.db
   840    db eval {
   841      CREATE TABLE [ta<>ble](x INTEGER PRIMARY KEY, y) WITHOUT ROWID;
   842      INSERT INTO [ta<>ble] VALUES(1,null), (12,''), (23,1),
   843                           (34,2.25), (45,'hello'), (56,x'807f');
   844    }
   845    catchcmd test2.db {.dump --preserve-rowids}
   846  } {0 {PRAGMA foreign_keys=OFF;
   847  BEGIN TRANSACTION;
   848  CREATE TABLE [ta<>ble](x INTEGER PRIMARY KEY, y) WITHOUT ROWID;
   849  INSERT INTO "ta<>ble" VALUES(1,NULL);
   850  INSERT INTO "ta<>ble" VALUES(12,'');
   851  INSERT INTO "ta<>ble" VALUES(23,1);
   852  INSERT INTO "ta<>ble" VALUES(34,2.25);
   853  INSERT INTO "ta<>ble" VALUES(45,'hello');
   854  INSERT INTO "ta<>ble" VALUES(56,X'807f');
   855  COMMIT;}}
   856  
   857  # Do not record rowids if the rowid is inaccessible
   858  #
   859  do_test shell1-4.1.5 {
   860    db close
   861    forcedelete test2.db
   862    sqlite3 db test2.db
   863    db eval {
   864      CREATE TABLE t1(_ROWID_,rowid,oid);
   865      INSERT INTO t1 VALUES(1,null,'alpha'), (12,'',99), (23,1,x'b0b1b2');
   866    }
   867    catchcmd test2.db {.dump --preserve-rowids}
   868  } {0 {PRAGMA foreign_keys=OFF;
   869  BEGIN TRANSACTION;
   870  CREATE TABLE t1(_ROWID_,rowid,oid);
   871  INSERT INTO t1 VALUES(1,NULL,'alpha');
   872  INSERT INTO t1 VALUES(12,'',99);
   873  INSERT INTO t1 VALUES(23,1,X'b0b1b2');
   874  COMMIT;}}
   875  
   876  } else {
   877  
   878  do_test shell1-4.1.6 {
   879    db close
   880    forcedelete test2.db
   881    sqlite3 db test2.db
   882    db eval {
   883      CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
   884      INSERT INTO t1 VALUES(1,null), (2,''), (3,1),
   885                           (4,2.25), (5,'hello'), (6,x'807f');
   886    }
   887    catchcmd test2.db {.dump --preserve-rowids}
   888  } {1 {The --preserve-rowids option is not compatible with SQLITE_OMIT_VIRTUALTABLE}}
   889  
   890  }
   891  
   892  
   893  # Test the output of ".mode insert"
   894  #
   895  do_test shell1-4.2.1 {
   896    catchcmd test.db ".mode insert t1\nselect * from t1;"
   897  } {0 {INSERT INTO t1 VALUES(NULL);
   898  INSERT INTO t1 VALUES('');
   899  INSERT INTO t1 VALUES(1);
   900  INSERT INTO t1 VALUES(2.25);
   901  INSERT INTO t1 VALUES('hello');
   902  INSERT INTO t1 VALUES(X'807f');}}
   903  
   904  # Test the output of ".mode insert" with headers
   905  #
   906  do_test shell1-4.2.2 {
   907    catchcmd test.db ".mode insert t1\n.headers on\nselect * from t1;"
   908  } {0 {INSERT INTO t1(x) VALUES(NULL);
   909  INSERT INTO t1(x) VALUES('');
   910  INSERT INTO t1(x) VALUES(1);
   911  INSERT INTO t1(x) VALUES(2.25);
   912  INSERT INTO t1(x) VALUES('hello');
   913  INSERT INTO t1(x) VALUES(X'807f');}}
   914  
   915  # Test the output of ".mode insert"
   916  #
   917  do_test shell1-4.2.3 {
   918    catchcmd test.db ".mode insert t3\nselect * from t3;"
   919  } {0 {INSERT INTO t3 VALUES(1,NULL);
   920  INSERT INTO t3 VALUES(2,'');
   921  INSERT INTO t3 VALUES(3,1);
   922  INSERT INTO t3 VALUES(4,2.25);
   923  INSERT INTO t3 VALUES(5,'hello');
   924  INSERT INTO t3 VALUES(6,X'807f');}}
   925  
   926  # Test the output of ".mode insert" with headers
   927  #
   928  do_test shell1-4.2.4 {
   929    catchcmd test.db ".mode insert t3\n.headers on\nselect * from t3;"
   930  } {0 {INSERT INTO t3(x,y) VALUES(1,NULL);
   931  INSERT INTO t3(x,y) VALUES(2,'');
   932  INSERT INTO t3(x,y) VALUES(3,1);
   933  INSERT INTO t3(x,y) VALUES(4,2.25);
   934  INSERT INTO t3(x,y) VALUES(5,'hello');
   935  INSERT INTO t3(x,y) VALUES(6,X'807f');}}
   936  
   937  # Test the output of ".mode tcl"
   938  #
   939  do_test shell1-4.3 {
   940    db close
   941    forcedelete test.db
   942    sqlite3 db test.db
   943    db eval {
   944      PRAGMA encoding=UTF8;
   945      CREATE TABLE t1(x);
   946      INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f');
   947    }
   948    catchcmd test.db ".mode tcl\nselect * from t1;"
   949  } {0 {""
   950  ""
   951  "1"
   952  "2.25"
   953  "hello"
   954  "\200\177"}}
   955  
   956  # Test the output of ".mode tcl" with multiple columns
   957  #
   958  do_test shell1-4.4 {
   959    db eval {
   960      CREATE TABLE t2(x,y);
   961      INSERT INTO t2 VALUES(null, ''), (1, 2.25), ('hello', x'807f');
   962    }
   963    catchcmd test.db ".mode tcl\nselect * from t2;"
   964  } {0 {"" ""
   965  "1" "2.25"
   966  "hello" "\200\177"}}
   967  
   968  # Test the output of ".mode tcl" with ".nullvalue"
   969  #
   970  do_test shell1-4.5 {
   971    catchcmd test.db ".mode tcl\n.nullvalue NULL\nselect * from t2;"
   972  } {0 {"NULL" ""
   973  "1" "2.25"
   974  "hello" "\200\177"}}
   975  
   976  # Test the output of ".mode tcl" with Tcl reserved characters
   977  #
   978  do_test shell1-4.6 {
   979    db eval {
   980      CREATE TABLE tcl1(x);
   981      INSERT INTO tcl1 VALUES('"'), ('['), (']'), ('\{'), ('\}'), (';'), ('$');
   982    }
   983    foreach {x y} [catchcmd test.db ".mode tcl\nselect * from tcl1;"] break
   984    list $x $y [llength $y]
   985  } {0 {"\""
   986  "["
   987  "]"
   988  "\\{"
   989  "\\}"
   990  ";"
   991  "$"} 7}
   992  
   993  # Test using arbitrary byte data with the shell via standard input/output.
   994  #
   995  do_test shell1-5.0 {
   996    #
   997    # NOTE: Skip NUL byte because it appears to be incompatible with command
   998    #       shell argument parsing.
   999    #
  1000    for {set i 1} {$i < 256} {incr i} {
  1001      #
  1002      # NOTE: Due to how the Tcl [exec] command works (i.e. where it treats
  1003      #       command channels opened for it as textual ones), the carriage
  1004      #       return character (and on Windows, the end-of-file character)
  1005      #       cannot be used here.
  1006      #
  1007      if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} {
  1008        continue
  1009      }
  1010      if {$i>=0xE0 && $tcl_platform(os)=="OpenBSD"}  continue
  1011      if {$i>=0xE0 && $i<=0xEF && $tcl_platform(os)=="Linux"}  continue
  1012      set hex [format %02X $i]
  1013      set char [subst \\x$hex]; set oldChar $char
  1014      set escapes [list]
  1015      if {$tcl_platform(platform)=="windows"} {
  1016        #
  1017        # NOTE: On Windows, we need to escape all the whitespace characters,
  1018        #       the alarm (\a) character, and those with special meaning to
  1019        #       the SQLite shell itself.
  1020        #
  1021        set escapes [list \
  1022            \a \\a \b \\b \t \\t \n \\n \v \\v \f \\f \r \\r \
  1023            " " "\" \"" \" \\\" ' \"'\" \\ \\\\]
  1024      } else {
  1025        #
  1026        # NOTE: On Unix, we need to escape most of the whitespace characters
  1027        #       and those with special meaning to the SQLite shell itself.
  1028        #       The alarm (\a), backspace (\b), and carriage-return (\r)
  1029        #       characters do not appear to require escaping on Unix.  For
  1030        #       the alarm and backspace characters, this is probably due to
  1031        #       differences in the command shell.  For the carriage-return,
  1032        #       it is probably due to differences in how Tcl handles command
  1033        #       channel end-of-line translations.
  1034        #
  1035        set escapes [list \
  1036            \t \\t \n \\n \v \\v \f \\f \
  1037            " " "\" \"" \" \\\" ' \"'\" \\ \\\\]
  1038      }
  1039      set char [string map $escapes $char]
  1040      set x [catchcmdex test.db ".print $char\n"]
  1041      set code [lindex $x 0]
  1042      set res [lindex $x 1]
  1043      if {$code ne "0"} {
  1044        error "failed with error: $res"
  1045      }
  1046      if {$res ne "$oldChar\n"} {
  1047        if {[llength $res] > 0} {
  1048          set got [format %02X [scan $res %c]]
  1049        } else {
  1050          set got <empty>
  1051        }
  1052        error "failed with byte $hex mismatch, got $got"
  1053      }
  1054    }
  1055  } {}
  1056  
  1057  # These test cases do not work on MinGW
  1058  if 0 {
  1059  
  1060  # The string used here is the word "test" in Chinese.
  1061  # In UTF-8, it is encoded as: \xE6\xB5\x8B\xE8\xAF\x95
  1062  set test \u6D4B\u8BD5
  1063  
  1064  do_test shell1-6.0 {
  1065    set fileName $test; append fileName .db
  1066    catch {forcedelete $fileName}
  1067    set x [catchcmdex $fileName "CREATE TABLE t1(x);\n.schema\n"]
  1068    set code [lindex $x 0]
  1069    set res [string trim [lindex $x 1]]
  1070    if {$code ne "0"} {
  1071      error "failed with error: $res"
  1072    }
  1073    if {$res ne "CREATE TABLE t1(x);"} {
  1074      error "failed with mismatch: $res"
  1075    }
  1076    if {![file exists $fileName]} {
  1077      error "file \"$fileName\" (Unicode) does not exist"
  1078    }
  1079    forcedelete $fileName
  1080  } {}
  1081  
  1082  do_test shell1-6.1 {
  1083    catch {forcedelete test3.db}
  1084    set x [catchcmdex test3.db \
  1085        "CREATE TABLE [encoding convertto utf-8 $test](x);\n.schema\n"]
  1086    set code [lindex $x 0]
  1087    set res [string trim [lindex $x 1]]
  1088    if {$code ne "0"} {
  1089      error "failed with error: $res"
  1090    }
  1091    if {$res ne "CREATE TABLE ${test}(x);"} {
  1092      error "failed with mismatch: $res"
  1093    }
  1094    forcedelete test3.db
  1095  } {}
  1096  }
  1097  
  1098  finish_test