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