blob: 6b038495f5d7e430cb151204515de2eb74b84bee [file] [log] [blame]
drh2ce15c32017-07-11 13:34:40 +00001/*
2** 2001 September 15
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11*************************************************************************
12** This file contains code to implement the "sqlite" command line
13** utility for accessing SQLite databases.
14*/
15#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
16/* This needs to come before any includes for MSVC compiler */
17#define _CRT_SECURE_NO_WARNINGS
18#endif
drh80fafc22022-11-07 19:40:20 +000019typedef unsigned int u32;
20typedef unsigned short int u16;
drh2ce15c32017-07-11 13:34:40 +000021
22/*
larrybra13c0c72021-07-09 00:12:05 +000023** Optionally #include a user-defined header, whereby compilation options
24** may be set prior to where they take effect, but after platform setup.
25** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include
26** file. Note that this macro has a like effect on sqlite3.c compilation.
27*/
larrybr78138392022-02-12 02:15:37 +000028# define SHELL_STRINGIFY_(f) #f
29# define SHELL_STRINGIFY(f) SHELL_STRINGIFY_(f)
larrybra13c0c72021-07-09 00:12:05 +000030#ifdef SQLITE_CUSTOM_INCLUDE
larrybr78138392022-02-12 02:15:37 +000031# include SHELL_STRINGIFY(SQLITE_CUSTOM_INCLUDE)
larrybra13c0c72021-07-09 00:12:05 +000032#endif
33
34/*
mistachkin43e86272020-04-09 15:31:22 +000035** Determine if we are dealing with WinRT, which provides only a subset of
36** the full Win32 API.
37*/
38#if !defined(SQLITE_OS_WINRT)
39# define SQLITE_OS_WINRT 0
40#endif
41
42/*
stephan4413ec72022-07-12 15:53:02 +000043** If SQLITE_SHELL_FIDDLE is defined then the shell is modified
44** somewhat for use as a WASM module in a web browser. This flag
45** should only be used when building the "fiddle" web application, as
46** the browser-mode build has much different user input requirements
47** and this build mode rewires the user input subsystem to account for
48** that.
stephanea1e3b42022-07-12 09:40:27 +000049*/
50
51/*
drh2ce15c32017-07-11 13:34:40 +000052** Warning pragmas copied from msvc.h in the core.
53*/
54#if defined(_MSC_VER)
55#pragma warning(disable : 4054)
56#pragma warning(disable : 4055)
57#pragma warning(disable : 4100)
58#pragma warning(disable : 4127)
59#pragma warning(disable : 4130)
60#pragma warning(disable : 4152)
61#pragma warning(disable : 4189)
62#pragma warning(disable : 4206)
63#pragma warning(disable : 4210)
64#pragma warning(disable : 4232)
65#pragma warning(disable : 4244)
66#pragma warning(disable : 4305)
67#pragma warning(disable : 4306)
68#pragma warning(disable : 4702)
69#pragma warning(disable : 4706)
70#endif /* defined(_MSC_VER) */
71
72/*
73** No support for loadable extensions in VxWorks.
74*/
75#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION
76# define SQLITE_OMIT_LOAD_EXTENSION 1
77#endif
78
79/*
80** Enable large-file support for fopen() and friends on unix.
81*/
82#ifndef SQLITE_DISABLE_LFS
83# define _LARGE_FILE 1
84# ifndef _FILE_OFFSET_BITS
85# define _FILE_OFFSET_BITS 64
86# endif
87# define _LARGEFILE_SOURCE 1
88#endif
89
stephan65022712022-09-21 16:21:21 +000090#if defined(SQLITE_SHELL_FIDDLE) && !defined(_POSIX_SOURCE)
91/*
92** emcc requires _POSIX_SOURCE (or one of several similar defines)
93** to expose strdup().
94*/
95# define _POSIX_SOURCE
96#endif
97
drh2ce15c32017-07-11 13:34:40 +000098#include <stdlib.h>
99#include <string.h>
100#include <stdio.h>
101#include <assert.h>
102#include "sqlite3.h"
drh1e506b52018-01-05 21:01:37 +0000103typedef sqlite3_int64 i64;
104typedef sqlite3_uint64 u64;
drh1fa6d9f2018-01-06 21:46:01 +0000105typedef unsigned char u8;
drh2ce15c32017-07-11 13:34:40 +0000106#if SQLITE_USER_AUTHENTICATION
107# include "sqlite3userauth.h"
108#endif
109#include <ctype.h>
110#include <stdarg.h>
111
112#if !defined(_WIN32) && !defined(WIN32)
113# include <signal.h>
114# if !defined(__RTP__) && !defined(_WRS_KERNEL)
115# include <pwd.h>
116# endif
mistachkinacae8c32018-01-05 20:08:46 +0000117#endif
mistachkin562f0c82018-01-09 00:28:24 +0000118#if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__)
drh2ce15c32017-07-11 13:34:40 +0000119# include <unistd.h>
mistachkinacae8c32018-01-05 20:08:46 +0000120# include <dirent.h>
mistachkin1e8487d2018-07-22 06:25:35 +0000121# define GETPID getpid
mistachkin562f0c82018-01-09 00:28:24 +0000122# if defined(__MINGW32__)
mistachkinacae8c32018-01-05 20:08:46 +0000123# define DIRENT dirent
mistachkin2f74b3c2018-01-05 20:26:06 +0000124# ifndef S_ISLNK
125# define S_ISLNK(mode) (0)
126# endif
mistachkinacae8c32018-01-05 20:08:46 +0000127# endif
mistachkin1e8487d2018-07-22 06:25:35 +0000128#else
129# define GETPID (int)GetCurrentProcessId
drh2ce15c32017-07-11 13:34:40 +0000130#endif
mistachkindfdfd8c2018-01-04 22:46:08 +0000131#include <sys/types.h>
132#include <sys/stat.h>
drh2ce15c32017-07-11 13:34:40 +0000133
134#if HAVE_READLINE
135# include <readline/readline.h>
136# include <readline/history.h>
137#endif
138
139#if HAVE_EDITLINE
140# include <editline/readline.h>
141#endif
142
143#if HAVE_EDITLINE || HAVE_READLINE
144
145# define shell_add_history(X) add_history(X)
146# define shell_read_history(X) read_history(X)
147# define shell_write_history(X) write_history(X)
148# define shell_stifle_history(X) stifle_history(X)
149# define shell_readline(X) readline(X)
150
151#elif HAVE_LINENOISE
152
153# include "linenoise.h"
154# define shell_add_history(X) linenoiseHistoryAdd(X)
155# define shell_read_history(X) linenoiseHistoryLoad(X)
156# define shell_write_history(X) linenoiseHistorySave(X)
157# define shell_stifle_history(X) linenoiseHistorySetMaxLen(X)
158# define shell_readline(X) linenoise(X)
159
160#else
161
162# define shell_read_history(X)
163# define shell_write_history(X)
164# define shell_stifle_history(X)
165
166# define SHELL_USE_LOCAL_GETLINE 1
167#endif
168
169
170#if defined(_WIN32) || defined(WIN32)
mistachkin43e86272020-04-09 15:31:22 +0000171# if SQLITE_OS_WINRT
172# define SQLITE_OMIT_POPEN 1
173# else
174# include <io.h>
175# include <fcntl.h>
176# define isatty(h) _isatty(h)
177# ifndef access
178# define access(f,m) _access((f),(m))
179# endif
180# ifndef unlink
181# define unlink _unlink
182# endif
183# ifndef strdup
184# define strdup _strdup
185# endif
186# undef popen
187# define popen _popen
188# undef pclose
189# define pclose _pclose
drh2ce15c32017-07-11 13:34:40 +0000190# endif
drh2ce15c32017-07-11 13:34:40 +0000191#else
192 /* Make sure isatty() has a prototype. */
193 extern int isatty(int);
194
195# if !defined(__RTP__) && !defined(_WRS_KERNEL)
196 /* popen and pclose are not C89 functions and so are
197 ** sometimes omitted from the <stdio.h> header */
198 extern FILE *popen(const char*,const char*);
199 extern int pclose(FILE*);
200# else
201# define SQLITE_OMIT_POPEN 1
202# endif
203#endif
204
205#if defined(_WIN32_WCE)
206/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
207 * thus we always assume that we have a console. That can be
208 * overridden with the -batch command line option.
209 */
210#define isatty(x) 1
211#endif
212
213/* ctype macros that work with signed characters */
214#define IsSpace(X) isspace((unsigned char)X)
215#define IsDigit(X) isdigit((unsigned char)X)
216#define ToLower(X) (char)tolower((unsigned char)X)
217
218#if defined(_WIN32) || defined(WIN32)
mistachkin43e86272020-04-09 15:31:22 +0000219#if SQLITE_OS_WINRT
220#include <intrin.h>
221#endif
drh2ce15c32017-07-11 13:34:40 +0000222#include <windows.h>
223
224/* string conversion routines only needed on Win32 */
225extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
226extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
227extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
228extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
229#endif
230
231/* On Windows, we normally run with output mode of TEXT so that \n characters
232** are automatically translated into \r\n. However, this behavior needs
233** to be disabled in some cases (ex: when generating CSV output and when
234** rendering quoted strings that contain \n characters). The following
235** routines take care of that.
236*/
mistachkin43e86272020-04-09 15:31:22 +0000237#if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
drh2ce15c32017-07-11 13:34:40 +0000238static void setBinaryMode(FILE *file, int isOutput){
239 if( isOutput ) fflush(file);
240 _setmode(_fileno(file), _O_BINARY);
241}
242static void setTextMode(FILE *file, int isOutput){
243 if( isOutput ) fflush(file);
244 _setmode(_fileno(file), _O_TEXT);
245}
246#else
247# define setBinaryMode(X,Y)
248# define setTextMode(X,Y)
249#endif
250
drh2ce15c32017-07-11 13:34:40 +0000251/* True if the timer is enabled */
252static int enableTimer = 0;
253
drhbf70f1b2022-10-19 18:04:42 +0000254/* A version of strcmp() that works with NULL values */
255static int cli_strcmp(const char *a, const char *b){
256 if( a==0 ) a = "";
257 if( b==0 ) b = "";
258 return strcmp(a,b);
259}
260static int cli_strncmp(const char *a, const char *b, size_t n){
261 if( a==0 ) a = "";
262 if( b==0 ) b = "";
263 return strncmp(a,b,n);
264}
265
drh2ce15c32017-07-11 13:34:40 +0000266/* Return the current wall-clock time */
267static sqlite3_int64 timeOfDay(void){
268 static sqlite3_vfs *clockVfs = 0;
269 sqlite3_int64 t;
270 if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
drha959bf52021-06-15 15:15:40 +0000271 if( clockVfs==0 ) return 0; /* Never actually happens */
drh2ce15c32017-07-11 13:34:40 +0000272 if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
273 clockVfs->xCurrentTimeInt64(clockVfs, &t);
274 }else{
275 double r;
276 clockVfs->xCurrentTime(clockVfs, &r);
277 t = (sqlite3_int64)(r*86400000.0);
278 }
279 return t;
280}
281
282#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
283#include <sys/time.h>
284#include <sys/resource.h>
285
286/* VxWorks does not support getrusage() as far as we can determine */
287#if defined(_WRS_KERNEL) || defined(__RTP__)
288struct rusage {
289 struct timeval ru_utime; /* user CPU time used */
290 struct timeval ru_stime; /* system CPU time used */
291};
292#define getrusage(A,B) memset(B,0,sizeof(*B))
293#endif
294
295/* Saved resource information for the beginning of an operation */
296static struct rusage sBegin; /* CPU time at start */
297static sqlite3_int64 iBegin; /* Wall-clock time at start */
298
299/*
300** Begin timing an operation
301*/
302static void beginTimer(void){
303 if( enableTimer ){
304 getrusage(RUSAGE_SELF, &sBegin);
305 iBegin = timeOfDay();
306 }
307}
308
309/* Return the difference of two time_structs in seconds */
310static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
311 return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
312 (double)(pEnd->tv_sec - pStart->tv_sec);
313}
314
315/*
316** Print the timing results.
317*/
318static void endTimer(void){
319 if( enableTimer ){
320 sqlite3_int64 iEnd = timeOfDay();
321 struct rusage sEnd;
322 getrusage(RUSAGE_SELF, &sEnd);
323 printf("Run Time: real %.3f user %f sys %f\n",
324 (iEnd - iBegin)*0.001,
325 timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
326 timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
327 }
328}
329
330#define BEGIN_TIMER beginTimer()
331#define END_TIMER endTimer()
332#define HAS_TIMER 1
333
334#elif (defined(_WIN32) || defined(WIN32))
335
336/* Saved resource information for the beginning of an operation */
337static HANDLE hProcess;
338static FILETIME ftKernelBegin;
339static FILETIME ftUserBegin;
340static sqlite3_int64 ftWallBegin;
341typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME,
342 LPFILETIME, LPFILETIME);
343static GETPROCTIMES getProcessTimesAddr = NULL;
344
345/*
346** Check to see if we have timer support. Return 1 if necessary
347** support found (or found previously).
348*/
349static int hasTimer(void){
350 if( getProcessTimesAddr ){
351 return 1;
352 } else {
mistachkin43e86272020-04-09 15:31:22 +0000353#if !SQLITE_OS_WINRT
drh2ce15c32017-07-11 13:34:40 +0000354 /* GetProcessTimes() isn't supported in WIN95 and some other Windows
355 ** versions. See if the version we are running on has it, and if it
356 ** does, save off a pointer to it and the current process handle.
357 */
358 hProcess = GetCurrentProcess();
359 if( hProcess ){
360 HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
361 if( NULL != hinstLib ){
362 getProcessTimesAddr =
363 (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
364 if( NULL != getProcessTimesAddr ){
365 return 1;
366 }
367 FreeLibrary(hinstLib);
368 }
369 }
mistachkin43e86272020-04-09 15:31:22 +0000370#endif
drh2ce15c32017-07-11 13:34:40 +0000371 }
372 return 0;
373}
374
375/*
376** Begin timing an operation
377*/
378static void beginTimer(void){
379 if( enableTimer && getProcessTimesAddr ){
380 FILETIME ftCreation, ftExit;
381 getProcessTimesAddr(hProcess,&ftCreation,&ftExit,
382 &ftKernelBegin,&ftUserBegin);
383 ftWallBegin = timeOfDay();
384 }
385}
386
387/* Return the difference of two FILETIME structs in seconds */
388static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
389 sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
390 sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
391 return (double) ((i64End - i64Start) / 10000000.0);
392}
393
394/*
395** Print the timing results.
396*/
397static void endTimer(void){
398 if( enableTimer && getProcessTimesAddr){
399 FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
400 sqlite3_int64 ftWallEnd = timeOfDay();
401 getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
402 printf("Run Time: real %.3f user %f sys %f\n",
403 (ftWallEnd - ftWallBegin)*0.001,
404 timeDiff(&ftUserBegin, &ftUserEnd),
405 timeDiff(&ftKernelBegin, &ftKernelEnd));
406 }
407}
408
409#define BEGIN_TIMER beginTimer()
410#define END_TIMER endTimer()
411#define HAS_TIMER hasTimer()
412
413#else
414#define BEGIN_TIMER
415#define END_TIMER
416#define HAS_TIMER 0
417#endif
418
419/*
420** Used to prevent warnings about unused parameters
421*/
422#define UNUSED_PARAMETER(x) (void)(x)
423
424/*
drh5af06982018-01-10 00:53:55 +0000425** Number of elements in an array
426*/
427#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
428
429/*
drh2ce15c32017-07-11 13:34:40 +0000430** If the following flag is set, then command execution stops
431** at an error if we are not interactive.
432*/
433static int bail_on_error = 0;
434
435/*
436** Threat stdin as an interactive input if the following variable
437** is true. Otherwise, assume stdin is connected to a file or pipe.
438*/
439static int stdin_is_interactive = 1;
440
441/*
442** On Windows systems we have to know if standard output is a console
443** in order to translate UTF-8 into MBCS. The following variable is
444** true if translation is required.
445*/
446static int stdout_is_console = 1;
447
448/*
449** The following is the open SQLite database. We make a pointer
450** to this database a static variable so that it can be accessed
451** by the SIGINT handler to interrupt database processing.
452*/
453static sqlite3 *globalDb = 0;
454
455/*
456** True if an interrupt (Control-C) has been received.
457*/
458static volatile int seenInterrupt = 0;
459
460/*
461** This is the name of our program. It is set in main(), used
462** in a number of other places, mostly for error messages.
463*/
464static char *Argv0;
465
466/*
467** Prompt strings. Initialized in main. Settable with
468** .prompt main continue
469*/
470static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
471static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
472
473/*
474** Render output like fprintf(). Except, if the output is going to the
475** console and if this is running on a Windows machine, translate the
476** output from UTF-8 into MBCS.
477*/
478#if defined(_WIN32) || defined(WIN32)
479void utf8_printf(FILE *out, const char *zFormat, ...){
480 va_list ap;
481 va_start(ap, zFormat);
482 if( stdout_is_console && (out==stdout || out==stderr) ){
483 char *z1 = sqlite3_vmprintf(zFormat, ap);
484 char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
485 sqlite3_free(z1);
486 fputs(z2, out);
487 sqlite3_free(z2);
488 }else{
489 vfprintf(out, zFormat, ap);
490 }
491 va_end(ap);
492}
493#elif !defined(utf8_printf)
494# define utf8_printf fprintf
495#endif
496
497/*
498** Render output like fprintf(). This should not be used on anything that
499** includes string formatting (e.g. "%s").
500*/
501#if !defined(raw_printf)
502# define raw_printf fprintf
503#endif
504
drh4b5345c2018-04-24 13:07:40 +0000505/* Indicate out-of-memory and exit. */
506static void shell_out_of_memory(void){
507 raw_printf(stderr,"Error: out of memory\n");
508 exit(1);
509}
510
drhe3e25652021-12-16 13:29:28 +0000511/* Check a pointer to see if it is NULL. If it is NULL, exit with an
512** out-of-memory error.
513*/
514static void shell_check_oom(void *p){
515 if( p==0 ) shell_out_of_memory();
516}
517
drh2ce15c32017-07-11 13:34:40 +0000518/*
519** Write I/O traces to the following stream.
520*/
521#ifdef SQLITE_ENABLE_IOTRACE
522static FILE *iotrace = 0;
523#endif
524
525/*
526** This routine works like printf in that its first argument is a
527** format string and subsequent arguments are values to be substituted
528** in place of % fields. The result of formatting this string
529** is written to iotrace.
530*/
531#ifdef SQLITE_ENABLE_IOTRACE
532static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
533 va_list ap;
534 char *z;
535 if( iotrace==0 ) return;
536 va_start(ap, zFormat);
537 z = sqlite3_vmprintf(zFormat, ap);
538 va_end(ap);
539 utf8_printf(iotrace, "%s", z);
540 sqlite3_free(z);
541}
542#endif
543
544/*
545** Output string zUtf to stream pOut as w characters. If w is negative,
546** then right-justify the text. W is the width in UTF-8 characters, not
547** in bytes. This is different from the %*.*s specification in printf
548** since with %*.*s the width is measured in bytes, not characters.
549*/
550static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
551 int i;
552 int n;
553 int aw = w<0 ? -w : w;
drh4853aa12022-10-27 18:20:08 +0000554 if( zUtf==0 ) zUtf = "";
drh2ce15c32017-07-11 13:34:40 +0000555 for(i=n=0; zUtf[i]; i++){
556 if( (zUtf[i]&0xc0)!=0x80 ){
557 n++;
558 if( n==aw ){
559 do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
560 break;
561 }
562 }
563 }
564 if( n>=aw ){
565 utf8_printf(pOut, "%.*s", i, zUtf);
566 }else if( w<0 ){
567 utf8_printf(pOut, "%*s%s", aw-n, "", zUtf);
568 }else{
569 utf8_printf(pOut, "%s%*s", zUtf, aw-n, "");
570 }
571}
572
573
574/*
575** Determines if a string is a number of not.
576*/
577static int isNumber(const char *z, int *realnum){
578 if( *z=='-' || *z=='+' ) z++;
579 if( !IsDigit(*z) ){
580 return 0;
581 }
582 z++;
583 if( realnum ) *realnum = 0;
584 while( IsDigit(*z) ){ z++; }
585 if( *z=='.' ){
586 z++;
587 if( !IsDigit(*z) ) return 0;
588 while( IsDigit(*z) ){ z++; }
589 if( realnum ) *realnum = 1;
590 }
591 if( *z=='e' || *z=='E' ){
592 z++;
593 if( *z=='+' || *z=='-' ) z++;
594 if( !IsDigit(*z) ) return 0;
595 while( IsDigit(*z) ){ z++; }
596 if( realnum ) *realnum = 1;
597 }
598 return *z==0;
599}
600
601/*
602** Compute a string length that is limited to what can be stored in
603** lower 30 bits of a 32-bit signed integer.
604*/
605static int strlen30(const char *z){
606 const char *z2 = z;
607 while( *z2 ){ z2++; }
608 return 0x3fffffff & (int)(z2 - z);
609}
610
611/*
612** Return the length of a string in characters. Multibyte UTF8 characters
613** count as a single character.
614*/
615static int strlenChar(const char *z){
616 int n = 0;
617 while( *z ){
618 if( (0xc0&*(z++))!=0x80 ) n++;
619 }
620 return n;
621}
622
623/*
larrybrd96bcc72021-09-17 21:12:47 +0000624** Return open FILE * if zFile exists, can be opened for read
625** and is an ordinary file or a character stream source.
626** Otherwise return 0.
drhbbd620e2020-07-20 23:33:11 +0000627*/
larrybrd96bcc72021-09-17 21:12:47 +0000628static FILE * openChrSource(const char *zFile){
drhbbd620e2020-07-20 23:33:11 +0000629#ifdef _WIN32
larrybrd0007852021-09-13 23:11:46 +0000630 struct _stat x = {0};
larrybrd0007852021-09-13 23:11:46 +0000631# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
larrybrd96bcc72021-09-17 21:12:47 +0000632 /* On Windows, open first, then check the stream nature. This order
633 ** is necessary because _stat() and sibs, when checking a named pipe,
634 ** effectively break the pipe as its supplier sees it. */
635 FILE *rv = fopen(zFile, "rb");
636 if( rv==0 ) return 0;
637 if( _fstat(_fileno(rv), &x) != 0
638 || !STAT_CHR_SRC(x.st_mode)){
639 fclose(rv);
640 rv = 0;
641 }
642 return rv;
drhbbd620e2020-07-20 23:33:11 +0000643#else
larrybrd0007852021-09-13 23:11:46 +0000644 struct stat x = {0};
645 int rc = stat(zFile, &x);
646# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
larrybrd96bcc72021-09-17 21:12:47 +0000647 if( rc!=0 ) return 0;
648 if( STAT_CHR_SRC(x.st_mode) ){
649 return fopen(zFile, "rb");
650 }else{
651 return 0;
652 }
drhbbd620e2020-07-20 23:33:11 +0000653#endif
larrybrd0007852021-09-13 23:11:46 +0000654#undef STAT_CHR_SRC
655}
drhbbd620e2020-07-20 23:33:11 +0000656
657/*
drh2ce15c32017-07-11 13:34:40 +0000658** This routine reads a line of text from FILE in, stores
659** the text in memory obtained from malloc() and returns a pointer
660** to the text. NULL is returned at end of file, or if malloc()
661** fails.
662**
663** If zLine is not NULL then it is a malloced buffer returned from
664** a previous call to this routine that may be reused.
665*/
666static char *local_getline(char *zLine, FILE *in){
667 int nLine = zLine==0 ? 0 : 100;
668 int n = 0;
669
670 while( 1 ){
671 if( n+100>nLine ){
672 nLine = nLine*2 + 100;
673 zLine = realloc(zLine, nLine);
drhe3e25652021-12-16 13:29:28 +0000674 shell_check_oom(zLine);
drh2ce15c32017-07-11 13:34:40 +0000675 }
676 if( fgets(&zLine[n], nLine - n, in)==0 ){
677 if( n==0 ){
678 free(zLine);
679 return 0;
680 }
681 zLine[n] = 0;
682 break;
683 }
684 while( zLine[n] ) n++;
685 if( n>0 && zLine[n-1]=='\n' ){
686 n--;
687 if( n>0 && zLine[n-1]=='\r' ) n--;
688 zLine[n] = 0;
689 break;
690 }
691 }
692#if defined(_WIN32) || defined(WIN32)
693 /* For interactive input on Windows systems, translate the
694 ** multi-byte characterset characters into UTF-8. */
695 if( stdin_is_interactive && in==stdin ){
696 char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
697 if( zTrans ){
drh7d23d152022-10-11 12:02:42 +0000698 i64 nTrans = strlen(zTrans)+1;
drh2ce15c32017-07-11 13:34:40 +0000699 if( nTrans>nLine ){
700 zLine = realloc(zLine, nTrans);
drhe3e25652021-12-16 13:29:28 +0000701 shell_check_oom(zLine);
drh2ce15c32017-07-11 13:34:40 +0000702 }
703 memcpy(zLine, zTrans, nTrans);
704 sqlite3_free(zTrans);
705 }
706 }
707#endif /* defined(_WIN32) || defined(WIN32) */
708 return zLine;
709}
710
711/*
712** Retrieve a single line of input text.
713**
714** If in==0 then read from standard input and prompt before each line.
715** If isContinuation is true, then a continuation prompt is appropriate.
716** If isContinuation is zero, then the main prompt should be used.
717**
718** If zPrior is not NULL then it is a buffer from a prior call to this
719** routine that can be reused.
720**
721** The result is stored in space obtained from malloc() and must either
722** be freed by the caller or else passed back into this routine via the
723** zPrior argument for reuse.
724*/
stephan4413ec72022-07-12 15:53:02 +0000725#ifndef SQLITE_SHELL_FIDDLE
drh2ce15c32017-07-11 13:34:40 +0000726static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
727 char *zPrompt;
728 char *zResult;
729 if( in!=0 ){
730 zResult = local_getline(zPrior, in);
731 }else{
732 zPrompt = isContinuation ? continuePrompt : mainPrompt;
733#if SHELL_USE_LOCAL_GETLINE
734 printf("%s", zPrompt);
735 fflush(stdout);
736 zResult = local_getline(zPrior, stdin);
737#else
738 free(zPrior);
739 zResult = shell_readline(zPrompt);
740 if( zResult && *zResult ) shell_add_history(zResult);
741#endif
742 }
743 return zResult;
744}
stephan4413ec72022-07-12 15:53:02 +0000745#endif /* !SQLITE_SHELL_FIDDLE */
drh5af06982018-01-10 00:53:55 +0000746
747/*
748** Return the value of a hexadecimal digit. Return -1 if the input
749** is not a hex digit.
750*/
751static int hexDigitValue(char c){
752 if( c>='0' && c<='9' ) return c - '0';
753 if( c>='a' && c<='f' ) return c - 'a' + 10;
754 if( c>='A' && c<='F' ) return c - 'A' + 10;
755 return -1;
756}
757
758/*
759** Interpret zArg as an integer value, possibly with suffixes.
760*/
761static sqlite3_int64 integerValue(const char *zArg){
762 sqlite3_int64 v = 0;
763 static const struct { char *zSuffix; int iMult; } aMult[] = {
764 { "KiB", 1024 },
765 { "MiB", 1024*1024 },
766 { "GiB", 1024*1024*1024 },
767 { "KB", 1000 },
768 { "MB", 1000000 },
769 { "GB", 1000000000 },
770 { "K", 1000 },
771 { "M", 1000000 },
772 { "G", 1000000000 },
773 };
774 int i;
775 int isNeg = 0;
776 if( zArg[0]=='-' ){
777 isNeg = 1;
778 zArg++;
779 }else if( zArg[0]=='+' ){
780 zArg++;
781 }
782 if( zArg[0]=='0' && zArg[1]=='x' ){
783 int x;
784 zArg += 2;
785 while( (x = hexDigitValue(zArg[0]))>=0 ){
786 v = (v<<4) + x;
787 zArg++;
788 }
789 }else{
790 while( IsDigit(zArg[0]) ){
791 v = v*10 + zArg[0] - '0';
792 zArg++;
793 }
794 }
795 for(i=0; i<ArraySize(aMult); i++){
796 if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
797 v *= aMult[i].iMult;
798 break;
799 }
800 }
801 return isNeg? -v : v;
802}
803
drh2ce15c32017-07-11 13:34:40 +0000804/*
805** A variable length string to which one can append text.
806*/
807typedef struct ShellText ShellText;
808struct ShellText {
809 char *z;
810 int n;
811 int nAlloc;
812};
813
814/*
815** Initialize and destroy a ShellText object
816*/
817static void initText(ShellText *p){
818 memset(p, 0, sizeof(*p));
819}
820static void freeText(ShellText *p){
821 free(p->z);
822 initText(p);
823}
824
825/* zIn is either a pointer to a NULL-terminated string in memory obtained
826** from malloc(), or a NULL pointer. The string pointed to by zAppend is
827** added to zIn, and the result returned in memory obtained from malloc().
828** zIn, if it was not NULL, is freed.
829**
830** If the third argument, quote, is not '\0', then it is used as a
831** quote character for zAppend.
832*/
stephan0076e492022-05-18 18:10:17 +0000833static void appendText(ShellText *p, const char *zAppend, char quote){
drh7d23d152022-10-11 12:02:42 +0000834 i64 len;
835 i64 i;
836 i64 nAppend = strlen30(zAppend);
drh2ce15c32017-07-11 13:34:40 +0000837
838 len = nAppend+p->n+1;
839 if( quote ){
840 len += 2;
841 for(i=0; i<nAppend; i++){
842 if( zAppend[i]==quote ) len++;
843 }
844 }
845
drh11a9ad52021-10-04 18:21:14 +0000846 if( p->z==0 || p->n+len>=p->nAlloc ){
drh2ce15c32017-07-11 13:34:40 +0000847 p->nAlloc = p->nAlloc*2 + len + 20;
848 p->z = realloc(p->z, p->nAlloc);
drhe3e25652021-12-16 13:29:28 +0000849 shell_check_oom(p->z);
drh2ce15c32017-07-11 13:34:40 +0000850 }
851
852 if( quote ){
853 char *zCsr = p->z+p->n;
854 *zCsr++ = quote;
855 for(i=0; i<nAppend; i++){
856 *zCsr++ = zAppend[i];
857 if( zAppend[i]==quote ) *zCsr++ = quote;
858 }
859 *zCsr++ = quote;
860 p->n = (int)(zCsr - p->z);
861 *zCsr = '\0';
862 }else{
863 memcpy(p->z+p->n, zAppend, nAppend);
864 p->n += nAppend;
865 p->z[p->n] = '\0';
866 }
867}
868
869/*
870** Attempt to determine if identifier zName needs to be quoted, either
871** because it contains non-alphanumeric characters, or because it is an
872** SQLite keyword. Be conservative in this estimate: When in doubt assume
873** that quoting is required.
874**
875** Return '"' if quoting is required. Return 0 if no quoting is required.
876*/
877static char quoteChar(const char *zName){
drhfc0ec3e2018-04-25 19:02:48 +0000878 int i;
drh2ce15c32017-07-11 13:34:40 +0000879 if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
880 for(i=0; zName[i]; i++){
881 if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
882 }
drhfc0ec3e2018-04-25 19:02:48 +0000883 return sqlite3_keyword_check(zName, i) ? '"' : 0;
drh2ce15c32017-07-11 13:34:40 +0000884}
885
886/*
drh667a2a22018-01-02 00:04:37 +0000887** Construct a fake object name and column list to describe the structure
888** of the view, virtual table, or table valued function zSchema.zName.
drhceba7922018-01-01 21:28:25 +0000889*/
drh667a2a22018-01-02 00:04:37 +0000890static char *shellFakeSchema(
drhceba7922018-01-01 21:28:25 +0000891 sqlite3 *db, /* The database connection containing the vtab */
892 const char *zSchema, /* Schema of the database holding the vtab */
893 const char *zName /* The name of the virtual table */
894){
895 sqlite3_stmt *pStmt = 0;
896 char *zSql;
drh1d315cf2018-01-01 21:49:43 +0000897 ShellText s;
898 char cQuote;
899 char *zDiv = "(";
drh667a2a22018-01-02 00:04:37 +0000900 int nRow = 0;
drhceba7922018-01-01 21:28:25 +0000901
drh1d315cf2018-01-01 21:49:43 +0000902 zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
903 zSchema ? zSchema : "main", zName);
drhe3e25652021-12-16 13:29:28 +0000904 shell_check_oom(zSql);
drhceba7922018-01-01 21:28:25 +0000905 sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
906 sqlite3_free(zSql);
drh1d315cf2018-01-01 21:49:43 +0000907 initText(&s);
908 if( zSchema ){
909 cQuote = quoteChar(zSchema);
910 if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0;
911 appendText(&s, zSchema, cQuote);
912 appendText(&s, ".", 0);
drhceba7922018-01-01 21:28:25 +0000913 }
drh1d315cf2018-01-01 21:49:43 +0000914 cQuote = quoteChar(zName);
915 appendText(&s, zName, cQuote);
916 while( sqlite3_step(pStmt)==SQLITE_ROW ){
917 const char *zCol = (const char*)sqlite3_column_text(pStmt, 1);
drh667a2a22018-01-02 00:04:37 +0000918 nRow++;
drh1d315cf2018-01-01 21:49:43 +0000919 appendText(&s, zDiv, 0);
920 zDiv = ",";
drh621a5e02021-12-16 17:35:27 +0000921 if( zCol==0 ) zCol = "";
drh1d315cf2018-01-01 21:49:43 +0000922 cQuote = quoteChar(zCol);
923 appendText(&s, zCol, cQuote);
924 }
925 appendText(&s, ")", 0);
drhceba7922018-01-01 21:28:25 +0000926 sqlite3_finalize(pStmt);
drh667a2a22018-01-02 00:04:37 +0000927 if( nRow==0 ){
928 freeText(&s);
929 s.z = 0;
930 }
drh1d315cf2018-01-01 21:49:43 +0000931 return s.z;
drhceba7922018-01-01 21:28:25 +0000932}
933
934/*
drh667a2a22018-01-02 00:04:37 +0000935** SQL function: shell_module_schema(X)
936**
937** Return a fake schema for the table-valued function or eponymous virtual
938** table X.
939*/
940static void shellModuleSchema(
941 sqlite3_context *pCtx,
942 int nVal,
943 sqlite3_value **apVal
944){
drh511b1182021-12-16 13:56:04 +0000945 const char *zName;
946 char *zFake;
drhb9685182018-01-17 13:15:23 +0000947 UNUSED_PARAMETER(nVal);
drh511b1182021-12-16 13:56:04 +0000948 zName = (const char*)sqlite3_value_text(apVal[0]);
949 zFake = zName ? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0;
drh667a2a22018-01-02 00:04:37 +0000950 if( zFake ){
dandcfbff92018-01-08 17:05:32 +0000951 sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
drh667a2a22018-01-02 00:04:37 +0000952 -1, sqlite3_free);
dandcfbff92018-01-08 17:05:32 +0000953 free(zFake);
drh667a2a22018-01-02 00:04:37 +0000954 }
955}
956
957/*
drh2ce15c32017-07-11 13:34:40 +0000958** SQL function: shell_add_schema(S,X)
959**
960** Add the schema name X to the CREATE statement in S and return the result.
961** Examples:
962**
963** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x);
964**
965** Also works on
966**
967** CREATE INDEX
968** CREATE UNIQUE INDEX
969** CREATE VIEW
970** CREATE TRIGGER
971** CREATE VIRTUAL TABLE
972**
973** This UDF is used by the .schema command to insert the schema name of
drh067b92b2020-06-19 15:24:12 +0000974** attached databases into the middle of the sqlite_schema.sql field.
drh2ce15c32017-07-11 13:34:40 +0000975*/
976static void shellAddSchemaName(
977 sqlite3_context *pCtx,
978 int nVal,
979 sqlite3_value **apVal
980){
981 static const char *aPrefix[] = {
982 "TABLE",
983 "INDEX",
984 "UNIQUE INDEX",
985 "VIEW",
986 "TRIGGER",
987 "VIRTUAL TABLE"
988 };
989 int i = 0;
990 const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
991 const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
drh667a2a22018-01-02 00:04:37 +0000992 const char *zName = (const char*)sqlite3_value_text(apVal[2]);
drhceba7922018-01-01 21:28:25 +0000993 sqlite3 *db = sqlite3_context_db_handle(pCtx);
drhb9685182018-01-17 13:15:23 +0000994 UNUSED_PARAMETER(nVal);
drhbf70f1b2022-10-19 18:04:42 +0000995 if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){
drh37407122021-07-23 18:43:58 +0000996 for(i=0; i<ArraySize(aPrefix); i++){
drh2ce15c32017-07-11 13:34:40 +0000997 int n = strlen30(aPrefix[i]);
drhbf70f1b2022-10-19 18:04:42 +0000998 if( cli_strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
drhceba7922018-01-01 21:28:25 +0000999 char *z = 0;
drh667a2a22018-01-02 00:04:37 +00001000 char *zFake = 0;
drhceba7922018-01-01 21:28:25 +00001001 if( zSchema ){
1002 char cQuote = quoteChar(zSchema);
1003 if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
1004 z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
1005 }else{
1006 z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
1007 }
drh2ce15c32017-07-11 13:34:40 +00001008 }
drh667a2a22018-01-02 00:04:37 +00001009 if( zName
1010 && aPrefix[i][0]=='V'
1011 && (zFake = shellFakeSchema(db, zSchema, zName))!=0
1012 ){
1013 if( z==0 ){
dandcfbff92018-01-08 17:05:32 +00001014 z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake);
drh667a2a22018-01-02 00:04:37 +00001015 }else{
dandcfbff92018-01-08 17:05:32 +00001016 z = sqlite3_mprintf("%z\n/* %s */", z, zFake);
drh667a2a22018-01-02 00:04:37 +00001017 }
dandcfbff92018-01-08 17:05:32 +00001018 free(zFake);
drhceba7922018-01-01 21:28:25 +00001019 }
1020 if( z ){
1021 sqlite3_result_text(pCtx, z, -1, sqlite3_free);
1022 return;
1023 }
drh2ce15c32017-07-11 13:34:40 +00001024 }
1025 }
1026 }
1027 sqlite3_result_value(pCtx, apVal[0]);
1028}
1029
1030/*
1031** The source code for several run-time loadable extensions is inserted
1032** below by the ../tool/mkshellc.tcl script. Before processing that included
1033** code, we need to override some macros to make the included program code
1034** work here in the middle of this regular program.
1035*/
1036#define SQLITE_EXTENSION_INIT1
drh89997982017-07-11 18:11:33 +00001037#define SQLITE_EXTENSION_INIT2(X) (void)(X)
drh2ce15c32017-07-11 13:34:40 +00001038
mistachkinacae8c32018-01-05 20:08:46 +00001039#if defined(_WIN32) && defined(_MSC_VER)
drh03491a12018-01-07 21:58:17 +00001040INCLUDE test_windirent.h
mistachkindfdfd8c2018-01-04 22:46:08 +00001041INCLUDE test_windirent.c
1042#define dirent DIRENT
mistachkindfdfd8c2018-01-04 22:46:08 +00001043#endif
drh50b910a2019-01-21 14:55:03 +00001044INCLUDE ../ext/misc/memtrace.c
stephanf8cd3d22022-05-18 17:14:24 +00001045INCLUDE ../ext/misc/shathree.c
drhf05dd032020-04-14 15:53:58 +00001046INCLUDE ../ext/misc/uint.c
drhbeb9def2020-06-22 19:12:23 +00001047INCLUDE ../ext/misc/decimal.c
drh8cda77d2020-06-24 15:06:29 +00001048INCLUDE ../ext/misc/ieee754.c
mistachkin72c38d82020-08-28 18:47:39 +00001049INCLUDE ../ext/misc/series.c
drh64689902021-06-03 13:51:31 +00001050INCLUDE ../ext/misc/regexp.c
stephan4413ec72022-07-12 15:53:02 +00001051#ifndef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +00001052INCLUDE ../ext/misc/fileio.c
1053INCLUDE ../ext/misc/completion.c
1054INCLUDE ../ext/misc/appendvfs.c
1055#endif
dan72afc3c2017-12-05 18:32:40 +00001056#ifdef SQLITE_HAVE_ZLIB
dan9ebfaad2017-12-26 20:39:58 +00001057INCLUDE ../ext/misc/zipfile.c
dand1b51d42017-12-16 19:11:26 +00001058INCLUDE ../ext/misc/sqlar.c
dan72afc3c2017-12-05 18:32:40 +00001059#endif
dan43efc182017-12-19 17:42:13 +00001060INCLUDE ../ext/expert/sqlite3expert.h
1061INCLUDE ../ext/expert/sqlite3expert.c
drh2ce15c32017-07-11 13:34:40 +00001062
stephanbb5136e2022-10-27 11:32:20 +00001063#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
stephan3d420832022-10-27 03:56:01 +00001064#define SQLITE_SHELL_HAVE_RECOVER 1
1065#else
1066#define SQLITE_SHELL_HAVE_RECOVER 0
1067#endif
1068#if SQLITE_SHELL_HAVE_RECOVER
dan361fb982022-10-19 18:03:39 +00001069INCLUDE ../ext/recover/dbdata.c
dan9a27d652022-09-08 19:22:29 +00001070INCLUDE ../ext/recover/sqlite3recover.h
1071INCLUDE ../ext/recover/sqlite3recover.c
dan1b162162019-04-27 20:15:15 +00001072#endif
dan68cb86e2019-04-20 20:57:28 +00001073
drh2ce15c32017-07-11 13:34:40 +00001074#if defined(SQLITE_ENABLE_SESSION)
1075/*
1076** State information for a single open session
1077*/
1078typedef struct OpenSession OpenSession;
1079struct OpenSession {
1080 char *zName; /* Symbolic name for this session */
1081 int nFilter; /* Number of xFilter rejection GLOB patterns */
1082 char **azFilter; /* Array of xFilter rejection GLOB patterns */
1083 sqlite3_session *p; /* The open session */
1084};
1085#endif
1086
dan43efc182017-12-19 17:42:13 +00001087typedef struct ExpertInfo ExpertInfo;
1088struct ExpertInfo {
1089 sqlite3expert *pExpert;
1090 int bVerbose;
1091};
1092
drh4b5345c2018-04-24 13:07:40 +00001093/* A single line in the EQP output */
1094typedef struct EQPGraphRow EQPGraphRow;
1095struct EQPGraphRow {
drhe2ca99c2018-05-02 00:33:43 +00001096 int iEqpId; /* ID for this row */
1097 int iParentId; /* ID of the parent row */
drh4b5345c2018-04-24 13:07:40 +00001098 EQPGraphRow *pNext; /* Next row in sequence */
1099 char zText[1]; /* Text to display for this row */
1100};
1101
1102/* All EQP output is collected into an instance of the following */
1103typedef struct EQPGraph EQPGraph;
1104struct EQPGraph {
1105 EQPGraphRow *pRow; /* Linked list of all rows of the EQP output */
1106 EQPGraphRow *pLast; /* Last element of the pRow list */
1107 char zPrefix[100]; /* Graph prefix */
1108};
1109
larrybrcc4d55c2022-02-01 02:50:45 +00001110/* Parameters affecting columnar mode result display (defaulting together) */
1111typedef struct ColModeOpts {
1112 int iWrap; /* In columnar modes, wrap lines reaching this limit */
1113 u8 bQuote; /* Quote results for .mode box and table */
1114 u8 bWordWrap; /* In columnar modes, wrap at word boundaries */
1115} ColModeOpts;
1116#define ColModeOpts_default { 60, 0, 0 }
1117#define ColModeOpts_default_qbox { 60, 1, 0 }
larrybrcc4d55c2022-02-01 02:50:45 +00001118
drh2ce15c32017-07-11 13:34:40 +00001119/*
1120** State information about the database connection is contained in an
1121** instance of the following structure.
1122*/
1123typedef struct ShellState ShellState;
1124struct ShellState {
1125 sqlite3 *db; /* The database */
drh1fa6d9f2018-01-06 21:46:01 +00001126 u8 autoExplain; /* Automatically turn on .explain mode */
1127 u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
drhe2ca99c2018-05-02 00:33:43 +00001128 u8 autoEQPtest; /* autoEQP is in test mode */
drhb4e50392019-01-26 15:40:04 +00001129 u8 autoEQPtrace; /* autoEQP is in trace mode */
drh1fa6d9f2018-01-06 21:46:01 +00001130 u8 scanstatsOn; /* True to display scan stats before each finalize */
1131 u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
drh13c20932018-01-10 21:41:55 +00001132 u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */
drh4b5345c2018-04-24 13:07:40 +00001133 u8 nEqpLevel; /* Depth of the EQP output graph */
drh707821f2018-12-05 13:39:06 +00001134 u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
drhb97e2ad2021-08-26 18:31:39 +00001135 u8 bSafeMode; /* True to prohibit unsafe operations */
1136 u8 bSafeModePersist; /* The long-term value of bSafeMode */
larrybrcc4d55c2022-02-01 02:50:45 +00001137 ColModeOpts cmOpts; /* Option values affecting columnar mode output */
drha6e6cf22021-01-09 19:10:04 +00001138 unsigned statsOn; /* True to display memory stats before each finalize */
drh4b5345c2018-04-24 13:07:40 +00001139 unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */
larrybrd48e88e2022-01-24 06:36:16 +00001140 int inputNesting; /* Track nesting level of .read and other redirects */
drh2ce15c32017-07-11 13:34:40 +00001141 int outCount; /* Revert to stdout when reaching zero */
1142 int cnt; /* Number of records displayed so far */
drh2c8ee022018-12-13 18:59:30 +00001143 int lineno; /* Line number of last line read from in */
drh0933aad2019-11-18 17:46:38 +00001144 int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */
drh60379d42018-12-13 18:30:01 +00001145 FILE *in; /* Read commands from this stream */
drh2ce15c32017-07-11 13:34:40 +00001146 FILE *out; /* Write results here */
1147 FILE *traceOut; /* Output for sqlite3_trace() */
1148 int nErr; /* Number of errors seen */
1149 int mode; /* An output mode setting */
drh3c484e82018-01-10 22:27:21 +00001150 int modePrior; /* Saved mode */
drh2ce15c32017-07-11 13:34:40 +00001151 int cMode; /* temporary output mode for the current query */
1152 int normalMode; /* Output mode before ".explain on" */
1153 int writableSchema; /* True if PRAGMA writable_schema=ON */
1154 int showHeader; /* True to show column names in List or Column mode */
1155 int nCheck; /* Number of ".check" commands run */
drh3f83f592019-02-04 14:53:18 +00001156 unsigned nProgress; /* Number of progress callbacks encountered */
1157 unsigned mxProgress; /* Maximum progress callbacks before failing */
1158 unsigned flgProgress; /* Flags for the progress callback */
drh2ce15c32017-07-11 13:34:40 +00001159 unsigned shellFlgs; /* Various flags */
drh7a431002020-04-18 14:12:00 +00001160 unsigned priorShFlgs; /* Saved copy of flags */
drh6ca64482019-01-22 16:06:20 +00001161 sqlite3_int64 szMax; /* --maxsize argument to .open */
drh2ce15c32017-07-11 13:34:40 +00001162 char *zDestTable; /* Name of destination table when MODE_Insert */
drh13c20932018-01-10 21:41:55 +00001163 char *zTempFile; /* Temporary file that might need deleting */
drh2ce15c32017-07-11 13:34:40 +00001164 char zTestcase[30]; /* Name of current test case */
1165 char colSeparator[20]; /* Column separator character for several modes */
1166 char rowSeparator[20]; /* Row separator character for MODE_Ascii */
drh3c484e82018-01-10 22:27:21 +00001167 char colSepPrior[20]; /* Saved column separator */
1168 char rowSepPrior[20]; /* Saved row separator */
drh0285d982020-05-29 14:38:43 +00001169 int *colWidth; /* Requested width of each column in columnar modes */
1170 int *actualWidth; /* Actual width of each column */
1171 int nWidth; /* Number of slots in colWidth[] and actualWidth[] */
drh2ce15c32017-07-11 13:34:40 +00001172 char nullValue[20]; /* The text to print when a NULL comes back from
1173 ** the database */
1174 char outfile[FILENAME_MAX]; /* Filename for *out */
drh2ce15c32017-07-11 13:34:40 +00001175 sqlite3_stmt *pStmt; /* Current statement if any. */
1176 FILE *pLog; /* Write log output here */
drh37407122021-07-23 18:43:58 +00001177 struct AuxDb { /* Storage space for auxiliary database connections */
1178 sqlite3 *db; /* Connection pointer */
1179 const char *zDbFilename; /* Filename used to open the connection */
1180 char *zFreeOnClose; /* Free this memory allocation on close */
1181#if defined(SQLITE_ENABLE_SESSION)
1182 int nSession; /* Number of active sessions */
1183 OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */
1184#endif
1185 } aAuxDb[5], /* Array of all database connections */
1186 *pAuxDb; /* Currently active database connection */
drh2ce15c32017-07-11 13:34:40 +00001187 int *aiIndent; /* Array of indents used in MODE_Explain */
1188 int nIndent; /* Size of array aiIndent[] */
1189 int iIndent; /* Index of current op in aiIndent[] */
drhb97e2ad2021-08-26 18:31:39 +00001190 char *zNonce; /* Nonce for temporary safe-mode excapes */
drh4b5345c2018-04-24 13:07:40 +00001191 EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */
drhb97e2ad2021-08-26 18:31:39 +00001192 ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */
stephan4413ec72022-07-12 15:53:02 +00001193#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +00001194 struct {
1195 const char * zInput; /* Input string from wasm/JS proxy */
stephan0076e492022-05-18 18:10:17 +00001196 const char * zPos; /* Cursor pos into zInput */
stephan60d9aa72022-09-24 07:36:45 +00001197 const char * zDefaultDbName; /* Default name for db file */
stephanf8cd3d22022-05-18 17:14:24 +00001198 } wasm;
1199#endif
drh2ce15c32017-07-11 13:34:40 +00001200};
1201
stephan4413ec72022-07-12 15:53:02 +00001202#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +00001203static ShellState shellState;
1204#endif
1205
drh1fa6d9f2018-01-06 21:46:01 +00001206
drhada70452017-12-21 21:02:27 +00001207/* Allowed values for ShellState.autoEQP
1208*/
drhe2ca99c2018-05-02 00:33:43 +00001209#define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */
1210#define AUTOEQP_on 1 /* Automatic EQP is on */
1211#define AUTOEQP_trigger 2 /* On and also show plans for triggers */
1212#define AUTOEQP_full 3 /* Show full EXPLAIN */
drhada70452017-12-21 21:02:27 +00001213
drh1fa6d9f2018-01-06 21:46:01 +00001214/* Allowed values for ShellState.openMode
1215*/
drh60f34ae2018-10-30 13:19:49 +00001216#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */
1217#define SHELL_OPEN_NORMAL 1 /* Normal database file */
1218#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */
1219#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */
1220#define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */
1221#define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */
drh33746482018-12-13 15:06:26 +00001222#define SHELL_OPEN_HEXDB 6 /* Use "dbtotxt" output as data source */
drh1fa6d9f2018-01-06 21:46:01 +00001223
drh707821f2018-12-05 13:39:06 +00001224/* Allowed values for ShellState.eTraceType
1225*/
1226#define SHELL_TRACE_PLAIN 0 /* Show input SQL text */
1227#define SHELL_TRACE_EXPANDED 1 /* Show expanded SQL text */
1228#define SHELL_TRACE_NORMALIZED 2 /* Show normalized SQL text */
1229
drh3f83f592019-02-04 14:53:18 +00001230/* Bits in the ShellState.flgProgress variable */
drhfc4eeef2019-02-05 19:48:46 +00001231#define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */
1232#define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progres
1233 ** callback limit is reached, and for each
1234 ** top-level SQL statement */
1235#define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
drh3f83f592019-02-04 14:53:18 +00001236
drh2ce15c32017-07-11 13:34:40 +00001237/*
1238** These are the allowed shellFlgs values
1239*/
drhb2a0f752017-08-28 15:51:35 +00001240#define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
1241#define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
1242#define SHFLG_Backslash 0x00000004 /* The --backslash option is used */
1243#define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */
1244#define SHFLG_Newlines 0x00000010 /* .dump --newline flag */
1245#define SHFLG_CountChanges 0x00000020 /* .changes setting */
larrybr527c39d2022-05-10 14:55:45 +00001246#define SHFLG_Echo 0x00000040 /* .echo on/off, or --echo setting */
larrybrae509122021-09-10 01:45:20 +00001247#define SHFLG_HeaderSet 0x00000080 /* showHeader has been specified */
drhc1962192020-10-12 16:54:28 +00001248#define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */
1249#define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */
drh2ce15c32017-07-11 13:34:40 +00001250
1251/*
1252** Macros for testing and setting shellFlgs
1253*/
1254#define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0)
1255#define ShellSetFlag(P,X) ((P)->shellFlgs|=(X))
1256#define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X)))
1257
1258/*
1259** These are the allowed modes.
1260*/
1261#define MODE_Line 0 /* One column per line. Blank line between records */
1262#define MODE_Column 1 /* One record per line in neat columns */
1263#define MODE_List 2 /* One record per line with a separator */
1264#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
1265#define MODE_Html 4 /* Generate an XHTML table */
1266#define MODE_Insert 5 /* Generate SQL "insert" statements */
1267#define MODE_Quote 6 /* Quote values as for SQL */
1268#define MODE_Tcl 7 /* Generate ANSI-C or TCL quoted elements */
1269#define MODE_Csv 8 /* Quote strings, numbers are plain */
1270#define MODE_Explain 9 /* Like MODE_Column, but do not truncate data */
1271#define MODE_Ascii 10 /* Use ASCII unit and record separators (0x1F/0x1E) */
1272#define MODE_Pretty 11 /* Pretty-print schemas */
drh4b5345c2018-04-24 13:07:40 +00001273#define MODE_EQP 12 /* Converts EXPLAIN QUERY PLAN output into a graph */
drh30c54a02020-05-28 23:49:50 +00001274#define MODE_Json 13 /* Output JSON */
1275#define MODE_Markdown 14 /* Markdown formatting */
1276#define MODE_Table 15 /* MySQL-style table formatting */
drh0908e382020-06-04 18:05:39 +00001277#define MODE_Box 16 /* Unicode box-drawing characters */
drh5d88be82021-12-09 16:17:43 +00001278#define MODE_Count 17 /* Output only a count of the rows of output */
1279#define MODE_Off 18 /* No query output shown */
drh2ce15c32017-07-11 13:34:40 +00001280
1281static const char *modeDescr[] = {
1282 "line",
1283 "column",
1284 "list",
1285 "semi",
1286 "html",
1287 "insert",
1288 "quote",
1289 "tcl",
1290 "csv",
1291 "explain",
1292 "ascii",
1293 "prettyprint",
drh30c54a02020-05-28 23:49:50 +00001294 "eqp",
1295 "json",
1296 "markdown",
drh0908e382020-06-04 18:05:39 +00001297 "table",
drh5d88be82021-12-09 16:17:43 +00001298 "box",
1299 "count",
1300 "off"
drh2ce15c32017-07-11 13:34:40 +00001301};
1302
1303/*
1304** These are the column/row/line separators used by the various
1305** import/export modes.
1306*/
1307#define SEP_Column "|"
1308#define SEP_Row "\n"
1309#define SEP_Tab "\t"
1310#define SEP_Space " "
1311#define SEP_Comma ","
1312#define SEP_CrLf "\r\n"
1313#define SEP_Unit "\x1F"
1314#define SEP_Record "\x1E"
1315
1316/*
larrybrd48e88e2022-01-24 06:36:16 +00001317** Limit input nesting via .read or any other input redirect.
1318** It's not too expensive, so a generous allowance can be made.
1319*/
1320#define MAX_INPUT_NESTING 25
1321
1322/*
drh2ce15c32017-07-11 13:34:40 +00001323** A callback for the sqlite3_log() interface.
1324*/
1325static void shellLog(void *pArg, int iErrCode, const char *zMsg){
1326 ShellState *p = (ShellState*)pArg;
1327 if( p->pLog==0 ) return;
1328 utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
1329 fflush(p->pLog);
1330}
1331
1332/*
drh634c70f2018-01-10 16:50:18 +00001333** SQL function: shell_putsnl(X)
1334**
1335** Write the text X to the screen (or whatever output is being directed)
1336** adding a newline at the end, and then return X.
1337*/
1338static void shellPutsFunc(
1339 sqlite3_context *pCtx,
1340 int nVal,
1341 sqlite3_value **apVal
1342){
1343 ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
drhb9685182018-01-17 13:15:23 +00001344 (void)nVal;
drh634c70f2018-01-10 16:50:18 +00001345 utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
1346 sqlite3_result_value(pCtx, apVal[0]);
1347}
1348
1349/*
drhb97e2ad2021-08-26 18:31:39 +00001350** If in safe mode, print an error message described by the arguments
1351** and exit immediately.
1352*/
1353static void failIfSafeMode(
1354 ShellState *p,
1355 const char *zErrMsg,
1356 ...
1357){
1358 if( p->bSafeMode ){
1359 va_list ap;
1360 char *zMsg;
1361 va_start(ap, zErrMsg);
1362 zMsg = sqlite3_vmprintf(zErrMsg, ap);
1363 va_end(ap);
1364 raw_printf(stderr, "line %d: ", p->lineno);
1365 utf8_printf(stderr, "%s\n", zMsg);
1366 exit(1);
1367 }
1368}
1369
1370/*
drh97913132018-01-11 00:04:00 +00001371** SQL function: edit(VALUE)
1372** edit(VALUE,EDITOR)
1373**
1374** These steps:
1375**
1376** (1) Write VALUE into a temporary file.
1377** (2) Run program EDITOR on that temporary file.
1378** (3) Read the temporary file back and return its content as the result.
1379** (4) Delete the temporary file
1380**
1381** If the EDITOR argument is omitted, use the value in the VISUAL
1382** environment variable. If still there is no EDITOR, through an error.
1383**
1384** Also throw an error if the EDITOR program returns a non-zero exit code.
1385*/
drh04a28c32018-01-31 01:38:44 +00001386#ifndef SQLITE_NOHAVE_SYSTEM
drh97913132018-01-11 00:04:00 +00001387static void editFunc(
1388 sqlite3_context *context,
1389 int argc,
1390 sqlite3_value **argv
1391){
1392 const char *zEditor;
1393 char *zTempFile = 0;
1394 sqlite3 *db;
1395 char *zCmd = 0;
1396 int bBin;
1397 int rc;
drhf018fd52018-08-06 02:08:53 +00001398 int hasCRNL = 0;
drh97913132018-01-11 00:04:00 +00001399 FILE *f = 0;
1400 sqlite3_int64 sz;
1401 sqlite3_int64 x;
1402 unsigned char *p = 0;
1403
1404 if( argc==2 ){
1405 zEditor = (const char*)sqlite3_value_text(argv[1]);
1406 }else{
1407 zEditor = getenv("VISUAL");
1408 }
1409 if( zEditor==0 ){
1410 sqlite3_result_error(context, "no editor for edit()", -1);
1411 return;
1412 }
1413 if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
1414 sqlite3_result_error(context, "NULL input to edit()", -1);
1415 return;
1416 }
1417 db = sqlite3_context_db_handle(context);
1418 zTempFile = 0;
1419 sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, &zTempFile);
1420 if( zTempFile==0 ){
1421 sqlite3_uint64 r = 0;
1422 sqlite3_randomness(sizeof(r), &r);
1423 zTempFile = sqlite3_mprintf("temp%llx", r);
1424 if( zTempFile==0 ){
1425 sqlite3_result_error_nomem(context);
1426 return;
1427 }
1428 }
1429 bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
drhf018fd52018-08-06 02:08:53 +00001430 /* When writing the file to be edited, do \n to \r\n conversions on systems
1431 ** that want \r\n line endings */
drh97913132018-01-11 00:04:00 +00001432 f = fopen(zTempFile, bBin ? "wb" : "w");
1433 if( f==0 ){
1434 sqlite3_result_error(context, "edit() cannot open temp file", -1);
1435 goto edit_func_end;
1436 }
1437 sz = sqlite3_value_bytes(argv[0]);
1438 if( bBin ){
dan4d02b5f2019-07-17 07:23:06 +00001439 x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f);
drh97913132018-01-11 00:04:00 +00001440 }else{
drhf018fd52018-08-06 02:08:53 +00001441 const char *z = (const char*)sqlite3_value_text(argv[0]);
1442 /* Remember whether or not the value originally contained \r\n */
1443 if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1;
dan4d02b5f2019-07-17 07:23:06 +00001444 x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
drh97913132018-01-11 00:04:00 +00001445 }
1446 fclose(f);
1447 f = 0;
1448 if( x!=sz ){
1449 sqlite3_result_error(context, "edit() could not write the whole file", -1);
1450 goto edit_func_end;
1451 }
1452 zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile);
1453 if( zCmd==0 ){
1454 sqlite3_result_error_nomem(context);
1455 goto edit_func_end;
1456 }
1457 rc = system(zCmd);
1458 sqlite3_free(zCmd);
1459 if( rc ){
1460 sqlite3_result_error(context, "EDITOR returned non-zero", -1);
1461 goto edit_func_end;
1462 }
drhf018fd52018-08-06 02:08:53 +00001463 f = fopen(zTempFile, "rb");
drh97913132018-01-11 00:04:00 +00001464 if( f==0 ){
1465 sqlite3_result_error(context,
1466 "edit() cannot reopen temp file after edit", -1);
1467 goto edit_func_end;
1468 }
1469 fseek(f, 0, SEEK_END);
1470 sz = ftell(f);
1471 rewind(f);
drhee37f8b2019-08-23 23:05:32 +00001472 p = sqlite3_malloc64( sz+1 );
drh97913132018-01-11 00:04:00 +00001473 if( p==0 ){
1474 sqlite3_result_error_nomem(context);
1475 goto edit_func_end;
1476 }
dan4d02b5f2019-07-17 07:23:06 +00001477 x = fread(p, 1, (size_t)sz, f);
drh97913132018-01-11 00:04:00 +00001478 fclose(f);
1479 f = 0;
1480 if( x!=sz ){
1481 sqlite3_result_error(context, "could not read back the whole file", -1);
1482 goto edit_func_end;
1483 }
1484 if( bBin ){
mistachkinb71aa092018-01-23 00:05:18 +00001485 sqlite3_result_blob64(context, p, sz, sqlite3_free);
drh97913132018-01-11 00:04:00 +00001486 }else{
dan60bdcf52018-10-03 11:13:30 +00001487 sqlite3_int64 i, j;
drhf018fd52018-08-06 02:08:53 +00001488 if( hasCRNL ){
1489 /* If the original contains \r\n then do no conversions back to \n */
drhf018fd52018-08-06 02:08:53 +00001490 }else{
1491 /* If the file did not originally contain \r\n then convert any new
1492 ** \r\n back into \n */
1493 for(i=j=0; i<sz; i++){
1494 if( p[i]=='\r' && p[i+1]=='\n' ) i++;
1495 p[j++] = p[i];
1496 }
1497 sz = j;
1498 p[sz] = 0;
1499 }
mistachkinb71aa092018-01-23 00:05:18 +00001500 sqlite3_result_text64(context, (const char*)p, sz,
1501 sqlite3_free, SQLITE_UTF8);
drh97913132018-01-11 00:04:00 +00001502 }
1503 p = 0;
1504
1505edit_func_end:
1506 if( f ) fclose(f);
1507 unlink(zTempFile);
1508 sqlite3_free(zTempFile);
1509 sqlite3_free(p);
1510}
drh04a28c32018-01-31 01:38:44 +00001511#endif /* SQLITE_NOHAVE_SYSTEM */
drh97913132018-01-11 00:04:00 +00001512
1513/*
drh3c484e82018-01-10 22:27:21 +00001514** Save or restore the current output mode
1515*/
1516static void outputModePush(ShellState *p){
1517 p->modePrior = p->mode;
drh7a431002020-04-18 14:12:00 +00001518 p->priorShFlgs = p->shellFlgs;
drh3c484e82018-01-10 22:27:21 +00001519 memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
1520 memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
1521}
1522static void outputModePop(ShellState *p){
1523 p->mode = p->modePrior;
drh7a431002020-04-18 14:12:00 +00001524 p->shellFlgs = p->priorShFlgs;
drh3c484e82018-01-10 22:27:21 +00001525 memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
1526 memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
1527}
1528
1529/*
drh2ce15c32017-07-11 13:34:40 +00001530** Output the given string as a hex-encoded blob (eg. X'1234' )
1531*/
1532static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
1533 int i;
dan2ce2b772022-08-24 11:51:31 +00001534 unsigned char *aBlob = (unsigned char*)pBlob;
1535
1536 char *zStr = sqlite3_malloc(nBlob*2 + 1);
1537 shell_check_oom(zStr);
1538
1539 for(i=0; i<nBlob; i++){
1540 static const char aHex[] = {
1541 '0', '1', '2', '3', '4', '5', '6', '7',
1542 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1543 };
1544 zStr[i*2] = aHex[ (aBlob[i] >> 4) ];
1545 zStr[i*2+1] = aHex[ (aBlob[i] & 0x0F) ];
1546 }
1547 zStr[i*2] = '\0';
1548
1549 raw_printf(out,"X'%s'", zStr);
1550 sqlite3_free(zStr);
drh2ce15c32017-07-11 13:34:40 +00001551}
1552
1553/*
1554** Find a string that is not found anywhere in z[]. Return a pointer
1555** to that string.
1556**
1557** Try to use zA and zB first. If both of those are already found in z[]
1558** then make up some string and store it in the buffer zBuf.
1559*/
1560static const char *unused_string(
1561 const char *z, /* Result must not appear anywhere in z */
1562 const char *zA, const char *zB, /* Try these first */
1563 char *zBuf /* Space to store a generated string */
1564){
1565 unsigned i = 0;
1566 if( strstr(z, zA)==0 ) return zA;
1567 if( strstr(z, zB)==0 ) return zB;
1568 do{
1569 sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
1570 }while( strstr(z,zBuf)!=0 );
1571 return zBuf;
1572}
1573
1574/*
1575** Output the given string as a quoted string using SQL quoting conventions.
1576**
1577** See also: output_quoted_escaped_string()
1578*/
1579static void output_quoted_string(FILE *out, const char *z){
1580 int i;
1581 char c;
1582 setBinaryMode(out, 1);
1583 for(i=0; (c = z[i])!=0 && c!='\''; i++){}
1584 if( c==0 ){
1585 utf8_printf(out,"'%s'",z);
1586 }else{
1587 raw_printf(out, "'");
1588 while( *z ){
1589 for(i=0; (c = z[i])!=0 && c!='\''; i++){}
1590 if( c=='\'' ) i++;
1591 if( i ){
1592 utf8_printf(out, "%.*s", i, z);
1593 z += i;
1594 }
1595 if( c=='\'' ){
1596 raw_printf(out, "'");
1597 continue;
1598 }
1599 if( c==0 ){
1600 break;
1601 }
1602 z++;
1603 }
1604 raw_printf(out, "'");
1605 }
1606 setTextMode(out, 1);
1607}
1608
1609/*
1610** Output the given string as a quoted string using SQL quoting conventions.
1611** Additionallly , escape the "\n" and "\r" characters so that they do not
1612** get corrupted by end-of-line translation facilities in some operating
1613** systems.
1614**
1615** This is like output_quoted_string() but with the addition of the \r\n
1616** escape mechanism.
1617*/
1618static void output_quoted_escaped_string(FILE *out, const char *z){
1619 int i;
1620 char c;
1621 setBinaryMode(out, 1);
1622 for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
1623 if( c==0 ){
1624 utf8_printf(out,"'%s'",z);
1625 }else{
1626 const char *zNL = 0;
1627 const char *zCR = 0;
1628 int nNL = 0;
1629 int nCR = 0;
1630 char zBuf1[20], zBuf2[20];
1631 for(i=0; z[i]; i++){
1632 if( z[i]=='\n' ) nNL++;
1633 if( z[i]=='\r' ) nCR++;
1634 }
1635 if( nNL ){
1636 raw_printf(out, "replace(");
1637 zNL = unused_string(z, "\\n", "\\012", zBuf1);
1638 }
1639 if( nCR ){
1640 raw_printf(out, "replace(");
1641 zCR = unused_string(z, "\\r", "\\015", zBuf2);
1642 }
1643 raw_printf(out, "'");
1644 while( *z ){
1645 for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
1646 if( c=='\'' ) i++;
1647 if( i ){
1648 utf8_printf(out, "%.*s", i, z);
1649 z += i;
1650 }
1651 if( c=='\'' ){
1652 raw_printf(out, "'");
1653 continue;
1654 }
1655 if( c==0 ){
1656 break;
1657 }
1658 z++;
1659 if( c=='\n' ){
1660 raw_printf(out, "%s", zNL);
1661 continue;
1662 }
1663 raw_printf(out, "%s", zCR);
1664 }
1665 raw_printf(out, "'");
1666 if( nCR ){
1667 raw_printf(out, ",'%s',char(13))", zCR);
1668 }
1669 if( nNL ){
1670 raw_printf(out, ",'%s',char(10))", zNL);
1671 }
1672 }
1673 setTextMode(out, 1);
1674}
1675
1676/*
1677** Output the given string as a quoted according to C or TCL quoting rules.
1678*/
1679static void output_c_string(FILE *out, const char *z){
1680 unsigned int c;
1681 fputc('"', out);
1682 while( (c = *(z++))!=0 ){
1683 if( c=='\\' ){
1684 fputc(c, out);
1685 fputc(c, out);
1686 }else if( c=='"' ){
1687 fputc('\\', out);
1688 fputc('"', out);
1689 }else if( c=='\t' ){
1690 fputc('\\', out);
1691 fputc('t', out);
1692 }else if( c=='\n' ){
1693 fputc('\\', out);
1694 fputc('n', out);
1695 }else if( c=='\r' ){
1696 fputc('\\', out);
1697 fputc('r', out);
1698 }else if( !isprint(c&0xff) ){
1699 raw_printf(out, "\\%03o", c&0xff);
1700 }else{
1701 fputc(c, out);
1702 }
1703 }
1704 fputc('"', out);
1705}
1706
1707/*
drh69c093d2020-05-29 00:21:43 +00001708** Output the given string as a quoted according to JSON quoting rules.
1709*/
drh7d23d152022-10-11 12:02:42 +00001710static void output_json_string(FILE *out, const char *z, i64 n){
drh69c093d2020-05-29 00:21:43 +00001711 unsigned int c;
drh7d23d152022-10-11 12:02:42 +00001712 if( n<0 ) n = strlen(z);
drh69c093d2020-05-29 00:21:43 +00001713 fputc('"', out);
1714 while( n-- ){
1715 c = *(z++);
1716 if( c=='\\' || c=='"' ){
1717 fputc('\\', out);
1718 fputc(c, out);
1719 }else if( c<=0x1f ){
1720 fputc('\\', out);
1721 if( c=='\b' ){
1722 fputc('b', out);
1723 }else if( c=='\f' ){
1724 fputc('f', out);
1725 }else if( c=='\n' ){
1726 fputc('n', out);
1727 }else if( c=='\r' ){
1728 fputc('r', out);
1729 }else if( c=='\t' ){
1730 fputc('t', out);
1731 }else{
1732 raw_printf(out, "u%04x",c);
1733 }
1734 }else{
1735 fputc(c, out);
1736 }
1737 }
1738 fputc('"', out);
1739}
1740
1741/*
drh2ce15c32017-07-11 13:34:40 +00001742** Output the given string with characters that are special to
1743** HTML escaped.
1744*/
1745static void output_html_string(FILE *out, const char *z){
1746 int i;
1747 if( z==0 ) z = "";
1748 while( *z ){
1749 for(i=0; z[i]
1750 && z[i]!='<'
1751 && z[i]!='&'
1752 && z[i]!='>'
1753 && z[i]!='\"'
1754 && z[i]!='\'';
1755 i++){}
1756 if( i>0 ){
1757 utf8_printf(out,"%.*s",i,z);
1758 }
1759 if( z[i]=='<' ){
1760 raw_printf(out,"&lt;");
1761 }else if( z[i]=='&' ){
1762 raw_printf(out,"&amp;");
1763 }else if( z[i]=='>' ){
1764 raw_printf(out,"&gt;");
1765 }else if( z[i]=='\"' ){
1766 raw_printf(out,"&quot;");
1767 }else if( z[i]=='\'' ){
1768 raw_printf(out,"&#39;");
1769 }else{
1770 break;
1771 }
1772 z += i + 1;
1773 }
1774}
1775
1776/*
1777** If a field contains any character identified by a 1 in the following
1778** array, then the string must be quoted for CSV.
1779*/
1780static const char needCsvQuote[] = {
1781 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1782 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1783 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1784 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1785 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1786 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1787 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1788 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1789 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1790 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1791 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1792 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1793 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1794 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1795 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1796 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1797};
1798
1799/*
1800** Output a single term of CSV. Actually, p->colSeparator is used for
1801** the separator, which may or may not be a comma. p->nullValue is
1802** the null value. Strings are quoted if necessary. The separator
1803** is only issued if bSep is true.
1804*/
1805static void output_csv(ShellState *p, const char *z, int bSep){
1806 FILE *out = p->out;
1807 if( z==0 ){
1808 utf8_printf(out,"%s",p->nullValue);
1809 }else{
drh9cd0c3d2021-11-18 15:40:05 +00001810 unsigned i;
1811 for(i=0; z[i]; i++){
1812 if( needCsvQuote[((unsigned char*)z)[i]] ){
drh2ce15c32017-07-11 13:34:40 +00001813 i = 0;
1814 break;
1815 }
1816 }
drh9cd0c3d2021-11-18 15:40:05 +00001817 if( i==0 || strstr(z, p->colSeparator)!=0 ){
drh9b7affc2017-11-26 02:14:18 +00001818 char *zQuoted = sqlite3_mprintf("\"%w\"", z);
drhe3e25652021-12-16 13:29:28 +00001819 shell_check_oom(zQuoted);
drh9b7affc2017-11-26 02:14:18 +00001820 utf8_printf(out, "%s", zQuoted);
1821 sqlite3_free(zQuoted);
drh2ce15c32017-07-11 13:34:40 +00001822 }else{
1823 utf8_printf(out, "%s", z);
1824 }
1825 }
1826 if( bSep ){
1827 utf8_printf(p->out, "%s", p->colSeparator);
1828 }
1829}
1830
drh2ce15c32017-07-11 13:34:40 +00001831/*
1832** This routine runs when the user presses Ctrl-C
1833*/
1834static void interrupt_handler(int NotUsed){
1835 UNUSED_PARAMETER(NotUsed);
1836 seenInterrupt++;
1837 if( seenInterrupt>2 ) exit(1);
1838 if( globalDb ) sqlite3_interrupt(globalDb);
1839}
mistachkinb4bab902017-10-27 17:09:44 +00001840
1841#if (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
1842/*
1843** This routine runs for console events (e.g. Ctrl-C) on Win32
1844*/
1845static BOOL WINAPI ConsoleCtrlHandler(
1846 DWORD dwCtrlType /* One of the CTRL_*_EVENT constants */
1847){
1848 if( dwCtrlType==CTRL_C_EVENT ){
1849 interrupt_handler(0);
1850 return TRUE;
1851 }
1852 return FALSE;
1853}
drh2ce15c32017-07-11 13:34:40 +00001854#endif
1855
1856#ifndef SQLITE_OMIT_AUTHORIZATION
1857/*
drhb97e2ad2021-08-26 18:31:39 +00001858** This authorizer runs in safe mode.
1859*/
1860static int safeModeAuth(
1861 void *pClientData,
1862 int op,
1863 const char *zA1,
1864 const char *zA2,
1865 const char *zA3,
1866 const char *zA4
1867){
1868 ShellState *p = (ShellState*)pClientData;
1869 static const char *azProhibitedFunctions[] = {
1870 "edit",
1871 "fts3_tokenizer",
1872 "load_extension",
1873 "readfile",
1874 "writefile",
1875 "zipfile",
1876 "zipfile_cds",
1877 };
1878 UNUSED_PARAMETER(zA2);
1879 UNUSED_PARAMETER(zA3);
1880 UNUSED_PARAMETER(zA4);
1881 switch( op ){
1882 case SQLITE_ATTACH: {
stephan4413ec72022-07-12 15:53:02 +00001883#ifndef SQLITE_SHELL_FIDDLE
stephan626aa482022-06-06 04:09:44 +00001884 /* In WASM builds the filesystem is a virtual sandbox, so
1885 ** there's no harm in using ATTACH. */
drhb97e2ad2021-08-26 18:31:39 +00001886 failIfSafeMode(p, "cannot run ATTACH in safe mode");
stephan626aa482022-06-06 04:09:44 +00001887#endif
drhb97e2ad2021-08-26 18:31:39 +00001888 break;
1889 }
1890 case SQLITE_FUNCTION: {
1891 int i;
1892 for(i=0; i<ArraySize(azProhibitedFunctions); i++){
1893 if( sqlite3_stricmp(zA1, azProhibitedFunctions[i])==0 ){
1894 failIfSafeMode(p, "cannot use the %s() function in safe mode",
1895 azProhibitedFunctions[i]);
1896 }
1897 }
1898 break;
1899 }
1900 }
1901 return SQLITE_OK;
1902}
1903
1904/*
drh2ce15c32017-07-11 13:34:40 +00001905** When the ".auth ON" is set, the following authorizer callback is
1906** invoked. It always returns SQLITE_OK.
1907*/
1908static int shellAuth(
1909 void *pClientData,
1910 int op,
1911 const char *zA1,
1912 const char *zA2,
1913 const char *zA3,
1914 const char *zA4
1915){
1916 ShellState *p = (ShellState*)pClientData;
1917 static const char *azAction[] = { 0,
1918 "CREATE_INDEX", "CREATE_TABLE", "CREATE_TEMP_INDEX",
1919 "CREATE_TEMP_TABLE", "CREATE_TEMP_TRIGGER", "CREATE_TEMP_VIEW",
1920 "CREATE_TRIGGER", "CREATE_VIEW", "DELETE",
1921 "DROP_INDEX", "DROP_TABLE", "DROP_TEMP_INDEX",
1922 "DROP_TEMP_TABLE", "DROP_TEMP_TRIGGER", "DROP_TEMP_VIEW",
1923 "DROP_TRIGGER", "DROP_VIEW", "INSERT",
1924 "PRAGMA", "READ", "SELECT",
1925 "TRANSACTION", "UPDATE", "ATTACH",
1926 "DETACH", "ALTER_TABLE", "REINDEX",
1927 "ANALYZE", "CREATE_VTABLE", "DROP_VTABLE",
1928 "FUNCTION", "SAVEPOINT", "RECURSIVE"
1929 };
1930 int i;
1931 const char *az[4];
1932 az[0] = zA1;
1933 az[1] = zA2;
1934 az[2] = zA3;
1935 az[3] = zA4;
1936 utf8_printf(p->out, "authorizer: %s", azAction[op]);
1937 for(i=0; i<4; i++){
1938 raw_printf(p->out, " ");
1939 if( az[i] ){
1940 output_c_string(p->out, az[i]);
1941 }else{
1942 raw_printf(p->out, "NULL");
1943 }
1944 }
1945 raw_printf(p->out, "\n");
drhb97e2ad2021-08-26 18:31:39 +00001946 if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
drh2ce15c32017-07-11 13:34:40 +00001947 return SQLITE_OK;
1948}
1949#endif
1950
1951/*
1952** Print a schema statement. Part of MODE_Semi and MODE_Pretty output.
1953**
1954** This routine converts some CREATE TABLE statements for shadow tables
1955** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
drh78ed74e2022-08-17 20:18:34 +00001956**
1957** If the schema statement in z[] contains a start-of-comment and if
1958** sqlite3_complete() returns false, try to terminate the comment before
1959** printing the result. https://sqlite.org/forum/forumpost/d7be961c5c
drh2ce15c32017-07-11 13:34:40 +00001960*/
1961static void printSchemaLine(FILE *out, const char *z, const char *zTail){
drh78ed74e2022-08-17 20:18:34 +00001962 char *zToFree = 0;
drh0a0536a2019-05-09 18:13:30 +00001963 if( z==0 ) return;
1964 if( zTail==0 ) return;
drh78ed74e2022-08-17 20:18:34 +00001965 if( zTail[0]==';' && (strstr(z, "/*")!=0 || strstr(z,"--")!=0) ){
1966 const char *zOrig = z;
1967 static const char *azTerm[] = { "", "*/", "\n" };
1968 int i;
1969 for(i=0; i<ArraySize(azTerm); i++){
1970 char *zNew = sqlite3_mprintf("%s%s;", zOrig, azTerm[i]);
1971 if( sqlite3_complete(zNew) ){
1972 size_t n = strlen(zNew);
1973 zNew[n-1] = 0;
1974 zToFree = zNew;
1975 z = zNew;
1976 break;
1977 }
1978 sqlite3_free(zNew);
1979 }
1980 }
drh2ce15c32017-07-11 13:34:40 +00001981 if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
1982 utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
1983 }else{
1984 utf8_printf(out, "%s%s", z, zTail);
1985 }
drh78ed74e2022-08-17 20:18:34 +00001986 sqlite3_free(zToFree);
drh2ce15c32017-07-11 13:34:40 +00001987}
1988static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
1989 char c = z[n];
1990 z[n] = 0;
1991 printSchemaLine(out, z, zTail);
1992 z[n] = c;
1993}
1994
1995/*
drh11be81d2018-01-06 15:46:20 +00001996** Return true if string z[] has nothing but whitespace and comments to the
1997** end of the first line.
1998*/
1999static int wsToEol(const char *z){
2000 int i;
2001 for(i=0; z[i]; i++){
2002 if( z[i]=='\n' ) return 1;
2003 if( IsSpace(z[i]) ) continue;
2004 if( z[i]=='-' && z[i+1]=='-' ) return 1;
2005 return 0;
2006 }
2007 return 1;
2008}
drh4b5345c2018-04-24 13:07:40 +00002009
2010/*
2011** Add a new entry to the EXPLAIN QUERY PLAN data
2012*/
drhe2ca99c2018-05-02 00:33:43 +00002013static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){
drh4b5345c2018-04-24 13:07:40 +00002014 EQPGraphRow *pNew;
drh8be89242022-10-17 16:09:33 +00002015 i64 nText;
2016 if( zText==0 ) return;
2017 nText = strlen(zText);
drhe2ca99c2018-05-02 00:33:43 +00002018 if( p->autoEQPtest ){
2019 utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
2020 }
drh4b5345c2018-04-24 13:07:40 +00002021 pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
drhe3e25652021-12-16 13:29:28 +00002022 shell_check_oom(pNew);
drhe2ca99c2018-05-02 00:33:43 +00002023 pNew->iEqpId = iEqpId;
2024 pNew->iParentId = p2;
drh4b5345c2018-04-24 13:07:40 +00002025 memcpy(pNew->zText, zText, nText+1);
2026 pNew->pNext = 0;
2027 if( p->sGraph.pLast ){
2028 p->sGraph.pLast->pNext = pNew;
2029 }else{
2030 p->sGraph.pRow = pNew;
2031 }
2032 p->sGraph.pLast = pNew;
2033}
2034
2035/*
2036** Free and reset the EXPLAIN QUERY PLAN data that has been collected
2037** in p->sGraph.
2038*/
2039static void eqp_reset(ShellState *p){
2040 EQPGraphRow *pRow, *pNext;
2041 for(pRow = p->sGraph.pRow; pRow; pRow = pNext){
2042 pNext = pRow->pNext;
2043 sqlite3_free(pRow);
2044 }
2045 memset(&p->sGraph, 0, sizeof(p->sGraph));
2046}
2047
drhe2ca99c2018-05-02 00:33:43 +00002048/* Return the next EXPLAIN QUERY PLAN line with iEqpId that occurs after
drh4b5345c2018-04-24 13:07:40 +00002049** pOld, or return the first such line if pOld is NULL
2050*/
drhe2ca99c2018-05-02 00:33:43 +00002051static EQPGraphRow *eqp_next_row(ShellState *p, int iEqpId, EQPGraphRow *pOld){
drh4b5345c2018-04-24 13:07:40 +00002052 EQPGraphRow *pRow = pOld ? pOld->pNext : p->sGraph.pRow;
drhe2ca99c2018-05-02 00:33:43 +00002053 while( pRow && pRow->iParentId!=iEqpId ) pRow = pRow->pNext;
drh4b5345c2018-04-24 13:07:40 +00002054 return pRow;
2055}
2056
drhe2ca99c2018-05-02 00:33:43 +00002057/* Render a single level of the graph that has iEqpId as its parent. Called
drh4b5345c2018-04-24 13:07:40 +00002058** recursively to render sublevels.
2059*/
drhe2ca99c2018-05-02 00:33:43 +00002060static void eqp_render_level(ShellState *p, int iEqpId){
drh4b5345c2018-04-24 13:07:40 +00002061 EQPGraphRow *pRow, *pNext;
drh7d23d152022-10-11 12:02:42 +00002062 i64 n = strlen(p->sGraph.zPrefix);
drh4b5345c2018-04-24 13:07:40 +00002063 char *z;
drhe2ca99c2018-05-02 00:33:43 +00002064 for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
2065 pNext = eqp_next_row(p, iEqpId, pRow);
drh4b5345c2018-04-24 13:07:40 +00002066 z = pRow->zText;
drhe2754c12019-08-26 12:50:01 +00002067 utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix,
2068 pNext ? "|--" : "`--", z);
drh7d23d152022-10-11 12:02:42 +00002069 if( n<(i64)sizeof(p->sGraph.zPrefix)-7 ){
drh4b5345c2018-04-24 13:07:40 +00002070 memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
drhe2ca99c2018-05-02 00:33:43 +00002071 eqp_render_level(p, pRow->iEqpId);
drh4b5345c2018-04-24 13:07:40 +00002072 p->sGraph.zPrefix[n] = 0;
2073 }
2074 }
2075}
2076
2077/*
2078** Display and reset the EXPLAIN QUERY PLAN data
2079*/
2080static void eqp_render(ShellState *p){
2081 EQPGraphRow *pRow = p->sGraph.pRow;
2082 if( pRow ){
2083 if( pRow->zText[0]=='-' ){
2084 if( pRow->pNext==0 ){
2085 eqp_reset(p);
2086 return;
2087 }
2088 utf8_printf(p->out, "%s\n", pRow->zText+3);
2089 p->sGraph.pRow = pRow->pNext;
2090 sqlite3_free(pRow);
2091 }else{
2092 utf8_printf(p->out, "QUERY PLAN\n");
2093 }
2094 p->sGraph.zPrefix[0] = 0;
2095 eqp_render_level(p, 0);
2096 eqp_reset(p);
2097 }
2098}
drh11be81d2018-01-06 15:46:20 +00002099
drh569b1d92019-02-05 20:51:41 +00002100#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
drh11be81d2018-01-06 15:46:20 +00002101/*
drh3f83f592019-02-04 14:53:18 +00002102** Progress handler callback.
2103*/
2104static int progress_handler(void *pClientData) {
2105 ShellState *p = (ShellState*)pClientData;
2106 p->nProgress++;
2107 if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){
2108 raw_printf(p->out, "Progress limit reached (%u)\n", p->nProgress);
drhfc4eeef2019-02-05 19:48:46 +00002109 if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
2110 if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0;
drh3f83f592019-02-04 14:53:18 +00002111 return 1;
2112 }
drhfc4eeef2019-02-05 19:48:46 +00002113 if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){
drh3f83f592019-02-04 14:53:18 +00002114 raw_printf(p->out, "Progress %u\n", p->nProgress);
2115 }
2116 return 0;
2117}
drh569b1d92019-02-05 20:51:41 +00002118#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
drh3f83f592019-02-04 14:53:18 +00002119
2120/*
drh30c54a02020-05-28 23:49:50 +00002121** Print N dashes
2122*/
2123static void print_dashes(FILE *out, int N){
2124 const char zDash[] = "--------------------------------------------------";
2125 const int nDash = sizeof(zDash) - 1;
2126 while( N>nDash ){
2127 fputs(zDash, out);
2128 N -= nDash;
2129 }
2130 raw_printf(out, "%.*s", N, zDash);
2131}
2132
2133/*
drh0908e382020-06-04 18:05:39 +00002134** Print a markdown or table-style row separator using ascii-art
drh30c54a02020-05-28 23:49:50 +00002135*/
2136static void print_row_separator(
2137 ShellState *p,
2138 int nArg,
2139 const char *zSep
2140){
2141 int i;
drh0908e382020-06-04 18:05:39 +00002142 if( nArg>0 ){
drh30c54a02020-05-28 23:49:50 +00002143 fputs(zSep, p->out);
drh0908e382020-06-04 18:05:39 +00002144 print_dashes(p->out, p->actualWidth[0]+2);
2145 for(i=1; i<nArg; i++){
2146 fputs(zSep, p->out);
2147 print_dashes(p->out, p->actualWidth[i]+2);
2148 }
2149 fputs(zSep, p->out);
drh30c54a02020-05-28 23:49:50 +00002150 }
drh30c54a02020-05-28 23:49:50 +00002151 fputs("\n", p->out);
2152}
2153
2154/*
drh2ce15c32017-07-11 13:34:40 +00002155** This is the callback routine that the shell
2156** invokes for each row of a query result.
2157*/
2158static int shell_callback(
2159 void *pArg,
2160 int nArg, /* Number of result columns */
2161 char **azArg, /* Text of each result column */
2162 char **azCol, /* Column names */
drhd6f25242020-05-29 12:31:53 +00002163 int *aiType /* Column types. Might be NULL */
drh2ce15c32017-07-11 13:34:40 +00002164){
2165 int i;
2166 ShellState *p = (ShellState*)pArg;
2167
drhb3c45232017-08-28 14:33:27 +00002168 if( azArg==0 ) return 0;
drh2ce15c32017-07-11 13:34:40 +00002169 switch( p->cMode ){
drh5d88be82021-12-09 16:17:43 +00002170 case MODE_Count:
2171 case MODE_Off: {
2172 break;
2173 }
drh2ce15c32017-07-11 13:34:40 +00002174 case MODE_Line: {
2175 int w = 5;
2176 if( azArg==0 ) break;
2177 for(i=0; i<nArg; i++){
2178 int len = strlen30(azCol[i] ? azCol[i] : "");
2179 if( len>w ) w = len;
2180 }
2181 if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator);
2182 for(i=0; i<nArg; i++){
2183 utf8_printf(p->out,"%*s = %s%s", w, azCol[i],
2184 azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
2185 }
2186 break;
2187 }
drh8c748632020-05-29 16:15:58 +00002188 case MODE_Explain: {
2189 static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
2190 if( nArg>ArraySize(aExplainWidth) ){
2191 nArg = ArraySize(aExplainWidth);
drh2ce15c32017-07-11 13:34:40 +00002192 }
2193 if( p->cnt++==0 ){
2194 for(i=0; i<nArg; i++){
drh8c748632020-05-29 16:15:58 +00002195 int w = aExplainWidth[i];
2196 utf8_width_print(p->out, w, azCol[i]);
2197 fputs(i==nArg-1 ? "\n" : " ", p->out);
drh2ce15c32017-07-11 13:34:40 +00002198 }
drhe566ceb2020-05-30 15:34:49 +00002199 for(i=0; i<nArg; i++){
2200 int w = aExplainWidth[i];
2201 print_dashes(p->out, w);
2202 fputs(i==nArg-1 ? "\n" : " ", p->out);
2203 }
drh2ce15c32017-07-11 13:34:40 +00002204 }
2205 if( azArg==0 ) break;
2206 for(i=0; i<nArg; i++){
drh8c748632020-05-29 16:15:58 +00002207 int w = aExplainWidth[i];
drhaa556b02021-01-13 12:59:20 +00002208 if( i==nArg-1 ) w = 0;
drh8c748632020-05-29 16:15:58 +00002209 if( azArg[i] && strlenChar(azArg[i])>w ){
2210 w = strlenChar(azArg[i]);
drh2ce15c32017-07-11 13:34:40 +00002211 }
drh8c748632020-05-29 16:15:58 +00002212 if( i==1 && p->aiIndent && p->pStmt ){
2213 if( p->iIndent<p->nIndent ){
2214 utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
drh2ce15c32017-07-11 13:34:40 +00002215 }
drh8c748632020-05-29 16:15:58 +00002216 p->iIndent++;
drh2ce15c32017-07-11 13:34:40 +00002217 }
2218 utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
drh8c748632020-05-29 16:15:58 +00002219 fputs(i==nArg-1 ? "\n" : " ", p->out);
drh2ce15c32017-07-11 13:34:40 +00002220 }
2221 break;
2222 }
2223 case MODE_Semi: { /* .schema and .fullschema output */
2224 printSchemaLine(p->out, azArg[0], ";\n");
2225 break;
2226 }
2227 case MODE_Pretty: { /* .schema and .fullschema with --indent */
2228 char *z;
2229 int j;
2230 int nParen = 0;
2231 char cEnd = 0;
2232 char c;
2233 int nLine = 0;
2234 assert( nArg==1 );
2235 if( azArg[0]==0 ) break;
2236 if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
2237 || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
2238 ){
2239 utf8_printf(p->out, "%s;\n", azArg[0]);
2240 break;
2241 }
2242 z = sqlite3_mprintf("%s", azArg[0]);
drhe3e25652021-12-16 13:29:28 +00002243 shell_check_oom(z);
drh2ce15c32017-07-11 13:34:40 +00002244 j = 0;
2245 for(i=0; IsSpace(z[i]); i++){}
2246 for(; (c = z[i])!=0; i++){
2247 if( IsSpace(c) ){
drhc3cbd672017-10-05 19:12:10 +00002248 if( z[j-1]=='\r' ) z[j-1] = '\n';
drh2ce15c32017-07-11 13:34:40 +00002249 if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
2250 }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
2251 j--;
2252 }
2253 z[j++] = c;
2254 }
2255 while( j>0 && IsSpace(z[j-1]) ){ j--; }
2256 z[j] = 0;
2257 if( strlen30(z)>=79 ){
drhe2754c12019-08-26 12:50:01 +00002258 for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */
drh2ce15c32017-07-11 13:34:40 +00002259 if( c==cEnd ){
2260 cEnd = 0;
2261 }else if( c=='"' || c=='\'' || c=='`' ){
2262 cEnd = c;
2263 }else if( c=='[' ){
2264 cEnd = ']';
drh11be81d2018-01-06 15:46:20 +00002265 }else if( c=='-' && z[i+1]=='-' ){
2266 cEnd = '\n';
drh2ce15c32017-07-11 13:34:40 +00002267 }else if( c=='(' ){
2268 nParen++;
2269 }else if( c==')' ){
2270 nParen--;
2271 if( nLine>0 && nParen==0 && j>0 ){
2272 printSchemaLineN(p->out, z, j, "\n");
2273 j = 0;
2274 }
2275 }
2276 z[j++] = c;
drh11be81d2018-01-06 15:46:20 +00002277 if( nParen==1 && cEnd==0
2278 && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
2279 ){
drh2ce15c32017-07-11 13:34:40 +00002280 if( c=='\n' ) j--;
2281 printSchemaLineN(p->out, z, j, "\n ");
2282 j = 0;
2283 nLine++;
2284 while( IsSpace(z[i+1]) ){ i++; }
2285 }
2286 }
2287 z[j] = 0;
2288 }
2289 printSchemaLine(p->out, z, ";\n");
2290 sqlite3_free(z);
2291 break;
2292 }
2293 case MODE_List: {
2294 if( p->cnt++==0 && p->showHeader ){
2295 for(i=0; i<nArg; i++){
2296 utf8_printf(p->out,"%s%s",azCol[i],
2297 i==nArg-1 ? p->rowSeparator : p->colSeparator);
2298 }
2299 }
2300 if( azArg==0 ) break;
2301 for(i=0; i<nArg; i++){
2302 char *z = azArg[i];
2303 if( z==0 ) z = p->nullValue;
2304 utf8_printf(p->out, "%s", z);
2305 if( i<nArg-1 ){
2306 utf8_printf(p->out, "%s", p->colSeparator);
2307 }else{
2308 utf8_printf(p->out, "%s", p->rowSeparator);
2309 }
2310 }
2311 break;
2312 }
2313 case MODE_Html: {
2314 if( p->cnt++==0 && p->showHeader ){
2315 raw_printf(p->out,"<TR>");
2316 for(i=0; i<nArg; i++){
2317 raw_printf(p->out,"<TH>");
2318 output_html_string(p->out, azCol[i]);
2319 raw_printf(p->out,"</TH>\n");
2320 }
2321 raw_printf(p->out,"</TR>\n");
2322 }
2323 if( azArg==0 ) break;
2324 raw_printf(p->out,"<TR>");
2325 for(i=0; i<nArg; i++){
2326 raw_printf(p->out,"<TD>");
2327 output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
2328 raw_printf(p->out,"</TD>\n");
2329 }
2330 raw_printf(p->out,"</TR>\n");
2331 break;
2332 }
2333 case MODE_Tcl: {
2334 if( p->cnt++==0 && p->showHeader ){
2335 for(i=0; i<nArg; i++){
2336 output_c_string(p->out,azCol[i] ? azCol[i] : "");
2337 if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
2338 }
2339 utf8_printf(p->out, "%s", p->rowSeparator);
2340 }
2341 if( azArg==0 ) break;
2342 for(i=0; i<nArg; i++){
2343 output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
2344 if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
2345 }
2346 utf8_printf(p->out, "%s", p->rowSeparator);
2347 break;
2348 }
2349 case MODE_Csv: {
2350 setBinaryMode(p->out, 1);
2351 if( p->cnt++==0 && p->showHeader ){
2352 for(i=0; i<nArg; i++){
2353 output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
2354 }
2355 utf8_printf(p->out, "%s", p->rowSeparator);
2356 }
2357 if( nArg>0 ){
2358 for(i=0; i<nArg; i++){
2359 output_csv(p, azArg[i], i<nArg-1);
2360 }
2361 utf8_printf(p->out, "%s", p->rowSeparator);
2362 }
2363 setTextMode(p->out, 1);
2364 break;
2365 }
2366 case MODE_Insert: {
2367 if( azArg==0 ) break;
2368 utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
2369 if( p->showHeader ){
2370 raw_printf(p->out,"(");
2371 for(i=0; i<nArg; i++){
2372 if( i>0 ) raw_printf(p->out, ",");
2373 if( quoteChar(azCol[i]) ){
2374 char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
drhe3e25652021-12-16 13:29:28 +00002375 shell_check_oom(z);
drh2ce15c32017-07-11 13:34:40 +00002376 utf8_printf(p->out, "%s", z);
2377 sqlite3_free(z);
2378 }else{
2379 raw_printf(p->out, "%s", azCol[i]);
2380 }
2381 }
2382 raw_printf(p->out,")");
2383 }
2384 p->cnt++;
2385 for(i=0; i<nArg; i++){
2386 raw_printf(p->out, i>0 ? "," : " VALUES(");
2387 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
2388 utf8_printf(p->out,"NULL");
2389 }else if( aiType && aiType[i]==SQLITE_TEXT ){
2390 if( ShellHasFlag(p, SHFLG_Newlines) ){
2391 output_quoted_string(p->out, azArg[i]);
2392 }else{
2393 output_quoted_escaped_string(p->out, azArg[i]);
2394 }
2395 }else if( aiType && aiType[i]==SQLITE_INTEGER ){
2396 utf8_printf(p->out,"%s", azArg[i]);
2397 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
2398 char z[50];
2399 double r = sqlite3_column_double(p->pStmt, i);
drh2f1f8802018-06-13 17:19:20 +00002400 sqlite3_uint64 ur;
2401 memcpy(&ur,&r,sizeof(r));
2402 if( ur==0x7ff0000000000000LL ){
2403 raw_printf(p->out, "1e999");
2404 }else if( ur==0xfff0000000000000LL ){
2405 raw_printf(p->out, "-1e999");
2406 }else{
drh537a6bf2022-02-15 13:23:09 +00002407 sqlite3_int64 ir = (sqlite3_int64)r;
2408 if( r==(double)ir ){
2409 sqlite3_snprintf(50,z,"%lld.0", ir);
2410 }else{
2411 sqlite3_snprintf(50,z,"%!.20g", r);
2412 }
drh2f1f8802018-06-13 17:19:20 +00002413 raw_printf(p->out, "%s", z);
2414 }
drh2ce15c32017-07-11 13:34:40 +00002415 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
2416 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
2417 int nBlob = sqlite3_column_bytes(p->pStmt, i);
2418 output_hex_blob(p->out, pBlob, nBlob);
2419 }else if( isNumber(azArg[i], 0) ){
2420 utf8_printf(p->out,"%s", azArg[i]);
2421 }else if( ShellHasFlag(p, SHFLG_Newlines) ){
2422 output_quoted_string(p->out, azArg[i]);
2423 }else{
2424 output_quoted_escaped_string(p->out, azArg[i]);
2425 }
2426 }
2427 raw_printf(p->out,");\n");
2428 break;
2429 }
drh30c54a02020-05-28 23:49:50 +00002430 case MODE_Json: {
2431 if( azArg==0 ) break;
2432 if( p->cnt==0 ){
2433 fputs("[{", p->out);
2434 }else{
2435 fputs(",\n{", p->out);
2436 }
2437 p->cnt++;
2438 for(i=0; i<nArg; i++){
drh69c093d2020-05-29 00:21:43 +00002439 output_json_string(p->out, azCol[i], -1);
drh30c54a02020-05-28 23:49:50 +00002440 putc(':', p->out);
2441 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
2442 fputs("null",p->out);
2443 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
2444 char z[50];
2445 double r = sqlite3_column_double(p->pStmt, i);
2446 sqlite3_uint64 ur;
2447 memcpy(&ur,&r,sizeof(r));
2448 if( ur==0x7ff0000000000000LL ){
2449 raw_printf(p->out, "1e999");
2450 }else if( ur==0xfff0000000000000LL ){
2451 raw_printf(p->out, "-1e999");
2452 }else{
2453 sqlite3_snprintf(50,z,"%!.20g", r);
2454 raw_printf(p->out, "%s", z);
2455 }
2456 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
2457 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
2458 int nBlob = sqlite3_column_bytes(p->pStmt, i);
drh69c093d2020-05-29 00:21:43 +00002459 output_json_string(p->out, pBlob, nBlob);
drh30c54a02020-05-28 23:49:50 +00002460 }else if( aiType && aiType[i]==SQLITE_TEXT ){
drh69c093d2020-05-29 00:21:43 +00002461 output_json_string(p->out, azArg[i], -1);
drh30c54a02020-05-28 23:49:50 +00002462 }else{
2463 utf8_printf(p->out,"%s", azArg[i]);
2464 }
2465 if( i<nArg-1 ){
2466 putc(',', p->out);
2467 }
2468 }
2469 putc('}', p->out);
2470 break;
2471 }
drh2ce15c32017-07-11 13:34:40 +00002472 case MODE_Quote: {
2473 if( azArg==0 ) break;
2474 if( p->cnt==0 && p->showHeader ){
2475 for(i=0; i<nArg; i++){
drhc6835732020-05-28 20:37:17 +00002476 if( i>0 ) fputs(p->colSeparator, p->out);
drh2ce15c32017-07-11 13:34:40 +00002477 output_quoted_string(p->out, azCol[i]);
2478 }
drhc6835732020-05-28 20:37:17 +00002479 fputs(p->rowSeparator, p->out);
drh2ce15c32017-07-11 13:34:40 +00002480 }
2481 p->cnt++;
2482 for(i=0; i<nArg; i++){
drhc6835732020-05-28 20:37:17 +00002483 if( i>0 ) fputs(p->colSeparator, p->out);
drh2ce15c32017-07-11 13:34:40 +00002484 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
2485 utf8_printf(p->out,"NULL");
2486 }else if( aiType && aiType[i]==SQLITE_TEXT ){
2487 output_quoted_string(p->out, azArg[i]);
2488 }else if( aiType && aiType[i]==SQLITE_INTEGER ){
2489 utf8_printf(p->out,"%s", azArg[i]);
2490 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
2491 char z[50];
2492 double r = sqlite3_column_double(p->pStmt, i);
2493 sqlite3_snprintf(50,z,"%!.20g", r);
2494 raw_printf(p->out, "%s", z);
2495 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
2496 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
2497 int nBlob = sqlite3_column_bytes(p->pStmt, i);
2498 output_hex_blob(p->out, pBlob, nBlob);
2499 }else if( isNumber(azArg[i], 0) ){
2500 utf8_printf(p->out,"%s", azArg[i]);
2501 }else{
2502 output_quoted_string(p->out, azArg[i]);
2503 }
2504 }
drhc6835732020-05-28 20:37:17 +00002505 fputs(p->rowSeparator, p->out);
drh2ce15c32017-07-11 13:34:40 +00002506 break;
2507 }
2508 case MODE_Ascii: {
2509 if( p->cnt++==0 && p->showHeader ){
2510 for(i=0; i<nArg; i++){
2511 if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
2512 utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : "");
2513 }
2514 utf8_printf(p->out, "%s", p->rowSeparator);
2515 }
2516 if( azArg==0 ) break;
2517 for(i=0; i<nArg; i++){
2518 if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
2519 utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
2520 }
2521 utf8_printf(p->out, "%s", p->rowSeparator);
2522 break;
2523 }
drh4b5345c2018-04-24 13:07:40 +00002524 case MODE_EQP: {
drhe2ca99c2018-05-02 00:33:43 +00002525 eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]);
drh4b5345c2018-04-24 13:07:40 +00002526 break;
2527 }
drh2ce15c32017-07-11 13:34:40 +00002528 }
2529 return 0;
2530}
2531
2532/*
2533** This is the callback routine that the SQLite library
2534** invokes for each row of a query result.
2535*/
2536static int callback(void *pArg, int nArg, char **azArg, char **azCol){
2537 /* since we don't have type info, call the shell_callback with a NULL value */
2538 return shell_callback(pArg, nArg, azArg, azCol, NULL);
2539}
2540
2541/*
2542** This is the callback routine from sqlite3_exec() that appends all
2543** output onto the end of a ShellText object.
2544*/
2545static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
2546 ShellText *p = (ShellText*)pArg;
2547 int i;
2548 UNUSED_PARAMETER(az);
drhb3c45232017-08-28 14:33:27 +00002549 if( azArg==0 ) return 0;
drh2ce15c32017-07-11 13:34:40 +00002550 if( p->n ) appendText(p, "|", 0);
2551 for(i=0; i<nArg; i++){
2552 if( i ) appendText(p, ",", 0);
2553 if( azArg[i] ) appendText(p, azArg[i], 0);
2554 }
2555 return 0;
2556}
2557
2558/*
2559** Generate an appropriate SELFTEST table in the main database.
2560*/
2561static void createSelftestTable(ShellState *p){
2562 char *zErrMsg = 0;
2563 sqlite3_exec(p->db,
2564 "SAVEPOINT selftest_init;\n"
2565 "CREATE TABLE IF NOT EXISTS selftest(\n"
2566 " tno INTEGER PRIMARY KEY,\n" /* Test number */
2567 " op TEXT,\n" /* Operator: memo run */
2568 " cmd TEXT,\n" /* Command text */
2569 " ans TEXT\n" /* Desired answer */
2570 ");"
2571 "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n"
2572 "INSERT INTO [_shell$self](rowid,op,cmd)\n"
2573 " VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n"
2574 " 'memo','Tests generated by --init');\n"
2575 "INSERT INTO [_shell$self]\n"
2576 " SELECT 'run',\n"
2577 " 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql "
drh067b92b2020-06-19 15:24:12 +00002578 "FROM sqlite_schema ORDER BY 2'',224))',\n"
drh2ce15c32017-07-11 13:34:40 +00002579 " hex(sha3_query('SELECT type,name,tbl_name,sql "
drh067b92b2020-06-19 15:24:12 +00002580 "FROM sqlite_schema ORDER BY 2',224));\n"
drh2ce15c32017-07-11 13:34:40 +00002581 "INSERT INTO [_shell$self]\n"
2582 " SELECT 'run',"
2583 " 'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
2584 " printf('%w',name) || '\" NOT INDEXED'',224))',\n"
2585 " hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
2586 " FROM (\n"
drh067b92b2020-06-19 15:24:12 +00002587 " SELECT name FROM sqlite_schema\n"
drh2ce15c32017-07-11 13:34:40 +00002588 " WHERE type='table'\n"
2589 " AND name<>'selftest'\n"
2590 " AND coalesce(rootpage,0)>0\n"
2591 " )\n"
2592 " ORDER BY name;\n"
2593 "INSERT INTO [_shell$self]\n"
2594 " VALUES('run','PRAGMA integrity_check','ok');\n"
2595 "INSERT INTO selftest(tno,op,cmd,ans)"
2596 " SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
2597 "DROP TABLE [_shell$self];"
2598 ,0,0,&zErrMsg);
2599 if( zErrMsg ){
2600 utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
2601 sqlite3_free(zErrMsg);
2602 }
2603 sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
2604}
2605
2606
2607/*
2608** Set the destination table field of the ShellState structure to
2609** the name of the table given. Escape any quote characters in the
2610** table name.
2611*/
2612static void set_table_name(ShellState *p, const char *zName){
2613 int i, n;
mistachkin2158a0c2017-09-09 00:51:36 +00002614 char cQuote;
drh2ce15c32017-07-11 13:34:40 +00002615 char *z;
2616
2617 if( p->zDestTable ){
2618 free(p->zDestTable);
2619 p->zDestTable = 0;
2620 }
2621 if( zName==0 ) return;
2622 cQuote = quoteChar(zName);
2623 n = strlen30(zName);
2624 if( cQuote ) n += n+2;
2625 z = p->zDestTable = malloc( n+1 );
drhe3e25652021-12-16 13:29:28 +00002626 shell_check_oom(z);
drh2ce15c32017-07-11 13:34:40 +00002627 n = 0;
2628 if( cQuote ) z[n++] = cQuote;
2629 for(i=0; zName[i]; i++){
2630 z[n++] = zName[i];
2631 if( zName[i]==cQuote ) z[n++] = cQuote;
2632 }
2633 if( cQuote ) z[n++] = cQuote;
2634 z[n] = 0;
2635}
2636
drhf62641e2021-12-24 20:22:13 +00002637/*
2638** Maybe construct two lines of text that point out the position of a
2639** syntax error. Return a pointer to the text, in memory obtained from
2640** sqlite3_malloc(). Or, if the most recent error does not involve a
2641** specific token that we can point to, return an empty string.
2642**
2643** In all cases, the memory returned is obtained from sqlite3_malloc64()
2644** and should be released by the caller invoking sqlite3_free().
2645*/
2646static char *shell_error_context(const char *zSql, sqlite3 *db){
2647 int iOffset;
2648 size_t len;
2649 char *zCode;
2650 char *zMsg;
2651 int i;
2652 if( db==0
2653 || zSql==0
2654 || (iOffset = sqlite3_error_offset(db))<0
2655 ){
2656 return sqlite3_mprintf("");
2657 }
2658 while( iOffset>50 ){
2659 iOffset--;
2660 zSql++;
2661 while( (zSql[0]&0xc0)==0x80 ){ zSql++; iOffset--; }
2662 }
2663 len = strlen(zSql);
2664 if( len>78 ){
2665 len = 78;
2666 while( (zSql[len]&0xc0)==0x80 ) len--;
2667 }
2668 zCode = sqlite3_mprintf("%.*s", len, zSql);
drh1e84e1e2022-10-31 01:22:38 +00002669 shell_check_oom(zCode);
drhf62641e2021-12-24 20:22:13 +00002670 for(i=0; zCode[i]; i++){ if( IsSpace(zSql[i]) ) zCode[i] = ' '; }
2671 if( iOffset<25 ){
2672 zMsg = sqlite3_mprintf("\n %z\n %*s^--- error here", zCode, iOffset, "");
2673 }else{
2674 zMsg = sqlite3_mprintf("\n %z\n %*serror here ---^", zCode, iOffset-14, "");
2675 }
2676 return zMsg;
2677}
2678
drh2ce15c32017-07-11 13:34:40 +00002679
2680/*
2681** Execute a query statement that will generate SQL output. Print
2682** the result columns, comma-separated, on a line and then add a
2683** semicolon terminator to the end of that line.
2684**
2685** If the number of columns is 1 and that column contains text "--"
2686** then write the semicolon on a separate line. That way, if a
2687** "--" comment occurs at the end of the statement, the comment
2688** won't consume the semicolon terminator.
2689*/
2690static int run_table_dump_query(
2691 ShellState *p, /* Query context */
drh8e9297f2020-03-25 12:50:13 +00002692 const char *zSelect /* SELECT statement to extract content */
drh2ce15c32017-07-11 13:34:40 +00002693){
2694 sqlite3_stmt *pSelect;
2695 int rc;
2696 int nResult;
2697 int i;
2698 const char *z;
2699 rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
2700 if( rc!=SQLITE_OK || !pSelect ){
drhf62641e2021-12-24 20:22:13 +00002701 char *zContext = shell_error_context(zSelect, p->db);
2702 utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n%s", rc,
2703 sqlite3_errmsg(p->db), zContext);
2704 sqlite3_free(zContext);
drh2ce15c32017-07-11 13:34:40 +00002705 if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
2706 return rc;
2707 }
2708 rc = sqlite3_step(pSelect);
2709 nResult = sqlite3_column_count(pSelect);
2710 while( rc==SQLITE_ROW ){
drh2ce15c32017-07-11 13:34:40 +00002711 z = (const char*)sqlite3_column_text(pSelect, 0);
2712 utf8_printf(p->out, "%s", z);
2713 for(i=1; i<nResult; i++){
2714 utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
2715 }
2716 if( z==0 ) z = "";
2717 while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
2718 if( z[0] ){
2719 raw_printf(p->out, "\n;\n");
2720 }else{
2721 raw_printf(p->out, ";\n");
2722 }
2723 rc = sqlite3_step(pSelect);
2724 }
2725 rc = sqlite3_finalize(pSelect);
2726 if( rc!=SQLITE_OK ){
2727 utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
2728 sqlite3_errmsg(p->db));
2729 if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
2730 }
2731 return rc;
2732}
2733
2734/*
larrybrf9a49b02021-10-26 16:57:09 +00002735** Allocate space and save off string indicating current error.
drh2ce15c32017-07-11 13:34:40 +00002736*/
2737static char *save_err_msg(
larrybrf9a49b02021-10-26 16:57:09 +00002738 sqlite3 *db, /* Database to query */
drh633c7982022-02-08 12:13:16 +00002739 const char *zPhase, /* When the error occcurs */
drhf62641e2021-12-24 20:22:13 +00002740 int rc, /* Error code returned from API */
2741 const char *zSql /* SQL string, or NULL */
drh2ce15c32017-07-11 13:34:40 +00002742){
drhe3e25652021-12-16 13:29:28 +00002743 char *zErr;
drhf62641e2021-12-24 20:22:13 +00002744 char *zContext;
drh633c7982022-02-08 12:13:16 +00002745 sqlite3_str *pStr = sqlite3_str_new(0);
2746 sqlite3_str_appendf(pStr, "%s, %s", zPhase, sqlite3_errmsg(db));
2747 if( rc>1 ){
2748 sqlite3_str_appendf(pStr, " (%d)", rc);
2749 }
drhf62641e2021-12-24 20:22:13 +00002750 zContext = shell_error_context(zSql, db);
drh633c7982022-02-08 12:13:16 +00002751 if( zContext ){
2752 sqlite3_str_appendall(pStr, zContext);
2753 sqlite3_free(zContext);
2754 }
2755 zErr = sqlite3_str_finish(pStr);
drhe3e25652021-12-16 13:29:28 +00002756 shell_check_oom(zErr);
2757 return zErr;
drh2ce15c32017-07-11 13:34:40 +00002758}
2759
2760#ifdef __linux__
2761/*
2762** Attempt to display I/O stats on Linux using /proc/PID/io
2763*/
2764static void displayLinuxIoStats(FILE *out){
2765 FILE *in;
2766 char z[200];
2767 sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
2768 in = fopen(z, "rb");
2769 if( in==0 ) return;
2770 while( fgets(z, sizeof(z), in)!=0 ){
2771 static const struct {
2772 const char *zPattern;
2773 const char *zDesc;
2774 } aTrans[] = {
2775 { "rchar: ", "Bytes received by read():" },
2776 { "wchar: ", "Bytes sent to write():" },
2777 { "syscr: ", "Read() system calls:" },
2778 { "syscw: ", "Write() system calls:" },
2779 { "read_bytes: ", "Bytes read from storage:" },
2780 { "write_bytes: ", "Bytes written to storage:" },
2781 { "cancelled_write_bytes: ", "Cancelled write bytes:" },
2782 };
2783 int i;
2784 for(i=0; i<ArraySize(aTrans); i++){
drhaf2770f2018-01-05 14:55:43 +00002785 int n = strlen30(aTrans[i].zPattern);
drhbf70f1b2022-10-19 18:04:42 +00002786 if( cli_strncmp(aTrans[i].zPattern, z, n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00002787 utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
2788 break;
2789 }
2790 }
2791 }
2792 fclose(in);
2793}
2794#endif
2795
2796/*
2797** Display a single line of status using 64-bit values.
2798*/
2799static void displayStatLine(
2800 ShellState *p, /* The shell context */
2801 char *zLabel, /* Label for this one line */
2802 char *zFormat, /* Format for the result */
2803 int iStatusCtrl, /* Which status to display */
2804 int bReset /* True to reset the stats */
2805){
2806 sqlite3_int64 iCur = -1;
2807 sqlite3_int64 iHiwtr = -1;
2808 int i, nPercent;
2809 char zLine[200];
2810 sqlite3_status64(iStatusCtrl, &iCur, &iHiwtr, bReset);
2811 for(i=0, nPercent=0; zFormat[i]; i++){
2812 if( zFormat[i]=='%' ) nPercent++;
2813 }
2814 if( nPercent>1 ){
2815 sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
2816 }else{
2817 sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
2818 }
2819 raw_printf(p->out, "%-36s %s\n", zLabel, zLine);
2820}
2821
2822/*
2823** Display memory stats.
2824*/
2825static int display_stats(
2826 sqlite3 *db, /* Database to query */
2827 ShellState *pArg, /* Pointer to ShellState */
2828 int bReset /* True to reset the stats */
2829){
2830 int iCur;
2831 int iHiwtr;
drh393344f2018-03-09 16:37:05 +00002832 FILE *out;
2833 if( pArg==0 || pArg->out==0 ) return 0;
2834 out = pArg->out;
drh2ce15c32017-07-11 13:34:40 +00002835
drha6e6cf22021-01-09 19:10:04 +00002836 if( pArg->pStmt && pArg->statsOn==2 ){
drh393344f2018-03-09 16:37:05 +00002837 int nCol, i, x;
2838 sqlite3_stmt *pStmt = pArg->pStmt;
2839 char z[100];
2840 nCol = sqlite3_column_count(pStmt);
2841 raw_printf(out, "%-36s %d\n", "Number of output columns:", nCol);
2842 for(i=0; i<nCol; i++){
2843 sqlite3_snprintf(sizeof(z),z,"Column %d %nname:", i, &x);
2844 utf8_printf(out, "%-36s %s\n", z, sqlite3_column_name(pStmt,i));
drh929cce82018-03-17 16:26:36 +00002845#ifndef SQLITE_OMIT_DECLTYPE
drh393344f2018-03-09 16:37:05 +00002846 sqlite3_snprintf(30, z+x, "declared type:");
2847 utf8_printf(out, "%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
drh929cce82018-03-17 16:26:36 +00002848#endif
2849#ifdef SQLITE_ENABLE_COLUMN_METADATA
drh393344f2018-03-09 16:37:05 +00002850 sqlite3_snprintf(30, z+x, "database name:");
2851 utf8_printf(out, "%-36s %s\n", z, sqlite3_column_database_name(pStmt,i));
2852 sqlite3_snprintf(30, z+x, "table name:");
2853 utf8_printf(out, "%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
2854 sqlite3_snprintf(30, z+x, "origin name:");
2855 utf8_printf(out, "%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i));
drh929cce82018-03-17 16:26:36 +00002856#endif
drh2ce15c32017-07-11 13:34:40 +00002857 }
drh929cce82018-03-17 16:26:36 +00002858 }
drh2ce15c32017-07-11 13:34:40 +00002859
drha6e6cf22021-01-09 19:10:04 +00002860 if( pArg->statsOn==3 ){
2861 if( pArg->pStmt ){
2862 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
2863 raw_printf(pArg->out, "VM-steps: %d\n", iCur);
2864 }
2865 return 0;
2866 }
2867
drh393344f2018-03-09 16:37:05 +00002868 displayStatLine(pArg, "Memory Used:",
2869 "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
2870 displayStatLine(pArg, "Number of Outstanding Allocations:",
2871 "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
2872 if( pArg->shellFlgs & SHFLG_Pagecache ){
2873 displayStatLine(pArg, "Number of Pcache Pages Used:",
2874 "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
2875 }
2876 displayStatLine(pArg, "Number of Pcache Overflow Bytes:",
2877 "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
2878 displayStatLine(pArg, "Largest Allocation:",
2879 "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
2880 displayStatLine(pArg, "Largest Pcache Allocation:",
2881 "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
2882#ifdef YYTRACKMAXSTACKDEPTH
2883 displayStatLine(pArg, "Deepest Parser Stack:",
2884 "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
2885#endif
2886
2887 if( db ){
drh2ce15c32017-07-11 13:34:40 +00002888 if( pArg->shellFlgs & SHFLG_Lookaside ){
2889 iHiwtr = iCur = -1;
2890 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
2891 &iCur, &iHiwtr, bReset);
2892 raw_printf(pArg->out,
2893 "Lookaside Slots Used: %d (max %d)\n",
2894 iCur, iHiwtr);
2895 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
2896 &iCur, &iHiwtr, bReset);
2897 raw_printf(pArg->out, "Successful lookaside attempts: %d\n",
2898 iHiwtr);
2899 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
2900 &iCur, &iHiwtr, bReset);
2901 raw_printf(pArg->out, "Lookaside failures due to size: %d\n",
2902 iHiwtr);
2903 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
2904 &iCur, &iHiwtr, bReset);
2905 raw_printf(pArg->out, "Lookaside failures due to OOM: %d\n",
2906 iHiwtr);
2907 }
2908 iHiwtr = iCur = -1;
2909 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
2910 raw_printf(pArg->out, "Pager Heap Usage: %d bytes\n",
2911 iCur);
2912 iHiwtr = iCur = -1;
2913 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
2914 raw_printf(pArg->out, "Page cache hits: %d\n", iCur);
2915 iHiwtr = iCur = -1;
2916 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
2917 raw_printf(pArg->out, "Page cache misses: %d\n", iCur);
2918 iHiwtr = iCur = -1;
2919 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
2920 raw_printf(pArg->out, "Page cache writes: %d\n", iCur);
2921 iHiwtr = iCur = -1;
drhffc78a42018-03-14 14:53:50 +00002922 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1);
2923 raw_printf(pArg->out, "Page cache spills: %d\n", iCur);
2924 iHiwtr = iCur = -1;
drh2ce15c32017-07-11 13:34:40 +00002925 sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
2926 raw_printf(pArg->out, "Schema Heap Usage: %d bytes\n",
2927 iCur);
2928 iHiwtr = iCur = -1;
2929 sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
2930 raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n",
2931 iCur);
2932 }
2933
drh393344f2018-03-09 16:37:05 +00002934 if( pArg->pStmt ){
drh23d41e62021-12-06 21:45:31 +00002935 int iHit, iMiss;
drh2ce15c32017-07-11 13:34:40 +00002936 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
2937 bReset);
2938 raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur);
2939 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
2940 raw_printf(pArg->out, "Sort Operations: %d\n", iCur);
2941 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
2942 raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur);
drh23d41e62021-12-06 21:45:31 +00002943 iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT, bReset);
2944 iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS, bReset);
2945 if( iHit || iMiss ){
2946 raw_printf(pArg->out, "Bloom filter bypass taken: %d/%d\n",
2947 iHit, iHit+iMiss);
2948 }
drh2ce15c32017-07-11 13:34:40 +00002949 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
2950 raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
drhe2754c12019-08-26 12:50:01 +00002951 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
drh393344f2018-03-09 16:37:05 +00002952 raw_printf(pArg->out, "Reprepare operations: %d\n", iCur);
2953 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
2954 raw_printf(pArg->out, "Number of times run: %d\n", iCur);
2955 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset);
2956 raw_printf(pArg->out, "Memory used by prepared stmt: %d\n", iCur);
drh2ce15c32017-07-11 13:34:40 +00002957 }
2958
2959#ifdef __linux__
2960 displayLinuxIoStats(pArg->out);
2961#endif
2962
2963 /* Do not remove this machine readable comment: extra-stats-output-here */
2964
2965 return 0;
2966}
2967
2968/*
2969** Display scan stats.
2970*/
2971static void display_scanstats(
2972 sqlite3 *db, /* Database to query */
2973 ShellState *pArg /* Pointer to ShellState */
2974){
2975#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
2976 UNUSED_PARAMETER(db);
2977 UNUSED_PARAMETER(pArg);
2978#else
2979 int i, k, n, mx;
2980 raw_printf(pArg->out, "-------- scanstats --------\n");
2981 mx = 0;
2982 for(k=0; k<=mx; k++){
2983 double rEstLoop = 1.0;
2984 for(i=n=0; 1; i++){
2985 sqlite3_stmt *p = pArg->pStmt;
2986 sqlite3_int64 nLoop, nVisit;
2987 double rEst;
2988 int iSid;
2989 const char *zExplain;
2990 if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){
2991 break;
2992 }
2993 sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid);
2994 if( iSid>mx ) mx = iSid;
2995 if( iSid!=k ) continue;
2996 if( n==0 ){
2997 rEstLoop = (double)nLoop;
2998 if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k);
2999 }
3000 n++;
3001 sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
3002 sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
3003 sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
3004 utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain);
3005 rEstLoop *= rEst;
3006 raw_printf(pArg->out,
3007 " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
3008 nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
3009 );
3010 }
3011 }
3012 raw_printf(pArg->out, "---------------------------\n");
3013#endif
3014}
3015
3016/*
3017** Parameter azArray points to a zero-terminated array of strings. zStr
3018** points to a single nul-terminated string. Return non-zero if zStr
3019** is equal, according to strcmp(), to any of the strings in the array.
3020** Otherwise, return zero.
3021*/
3022static int str_in_array(const char *zStr, const char **azArray){
3023 int i;
3024 for(i=0; azArray[i]; i++){
drhbf70f1b2022-10-19 18:04:42 +00003025 if( 0==cli_strcmp(zStr, azArray[i]) ) return 1;
drh2ce15c32017-07-11 13:34:40 +00003026 }
3027 return 0;
3028}
3029
3030/*
3031** If compiled statement pSql appears to be an EXPLAIN statement, allocate
3032** and populate the ShellState.aiIndent[] array with the number of
3033** spaces each opcode should be indented before it is output.
3034**
3035** The indenting rules are:
3036**
3037** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
3038** all opcodes that occur between the p2 jump destination and the opcode
3039** itself by 2 spaces.
3040**
drhe603ab02022-04-07 19:06:31 +00003041** * Do the previous for "Return" instructions for when P2 is positive.
3042** See tag-20220407a in wherecode.c and vdbe.c.
3043**
drh2ce15c32017-07-11 13:34:40 +00003044** * For each "Goto", if the jump destination is earlier in the program
3045** and ends on one of:
3046** Yield SeekGt SeekLt RowSetRead Rewind
3047** or if the P1 parameter is one instead of zero,
3048** then indent all opcodes between the earlier instruction
3049** and "Goto" by 2 spaces.
3050*/
3051static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
3052 const char *zSql; /* The text of the SQL statement */
3053 const char *z; /* Used to check if this is an EXPLAIN */
3054 int *abYield = 0; /* True if op is an OP_Yield */
3055 int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
3056 int iOp; /* Index of operation in p->aiIndent[] */
3057
drhe603ab02022-04-07 19:06:31 +00003058 const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
3059 "Return", 0 };
drh2ce15c32017-07-11 13:34:40 +00003060 const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
3061 "Rewind", 0 };
3062 const char *azGoto[] = { "Goto", 0 };
3063
3064 /* Try to figure out if this is really an EXPLAIN statement. If this
3065 ** cannot be verified, return early. */
3066 if( sqlite3_column_count(pSql)!=8 ){
3067 p->cMode = p->mode;
3068 return;
3069 }
3070 zSql = sqlite3_sql(pSql);
3071 if( zSql==0 ) return;
3072 for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
3073 if( sqlite3_strnicmp(z, "explain", 7) ){
3074 p->cMode = p->mode;
3075 return;
3076 }
3077
3078 for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
3079 int i;
3080 int iAddr = sqlite3_column_int(pSql, 0);
3081 const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
3082
3083 /* Set p2 to the P2 field of the current opcode. Then, assuming that
3084 ** p2 is an instruction address, set variable p2op to the index of that
3085 ** instruction in the aiIndent[] array. p2 and p2op may be different if
3086 ** the current instruction is part of a sub-program generated by an
3087 ** SQL trigger or foreign key. */
3088 int p2 = sqlite3_column_int(pSql, 3);
3089 int p2op = (p2 + (iOp-iAddr));
3090
3091 /* Grow the p->aiIndent array as required */
3092 if( iOp>=nAlloc ){
3093 if( iOp==0 ){
3094 /* Do further verfication that this is explain output. Abort if
3095 ** it is not */
3096 static const char *explainCols[] = {
3097 "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
3098 int jj;
3099 for(jj=0; jj<ArraySize(explainCols); jj++){
drhbf70f1b2022-10-19 18:04:42 +00003100 if( cli_strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
drh2ce15c32017-07-11 13:34:40 +00003101 p->cMode = p->mode;
3102 sqlite3_reset(pSql);
3103 return;
3104 }
3105 }
3106 }
3107 nAlloc += 100;
3108 p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
drhe3e25652021-12-16 13:29:28 +00003109 shell_check_oom(p->aiIndent);
drh2ce15c32017-07-11 13:34:40 +00003110 abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
drhe3e25652021-12-16 13:29:28 +00003111 shell_check_oom(abYield);
drh2ce15c32017-07-11 13:34:40 +00003112 }
3113 abYield[iOp] = str_in_array(zOp, azYield);
3114 p->aiIndent[iOp] = 0;
3115 p->nIndent = iOp+1;
3116
drhe603ab02022-04-07 19:06:31 +00003117 if( str_in_array(zOp, azNext) && p2op>0 ){
drh2ce15c32017-07-11 13:34:40 +00003118 for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
3119 }
3120 if( str_in_array(zOp, azGoto) && p2op<p->nIndent
3121 && (abYield[p2op] || sqlite3_column_int(pSql, 2))
3122 ){
3123 for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
3124 }
3125 }
3126
3127 p->iIndent = 0;
3128 sqlite3_free(abYield);
3129 sqlite3_reset(pSql);
3130}
3131
3132/*
3133** Free the array allocated by explain_data_prepare().
3134*/
3135static void explain_data_delete(ShellState *p){
3136 sqlite3_free(p->aiIndent);
3137 p->aiIndent = 0;
3138 p->nIndent = 0;
3139 p->iIndent = 0;
3140}
3141
3142/*
drh5e431be2022-04-06 11:08:38 +00003143** Disable and restore .wheretrace and .treetrace/.selecttrace settings.
drh2ce15c32017-07-11 13:34:40 +00003144*/
drhc0622a42020-12-04 01:17:57 +00003145static unsigned int savedSelectTrace;
3146static unsigned int savedWhereTrace;
drh2ce15c32017-07-11 13:34:40 +00003147static void disable_debug_trace_modes(void){
drh0a2fb792020-12-04 16:58:20 +00003148 unsigned int zero = 0;
drhc0622a42020-12-04 01:17:57 +00003149 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 0, &savedSelectTrace);
drh0a2fb792020-12-04 16:58:20 +00003150 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &zero);
drhc0622a42020-12-04 01:17:57 +00003151 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 2, &savedWhereTrace);
drh0a2fb792020-12-04 16:58:20 +00003152 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &zero);
drh2ce15c32017-07-11 13:34:40 +00003153}
3154static void restore_debug_trace_modes(void){
drhc0622a42020-12-04 01:17:57 +00003155 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &savedSelectTrace);
3156 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &savedWhereTrace);
drh2ce15c32017-07-11 13:34:40 +00003157}
3158
drh9cb02642019-02-28 20:10:52 +00003159/* Create the TEMP table used to store parameter bindings */
3160static void bind_table_init(ShellState *p){
drh346f4e22019-03-25 21:35:41 +00003161 int wrSchema = 0;
drh4b86e202020-01-19 20:37:26 +00003162 int defensiveMode = 0;
3163 sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, -1, &defensiveMode);
3164 sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
drh346f4e22019-03-25 21:35:41 +00003165 sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema);
3166 sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0);
drh9cb02642019-02-28 20:10:52 +00003167 sqlite3_exec(p->db,
drh65c29fd2019-03-25 21:56:26 +00003168 "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n"
drh9cb02642019-02-28 20:10:52 +00003169 " key TEXT PRIMARY KEY,\n"
larrybrdabada62021-04-04 12:52:58 +00003170 " value\n"
drh9cb02642019-02-28 20:10:52 +00003171 ") WITHOUT ROWID;",
3172 0, 0, 0);
drh346f4e22019-03-25 21:35:41 +00003173 sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0);
drh4b86e202020-01-19 20:37:26 +00003174 sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, defensiveMode, 0);
drh9cb02642019-02-28 20:10:52 +00003175}
3176
drh8b738d02019-02-25 18:43:54 +00003177/*
3178** Bind parameters on a prepared statement.
3179**
3180** Parameter bindings are taken from a TEMP table of the form:
3181**
drh1cb02632019-03-25 22:05:22 +00003182** CREATE TEMP TABLE sqlite_parameters(key TEXT PRIMARY KEY, value)
drh8b738d02019-02-25 18:43:54 +00003183** WITHOUT ROWID;
3184**
drh91654b22020-04-02 13:21:10 +00003185** No bindings occur if this table does not exist. The name of the table
3186** begins with "sqlite_" so that it will not collide with ordinary application
3187** tables. The table must be in the TEMP schema.
drh8b738d02019-02-25 18:43:54 +00003188*/
3189static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
3190 int nVar;
3191 int i;
3192 int rc;
3193 sqlite3_stmt *pQ = 0;
3194
3195 nVar = sqlite3_bind_parameter_count(pStmt);
3196 if( nVar==0 ) return; /* Nothing to do */
drh65c29fd2019-03-25 21:56:26 +00003197 if( sqlite3_table_column_metadata(pArg->db, "TEMP", "sqlite_parameters",
drh8b738d02019-02-25 18:43:54 +00003198 "key", 0, 0, 0, 0, 0)!=SQLITE_OK ){
3199 return; /* Parameter table does not exist */
3200 }
3201 rc = sqlite3_prepare_v2(pArg->db,
drh65c29fd2019-03-25 21:56:26 +00003202 "SELECT value FROM temp.sqlite_parameters"
drh8b738d02019-02-25 18:43:54 +00003203 " WHERE key=?1", -1, &pQ, 0);
3204 if( rc || pQ==0 ) return;
3205 for(i=1; i<=nVar; i++){
3206 char zNum[30];
3207 const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
3208 if( zVar==0 ){
3209 sqlite3_snprintf(sizeof(zNum),zNum,"?%d",i);
3210 zVar = zNum;
3211 }
3212 sqlite3_bind_text(pQ, 1, zVar, -1, SQLITE_STATIC);
3213 if( sqlite3_step(pQ)==SQLITE_ROW ){
3214 sqlite3_bind_value(pStmt, i, sqlite3_column_value(pQ, 0));
3215 }else{
3216 sqlite3_bind_null(pStmt, i);
3217 }
3218 sqlite3_reset(pQ);
3219 }
3220 sqlite3_finalize(pQ);
3221}
3222
drh30c54a02020-05-28 23:49:50 +00003223/*
drh0908e382020-06-04 18:05:39 +00003224** UTF8 box-drawing characters. Imagine box lines like this:
3225**
3226** 1
3227** |
3228** 4 --+-- 2
3229** |
3230** 3
3231**
3232** Each box characters has between 2 and 4 of the lines leading from
3233** the center. The characters are here identified by the numbers of
3234** their corresponding lines.
3235*/
3236#define BOX_24 "\342\224\200" /* U+2500 --- */
3237#define BOX_13 "\342\224\202" /* U+2502 | */
3238#define BOX_23 "\342\224\214" /* U+250c ,- */
3239#define BOX_34 "\342\224\220" /* U+2510 -, */
3240#define BOX_12 "\342\224\224" /* U+2514 '- */
3241#define BOX_14 "\342\224\230" /* U+2518 -' */
3242#define BOX_123 "\342\224\234" /* U+251c |- */
3243#define BOX_134 "\342\224\244" /* U+2524 -| */
3244#define BOX_234 "\342\224\254" /* U+252c -,- */
3245#define BOX_124 "\342\224\264" /* U+2534 -'- */
3246#define BOX_1234 "\342\224\274" /* U+253c -|- */
3247
3248/* Draw horizontal line N characters long using unicode box
3249** characters
3250*/
3251static void print_box_line(FILE *out, int N){
3252 const char zDash[] =
3253 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24
3254 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24;
3255 const int nDash = sizeof(zDash) - 1;
3256 N *= 3;
3257 while( N>nDash ){
3258 utf8_printf(out, zDash);
3259 N -= nDash;
3260 }
3261 utf8_printf(out, "%.*s", N, zDash);
3262}
3263
3264/*
3265** Draw a horizontal separator for a MODE_Box table.
3266*/
3267static void print_box_row_separator(
3268 ShellState *p,
3269 int nArg,
3270 const char *zSep1,
3271 const char *zSep2,
3272 const char *zSep3
3273){
3274 int i;
3275 if( nArg>0 ){
3276 utf8_printf(p->out, "%s", zSep1);
3277 print_box_line(p->out, p->actualWidth[0]+2);
3278 for(i=1; i<nArg; i++){
3279 utf8_printf(p->out, "%s", zSep2);
3280 print_box_line(p->out, p->actualWidth[i]+2);
3281 }
3282 utf8_printf(p->out, "%s", zSep3);
3283 }
3284 fputs("\n", p->out);
3285}
3286
drh09a39ed2022-01-30 21:09:03 +00003287/*
3288** z[] is a line of text that is to be displayed the .mode box or table or
3289** similar tabular formats. z[] might contain control characters such
3290** as \n, \t, \f, or \r.
3291**
3292** Compute characters to display on the first line of z[]. Stop at the
3293** first \r, \n, or \f. Expand \t into spaces. Return a copy (obtained
larrybrcc4d55c2022-02-01 02:50:45 +00003294** from malloc()) of that first line, which caller should free sometime.
3295** Write anything to display on the next line into *pzTail. If this is
3296** the last line, write a NULL into *pzTail. (*pzTail is not allocated.)
drh09a39ed2022-01-30 21:09:03 +00003297*/
3298static char *translateForDisplayAndDup(
drhca1776b2022-02-01 12:28:17 +00003299 const unsigned char *z, /* Input text to be transformed */
3300 const unsigned char **pzTail, /* OUT: Tail of the input for next line */
3301 int mxWidth, /* Max width. 0 means no limit */
3302 u8 bWordWrap /* If true, avoid breaking mid-word */
drh09a39ed2022-01-30 21:09:03 +00003303){
drhca1776b2022-02-01 12:28:17 +00003304 int i; /* Input bytes consumed */
3305 int j; /* Output bytes generated */
3306 int k; /* Input bytes to be displayed */
3307 int n; /* Output column number */
3308 unsigned char *zOut; /* Output text */
3309
drh09a39ed2022-01-30 21:09:03 +00003310 if( z==0 ){
3311 *pzTail = 0;
3312 return 0;
3313 }
3314 if( mxWidth<0 ) mxWidth = -mxWidth;
3315 if( mxWidth==0 ) mxWidth = 1000000;
drhca1776b2022-02-01 12:28:17 +00003316 i = j = n = 0;
drh09a39ed2022-01-30 21:09:03 +00003317 while( n<mxWidth ){
3318 if( z[i]>=' ' ){
3319 n++;
drhb6172192022-01-31 10:55:50 +00003320 do{ i++; j++; }while( (z[i]&0xc0)==0x80 );
drh09a39ed2022-01-30 21:09:03 +00003321 continue;
3322 }
3323 if( z[i]=='\t' ){
drhb6172192022-01-31 10:55:50 +00003324 do{
3325 n++;
3326 j++;
3327 }while( (n&7)!=0 && n<mxWidth );
drh09a39ed2022-01-30 21:09:03 +00003328 i++;
3329 continue;
3330 }
3331 break;
3332 }
drhca1776b2022-02-01 12:28:17 +00003333 if( n>=mxWidth && bWordWrap ){
3334 /* Perhaps try to back up to a better place to break the line */
3335 for(k=i; k>i/2; k--){
3336 if( isspace(z[k-1]) ) break;
3337 }
3338 if( k<=i/2 ){
3339 for(k=i; k>i/2; k--){
drhe66532a2022-02-01 13:17:11 +00003340 if( isalnum(z[k-1])!=isalnum(z[k]) && (z[k]&0xc0)!=0x80 ) break;
drhca1776b2022-02-01 12:28:17 +00003341 }
3342 }
3343 if( k<=i/2 ){
3344 k = i;
3345 }else{
3346 i = k;
3347 while( z[i]==' ' ) i++;
3348 }
3349 }else{
3350 k = i;
larrybrcc4d55c2022-02-01 02:50:45 +00003351 }
drh09a39ed2022-01-30 21:09:03 +00003352 if( n>=mxWidth && z[i]>=' ' ){
3353 *pzTail = &z[i];
3354 }else if( z[i]=='\r' && z[i+1]=='\n' ){
3355 *pzTail = z[i+2] ? &z[i+2] : 0;
drhb6172192022-01-31 10:55:50 +00003356 }else if( z[i]==0 || z[i+1]==0 ){
drh09a39ed2022-01-30 21:09:03 +00003357 *pzTail = 0;
3358 }else{
3359 *pzTail = &z[i+1];
3360 }
drhb6172192022-01-31 10:55:50 +00003361 zOut = malloc( j+1 );
drh09a39ed2022-01-30 21:09:03 +00003362 shell_check_oom(zOut);
drhb6172192022-01-31 10:55:50 +00003363 i = j = n = 0;
drhca1776b2022-02-01 12:28:17 +00003364 while( i<k ){
drh09a39ed2022-01-30 21:09:03 +00003365 if( z[i]>=' ' ){
drhb6172192022-01-31 10:55:50 +00003366 n++;
3367 do{ zOut[j++] = z[i++]; }while( (z[i]&0xc0)==0x80 );
drh09a39ed2022-01-30 21:09:03 +00003368 continue;
3369 }
3370 if( z[i]=='\t' ){
3371 do{
drhb6172192022-01-31 10:55:50 +00003372 n++;
3373 zOut[j++] = ' ';
drh09a39ed2022-01-30 21:09:03 +00003374 }while( (n&7)!=0 && n<mxWidth );
3375 i++;
3376 continue;
3377 }
3378 break;
3379 }
drhb6172192022-01-31 10:55:50 +00003380 zOut[j] = 0;
drh09a39ed2022-01-30 21:09:03 +00003381 return (char*)zOut;
3382}
3383
drhe40f2862022-01-31 14:14:29 +00003384/* Extract the value of the i-th current column for pStmt as an SQL literal
3385** value. Memory is obtained from sqlite3_malloc64() and must be freed by
3386** the caller.
3387*/
3388static char *quoted_column(sqlite3_stmt *pStmt, int i){
3389 switch( sqlite3_column_type(pStmt, i) ){
3390 case SQLITE_NULL: {
3391 return sqlite3_mprintf("NULL");
3392 }
3393 case SQLITE_INTEGER:
3394 case SQLITE_FLOAT: {
3395 return sqlite3_mprintf("%s",sqlite3_column_text(pStmt,i));
3396 }
3397 case SQLITE_TEXT: {
3398 return sqlite3_mprintf("%Q",sqlite3_column_text(pStmt,i));
3399 }
3400 case SQLITE_BLOB: {
3401 int j;
3402 sqlite3_str *pStr = sqlite3_str_new(0);
3403 const unsigned char *a = sqlite3_column_blob(pStmt,i);
3404 int n = sqlite3_column_bytes(pStmt,i);
3405 sqlite3_str_append(pStr, "x'", 2);
3406 for(j=0; j<n; j++){
3407 sqlite3_str_appendf(pStr, "%02x", a[j]);
3408 }
3409 sqlite3_str_append(pStr, "'", 1);
3410 return sqlite3_str_finish(pStr);
3411 }
3412 }
3413 return 0; /* Not reached */
3414}
drh0908e382020-06-04 18:05:39 +00003415
3416/*
drh30c54a02020-05-28 23:49:50 +00003417** Run a prepared statement and output the result in one of the
drh0908e382020-06-04 18:05:39 +00003418** table-oriented formats: MODE_Column, MODE_Markdown, MODE_Table,
3419** or MODE_Box.
drh30c54a02020-05-28 23:49:50 +00003420**
3421** This is different from ordinary exec_prepared_stmt() in that
3422** it has to run the entire query and gather the results into memory
3423** first, in order to determine column widths, before providing
3424** any output.
3425*/
drh8c748632020-05-29 16:15:58 +00003426static void exec_prepared_stmt_columnar(
3427 ShellState *p, /* Pointer to ShellState */
3428 sqlite3_stmt *pStmt /* Statment to run */
drh30c54a02020-05-28 23:49:50 +00003429){
drhf82ce382020-08-06 16:45:22 +00003430 sqlite3_int64 nRow = 0;
drh8c748632020-05-29 16:15:58 +00003431 int nColumn = 0;
3432 char **azData = 0;
drhf82ce382020-08-06 16:45:22 +00003433 sqlite3_int64 nAlloc = 0;
drh09a39ed2022-01-30 21:09:03 +00003434 char *abRowDiv = 0;
3435 const unsigned char *uz;
drh8c748632020-05-29 16:15:58 +00003436 const char *z;
drhe40f2862022-01-31 14:14:29 +00003437 char **azQuoted = 0;
drh8c748632020-05-29 16:15:58 +00003438 int rc;
drhf82ce382020-08-06 16:45:22 +00003439 sqlite3_int64 i, nData;
3440 int j, nTotal, w, n;
drh0908e382020-06-04 18:05:39 +00003441 const char *colSep = 0;
3442 const char *rowSep = 0;
drh09a39ed2022-01-30 21:09:03 +00003443 const unsigned char **azNextLine = 0;
3444 int bNextLine = 0;
3445 int bMultiLineRowExists = 0;
drhca1776b2022-02-01 12:28:17 +00003446 int bw = p->cmOpts.bWordWrap;
larrybr6403e772022-04-20 22:41:10 +00003447 const char *zEmpty = "";
3448 const char *zShowNull = p->nullValue;
drh30c54a02020-05-28 23:49:50 +00003449
drhf82ce382020-08-06 16:45:22 +00003450 rc = sqlite3_step(pStmt);
3451 if( rc!=SQLITE_ROW ) return;
3452 nColumn = sqlite3_column_count(pStmt);
3453 nAlloc = nColumn*4;
drh01a8ad22021-03-20 23:15:52 +00003454 if( nAlloc<=0 ) nAlloc = 1;
drhf82ce382020-08-06 16:45:22 +00003455 azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
drhe3e25652021-12-16 13:29:28 +00003456 shell_check_oom(azData);
drh09a39ed2022-01-30 21:09:03 +00003457 azNextLine = sqlite3_malloc64( nColumn*sizeof(char*) );
drh5dce6f92022-01-31 16:29:06 +00003458 shell_check_oom((void*)azNextLine);
3459 memset((void*)azNextLine, 0, nColumn*sizeof(char*) );
larrybrcc4d55c2022-02-01 02:50:45 +00003460 if( p->cmOpts.bQuote ){
drhe40f2862022-01-31 14:14:29 +00003461 azQuoted = sqlite3_malloc64( nColumn*sizeof(char*) );
3462 shell_check_oom(azQuoted);
3463 memset(azQuoted, 0, nColumn*sizeof(char*) );
3464 }
drh09a39ed2022-01-30 21:09:03 +00003465 abRowDiv = sqlite3_malloc64( nAlloc/nColumn );
3466 shell_check_oom(abRowDiv);
drh8c748632020-05-29 16:15:58 +00003467 if( nColumn>p->nWidth ){
drh76fc88f2021-10-02 16:39:16 +00003468 p->colWidth = realloc(p->colWidth, (nColumn+1)*2*sizeof(int));
drhe3e25652021-12-16 13:29:28 +00003469 shell_check_oom(p->colWidth);
drh8c748632020-05-29 16:15:58 +00003470 for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
3471 p->nWidth = nColumn;
3472 p->actualWidth = &p->colWidth[nColumn];
3473 }
3474 memset(p->actualWidth, 0, nColumn*sizeof(int));
3475 for(i=0; i<nColumn; i++){
3476 w = p->colWidth[i];
3477 if( w<0 ) w = -w;
3478 p->actualWidth[i] = w;
3479 }
drh09a39ed2022-01-30 21:09:03 +00003480 for(i=0; i<nColumn; i++){
drh47741b82022-01-31 22:14:53 +00003481 const unsigned char *zNotUsed;
3482 int wx = p->colWidth[i];
larrybrcc4d55c2022-02-01 02:50:45 +00003483 if( wx==0 ){
3484 wx = p->cmOpts.iWrap;
larrybrcc4d55c2022-02-01 02:50:45 +00003485 }
drh47741b82022-01-31 22:14:53 +00003486 if( wx<0 ) wx = -wx;
3487 uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
larrybrcc4d55c2022-02-01 02:50:45 +00003488 azData[i] = translateForDisplayAndDup(uz, &zNotUsed, wx, bw);
drh09a39ed2022-01-30 21:09:03 +00003489 }
3490 do{
3491 int useNextLine = bNextLine;
3492 bNextLine = 0;
3493 if( (nRow+2)*nColumn >= nAlloc ){
3494 nAlloc *= 2;
3495 azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
3496 shell_check_oom(azData);
3497 abRowDiv = sqlite3_realloc64(abRowDiv, nAlloc/nColumn);
3498 shell_check_oom(abRowDiv);
3499 }
3500 abRowDiv[nRow] = 1;
3501 nRow++;
3502 for(i=0; i<nColumn; i++){
drh5dce6f92022-01-31 16:29:06 +00003503 int wx = p->colWidth[i];
larrybrcc4d55c2022-02-01 02:50:45 +00003504 if( wx==0 ){
3505 wx = p->cmOpts.iWrap;
larrybrcc4d55c2022-02-01 02:50:45 +00003506 }
drh47741b82022-01-31 22:14:53 +00003507 if( wx<0 ) wx = -wx;
drh09a39ed2022-01-30 21:09:03 +00003508 if( useNextLine ){
3509 uz = azNextLine[i];
drh7e9a56f2022-04-21 19:14:23 +00003510 if( uz==0 ) uz = (u8*)zEmpty;
larrybrcc4d55c2022-02-01 02:50:45 +00003511 }else if( p->cmOpts.bQuote ){
drhe40f2862022-01-31 14:14:29 +00003512 sqlite3_free(azQuoted[i]);
3513 azQuoted[i] = quoted_column(pStmt,i);
3514 uz = (const unsigned char*)azQuoted[i];
drh09a39ed2022-01-30 21:09:03 +00003515 }else{
3516 uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
drh7e9a56f2022-04-21 19:14:23 +00003517 if( uz==0 ) uz = (u8*)zShowNull;
drh09a39ed2022-01-30 21:09:03 +00003518 }
larrybrcc4d55c2022-02-01 02:50:45 +00003519 azData[nRow*nColumn + i]
3520 = translateForDisplayAndDup(uz, &azNextLine[i], wx, bw);
drh09a39ed2022-01-30 21:09:03 +00003521 if( azNextLine[i] ){
3522 bNextLine = 1;
3523 abRowDiv[nRow-1] = 0;
3524 bMultiLineRowExists = 1;
3525 }
3526 }
3527 }while( bNextLine || sqlite3_step(pStmt)==SQLITE_ROW );
drh8c748632020-05-29 16:15:58 +00003528 nTotal = nColumn*(nRow+1);
3529 for(i=0; i<nTotal; i++){
3530 z = azData[i];
larrybr6403e772022-04-20 22:41:10 +00003531 if( z==0 ) z = (char*)zEmpty;
drh8c748632020-05-29 16:15:58 +00003532 n = strlenChar(z);
3533 j = i%nColumn;
3534 if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
3535 }
drh99942982020-06-15 20:05:37 +00003536 if( seenInterrupt ) goto columnar_end;
drh01a8ad22021-03-20 23:15:52 +00003537 if( nColumn==0 ) goto columnar_end;
drh0908e382020-06-04 18:05:39 +00003538 switch( p->cMode ){
3539 case MODE_Column: {
3540 colSep = " ";
3541 rowSep = "\n";
3542 if( p->showHeader ){
3543 for(i=0; i<nColumn; i++){
3544 w = p->actualWidth[i];
3545 if( p->colWidth[i]<0 ) w = -w;
3546 utf8_width_print(p->out, w, azData[i]);
3547 fputs(i==nColumn-1?"\n":" ", p->out);
3548 }
3549 for(i=0; i<nColumn; i++){
3550 print_dashes(p->out, p->actualWidth[i]);
3551 fputs(i==nColumn-1?"\n":" ", p->out);
3552 }
3553 }
3554 break;
3555 }
3556 case MODE_Table: {
3557 colSep = " | ";
3558 rowSep = " |\n";
3559 print_row_separator(p, nColumn, "+");
3560 fputs("| ", p->out);
drh8c748632020-05-29 16:15:58 +00003561 for(i=0; i<nColumn; i++){
3562 w = p->actualWidth[i];
drh0908e382020-06-04 18:05:39 +00003563 n = strlenChar(azData[i]);
3564 utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
3565 fputs(i==nColumn-1?" |\n":" | ", p->out);
drh8c748632020-05-29 16:15:58 +00003566 }
drh0908e382020-06-04 18:05:39 +00003567 print_row_separator(p, nColumn, "+");
3568 break;
3569 }
3570 case MODE_Markdown: {
3571 colSep = " | ";
3572 rowSep = " |\n";
3573 fputs("| ", p->out);
drh8c748632020-05-29 16:15:58 +00003574 for(i=0; i<nColumn; i++){
drh0908e382020-06-04 18:05:39 +00003575 w = p->actualWidth[i];
3576 n = strlenChar(azData[i]);
3577 utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
3578 fputs(i==nColumn-1?" |\n":" | ", p->out);
drh8c748632020-05-29 16:15:58 +00003579 }
drh0908e382020-06-04 18:05:39 +00003580 print_row_separator(p, nColumn, "|");
3581 break;
drh8c748632020-05-29 16:15:58 +00003582 }
drh0908e382020-06-04 18:05:39 +00003583 case MODE_Box: {
3584 colSep = " " BOX_13 " ";
3585 rowSep = " " BOX_13 "\n";
3586 print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
3587 utf8_printf(p->out, BOX_13 " ");
3588 for(i=0; i<nColumn; i++){
3589 w = p->actualWidth[i];
3590 n = strlenChar(azData[i]);
3591 utf8_printf(p->out, "%*s%s%*s%s",
3592 (w-n)/2, "", azData[i], (w-n+1)/2, "",
3593 i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
3594 }
3595 print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
3596 break;
drh8c748632020-05-29 16:15:58 +00003597 }
drh8c748632020-05-29 16:15:58 +00003598 }
3599 for(i=nColumn, j=0; i<nTotal; i++, j++){
drh0908e382020-06-04 18:05:39 +00003600 if( j==0 && p->cMode!=MODE_Column ){
3601 utf8_printf(p->out, "%s", p->cMode==MODE_Box?BOX_13" ":"| ");
3602 }
drh8c748632020-05-29 16:15:58 +00003603 z = azData[i];
3604 if( z==0 ) z = p->nullValue;
3605 w = p->actualWidth[j];
3606 if( p->colWidth[j]<0 ) w = -w;
3607 utf8_width_print(p->out, w, z);
3608 if( j==nColumn-1 ){
drh0908e382020-06-04 18:05:39 +00003609 utf8_printf(p->out, "%s", rowSep);
drh09a39ed2022-01-30 21:09:03 +00003610 if( bMultiLineRowExists && abRowDiv[i/nColumn-1] && i+1<nTotal ){
3611 if( p->cMode==MODE_Table ){
3612 print_row_separator(p, nColumn, "+");
3613 }else if( p->cMode==MODE_Box ){
3614 print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
drh5aabdae2022-02-01 00:00:08 +00003615 }else if( p->cMode==MODE_Column ){
3616 raw_printf(p->out, "\n");
drh09a39ed2022-01-30 21:09:03 +00003617 }
3618 }
drh8c748632020-05-29 16:15:58 +00003619 j = -1;
drhdd853c32020-06-16 17:34:40 +00003620 if( seenInterrupt ) goto columnar_end;
drh8c748632020-05-29 16:15:58 +00003621 }else{
drh0908e382020-06-04 18:05:39 +00003622 utf8_printf(p->out, "%s", colSep);
drh8c748632020-05-29 16:15:58 +00003623 }
3624 }
3625 if( p->cMode==MODE_Table ){
3626 print_row_separator(p, nColumn, "+");
drh0908e382020-06-04 18:05:39 +00003627 }else if( p->cMode==MODE_Box ){
3628 print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14);
drh8c748632020-05-29 16:15:58 +00003629 }
drh99942982020-06-15 20:05:37 +00003630columnar_end:
drhdd853c32020-06-16 17:34:40 +00003631 if( seenInterrupt ){
3632 utf8_printf(p->out, "Interrupt\n");
3633 }
drhf82ce382020-08-06 16:45:22 +00003634 nData = (nRow+1)*nColumn;
larrybr6403e772022-04-20 22:41:10 +00003635 for(i=0; i<nData; i++){
3636 z = azData[i];
drh744c17c2022-05-05 10:02:19 +00003637 if( z!=zEmpty && z!=zShowNull ) free(azData[i]);
larrybr6403e772022-04-20 22:41:10 +00003638 }
drhf82ce382020-08-06 16:45:22 +00003639 sqlite3_free(azData);
drh5dce6f92022-01-31 16:29:06 +00003640 sqlite3_free((void*)azNextLine);
drh09a39ed2022-01-30 21:09:03 +00003641 sqlite3_free(abRowDiv);
drhe40f2862022-01-31 14:14:29 +00003642 if( azQuoted ){
3643 for(i=0; i<nColumn; i++) sqlite3_free(azQuoted[i]);
3644 sqlite3_free(azQuoted);
3645 }
drh30c54a02020-05-28 23:49:50 +00003646}
drh30c54a02020-05-28 23:49:50 +00003647
drh2ce15c32017-07-11 13:34:40 +00003648/*
3649** Run a prepared statement
3650*/
3651static void exec_prepared_stmt(
3652 ShellState *pArg, /* Pointer to ShellState */
drha10b9992018-03-09 15:24:33 +00003653 sqlite3_stmt *pStmt /* Statment to run */
drh2ce15c32017-07-11 13:34:40 +00003654){
3655 int rc;
drh5d88be82021-12-09 16:17:43 +00003656 sqlite3_uint64 nRow = 0;
drh2ce15c32017-07-11 13:34:40 +00003657
drh8c748632020-05-29 16:15:58 +00003658 if( pArg->cMode==MODE_Column
3659 || pArg->cMode==MODE_Table
drh0908e382020-06-04 18:05:39 +00003660 || pArg->cMode==MODE_Box
drh8c748632020-05-29 16:15:58 +00003661 || pArg->cMode==MODE_Markdown
3662 ){
3663 exec_prepared_stmt_columnar(pArg, pStmt);
3664 return;
3665 }
3666
drh2ce15c32017-07-11 13:34:40 +00003667 /* perform the first step. this will tell us if we
3668 ** have a result set or not and how wide it is.
3669 */
3670 rc = sqlite3_step(pStmt);
3671 /* if we have a result set... */
3672 if( SQLITE_ROW == rc ){
drha10b9992018-03-09 15:24:33 +00003673 /* allocate space for col name ptr, value ptr, and type */
3674 int nCol = sqlite3_column_count(pStmt);
3675 void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
3676 if( !pData ){
drhe85e1da2021-10-01 21:01:07 +00003677 shell_out_of_memory();
drh2ce15c32017-07-11 13:34:40 +00003678 }else{
drha10b9992018-03-09 15:24:33 +00003679 char **azCols = (char **)pData; /* Names of result columns */
3680 char **azVals = &azCols[nCol]; /* Results */
3681 int *aiTypes = (int *)&azVals[nCol]; /* Result types */
3682 int i, x;
3683 assert(sizeof(int) <= sizeof(char *));
3684 /* save off ptrs to column names */
3685 for(i=0; i<nCol; i++){
3686 azCols[i] = (char *)sqlite3_column_name(pStmt, i);
3687 }
drh2ce15c32017-07-11 13:34:40 +00003688 do{
drh5d88be82021-12-09 16:17:43 +00003689 nRow++;
drha10b9992018-03-09 15:24:33 +00003690 /* extract the data and data types */
3691 for(i=0; i<nCol; i++){
3692 aiTypes[i] = x = sqlite3_column_type(pStmt, i);
drh5d1bf4f2022-01-02 20:54:33 +00003693 if( x==SQLITE_BLOB
3694 && pArg
3695 && (pArg->cMode==MODE_Insert || pArg->cMode==MODE_Quote)
3696 ){
drha10b9992018-03-09 15:24:33 +00003697 azVals[i] = "";
3698 }else{
3699 azVals[i] = (char*)sqlite3_column_text(pStmt, i);
3700 }
3701 if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
3702 rc = SQLITE_NOMEM;
3703 break; /* from for */
3704 }
3705 } /* end for */
3706
3707 /* if data and types extracted successfully... */
3708 if( SQLITE_ROW == rc ){
3709 /* call the supplied callback with the result row data */
3710 if( shell_callback(pArg, nCol, azVals, azCols, aiTypes) ){
3711 rc = SQLITE_ABORT;
3712 }else{
3713 rc = sqlite3_step(pStmt);
3714 }
3715 }
3716 } while( SQLITE_ROW == rc );
3717 sqlite3_free(pData);
drh0908e382020-06-04 18:05:39 +00003718 if( pArg->cMode==MODE_Json ){
drh30c54a02020-05-28 23:49:50 +00003719 fputs("]\n", pArg->out);
drh5d88be82021-12-09 16:17:43 +00003720 }else if( pArg->cMode==MODE_Count ){
mistachkinc158c072021-12-31 19:08:20 +00003721 char zBuf[200];
3722 sqlite3_snprintf(sizeof(zBuf), zBuf, "%llu row%s\n",
3723 nRow, nRow!=1 ? "s" : "");
3724 printf("%s", zBuf);
drh30c54a02020-05-28 23:49:50 +00003725 }
drh2ce15c32017-07-11 13:34:40 +00003726 }
3727 }
3728}
3729
dan6b046be2018-01-09 15:25:55 +00003730#ifndef SQLITE_OMIT_VIRTUALTABLE
drh2ce15c32017-07-11 13:34:40 +00003731/*
dan43efc182017-12-19 17:42:13 +00003732** This function is called to process SQL if the previous shell command
3733** was ".expert". It passes the SQL in the second argument directly to
3734** the sqlite3expert object.
3735**
3736** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
3737** code. In this case, (*pzErr) may be set to point to a buffer containing
3738** an English language error message. It is the responsibility of the
3739** caller to eventually free this buffer using sqlite3_free().
3740*/
3741static int expertHandleSQL(
3742 ShellState *pState,
3743 const char *zSql,
3744 char **pzErr
3745){
3746 assert( pState->expert.pExpert );
3747 assert( pzErr==0 || *pzErr==0 );
3748 return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr);
3749}
3750
3751/*
3752** This function is called either to silently clean up the object
3753** created by the ".expert" command (if bCancel==1), or to generate a
3754** report from it and then clean it up (if bCancel==0).
3755**
3756** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
3757** code. In this case, (*pzErr) may be set to point to a buffer containing
3758** an English language error message. It is the responsibility of the
3759** caller to eventually free this buffer using sqlite3_free().
3760*/
3761static int expertFinish(
3762 ShellState *pState,
3763 int bCancel,
3764 char **pzErr
3765){
3766 int rc = SQLITE_OK;
3767 sqlite3expert *p = pState->expert.pExpert;
3768 assert( p );
3769 assert( bCancel || pzErr==0 || *pzErr==0 );
3770 if( bCancel==0 ){
3771 FILE *out = pState->out;
3772 int bVerbose = pState->expert.bVerbose;
3773
3774 rc = sqlite3_expert_analyze(p, pzErr);
3775 if( rc==SQLITE_OK ){
3776 int nQuery = sqlite3_expert_count(p);
3777 int i;
3778
3779 if( bVerbose ){
3780 const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
3781 raw_printf(out, "-- Candidates -----------------------------\n");
3782 raw_printf(out, "%s\n", zCand);
3783 }
3784 for(i=0; i<nQuery; i++){
3785 const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
3786 const char *zIdx = sqlite3_expert_report(p, i, EXPERT_REPORT_INDEXES);
3787 const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
3788 if( zIdx==0 ) zIdx = "(no new indexes)\n";
3789 if( bVerbose ){
3790 raw_printf(out, "-- Query %d --------------------------------\n",i+1);
3791 raw_printf(out, "%s\n\n", zSql);
3792 }
3793 raw_printf(out, "%s\n", zIdx);
3794 raw_printf(out, "%s\n", zEQP);
3795 }
3796 }
3797 }
3798 sqlite3_expert_destroy(p);
3799 pState->expert.pExpert = 0;
3800 return rc;
3801}
3802
dan6b046be2018-01-09 15:25:55 +00003803/*
3804** Implementation of ".expert" dot command.
3805*/
3806static int expertDotCommand(
3807 ShellState *pState, /* Current shell tool state */
3808 char **azArg, /* Array of arguments passed to dot command */
3809 int nArg /* Number of entries in azArg[] */
3810){
3811 int rc = SQLITE_OK;
3812 char *zErr = 0;
3813 int i;
3814 int iSample = 0;
3815
3816 assert( pState->expert.pExpert==0 );
3817 memset(&pState->expert, 0, sizeof(ExpertInfo));
3818
3819 for(i=1; rc==SQLITE_OK && i<nArg; i++){
3820 char *z = azArg[i];
3821 int n;
3822 if( z[0]=='-' && z[1]=='-' ) z++;
3823 n = strlen30(z);
drhbf70f1b2022-10-19 18:04:42 +00003824 if( n>=2 && 0==cli_strncmp(z, "-verbose", n) ){
dan6b046be2018-01-09 15:25:55 +00003825 pState->expert.bVerbose = 1;
3826 }
drhbf70f1b2022-10-19 18:04:42 +00003827 else if( n>=2 && 0==cli_strncmp(z, "-sample", n) ){
dan6b046be2018-01-09 15:25:55 +00003828 if( i==(nArg-1) ){
3829 raw_printf(stderr, "option requires an argument: %s\n", z);
3830 rc = SQLITE_ERROR;
3831 }else{
3832 iSample = (int)integerValue(azArg[++i]);
3833 if( iSample<0 || iSample>100 ){
3834 raw_printf(stderr, "value out of range: %s\n", azArg[i]);
3835 rc = SQLITE_ERROR;
3836 }
3837 }
3838 }
3839 else{
3840 raw_printf(stderr, "unknown option: %s\n", z);
3841 rc = SQLITE_ERROR;
3842 }
3843 }
3844
3845 if( rc==SQLITE_OK ){
3846 pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
3847 if( pState->expert.pExpert==0 ){
drhe0adf602021-12-16 14:26:16 +00003848 raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory");
dan6b046be2018-01-09 15:25:55 +00003849 rc = SQLITE_ERROR;
3850 }else{
3851 sqlite3_expert_config(
3852 pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
3853 );
3854 }
3855 }
drhe0adf602021-12-16 14:26:16 +00003856 sqlite3_free(zErr);
dan6b046be2018-01-09 15:25:55 +00003857
3858 return rc;
3859}
3860#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
dan43efc182017-12-19 17:42:13 +00003861
3862/*
drh2ce15c32017-07-11 13:34:40 +00003863** Execute a statement or set of statements. Print
3864** any result rows/columns depending on the current mode
3865** set via the supplied callback.
3866**
3867** This is very similar to SQLite's built-in sqlite3_exec()
3868** function except it takes a slightly different callback
3869** and callback data argument.
3870*/
3871static int shell_exec(
drh2ce15c32017-07-11 13:34:40 +00003872 ShellState *pArg, /* Pointer to ShellState */
drha10b9992018-03-09 15:24:33 +00003873 const char *zSql, /* SQL to be evaluated */
drh2ce15c32017-07-11 13:34:40 +00003874 char **pzErrMsg /* Error msg written here */
3875){
3876 sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
3877 int rc = SQLITE_OK; /* Return Code */
3878 int rc2;
3879 const char *zLeftover; /* Tail of unprocessed SQL */
drha10b9992018-03-09 15:24:33 +00003880 sqlite3 *db = pArg->db;
drh2ce15c32017-07-11 13:34:40 +00003881
3882 if( pzErrMsg ){
3883 *pzErrMsg = NULL;
3884 }
3885
dan6b046be2018-01-09 15:25:55 +00003886#ifndef SQLITE_OMIT_VIRTUALTABLE
dan43efc182017-12-19 17:42:13 +00003887 if( pArg->expert.pExpert ){
3888 rc = expertHandleSQL(pArg, zSql, pzErrMsg);
3889 return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg);
3890 }
dan6b046be2018-01-09 15:25:55 +00003891#endif
dan43efc182017-12-19 17:42:13 +00003892
drh2ce15c32017-07-11 13:34:40 +00003893 while( zSql[0] && (SQLITE_OK == rc) ){
3894 static const char *zStmtSql;
3895 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
3896 if( SQLITE_OK != rc ){
3897 if( pzErrMsg ){
drh633c7982022-02-08 12:13:16 +00003898 *pzErrMsg = save_err_msg(db, "in prepare", rc, zSql);
drh2ce15c32017-07-11 13:34:40 +00003899 }
3900 }else{
3901 if( !pStmt ){
3902 /* this happens for a comment or white-space */
3903 zSql = zLeftover;
3904 while( IsSpace(zSql[0]) ) zSql++;
3905 continue;
3906 }
3907 zStmtSql = sqlite3_sql(pStmt);
3908 if( zStmtSql==0 ) zStmtSql = "";
3909 while( IsSpace(zStmtSql[0]) ) zStmtSql++;
3910
3911 /* save off the prepared statment handle and reset row count */
3912 if( pArg ){
3913 pArg->pStmt = pStmt;
3914 pArg->cnt = 0;
3915 }
3916
drh2ce15c32017-07-11 13:34:40 +00003917 /* Show the EXPLAIN QUERY PLAN if .eqp is on */
drh39c5c4a2019-03-06 14:53:27 +00003918 if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){
drh2ce15c32017-07-11 13:34:40 +00003919 sqlite3_stmt *pExplain;
3920 char *zEQP;
drhada70452017-12-21 21:02:27 +00003921 int triggerEQP = 0;
drh2ce15c32017-07-11 13:34:40 +00003922 disable_debug_trace_modes();
drhada70452017-12-21 21:02:27 +00003923 sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP);
3924 if( pArg->autoEQP>=AUTOEQP_trigger ){
3925 sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0);
3926 }
drh2ce15c32017-07-11 13:34:40 +00003927 zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
drhe3e25652021-12-16 13:29:28 +00003928 shell_check_oom(zEQP);
drh2ce15c32017-07-11 13:34:40 +00003929 rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
3930 if( rc==SQLITE_OK ){
3931 while( sqlite3_step(pExplain)==SQLITE_ROW ){
drh4b5345c2018-04-24 13:07:40 +00003932 const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3);
drhe2ca99c2018-05-02 00:33:43 +00003933 int iEqpId = sqlite3_column_int(pExplain, 0);
3934 int iParentId = sqlite3_column_int(pExplain, 1);
drh7e088a62020-05-02 00:01:39 +00003935 if( zEQPLine==0 ) zEQPLine = "";
drh4b5345c2018-04-24 13:07:40 +00003936 if( zEQPLine[0]=='-' ) eqp_render(pArg);
drhe2ca99c2018-05-02 00:33:43 +00003937 eqp_append(pArg, iEqpId, iParentId, zEQPLine);
drh2ce15c32017-07-11 13:34:40 +00003938 }
drh4b5345c2018-04-24 13:07:40 +00003939 eqp_render(pArg);
drh2ce15c32017-07-11 13:34:40 +00003940 }
3941 sqlite3_finalize(pExplain);
3942 sqlite3_free(zEQP);
drhada70452017-12-21 21:02:27 +00003943 if( pArg->autoEQP>=AUTOEQP_full ){
drh2ce15c32017-07-11 13:34:40 +00003944 /* Also do an EXPLAIN for ".eqp full" mode */
3945 zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
drhe3e25652021-12-16 13:29:28 +00003946 shell_check_oom(zEQP);
drh2ce15c32017-07-11 13:34:40 +00003947 rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
3948 if( rc==SQLITE_OK ){
3949 pArg->cMode = MODE_Explain;
3950 explain_data_prepare(pArg, pExplain);
drha10b9992018-03-09 15:24:33 +00003951 exec_prepared_stmt(pArg, pExplain);
drh2ce15c32017-07-11 13:34:40 +00003952 explain_data_delete(pArg);
3953 }
3954 sqlite3_finalize(pExplain);
3955 sqlite3_free(zEQP);
3956 }
drh51efe092018-03-20 12:04:38 +00003957 if( pArg->autoEQP>=AUTOEQP_trigger && triggerEQP==0 ){
3958 sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 0, 0);
3959 /* Reprepare pStmt before reactiving trace modes */
3960 sqlite3_finalize(pStmt);
3961 sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
drh3c49eaf2018-06-07 15:23:43 +00003962 if( pArg ) pArg->pStmt = pStmt;
drh51efe092018-03-20 12:04:38 +00003963 }
drh2ce15c32017-07-11 13:34:40 +00003964 restore_debug_trace_modes();
3965 }
3966
3967 if( pArg ){
3968 pArg->cMode = pArg->mode;
drh4b5345c2018-04-24 13:07:40 +00003969 if( pArg->autoExplain ){
drh39c5c4a2019-03-06 14:53:27 +00003970 if( sqlite3_stmt_isexplain(pStmt)==1 ){
drh4b5345c2018-04-24 13:07:40 +00003971 pArg->cMode = MODE_Explain;
3972 }
drh39c5c4a2019-03-06 14:53:27 +00003973 if( sqlite3_stmt_isexplain(pStmt)==2 ){
drh4b5345c2018-04-24 13:07:40 +00003974 pArg->cMode = MODE_EQP;
3975 }
drh2ce15c32017-07-11 13:34:40 +00003976 }
3977
3978 /* If the shell is currently in ".explain" mode, gather the extra
3979 ** data required to add indents to the output.*/
3980 if( pArg->cMode==MODE_Explain ){
3981 explain_data_prepare(pArg, pStmt);
3982 }
3983 }
3984
drh8b738d02019-02-25 18:43:54 +00003985 bind_prepared_stmt(pArg, pStmt);
drha10b9992018-03-09 15:24:33 +00003986 exec_prepared_stmt(pArg, pStmt);
drh2ce15c32017-07-11 13:34:40 +00003987 explain_data_delete(pArg);
drh4b5345c2018-04-24 13:07:40 +00003988 eqp_render(pArg);
drh2ce15c32017-07-11 13:34:40 +00003989
3990 /* print usage stats if stats on */
3991 if( pArg && pArg->statsOn ){
3992 display_stats(db, pArg, 0);
3993 }
3994
3995 /* print loop-counters if required */
3996 if( pArg && pArg->scanstatsOn ){
3997 display_scanstats(db, pArg);
3998 }
3999
4000 /* Finalize the statement just executed. If this fails, save a
4001 ** copy of the error message. Otherwise, set zSql to point to the
4002 ** next statement to execute. */
4003 rc2 = sqlite3_finalize(pStmt);
4004 if( rc!=SQLITE_NOMEM ) rc = rc2;
4005 if( rc==SQLITE_OK ){
4006 zSql = zLeftover;
4007 while( IsSpace(zSql[0]) ) zSql++;
4008 }else if( pzErrMsg ){
drh633c7982022-02-08 12:13:16 +00004009 *pzErrMsg = save_err_msg(db, "stepping", rc, 0);
drh2ce15c32017-07-11 13:34:40 +00004010 }
4011
4012 /* clear saved stmt handle */
4013 if( pArg ){
4014 pArg->pStmt = NULL;
4015 }
4016 }
4017 } /* end while */
4018
4019 return rc;
4020}
4021
4022/*
4023** Release memory previously allocated by tableColumnList().
4024*/
4025static void freeColumnList(char **azCol){
4026 int i;
4027 for(i=1; azCol[i]; i++){
4028 sqlite3_free(azCol[i]);
4029 }
4030 /* azCol[0] is a static string */
4031 sqlite3_free(azCol);
4032}
4033
4034/*
4035** Return a list of pointers to strings which are the names of all
4036** columns in table zTab. The memory to hold the names is dynamically
4037** allocated and must be released by the caller using a subsequent call
4038** to freeColumnList().
4039**
4040** The azCol[0] entry is usually NULL. However, if zTab contains a rowid
4041** value that needs to be preserved, then azCol[0] is filled in with the
4042** name of the rowid column.
4043**
4044** The first regular column in the table is azCol[1]. The list is terminated
4045** by an entry with azCol[i]==0.
4046*/
4047static char **tableColumnList(ShellState *p, const char *zTab){
4048 char **azCol = 0;
4049 sqlite3_stmt *pStmt;
4050 char *zSql;
4051 int nCol = 0;
4052 int nAlloc = 0;
4053 int nPK = 0; /* Number of PRIMARY KEY columns seen */
4054 int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */
4055 int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid);
4056 int rc;
4057
4058 zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
drhe3e25652021-12-16 13:29:28 +00004059 shell_check_oom(zSql);
drh2ce15c32017-07-11 13:34:40 +00004060 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
4061 sqlite3_free(zSql);
4062 if( rc ) return 0;
4063 while( sqlite3_step(pStmt)==SQLITE_ROW ){
4064 if( nCol>=nAlloc-2 ){
4065 nAlloc = nAlloc*2 + nCol + 10;
4066 azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
drhe3e25652021-12-16 13:29:28 +00004067 shell_check_oom(azCol);
drh2ce15c32017-07-11 13:34:40 +00004068 }
4069 azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
drhe3e25652021-12-16 13:29:28 +00004070 shell_check_oom(azCol[nCol]);
drh2ce15c32017-07-11 13:34:40 +00004071 if( sqlite3_column_int(pStmt, 5) ){
4072 nPK++;
4073 if( nPK==1
4074 && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2),
4075 "INTEGER")==0
4076 ){
4077 isIPK = 1;
4078 }else{
4079 isIPK = 0;
4080 }
4081 }
4082 }
4083 sqlite3_finalize(pStmt);
drh4c6cddc2017-10-12 10:28:30 +00004084 if( azCol==0 ) return 0;
drh2ce15c32017-07-11 13:34:40 +00004085 azCol[0] = 0;
4086 azCol[nCol+1] = 0;
4087
4088 /* The decision of whether or not a rowid really needs to be preserved
4089 ** is tricky. We never need to preserve a rowid for a WITHOUT ROWID table
4090 ** or a table with an INTEGER PRIMARY KEY. We are unable to preserve
4091 ** rowids on tables where the rowid is inaccessible because there are other
4092 ** columns in the table named "rowid", "_rowid_", and "oid".
4093 */
4094 if( preserveRowid && isIPK ){
4095 /* If a single PRIMARY KEY column with type INTEGER was seen, then it
4096 ** might be an alise for the ROWID. But it might also be a WITHOUT ROWID
4097 ** table or a INTEGER PRIMARY KEY DESC column, neither of which are
4098 ** ROWID aliases. To distinguish these cases, check to see if
4099 ** there is a "pk" entry in "PRAGMA index_list". There will be
4100 ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID.
4101 */
4102 zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
4103 " WHERE origin='pk'", zTab);
drhe3e25652021-12-16 13:29:28 +00004104 shell_check_oom(zSql);
drh2ce15c32017-07-11 13:34:40 +00004105 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
4106 sqlite3_free(zSql);
4107 if( rc ){
4108 freeColumnList(azCol);
4109 return 0;
4110 }
4111 rc = sqlite3_step(pStmt);
4112 sqlite3_finalize(pStmt);
4113 preserveRowid = rc==SQLITE_ROW;
4114 }
4115 if( preserveRowid ){
4116 /* Only preserve the rowid if we can find a name to use for the
4117 ** rowid */
4118 static char *azRowid[] = { "rowid", "_rowid_", "oid" };
4119 int i, j;
4120 for(j=0; j<3; j++){
4121 for(i=1; i<=nCol; i++){
4122 if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break;
4123 }
4124 if( i>nCol ){
4125 /* At this point, we know that azRowid[j] is not the name of any
4126 ** ordinary column in the table. Verify that azRowid[j] is a valid
4127 ** name for the rowid before adding it to azCol[0]. WITHOUT ROWID
4128 ** tables will fail this last check */
4129 rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
4130 if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
4131 break;
4132 }
4133 }
4134 }
4135 return azCol;
4136}
4137
4138/*
4139** Toggle the reverse_unordered_selects setting.
4140*/
4141static void toggleSelectOrder(sqlite3 *db){
4142 sqlite3_stmt *pStmt = 0;
4143 int iSetting = 0;
4144 char zStmt[100];
4145 sqlite3_prepare_v2(db, "PRAGMA reverse_unordered_selects", -1, &pStmt, 0);
4146 if( sqlite3_step(pStmt)==SQLITE_ROW ){
4147 iSetting = sqlite3_column_int(pStmt, 0);
4148 }
4149 sqlite3_finalize(pStmt);
4150 sqlite3_snprintf(sizeof(zStmt), zStmt,
4151 "PRAGMA reverse_unordered_selects(%d)", !iSetting);
4152 sqlite3_exec(db, zStmt, 0, 0, 0);
4153}
4154
4155/*
4156** This is a different callback routine used for dumping the database.
4157** Each row received by this callback consists of a table name,
4158** the table type ("index" or "table") and SQL to create the table.
4159** This routine should print text sufficient to recreate the table.
4160*/
4161static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
4162 int rc;
4163 const char *zTable;
4164 const char *zType;
4165 const char *zSql;
4166 ShellState *p = (ShellState *)pArg;
mistachkina00a0162020-10-18 18:35:34 +00004167 int dataOnly;
4168 int noSys;
drh2ce15c32017-07-11 13:34:40 +00004169
4170 UNUSED_PARAMETER(azNotUsed);
drhb3c45232017-08-28 14:33:27 +00004171 if( nArg!=3 || azArg==0 ) return 0;
drh2ce15c32017-07-11 13:34:40 +00004172 zTable = azArg[0];
4173 zType = azArg[1];
4174 zSql = azArg[2];
drhd5ca2c42022-10-25 13:42:10 +00004175 if( zTable==0 ) return 0;
4176 if( zType==0 ) return 0;
mistachkina00a0162020-10-18 18:35:34 +00004177 dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0;
4178 noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
drh2ce15c32017-07-11 13:34:40 +00004179
drhbf70f1b2022-10-19 18:04:42 +00004180 if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
drhc1962192020-10-12 16:54:28 +00004181 if( !dataOnly ) raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
4182 }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
4183 if( !dataOnly ) raw_printf(p->out, "ANALYZE sqlite_schema;\n");
drhbf70f1b2022-10-19 18:04:42 +00004184 }else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){
drh2ce15c32017-07-11 13:34:40 +00004185 return 0;
drhc1962192020-10-12 16:54:28 +00004186 }else if( dataOnly ){
4187 /* no-op */
drhbf70f1b2022-10-19 18:04:42 +00004188 }else if( cli_strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
drh2ce15c32017-07-11 13:34:40 +00004189 char *zIns;
4190 if( !p->writableSchema ){
4191 raw_printf(p->out, "PRAGMA writable_schema=ON;\n");
4192 p->writableSchema = 1;
4193 }
4194 zIns = sqlite3_mprintf(
drh067b92b2020-06-19 15:24:12 +00004195 "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
drh2ce15c32017-07-11 13:34:40 +00004196 "VALUES('table','%q','%q',0,'%q');",
4197 zTable, zTable, zSql);
drhe3e25652021-12-16 13:29:28 +00004198 shell_check_oom(zIns);
drh2ce15c32017-07-11 13:34:40 +00004199 utf8_printf(p->out, "%s\n", zIns);
4200 sqlite3_free(zIns);
4201 return 0;
4202 }else{
4203 printSchemaLine(p->out, zSql, ";\n");
4204 }
4205
drhbf70f1b2022-10-19 18:04:42 +00004206 if( cli_strcmp(zType, "table")==0 ){
drh2ce15c32017-07-11 13:34:40 +00004207 ShellText sSelect;
4208 ShellText sTable;
4209 char **azCol;
4210 int i;
4211 char *savedDestTable;
4212 int savedMode;
4213
4214 azCol = tableColumnList(p, zTable);
4215 if( azCol==0 ){
4216 p->nErr++;
4217 return 0;
4218 }
4219
4220 /* Always quote the table name, even if it appears to be pure ascii,
4221 ** in case it is a keyword. Ex: INSERT INTO "table" ... */
4222 initText(&sTable);
4223 appendText(&sTable, zTable, quoteChar(zTable));
4224 /* If preserving the rowid, add a column list after the table name.
4225 ** In other words: "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
4226 ** instead of the usual "INSERT INTO tab VALUES(...)".
4227 */
4228 if( azCol[0] ){
4229 appendText(&sTable, "(", 0);
4230 appendText(&sTable, azCol[0], 0);
4231 for(i=1; azCol[i]; i++){
4232 appendText(&sTable, ",", 0);
4233 appendText(&sTable, azCol[i], quoteChar(azCol[i]));
4234 }
4235 appendText(&sTable, ")", 0);
4236 }
4237
4238 /* Build an appropriate SELECT statement */
4239 initText(&sSelect);
4240 appendText(&sSelect, "SELECT ", 0);
4241 if( azCol[0] ){
4242 appendText(&sSelect, azCol[0], 0);
4243 appendText(&sSelect, ",", 0);
4244 }
4245 for(i=1; azCol[i]; i++){
4246 appendText(&sSelect, azCol[i], quoteChar(azCol[i]));
4247 if( azCol[i+1] ){
4248 appendText(&sSelect, ",", 0);
4249 }
4250 }
4251 freeColumnList(azCol);
4252 appendText(&sSelect, " FROM ", 0);
4253 appendText(&sSelect, zTable, quoteChar(zTable));
4254
4255 savedDestTable = p->zDestTable;
4256 savedMode = p->mode;
4257 p->zDestTable = sTable.z;
4258 p->mode = p->cMode = MODE_Insert;
drha10b9992018-03-09 15:24:33 +00004259 rc = shell_exec(p, sSelect.z, 0);
drh2ce15c32017-07-11 13:34:40 +00004260 if( (rc&0xff)==SQLITE_CORRUPT ){
4261 raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
4262 toggleSelectOrder(p->db);
drha10b9992018-03-09 15:24:33 +00004263 shell_exec(p, sSelect.z, 0);
drh2ce15c32017-07-11 13:34:40 +00004264 toggleSelectOrder(p->db);
4265 }
4266 p->zDestTable = savedDestTable;
4267 p->mode = savedMode;
4268 freeText(&sTable);
4269 freeText(&sSelect);
4270 if( rc ) p->nErr++;
4271 }
4272 return 0;
4273}
4274
4275/*
4276** Run zQuery. Use dump_callback() as the callback routine so that
4277** the contents of the query are output as SQL statements.
4278**
4279** If we get a SQLITE_CORRUPT error, rerun the query after appending
4280** "ORDER BY rowid DESC" to the end.
4281*/
4282static int run_schema_dump_query(
4283 ShellState *p,
4284 const char *zQuery
4285){
4286 int rc;
4287 char *zErr = 0;
4288 rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
4289 if( rc==SQLITE_CORRUPT ){
4290 char *zQ2;
4291 int len = strlen30(zQuery);
4292 raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
4293 if( zErr ){
4294 utf8_printf(p->out, "/****** %s ******/\n", zErr);
4295 sqlite3_free(zErr);
4296 zErr = 0;
4297 }
4298 zQ2 = malloc( len+100 );
4299 if( zQ2==0 ) return rc;
4300 sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
4301 rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
4302 if( rc ){
4303 utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr);
4304 }else{
4305 rc = SQLITE_CORRUPT;
4306 }
4307 sqlite3_free(zErr);
4308 free(zQ2);
4309 }
4310 return rc;
4311}
4312
4313/*
drh98aa2ab2018-09-26 16:53:51 +00004314** Text of help messages.
4315**
4316** The help text for each individual command begins with a line that starts
stephan02520cc2022-05-18 22:58:34 +00004317** with ".". Subsequent lines are supplemental information.
drh98aa2ab2018-09-26 16:53:51 +00004318**
4319** There must be two or more spaces between the end of the command and the
4320** start of the description of what that command does.
drh2ce15c32017-07-11 13:34:40 +00004321*/
drh98aa2ab2018-09-26 16:53:51 +00004322static const char *(azHelp[]) = {
stephan02520cc2022-05-18 22:58:34 +00004323#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) \
stephan4413ec72022-07-12 15:53:02 +00004324 && !defined(SQLITE_SHELL_FIDDLE)
drh98aa2ab2018-09-26 16:53:51 +00004325 ".archive ... Manage SQL archives",
4326 " Each command must have exactly one of the following options:",
4327 " -c, --create Create a new archive",
drhe2754c12019-08-26 12:50:01 +00004328 " -u, --update Add or update files with changed mtime",
4329 " -i, --insert Like -u but always add even if unchanged",
larrybr47061b92021-11-01 17:22:52 +00004330 " -r, --remove Remove files from archive",
drh98aa2ab2018-09-26 16:53:51 +00004331 " -t, --list List contents of archive",
4332 " -x, --extract Extract files from archive",
4333 " Optional arguments:",
4334 " -v, --verbose Print each filename as it is processed",
drhe2754c12019-08-26 12:50:01 +00004335 " -f FILE, --file FILE Use archive FILE (default is current db)",
4336 " -a FILE, --append FILE Open FILE using the apndvfs VFS",
4337 " -C DIR, --directory DIR Read/extract files from directory DIR",
larrybr8f09f4b2021-11-02 00:18:11 +00004338 " -g, --glob Use glob matching for names in archive",
drh98aa2ab2018-09-26 16:53:51 +00004339 " -n, --dryrun Show the SQL that would have occurred",
4340 " Examples:",
drhe2754c12019-08-26 12:50:01 +00004341 " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar",
4342 " .ar -tf ARCHIVE # List members of ARCHIVE",
4343 " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE",
drh98aa2ab2018-09-26 16:53:51 +00004344 " See also:",
larrybrbd0d62c2021-06-13 08:23:28 +00004345 " http://sqlite.org/cli.html#sqlite_archive_support",
drhe37c0e12018-01-06 19:19:50 +00004346#endif
drh2ce15c32017-07-11 13:34:40 +00004347#ifndef SQLITE_OMIT_AUTHORIZATION
drh98aa2ab2018-09-26 16:53:51 +00004348 ".auth ON|OFF Show authorizer callbacks",
drh2ce15c32017-07-11 13:34:40 +00004349#endif
stephan4413ec72022-07-12 15:53:02 +00004350#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004351 ".backup ?DB? FILE Backup DB (default \"main\") to FILE",
larrybra7919ad2022-02-19 21:25:48 +00004352 " Options:",
drh98aa2ab2018-09-26 16:53:51 +00004353 " --append Use the appendvfs",
drhe2754c12019-08-26 12:50:01 +00004354 " --async Write to FILE without journal and fsync()",
stephan02520cc2022-05-18 22:58:34 +00004355#endif
drh98aa2ab2018-09-26 16:53:51 +00004356 ".bail on|off Stop after hitting an error. Default OFF",
4357 ".binary on|off Turn binary output on or off. Default OFF",
stephan4413ec72022-07-12 15:53:02 +00004358#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004359 ".cd DIRECTORY Change the working directory to DIRECTORY",
stephan1c0dcec2022-05-19 21:56:50 +00004360#endif
drh98aa2ab2018-09-26 16:53:51 +00004361 ".changes on|off Show number of rows changed by SQL",
stephan4413ec72022-07-12 15:53:02 +00004362#ifndef SQLITE_SHELL_FIDDLE
stephane26d1622022-05-19 22:04:23 +00004363 ".check GLOB Fail if output since .testcase does not match",
drh98aa2ab2018-09-26 16:53:51 +00004364 ".clone NEWDB Clone data into NEWDB from the existing database",
stephan1c0dcec2022-05-19 21:56:50 +00004365#endif
drh37407122021-07-23 18:43:58 +00004366 ".connection [close] [#] Open or close an auxiliary database connection",
drh98aa2ab2018-09-26 16:53:51 +00004367 ".databases List names and files of attached databases",
4368 ".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
stephan3d420832022-10-27 03:56:01 +00004369#if SQLITE_SHELL_HAVE_RECOVER
drh98aa2ab2018-09-26 16:53:51 +00004370 ".dbinfo ?DB? Show status information about the database",
larrybrf3d6e8f2022-06-05 22:58:40 +00004371#endif
larrybr7bdbe592021-03-15 12:56:00 +00004372 ".dump ?OBJECTS? Render database content as SQL",
drheb7f2a02018-09-26 18:02:32 +00004373 " Options:",
drhc1962192020-10-12 16:54:28 +00004374 " --data-only Output only INSERT statements",
drheb7f2a02018-09-26 18:02:32 +00004375 " --newlines Allow unescaped newline characters in output",
drhc1962192020-10-12 16:54:28 +00004376 " --nosys Omit system tables (ex: \"sqlite_stat1\")",
4377 " --preserve-rowids Include ROWID values in the output",
larrybr7bdbe592021-03-15 12:56:00 +00004378 " OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump",
drh8e9297f2020-03-25 12:50:13 +00004379 " Additional LIKE patterns can be given in subsequent arguments",
drh98aa2ab2018-09-26 16:53:51 +00004380 ".echo on|off Turn command echo on or off",
drhb4e50392019-01-26 15:40:04 +00004381 ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN",
4382 " Other Modes:",
4383#ifdef SQLITE_DEBUG
4384 " test Show raw EXPLAIN QUERY PLAN output",
drhe2754c12019-08-26 12:50:01 +00004385 " trace Like \"full\" but enable \"PRAGMA vdbe_trace\"",
drhb4e50392019-01-26 15:40:04 +00004386#endif
4387 " trigger Like \"full\" but also show trigger bytecode",
stephan4413ec72022-07-12 15:53:02 +00004388#ifndef SQLITE_SHELL_FIDDLE
drhe2754c12019-08-26 12:50:01 +00004389 ".excel Display the output of next command in spreadsheet",
drh7a431002020-04-18 14:12:00 +00004390 " --bom Put a UTF8 byte-order mark on intermediate file",
stephan02520cc2022-05-18 22:58:34 +00004391#endif
stephan4413ec72022-07-12 15:53:02 +00004392#ifndef SQLITE_SHELL_FIDDLE
drheb7f2a02018-09-26 18:02:32 +00004393 ".exit ?CODE? Exit this program with return-code CODE",
stephan02520cc2022-05-18 22:58:34 +00004394#endif
drhe2754c12019-08-26 12:50:01 +00004395 ".expert EXPERIMENTAL. Suggest indexes for queries",
drh978256f2019-11-02 00:00:14 +00004396 ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto",
drhd985f722019-06-05 14:29:53 +00004397 ".filectrl CMD ... Run various sqlite3_file_control() operations",
drh541ef2c2020-04-20 16:21:30 +00004398 " --schema SCHEMA Use SCHEMA instead of \"main\"",
4399 " --help Show CMD details",
drh98aa2ab2018-09-26 16:53:51 +00004400 ".fullschema ?--indent? Show schema and the content of sqlite_stat tables",
4401 ".headers on|off Turn display of headers on or off",
4402 ".help ?-all? ?PATTERN? Show help text for PATTERN",
stephan4413ec72022-07-12 15:53:02 +00004403#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004404 ".import FILE TABLE Import data from FILE into TABLE",
drhccb37812020-03-09 15:39:39 +00004405 " Options:",
4406 " --ascii Use \\037 and \\036 as column and row separators",
4407 " --csv Use , and \\n as column and row separators",
4408 " --skip N Skip the first N rows of input",
larrybr738d7b92022-01-13 21:22:54 +00004409 " --schema S Target table to be S.TABLE",
drhccb37812020-03-09 15:39:39 +00004410 " -v \"Verbose\" - increase auxiliary output",
4411 " Notes:",
4412 " * If TABLE does not exist, it is created. The first row of input",
4413 " determines the column names.",
4414 " * If neither --csv or --ascii are used, the input mode is derived",
4415 " from the \".mode\" output mode",
4416 " * If FILE begins with \"|\" then it is a command that generates the",
4417 " input text.",
stephan29f24582022-05-19 00:38:34 +00004418#endif
drh2ce15c32017-07-11 13:34:40 +00004419#ifndef SQLITE_OMIT_TEST_CONTROL
drh98aa2ab2018-09-26 16:53:51 +00004420 ".imposter INDEX TABLE Create imposter table TABLE on index INDEX",
drh2ce15c32017-07-11 13:34:40 +00004421#endif
drh98aa2ab2018-09-26 16:53:51 +00004422 ".indexes ?TABLE? Show names of indexes",
4423 " If TABLE is specified, only show indexes for",
4424 " tables matching TABLE using the LIKE operator.",
drh2ce15c32017-07-11 13:34:40 +00004425#ifdef SQLITE_ENABLE_IOTRACE
drh98aa2ab2018-09-26 16:53:51 +00004426 ".iotrace FILE Enable I/O diagnostic logging to FILE",
drh2ce15c32017-07-11 13:34:40 +00004427#endif
drh98aa2ab2018-09-26 16:53:51 +00004428 ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT",
4429 ".lint OPTIONS Report potential schema issues.",
4430 " Options:",
4431 " fkey-indexes Find missing foreign key indexes",
stephan4413ec72022-07-12 15:53:02 +00004432#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_FIDDLE)
drh98aa2ab2018-09-26 16:53:51 +00004433 ".load FILE ?ENTRY? Load an extension library",
drh2ce15c32017-07-11 13:34:40 +00004434#endif
stephan4413ec72022-07-12 15:53:02 +00004435#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004436 ".log FILE|off Turn logging on or off. FILE can be stderr/stdout",
stephan618a3752022-05-19 10:24:50 +00004437#endif
drh47741b82022-01-31 22:14:53 +00004438 ".mode MODE ?OPTIONS? Set output mode",
drh98aa2ab2018-09-26 16:53:51 +00004439 " MODE is one of:",
drhe40f2862022-01-31 14:14:29 +00004440 " ascii Columns/rows delimited by 0x1F and 0x1E",
4441 " box Tables using unicode box-drawing characters",
4442 " csv Comma-separated values",
4443 " column Output in columns. (See .width)",
4444 " html HTML <table> code",
4445 " insert SQL insert statements for TABLE",
4446 " json Results in a JSON array",
4447 " line One value per line",
4448 " list Values delimited by \"|\"",
4449 " markdown Markdown table format",
drh1f41a8c2022-10-24 11:10:40 +00004450 " qbox Shorthand for \"box --wrap 60 --quote\"",
drhe40f2862022-01-31 14:14:29 +00004451 " quote Escape answers as for SQL",
4452 " table ASCII-art table",
4453 " tabs Tab-separated values",
4454 " tcl TCL list elements",
larrybrcc4d55c2022-02-01 02:50:45 +00004455 " OPTIONS: (for columnar modes or insert mode):",
4456 " --wrap N Wrap output lines to no longer than N characters",
drhca1776b2022-02-01 12:28:17 +00004457 " --wordwrap B Wrap or not at word boundaries per B (on/off)",
4458 " --ww Shorthand for \"--wordwrap 1\"",
larrybrcc4d55c2022-02-01 02:50:45 +00004459 " --quote Quote output text as SQL literals",
4460 " --noquote Do not quote output text",
4461 " TABLE The name of SQL table used for \"insert\" mode",
stephan4413ec72022-07-12 15:53:02 +00004462#ifndef SQLITE_SHELL_FIDDLE
larrybrcc4d55c2022-02-01 02:50:45 +00004463 ".nonce STRING Suspend safe mode for one command if nonce matches",
stephane26d1622022-05-19 22:04:23 +00004464#endif
drh98aa2ab2018-09-26 16:53:51 +00004465 ".nullvalue STRING Use STRING in place of NULL values",
stephan4413ec72022-07-12 15:53:02 +00004466#ifndef SQLITE_SHELL_FIDDLE
drh7a431002020-04-18 14:12:00 +00004467 ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
drh98aa2ab2018-09-26 16:53:51 +00004468 " If FILE begins with '|' then open as a pipe",
drh7a431002020-04-18 14:12:00 +00004469 " --bom Put a UTF8 byte-order mark at the beginning",
4470 " -e Send output to the system text editor",
4471 " -x Send output as CSV to a spreadsheet (same as \".excel\")",
stephande1e02e2022-05-24 19:01:21 +00004472 /* Note that .open is (partially) available in WASM builds but is
stephan085c5c62022-05-25 04:35:22 +00004473 ** currently only intended to be used by the fiddle tool, not
4474 ** end users, so is "undocumented." */
drh98aa2ab2018-09-26 16:53:51 +00004475 ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
4476 " Options:",
drh60f34ae2018-10-30 13:19:49 +00004477 " --append Use appendvfs to append database to the end of FILE",
stephan02520cc2022-05-18 22:58:34 +00004478#endif
drh8d889af2021-05-08 17:18:23 +00004479#ifndef SQLITE_OMIT_DESERIALIZE
drhd10c3ca2021-05-08 11:57:35 +00004480 " --deserialize Load into memory using sqlite3_deserialize()",
drhe2754c12019-08-26 12:50:01 +00004481 " --hexdb Load the output of \"dbtotxt\" as an in-memory db",
drh6ca64482019-01-22 16:06:20 +00004482 " --maxsize N Maximum size for --hexdb or --deserialized database",
drha751f392018-10-30 15:31:22 +00004483#endif
drh60f34ae2018-10-30 13:19:49 +00004484 " --new Initialize FILE to an empty database",
drh0933aad2019-11-18 17:46:38 +00004485 " --nofollow Do not follow symbolic links",
drh60f34ae2018-10-30 13:19:49 +00004486 " --readonly Open FILE readonly",
4487 " --zip FILE is a ZIP archive",
stephan4413ec72022-07-12 15:53:02 +00004488#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004489 ".output ?FILE? Send output to FILE or stdout if FILE is omitted",
drh7a431002020-04-18 14:12:00 +00004490 " If FILE begins with '|' then open it as a pipe.",
4491 " Options:",
4492 " --bom Prefix output with a UTF8 byte-order mark",
4493 " -e Send output to the system text editor",
4494 " -x Send output as CSV to a spreadsheet",
stephande1e02e2022-05-24 19:01:21 +00004495#endif
drh9cb02642019-02-28 20:10:52 +00004496 ".parameter CMD ... Manage SQL parameter bindings",
4497 " clear Erase all bindings",
4498 " init Initialize the TEMP table that holds bindings",
4499 " list List the current parameter bindings",
4500 " set PARAMETER VALUE Given SQL parameter PARAMETER a value of VALUE",
drhe2754c12019-08-26 12:50:01 +00004501 " PARAMETER should start with one of: $ : @ ?",
drh9cb02642019-02-28 20:10:52 +00004502 " unset PARAMETER Remove PARAMETER from the binding table",
drh98aa2ab2018-09-26 16:53:51 +00004503 ".print STRING... Print literal STRING",
drh569b1d92019-02-05 20:51:41 +00004504#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
drh3f83f592019-02-04 14:53:18 +00004505 ".progress N Invoke progress handler after every N opcodes",
4506 " --limit N Interrupt after N progress callbacks",
4507 " --once Do no more than one progress interrupt",
4508 " --quiet|-q No output except at interrupts",
4509 " --reset Reset the count for each input and interrupt",
drh569b1d92019-02-05 20:51:41 +00004510#endif
drh98aa2ab2018-09-26 16:53:51 +00004511 ".prompt MAIN CONTINUE Replace the standard prompts",
stephan4413ec72022-07-12 15:53:02 +00004512#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004513 ".quit Exit this program",
larrybra2ba25b2021-12-28 05:08:38 +00004514 ".read FILE Read input from FILE or command output",
4515 " If FILE begins with \"|\", it is a command that generates the input.",
stephan02520cc2022-05-18 22:58:34 +00004516#endif
stephan3d420832022-10-27 03:56:01 +00004517#if SQLITE_SHELL_HAVE_RECOVER
dan42ebb012019-04-27 18:47:03 +00004518 ".recover Recover as much data as possible from corrupt db.",
danf7fea5b2022-10-27 18:19:45 +00004519 " --ignore-freelist Ignore pages that appear to be on db freelist",
drhe2754c12019-08-26 12:50:01 +00004520 " --lost-and-found TABLE Alternative name for the lost-and-found table",
dan8cce6b82019-09-14 16:44:51 +00004521 " --no-rowids Do not attempt to recover rowid values",
4522 " that are not also INTEGER PRIMARY KEYs",
dan1b162162019-04-27 20:15:15 +00004523#endif
stephan4413ec72022-07-12 15:53:02 +00004524#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004525 ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE",
larrybra7919ad2022-02-19 21:25:48 +00004526 ".save ?OPTIONS? FILE Write database to FILE (an alias for .backup ...)",
stephan02520cc2022-05-18 22:58:34 +00004527#endif
drh98aa2ab2018-09-26 16:53:51 +00004528 ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off",
4529 ".schema ?PATTERN? Show the CREATE statements matching PATTERN",
drhbbb29ec2020-10-12 14:56:47 +00004530 " Options:",
4531 " --indent Try to pretty-print the schema",
4532 " --nosys Omit objects whose names start with \"sqlite_\"",
drheb7f2a02018-09-26 18:02:32 +00004533 ".selftest ?OPTIONS? Run tests defined in the SELFTEST table",
4534 " Options:",
4535 " --init Create a new SELFTEST table",
4536 " -v Verbose output",
drh98aa2ab2018-09-26 16:53:51 +00004537 ".separator COL ?ROW? Change the column and row separators",
drh2ce15c32017-07-11 13:34:40 +00004538#if defined(SQLITE_ENABLE_SESSION)
drheb7f2a02018-09-26 18:02:32 +00004539 ".session ?NAME? CMD ... Create or control sessions",
4540 " Subcommands:",
4541 " attach TABLE Attach TABLE",
4542 " changeset FILE Write a changeset into FILE",
4543 " close Close one session",
4544 " enable ?BOOLEAN? Set or query the enable bit",
4545 " filter GLOB... Reject tables matching GLOBs",
4546 " indirect ?BOOLEAN? Mark or query the indirect status",
4547 " isempty Query whether the session is empty",
4548 " list List currently open session names",
4549 " open DB NAME Open a new session on DB",
4550 " patchset FILE Write a patchset into FILE",
4551 " If ?NAME? is omitted, the first defined session is used.",
drh2ce15c32017-07-11 13:34:40 +00004552#endif
drheb7f2a02018-09-26 18:02:32 +00004553 ".sha3sum ... Compute a SHA3 hash of database content",
4554 " Options:",
drh067b92b2020-06-19 15:24:12 +00004555 " --schema Also hash the sqlite_schema table",
drheb7f2a02018-09-26 18:02:32 +00004556 " --sha3-224 Use the sha3-224 algorithm",
drhe2754c12019-08-26 12:50:01 +00004557 " --sha3-256 Use the sha3-256 algorithm (default)",
drheb7f2a02018-09-26 18:02:32 +00004558 " --sha3-384 Use the sha3-384 algorithm",
4559 " --sha3-512 Use the sha3-512 algorithm",
4560 " Any other argument is a LIKE pattern for tables to hash",
stephan4413ec72022-07-12 15:53:02 +00004561#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
drh98aa2ab2018-09-26 16:53:51 +00004562 ".shell CMD ARGS... Run CMD ARGS... in a system shell",
drh04a28c32018-01-31 01:38:44 +00004563#endif
drh98aa2ab2018-09-26 16:53:51 +00004564 ".show Show the current values for various settings",
drha6e6cf22021-01-09 19:10:04 +00004565 ".stats ?ARG? Show stats or turn stats on or off",
4566 " off Turn off automatic stat display",
4567 " on Turn on automatic stat display",
4568 " stmt Show statement stats",
4569 " vmstep Show the virtual machine step count only",
stephan4413ec72022-07-12 15:53:02 +00004570#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
drh98aa2ab2018-09-26 16:53:51 +00004571 ".system CMD ARGS... Run CMD ARGS... in a system shell",
drh04a28c32018-01-31 01:38:44 +00004572#endif
drh98aa2ab2018-09-26 16:53:51 +00004573 ".tables ?TABLE? List names of tables matching LIKE pattern TABLE",
stephan4413ec72022-07-12 15:53:02 +00004574#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004575 ".testcase NAME Begin redirecting output to 'testcase-out.txt'",
stephan02520cc2022-05-18 22:58:34 +00004576#endif
drhd985f722019-06-05 14:29:53 +00004577 ".testctrl CMD ... Run various sqlite3_test_control() operations",
4578 " Run \".testctrl\" with no arguments for details",
drh98aa2ab2018-09-26 16:53:51 +00004579 ".timeout MS Try opening locked tables for MS milliseconds",
4580 ".timer on|off Turn SQL timer on or off",
drh707821f2018-12-05 13:39:06 +00004581#ifndef SQLITE_OMIT_TRACE
4582 ".trace ?OPTIONS? Output each SQL statement as it is run",
4583 " FILE Send output to FILE",
4584 " stdout Send output to stdout",
4585 " stderr Send output to stderr",
4586 " off Disable tracing",
4587 " --expanded Expand query parameters",
4588#ifdef SQLITE_ENABLE_NORMALIZE
4589 " --normalized Normal the SQL statements",
4590#endif
4591 " --plain Show SQL as it is input",
4592 " --stmt Trace statement execution (SQLITE_TRACE_STMT)",
4593 " --profile Profile statements (SQLITE_TRACE_PROFILE)",
4594 " --row Trace each row (SQLITE_TRACE_ROW)",
4595 " --close Trace connection close (SQLITE_TRACE_CLOSE)",
4596#endif /* SQLITE_OMIT_TRACE */
drhcc5979d2019-08-16 22:58:29 +00004597#ifdef SQLITE_DEBUG
4598 ".unmodule NAME ... Unregister virtual table modules",
drh5df84282019-08-17 19:45:25 +00004599 " --allexcept Unregister everything except those named",
drhcc5979d2019-08-16 22:58:29 +00004600#endif
drh98aa2ab2018-09-26 16:53:51 +00004601 ".vfsinfo ?AUX? Information about the top-level VFS",
4602 ".vfslist List all available VFSes",
4603 ".vfsname ?AUX? Print the name of the VFS stack",
drh7da29a32020-05-29 19:17:20 +00004604 ".width NUM1 NUM2 ... Set minimum column widths for columnar output",
drh98aa2ab2018-09-26 16:53:51 +00004605 " Negative values right-justify",
4606};
4607
4608/*
4609** Output help text.
4610**
4611** zPattern describes the set of commands for which help text is provided.
4612** If zPattern is NULL, then show all commands, but only give a one-line
4613** description of each.
4614**
4615** Return the number of matches.
4616*/
4617static int showHelp(FILE *out, const char *zPattern){
drhe93f8262018-10-11 16:53:37 +00004618 int i = 0;
4619 int j = 0;
drh98aa2ab2018-09-26 16:53:51 +00004620 int n = 0;
4621 char *zPat;
drh488cddf2018-10-06 14:38:17 +00004622 if( zPattern==0
4623 || zPattern[0]=='0'
drhbf70f1b2022-10-19 18:04:42 +00004624 || cli_strcmp(zPattern,"-a")==0
4625 || cli_strcmp(zPattern,"-all")==0
4626 || cli_strcmp(zPattern,"--all")==0
drh488cddf2018-10-06 14:38:17 +00004627 ){
drh98aa2ab2018-09-26 16:53:51 +00004628 /* Show all commands, but only one line per command */
drh488cddf2018-10-06 14:38:17 +00004629 if( zPattern==0 ) zPattern = "";
drh98aa2ab2018-09-26 16:53:51 +00004630 for(i=0; i<ArraySize(azHelp); i++){
drh488cddf2018-10-06 14:38:17 +00004631 if( azHelp[i][0]=='.' || zPattern[0] ){
drh98aa2ab2018-09-26 16:53:51 +00004632 utf8_printf(out, "%s\n", azHelp[i]);
4633 n++;
4634 }
4635 }
4636 }else{
4637 /* Look for commands that for which zPattern is an exact prefix */
4638 zPat = sqlite3_mprintf(".%s*", zPattern);
drhe3e25652021-12-16 13:29:28 +00004639 shell_check_oom(zPat);
drh98aa2ab2018-09-26 16:53:51 +00004640 for(i=0; i<ArraySize(azHelp); i++){
4641 if( sqlite3_strglob(zPat, azHelp[i])==0 ){
4642 utf8_printf(out, "%s\n", azHelp[i]);
drheb7f2a02018-09-26 18:02:32 +00004643 j = i+1;
drh98aa2ab2018-09-26 16:53:51 +00004644 n++;
4645 }
4646 }
4647 sqlite3_free(zPat);
drheb7f2a02018-09-26 18:02:32 +00004648 if( n ){
4649 if( n==1 ){
4650 /* when zPattern is a prefix of exactly one command, then include the
4651 ** details of that command, which should begin at offset j */
4652 while( j<ArraySize(azHelp)-1 && azHelp[j][0]!='.' ){
4653 utf8_printf(out, "%s\n", azHelp[j]);
4654 j++;
4655 }
4656 }
4657 return n;
4658 }
4659 /* Look for commands that contain zPattern anywhere. Show the complete
4660 ** text of all commands that match. */
drh98aa2ab2018-09-26 16:53:51 +00004661 zPat = sqlite3_mprintf("%%%s%%", zPattern);
drhe3e25652021-12-16 13:29:28 +00004662 shell_check_oom(zPat);
drh98aa2ab2018-09-26 16:53:51 +00004663 for(i=0; i<ArraySize(azHelp); i++){
4664 if( azHelp[i][0]=='.' ) j = i;
4665 if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
4666 utf8_printf(out, "%s\n", azHelp[j]);
4667 while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]!='.' ){
4668 j++;
4669 utf8_printf(out, "%s\n", azHelp[j]);
4670 }
4671 i = j;
4672 n++;
4673 }
4674 }
4675 sqlite3_free(zPat);
4676 }
4677 return n;
4678}
drh2ce15c32017-07-11 13:34:40 +00004679
drh2ce15c32017-07-11 13:34:40 +00004680/* Forward reference */
drh60379d42018-12-13 18:30:01 +00004681static int process_input(ShellState *p);
drh2ce15c32017-07-11 13:34:40 +00004682
4683/*
4684** Read the content of file zName into memory obtained from sqlite3_malloc64()
4685** and return a pointer to the buffer. The caller is responsible for freeing
4686** the memory.
4687**
4688** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
4689** read.
4690**
4691** For convenience, a nul-terminator byte is always appended to the data read
4692** from the file before the buffer is returned. This byte is not included in
4693** the final value of (*pnByte), if applicable.
4694**
4695** NULL is returned if any error is encountered. The final value of *pnByte
4696** is undefined in this case.
4697*/
4698static char *readFile(const char *zName, int *pnByte){
4699 FILE *in = fopen(zName, "rb");
4700 long nIn;
4701 size_t nRead;
4702 char *pBuf;
4703 if( in==0 ) return 0;
4704 fseek(in, 0, SEEK_END);
4705 nIn = ftell(in);
4706 rewind(in);
4707 pBuf = sqlite3_malloc64( nIn+1 );
drh1dbb1472018-10-11 10:37:24 +00004708 if( pBuf==0 ){ fclose(in); return 0; }
drh2ce15c32017-07-11 13:34:40 +00004709 nRead = fread(pBuf, nIn, 1, in);
4710 fclose(in);
4711 if( nRead!=1 ){
4712 sqlite3_free(pBuf);
4713 return 0;
4714 }
4715 pBuf[nIn] = 0;
4716 if( pnByte ) *pnByte = nIn;
4717 return pBuf;
4718}
4719
4720#if defined(SQLITE_ENABLE_SESSION)
4721/*
4722** Close a single OpenSession object and release all of its associated
4723** resources.
4724*/
4725static void session_close(OpenSession *pSession){
4726 int i;
4727 sqlite3session_delete(pSession->p);
4728 sqlite3_free(pSession->zName);
4729 for(i=0; i<pSession->nFilter; i++){
4730 sqlite3_free(pSession->azFilter[i]);
4731 }
4732 sqlite3_free(pSession->azFilter);
4733 memset(pSession, 0, sizeof(OpenSession));
4734}
4735#endif
4736
4737/*
4738** Close all OpenSession objects and release all associated resources.
4739*/
4740#if defined(SQLITE_ENABLE_SESSION)
drh37407122021-07-23 18:43:58 +00004741static void session_close_all(ShellState *p, int i){
4742 int j;
4743 struct AuxDb *pAuxDb = i<0 ? p->pAuxDb : &p->aAuxDb[i];
4744 for(j=0; j<pAuxDb->nSession; j++){
4745 session_close(&pAuxDb->aSession[j]);
drh2ce15c32017-07-11 13:34:40 +00004746 }
drh37407122021-07-23 18:43:58 +00004747 pAuxDb->nSession = 0;
drh2ce15c32017-07-11 13:34:40 +00004748}
4749#else
drh37407122021-07-23 18:43:58 +00004750# define session_close_all(X,Y)
drh2ce15c32017-07-11 13:34:40 +00004751#endif
4752
4753/*
4754** Implementation of the xFilter function for an open session. Omit
4755** any tables named by ".session filter" but let all other table through.
4756*/
4757#if defined(SQLITE_ENABLE_SESSION)
4758static int session_filter(void *pCtx, const char *zTab){
4759 OpenSession *pSession = (OpenSession*)pCtx;
4760 int i;
4761 for(i=0; i<pSession->nFilter; i++){
4762 if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
4763 }
4764 return 1;
4765}
4766#endif
4767
4768/*
drh1fa6d9f2018-01-06 21:46:01 +00004769** Try to deduce the type of file for zName based on its content. Return
4770** one of the SHELL_OPEN_* constants.
drh1bf208c2018-03-09 21:54:01 +00004771**
4772** If the file does not exist or is empty but its name looks like a ZIP
4773** archive and the dfltZip flag is true, then assume it is a ZIP archive.
4774** Otherwise, assume an ordinary database regardless of the filename if
4775** the type cannot be determined from content.
drh1fa6d9f2018-01-06 21:46:01 +00004776*/
drhfc97c1c2018-05-14 00:41:12 +00004777int deduceDatabaseType(const char *zName, int dfltZip){
drh1fa6d9f2018-01-06 21:46:01 +00004778 FILE *f = fopen(zName, "rb");
4779 size_t n;
4780 int rc = SHELL_OPEN_UNSPEC;
4781 char zBuf[100];
drh1bf208c2018-03-09 21:54:01 +00004782 if( f==0 ){
drhbe4ccb22018-05-17 20:04:24 +00004783 if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
4784 return SHELL_OPEN_ZIPFILE;
4785 }else{
4786 return SHELL_OPEN_NORMAL;
4787 }
drh1bf208c2018-03-09 21:54:01 +00004788 }
drh2b3c4af2018-10-30 14:36:21 +00004789 n = fread(zBuf, 16, 1, f);
4790 if( n==1 && memcmp(zBuf, "SQLite format 3", 16)==0 ){
4791 fclose(f);
4792 return SHELL_OPEN_NORMAL;
4793 }
drh1fa6d9f2018-01-06 21:46:01 +00004794 fseek(f, -25, SEEK_END);
4795 n = fread(zBuf, 25, 1, f);
4796 if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){
4797 rc = SHELL_OPEN_APPENDVFS;
4798 }else{
4799 fseek(f, -22, SEEK_END);
4800 n = fread(zBuf, 22, 1, f);
4801 if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05
4802 && zBuf[3]==0x06 ){
4803 rc = SHELL_OPEN_ZIPFILE;
drh1bf208c2018-03-09 21:54:01 +00004804 }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
mistachkina3926f42018-05-14 12:23:04 +00004805 rc = SHELL_OPEN_ZIPFILE;
drh1fa6d9f2018-01-06 21:46:01 +00004806 }
4807 }
4808 fclose(f);
4809 return rc;
4810}
4811
drh8d889af2021-05-08 17:18:23 +00004812#ifndef SQLITE_OMIT_DESERIALIZE
drh33746482018-12-13 15:06:26 +00004813/*
4814** Reconstruct an in-memory database using the output from the "dbtotxt"
drh37407122021-07-23 18:43:58 +00004815** program. Read content from the file in p->aAuxDb[].zDbFilename.
4816** If p->aAuxDb[].zDbFilename is 0, then read from standard input.
drh33746482018-12-13 15:06:26 +00004817*/
4818static unsigned char *readHexDb(ShellState *p, int *pnData){
4819 unsigned char *a = 0;
drh2c8ee022018-12-13 18:59:30 +00004820 int nLine;
drh33746482018-12-13 15:06:26 +00004821 int n = 0;
4822 int pgsz = 0;
4823 int iOffset = 0;
4824 int j, k;
4825 int rc;
4826 FILE *in;
drh37407122021-07-23 18:43:58 +00004827 const char *zDbFilename = p->pAuxDb->zDbFilename;
drh3ea557e2019-04-23 15:30:58 +00004828 unsigned int x[16];
drh2c8ee022018-12-13 18:59:30 +00004829 char zLine[1000];
drh37407122021-07-23 18:43:58 +00004830 if( zDbFilename ){
4831 in = fopen(zDbFilename, "r");
drh33746482018-12-13 15:06:26 +00004832 if( in==0 ){
drh37407122021-07-23 18:43:58 +00004833 utf8_printf(stderr, "cannot open \"%s\" for reading\n", zDbFilename);
drh33746482018-12-13 15:06:26 +00004834 return 0;
4835 }
drh2c8ee022018-12-13 18:59:30 +00004836 nLine = 0;
drh33746482018-12-13 15:06:26 +00004837 }else{
drh60379d42018-12-13 18:30:01 +00004838 in = p->in;
drh2c8ee022018-12-13 18:59:30 +00004839 nLine = p->lineno;
drh5bf46442019-05-03 02:41:36 +00004840 if( in==0 ) in = stdin;
drh33746482018-12-13 15:06:26 +00004841 }
4842 *pnData = 0;
drh2c8ee022018-12-13 18:59:30 +00004843 nLine++;
drh33746482018-12-13 15:06:26 +00004844 if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
4845 rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
4846 if( rc!=2 ) goto readHexDb_error;
drh68feae52019-05-09 11:18:41 +00004847 if( n<0 ) goto readHexDb_error;
drh09ea1252019-07-17 15:05:16 +00004848 if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error;
4849 n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */
drh68feae52019-05-09 11:18:41 +00004850 a = sqlite3_malloc( n ? n : 1 );
drhe3e25652021-12-16 13:29:28 +00004851 shell_check_oom(a);
drh33746482018-12-13 15:06:26 +00004852 memset(a, 0, n);
4853 if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
4854 utf8_printf(stderr, "invalid pagesize\n");
4855 goto readHexDb_error;
4856 }
drh2c8ee022018-12-13 18:59:30 +00004857 for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
drh33746482018-12-13 15:06:26 +00004858 rc = sscanf(zLine, "| page %d offset %d", &j, &k);
4859 if( rc==2 ){
4860 iOffset = k;
4861 continue;
4862 }
drhbf70f1b2022-10-19 18:04:42 +00004863 if( cli_strncmp(zLine, "| end ", 6)==0 ){
drh33746482018-12-13 15:06:26 +00004864 break;
4865 }
drh3ea557e2019-04-23 15:30:58 +00004866 rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
drh33746482018-12-13 15:06:26 +00004867 &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
4868 &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
4869 if( rc==17 ){
4870 k = iOffset+j;
drh82978ac2021-10-01 17:06:44 +00004871 if( k+16<=n && k>=0 ){
drh3ea557e2019-04-23 15:30:58 +00004872 int ii;
4873 for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff;
drh33746482018-12-13 15:06:26 +00004874 }
drh33746482018-12-13 15:06:26 +00004875 }
4876 }
4877 *pnData = n;
drh2c8ee022018-12-13 18:59:30 +00004878 if( in!=p->in ){
4879 fclose(in);
4880 }else{
4881 p->lineno = nLine;
4882 }
drh33746482018-12-13 15:06:26 +00004883 return a;
4884
4885readHexDb_error:
drh68feae52019-05-09 11:18:41 +00004886 if( in!=p->in ){
drh33746482018-12-13 15:06:26 +00004887 fclose(in);
4888 }else{
drh60379d42018-12-13 18:30:01 +00004889 while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
drh2c8ee022018-12-13 18:59:30 +00004890 nLine++;
drhbf70f1b2022-10-19 18:04:42 +00004891 if(cli_strncmp(zLine, "| end ", 6)==0 ) break;
drh33746482018-12-13 15:06:26 +00004892 }
drh2c8ee022018-12-13 18:59:30 +00004893 p->lineno = nLine;
drh33746482018-12-13 15:06:26 +00004894 }
4895 sqlite3_free(a);
4896 utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine);
4897 return 0;
4898}
drh8d889af2021-05-08 17:18:23 +00004899#endif /* SQLITE_OMIT_DESERIALIZE */
drh33746482018-12-13 15:06:26 +00004900
danb1825882019-04-23 20:48:32 +00004901/*
dan9c014f82019-04-25 19:23:15 +00004902** Scalar function "shell_int32". The first argument to this function
4903** must be a blob. The second a non-negative integer. This function
4904** reads and returns a 32-bit big-endian integer from byte
4905** offset (4*<arg2>) of the blob.
4906*/
4907static void shellInt32(
4908 sqlite3_context *context,
4909 int argc,
4910 sqlite3_value **argv
4911){
4912 const unsigned char *pBlob;
4913 int nBlob;
4914 int iInt;
drh9546c762019-05-10 17:50:33 +00004915
4916 UNUSED_PARAMETER(argc);
dan9c014f82019-04-25 19:23:15 +00004917 nBlob = sqlite3_value_bytes(argv[0]);
4918 pBlob = (const unsigned char*)sqlite3_value_blob(argv[0]);
4919 iInt = sqlite3_value_int(argv[1]);
4920
4921 if( iInt>=0 && (iInt+1)*4<=nBlob ){
4922 const unsigned char *a = &pBlob[iInt*4];
4923 sqlite3_int64 iVal = ((sqlite3_int64)a[0]<<24)
4924 + ((sqlite3_int64)a[1]<<16)
4925 + ((sqlite3_int64)a[2]<< 8)
4926 + ((sqlite3_int64)a[3]<< 0);
4927 sqlite3_result_int64(context, iVal);
4928 }
4929}
4930
4931/*
drha2de66c2019-08-06 20:26:17 +00004932** Scalar function "shell_idquote(X)" returns string X quoted as an identifier,
4933** using "..." with internal double-quote characters doubled.
4934*/
4935static void shellIdQuote(
4936 sqlite3_context *context,
4937 int argc,
4938 sqlite3_value **argv
4939){
4940 const char *zName = (const char*)sqlite3_value_text(argv[0]);
drh51755a72019-08-08 19:40:29 +00004941 UNUSED_PARAMETER(argc);
drha2de66c2019-08-06 20:26:17 +00004942 if( zName ){
4943 char *z = sqlite3_mprintf("\"%w\"", zName);
4944 sqlite3_result_text(context, z, -1, sqlite3_free);
4945 }
4946}
4947
4948/*
drhddcfe922020-09-15 12:29:35 +00004949** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X.
4950*/
4951static void shellUSleepFunc(
4952 sqlite3_context *context,
drhd36f5882020-11-25 16:28:04 +00004953 int argcUnused,
drhddcfe922020-09-15 12:29:35 +00004954 sqlite3_value **argv
4955){
4956 int sleep = sqlite3_value_int(argv[0]);
drhd36f5882020-11-25 16:28:04 +00004957 (void)argcUnused;
drhddcfe922020-09-15 12:29:35 +00004958 sqlite3_sleep(sleep/1000);
4959 sqlite3_result_int(context, sleep);
4960}
4961
4962/*
danb1825882019-04-23 20:48:32 +00004963** Scalar function "shell_escape_crnl" used by the .recover command.
4964** The argument passed to this function is the output of built-in
4965** function quote(). If the first character of the input is "'",
4966** indicating that the value passed to quote() was a text value,
4967** then this function searches the input for "\n" and "\r" characters
4968** and adds a wrapper similar to the following:
4969**
4970** replace(replace(<input>, '\n', char(10), '\r', char(13));
4971**
4972** Or, if the first character of the input is not "'", then a copy
4973** of the input is returned.
4974*/
4975static void shellEscapeCrnl(
4976 sqlite3_context *context,
4977 int argc,
4978 sqlite3_value **argv
4979){
4980 const char *zText = (const char*)sqlite3_value_text(argv[0]);
drh9546c762019-05-10 17:50:33 +00004981 UNUSED_PARAMETER(argc);
drh621a5e02021-12-16 17:35:27 +00004982 if( zText && zText[0]=='\'' ){
drh7d23d152022-10-11 12:02:42 +00004983 i64 nText = sqlite3_value_bytes(argv[0]);
4984 i64 i;
danb1825882019-04-23 20:48:32 +00004985 char zBuf1[20];
4986 char zBuf2[20];
4987 const char *zNL = 0;
4988 const char *zCR = 0;
drh7d23d152022-10-11 12:02:42 +00004989 i64 nCR = 0;
4990 i64 nNL = 0;
danb1825882019-04-23 20:48:32 +00004991
4992 for(i=0; zText[i]; i++){
4993 if( zNL==0 && zText[i]=='\n' ){
4994 zNL = unused_string(zText, "\\n", "\\012", zBuf1);
drh7d23d152022-10-11 12:02:42 +00004995 nNL = strlen(zNL);
danb1825882019-04-23 20:48:32 +00004996 }
4997 if( zCR==0 && zText[i]=='\r' ){
4998 zCR = unused_string(zText, "\\r", "\\015", zBuf2);
drh7d23d152022-10-11 12:02:42 +00004999 nCR = strlen(zCR);
danb1825882019-04-23 20:48:32 +00005000 }
5001 }
5002
5003 if( zNL || zCR ){
drh7d23d152022-10-11 12:02:42 +00005004 i64 iOut = 0;
danb1825882019-04-23 20:48:32 +00005005 i64 nMax = (nNL > nCR) ? nNL : nCR;
dan51f5ffa2019-04-29 11:41:46 +00005006 i64 nAlloc = nMax * nText + (nMax+64)*2;
danb1825882019-04-23 20:48:32 +00005007 char *zOut = (char*)sqlite3_malloc64(nAlloc);
5008 if( zOut==0 ){
5009 sqlite3_result_error_nomem(context);
5010 return;
5011 }
5012
5013 if( zNL && zCR ){
5014 memcpy(&zOut[iOut], "replace(replace(", 16);
5015 iOut += 16;
5016 }else{
5017 memcpy(&zOut[iOut], "replace(", 8);
5018 iOut += 8;
5019 }
5020 for(i=0; zText[i]; i++){
5021 if( zText[i]=='\n' ){
5022 memcpy(&zOut[iOut], zNL, nNL);
5023 iOut += nNL;
5024 }else if( zText[i]=='\r' ){
5025 memcpy(&zOut[iOut], zCR, nCR);
5026 iOut += nCR;
5027 }else{
5028 zOut[iOut] = zText[i];
5029 iOut++;
5030 }
5031 }
5032
5033 if( zNL ){
5034 memcpy(&zOut[iOut], ",'", 2); iOut += 2;
5035 memcpy(&zOut[iOut], zNL, nNL); iOut += nNL;
5036 memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12;
5037 }
5038 if( zCR ){
5039 memcpy(&zOut[iOut], ",'", 2); iOut += 2;
5040 memcpy(&zOut[iOut], zCR, nCR); iOut += nCR;
5041 memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12;
5042 }
5043
5044 sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT);
5045 sqlite3_free(zOut);
5046 return;
5047 }
5048 }
5049
5050 sqlite3_result_value(context, argv[0]);
5051}
5052
drhbe4ccb22018-05-17 20:04:24 +00005053/* Flags for open_db().
5054**
5055** The default behavior of open_db() is to exit(1) if the database fails to
5056** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error
5057** but still returns without calling exit.
5058**
5059** The OPEN_DB_ZIPFILE flag causes open_db() to prefer to open files as a
5060** ZIP archive if the file does not exist or is empty and its name matches
5061** the *.zip pattern.
5062*/
5063#define OPEN_DB_KEEPALIVE 0x001 /* Return after error if true */
5064#define OPEN_DB_ZIPFILE 0x002 /* Open as ZIP if name matches *.zip */
5065
drh1fa6d9f2018-01-06 21:46:01 +00005066/*
drh2ce15c32017-07-11 13:34:40 +00005067** Make sure the database is open. If it is not, then open it. If
5068** the database fails to open, print an error message and exit.
5069*/
drhbe4ccb22018-05-17 20:04:24 +00005070static void open_db(ShellState *p, int openFlags){
drh2ce15c32017-07-11 13:34:40 +00005071 if( p->db==0 ){
drh37407122021-07-23 18:43:58 +00005072 const char *zDbFilename = p->pAuxDb->zDbFilename;
drhf2072d12018-05-11 15:10:11 +00005073 if( p->openMode==SHELL_OPEN_UNSPEC ){
drh37407122021-07-23 18:43:58 +00005074 if( zDbFilename==0 || zDbFilename[0]==0 ){
drhf2072d12018-05-11 15:10:11 +00005075 p->openMode = SHELL_OPEN_NORMAL;
drhbe4ccb22018-05-17 20:04:24 +00005076 }else{
drh37407122021-07-23 18:43:58 +00005077 p->openMode = (u8)deduceDatabaseType(zDbFilename,
drhbe4ccb22018-05-17 20:04:24 +00005078 (openFlags & OPEN_DB_ZIPFILE)!=0);
drhf2072d12018-05-11 15:10:11 +00005079 }
drh1fa6d9f2018-01-06 21:46:01 +00005080 }
5081 switch( p->openMode ){
5082 case SHELL_OPEN_APPENDVFS: {
drh37407122021-07-23 18:43:58 +00005083 sqlite3_open_v2(zDbFilename, &p->db,
drh0933aad2019-11-18 17:46:38 +00005084 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs");
drh1fa6d9f2018-01-06 21:46:01 +00005085 break;
5086 }
drh33746482018-12-13 15:06:26 +00005087 case SHELL_OPEN_HEXDB:
drh60f34ae2018-10-30 13:19:49 +00005088 case SHELL_OPEN_DESERIALIZE: {
5089 sqlite3_open(0, &p->db);
5090 break;
5091 }
drh1fa6d9f2018-01-06 21:46:01 +00005092 case SHELL_OPEN_ZIPFILE: {
5093 sqlite3_open(":memory:", &p->db);
5094 break;
5095 }
drhee269a62018-02-14 23:27:43 +00005096 case SHELL_OPEN_READONLY: {
drh37407122021-07-23 18:43:58 +00005097 sqlite3_open_v2(zDbFilename, &p->db,
drh0933aad2019-11-18 17:46:38 +00005098 SQLITE_OPEN_READONLY|p->openFlags, 0);
drhee269a62018-02-14 23:27:43 +00005099 break;
5100 }
drh1fa6d9f2018-01-06 21:46:01 +00005101 case SHELL_OPEN_UNSPEC:
5102 case SHELL_OPEN_NORMAL: {
drh37407122021-07-23 18:43:58 +00005103 sqlite3_open_v2(zDbFilename, &p->db,
drh0933aad2019-11-18 17:46:38 +00005104 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
drh1fa6d9f2018-01-06 21:46:01 +00005105 break;
5106 }
5107 }
drh2ce15c32017-07-11 13:34:40 +00005108 globalDb = p->db;
5109 if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
5110 utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
drh37407122021-07-23 18:43:58 +00005111 zDbFilename, sqlite3_errmsg(p->db));
drhf25cc4f2019-01-04 14:29:21 +00005112 if( openFlags & OPEN_DB_KEEPALIVE ){
5113 sqlite3_open(":memory:", &p->db);
5114 return;
5115 }
drh2ce15c32017-07-11 13:34:40 +00005116 exit(1);
5117 }
5118#ifndef SQLITE_OMIT_LOAD_EXTENSION
5119 sqlite3_enable_load_extension(p->db, 1);
5120#endif
drh2ce15c32017-07-11 13:34:40 +00005121 sqlite3_shathree_init(p->db, 0, 0);
drhf05dd032020-04-14 15:53:58 +00005122 sqlite3_uint_init(p->db, 0, 0);
drhbeb9def2020-06-22 19:12:23 +00005123 sqlite3_decimal_init(p->db, 0, 0);
drh64689902021-06-03 13:51:31 +00005124 sqlite3_regexp_init(p->db, 0, 0);
drh8cda77d2020-06-24 15:06:29 +00005125 sqlite3_ieee_init(p->db, 0, 0);
mistachkin72c38d82020-08-28 18:47:39 +00005126 sqlite3_series_init(p->db, 0, 0);
stephan4413ec72022-07-12 15:53:02 +00005127#ifndef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +00005128 sqlite3_fileio_init(p->db, 0, 0);
5129 sqlite3_completion_init(p->db, 0, 0);
5130#endif
stephan3d420832022-10-27 03:56:01 +00005131#if SQLITE_SHELL_HAVE_RECOVER
dan68cb86e2019-04-20 20:57:28 +00005132 sqlite3_dbdata_init(p->db, 0, 0);
dan1b162162019-04-27 20:15:15 +00005133#endif
dan72afc3c2017-12-05 18:32:40 +00005134#ifdef SQLITE_HAVE_ZLIB
drh9198f5a2022-03-19 15:19:35 +00005135 if( !p->bSafeModePersist ){
5136 sqlite3_zipfile_init(p->db, 0, 0);
5137 sqlite3_sqlar_init(p->db, 0, 0);
5138 }
dan72afc3c2017-12-05 18:32:40 +00005139#endif
drhceba7922018-01-01 21:28:25 +00005140 sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
drh2ce15c32017-07-11 13:34:40 +00005141 shellAddSchemaName, 0, 0);
drh667a2a22018-01-02 00:04:37 +00005142 sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
5143 shellModuleSchema, 0, 0);
drh634c70f2018-01-10 16:50:18 +00005144 sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
5145 shellPutsFunc, 0, 0);
danb1825882019-04-23 20:48:32 +00005146 sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0,
5147 shellEscapeCrnl, 0, 0);
dan9c014f82019-04-25 19:23:15 +00005148 sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0,
5149 shellInt32, 0, 0);
drha2de66c2019-08-06 20:26:17 +00005150 sqlite3_create_function(p->db, "shell_idquote", 1, SQLITE_UTF8, 0,
5151 shellIdQuote, 0, 0);
drhddcfe922020-09-15 12:29:35 +00005152 sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0,
5153 shellUSleepFunc, 0, 0);
drh04a28c32018-01-31 01:38:44 +00005154#ifndef SQLITE_NOHAVE_SYSTEM
drh97913132018-01-11 00:04:00 +00005155 sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
5156 editFunc, 0, 0);
5157 sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
5158 editFunc, 0, 0);
drh04a28c32018-01-31 01:38:44 +00005159#endif
drh1fa6d9f2018-01-06 21:46:01 +00005160 if( p->openMode==SHELL_OPEN_ZIPFILE ){
5161 char *zSql = sqlite3_mprintf(
drh37407122021-07-23 18:43:58 +00005162 "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename);
drhe3e25652021-12-16 13:29:28 +00005163 shell_check_oom(zSql);
drh1fa6d9f2018-01-06 21:46:01 +00005164 sqlite3_exec(p->db, zSql, 0, 0, 0);
5165 sqlite3_free(zSql);
drha751f392018-10-30 15:31:22 +00005166 }
drh8d889af2021-05-08 17:18:23 +00005167#ifndef SQLITE_OMIT_DESERIALIZE
drh33746482018-12-13 15:06:26 +00005168 else
5169 if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){
mistachkin99490932018-12-17 22:19:57 +00005170 int rc;
drh60f34ae2018-10-30 13:19:49 +00005171 int nData = 0;
drh33746482018-12-13 15:06:26 +00005172 unsigned char *aData;
5173 if( p->openMode==SHELL_OPEN_DESERIALIZE ){
drh37407122021-07-23 18:43:58 +00005174 aData = (unsigned char*)readFile(zDbFilename, &nData);
drh33746482018-12-13 15:06:26 +00005175 }else{
5176 aData = readHexDb(p, &nData);
5177 if( aData==0 ){
drh33746482018-12-13 15:06:26 +00005178 return;
5179 }
5180 }
mistachkin99490932018-12-17 22:19:57 +00005181 rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
drh60f34ae2018-10-30 13:19:49 +00005182 SQLITE_DESERIALIZE_RESIZEABLE |
5183 SQLITE_DESERIALIZE_FREEONCLOSE);
5184 if( rc ){
5185 utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc);
5186 }
drh6ca64482019-01-22 16:06:20 +00005187 if( p->szMax>0 ){
5188 sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
5189 }
drh1fa6d9f2018-01-06 21:46:01 +00005190 }
drha751f392018-10-30 15:31:22 +00005191#endif
drh2ce15c32017-07-11 13:34:40 +00005192 }
drhb97e2ad2021-08-26 18:31:39 +00005193 if( p->bSafeModePersist && p->db!=0 ){
5194 sqlite3_set_authorizer(p->db, safeModeAuth, p);
5195 }
drh2ce15c32017-07-11 13:34:40 +00005196}
5197
drh9e804032018-05-18 17:11:50 +00005198/*
5199** Attempt to close the databaes connection. Report errors.
5200*/
5201void close_db(sqlite3 *db){
5202 int rc = sqlite3_close(db);
5203 if( rc ){
5204 utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n",
5205 rc, sqlite3_errmsg(db));
5206 }
5207}
5208
drh56eb09b2017-07-11 13:59:07 +00005209#if HAVE_READLINE || HAVE_EDITLINE
5210/*
5211** Readline completion callbacks
5212*/
5213static char *readline_completion_generator(const char *text, int state){
5214 static sqlite3_stmt *pStmt = 0;
5215 char *zRet;
5216 if( state==0 ){
5217 char *zSql;
drh56eb09b2017-07-11 13:59:07 +00005218 sqlite3_finalize(pStmt);
5219 zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
5220 " FROM completion(%Q) ORDER BY 1", text);
drhe3e25652021-12-16 13:29:28 +00005221 shell_check_oom(zSql);
drh56eb09b2017-07-11 13:59:07 +00005222 sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
5223 sqlite3_free(zSql);
5224 }
5225 if( sqlite3_step(pStmt)==SQLITE_ROW ){
drh621a5e02021-12-16 17:35:27 +00005226 const char *z = (const char*)sqlite3_column_text(pStmt,0);
5227 zRet = z ? strdup(z) : 0;
drh56eb09b2017-07-11 13:59:07 +00005228 }else{
5229 sqlite3_finalize(pStmt);
5230 pStmt = 0;
5231 zRet = 0;
5232 }
5233 return zRet;
5234}
5235static char **readline_completion(const char *zText, int iStart, int iEnd){
5236 rl_attempted_completion_over = 1;
5237 return rl_completion_matches(zText, readline_completion_generator);
5238}
5239
5240#elif HAVE_LINENOISE
5241/*
5242** Linenoise completion callback
5243*/
5244static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
drh7d23d152022-10-11 12:02:42 +00005245 i64 nLine = strlen(zLine);
5246 i64 i, iStart;
drh56eb09b2017-07-11 13:59:07 +00005247 sqlite3_stmt *pStmt = 0;
5248 char *zSql;
5249 char zBuf[1000];
5250
5251 if( nLine>sizeof(zBuf)-30 ) return;
drh1615c372018-05-12 23:56:22 +00005252 if( zLine[0]=='.' || zLine[0]=='#') return;
drh56eb09b2017-07-11 13:59:07 +00005253 for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
5254 if( i==nLine-1 ) return;
5255 iStart = i+1;
5256 memcpy(zBuf, zLine, iStart);
5257 zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
5258 " FROM completion(%Q,%Q) ORDER BY 1",
5259 &zLine[iStart], zLine);
drhe3e25652021-12-16 13:29:28 +00005260 shell_check_oom(zSql);
drh56eb09b2017-07-11 13:59:07 +00005261 sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
5262 sqlite3_free(zSql);
5263 sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
5264 while( sqlite3_step(pStmt)==SQLITE_ROW ){
5265 const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
5266 int nCompletion = sqlite3_column_bytes(pStmt, 0);
drh621a5e02021-12-16 17:35:27 +00005267 if( iStart+nCompletion < sizeof(zBuf)-1 && zCompletion ){
drh56eb09b2017-07-11 13:59:07 +00005268 memcpy(zBuf+iStart, zCompletion, nCompletion+1);
5269 linenoiseAddCompletion(lc, zBuf);
5270 }
5271 }
5272 sqlite3_finalize(pStmt);
5273}
5274#endif
5275
drh2ce15c32017-07-11 13:34:40 +00005276/*
5277** Do C-language style dequoting.
5278**
5279** \a -> alarm
5280** \b -> backspace
5281** \t -> tab
5282** \n -> newline
5283** \v -> vertical tab
5284** \f -> form feed
5285** \r -> carriage return
5286** \s -> space
5287** \" -> "
5288** \' -> '
5289** \\ -> backslash
5290** \NNN -> ascii character NNN in octal
5291*/
5292static void resolve_backslashes(char *z){
5293 int i, j;
5294 char c;
5295 while( *z && *z!='\\' ) z++;
5296 for(i=j=0; (c = z[i])!=0; i++, j++){
5297 if( c=='\\' && z[i+1]!=0 ){
5298 c = z[++i];
5299 if( c=='a' ){
5300 c = '\a';
5301 }else if( c=='b' ){
5302 c = '\b';
5303 }else if( c=='t' ){
5304 c = '\t';
5305 }else if( c=='n' ){
5306 c = '\n';
5307 }else if( c=='v' ){
5308 c = '\v';
5309 }else if( c=='f' ){
5310 c = '\f';
5311 }else if( c=='r' ){
5312 c = '\r';
5313 }else if( c=='"' ){
5314 c = '"';
5315 }else if( c=='\'' ){
5316 c = '\'';
5317 }else if( c=='\\' ){
5318 c = '\\';
5319 }else if( c>='0' && c<='7' ){
5320 c -= '0';
5321 if( z[i+1]>='0' && z[i+1]<='7' ){
5322 i++;
5323 c = (c<<3) + z[i] - '0';
5324 if( z[i+1]>='0' && z[i+1]<='7' ){
5325 i++;
5326 c = (c<<3) + z[i] - '0';
5327 }
5328 }
5329 }
5330 }
5331 z[j] = c;
5332 }
5333 if( j<i ) z[j] = 0;
5334}
5335
5336/*
drh2ce15c32017-07-11 13:34:40 +00005337** Interpret zArg as either an integer or a boolean value. Return 1 or 0
5338** for TRUE and FALSE. Return the integer value if appropriate.
5339*/
5340static int booleanValue(const char *zArg){
5341 int i;
5342 if( zArg[0]=='0' && zArg[1]=='x' ){
5343 for(i=2; hexDigitValue(zArg[i])>=0; i++){}
5344 }else{
5345 for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
5346 }
5347 if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
5348 if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
5349 return 1;
5350 }
5351 if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
5352 return 0;
5353 }
5354 utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
5355 zArg);
5356 return 0;
5357}
5358
5359/*
5360** Set or clear a shell flag according to a boolean value.
5361*/
5362static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){
5363 if( booleanValue(zArg) ){
5364 ShellSetFlag(p, mFlag);
5365 }else{
5366 ShellClearFlag(p, mFlag);
5367 }
5368}
5369
5370/*
5371** Close an output file, assuming it is not stderr or stdout
5372*/
5373static void output_file_close(FILE *f){
5374 if( f && f!=stdout && f!=stderr ) fclose(f);
5375}
5376
5377/*
5378** Try to open an output file. The names "stdout" and "stderr" are
5379** recognized and do the right thing. NULL is returned if the output
5380** filename is "off".
5381*/
drha92a01a2018-01-10 22:15:37 +00005382static FILE *output_file_open(const char *zFile, int bTextMode){
drh2ce15c32017-07-11 13:34:40 +00005383 FILE *f;
drhbf70f1b2022-10-19 18:04:42 +00005384 if( cli_strcmp(zFile,"stdout")==0 ){
drh2ce15c32017-07-11 13:34:40 +00005385 f = stdout;
drhbf70f1b2022-10-19 18:04:42 +00005386 }else if( cli_strcmp(zFile, "stderr")==0 ){
drh2ce15c32017-07-11 13:34:40 +00005387 f = stderr;
drhbf70f1b2022-10-19 18:04:42 +00005388 }else if( cli_strcmp(zFile, "off")==0 ){
drh2ce15c32017-07-11 13:34:40 +00005389 f = 0;
5390 }else{
drha92a01a2018-01-10 22:15:37 +00005391 f = fopen(zFile, bTextMode ? "w" : "wb");
drh2ce15c32017-07-11 13:34:40 +00005392 if( f==0 ){
5393 utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
5394 }
5395 }
5396 return f;
5397}
5398
drh707821f2018-12-05 13:39:06 +00005399#ifndef SQLITE_OMIT_TRACE
drh2ce15c32017-07-11 13:34:40 +00005400/*
5401** A routine for handling output from sqlite3_trace().
5402*/
5403static int sql_trace_callback(
drh707821f2018-12-05 13:39:06 +00005404 unsigned mType, /* The trace type */
5405 void *pArg, /* The ShellState pointer */
5406 void *pP, /* Usually a pointer to sqlite_stmt */
5407 void *pX /* Auxiliary output */
drh2ce15c32017-07-11 13:34:40 +00005408){
drh707821f2018-12-05 13:39:06 +00005409 ShellState *p = (ShellState*)pArg;
5410 sqlite3_stmt *pStmt;
5411 const char *zSql;
drh7d23d152022-10-11 12:02:42 +00005412 i64 nSql;
drh707821f2018-12-05 13:39:06 +00005413 if( p->traceOut==0 ) return 0;
5414 if( mType==SQLITE_TRACE_CLOSE ){
5415 utf8_printf(p->traceOut, "-- closing database connection\n");
5416 return 0;
5417 }
5418 if( mType!=SQLITE_TRACE_ROW && ((const char*)pX)[0]=='-' ){
5419 zSql = (const char*)pX;
5420 }else{
5421 pStmt = (sqlite3_stmt*)pP;
5422 switch( p->eTraceType ){
5423 case SHELL_TRACE_EXPANDED: {
5424 zSql = sqlite3_expanded_sql(pStmt);
5425 break;
5426 }
5427#ifdef SQLITE_ENABLE_NORMALIZE
5428 case SHELL_TRACE_NORMALIZED: {
5429 zSql = sqlite3_normalized_sql(pStmt);
5430 break;
5431 }
5432#endif
5433 default: {
5434 zSql = sqlite3_sql(pStmt);
5435 break;
5436 }
5437 }
5438 }
5439 if( zSql==0 ) return 0;
drh7d23d152022-10-11 12:02:42 +00005440 nSql = strlen(zSql);
5441 if( nSql>1000000000 ) nSql = 1000000000;
drh707821f2018-12-05 13:39:06 +00005442 while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
5443 switch( mType ){
5444 case SQLITE_TRACE_ROW:
5445 case SQLITE_TRACE_STMT: {
drh7d23d152022-10-11 12:02:42 +00005446 utf8_printf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
drh707821f2018-12-05 13:39:06 +00005447 break;
5448 }
5449 case SQLITE_TRACE_PROFILE: {
5450 sqlite3_int64 nNanosec = *(sqlite3_int64*)pX;
drh7d23d152022-10-11 12:02:42 +00005451 utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
drh707821f2018-12-05 13:39:06 +00005452 break;
5453 }
drh2ce15c32017-07-11 13:34:40 +00005454 }
5455 return 0;
5456}
5457#endif
drh2ce15c32017-07-11 13:34:40 +00005458
5459/*
5460** A no-op routine that runs with the ".breakpoint" doc-command. This is
5461** a useful spot to set a debugger breakpoint.
5462*/
5463static void test_breakpoint(void){
5464 static int nCall = 0;
5465 nCall++;
5466}
5467
5468/*
5469** An object used to read a CSV and other files for import.
5470*/
5471typedef struct ImportCtx ImportCtx;
5472struct ImportCtx {
5473 const char *zFile; /* Name of the input file */
5474 FILE *in; /* Read the CSV text from this input stream */
drh97767842020-05-29 19:39:35 +00005475 int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close in */
drh2ce15c32017-07-11 13:34:40 +00005476 char *z; /* Accumulated text for a field */
5477 int n; /* Number of bytes in z */
5478 int nAlloc; /* Space allocated for z[] */
5479 int nLine; /* Current line number */
drhccb37812020-03-09 15:39:39 +00005480 int nRow; /* Number of rows imported */
5481 int nErr; /* Number of errors encountered */
drh2ce15c32017-07-11 13:34:40 +00005482 int bNotFirst; /* True if one or more bytes already read */
5483 int cTerm; /* Character that terminated the most recent field */
5484 int cColSep; /* The column separator character. (Usually ",") */
5485 int cRowSep; /* The row separator character. (Usually "\n") */
5486};
5487
drh97767842020-05-29 19:39:35 +00005488/* Clean up resourced used by an ImportCtx */
5489static void import_cleanup(ImportCtx *p){
drh42c2a042020-05-29 20:16:19 +00005490 if( p->in!=0 && p->xCloser!=0 ){
drh97767842020-05-29 19:39:35 +00005491 p->xCloser(p->in);
5492 p->in = 0;
5493 }
5494 sqlite3_free(p->z);
5495 p->z = 0;
5496}
5497
drh2ce15c32017-07-11 13:34:40 +00005498/* Append a single byte to z[] */
5499static void import_append_char(ImportCtx *p, int c){
5500 if( p->n+1>=p->nAlloc ){
5501 p->nAlloc += p->nAlloc + 100;
5502 p->z = sqlite3_realloc64(p->z, p->nAlloc);
drhe3e25652021-12-16 13:29:28 +00005503 shell_check_oom(p->z);
drh2ce15c32017-07-11 13:34:40 +00005504 }
5505 p->z[p->n++] = (char)c;
5506}
5507
5508/* Read a single field of CSV text. Compatible with rfc4180 and extended
5509** with the option of having a separator other than ",".
5510**
5511** + Input comes from p->in.
5512** + Store results in p->z of length p->n. Space to hold p->z comes
5513** from sqlite3_malloc64().
5514** + Use p->cSep as the column separator. The default is ",".
5515** + Use p->rSep as the row separator. The default is "\n".
5516** + Keep track of the line number in p->nLine.
5517** + Store the character that terminates the field in p->cTerm. Store
5518** EOF on end-of-file.
5519** + Report syntax errors on stderr
5520*/
5521static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
5522 int c;
5523 int cSep = p->cColSep;
5524 int rSep = p->cRowSep;
5525 p->n = 0;
5526 c = fgetc(p->in);
5527 if( c==EOF || seenInterrupt ){
5528 p->cTerm = EOF;
5529 return 0;
5530 }
5531 if( c=='"' ){
5532 int pc, ppc;
5533 int startLine = p->nLine;
5534 int cQuote = c;
5535 pc = ppc = 0;
5536 while( 1 ){
5537 c = fgetc(p->in);
5538 if( c==rSep ) p->nLine++;
5539 if( c==cQuote ){
5540 if( pc==cQuote ){
5541 pc = 0;
5542 continue;
5543 }
5544 }
5545 if( (c==cSep && pc==cQuote)
5546 || (c==rSep && pc==cQuote)
5547 || (c==rSep && pc=='\r' && ppc==cQuote)
5548 || (c==EOF && pc==cQuote)
5549 ){
5550 do{ p->n--; }while( p->z[p->n]!=cQuote );
5551 p->cTerm = c;
5552 break;
5553 }
5554 if( pc==cQuote && c!='\r' ){
5555 utf8_printf(stderr, "%s:%d: unescaped %c character\n",
5556 p->zFile, p->nLine, cQuote);
5557 }
5558 if( c==EOF ){
5559 utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n",
5560 p->zFile, startLine, cQuote);
5561 p->cTerm = c;
5562 break;
5563 }
5564 import_append_char(p, c);
5565 ppc = pc;
5566 pc = c;
5567 }
5568 }else{
5569 /* If this is the first field being parsed and it begins with the
5570 ** UTF-8 BOM (0xEF BB BF) then skip the BOM */
5571 if( (c&0xff)==0xef && p->bNotFirst==0 ){
5572 import_append_char(p, c);
5573 c = fgetc(p->in);
5574 if( (c&0xff)==0xbb ){
5575 import_append_char(p, c);
5576 c = fgetc(p->in);
5577 if( (c&0xff)==0xbf ){
5578 p->bNotFirst = 1;
5579 p->n = 0;
5580 return csv_read_one_field(p);
5581 }
5582 }
5583 }
5584 while( c!=EOF && c!=cSep && c!=rSep ){
5585 import_append_char(p, c);
5586 c = fgetc(p->in);
5587 }
5588 if( c==rSep ){
5589 p->nLine++;
5590 if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
5591 }
5592 p->cTerm = c;
5593 }
5594 if( p->z ) p->z[p->n] = 0;
5595 p->bNotFirst = 1;
5596 return p->z;
5597}
5598
5599/* Read a single field of ASCII delimited text.
5600**
5601** + Input comes from p->in.
5602** + Store results in p->z of length p->n. Space to hold p->z comes
5603** from sqlite3_malloc64().
5604** + Use p->cSep as the column separator. The default is "\x1F".
5605** + Use p->rSep as the row separator. The default is "\x1E".
5606** + Keep track of the row number in p->nLine.
5607** + Store the character that terminates the field in p->cTerm. Store
5608** EOF on end-of-file.
5609** + Report syntax errors on stderr
5610*/
5611static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
5612 int c;
5613 int cSep = p->cColSep;
5614 int rSep = p->cRowSep;
5615 p->n = 0;
5616 c = fgetc(p->in);
5617 if( c==EOF || seenInterrupt ){
5618 p->cTerm = EOF;
5619 return 0;
5620 }
5621 while( c!=EOF && c!=cSep && c!=rSep ){
5622 import_append_char(p, c);
5623 c = fgetc(p->in);
5624 }
5625 if( c==rSep ){
5626 p->nLine++;
5627 }
5628 p->cTerm = c;
5629 if( p->z ) p->z[p->n] = 0;
5630 return p->z;
5631}
5632
5633/*
5634** Try to transfer data for table zTable. If an error is seen while
5635** moving forward, try to go backwards. The backwards movement won't
5636** work for WITHOUT ROWID tables.
5637*/
5638static void tryToCloneData(
5639 ShellState *p,
5640 sqlite3 *newDb,
5641 const char *zTable
5642){
5643 sqlite3_stmt *pQuery = 0;
5644 sqlite3_stmt *pInsert = 0;
5645 char *zQuery = 0;
5646 char *zInsert = 0;
5647 int rc;
5648 int i, j, n;
drhaf2770f2018-01-05 14:55:43 +00005649 int nTable = strlen30(zTable);
drh2ce15c32017-07-11 13:34:40 +00005650 int k = 0;
5651 int cnt = 0;
5652 const int spinRate = 10000;
5653
5654 zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
drhe3e25652021-12-16 13:29:28 +00005655 shell_check_oom(zQuery);
drh2ce15c32017-07-11 13:34:40 +00005656 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
5657 if( rc ){
5658 utf8_printf(stderr, "Error %d: %s on [%s]\n",
5659 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
5660 zQuery);
5661 goto end_data_xfer;
5662 }
5663 n = sqlite3_column_count(pQuery);
5664 zInsert = sqlite3_malloc64(200 + nTable + n*3);
drhe3e25652021-12-16 13:29:28 +00005665 shell_check_oom(zInsert);
drh2ce15c32017-07-11 13:34:40 +00005666 sqlite3_snprintf(200+nTable,zInsert,
5667 "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
drhaf2770f2018-01-05 14:55:43 +00005668 i = strlen30(zInsert);
drh2ce15c32017-07-11 13:34:40 +00005669 for(j=1; j<n; j++){
5670 memcpy(zInsert+i, ",?", 2);
5671 i += 2;
5672 }
5673 memcpy(zInsert+i, ");", 3);
5674 rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
5675 if( rc ){
5676 utf8_printf(stderr, "Error %d: %s on [%s]\n",
5677 sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
5678 zQuery);
5679 goto end_data_xfer;
5680 }
5681 for(k=0; k<2; k++){
5682 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
5683 for(i=0; i<n; i++){
5684 switch( sqlite3_column_type(pQuery, i) ){
5685 case SQLITE_NULL: {
5686 sqlite3_bind_null(pInsert, i+1);
5687 break;
5688 }
5689 case SQLITE_INTEGER: {
5690 sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
5691 break;
5692 }
5693 case SQLITE_FLOAT: {
5694 sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
5695 break;
5696 }
5697 case SQLITE_TEXT: {
5698 sqlite3_bind_text(pInsert, i+1,
5699 (const char*)sqlite3_column_text(pQuery,i),
5700 -1, SQLITE_STATIC);
5701 break;
5702 }
5703 case SQLITE_BLOB: {
5704 sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
5705 sqlite3_column_bytes(pQuery,i),
5706 SQLITE_STATIC);
5707 break;
5708 }
5709 }
5710 } /* End for */
5711 rc = sqlite3_step(pInsert);
5712 if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
5713 utf8_printf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
5714 sqlite3_errmsg(newDb));
5715 }
5716 sqlite3_reset(pInsert);
5717 cnt++;
5718 if( (cnt%spinRate)==0 ){
5719 printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
5720 fflush(stdout);
5721 }
5722 } /* End while */
5723 if( rc==SQLITE_DONE ) break;
5724 sqlite3_finalize(pQuery);
5725 sqlite3_free(zQuery);
5726 zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
5727 zTable);
drhe3e25652021-12-16 13:29:28 +00005728 shell_check_oom(zQuery);
drh2ce15c32017-07-11 13:34:40 +00005729 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
5730 if( rc ){
5731 utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
5732 break;
5733 }
5734 } /* End for(k=0...) */
5735
5736end_data_xfer:
5737 sqlite3_finalize(pQuery);
5738 sqlite3_finalize(pInsert);
5739 sqlite3_free(zQuery);
5740 sqlite3_free(zInsert);
5741}
5742
5743
5744/*
5745** Try to transfer all rows of the schema that match zWhere. For
5746** each row, invoke xForEach() on the object defined by that row.
5747** If an error is encountered while moving forward through the
drh067b92b2020-06-19 15:24:12 +00005748** sqlite_schema table, try again moving backwards.
drh2ce15c32017-07-11 13:34:40 +00005749*/
5750static void tryToCloneSchema(
5751 ShellState *p,
5752 sqlite3 *newDb,
5753 const char *zWhere,
5754 void (*xForEach)(ShellState*,sqlite3*,const char*)
5755){
5756 sqlite3_stmt *pQuery = 0;
5757 char *zQuery = 0;
5758 int rc;
5759 const unsigned char *zName;
5760 const unsigned char *zSql;
5761 char *zErrMsg = 0;
5762
drh067b92b2020-06-19 15:24:12 +00005763 zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +00005764 " WHERE %s", zWhere);
drhe3e25652021-12-16 13:29:28 +00005765 shell_check_oom(zQuery);
drh2ce15c32017-07-11 13:34:40 +00005766 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
5767 if( rc ){
5768 utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
5769 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
5770 zQuery);
5771 goto end_schema_xfer;
5772 }
5773 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
5774 zName = sqlite3_column_text(pQuery, 0);
5775 zSql = sqlite3_column_text(pQuery, 1);
drh621a5e02021-12-16 17:35:27 +00005776 if( zName==0 || zSql==0 ) continue;
drh2ce15c32017-07-11 13:34:40 +00005777 printf("%s... ", zName); fflush(stdout);
5778 sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
5779 if( zErrMsg ){
5780 utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
5781 sqlite3_free(zErrMsg);
5782 zErrMsg = 0;
5783 }
5784 if( xForEach ){
5785 xForEach(p, newDb, (const char*)zName);
5786 }
5787 printf("done\n");
5788 }
5789 if( rc!=SQLITE_DONE ){
5790 sqlite3_finalize(pQuery);
5791 sqlite3_free(zQuery);
drh067b92b2020-06-19 15:24:12 +00005792 zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +00005793 " WHERE %s ORDER BY rowid DESC", zWhere);
drhe3e25652021-12-16 13:29:28 +00005794 shell_check_oom(zQuery);
drh2ce15c32017-07-11 13:34:40 +00005795 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
5796 if( rc ){
5797 utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
5798 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
5799 zQuery);
5800 goto end_schema_xfer;
5801 }
drh76fc88f2021-10-02 16:39:16 +00005802 while( sqlite3_step(pQuery)==SQLITE_ROW ){
drh2ce15c32017-07-11 13:34:40 +00005803 zName = sqlite3_column_text(pQuery, 0);
5804 zSql = sqlite3_column_text(pQuery, 1);
drh621a5e02021-12-16 17:35:27 +00005805 if( zName==0 || zSql==0 ) continue;
drh2ce15c32017-07-11 13:34:40 +00005806 printf("%s... ", zName); fflush(stdout);
5807 sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
5808 if( zErrMsg ){
5809 utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
5810 sqlite3_free(zErrMsg);
5811 zErrMsg = 0;
5812 }
5813 if( xForEach ){
5814 xForEach(p, newDb, (const char*)zName);
5815 }
5816 printf("done\n");
5817 }
5818 }
5819end_schema_xfer:
5820 sqlite3_finalize(pQuery);
5821 sqlite3_free(zQuery);
5822}
5823
5824/*
5825** Open a new database file named "zNewDb". Try to recover as much information
5826** as possible out of the main database (which might be corrupt) and write it
5827** into zNewDb.
5828*/
5829static void tryToClone(ShellState *p, const char *zNewDb){
5830 int rc;
5831 sqlite3 *newDb = 0;
5832 if( access(zNewDb,0)==0 ){
5833 utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb);
5834 return;
5835 }
5836 rc = sqlite3_open(zNewDb, &newDb);
5837 if( rc ){
5838 utf8_printf(stderr, "Cannot create output database: %s\n",
5839 sqlite3_errmsg(newDb));
5840 }else{
5841 sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
5842 sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
5843 tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
5844 tryToCloneSchema(p, newDb, "type!='table'", 0);
5845 sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
5846 sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
5847 }
drh9e804032018-05-18 17:11:50 +00005848 close_db(newDb);
drh2ce15c32017-07-11 13:34:40 +00005849}
5850
5851/*
drh13c20932018-01-10 21:41:55 +00005852** Change the output file back to stdout.
5853**
5854** If the p->doXdgOpen flag is set, that means the output was being
5855** redirected to a temporary file named by p->zTempFile. In that case,
5856** launch start/open/xdg-open on that temporary file.
drh2ce15c32017-07-11 13:34:40 +00005857*/
5858static void output_reset(ShellState *p){
5859 if( p->outfile[0]=='|' ){
5860#ifndef SQLITE_OMIT_POPEN
5861 pclose(p->out);
5862#endif
5863 }else{
5864 output_file_close(p->out);
drh04a28c32018-01-31 01:38:44 +00005865#ifndef SQLITE_NOHAVE_SYSTEM
drh13c20932018-01-10 21:41:55 +00005866 if( p->doXdgOpen ){
5867 const char *zXdgOpenCmd =
5868#if defined(_WIN32)
5869 "start";
5870#elif defined(__APPLE__)
5871 "open";
5872#else
5873 "xdg-open";
5874#endif
5875 char *zCmd;
5876 zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
drha92a01a2018-01-10 22:15:37 +00005877 if( system(zCmd) ){
5878 utf8_printf(stderr, "Failed: [%s]\n", zCmd);
drh1d9ea272020-04-17 23:46:54 +00005879 }else{
5880 /* Give the start/open/xdg-open command some time to get
5881 ** going before we continue, and potential delete the
5882 ** p->zTempFile data file out from under it */
5883 sqlite3_sleep(2000);
drha92a01a2018-01-10 22:15:37 +00005884 }
drh13c20932018-01-10 21:41:55 +00005885 sqlite3_free(zCmd);
drh3c484e82018-01-10 22:27:21 +00005886 outputModePop(p);
drh13c20932018-01-10 21:41:55 +00005887 p->doXdgOpen = 0;
5888 }
drh04a28c32018-01-31 01:38:44 +00005889#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
drh2ce15c32017-07-11 13:34:40 +00005890 }
5891 p->outfile[0] = 0;
5892 p->out = stdout;
5893}
5894
5895/*
5896** Run an SQL command and return the single integer result.
5897*/
larrybr58a53d62022-02-10 03:21:48 +00005898static int db_int(sqlite3 *db, const char *zSql){
drh2ce15c32017-07-11 13:34:40 +00005899 sqlite3_stmt *pStmt;
5900 int res = 0;
larrybr58a53d62022-02-10 03:21:48 +00005901 sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
drh2ce15c32017-07-11 13:34:40 +00005902 if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
5903 res = sqlite3_column_int(pStmt,0);
5904 }
5905 sqlite3_finalize(pStmt);
5906 return res;
5907}
5908
drh04836682022-06-08 18:29:23 +00005909#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
drh2ce15c32017-07-11 13:34:40 +00005910/*
5911** Convert a 2-byte or 4-byte big-endian integer into a native integer
5912*/
5913static unsigned int get2byteInt(unsigned char *a){
5914 return (a[0]<<8) + a[1];
5915}
5916static unsigned int get4byteInt(unsigned char *a){
5917 return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
5918}
5919
5920/*
drh76c12062020-01-14 13:13:19 +00005921** Implementation of the ".dbinfo" command.
drh2ce15c32017-07-11 13:34:40 +00005922**
5923** Return 1 on error, 2 to exit, and 0 otherwise.
5924*/
5925static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
5926 static const struct { const char *zName; int ofst; } aField[] = {
5927 { "file change counter:", 24 },
5928 { "database page count:", 28 },
5929 { "freelist page count:", 36 },
5930 { "schema cookie:", 40 },
5931 { "schema format:", 44 },
5932 { "default cache size:", 48 },
5933 { "autovacuum top root:", 52 },
5934 { "incremental vacuum:", 64 },
5935 { "text encoding:", 56 },
5936 { "user version:", 60 },
5937 { "application id:", 68 },
5938 { "software version:", 96 },
5939 };
5940 static const struct { const char *zName; const char *zSql; } aQuery[] = {
5941 { "number of tables:",
5942 "SELECT count(*) FROM %s WHERE type='table'" },
5943 { "number of indexes:",
5944 "SELECT count(*) FROM %s WHERE type='index'" },
5945 { "number of triggers:",
5946 "SELECT count(*) FROM %s WHERE type='trigger'" },
5947 { "number of views:",
5948 "SELECT count(*) FROM %s WHERE type='view'" },
5949 { "schema size:",
5950 "SELECT total(length(sql)) FROM %s" },
5951 };
drh87c889c2019-03-20 18:22:51 +00005952 int i, rc;
drhea99a312018-07-18 19:09:07 +00005953 unsigned iDataVersion;
drh2ce15c32017-07-11 13:34:40 +00005954 char *zSchemaTab;
5955 char *zDb = nArg>=2 ? azArg[1] : "main";
drh512e6c32017-10-11 17:51:08 +00005956 sqlite3_stmt *pStmt = 0;
drh2ce15c32017-07-11 13:34:40 +00005957 unsigned char aHdr[100];
5958 open_db(p, 0);
5959 if( p->db==0 ) return 1;
drh87c889c2019-03-20 18:22:51 +00005960 rc = sqlite3_prepare_v2(p->db,
5961 "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
5962 -1, &pStmt, 0);
5963 if( rc ){
drh451f89a2020-04-28 23:09:56 +00005964 utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db));
drh87c889c2019-03-20 18:22:51 +00005965 sqlite3_finalize(pStmt);
5966 return 1;
5967 }
drh512e6c32017-10-11 17:51:08 +00005968 sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
5969 if( sqlite3_step(pStmt)==SQLITE_ROW
5970 && sqlite3_column_bytes(pStmt,0)>100
5971 ){
5972 memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
5973 sqlite3_finalize(pStmt);
5974 }else{
drh2ce15c32017-07-11 13:34:40 +00005975 raw_printf(stderr, "unable to read database header\n");
drh512e6c32017-10-11 17:51:08 +00005976 sqlite3_finalize(pStmt);
drh2ce15c32017-07-11 13:34:40 +00005977 return 1;
5978 }
5979 i = get2byteInt(aHdr+16);
5980 if( i==1 ) i = 65536;
5981 utf8_printf(p->out, "%-20s %d\n", "database page size:", i);
5982 utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
5983 utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
5984 utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
5985 for(i=0; i<ArraySize(aField); i++){
5986 int ofst = aField[i].ofst;
5987 unsigned int val = get4byteInt(aHdr + ofst);
5988 utf8_printf(p->out, "%-20s %u", aField[i].zName, val);
5989 switch( ofst ){
5990 case 56: {
5991 if( val==1 ) raw_printf(p->out, " (utf8)");
5992 if( val==2 ) raw_printf(p->out, " (utf16le)");
5993 if( val==3 ) raw_printf(p->out, " (utf16be)");
5994 }
5995 }
5996 raw_printf(p->out, "\n");
5997 }
5998 if( zDb==0 ){
drh067b92b2020-06-19 15:24:12 +00005999 zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
drhbf70f1b2022-10-19 18:04:42 +00006000 }else if( cli_strcmp(zDb,"temp")==0 ){
drh067b92b2020-06-19 15:24:12 +00006001 zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema");
drh2ce15c32017-07-11 13:34:40 +00006002 }else{
drh067b92b2020-06-19 15:24:12 +00006003 zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
drh2ce15c32017-07-11 13:34:40 +00006004 }
6005 for(i=0; i<ArraySize(aQuery); i++){
6006 char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
larrybr58a53d62022-02-10 03:21:48 +00006007 int val = db_int(p->db, zSql);
drh2ce15c32017-07-11 13:34:40 +00006008 sqlite3_free(zSql);
6009 utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
6010 }
6011 sqlite3_free(zSchemaTab);
drhea99a312018-07-18 19:09:07 +00006012 sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
6013 utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion);
drh2ce15c32017-07-11 13:34:40 +00006014 return 0;
6015}
stephan3d420832022-10-27 03:56:01 +00006016#endif /* SQLITE_SHELL_HAVE_RECOVER */
drh2ce15c32017-07-11 13:34:40 +00006017
6018/*
6019** Print the current sqlite3_errmsg() value to stderr and return 1.
6020*/
6021static int shellDatabaseError(sqlite3 *db){
6022 const char *zErr = sqlite3_errmsg(db);
6023 utf8_printf(stderr, "Error: %s\n", zErr);
6024 return 1;
6025}
6026
6027/*
drh2ce15c32017-07-11 13:34:40 +00006028** Compare the pattern in zGlob[] against the text in z[]. Return TRUE
6029** if they match and FALSE (0) if they do not match.
6030**
6031** Globbing rules:
6032**
6033** '*' Matches any sequence of zero or more characters.
6034**
6035** '?' Matches exactly one character.
6036**
6037** [...] Matches one character from the enclosed list of
6038** characters.
6039**
6040** [^...] Matches one character not in the enclosed list.
6041**
6042** '#' Matches any sequence of one or more digits with an
6043** optional + or - sign in front
6044**
6045** ' ' Any span of whitespace matches any other span of
6046** whitespace.
6047**
6048** Extra whitespace at the end of z[] is ignored.
6049*/
6050static int testcase_glob(const char *zGlob, const char *z){
6051 int c, c2;
6052 int invert;
6053 int seen;
6054
6055 while( (c = (*(zGlob++)))!=0 ){
6056 if( IsSpace(c) ){
6057 if( !IsSpace(*z) ) return 0;
6058 while( IsSpace(*zGlob) ) zGlob++;
6059 while( IsSpace(*z) ) z++;
6060 }else if( c=='*' ){
6061 while( (c=(*(zGlob++))) == '*' || c=='?' ){
6062 if( c=='?' && (*(z++))==0 ) return 0;
6063 }
6064 if( c==0 ){
6065 return 1;
6066 }else if( c=='[' ){
6067 while( *z && testcase_glob(zGlob-1,z)==0 ){
6068 z++;
6069 }
6070 return (*z)!=0;
6071 }
6072 while( (c2 = (*(z++)))!=0 ){
6073 while( c2!=c ){
6074 c2 = *(z++);
6075 if( c2==0 ) return 0;
6076 }
6077 if( testcase_glob(zGlob,z) ) return 1;
6078 }
6079 return 0;
6080 }else if( c=='?' ){
6081 if( (*(z++))==0 ) return 0;
6082 }else if( c=='[' ){
6083 int prior_c = 0;
6084 seen = 0;
6085 invert = 0;
6086 c = *(z++);
6087 if( c==0 ) return 0;
6088 c2 = *(zGlob++);
6089 if( c2=='^' ){
6090 invert = 1;
6091 c2 = *(zGlob++);
6092 }
6093 if( c2==']' ){
6094 if( c==']' ) seen = 1;
6095 c2 = *(zGlob++);
6096 }
6097 while( c2 && c2!=']' ){
6098 if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
6099 c2 = *(zGlob++);
6100 if( c>=prior_c && c<=c2 ) seen = 1;
6101 prior_c = 0;
6102 }else{
6103 if( c==c2 ){
6104 seen = 1;
6105 }
6106 prior_c = c2;
6107 }
6108 c2 = *(zGlob++);
6109 }
6110 if( c2==0 || (seen ^ invert)==0 ) return 0;
6111 }else if( c=='#' ){
6112 if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++;
6113 if( !IsDigit(z[0]) ) return 0;
6114 z++;
6115 while( IsDigit(z[0]) ){ z++; }
6116 }else{
6117 if( c!=(*(z++)) ) return 0;
6118 }
6119 }
6120 while( IsSpace(*z) ){ z++; }
6121 return *z==0;
6122}
6123
6124
6125/*
6126** Compare the string as a command-line option with either one or two
6127** initial "-" characters.
6128*/
6129static int optionMatch(const char *zStr, const char *zOpt){
6130 if( zStr[0]!='-' ) return 0;
6131 zStr++;
6132 if( zStr[0]=='-' ) zStr++;
drhbf70f1b2022-10-19 18:04:42 +00006133 return cli_strcmp(zStr, zOpt)==0;
drh2ce15c32017-07-11 13:34:40 +00006134}
6135
6136/*
6137** Delete a file.
6138*/
6139int shellDeleteFile(const char *zFilename){
6140 int rc;
6141#ifdef _WIN32
6142 wchar_t *z = sqlite3_win32_utf8_to_unicode(zFilename);
6143 rc = _wunlink(z);
6144 sqlite3_free(z);
6145#else
6146 rc = unlink(zFilename);
6147#endif
6148 return rc;
6149}
6150
drh13c20932018-01-10 21:41:55 +00006151/*
6152** Try to delete the temporary file (if there is one) and free the
6153** memory used to hold the name of the temp file.
6154*/
6155static void clearTempFile(ShellState *p){
6156 if( p->zTempFile==0 ) return;
drh536c3452018-01-11 00:38:39 +00006157 if( p->doXdgOpen ) return;
drh13c20932018-01-10 21:41:55 +00006158 if( shellDeleteFile(p->zTempFile) ) return;
6159 sqlite3_free(p->zTempFile);
6160 p->zTempFile = 0;
6161}
6162
6163/*
6164** Create a new temp file name with the given suffix.
6165*/
6166static void newTempFile(ShellState *p, const char *zSuffix){
6167 clearTempFile(p);
6168 sqlite3_free(p->zTempFile);
6169 p->zTempFile = 0;
drh7f3bf8a2018-01-10 21:50:08 +00006170 if( p->db ){
6171 sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
6172 }
drh13c20932018-01-10 21:41:55 +00006173 if( p->zTempFile==0 ){
drh1d9ea272020-04-17 23:46:54 +00006174 /* If p->db is an in-memory database then the TEMPFILENAME file-control
6175 ** will not work and we will need to fallback to guessing */
6176 char *zTemp;
drh13c20932018-01-10 21:41:55 +00006177 sqlite3_uint64 r;
6178 sqlite3_randomness(sizeof(r), &r);
drh1d9ea272020-04-17 23:46:54 +00006179 zTemp = getenv("TEMP");
6180 if( zTemp==0 ) zTemp = getenv("TMP");
6181 if( zTemp==0 ){
6182#ifdef _WIN32
6183 zTemp = "\\tmp";
6184#else
6185 zTemp = "/tmp";
6186#endif
6187 }
6188 p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
drh13c20932018-01-10 21:41:55 +00006189 }else{
6190 p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
6191 }
drhe3e25652021-12-16 13:29:28 +00006192 shell_check_oom(p->zTempFile);
drh13c20932018-01-10 21:41:55 +00006193}
6194
drh2ce15c32017-07-11 13:34:40 +00006195
6196/*
6197** The implementation of SQL scalar function fkey_collate_clause(), used
6198** by the ".lint fkey-indexes" command. This scalar function is always
6199** called with four arguments - the parent table name, the parent column name,
6200** the child table name and the child column name.
6201**
6202** fkey_collate_clause('parent-tab', 'parent-col', 'child-tab', 'child-col')
6203**
6204** If either of the named tables or columns do not exist, this function
6205** returns an empty string. An empty string is also returned if both tables
6206** and columns exist but have the same default collation sequence. Or,
6207** if both exist but the default collation sequences are different, this
6208** function returns the string " COLLATE <parent-collation>", where
6209** <parent-collation> is the default collation sequence of the parent column.
6210*/
6211static void shellFkeyCollateClause(
6212 sqlite3_context *pCtx,
6213 int nVal,
6214 sqlite3_value **apVal
6215){
6216 sqlite3 *db = sqlite3_context_db_handle(pCtx);
6217 const char *zParent;
6218 const char *zParentCol;
6219 const char *zParentSeq;
6220 const char *zChild;
6221 const char *zChildCol;
6222 const char *zChildSeq = 0; /* Initialize to avoid false-positive warning */
6223 int rc;
6224
6225 assert( nVal==4 );
6226 zParent = (const char*)sqlite3_value_text(apVal[0]);
6227 zParentCol = (const char*)sqlite3_value_text(apVal[1]);
6228 zChild = (const char*)sqlite3_value_text(apVal[2]);
6229 zChildCol = (const char*)sqlite3_value_text(apVal[3]);
6230
6231 sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
6232 rc = sqlite3_table_column_metadata(
6233 db, "main", zParent, zParentCol, 0, &zParentSeq, 0, 0, 0
6234 );
6235 if( rc==SQLITE_OK ){
6236 rc = sqlite3_table_column_metadata(
6237 db, "main", zChild, zChildCol, 0, &zChildSeq, 0, 0, 0
6238 );
6239 }
6240
6241 if( rc==SQLITE_OK && sqlite3_stricmp(zParentSeq, zChildSeq) ){
6242 char *z = sqlite3_mprintf(" COLLATE %s", zParentSeq);
6243 sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
6244 sqlite3_free(z);
6245 }
6246}
6247
6248
6249/*
6250** The implementation of dot-command ".lint fkey-indexes".
6251*/
6252static int lintFkeyIndexes(
6253 ShellState *pState, /* Current shell tool state */
6254 char **azArg, /* Array of arguments passed to dot command */
6255 int nArg /* Number of entries in azArg[] */
6256){
6257 sqlite3 *db = pState->db; /* Database handle to query "main" db of */
6258 FILE *out = pState->out; /* Stream to write non-error output to */
6259 int bVerbose = 0; /* If -verbose is present */
6260 int bGroupByParent = 0; /* If -groupbyparent is present */
6261 int i; /* To iterate through azArg[] */
6262 const char *zIndent = ""; /* How much to indent CREATE INDEX by */
6263 int rc; /* Return code */
6264 sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
6265
6266 /*
6267 ** This SELECT statement returns one row for each foreign key constraint
6268 ** in the schema of the main database. The column values are:
6269 **
6270 ** 0. The text of an SQL statement similar to:
6271 **
danf9679312017-12-01 18:40:18 +00006272 ** "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
drh2ce15c32017-07-11 13:34:40 +00006273 **
danf9679312017-12-01 18:40:18 +00006274 ** This SELECT is similar to the one that the foreign keys implementation
6275 ** needs to run internally on child tables. If there is an index that can
drh2ce15c32017-07-11 13:34:40 +00006276 ** be used to optimize this query, then it can also be used by the FK
6277 ** implementation to optimize DELETE or UPDATE statements on the parent
6278 ** table.
6279 **
6280 ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
6281 ** the EXPLAIN QUERY PLAN command matches this pattern, then the schema
6282 ** contains an index that can be used to optimize the query.
6283 **
6284 ** 2. Human readable text that describes the child table and columns. e.g.
6285 **
6286 ** "child_table(child_key1, child_key2)"
6287 **
6288 ** 3. Human readable text that describes the parent table and columns. e.g.
6289 **
6290 ** "parent_table(parent_key1, parent_key2)"
6291 **
6292 ** 4. A full CREATE INDEX statement for an index that could be used to
6293 ** optimize DELETE or UPDATE statements on the parent table. e.g.
6294 **
6295 ** "CREATE INDEX child_table_child_key ON child_table(child_key)"
6296 **
6297 ** 5. The name of the parent table.
6298 **
6299 ** These six values are used by the C logic below to generate the report.
6300 */
6301 const char *zSql =
6302 "SELECT "
danf9679312017-12-01 18:40:18 +00006303 " 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
drh2ce15c32017-07-11 13:34:40 +00006304 " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
6305 " || fkey_collate_clause("
6306 " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
6307 ", "
drh82102332021-03-20 15:11:29 +00006308 " 'SEARCH ' || s.name || ' USING COVERING INDEX*('"
drh2ce15c32017-07-11 13:34:40 +00006309 " || group_concat('*=?', ' AND ') || ')'"
6310 ", "
6311 " s.name || '(' || group_concat(f.[from], ', ') || ')'"
6312 ", "
6313 " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
6314 ", "
6315 " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
6316 " || ' ON ' || quote(s.name) || '('"
6317 " || group_concat(quote(f.[from]) ||"
6318 " fkey_collate_clause("
6319 " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
6320 " || ');'"
6321 ", "
6322 " f.[table] "
drh067b92b2020-06-19 15:24:12 +00006323 "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f "
drh2ce15c32017-07-11 13:34:40 +00006324 "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
6325 "GROUP BY s.name, f.id "
6326 "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
6327 ;
drh82102332021-03-20 15:11:29 +00006328 const char *zGlobIPK = "SEARCH * USING INTEGER PRIMARY KEY (rowid=?)";
drh2ce15c32017-07-11 13:34:40 +00006329
6330 for(i=2; i<nArg; i++){
drhaf2770f2018-01-05 14:55:43 +00006331 int n = strlen30(azArg[i]);
drh2ce15c32017-07-11 13:34:40 +00006332 if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
6333 bVerbose = 1;
6334 }
6335 else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
6336 bGroupByParent = 1;
6337 zIndent = " ";
6338 }
6339 else{
6340 raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
6341 azArg[0], azArg[1]
6342 );
6343 return SQLITE_ERROR;
6344 }
6345 }
6346
6347 /* Register the fkey_collate_clause() SQL function */
6348 rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
6349 0, shellFkeyCollateClause, 0, 0
6350 );
6351
6352
6353 if( rc==SQLITE_OK ){
6354 rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
6355 }
6356 if( rc==SQLITE_OK ){
6357 sqlite3_bind_int(pSql, 1, bGroupByParent);
6358 }
6359
6360 if( rc==SQLITE_OK ){
6361 int rc2;
6362 char *zPrev = 0;
6363 while( SQLITE_ROW==sqlite3_step(pSql) ){
6364 int res = -1;
6365 sqlite3_stmt *pExplain = 0;
6366 const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
6367 const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
6368 const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
6369 const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
6370 const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
6371 const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
6372
drh621a5e02021-12-16 17:35:27 +00006373 if( zEQP==0 ) continue;
6374 if( zGlob==0 ) continue;
drh2ce15c32017-07-11 13:34:40 +00006375 rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
6376 if( rc!=SQLITE_OK ) break;
6377 if( SQLITE_ROW==sqlite3_step(pExplain) ){
6378 const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
drh621a5e02021-12-16 17:35:27 +00006379 res = zPlan!=0 && ( 0==sqlite3_strglob(zGlob, zPlan)
6380 || 0==sqlite3_strglob(zGlobIPK, zPlan));
drh2ce15c32017-07-11 13:34:40 +00006381 }
6382 rc = sqlite3_finalize(pExplain);
6383 if( rc!=SQLITE_OK ) break;
6384
6385 if( res<0 ){
6386 raw_printf(stderr, "Error: internal error");
6387 break;
6388 }else{
6389 if( bGroupByParent
6390 && (bVerbose || res==0)
6391 && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
6392 ){
6393 raw_printf(out, "-- Parent table %s\n", zParent);
6394 sqlite3_free(zPrev);
6395 zPrev = sqlite3_mprintf("%s", zParent);
6396 }
6397
6398 if( res==0 ){
6399 raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
6400 }else if( bVerbose ){
6401 raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
6402 zIndent, zFrom, zTarget
6403 );
6404 }
6405 }
6406 }
6407 sqlite3_free(zPrev);
6408
6409 if( rc!=SQLITE_OK ){
6410 raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
6411 }
6412
6413 rc2 = sqlite3_finalize(pSql);
6414 if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
6415 rc = rc2;
6416 raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
6417 }
6418 }else{
6419 raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
6420 }
6421
6422 return rc;
6423}
6424
6425/*
6426** Implementation of ".lint" dot command.
6427*/
6428static int lintDotCommand(
6429 ShellState *pState, /* Current shell tool state */
6430 char **azArg, /* Array of arguments passed to dot command */
6431 int nArg /* Number of entries in azArg[] */
6432){
6433 int n;
drhaf2770f2018-01-05 14:55:43 +00006434 n = (nArg>=2 ? strlen30(azArg[1]) : 0);
drh2ce15c32017-07-11 13:34:40 +00006435 if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
6436 return lintFkeyIndexes(pState, azArg, nArg);
6437
6438 usage:
6439 raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
6440 raw_printf(stderr, "Where sub-commands are:\n");
6441 raw_printf(stderr, " fkey-indexes\n");
6442 return SQLITE_ERROR;
6443}
6444
dan1b162162019-04-27 20:15:15 +00006445#if !defined SQLITE_OMIT_VIRTUALTABLE
danfd0245d2017-12-07 15:44:29 +00006446static void shellPrepare(
dand4b56e52017-12-12 20:04:59 +00006447 sqlite3 *db,
danfd0245d2017-12-07 15:44:29 +00006448 int *pRc,
6449 const char *zSql,
6450 sqlite3_stmt **ppStmt
6451){
6452 *ppStmt = 0;
6453 if( *pRc==SQLITE_OK ){
dand4b56e52017-12-12 20:04:59 +00006454 int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
danfd0245d2017-12-07 15:44:29 +00006455 if( rc!=SQLITE_OK ){
6456 raw_printf(stderr, "sql error: %s (%d)\n",
dand4b56e52017-12-12 20:04:59 +00006457 sqlite3_errmsg(db), sqlite3_errcode(db)
danfd0245d2017-12-07 15:44:29 +00006458 );
6459 *pRc = rc;
6460 }
6461 }
6462}
6463
drh9546c762019-05-10 17:50:33 +00006464/*
6465** Create a prepared statement using printf-style arguments for the SQL.
6466**
6467** This routine is could be marked "static". But it is not always used,
6468** depending on compile-time options. By omitting the "static", we avoid
6469** nuisance compiler warnings about "defined but not used".
6470*/
6471void shellPreparePrintf(
dan3f67ddf2017-12-13 20:04:53 +00006472 sqlite3 *db,
6473 int *pRc,
danac15e2d2017-12-14 19:15:07 +00006474 sqlite3_stmt **ppStmt,
6475 const char *zFmt,
6476 ...
dan3f67ddf2017-12-13 20:04:53 +00006477){
danac15e2d2017-12-14 19:15:07 +00006478 *ppStmt = 0;
6479 if( *pRc==SQLITE_OK ){
6480 va_list ap;
6481 char *z;
6482 va_start(ap, zFmt);
6483 z = sqlite3_vmprintf(zFmt, ap);
drh1dbb1472018-10-11 10:37:24 +00006484 va_end(ap);
dan3f67ddf2017-12-13 20:04:53 +00006485 if( z==0 ){
6486 *pRc = SQLITE_NOMEM;
6487 }else{
6488 shellPrepare(db, pRc, z, ppStmt);
6489 sqlite3_free(z);
6490 }
dan3f67ddf2017-12-13 20:04:53 +00006491 }
6492}
6493
drh9546c762019-05-10 17:50:33 +00006494/* Finalize the prepared statement created using shellPreparePrintf().
6495**
6496** This routine is could be marked "static". But it is not always used,
6497** depending on compile-time options. By omitting the "static", we avoid
6498** nuisance compiler warnings about "defined but not used".
6499*/
6500void shellFinalize(
danfd0245d2017-12-07 15:44:29 +00006501 int *pRc,
6502 sqlite3_stmt *pStmt
6503){
dan25c12182017-12-07 21:03:33 +00006504 if( pStmt ){
6505 sqlite3 *db = sqlite3_db_handle(pStmt);
6506 int rc = sqlite3_finalize(pStmt);
6507 if( *pRc==SQLITE_OK ){
6508 if( rc!=SQLITE_OK ){
6509 raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
6510 }
6511 *pRc = rc;
6512 }
6513 }
danfd0245d2017-12-07 15:44:29 +00006514}
6515
drh9546c762019-05-10 17:50:33 +00006516/* Reset the prepared statement created using shellPreparePrintf().
6517**
6518** This routine is could be marked "static". But it is not always used,
6519** depending on compile-time options. By omitting the "static", we avoid
6520** nuisance compiler warnings about "defined but not used".
6521*/
6522void shellReset(
danfd0245d2017-12-07 15:44:29 +00006523 int *pRc,
6524 sqlite3_stmt *pStmt
6525){
6526 int rc = sqlite3_reset(pStmt);
dan5a78b812017-12-27 18:54:11 +00006527 if( *pRc==SQLITE_OK ){
6528 if( rc!=SQLITE_OK ){
6529 sqlite3 *db = sqlite3_db_handle(pStmt);
6530 raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
6531 }
6532 *pRc = rc;
6533 }
danfd0245d2017-12-07 15:44:29 +00006534}
dan1b162162019-04-27 20:15:15 +00006535#endif /* !defined SQLITE_OMIT_VIRTUALTABLE */
6536
6537#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
drhe2754c12019-08-26 12:50:01 +00006538/******************************************************************************
dan1b162162019-04-27 20:15:15 +00006539** The ".archive" or ".ar" command.
6540*/
drhe37c0e12018-01-06 19:19:50 +00006541/*
dan88be0202017-12-09 17:58:02 +00006542** Structure representing a single ".ar" command.
6543*/
6544typedef struct ArCommand ArCommand;
6545struct ArCommand {
drhb376b3d2018-01-10 13:11:51 +00006546 u8 eCmd; /* An AR_CMD_* value */
6547 u8 bVerbose; /* True if --verbose */
drha5676c42018-01-10 15:17:34 +00006548 u8 bZip; /* True if the archive is a ZIP */
drhb376b3d2018-01-10 13:11:51 +00006549 u8 bDryRun; /* True if --dry-run */
drha5676c42018-01-10 15:17:34 +00006550 u8 bAppend; /* True if --append */
larrybr8f09f4b2021-11-02 00:18:11 +00006551 u8 bGlob; /* True if --glob */
drhd0f9cdc2018-05-17 14:09:06 +00006552 u8 fromCmdLine; /* Run from -A instead of .archive */
drhb376b3d2018-01-10 13:11:51 +00006553 int nArg; /* Number of command arguments */
drha5676c42018-01-10 15:17:34 +00006554 char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */
dan88be0202017-12-09 17:58:02 +00006555 const char *zFile; /* --file argument, or NULL */
6556 const char *zDir; /* --directory argument, or NULL */
dan88be0202017-12-09 17:58:02 +00006557 char **azArg; /* Array of command arguments */
drhb376b3d2018-01-10 13:11:51 +00006558 ShellState *p; /* Shell state */
6559 sqlite3 *db; /* Database containing the archive */
dan88be0202017-12-09 17:58:02 +00006560};
6561
6562/*
6563** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
6564*/
dan0d0547f2017-12-14 15:40:42 +00006565static int arUsage(FILE *f){
drh98aa2ab2018-09-26 16:53:51 +00006566 showHelp(f,"archive");
dan0d0547f2017-12-14 15:40:42 +00006567 return SQLITE_ERROR;
6568}
6569
6570/*
6571** Print an error message for the .ar command to stderr and return
6572** SQLITE_ERROR.
6573*/
drhd0f9cdc2018-05-17 14:09:06 +00006574static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){
dan0d0547f2017-12-14 15:40:42 +00006575 va_list ap;
6576 char *z;
6577 va_start(ap, zFmt);
6578 z = sqlite3_vmprintf(zFmt, ap);
6579 va_end(ap);
drhd0f9cdc2018-05-17 14:09:06 +00006580 utf8_printf(stderr, "Error: %s\n", z);
6581 if( pAr->fromCmdLine ){
6582 utf8_printf(stderr, "Use \"-A\" for more help\n");
6583 }else{
6584 utf8_printf(stderr, "Use \".archive --help\" for more help\n");
6585 }
dan0d0547f2017-12-14 15:40:42 +00006586 sqlite3_free(z);
dan88be0202017-12-09 17:58:02 +00006587 return SQLITE_ERROR;
6588}
6589
6590/*
6591** Values for ArCommand.eCmd.
6592*/
dand4b56e52017-12-12 20:04:59 +00006593#define AR_CMD_CREATE 1
drhb17ea912019-03-25 14:24:19 +00006594#define AR_CMD_UPDATE 2
6595#define AR_CMD_INSERT 3
6596#define AR_CMD_EXTRACT 4
6597#define AR_CMD_LIST 5
6598#define AR_CMD_HELP 6
larrybr47061b92021-11-01 17:22:52 +00006599#define AR_CMD_REMOVE 7
dand4b56e52017-12-12 20:04:59 +00006600
6601/*
6602** Other (non-command) switches.
6603*/
larrybr47061b92021-11-01 17:22:52 +00006604#define AR_SWITCH_VERBOSE 8
6605#define AR_SWITCH_FILE 9
6606#define AR_SWITCH_DIRECTORY 10
6607#define AR_SWITCH_APPEND 11
larrybr719506f2021-11-01 22:33:20 +00006608#define AR_SWITCH_DRYRUN 12
larrybr8f09f4b2021-11-02 00:18:11 +00006609#define AR_SWITCH_GLOB 13
dand4b56e52017-12-12 20:04:59 +00006610
6611static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
6612 switch( eSwitch ){
6613 case AR_CMD_CREATE:
6614 case AR_CMD_EXTRACT:
6615 case AR_CMD_LIST:
larrybr47061b92021-11-01 17:22:52 +00006616 case AR_CMD_REMOVE:
dand4b56e52017-12-12 20:04:59 +00006617 case AR_CMD_UPDATE:
drhb17ea912019-03-25 14:24:19 +00006618 case AR_CMD_INSERT:
dan0d0547f2017-12-14 15:40:42 +00006619 case AR_CMD_HELP:
6620 if( pAr->eCmd ){
drhd0f9cdc2018-05-17 14:09:06 +00006621 return arErrorMsg(pAr, "multiple command options");
dan0d0547f2017-12-14 15:40:42 +00006622 }
dand4b56e52017-12-12 20:04:59 +00006623 pAr->eCmd = eSwitch;
6624 break;
6625
drhb376b3d2018-01-10 13:11:51 +00006626 case AR_SWITCH_DRYRUN:
6627 pAr->bDryRun = 1;
6628 break;
larrybr8f09f4b2021-11-02 00:18:11 +00006629 case AR_SWITCH_GLOB:
6630 pAr->bGlob = 1;
6631 break;
dand4b56e52017-12-12 20:04:59 +00006632 case AR_SWITCH_VERBOSE:
6633 pAr->bVerbose = 1;
6634 break;
drha5676c42018-01-10 15:17:34 +00006635 case AR_SWITCH_APPEND:
6636 pAr->bAppend = 1;
drhca7733b2018-01-10 18:09:20 +00006637 /* Fall thru into --file */
dand4b56e52017-12-12 20:04:59 +00006638 case AR_SWITCH_FILE:
6639 pAr->zFile = zArg;
6640 break;
6641 case AR_SWITCH_DIRECTORY:
6642 pAr->zDir = zArg;
6643 break;
6644 }
6645
6646 return SQLITE_OK;
6647}
dan88be0202017-12-09 17:58:02 +00006648
6649/*
6650** Parse the command line for an ".ar" command. The results are written into
6651** structure (*pAr). SQLITE_OK is returned if the command line is parsed
6652** successfully, otherwise an error message is written to stderr and
6653** SQLITE_ERROR returned.
6654*/
6655static int arParseCommand(
6656 char **azArg, /* Array of arguments passed to dot command */
6657 int nArg, /* Number of entries in azArg[] */
6658 ArCommand *pAr /* Populate this object */
6659){
dand4b56e52017-12-12 20:04:59 +00006660 struct ArSwitch {
dand4b56e52017-12-12 20:04:59 +00006661 const char *zLong;
drhb376b3d2018-01-10 13:11:51 +00006662 char cShort;
6663 u8 eSwitch;
6664 u8 bArg;
dand4b56e52017-12-12 20:04:59 +00006665 } aSwitch[] = {
drhb376b3d2018-01-10 13:11:51 +00006666 { "create", 'c', AR_CMD_CREATE, 0 },
6667 { "extract", 'x', AR_CMD_EXTRACT, 0 },
drhb17ea912019-03-25 14:24:19 +00006668 { "insert", 'i', AR_CMD_INSERT, 0 },
drhb376b3d2018-01-10 13:11:51 +00006669 { "list", 't', AR_CMD_LIST, 0 },
larrybr47061b92021-11-01 17:22:52 +00006670 { "remove", 'r', AR_CMD_REMOVE, 0 },
drhb376b3d2018-01-10 13:11:51 +00006671 { "update", 'u', AR_CMD_UPDATE, 0 },
6672 { "help", 'h', AR_CMD_HELP, 0 },
6673 { "verbose", 'v', AR_SWITCH_VERBOSE, 0 },
6674 { "file", 'f', AR_SWITCH_FILE, 1 },
drhca7733b2018-01-10 18:09:20 +00006675 { "append", 'a', AR_SWITCH_APPEND, 1 },
drhb376b3d2018-01-10 13:11:51 +00006676 { "directory", 'C', AR_SWITCH_DIRECTORY, 1 },
drhb376b3d2018-01-10 13:11:51 +00006677 { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 },
larrybr8f09f4b2021-11-02 00:18:11 +00006678 { "glob", 'g', AR_SWITCH_GLOB, 0 },
dand4b56e52017-12-12 20:04:59 +00006679 };
6680 int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
6681 struct ArSwitch *pEnd = &aSwitch[nSwitch];
6682
dan88be0202017-12-09 17:58:02 +00006683 if( nArg<=1 ){
drh98aa2ab2018-09-26 16:53:51 +00006684 utf8_printf(stderr, "Wrong number of arguments. Usage:\n");
dan0d0547f2017-12-14 15:40:42 +00006685 return arUsage(stderr);
dan88be0202017-12-09 17:58:02 +00006686 }else{
6687 char *z = azArg[1];
dan88be0202017-12-09 17:58:02 +00006688 if( z[0]!='-' ){
6689 /* Traditional style [tar] invocation */
6690 int i;
6691 int iArg = 2;
6692 for(i=0; z[i]; i++){
dand4b56e52017-12-12 20:04:59 +00006693 const char *zArg = 0;
6694 struct ArSwitch *pOpt;
6695 for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
6696 if( z[i]==pOpt->cShort ) break;
dan88be0202017-12-09 17:58:02 +00006697 }
dan0d0547f2017-12-14 15:40:42 +00006698 if( pOpt==pEnd ){
drhd0f9cdc2018-05-17 14:09:06 +00006699 return arErrorMsg(pAr, "unrecognized option: %c", z[i]);
dan0d0547f2017-12-14 15:40:42 +00006700 }
dand4b56e52017-12-12 20:04:59 +00006701 if( pOpt->bArg ){
dan0d0547f2017-12-14 15:40:42 +00006702 if( iArg>=nArg ){
drhd0f9cdc2018-05-17 14:09:06 +00006703 return arErrorMsg(pAr, "option requires an argument: %c",z[i]);
dan0d0547f2017-12-14 15:40:42 +00006704 }
dand4b56e52017-12-12 20:04:59 +00006705 zArg = azArg[iArg++];
6706 }
6707 if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
dan88be0202017-12-09 17:58:02 +00006708 }
dan88be0202017-12-09 17:58:02 +00006709 pAr->nArg = nArg-iArg;
6710 if( pAr->nArg>0 ){
6711 pAr->azArg = &azArg[iArg];
6712 }
dand4b56e52017-12-12 20:04:59 +00006713 }else{
6714 /* Non-traditional invocation */
6715 int iArg;
6716 for(iArg=1; iArg<nArg; iArg++){
6717 int n;
6718 z = azArg[iArg];
6719 if( z[0]!='-' ){
6720 /* All remaining command line words are command arguments. */
6721 pAr->azArg = &azArg[iArg];
6722 pAr->nArg = nArg-iArg;
6723 break;
6724 }
drhaf2770f2018-01-05 14:55:43 +00006725 n = strlen30(z);
dand4b56e52017-12-12 20:04:59 +00006726
6727 if( z[1]!='-' ){
6728 int i;
6729 /* One or more short options */
6730 for(i=1; i<n; i++){
6731 const char *zArg = 0;
6732 struct ArSwitch *pOpt;
6733 for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
6734 if( z[i]==pOpt->cShort ) break;
6735 }
dan0d0547f2017-12-14 15:40:42 +00006736 if( pOpt==pEnd ){
drhd0f9cdc2018-05-17 14:09:06 +00006737 return arErrorMsg(pAr, "unrecognized option: %c", z[i]);
dan0d0547f2017-12-14 15:40:42 +00006738 }
dand4b56e52017-12-12 20:04:59 +00006739 if( pOpt->bArg ){
6740 if( i<(n-1) ){
6741 zArg = &z[i+1];
6742 i = n;
6743 }else{
dan0d0547f2017-12-14 15:40:42 +00006744 if( iArg>=(nArg-1) ){
drhe2754c12019-08-26 12:50:01 +00006745 return arErrorMsg(pAr, "option requires an argument: %c",
6746 z[i]);
dan0d0547f2017-12-14 15:40:42 +00006747 }
dand4b56e52017-12-12 20:04:59 +00006748 zArg = azArg[++iArg];
6749 }
6750 }
6751 if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
6752 }
6753 }else if( z[2]=='\0' ){
6754 /* A -- option, indicating that all remaining command line words
6755 ** are command arguments. */
6756 pAr->azArg = &azArg[iArg+1];
6757 pAr->nArg = nArg-iArg-1;
6758 break;
6759 }else{
6760 /* A long option */
6761 const char *zArg = 0; /* Argument for option, if any */
6762 struct ArSwitch *pMatch = 0; /* Matching option */
6763 struct ArSwitch *pOpt; /* Iterator */
6764 for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
6765 const char *zLong = pOpt->zLong;
drhaf2770f2018-01-05 14:55:43 +00006766 if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){
dand4b56e52017-12-12 20:04:59 +00006767 if( pMatch ){
drhd0f9cdc2018-05-17 14:09:06 +00006768 return arErrorMsg(pAr, "ambiguous option: %s",z);
dand4b56e52017-12-12 20:04:59 +00006769 }else{
6770 pMatch = pOpt;
6771 }
6772 }
6773 }
6774
6775 if( pMatch==0 ){
drhd0f9cdc2018-05-17 14:09:06 +00006776 return arErrorMsg(pAr, "unrecognized option: %s", z);
dand4b56e52017-12-12 20:04:59 +00006777 }
6778 if( pMatch->bArg ){
dan0d0547f2017-12-14 15:40:42 +00006779 if( iArg>=(nArg-1) ){
drhd0f9cdc2018-05-17 14:09:06 +00006780 return arErrorMsg(pAr, "option requires an argument: %s", z);
dan0d0547f2017-12-14 15:40:42 +00006781 }
dand4b56e52017-12-12 20:04:59 +00006782 zArg = azArg[++iArg];
6783 }
6784 if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR;
6785 }
6786 }
dan88be0202017-12-09 17:58:02 +00006787 }
6788 }
6789
6790 return SQLITE_OK;
6791}
6792
6793/*
dan3f67ddf2017-12-13 20:04:53 +00006794** This function assumes that all arguments within the ArCommand.azArg[]
larrybr47061b92021-11-01 17:22:52 +00006795** array refer to archive members, as for the --extract, --list or --remove
larrybr8f09f4b2021-11-02 00:18:11 +00006796** commands. It checks that each of them are "present". If any specified
6797** file is not present in the archive, an error is printed to stderr and an
larrybr47061b92021-11-01 17:22:52 +00006798** error code returned. Otherwise, if all specified arguments are present
larrybr8f09f4b2021-11-02 00:18:11 +00006799** in the archive, SQLITE_OK is returned. Here, "present" means either an
6800** exact equality when pAr->bGlob is false or a "name GLOB pattern" match
drh0c0fb9c2021-11-02 10:54:39 +00006801** when pAr->bGlob is true.
dan3f67ddf2017-12-13 20:04:53 +00006802**
6803** This function strips any trailing '/' characters from each argument.
6804** This is consistent with the way the [tar] command seems to work on
6805** Linux.
6806*/
drhb376b3d2018-01-10 13:11:51 +00006807static int arCheckEntries(ArCommand *pAr){
dan3f67ddf2017-12-13 20:04:53 +00006808 int rc = SQLITE_OK;
6809 if( pAr->nArg ){
drhb376b3d2018-01-10 13:11:51 +00006810 int i, j;
dan3f67ddf2017-12-13 20:04:53 +00006811 sqlite3_stmt *pTest = 0;
larrybr8f09f4b2021-11-02 00:18:11 +00006812 const char *zSel = (pAr->bGlob)
6813 ? "SELECT name FROM %s WHERE glob($name,name)"
6814 : "SELECT name FROM %s WHERE name=$name";
dan3f67ddf2017-12-13 20:04:53 +00006815
larrybr8f09f4b2021-11-02 00:18:11 +00006816 shellPreparePrintf(pAr->db, &rc, &pTest, zSel, pAr->zSrcTable);
drhb376b3d2018-01-10 13:11:51 +00006817 j = sqlite3_bind_parameter_index(pTest, "$name");
dan3f67ddf2017-12-13 20:04:53 +00006818 for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
6819 char *z = pAr->azArg[i];
drhaf2770f2018-01-05 14:55:43 +00006820 int n = strlen30(z);
dan3f67ddf2017-12-13 20:04:53 +00006821 int bOk = 0;
6822 while( n>0 && z[n-1]=='/' ) n--;
6823 z[n] = '\0';
drhb376b3d2018-01-10 13:11:51 +00006824 sqlite3_bind_text(pTest, j, z, -1, SQLITE_STATIC);
dan3f67ddf2017-12-13 20:04:53 +00006825 if( SQLITE_ROW==sqlite3_step(pTest) ){
6826 bOk = 1;
6827 }
6828 shellReset(&rc, pTest);
6829 if( rc==SQLITE_OK && bOk==0 ){
drhb376b3d2018-01-10 13:11:51 +00006830 utf8_printf(stderr, "not found in archive: %s\n", z);
dan3f67ddf2017-12-13 20:04:53 +00006831 rc = SQLITE_ERROR;
6832 }
6833 }
6834 shellFinalize(&rc, pTest);
6835 }
dan3f67ddf2017-12-13 20:04:53 +00006836 return rc;
6837}
6838
6839/*
6840** Format a WHERE clause that can be used against the "sqlar" table to
6841** identify all archive members that match the command arguments held
6842** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning.
6843** The caller is responsible for eventually calling sqlite3_free() on
larrybr8f09f4b2021-11-02 00:18:11 +00006844** any non-NULL (*pzWhere) value. Here, "match" means strict equality
6845** when pAr->bGlob is false and GLOB match when pAr->bGlob is true.
dan3f67ddf2017-12-13 20:04:53 +00006846*/
6847static void arWhereClause(
6848 int *pRc,
larrybr8f09f4b2021-11-02 00:18:11 +00006849 ArCommand *pAr,
danac15e2d2017-12-14 19:15:07 +00006850 char **pzWhere /* OUT: New WHERE clause */
dan3f67ddf2017-12-13 20:04:53 +00006851){
6852 char *zWhere = 0;
larrybr8f09f4b2021-11-02 00:18:11 +00006853 const char *zSameOp = (pAr->bGlob)? "GLOB" : "=";
dan3f67ddf2017-12-13 20:04:53 +00006854 if( *pRc==SQLITE_OK ){
danac15e2d2017-12-14 19:15:07 +00006855 if( pAr->nArg==0 ){
6856 zWhere = sqlite3_mprintf("1");
6857 }else{
6858 int i;
6859 const char *zSep = "";
6860 for(i=0; i<pAr->nArg; i++){
6861 const char *z = pAr->azArg[i];
6862 zWhere = sqlite3_mprintf(
larrybr8f09f4b2021-11-02 00:18:11 +00006863 "%z%s name %s '%q' OR substr(name,1,%d) %s '%q/'",
6864 zWhere, zSep, zSameOp, z, strlen30(z)+1, zSameOp, z
drhb376b3d2018-01-10 13:11:51 +00006865 );
danac15e2d2017-12-14 19:15:07 +00006866 if( zWhere==0 ){
6867 *pRc = SQLITE_NOMEM;
6868 break;
6869 }
6870 zSep = " OR ";
dan3f67ddf2017-12-13 20:04:53 +00006871 }
dan3f67ddf2017-12-13 20:04:53 +00006872 }
6873 }
6874 *pzWhere = zWhere;
6875}
6876
6877/*
dan88be0202017-12-09 17:58:02 +00006878** Implementation of .ar "lisT" command.
6879*/
drhb376b3d2018-01-10 13:11:51 +00006880static int arListCommand(ArCommand *pAr){
danb5090e42017-12-27 21:13:21 +00006881 const char *zSql = "SELECT %s FROM %s WHERE %s";
danb5090e42017-12-27 21:13:21 +00006882 const char *azCols[] = {
6883 "name",
drh410cad92018-01-10 17:19:16 +00006884 "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name"
danb5090e42017-12-27 21:13:21 +00006885 };
dan5a78b812017-12-27 18:54:11 +00006886
dan3f67ddf2017-12-13 20:04:53 +00006887 char *zWhere = 0;
6888 sqlite3_stmt *pSql = 0;
6889 int rc;
6890
drhb376b3d2018-01-10 13:11:51 +00006891 rc = arCheckEntries(pAr);
dan3f67ddf2017-12-13 20:04:53 +00006892 arWhereClause(&rc, pAr, &zWhere);
6893
drhb376b3d2018-01-10 13:11:51 +00006894 shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
6895 pAr->zSrcTable, zWhere);
drhb376b3d2018-01-10 13:11:51 +00006896 if( pAr->bDryRun ){
6897 utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
6898 }else{
6899 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
6900 if( pAr->bVerbose ){
drh410cad92018-01-10 17:19:16 +00006901 utf8_printf(pAr->p->out, "%s % 10d %s %s\n",
6902 sqlite3_column_text(pSql, 0),
drhb376b3d2018-01-10 13:11:51 +00006903 sqlite3_column_int(pSql, 1),
6904 sqlite3_column_text(pSql, 2),
6905 sqlite3_column_text(pSql, 3)
6906 );
6907 }else{
6908 utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
6909 }
danb5090e42017-12-27 21:13:21 +00006910 }
dan3f67ddf2017-12-13 20:04:53 +00006911 }
dan5a78b812017-12-27 18:54:11 +00006912 shellFinalize(&rc, pSql);
drhd0f9cdc2018-05-17 14:09:06 +00006913 sqlite3_free(zWhere);
dan3f67ddf2017-12-13 20:04:53 +00006914 return rc;
dan88be0202017-12-09 17:58:02 +00006915}
6916
6917
danfd0245d2017-12-07 15:44:29 +00006918/*
larrybr47061b92021-11-01 17:22:52 +00006919** Implementation of .ar "Remove" command.
6920*/
6921static int arRemoveCommand(ArCommand *pAr){
larrybr7774fc02021-11-01 22:30:24 +00006922 int rc = 0;
larrybr47061b92021-11-01 17:22:52 +00006923 char *zSql = 0;
6924 char *zWhere = 0;
6925
6926 if( pAr->nArg ){
6927 /* Verify that args actually exist within the archive before proceeding.
6928 ** And formulate a WHERE clause to match them. */
6929 rc = arCheckEntries(pAr);
6930 arWhereClause(&rc, pAr, &zWhere);
6931 }
6932 if( rc==SQLITE_OK ){
6933 zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;",
6934 pAr->zSrcTable, zWhere);
6935 if( pAr->bDryRun ){
6936 utf8_printf(pAr->p->out, "%s\n", zSql);
6937 }else{
6938 char *zErr = 0;
6939 rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0);
6940 if( rc==SQLITE_OK ){
6941 rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
6942 if( rc!=SQLITE_OK ){
6943 sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0);
6944 }else{
6945 rc = sqlite3_exec(pAr->db, "RELEASE ar;", 0, 0, 0);
6946 }
6947 }
6948 if( zErr ){
6949 utf8_printf(stdout, "ERROR: %s\n", zErr);
6950 sqlite3_free(zErr);
6951 }
6952 }
6953 }
6954 sqlite3_free(zWhere);
6955 sqlite3_free(zSql);
6956 return rc;
6957}
6958
6959/*
danfd0245d2017-12-07 15:44:29 +00006960** Implementation of .ar "eXtract" command.
6961*/
drhb376b3d2018-01-10 13:11:51 +00006962static int arExtractCommand(ArCommand *pAr){
dan25c12182017-12-07 21:03:33 +00006963 const char *zSql1 =
dand1b51d42017-12-16 19:11:26 +00006964 "SELECT "
drhb376b3d2018-01-10 13:11:51 +00006965 " ($dir || name),"
6966 " writefile(($dir || name), %s, mode, mtime) "
drh0cfd46a2018-06-06 01:18:01 +00006967 "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)"
6968 " AND name NOT GLOB '*..[/\\]*'";
dan5a78b812017-12-27 18:54:11 +00006969
6970 const char *azExtraArg[] = {
6971 "sqlar_uncompress(data, sz)",
dan7c15ac12018-01-08 19:59:59 +00006972 "data"
dan5a78b812017-12-27 18:54:11 +00006973 };
dan5a78b812017-12-27 18:54:11 +00006974
danfd0245d2017-12-07 15:44:29 +00006975 sqlite3_stmt *pSql = 0;
6976 int rc = SQLITE_OK;
dan2ad09492017-12-09 18:28:22 +00006977 char *zDir = 0;
dan3f67ddf2017-12-13 20:04:53 +00006978 char *zWhere = 0;
drhb376b3d2018-01-10 13:11:51 +00006979 int i, j;
dan2ad09492017-12-09 18:28:22 +00006980
dan3f67ddf2017-12-13 20:04:53 +00006981 /* If arguments are specified, check that they actually exist within
6982 ** the archive before proceeding. And formulate a WHERE clause to
6983 ** match them. */
drhb376b3d2018-01-10 13:11:51 +00006984 rc = arCheckEntries(pAr);
dan3f67ddf2017-12-13 20:04:53 +00006985 arWhereClause(&rc, pAr, &zWhere);
6986
6987 if( rc==SQLITE_OK ){
6988 if( pAr->zDir ){
6989 zDir = sqlite3_mprintf("%s/", pAr->zDir);
6990 }else{
6991 zDir = sqlite3_mprintf("");
6992 }
6993 if( zDir==0 ) rc = SQLITE_NOMEM;
dan2ad09492017-12-09 18:28:22 +00006994 }
danfd0245d2017-12-07 15:44:29 +00006995
drhb376b3d2018-01-10 13:11:51 +00006996 shellPreparePrintf(pAr->db, &rc, &pSql, zSql1,
6997 azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere
dan5a78b812017-12-27 18:54:11 +00006998 );
6999
dan2ad09492017-12-09 18:28:22 +00007000 if( rc==SQLITE_OK ){
drhb376b3d2018-01-10 13:11:51 +00007001 j = sqlite3_bind_parameter_index(pSql, "$dir");
7002 sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC);
dan25c12182017-12-07 21:03:33 +00007003
danac15e2d2017-12-14 19:15:07 +00007004 /* Run the SELECT statement twice. The first time, writefile() is called
7005 ** for all archive members that should be extracted. The second time,
7006 ** only for the directories. This is because the timestamps for
7007 ** extracted directories must be reset after they are populated (as
7008 ** populating them changes the timestamp). */
7009 for(i=0; i<2; i++){
drhb376b3d2018-01-10 13:11:51 +00007010 j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
7011 sqlite3_bind_int(pSql, j, i);
7012 if( pAr->bDryRun ){
7013 utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
7014 }else{
7015 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
7016 if( i==0 && pAr->bVerbose ){
7017 utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
7018 }
danac15e2d2017-12-14 19:15:07 +00007019 }
7020 }
7021 shellReset(&rc, pSql);
dan25c12182017-12-07 21:03:33 +00007022 }
danac15e2d2017-12-14 19:15:07 +00007023 shellFinalize(&rc, pSql);
dan25c12182017-12-07 21:03:33 +00007024 }
dan25c12182017-12-07 21:03:33 +00007025
dan2ad09492017-12-09 18:28:22 +00007026 sqlite3_free(zDir);
dan3f67ddf2017-12-13 20:04:53 +00007027 sqlite3_free(zWhere);
danfd0245d2017-12-07 15:44:29 +00007028 return rc;
7029}
7030
drhb376b3d2018-01-10 13:11:51 +00007031/*
7032** Run the SQL statement in zSql. Or if doing a --dryrun, merely print it out.
7033*/
7034static int arExecSql(ArCommand *pAr, const char *zSql){
7035 int rc;
7036 if( pAr->bDryRun ){
7037 utf8_printf(pAr->p->out, "%s\n", zSql);
7038 rc = SQLITE_OK;
7039 }else{
drh410cad92018-01-10 17:19:16 +00007040 char *zErr = 0;
7041 rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
7042 if( zErr ){
7043 utf8_printf(stdout, "ERROR: %s\n", zErr);
7044 sqlite3_free(zErr);
7045 }
drhb376b3d2018-01-10 13:11:51 +00007046 }
7047 return rc;
7048}
7049
dan1ad3f612017-12-11 20:22:02 +00007050
danfd0245d2017-12-07 15:44:29 +00007051/*
drhb17ea912019-03-25 14:24:19 +00007052** Implementation of .ar "create", "insert", and "update" commands.
7053**
7054** create -> Create a new SQL archive
7055** insert -> Insert or reinsert all files listed
7056** update -> Insert files that have changed or that were not
7057** previously in the archive
danfd0245d2017-12-07 15:44:29 +00007058**
7059** Create the "sqlar" table in the database if it does not already exist.
7060** Then add each file in the azFile[] array to the archive. Directories
7061** are added recursively. If argument bVerbose is non-zero, a message is
7062** printed on stdout for each file archived.
dan06741a32017-12-13 20:17:18 +00007063**
7064** The create command is the same as update, except that it drops
drhb17ea912019-03-25 14:24:19 +00007065** any existing "sqlar" table before beginning. The "insert" command
7066** always overwrites every file named on the command-line, where as
7067** "update" only overwrites if the size or mtime or mode has changed.
danfd0245d2017-12-07 15:44:29 +00007068*/
drhb376b3d2018-01-10 13:11:51 +00007069static int arCreateOrUpdateCommand(
dan06741a32017-12-13 20:17:18 +00007070 ArCommand *pAr, /* Command arguments and options */
drhb17ea912019-03-25 14:24:19 +00007071 int bUpdate, /* true for a --create. */
7072 int bOnlyIfChanged /* Only update if file has changed */
danfd0245d2017-12-07 15:44:29 +00007073){
dand4b56e52017-12-12 20:04:59 +00007074 const char *zCreate =
drhafba1802018-01-06 15:49:57 +00007075 "CREATE TABLE IF NOT EXISTS sqlar(\n"
7076 " name TEXT PRIMARY KEY, -- name of the file\n"
7077 " mode INT, -- access permissions\n"
7078 " mtime INT, -- last modification time\n"
7079 " sz INT, -- original file size\n"
7080 " data BLOB -- compressed content\n"
7081 ")";
dand4b56e52017-12-12 20:04:59 +00007082 const char *zDrop = "DROP TABLE IF EXISTS sqlar";
drh1bf208c2018-03-09 21:54:01 +00007083 const char *zInsertFmt[2] = {
7084 "REPLACE INTO %s(name,mode,mtime,sz,data)\n"
drh634c70f2018-01-10 16:50:18 +00007085 " SELECT\n"
7086 " %s,\n"
7087 " mode,\n"
7088 " mtime,\n"
drh410cad92018-01-10 17:19:16 +00007089 " CASE substr(lsmode(mode),1,1)\n"
7090 " WHEN '-' THEN length(data)\n"
7091 " WHEN 'd' THEN 0\n"
drh634c70f2018-01-10 16:50:18 +00007092 " ELSE -1 END,\n"
drh69d2d352018-03-09 22:18:53 +00007093 " sqlar_compress(data)\n"
drhb17ea912019-03-25 14:24:19 +00007094 " FROM fsdir(%Q,%Q) AS disk\n"
7095 " WHERE lsmode(mode) NOT LIKE '?%%'%s;"
7096 ,
drh1bf208c2018-03-09 21:54:01 +00007097 "REPLACE INTO %s(name,mode,mtime,data)\n"
7098 " SELECT\n"
7099 " %s,\n"
7100 " mode,\n"
7101 " mtime,\n"
7102 " data\n"
drhb17ea912019-03-25 14:24:19 +00007103 " FROM fsdir(%Q,%Q) AS disk\n"
7104 " WHERE lsmode(mode) NOT LIKE '?%%'%s;"
drh1bf208c2018-03-09 21:54:01 +00007105 };
danfd0245d2017-12-07 15:44:29 +00007106 int i; /* For iterating through azFile[] */
7107 int rc; /* Return code */
drh1bf208c2018-03-09 21:54:01 +00007108 const char *zTab = 0; /* SQL table into which to insert */
7109 char *zSql;
7110 char zTemp[50];
drhb17ea912019-03-25 14:24:19 +00007111 char *zExists = 0;
danfd0245d2017-12-07 15:44:29 +00007112
drh1bf208c2018-03-09 21:54:01 +00007113 arExecSql(pAr, "PRAGMA page_size=512");
drhb376b3d2018-01-10 13:11:51 +00007114 rc = arExecSql(pAr, "SAVEPOINT ar;");
danfd0245d2017-12-07 15:44:29 +00007115 if( rc!=SQLITE_OK ) return rc;
drh1bf208c2018-03-09 21:54:01 +00007116 zTemp[0] = 0;
7117 if( pAr->bZip ){
7118 /* Initialize the zipfile virtual table, if necessary */
7119 if( pAr->zFile ){
7120 sqlite3_uint64 r;
7121 sqlite3_randomness(sizeof(r),&r);
7122 sqlite3_snprintf(sizeof(zTemp),zTemp,"zip%016llx",r);
7123 zTab = zTemp;
7124 zSql = sqlite3_mprintf(
7125 "CREATE VIRTUAL TABLE temp.%s USING zipfile(%Q)",
7126 zTab, pAr->zFile
7127 );
7128 rc = arExecSql(pAr, zSql);
7129 sqlite3_free(zSql);
7130 }else{
7131 zTab = "zip";
7132 }
7133 }else{
7134 /* Initialize the table for an SQLAR */
7135 zTab = "sqlar";
7136 if( bUpdate==0 ){
7137 rc = arExecSql(pAr, zDrop);
7138 if( rc!=SQLITE_OK ) goto end_ar_transaction;
7139 }
7140 rc = arExecSql(pAr, zCreate);
dan06741a32017-12-13 20:17:18 +00007141 }
drhb17ea912019-03-25 14:24:19 +00007142 if( bOnlyIfChanged ){
7143 zExists = sqlite3_mprintf(
7144 " AND NOT EXISTS("
7145 "SELECT 1 FROM %s AS mem"
7146 " WHERE mem.name=disk.name"
7147 " AND mem.mtime=disk.mtime"
7148 " AND mem.mode=disk.mode)", zTab);
7149 }else{
7150 zExists = sqlite3_mprintf("");
7151 }
7152 if( zExists==0 ) rc = SQLITE_NOMEM;
dan88be0202017-12-09 17:58:02 +00007153 for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
mistachkince2052b2018-03-23 00:31:53 +00007154 char *zSql2 = sqlite3_mprintf(zInsertFmt[pAr->bZip], zTab,
drh634c70f2018-01-10 16:50:18 +00007155 pAr->bVerbose ? "shell_putsnl(name)" : "name",
drhb17ea912019-03-25 14:24:19 +00007156 pAr->azArg[i], pAr->zDir, zExists);
mistachkince2052b2018-03-23 00:31:53 +00007157 rc = arExecSql(pAr, zSql2);
7158 sqlite3_free(zSql2);
danfd0245d2017-12-07 15:44:29 +00007159 }
drh1bf208c2018-03-09 21:54:01 +00007160end_ar_transaction:
danfd0245d2017-12-07 15:44:29 +00007161 if( rc!=SQLITE_OK ){
drh2bd207f2019-01-11 17:19:59 +00007162 sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0);
danfd0245d2017-12-07 15:44:29 +00007163 }else{
drhb376b3d2018-01-10 13:11:51 +00007164 rc = arExecSql(pAr, "RELEASE ar;");
drh1bf208c2018-03-09 21:54:01 +00007165 if( pAr->bZip && pAr->zFile ){
7166 zSql = sqlite3_mprintf("DROP TABLE %s", zTemp);
7167 arExecSql(pAr, zSql);
7168 sqlite3_free(zSql);
7169 }
danfd0245d2017-12-07 15:44:29 +00007170 }
drhb17ea912019-03-25 14:24:19 +00007171 sqlite3_free(zExists);
danfd0245d2017-12-07 15:44:29 +00007172 return rc;
7173}
7174
7175/*
7176** Implementation of ".ar" dot command.
7177*/
7178static int arDotCommand(
drhe2754c12019-08-26 12:50:01 +00007179 ShellState *pState, /* Current shell tool state */
7180 int fromCmdLine, /* True if -A command-line option, not .ar cmd */
7181 char **azArg, /* Array of arguments passed to dot command */
7182 int nArg /* Number of entries in azArg[] */
danfd0245d2017-12-07 15:44:29 +00007183){
dan88be0202017-12-09 17:58:02 +00007184 ArCommand cmd;
7185 int rc;
drh34660642018-01-10 17:39:54 +00007186 memset(&cmd, 0, sizeof(cmd));
drhd0f9cdc2018-05-17 14:09:06 +00007187 cmd.fromCmdLine = fromCmdLine;
dan88be0202017-12-09 17:58:02 +00007188 rc = arParseCommand(azArg, nArg, &cmd);
7189 if( rc==SQLITE_OK ){
drha5676c42018-01-10 15:17:34 +00007190 int eDbType = SHELL_OPEN_UNSPEC;
drhb376b3d2018-01-10 13:11:51 +00007191 cmd.p = pState;
7192 cmd.db = pState->db;
drha5676c42018-01-10 15:17:34 +00007193 if( cmd.zFile ){
drh1bf208c2018-03-09 21:54:01 +00007194 eDbType = deduceDatabaseType(cmd.zFile, 1);
drha5676c42018-01-10 15:17:34 +00007195 }else{
7196 eDbType = pState->openMode;
7197 }
7198 if( eDbType==SHELL_OPEN_ZIPFILE ){
drh1bf208c2018-03-09 21:54:01 +00007199 if( cmd.eCmd==AR_CMD_EXTRACT || cmd.eCmd==AR_CMD_LIST ){
7200 if( cmd.zFile==0 ){
7201 cmd.zSrcTable = sqlite3_mprintf("zip");
7202 }else{
7203 cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile);
7204 }
dan5a78b812017-12-27 18:54:11 +00007205 }
drha5676c42018-01-10 15:17:34 +00007206 cmd.bZip = 1;
dan5a78b812017-12-27 18:54:11 +00007207 }else if( cmd.zFile ){
dand4b56e52017-12-12 20:04:59 +00007208 int flags;
drha5676c42018-01-10 15:17:34 +00007209 if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS;
drhb17ea912019-03-25 14:24:19 +00007210 if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT
larrybr47061b92021-11-01 17:22:52 +00007211 || cmd.eCmd==AR_CMD_REMOVE || cmd.eCmd==AR_CMD_UPDATE ){
dand4b56e52017-12-12 20:04:59 +00007212 flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
7213 }else{
7214 flags = SQLITE_OPEN_READONLY;
7215 }
drha82c95b2018-01-10 14:00:00 +00007216 cmd.db = 0;
drha5676c42018-01-10 15:17:34 +00007217 if( cmd.bDryRun ){
7218 utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile,
7219 eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
7220 }
7221 rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags,
7222 eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
dand4b56e52017-12-12 20:04:59 +00007223 if( rc!=SQLITE_OK ){
drhb376b3d2018-01-10 13:11:51 +00007224 utf8_printf(stderr, "cannot open file: %s (%s)\n",
7225 cmd.zFile, sqlite3_errmsg(cmd.db)
dand4b56e52017-12-12 20:04:59 +00007226 );
drha5676c42018-01-10 15:17:34 +00007227 goto end_ar_command;
dand4b56e52017-12-12 20:04:59 +00007228 }
drhb376b3d2018-01-10 13:11:51 +00007229 sqlite3_fileio_init(cmd.db, 0, 0);
drhb376b3d2018-01-10 13:11:51 +00007230 sqlite3_sqlar_init(cmd.db, 0, 0);
drh34660642018-01-10 17:39:54 +00007231 sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
7232 shellPutsFunc, 0, 0);
7233
dand4b56e52017-12-12 20:04:59 +00007234 }
drhd0f9cdc2018-05-17 14:09:06 +00007235 if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){
drh634c70f2018-01-10 16:50:18 +00007236 if( cmd.eCmd!=AR_CMD_CREATE
7237 && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
7238 ){
drha5676c42018-01-10 15:17:34 +00007239 utf8_printf(stderr, "database does not contain an 'sqlar' table\n");
7240 rc = SQLITE_ERROR;
7241 goto end_ar_command;
7242 }
7243 cmd.zSrcTable = sqlite3_mprintf("sqlar");
7244 }
dand4b56e52017-12-12 20:04:59 +00007245
dan88be0202017-12-09 17:58:02 +00007246 switch( cmd.eCmd ){
7247 case AR_CMD_CREATE:
drhb17ea912019-03-25 14:24:19 +00007248 rc = arCreateOrUpdateCommand(&cmd, 0, 0);
dan88be0202017-12-09 17:58:02 +00007249 break;
danfd0245d2017-12-07 15:44:29 +00007250
dan88be0202017-12-09 17:58:02 +00007251 case AR_CMD_EXTRACT:
drhb376b3d2018-01-10 13:11:51 +00007252 rc = arExtractCommand(&cmd);
dan88be0202017-12-09 17:58:02 +00007253 break;
7254
7255 case AR_CMD_LIST:
drhb376b3d2018-01-10 13:11:51 +00007256 rc = arListCommand(&cmd);
dan88be0202017-12-09 17:58:02 +00007257 break;
7258
dan0d0547f2017-12-14 15:40:42 +00007259 case AR_CMD_HELP:
7260 arUsage(pState->out);
7261 break;
7262
drhb17ea912019-03-25 14:24:19 +00007263 case AR_CMD_INSERT:
7264 rc = arCreateOrUpdateCommand(&cmd, 1, 0);
7265 break;
7266
larrybr47061b92021-11-01 17:22:52 +00007267 case AR_CMD_REMOVE:
7268 rc = arRemoveCommand(&cmd);
7269 break;
7270
dan88be0202017-12-09 17:58:02 +00007271 default:
7272 assert( cmd.eCmd==AR_CMD_UPDATE );
drhb17ea912019-03-25 14:24:19 +00007273 rc = arCreateOrUpdateCommand(&cmd, 1, 1);
dan88be0202017-12-09 17:58:02 +00007274 break;
danfd0245d2017-12-07 15:44:29 +00007275 }
7276 }
drha5676c42018-01-10 15:17:34 +00007277end_ar_command:
7278 if( cmd.db!=pState->db ){
drh9e804032018-05-18 17:11:50 +00007279 close_db(cmd.db);
drha5676c42018-01-10 15:17:34 +00007280 }
7281 sqlite3_free(cmd.zSrcTable);
danfd0245d2017-12-07 15:44:29 +00007282
dan88be0202017-12-09 17:58:02 +00007283 return rc;
danfd0245d2017-12-07 15:44:29 +00007284}
drhe37c0e12018-01-06 19:19:50 +00007285/* End of the ".archive" or ".ar" command logic
drhe2754c12019-08-26 12:50:01 +00007286*******************************************************************************/
drhe37c0e12018-01-06 19:19:50 +00007287#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
danfd0245d2017-12-07 15:44:29 +00007288
stephan3d420832022-10-27 03:56:01 +00007289#if SQLITE_SHELL_HAVE_RECOVER
dan68cb86e2019-04-20 20:57:28 +00007290
dan42ebb012019-04-27 18:47:03 +00007291/*
dan9a27d652022-09-08 19:22:29 +00007292** This function is used as a callback by the recover extension. Simply
7293** print the supplied SQL statement to stdout.
dan42ebb012019-04-27 18:47:03 +00007294*/
dan9a27d652022-09-08 19:22:29 +00007295static int recoverSqlCb(void *pCtx, const char *zSql){
7296 ShellState *pState = (ShellState*)pCtx;
dan80b1f6f2022-09-23 11:40:43 +00007297 utf8_printf(pState->out, "%s;\n", zSql);
dan9a27d652022-09-08 19:22:29 +00007298 return SQLITE_OK;
dan68cb86e2019-04-20 20:57:28 +00007299}
7300
7301/*
7302** This function is called to recover data from the database. A script
7303** to construct a new database containing all recovered data is output
7304** on stream pState->out.
7305*/
danb9b71db2019-04-25 16:20:40 +00007306static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
dan68cb86e2019-04-20 20:57:28 +00007307 int rc = SQLITE_OK;
drh2cdcc7f2022-11-02 14:08:26 +00007308 const char *zRecoveryDb = ""; /* Name of "recovery" database. Debug only */
dan9a27d652022-09-08 19:22:29 +00007309 const char *zLAF = "lost_and_found";
danf7fea5b2022-10-27 18:19:45 +00007310 int bFreelist = 1; /* 0 if --ignore-freelist is specified */
dan8cce6b82019-09-14 16:44:51 +00007311 int bRowids = 1; /* 0 if --no-rowids */
dan9a27d652022-09-08 19:22:29 +00007312 sqlite3_recover *p = 0;
7313 int i = 0;
7314
dan9c014f82019-04-25 19:23:15 +00007315 for(i=1; i<nArg; i++){
7316 char *z = azArg[i];
7317 int n;
7318 if( z[0]=='-' && z[1]=='-' ) z++;
drh4245e042019-06-13 13:52:46 +00007319 n = strlen30(z);
danf7fea5b2022-10-27 18:19:45 +00007320 if( n<=17 && memcmp("-ignore-freelist", z, n)==0 ){
dan9c014f82019-04-25 19:23:15 +00007321 bFreelist = 0;
dan42ebb012019-04-27 18:47:03 +00007322 }else
danc0b42432019-04-26 15:14:53 +00007323 if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){
drh2cdcc7f2022-11-02 14:08:26 +00007324 /* This option determines the name of the ATTACH-ed database used
7325 ** internally by the recovery extension. The default is "" which
7326 ** means to use a temporary database that is automatically deleted
7327 ** when closed. This option is undocumented and might disappear at
7328 ** any moment. */
danc0b42432019-04-26 15:14:53 +00007329 i++;
7330 zRecoveryDb = azArg[i];
dan42ebb012019-04-27 18:47:03 +00007331 }else
7332 if( n<=15 && memcmp("-lost-and-found", z, n)==0 && i<(nArg-1) ){
7333 i++;
dan9a27d652022-09-08 19:22:29 +00007334 zLAF = azArg[i];
dan8cce6b82019-09-14 16:44:51 +00007335 }else
7336 if( n<=10 && memcmp("-no-rowids", z, n)==0 ){
7337 bRowids = 0;
danc0b42432019-04-26 15:14:53 +00007338 }
dan9c014f82019-04-25 19:23:15 +00007339 else{
drhe2754c12019-08-26 12:50:01 +00007340 utf8_printf(stderr, "unexpected option: %s\n", azArg[i]);
7341 showHelp(pState->out, azArg[0]);
dan9c014f82019-04-25 19:23:15 +00007342 return 1;
7343 }
7344 }
dan68cb86e2019-04-20 20:57:28 +00007345
dan9a27d652022-09-08 19:22:29 +00007346 p = sqlite3_recover_init_sql(
7347 pState->db, "main", recoverSqlCb, (void*)pState
dan9c014f82019-04-25 19:23:15 +00007348 );
7349
drh2cdcc7f2022-11-02 14:08:26 +00007350 sqlite3_recover_config(p, 789, (void*)zRecoveryDb); /* Debug use only */
dan9a27d652022-09-08 19:22:29 +00007351 sqlite3_recover_config(p, SQLITE_RECOVER_LOST_AND_FOUND, (void*)zLAF);
7352 sqlite3_recover_config(p, SQLITE_RECOVER_ROWIDS, (void*)&bRowids);
7353 sqlite3_recover_config(p, SQLITE_RECOVER_FREELIST_CORRUPT,(void*)&bFreelist);
7354
dan46d43982022-09-08 21:43:18 +00007355 sqlite3_recover_run(p);
dan9a27d652022-09-08 19:22:29 +00007356 if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
7357 const char *zErr = sqlite3_recover_errmsg(p);
7358 int errCode = sqlite3_recover_errcode(p);
7359 raw_printf(stderr, "sql error: %s (%d)\n", zErr, errCode);
dan9c014f82019-04-25 19:23:15 +00007360 }
dan9a27d652022-09-08 19:22:29 +00007361 rc = sqlite3_recover_finish(p);
dan68cb86e2019-04-20 20:57:28 +00007362 return rc;
7363}
stephan3d420832022-10-27 03:56:01 +00007364#endif /* SQLITE_SHELL_HAVE_RECOVER */
dan68cb86e2019-04-20 20:57:28 +00007365
larrybr42de1c52022-02-13 22:18:22 +00007366
larrybr2d27d362022-04-16 17:53:25 +00007367/*
larrybr42de1c52022-02-13 22:18:22 +00007368 * zAutoColumn(zCol, &db, ?) => Maybe init db, add column zCol to it.
7369 * zAutoColumn(0, &db, ?) => (db!=0) Form columns spec for CREATE TABLE,
7370 * close db and set it to 0, and return the columns spec, to later
7371 * be sqlite3_free()'ed by the caller.
7372 * The return is 0 when either:
7373 * (a) The db was not initialized and zCol==0 (There are no columns.)
7374 * (b) zCol!=0 (Column was added, db initialized as needed.)
7375 * The 3rd argument, pRenamed, references an out parameter. If the
larrybr33633862022-02-14 01:12:46 +00007376 * pointer is non-zero, its referent will be set to a summary of renames
7377 * done if renaming was necessary, or set to 0 if none was done. The out
7378 * string (if any) must be sqlite3_free()'ed by the caller.
larrybr42de1c52022-02-13 22:18:22 +00007379 */
7380#ifdef SHELL_DEBUG
7381#define rc_err_oom_die(rc) \
7382 if( rc==SQLITE_NOMEM ) shell_check_oom(0); \
7383 else if(!(rc==SQLITE_OK||rc==SQLITE_DONE)) \
7384 fprintf(stderr,"E:%d\n",rc), assert(0)
7385#else
7386static void rc_err_oom_die(int rc){
7387 if( rc==SQLITE_NOMEM ) shell_check_oom(0);
7388 assert(rc==SQLITE_OK||rc==SQLITE_DONE);
7389}
7390#endif
7391
7392#ifdef SHELL_COLFIX_DB /* If this is set, the DB can be in a file. */
7393static char zCOL_DB[] = SHELL_STRINGIFY(SHELL_COLFIX_DB);
7394#else /* Otherwise, memory is faster/better for the transient DB. */
7395static const char *zCOL_DB = ":memory:";
7396#endif
7397
7398/* Define character (as C string) to separate generated column ordinal
7399 * from protected part of incoming column names. This defaults to "_"
7400 * so that incoming column identifiers that did not need not be quoted
7401 * remain usable without being quoted. It must be one character.
7402 */
7403#ifndef SHELL_AUTOCOLUMN_SEP
7404# define AUTOCOLUMN_SEP "_"
7405#else
7406# define AUTOCOLUMN_SEP SHELL_STRINGIFY(SHELL_AUTOCOLUMN_SEP)
7407#endif
7408
larrybr33633862022-02-14 01:12:46 +00007409static char *zAutoColumn(const char *zColNew, sqlite3 **pDb, char **pzRenamed){
larrybr42de1c52022-02-13 22:18:22 +00007410 /* Queries and D{D,M}L used here */
7411 static const char * const zTabMake = "\
7412CREATE TABLE ColNames(\
7413 cpos INTEGER PRIMARY KEY,\
larrybr33633862022-02-14 01:12:46 +00007414 name TEXT, nlen INT, chop INT, reps INT, suff TEXT);\
7415CREATE VIEW RepeatedNames AS \
7416SELECT DISTINCT t.name FROM ColNames t \
7417WHERE t.name COLLATE NOCASE IN (\
7418 SELECT o.name FROM ColNames o WHERE o.cpos<>t.cpos\
7419);\
larrybr42de1c52022-02-13 22:18:22 +00007420";
7421 static const char * const zTabFill = "\
7422INSERT INTO ColNames(name,nlen,chop,reps,suff)\
7423 VALUES(iif(length(?1)>0,?1,'?'),max(length(?1),1),0,0,'')\
7424";
7425 static const char * const zHasDupes = "\
7426SELECT count(DISTINCT (substring(name,1,nlen-chop)||suff) COLLATE NOCASE)\
7427 <count(name) FROM ColNames\
7428";
larrybr33633862022-02-14 01:12:46 +00007429#ifdef SHELL_COLUMN_RENAME_CLEAN
larrybr42de1c52022-02-13 22:18:22 +00007430 static const char * const zDedoctor = "\
7431UPDATE ColNames SET chop=iif(\
7432 (substring(name,nlen,1) BETWEEN '0' AND '9')\
7433 AND (rtrim(name,'0123456790') glob '*"AUTOCOLUMN_SEP"'),\
7434 nlen-length(rtrim(name, '"AUTOCOLUMN_SEP"0123456789')),\
7435 0\
7436)\
7437";
larrybr33633862022-02-14 01:12:46 +00007438#endif
larrybr42de1c52022-02-13 22:18:22 +00007439 static const char * const zSetReps = "\
7440UPDATE ColNames AS t SET reps=\
7441(SELECT count(*) FROM ColNames d \
7442 WHERE substring(t.name,1,t.nlen-t.chop)=substring(d.name,1,d.nlen-d.chop)\
7443 COLLATE NOCASE\
7444)\
7445";
7446#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
7447 static const char * const zColDigits = "\
7448SELECT CAST(ceil(log(count(*)+0.5)) AS INT) FROM ColNames \
7449";
larrybr2d27d362022-04-16 17:53:25 +00007450#else
7451 /* Counting on SQLITE_MAX_COLUMN < 100,000 here. (32767 is the hard limit.) */
7452 static const char * const zColDigits = "\
7453SELECT CASE WHEN (nc < 10) THEN 1 WHEN (nc < 100) THEN 2 \
7454 WHEN (nc < 1000) THEN 3 WHEN (nc < 10000) THEN 4 \
7455 ELSE 5 FROM (SELECT count(*) AS nc FROM ColNames) \
7456";
larrybr42de1c52022-02-13 22:18:22 +00007457#endif
7458 static const char * const zRenameRank =
larrybr33633862022-02-14 01:12:46 +00007459#ifdef SHELL_COLUMN_RENAME_CLEAN
larrybr42de1c52022-02-13 22:18:22 +00007460 "UPDATE ColNames AS t SET suff="
7461 "iif(reps>1, printf('%c%0*d', '"AUTOCOLUMN_SEP"', $1, cpos), '')"
larrybr33633862022-02-14 01:12:46 +00007462#else /* ...RENAME_MINIMAL_ONE_PASS */
7463"WITH Lzn(nlz) AS (" /* Find minimum extraneous leading 0's for uniqueness */
7464" SELECT 0 AS nlz"
7465" UNION"
7466" SELECT nlz+1 AS nlz FROM Lzn"
7467" WHERE EXISTS("
7468" SELECT 1"
7469" FROM ColNames t, ColNames o"
7470" WHERE"
7471" iif(t.name IN (SELECT * FROM RepeatedNames),"
7472" printf('%s"AUTOCOLUMN_SEP"%s',"
7473" t.name, substring(printf('%.*c%0.*d',nlz+1,'0',$1,t.cpos),2)),"
7474" t.name"
7475" )"
7476" ="
7477" iif(o.name IN (SELECT * FROM RepeatedNames),"
7478" printf('%s"AUTOCOLUMN_SEP"%s',"
7479" o.name, substring(printf('%.*c%0.*d',nlz+1,'0',$1,o.cpos),2)),"
7480" o.name"
7481" )"
7482" COLLATE NOCASE"
7483" AND o.cpos<>t.cpos"
7484" GROUP BY t.cpos"
7485" )"
7486") UPDATE Colnames AS t SET"
7487" chop = 0," /* No chopping, never touch incoming names. */
7488" suff = iif(name IN (SELECT * FROM RepeatedNames),"
7489" printf('"AUTOCOLUMN_SEP"%s', substring("
7490" printf('%.*c%0.*d',(SELECT max(nlz) FROM Lzn)+1,'0',1,t.cpos),2)),"
7491" ''"
7492" )"
larrybr42de1c52022-02-13 22:18:22 +00007493#endif
7494 ;
7495 static const char * const zCollectVar = "\
7496SELECT\
7497 '('||x'0a'\
7498 || group_concat(\
7499 cname||' TEXT',\
7500 ','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\
7501 ||')' AS ColsSpec \
7502FROM (\
larrybr039132b2022-04-09 18:51:49 +00007503 SELECT cpos, printf('\"%w\"',printf('%!.*s%s', nlen-chop,name,suff)) AS cname \
larrybr42de1c52022-02-13 22:18:22 +00007504 FROM ColNames ORDER BY cpos\
7505)";
larrybr33633862022-02-14 01:12:46 +00007506 static const char * const zRenamesDone =
7507 "SELECT group_concat("
larrybr039132b2022-04-09 18:51:49 +00007508 " printf('\"%w\" to \"%w\"',name,printf('%!.*s%s', nlen-chop, name, suff)),"
larrybr33633862022-02-14 01:12:46 +00007509 " ','||x'0a')"
7510 "FROM ColNames WHERE suff<>'' OR chop!=0"
7511 ;
larrybr42de1c52022-02-13 22:18:22 +00007512 int rc;
7513 sqlite3_stmt *pStmt = 0;
7514 assert(pDb!=0);
7515 if( zColNew ){
7516 /* Add initial or additional column. Init db if necessary. */
7517 if( *pDb==0 ){
7518 if( SQLITE_OK!=sqlite3_open(zCOL_DB, pDb) ) return 0;
7519#ifdef SHELL_COLFIX_DB
7520 if(*zCOL_DB!=':')
larrybr33633862022-02-14 01:12:46 +00007521 sqlite3_exec(*pDb,"drop table if exists ColNames;"
7522 "drop view if exists RepeatedNames;",0,0,0);
larrybr42de1c52022-02-13 22:18:22 +00007523#endif
7524 rc = sqlite3_exec(*pDb, zTabMake, 0, 0, 0);
7525 rc_err_oom_die(rc);
7526 }
7527 assert(*pDb!=0);
7528 rc = sqlite3_prepare_v2(*pDb, zTabFill, -1, &pStmt, 0);
7529 rc_err_oom_die(rc);
7530 rc = sqlite3_bind_text(pStmt, 1, zColNew, -1, 0);
7531 rc_err_oom_die(rc);
7532 rc = sqlite3_step(pStmt);
7533 rc_err_oom_die(rc);
7534 sqlite3_finalize(pStmt);
7535 return 0;
7536 }else if( *pDb==0 ){
7537 return 0;
7538 }else{
7539 /* Formulate the columns spec, close the DB, zero *pDb. */
7540 char *zColsSpec = 0;
7541 int hasDupes = db_int(*pDb, zHasDupes);
larrybr42de1c52022-02-13 22:18:22 +00007542 int nDigits = (hasDupes)? db_int(*pDb, zColDigits) : 0;
larrybr42de1c52022-02-13 22:18:22 +00007543 if( hasDupes ){
larrybr33633862022-02-14 01:12:46 +00007544#ifdef SHELL_COLUMN_RENAME_CLEAN
larrybr42de1c52022-02-13 22:18:22 +00007545 rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
7546 rc_err_oom_die(rc);
larrybr33633862022-02-14 01:12:46 +00007547#endif
larrybr42de1c52022-02-13 22:18:22 +00007548 rc = sqlite3_exec(*pDb, zSetReps, 0, 0, 0);
7549 rc_err_oom_die(rc);
7550 rc = sqlite3_prepare_v2(*pDb, zRenameRank, -1, &pStmt, 0);
7551 rc_err_oom_die(rc);
7552 sqlite3_bind_int(pStmt, 1, nDigits);
7553 rc = sqlite3_step(pStmt);
7554 sqlite3_finalize(pStmt);
7555 assert(rc==SQLITE_DONE);
7556 }
7557 assert(db_int(*pDb, zHasDupes)==0); /* Consider: remove this */
7558 rc = sqlite3_prepare_v2(*pDb, zCollectVar, -1, &pStmt, 0);
7559 rc_err_oom_die(rc);
7560 rc = sqlite3_step(pStmt);
7561 if( rc==SQLITE_ROW ){
7562 zColsSpec = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
7563 }else{
7564 zColsSpec = 0;
7565 }
larrybr33633862022-02-14 01:12:46 +00007566 if( pzRenamed!=0 ){
7567 if( !hasDupes ) *pzRenamed = 0;
7568 else{
7569 sqlite3_finalize(pStmt);
7570 if( SQLITE_OK==sqlite3_prepare_v2(*pDb, zRenamesDone, -1, &pStmt, 0)
7571 && SQLITE_ROW==sqlite3_step(pStmt) ){
7572 *pzRenamed = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
7573 }else
7574 *pzRenamed = 0;
7575 }
7576 }
larrybr42de1c52022-02-13 22:18:22 +00007577 sqlite3_finalize(pStmt);
7578 sqlite3_close(*pDb);
7579 *pDb = 0;
7580 return zColsSpec;
7581 }
7582}
7583
drh2ce15c32017-07-11 13:34:40 +00007584/*
7585** If an input line begins with "." then invoke this routine to
7586** process that line.
7587**
7588** Return 1 on error, 2 to exit, and 0 otherwise.
7589*/
7590static int do_meta_command(char *zLine, ShellState *p){
7591 int h = 1;
7592 int nArg = 0;
7593 int n, c;
7594 int rc = 0;
drh5df84282019-08-17 19:45:25 +00007595 char *azArg[52];
drh2ce15c32017-07-11 13:34:40 +00007596
dan6b046be2018-01-09 15:25:55 +00007597#ifndef SQLITE_OMIT_VIRTUALTABLE
dan43efc182017-12-19 17:42:13 +00007598 if( p->expert.pExpert ){
7599 expertFinish(p, 1, 0);
7600 }
dan6b046be2018-01-09 15:25:55 +00007601#endif
dan43efc182017-12-19 17:42:13 +00007602
drh2ce15c32017-07-11 13:34:40 +00007603 /* Parse the input line into tokens.
7604 */
drh5df84282019-08-17 19:45:25 +00007605 while( zLine[h] && nArg<ArraySize(azArg)-1 ){
drh2ce15c32017-07-11 13:34:40 +00007606 while( IsSpace(zLine[h]) ){ h++; }
7607 if( zLine[h]==0 ) break;
7608 if( zLine[h]=='\'' || zLine[h]=='"' ){
7609 int delim = zLine[h++];
7610 azArg[nArg++] = &zLine[h];
7611 while( zLine[h] && zLine[h]!=delim ){
7612 if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
7613 h++;
7614 }
7615 if( zLine[h]==delim ){
7616 zLine[h++] = 0;
7617 }
7618 if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
7619 }else{
7620 azArg[nArg++] = &zLine[h];
7621 while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
7622 if( zLine[h] ) zLine[h++] = 0;
7623 resolve_backslashes(azArg[nArg-1]);
7624 }
7625 }
drh5df84282019-08-17 19:45:25 +00007626 azArg[nArg] = 0;
drh2ce15c32017-07-11 13:34:40 +00007627
7628 /* Process the input line.
7629 */
7630 if( nArg==0 ) return 0; /* no tokens, no error */
7631 n = strlen30(azArg[0]);
7632 c = azArg[0][0];
drh13c20932018-01-10 21:41:55 +00007633 clearTempFile(p);
drh2ce15c32017-07-11 13:34:40 +00007634
7635#ifndef SQLITE_OMIT_AUTHORIZATION
drhbf70f1b2022-10-19 18:04:42 +00007636 if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00007637 if( nArg!=2 ){
7638 raw_printf(stderr, "Usage: .auth ON|OFF\n");
7639 rc = 1;
7640 goto meta_command_exit;
7641 }
7642 open_db(p, 0);
7643 if( booleanValue(azArg[1]) ){
7644 sqlite3_set_authorizer(p->db, shellAuth, p);
drhb97e2ad2021-08-26 18:31:39 +00007645 }else if( p->bSafeModePersist ){
7646 sqlite3_set_authorizer(p->db, safeModeAuth, p);
drh2ce15c32017-07-11 13:34:40 +00007647 }else{
7648 sqlite3_set_authorizer(p->db, 0, 0);
7649 }
7650 }else
7651#endif
7652
stephan02520cc2022-05-18 22:58:34 +00007653#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) \
stephan4413ec72022-07-12 15:53:02 +00007654 && !defined(SQLITE_SHELL_FIDDLE)
drhbf70f1b2022-10-19 18:04:42 +00007655 if( c=='a' && cli_strncmp(azArg[0], "archive", n)==0 ){
danfd0245d2017-12-07 15:44:29 +00007656 open_db(p, 0);
drhb97e2ad2021-08-26 18:31:39 +00007657 failIfSafeMode(p, "cannot run .archive in safe mode");
drhd0f9cdc2018-05-17 14:09:06 +00007658 rc = arDotCommand(p, 0, azArg, nArg);
danfd0245d2017-12-07 15:44:29 +00007659 }else
7660#endif
7661
stephan4413ec72022-07-12 15:53:02 +00007662#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00007663 if( (c=='b' && n>=3 && cli_strncmp(azArg[0], "backup", n)==0)
7664 || (c=='s' && n>=3 && cli_strncmp(azArg[0], "save", n)==0)
drh2ce15c32017-07-11 13:34:40 +00007665 ){
7666 const char *zDestFile = 0;
7667 const char *zDb = 0;
7668 sqlite3 *pDest;
7669 sqlite3_backup *pBackup;
7670 int j;
drha50bffb2018-12-08 01:09:14 +00007671 int bAsync = 0;
drh69ed38a2018-05-14 00:23:08 +00007672 const char *zVfs = 0;
drhb97e2ad2021-08-26 18:31:39 +00007673 failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
drh2ce15c32017-07-11 13:34:40 +00007674 for(j=1; j<nArg; j++){
7675 const char *z = azArg[j];
7676 if( z[0]=='-' ){
drh69ed38a2018-05-14 00:23:08 +00007677 if( z[1]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +00007678 if( cli_strcmp(z, "-append")==0 ){
drh69ed38a2018-05-14 00:23:08 +00007679 zVfs = "apndvfs";
7680 }else
drhbf70f1b2022-10-19 18:04:42 +00007681 if( cli_strcmp(z, "-async")==0 ){
drha50bffb2018-12-08 01:09:14 +00007682 bAsync = 1;
7683 }else
drh2ce15c32017-07-11 13:34:40 +00007684 {
7685 utf8_printf(stderr, "unknown option: %s\n", azArg[j]);
7686 return 1;
7687 }
7688 }else if( zDestFile==0 ){
7689 zDestFile = azArg[j];
7690 }else if( zDb==0 ){
7691 zDb = zDestFile;
7692 zDestFile = azArg[j];
7693 }else{
drha50bffb2018-12-08 01:09:14 +00007694 raw_printf(stderr, "Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
drh2ce15c32017-07-11 13:34:40 +00007695 return 1;
7696 }
7697 }
7698 if( zDestFile==0 ){
7699 raw_printf(stderr, "missing FILENAME argument on .backup\n");
7700 return 1;
7701 }
7702 if( zDb==0 ) zDb = "main";
drh69ed38a2018-05-14 00:23:08 +00007703 rc = sqlite3_open_v2(zDestFile, &pDest,
7704 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs);
drh2ce15c32017-07-11 13:34:40 +00007705 if( rc!=SQLITE_OK ){
7706 utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
drh9e804032018-05-18 17:11:50 +00007707 close_db(pDest);
drh2ce15c32017-07-11 13:34:40 +00007708 return 1;
7709 }
drha50bffb2018-12-08 01:09:14 +00007710 if( bAsync ){
7711 sqlite3_exec(pDest, "PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF;",
7712 0, 0, 0);
7713 }
drh2ce15c32017-07-11 13:34:40 +00007714 open_db(p, 0);
7715 pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
7716 if( pBackup==0 ){
7717 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
drh9e804032018-05-18 17:11:50 +00007718 close_db(pDest);
drh2ce15c32017-07-11 13:34:40 +00007719 return 1;
7720 }
7721 while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
7722 sqlite3_backup_finish(pBackup);
7723 if( rc==SQLITE_DONE ){
7724 rc = 0;
7725 }else{
7726 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
7727 rc = 1;
7728 }
drh9e804032018-05-18 17:11:50 +00007729 close_db(pDest);
drh2ce15c32017-07-11 13:34:40 +00007730 }else
stephan4413ec72022-07-12 15:53:02 +00007731#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00007732
drhbf70f1b2022-10-19 18:04:42 +00007733 if( c=='b' && n>=3 && cli_strncmp(azArg[0], "bail", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00007734 if( nArg==2 ){
7735 bail_on_error = booleanValue(azArg[1]);
7736 }else{
7737 raw_printf(stderr, "Usage: .bail on|off\n");
7738 rc = 1;
7739 }
7740 }else
7741
drhbf70f1b2022-10-19 18:04:42 +00007742 if( c=='b' && n>=3 && cli_strncmp(azArg[0], "binary", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00007743 if( nArg==2 ){
7744 if( booleanValue(azArg[1]) ){
7745 setBinaryMode(p->out, 1);
7746 }else{
7747 setTextMode(p->out, 1);
7748 }
7749 }else{
7750 raw_printf(stderr, "Usage: .binary on|off\n");
7751 rc = 1;
7752 }
7753 }else
7754
drh37407122021-07-23 18:43:58 +00007755 /* The undocumented ".breakpoint" command causes a call to the no-op
7756 ** routine named test_breakpoint().
7757 */
drhbf70f1b2022-10-19 18:04:42 +00007758 if( c=='b' && n>=3 && cli_strncmp(azArg[0], "breakpoint", n)==0 ){
drh37407122021-07-23 18:43:58 +00007759 test_breakpoint();
7760 }else
7761
stephan4413ec72022-07-12 15:53:02 +00007762#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00007763 if( c=='c' && cli_strcmp(azArg[0],"cd")==0 ){
drhb97e2ad2021-08-26 18:31:39 +00007764 failIfSafeMode(p, "cannot run .cd in safe mode");
drh2ce15c32017-07-11 13:34:40 +00007765 if( nArg==2 ){
7766#if defined(_WIN32) || defined(WIN32)
7767 wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
7768 rc = !SetCurrentDirectoryW(z);
7769 sqlite3_free(z);
7770#else
7771 rc = chdir(azArg[1]);
7772#endif
7773 if( rc ){
7774 utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
7775 rc = 1;
7776 }
7777 }else{
7778 raw_printf(stderr, "Usage: .cd DIRECTORY\n");
7779 rc = 1;
7780 }
7781 }else
stephan4413ec72022-07-12 15:53:02 +00007782#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00007783
drhbf70f1b2022-10-19 18:04:42 +00007784 if( c=='c' && n>=3 && cli_strncmp(azArg[0], "changes", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00007785 if( nArg==2 ){
7786 setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
7787 }else{
7788 raw_printf(stderr, "Usage: .changes on|off\n");
7789 rc = 1;
7790 }
7791 }else
7792
stephan4413ec72022-07-12 15:53:02 +00007793#ifndef SQLITE_SHELL_FIDDLE
drh2ce15c32017-07-11 13:34:40 +00007794 /* Cancel output redirection, if it is currently set (by .testcase)
7795 ** Then read the content of the testcase-out.txt file and compare against
7796 ** azArg[1]. If there are differences, report an error and exit.
7797 */
drhbf70f1b2022-10-19 18:04:42 +00007798 if( c=='c' && n>=3 && cli_strncmp(azArg[0], "check", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00007799 char *zRes = 0;
7800 output_reset(p);
7801 if( nArg!=2 ){
7802 raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
7803 rc = 2;
7804 }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
7805 raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
7806 rc = 2;
7807 }else if( testcase_glob(azArg[1],zRes)==0 ){
7808 utf8_printf(stderr,
7809 "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
7810 p->zTestcase, azArg[1], zRes);
drhf30d3452017-10-17 13:44:46 +00007811 rc = 1;
drh2ce15c32017-07-11 13:34:40 +00007812 }else{
7813 utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
7814 p->nCheck++;
7815 }
7816 sqlite3_free(zRes);
7817 }else
stephan4413ec72022-07-12 15:53:02 +00007818#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00007819
stephan4413ec72022-07-12 15:53:02 +00007820#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00007821 if( c=='c' && cli_strncmp(azArg[0], "clone", n)==0 ){
drhb97e2ad2021-08-26 18:31:39 +00007822 failIfSafeMode(p, "cannot run .clone in safe mode");
drh2ce15c32017-07-11 13:34:40 +00007823 if( nArg==2 ){
7824 tryToClone(p, azArg[1]);
7825 }else{
7826 raw_printf(stderr, "Usage: .clone FILENAME\n");
7827 rc = 1;
7828 }
7829 }else
stephan4413ec72022-07-12 15:53:02 +00007830#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00007831
drhbf70f1b2022-10-19 18:04:42 +00007832 if( c=='c' && cli_strncmp(azArg[0], "connection", n)==0 ){
drh37407122021-07-23 18:43:58 +00007833 if( nArg==1 ){
7834 /* List available connections */
7835 int i;
7836 for(i=0; i<ArraySize(p->aAuxDb); i++){
7837 const char *zFile = p->aAuxDb[i].zDbFilename;
7838 if( p->aAuxDb[i].db==0 && p->pAuxDb!=&p->aAuxDb[i] ){
7839 zFile = "(not open)";
7840 }else if( zFile==0 ){
7841 zFile = "(memory)";
7842 }else if( zFile[0]==0 ){
7843 zFile = "(temporary-file)";
7844 }
7845 if( p->pAuxDb == &p->aAuxDb[i] ){
7846 utf8_printf(stdout, "ACTIVE %d: %s\n", i, zFile);
7847 }else if( p->aAuxDb[i].db!=0 ){
7848 utf8_printf(stdout, " %d: %s\n", i, zFile);
7849 }
7850 }
7851 }else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){
7852 int i = azArg[1][0] - '0';
7853 if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && i<ArraySize(p->aAuxDb) ){
7854 p->pAuxDb->db = p->db;
7855 p->pAuxDb = &p->aAuxDb[i];
7856 globalDb = p->db = p->pAuxDb->db;
7857 p->pAuxDb->db = 0;
7858 }
drhbf70f1b2022-10-19 18:04:42 +00007859 }else if( nArg==3 && cli_strcmp(azArg[1], "close")==0
drh37407122021-07-23 18:43:58 +00007860 && IsDigit(azArg[2][0]) && azArg[2][1]==0 ){
7861 int i = azArg[2][0] - '0';
7862 if( i<0 || i>=ArraySize(p->aAuxDb) ){
7863 /* No-op */
7864 }else if( p->pAuxDb == &p->aAuxDb[i] ){
7865 raw_printf(stderr, "cannot close the active database connection\n");
7866 rc = 1;
7867 }else if( p->aAuxDb[i].db ){
7868 session_close_all(p, i);
7869 close_db(p->aAuxDb[i].db);
7870 p->aAuxDb[i].db = 0;
7871 }
7872 }else{
7873 raw_printf(stderr, "Usage: .connection [close] [CONNECTION-NUMBER]\n");
7874 rc = 1;
7875 }
7876 }else
7877
drhbf70f1b2022-10-19 18:04:42 +00007878 if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){
drh60081a02020-08-26 19:07:18 +00007879 char **azName = 0;
7880 int nName = 0;
7881 sqlite3_stmt *pStmt;
drh60081a02020-08-26 19:07:18 +00007882 int i;
drh2ce15c32017-07-11 13:34:40 +00007883 open_db(p, 0);
drh60081a02020-08-26 19:07:18 +00007884 rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
7885 if( rc ){
7886 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
drh2ce15c32017-07-11 13:34:40 +00007887 rc = 1;
drh60081a02020-08-26 19:07:18 +00007888 }else{
7889 while( sqlite3_step(pStmt)==SQLITE_ROW ){
7890 const char *zSchema = (const char *)sqlite3_column_text(pStmt,1);
7891 const char *zFile = (const char*)sqlite3_column_text(pStmt,2);
drh621a5e02021-12-16 17:35:27 +00007892 if( zSchema==0 || zFile==0 ) continue;
drh60081a02020-08-26 19:07:18 +00007893 azName = sqlite3_realloc(azName, (nName+1)*2*sizeof(char*));
drhe3e25652021-12-16 13:29:28 +00007894 shell_check_oom(azName);
drh60081a02020-08-26 19:07:18 +00007895 azName[nName*2] = strdup(zSchema);
7896 azName[nName*2+1] = strdup(zFile);
7897 nName++;
7898 }
drh2ce15c32017-07-11 13:34:40 +00007899 }
drh60081a02020-08-26 19:07:18 +00007900 sqlite3_finalize(pStmt);
7901 for(i=0; i<nName; i++){
7902 int eTxn = sqlite3_txn_state(p->db, azName[i*2]);
7903 int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]);
7904 const char *z = azName[i*2+1];
7905 utf8_printf(p->out, "%s: %s %s%s\n",
7906 azName[i*2],
7907 z && z[0] ? z : "\"\"",
7908 bRdonly ? "r/o" : "r/w",
7909 eTxn==SQLITE_TXN_NONE ? "" :
7910 eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn");
7911 free(azName[i*2]);
7912 free(azName[i*2+1]);
7913 }
7914 sqlite3_free(azName);
drh2ce15c32017-07-11 13:34:40 +00007915 }else
7916
drhbf70f1b2022-10-19 18:04:42 +00007917 if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbconfig", n)==0 ){
drheb7f2a02018-09-26 18:02:32 +00007918 static const struct DbConfigChoices {
7919 const char *zName;
7920 int op;
7921 } aDbConfig[] = {
drhb945bcd2019-12-31 22:52:10 +00007922 { "defensive", SQLITE_DBCONFIG_DEFENSIVE },
7923 { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
7924 { "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
drh0a6873b2019-06-14 21:25:25 +00007925 { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
drhb945bcd2019-12-31 22:52:10 +00007926 { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
drh0a6873b2019-06-14 21:25:25 +00007927 { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
drh11d88e62019-08-15 21:27:20 +00007928 { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
drh0a6873b2019-06-14 21:25:25 +00007929 { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
drhb945bcd2019-12-31 22:52:10 +00007930 { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
7931 { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT },
drh0a6873b2019-06-14 21:25:25 +00007932 { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
7933 { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
drh0a6873b2019-06-14 21:25:25 +00007934 { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE },
drhb945bcd2019-12-31 22:52:10 +00007935 { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
drhb77da372020-01-07 16:09:11 +00007936 { "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA },
dan07312a62019-06-21 14:05:27 +00007937 { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
drh7df01192018-04-28 12:43:16 +00007938 };
7939 int ii, v;
7940 open_db(p, 0);
7941 for(ii=0; ii<ArraySize(aDbConfig); ii++){
drhbf70f1b2022-10-19 18:04:42 +00007942 if( nArg>1 && cli_strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
drh7df01192018-04-28 12:43:16 +00007943 if( nArg>=3 ){
7944 sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
7945 }
7946 sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
drhb945bcd2019-12-31 22:52:10 +00007947 utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
drh7df01192018-04-28 12:43:16 +00007948 if( nArg>1 ) break;
7949 }
7950 if( nArg>1 && ii==ArraySize(aDbConfig) ){
7951 utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]);
7952 utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n");
7953 }
7954 }else
7955
stephan3d420832022-10-27 03:56:01 +00007956#if SQLITE_SHELL_HAVE_RECOVER
drhbf70f1b2022-10-19 18:04:42 +00007957 if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00007958 rc = shell_dbinfo_command(p, nArg, azArg);
7959 }else
7960
drhbf70f1b2022-10-19 18:04:42 +00007961 if( c=='r' && cli_strncmp(azArg[0], "recover", n)==0 ){
dan68cb86e2019-04-20 20:57:28 +00007962 open_db(p, 0);
danb9b71db2019-04-25 16:20:40 +00007963 rc = recoverDatabaseCmd(p, nArg, azArg);
dan68cb86e2019-04-20 20:57:28 +00007964 }else
stephan3d420832022-10-27 03:56:01 +00007965#endif /* SQLITE_SHELL_HAVE_RECOVER */
dan68cb86e2019-04-20 20:57:28 +00007966
drhbf70f1b2022-10-19 18:04:42 +00007967 if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){
drh8e9297f2020-03-25 12:50:13 +00007968 char *zLike = 0;
7969 char *zSql;
drh2ce15c32017-07-11 13:34:40 +00007970 int i;
7971 int savedShowHeader = p->showHeader;
drhf213b332018-07-05 17:35:46 +00007972 int savedShellFlags = p->shellFlgs;
larrybr527c39d2022-05-10 14:55:45 +00007973 ShellClearFlag(p,
drhc1962192020-10-12 16:54:28 +00007974 SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo
7975 |SHFLG_DumpDataOnly|SHFLG_DumpNoSys);
drh2ce15c32017-07-11 13:34:40 +00007976 for(i=1; i<nArg; i++){
7977 if( azArg[i][0]=='-' ){
7978 const char *z = azArg[i]+1;
7979 if( z[0]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +00007980 if( cli_strcmp(z,"preserve-rowids")==0 ){
drh2ce15c32017-07-11 13:34:40 +00007981#ifdef SQLITE_OMIT_VIRTUALTABLE
7982 raw_printf(stderr, "The --preserve-rowids option is not compatible"
7983 " with SQLITE_OMIT_VIRTUALTABLE\n");
7984 rc = 1;
drh1d29fd82020-05-29 19:03:03 +00007985 sqlite3_free(zLike);
drh2ce15c32017-07-11 13:34:40 +00007986 goto meta_command_exit;
7987#else
7988 ShellSetFlag(p, SHFLG_PreserveRowid);
7989#endif
7990 }else
drhbf70f1b2022-10-19 18:04:42 +00007991 if( cli_strcmp(z,"newlines")==0 ){
drh2ce15c32017-07-11 13:34:40 +00007992 ShellSetFlag(p, SHFLG_Newlines);
7993 }else
drhbf70f1b2022-10-19 18:04:42 +00007994 if( cli_strcmp(z,"data-only")==0 ){
drhc1962192020-10-12 16:54:28 +00007995 ShellSetFlag(p, SHFLG_DumpDataOnly);
7996 }else
drhbf70f1b2022-10-19 18:04:42 +00007997 if( cli_strcmp(z,"nosys")==0 ){
drhc1962192020-10-12 16:54:28 +00007998 ShellSetFlag(p, SHFLG_DumpNoSys);
7999 }else
drh2ce15c32017-07-11 13:34:40 +00008000 {
8001 raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
8002 rc = 1;
drh1d29fd82020-05-29 19:03:03 +00008003 sqlite3_free(zLike);
drh2ce15c32017-07-11 13:34:40 +00008004 goto meta_command_exit;
8005 }
drh2ce15c32017-07-11 13:34:40 +00008006 }else{
dan78a9d752021-05-25 11:39:14 +00008007 /* azArg[i] contains a LIKE pattern. This ".dump" request should
8008 ** only dump data for tables for which either the table name matches
8009 ** the LIKE pattern, or the table appears to be a shadow table of
8010 ** a virtual table for which the name matches the LIKE pattern.
8011 */
8012 char *zExpr = sqlite3_mprintf(
8013 "name LIKE %Q ESCAPE '\\' OR EXISTS ("
8014 " SELECT 1 FROM sqlite_schema WHERE "
8015 " name LIKE %Q ESCAPE '\\' AND"
8016 " sql LIKE 'CREATE VIRTUAL TABLE%%' AND"
8017 " substr(o.name, 1, length(name)+1) == (name||'_')"
8018 ")", azArg[i], azArg[i]
8019 );
8020
8021 if( zLike ){
8022 zLike = sqlite3_mprintf("%z OR %z", zLike, zExpr);
8023 }else{
8024 zLike = zExpr;
8025 }
drh2ce15c32017-07-11 13:34:40 +00008026 }
8027 }
dan68cb86e2019-04-20 20:57:28 +00008028
drh2ce15c32017-07-11 13:34:40 +00008029 open_db(p, 0);
dan68cb86e2019-04-20 20:57:28 +00008030
drhc1962192020-10-12 16:54:28 +00008031 if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
8032 /* When playing back a "dump", the content might appear in an order
8033 ** which causes immediate foreign key constraints to be violated.
8034 ** So disable foreign-key constraint enforcement to prevent problems. */
8035 raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
8036 raw_printf(p->out, "BEGIN TRANSACTION;\n");
8037 }
drh2ce15c32017-07-11 13:34:40 +00008038 p->writableSchema = 0;
8039 p->showHeader = 0;
8040 /* Set writable_schema=ON since doing so forces SQLite to initialize
drh067b92b2020-06-19 15:24:12 +00008041 ** as much of the schema as it can even if the sqlite_schema table is
drh2ce15c32017-07-11 13:34:40 +00008042 ** corrupt. */
8043 sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
8044 p->nErr = 0;
drh8e9297f2020-03-25 12:50:13 +00008045 if( zLike==0 ) zLike = sqlite3_mprintf("true");
8046 zSql = sqlite3_mprintf(
dan78a9d752021-05-25 11:39:14 +00008047 "SELECT name, type, sql FROM sqlite_schema AS o "
drh8e9297f2020-03-25 12:50:13 +00008048 "WHERE (%s) AND type=='table'"
8049 " AND sql NOT NULL"
8050 " ORDER BY tbl_name='sqlite_sequence', rowid",
8051 zLike
8052 );
8053 run_schema_dump_query(p,zSql);
8054 sqlite3_free(zSql);
drhc1962192020-10-12 16:54:28 +00008055 if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
8056 zSql = sqlite3_mprintf(
dan78a9d752021-05-25 11:39:14 +00008057 "SELECT sql FROM sqlite_schema AS o "
drhc1962192020-10-12 16:54:28 +00008058 "WHERE (%s) AND sql NOT NULL"
8059 " AND type IN ('index','trigger','view')",
8060 zLike
8061 );
8062 run_table_dump_query(p, zSql);
8063 sqlite3_free(zSql);
8064 }
drh8e9297f2020-03-25 12:50:13 +00008065 sqlite3_free(zLike);
drh2ce15c32017-07-11 13:34:40 +00008066 if( p->writableSchema ){
8067 raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
8068 p->writableSchema = 0;
8069 }
8070 sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
8071 sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
drhc1962192020-10-12 16:54:28 +00008072 if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
8073 raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
8074 }
drh2ce15c32017-07-11 13:34:40 +00008075 p->showHeader = savedShowHeader;
drhf213b332018-07-05 17:35:46 +00008076 p->shellFlgs = savedShellFlags;
drh2ce15c32017-07-11 13:34:40 +00008077 }else
8078
drhbf70f1b2022-10-19 18:04:42 +00008079 if( c=='e' && cli_strncmp(azArg[0], "echo", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008080 if( nArg==2 ){
8081 setOrClearFlag(p, SHFLG_Echo, azArg[1]);
8082 }else{
8083 raw_printf(stderr, "Usage: .echo on|off\n");
8084 rc = 1;
8085 }
8086 }else
8087
drhbf70f1b2022-10-19 18:04:42 +00008088 if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008089 if( nArg==2 ){
drhe2ca99c2018-05-02 00:33:43 +00008090 p->autoEQPtest = 0;
drhb4e50392019-01-26 15:40:04 +00008091 if( p->autoEQPtrace ){
8092 if( p->db ) sqlite3_exec(p->db, "PRAGMA vdbe_trace=OFF;", 0, 0, 0);
8093 p->autoEQPtrace = 0;
8094 }
drhbf70f1b2022-10-19 18:04:42 +00008095 if( cli_strcmp(azArg[1],"full")==0 ){
drhada70452017-12-21 21:02:27 +00008096 p->autoEQP = AUTOEQP_full;
drhbf70f1b2022-10-19 18:04:42 +00008097 }else if( cli_strcmp(azArg[1],"trigger")==0 ){
drhada70452017-12-21 21:02:27 +00008098 p->autoEQP = AUTOEQP_trigger;
drhb4e50392019-01-26 15:40:04 +00008099#ifdef SQLITE_DEBUG
drhbf70f1b2022-10-19 18:04:42 +00008100 }else if( cli_strcmp(azArg[1],"test")==0 ){
drhe2ca99c2018-05-02 00:33:43 +00008101 p->autoEQP = AUTOEQP_on;
8102 p->autoEQPtest = 1;
drhbf70f1b2022-10-19 18:04:42 +00008103 }else if( cli_strcmp(azArg[1],"trace")==0 ){
drhb4e50392019-01-26 15:40:04 +00008104 p->autoEQP = AUTOEQP_full;
8105 p->autoEQPtrace = 1;
8106 open_db(p, 0);
drh067b92b2020-06-19 15:24:12 +00008107 sqlite3_exec(p->db, "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0);
drhb4e50392019-01-26 15:40:04 +00008108 sqlite3_exec(p->db, "PRAGMA vdbe_trace=ON;", 0, 0, 0);
8109#endif
drh2ce15c32017-07-11 13:34:40 +00008110 }else{
mistachkinb71aa092018-01-23 00:05:18 +00008111 p->autoEQP = (u8)booleanValue(azArg[1]);
drh2ce15c32017-07-11 13:34:40 +00008112 }
8113 }else{
drhb4e50392019-01-26 15:40:04 +00008114 raw_printf(stderr, "Usage: .eqp off|on|trace|trigger|full\n");
drh2ce15c32017-07-11 13:34:40 +00008115 rc = 1;
8116 }
8117 }else
8118
stephan4413ec72022-07-12 15:53:02 +00008119#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00008120 if( c=='e' && cli_strncmp(azArg[0], "exit", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008121 if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
8122 rc = 2;
8123 }else
stephan02520cc2022-05-18 22:58:34 +00008124#endif
drh2ce15c32017-07-11 13:34:40 +00008125
8126 /* The ".explain" command is automatic now. It is largely pointless. It
8127 ** retained purely for backwards compatibility */
drhbf70f1b2022-10-19 18:04:42 +00008128 if( c=='e' && cli_strncmp(azArg[0], "explain", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008129 int val = 1;
8130 if( nArg>=2 ){
drhbf70f1b2022-10-19 18:04:42 +00008131 if( cli_strcmp(azArg[1],"auto")==0 ){
drh2ce15c32017-07-11 13:34:40 +00008132 val = 99;
8133 }else{
8134 val = booleanValue(azArg[1]);
8135 }
8136 }
8137 if( val==1 && p->mode!=MODE_Explain ){
8138 p->normalMode = p->mode;
8139 p->mode = MODE_Explain;
8140 p->autoExplain = 0;
8141 }else if( val==0 ){
8142 if( p->mode==MODE_Explain ) p->mode = p->normalMode;
8143 p->autoExplain = 0;
8144 }else if( val==99 ){
8145 if( p->mode==MODE_Explain ) p->mode = p->normalMode;
8146 p->autoExplain = 1;
8147 }
8148 }else
8149
dan6b046be2018-01-09 15:25:55 +00008150#ifndef SQLITE_OMIT_VIRTUALTABLE
drhbf70f1b2022-10-19 18:04:42 +00008151 if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){
drhfe463172021-12-16 17:57:21 +00008152 if( p->bSafeMode ){
8153 raw_printf(stderr,
8154 "Cannot run experimental commands such as \"%s\" in safe mode\n",
8155 azArg[0]);
8156 rc = 1;
8157 }else{
8158 open_db(p, 0);
8159 expertDotCommand(p, azArg, nArg);
8160 }
dan43efc182017-12-19 17:42:13 +00008161 }else
dan6b046be2018-01-09 15:25:55 +00008162#endif
dan43efc182017-12-19 17:42:13 +00008163
drhbf70f1b2022-10-19 18:04:42 +00008164 if( c=='f' && cli_strncmp(azArg[0], "filectrl", n)==0 ){
drhd985f722019-06-05 14:29:53 +00008165 static const struct {
8166 const char *zCtrlName; /* Name of a test-control option */
8167 int ctrlCode; /* Integer code for that option */
8168 const char *zUsage; /* Usage notes */
8169 } aCtrl[] = {
drhd985f722019-06-05 14:29:53 +00008170 { "chunk_size", SQLITE_FCNTL_CHUNK_SIZE, "SIZE" },
drh18a4bbd2020-12-17 15:17:42 +00008171 { "data_version", SQLITE_FCNTL_DATA_VERSION, "" },
drhd985f722019-06-05 14:29:53 +00008172 { "has_moved", SQLITE_FCNTL_HAS_MOVED, "" },
8173 { "lock_timeout", SQLITE_FCNTL_LOCK_TIMEOUT, "MILLISEC" },
drh18a4bbd2020-12-17 15:17:42 +00008174 { "persist_wal", SQLITE_FCNTL_PERSIST_WAL, "[BOOLEAN]" },
8175 /* { "pragma", SQLITE_FCNTL_PRAGMA, "NAME ARG" },*/
8176 { "psow", SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]" },
drh541ef2c2020-04-20 16:21:30 +00008177 { "reserve_bytes", SQLITE_FCNTL_RESERVE_BYTES, "[N]" },
drh18a4bbd2020-12-17 15:17:42 +00008178 { "size_limit", SQLITE_FCNTL_SIZE_LIMIT, "[LIMIT]" },
8179 { "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" },
8180 /* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY, "COUNT DELAY" },*/
drhd985f722019-06-05 14:29:53 +00008181 };
8182 int filectrl = -1;
8183 int iCtrl = -1;
drh4245e042019-06-13 13:52:46 +00008184 sqlite3_int64 iRes = 0; /* Integer result to display if rc2==1 */
8185 int isOk = 0; /* 0: usage 1: %lld 2: no-result */
drhd985f722019-06-05 14:29:53 +00008186 int n2, i;
8187 const char *zCmd = 0;
drh541ef2c2020-04-20 16:21:30 +00008188 const char *zSchema = 0;
drhd985f722019-06-05 14:29:53 +00008189
8190 open_db(p, 0);
8191 zCmd = nArg>=2 ? azArg[1] : "help";
8192
drh541ef2c2020-04-20 16:21:30 +00008193 if( zCmd[0]=='-'
drhbf70f1b2022-10-19 18:04:42 +00008194 && (cli_strcmp(zCmd,"--schema")==0 || cli_strcmp(zCmd,"-schema")==0)
drh541ef2c2020-04-20 16:21:30 +00008195 && nArg>=4
8196 ){
8197 zSchema = azArg[2];
8198 for(i=3; i<nArg; i++) azArg[i-2] = azArg[i];
8199 nArg -= 2;
8200 zCmd = azArg[1];
8201 }
8202
drhd985f722019-06-05 14:29:53 +00008203 /* The argument can optionally begin with "-" or "--" */
8204 if( zCmd[0]=='-' && zCmd[1] ){
8205 zCmd++;
8206 if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
8207 }
8208
8209 /* --help lists all file-controls */
drhbf70f1b2022-10-19 18:04:42 +00008210 if( cli_strcmp(zCmd,"help")==0 ){
drhd985f722019-06-05 14:29:53 +00008211 utf8_printf(p->out, "Available file-controls:\n");
8212 for(i=0; i<ArraySize(aCtrl); i++){
8213 utf8_printf(p->out, " .filectrl %s %s\n",
8214 aCtrl[i].zCtrlName, aCtrl[i].zUsage);
8215 }
8216 rc = 1;
8217 goto meta_command_exit;
8218 }
8219
8220 /* convert filectrl text option to value. allow any unique prefix
8221 ** of the option name, or a numerical value. */
8222 n2 = strlen30(zCmd);
8223 for(i=0; i<ArraySize(aCtrl); i++){
drhbf70f1b2022-10-19 18:04:42 +00008224 if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
drhd985f722019-06-05 14:29:53 +00008225 if( filectrl<0 ){
8226 filectrl = aCtrl[i].ctrlCode;
8227 iCtrl = i;
8228 }else{
8229 utf8_printf(stderr, "Error: ambiguous file-control: \"%s\"\n"
8230 "Use \".filectrl --help\" for help\n", zCmd);
8231 rc = 1;
8232 goto meta_command_exit;
8233 }
8234 }
8235 }
8236 if( filectrl<0 ){
8237 utf8_printf(stderr,"Error: unknown file-control: %s\n"
8238 "Use \".filectrl --help\" for help\n", zCmd);
8239 }else{
8240 switch(filectrl){
8241 case SQLITE_FCNTL_SIZE_LIMIT: {
8242 if( nArg!=2 && nArg!=3 ) break;
8243 iRes = nArg==3 ? integerValue(azArg[2]) : -1;
drh541ef2c2020-04-20 16:21:30 +00008244 sqlite3_file_control(p->db, zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
drhd985f722019-06-05 14:29:53 +00008245 isOk = 1;
8246 break;
8247 }
8248 case SQLITE_FCNTL_LOCK_TIMEOUT:
8249 case SQLITE_FCNTL_CHUNK_SIZE: {
8250 int x;
8251 if( nArg!=3 ) break;
8252 x = (int)integerValue(azArg[2]);
drh541ef2c2020-04-20 16:21:30 +00008253 sqlite3_file_control(p->db, zSchema, filectrl, &x);
drhd985f722019-06-05 14:29:53 +00008254 isOk = 2;
8255 break;
8256 }
8257 case SQLITE_FCNTL_PERSIST_WAL:
8258 case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
8259 int x;
8260 if( nArg!=2 && nArg!=3 ) break;
8261 x = nArg==3 ? booleanValue(azArg[2]) : -1;
drh541ef2c2020-04-20 16:21:30 +00008262 sqlite3_file_control(p->db, zSchema, filectrl, &x);
drhd985f722019-06-05 14:29:53 +00008263 iRes = x;
8264 isOk = 1;
8265 break;
8266 }
drh18a4bbd2020-12-17 15:17:42 +00008267 case SQLITE_FCNTL_DATA_VERSION:
drhd985f722019-06-05 14:29:53 +00008268 case SQLITE_FCNTL_HAS_MOVED: {
8269 int x;
8270 if( nArg!=2 ) break;
drh541ef2c2020-04-20 16:21:30 +00008271 sqlite3_file_control(p->db, zSchema, filectrl, &x);
drhd985f722019-06-05 14:29:53 +00008272 iRes = x;
8273 isOk = 1;
8274 break;
8275 }
8276 case SQLITE_FCNTL_TEMPFILENAME: {
8277 char *z = 0;
8278 if( nArg!=2 ) break;
drh541ef2c2020-04-20 16:21:30 +00008279 sqlite3_file_control(p->db, zSchema, filectrl, &z);
drhd985f722019-06-05 14:29:53 +00008280 if( z ){
8281 utf8_printf(p->out, "%s\n", z);
8282 sqlite3_free(z);
8283 }
8284 isOk = 2;
8285 break;
8286 }
drh541ef2c2020-04-20 16:21:30 +00008287 case SQLITE_FCNTL_RESERVE_BYTES: {
8288 int x;
8289 if( nArg>=3 ){
8290 x = atoi(azArg[2]);
8291 sqlite3_file_control(p->db, zSchema, filectrl, &x);
8292 }
8293 x = -1;
8294 sqlite3_file_control(p->db, zSchema, filectrl, &x);
8295 utf8_printf(p->out,"%d\n", x);
8296 isOk = 2;
8297 break;
8298 }
drhd985f722019-06-05 14:29:53 +00008299 }
8300 }
8301 if( isOk==0 && iCtrl>=0 ){
8302 utf8_printf(p->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
8303 rc = 1;
8304 }else if( isOk==1 ){
drhe2500762019-06-13 14:07:41 +00008305 char zBuf[100];
8306 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
8307 raw_printf(p->out, "%s\n", zBuf);
drhd985f722019-06-05 14:29:53 +00008308 }
8309 }else
8310
drhbf70f1b2022-10-19 18:04:42 +00008311 if( c=='f' && cli_strncmp(azArg[0], "fullschema", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008312 ShellState data;
drh2ce15c32017-07-11 13:34:40 +00008313 int doStats = 0;
8314 memcpy(&data, p, sizeof(data));
8315 data.showHeader = 0;
8316 data.cMode = data.mode = MODE_Semi;
8317 if( nArg==2 && optionMatch(azArg[1], "indent") ){
8318 data.cMode = data.mode = MODE_Pretty;
8319 nArg = 1;
8320 }
8321 if( nArg!=1 ){
8322 raw_printf(stderr, "Usage: .fullschema ?--indent?\n");
8323 rc = 1;
8324 goto meta_command_exit;
8325 }
8326 open_db(p, 0);
8327 rc = sqlite3_exec(p->db,
8328 "SELECT sql FROM"
8329 " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
drh067b92b2020-06-19 15:24:12 +00008330 " FROM sqlite_schema UNION ALL"
8331 " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) "
drh2ce15c32017-07-11 13:34:40 +00008332 "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
drh69935c02021-06-25 11:14:10 +00008333 "ORDER BY x",
drhf83d5012021-05-03 13:35:00 +00008334 callback, &data, 0
drh2ce15c32017-07-11 13:34:40 +00008335 );
8336 if( rc==SQLITE_OK ){
8337 sqlite3_stmt *pStmt;
8338 rc = sqlite3_prepare_v2(p->db,
drh067b92b2020-06-19 15:24:12 +00008339 "SELECT rowid FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +00008340 " WHERE name GLOB 'sqlite_stat[134]'",
8341 -1, &pStmt, 0);
8342 doStats = sqlite3_step(pStmt)==SQLITE_ROW;
8343 sqlite3_finalize(pStmt);
8344 }
8345 if( doStats==0 ){
8346 raw_printf(p->out, "/* No STAT tables available */\n");
8347 }else{
drh067b92b2020-06-19 15:24:12 +00008348 raw_printf(p->out, "ANALYZE sqlite_schema;\n");
drh2ce15c32017-07-11 13:34:40 +00008349 data.cMode = data.mode = MODE_Insert;
8350 data.zDestTable = "sqlite_stat1";
drhf83d5012021-05-03 13:35:00 +00008351 shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
drh2ce15c32017-07-11 13:34:40 +00008352 data.zDestTable = "sqlite_stat4";
drhf83d5012021-05-03 13:35:00 +00008353 shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
drh067b92b2020-06-19 15:24:12 +00008354 raw_printf(p->out, "ANALYZE sqlite_schema;\n");
drh2ce15c32017-07-11 13:34:40 +00008355 }
8356 }else
8357
drhbf70f1b2022-10-19 18:04:42 +00008358 if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008359 if( nArg==2 ){
8360 p->showHeader = booleanValue(azArg[1]);
drhc0605082020-06-05 00:54:27 +00008361 p->shellFlgs |= SHFLG_HeaderSet;
drh2ce15c32017-07-11 13:34:40 +00008362 }else{
8363 raw_printf(stderr, "Usage: .headers on|off\n");
8364 rc = 1;
8365 }
8366 }else
8367
drhbf70f1b2022-10-19 18:04:42 +00008368 if( c=='h' && cli_strncmp(azArg[0], "help", n)==0 ){
drh98aa2ab2018-09-26 16:53:51 +00008369 if( nArg>=2 ){
drhe93f8262018-10-11 16:53:37 +00008370 n = showHelp(p->out, azArg[1]);
drh98aa2ab2018-09-26 16:53:51 +00008371 if( n==0 ){
8372 utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]);
8373 }
8374 }else{
8375 showHelp(p->out, 0);
8376 }
drh2ce15c32017-07-11 13:34:40 +00008377 }else
8378
stephan4413ec72022-07-12 15:53:02 +00008379#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00008380 if( c=='i' && cli_strncmp(azArg[0], "import", n)==0 ){
drhccb37812020-03-09 15:39:39 +00008381 char *zTable = 0; /* Insert data into this table */
larrybr53e11862022-03-06 23:41:21 +00008382 char *zSchema = 0; /* within this schema (may default to "main") */
drhccb37812020-03-09 15:39:39 +00008383 char *zFile = 0; /* Name of file to extra content from */
drh2ce15c32017-07-11 13:34:40 +00008384 sqlite3_stmt *pStmt = NULL; /* A statement */
8385 int nCol; /* Number of columns in the table */
8386 int nByte; /* Number of bytes in an SQL string */
8387 int i, j; /* Loop counters */
8388 int needCommit; /* True to COMMIT or ROLLBACK at end */
8389 int nSep; /* Number of bytes in p->colSeparator[] */
8390 char *zSql; /* An SQL statement */
larrybr41f46702022-03-07 00:14:52 +00008391 char *zFullTabName; /* Table name with schema if applicable */
drh2ce15c32017-07-11 13:34:40 +00008392 ImportCtx sCtx; /* Reader context */
8393 char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
drhccb37812020-03-09 15:39:39 +00008394 int eVerbose = 0; /* Larger for more console output */
8395 int nSkip = 0; /* Initial lines to skip */
8396 int useOutputMode = 1; /* Use output mode to determine separators */
drhe684ac62022-03-08 13:59:46 +00008397 char *zCreate = 0; /* CREATE TABLE statement text */
drh2ce15c32017-07-11 13:34:40 +00008398
drhb97e2ad2021-08-26 18:31:39 +00008399 failIfSafeMode(p, "cannot run .import in safe mode");
drhccb37812020-03-09 15:39:39 +00008400 memset(&sCtx, 0, sizeof(sCtx));
8401 if( p->mode==MODE_Ascii ){
8402 xRead = ascii_read_one_field;
8403 }else{
8404 xRead = csv_read_one_field;
8405 }
larrybr2f5f6742022-05-09 12:29:47 +00008406 rc = 1;
drhccb37812020-03-09 15:39:39 +00008407 for(i=1; i<nArg; i++){
8408 char *z = azArg[i];
8409 if( z[0]=='-' && z[1]=='-' ) z++;
8410 if( z[0]!='-' ){
8411 if( zFile==0 ){
8412 zFile = z;
8413 }else if( zTable==0 ){
8414 zTable = z;
8415 }else{
8416 utf8_printf(p->out, "ERROR: extra argument: \"%s\". Usage:\n", z);
8417 showHelp(p->out, "import");
drhccb37812020-03-09 15:39:39 +00008418 goto meta_command_exit;
8419 }
drhbf70f1b2022-10-19 18:04:42 +00008420 }else if( cli_strcmp(z,"-v")==0 ){
drhccb37812020-03-09 15:39:39 +00008421 eVerbose++;
drhbf70f1b2022-10-19 18:04:42 +00008422 }else if( cli_strcmp(z,"-schema")==0 && i<nArg-1 ){
larrybr738d7b92022-01-13 21:22:54 +00008423 zSchema = azArg[++i];
drhbf70f1b2022-10-19 18:04:42 +00008424 }else if( cli_strcmp(z,"-skip")==0 && i<nArg-1 ){
drhccb37812020-03-09 15:39:39 +00008425 nSkip = integerValue(azArg[++i]);
drhbf70f1b2022-10-19 18:04:42 +00008426 }else if( cli_strcmp(z,"-ascii")==0 ){
drhccb37812020-03-09 15:39:39 +00008427 sCtx.cColSep = SEP_Unit[0];
8428 sCtx.cRowSep = SEP_Record[0];
8429 xRead = ascii_read_one_field;
8430 useOutputMode = 0;
drhbf70f1b2022-10-19 18:04:42 +00008431 }else if( cli_strcmp(z,"-csv")==0 ){
drhccb37812020-03-09 15:39:39 +00008432 sCtx.cColSep = ',';
8433 sCtx.cRowSep = '\n';
8434 xRead = csv_read_one_field;
8435 useOutputMode = 0;
8436 }else{
8437 utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z);
8438 showHelp(p->out, "import");
drhccb37812020-03-09 15:39:39 +00008439 goto meta_command_exit;
8440 }
8441 }
8442 if( zTable==0 ){
8443 utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n",
8444 zFile==0 ? "FILE" : "TABLE");
8445 showHelp(p->out, "import");
drh2ce15c32017-07-11 13:34:40 +00008446 goto meta_command_exit;
8447 }
drh2ce15c32017-07-11 13:34:40 +00008448 seenInterrupt = 0;
drh2ce15c32017-07-11 13:34:40 +00008449 open_db(p, 0);
drhccb37812020-03-09 15:39:39 +00008450 if( useOutputMode ){
8451 /* If neither the --csv or --ascii options are specified, then set
8452 ** the column and row separator characters from the output mode. */
8453 nSep = strlen30(p->colSeparator);
8454 if( nSep==0 ){
8455 raw_printf(stderr,
8456 "Error: non-null column separator required for import\n");
drhccb37812020-03-09 15:39:39 +00008457 goto meta_command_exit;
8458 }
8459 if( nSep>1 ){
larrybr2f5f6742022-05-09 12:29:47 +00008460 raw_printf(stderr,
drhccb37812020-03-09 15:39:39 +00008461 "Error: multi-character column separators not allowed"
8462 " for import\n");
drhccb37812020-03-09 15:39:39 +00008463 goto meta_command_exit;
8464 }
drh2ce15c32017-07-11 13:34:40 +00008465 nSep = strlen30(p->rowSeparator);
drhccb37812020-03-09 15:39:39 +00008466 if( nSep==0 ){
8467 raw_printf(stderr,
8468 "Error: non-null row separator required for import\n");
drhccb37812020-03-09 15:39:39 +00008469 goto meta_command_exit;
8470 }
drhbf70f1b2022-10-19 18:04:42 +00008471 if( nSep==2 && p->mode==MODE_Csv
8472 && cli_strcmp(p->rowSeparator,SEP_CrLf)==0
8473 ){
drhccb37812020-03-09 15:39:39 +00008474 /* When importing CSV (only), if the row separator is set to the
8475 ** default output row separator, change it to the default input
8476 ** row separator. This avoids having to maintain different input
8477 ** and output row separators. */
8478 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
8479 nSep = strlen30(p->rowSeparator);
8480 }
8481 if( nSep>1 ){
8482 raw_printf(stderr, "Error: multi-character row separators not allowed"
8483 " for import\n");
drhccb37812020-03-09 15:39:39 +00008484 goto meta_command_exit;
8485 }
8486 sCtx.cColSep = p->colSeparator[0];
8487 sCtx.cRowSep = p->rowSeparator[0];
drh2ce15c32017-07-11 13:34:40 +00008488 }
8489 sCtx.zFile = zFile;
8490 sCtx.nLine = 1;
8491 if( sCtx.zFile[0]=='|' ){
8492#ifdef SQLITE_OMIT_POPEN
8493 raw_printf(stderr, "Error: pipes are not supported in this OS\n");
drhccb37812020-03-09 15:39:39 +00008494 goto meta_command_exit;
drh2ce15c32017-07-11 13:34:40 +00008495#else
8496 sCtx.in = popen(sCtx.zFile+1, "r");
8497 sCtx.zFile = "<pipe>";
drh97767842020-05-29 19:39:35 +00008498 sCtx.xCloser = pclose;
drh2ce15c32017-07-11 13:34:40 +00008499#endif
8500 }else{
8501 sCtx.in = fopen(sCtx.zFile, "rb");
drh97767842020-05-29 19:39:35 +00008502 sCtx.xCloser = fclose;
drh2ce15c32017-07-11 13:34:40 +00008503 }
drh2ce15c32017-07-11 13:34:40 +00008504 if( sCtx.in==0 ){
8505 utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
drhccb37812020-03-09 15:39:39 +00008506 goto meta_command_exit;
drh2ce15c32017-07-11 13:34:40 +00008507 }
drhccb37812020-03-09 15:39:39 +00008508 if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
8509 char zSep[2];
8510 zSep[1] = 0;
8511 zSep[0] = sCtx.cColSep;
8512 utf8_printf(p->out, "Column separator ");
8513 output_c_string(p->out, zSep);
8514 utf8_printf(p->out, ", row separator ");
8515 zSep[0] = sCtx.cRowSep;
8516 output_c_string(p->out, zSep);
8517 utf8_printf(p->out, "\n");
8518 }
larrybr2f5f6742022-05-09 12:29:47 +00008519 sCtx.z = sqlite3_malloc64(120);
8520 if( sCtx.z==0 ){
8521 import_cleanup(&sCtx);
8522 shell_out_of_memory();
8523 }
larrybr53e11862022-03-06 23:41:21 +00008524 /* Below, resources must be freed before exit. */
drhccb37812020-03-09 15:39:39 +00008525 while( (nSkip--)>0 ){
8526 while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
drhccb37812020-03-09 15:39:39 +00008527 }
larrybr53e11862022-03-06 23:41:21 +00008528 if( zSchema!=0 ){
larrybr41f46702022-03-07 00:14:52 +00008529 zFullTabName = sqlite3_mprintf("\"%w\".\"%w\"", zSchema, zTable);
larrybr53e11862022-03-06 23:41:21 +00008530 }else{
larrybr41f46702022-03-07 00:14:52 +00008531 zFullTabName = sqlite3_mprintf("\"%w\"", zTable);
larrybr53e11862022-03-06 23:41:21 +00008532 }
larrybr41f46702022-03-07 00:14:52 +00008533 zSql = sqlite3_mprintf("SELECT * FROM %s", zFullTabName);
8534 if( zSql==0 || zFullTabName==0 ){
drh97767842020-05-29 19:39:35 +00008535 import_cleanup(&sCtx);
drh4b5345c2018-04-24 13:07:40 +00008536 shell_out_of_memory();
drh2ce15c32017-07-11 13:34:40 +00008537 }
8538 nByte = strlen30(zSql);
8539 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
8540 import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
8541 if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
larrybr58a53d62022-02-10 03:21:48 +00008542 sqlite3 *dbCols = 0;
larrybr33633862022-02-14 01:12:46 +00008543 char *zRenames = 0;
larrybr58a53d62022-02-10 03:21:48 +00008544 char *zColDefs;
drhe684ac62022-03-08 13:59:46 +00008545 zCreate = sqlite3_mprintf("CREATE TABLE %s", zFullTabName);
drh2ce15c32017-07-11 13:34:40 +00008546 while( xRead(&sCtx) ){
larrybra0337272022-02-11 13:40:25 +00008547 zAutoColumn(sCtx.z, &dbCols, 0);
drh2ce15c32017-07-11 13:34:40 +00008548 if( sCtx.cTerm!=sCtx.cColSep ) break;
larrybr4c5c6212022-02-11 01:21:09 +00008549 }
larrybr33633862022-02-14 01:12:46 +00008550 zColDefs = zAutoColumn(0, &dbCols, &zRenames);
8551 if( zRenames!=0 ){
larrybra0337272022-02-11 13:40:25 +00008552 utf8_printf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
larrybr33633862022-02-14 01:12:46 +00008553 "Columns renamed during .import %s due to duplicates:\n"
8554 "%s\n", sCtx.zFile, zRenames);
8555 sqlite3_free(zRenames);
larrybra0337272022-02-11 13:40:25 +00008556 }
larrybr58a53d62022-02-10 03:21:48 +00008557 assert(dbCols==0);
8558 if( zColDefs==0 ){
drh2ce15c32017-07-11 13:34:40 +00008559 utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
larrybr53e11862022-03-06 23:41:21 +00008560 import_fail:
8561 sqlite3_free(zCreate);
8562 sqlite3_free(zSql);
larrybr41f46702022-03-07 00:14:52 +00008563 sqlite3_free(zFullTabName);
larrybr53e11862022-03-06 23:41:21 +00008564 import_cleanup(&sCtx);
drhccb37812020-03-09 15:39:39 +00008565 rc = 1;
8566 goto meta_command_exit;
drh2ce15c32017-07-11 13:34:40 +00008567 }
larrybr58a53d62022-02-10 03:21:48 +00008568 zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs);
drhccb37812020-03-09 15:39:39 +00008569 if( eVerbose>=1 ){
8570 utf8_printf(p->out, "%s\n", zCreate);
8571 }
drh2ce15c32017-07-11 13:34:40 +00008572 rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
drh2ce15c32017-07-11 13:34:40 +00008573 if( rc ){
larrybrce0b5e42022-01-14 16:29:45 +00008574 utf8_printf(stderr, "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
larrybr53e11862022-03-06 23:41:21 +00008575 goto import_fail;
drh2ce15c32017-07-11 13:34:40 +00008576 }
larrybrce0b5e42022-01-14 16:29:45 +00008577 sqlite3_free(zCreate);
larrybr53e11862022-03-06 23:41:21 +00008578 zCreate = 0;
drh2ce15c32017-07-11 13:34:40 +00008579 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
8580 }
drh2ce15c32017-07-11 13:34:40 +00008581 if( rc ){
8582 if (pStmt) sqlite3_finalize(pStmt);
8583 utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
larrybr53e11862022-03-06 23:41:21 +00008584 goto import_fail;
drh2ce15c32017-07-11 13:34:40 +00008585 }
larrybr53e11862022-03-06 23:41:21 +00008586 sqlite3_free(zSql);
drh2ce15c32017-07-11 13:34:40 +00008587 nCol = sqlite3_column_count(pStmt);
8588 sqlite3_finalize(pStmt);
8589 pStmt = 0;
8590 if( nCol==0 ) return 0; /* no columns, no error */
8591 zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
8592 if( zSql==0 ){
drh97767842020-05-29 19:39:35 +00008593 import_cleanup(&sCtx);
drh4b5345c2018-04-24 13:07:40 +00008594 shell_out_of_memory();
drh2ce15c32017-07-11 13:34:40 +00008595 }
larrybr41f46702022-03-07 00:14:52 +00008596 sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zFullTabName);
drh2ce15c32017-07-11 13:34:40 +00008597 j = strlen30(zSql);
8598 for(i=1; i<nCol; i++){
8599 zSql[j++] = ',';
8600 zSql[j++] = '?';
8601 }
8602 zSql[j++] = ')';
8603 zSql[j] = 0;
drhccb37812020-03-09 15:39:39 +00008604 if( eVerbose>=2 ){
8605 utf8_printf(p->out, "Insert using: %s\n", zSql);
8606 }
drh2ce15c32017-07-11 13:34:40 +00008607 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
drh2ce15c32017-07-11 13:34:40 +00008608 if( rc ){
8609 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
8610 if (pStmt) sqlite3_finalize(pStmt);
larrybr53e11862022-03-06 23:41:21 +00008611 goto import_fail;
drh2ce15c32017-07-11 13:34:40 +00008612 }
larrybr53e11862022-03-06 23:41:21 +00008613 sqlite3_free(zSql);
larrybr41f46702022-03-07 00:14:52 +00008614 sqlite3_free(zFullTabName);
drh2ce15c32017-07-11 13:34:40 +00008615 needCommit = sqlite3_get_autocommit(p->db);
8616 if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
8617 do{
8618 int startLine = sCtx.nLine;
8619 for(i=0; i<nCol; i++){
8620 char *z = xRead(&sCtx);
8621 /*
8622 ** Did we reach end-of-file before finding any columns?
8623 ** If so, stop instead of NULL filling the remaining columns.
8624 */
8625 if( z==0 && i==0 ) break;
8626 /*
8627 ** Did we reach end-of-file OR end-of-line before finding any
8628 ** columns in ASCII mode? If so, stop instead of NULL filling
8629 ** the remaining columns.
8630 */
8631 if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
8632 sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
8633 if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
8634 utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
8635 "filling the rest with NULL\n",
8636 sCtx.zFile, startLine, nCol, i+1);
8637 i += 2;
8638 while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
8639 }
8640 }
8641 if( sCtx.cTerm==sCtx.cColSep ){
8642 do{
8643 xRead(&sCtx);
8644 i++;
8645 }while( sCtx.cTerm==sCtx.cColSep );
8646 utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
8647 "extras ignored\n",
8648 sCtx.zFile, startLine, nCol, i);
8649 }
8650 if( i>=nCol ){
8651 sqlite3_step(pStmt);
8652 rc = sqlite3_reset(pStmt);
8653 if( rc!=SQLITE_OK ){
8654 utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
8655 startLine, sqlite3_errmsg(p->db));
drhccb37812020-03-09 15:39:39 +00008656 sCtx.nErr++;
8657 }else{
8658 sCtx.nRow++;
drh2ce15c32017-07-11 13:34:40 +00008659 }
8660 }
8661 }while( sCtx.cTerm!=EOF );
8662
drh97767842020-05-29 19:39:35 +00008663 import_cleanup(&sCtx);
drh2ce15c32017-07-11 13:34:40 +00008664 sqlite3_finalize(pStmt);
8665 if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
drhccb37812020-03-09 15:39:39 +00008666 if( eVerbose>0 ){
8667 utf8_printf(p->out,
8668 "Added %d rows with %d errors using %d lines of input\n",
8669 sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
8670 }
drh2ce15c32017-07-11 13:34:40 +00008671 }else
stephan4413ec72022-07-12 15:53:02 +00008672#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00008673
8674#ifndef SQLITE_UNTESTABLE
drhbf70f1b2022-10-19 18:04:42 +00008675 if( c=='i' && cli_strncmp(azArg[0], "imposter", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008676 char *zSql;
8677 char *zCollist = 0;
8678 sqlite3_stmt *pStmt;
8679 int tnum = 0;
drh491c5be2019-10-18 15:58:50 +00008680 int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */
8681 int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
drh2ce15c32017-07-11 13:34:40 +00008682 int i;
drh48d219a2018-04-23 18:38:48 +00008683 if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
8684 utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n"
8685 " .imposter off\n");
drh491c5be2019-10-18 15:58:50 +00008686 /* Also allowed, but not documented:
8687 **
8688 ** .imposter TABLE IMPOSTER
8689 **
8690 ** where TABLE is a WITHOUT ROWID table. In that case, the
8691 ** imposter is another WITHOUT ROWID table with the columns in
8692 ** storage order. */
drh2ce15c32017-07-11 13:34:40 +00008693 rc = 1;
8694 goto meta_command_exit;
8695 }
8696 open_db(p, 0);
drh48d219a2018-04-23 18:38:48 +00008697 if( nArg==2 ){
8698 sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1);
8699 goto meta_command_exit;
8700 }
drh491c5be2019-10-18 15:58:50 +00008701 zSql = sqlite3_mprintf(
drh067b92b2020-06-19 15:24:12 +00008702 "SELECT rootpage, 0 FROM sqlite_schema"
drh491c5be2019-10-18 15:58:50 +00008703 " WHERE name='%q' AND type='index'"
8704 "UNION ALL "
drh067b92b2020-06-19 15:24:12 +00008705 "SELECT rootpage, 1 FROM sqlite_schema"
drh491c5be2019-10-18 15:58:50 +00008706 " WHERE name='%q' AND type='table'"
8707 " AND sql LIKE '%%without%%rowid%%'",
8708 azArg[1], azArg[1]
8709 );
drh2ce15c32017-07-11 13:34:40 +00008710 sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
8711 sqlite3_free(zSql);
8712 if( sqlite3_step(pStmt)==SQLITE_ROW ){
8713 tnum = sqlite3_column_int(pStmt, 0);
drh491c5be2019-10-18 15:58:50 +00008714 isWO = sqlite3_column_int(pStmt, 1);
drh2ce15c32017-07-11 13:34:40 +00008715 }
8716 sqlite3_finalize(pStmt);
drh2ce15c32017-07-11 13:34:40 +00008717 zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
8718 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
8719 sqlite3_free(zSql);
8720 i = 0;
drhe85e1da2021-10-01 21:01:07 +00008721 while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
drh2ce15c32017-07-11 13:34:40 +00008722 char zLabel[20];
8723 const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
8724 i++;
8725 if( zCol==0 ){
8726 if( sqlite3_column_int(pStmt,1)==-1 ){
8727 zCol = "_ROWID_";
8728 }else{
8729 sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i);
8730 zCol = zLabel;
8731 }
8732 }
drh491c5be2019-10-18 15:58:50 +00008733 if( isWO && lenPK==0 && sqlite3_column_int(pStmt,5)==0 && zCollist ){
8734 lenPK = (int)strlen(zCollist);
8735 }
drh2ce15c32017-07-11 13:34:40 +00008736 if( zCollist==0 ){
8737 zCollist = sqlite3_mprintf("\"%w\"", zCol);
8738 }else{
8739 zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
8740 }
8741 }
8742 sqlite3_finalize(pStmt);
drh491c5be2019-10-18 15:58:50 +00008743 if( i==0 || tnum==0 ){
8744 utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
8745 rc = 1;
8746 sqlite3_free(zCollist);
8747 goto meta_command_exit;
8748 }
8749 if( lenPK==0 ) lenPK = 100000;
drh2ce15c32017-07-11 13:34:40 +00008750 zSql = sqlite3_mprintf(
drh491c5be2019-10-18 15:58:50 +00008751 "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))WITHOUT ROWID",
8752 azArg[2], zCollist, lenPK, zCollist);
drh2ce15c32017-07-11 13:34:40 +00008753 sqlite3_free(zCollist);
8754 rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
8755 if( rc==SQLITE_OK ){
8756 rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
8757 sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
8758 if( rc ){
8759 utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
8760 }else{
8761 utf8_printf(stdout, "%s;\n", zSql);
8762 raw_printf(stdout,
drh491c5be2019-10-18 15:58:50 +00008763 "WARNING: writing to an imposter table will corrupt the \"%s\" %s!\n",
8764 azArg[1], isWO ? "table" : "index"
drh2ce15c32017-07-11 13:34:40 +00008765 );
8766 }
8767 }else{
8768 raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
8769 rc = 1;
8770 }
8771 sqlite3_free(zSql);
8772 }else
8773#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
8774
8775#ifdef SQLITE_ENABLE_IOTRACE
drhbf70f1b2022-10-19 18:04:42 +00008776 if( c=='i' && cli_strncmp(azArg[0], "iotrace", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008777 SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
8778 if( iotrace && iotrace!=stdout ) fclose(iotrace);
8779 iotrace = 0;
8780 if( nArg<2 ){
8781 sqlite3IoTrace = 0;
drhbf70f1b2022-10-19 18:04:42 +00008782 }else if( cli_strcmp(azArg[1], "-")==0 ){
drh2ce15c32017-07-11 13:34:40 +00008783 sqlite3IoTrace = iotracePrintf;
8784 iotrace = stdout;
8785 }else{
8786 iotrace = fopen(azArg[1], "w");
8787 if( iotrace==0 ){
8788 utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
8789 sqlite3IoTrace = 0;
8790 rc = 1;
8791 }else{
8792 sqlite3IoTrace = iotracePrintf;
8793 }
8794 }
8795 }else
8796#endif
8797
drhbf70f1b2022-10-19 18:04:42 +00008798 if( c=='l' && n>=5 && cli_strncmp(azArg[0], "limits", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008799 static const struct {
8800 const char *zLimitName; /* Name of a limit */
8801 int limitCode; /* Integer code for that limit */
8802 } aLimit[] = {
8803 { "length", SQLITE_LIMIT_LENGTH },
8804 { "sql_length", SQLITE_LIMIT_SQL_LENGTH },
8805 { "column", SQLITE_LIMIT_COLUMN },
8806 { "expr_depth", SQLITE_LIMIT_EXPR_DEPTH },
8807 { "compound_select", SQLITE_LIMIT_COMPOUND_SELECT },
8808 { "vdbe_op", SQLITE_LIMIT_VDBE_OP },
8809 { "function_arg", SQLITE_LIMIT_FUNCTION_ARG },
8810 { "attached", SQLITE_LIMIT_ATTACHED },
8811 { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH },
8812 { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER },
8813 { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH },
8814 { "worker_threads", SQLITE_LIMIT_WORKER_THREADS },
8815 };
8816 int i, n2;
8817 open_db(p, 0);
8818 if( nArg==1 ){
8819 for(i=0; i<ArraySize(aLimit); i++){
8820 printf("%20s %d\n", aLimit[i].zLimitName,
8821 sqlite3_limit(p->db, aLimit[i].limitCode, -1));
8822 }
8823 }else if( nArg>3 ){
8824 raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
8825 rc = 1;
8826 goto meta_command_exit;
8827 }else{
8828 int iLimit = -1;
8829 n2 = strlen30(azArg[1]);
8830 for(i=0; i<ArraySize(aLimit); i++){
8831 if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
8832 if( iLimit<0 ){
8833 iLimit = i;
8834 }else{
8835 utf8_printf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
8836 rc = 1;
8837 goto meta_command_exit;
8838 }
8839 }
8840 }
8841 if( iLimit<0 ){
8842 utf8_printf(stderr, "unknown limit: \"%s\"\n"
8843 "enter \".limits\" with no arguments for a list.\n",
8844 azArg[1]);
8845 rc = 1;
8846 goto meta_command_exit;
8847 }
8848 if( nArg==3 ){
8849 sqlite3_limit(p->db, aLimit[iLimit].limitCode,
8850 (int)integerValue(azArg[2]));
8851 }
8852 printf("%20s %d\n", aLimit[iLimit].zLimitName,
8853 sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
8854 }
8855 }else
8856
drhbf70f1b2022-10-19 18:04:42 +00008857 if( c=='l' && n>2 && cli_strncmp(azArg[0], "lint", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008858 open_db(p, 0);
8859 lintDotCommand(p, azArg, nArg);
8860 }else
8861
stephan4413ec72022-07-12 15:53:02 +00008862#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_FIDDLE)
drhbf70f1b2022-10-19 18:04:42 +00008863 if( c=='l' && cli_strncmp(azArg[0], "load", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008864 const char *zFile, *zProc;
8865 char *zErrMsg = 0;
drhb97e2ad2021-08-26 18:31:39 +00008866 failIfSafeMode(p, "cannot run .load in safe mode");
drh2ce15c32017-07-11 13:34:40 +00008867 if( nArg<2 ){
8868 raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
8869 rc = 1;
8870 goto meta_command_exit;
8871 }
8872 zFile = azArg[1];
8873 zProc = nArg>=3 ? azArg[2] : 0;
8874 open_db(p, 0);
8875 rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
8876 if( rc!=SQLITE_OK ){
8877 utf8_printf(stderr, "Error: %s\n", zErrMsg);
8878 sqlite3_free(zErrMsg);
8879 rc = 1;
8880 }
8881 }else
8882#endif
8883
stephan4413ec72022-07-12 15:53:02 +00008884#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00008885 if( c=='l' && cli_strncmp(azArg[0], "log", n)==0 ){
drhb97e2ad2021-08-26 18:31:39 +00008886 failIfSafeMode(p, "cannot run .log in safe mode");
drh2ce15c32017-07-11 13:34:40 +00008887 if( nArg!=2 ){
8888 raw_printf(stderr, "Usage: .log FILENAME\n");
8889 rc = 1;
8890 }else{
8891 const char *zFile = azArg[1];
8892 output_file_close(p->pLog);
drha92a01a2018-01-10 22:15:37 +00008893 p->pLog = output_file_open(zFile, 0);
drh2ce15c32017-07-11 13:34:40 +00008894 }
8895 }else
stephan618a3752022-05-19 10:24:50 +00008896#endif
drh2ce15c32017-07-11 13:34:40 +00008897
drhbf70f1b2022-10-19 18:04:42 +00008898 if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
drhe40f2862022-01-31 14:14:29 +00008899 const char *zMode = 0;
8900 const char *zTabname = 0;
8901 int i, n2;
larrybrcc4d55c2022-02-01 02:50:45 +00008902 ColModeOpts cmOpts = ColModeOpts_default;
drhe40f2862022-01-31 14:14:29 +00008903 for(i=1; i<nArg; i++){
8904 const char *z = azArg[i];
8905 if( optionMatch(z,"wrap") && i+1<nArg ){
larrybrcc4d55c2022-02-01 02:50:45 +00008906 cmOpts.iWrap = integerValue(azArg[++i]);
drhca1776b2022-02-01 12:28:17 +00008907 }else if( optionMatch(z,"ww") ){
8908 cmOpts.bWordWrap = 1;
larrybrcc4d55c2022-02-01 02:50:45 +00008909 }else if( optionMatch(z,"wordwrap") && i+1<nArg ){
8910 cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
drhe40f2862022-01-31 14:14:29 +00008911 }else if( optionMatch(z,"quote") ){
larrybrcc4d55c2022-02-01 02:50:45 +00008912 cmOpts.bQuote = 1;
drhe40f2862022-01-31 14:14:29 +00008913 }else if( optionMatch(z,"noquote") ){
larrybrcc4d55c2022-02-01 02:50:45 +00008914 cmOpts.bQuote = 0;
drhe40f2862022-01-31 14:14:29 +00008915 }else if( zMode==0 ){
8916 zMode = z;
drh1f41a8c2022-10-24 11:10:40 +00008917 /* Apply defaults for qbox pseudo-mode. If that
larrybrcc4d55c2022-02-01 02:50:45 +00008918 * overwrites already-set values, user was informed of this.
8919 */
drhbf70f1b2022-10-19 18:04:42 +00008920 if( cli_strcmp(z, "qbox")==0 ){
larrybrcc4d55c2022-02-01 02:50:45 +00008921 ColModeOpts cmo = ColModeOpts_default_qbox;
8922 zMode = "box";
8923 cmOpts = cmo;
larrybrcc4d55c2022-02-01 02:50:45 +00008924 }
drhe40f2862022-01-31 14:14:29 +00008925 }else if( zTabname==0 ){
8926 zTabname = z;
8927 }else if( z[0]=='-' ){
8928 utf8_printf(stderr, "unknown option: %s\n", z);
8929 utf8_printf(stderr, "options:\n"
8930 " --noquote\n"
8931 " --quote\n"
larrybrcc4d55c2022-02-01 02:50:45 +00008932 " --wordwrap on/off\n"
drhca1776b2022-02-01 12:28:17 +00008933 " --wrap N\n"
8934 " --ww\n");
drhe40f2862022-01-31 14:14:29 +00008935 rc = 1;
8936 goto meta_command_exit;
8937 }else{
8938 utf8_printf(stderr, "extra argument: \"%s\"\n", z);
8939 rc = 1;
8940 goto meta_command_exit;
8941 }
8942 }
8943 if( zMode==0 ){
8944 if( p->mode==MODE_Column
8945 || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
8946 ){
larrybrcc4d55c2022-02-01 02:50:45 +00008947 raw_printf
8948 (p->out,
8949 "current output mode: %s --wrap %d --wordwrap %s --%squote\n",
8950 modeDescr[p->mode], p->cmOpts.iWrap,
8951 p->cmOpts.bWordWrap ? "on" : "off",
8952 p->cmOpts.bQuote ? "" : "no");
drhe40f2862022-01-31 14:14:29 +00008953 }else{
8954 raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
8955 }
drhe40f2862022-01-31 14:14:29 +00008956 zMode = modeDescr[p->mode];
8957 }
8958 n2 = strlen30(zMode);
drhbf70f1b2022-10-19 18:04:42 +00008959 if( cli_strncmp(zMode,"lines",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008960 p->mode = MODE_Line;
8961 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +00008962 }else if( cli_strncmp(zMode,"columns",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008963 p->mode = MODE_Column;
drhc0605082020-06-05 00:54:27 +00008964 if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
8965 p->showHeader = 1;
8966 }
drh2ce15c32017-07-11 13:34:40 +00008967 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
larrybrcc4d55c2022-02-01 02:50:45 +00008968 p->cmOpts = cmOpts;
drhbf70f1b2022-10-19 18:04:42 +00008969 }else if( cli_strncmp(zMode,"list",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008970 p->mode = MODE_List;
8971 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
8972 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +00008973 }else if( cli_strncmp(zMode,"html",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008974 p->mode = MODE_Html;
drhbf70f1b2022-10-19 18:04:42 +00008975 }else if( cli_strncmp(zMode,"tcl",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008976 p->mode = MODE_Tcl;
8977 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
8978 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +00008979 }else if( cli_strncmp(zMode,"csv",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008980 p->mode = MODE_Csv;
8981 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
8982 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
drhbf70f1b2022-10-19 18:04:42 +00008983 }else if( cli_strncmp(zMode,"tabs",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008984 p->mode = MODE_List;
8985 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
drhbf70f1b2022-10-19 18:04:42 +00008986 }else if( cli_strncmp(zMode,"insert",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008987 p->mode = MODE_Insert;
drhe40f2862022-01-31 14:14:29 +00008988 set_table_name(p, zTabname ? zTabname : "table");
drhbf70f1b2022-10-19 18:04:42 +00008989 }else if( cli_strncmp(zMode,"quote",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008990 p->mode = MODE_Quote;
drhc6835732020-05-28 20:37:17 +00008991 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
8992 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +00008993 }else if( cli_strncmp(zMode,"ascii",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008994 p->mode = MODE_Ascii;
8995 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
8996 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
drhbf70f1b2022-10-19 18:04:42 +00008997 }else if( cli_strncmp(zMode,"markdown",n2)==0 ){
drh30c54a02020-05-28 23:49:50 +00008998 p->mode = MODE_Markdown;
larrybrcc4d55c2022-02-01 02:50:45 +00008999 p->cmOpts = cmOpts;
drhbf70f1b2022-10-19 18:04:42 +00009000 }else if( cli_strncmp(zMode,"table",n2)==0 ){
drh30c54a02020-05-28 23:49:50 +00009001 p->mode = MODE_Table;
larrybrcc4d55c2022-02-01 02:50:45 +00009002 p->cmOpts = cmOpts;
drhbf70f1b2022-10-19 18:04:42 +00009003 }else if( cli_strncmp(zMode,"box",n2)==0 ){
drh0908e382020-06-04 18:05:39 +00009004 p->mode = MODE_Box;
larrybrcc4d55c2022-02-01 02:50:45 +00009005 p->cmOpts = cmOpts;
drhbf70f1b2022-10-19 18:04:42 +00009006 }else if( cli_strncmp(zMode,"count",n2)==0 ){
drh5d88be82021-12-09 16:17:43 +00009007 p->mode = MODE_Count;
drhbf70f1b2022-10-19 18:04:42 +00009008 }else if( cli_strncmp(zMode,"off",n2)==0 ){
drh5d88be82021-12-09 16:17:43 +00009009 p->mode = MODE_Off;
drhbf70f1b2022-10-19 18:04:42 +00009010 }else if( cli_strncmp(zMode,"json",n2)==0 ){
drh30c54a02020-05-28 23:49:50 +00009011 p->mode = MODE_Json;
drh2ce15c32017-07-11 13:34:40 +00009012 }else{
9013 raw_printf(stderr, "Error: mode should be one of: "
drh0908e382020-06-04 18:05:39 +00009014 "ascii box column csv html insert json line list markdown "
drhca1776b2022-02-01 12:28:17 +00009015 "qbox quote table tabs tcl\n");
drh2ce15c32017-07-11 13:34:40 +00009016 rc = 1;
9017 }
9018 p->cMode = p->mode;
9019 }else
9020
stephan4413ec72022-07-12 15:53:02 +00009021#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00009022 if( c=='n' && cli_strcmp(azArg[0], "nonce")==0 ){
drhb97e2ad2021-08-26 18:31:39 +00009023 if( nArg!=2 ){
9024 raw_printf(stderr, "Usage: .nonce NONCE\n");
9025 rc = 1;
drhbf70f1b2022-10-19 18:04:42 +00009026 }else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){
drhfe463172021-12-16 17:57:21 +00009027 raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n",
9028 p->lineno, azArg[1]);
drhb97e2ad2021-08-26 18:31:39 +00009029 exit(1);
drhe85e1da2021-10-01 21:01:07 +00009030 }else{
9031 p->bSafeMode = 0;
9032 return 0; /* Return immediately to bypass the safe mode reset
9033 ** at the end of this procedure */
drhb97e2ad2021-08-26 18:31:39 +00009034 }
drhb97e2ad2021-08-26 18:31:39 +00009035 }else
stephan4413ec72022-07-12 15:53:02 +00009036#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drhb97e2ad2021-08-26 18:31:39 +00009037
drhbf70f1b2022-10-19 18:04:42 +00009038 if( c=='n' && cli_strncmp(azArg[0], "nullvalue", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009039 if( nArg==2 ){
9040 sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
9041 "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
9042 }else{
9043 raw_printf(stderr, "Usage: .nullvalue STRING\n");
9044 rc = 1;
9045 }
9046 }else
9047
drhbf70f1b2022-10-19 18:04:42 +00009048 if( c=='o' && cli_strncmp(azArg[0], "open", n)==0 && n>=2 ){
drh61fd4b92021-12-16 14:59:25 +00009049 const char *zFN = 0; /* Pointer to constant filename */
drhf30bbce2020-12-02 18:27:48 +00009050 char *zNewFilename = 0; /* Name of the database file to open */
9051 int iName = 1; /* Index in azArg[] of the filename */
9052 int newFlag = 0; /* True to delete file before opening */
dan1872c5b2021-12-02 14:16:30 +00009053 int openMode = SHELL_OPEN_UNSPEC;
9054
drh2ce15c32017-07-11 13:34:40 +00009055 /* Check for command-line arguments */
drhf30bbce2020-12-02 18:27:48 +00009056 for(iName=1; iName<nArg; iName++){
drh2ce15c32017-07-11 13:34:40 +00009057 const char *z = azArg[iName];
stephan4413ec72022-07-12 15:53:02 +00009058#ifndef SQLITE_SHELL_FIDDLE
drh2ce15c32017-07-11 13:34:40 +00009059 if( optionMatch(z,"new") ){
9060 newFlag = 1;
drh3baed312018-03-08 18:14:41 +00009061#ifdef SQLITE_HAVE_ZLIB
drh1fa6d9f2018-01-06 21:46:01 +00009062 }else if( optionMatch(z, "zip") ){
dan1872c5b2021-12-02 14:16:30 +00009063 openMode = SHELL_OPEN_ZIPFILE;
drh1fa6d9f2018-01-06 21:46:01 +00009064#endif
9065 }else if( optionMatch(z, "append") ){
dan1872c5b2021-12-02 14:16:30 +00009066 openMode = SHELL_OPEN_APPENDVFS;
drhee269a62018-02-14 23:27:43 +00009067 }else if( optionMatch(z, "readonly") ){
dan1872c5b2021-12-02 14:16:30 +00009068 openMode = SHELL_OPEN_READONLY;
drh0933aad2019-11-18 17:46:38 +00009069 }else if( optionMatch(z, "nofollow") ){
9070 p->openFlags |= SQLITE_OPEN_NOFOLLOW;
drh8d889af2021-05-08 17:18:23 +00009071#ifndef SQLITE_OMIT_DESERIALIZE
drh60f34ae2018-10-30 13:19:49 +00009072 }else if( optionMatch(z, "deserialize") ){
dan1872c5b2021-12-02 14:16:30 +00009073 openMode = SHELL_OPEN_DESERIALIZE;
drh33746482018-12-13 15:06:26 +00009074 }else if( optionMatch(z, "hexdb") ){
dan1872c5b2021-12-02 14:16:30 +00009075 openMode = SHELL_OPEN_HEXDB;
drh6ca64482019-01-22 16:06:20 +00009076 }else if( optionMatch(z, "maxsize") && iName+1<nArg ){
9077 p->szMax = integerValue(azArg[++iName]);
drh8d889af2021-05-08 17:18:23 +00009078#endif /* SQLITE_OMIT_DESERIALIZE */
stephande1e02e2022-05-24 19:01:21 +00009079 }else
stephan4413ec72022-07-12 15:53:02 +00009080#endif /* !SQLITE_SHELL_FIDDLE */
stephande1e02e2022-05-24 19:01:21 +00009081 if( z[0]=='-' ){
drh2ce15c32017-07-11 13:34:40 +00009082 utf8_printf(stderr, "unknown option: %s\n", z);
9083 rc = 1;
9084 goto meta_command_exit;
drh61fd4b92021-12-16 14:59:25 +00009085 }else if( zFN ){
drhf30bbce2020-12-02 18:27:48 +00009086 utf8_printf(stderr, "extra argument: \"%s\"\n", z);
9087 rc = 1;
9088 goto meta_command_exit;
9089 }else{
drh61fd4b92021-12-16 14:59:25 +00009090 zFN = z;
drh2ce15c32017-07-11 13:34:40 +00009091 }
9092 }
dan1872c5b2021-12-02 14:16:30 +00009093
9094 /* Close the existing database */
9095 session_close_all(p, -1);
9096 close_db(p->db);
9097 p->db = 0;
9098 p->pAuxDb->zDbFilename = 0;
9099 sqlite3_free(p->pAuxDb->zFreeOnClose);
9100 p->pAuxDb->zFreeOnClose = 0;
9101 p->openMode = openMode;
9102 p->openFlags = 0;
9103 p->szMax = 0;
9104
drh2ce15c32017-07-11 13:34:40 +00009105 /* If a filename is specified, try to open it first */
drh61fd4b92021-12-16 14:59:25 +00009106 if( zFN || p->openMode==SHELL_OPEN_HEXDB ){
drhc320e062021-12-24 19:44:11 +00009107 if( newFlag && zFN && !p->bSafeMode ) shellDeleteFile(zFN);
stephan4413ec72022-07-12 15:53:02 +00009108#ifndef SQLITE_SHELL_FIDDLE
drhb97e2ad2021-08-26 18:31:39 +00009109 if( p->bSafeMode
9110 && p->openMode!=SHELL_OPEN_HEXDB
drhc320e062021-12-24 19:44:11 +00009111 && zFN
drhbf70f1b2022-10-19 18:04:42 +00009112 && cli_strcmp(zFN,":memory:")!=0
drhb97e2ad2021-08-26 18:31:39 +00009113 ){
9114 failIfSafeMode(p, "cannot open disk-based database files in safe mode");
9115 }
stephande1e02e2022-05-24 19:01:21 +00009116#else
9117 /* WASM mode has its own sandboxed pseudo-filesystem. */
9118#endif
drh61fd4b92021-12-16 14:59:25 +00009119 if( zFN ){
9120 zNewFilename = sqlite3_mprintf("%s", zFN);
9121 shell_check_oom(zNewFilename);
9122 }else{
9123 zNewFilename = 0;
9124 }
drh37407122021-07-23 18:43:58 +00009125 p->pAuxDb->zDbFilename = zNewFilename;
drhbe4ccb22018-05-17 20:04:24 +00009126 open_db(p, OPEN_DB_KEEPALIVE);
drh2ce15c32017-07-11 13:34:40 +00009127 if( p->db==0 ){
9128 utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename);
9129 sqlite3_free(zNewFilename);
9130 }else{
drh37407122021-07-23 18:43:58 +00009131 p->pAuxDb->zFreeOnClose = zNewFilename;
drh2ce15c32017-07-11 13:34:40 +00009132 }
9133 }
9134 if( p->db==0 ){
9135 /* As a fall-back open a TEMP database */
drh37407122021-07-23 18:43:58 +00009136 p->pAuxDb->zDbFilename = 0;
drh2ce15c32017-07-11 13:34:40 +00009137 open_db(p, 0);
9138 }
9139 }else
9140
stephan4413ec72022-07-12 15:53:02 +00009141#ifndef SQLITE_SHELL_FIDDLE
drh13c20932018-01-10 21:41:55 +00009142 if( (c=='o'
drhbf70f1b2022-10-19 18:04:42 +00009143 && (cli_strncmp(azArg[0], "output", n)==0
9144 || cli_strncmp(azArg[0], "once", n)==0))
9145 || (c=='e' && n==5 && cli_strcmp(azArg[0],"excel")==0)
drh2ce15c32017-07-11 13:34:40 +00009146 ){
drh4b0229a2021-02-17 13:19:22 +00009147 char *zFile = 0;
drha92a01a2018-01-10 22:15:37 +00009148 int bTxtMode = 0;
drh7a431002020-04-18 14:12:00 +00009149 int i;
9150 int eMode = 0;
drh8ad3c432022-03-23 10:04:52 +00009151 int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
9152 unsigned char zBOM[4]; /* Byte-order mark to using if --bom is present */
drh7a431002020-04-18 14:12:00 +00009153
drh8ad3c432022-03-23 10:04:52 +00009154 zBOM[0] = 0;
drhb97e2ad2021-08-26 18:31:39 +00009155 failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
drh7a431002020-04-18 14:12:00 +00009156 if( c=='e' ){
9157 eMode = 'x';
9158 bOnce = 2;
drhbf70f1b2022-10-19 18:04:42 +00009159 }else if( cli_strncmp(azArg[0],"once",n)==0 ){
drh7a431002020-04-18 14:12:00 +00009160 bOnce = 1;
drh13c20932018-01-10 21:41:55 +00009161 }
drh7a431002020-04-18 14:12:00 +00009162 for(i=1; i<nArg; i++){
9163 char *z = azArg[i];
9164 if( z[0]=='-' ){
9165 if( z[1]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +00009166 if( cli_strcmp(z,"-bom")==0 ){
drh8ad3c432022-03-23 10:04:52 +00009167 zBOM[0] = 0xef;
9168 zBOM[1] = 0xbb;
9169 zBOM[2] = 0xbf;
9170 zBOM[3] = 0;
drhbf70f1b2022-10-19 18:04:42 +00009171 }else if( c!='e' && cli_strcmp(z,"-x")==0 ){
drh7a431002020-04-18 14:12:00 +00009172 eMode = 'x'; /* spreadsheet */
drhbf70f1b2022-10-19 18:04:42 +00009173 }else if( c!='e' && cli_strcmp(z,"-e")==0 ){
drh7a431002020-04-18 14:12:00 +00009174 eMode = 'e'; /* text editor */
9175 }else{
9176 utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n",
9177 azArg[i]);
9178 showHelp(p->out, azArg[0]);
9179 rc = 1;
9180 goto meta_command_exit;
9181 }
drh4b0229a2021-02-17 13:19:22 +00009182 }else if( zFile==0 && eMode!='e' && eMode!='x' ){
9183 zFile = sqlite3_mprintf("%s", z);
drhe3e25652021-12-16 13:29:28 +00009184 if( zFile && zFile[0]=='|' ){
drh4b0229a2021-02-17 13:19:22 +00009185 while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]);
9186 break;
9187 }
drh7a431002020-04-18 14:12:00 +00009188 }else{
9189 utf8_printf(p->out,"ERROR: extra parameter: \"%s\". Usage:\n",
9190 azArg[i]);
9191 showHelp(p->out, azArg[0]);
drh2ce15c32017-07-11 13:34:40 +00009192 rc = 1;
drh4b0229a2021-02-17 13:19:22 +00009193 sqlite3_free(zFile);
drh2ce15c32017-07-11 13:34:40 +00009194 goto meta_command_exit;
9195 }
drh7a431002020-04-18 14:12:00 +00009196 }
drhe3e25652021-12-16 13:29:28 +00009197 if( zFile==0 ){
9198 zFile = sqlite3_mprintf("stdout");
9199 }
drh7a431002020-04-18 14:12:00 +00009200 if( bOnce ){
drh2ce15c32017-07-11 13:34:40 +00009201 p->outCount = 2;
9202 }else{
9203 p->outCount = 0;
9204 }
9205 output_reset(p);
drh04a28c32018-01-31 01:38:44 +00009206#ifndef SQLITE_NOHAVE_SYSTEM
drh7a431002020-04-18 14:12:00 +00009207 if( eMode=='e' || eMode=='x' ){
drh3c484e82018-01-10 22:27:21 +00009208 p->doXdgOpen = 1;
9209 outputModePush(p);
drh7a431002020-04-18 14:12:00 +00009210 if( eMode=='x' ){
9211 /* spreadsheet mode. Output as CSV. */
drh13c20932018-01-10 21:41:55 +00009212 newTempFile(p, "csv");
drh7a431002020-04-18 14:12:00 +00009213 ShellClearFlag(p, SHFLG_Echo);
drh13c20932018-01-10 21:41:55 +00009214 p->mode = MODE_Csv;
9215 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
9216 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
9217 }else{
drh7a431002020-04-18 14:12:00 +00009218 /* text editor mode */
drh13c20932018-01-10 21:41:55 +00009219 newTempFile(p, "txt");
drha92a01a2018-01-10 22:15:37 +00009220 bTxtMode = 1;
drh13c20932018-01-10 21:41:55 +00009221 }
drh4b0229a2021-02-17 13:19:22 +00009222 sqlite3_free(zFile);
9223 zFile = sqlite3_mprintf("%s", p->zTempFile);
drh13c20932018-01-10 21:41:55 +00009224 }
drh04a28c32018-01-31 01:38:44 +00009225#endif /* SQLITE_NOHAVE_SYSTEM */
drhe3e25652021-12-16 13:29:28 +00009226 shell_check_oom(zFile);
drh2ce15c32017-07-11 13:34:40 +00009227 if( zFile[0]=='|' ){
9228#ifdef SQLITE_OMIT_POPEN
9229 raw_printf(stderr, "Error: pipes are not supported in this OS\n");
9230 rc = 1;
9231 p->out = stdout;
9232#else
9233 p->out = popen(zFile + 1, "w");
9234 if( p->out==0 ){
9235 utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
9236 p->out = stdout;
9237 rc = 1;
9238 }else{
drh8ad3c432022-03-23 10:04:52 +00009239 if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
drh2ce15c32017-07-11 13:34:40 +00009240 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
9241 }
9242#endif
9243 }else{
drha92a01a2018-01-10 22:15:37 +00009244 p->out = output_file_open(zFile, bTxtMode);
drh2ce15c32017-07-11 13:34:40 +00009245 if( p->out==0 ){
drhbf70f1b2022-10-19 18:04:42 +00009246 if( cli_strcmp(zFile,"off")!=0 ){
drh2ce15c32017-07-11 13:34:40 +00009247 utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
9248 }
9249 p->out = stdout;
9250 rc = 1;
9251 } else {
drh8ad3c432022-03-23 10:04:52 +00009252 if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
drh2ce15c32017-07-11 13:34:40 +00009253 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
9254 }
9255 }
drh4b0229a2021-02-17 13:19:22 +00009256 sqlite3_free(zFile);
drh2ce15c32017-07-11 13:34:40 +00009257 }else
stephan4413ec72022-07-12 15:53:02 +00009258#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00009259
drhbf70f1b2022-10-19 18:04:42 +00009260 if( c=='p' && n>=3 && cli_strncmp(azArg[0], "parameter", n)==0 ){
drh9cb02642019-02-28 20:10:52 +00009261 open_db(p,0);
9262 if( nArg<=1 ) goto parameter_syntax_error;
9263
9264 /* .parameter clear
9265 ** Clear all bind parameters by dropping the TEMP table that holds them.
9266 */
drhbf70f1b2022-10-19 18:04:42 +00009267 if( nArg==2 && cli_strcmp(azArg[1],"clear")==0 ){
drh65c29fd2019-03-25 21:56:26 +00009268 sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;",
drh9cb02642019-02-28 20:10:52 +00009269 0, 0, 0);
9270 }else
9271
9272 /* .parameter list
9273 ** List all bind parameters.
9274 */
drhbf70f1b2022-10-19 18:04:42 +00009275 if( nArg==2 && cli_strcmp(azArg[1],"list")==0 ){
drh9cb02642019-02-28 20:10:52 +00009276 sqlite3_stmt *pStmt = 0;
9277 int rx;
9278 int len = 0;
9279 rx = sqlite3_prepare_v2(p->db,
9280 "SELECT max(length(key)) "
drh65c29fd2019-03-25 21:56:26 +00009281 "FROM temp.sqlite_parameters;", -1, &pStmt, 0);
drh9cb02642019-02-28 20:10:52 +00009282 if( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
9283 len = sqlite3_column_int(pStmt, 0);
9284 if( len>40 ) len = 40;
9285 }
9286 sqlite3_finalize(pStmt);
9287 pStmt = 0;
9288 if( len ){
9289 rx = sqlite3_prepare_v2(p->db,
9290 "SELECT key, quote(value) "
drh65c29fd2019-03-25 21:56:26 +00009291 "FROM temp.sqlite_parameters;", -1, &pStmt, 0);
drhe85e1da2021-10-01 21:01:07 +00009292 while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
drh9cb02642019-02-28 20:10:52 +00009293 utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
9294 sqlite3_column_text(pStmt,1));
9295 }
9296 sqlite3_finalize(pStmt);
9297 }
9298 }else
9299
9300 /* .parameter init
9301 ** Make sure the TEMP table used to hold bind parameters exists.
9302 ** Create it if necessary.
9303 */
drhbf70f1b2022-10-19 18:04:42 +00009304 if( nArg==2 && cli_strcmp(azArg[1],"init")==0 ){
drh9cb02642019-02-28 20:10:52 +00009305 bind_table_init(p);
9306 }else
9307
9308 /* .parameter set NAME VALUE
9309 ** Set or reset a bind parameter. NAME should be the full parameter
9310 ** name exactly as it appears in the query. (ex: $abc, @def). The
9311 ** VALUE can be in either SQL literal notation, or if not it will be
9312 ** understood to be a text string.
9313 */
drhbf70f1b2022-10-19 18:04:42 +00009314 if( nArg==4 && cli_strcmp(azArg[1],"set")==0 ){
drh9cb02642019-02-28 20:10:52 +00009315 int rx;
9316 char *zSql;
9317 sqlite3_stmt *pStmt;
9318 const char *zKey = azArg[2];
9319 const char *zValue = azArg[3];
9320 bind_table_init(p);
9321 zSql = sqlite3_mprintf(
drh65c29fd2019-03-25 21:56:26 +00009322 "REPLACE INTO temp.sqlite_parameters(key,value)"
drh9cb02642019-02-28 20:10:52 +00009323 "VALUES(%Q,%s);", zKey, zValue);
drhe3e25652021-12-16 13:29:28 +00009324 shell_check_oom(zSql);
drh9cb02642019-02-28 20:10:52 +00009325 pStmt = 0;
9326 rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
9327 sqlite3_free(zSql);
9328 if( rx!=SQLITE_OK ){
9329 sqlite3_finalize(pStmt);
9330 pStmt = 0;
9331 zSql = sqlite3_mprintf(
drh65c29fd2019-03-25 21:56:26 +00009332 "REPLACE INTO temp.sqlite_parameters(key,value)"
drh9cb02642019-02-28 20:10:52 +00009333 "VALUES(%Q,%Q);", zKey, zValue);
drhe3e25652021-12-16 13:29:28 +00009334 shell_check_oom(zSql);
drh9cb02642019-02-28 20:10:52 +00009335 rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
9336 sqlite3_free(zSql);
9337 if( rx!=SQLITE_OK ){
9338 utf8_printf(p->out, "Error: %s\n", sqlite3_errmsg(p->db));
9339 sqlite3_finalize(pStmt);
9340 pStmt = 0;
9341 rc = 1;
9342 }
9343 }
9344 sqlite3_step(pStmt);
9345 sqlite3_finalize(pStmt);
9346 }else
9347
9348 /* .parameter unset NAME
9349 ** Remove the NAME binding from the parameter binding table, if it
9350 ** exists.
9351 */
drhbf70f1b2022-10-19 18:04:42 +00009352 if( nArg==3 && cli_strcmp(azArg[1],"unset")==0 ){
drh9cb02642019-02-28 20:10:52 +00009353 char *zSql = sqlite3_mprintf(
drh65c29fd2019-03-25 21:56:26 +00009354 "DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]);
drhe3e25652021-12-16 13:29:28 +00009355 shell_check_oom(zSql);
drh9cb02642019-02-28 20:10:52 +00009356 sqlite3_exec(p->db, zSql, 0, 0, 0);
9357 sqlite3_free(zSql);
9358 }else
9359 /* If no command name matches, show a syntax error */
9360 parameter_syntax_error:
9361 showHelp(p->out, "parameter");
9362 }else
9363
drhbf70f1b2022-10-19 18:04:42 +00009364 if( c=='p' && n>=3 && cli_strncmp(azArg[0], "print", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009365 int i;
9366 for(i=1; i<nArg; i++){
9367 if( i>1 ) raw_printf(p->out, " ");
9368 utf8_printf(p->out, "%s", azArg[i]);
9369 }
9370 raw_printf(p->out, "\n");
9371 }else
9372
drh569b1d92019-02-05 20:51:41 +00009373#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
drhbf70f1b2022-10-19 18:04:42 +00009374 if( c=='p' && n>=3 && cli_strncmp(azArg[0], "progress", n)==0 ){
drh3f83f592019-02-04 14:53:18 +00009375 int i;
drhfc4eeef2019-02-05 19:48:46 +00009376 int nn = 0;
drh3f83f592019-02-04 14:53:18 +00009377 p->flgProgress = 0;
9378 p->mxProgress = 0;
9379 p->nProgress = 0;
9380 for(i=1; i<nArg; i++){
9381 const char *z = azArg[i];
9382 if( z[0]=='-' ){
9383 z++;
9384 if( z[0]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +00009385 if( cli_strcmp(z,"quiet")==0 || cli_strcmp(z,"q")==0 ){
drhfc4eeef2019-02-05 19:48:46 +00009386 p->flgProgress |= SHELL_PROGRESS_QUIET;
drh3f83f592019-02-04 14:53:18 +00009387 continue;
9388 }
drhbf70f1b2022-10-19 18:04:42 +00009389 if( cli_strcmp(z,"reset")==0 ){
drhfc4eeef2019-02-05 19:48:46 +00009390 p->flgProgress |= SHELL_PROGRESS_RESET;
drh3f83f592019-02-04 14:53:18 +00009391 continue;
9392 }
drhbf70f1b2022-10-19 18:04:42 +00009393 if( cli_strcmp(z,"once")==0 ){
drhfc4eeef2019-02-05 19:48:46 +00009394 p->flgProgress |= SHELL_PROGRESS_ONCE;
drh3f83f592019-02-04 14:53:18 +00009395 continue;
9396 }
drhbf70f1b2022-10-19 18:04:42 +00009397 if( cli_strcmp(z,"limit")==0 ){
drh3f83f592019-02-04 14:53:18 +00009398 if( i+1>=nArg ){
9399 utf8_printf(stderr, "Error: missing argument on --limit\n");
9400 rc = 1;
9401 goto meta_command_exit;
9402 }else{
9403 p->mxProgress = (int)integerValue(azArg[++i]);
9404 }
9405 continue;
9406 }
9407 utf8_printf(stderr, "Error: unknown option: \"%s\"\n", azArg[i]);
9408 rc = 1;
9409 goto meta_command_exit;
9410 }else{
drhfc4eeef2019-02-05 19:48:46 +00009411 nn = (int)integerValue(z);
drh3f83f592019-02-04 14:53:18 +00009412 }
9413 }
9414 open_db(p, 0);
drhfc4eeef2019-02-05 19:48:46 +00009415 sqlite3_progress_handler(p->db, nn, progress_handler, p);
drh3f83f592019-02-04 14:53:18 +00009416 }else
drh569b1d92019-02-05 20:51:41 +00009417#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
drh3f83f592019-02-04 14:53:18 +00009418
drhbf70f1b2022-10-19 18:04:42 +00009419 if( c=='p' && cli_strncmp(azArg[0], "prompt", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009420 if( nArg >= 2) {
9421 strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
9422 }
9423 if( nArg >= 3) {
9424 strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
9425 }
9426 }else
9427
stephan4413ec72022-07-12 15:53:02 +00009428#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00009429 if( c=='q' && cli_strncmp(azArg[0], "quit", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009430 rc = 2;
9431 }else
stephan02520cc2022-05-18 22:58:34 +00009432#endif
drh2ce15c32017-07-11 13:34:40 +00009433
stephan4413ec72022-07-12 15:53:02 +00009434#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00009435 if( c=='r' && n>=3 && cli_strncmp(azArg[0], "read", n)==0 ){
drh60379d42018-12-13 18:30:01 +00009436 FILE *inSaved = p->in;
drh2c8ee022018-12-13 18:59:30 +00009437 int savedLineno = p->lineno;
drhb97e2ad2021-08-26 18:31:39 +00009438 failIfSafeMode(p, "cannot run .read in safe mode");
drh2ce15c32017-07-11 13:34:40 +00009439 if( nArg!=2 ){
9440 raw_printf(stderr, "Usage: .read FILE\n");
9441 rc = 1;
9442 goto meta_command_exit;
9443 }
drh30497f42020-08-26 10:50:48 +00009444 if( azArg[1][0]=='|' ){
drh9d59e3b2021-03-12 01:49:08 +00009445#ifdef SQLITE_OMIT_POPEN
9446 raw_printf(stderr, "Error: pipes are not supported in this OS\n");
9447 rc = 1;
9448 p->out = stdout;
9449#else
drh30497f42020-08-26 10:50:48 +00009450 p->in = popen(azArg[1]+1, "r");
9451 if( p->in==0 ){
9452 utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
9453 rc = 1;
9454 }else{
9455 rc = process_input(p);
9456 pclose(p->in);
9457 }
drh9d59e3b2021-03-12 01:49:08 +00009458#endif
larrybrd96bcc72021-09-17 21:12:47 +00009459 }else if( (p->in = openChrSource(azArg[1]))==0 ){
drh2ce15c32017-07-11 13:34:40 +00009460 utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
9461 rc = 1;
9462 }else{
drh60379d42018-12-13 18:30:01 +00009463 rc = process_input(p);
9464 fclose(p->in);
drh2ce15c32017-07-11 13:34:40 +00009465 }
drh60379d42018-12-13 18:30:01 +00009466 p->in = inSaved;
drh2c8ee022018-12-13 18:59:30 +00009467 p->lineno = savedLineno;
drh2ce15c32017-07-11 13:34:40 +00009468 }else
stephan4413ec72022-07-12 15:53:02 +00009469#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00009470
stephan4413ec72022-07-12 15:53:02 +00009471#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00009472 if( c=='r' && n>=3 && cli_strncmp(azArg[0], "restore", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009473 const char *zSrcFile;
9474 const char *zDb;
9475 sqlite3 *pSrc;
9476 sqlite3_backup *pBackup;
9477 int nTimeout = 0;
9478
drhb97e2ad2021-08-26 18:31:39 +00009479 failIfSafeMode(p, "cannot run .restore in safe mode");
drh2ce15c32017-07-11 13:34:40 +00009480 if( nArg==2 ){
9481 zSrcFile = azArg[1];
9482 zDb = "main";
9483 }else if( nArg==3 ){
9484 zSrcFile = azArg[2];
9485 zDb = azArg[1];
9486 }else{
9487 raw_printf(stderr, "Usage: .restore ?DB? FILE\n");
9488 rc = 1;
9489 goto meta_command_exit;
9490 }
9491 rc = sqlite3_open(zSrcFile, &pSrc);
9492 if( rc!=SQLITE_OK ){
9493 utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
drh9e804032018-05-18 17:11:50 +00009494 close_db(pSrc);
drh2ce15c32017-07-11 13:34:40 +00009495 return 1;
9496 }
9497 open_db(p, 0);
9498 pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
9499 if( pBackup==0 ){
9500 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
drh9e804032018-05-18 17:11:50 +00009501 close_db(pSrc);
drh2ce15c32017-07-11 13:34:40 +00009502 return 1;
9503 }
9504 while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
9505 || rc==SQLITE_BUSY ){
9506 if( rc==SQLITE_BUSY ){
9507 if( nTimeout++ >= 3 ) break;
9508 sqlite3_sleep(100);
9509 }
9510 }
9511 sqlite3_backup_finish(pBackup);
9512 if( rc==SQLITE_DONE ){
9513 rc = 0;
9514 }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
9515 raw_printf(stderr, "Error: source database is busy\n");
9516 rc = 1;
9517 }else{
9518 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
9519 rc = 1;
9520 }
drh9e804032018-05-18 17:11:50 +00009521 close_db(pSrc);
drh2ce15c32017-07-11 13:34:40 +00009522 }else
stephan4413ec72022-07-12 15:53:02 +00009523#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00009524
drhbf70f1b2022-10-19 18:04:42 +00009525 if( c=='s' && cli_strncmp(azArg[0], "scanstats", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009526 if( nArg==2 ){
mistachkinb71aa092018-01-23 00:05:18 +00009527 p->scanstatsOn = (u8)booleanValue(azArg[1]);
drh2ce15c32017-07-11 13:34:40 +00009528#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
9529 raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
9530#endif
9531 }else{
9532 raw_printf(stderr, "Usage: .scanstats on|off\n");
9533 rc = 1;
9534 }
9535 }else
9536
drhbf70f1b2022-10-19 18:04:42 +00009537 if( c=='s' && cli_strncmp(azArg[0], "schema", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009538 ShellText sSelect;
9539 ShellState data;
9540 char *zErrMsg = 0;
drh667a2a22018-01-02 00:04:37 +00009541 const char *zDiv = "(";
drhceba7922018-01-01 21:28:25 +00009542 const char *zName = 0;
drh2ce15c32017-07-11 13:34:40 +00009543 int iSchema = 0;
drhceba7922018-01-01 21:28:25 +00009544 int bDebug = 0;
drhbbb29ec2020-10-12 14:56:47 +00009545 int bNoSystemTabs = 0;
drhceba7922018-01-01 21:28:25 +00009546 int ii;
drh2ce15c32017-07-11 13:34:40 +00009547
9548 open_db(p, 0);
9549 memcpy(&data, p, sizeof(data));
9550 data.showHeader = 0;
9551 data.cMode = data.mode = MODE_Semi;
9552 initText(&sSelect);
drhceba7922018-01-01 21:28:25 +00009553 for(ii=1; ii<nArg; ii++){
9554 if( optionMatch(azArg[ii],"indent") ){
9555 data.cMode = data.mode = MODE_Pretty;
9556 }else if( optionMatch(azArg[ii],"debug") ){
9557 bDebug = 1;
drhbbb29ec2020-10-12 14:56:47 +00009558 }else if( optionMatch(azArg[ii],"nosys") ){
9559 bNoSystemTabs = 1;
9560 }else if( azArg[ii][0]=='-' ){
9561 utf8_printf(stderr, "Unknown option: \"%s\"\n", azArg[ii]);
9562 rc = 1;
9563 goto meta_command_exit;
drhceba7922018-01-01 21:28:25 +00009564 }else if( zName==0 ){
9565 zName = azArg[ii];
drh2ce15c32017-07-11 13:34:40 +00009566 }else{
drhbbb29ec2020-10-12 14:56:47 +00009567 raw_printf(stderr, "Usage: .schema ?--indent? ?--nosys? ?LIKE-PATTERN?\n");
drhceba7922018-01-01 21:28:25 +00009568 rc = 1;
9569 goto meta_command_exit;
drh2ce15c32017-07-11 13:34:40 +00009570 }
drh2ce15c32017-07-11 13:34:40 +00009571 }
drhceba7922018-01-01 21:28:25 +00009572 if( zName!=0 ){
drh067b92b2020-06-19 15:24:12 +00009573 int isSchema = sqlite3_strlike(zName, "sqlite_master", '\\')==0
drh346a70c2020-06-15 20:27:35 +00009574 || sqlite3_strlike(zName, "sqlite_schema", '\\')==0
9575 || sqlite3_strlike(zName,"sqlite_temp_master", '\\')==0
9576 || sqlite3_strlike(zName,"sqlite_temp_schema", '\\')==0;
drh067b92b2020-06-19 15:24:12 +00009577 if( isSchema ){
drh2ce15c32017-07-11 13:34:40 +00009578 char *new_argv[2], *new_colv[2];
drhc22b7162018-01-01 20:11:23 +00009579 new_argv[0] = sqlite3_mprintf(
9580 "CREATE TABLE %s (\n"
drh2ce15c32017-07-11 13:34:40 +00009581 " type text,\n"
9582 " name text,\n"
9583 " tbl_name text,\n"
9584 " rootpage integer,\n"
9585 " sql text\n"
drh346a70c2020-06-15 20:27:35 +00009586 ")", zName);
drhe3e25652021-12-16 13:29:28 +00009587 shell_check_oom(new_argv[0]);
drh2ce15c32017-07-11 13:34:40 +00009588 new_argv[1] = 0;
9589 new_colv[0] = "sql";
9590 new_colv[1] = 0;
9591 callback(&data, 1, new_argv, new_colv);
drhc22b7162018-01-01 20:11:23 +00009592 sqlite3_free(new_argv[0]);
drh2ce15c32017-07-11 13:34:40 +00009593 }
drh2ce15c32017-07-11 13:34:40 +00009594 }
9595 if( zDiv ){
9596 sqlite3_stmt *pStmt = 0;
9597 rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
9598 -1, &pStmt, 0);
9599 if( rc ){
9600 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
9601 sqlite3_finalize(pStmt);
9602 rc = 1;
9603 goto meta_command_exit;
9604 }
9605 appendText(&sSelect, "SELECT sql FROM", 0);
9606 iSchema = 0;
9607 while( sqlite3_step(pStmt)==SQLITE_ROW ){
9608 const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
9609 char zScNum[30];
9610 sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
9611 appendText(&sSelect, zDiv, 0);
9612 zDiv = " UNION ALL ";
drhceba7922018-01-01 21:28:25 +00009613 appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
9614 if( sqlite3_stricmp(zDb, "main")!=0 ){
drhea38f4f2019-07-13 17:21:47 +00009615 appendText(&sSelect, zDb, '\'');
drh2ce15c32017-07-11 13:34:40 +00009616 }else{
drhceba7922018-01-01 21:28:25 +00009617 appendText(&sSelect, "NULL", 0);
drh2ce15c32017-07-11 13:34:40 +00009618 }
drhceba7922018-01-01 21:28:25 +00009619 appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0);
9620 appendText(&sSelect, zScNum, 0);
9621 appendText(&sSelect, " AS snum, ", 0);
9622 appendText(&sSelect, zDb, '\'');
9623 appendText(&sSelect, " AS sname FROM ", 0);
drhea38f4f2019-07-13 17:21:47 +00009624 appendText(&sSelect, zDb, quoteChar(zDb));
drh067b92b2020-06-19 15:24:12 +00009625 appendText(&sSelect, ".sqlite_schema", 0);
drh2ce15c32017-07-11 13:34:40 +00009626 }
9627 sqlite3_finalize(pStmt);
drhcc3f3d12019-08-17 15:27:58 +00009628#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
drh667a2a22018-01-02 00:04:37 +00009629 if( zName ){
9630 appendText(&sSelect,
9631 " UNION ALL SELECT shell_module_schema(name),"
drhe2754c12019-08-26 12:50:01 +00009632 " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list",
9633 0);
drh667a2a22018-01-02 00:04:37 +00009634 }
drhcde7b772018-01-02 12:50:40 +00009635#endif
drh2ce15c32017-07-11 13:34:40 +00009636 appendText(&sSelect, ") WHERE ", 0);
drhceba7922018-01-01 21:28:25 +00009637 if( zName ){
9638 char *zQarg = sqlite3_mprintf("%Q", zName);
mistachkinc158c072021-12-31 19:08:20 +00009639 int bGlob;
drhe3e25652021-12-16 13:29:28 +00009640 shell_check_oom(zQarg);
mistachkinc158c072021-12-31 19:08:20 +00009641 bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 ||
9642 strchr(zName, '[') != 0;
drhceba7922018-01-01 21:28:25 +00009643 if( strchr(zName, '.') ){
drh2ce15c32017-07-11 13:34:40 +00009644 appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
9645 }else{
9646 appendText(&sSelect, "lower(tbl_name)", 0);
9647 }
mistachkin9d107262018-03-23 14:24:34 +00009648 appendText(&sSelect, bGlob ? " GLOB " : " LIKE ", 0);
drh2ce15c32017-07-11 13:34:40 +00009649 appendText(&sSelect, zQarg, 0);
mistachkin9d107262018-03-23 14:24:34 +00009650 if( !bGlob ){
9651 appendText(&sSelect, " ESCAPE '\\' ", 0);
9652 }
drh2ce15c32017-07-11 13:34:40 +00009653 appendText(&sSelect, " AND ", 0);
9654 sqlite3_free(zQarg);
9655 }
drhbbb29ec2020-10-12 14:56:47 +00009656 if( bNoSystemTabs ){
9657 appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0);
9658 }
9659 appendText(&sSelect, "sql IS NOT NULL"
drh2ce15c32017-07-11 13:34:40 +00009660 " ORDER BY snum, rowid", 0);
drhceba7922018-01-01 21:28:25 +00009661 if( bDebug ){
9662 utf8_printf(p->out, "SQL: %s;\n", sSelect.z);
9663 }else{
9664 rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
9665 }
drh2ce15c32017-07-11 13:34:40 +00009666 freeText(&sSelect);
9667 }
9668 if( zErrMsg ){
9669 utf8_printf(stderr,"Error: %s\n", zErrMsg);
9670 sqlite3_free(zErrMsg);
9671 rc = 1;
9672 }else if( rc != SQLITE_OK ){
9673 raw_printf(stderr,"Error: querying schema information\n");
9674 rc = 1;
9675 }else{
9676 rc = 0;
9677 }
9678 }else
9679
drhbf70f1b2022-10-19 18:04:42 +00009680 if( (c=='s' && n==11 && cli_strncmp(azArg[0], "selecttrace", n)==0)
9681 || (c=='t' && n==9 && cli_strncmp(azArg[0], "treetrace", n)==0)
drh5e431be2022-04-06 11:08:38 +00009682 ){
drhfda8e492020-12-04 16:04:45 +00009683 unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
drhc0622a42020-12-04 01:17:57 +00009684 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x);
drh2ce15c32017-07-11 13:34:40 +00009685 }else
drh2ce15c32017-07-11 13:34:40 +00009686
9687#if defined(SQLITE_ENABLE_SESSION)
drhbf70f1b2022-10-19 18:04:42 +00009688 if( c=='s' && cli_strncmp(azArg[0],"session",n)==0 && n>=3 ){
drh37407122021-07-23 18:43:58 +00009689 struct AuxDb *pAuxDb = p->pAuxDb;
9690 OpenSession *pSession = &pAuxDb->aSession[0];
drh2ce15c32017-07-11 13:34:40 +00009691 char **azCmd = &azArg[1];
9692 int iSes = 0;
9693 int nCmd = nArg - 1;
9694 int i;
9695 if( nArg<=1 ) goto session_syntax_error;
9696 open_db(p, 0);
9697 if( nArg>=3 ){
drh37407122021-07-23 18:43:58 +00009698 for(iSes=0; iSes<pAuxDb->nSession; iSes++){
drhbf70f1b2022-10-19 18:04:42 +00009699 if( cli_strcmp(pAuxDb->aSession[iSes].zName, azArg[1])==0 ) break;
drh2ce15c32017-07-11 13:34:40 +00009700 }
drh37407122021-07-23 18:43:58 +00009701 if( iSes<pAuxDb->nSession ){
9702 pSession = &pAuxDb->aSession[iSes];
drh2ce15c32017-07-11 13:34:40 +00009703 azCmd++;
9704 nCmd--;
9705 }else{
drh37407122021-07-23 18:43:58 +00009706 pSession = &pAuxDb->aSession[0];
drh2ce15c32017-07-11 13:34:40 +00009707 iSes = 0;
9708 }
9709 }
9710
9711 /* .session attach TABLE
9712 ** Invoke the sqlite3session_attach() interface to attach a particular
9713 ** table so that it is never filtered.
9714 */
drhbf70f1b2022-10-19 18:04:42 +00009715 if( cli_strcmp(azCmd[0],"attach")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009716 if( nCmd!=2 ) goto session_syntax_error;
9717 if( pSession->p==0 ){
9718 session_not_open:
9719 raw_printf(stderr, "ERROR: No sessions are open\n");
9720 }else{
9721 rc = sqlite3session_attach(pSession->p, azCmd[1]);
9722 if( rc ){
9723 raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc);
9724 rc = 0;
9725 }
9726 }
9727 }else
9728
9729 /* .session changeset FILE
9730 ** .session patchset FILE
9731 ** Write a changeset or patchset into a file. The file is overwritten.
9732 */
drhbf70f1b2022-10-19 18:04:42 +00009733 if( cli_strcmp(azCmd[0],"changeset")==0
9734 || cli_strcmp(azCmd[0],"patchset")==0
9735 ){
drh2ce15c32017-07-11 13:34:40 +00009736 FILE *out = 0;
drhb97e2ad2021-08-26 18:31:39 +00009737 failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]);
drh2ce15c32017-07-11 13:34:40 +00009738 if( nCmd!=2 ) goto session_syntax_error;
9739 if( pSession->p==0 ) goto session_not_open;
9740 out = fopen(azCmd[1], "wb");
9741 if( out==0 ){
drhe2754c12019-08-26 12:50:01 +00009742 utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n",
9743 azCmd[1]);
drh2ce15c32017-07-11 13:34:40 +00009744 }else{
9745 int szChng;
9746 void *pChng;
9747 if( azCmd[0][0]=='c' ){
9748 rc = sqlite3session_changeset(pSession->p, &szChng, &pChng);
9749 }else{
9750 rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
9751 }
9752 if( rc ){
9753 printf("Error: error code %d\n", rc);
9754 rc = 0;
9755 }
9756 if( pChng
9757 && fwrite(pChng, szChng, 1, out)!=1 ){
9758 raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n",
9759 szChng);
9760 }
9761 sqlite3_free(pChng);
9762 fclose(out);
9763 }
9764 }else
9765
9766 /* .session close
9767 ** Close the identified session
9768 */
drhbf70f1b2022-10-19 18:04:42 +00009769 if( cli_strcmp(azCmd[0], "close")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009770 if( nCmd!=1 ) goto session_syntax_error;
drh37407122021-07-23 18:43:58 +00009771 if( pAuxDb->nSession ){
drh2ce15c32017-07-11 13:34:40 +00009772 session_close(pSession);
drh37407122021-07-23 18:43:58 +00009773 pAuxDb->aSession[iSes] = pAuxDb->aSession[--pAuxDb->nSession];
drh2ce15c32017-07-11 13:34:40 +00009774 }
9775 }else
9776
9777 /* .session enable ?BOOLEAN?
9778 ** Query or set the enable flag
9779 */
drhbf70f1b2022-10-19 18:04:42 +00009780 if( cli_strcmp(azCmd[0], "enable")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009781 int ii;
9782 if( nCmd>2 ) goto session_syntax_error;
9783 ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
drh37407122021-07-23 18:43:58 +00009784 if( pAuxDb->nSession ){
drh2ce15c32017-07-11 13:34:40 +00009785 ii = sqlite3session_enable(pSession->p, ii);
9786 utf8_printf(p->out, "session %s enable flag = %d\n",
9787 pSession->zName, ii);
9788 }
9789 }else
9790
9791 /* .session filter GLOB ....
9792 ** Set a list of GLOB patterns of table names to be excluded.
9793 */
drhbf70f1b2022-10-19 18:04:42 +00009794 if( cli_strcmp(azCmd[0], "filter")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009795 int ii, nByte;
9796 if( nCmd<2 ) goto session_syntax_error;
drh37407122021-07-23 18:43:58 +00009797 if( pAuxDb->nSession ){
drh2ce15c32017-07-11 13:34:40 +00009798 for(ii=0; ii<pSession->nFilter; ii++){
9799 sqlite3_free(pSession->azFilter[ii]);
9800 }
9801 sqlite3_free(pSession->azFilter);
9802 nByte = sizeof(pSession->azFilter[0])*(nCmd-1);
9803 pSession->azFilter = sqlite3_malloc( nByte );
9804 if( pSession->azFilter==0 ){
9805 raw_printf(stderr, "Error: out or memory\n");
9806 exit(1);
9807 }
9808 for(ii=1; ii<nCmd; ii++){
drhe3e25652021-12-16 13:29:28 +00009809 char *x = pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]);
9810 shell_check_oom(x);
drh2ce15c32017-07-11 13:34:40 +00009811 }
9812 pSession->nFilter = ii-1;
9813 }
9814 }else
9815
9816 /* .session indirect ?BOOLEAN?
9817 ** Query or set the indirect flag
9818 */
drhbf70f1b2022-10-19 18:04:42 +00009819 if( cli_strcmp(azCmd[0], "indirect")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009820 int ii;
9821 if( nCmd>2 ) goto session_syntax_error;
9822 ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
drh37407122021-07-23 18:43:58 +00009823 if( pAuxDb->nSession ){
drh2ce15c32017-07-11 13:34:40 +00009824 ii = sqlite3session_indirect(pSession->p, ii);
9825 utf8_printf(p->out, "session %s indirect flag = %d\n",
9826 pSession->zName, ii);
9827 }
9828 }else
9829
9830 /* .session isempty
9831 ** Determine if the session is empty
9832 */
drhbf70f1b2022-10-19 18:04:42 +00009833 if( cli_strcmp(azCmd[0], "isempty")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009834 int ii;
9835 if( nCmd!=1 ) goto session_syntax_error;
drh37407122021-07-23 18:43:58 +00009836 if( pAuxDb->nSession ){
drh2ce15c32017-07-11 13:34:40 +00009837 ii = sqlite3session_isempty(pSession->p);
9838 utf8_printf(p->out, "session %s isempty flag = %d\n",
9839 pSession->zName, ii);
9840 }
9841 }else
9842
9843 /* .session list
9844 ** List all currently open sessions
9845 */
drhbf70f1b2022-10-19 18:04:42 +00009846 if( cli_strcmp(azCmd[0],"list")==0 ){
drh37407122021-07-23 18:43:58 +00009847 for(i=0; i<pAuxDb->nSession; i++){
9848 utf8_printf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName);
drh2ce15c32017-07-11 13:34:40 +00009849 }
9850 }else
9851
9852 /* .session open DB NAME
9853 ** Open a new session called NAME on the attached database DB.
9854 ** DB is normally "main".
9855 */
drhbf70f1b2022-10-19 18:04:42 +00009856 if( cli_strcmp(azCmd[0],"open")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009857 char *zName;
9858 if( nCmd!=3 ) goto session_syntax_error;
9859 zName = azCmd[2];
9860 if( zName[0]==0 ) goto session_syntax_error;
drh37407122021-07-23 18:43:58 +00009861 for(i=0; i<pAuxDb->nSession; i++){
drhbf70f1b2022-10-19 18:04:42 +00009862 if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009863 utf8_printf(stderr, "Session \"%s\" already exists\n", zName);
9864 goto meta_command_exit;
9865 }
9866 }
drh37407122021-07-23 18:43:58 +00009867 if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){
9868 raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
drh2ce15c32017-07-11 13:34:40 +00009869 goto meta_command_exit;
9870 }
drh37407122021-07-23 18:43:58 +00009871 pSession = &pAuxDb->aSession[pAuxDb->nSession];
drh2ce15c32017-07-11 13:34:40 +00009872 rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
9873 if( rc ){
9874 raw_printf(stderr, "Cannot open session: error code=%d\n", rc);
9875 rc = 0;
9876 goto meta_command_exit;
9877 }
9878 pSession->nFilter = 0;
9879 sqlite3session_table_filter(pSession->p, session_filter, pSession);
drh37407122021-07-23 18:43:58 +00009880 pAuxDb->nSession++;
drh2ce15c32017-07-11 13:34:40 +00009881 pSession->zName = sqlite3_mprintf("%s", zName);
drhe3e25652021-12-16 13:29:28 +00009882 shell_check_oom(pSession->zName);
drh2ce15c32017-07-11 13:34:40 +00009883 }else
9884 /* If no command name matches, show a syntax error */
9885 session_syntax_error:
drheb7f2a02018-09-26 18:02:32 +00009886 showHelp(p->out, "session");
drh2ce15c32017-07-11 13:34:40 +00009887 }else
9888#endif
9889
9890#ifdef SQLITE_DEBUG
9891 /* Undocumented commands for internal testing. Subject to change
9892 ** without notice. */
drhbf70f1b2022-10-19 18:04:42 +00009893 if( c=='s' && n>=10 && cli_strncmp(azArg[0], "selftest-", 9)==0 ){
9894 if( cli_strncmp(azArg[0]+9, "boolean", n-9)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009895 int i, v;
9896 for(i=1; i<nArg; i++){
9897 v = booleanValue(azArg[i]);
9898 utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
9899 }
9900 }
drhbf70f1b2022-10-19 18:04:42 +00009901 if( cli_strncmp(azArg[0]+9, "integer", n-9)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009902 int i; sqlite3_int64 v;
9903 for(i=1; i<nArg; i++){
9904 char zBuf[200];
9905 v = integerValue(azArg[i]);
9906 sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
9907 utf8_printf(p->out, "%s", zBuf);
9908 }
9909 }
9910 }else
9911#endif
9912
drhbf70f1b2022-10-19 18:04:42 +00009913 if( c=='s' && n>=4 && cli_strncmp(azArg[0],"selftest",n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009914 int bIsInit = 0; /* True to initialize the SELFTEST table */
9915 int bVerbose = 0; /* Verbose output */
9916 int bSelftestExists; /* True if SELFTEST already exists */
9917 int i, k; /* Loop counters */
9918 int nTest = 0; /* Number of tests runs */
9919 int nErr = 0; /* Number of errors seen */
9920 ShellText str; /* Answer for a query */
9921 sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
9922
9923 open_db(p,0);
9924 for(i=1; i<nArg; i++){
9925 const char *z = azArg[i];
9926 if( z[0]=='-' && z[1]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +00009927 if( cli_strcmp(z,"-init")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009928 bIsInit = 1;
9929 }else
drhbf70f1b2022-10-19 18:04:42 +00009930 if( cli_strcmp(z,"-v")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009931 bVerbose++;
9932 }else
9933 {
9934 utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
9935 azArg[i], azArg[0]);
9936 raw_printf(stderr, "Should be one of: --init -v\n");
9937 rc = 1;
9938 goto meta_command_exit;
9939 }
9940 }
9941 if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
9942 != SQLITE_OK ){
9943 bSelftestExists = 0;
9944 }else{
9945 bSelftestExists = 1;
9946 }
9947 if( bIsInit ){
9948 createSelftestTable(p);
9949 bSelftestExists = 1;
9950 }
9951 initText(&str);
9952 appendText(&str, "x", 0);
9953 for(k=bSelftestExists; k>=0; k--){
9954 if( k==1 ){
9955 rc = sqlite3_prepare_v2(p->db,
9956 "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
9957 -1, &pStmt, 0);
9958 }else{
9959 rc = sqlite3_prepare_v2(p->db,
9960 "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
9961 " (1,'run','PRAGMA integrity_check','ok')",
9962 -1, &pStmt, 0);
9963 }
9964 if( rc ){
9965 raw_printf(stderr, "Error querying the selftest table\n");
9966 rc = 1;
9967 sqlite3_finalize(pStmt);
9968 goto meta_command_exit;
9969 }
9970 for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
9971 int tno = sqlite3_column_int(pStmt, 0);
9972 const char *zOp = (const char*)sqlite3_column_text(pStmt, 1);
9973 const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
9974 const char *zAns = (const char*)sqlite3_column_text(pStmt, 3);
9975
drh621a5e02021-12-16 17:35:27 +00009976 if( zOp==0 ) continue;
9977 if( zSql==0 ) continue;
9978 if( zAns==0 ) continue;
drh2ce15c32017-07-11 13:34:40 +00009979 k = 0;
9980 if( bVerbose>0 ){
drh2ce15c32017-07-11 13:34:40 +00009981 printf("%d: %s %s\n", tno, zOp, zSql);
drh2ce15c32017-07-11 13:34:40 +00009982 }
drhbf70f1b2022-10-19 18:04:42 +00009983 if( cli_strcmp(zOp,"memo")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009984 utf8_printf(p->out, "%s\n", zSql);
9985 }else
drhbf70f1b2022-10-19 18:04:42 +00009986 if( cli_strcmp(zOp,"run")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009987 char *zErrMsg = 0;
9988 str.n = 0;
9989 str.z[0] = 0;
9990 rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
9991 nTest++;
9992 if( bVerbose ){
9993 utf8_printf(p->out, "Result: %s\n", str.z);
9994 }
9995 if( rc || zErrMsg ){
9996 nErr++;
9997 rc = 1;
9998 utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
9999 sqlite3_free(zErrMsg);
drhbf70f1b2022-10-19 18:04:42 +000010000 }else if( cli_strcmp(zAns,str.z)!=0 ){
drh2ce15c32017-07-11 13:34:40 +000010001 nErr++;
10002 rc = 1;
10003 utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
10004 utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
10005 }
10006 }else
10007 {
10008 utf8_printf(stderr,
10009 "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
10010 rc = 1;
10011 break;
10012 }
10013 } /* End loop over rows of content from SELFTEST */
10014 sqlite3_finalize(pStmt);
10015 } /* End loop over k */
10016 freeText(&str);
10017 utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
10018 }else
10019
drhbf70f1b2022-10-19 18:04:42 +000010020 if( c=='s' && cli_strncmp(azArg[0], "separator", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010021 if( nArg<2 || nArg>3 ){
10022 raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
10023 rc = 1;
10024 }
10025 if( nArg>=2 ){
10026 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
10027 "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
10028 }
10029 if( nArg>=3 ){
10030 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
10031 "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
10032 }
10033 }else
10034
drhbf70f1b2022-10-19 18:04:42 +000010035 if( c=='s' && n>=4 && cli_strncmp(azArg[0],"sha3sum",n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010036 const char *zLike = 0; /* Which table to checksum. 0 means everything */
10037 int i; /* Loop counter */
10038 int bSchema = 0; /* Also hash the schema */
10039 int bSeparate = 0; /* Hash each table separately */
10040 int iSize = 224; /* Hash algorithm to use */
10041 int bDebug = 0; /* Only show the query that would have run */
10042 sqlite3_stmt *pStmt; /* For querying tables names */
10043 char *zSql; /* SQL to be run */
10044 char *zSep; /* Separator */
10045 ShellText sSql; /* Complete SQL for the query to run the hash */
10046 ShellText sQuery; /* Set of queries used to read all content */
10047 open_db(p, 0);
10048 for(i=1; i<nArg; i++){
10049 const char *z = azArg[i];
10050 if( z[0]=='-' ){
10051 z++;
10052 if( z[0]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +000010053 if( cli_strcmp(z,"schema")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010054 bSchema = 1;
10055 }else
drhbf70f1b2022-10-19 18:04:42 +000010056 if( cli_strcmp(z,"sha3-224")==0 || cli_strcmp(z,"sha3-256")==0
10057 || cli_strcmp(z,"sha3-384")==0 || cli_strcmp(z,"sha3-512")==0
drh2ce15c32017-07-11 13:34:40 +000010058 ){
10059 iSize = atoi(&z[5]);
10060 }else
drhbf70f1b2022-10-19 18:04:42 +000010061 if( cli_strcmp(z,"debug")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010062 bDebug = 1;
10063 }else
10064 {
10065 utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
10066 azArg[i], azArg[0]);
drhe2754c12019-08-26 12:50:01 +000010067 showHelp(p->out, azArg[0]);
drh2ce15c32017-07-11 13:34:40 +000010068 rc = 1;
10069 goto meta_command_exit;
10070 }
10071 }else if( zLike ){
10072 raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n");
10073 rc = 1;
10074 goto meta_command_exit;
10075 }else{
10076 zLike = z;
10077 bSeparate = 1;
drhcedfecf2018-03-23 12:59:10 +000010078 if( sqlite3_strlike("sqlite\\_%", zLike, '\\')==0 ) bSchema = 1;
drh2ce15c32017-07-11 13:34:40 +000010079 }
10080 }
10081 if( bSchema ){
drh067b92b2020-06-19 15:24:12 +000010082 zSql = "SELECT lower(name) FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +000010083 " WHERE type='table' AND coalesce(rootpage,0)>1"
drh067b92b2020-06-19 15:24:12 +000010084 " UNION ALL SELECT 'sqlite_schema'"
drh2ce15c32017-07-11 13:34:40 +000010085 " ORDER BY 1 collate nocase";
10086 }else{
drh067b92b2020-06-19 15:24:12 +000010087 zSql = "SELECT lower(name) FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +000010088 " WHERE type='table' AND coalesce(rootpage,0)>1"
10089 " AND name NOT LIKE 'sqlite_%'"
10090 " ORDER BY 1 collate nocase";
10091 }
10092 sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
10093 initText(&sQuery);
10094 initText(&sSql);
10095 appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
10096 zSep = "VALUES(";
10097 while( SQLITE_ROW==sqlite3_step(pStmt) ){
10098 const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
drh621a5e02021-12-16 17:35:27 +000010099 if( zTab==0 ) continue;
drh2ce15c32017-07-11 13:34:40 +000010100 if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
drhbf70f1b2022-10-19 18:04:42 +000010101 if( cli_strncmp(zTab, "sqlite_",7)!=0 ){
drh2ce15c32017-07-11 13:34:40 +000010102 appendText(&sQuery,"SELECT * FROM ", 0);
10103 appendText(&sQuery,zTab,'"');
10104 appendText(&sQuery," NOT INDEXED;", 0);
drhbf70f1b2022-10-19 18:04:42 +000010105 }else if( cli_strcmp(zTab, "sqlite_schema")==0 ){
drh067b92b2020-06-19 15:24:12 +000010106 appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +000010107 " ORDER BY name;", 0);
drhbf70f1b2022-10-19 18:04:42 +000010108 }else if( cli_strcmp(zTab, "sqlite_sequence")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010109 appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
10110 " ORDER BY name;", 0);
drhbf70f1b2022-10-19 18:04:42 +000010111 }else if( cli_strcmp(zTab, "sqlite_stat1")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010112 appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1"
10113 " ORDER BY tbl,idx;", 0);
drhbf70f1b2022-10-19 18:04:42 +000010114 }else if( cli_strcmp(zTab, "sqlite_stat4")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010115 appendText(&sQuery, "SELECT * FROM ", 0);
10116 appendText(&sQuery, zTab, 0);
10117 appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0);
10118 }
10119 appendText(&sSql, zSep, 0);
10120 appendText(&sSql, sQuery.z, '\'');
10121 sQuery.n = 0;
10122 appendText(&sSql, ",", 0);
10123 appendText(&sSql, zTab, '\'');
10124 zSep = "),(";
10125 }
10126 sqlite3_finalize(pStmt);
10127 if( bSeparate ){
10128 zSql = sqlite3_mprintf(
10129 "%s))"
10130 " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label"
10131 " FROM [sha3sum$query]",
10132 sSql.z, iSize);
10133 }else{
10134 zSql = sqlite3_mprintf(
10135 "%s))"
10136 " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash"
10137 " FROM [sha3sum$query]",
10138 sSql.z, iSize);
10139 }
drhe3e25652021-12-16 13:29:28 +000010140 shell_check_oom(zSql);
drh2ce15c32017-07-11 13:34:40 +000010141 freeText(&sQuery);
10142 freeText(&sSql);
10143 if( bDebug ){
10144 utf8_printf(p->out, "%s\n", zSql);
10145 }else{
drha10b9992018-03-09 15:24:33 +000010146 shell_exec(p, zSql, 0);
drh2ce15c32017-07-11 13:34:40 +000010147 }
10148 sqlite3_free(zSql);
10149 }else
10150
stephan4413ec72022-07-12 15:53:02 +000010151#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
drh2ce15c32017-07-11 13:34:40 +000010152 if( c=='s'
drhbf70f1b2022-10-19 18:04:42 +000010153 && (cli_strncmp(azArg[0], "shell", n)==0
10154 || cli_strncmp(azArg[0],"system",n)==0)
drh2ce15c32017-07-11 13:34:40 +000010155 ){
10156 char *zCmd;
10157 int i, x;
drhb97e2ad2021-08-26 18:31:39 +000010158 failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
drh2ce15c32017-07-11 13:34:40 +000010159 if( nArg<2 ){
10160 raw_printf(stderr, "Usage: .system COMMAND\n");
10161 rc = 1;
10162 goto meta_command_exit;
10163 }
10164 zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
drhe3e25652021-12-16 13:29:28 +000010165 for(i=2; i<nArg && zCmd!=0; i++){
drh2ce15c32017-07-11 13:34:40 +000010166 zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
10167 zCmd, azArg[i]);
10168 }
drhe3e25652021-12-16 13:29:28 +000010169 x = zCmd!=0 ? system(zCmd) : 1;
drh2ce15c32017-07-11 13:34:40 +000010170 sqlite3_free(zCmd);
10171 if( x ) raw_printf(stderr, "System command returns %d\n", x);
10172 }else
stephan4413ec72022-07-12 15:53:02 +000010173#endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +000010174
drhbf70f1b2022-10-19 18:04:42 +000010175 if( c=='s' && cli_strncmp(azArg[0], "show", n)==0 ){
drhada70452017-12-21 21:02:27 +000010176 static const char *azBool[] = { "off", "on", "trigger", "full"};
drha6e6cf22021-01-09 19:10:04 +000010177 const char *zOut;
drh2ce15c32017-07-11 13:34:40 +000010178 int i;
10179 if( nArg!=1 ){
10180 raw_printf(stderr, "Usage: .show\n");
10181 rc = 1;
10182 goto meta_command_exit;
10183 }
10184 utf8_printf(p->out, "%12.12s: %s\n","echo",
larrybrf4874812022-05-11 19:59:31 +000010185 azBool[ShellHasFlag(p, SHFLG_Echo)]);
drh2ce15c32017-07-11 13:34:40 +000010186 utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
10187 utf8_printf(p->out, "%12.12s: %s\n","explain",
10188 p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
10189 utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
drhe40f2862022-01-31 14:14:29 +000010190 if( p->mode==MODE_Column
10191 || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
10192 ){
larrybrcc4d55c2022-02-01 02:50:45 +000010193 utf8_printf
10194 (p->out, "%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
10195 modeDescr[p->mode], p->cmOpts.iWrap,
10196 p->cmOpts.bWordWrap ? "on" : "off",
10197 p->cmOpts.bQuote ? "" : "no");
drhe40f2862022-01-31 14:14:29 +000010198 }else{
10199 utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
10200 }
drh2ce15c32017-07-11 13:34:40 +000010201 utf8_printf(p->out, "%12.12s: ", "nullvalue");
10202 output_c_string(p->out, p->nullValue);
10203 raw_printf(p->out, "\n");
10204 utf8_printf(p->out,"%12.12s: %s\n","output",
10205 strlen30(p->outfile) ? p->outfile : "stdout");
10206 utf8_printf(p->out,"%12.12s: ", "colseparator");
10207 output_c_string(p->out, p->colSeparator);
10208 raw_printf(p->out, "\n");
10209 utf8_printf(p->out,"%12.12s: ", "rowseparator");
10210 output_c_string(p->out, p->rowSeparator);
10211 raw_printf(p->out, "\n");
drha6e6cf22021-01-09 19:10:04 +000010212 switch( p->statsOn ){
10213 case 0: zOut = "off"; break;
10214 default: zOut = "on"; break;
10215 case 2: zOut = "stmt"; break;
10216 case 3: zOut = "vmstep"; break;
10217 }
10218 utf8_printf(p->out, "%12.12s: %s\n","stats", zOut);
drh2ce15c32017-07-11 13:34:40 +000010219 utf8_printf(p->out, "%12.12s: ", "width");
drh0285d982020-05-29 14:38:43 +000010220 for (i=0;i<p->nWidth;i++) {
drh2ce15c32017-07-11 13:34:40 +000010221 raw_printf(p->out, "%d ", p->colWidth[i]);
10222 }
10223 raw_printf(p->out, "\n");
10224 utf8_printf(p->out, "%12.12s: %s\n", "filename",
drh37407122021-07-23 18:43:58 +000010225 p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : "");
drh2ce15c32017-07-11 13:34:40 +000010226 }else
10227
drhbf70f1b2022-10-19 18:04:42 +000010228 if( c=='s' && cli_strncmp(azArg[0], "stats", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010229 if( nArg==2 ){
drhbf70f1b2022-10-19 18:04:42 +000010230 if( cli_strcmp(azArg[1],"stmt")==0 ){
drha6e6cf22021-01-09 19:10:04 +000010231 p->statsOn = 2;
drhbf70f1b2022-10-19 18:04:42 +000010232 }else if( cli_strcmp(azArg[1],"vmstep")==0 ){
drha6e6cf22021-01-09 19:10:04 +000010233 p->statsOn = 3;
10234 }else{
10235 p->statsOn = (u8)booleanValue(azArg[1]);
10236 }
drh2ce15c32017-07-11 13:34:40 +000010237 }else if( nArg==1 ){
10238 display_stats(p->db, p, 0);
10239 }else{
drha6e6cf22021-01-09 19:10:04 +000010240 raw_printf(stderr, "Usage: .stats ?on|off|stmt|vmstep?\n");
drh2ce15c32017-07-11 13:34:40 +000010241 rc = 1;
10242 }
10243 }else
10244
drhbf70f1b2022-10-19 18:04:42 +000010245 if( (c=='t' && n>1 && cli_strncmp(azArg[0], "tables", n)==0)
10246 || (c=='i' && (cli_strncmp(azArg[0], "indices", n)==0
10247 || cli_strncmp(azArg[0], "indexes", n)==0) )
drh2ce15c32017-07-11 13:34:40 +000010248 ){
10249 sqlite3_stmt *pStmt;
10250 char **azResult;
10251 int nRow, nAlloc;
10252 int ii;
10253 ShellText s;
10254 initText(&s);
10255 open_db(p, 0);
10256 rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
drh9e804032018-05-18 17:11:50 +000010257 if( rc ){
10258 sqlite3_finalize(pStmt);
10259 return shellDatabaseError(p->db);
10260 }
drh2ce15c32017-07-11 13:34:40 +000010261
10262 if( nArg>2 && c=='i' ){
10263 /* It is an historical accident that the .indexes command shows an error
10264 ** when called with the wrong number of arguments whereas the .tables
10265 ** command does not. */
10266 raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
10267 rc = 1;
drh9e804032018-05-18 17:11:50 +000010268 sqlite3_finalize(pStmt);
drh2ce15c32017-07-11 13:34:40 +000010269 goto meta_command_exit;
10270 }
10271 for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
10272 const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
10273 if( zDbName==0 ) continue;
10274 if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0);
10275 if( sqlite3_stricmp(zDbName, "main")==0 ){
10276 appendText(&s, "SELECT name FROM ", 0);
10277 }else{
10278 appendText(&s, "SELECT ", 0);
10279 appendText(&s, zDbName, '\'');
10280 appendText(&s, "||'.'||name FROM ", 0);
10281 }
10282 appendText(&s, zDbName, '"');
drh067b92b2020-06-19 15:24:12 +000010283 appendText(&s, ".sqlite_schema ", 0);
drh2ce15c32017-07-11 13:34:40 +000010284 if( c=='t' ){
10285 appendText(&s," WHERE type IN ('table','view')"
10286 " AND name NOT LIKE 'sqlite_%'"
10287 " AND name LIKE ?1", 0);
10288 }else{
10289 appendText(&s," WHERE type='index'"
10290 " AND tbl_name LIKE ?1", 0);
10291 }
10292 }
10293 rc = sqlite3_finalize(pStmt);
drhe85e1da2021-10-01 21:01:07 +000010294 if( rc==SQLITE_OK ){
10295 appendText(&s, " ORDER BY 1", 0);
10296 rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
10297 }
drh2ce15c32017-07-11 13:34:40 +000010298 freeText(&s);
10299 if( rc ) return shellDatabaseError(p->db);
10300
10301 /* Run the SQL statement prepared by the above block. Store the results
10302 ** as an array of nul-terminated strings in azResult[]. */
10303 nRow = nAlloc = 0;
10304 azResult = 0;
10305 if( nArg>1 ){
10306 sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT);
10307 }else{
10308 sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
10309 }
10310 while( sqlite3_step(pStmt)==SQLITE_ROW ){
10311 if( nRow>=nAlloc ){
10312 char **azNew;
10313 int n2 = nAlloc*2 + 10;
10314 azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
drhe3e25652021-12-16 13:29:28 +000010315 shell_check_oom(azNew);
drh2ce15c32017-07-11 13:34:40 +000010316 nAlloc = n2;
10317 azResult = azNew;
10318 }
10319 azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
drhe3e25652021-12-16 13:29:28 +000010320 shell_check_oom(azResult[nRow]);
drh2ce15c32017-07-11 13:34:40 +000010321 nRow++;
10322 }
10323 if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
10324 rc = shellDatabaseError(p->db);
10325 }
10326
10327 /* Pretty-print the contents of array azResult[] to the output */
10328 if( rc==0 && nRow>0 ){
10329 int len, maxlen = 0;
10330 int i, j;
10331 int nPrintCol, nPrintRow;
10332 for(i=0; i<nRow; i++){
10333 len = strlen30(azResult[i]);
10334 if( len>maxlen ) maxlen = len;
10335 }
10336 nPrintCol = 80/(maxlen+2);
10337 if( nPrintCol<1 ) nPrintCol = 1;
10338 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
10339 for(i=0; i<nPrintRow; i++){
10340 for(j=i; j<nRow; j+=nPrintRow){
10341 char *zSp = j<nPrintRow ? "" : " ";
10342 utf8_printf(p->out, "%s%-*s", zSp, maxlen,
10343 azResult[j] ? azResult[j]:"");
10344 }
10345 raw_printf(p->out, "\n");
10346 }
10347 }
10348
10349 for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
10350 sqlite3_free(azResult);
10351 }else
10352
stephan4413ec72022-07-12 15:53:02 +000010353#ifndef SQLITE_SHELL_FIDDLE
drh2ce15c32017-07-11 13:34:40 +000010354 /* Begin redirecting output to the file "testcase-out.txt" */
drhbf70f1b2022-10-19 18:04:42 +000010355 if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010356 output_reset(p);
drha92a01a2018-01-10 22:15:37 +000010357 p->out = output_file_open("testcase-out.txt", 0);
drh2ce15c32017-07-11 13:34:40 +000010358 if( p->out==0 ){
10359 raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
10360 }
10361 if( nArg>=2 ){
10362 sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
10363 }else{
10364 sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
10365 }
10366 }else
stephan4413ec72022-07-12 15:53:02 +000010367#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +000010368
10369#ifndef SQLITE_UNTESTABLE
drhbf70f1b2022-10-19 18:04:42 +000010370 if( c=='t' && n>=8 && cli_strncmp(azArg[0], "testctrl", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010371 static const struct {
10372 const char *zCtrlName; /* Name of a test-control option */
10373 int ctrlCode; /* Integer code for that option */
drh38ed1ce2021-12-06 15:24:36 +000010374 int unSafe; /* Not valid for --safe mode */
drhef302e82017-11-15 19:14:08 +000010375 const char *zUsage; /* Usage notes */
drh2ce15c32017-07-11 13:34:40 +000010376 } aCtrl[] = {
drh38ed1ce2021-12-06 15:24:36 +000010377 { "always", SQLITE_TESTCTRL_ALWAYS, 1, "BOOLEAN" },
10378 { "assert", SQLITE_TESTCTRL_ASSERT, 1, "BOOLEAN" },
10379 /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,1, "" },*/
10380 /*{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/
10381 { "byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" },
10382 { "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" },
10383 /*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"" },*/
10384 { "imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"},
10385 { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" },
10386 { "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" },
10387 { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" },
10388 { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" },
drh0d9de992017-12-26 18:04:23 +000010389#ifdef YYCOVERAGE
drh38ed1ce2021-12-06 15:24:36 +000010390 { "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" },
drh0d9de992017-12-26 18:04:23 +000010391#endif
drh38ed1ce2021-12-06 15:24:36 +000010392 { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,0, "OFFSET " },
10393 { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" },
10394 { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" },
10395 { "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" },
10396 { "seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" },
10397 { "sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" },
10398 { "tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" },
drh2ce15c32017-07-11 13:34:40 +000010399 };
10400 int testctrl = -1;
drhef302e82017-11-15 19:14:08 +000010401 int iCtrl = -1;
10402 int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */
10403 int isOk = 0;
drh2ce15c32017-07-11 13:34:40 +000010404 int i, n2;
mistachkinc6bc15a2017-11-21 21:14:32 +000010405 const char *zCmd = 0;
10406
drh2ce15c32017-07-11 13:34:40 +000010407 open_db(p, 0);
mistachkinc6bc15a2017-11-21 21:14:32 +000010408 zCmd = nArg>=2 ? azArg[1] : "help";
drh35f51a42017-11-15 17:07:22 +000010409
10410 /* The argument can optionally begin with "-" or "--" */
10411 if( zCmd[0]=='-' && zCmd[1] ){
10412 zCmd++;
10413 if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
10414 }
10415
10416 /* --help lists all test-controls */
drhbf70f1b2022-10-19 18:04:42 +000010417 if( cli_strcmp(zCmd,"help")==0 ){
drh35f51a42017-11-15 17:07:22 +000010418 utf8_printf(p->out, "Available test-controls:\n");
10419 for(i=0; i<ArraySize(aCtrl); i++){
drhef302e82017-11-15 19:14:08 +000010420 utf8_printf(p->out, " .testctrl %s %s\n",
10421 aCtrl[i].zCtrlName, aCtrl[i].zUsage);
drh35f51a42017-11-15 17:07:22 +000010422 }
10423 rc = 1;
10424 goto meta_command_exit;
10425 }
drh2ce15c32017-07-11 13:34:40 +000010426
10427 /* convert testctrl text option to value. allow any unique prefix
10428 ** of the option name, or a numerical value. */
drh35f51a42017-11-15 17:07:22 +000010429 n2 = strlen30(zCmd);
drh2ce15c32017-07-11 13:34:40 +000010430 for(i=0; i<ArraySize(aCtrl); i++){
drhbf70f1b2022-10-19 18:04:42 +000010431 if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010432 if( testctrl<0 ){
10433 testctrl = aCtrl[i].ctrlCode;
drhef302e82017-11-15 19:14:08 +000010434 iCtrl = i;
drh2ce15c32017-07-11 13:34:40 +000010435 }else{
drh35f51a42017-11-15 17:07:22 +000010436 utf8_printf(stderr, "Error: ambiguous test-control: \"%s\"\n"
10437 "Use \".testctrl --help\" for help\n", zCmd);
10438 rc = 1;
10439 goto meta_command_exit;
drh2ce15c32017-07-11 13:34:40 +000010440 }
10441 }
10442 }
drhef302e82017-11-15 19:14:08 +000010443 if( testctrl<0 ){
drh35f51a42017-11-15 17:07:22 +000010444 utf8_printf(stderr,"Error: unknown test-control: %s\n"
10445 "Use \".testctrl --help\" for help\n", zCmd);
drh38ed1ce2021-12-06 15:24:36 +000010446 }else if( aCtrl[iCtrl].unSafe && p->bSafeMode ){
10447 utf8_printf(stderr,
10448 "line %d: \".testctrl %s\" may not be used in safe mode\n",
10449 p->lineno, aCtrl[iCtrl].zCtrlName);
10450 exit(1);
drh2ce15c32017-07-11 13:34:40 +000010451 }else{
10452 switch(testctrl){
10453
10454 /* sqlite3_test_control(int, db, int) */
10455 case SQLITE_TESTCTRL_OPTIMIZATIONS:
drh2ce15c32017-07-11 13:34:40 +000010456 if( nArg==3 ){
drhaf7b7652021-01-13 19:28:17 +000010457 unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0);
drh2ce15c32017-07-11 13:34:40 +000010458 rc2 = sqlite3_test_control(testctrl, p->db, opt);
drhef302e82017-11-15 19:14:08 +000010459 isOk = 3;
drh2ce15c32017-07-11 13:34:40 +000010460 }
10461 break;
10462
10463 /* sqlite3_test_control(int) */
10464 case SQLITE_TESTCTRL_PRNG_SAVE:
10465 case SQLITE_TESTCTRL_PRNG_RESTORE:
drh2ce15c32017-07-11 13:34:40 +000010466 case SQLITE_TESTCTRL_BYTEORDER:
10467 if( nArg==2 ){
10468 rc2 = sqlite3_test_control(testctrl);
drhef302e82017-11-15 19:14:08 +000010469 isOk = testctrl==SQLITE_TESTCTRL_BYTEORDER ? 1 : 3;
drh2ce15c32017-07-11 13:34:40 +000010470 }
10471 break;
10472
10473 /* sqlite3_test_control(int, uint) */
10474 case SQLITE_TESTCTRL_PENDING_BYTE:
10475 if( nArg==3 ){
10476 unsigned int opt = (unsigned int)integerValue(azArg[2]);
10477 rc2 = sqlite3_test_control(testctrl, opt);
drhef302e82017-11-15 19:14:08 +000010478 isOk = 3;
drh2ce15c32017-07-11 13:34:40 +000010479 }
10480 break;
10481
drh2e6d83b2019-08-03 01:39:20 +000010482 /* sqlite3_test_control(int, int, sqlite3*) */
10483 case SQLITE_TESTCTRL_PRNG_SEED:
10484 if( nArg==3 || nArg==4 ){
drh51755a72019-08-08 19:40:29 +000010485 int ii = (int)integerValue(azArg[2]);
drh2e6d83b2019-08-03 01:39:20 +000010486 sqlite3 *db;
drhbf70f1b2022-10-19 18:04:42 +000010487 if( ii==0 && cli_strcmp(azArg[2],"random")==0 ){
drh41428a92019-08-12 16:25:11 +000010488 sqlite3_randomness(sizeof(ii),&ii);
10489 printf("-- random seed: %d\n", ii);
10490 }
drh2e6d83b2019-08-03 01:39:20 +000010491 if( nArg==3 ){
10492 db = 0;
10493 }else{
10494 db = p->db;
10495 /* Make sure the schema has been loaded */
10496 sqlite3_table_column_metadata(db, 0, "x", 0, 0, 0, 0, 0, 0);
10497 }
drh51755a72019-08-08 19:40:29 +000010498 rc2 = sqlite3_test_control(testctrl, ii, db);
drh2e6d83b2019-08-03 01:39:20 +000010499 isOk = 3;
10500 }
10501 break;
10502
drh2ce15c32017-07-11 13:34:40 +000010503 /* sqlite3_test_control(int, int) */
10504 case SQLITE_TESTCTRL_ASSERT:
10505 case SQLITE_TESTCTRL_ALWAYS:
drhef302e82017-11-15 19:14:08 +000010506 if( nArg==3 ){
10507 int opt = booleanValue(azArg[2]);
10508 rc2 = sqlite3_test_control(testctrl, opt);
10509 isOk = 1;
10510 }
10511 break;
10512
10513 /* sqlite3_test_control(int, int) */
10514 case SQLITE_TESTCTRL_LOCALTIME_FAULT:
drh2ce15c32017-07-11 13:34:40 +000010515 case SQLITE_TESTCTRL_NEVER_CORRUPT:
10516 if( nArg==3 ){
10517 int opt = booleanValue(azArg[2]);
10518 rc2 = sqlite3_test_control(testctrl, opt);
drhef302e82017-11-15 19:14:08 +000010519 isOk = 3;
drh2ce15c32017-07-11 13:34:40 +000010520 }
10521 break;
10522
drh171c50e2020-01-01 15:43:30 +000010523 /* sqlite3_test_control(sqlite3*) */
10524 case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
10525 rc2 = sqlite3_test_control(testctrl, p->db);
drh2a83c102020-01-01 23:02:35 +000010526 isOk = 3;
drh171c50e2020-01-01 15:43:30 +000010527 break;
10528
drh2ce15c32017-07-11 13:34:40 +000010529 case SQLITE_TESTCTRL_IMPOSTER:
10530 if( nArg==5 ){
10531 rc2 = sqlite3_test_control(testctrl, p->db,
10532 azArg[2],
10533 integerValue(azArg[3]),
10534 integerValue(azArg[4]));
drhef302e82017-11-15 19:14:08 +000010535 isOk = 3;
drh2ce15c32017-07-11 13:34:40 +000010536 }
10537 break;
drh0d9de992017-12-26 18:04:23 +000010538
drh37ccfcf2020-08-31 18:49:04 +000010539 case SQLITE_TESTCTRL_SEEK_COUNT: {
10540 u64 x = 0;
10541 rc2 = sqlite3_test_control(testctrl, p->db, &x);
10542 utf8_printf(p->out, "%llu\n", x);
10543 isOk = 3;
10544 break;
10545 }
10546
drh0d9de992017-12-26 18:04:23 +000010547#ifdef YYCOVERAGE
drhf3c12562021-06-04 13:16:46 +000010548 case SQLITE_TESTCTRL_PARSER_COVERAGE: {
drh0d9de992017-12-26 18:04:23 +000010549 if( nArg==2 ){
10550 sqlite3_test_control(testctrl, p->out);
10551 isOk = 3;
10552 }
drhf3c12562021-06-04 13:16:46 +000010553 break;
10554 }
10555#endif
10556#ifdef SQLITE_DEBUG
10557 case SQLITE_TESTCTRL_TUNE: {
10558 if( nArg==4 ){
10559 int id = (int)integerValue(azArg[2]);
drh2d26cfc2021-06-04 13:40:26 +000010560 int val = (int)integerValue(azArg[3]);
10561 sqlite3_test_control(testctrl, id, &val);
10562 isOk = 3;
10563 }else if( nArg==3 ){
10564 int id = (int)integerValue(azArg[2]);
10565 sqlite3_test_control(testctrl, -id, &rc2);
10566 isOk = 1;
10567 }else if( nArg==2 ){
10568 int id = 1;
10569 while(1){
10570 int val = 0;
10571 rc2 = sqlite3_test_control(testctrl, -id, &val);
10572 if( rc2!=SQLITE_OK ) break;
10573 if( id>1 ) utf8_printf(p->out, " ");
10574 utf8_printf(p->out, "%d: %d", id, val);
10575 id++;
10576 }
10577 if( id>1 ) utf8_printf(p->out, "\n");
drhf3c12562021-06-04 13:16:46 +000010578 isOk = 3;
10579 }
10580 break;
10581 }
drh0d9de992017-12-26 18:04:23 +000010582#endif
dan779e9902021-07-28 18:13:28 +000010583 case SQLITE_TESTCTRL_SORTER_MMAP:
10584 if( nArg==3 ){
10585 int opt = (unsigned int)integerValue(azArg[2]);
10586 rc2 = sqlite3_test_control(testctrl, p->db, opt);
10587 isOk = 3;
10588 }
10589 break;
drh2ce15c32017-07-11 13:34:40 +000010590 }
10591 }
drhef302e82017-11-15 19:14:08 +000010592 if( isOk==0 && iCtrl>=0 ){
drhe2754c12019-08-26 12:50:01 +000010593 utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
drhef302e82017-11-15 19:14:08 +000010594 rc = 1;
10595 }else if( isOk==1 ){
10596 raw_printf(p->out, "%d\n", rc2);
10597 }else if( isOk==2 ){
10598 raw_printf(p->out, "0x%08x\n", rc2);
10599 }
drh2ce15c32017-07-11 13:34:40 +000010600 }else
10601#endif /* !defined(SQLITE_UNTESTABLE) */
10602
drhbf70f1b2022-10-19 18:04:42 +000010603 if( c=='t' && n>4 && cli_strncmp(azArg[0], "timeout", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010604 open_db(p, 0);
10605 sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
10606 }else
10607
drhbf70f1b2022-10-19 18:04:42 +000010608 if( c=='t' && n>=5 && cli_strncmp(azArg[0], "timer", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010609 if( nArg==2 ){
10610 enableTimer = booleanValue(azArg[1]);
10611 if( enableTimer && !HAS_TIMER ){
10612 raw_printf(stderr, "Error: timer not available on this system.\n");
10613 enableTimer = 0;
10614 }
10615 }else{
10616 raw_printf(stderr, "Usage: .timer on|off\n");
10617 rc = 1;
10618 }
10619 }else
10620
drh707821f2018-12-05 13:39:06 +000010621#ifndef SQLITE_OMIT_TRACE
drhbf70f1b2022-10-19 18:04:42 +000010622 if( c=='t' && cli_strncmp(azArg[0], "trace", n)==0 ){
drh707821f2018-12-05 13:39:06 +000010623 int mType = 0;
10624 int jj;
drh2ce15c32017-07-11 13:34:40 +000010625 open_db(p, 0);
drh707821f2018-12-05 13:39:06 +000010626 for(jj=1; jj<nArg; jj++){
10627 const char *z = azArg[jj];
10628 if( z[0]=='-' ){
10629 if( optionMatch(z, "expanded") ){
10630 p->eTraceType = SHELL_TRACE_EXPANDED;
10631 }
10632#ifdef SQLITE_ENABLE_NORMALIZE
10633 else if( optionMatch(z, "normalized") ){
10634 p->eTraceType = SHELL_TRACE_NORMALIZED;
10635 }
10636#endif
10637 else if( optionMatch(z, "plain") ){
10638 p->eTraceType = SHELL_TRACE_PLAIN;
10639 }
10640 else if( optionMatch(z, "profile") ){
10641 mType |= SQLITE_TRACE_PROFILE;
10642 }
10643 else if( optionMatch(z, "row") ){
10644 mType |= SQLITE_TRACE_ROW;
10645 }
10646 else if( optionMatch(z, "stmt") ){
10647 mType |= SQLITE_TRACE_STMT;
10648 }
10649 else if( optionMatch(z, "close") ){
10650 mType |= SQLITE_TRACE_CLOSE;
10651 }
10652 else {
10653 raw_printf(stderr, "Unknown option \"%s\" on \".trace\"\n", z);
10654 rc = 1;
10655 goto meta_command_exit;
10656 }
10657 }else{
10658 output_file_close(p->traceOut);
10659 p->traceOut = output_file_open(azArg[1], 0);
10660 }
drh2ce15c32017-07-11 13:34:40 +000010661 }
drh2ce15c32017-07-11 13:34:40 +000010662 if( p->traceOut==0 ){
10663 sqlite3_trace_v2(p->db, 0, 0, 0);
10664 }else{
drh707821f2018-12-05 13:39:06 +000010665 if( mType==0 ) mType = SQLITE_TRACE_STMT;
10666 sqlite3_trace_v2(p->db, mType, sql_trace_callback, p);
drh2ce15c32017-07-11 13:34:40 +000010667 }
drh2ce15c32017-07-11 13:34:40 +000010668 }else
drh707821f2018-12-05 13:39:06 +000010669#endif /* !defined(SQLITE_OMIT_TRACE) */
drh2ce15c32017-07-11 13:34:40 +000010670
drhe2b7a762019-10-02 00:25:08 +000010671#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE)
drhbf70f1b2022-10-19 18:04:42 +000010672 if( c=='u' && cli_strncmp(azArg[0], "unmodule", n)==0 ){
drhcc5979d2019-08-16 22:58:29 +000010673 int ii;
drh8c754a32019-08-19 20:35:30 +000010674 int lenOpt;
drh5df84282019-08-17 19:45:25 +000010675 char *zOpt;
drhcc5979d2019-08-16 22:58:29 +000010676 if( nArg<2 ){
drh5df84282019-08-17 19:45:25 +000010677 raw_printf(stderr, "Usage: .unmodule [--allexcept] NAME ...\n");
drhcc5979d2019-08-16 22:58:29 +000010678 rc = 1;
10679 goto meta_command_exit;
10680 }
10681 open_db(p, 0);
drh5df84282019-08-17 19:45:25 +000010682 zOpt = azArg[1];
10683 if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++;
drh8c754a32019-08-19 20:35:30 +000010684 lenOpt = (int)strlen(zOpt);
drhbf70f1b2022-10-19 18:04:42 +000010685 if( lenOpt>=3 && cli_strncmp(zOpt, "-allexcept",lenOpt)==0 ){
drh5df84282019-08-17 19:45:25 +000010686 assert( azArg[nArg]==0 );
drh8c754a32019-08-19 20:35:30 +000010687 sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0);
drh5df84282019-08-17 19:45:25 +000010688 }else{
10689 for(ii=1; ii<nArg; ii++){
10690 sqlite3_create_module(p->db, azArg[ii], 0, 0);
10691 }
drhcc5979d2019-08-16 22:58:29 +000010692 }
10693 }else
10694#endif
10695
drh2ce15c32017-07-11 13:34:40 +000010696#if SQLITE_USER_AUTHENTICATION
drhbf70f1b2022-10-19 18:04:42 +000010697 if( c=='u' && cli_strncmp(azArg[0], "user", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010698 if( nArg<2 ){
10699 raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n");
10700 rc = 1;
10701 goto meta_command_exit;
10702 }
10703 open_db(p, 0);
drhbf70f1b2022-10-19 18:04:42 +000010704 if( cli_strcmp(azArg[1],"login")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010705 if( nArg!=4 ){
10706 raw_printf(stderr, "Usage: .user login USER PASSWORD\n");
10707 rc = 1;
10708 goto meta_command_exit;
10709 }
drhe2754c12019-08-26 12:50:01 +000010710 rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
10711 strlen30(azArg[3]));
drh2ce15c32017-07-11 13:34:40 +000010712 if( rc ){
10713 utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
10714 rc = 1;
10715 }
drhbf70f1b2022-10-19 18:04:42 +000010716 }else if( cli_strcmp(azArg[1],"add")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010717 if( nArg!=5 ){
10718 raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
10719 rc = 1;
10720 goto meta_command_exit;
10721 }
drhaf2770f2018-01-05 14:55:43 +000010722 rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
drh2ce15c32017-07-11 13:34:40 +000010723 booleanValue(azArg[4]));
10724 if( rc ){
10725 raw_printf(stderr, "User-Add failed: %d\n", rc);
10726 rc = 1;
10727 }
drhbf70f1b2022-10-19 18:04:42 +000010728 }else if( cli_strcmp(azArg[1],"edit")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010729 if( nArg!=5 ){
10730 raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
10731 rc = 1;
10732 goto meta_command_exit;
10733 }
drhaf2770f2018-01-05 14:55:43 +000010734 rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
drh2ce15c32017-07-11 13:34:40 +000010735 booleanValue(azArg[4]));
10736 if( rc ){
10737 raw_printf(stderr, "User-Edit failed: %d\n", rc);
10738 rc = 1;
10739 }
drhbf70f1b2022-10-19 18:04:42 +000010740 }else if( cli_strcmp(azArg[1],"delete")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010741 if( nArg!=3 ){
10742 raw_printf(stderr, "Usage: .user delete USER\n");
10743 rc = 1;
10744 goto meta_command_exit;
10745 }
10746 rc = sqlite3_user_delete(p->db, azArg[2]);
10747 if( rc ){
10748 raw_printf(stderr, "User-Delete failed: %d\n", rc);
10749 rc = 1;
10750 }
10751 }else{
10752 raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n");
10753 rc = 1;
10754 goto meta_command_exit;
10755 }
10756 }else
10757#endif /* SQLITE_USER_AUTHENTICATION */
10758
drhbf70f1b2022-10-19 18:04:42 +000010759 if( c=='v' && cli_strncmp(azArg[0], "version", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010760 utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
10761 sqlite3_libversion(), sqlite3_sourceid());
drh0ed2fd82018-01-16 20:05:27 +000010762#if SQLITE_HAVE_ZLIB
10763 utf8_printf(p->out, "zlib version %s\n", zlibVersion());
10764#endif
10765#define CTIMEOPT_VAL_(opt) #opt
10766#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
10767#if defined(__clang__) && defined(__clang_major__)
10768 utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
10769 CTIMEOPT_VAL(__clang_minor__) "."
10770 CTIMEOPT_VAL(__clang_patchlevel__) "\n");
10771#elif defined(_MSC_VER)
10772 utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n");
10773#elif defined(__GNUC__) && defined(__VERSION__)
10774 utf8_printf(p->out, "gcc-" __VERSION__ "\n");
10775#endif
drh2ce15c32017-07-11 13:34:40 +000010776 }else
10777
drhbf70f1b2022-10-19 18:04:42 +000010778 if( c=='v' && cli_strncmp(azArg[0], "vfsinfo", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010779 const char *zDbName = nArg==2 ? azArg[1] : "main";
10780 sqlite3_vfs *pVfs = 0;
10781 if( p->db ){
10782 sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
10783 if( pVfs ){
10784 utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
10785 raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
10786 raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
10787 raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
10788 }
10789 }
10790 }else
10791
drhbf70f1b2022-10-19 18:04:42 +000010792 if( c=='v' && cli_strncmp(azArg[0], "vfslist", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010793 sqlite3_vfs *pVfs;
10794 sqlite3_vfs *pCurrent = 0;
10795 if( p->db ){
10796 sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
10797 }
10798 for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
10799 utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
10800 pVfs==pCurrent ? " <--- CURRENT" : "");
10801 raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
10802 raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
10803 raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
10804 if( pVfs->pNext ){
10805 raw_printf(p->out, "-----------------------------------\n");
10806 }
10807 }
10808 }else
10809
drhbf70f1b2022-10-19 18:04:42 +000010810 if( c=='v' && cli_strncmp(azArg[0], "vfsname", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010811 const char *zDbName = nArg==2 ? azArg[1] : "main";
10812 char *zVfsName = 0;
10813 if( p->db ){
10814 sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
10815 if( zVfsName ){
10816 utf8_printf(p->out, "%s\n", zVfsName);
10817 sqlite3_free(zVfsName);
10818 }
10819 }
10820 }else
10821
drhbf70f1b2022-10-19 18:04:42 +000010822 if( c=='w' && cli_strncmp(azArg[0], "wheretrace", n)==0 ){
drhc0622a42020-12-04 01:17:57 +000010823 unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
10824 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x);
drh2ce15c32017-07-11 13:34:40 +000010825 }else
drh2ce15c32017-07-11 13:34:40 +000010826
drhbf70f1b2022-10-19 18:04:42 +000010827 if( c=='w' && cli_strncmp(azArg[0], "width", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010828 int j;
10829 assert( nArg<=ArraySize(azArg) );
drh0285d982020-05-29 14:38:43 +000010830 p->nWidth = nArg-1;
drh76fc88f2021-10-02 16:39:16 +000010831 p->colWidth = realloc(p->colWidth, (p->nWidth+1)*sizeof(int)*2);
drh0285d982020-05-29 14:38:43 +000010832 if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory();
10833 if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth];
10834 for(j=1; j<nArg; j++){
drh2ce15c32017-07-11 13:34:40 +000010835 p->colWidth[j-1] = (int)integerValue(azArg[j]);
10836 }
10837 }else
10838
10839 {
10840 utf8_printf(stderr, "Error: unknown command or invalid arguments: "
10841 " \"%s\". Enter \".help\" for help\n", azArg[0]);
10842 rc = 1;
10843 }
10844
10845meta_command_exit:
10846 if( p->outCount ){
10847 p->outCount--;
10848 if( p->outCount==0 ) output_reset(p);
10849 }
drhb97e2ad2021-08-26 18:31:39 +000010850 p->bSafeMode = p->bSafeModePersist;
drh2ce15c32017-07-11 13:34:40 +000010851 return rc;
10852}
10853
larrybr8bc4cbc2021-09-10 00:58:46 +000010854/* Line scan result and intermediate states (supporting scan resumption)
drh2ce15c32017-07-11 13:34:40 +000010855*/
drh68911c22021-09-22 14:26:22 +000010856#ifndef CHAR_BIT
10857# define CHAR_BIT 8
10858#endif
larrybr8bc4cbc2021-09-10 00:58:46 +000010859typedef enum {
larrybr7e009842021-09-18 21:35:22 +000010860 QSS_HasDark = 1<<CHAR_BIT, QSS_EndingSemi = 2<<CHAR_BIT,
10861 QSS_CharMask = (1<<CHAR_BIT)-1, QSS_ScanMask = 3<<CHAR_BIT,
larrybra96bbe92021-09-10 19:45:22 +000010862 QSS_Start = 0
larrybr8bc4cbc2021-09-10 00:58:46 +000010863} QuickScanState;
larrybr7e009842021-09-18 21:35:22 +000010864#define QSS_SETV(qss, newst) ((newst) | ((qss) & QSS_ScanMask))
10865#define QSS_INPLAIN(qss) (((qss)&QSS_CharMask)==QSS_Start)
10866#define QSS_PLAINWHITE(qss) (((qss)&~QSS_EndingSemi)==QSS_Start)
larrybra96bbe92021-09-10 19:45:22 +000010867#define QSS_PLAINDARK(qss) (((qss)&~QSS_EndingSemi)==QSS_HasDark)
larrybr7e009842021-09-18 21:35:22 +000010868#define QSS_SEMITERM(qss) (((qss)&~QSS_HasDark)==QSS_EndingSemi)
drh2ce15c32017-07-11 13:34:40 +000010869
10870/*
larrybr8bc4cbc2021-09-10 00:58:46 +000010871** Scan line for classification to guide shell's handling.
10872** The scan is resumable for subsequent lines when prior
10873** return values are passed as the 2nd argument.
drh2ce15c32017-07-11 13:34:40 +000010874*/
larrybr8bc4cbc2021-09-10 00:58:46 +000010875static QuickScanState quickscan(char *zLine, QuickScanState qss){
10876 char cin;
larrybr7e009842021-09-18 21:35:22 +000010877 char cWait = (char)qss; /* intentional narrowing loss */
10878 if( cWait==0 ){
10879 PlainScan:
drhe85e1da2021-10-01 21:01:07 +000010880 assert( cWait==0 );
drhfd7abcd2021-09-22 13:43:16 +000010881 while( (cin = *zLine++)!=0 ){
larrybr8bc4cbc2021-09-10 00:58:46 +000010882 if( IsSpace(cin) )
10883 continue;
10884 switch (cin){
10885 case '-':
larrybr7e009842021-09-18 21:35:22 +000010886 if( *zLine!='-' )
10887 break;
10888 while((cin = *++zLine)!=0 )
10889 if( cin=='\n')
10890 goto PlainScan;
10891 return qss;
larrybr8bc4cbc2021-09-10 00:58:46 +000010892 case ';':
larrybra96bbe92021-09-10 19:45:22 +000010893 qss |= QSS_EndingSemi;
10894 continue;
larrybr8bc4cbc2021-09-10 00:58:46 +000010895 case '/':
10896 if( *zLine=='*' ){
10897 ++zLine;
larrybr7e009842021-09-18 21:35:22 +000010898 cWait = '*';
10899 qss = QSS_SETV(qss, cWait);
10900 goto TermScan;
larrybr8bc4cbc2021-09-10 00:58:46 +000010901 }
10902 break;
larrybra96bbe92021-09-10 19:45:22 +000010903 case '[':
10904 cin = ']';
10905 /* fall thru */
10906 case '`': case '\'': case '"':
larrybr7e009842021-09-18 21:35:22 +000010907 cWait = cin;
10908 qss = QSS_HasDark | cWait;
10909 goto TermScan;
larrybr8bc4cbc2021-09-10 00:58:46 +000010910 default:
10911 break;
10912 }
larrybr7e009842021-09-18 21:35:22 +000010913 qss = (qss & ~QSS_EndingSemi) | QSS_HasDark;
drh2ce15c32017-07-11 13:34:40 +000010914 }
larrybr7e009842021-09-18 21:35:22 +000010915 }else{
10916 TermScan:
drhfd7abcd2021-09-22 13:43:16 +000010917 while( (cin = *zLine++)!=0 ){
larrybr7e009842021-09-18 21:35:22 +000010918 if( cin==cWait ){
10919 switch( cWait ){
10920 case '*':
10921 if( *zLine != '/' )
10922 continue;
10923 ++zLine;
10924 cWait = 0;
10925 qss = QSS_SETV(qss, 0);
10926 goto PlainScan;
10927 case '`': case '\'': case '"':
10928 if(*zLine==cWait){
larrybr8d463ce2021-09-11 02:42:04 +000010929 ++zLine;
larrybr7e009842021-09-18 21:35:22 +000010930 continue;
10931 }
10932 /* fall thru */
10933 case ']':
10934 cWait = 0;
10935 qss = QSS_SETV(qss, 0);
10936 goto PlainScan;
larrybr527c39d2022-05-10 14:55:45 +000010937 default: assert(0);
larrybr8bc4cbc2021-09-10 00:58:46 +000010938 }
10939 }
10940 }
drh2ce15c32017-07-11 13:34:40 +000010941 }
larrybr8bc4cbc2021-09-10 00:58:46 +000010942 return qss;
drh2ce15c32017-07-11 13:34:40 +000010943}
10944
10945/*
10946** Return TRUE if the line typed in is an SQL command terminator other
10947** than a semi-colon. The SQL Server style "go" command is understood
10948** as is the Oracle "/".
10949*/
larrybr8bc4cbc2021-09-10 00:58:46 +000010950static int line_is_command_terminator(char *zLine){
drh2ce15c32017-07-11 13:34:40 +000010951 while( IsSpace(zLine[0]) ){ zLine++; };
larrybr8bc4cbc2021-09-10 00:58:46 +000010952 if( zLine[0]=='/' )
10953 zLine += 1; /* Oracle */
10954 else if ( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' )
10955 zLine += 2; /* SQL Server */
10956 else
10957 return 0;
larrybr527c39d2022-05-10 14:55:45 +000010958 return quickscan(zLine, QSS_Start)==QSS_Start;
drh2ce15c32017-07-11 13:34:40 +000010959}
10960
10961/*
drh841c98e2022-11-17 01:24:06 +000010962** The CLI needs a working sqlite3_complete() to work properly. So error
10963** out of the build if compiling with SQLITE_OMIT_COMPLETE.
drh56f17742018-01-24 01:58:49 +000010964*/
10965#ifdef SQLITE_OMIT_COMPLETE
drh841c98e2022-11-17 01:24:06 +000010966# error the CLI application is imcompatable with SQLITE_OMIT_COMPLETE.
drh56f17742018-01-24 01:58:49 +000010967#endif
10968
10969/*
drh2ce15c32017-07-11 13:34:40 +000010970** Return true if zSql is a complete SQL statement. Return false if it
10971** ends in the middle of a string literal or C-style comment.
10972*/
10973static int line_is_complete(char *zSql, int nSql){
10974 int rc;
10975 if( zSql==0 ) return 1;
10976 zSql[nSql] = ';';
10977 zSql[nSql+1] = 0;
10978 rc = sqlite3_complete(zSql);
10979 zSql[nSql] = 0;
10980 return rc;
10981}
10982
10983/*
drhfc29a862018-05-11 19:11:18 +000010984** Run a single line of SQL. Return the number of errors.
drh2ce15c32017-07-11 13:34:40 +000010985*/
10986static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
10987 int rc;
10988 char *zErrMsg = 0;
10989
10990 open_db(p, 0);
10991 if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
drhfc4eeef2019-02-05 19:48:46 +000010992 if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
drh2ce15c32017-07-11 13:34:40 +000010993 BEGIN_TIMER;
drha10b9992018-03-09 15:24:33 +000010994 rc = shell_exec(p, zSql, &zErrMsg);
drh2ce15c32017-07-11 13:34:40 +000010995 END_TIMER;
10996 if( rc || zErrMsg ){
10997 char zPrefix[100];
drh3e46db22022-02-08 11:52:45 +000010998 const char *zErrorTail;
10999 const char *zErrorType;
11000 if( zErrMsg==0 ){
11001 zErrorType = "Error";
11002 zErrorTail = sqlite3_errmsg(p->db);
drhbf70f1b2022-10-19 18:04:42 +000011003 }else if( cli_strncmp(zErrMsg, "in prepare, ",12)==0 ){
drh3e46db22022-02-08 11:52:45 +000011004 zErrorType = "Parse error";
11005 zErrorTail = &zErrMsg[12];
drhbf70f1b2022-10-19 18:04:42 +000011006 }else if( cli_strncmp(zErrMsg, "stepping, ", 10)==0 ){
drh3e46db22022-02-08 11:52:45 +000011007 zErrorType = "Runtime error";
11008 zErrorTail = &zErrMsg[10];
11009 }else{
11010 zErrorType = "Error";
11011 zErrorTail = zErrMsg;
11012 }
drh2ce15c32017-07-11 13:34:40 +000011013 if( in!=0 || !stdin_is_interactive ){
11014 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
drh3e46db22022-02-08 11:52:45 +000011015 "%s near line %d:", zErrorType, startline);
drh2ce15c32017-07-11 13:34:40 +000011016 }else{
drh3e46db22022-02-08 11:52:45 +000011017 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType);
drh2ce15c32017-07-11 13:34:40 +000011018 }
drh3e46db22022-02-08 11:52:45 +000011019 utf8_printf(stderr, "%s %s\n", zPrefix, zErrorTail);
11020 sqlite3_free(zErrMsg);
11021 zErrMsg = 0;
drh2ce15c32017-07-11 13:34:40 +000011022 return 1;
11023 }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
drh6d9f0342021-09-22 10:28:50 +000011024 char zLineBuf[2000];
11025 sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
11026 "changes: %lld total_changes: %lld",
larrybr10496f72021-06-23 16:07:20 +000011027 sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
drh6d9f0342021-09-22 10:28:50 +000011028 raw_printf(p->out, "%s\n", zLineBuf);
drh2ce15c32017-07-11 13:34:40 +000011029 }
11030 return 0;
11031}
11032
larrybrf4874812022-05-11 19:59:31 +000011033static void echo_group_input(ShellState *p, const char *zDo){
11034 if( ShellHasFlag(p, SHFLG_Echo) ) utf8_printf(p->out, "%s\n", zDo);
11035}
drh2ce15c32017-07-11 13:34:40 +000011036
stephan4413ec72022-07-12 15:53:02 +000011037#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +000011038/*
11039** Alternate one_input_line() impl for wasm mode. This is not in the primary impl
11040** because we need the global shellState and cannot access it from that function
11041** without moving lots of code around (creating a larger/messier diff).
11042*/
11043static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
11044 /* Parse the next line from shellState.wasm.zInput. */
11045 const char *zBegin = shellState.wasm.zPos;
11046 const char *z = zBegin;
11047 char *zLine = 0;
drh7d23d152022-10-11 12:02:42 +000011048 i64 nZ = 0;
stephanf8cd3d22022-05-18 17:14:24 +000011049
11050 UNUSED_PARAMETER(in);
11051 UNUSED_PARAMETER(isContinuation);
11052 if(!z || !*z){
11053 return 0;
11054 }
11055 while(*z && isspace(*z)) ++z;
11056 zBegin = z;
11057 for(; *z && '\n'!=*z; ++nZ, ++z){}
11058 if(nZ>0 && '\r'==zBegin[nZ-1]){
11059 --nZ;
11060 }
11061 shellState.wasm.zPos = z;
11062 zLine = realloc(zPrior, nZ+1);
11063 shell_check_oom(zLine);
drh7d23d152022-10-11 12:02:42 +000011064 memcpy(zLine, zBegin, nZ);
stephanf8cd3d22022-05-18 17:14:24 +000011065 zLine[nZ] = 0;
11066 return zLine;
11067}
stephan4413ec72022-07-12 15:53:02 +000011068#endif /* SQLITE_SHELL_FIDDLE */
stephanf8cd3d22022-05-18 17:14:24 +000011069
drh2ce15c32017-07-11 13:34:40 +000011070/*
11071** Read input from *in and process it. If *in==0 then input
11072** is interactive - the user is typing it it. Otherwise, input
11073** is coming from a file or device. A prompt is issued and history
11074** is saved only if input is interactive. An interrupt signal will
11075** cause this routine to exit immediately, unless input is interactive.
11076**
11077** Return the number of errors.
11078*/
drh60379d42018-12-13 18:30:01 +000011079static int process_input(ShellState *p){
drh2ce15c32017-07-11 13:34:40 +000011080 char *zLine = 0; /* A single input line */
11081 char *zSql = 0; /* Accumulated SQL text */
drh7d23d152022-10-11 12:02:42 +000011082 i64 nLine; /* Length of current line */
11083 i64 nSql = 0; /* Bytes of zSql[] used */
11084 i64 nAlloc = 0; /* Allocated zSql[] space */
drh2ce15c32017-07-11 13:34:40 +000011085 int rc; /* Error code */
11086 int errCnt = 0; /* Number of errors seen */
drh7d23d152022-10-11 12:02:42 +000011087 i64 startline = 0; /* Line number for start of current input */
larrybr7e009842021-09-18 21:35:22 +000011088 QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
drh2ce15c32017-07-11 13:34:40 +000011089
larrybrd48e88e2022-01-24 06:36:16 +000011090 if( p->inputNesting==MAX_INPUT_NESTING ){
11091 /* This will be more informative in a later version. */
11092 utf8_printf(stderr,"Input nesting limit (%d) reached at line %d."
11093 " Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
11094 return 1;
11095 }
11096 ++p->inputNesting;
drh2c8ee022018-12-13 18:59:30 +000011097 p->lineno = 0;
drh60379d42018-12-13 18:30:01 +000011098 while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
drh2ce15c32017-07-11 13:34:40 +000011099 fflush(p->out);
drh60379d42018-12-13 18:30:01 +000011100 zLine = one_input_line(p->in, zLine, nSql>0);
drh2ce15c32017-07-11 13:34:40 +000011101 if( zLine==0 ){
11102 /* End of input */
drh60379d42018-12-13 18:30:01 +000011103 if( p->in==0 && stdin_is_interactive ) printf("\n");
drh2ce15c32017-07-11 13:34:40 +000011104 break;
11105 }
11106 if( seenInterrupt ){
drh60379d42018-12-13 18:30:01 +000011107 if( p->in!=0 ) break;
drh2ce15c32017-07-11 13:34:40 +000011108 seenInterrupt = 0;
11109 }
drh2c8ee022018-12-13 18:59:30 +000011110 p->lineno++;
larrybr7e009842021-09-18 21:35:22 +000011111 if( QSS_INPLAIN(qss)
larrybr8bc4cbc2021-09-10 00:58:46 +000011112 && line_is_command_terminator(zLine)
11113 && line_is_complete(zSql, nSql) ){
11114 memcpy(zLine,";",2);
11115 }
11116 qss = quickscan(zLine, qss);
11117 if( QSS_PLAINWHITE(qss) && nSql==0 ){
larrybrd797d6b2021-10-03 22:03:59 +000011118 /* Just swallow single-line whitespace */
larrybrf4874812022-05-11 19:59:31 +000011119 echo_group_input(p, zLine);
larrybrd797d6b2021-10-03 22:03:59 +000011120 qss = QSS_Start;
larrybr8bc4cbc2021-09-10 00:58:46 +000011121 continue;
drh2ce15c32017-07-11 13:34:40 +000011122 }
drh1615c372018-05-12 23:56:22 +000011123 if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){
larrybrf4874812022-05-11 19:59:31 +000011124 echo_group_input(p, zLine);
drh1615c372018-05-12 23:56:22 +000011125 if( zLine[0]=='.' ){
11126 rc = do_meta_command(zLine, p);
11127 if( rc==2 ){ /* exit requested */
11128 break;
11129 }else if( rc ){
11130 errCnt++;
11131 }
drh2ce15c32017-07-11 13:34:40 +000011132 }
larrybr81012162021-10-02 15:34:52 +000011133 qss = QSS_Start;
drh2ce15c32017-07-11 13:34:40 +000011134 continue;
11135 }
larrybrd797d6b2021-10-03 22:03:59 +000011136 /* No single-line dispositions remain; accumulate line(s). */
drh7d23d152022-10-11 12:02:42 +000011137 nLine = strlen(zLine);
drh2ce15c32017-07-11 13:34:40 +000011138 if( nSql+nLine+2>=nAlloc ){
larrybr31bffb42021-09-08 21:49:03 +000011139 /* Grow buffer by half-again increments when big. */
11140 nAlloc = nSql+(nSql>>1)+nLine+100;
drh2ce15c32017-07-11 13:34:40 +000011141 zSql = realloc(zSql, nAlloc);
drhe3e25652021-12-16 13:29:28 +000011142 shell_check_oom(zSql);
drh2ce15c32017-07-11 13:34:40 +000011143 }
drh2ce15c32017-07-11 13:34:40 +000011144 if( nSql==0 ){
drh7d23d152022-10-11 12:02:42 +000011145 i64 i;
drh2ce15c32017-07-11 13:34:40 +000011146 for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
11147 assert( nAlloc>0 && zSql!=0 );
11148 memcpy(zSql, zLine+i, nLine+1-i);
drh2c8ee022018-12-13 18:59:30 +000011149 startline = p->lineno;
drh2ce15c32017-07-11 13:34:40 +000011150 nSql = nLine-i;
11151 }else{
11152 zSql[nSql++] = '\n';
11153 memcpy(zSql+nSql, zLine, nLine+1);
11154 nSql += nLine;
11155 }
larrybra96bbe92021-09-10 19:45:22 +000011156 if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){
larrybrf4874812022-05-11 19:59:31 +000011157 echo_group_input(p, zSql);
drh60379d42018-12-13 18:30:01 +000011158 errCnt += runOneSqlLine(p, zSql, p->in, startline);
drh2ce15c32017-07-11 13:34:40 +000011159 nSql = 0;
11160 if( p->outCount ){
11161 output_reset(p);
11162 p->outCount = 0;
drh13c20932018-01-10 21:41:55 +000011163 }else{
11164 clearTempFile(p);
drh2ce15c32017-07-11 13:34:40 +000011165 }
drhb97e2ad2021-08-26 18:31:39 +000011166 p->bSafeMode = p->bSafeModePersist;
larrybrd797d6b2021-10-03 22:03:59 +000011167 qss = QSS_Start;
larrybr8bc4cbc2021-09-10 00:58:46 +000011168 }else if( nSql && QSS_PLAINWHITE(qss) ){
larrybrf4874812022-05-11 19:59:31 +000011169 echo_group_input(p, zSql);
drh2ce15c32017-07-11 13:34:40 +000011170 nSql = 0;
larrybrd797d6b2021-10-03 22:03:59 +000011171 qss = QSS_Start;
drh2ce15c32017-07-11 13:34:40 +000011172 }
11173 }
larrybrc6e2f2e2022-03-15 17:57:42 +000011174 if( nSql ){
11175 /* This may be incomplete. Let the SQL parser deal with that. */
larrybrf4874812022-05-11 19:59:31 +000011176 echo_group_input(p, zSql);
drh60379d42018-12-13 18:30:01 +000011177 errCnt += runOneSqlLine(p, zSql, p->in, startline);
drh2ce15c32017-07-11 13:34:40 +000011178 }
11179 free(zSql);
11180 free(zLine);
larrybrd48e88e2022-01-24 06:36:16 +000011181 --p->inputNesting;
drh2ce15c32017-07-11 13:34:40 +000011182 return errCnt>0;
11183}
11184
11185/*
11186** Return a pathname which is the user's home directory. A
11187** 0 return indicates an error of some kind.
11188*/
11189static char *find_home_dir(int clearFlag){
11190 static char *home_dir = NULL;
11191 if( clearFlag ){
11192 free(home_dir);
11193 home_dir = 0;
11194 return 0;
11195 }
11196 if( home_dir ) return home_dir;
11197
11198#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
11199 && !defined(__RTP__) && !defined(_WRS_KERNEL)
11200 {
11201 struct passwd *pwent;
11202 uid_t uid = getuid();
11203 if( (pwent=getpwuid(uid)) != NULL) {
11204 home_dir = pwent->pw_dir;
11205 }
11206 }
11207#endif
11208
11209#if defined(_WIN32_WCE)
11210 /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
11211 */
11212 home_dir = "/";
11213#else
11214
11215#if defined(_WIN32) || defined(WIN32)
11216 if (!home_dir) {
11217 home_dir = getenv("USERPROFILE");
11218 }
11219#endif
11220
11221 if (!home_dir) {
11222 home_dir = getenv("HOME");
11223 }
11224
11225#if defined(_WIN32) || defined(WIN32)
11226 if (!home_dir) {
11227 char *zDrive, *zPath;
11228 int n;
11229 zDrive = getenv("HOMEDRIVE");
11230 zPath = getenv("HOMEPATH");
11231 if( zDrive && zPath ){
11232 n = strlen30(zDrive) + strlen30(zPath) + 1;
11233 home_dir = malloc( n );
11234 if( home_dir==0 ) return 0;
11235 sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
11236 return home_dir;
11237 }
11238 home_dir = "c:\\";
11239 }
11240#endif
11241
11242#endif /* !_WIN32_WCE */
11243
11244 if( home_dir ){
drh7d23d152022-10-11 12:02:42 +000011245 i64 n = strlen(home_dir) + 1;
drh2ce15c32017-07-11 13:34:40 +000011246 char *z = malloc( n );
11247 if( z ) memcpy(z, home_dir, n);
11248 home_dir = z;
11249 }
11250
11251 return home_dir;
11252}
11253
11254/*
11255** Read input from the file given by sqliterc_override. Or if that
11256** parameter is NULL, take input from ~/.sqliterc
11257**
11258** Returns the number of errors.
11259*/
11260static void process_sqliterc(
11261 ShellState *p, /* Configuration data */
11262 const char *sqliterc_override /* Name of config file. NULL to use default */
11263){
11264 char *home_dir = NULL;
11265 const char *sqliterc = sqliterc_override;
11266 char *zBuf = 0;
drh60379d42018-12-13 18:30:01 +000011267 FILE *inSaved = p->in;
drh2c8ee022018-12-13 18:59:30 +000011268 int savedLineno = p->lineno;
drh2ce15c32017-07-11 13:34:40 +000011269
11270 if (sqliterc == NULL) {
11271 home_dir = find_home_dir(0);
11272 if( home_dir==0 ){
11273 raw_printf(stderr, "-- warning: cannot find home directory;"
11274 " cannot read ~/.sqliterc\n");
11275 return;
11276 }
drh2ce15c32017-07-11 13:34:40 +000011277 zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
drhe3e25652021-12-16 13:29:28 +000011278 shell_check_oom(zBuf);
drh2ce15c32017-07-11 13:34:40 +000011279 sqliterc = zBuf;
11280 }
drh60379d42018-12-13 18:30:01 +000011281 p->in = fopen(sqliterc,"rb");
11282 if( p->in ){
drh2ce15c32017-07-11 13:34:40 +000011283 if( stdin_is_interactive ){
11284 utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
11285 }
drhb7c46aa2020-11-25 13:59:47 +000011286 if( process_input(p) && bail_on_error ) exit(1);
drh60379d42018-12-13 18:30:01 +000011287 fclose(p->in);
drhb7c46aa2020-11-25 13:59:47 +000011288 }else if( sqliterc_override!=0 ){
11289 utf8_printf(stderr,"cannot open: \"%s\"\n", sqliterc);
11290 if( bail_on_error ) exit(1);
drh2ce15c32017-07-11 13:34:40 +000011291 }
drh60379d42018-12-13 18:30:01 +000011292 p->in = inSaved;
drh2c8ee022018-12-13 18:59:30 +000011293 p->lineno = savedLineno;
drh2ce15c32017-07-11 13:34:40 +000011294 sqlite3_free(zBuf);
11295}
11296
11297/*
11298** Show available command line options
11299*/
11300static const char zOptions[] =
drhda57d962018-03-05 19:34:05 +000011301#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
drhad7fd5d2018-03-05 20:21:50 +000011302 " -A ARGS... run \".archive ARGS\" and exit\n"
drhda57d962018-03-05 19:34:05 +000011303#endif
drh3baed312018-03-08 18:14:41 +000011304 " -append append the database to the end of the file\n"
drh2ce15c32017-07-11 13:34:40 +000011305 " -ascii set output mode to 'ascii'\n"
11306 " -bail stop after hitting an error\n"
11307 " -batch force batch I/O\n"
drh0908e382020-06-04 18:05:39 +000011308 " -box set output mode to 'box'\n"
drh2ce15c32017-07-11 13:34:40 +000011309 " -column set output mode to 'column'\n"
11310 " -cmd COMMAND run \"COMMAND\" before reading stdin\n"
11311 " -csv set output mode to 'csv'\n"
drh8d889af2021-05-08 17:18:23 +000011312#if !defined(SQLITE_OMIT_DESERIALIZE)
drh6ca64482019-01-22 16:06:20 +000011313 " -deserialize open the database using sqlite3_deserialize()\n"
11314#endif
larrybr527c39d2022-05-10 14:55:45 +000011315 " -echo print inputs before execution\n"
drh2ce15c32017-07-11 13:34:40 +000011316 " -init FILENAME read/process named file\n"
11317 " -[no]header turn headers on or off\n"
11318#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
11319 " -heap SIZE Size of heap for memsys3 or memsys5\n"
11320#endif
11321 " -help show this message\n"
11322 " -html set output mode to HTML\n"
11323 " -interactive force interactive I/O\n"
drh30c54a02020-05-28 23:49:50 +000011324 " -json set output mode to 'json'\n"
drh2ce15c32017-07-11 13:34:40 +000011325 " -line set output mode to 'line'\n"
11326 " -list set output mode to 'list'\n"
11327 " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
drh30c54a02020-05-28 23:49:50 +000011328 " -markdown set output mode to 'markdown'\n"
drh8d889af2021-05-08 17:18:23 +000011329#if !defined(SQLITE_OMIT_DESERIALIZE)
drh6ca64482019-01-22 16:06:20 +000011330 " -maxsize N maximum size for a --deserialize database\n"
11331#endif
drhaf482572019-02-04 19:52:39 +000011332 " -memtrace trace all memory allocations and deallocations\n"
drh2ce15c32017-07-11 13:34:40 +000011333 " -mmap N default mmap size set to N\n"
11334#ifdef SQLITE_ENABLE_MULTIPLEX
11335 " -multiplex enable the multiplexor VFS\n"
11336#endif
11337 " -newline SEP set output row separator. Default: '\\n'\n"
drh0933aad2019-11-18 17:46:38 +000011338 " -nofollow refuse to open symbolic links to database files\n"
drhb97e2ad2021-08-26 18:31:39 +000011339 " -nonce STRING set the safe-mode escape nonce\n"
drh2ce15c32017-07-11 13:34:40 +000011340 " -nullvalue TEXT set text string for NULL values. Default ''\n"
11341 " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
11342 " -quote set output mode to 'quote'\n"
drhee269a62018-02-14 23:27:43 +000011343 " -readonly open the database read-only\n"
drhb97e2ad2021-08-26 18:31:39 +000011344 " -safe enable safe-mode\n"
drh2ce15c32017-07-11 13:34:40 +000011345 " -separator SEP set output column separator. Default: '|'\n"
drha90d84f2018-04-18 15:21:13 +000011346#ifdef SQLITE_ENABLE_SORTER_REFERENCES
11347 " -sorterref SIZE sorter references threshold size\n"
11348#endif
drh2ce15c32017-07-11 13:34:40 +000011349 " -stats print memory stats before each finalize\n"
drh30c54a02020-05-28 23:49:50 +000011350 " -table set output mode to 'table'\n"
drh2fa78182020-10-31 18:58:37 +000011351 " -tabs set output mode to 'tabs'\n"
drh2ce15c32017-07-11 13:34:40 +000011352 " -version show SQLite version\n"
11353 " -vfs NAME use NAME as the default VFS\n"
11354#ifdef SQLITE_ENABLE_VFSTRACE
11355 " -vfstrace enable tracing of all VFS calls\n"
11356#endif
drh3baed312018-03-08 18:14:41 +000011357#ifdef SQLITE_HAVE_ZLIB
11358 " -zip open the file as a ZIP Archive\n"
11359#endif
drh2ce15c32017-07-11 13:34:40 +000011360;
11361static void usage(int showDetail){
11362 utf8_printf(stderr,
11363 "Usage: %s [OPTIONS] FILENAME [SQL]\n"
11364 "FILENAME is the name of an SQLite database. A new database is created\n"
11365 "if the file does not previously exist.\n", Argv0);
11366 if( showDetail ){
11367 utf8_printf(stderr, "OPTIONS include:\n%s", zOptions);
11368 }else{
11369 raw_printf(stderr, "Use the -help option for additional information\n");
11370 }
11371 exit(1);
11372}
11373
11374/*
drhe7df8922018-04-18 10:44:58 +000011375** Internal check: Verify that the SQLite is uninitialized. Print a
11376** error message if it is initialized.
11377*/
11378static void verify_uninitialized(void){
11379 if( sqlite3_config(-1)==SQLITE_MISUSE ){
drh8e02a182018-05-30 07:24:41 +000011380 utf8_printf(stdout, "WARNING: attempt to configure SQLite after"
drhe7df8922018-04-18 10:44:58 +000011381 " initialization.\n");
11382 }
11383}
11384
11385/*
drh2ce15c32017-07-11 13:34:40 +000011386** Initialize the state information in data
11387*/
11388static void main_init(ShellState *data) {
11389 memset(data, 0, sizeof(*data));
11390 data->normalMode = data->cMode = data->mode = MODE_List;
11391 data->autoExplain = 1;
drh37407122021-07-23 18:43:58 +000011392 data->pAuxDb = &data->aAuxDb[0];
drh2ce15c32017-07-11 13:34:40 +000011393 memcpy(data->colSeparator,SEP_Column, 2);
11394 memcpy(data->rowSeparator,SEP_Row, 2);
11395 data->showHeader = 0;
11396 data->shellFlgs = SHFLG_Lookaside;
drhe7df8922018-04-18 10:44:58 +000011397 verify_uninitialized();
drh2ce15c32017-07-11 13:34:40 +000011398 sqlite3_config(SQLITE_CONFIG_URI, 1);
11399 sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
11400 sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
11401 sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
11402 sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
11403}
11404
11405/*
11406** Output text to the console in a font that attracts extra attention.
11407*/
11408#ifdef _WIN32
11409static void printBold(const char *zText){
mistachkin43e86272020-04-09 15:31:22 +000011410#if !SQLITE_OS_WINRT
drh2ce15c32017-07-11 13:34:40 +000011411 HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
11412 CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
11413 GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
11414 SetConsoleTextAttribute(out,
11415 FOREGROUND_RED|FOREGROUND_INTENSITY
11416 );
mistachkin43e86272020-04-09 15:31:22 +000011417#endif
drh2ce15c32017-07-11 13:34:40 +000011418 printf("%s", zText);
mistachkin43e86272020-04-09 15:31:22 +000011419#if !SQLITE_OS_WINRT
drh2ce15c32017-07-11 13:34:40 +000011420 SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
mistachkin43e86272020-04-09 15:31:22 +000011421#endif
drh2ce15c32017-07-11 13:34:40 +000011422}
11423#else
11424static void printBold(const char *zText){
11425 printf("\033[1m%s\033[0m", zText);
11426}
11427#endif
11428
11429/*
11430** Get the argument to an --option. Throw an error and die if no argument
11431** is available.
11432*/
11433static char *cmdline_option_value(int argc, char **argv, int i){
11434 if( i==argc ){
11435 utf8_printf(stderr, "%s: Error: missing argument to %s\n",
11436 argv[0], argv[argc-1]);
11437 exit(1);
11438 }
11439 return argv[i];
11440}
11441
11442#ifndef SQLITE_SHELL_IS_UTF8
dan39b6bd52021-03-04 18:31:07 +000011443# if (defined(_WIN32) || defined(WIN32)) \
11444 && (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
drh2ce15c32017-07-11 13:34:40 +000011445# define SQLITE_SHELL_IS_UTF8 (0)
11446# else
11447# define SQLITE_SHELL_IS_UTF8 (1)
11448# endif
11449#endif
11450
stephan4413ec72022-07-12 15:53:02 +000011451#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +000011452# define main fiddle_main
11453#endif
11454
drh2ce15c32017-07-11 13:34:40 +000011455#if SQLITE_SHELL_IS_UTF8
11456int SQLITE_CDECL main(int argc, char **argv){
11457#else
11458int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
11459 char **argv;
11460#endif
larrybrfa5dfa82022-05-07 03:53:14 +000011461#ifdef SQLITE_DEBUG
mistachkin07fae322022-07-06 23:50:01 +000011462 sqlite3_int64 mem_main_enter = sqlite3_memory_used();
larrybrfa5dfa82022-05-07 03:53:14 +000011463#endif
drh2ce15c32017-07-11 13:34:40 +000011464 char *zErrMsg = 0;
stephan4413ec72022-07-12 15:53:02 +000011465#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +000011466# define data shellState
11467#else
drh2ce15c32017-07-11 13:34:40 +000011468 ShellState data;
stephanf8cd3d22022-05-18 17:14:24 +000011469#endif
drh2ce15c32017-07-11 13:34:40 +000011470 const char *zInitFile = 0;
11471 int i;
11472 int rc = 0;
11473 int warnInmemoryDb = 0;
11474 int readStdin = 1;
11475 int nCmd = 0;
11476 char **azCmd = 0;
dan16a47422018-04-18 09:16:11 +000011477 const char *zVfs = 0; /* Value of -vfs command-line option */
drh1f22f622018-05-17 13:29:14 +000011478#if !SQLITE_SHELL_IS_UTF8
11479 char **argvToFree = 0;
11480 int argcToFree = 0;
11481#endif
drh2ce15c32017-07-11 13:34:40 +000011482
11483 setBinaryMode(stdin, 0);
11484 setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
stephan4413ec72022-07-12 15:53:02 +000011485#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +000011486 stdin_is_interactive = 0;
11487 stdout_is_console = 1;
stephan60d9aa72022-09-24 07:36:45 +000011488 data.wasm.zDefaultDbName = "/fiddle.sqlite3";
stephanf8cd3d22022-05-18 17:14:24 +000011489#else
drh2ce15c32017-07-11 13:34:40 +000011490 stdin_is_interactive = isatty(0);
11491 stdout_is_console = isatty(1);
stephanf8cd3d22022-05-18 17:14:24 +000011492#endif
drh2ce15c32017-07-11 13:34:40 +000011493
mistachkin1e8487d2018-07-22 06:25:35 +000011494#if !defined(_WIN32_WCE)
11495 if( getenv("SQLITE_DEBUG_BREAK") ){
11496 if( isatty(0) && isatty(2) ){
11497 fprintf(stderr,
11498 "attach debugger to process %d and press any key to continue.\n",
11499 GETPID());
11500 fgetc(stdin);
11501 }else{
11502#if defined(_WIN32) || defined(WIN32)
mistachkin43e86272020-04-09 15:31:22 +000011503#if SQLITE_OS_WINRT
11504 __debugbreak();
11505#else
mistachkin1e8487d2018-07-22 06:25:35 +000011506 DebugBreak();
mistachkin43e86272020-04-09 15:31:22 +000011507#endif
mistachkin1e8487d2018-07-22 06:25:35 +000011508#elif defined(SIGTRAP)
11509 raise(SIGTRAP);
11510#endif
11511 }
11512 }
11513#endif
11514
drh2ce15c32017-07-11 13:34:40 +000011515#if USE_SYSTEM_SQLITE+0!=1
drhbf70f1b2022-10-19 18:04:42 +000011516 if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
drh2ce15c32017-07-11 13:34:40 +000011517 utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
11518 sqlite3_sourceid(), SQLITE_SOURCE_ID);
11519 exit(1);
11520 }
11521#endif
11522 main_init(&data);
drh501ea052018-02-15 01:03:37 +000011523
11524 /* On Windows, we must translate command-line arguments into UTF-8.
11525 ** The SQLite memory allocator subsystem has to be enabled in order to
11526 ** do this. But we want to run an sqlite3_shutdown() afterwards so that
11527 ** subsequent sqlite3_config() calls will work. So copy all results into
11528 ** memory that does not come from the SQLite memory allocator.
11529 */
drh4b18c1d2018-02-04 20:33:13 +000011530#if !SQLITE_SHELL_IS_UTF8
drh501ea052018-02-15 01:03:37 +000011531 sqlite3_initialize();
drh1f22f622018-05-17 13:29:14 +000011532 argvToFree = malloc(sizeof(argv[0])*argc*2);
drhe3e25652021-12-16 13:29:28 +000011533 shell_check_oom(argvToFree);
drh1f22f622018-05-17 13:29:14 +000011534 argcToFree = argc;
11535 argv = argvToFree + argc;
drh2ce15c32017-07-11 13:34:40 +000011536 for(i=0; i<argc; i++){
drh501ea052018-02-15 01:03:37 +000011537 char *z = sqlite3_win32_unicode_to_utf8(wargv[i]);
drh7d23d152022-10-11 12:02:42 +000011538 i64 n;
drhe3e25652021-12-16 13:29:28 +000011539 shell_check_oom(z);
drh7d23d152022-10-11 12:02:42 +000011540 n = strlen(z);
drh501ea052018-02-15 01:03:37 +000011541 argv[i] = malloc( n+1 );
drhe3e25652021-12-16 13:29:28 +000011542 shell_check_oom(argv[i]);
drh501ea052018-02-15 01:03:37 +000011543 memcpy(argv[i], z, n+1);
drh1f22f622018-05-17 13:29:14 +000011544 argvToFree[i] = argv[i];
drh501ea052018-02-15 01:03:37 +000011545 sqlite3_free(z);
drh2ce15c32017-07-11 13:34:40 +000011546 }
drh501ea052018-02-15 01:03:37 +000011547 sqlite3_shutdown();
drh2ce15c32017-07-11 13:34:40 +000011548#endif
drh501ea052018-02-15 01:03:37 +000011549
drh2ce15c32017-07-11 13:34:40 +000011550 assert( argc>=1 && argv && argv[0] );
11551 Argv0 = argv[0];
11552
11553 /* Make sure we have a valid signal handler early, before anything
11554 ** else is done.
11555 */
11556#ifdef SIGINT
11557 signal(SIGINT, interrupt_handler);
mistachkinb4bab902017-10-27 17:09:44 +000011558#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
11559 SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
drh2ce15c32017-07-11 13:34:40 +000011560#endif
11561
11562#ifdef SQLITE_SHELL_DBNAME_PROC
11563 {
11564 /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
11565 ** of a C-function that will provide the name of the database file. Use
11566 ** this compile-time option to embed this shell program in larger
11567 ** applications. */
11568 extern void SQLITE_SHELL_DBNAME_PROC(const char**);
drh37407122021-07-23 18:43:58 +000011569 SQLITE_SHELL_DBNAME_PROC(&data.pAuxDb->zDbFilename);
drh2ce15c32017-07-11 13:34:40 +000011570 warnInmemoryDb = 0;
11571 }
11572#endif
11573
11574 /* Do an initial pass through the command-line argument to locate
11575 ** the name of the database file, the name of the initialization file,
11576 ** the size of the alternative malloc heap,
11577 ** and the first command to execute.
11578 */
drhe7df8922018-04-18 10:44:58 +000011579 verify_uninitialized();
drh2ce15c32017-07-11 13:34:40 +000011580 for(i=1; i<argc; i++){
11581 char *z;
11582 z = argv[i];
11583 if( z[0]!='-' ){
drh37407122021-07-23 18:43:58 +000011584 if( data.aAuxDb->zDbFilename==0 ){
11585 data.aAuxDb->zDbFilename = z;
drh2ce15c32017-07-11 13:34:40 +000011586 }else{
11587 /* Excesss arguments are interpreted as SQL (or dot-commands) and
11588 ** mean that nothing is read from stdin */
11589 readStdin = 0;
11590 nCmd++;
11591 azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
drhe3e25652021-12-16 13:29:28 +000011592 shell_check_oom(azCmd);
drh2ce15c32017-07-11 13:34:40 +000011593 azCmd[nCmd-1] = z;
11594 }
11595 }
11596 if( z[1]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +000011597 if( cli_strcmp(z,"-separator")==0
11598 || cli_strcmp(z,"-nullvalue")==0
11599 || cli_strcmp(z,"-newline")==0
11600 || cli_strcmp(z,"-cmd")==0
drh2ce15c32017-07-11 13:34:40 +000011601 ){
11602 (void)cmdline_option_value(argc, argv, ++i);
drhbf70f1b2022-10-19 18:04:42 +000011603 }else if( cli_strcmp(z,"-init")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011604 zInitFile = cmdline_option_value(argc, argv, ++i);
drhbf70f1b2022-10-19 18:04:42 +000011605 }else if( cli_strcmp(z,"-batch")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011606 /* Need to check for batch mode here to so we can avoid printing
11607 ** informational messages (like from process_sqliterc) before
11608 ** we do the actual processing of arguments later in a second pass.
11609 */
11610 stdin_is_interactive = 0;
drhbf70f1b2022-10-19 18:04:42 +000011611 }else if( cli_strcmp(z,"-heap")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011612#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
11613 const char *zSize;
11614 sqlite3_int64 szHeap;
11615
11616 zSize = cmdline_option_value(argc, argv, ++i);
11617 szHeap = integerValue(zSize);
11618 if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
11619 sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
11620#else
11621 (void)cmdline_option_value(argc, argv, ++i);
11622#endif
drhbf70f1b2022-10-19 18:04:42 +000011623 }else if( cli_strcmp(z,"-pagecache")==0 ){
drhf573b4f2020-09-28 13:34:05 +000011624 sqlite3_int64 n, sz;
11625 sz = integerValue(cmdline_option_value(argc,argv,++i));
drh2ce15c32017-07-11 13:34:40 +000011626 if( sz>70000 ) sz = 70000;
11627 if( sz<0 ) sz = 0;
drhf573b4f2020-09-28 13:34:05 +000011628 n = integerValue(cmdline_option_value(argc,argv,++i));
11629 if( sz>0 && n>0 && 0xffffffffffffLL/sz<n ){
11630 n = 0xffffffffffffLL/sz;
11631 }
drh2ce15c32017-07-11 13:34:40 +000011632 sqlite3_config(SQLITE_CONFIG_PAGECACHE,
11633 (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
11634 data.shellFlgs |= SHFLG_Pagecache;
drhbf70f1b2022-10-19 18:04:42 +000011635 }else if( cli_strcmp(z,"-lookaside")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011636 int n, sz;
11637 sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
11638 if( sz<0 ) sz = 0;
11639 n = (int)integerValue(cmdline_option_value(argc,argv,++i));
11640 if( n<0 ) n = 0;
11641 sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
11642 if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
drhbf70f1b2022-10-19 18:04:42 +000011643 }else if( cli_strcmp(z,"-threadsafe")==0 ){
drh9d16fb12021-08-09 17:45:00 +000011644 int n;
11645 n = (int)integerValue(cmdline_option_value(argc,argv,++i));
11646 switch( n ){
drhaf6d1af2021-08-09 17:37:58 +000011647 case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break;
11648 case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break;
11649 default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break;
11650 }
drh2ce15c32017-07-11 13:34:40 +000011651#ifdef SQLITE_ENABLE_VFSTRACE
drhbf70f1b2022-10-19 18:04:42 +000011652 }else if( cli_strcmp(z,"-vfstrace")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011653 extern int vfstrace_register(
11654 const char *zTraceName,
11655 const char *zOldVfsName,
11656 int (*xOut)(const char*,void*),
11657 void *pOutArg,
11658 int makeDefault
11659 );
11660 vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
11661#endif
11662#ifdef SQLITE_ENABLE_MULTIPLEX
drhbf70f1b2022-10-19 18:04:42 +000011663 }else if( cli_strcmp(z,"-multiplex")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011664 extern int sqlite3_multiple_initialize(const char*,int);
11665 sqlite3_multiplex_initialize(0, 1);
11666#endif
drhbf70f1b2022-10-19 18:04:42 +000011667 }else if( cli_strcmp(z,"-mmap")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011668 sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
11669 sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
drha90d84f2018-04-18 15:21:13 +000011670#ifdef SQLITE_ENABLE_SORTER_REFERENCES
drhbf70f1b2022-10-19 18:04:42 +000011671 }else if( cli_strcmp(z,"-sorterref")==0 ){
drha90d84f2018-04-18 15:21:13 +000011672 sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
11673 sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, (int)sz);
11674#endif
drhbf70f1b2022-10-19 18:04:42 +000011675 }else if( cli_strcmp(z,"-vfs")==0 ){
dan16a47422018-04-18 09:16:11 +000011676 zVfs = cmdline_option_value(argc, argv, ++i);
drh3baed312018-03-08 18:14:41 +000011677#ifdef SQLITE_HAVE_ZLIB
drhbf70f1b2022-10-19 18:04:42 +000011678 }else if( cli_strcmp(z,"-zip")==0 ){
drh8682e122018-01-07 20:38:10 +000011679 data.openMode = SHELL_OPEN_ZIPFILE;
11680#endif
drhbf70f1b2022-10-19 18:04:42 +000011681 }else if( cli_strcmp(z,"-append")==0 ){
drh8682e122018-01-07 20:38:10 +000011682 data.openMode = SHELL_OPEN_APPENDVFS;
drh8d889af2021-05-08 17:18:23 +000011683#ifndef SQLITE_OMIT_DESERIALIZE
drhbf70f1b2022-10-19 18:04:42 +000011684 }else if( cli_strcmp(z,"-deserialize")==0 ){
drh60f34ae2018-10-30 13:19:49 +000011685 data.openMode = SHELL_OPEN_DESERIALIZE;
drhbf70f1b2022-10-19 18:04:42 +000011686 }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){
drh6ca64482019-01-22 16:06:20 +000011687 data.szMax = integerValue(argv[++i]);
drha751f392018-10-30 15:31:22 +000011688#endif
drhbf70f1b2022-10-19 18:04:42 +000011689 }else if( cli_strcmp(z,"-readonly")==0 ){
drhee269a62018-02-14 23:27:43 +000011690 data.openMode = SHELL_OPEN_READONLY;
drhbf70f1b2022-10-19 18:04:42 +000011691 }else if( cli_strcmp(z,"-nofollow")==0 ){
drh0933aad2019-11-18 17:46:38 +000011692 data.openFlags = SQLITE_OPEN_NOFOLLOW;
drhda57d962018-03-05 19:34:05 +000011693#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
drhbf70f1b2022-10-19 18:04:42 +000011694 }else if( cli_strncmp(z, "-A",2)==0 ){
drhda57d962018-03-05 19:34:05 +000011695 /* All remaining command-line arguments are passed to the ".archive"
11696 ** command, so ignore them */
11697 break;
11698#endif
drhbf70f1b2022-10-19 18:04:42 +000011699 }else if( cli_strcmp(z, "-memtrace")==0 ){
drh50b910a2019-01-21 14:55:03 +000011700 sqlite3MemTraceActivate(stderr);
drhbf70f1b2022-10-19 18:04:42 +000011701 }else if( cli_strcmp(z,"-bail")==0 ){
drhb7c46aa2020-11-25 13:59:47 +000011702 bail_on_error = 1;
drhbf70f1b2022-10-19 18:04:42 +000011703 }else if( cli_strcmp(z,"-nonce")==0 ){
drhb97e2ad2021-08-26 18:31:39 +000011704 free(data.zNonce);
11705 data.zNonce = strdup(argv[++i]);
drhbf70f1b2022-10-19 18:04:42 +000011706 }else if( cli_strcmp(z,"-safe")==0 ){
drhb97e2ad2021-08-26 18:31:39 +000011707 /* no-op - catch this on the second pass */
drh2ce15c32017-07-11 13:34:40 +000011708 }
11709 }
drhe7df8922018-04-18 10:44:58 +000011710 verify_uninitialized();
11711
dan16a47422018-04-18 09:16:11 +000011712
drhd11b8f62018-04-25 13:27:07 +000011713#ifdef SQLITE_SHELL_INIT_PROC
11714 {
11715 /* If the SQLITE_SHELL_INIT_PROC macro is defined, then it is the name
11716 ** of a C-function that will perform initialization actions on SQLite that
11717 ** occur just before or after sqlite3_initialize(). Use this compile-time
11718 ** option to embed this shell program in larger applications. */
11719 extern void SQLITE_SHELL_INIT_PROC(void);
11720 SQLITE_SHELL_INIT_PROC();
11721 }
11722#else
dan16a47422018-04-18 09:16:11 +000011723 /* All the sqlite3_config() calls have now been made. So it is safe
11724 ** to call sqlite3_initialize() and process any command line -vfs option. */
11725 sqlite3_initialize();
drhd11b8f62018-04-25 13:27:07 +000011726#endif
11727
dan16a47422018-04-18 09:16:11 +000011728 if( zVfs ){
11729 sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs);
11730 if( pVfs ){
11731 sqlite3_vfs_register(pVfs, 1);
11732 }else{
11733 utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]);
11734 exit(1);
11735 }
11736 }
11737
drh37407122021-07-23 18:43:58 +000011738 if( data.pAuxDb->zDbFilename==0 ){
drh2ce15c32017-07-11 13:34:40 +000011739#ifndef SQLITE_OMIT_MEMORYDB
drh37407122021-07-23 18:43:58 +000011740 data.pAuxDb->zDbFilename = ":memory:";
drh2ce15c32017-07-11 13:34:40 +000011741 warnInmemoryDb = argc==1;
11742#else
11743 utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
11744 return 1;
11745#endif
11746 }
11747 data.out = stdout;
stephan4413ec72022-07-12 15:53:02 +000011748#ifndef SQLITE_SHELL_FIDDLE
drh8682e122018-01-07 20:38:10 +000011749 sqlite3_appendvfs_init(0,0,0);
stephanf8cd3d22022-05-18 17:14:24 +000011750#endif
drh2ce15c32017-07-11 13:34:40 +000011751
11752 /* Go ahead and open the database file if it already exists. If the
11753 ** file does not exist, delay opening it. This prevents empty database
11754 ** files from being created if a user mistypes the database name argument
11755 ** to the sqlite command-line tool.
11756 */
drh37407122021-07-23 18:43:58 +000011757 if( access(data.pAuxDb->zDbFilename, 0)==0 ){
drh2ce15c32017-07-11 13:34:40 +000011758 open_db(&data, 0);
11759 }
11760
11761 /* Process the initialization file if there is one. If no -init option
11762 ** is given on the command line, look for a file named ~/.sqliterc and
11763 ** try to process it.
11764 */
11765 process_sqliterc(&data,zInitFile);
11766
11767 /* Make a second pass through the command-line argument and set
11768 ** options. This second pass is delayed until after the initialization
11769 ** file is processed so that the command-line arguments will override
11770 ** settings in the initialization file.
11771 */
11772 for(i=1; i<argc; i++){
11773 char *z = argv[i];
11774 if( z[0]!='-' ) continue;
11775 if( z[1]=='-' ){ z++; }
drhbf70f1b2022-10-19 18:04:42 +000011776 if( cli_strcmp(z,"-init")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011777 i++;
drhbf70f1b2022-10-19 18:04:42 +000011778 }else if( cli_strcmp(z,"-html")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011779 data.mode = MODE_Html;
drhbf70f1b2022-10-19 18:04:42 +000011780 }else if( cli_strcmp(z,"-list")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011781 data.mode = MODE_List;
drhbf70f1b2022-10-19 18:04:42 +000011782 }else if( cli_strcmp(z,"-quote")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011783 data.mode = MODE_Quote;
drh9191c702020-08-17 09:11:21 +000011784 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Comma);
11785 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +000011786 }else if( cli_strcmp(z,"-line")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011787 data.mode = MODE_Line;
drhbf70f1b2022-10-19 18:04:42 +000011788 }else if( cli_strcmp(z,"-column")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011789 data.mode = MODE_Column;
drhbf70f1b2022-10-19 18:04:42 +000011790 }else if( cli_strcmp(z,"-json")==0 ){
drh30c54a02020-05-28 23:49:50 +000011791 data.mode = MODE_Json;
drhbf70f1b2022-10-19 18:04:42 +000011792 }else if( cli_strcmp(z,"-markdown")==0 ){
drh30c54a02020-05-28 23:49:50 +000011793 data.mode = MODE_Markdown;
drhbf70f1b2022-10-19 18:04:42 +000011794 }else if( cli_strcmp(z,"-table")==0 ){
drh30c54a02020-05-28 23:49:50 +000011795 data.mode = MODE_Table;
drhbf70f1b2022-10-19 18:04:42 +000011796 }else if( cli_strcmp(z,"-box")==0 ){
drh0908e382020-06-04 18:05:39 +000011797 data.mode = MODE_Box;
drhbf70f1b2022-10-19 18:04:42 +000011798 }else if( cli_strcmp(z,"-csv")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011799 data.mode = MODE_Csv;
11800 memcpy(data.colSeparator,",",2);
drh3baed312018-03-08 18:14:41 +000011801#ifdef SQLITE_HAVE_ZLIB
drhbf70f1b2022-10-19 18:04:42 +000011802 }else if( cli_strcmp(z,"-zip")==0 ){
drh1fa6d9f2018-01-06 21:46:01 +000011803 data.openMode = SHELL_OPEN_ZIPFILE;
11804#endif
drhbf70f1b2022-10-19 18:04:42 +000011805 }else if( cli_strcmp(z,"-append")==0 ){
drh1fa6d9f2018-01-06 21:46:01 +000011806 data.openMode = SHELL_OPEN_APPENDVFS;
drh8d889af2021-05-08 17:18:23 +000011807#ifndef SQLITE_OMIT_DESERIALIZE
drhbf70f1b2022-10-19 18:04:42 +000011808 }else if( cli_strcmp(z,"-deserialize")==0 ){
drh60f34ae2018-10-30 13:19:49 +000011809 data.openMode = SHELL_OPEN_DESERIALIZE;
drhbf70f1b2022-10-19 18:04:42 +000011810 }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){
drh6ca64482019-01-22 16:06:20 +000011811 data.szMax = integerValue(argv[++i]);
drha751f392018-10-30 15:31:22 +000011812#endif
drhbf70f1b2022-10-19 18:04:42 +000011813 }else if( cli_strcmp(z,"-readonly")==0 ){
drh4aafe592018-03-23 16:08:30 +000011814 data.openMode = SHELL_OPEN_READONLY;
drhbf70f1b2022-10-19 18:04:42 +000011815 }else if( cli_strcmp(z,"-nofollow")==0 ){
drh0933aad2019-11-18 17:46:38 +000011816 data.openFlags |= SQLITE_OPEN_NOFOLLOW;
drhbf70f1b2022-10-19 18:04:42 +000011817 }else if( cli_strcmp(z,"-ascii")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011818 data.mode = MODE_Ascii;
drh2fa78182020-10-31 18:58:37 +000011819 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Unit);
11820 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Record);
drhbf70f1b2022-10-19 18:04:42 +000011821 }else if( cli_strcmp(z,"-tabs")==0 ){
drh2fa78182020-10-31 18:58:37 +000011822 data.mode = MODE_List;
11823 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Tab);
11824 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +000011825 }else if( cli_strcmp(z,"-separator")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011826 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
11827 "%s",cmdline_option_value(argc,argv,++i));
drhbf70f1b2022-10-19 18:04:42 +000011828 }else if( cli_strcmp(z,"-newline")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011829 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
11830 "%s",cmdline_option_value(argc,argv,++i));
drhbf70f1b2022-10-19 18:04:42 +000011831 }else if( cli_strcmp(z,"-nullvalue")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011832 sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
11833 "%s",cmdline_option_value(argc,argv,++i));
drhbf70f1b2022-10-19 18:04:42 +000011834 }else if( cli_strcmp(z,"-header")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011835 data.showHeader = 1;
larrybrae509122021-09-10 01:45:20 +000011836 ShellSetFlag(&data, SHFLG_HeaderSet);
drhbf70f1b2022-10-19 18:04:42 +000011837 }else if( cli_strcmp(z,"-noheader")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011838 data.showHeader = 0;
larrybrae509122021-09-10 01:45:20 +000011839 ShellSetFlag(&data, SHFLG_HeaderSet);
drhbf70f1b2022-10-19 18:04:42 +000011840 }else if( cli_strcmp(z,"-echo")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011841 ShellSetFlag(&data, SHFLG_Echo);
drhbf70f1b2022-10-19 18:04:42 +000011842 }else if( cli_strcmp(z,"-eqp")==0 ){
drhada70452017-12-21 21:02:27 +000011843 data.autoEQP = AUTOEQP_on;
drhbf70f1b2022-10-19 18:04:42 +000011844 }else if( cli_strcmp(z,"-eqpfull")==0 ){
drhada70452017-12-21 21:02:27 +000011845 data.autoEQP = AUTOEQP_full;
drhbf70f1b2022-10-19 18:04:42 +000011846 }else if( cli_strcmp(z,"-stats")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011847 data.statsOn = 1;
drhbf70f1b2022-10-19 18:04:42 +000011848 }else if( cli_strcmp(z,"-scanstats")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011849 data.scanstatsOn = 1;
drhbf70f1b2022-10-19 18:04:42 +000011850 }else if( cli_strcmp(z,"-backslash")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011851 /* Undocumented command-line option: -backslash
11852 ** Causes C-style backslash escapes to be evaluated in SQL statements
11853 ** prior to sending the SQL into SQLite. Useful for injecting
11854 ** crazy bytes in the middle of SQL statements for testing and debugging.
11855 */
11856 ShellSetFlag(&data, SHFLG_Backslash);
drhbf70f1b2022-10-19 18:04:42 +000011857 }else if( cli_strcmp(z,"-bail")==0 ){
drhb7c46aa2020-11-25 13:59:47 +000011858 /* No-op. The bail_on_error flag should already be set. */
drhbf70f1b2022-10-19 18:04:42 +000011859 }else if( cli_strcmp(z,"-version")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011860 printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
11861 return 0;
drhbf70f1b2022-10-19 18:04:42 +000011862 }else if( cli_strcmp(z,"-interactive")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011863 stdin_is_interactive = 1;
drhbf70f1b2022-10-19 18:04:42 +000011864 }else if( cli_strcmp(z,"-batch")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011865 stdin_is_interactive = 0;
drhbf70f1b2022-10-19 18:04:42 +000011866 }else if( cli_strcmp(z,"-heap")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011867 i++;
drhbf70f1b2022-10-19 18:04:42 +000011868 }else if( cli_strcmp(z,"-pagecache")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011869 i+=2;
drhbf70f1b2022-10-19 18:04:42 +000011870 }else if( cli_strcmp(z,"-lookaside")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011871 i+=2;
drhbf70f1b2022-10-19 18:04:42 +000011872 }else if( cli_strcmp(z,"-threadsafe")==0 ){
drhaf6d1af2021-08-09 17:37:58 +000011873 i+=2;
drhbf70f1b2022-10-19 18:04:42 +000011874 }else if( cli_strcmp(z,"-nonce")==0 ){
drhb97e2ad2021-08-26 18:31:39 +000011875 i += 2;
drhbf70f1b2022-10-19 18:04:42 +000011876 }else if( cli_strcmp(z,"-mmap")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011877 i++;
drhbf70f1b2022-10-19 18:04:42 +000011878 }else if( cli_strcmp(z,"-memtrace")==0 ){
drh50b910a2019-01-21 14:55:03 +000011879 i++;
drha90d84f2018-04-18 15:21:13 +000011880#ifdef SQLITE_ENABLE_SORTER_REFERENCES
drhbf70f1b2022-10-19 18:04:42 +000011881 }else if( cli_strcmp(z,"-sorterref")==0 ){
drha90d84f2018-04-18 15:21:13 +000011882 i++;
11883#endif
drhbf70f1b2022-10-19 18:04:42 +000011884 }else if( cli_strcmp(z,"-vfs")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011885 i++;
11886#ifdef SQLITE_ENABLE_VFSTRACE
drhbf70f1b2022-10-19 18:04:42 +000011887 }else if( cli_strcmp(z,"-vfstrace")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011888 i++;
11889#endif
11890#ifdef SQLITE_ENABLE_MULTIPLEX
drhbf70f1b2022-10-19 18:04:42 +000011891 }else if( cli_strcmp(z,"-multiplex")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011892 i++;
11893#endif
drhbf70f1b2022-10-19 18:04:42 +000011894 }else if( cli_strcmp(z,"-help")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011895 usage(1);
drhbf70f1b2022-10-19 18:04:42 +000011896 }else if( cli_strcmp(z,"-cmd")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011897 /* Run commands that follow -cmd first and separately from commands
11898 ** that simply appear on the command-line. This seems goofy. It would
11899 ** be better if all commands ran in the order that they appear. But
11900 ** we retain the goofy behavior for historical compatibility. */
11901 if( i==argc-1 ) break;
11902 z = cmdline_option_value(argc,argv,++i);
11903 if( z[0]=='.' ){
11904 rc = do_meta_command(z, &data);
11905 if( rc && bail_on_error ) return rc==2 ? 0 : rc;
11906 }else{
11907 open_db(&data, 0);
drha10b9992018-03-09 15:24:33 +000011908 rc = shell_exec(&data, z, &zErrMsg);
drh2ce15c32017-07-11 13:34:40 +000011909 if( zErrMsg!=0 ){
11910 utf8_printf(stderr,"Error: %s\n", zErrMsg);
11911 if( bail_on_error ) return rc!=0 ? rc : 1;
11912 }else if( rc!=0 ){
11913 utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z);
11914 if( bail_on_error ) return rc;
11915 }
11916 }
drhda57d962018-03-05 19:34:05 +000011917#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
drhbf70f1b2022-10-19 18:04:42 +000011918 }else if( cli_strncmp(z, "-A", 2)==0 ){
drhda57d962018-03-05 19:34:05 +000011919 if( nCmd>0 ){
11920 utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands"
11921 " with \"%s\"\n", z);
11922 return 1;
11923 }
drhbe4ccb22018-05-17 20:04:24 +000011924 open_db(&data, OPEN_DB_ZIPFILE);
drh93b77312018-03-05 20:20:22 +000011925 if( z[2] ){
11926 argv[i] = &z[2];
drhd0f9cdc2018-05-17 14:09:06 +000011927 arDotCommand(&data, 1, argv+(i-1), argc-(i-1));
drh93b77312018-03-05 20:20:22 +000011928 }else{
drhd0f9cdc2018-05-17 14:09:06 +000011929 arDotCommand(&data, 1, argv+i, argc-i);
drh93b77312018-03-05 20:20:22 +000011930 }
drhda57d962018-03-05 19:34:05 +000011931 readStdin = 0;
11932 break;
11933#endif
drhbf70f1b2022-10-19 18:04:42 +000011934 }else if( cli_strcmp(z,"-safe")==0 ){
drhb97e2ad2021-08-26 18:31:39 +000011935 data.bSafeMode = data.bSafeModePersist = 1;
drh2ce15c32017-07-11 13:34:40 +000011936 }else{
11937 utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
11938 raw_printf(stderr,"Use -help for a list of options.\n");
11939 return 1;
11940 }
11941 data.cMode = data.mode;
11942 }
11943
11944 if( !readStdin ){
11945 /* Run all arguments that do not begin with '-' as if they were separate
11946 ** command-line inputs, except for the argToSkip argument which contains
11947 ** the database filename.
11948 */
11949 for(i=0; i<nCmd; i++){
11950 if( azCmd[i][0]=='.' ){
11951 rc = do_meta_command(azCmd[i], &data);
danaff1a572020-11-17 21:09:56 +000011952 if( rc ){
11953 free(azCmd);
11954 return rc==2 ? 0 : rc;
11955 }
drh2ce15c32017-07-11 13:34:40 +000011956 }else{
11957 open_db(&data, 0);
drha10b9992018-03-09 15:24:33 +000011958 rc = shell_exec(&data, azCmd[i], &zErrMsg);
danaff1a572020-11-17 21:09:56 +000011959 if( zErrMsg || rc ){
11960 if( zErrMsg!=0 ){
11961 utf8_printf(stderr,"Error: %s\n", zErrMsg);
11962 }else{
11963 utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
11964 }
11965 sqlite3_free(zErrMsg);
11966 free(azCmd);
drh2ce15c32017-07-11 13:34:40 +000011967 return rc!=0 ? rc : 1;
drh2ce15c32017-07-11 13:34:40 +000011968 }
11969 }
11970 }
drh2ce15c32017-07-11 13:34:40 +000011971 }else{
11972 /* Run commands received from standard input
11973 */
11974 if( stdin_is_interactive ){
11975 char *zHome;
drha9e4be32018-10-10 18:56:40 +000011976 char *zHistory;
drh2ce15c32017-07-11 13:34:40 +000011977 int nHistory;
11978 printf(
11979 "SQLite version %s %.19s\n" /*extra-version-info*/
11980 "Enter \".help\" for usage hints.\n",
11981 sqlite3_libversion(), sqlite3_sourceid()
11982 );
11983 if( warnInmemoryDb ){
11984 printf("Connected to a ");
11985 printBold("transient in-memory database");
11986 printf(".\nUse \".open FILENAME\" to reopen on a "
11987 "persistent database.\n");
11988 }
drha9e4be32018-10-10 18:56:40 +000011989 zHistory = getenv("SQLITE_HISTORY");
11990 if( zHistory ){
11991 zHistory = strdup(zHistory);
11992 }else if( (zHome = find_home_dir(0))!=0 ){
drh2ce15c32017-07-11 13:34:40 +000011993 nHistory = strlen30(zHome) + 20;
11994 if( (zHistory = malloc(nHistory))!=0 ){
11995 sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
11996 }
11997 }
11998 if( zHistory ){ shell_read_history(zHistory); }
drh56eb09b2017-07-11 13:59:07 +000011999#if HAVE_READLINE || HAVE_EDITLINE
12000 rl_attempted_completion_function = readline_completion;
12001#elif HAVE_LINENOISE
12002 linenoiseSetCompletionCallback(linenoise_completion);
12003#endif
drh60379d42018-12-13 18:30:01 +000012004 data.in = 0;
12005 rc = process_input(&data);
drh2ce15c32017-07-11 13:34:40 +000012006 if( zHistory ){
drh5a75dd82017-07-18 20:59:40 +000012007 shell_stifle_history(2000);
drh2ce15c32017-07-11 13:34:40 +000012008 shell_write_history(zHistory);
12009 free(zHistory);
12010 }
12011 }else{
drh60379d42018-12-13 18:30:01 +000012012 data.in = stdin;
12013 rc = process_input(&data);
drh2ce15c32017-07-11 13:34:40 +000012014 }
12015 }
stephan4413ec72022-07-12 15:53:02 +000012016#ifndef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +000012017 /* In WASM mode we have to leave the db state in place so that
12018 ** client code can "push" SQL into it after this call returns. */
danaff1a572020-11-17 21:09:56 +000012019 free(azCmd);
drh2ce15c32017-07-11 13:34:40 +000012020 set_table_name(&data, 0);
12021 if( data.db ){
drh37407122021-07-23 18:43:58 +000012022 session_close_all(&data, -1);
drh9e804032018-05-18 17:11:50 +000012023 close_db(data.db);
drh2ce15c32017-07-11 13:34:40 +000012024 }
drh37407122021-07-23 18:43:58 +000012025 for(i=0; i<ArraySize(data.aAuxDb); i++){
12026 sqlite3_free(data.aAuxDb[i].zFreeOnClose);
12027 if( data.aAuxDb[i].db ){
12028 session_close_all(&data, i);
12029 close_db(data.aAuxDb[i].db);
12030 }
12031 }
drh2ce15c32017-07-11 13:34:40 +000012032 find_home_dir(1);
drh536c3452018-01-11 00:38:39 +000012033 output_reset(&data);
12034 data.doXdgOpen = 0;
drh13c20932018-01-10 21:41:55 +000012035 clearTempFile(&data);
drh2ce15c32017-07-11 13:34:40 +000012036#if !SQLITE_SHELL_IS_UTF8
drh1f22f622018-05-17 13:29:14 +000012037 for(i=0; i<argcToFree; i++) free(argvToFree[i]);
12038 free(argvToFree);
drh2ce15c32017-07-11 13:34:40 +000012039#endif
drh0285d982020-05-29 14:38:43 +000012040 free(data.colWidth);
drhb97e2ad2021-08-26 18:31:39 +000012041 free(data.zNonce);
drh9e804032018-05-18 17:11:50 +000012042 /* Clear the global data structure so that valgrind will detect memory
12043 ** leaks */
12044 memset(&data, 0, sizeof(data));
larrybrfa5dfa82022-05-07 03:53:14 +000012045#ifdef SQLITE_DEBUG
12046 if( sqlite3_memory_used()>mem_main_enter ){
12047 utf8_printf(stderr, "Memory leaked: %u bytes\n",
12048 (unsigned int)(sqlite3_memory_used()-mem_main_enter));
12049 }
12050#endif
stephan4413ec72022-07-12 15:53:02 +000012051#endif /* !SQLITE_SHELL_FIDDLE */
drh2ce15c32017-07-11 13:34:40 +000012052 return rc;
12053}
stephanf8cd3d22022-05-18 17:14:24 +000012054
12055
stephan4413ec72022-07-12 15:53:02 +000012056#ifdef SQLITE_SHELL_FIDDLE
stephan2eb45412022-05-21 00:01:45 +000012057/* Only for emcc experimentation purposes. */
12058int fiddle_experiment(int a,int b){
stephan278d3fa2022-09-26 13:55:10 +000012059 return a + b;
stephan2eb45412022-05-21 00:01:45 +000012060}
12061
stephan1f095d42022-09-26 11:38:58 +000012062/*
12063** Returns a pointer to the current DB handle.
stephan2eb45412022-05-21 00:01:45 +000012064*/
stephan1f095d42022-09-26 11:38:58 +000012065sqlite3 * fiddle_db_handle(){
stephan278d3fa2022-09-26 13:55:10 +000012066 return globalDb;
stephan2eb45412022-05-21 00:01:45 +000012067}
stephan278d3fa2022-09-26 13:55:10 +000012068
12069/*
12070** Returns a pointer to the given DB name's VFS. If zDbName is 0 then
12071** "main" is assumed. Returns 0 if no db with the given name is
12072** open.
12073*/
12074sqlite3_vfs * fiddle_db_vfs(const char *zDbName){
12075 sqlite3_vfs * pVfs = 0;
12076 if(globalDb){
12077 sqlite3_file_control(globalDb, zDbName ? zDbName : "main",
12078 SQLITE_FCNTL_VFS_POINTER, &pVfs);
12079 }
12080 return pVfs;
stephan2eb45412022-05-21 00:01:45 +000012081}
stephan1f095d42022-09-26 11:38:58 +000012082
stephan2eb45412022-05-21 00:01:45 +000012083/* Only for emcc experimentation purposes. */
12084sqlite3 * fiddle_db_arg(sqlite3 *arg){
12085 printf("fiddle_db_arg(%p)\n", (const void*)arg);
12086 return arg;
12087}
12088
stephanf8cd3d22022-05-18 17:14:24 +000012089/*
stephan42573732022-05-21 14:19:05 +000012090** Intended to be called via a SharedWorker() while a separate
12091** SharedWorker() (which manages the wasm module) is performing work
stephan085c5c62022-05-25 04:35:22 +000012092** which should be interrupted. Unfortunately, SharedWorker is not
12093** portable enough to make real use of.
stephan42573732022-05-21 14:19:05 +000012094*/
12095void fiddle_interrupt(void){
stephan278d3fa2022-09-26 13:55:10 +000012096 if( globalDb ) sqlite3_interrupt(globalDb);
stephan42573732022-05-21 14:19:05 +000012097}
12098
12099/*
stephan085c5c62022-05-25 04:35:22 +000012100** Returns the filename of the given db name, assuming "main" if
12101** zDbName is NULL. Returns NULL if globalDb is not opened.
stephan80bf8692022-05-24 22:16:12 +000012102*/
12103const char * fiddle_db_filename(const char * zDbName){
12104 return globalDb
12105 ? sqlite3_db_filename(globalDb, zDbName ? zDbName : "main")
12106 : NULL;
12107}
12108
12109/*
stephana4c357f2022-10-03 11:42:45 +000012110** Completely wipes out the contents of the currently-opened database
12111** but leaves its storage intact for reuse.
stephancd697842022-05-27 03:27:10 +000012112*/
12113void fiddle_reset_db(void){
stephana4c357f2022-10-03 11:42:45 +000012114 if( globalDb ){
12115 int rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
12116 if( 0==rc ) rc = sqlite3_exec(globalDb, "VACUUM", 0, 0, 0);
12117 sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
stephancd697842022-05-27 03:27:10 +000012118 }
stephancd697842022-05-27 03:27:10 +000012119}
12120
12121/*
stephan278d3fa2022-09-26 13:55:10 +000012122** Uses the current database's VFS xRead to stream the db file's
12123** contents out to the given callback. The callback gets a single
12124** chunk of size n (its 2nd argument) on each call and must return 0
12125** on success, non-0 on error. This function returns 0 on success,
12126** SQLITE_NOTFOUND if no db is open, or propagates any other non-0
12127** code from the callback. Note that this is not thread-friendly: it
12128** expects that it will be the only thread reading the db file and
12129** takes no measures to ensure that is the case.
stephan1f095d42022-09-26 11:38:58 +000012130*/
stephan278d3fa2022-09-26 13:55:10 +000012131int fiddle_export_db( int (*xCallback)(unsigned const char *zOut, int n) ){
stephan1f095d42022-09-26 11:38:58 +000012132 sqlite3_int64 nSize = 0;
12133 sqlite3_int64 nPos = 0;
stephan1f095d42022-09-26 11:38:58 +000012134 sqlite3_file * pFile = 0;
stephan278d3fa2022-09-26 13:55:10 +000012135 unsigned char buf[1024 * 8];
12136 int nBuf = (int)sizeof(buf);
stephan1f095d42022-09-26 11:38:58 +000012137 int rc = shellState.db
12138 ? sqlite3_file_control(shellState.db, "main",
stephan278d3fa2022-09-26 13:55:10 +000012139 SQLITE_FCNTL_FILE_POINTER, &pFile)
12140 : SQLITE_NOTFOUND;
stephan1f095d42022-09-26 11:38:58 +000012141 if( rc ) return rc;
12142 rc = pFile->pMethods->xFileSize(pFile, &nSize);
stephan278d3fa2022-09-26 13:55:10 +000012143 if( rc ) return rc;
12144 if(nSize % nBuf){
12145 /* DB size is not an even multiple of the buffer size. Reduce
12146 ** buffer size so that we do not unduly inflate the db size when
12147 ** exporting. */
12148 if(0 == nSize % 4096) nBuf = 4096;
12149 else if(0 == nSize % 2048) nBuf = 2048;
12150 else if(0 == nSize % 1024) nBuf = 1024;
12151 else nBuf = 512;
12152 }
stephan1f095d42022-09-26 11:38:58 +000012153 for( ; 0==rc && nPos<nSize; nPos += nBuf ){
12154 rc = pFile->pMethods->xRead(pFile, buf, nBuf, nPos);
12155 if(SQLITE_IOERR_SHORT_READ == rc){
12156 rc = (nPos + nBuf) < nSize ? rc : 0/*assume EOF*/;
12157 }
stephan278d3fa2022-09-26 13:55:10 +000012158 if( 0==rc ) rc = xCallback(buf, nBuf);
stephan1f095d42022-09-26 11:38:58 +000012159 }
12160 return rc;
12161}
stephan1f095d42022-09-26 11:38:58 +000012162
12163/*
stephan60d9aa72022-09-24 07:36:45 +000012164** Trivial exportable function for emscripten. It processes zSql as if
12165** it were input to the sqlite3 shell and redirects all output to the
stephan842c5ee2022-10-20 05:14:37 +000012166** wasm binding. fiddle_main() must have been called before this
12167** is called, or results are undefined.
stephanf8cd3d22022-05-18 17:14:24 +000012168*/
stephan0076e492022-05-18 18:10:17 +000012169void fiddle_exec(const char * zSql){
stephan60d9aa72022-09-24 07:36:45 +000012170 if(zSql && *zSql){
12171 if('.'==*zSql) puts(zSql);
stephanf8cd3d22022-05-18 17:14:24 +000012172 shellState.wasm.zInput = zSql;
12173 shellState.wasm.zPos = zSql;
12174 process_input(&shellState);
stephan60d9aa72022-09-24 07:36:45 +000012175 shellState.wasm.zInput = shellState.wasm.zPos = 0;
stephanf8cd3d22022-05-18 17:14:24 +000012176 }
12177}
stephan4413ec72022-07-12 15:53:02 +000012178#endif /* SQLITE_SHELL_FIDDLE */