blob: 4ee30eb0f237a481e9183dfa1638431d2164f82e [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
larrybr0953c532022-12-23 19:04:59 +000024** may be set prior to where they take effect, but after platform setup.
larrybra13c0c72021-07-09 00:12:05 +000025** 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
larrybrfd318932023-01-04 16:54:55 +0000169#ifndef deliberate_fall_through
170/* Quiet some compilers about some of our intentional code. */
171# if GCC_VERSION>=7000000
172# define deliberate_fall_through __attribute__((fallthrough));
173# else
174# define deliberate_fall_through
175# endif
176#endif
drh2ce15c32017-07-11 13:34:40 +0000177
178#if defined(_WIN32) || defined(WIN32)
mistachkin43e86272020-04-09 15:31:22 +0000179# if SQLITE_OS_WINRT
180# define SQLITE_OMIT_POPEN 1
181# else
182# include <io.h>
183# include <fcntl.h>
184# define isatty(h) _isatty(h)
185# ifndef access
186# define access(f,m) _access((f),(m))
187# endif
188# ifndef unlink
189# define unlink _unlink
190# endif
191# ifndef strdup
192# define strdup _strdup
193# endif
194# undef popen
195# define popen _popen
196# undef pclose
197# define pclose _pclose
drh2ce15c32017-07-11 13:34:40 +0000198# endif
drh2ce15c32017-07-11 13:34:40 +0000199#else
200 /* Make sure isatty() has a prototype. */
201 extern int isatty(int);
202
203# if !defined(__RTP__) && !defined(_WRS_KERNEL)
204 /* popen and pclose are not C89 functions and so are
205 ** sometimes omitted from the <stdio.h> header */
206 extern FILE *popen(const char*,const char*);
207 extern int pclose(FILE*);
208# else
209# define SQLITE_OMIT_POPEN 1
210# endif
211#endif
212
213#if defined(_WIN32_WCE)
214/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
215 * thus we always assume that we have a console. That can be
216 * overridden with the -batch command line option.
217 */
218#define isatty(x) 1
219#endif
220
221/* ctype macros that work with signed characters */
222#define IsSpace(X) isspace((unsigned char)X)
223#define IsDigit(X) isdigit((unsigned char)X)
224#define ToLower(X) (char)tolower((unsigned char)X)
225
226#if defined(_WIN32) || defined(WIN32)
mistachkin43e86272020-04-09 15:31:22 +0000227#if SQLITE_OS_WINRT
228#include <intrin.h>
229#endif
drh2ce15c32017-07-11 13:34:40 +0000230#include <windows.h>
231
232/* string conversion routines only needed on Win32 */
233extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
234extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
235extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
236extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
237#endif
238
239/* On Windows, we normally run with output mode of TEXT so that \n characters
240** are automatically translated into \r\n. However, this behavior needs
241** to be disabled in some cases (ex: when generating CSV output and when
242** rendering quoted strings that contain \n characters). The following
243** routines take care of that.
244*/
mistachkin43e86272020-04-09 15:31:22 +0000245#if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
drh2ce15c32017-07-11 13:34:40 +0000246static void setBinaryMode(FILE *file, int isOutput){
247 if( isOutput ) fflush(file);
248 _setmode(_fileno(file), _O_BINARY);
249}
250static void setTextMode(FILE *file, int isOutput){
251 if( isOutput ) fflush(file);
252 _setmode(_fileno(file), _O_TEXT);
253}
254#else
255# define setBinaryMode(X,Y)
256# define setTextMode(X,Y)
257#endif
258
drh2ce15c32017-07-11 13:34:40 +0000259/* True if the timer is enabled */
260static int enableTimer = 0;
261
drhbf70f1b2022-10-19 18:04:42 +0000262/* A version of strcmp() that works with NULL values */
263static int cli_strcmp(const char *a, const char *b){
264 if( a==0 ) a = "";
265 if( b==0 ) b = "";
266 return strcmp(a,b);
267}
268static int cli_strncmp(const char *a, const char *b, size_t n){
269 if( a==0 ) a = "";
270 if( b==0 ) b = "";
271 return strncmp(a,b,n);
272}
273
drh2ce15c32017-07-11 13:34:40 +0000274/* Return the current wall-clock time */
275static sqlite3_int64 timeOfDay(void){
276 static sqlite3_vfs *clockVfs = 0;
277 sqlite3_int64 t;
278 if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
drha959bf52021-06-15 15:15:40 +0000279 if( clockVfs==0 ) return 0; /* Never actually happens */
drh2ce15c32017-07-11 13:34:40 +0000280 if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
281 clockVfs->xCurrentTimeInt64(clockVfs, &t);
282 }else{
283 double r;
284 clockVfs->xCurrentTime(clockVfs, &r);
285 t = (sqlite3_int64)(r*86400000.0);
286 }
287 return t;
288}
289
290#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
291#include <sys/time.h>
292#include <sys/resource.h>
293
294/* VxWorks does not support getrusage() as far as we can determine */
295#if defined(_WRS_KERNEL) || defined(__RTP__)
296struct rusage {
297 struct timeval ru_utime; /* user CPU time used */
298 struct timeval ru_stime; /* system CPU time used */
299};
300#define getrusage(A,B) memset(B,0,sizeof(*B))
301#endif
302
303/* Saved resource information for the beginning of an operation */
304static struct rusage sBegin; /* CPU time at start */
305static sqlite3_int64 iBegin; /* Wall-clock time at start */
306
307/*
308** Begin timing an operation
309*/
310static void beginTimer(void){
311 if( enableTimer ){
312 getrusage(RUSAGE_SELF, &sBegin);
313 iBegin = timeOfDay();
314 }
315}
316
317/* Return the difference of two time_structs in seconds */
318static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
319 return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
320 (double)(pEnd->tv_sec - pStart->tv_sec);
321}
322
323/*
324** Print the timing results.
325*/
326static void endTimer(void){
327 if( enableTimer ){
328 sqlite3_int64 iEnd = timeOfDay();
329 struct rusage sEnd;
330 getrusage(RUSAGE_SELF, &sEnd);
331 printf("Run Time: real %.3f user %f sys %f\n",
332 (iEnd - iBegin)*0.001,
333 timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
334 timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
335 }
336}
337
338#define BEGIN_TIMER beginTimer()
339#define END_TIMER endTimer()
340#define HAS_TIMER 1
341
342#elif (defined(_WIN32) || defined(WIN32))
343
344/* Saved resource information for the beginning of an operation */
345static HANDLE hProcess;
346static FILETIME ftKernelBegin;
347static FILETIME ftUserBegin;
348static sqlite3_int64 ftWallBegin;
349typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME,
350 LPFILETIME, LPFILETIME);
351static GETPROCTIMES getProcessTimesAddr = NULL;
352
353/*
354** Check to see if we have timer support. Return 1 if necessary
355** support found (or found previously).
356*/
357static int hasTimer(void){
358 if( getProcessTimesAddr ){
359 return 1;
360 } else {
mistachkin43e86272020-04-09 15:31:22 +0000361#if !SQLITE_OS_WINRT
drh2ce15c32017-07-11 13:34:40 +0000362 /* GetProcessTimes() isn't supported in WIN95 and some other Windows
363 ** versions. See if the version we are running on has it, and if it
364 ** does, save off a pointer to it and the current process handle.
365 */
366 hProcess = GetCurrentProcess();
367 if( hProcess ){
368 HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
369 if( NULL != hinstLib ){
370 getProcessTimesAddr =
371 (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
372 if( NULL != getProcessTimesAddr ){
373 return 1;
374 }
375 FreeLibrary(hinstLib);
376 }
377 }
mistachkin43e86272020-04-09 15:31:22 +0000378#endif
drh2ce15c32017-07-11 13:34:40 +0000379 }
380 return 0;
381}
382
383/*
384** Begin timing an operation
385*/
386static void beginTimer(void){
387 if( enableTimer && getProcessTimesAddr ){
388 FILETIME ftCreation, ftExit;
389 getProcessTimesAddr(hProcess,&ftCreation,&ftExit,
390 &ftKernelBegin,&ftUserBegin);
391 ftWallBegin = timeOfDay();
392 }
393}
394
395/* Return the difference of two FILETIME structs in seconds */
396static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
397 sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
398 sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
399 return (double) ((i64End - i64Start) / 10000000.0);
400}
401
402/*
403** Print the timing results.
404*/
405static void endTimer(void){
406 if( enableTimer && getProcessTimesAddr){
407 FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
408 sqlite3_int64 ftWallEnd = timeOfDay();
409 getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
410 printf("Run Time: real %.3f user %f sys %f\n",
411 (ftWallEnd - ftWallBegin)*0.001,
412 timeDiff(&ftUserBegin, &ftUserEnd),
413 timeDiff(&ftKernelBegin, &ftKernelEnd));
414 }
415}
416
417#define BEGIN_TIMER beginTimer()
418#define END_TIMER endTimer()
419#define HAS_TIMER hasTimer()
420
421#else
422#define BEGIN_TIMER
423#define END_TIMER
424#define HAS_TIMER 0
425#endif
426
427/*
428** Used to prevent warnings about unused parameters
429*/
430#define UNUSED_PARAMETER(x) (void)(x)
431
432/*
drh5af06982018-01-10 00:53:55 +0000433** Number of elements in an array
434*/
435#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
436
437/*
drh2ce15c32017-07-11 13:34:40 +0000438** If the following flag is set, then command execution stops
439** at an error if we are not interactive.
440*/
441static int bail_on_error = 0;
442
443/*
444** Threat stdin as an interactive input if the following variable
445** is true. Otherwise, assume stdin is connected to a file or pipe.
446*/
447static int stdin_is_interactive = 1;
448
449/*
450** On Windows systems we have to know if standard output is a console
451** in order to translate UTF-8 into MBCS. The following variable is
452** true if translation is required.
453*/
454static int stdout_is_console = 1;
455
456/*
457** The following is the open SQLite database. We make a pointer
458** to this database a static variable so that it can be accessed
459** by the SIGINT handler to interrupt database processing.
460*/
461static sqlite3 *globalDb = 0;
462
463/*
464** True if an interrupt (Control-C) has been received.
465*/
466static volatile int seenInterrupt = 0;
467
468/*
469** This is the name of our program. It is set in main(), used
470** in a number of other places, mostly for error messages.
471*/
472static char *Argv0;
473
474/*
475** Prompt strings. Initialized in main. Settable with
476** .prompt main continue
477*/
larrybr9ab15982022-12-06 05:09:51 +0000478#define PROMPT_LEN_MAX 20
479/* First line prompt. default: "sqlite> " */
480static char mainPrompt[PROMPT_LEN_MAX];
481/* Continuation prompt. default: " ...> " */
482static char continuePrompt[PROMPT_LEN_MAX];
483
484/*
485** Optionally disable dynamic continuation prompt.
486** Unless disabled, the continuation prompt shows open SQL lexemes if any,
487** or open parentheses level if non-zero, or continuation prompt as set.
488** This facility interacts with the scanner and process_input() where the
489** below 5 macros are used.
490*/
491#ifdef SQLITE_OMIT_DYNAPROMPT
492# define CONTINUATION_PROMPT continuePrompt
larrybr29226fc2022-12-06 17:59:05 +0000493# define CONTINUE_PROMPT_RESET
larrybr9ab15982022-12-06 05:09:51 +0000494# define CONTINUE_PROMPT_AWAITS(p,s)
495# define CONTINUE_PROMPT_AWAITC(p,c)
496# define CONTINUE_PAREN_INCR(p,n)
larrybr29226fc2022-12-06 17:59:05 +0000497# define CONTINUE_PROMPT_PSTATE 0
498typedef void *t_NoDynaPrompt;
499# define SCAN_TRACKER_REFTYPE t_NoDynaPrompt
larrybr9ab15982022-12-06 05:09:51 +0000500#else
501# define CONTINUATION_PROMPT dynamicContinuePrompt()
larrybr29226fc2022-12-06 17:59:05 +0000502# define CONTINUE_PROMPT_RESET \
503 do {setLexemeOpen(&dynPrompt,0,0); trackParenLevel(&dynPrompt,0);} while(0)
larrybr9ab15982022-12-06 05:09:51 +0000504# define CONTINUE_PROMPT_AWAITS(p,s) \
505 if(p && stdin_is_interactive) setLexemeOpen(p, s, 0)
506# define CONTINUE_PROMPT_AWAITC(p,c) \
507 if(p && stdin_is_interactive) setLexemeOpen(p, 0, c)
508# define CONTINUE_PAREN_INCR(p,n) \
509 if(p && stdin_is_interactive) (trackParenLevel(p,n))
larrybr29226fc2022-12-06 17:59:05 +0000510# define CONTINUE_PROMPT_PSTATE (&dynPrompt)
511typedef struct DynaPrompt *t_DynaPromptRef;
512# define SCAN_TRACKER_REFTYPE t_DynaPromptRef
larrybr9ab15982022-12-06 05:09:51 +0000513
514static struct DynaPrompt {
515 char dynamicPrompt[PROMPT_LEN_MAX];
516 char acAwait[2];
517 int inParenLevel;
518 char *zScannerAwaits;
519} dynPrompt = { {0}, {0}, 0, 0 };
520
521/* Record parenthesis nesting level change, or force level to 0. */
522static void trackParenLevel(struct DynaPrompt *p, int ni){
523 p->inParenLevel += ni;
524 if( ni==0 ) p->inParenLevel = 0;
525 p->zScannerAwaits = 0;
526}
527
528/* Record that a lexeme is opened, or closed with args==0. */
529static void setLexemeOpen(struct DynaPrompt *p, char *s, char c){
530 if( s!=0 || c==0 ){
531 p->zScannerAwaits = s;
532 p->acAwait[0] = 0;
533 }else{
534 p->acAwait[0] = c;
535 p->zScannerAwaits = p->acAwait;
536 }
537}
538
539/* Upon demand, derive the continuation prompt to display. */
540static char *dynamicContinuePrompt(void){
541 if( continuePrompt[0]==0
542 || (dynPrompt.zScannerAwaits==0 && dynPrompt.inParenLevel == 0) ){
543 return continuePrompt;
544 }else{
545 if( dynPrompt.zScannerAwaits ){
larrybr0953c532022-12-23 19:04:59 +0000546 size_t ncp = strlen(continuePrompt);
547 size_t ndp = strlen(dynPrompt.zScannerAwaits);
larrybr9ab15982022-12-06 05:09:51 +0000548 if( ndp > ncp-3 ) return continuePrompt;
drh209dbab2022-12-07 19:51:48 +0000549 strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
larrybr9ab15982022-12-06 05:09:51 +0000550 while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' ';
551 strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
larrybr88fbe1612022-12-17 19:56:28 +0000552 PROMPT_LEN_MAX-4);
larrybr9ab15982022-12-06 05:09:51 +0000553 }else{
554 if( dynPrompt.inParenLevel>9 ){
larrybr88fbe1612022-12-17 19:56:28 +0000555 strncpy(dynPrompt.dynamicPrompt, "(..", 4);
larrybr9ab15982022-12-06 05:09:51 +0000556 }else if( dynPrompt.inParenLevel<0 ){
larrybr88fbe1612022-12-17 19:56:28 +0000557 strncpy(dynPrompt.dynamicPrompt, ")x!", 4);
larrybr9ab15982022-12-06 05:09:51 +0000558 }else{
larrybr88fbe1612022-12-17 19:56:28 +0000559 strncpy(dynPrompt.dynamicPrompt, "(x.", 4);
560 dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel);
larrybr9ab15982022-12-06 05:09:51 +0000561 }
562 strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, PROMPT_LEN_MAX-4);
563 }
564 }
565 return dynPrompt.dynamicPrompt;
566}
567#endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */
drh2ce15c32017-07-11 13:34:40 +0000568
569/*
570** Render output like fprintf(). Except, if the output is going to the
571** console and if this is running on a Windows machine, translate the
572** output from UTF-8 into MBCS.
573*/
574#if defined(_WIN32) || defined(WIN32)
575void utf8_printf(FILE *out, const char *zFormat, ...){
576 va_list ap;
577 va_start(ap, zFormat);
578 if( stdout_is_console && (out==stdout || out==stderr) ){
579 char *z1 = sqlite3_vmprintf(zFormat, ap);
580 char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
581 sqlite3_free(z1);
582 fputs(z2, out);
583 sqlite3_free(z2);
584 }else{
585 vfprintf(out, zFormat, ap);
586 }
587 va_end(ap);
588}
589#elif !defined(utf8_printf)
590# define utf8_printf fprintf
591#endif
592
593/*
594** Render output like fprintf(). This should not be used on anything that
595** includes string formatting (e.g. "%s").
596*/
597#if !defined(raw_printf)
598# define raw_printf fprintf
599#endif
600
drh4b5345c2018-04-24 13:07:40 +0000601/* Indicate out-of-memory and exit. */
602static void shell_out_of_memory(void){
603 raw_printf(stderr,"Error: out of memory\n");
604 exit(1);
605}
606
drhe3e25652021-12-16 13:29:28 +0000607/* Check a pointer to see if it is NULL. If it is NULL, exit with an
608** out-of-memory error.
609*/
610static void shell_check_oom(void *p){
611 if( p==0 ) shell_out_of_memory();
612}
613
drh2ce15c32017-07-11 13:34:40 +0000614/*
615** Write I/O traces to the following stream.
616*/
617#ifdef SQLITE_ENABLE_IOTRACE
618static FILE *iotrace = 0;
619#endif
620
621/*
622** This routine works like printf in that its first argument is a
623** format string and subsequent arguments are values to be substituted
624** in place of % fields. The result of formatting this string
625** is written to iotrace.
626*/
627#ifdef SQLITE_ENABLE_IOTRACE
628static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
629 va_list ap;
630 char *z;
631 if( iotrace==0 ) return;
632 va_start(ap, zFormat);
633 z = sqlite3_vmprintf(zFormat, ap);
634 va_end(ap);
635 utf8_printf(iotrace, "%s", z);
636 sqlite3_free(z);
637}
638#endif
639
640/*
641** Output string zUtf to stream pOut as w characters. If w is negative,
642** then right-justify the text. W is the width in UTF-8 characters, not
643** in bytes. This is different from the %*.*s specification in printf
644** since with %*.*s the width is measured in bytes, not characters.
645*/
646static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
647 int i;
648 int n;
649 int aw = w<0 ? -w : w;
drh4853aa12022-10-27 18:20:08 +0000650 if( zUtf==0 ) zUtf = "";
drh2ce15c32017-07-11 13:34:40 +0000651 for(i=n=0; zUtf[i]; i++){
652 if( (zUtf[i]&0xc0)!=0x80 ){
653 n++;
654 if( n==aw ){
655 do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
656 break;
657 }
658 }
659 }
660 if( n>=aw ){
661 utf8_printf(pOut, "%.*s", i, zUtf);
662 }else if( w<0 ){
663 utf8_printf(pOut, "%*s%s", aw-n, "", zUtf);
664 }else{
665 utf8_printf(pOut, "%s%*s", zUtf, aw-n, "");
666 }
667}
668
669
670/*
671** Determines if a string is a number of not.
672*/
673static int isNumber(const char *z, int *realnum){
674 if( *z=='-' || *z=='+' ) z++;
675 if( !IsDigit(*z) ){
676 return 0;
677 }
678 z++;
679 if( realnum ) *realnum = 0;
680 while( IsDigit(*z) ){ z++; }
681 if( *z=='.' ){
682 z++;
683 if( !IsDigit(*z) ) return 0;
684 while( IsDigit(*z) ){ z++; }
685 if( realnum ) *realnum = 1;
686 }
687 if( *z=='e' || *z=='E' ){
688 z++;
689 if( *z=='+' || *z=='-' ) z++;
690 if( !IsDigit(*z) ) return 0;
691 while( IsDigit(*z) ){ z++; }
692 if( realnum ) *realnum = 1;
693 }
694 return *z==0;
695}
696
697/*
698** Compute a string length that is limited to what can be stored in
699** lower 30 bits of a 32-bit signed integer.
700*/
701static int strlen30(const char *z){
702 const char *z2 = z;
703 while( *z2 ){ z2++; }
704 return 0x3fffffff & (int)(z2 - z);
705}
706
707/*
708** Return the length of a string in characters. Multibyte UTF8 characters
709** count as a single character.
710*/
711static int strlenChar(const char *z){
712 int n = 0;
713 while( *z ){
714 if( (0xc0&*(z++))!=0x80 ) n++;
715 }
716 return n;
717}
718
719/*
larrybrd96bcc72021-09-17 21:12:47 +0000720** Return open FILE * if zFile exists, can be opened for read
721** and is an ordinary file or a character stream source.
722** Otherwise return 0.
drhbbd620e2020-07-20 23:33:11 +0000723*/
larrybrd96bcc72021-09-17 21:12:47 +0000724static FILE * openChrSource(const char *zFile){
drhbbd620e2020-07-20 23:33:11 +0000725#ifdef _WIN32
larrybrd0007852021-09-13 23:11:46 +0000726 struct _stat x = {0};
larrybrd0007852021-09-13 23:11:46 +0000727# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
larrybrd96bcc72021-09-17 21:12:47 +0000728 /* On Windows, open first, then check the stream nature. This order
729 ** is necessary because _stat() and sibs, when checking a named pipe,
730 ** effectively break the pipe as its supplier sees it. */
731 FILE *rv = fopen(zFile, "rb");
732 if( rv==0 ) return 0;
733 if( _fstat(_fileno(rv), &x) != 0
734 || !STAT_CHR_SRC(x.st_mode)){
735 fclose(rv);
736 rv = 0;
737 }
738 return rv;
drhbbd620e2020-07-20 23:33:11 +0000739#else
larrybrd0007852021-09-13 23:11:46 +0000740 struct stat x = {0};
741 int rc = stat(zFile, &x);
742# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
larrybrd96bcc72021-09-17 21:12:47 +0000743 if( rc!=0 ) return 0;
744 if( STAT_CHR_SRC(x.st_mode) ){
745 return fopen(zFile, "rb");
746 }else{
747 return 0;
748 }
drhbbd620e2020-07-20 23:33:11 +0000749#endif
larrybrd0007852021-09-13 23:11:46 +0000750#undef STAT_CHR_SRC
751}
drhbbd620e2020-07-20 23:33:11 +0000752
753/*
drh2ce15c32017-07-11 13:34:40 +0000754** This routine reads a line of text from FILE in, stores
755** the text in memory obtained from malloc() and returns a pointer
756** to the text. NULL is returned at end of file, or if malloc()
757** fails.
758**
759** If zLine is not NULL then it is a malloced buffer returned from
760** a previous call to this routine that may be reused.
761*/
762static char *local_getline(char *zLine, FILE *in){
763 int nLine = zLine==0 ? 0 : 100;
764 int n = 0;
765
766 while( 1 ){
767 if( n+100>nLine ){
768 nLine = nLine*2 + 100;
769 zLine = realloc(zLine, nLine);
drhe3e25652021-12-16 13:29:28 +0000770 shell_check_oom(zLine);
drh2ce15c32017-07-11 13:34:40 +0000771 }
772 if( fgets(&zLine[n], nLine - n, in)==0 ){
773 if( n==0 ){
774 free(zLine);
775 return 0;
776 }
777 zLine[n] = 0;
778 break;
779 }
780 while( zLine[n] ) n++;
781 if( n>0 && zLine[n-1]=='\n' ){
782 n--;
783 if( n>0 && zLine[n-1]=='\r' ) n--;
784 zLine[n] = 0;
785 break;
786 }
787 }
788#if defined(_WIN32) || defined(WIN32)
789 /* For interactive input on Windows systems, translate the
790 ** multi-byte characterset characters into UTF-8. */
791 if( stdin_is_interactive && in==stdin ){
792 char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
793 if( zTrans ){
drh7d23d152022-10-11 12:02:42 +0000794 i64 nTrans = strlen(zTrans)+1;
drh2ce15c32017-07-11 13:34:40 +0000795 if( nTrans>nLine ){
796 zLine = realloc(zLine, nTrans);
drhe3e25652021-12-16 13:29:28 +0000797 shell_check_oom(zLine);
drh2ce15c32017-07-11 13:34:40 +0000798 }
799 memcpy(zLine, zTrans, nTrans);
800 sqlite3_free(zTrans);
801 }
802 }
803#endif /* defined(_WIN32) || defined(WIN32) */
804 return zLine;
805}
806
807/*
808** Retrieve a single line of input text.
809**
810** If in==0 then read from standard input and prompt before each line.
811** If isContinuation is true, then a continuation prompt is appropriate.
812** If isContinuation is zero, then the main prompt should be used.
813**
814** If zPrior is not NULL then it is a buffer from a prior call to this
815** routine that can be reused.
816**
817** The result is stored in space obtained from malloc() and must either
818** be freed by the caller or else passed back into this routine via the
819** zPrior argument for reuse.
820*/
stephan4413ec72022-07-12 15:53:02 +0000821#ifndef SQLITE_SHELL_FIDDLE
drh2ce15c32017-07-11 13:34:40 +0000822static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
823 char *zPrompt;
824 char *zResult;
825 if( in!=0 ){
826 zResult = local_getline(zPrior, in);
827 }else{
larrybr9ab15982022-12-06 05:09:51 +0000828 zPrompt = isContinuation ? CONTINUATION_PROMPT : mainPrompt;
drh2ce15c32017-07-11 13:34:40 +0000829#if SHELL_USE_LOCAL_GETLINE
830 printf("%s", zPrompt);
831 fflush(stdout);
832 zResult = local_getline(zPrior, stdin);
833#else
834 free(zPrior);
835 zResult = shell_readline(zPrompt);
836 if( zResult && *zResult ) shell_add_history(zResult);
837#endif
838 }
839 return zResult;
840}
stephan4413ec72022-07-12 15:53:02 +0000841#endif /* !SQLITE_SHELL_FIDDLE */
drh5af06982018-01-10 00:53:55 +0000842
843/*
844** Return the value of a hexadecimal digit. Return -1 if the input
845** is not a hex digit.
846*/
847static int hexDigitValue(char c){
848 if( c>='0' && c<='9' ) return c - '0';
849 if( c>='a' && c<='f' ) return c - 'a' + 10;
850 if( c>='A' && c<='F' ) return c - 'A' + 10;
851 return -1;
852}
853
854/*
855** Interpret zArg as an integer value, possibly with suffixes.
856*/
857static sqlite3_int64 integerValue(const char *zArg){
858 sqlite3_int64 v = 0;
859 static const struct { char *zSuffix; int iMult; } aMult[] = {
860 { "KiB", 1024 },
861 { "MiB", 1024*1024 },
862 { "GiB", 1024*1024*1024 },
863 { "KB", 1000 },
864 { "MB", 1000000 },
865 { "GB", 1000000000 },
866 { "K", 1000 },
867 { "M", 1000000 },
868 { "G", 1000000000 },
869 };
870 int i;
871 int isNeg = 0;
872 if( zArg[0]=='-' ){
873 isNeg = 1;
874 zArg++;
875 }else if( zArg[0]=='+' ){
876 zArg++;
877 }
878 if( zArg[0]=='0' && zArg[1]=='x' ){
879 int x;
880 zArg += 2;
881 while( (x = hexDigitValue(zArg[0]))>=0 ){
882 v = (v<<4) + x;
883 zArg++;
884 }
885 }else{
886 while( IsDigit(zArg[0]) ){
887 v = v*10 + zArg[0] - '0';
888 zArg++;
889 }
890 }
891 for(i=0; i<ArraySize(aMult); i++){
892 if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
893 v *= aMult[i].iMult;
894 break;
895 }
896 }
897 return isNeg? -v : v;
898}
899
drh2ce15c32017-07-11 13:34:40 +0000900/*
901** A variable length string to which one can append text.
902*/
903typedef struct ShellText ShellText;
904struct ShellText {
905 char *z;
906 int n;
907 int nAlloc;
908};
909
910/*
911** Initialize and destroy a ShellText object
912*/
913static void initText(ShellText *p){
914 memset(p, 0, sizeof(*p));
915}
916static void freeText(ShellText *p){
917 free(p->z);
918 initText(p);
919}
920
921/* zIn is either a pointer to a NULL-terminated string in memory obtained
922** from malloc(), or a NULL pointer. The string pointed to by zAppend is
923** added to zIn, and the result returned in memory obtained from malloc().
924** zIn, if it was not NULL, is freed.
925**
926** If the third argument, quote, is not '\0', then it is used as a
927** quote character for zAppend.
928*/
stephan0076e492022-05-18 18:10:17 +0000929static void appendText(ShellText *p, const char *zAppend, char quote){
drh7d23d152022-10-11 12:02:42 +0000930 i64 len;
931 i64 i;
932 i64 nAppend = strlen30(zAppend);
drh2ce15c32017-07-11 13:34:40 +0000933
934 len = nAppend+p->n+1;
935 if( quote ){
936 len += 2;
937 for(i=0; i<nAppend; i++){
938 if( zAppend[i]==quote ) len++;
939 }
940 }
941
drh11a9ad52021-10-04 18:21:14 +0000942 if( p->z==0 || p->n+len>=p->nAlloc ){
drh2ce15c32017-07-11 13:34:40 +0000943 p->nAlloc = p->nAlloc*2 + len + 20;
944 p->z = realloc(p->z, p->nAlloc);
drhe3e25652021-12-16 13:29:28 +0000945 shell_check_oom(p->z);
drh2ce15c32017-07-11 13:34:40 +0000946 }
947
948 if( quote ){
949 char *zCsr = p->z+p->n;
950 *zCsr++ = quote;
951 for(i=0; i<nAppend; i++){
952 *zCsr++ = zAppend[i];
953 if( zAppend[i]==quote ) *zCsr++ = quote;
954 }
955 *zCsr++ = quote;
956 p->n = (int)(zCsr - p->z);
957 *zCsr = '\0';
958 }else{
959 memcpy(p->z+p->n, zAppend, nAppend);
960 p->n += nAppend;
961 p->z[p->n] = '\0';
962 }
963}
964
965/*
966** Attempt to determine if identifier zName needs to be quoted, either
967** because it contains non-alphanumeric characters, or because it is an
968** SQLite keyword. Be conservative in this estimate: When in doubt assume
969** that quoting is required.
970**
971** Return '"' if quoting is required. Return 0 if no quoting is required.
972*/
973static char quoteChar(const char *zName){
drhfc0ec3e2018-04-25 19:02:48 +0000974 int i;
drh2ce15c32017-07-11 13:34:40 +0000975 if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
976 for(i=0; zName[i]; i++){
977 if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
978 }
drhfc0ec3e2018-04-25 19:02:48 +0000979 return sqlite3_keyword_check(zName, i) ? '"' : 0;
drh2ce15c32017-07-11 13:34:40 +0000980}
981
982/*
drh667a2a22018-01-02 00:04:37 +0000983** Construct a fake object name and column list to describe the structure
984** of the view, virtual table, or table valued function zSchema.zName.
drhceba7922018-01-01 21:28:25 +0000985*/
drh667a2a22018-01-02 00:04:37 +0000986static char *shellFakeSchema(
drhceba7922018-01-01 21:28:25 +0000987 sqlite3 *db, /* The database connection containing the vtab */
988 const char *zSchema, /* Schema of the database holding the vtab */
989 const char *zName /* The name of the virtual table */
990){
991 sqlite3_stmt *pStmt = 0;
992 char *zSql;
drh1d315cf2018-01-01 21:49:43 +0000993 ShellText s;
994 char cQuote;
995 char *zDiv = "(";
drh667a2a22018-01-02 00:04:37 +0000996 int nRow = 0;
drhceba7922018-01-01 21:28:25 +0000997
drh1d315cf2018-01-01 21:49:43 +0000998 zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
999 zSchema ? zSchema : "main", zName);
drhe3e25652021-12-16 13:29:28 +00001000 shell_check_oom(zSql);
drhceba7922018-01-01 21:28:25 +00001001 sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
1002 sqlite3_free(zSql);
drh1d315cf2018-01-01 21:49:43 +00001003 initText(&s);
1004 if( zSchema ){
1005 cQuote = quoteChar(zSchema);
1006 if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0;
1007 appendText(&s, zSchema, cQuote);
1008 appendText(&s, ".", 0);
drhceba7922018-01-01 21:28:25 +00001009 }
drh1d315cf2018-01-01 21:49:43 +00001010 cQuote = quoteChar(zName);
1011 appendText(&s, zName, cQuote);
1012 while( sqlite3_step(pStmt)==SQLITE_ROW ){
1013 const char *zCol = (const char*)sqlite3_column_text(pStmt, 1);
drh667a2a22018-01-02 00:04:37 +00001014 nRow++;
drh1d315cf2018-01-01 21:49:43 +00001015 appendText(&s, zDiv, 0);
1016 zDiv = ",";
drh621a5e02021-12-16 17:35:27 +00001017 if( zCol==0 ) zCol = "";
drh1d315cf2018-01-01 21:49:43 +00001018 cQuote = quoteChar(zCol);
1019 appendText(&s, zCol, cQuote);
1020 }
1021 appendText(&s, ")", 0);
drhceba7922018-01-01 21:28:25 +00001022 sqlite3_finalize(pStmt);
drh667a2a22018-01-02 00:04:37 +00001023 if( nRow==0 ){
1024 freeText(&s);
1025 s.z = 0;
1026 }
drh1d315cf2018-01-01 21:49:43 +00001027 return s.z;
drhceba7922018-01-01 21:28:25 +00001028}
1029
1030/*
drh667a2a22018-01-02 00:04:37 +00001031** SQL function: shell_module_schema(X)
1032**
1033** Return a fake schema for the table-valued function or eponymous virtual
1034** table X.
1035*/
1036static void shellModuleSchema(
1037 sqlite3_context *pCtx,
1038 int nVal,
1039 sqlite3_value **apVal
1040){
drh511b1182021-12-16 13:56:04 +00001041 const char *zName;
1042 char *zFake;
drhb9685182018-01-17 13:15:23 +00001043 UNUSED_PARAMETER(nVal);
drh511b1182021-12-16 13:56:04 +00001044 zName = (const char*)sqlite3_value_text(apVal[0]);
larrybr0953c532022-12-23 19:04:59 +00001045 zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0;
drh667a2a22018-01-02 00:04:37 +00001046 if( zFake ){
dandcfbff92018-01-08 17:05:32 +00001047 sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
drh667a2a22018-01-02 00:04:37 +00001048 -1, sqlite3_free);
dandcfbff92018-01-08 17:05:32 +00001049 free(zFake);
drh667a2a22018-01-02 00:04:37 +00001050 }
1051}
1052
1053/*
drh2ce15c32017-07-11 13:34:40 +00001054** SQL function: shell_add_schema(S,X)
1055**
1056** Add the schema name X to the CREATE statement in S and return the result.
1057** Examples:
1058**
1059** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x);
1060**
1061** Also works on
1062**
1063** CREATE INDEX
1064** CREATE UNIQUE INDEX
1065** CREATE VIEW
1066** CREATE TRIGGER
1067** CREATE VIRTUAL TABLE
1068**
1069** This UDF is used by the .schema command to insert the schema name of
drh067b92b2020-06-19 15:24:12 +00001070** attached databases into the middle of the sqlite_schema.sql field.
drh2ce15c32017-07-11 13:34:40 +00001071*/
1072static void shellAddSchemaName(
1073 sqlite3_context *pCtx,
1074 int nVal,
1075 sqlite3_value **apVal
1076){
1077 static const char *aPrefix[] = {
1078 "TABLE",
1079 "INDEX",
1080 "UNIQUE INDEX",
1081 "VIEW",
1082 "TRIGGER",
1083 "VIRTUAL TABLE"
1084 };
1085 int i = 0;
1086 const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
1087 const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
drh667a2a22018-01-02 00:04:37 +00001088 const char *zName = (const char*)sqlite3_value_text(apVal[2]);
drhceba7922018-01-01 21:28:25 +00001089 sqlite3 *db = sqlite3_context_db_handle(pCtx);
drhb9685182018-01-17 13:15:23 +00001090 UNUSED_PARAMETER(nVal);
drhbf70f1b2022-10-19 18:04:42 +00001091 if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){
drh37407122021-07-23 18:43:58 +00001092 for(i=0; i<ArraySize(aPrefix); i++){
drh2ce15c32017-07-11 13:34:40 +00001093 int n = strlen30(aPrefix[i]);
drhbf70f1b2022-10-19 18:04:42 +00001094 if( cli_strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
drhceba7922018-01-01 21:28:25 +00001095 char *z = 0;
drh667a2a22018-01-02 00:04:37 +00001096 char *zFake = 0;
drhceba7922018-01-01 21:28:25 +00001097 if( zSchema ){
1098 char cQuote = quoteChar(zSchema);
1099 if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
1100 z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
1101 }else{
1102 z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
1103 }
drh2ce15c32017-07-11 13:34:40 +00001104 }
drh667a2a22018-01-02 00:04:37 +00001105 if( zName
1106 && aPrefix[i][0]=='V'
1107 && (zFake = shellFakeSchema(db, zSchema, zName))!=0
1108 ){
1109 if( z==0 ){
dandcfbff92018-01-08 17:05:32 +00001110 z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake);
drh667a2a22018-01-02 00:04:37 +00001111 }else{
dandcfbff92018-01-08 17:05:32 +00001112 z = sqlite3_mprintf("%z\n/* %s */", z, zFake);
drh667a2a22018-01-02 00:04:37 +00001113 }
dandcfbff92018-01-08 17:05:32 +00001114 free(zFake);
drhceba7922018-01-01 21:28:25 +00001115 }
1116 if( z ){
1117 sqlite3_result_text(pCtx, z, -1, sqlite3_free);
1118 return;
1119 }
drh2ce15c32017-07-11 13:34:40 +00001120 }
1121 }
1122 }
1123 sqlite3_result_value(pCtx, apVal[0]);
1124}
1125
1126/*
1127** The source code for several run-time loadable extensions is inserted
1128** below by the ../tool/mkshellc.tcl script. Before processing that included
1129** code, we need to override some macros to make the included program code
1130** work here in the middle of this regular program.
1131*/
1132#define SQLITE_EXTENSION_INIT1
drh89997982017-07-11 18:11:33 +00001133#define SQLITE_EXTENSION_INIT2(X) (void)(X)
drh2ce15c32017-07-11 13:34:40 +00001134
mistachkinacae8c32018-01-05 20:08:46 +00001135#if defined(_WIN32) && defined(_MSC_VER)
drh03491a12018-01-07 21:58:17 +00001136INCLUDE test_windirent.h
mistachkindfdfd8c2018-01-04 22:46:08 +00001137INCLUDE test_windirent.c
1138#define dirent DIRENT
mistachkindfdfd8c2018-01-04 22:46:08 +00001139#endif
drh50b910a2019-01-21 14:55:03 +00001140INCLUDE ../ext/misc/memtrace.c
stephanf8cd3d22022-05-18 17:14:24 +00001141INCLUDE ../ext/misc/shathree.c
drhf05dd032020-04-14 15:53:58 +00001142INCLUDE ../ext/misc/uint.c
drhbeb9def2020-06-22 19:12:23 +00001143INCLUDE ../ext/misc/decimal.c
larrybr0953c532022-12-23 19:04:59 +00001144#undef sqlite3_base_init
1145#define sqlite3_base_init sqlite3_base64_init
1146INCLUDE ../ext/misc/base64.c
1147#undef sqlite3_base_init
1148#define sqlite3_base_init sqlite3_base85_init
1149#define OMIT_BASE85_CHECKER
1150INCLUDE ../ext/misc/base85.c
drh8cda77d2020-06-24 15:06:29 +00001151INCLUDE ../ext/misc/ieee754.c
mistachkin72c38d82020-08-28 18:47:39 +00001152INCLUDE ../ext/misc/series.c
drh64689902021-06-03 13:51:31 +00001153INCLUDE ../ext/misc/regexp.c
stephan4413ec72022-07-12 15:53:02 +00001154#ifndef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +00001155INCLUDE ../ext/misc/fileio.c
1156INCLUDE ../ext/misc/completion.c
1157INCLUDE ../ext/misc/appendvfs.c
1158#endif
dan72afc3c2017-12-05 18:32:40 +00001159#ifdef SQLITE_HAVE_ZLIB
dan9ebfaad2017-12-26 20:39:58 +00001160INCLUDE ../ext/misc/zipfile.c
dand1b51d42017-12-16 19:11:26 +00001161INCLUDE ../ext/misc/sqlar.c
dan72afc3c2017-12-05 18:32:40 +00001162#endif
dan43efc182017-12-19 17:42:13 +00001163INCLUDE ../ext/expert/sqlite3expert.h
1164INCLUDE ../ext/expert/sqlite3expert.c
drh2ce15c32017-07-11 13:34:40 +00001165
stephanbb5136e2022-10-27 11:32:20 +00001166#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
stephan3d420832022-10-27 03:56:01 +00001167#define SQLITE_SHELL_HAVE_RECOVER 1
1168#else
1169#define SQLITE_SHELL_HAVE_RECOVER 0
1170#endif
1171#if SQLITE_SHELL_HAVE_RECOVER
dan9a27d652022-09-08 19:22:29 +00001172INCLUDE ../ext/recover/sqlite3recover.h
dan63b74e02022-11-22 16:12:53 +00001173# ifndef SQLITE_HAVE_SQLITE3R
1174INCLUDE ../ext/recover/dbdata.c
dan9a27d652022-09-08 19:22:29 +00001175INCLUDE ../ext/recover/sqlite3recover.c
dan63b74e02022-11-22 16:12:53 +00001176# endif
dan1b162162019-04-27 20:15:15 +00001177#endif
larrybr423003d2022-11-21 00:11:09 +00001178#ifdef SQLITE_SHELL_EXTSRC
1179# include SHELL_STRINGIFY(SQLITE_SHELL_EXTSRC)
1180#endif
dan68cb86e2019-04-20 20:57:28 +00001181
drh2ce15c32017-07-11 13:34:40 +00001182#if defined(SQLITE_ENABLE_SESSION)
1183/*
1184** State information for a single open session
1185*/
1186typedef struct OpenSession OpenSession;
1187struct OpenSession {
1188 char *zName; /* Symbolic name for this session */
1189 int nFilter; /* Number of xFilter rejection GLOB patterns */
1190 char **azFilter; /* Array of xFilter rejection GLOB patterns */
1191 sqlite3_session *p; /* The open session */
1192};
1193#endif
1194
dan43efc182017-12-19 17:42:13 +00001195typedef struct ExpertInfo ExpertInfo;
1196struct ExpertInfo {
1197 sqlite3expert *pExpert;
1198 int bVerbose;
1199};
1200
drh4b5345c2018-04-24 13:07:40 +00001201/* A single line in the EQP output */
1202typedef struct EQPGraphRow EQPGraphRow;
1203struct EQPGraphRow {
drhe2ca99c2018-05-02 00:33:43 +00001204 int iEqpId; /* ID for this row */
1205 int iParentId; /* ID of the parent row */
drh4b5345c2018-04-24 13:07:40 +00001206 EQPGraphRow *pNext; /* Next row in sequence */
1207 char zText[1]; /* Text to display for this row */
1208};
1209
1210/* All EQP output is collected into an instance of the following */
1211typedef struct EQPGraph EQPGraph;
1212struct EQPGraph {
1213 EQPGraphRow *pRow; /* Linked list of all rows of the EQP output */
1214 EQPGraphRow *pLast; /* Last element of the pRow list */
1215 char zPrefix[100]; /* Graph prefix */
1216};
1217
larrybrcc4d55c2022-02-01 02:50:45 +00001218/* Parameters affecting columnar mode result display (defaulting together) */
1219typedef struct ColModeOpts {
1220 int iWrap; /* In columnar modes, wrap lines reaching this limit */
1221 u8 bQuote; /* Quote results for .mode box and table */
1222 u8 bWordWrap; /* In columnar modes, wrap at word boundaries */
1223} ColModeOpts;
1224#define ColModeOpts_default { 60, 0, 0 }
1225#define ColModeOpts_default_qbox { 60, 1, 0 }
larrybrcc4d55c2022-02-01 02:50:45 +00001226
drh2ce15c32017-07-11 13:34:40 +00001227/*
1228** State information about the database connection is contained in an
1229** instance of the following structure.
1230*/
1231typedef struct ShellState ShellState;
1232struct ShellState {
1233 sqlite3 *db; /* The database */
drh1fa6d9f2018-01-06 21:46:01 +00001234 u8 autoExplain; /* Automatically turn on .explain mode */
1235 u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
drhe2ca99c2018-05-02 00:33:43 +00001236 u8 autoEQPtest; /* autoEQP is in test mode */
drhb4e50392019-01-26 15:40:04 +00001237 u8 autoEQPtrace; /* autoEQP is in trace mode */
drh1fa6d9f2018-01-06 21:46:01 +00001238 u8 scanstatsOn; /* True to display scan stats before each finalize */
1239 u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
drh13c20932018-01-10 21:41:55 +00001240 u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */
drh4b5345c2018-04-24 13:07:40 +00001241 u8 nEqpLevel; /* Depth of the EQP output graph */
drh707821f2018-12-05 13:39:06 +00001242 u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
drhb97e2ad2021-08-26 18:31:39 +00001243 u8 bSafeMode; /* True to prohibit unsafe operations */
1244 u8 bSafeModePersist; /* The long-term value of bSafeMode */
larrybrcc4d55c2022-02-01 02:50:45 +00001245 ColModeOpts cmOpts; /* Option values affecting columnar mode output */
drha6e6cf22021-01-09 19:10:04 +00001246 unsigned statsOn; /* True to display memory stats before each finalize */
drh4b5345c2018-04-24 13:07:40 +00001247 unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */
larrybrd48e88e2022-01-24 06:36:16 +00001248 int inputNesting; /* Track nesting level of .read and other redirects */
drh2ce15c32017-07-11 13:34:40 +00001249 int outCount; /* Revert to stdout when reaching zero */
1250 int cnt; /* Number of records displayed so far */
drh2c8ee022018-12-13 18:59:30 +00001251 int lineno; /* Line number of last line read from in */
drh0933aad2019-11-18 17:46:38 +00001252 int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */
drh60379d42018-12-13 18:30:01 +00001253 FILE *in; /* Read commands from this stream */
drh2ce15c32017-07-11 13:34:40 +00001254 FILE *out; /* Write results here */
1255 FILE *traceOut; /* Output for sqlite3_trace() */
1256 int nErr; /* Number of errors seen */
1257 int mode; /* An output mode setting */
drh3c484e82018-01-10 22:27:21 +00001258 int modePrior; /* Saved mode */
drh2ce15c32017-07-11 13:34:40 +00001259 int cMode; /* temporary output mode for the current query */
1260 int normalMode; /* Output mode before ".explain on" */
1261 int writableSchema; /* True if PRAGMA writable_schema=ON */
1262 int showHeader; /* True to show column names in List or Column mode */
1263 int nCheck; /* Number of ".check" commands run */
drh3f83f592019-02-04 14:53:18 +00001264 unsigned nProgress; /* Number of progress callbacks encountered */
1265 unsigned mxProgress; /* Maximum progress callbacks before failing */
1266 unsigned flgProgress; /* Flags for the progress callback */
drh2ce15c32017-07-11 13:34:40 +00001267 unsigned shellFlgs; /* Various flags */
drh7a431002020-04-18 14:12:00 +00001268 unsigned priorShFlgs; /* Saved copy of flags */
drh6ca64482019-01-22 16:06:20 +00001269 sqlite3_int64 szMax; /* --maxsize argument to .open */
drh2ce15c32017-07-11 13:34:40 +00001270 char *zDestTable; /* Name of destination table when MODE_Insert */
drh13c20932018-01-10 21:41:55 +00001271 char *zTempFile; /* Temporary file that might need deleting */
drh2ce15c32017-07-11 13:34:40 +00001272 char zTestcase[30]; /* Name of current test case */
1273 char colSeparator[20]; /* Column separator character for several modes */
1274 char rowSeparator[20]; /* Row separator character for MODE_Ascii */
drh3c484e82018-01-10 22:27:21 +00001275 char colSepPrior[20]; /* Saved column separator */
1276 char rowSepPrior[20]; /* Saved row separator */
drh0285d982020-05-29 14:38:43 +00001277 int *colWidth; /* Requested width of each column in columnar modes */
1278 int *actualWidth; /* Actual width of each column */
1279 int nWidth; /* Number of slots in colWidth[] and actualWidth[] */
drh2ce15c32017-07-11 13:34:40 +00001280 char nullValue[20]; /* The text to print when a NULL comes back from
1281 ** the database */
1282 char outfile[FILENAME_MAX]; /* Filename for *out */
drh2ce15c32017-07-11 13:34:40 +00001283 sqlite3_stmt *pStmt; /* Current statement if any. */
1284 FILE *pLog; /* Write log output here */
drh37407122021-07-23 18:43:58 +00001285 struct AuxDb { /* Storage space for auxiliary database connections */
1286 sqlite3 *db; /* Connection pointer */
1287 const char *zDbFilename; /* Filename used to open the connection */
1288 char *zFreeOnClose; /* Free this memory allocation on close */
1289#if defined(SQLITE_ENABLE_SESSION)
1290 int nSession; /* Number of active sessions */
1291 OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */
1292#endif
1293 } aAuxDb[5], /* Array of all database connections */
1294 *pAuxDb; /* Currently active database connection */
drh2ce15c32017-07-11 13:34:40 +00001295 int *aiIndent; /* Array of indents used in MODE_Explain */
1296 int nIndent; /* Size of array aiIndent[] */
1297 int iIndent; /* Index of current op in aiIndent[] */
drhb97e2ad2021-08-26 18:31:39 +00001298 char *zNonce; /* Nonce for temporary safe-mode excapes */
drh4b5345c2018-04-24 13:07:40 +00001299 EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */
drhb97e2ad2021-08-26 18:31:39 +00001300 ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */
stephan4413ec72022-07-12 15:53:02 +00001301#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +00001302 struct {
1303 const char * zInput; /* Input string from wasm/JS proxy */
stephan0076e492022-05-18 18:10:17 +00001304 const char * zPos; /* Cursor pos into zInput */
stephan60d9aa72022-09-24 07:36:45 +00001305 const char * zDefaultDbName; /* Default name for db file */
stephanf8cd3d22022-05-18 17:14:24 +00001306 } wasm;
1307#endif
drh2ce15c32017-07-11 13:34:40 +00001308};
1309
stephan4413ec72022-07-12 15:53:02 +00001310#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +00001311static ShellState shellState;
1312#endif
1313
drh1fa6d9f2018-01-06 21:46:01 +00001314
drhada70452017-12-21 21:02:27 +00001315/* Allowed values for ShellState.autoEQP
1316*/
drhe2ca99c2018-05-02 00:33:43 +00001317#define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */
1318#define AUTOEQP_on 1 /* Automatic EQP is on */
1319#define AUTOEQP_trigger 2 /* On and also show plans for triggers */
1320#define AUTOEQP_full 3 /* Show full EXPLAIN */
drhada70452017-12-21 21:02:27 +00001321
drh1fa6d9f2018-01-06 21:46:01 +00001322/* Allowed values for ShellState.openMode
1323*/
drh60f34ae2018-10-30 13:19:49 +00001324#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */
1325#define SHELL_OPEN_NORMAL 1 /* Normal database file */
1326#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */
1327#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */
1328#define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */
1329#define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */
drh33746482018-12-13 15:06:26 +00001330#define SHELL_OPEN_HEXDB 6 /* Use "dbtotxt" output as data source */
drh1fa6d9f2018-01-06 21:46:01 +00001331
drh707821f2018-12-05 13:39:06 +00001332/* Allowed values for ShellState.eTraceType
1333*/
1334#define SHELL_TRACE_PLAIN 0 /* Show input SQL text */
1335#define SHELL_TRACE_EXPANDED 1 /* Show expanded SQL text */
1336#define SHELL_TRACE_NORMALIZED 2 /* Show normalized SQL text */
1337
drh3f83f592019-02-04 14:53:18 +00001338/* Bits in the ShellState.flgProgress variable */
drhfc4eeef2019-02-05 19:48:46 +00001339#define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */
1340#define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progres
1341 ** callback limit is reached, and for each
1342 ** top-level SQL statement */
1343#define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
drh3f83f592019-02-04 14:53:18 +00001344
drh2ce15c32017-07-11 13:34:40 +00001345/*
1346** These are the allowed shellFlgs values
1347*/
drhb2a0f752017-08-28 15:51:35 +00001348#define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
1349#define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
1350#define SHFLG_Backslash 0x00000004 /* The --backslash option is used */
1351#define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */
1352#define SHFLG_Newlines 0x00000010 /* .dump --newline flag */
1353#define SHFLG_CountChanges 0x00000020 /* .changes setting */
larrybr527c39d2022-05-10 14:55:45 +00001354#define SHFLG_Echo 0x00000040 /* .echo on/off, or --echo setting */
larrybrae509122021-09-10 01:45:20 +00001355#define SHFLG_HeaderSet 0x00000080 /* showHeader has been specified */
drhc1962192020-10-12 16:54:28 +00001356#define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */
1357#define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */
drh2ce15c32017-07-11 13:34:40 +00001358
1359/*
1360** Macros for testing and setting shellFlgs
1361*/
1362#define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0)
1363#define ShellSetFlag(P,X) ((P)->shellFlgs|=(X))
1364#define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X)))
1365
1366/*
1367** These are the allowed modes.
1368*/
1369#define MODE_Line 0 /* One column per line. Blank line between records */
1370#define MODE_Column 1 /* One record per line in neat columns */
1371#define MODE_List 2 /* One record per line with a separator */
1372#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
1373#define MODE_Html 4 /* Generate an XHTML table */
1374#define MODE_Insert 5 /* Generate SQL "insert" statements */
1375#define MODE_Quote 6 /* Quote values as for SQL */
1376#define MODE_Tcl 7 /* Generate ANSI-C or TCL quoted elements */
1377#define MODE_Csv 8 /* Quote strings, numbers are plain */
1378#define MODE_Explain 9 /* Like MODE_Column, but do not truncate data */
1379#define MODE_Ascii 10 /* Use ASCII unit and record separators (0x1F/0x1E) */
1380#define MODE_Pretty 11 /* Pretty-print schemas */
drh4b5345c2018-04-24 13:07:40 +00001381#define MODE_EQP 12 /* Converts EXPLAIN QUERY PLAN output into a graph */
drh30c54a02020-05-28 23:49:50 +00001382#define MODE_Json 13 /* Output JSON */
1383#define MODE_Markdown 14 /* Markdown formatting */
1384#define MODE_Table 15 /* MySQL-style table formatting */
drh0908e382020-06-04 18:05:39 +00001385#define MODE_Box 16 /* Unicode box-drawing characters */
drh5d88be82021-12-09 16:17:43 +00001386#define MODE_Count 17 /* Output only a count of the rows of output */
1387#define MODE_Off 18 /* No query output shown */
drh2ce15c32017-07-11 13:34:40 +00001388
1389static const char *modeDescr[] = {
1390 "line",
1391 "column",
1392 "list",
1393 "semi",
1394 "html",
1395 "insert",
1396 "quote",
1397 "tcl",
1398 "csv",
1399 "explain",
1400 "ascii",
1401 "prettyprint",
drh30c54a02020-05-28 23:49:50 +00001402 "eqp",
1403 "json",
1404 "markdown",
drh0908e382020-06-04 18:05:39 +00001405 "table",
drh5d88be82021-12-09 16:17:43 +00001406 "box",
1407 "count",
1408 "off"
drh2ce15c32017-07-11 13:34:40 +00001409};
1410
1411/*
1412** These are the column/row/line separators used by the various
1413** import/export modes.
1414*/
1415#define SEP_Column "|"
1416#define SEP_Row "\n"
1417#define SEP_Tab "\t"
1418#define SEP_Space " "
1419#define SEP_Comma ","
1420#define SEP_CrLf "\r\n"
1421#define SEP_Unit "\x1F"
1422#define SEP_Record "\x1E"
1423
1424/*
larrybrd48e88e2022-01-24 06:36:16 +00001425** Limit input nesting via .read or any other input redirect.
1426** It's not too expensive, so a generous allowance can be made.
1427*/
1428#define MAX_INPUT_NESTING 25
1429
1430/*
drh2ce15c32017-07-11 13:34:40 +00001431** A callback for the sqlite3_log() interface.
1432*/
1433static void shellLog(void *pArg, int iErrCode, const char *zMsg){
1434 ShellState *p = (ShellState*)pArg;
1435 if( p->pLog==0 ) return;
1436 utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
1437 fflush(p->pLog);
1438}
1439
1440/*
drh634c70f2018-01-10 16:50:18 +00001441** SQL function: shell_putsnl(X)
1442**
1443** Write the text X to the screen (or whatever output is being directed)
1444** adding a newline at the end, and then return X.
1445*/
1446static void shellPutsFunc(
1447 sqlite3_context *pCtx,
1448 int nVal,
1449 sqlite3_value **apVal
1450){
1451 ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
drhb9685182018-01-17 13:15:23 +00001452 (void)nVal;
drh634c70f2018-01-10 16:50:18 +00001453 utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
1454 sqlite3_result_value(pCtx, apVal[0]);
1455}
1456
1457/*
drhb97e2ad2021-08-26 18:31:39 +00001458** If in safe mode, print an error message described by the arguments
1459** and exit immediately.
1460*/
1461static void failIfSafeMode(
1462 ShellState *p,
1463 const char *zErrMsg,
1464 ...
1465){
1466 if( p->bSafeMode ){
1467 va_list ap;
1468 char *zMsg;
1469 va_start(ap, zErrMsg);
1470 zMsg = sqlite3_vmprintf(zErrMsg, ap);
1471 va_end(ap);
1472 raw_printf(stderr, "line %d: ", p->lineno);
1473 utf8_printf(stderr, "%s\n", zMsg);
1474 exit(1);
1475 }
1476}
1477
1478/*
drh97913132018-01-11 00:04:00 +00001479** SQL function: edit(VALUE)
1480** edit(VALUE,EDITOR)
1481**
1482** These steps:
1483**
1484** (1) Write VALUE into a temporary file.
1485** (2) Run program EDITOR on that temporary file.
1486** (3) Read the temporary file back and return its content as the result.
1487** (4) Delete the temporary file
1488**
1489** If the EDITOR argument is omitted, use the value in the VISUAL
1490** environment variable. If still there is no EDITOR, through an error.
1491**
1492** Also throw an error if the EDITOR program returns a non-zero exit code.
1493*/
drh04a28c32018-01-31 01:38:44 +00001494#ifndef SQLITE_NOHAVE_SYSTEM
drh97913132018-01-11 00:04:00 +00001495static void editFunc(
1496 sqlite3_context *context,
1497 int argc,
1498 sqlite3_value **argv
1499){
1500 const char *zEditor;
1501 char *zTempFile = 0;
1502 sqlite3 *db;
1503 char *zCmd = 0;
1504 int bBin;
1505 int rc;
drhf018fd52018-08-06 02:08:53 +00001506 int hasCRNL = 0;
drh97913132018-01-11 00:04:00 +00001507 FILE *f = 0;
1508 sqlite3_int64 sz;
1509 sqlite3_int64 x;
1510 unsigned char *p = 0;
1511
1512 if( argc==2 ){
1513 zEditor = (const char*)sqlite3_value_text(argv[1]);
1514 }else{
1515 zEditor = getenv("VISUAL");
1516 }
1517 if( zEditor==0 ){
1518 sqlite3_result_error(context, "no editor for edit()", -1);
1519 return;
1520 }
1521 if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
1522 sqlite3_result_error(context, "NULL input to edit()", -1);
1523 return;
1524 }
1525 db = sqlite3_context_db_handle(context);
1526 zTempFile = 0;
1527 sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, &zTempFile);
1528 if( zTempFile==0 ){
1529 sqlite3_uint64 r = 0;
1530 sqlite3_randomness(sizeof(r), &r);
1531 zTempFile = sqlite3_mprintf("temp%llx", r);
1532 if( zTempFile==0 ){
1533 sqlite3_result_error_nomem(context);
1534 return;
1535 }
1536 }
1537 bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
drhf018fd52018-08-06 02:08:53 +00001538 /* When writing the file to be edited, do \n to \r\n conversions on systems
1539 ** that want \r\n line endings */
drh97913132018-01-11 00:04:00 +00001540 f = fopen(zTempFile, bBin ? "wb" : "w");
1541 if( f==0 ){
1542 sqlite3_result_error(context, "edit() cannot open temp file", -1);
1543 goto edit_func_end;
1544 }
1545 sz = sqlite3_value_bytes(argv[0]);
1546 if( bBin ){
dan4d02b5f2019-07-17 07:23:06 +00001547 x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f);
drh97913132018-01-11 00:04:00 +00001548 }else{
drhf018fd52018-08-06 02:08:53 +00001549 const char *z = (const char*)sqlite3_value_text(argv[0]);
1550 /* Remember whether or not the value originally contained \r\n */
1551 if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1;
dan4d02b5f2019-07-17 07:23:06 +00001552 x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
drh97913132018-01-11 00:04:00 +00001553 }
1554 fclose(f);
1555 f = 0;
1556 if( x!=sz ){
1557 sqlite3_result_error(context, "edit() could not write the whole file", -1);
1558 goto edit_func_end;
1559 }
1560 zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile);
1561 if( zCmd==0 ){
1562 sqlite3_result_error_nomem(context);
1563 goto edit_func_end;
1564 }
1565 rc = system(zCmd);
1566 sqlite3_free(zCmd);
1567 if( rc ){
1568 sqlite3_result_error(context, "EDITOR returned non-zero", -1);
1569 goto edit_func_end;
1570 }
drhf018fd52018-08-06 02:08:53 +00001571 f = fopen(zTempFile, "rb");
drh97913132018-01-11 00:04:00 +00001572 if( f==0 ){
1573 sqlite3_result_error(context,
1574 "edit() cannot reopen temp file after edit", -1);
1575 goto edit_func_end;
1576 }
1577 fseek(f, 0, SEEK_END);
1578 sz = ftell(f);
1579 rewind(f);
drhee37f8b2019-08-23 23:05:32 +00001580 p = sqlite3_malloc64( sz+1 );
drh97913132018-01-11 00:04:00 +00001581 if( p==0 ){
1582 sqlite3_result_error_nomem(context);
1583 goto edit_func_end;
1584 }
dan4d02b5f2019-07-17 07:23:06 +00001585 x = fread(p, 1, (size_t)sz, f);
drh97913132018-01-11 00:04:00 +00001586 fclose(f);
1587 f = 0;
1588 if( x!=sz ){
1589 sqlite3_result_error(context, "could not read back the whole file", -1);
1590 goto edit_func_end;
1591 }
1592 if( bBin ){
mistachkinb71aa092018-01-23 00:05:18 +00001593 sqlite3_result_blob64(context, p, sz, sqlite3_free);
drh97913132018-01-11 00:04:00 +00001594 }else{
dan60bdcf52018-10-03 11:13:30 +00001595 sqlite3_int64 i, j;
drhf018fd52018-08-06 02:08:53 +00001596 if( hasCRNL ){
1597 /* If the original contains \r\n then do no conversions back to \n */
drhf018fd52018-08-06 02:08:53 +00001598 }else{
1599 /* If the file did not originally contain \r\n then convert any new
1600 ** \r\n back into \n */
1601 for(i=j=0; i<sz; i++){
1602 if( p[i]=='\r' && p[i+1]=='\n' ) i++;
1603 p[j++] = p[i];
1604 }
1605 sz = j;
1606 p[sz] = 0;
larrybr0953c532022-12-23 19:04:59 +00001607 }
mistachkinb71aa092018-01-23 00:05:18 +00001608 sqlite3_result_text64(context, (const char*)p, sz,
1609 sqlite3_free, SQLITE_UTF8);
drh97913132018-01-11 00:04:00 +00001610 }
1611 p = 0;
1612
1613edit_func_end:
1614 if( f ) fclose(f);
1615 unlink(zTempFile);
1616 sqlite3_free(zTempFile);
1617 sqlite3_free(p);
1618}
drh04a28c32018-01-31 01:38:44 +00001619#endif /* SQLITE_NOHAVE_SYSTEM */
drh97913132018-01-11 00:04:00 +00001620
1621/*
drh3c484e82018-01-10 22:27:21 +00001622** Save or restore the current output mode
1623*/
1624static void outputModePush(ShellState *p){
1625 p->modePrior = p->mode;
drh7a431002020-04-18 14:12:00 +00001626 p->priorShFlgs = p->shellFlgs;
drh3c484e82018-01-10 22:27:21 +00001627 memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
1628 memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
1629}
1630static void outputModePop(ShellState *p){
1631 p->mode = p->modePrior;
drh7a431002020-04-18 14:12:00 +00001632 p->shellFlgs = p->priorShFlgs;
drh3c484e82018-01-10 22:27:21 +00001633 memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
1634 memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
1635}
1636
1637/*
drh2ce15c32017-07-11 13:34:40 +00001638** Output the given string as a hex-encoded blob (eg. X'1234' )
1639*/
1640static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
1641 int i;
dan2ce2b772022-08-24 11:51:31 +00001642 unsigned char *aBlob = (unsigned char*)pBlob;
1643
1644 char *zStr = sqlite3_malloc(nBlob*2 + 1);
1645 shell_check_oom(zStr);
1646
1647 for(i=0; i<nBlob; i++){
1648 static const char aHex[] = {
1649 '0', '1', '2', '3', '4', '5', '6', '7',
1650 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1651 };
1652 zStr[i*2] = aHex[ (aBlob[i] >> 4) ];
1653 zStr[i*2+1] = aHex[ (aBlob[i] & 0x0F) ];
1654 }
1655 zStr[i*2] = '\0';
1656
1657 raw_printf(out,"X'%s'", zStr);
1658 sqlite3_free(zStr);
drh2ce15c32017-07-11 13:34:40 +00001659}
1660
1661/*
1662** Find a string that is not found anywhere in z[]. Return a pointer
1663** to that string.
1664**
1665** Try to use zA and zB first. If both of those are already found in z[]
1666** then make up some string and store it in the buffer zBuf.
1667*/
1668static const char *unused_string(
1669 const char *z, /* Result must not appear anywhere in z */
1670 const char *zA, const char *zB, /* Try these first */
1671 char *zBuf /* Space to store a generated string */
1672){
1673 unsigned i = 0;
1674 if( strstr(z, zA)==0 ) return zA;
1675 if( strstr(z, zB)==0 ) return zB;
1676 do{
1677 sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
1678 }while( strstr(z,zBuf)!=0 );
1679 return zBuf;
1680}
1681
1682/*
1683** Output the given string as a quoted string using SQL quoting conventions.
1684**
1685** See also: output_quoted_escaped_string()
1686*/
1687static void output_quoted_string(FILE *out, const char *z){
1688 int i;
1689 char c;
1690 setBinaryMode(out, 1);
1691 for(i=0; (c = z[i])!=0 && c!='\''; i++){}
1692 if( c==0 ){
1693 utf8_printf(out,"'%s'",z);
1694 }else{
1695 raw_printf(out, "'");
1696 while( *z ){
1697 for(i=0; (c = z[i])!=0 && c!='\''; i++){}
1698 if( c=='\'' ) i++;
1699 if( i ){
1700 utf8_printf(out, "%.*s", i, z);
1701 z += i;
1702 }
1703 if( c=='\'' ){
1704 raw_printf(out, "'");
1705 continue;
1706 }
1707 if( c==0 ){
1708 break;
1709 }
1710 z++;
1711 }
1712 raw_printf(out, "'");
1713 }
1714 setTextMode(out, 1);
1715}
1716
1717/*
1718** Output the given string as a quoted string using SQL quoting conventions.
1719** Additionallly , escape the "\n" and "\r" characters so that they do not
1720** get corrupted by end-of-line translation facilities in some operating
1721** systems.
1722**
1723** This is like output_quoted_string() but with the addition of the \r\n
1724** escape mechanism.
1725*/
1726static void output_quoted_escaped_string(FILE *out, const char *z){
1727 int i;
1728 char c;
1729 setBinaryMode(out, 1);
1730 for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
1731 if( c==0 ){
1732 utf8_printf(out,"'%s'",z);
1733 }else{
1734 const char *zNL = 0;
1735 const char *zCR = 0;
1736 int nNL = 0;
1737 int nCR = 0;
1738 char zBuf1[20], zBuf2[20];
1739 for(i=0; z[i]; i++){
1740 if( z[i]=='\n' ) nNL++;
1741 if( z[i]=='\r' ) nCR++;
1742 }
1743 if( nNL ){
1744 raw_printf(out, "replace(");
1745 zNL = unused_string(z, "\\n", "\\012", zBuf1);
1746 }
1747 if( nCR ){
1748 raw_printf(out, "replace(");
1749 zCR = unused_string(z, "\\r", "\\015", zBuf2);
1750 }
1751 raw_printf(out, "'");
1752 while( *z ){
1753 for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
1754 if( c=='\'' ) i++;
1755 if( i ){
1756 utf8_printf(out, "%.*s", i, z);
1757 z += i;
1758 }
1759 if( c=='\'' ){
1760 raw_printf(out, "'");
1761 continue;
1762 }
1763 if( c==0 ){
1764 break;
1765 }
1766 z++;
1767 if( c=='\n' ){
1768 raw_printf(out, "%s", zNL);
1769 continue;
1770 }
1771 raw_printf(out, "%s", zCR);
1772 }
1773 raw_printf(out, "'");
1774 if( nCR ){
1775 raw_printf(out, ",'%s',char(13))", zCR);
1776 }
1777 if( nNL ){
1778 raw_printf(out, ",'%s',char(10))", zNL);
1779 }
1780 }
1781 setTextMode(out, 1);
1782}
1783
1784/*
1785** Output the given string as a quoted according to C or TCL quoting rules.
1786*/
1787static void output_c_string(FILE *out, const char *z){
1788 unsigned int c;
1789 fputc('"', out);
1790 while( (c = *(z++))!=0 ){
1791 if( c=='\\' ){
1792 fputc(c, out);
1793 fputc(c, out);
1794 }else if( c=='"' ){
1795 fputc('\\', out);
1796 fputc('"', out);
1797 }else if( c=='\t' ){
1798 fputc('\\', out);
1799 fputc('t', out);
1800 }else if( c=='\n' ){
1801 fputc('\\', out);
1802 fputc('n', out);
1803 }else if( c=='\r' ){
1804 fputc('\\', out);
1805 fputc('r', out);
1806 }else if( !isprint(c&0xff) ){
1807 raw_printf(out, "\\%03o", c&0xff);
1808 }else{
1809 fputc(c, out);
1810 }
1811 }
1812 fputc('"', out);
1813}
1814
1815/*
drh69c093d2020-05-29 00:21:43 +00001816** Output the given string as a quoted according to JSON quoting rules.
1817*/
drh7d23d152022-10-11 12:02:42 +00001818static void output_json_string(FILE *out, const char *z, i64 n){
drh69c093d2020-05-29 00:21:43 +00001819 unsigned int c;
drh7d23d152022-10-11 12:02:42 +00001820 if( n<0 ) n = strlen(z);
drh69c093d2020-05-29 00:21:43 +00001821 fputc('"', out);
1822 while( n-- ){
1823 c = *(z++);
1824 if( c=='\\' || c=='"' ){
1825 fputc('\\', out);
1826 fputc(c, out);
1827 }else if( c<=0x1f ){
1828 fputc('\\', out);
1829 if( c=='\b' ){
1830 fputc('b', out);
1831 }else if( c=='\f' ){
1832 fputc('f', out);
1833 }else if( c=='\n' ){
1834 fputc('n', out);
1835 }else if( c=='\r' ){
1836 fputc('r', out);
1837 }else if( c=='\t' ){
1838 fputc('t', out);
1839 }else{
1840 raw_printf(out, "u%04x",c);
1841 }
1842 }else{
1843 fputc(c, out);
1844 }
1845 }
1846 fputc('"', out);
1847}
1848
1849/*
drh2ce15c32017-07-11 13:34:40 +00001850** Output the given string with characters that are special to
1851** HTML escaped.
1852*/
1853static void output_html_string(FILE *out, const char *z){
1854 int i;
1855 if( z==0 ) z = "";
1856 while( *z ){
1857 for(i=0; z[i]
1858 && z[i]!='<'
1859 && z[i]!='&'
1860 && z[i]!='>'
1861 && z[i]!='\"'
1862 && z[i]!='\'';
1863 i++){}
1864 if( i>0 ){
1865 utf8_printf(out,"%.*s",i,z);
1866 }
1867 if( z[i]=='<' ){
1868 raw_printf(out,"&lt;");
1869 }else if( z[i]=='&' ){
1870 raw_printf(out,"&amp;");
1871 }else if( z[i]=='>' ){
1872 raw_printf(out,"&gt;");
1873 }else if( z[i]=='\"' ){
1874 raw_printf(out,"&quot;");
1875 }else if( z[i]=='\'' ){
1876 raw_printf(out,"&#39;");
1877 }else{
1878 break;
1879 }
1880 z += i + 1;
1881 }
1882}
1883
1884/*
1885** If a field contains any character identified by a 1 in the following
1886** array, then the string must be quoted for CSV.
1887*/
1888static const char needCsvQuote[] = {
1889 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1890 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1891 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1892 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1893 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1894 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1895 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1896 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1897 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1898 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1899 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1900 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1901 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1902 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1903 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1904 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1905};
1906
1907/*
1908** Output a single term of CSV. Actually, p->colSeparator is used for
1909** the separator, which may or may not be a comma. p->nullValue is
1910** the null value. Strings are quoted if necessary. The separator
1911** is only issued if bSep is true.
1912*/
1913static void output_csv(ShellState *p, const char *z, int bSep){
1914 FILE *out = p->out;
1915 if( z==0 ){
1916 utf8_printf(out,"%s",p->nullValue);
1917 }else{
drh9cd0c3d2021-11-18 15:40:05 +00001918 unsigned i;
1919 for(i=0; z[i]; i++){
1920 if( needCsvQuote[((unsigned char*)z)[i]] ){
drh2ce15c32017-07-11 13:34:40 +00001921 i = 0;
1922 break;
1923 }
1924 }
drh9cd0c3d2021-11-18 15:40:05 +00001925 if( i==0 || strstr(z, p->colSeparator)!=0 ){
drh9b7affc2017-11-26 02:14:18 +00001926 char *zQuoted = sqlite3_mprintf("\"%w\"", z);
drhe3e25652021-12-16 13:29:28 +00001927 shell_check_oom(zQuoted);
drh9b7affc2017-11-26 02:14:18 +00001928 utf8_printf(out, "%s", zQuoted);
1929 sqlite3_free(zQuoted);
drh2ce15c32017-07-11 13:34:40 +00001930 }else{
1931 utf8_printf(out, "%s", z);
1932 }
1933 }
1934 if( bSep ){
1935 utf8_printf(p->out, "%s", p->colSeparator);
1936 }
1937}
1938
drh2ce15c32017-07-11 13:34:40 +00001939/*
1940** This routine runs when the user presses Ctrl-C
1941*/
1942static void interrupt_handler(int NotUsed){
1943 UNUSED_PARAMETER(NotUsed);
1944 seenInterrupt++;
1945 if( seenInterrupt>2 ) exit(1);
1946 if( globalDb ) sqlite3_interrupt(globalDb);
1947}
mistachkinb4bab902017-10-27 17:09:44 +00001948
1949#if (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
1950/*
1951** This routine runs for console events (e.g. Ctrl-C) on Win32
1952*/
1953static BOOL WINAPI ConsoleCtrlHandler(
1954 DWORD dwCtrlType /* One of the CTRL_*_EVENT constants */
1955){
1956 if( dwCtrlType==CTRL_C_EVENT ){
1957 interrupt_handler(0);
1958 return TRUE;
1959 }
1960 return FALSE;
1961}
drh2ce15c32017-07-11 13:34:40 +00001962#endif
1963
1964#ifndef SQLITE_OMIT_AUTHORIZATION
1965/*
drhb97e2ad2021-08-26 18:31:39 +00001966** This authorizer runs in safe mode.
1967*/
1968static int safeModeAuth(
1969 void *pClientData,
1970 int op,
1971 const char *zA1,
1972 const char *zA2,
1973 const char *zA3,
1974 const char *zA4
1975){
1976 ShellState *p = (ShellState*)pClientData;
1977 static const char *azProhibitedFunctions[] = {
1978 "edit",
1979 "fts3_tokenizer",
1980 "load_extension",
1981 "readfile",
1982 "writefile",
1983 "zipfile",
1984 "zipfile_cds",
1985 };
larrybr8af6d712022-12-04 23:20:38 +00001986 UNUSED_PARAMETER(zA1);
drhb97e2ad2021-08-26 18:31:39 +00001987 UNUSED_PARAMETER(zA3);
1988 UNUSED_PARAMETER(zA4);
1989 switch( op ){
1990 case SQLITE_ATTACH: {
stephan4413ec72022-07-12 15:53:02 +00001991#ifndef SQLITE_SHELL_FIDDLE
stephan626aa482022-06-06 04:09:44 +00001992 /* In WASM builds the filesystem is a virtual sandbox, so
1993 ** there's no harm in using ATTACH. */
drhb97e2ad2021-08-26 18:31:39 +00001994 failIfSafeMode(p, "cannot run ATTACH in safe mode");
stephan626aa482022-06-06 04:09:44 +00001995#endif
drhb97e2ad2021-08-26 18:31:39 +00001996 break;
1997 }
1998 case SQLITE_FUNCTION: {
1999 int i;
2000 for(i=0; i<ArraySize(azProhibitedFunctions); i++){
larrybr8af6d712022-12-04 23:20:38 +00002001 if( sqlite3_stricmp(zA2, azProhibitedFunctions[i])==0 ){
drhb97e2ad2021-08-26 18:31:39 +00002002 failIfSafeMode(p, "cannot use the %s() function in safe mode",
2003 azProhibitedFunctions[i]);
2004 }
2005 }
2006 break;
2007 }
2008 }
2009 return SQLITE_OK;
2010}
2011
2012/*
drh2ce15c32017-07-11 13:34:40 +00002013** When the ".auth ON" is set, the following authorizer callback is
2014** invoked. It always returns SQLITE_OK.
2015*/
2016static int shellAuth(
2017 void *pClientData,
2018 int op,
2019 const char *zA1,
2020 const char *zA2,
2021 const char *zA3,
2022 const char *zA4
2023){
2024 ShellState *p = (ShellState*)pClientData;
2025 static const char *azAction[] = { 0,
2026 "CREATE_INDEX", "CREATE_TABLE", "CREATE_TEMP_INDEX",
2027 "CREATE_TEMP_TABLE", "CREATE_TEMP_TRIGGER", "CREATE_TEMP_VIEW",
2028 "CREATE_TRIGGER", "CREATE_VIEW", "DELETE",
2029 "DROP_INDEX", "DROP_TABLE", "DROP_TEMP_INDEX",
2030 "DROP_TEMP_TABLE", "DROP_TEMP_TRIGGER", "DROP_TEMP_VIEW",
2031 "DROP_TRIGGER", "DROP_VIEW", "INSERT",
2032 "PRAGMA", "READ", "SELECT",
2033 "TRANSACTION", "UPDATE", "ATTACH",
2034 "DETACH", "ALTER_TABLE", "REINDEX",
2035 "ANALYZE", "CREATE_VTABLE", "DROP_VTABLE",
2036 "FUNCTION", "SAVEPOINT", "RECURSIVE"
2037 };
2038 int i;
2039 const char *az[4];
2040 az[0] = zA1;
2041 az[1] = zA2;
2042 az[2] = zA3;
2043 az[3] = zA4;
2044 utf8_printf(p->out, "authorizer: %s", azAction[op]);
2045 for(i=0; i<4; i++){
2046 raw_printf(p->out, " ");
2047 if( az[i] ){
2048 output_c_string(p->out, az[i]);
2049 }else{
2050 raw_printf(p->out, "NULL");
2051 }
2052 }
2053 raw_printf(p->out, "\n");
drhb97e2ad2021-08-26 18:31:39 +00002054 if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
drh2ce15c32017-07-11 13:34:40 +00002055 return SQLITE_OK;
2056}
2057#endif
2058
2059/*
2060** Print a schema statement. Part of MODE_Semi and MODE_Pretty output.
2061**
2062** This routine converts some CREATE TABLE statements for shadow tables
2063** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
drh78ed74e2022-08-17 20:18:34 +00002064**
2065** If the schema statement in z[] contains a start-of-comment and if
2066** sqlite3_complete() returns false, try to terminate the comment before
2067** printing the result. https://sqlite.org/forum/forumpost/d7be961c5c
drh2ce15c32017-07-11 13:34:40 +00002068*/
2069static void printSchemaLine(FILE *out, const char *z, const char *zTail){
drh78ed74e2022-08-17 20:18:34 +00002070 char *zToFree = 0;
drh0a0536a2019-05-09 18:13:30 +00002071 if( z==0 ) return;
2072 if( zTail==0 ) return;
drh78ed74e2022-08-17 20:18:34 +00002073 if( zTail[0]==';' && (strstr(z, "/*")!=0 || strstr(z,"--")!=0) ){
2074 const char *zOrig = z;
2075 static const char *azTerm[] = { "", "*/", "\n" };
2076 int i;
2077 for(i=0; i<ArraySize(azTerm); i++){
2078 char *zNew = sqlite3_mprintf("%s%s;", zOrig, azTerm[i]);
2079 if( sqlite3_complete(zNew) ){
2080 size_t n = strlen(zNew);
2081 zNew[n-1] = 0;
2082 zToFree = zNew;
2083 z = zNew;
2084 break;
2085 }
2086 sqlite3_free(zNew);
2087 }
2088 }
drh2ce15c32017-07-11 13:34:40 +00002089 if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
2090 utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
2091 }else{
2092 utf8_printf(out, "%s%s", z, zTail);
2093 }
drh78ed74e2022-08-17 20:18:34 +00002094 sqlite3_free(zToFree);
drh2ce15c32017-07-11 13:34:40 +00002095}
2096static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
2097 char c = z[n];
2098 z[n] = 0;
2099 printSchemaLine(out, z, zTail);
2100 z[n] = c;
2101}
2102
2103/*
drh11be81d2018-01-06 15:46:20 +00002104** Return true if string z[] has nothing but whitespace and comments to the
2105** end of the first line.
2106*/
2107static int wsToEol(const char *z){
2108 int i;
2109 for(i=0; z[i]; i++){
2110 if( z[i]=='\n' ) return 1;
2111 if( IsSpace(z[i]) ) continue;
2112 if( z[i]=='-' && z[i+1]=='-' ) return 1;
2113 return 0;
2114 }
2115 return 1;
2116}
drh4b5345c2018-04-24 13:07:40 +00002117
2118/*
2119** Add a new entry to the EXPLAIN QUERY PLAN data
2120*/
drhe2ca99c2018-05-02 00:33:43 +00002121static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){
drh4b5345c2018-04-24 13:07:40 +00002122 EQPGraphRow *pNew;
drh8be89242022-10-17 16:09:33 +00002123 i64 nText;
2124 if( zText==0 ) return;
2125 nText = strlen(zText);
drhe2ca99c2018-05-02 00:33:43 +00002126 if( p->autoEQPtest ){
2127 utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
2128 }
drh4b5345c2018-04-24 13:07:40 +00002129 pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
drhe3e25652021-12-16 13:29:28 +00002130 shell_check_oom(pNew);
drhe2ca99c2018-05-02 00:33:43 +00002131 pNew->iEqpId = iEqpId;
2132 pNew->iParentId = p2;
drh4b5345c2018-04-24 13:07:40 +00002133 memcpy(pNew->zText, zText, nText+1);
2134 pNew->pNext = 0;
2135 if( p->sGraph.pLast ){
2136 p->sGraph.pLast->pNext = pNew;
2137 }else{
2138 p->sGraph.pRow = pNew;
2139 }
2140 p->sGraph.pLast = pNew;
2141}
2142
2143/*
2144** Free and reset the EXPLAIN QUERY PLAN data that has been collected
2145** in p->sGraph.
2146*/
2147static void eqp_reset(ShellState *p){
2148 EQPGraphRow *pRow, *pNext;
2149 for(pRow = p->sGraph.pRow; pRow; pRow = pNext){
2150 pNext = pRow->pNext;
2151 sqlite3_free(pRow);
2152 }
2153 memset(&p->sGraph, 0, sizeof(p->sGraph));
2154}
2155
drhe2ca99c2018-05-02 00:33:43 +00002156/* Return the next EXPLAIN QUERY PLAN line with iEqpId that occurs after
drh4b5345c2018-04-24 13:07:40 +00002157** pOld, or return the first such line if pOld is NULL
2158*/
drhe2ca99c2018-05-02 00:33:43 +00002159static EQPGraphRow *eqp_next_row(ShellState *p, int iEqpId, EQPGraphRow *pOld){
drh4b5345c2018-04-24 13:07:40 +00002160 EQPGraphRow *pRow = pOld ? pOld->pNext : p->sGraph.pRow;
drhe2ca99c2018-05-02 00:33:43 +00002161 while( pRow && pRow->iParentId!=iEqpId ) pRow = pRow->pNext;
drh4b5345c2018-04-24 13:07:40 +00002162 return pRow;
2163}
2164
drhe2ca99c2018-05-02 00:33:43 +00002165/* Render a single level of the graph that has iEqpId as its parent. Called
drh4b5345c2018-04-24 13:07:40 +00002166** recursively to render sublevels.
2167*/
drhe2ca99c2018-05-02 00:33:43 +00002168static void eqp_render_level(ShellState *p, int iEqpId){
drh4b5345c2018-04-24 13:07:40 +00002169 EQPGraphRow *pRow, *pNext;
drh7d23d152022-10-11 12:02:42 +00002170 i64 n = strlen(p->sGraph.zPrefix);
drh4b5345c2018-04-24 13:07:40 +00002171 char *z;
drhe2ca99c2018-05-02 00:33:43 +00002172 for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
2173 pNext = eqp_next_row(p, iEqpId, pRow);
drh4b5345c2018-04-24 13:07:40 +00002174 z = pRow->zText;
drhe2754c12019-08-26 12:50:01 +00002175 utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix,
2176 pNext ? "|--" : "`--", z);
drh7d23d152022-10-11 12:02:42 +00002177 if( n<(i64)sizeof(p->sGraph.zPrefix)-7 ){
drh4b5345c2018-04-24 13:07:40 +00002178 memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
drhe2ca99c2018-05-02 00:33:43 +00002179 eqp_render_level(p, pRow->iEqpId);
drh4b5345c2018-04-24 13:07:40 +00002180 p->sGraph.zPrefix[n] = 0;
2181 }
2182 }
2183}
2184
2185/*
2186** Display and reset the EXPLAIN QUERY PLAN data
2187*/
dan231ff4b2022-12-02 20:32:22 +00002188static void eqp_render(ShellState *p, i64 nCycle){
drh4b5345c2018-04-24 13:07:40 +00002189 EQPGraphRow *pRow = p->sGraph.pRow;
2190 if( pRow ){
2191 if( pRow->zText[0]=='-' ){
2192 if( pRow->pNext==0 ){
2193 eqp_reset(p);
2194 return;
2195 }
2196 utf8_printf(p->out, "%s\n", pRow->zText+3);
2197 p->sGraph.pRow = pRow->pNext;
2198 sqlite3_free(pRow);
dan231ff4b2022-12-02 20:32:22 +00002199 }else if( nCycle>0 ){
2200 utf8_printf(p->out, "QUERY PLAN (cycles=%lld [100%%])\n", nCycle);
drh4b5345c2018-04-24 13:07:40 +00002201 }else{
2202 utf8_printf(p->out, "QUERY PLAN\n");
2203 }
2204 p->sGraph.zPrefix[0] = 0;
2205 eqp_render_level(p, 0);
2206 eqp_reset(p);
2207 }
2208}
drh11be81d2018-01-06 15:46:20 +00002209
drh569b1d92019-02-05 20:51:41 +00002210#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
drh11be81d2018-01-06 15:46:20 +00002211/*
drh3f83f592019-02-04 14:53:18 +00002212** Progress handler callback.
2213*/
2214static int progress_handler(void *pClientData) {
2215 ShellState *p = (ShellState*)pClientData;
2216 p->nProgress++;
2217 if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){
2218 raw_printf(p->out, "Progress limit reached (%u)\n", p->nProgress);
drhfc4eeef2019-02-05 19:48:46 +00002219 if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
2220 if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0;
drh3f83f592019-02-04 14:53:18 +00002221 return 1;
2222 }
drhfc4eeef2019-02-05 19:48:46 +00002223 if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){
drh3f83f592019-02-04 14:53:18 +00002224 raw_printf(p->out, "Progress %u\n", p->nProgress);
2225 }
2226 return 0;
2227}
drh569b1d92019-02-05 20:51:41 +00002228#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
drh3f83f592019-02-04 14:53:18 +00002229
2230/*
drh30c54a02020-05-28 23:49:50 +00002231** Print N dashes
2232*/
2233static void print_dashes(FILE *out, int N){
2234 const char zDash[] = "--------------------------------------------------";
2235 const int nDash = sizeof(zDash) - 1;
2236 while( N>nDash ){
2237 fputs(zDash, out);
2238 N -= nDash;
2239 }
2240 raw_printf(out, "%.*s", N, zDash);
2241}
2242
2243/*
drh0908e382020-06-04 18:05:39 +00002244** Print a markdown or table-style row separator using ascii-art
drh30c54a02020-05-28 23:49:50 +00002245*/
2246static void print_row_separator(
2247 ShellState *p,
2248 int nArg,
2249 const char *zSep
2250){
2251 int i;
drh0908e382020-06-04 18:05:39 +00002252 if( nArg>0 ){
drh30c54a02020-05-28 23:49:50 +00002253 fputs(zSep, p->out);
drh0908e382020-06-04 18:05:39 +00002254 print_dashes(p->out, p->actualWidth[0]+2);
2255 for(i=1; i<nArg; i++){
2256 fputs(zSep, p->out);
2257 print_dashes(p->out, p->actualWidth[i]+2);
2258 }
2259 fputs(zSep, p->out);
drh30c54a02020-05-28 23:49:50 +00002260 }
drh30c54a02020-05-28 23:49:50 +00002261 fputs("\n", p->out);
2262}
2263
2264/*
drh2ce15c32017-07-11 13:34:40 +00002265** This is the callback routine that the shell
2266** invokes for each row of a query result.
2267*/
2268static int shell_callback(
2269 void *pArg,
2270 int nArg, /* Number of result columns */
2271 char **azArg, /* Text of each result column */
2272 char **azCol, /* Column names */
drhd6f25242020-05-29 12:31:53 +00002273 int *aiType /* Column types. Might be NULL */
drh2ce15c32017-07-11 13:34:40 +00002274){
2275 int i;
2276 ShellState *p = (ShellState*)pArg;
2277
drhb3c45232017-08-28 14:33:27 +00002278 if( azArg==0 ) return 0;
drh2ce15c32017-07-11 13:34:40 +00002279 switch( p->cMode ){
drh5d88be82021-12-09 16:17:43 +00002280 case MODE_Count:
2281 case MODE_Off: {
2282 break;
2283 }
drh2ce15c32017-07-11 13:34:40 +00002284 case MODE_Line: {
2285 int w = 5;
2286 if( azArg==0 ) break;
2287 for(i=0; i<nArg; i++){
2288 int len = strlen30(azCol[i] ? azCol[i] : "");
2289 if( len>w ) w = len;
2290 }
2291 if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator);
2292 for(i=0; i<nArg; i++){
2293 utf8_printf(p->out,"%*s = %s%s", w, azCol[i],
2294 azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
2295 }
2296 break;
2297 }
drh8c748632020-05-29 16:15:58 +00002298 case MODE_Explain: {
2299 static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
2300 if( nArg>ArraySize(aExplainWidth) ){
2301 nArg = ArraySize(aExplainWidth);
drh2ce15c32017-07-11 13:34:40 +00002302 }
2303 if( p->cnt++==0 ){
2304 for(i=0; i<nArg; i++){
drh8c748632020-05-29 16:15:58 +00002305 int w = aExplainWidth[i];
2306 utf8_width_print(p->out, w, azCol[i]);
2307 fputs(i==nArg-1 ? "\n" : " ", p->out);
drh2ce15c32017-07-11 13:34:40 +00002308 }
drhe566ceb2020-05-30 15:34:49 +00002309 for(i=0; i<nArg; i++){
2310 int w = aExplainWidth[i];
2311 print_dashes(p->out, w);
2312 fputs(i==nArg-1 ? "\n" : " ", p->out);
2313 }
drh2ce15c32017-07-11 13:34:40 +00002314 }
2315 if( azArg==0 ) break;
2316 for(i=0; i<nArg; i++){
drh8c748632020-05-29 16:15:58 +00002317 int w = aExplainWidth[i];
drhaa556b02021-01-13 12:59:20 +00002318 if( i==nArg-1 ) w = 0;
drh8c748632020-05-29 16:15:58 +00002319 if( azArg[i] && strlenChar(azArg[i])>w ){
2320 w = strlenChar(azArg[i]);
drh2ce15c32017-07-11 13:34:40 +00002321 }
drh8c748632020-05-29 16:15:58 +00002322 if( i==1 && p->aiIndent && p->pStmt ){
2323 if( p->iIndent<p->nIndent ){
2324 utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
drh2ce15c32017-07-11 13:34:40 +00002325 }
drh8c748632020-05-29 16:15:58 +00002326 p->iIndent++;
drh2ce15c32017-07-11 13:34:40 +00002327 }
2328 utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
drh8c748632020-05-29 16:15:58 +00002329 fputs(i==nArg-1 ? "\n" : " ", p->out);
drh2ce15c32017-07-11 13:34:40 +00002330 }
2331 break;
2332 }
2333 case MODE_Semi: { /* .schema and .fullschema output */
2334 printSchemaLine(p->out, azArg[0], ";\n");
2335 break;
2336 }
2337 case MODE_Pretty: { /* .schema and .fullschema with --indent */
2338 char *z;
2339 int j;
2340 int nParen = 0;
2341 char cEnd = 0;
2342 char c;
2343 int nLine = 0;
2344 assert( nArg==1 );
2345 if( azArg[0]==0 ) break;
2346 if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
2347 || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
2348 ){
2349 utf8_printf(p->out, "%s;\n", azArg[0]);
2350 break;
2351 }
2352 z = sqlite3_mprintf("%s", azArg[0]);
drhe3e25652021-12-16 13:29:28 +00002353 shell_check_oom(z);
drh2ce15c32017-07-11 13:34:40 +00002354 j = 0;
2355 for(i=0; IsSpace(z[i]); i++){}
2356 for(; (c = z[i])!=0; i++){
2357 if( IsSpace(c) ){
drhc3cbd672017-10-05 19:12:10 +00002358 if( z[j-1]=='\r' ) z[j-1] = '\n';
drh2ce15c32017-07-11 13:34:40 +00002359 if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
2360 }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
2361 j--;
2362 }
2363 z[j++] = c;
2364 }
2365 while( j>0 && IsSpace(z[j-1]) ){ j--; }
2366 z[j] = 0;
2367 if( strlen30(z)>=79 ){
drhe2754c12019-08-26 12:50:01 +00002368 for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */
drh2ce15c32017-07-11 13:34:40 +00002369 if( c==cEnd ){
2370 cEnd = 0;
2371 }else if( c=='"' || c=='\'' || c=='`' ){
2372 cEnd = c;
2373 }else if( c=='[' ){
2374 cEnd = ']';
drh11be81d2018-01-06 15:46:20 +00002375 }else if( c=='-' && z[i+1]=='-' ){
2376 cEnd = '\n';
drh2ce15c32017-07-11 13:34:40 +00002377 }else if( c=='(' ){
2378 nParen++;
2379 }else if( c==')' ){
2380 nParen--;
2381 if( nLine>0 && nParen==0 && j>0 ){
2382 printSchemaLineN(p->out, z, j, "\n");
2383 j = 0;
2384 }
2385 }
2386 z[j++] = c;
drh11be81d2018-01-06 15:46:20 +00002387 if( nParen==1 && cEnd==0
2388 && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
2389 ){
drh2ce15c32017-07-11 13:34:40 +00002390 if( c=='\n' ) j--;
2391 printSchemaLineN(p->out, z, j, "\n ");
2392 j = 0;
2393 nLine++;
2394 while( IsSpace(z[i+1]) ){ i++; }
2395 }
2396 }
2397 z[j] = 0;
2398 }
2399 printSchemaLine(p->out, z, ";\n");
2400 sqlite3_free(z);
2401 break;
2402 }
2403 case MODE_List: {
2404 if( p->cnt++==0 && p->showHeader ){
2405 for(i=0; i<nArg; i++){
2406 utf8_printf(p->out,"%s%s",azCol[i],
2407 i==nArg-1 ? p->rowSeparator : p->colSeparator);
2408 }
2409 }
2410 if( azArg==0 ) break;
2411 for(i=0; i<nArg; i++){
2412 char *z = azArg[i];
2413 if( z==0 ) z = p->nullValue;
2414 utf8_printf(p->out, "%s", z);
2415 if( i<nArg-1 ){
2416 utf8_printf(p->out, "%s", p->colSeparator);
2417 }else{
2418 utf8_printf(p->out, "%s", p->rowSeparator);
2419 }
2420 }
2421 break;
2422 }
2423 case MODE_Html: {
2424 if( p->cnt++==0 && p->showHeader ){
2425 raw_printf(p->out,"<TR>");
2426 for(i=0; i<nArg; i++){
2427 raw_printf(p->out,"<TH>");
2428 output_html_string(p->out, azCol[i]);
2429 raw_printf(p->out,"</TH>\n");
2430 }
2431 raw_printf(p->out,"</TR>\n");
2432 }
2433 if( azArg==0 ) break;
2434 raw_printf(p->out,"<TR>");
2435 for(i=0; i<nArg; i++){
2436 raw_printf(p->out,"<TD>");
2437 output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
2438 raw_printf(p->out,"</TD>\n");
2439 }
2440 raw_printf(p->out,"</TR>\n");
2441 break;
2442 }
2443 case MODE_Tcl: {
2444 if( p->cnt++==0 && p->showHeader ){
2445 for(i=0; i<nArg; i++){
2446 output_c_string(p->out,azCol[i] ? azCol[i] : "");
2447 if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
2448 }
2449 utf8_printf(p->out, "%s", p->rowSeparator);
2450 }
2451 if( azArg==0 ) break;
2452 for(i=0; i<nArg; i++){
2453 output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
2454 if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
2455 }
2456 utf8_printf(p->out, "%s", p->rowSeparator);
2457 break;
2458 }
2459 case MODE_Csv: {
2460 setBinaryMode(p->out, 1);
2461 if( p->cnt++==0 && p->showHeader ){
2462 for(i=0; i<nArg; i++){
2463 output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
2464 }
2465 utf8_printf(p->out, "%s", p->rowSeparator);
2466 }
2467 if( nArg>0 ){
2468 for(i=0; i<nArg; i++){
2469 output_csv(p, azArg[i], i<nArg-1);
2470 }
2471 utf8_printf(p->out, "%s", p->rowSeparator);
2472 }
2473 setTextMode(p->out, 1);
2474 break;
2475 }
2476 case MODE_Insert: {
2477 if( azArg==0 ) break;
2478 utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
2479 if( p->showHeader ){
2480 raw_printf(p->out,"(");
2481 for(i=0; i<nArg; i++){
2482 if( i>0 ) raw_printf(p->out, ",");
2483 if( quoteChar(azCol[i]) ){
2484 char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
drhe3e25652021-12-16 13:29:28 +00002485 shell_check_oom(z);
drh2ce15c32017-07-11 13:34:40 +00002486 utf8_printf(p->out, "%s", z);
2487 sqlite3_free(z);
2488 }else{
2489 raw_printf(p->out, "%s", azCol[i]);
2490 }
2491 }
2492 raw_printf(p->out,")");
2493 }
2494 p->cnt++;
2495 for(i=0; i<nArg; i++){
2496 raw_printf(p->out, i>0 ? "," : " VALUES(");
2497 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
2498 utf8_printf(p->out,"NULL");
2499 }else if( aiType && aiType[i]==SQLITE_TEXT ){
2500 if( ShellHasFlag(p, SHFLG_Newlines) ){
2501 output_quoted_string(p->out, azArg[i]);
2502 }else{
2503 output_quoted_escaped_string(p->out, azArg[i]);
2504 }
2505 }else if( aiType && aiType[i]==SQLITE_INTEGER ){
2506 utf8_printf(p->out,"%s", azArg[i]);
2507 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
2508 char z[50];
2509 double r = sqlite3_column_double(p->pStmt, i);
drh2f1f8802018-06-13 17:19:20 +00002510 sqlite3_uint64 ur;
2511 memcpy(&ur,&r,sizeof(r));
2512 if( ur==0x7ff0000000000000LL ){
2513 raw_printf(p->out, "1e999");
2514 }else if( ur==0xfff0000000000000LL ){
2515 raw_printf(p->out, "-1e999");
2516 }else{
drh537a6bf2022-02-15 13:23:09 +00002517 sqlite3_int64 ir = (sqlite3_int64)r;
2518 if( r==(double)ir ){
2519 sqlite3_snprintf(50,z,"%lld.0", ir);
2520 }else{
2521 sqlite3_snprintf(50,z,"%!.20g", r);
2522 }
drh2f1f8802018-06-13 17:19:20 +00002523 raw_printf(p->out, "%s", z);
2524 }
drh2ce15c32017-07-11 13:34:40 +00002525 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
2526 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
2527 int nBlob = sqlite3_column_bytes(p->pStmt, i);
2528 output_hex_blob(p->out, pBlob, nBlob);
2529 }else if( isNumber(azArg[i], 0) ){
2530 utf8_printf(p->out,"%s", azArg[i]);
2531 }else if( ShellHasFlag(p, SHFLG_Newlines) ){
2532 output_quoted_string(p->out, azArg[i]);
2533 }else{
2534 output_quoted_escaped_string(p->out, azArg[i]);
2535 }
2536 }
2537 raw_printf(p->out,");\n");
2538 break;
2539 }
drh30c54a02020-05-28 23:49:50 +00002540 case MODE_Json: {
2541 if( azArg==0 ) break;
2542 if( p->cnt==0 ){
2543 fputs("[{", p->out);
2544 }else{
2545 fputs(",\n{", p->out);
2546 }
2547 p->cnt++;
2548 for(i=0; i<nArg; i++){
drh69c093d2020-05-29 00:21:43 +00002549 output_json_string(p->out, azCol[i], -1);
drh30c54a02020-05-28 23:49:50 +00002550 putc(':', p->out);
2551 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
2552 fputs("null",p->out);
2553 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
2554 char z[50];
2555 double r = sqlite3_column_double(p->pStmt, i);
2556 sqlite3_uint64 ur;
2557 memcpy(&ur,&r,sizeof(r));
2558 if( ur==0x7ff0000000000000LL ){
2559 raw_printf(p->out, "1e999");
2560 }else if( ur==0xfff0000000000000LL ){
2561 raw_printf(p->out, "-1e999");
2562 }else{
2563 sqlite3_snprintf(50,z,"%!.20g", r);
2564 raw_printf(p->out, "%s", z);
2565 }
2566 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
2567 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
2568 int nBlob = sqlite3_column_bytes(p->pStmt, i);
drh69c093d2020-05-29 00:21:43 +00002569 output_json_string(p->out, pBlob, nBlob);
drh30c54a02020-05-28 23:49:50 +00002570 }else if( aiType && aiType[i]==SQLITE_TEXT ){
drh69c093d2020-05-29 00:21:43 +00002571 output_json_string(p->out, azArg[i], -1);
drh30c54a02020-05-28 23:49:50 +00002572 }else{
2573 utf8_printf(p->out,"%s", azArg[i]);
2574 }
2575 if( i<nArg-1 ){
2576 putc(',', p->out);
2577 }
2578 }
2579 putc('}', p->out);
2580 break;
2581 }
drh2ce15c32017-07-11 13:34:40 +00002582 case MODE_Quote: {
2583 if( azArg==0 ) break;
2584 if( p->cnt==0 && p->showHeader ){
2585 for(i=0; i<nArg; i++){
drhc6835732020-05-28 20:37:17 +00002586 if( i>0 ) fputs(p->colSeparator, p->out);
drh2ce15c32017-07-11 13:34:40 +00002587 output_quoted_string(p->out, azCol[i]);
2588 }
drhc6835732020-05-28 20:37:17 +00002589 fputs(p->rowSeparator, p->out);
drh2ce15c32017-07-11 13:34:40 +00002590 }
2591 p->cnt++;
2592 for(i=0; i<nArg; i++){
drhc6835732020-05-28 20:37:17 +00002593 if( i>0 ) fputs(p->colSeparator, p->out);
drh2ce15c32017-07-11 13:34:40 +00002594 if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
2595 utf8_printf(p->out,"NULL");
2596 }else if( aiType && aiType[i]==SQLITE_TEXT ){
2597 output_quoted_string(p->out, azArg[i]);
2598 }else if( aiType && aiType[i]==SQLITE_INTEGER ){
2599 utf8_printf(p->out,"%s", azArg[i]);
2600 }else if( aiType && aiType[i]==SQLITE_FLOAT ){
2601 char z[50];
2602 double r = sqlite3_column_double(p->pStmt, i);
2603 sqlite3_snprintf(50,z,"%!.20g", r);
2604 raw_printf(p->out, "%s", z);
2605 }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
2606 const void *pBlob = sqlite3_column_blob(p->pStmt, i);
2607 int nBlob = sqlite3_column_bytes(p->pStmt, i);
2608 output_hex_blob(p->out, pBlob, nBlob);
2609 }else if( isNumber(azArg[i], 0) ){
2610 utf8_printf(p->out,"%s", azArg[i]);
2611 }else{
2612 output_quoted_string(p->out, azArg[i]);
2613 }
2614 }
drhc6835732020-05-28 20:37:17 +00002615 fputs(p->rowSeparator, p->out);
drh2ce15c32017-07-11 13:34:40 +00002616 break;
2617 }
2618 case MODE_Ascii: {
2619 if( p->cnt++==0 && p->showHeader ){
2620 for(i=0; i<nArg; i++){
2621 if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
2622 utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : "");
2623 }
2624 utf8_printf(p->out, "%s", p->rowSeparator);
2625 }
2626 if( azArg==0 ) break;
2627 for(i=0; i<nArg; i++){
2628 if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
2629 utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
2630 }
2631 utf8_printf(p->out, "%s", p->rowSeparator);
2632 break;
2633 }
drh4b5345c2018-04-24 13:07:40 +00002634 case MODE_EQP: {
drhe2ca99c2018-05-02 00:33:43 +00002635 eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]);
drh4b5345c2018-04-24 13:07:40 +00002636 break;
2637 }
drh2ce15c32017-07-11 13:34:40 +00002638 }
2639 return 0;
2640}
2641
2642/*
2643** This is the callback routine that the SQLite library
2644** invokes for each row of a query result.
2645*/
2646static int callback(void *pArg, int nArg, char **azArg, char **azCol){
2647 /* since we don't have type info, call the shell_callback with a NULL value */
2648 return shell_callback(pArg, nArg, azArg, azCol, NULL);
2649}
2650
2651/*
2652** This is the callback routine from sqlite3_exec() that appends all
2653** output onto the end of a ShellText object.
2654*/
2655static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
2656 ShellText *p = (ShellText*)pArg;
2657 int i;
2658 UNUSED_PARAMETER(az);
drhb3c45232017-08-28 14:33:27 +00002659 if( azArg==0 ) return 0;
drh2ce15c32017-07-11 13:34:40 +00002660 if( p->n ) appendText(p, "|", 0);
2661 for(i=0; i<nArg; i++){
2662 if( i ) appendText(p, ",", 0);
2663 if( azArg[i] ) appendText(p, azArg[i], 0);
2664 }
2665 return 0;
2666}
2667
2668/*
2669** Generate an appropriate SELFTEST table in the main database.
2670*/
2671static void createSelftestTable(ShellState *p){
2672 char *zErrMsg = 0;
2673 sqlite3_exec(p->db,
2674 "SAVEPOINT selftest_init;\n"
2675 "CREATE TABLE IF NOT EXISTS selftest(\n"
2676 " tno INTEGER PRIMARY KEY,\n" /* Test number */
2677 " op TEXT,\n" /* Operator: memo run */
2678 " cmd TEXT,\n" /* Command text */
2679 " ans TEXT\n" /* Desired answer */
2680 ");"
2681 "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n"
2682 "INSERT INTO [_shell$self](rowid,op,cmd)\n"
2683 " VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n"
2684 " 'memo','Tests generated by --init');\n"
2685 "INSERT INTO [_shell$self]\n"
2686 " SELECT 'run',\n"
2687 " 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql "
drh067b92b2020-06-19 15:24:12 +00002688 "FROM sqlite_schema ORDER BY 2'',224))',\n"
drh2ce15c32017-07-11 13:34:40 +00002689 " hex(sha3_query('SELECT type,name,tbl_name,sql "
drh067b92b2020-06-19 15:24:12 +00002690 "FROM sqlite_schema ORDER BY 2',224));\n"
drh2ce15c32017-07-11 13:34:40 +00002691 "INSERT INTO [_shell$self]\n"
2692 " SELECT 'run',"
2693 " 'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
2694 " printf('%w',name) || '\" NOT INDEXED'',224))',\n"
2695 " hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
2696 " FROM (\n"
drh067b92b2020-06-19 15:24:12 +00002697 " SELECT name FROM sqlite_schema\n"
drh2ce15c32017-07-11 13:34:40 +00002698 " WHERE type='table'\n"
2699 " AND name<>'selftest'\n"
2700 " AND coalesce(rootpage,0)>0\n"
2701 " )\n"
2702 " ORDER BY name;\n"
2703 "INSERT INTO [_shell$self]\n"
2704 " VALUES('run','PRAGMA integrity_check','ok');\n"
2705 "INSERT INTO selftest(tno,op,cmd,ans)"
2706 " SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
2707 "DROP TABLE [_shell$self];"
2708 ,0,0,&zErrMsg);
2709 if( zErrMsg ){
2710 utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
2711 sqlite3_free(zErrMsg);
2712 }
2713 sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
2714}
2715
2716
2717/*
2718** Set the destination table field of the ShellState structure to
2719** the name of the table given. Escape any quote characters in the
2720** table name.
2721*/
2722static void set_table_name(ShellState *p, const char *zName){
2723 int i, n;
mistachkin2158a0c2017-09-09 00:51:36 +00002724 char cQuote;
drh2ce15c32017-07-11 13:34:40 +00002725 char *z;
2726
2727 if( p->zDestTable ){
2728 free(p->zDestTable);
2729 p->zDestTable = 0;
2730 }
2731 if( zName==0 ) return;
2732 cQuote = quoteChar(zName);
2733 n = strlen30(zName);
2734 if( cQuote ) n += n+2;
2735 z = p->zDestTable = malloc( n+1 );
drhe3e25652021-12-16 13:29:28 +00002736 shell_check_oom(z);
drh2ce15c32017-07-11 13:34:40 +00002737 n = 0;
2738 if( cQuote ) z[n++] = cQuote;
2739 for(i=0; zName[i]; i++){
2740 z[n++] = zName[i];
2741 if( zName[i]==cQuote ) z[n++] = cQuote;
2742 }
2743 if( cQuote ) z[n++] = cQuote;
2744 z[n] = 0;
2745}
2746
drhf62641e2021-12-24 20:22:13 +00002747/*
2748** Maybe construct two lines of text that point out the position of a
2749** syntax error. Return a pointer to the text, in memory obtained from
2750** sqlite3_malloc(). Or, if the most recent error does not involve a
2751** specific token that we can point to, return an empty string.
2752**
2753** In all cases, the memory returned is obtained from sqlite3_malloc64()
2754** and should be released by the caller invoking sqlite3_free().
2755*/
2756static char *shell_error_context(const char *zSql, sqlite3 *db){
2757 int iOffset;
2758 size_t len;
2759 char *zCode;
2760 char *zMsg;
2761 int i;
2762 if( db==0
2763 || zSql==0
2764 || (iOffset = sqlite3_error_offset(db))<0
2765 ){
2766 return sqlite3_mprintf("");
2767 }
2768 while( iOffset>50 ){
2769 iOffset--;
2770 zSql++;
2771 while( (zSql[0]&0xc0)==0x80 ){ zSql++; iOffset--; }
2772 }
2773 len = strlen(zSql);
2774 if( len>78 ){
2775 len = 78;
2776 while( (zSql[len]&0xc0)==0x80 ) len--;
2777 }
2778 zCode = sqlite3_mprintf("%.*s", len, zSql);
drh1e84e1e2022-10-31 01:22:38 +00002779 shell_check_oom(zCode);
drhf62641e2021-12-24 20:22:13 +00002780 for(i=0; zCode[i]; i++){ if( IsSpace(zSql[i]) ) zCode[i] = ' '; }
2781 if( iOffset<25 ){
larrybr0953c532022-12-23 19:04:59 +00002782 zMsg = sqlite3_mprintf("\n %z\n %*s^--- error here", zCode,iOffset,"");
drhf62641e2021-12-24 20:22:13 +00002783 }else{
larrybr0953c532022-12-23 19:04:59 +00002784 zMsg = sqlite3_mprintf("\n %z\n %*serror here ---^", zCode,iOffset-14,"");
drhf62641e2021-12-24 20:22:13 +00002785 }
2786 return zMsg;
2787}
2788
drh2ce15c32017-07-11 13:34:40 +00002789
2790/*
2791** Execute a query statement that will generate SQL output. Print
2792** the result columns, comma-separated, on a line and then add a
2793** semicolon terminator to the end of that line.
2794**
2795** If the number of columns is 1 and that column contains text "--"
2796** then write the semicolon on a separate line. That way, if a
2797** "--" comment occurs at the end of the statement, the comment
2798** won't consume the semicolon terminator.
2799*/
2800static int run_table_dump_query(
2801 ShellState *p, /* Query context */
drh8e9297f2020-03-25 12:50:13 +00002802 const char *zSelect /* SELECT statement to extract content */
drh2ce15c32017-07-11 13:34:40 +00002803){
2804 sqlite3_stmt *pSelect;
2805 int rc;
2806 int nResult;
2807 int i;
2808 const char *z;
2809 rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
2810 if( rc!=SQLITE_OK || !pSelect ){
drhf62641e2021-12-24 20:22:13 +00002811 char *zContext = shell_error_context(zSelect, p->db);
2812 utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n%s", rc,
2813 sqlite3_errmsg(p->db), zContext);
2814 sqlite3_free(zContext);
drh2ce15c32017-07-11 13:34:40 +00002815 if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
2816 return rc;
2817 }
2818 rc = sqlite3_step(pSelect);
2819 nResult = sqlite3_column_count(pSelect);
2820 while( rc==SQLITE_ROW ){
drh2ce15c32017-07-11 13:34:40 +00002821 z = (const char*)sqlite3_column_text(pSelect, 0);
2822 utf8_printf(p->out, "%s", z);
2823 for(i=1; i<nResult; i++){
2824 utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
2825 }
2826 if( z==0 ) z = "";
2827 while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
2828 if( z[0] ){
2829 raw_printf(p->out, "\n;\n");
2830 }else{
2831 raw_printf(p->out, ";\n");
2832 }
2833 rc = sqlite3_step(pSelect);
2834 }
2835 rc = sqlite3_finalize(pSelect);
2836 if( rc!=SQLITE_OK ){
2837 utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
2838 sqlite3_errmsg(p->db));
2839 if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
2840 }
2841 return rc;
2842}
2843
2844/*
larrybrf9a49b02021-10-26 16:57:09 +00002845** Allocate space and save off string indicating current error.
drh2ce15c32017-07-11 13:34:40 +00002846*/
2847static char *save_err_msg(
larrybrf9a49b02021-10-26 16:57:09 +00002848 sqlite3 *db, /* Database to query */
drh633c7982022-02-08 12:13:16 +00002849 const char *zPhase, /* When the error occcurs */
drhf62641e2021-12-24 20:22:13 +00002850 int rc, /* Error code returned from API */
2851 const char *zSql /* SQL string, or NULL */
drh2ce15c32017-07-11 13:34:40 +00002852){
drhe3e25652021-12-16 13:29:28 +00002853 char *zErr;
drhf62641e2021-12-24 20:22:13 +00002854 char *zContext;
drh633c7982022-02-08 12:13:16 +00002855 sqlite3_str *pStr = sqlite3_str_new(0);
2856 sqlite3_str_appendf(pStr, "%s, %s", zPhase, sqlite3_errmsg(db));
2857 if( rc>1 ){
2858 sqlite3_str_appendf(pStr, " (%d)", rc);
2859 }
drhf62641e2021-12-24 20:22:13 +00002860 zContext = shell_error_context(zSql, db);
drh633c7982022-02-08 12:13:16 +00002861 if( zContext ){
2862 sqlite3_str_appendall(pStr, zContext);
2863 sqlite3_free(zContext);
2864 }
2865 zErr = sqlite3_str_finish(pStr);
drhe3e25652021-12-16 13:29:28 +00002866 shell_check_oom(zErr);
2867 return zErr;
drh2ce15c32017-07-11 13:34:40 +00002868}
2869
2870#ifdef __linux__
2871/*
2872** Attempt to display I/O stats on Linux using /proc/PID/io
2873*/
2874static void displayLinuxIoStats(FILE *out){
2875 FILE *in;
2876 char z[200];
2877 sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
2878 in = fopen(z, "rb");
2879 if( in==0 ) return;
2880 while( fgets(z, sizeof(z), in)!=0 ){
2881 static const struct {
2882 const char *zPattern;
2883 const char *zDesc;
2884 } aTrans[] = {
2885 { "rchar: ", "Bytes received by read():" },
2886 { "wchar: ", "Bytes sent to write():" },
2887 { "syscr: ", "Read() system calls:" },
2888 { "syscw: ", "Write() system calls:" },
2889 { "read_bytes: ", "Bytes read from storage:" },
2890 { "write_bytes: ", "Bytes written to storage:" },
2891 { "cancelled_write_bytes: ", "Cancelled write bytes:" },
2892 };
2893 int i;
2894 for(i=0; i<ArraySize(aTrans); i++){
drhaf2770f2018-01-05 14:55:43 +00002895 int n = strlen30(aTrans[i].zPattern);
drhbf70f1b2022-10-19 18:04:42 +00002896 if( cli_strncmp(aTrans[i].zPattern, z, n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00002897 utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
2898 break;
2899 }
2900 }
2901 }
2902 fclose(in);
2903}
2904#endif
2905
2906/*
2907** Display a single line of status using 64-bit values.
2908*/
2909static void displayStatLine(
2910 ShellState *p, /* The shell context */
2911 char *zLabel, /* Label for this one line */
2912 char *zFormat, /* Format for the result */
2913 int iStatusCtrl, /* Which status to display */
2914 int bReset /* True to reset the stats */
2915){
2916 sqlite3_int64 iCur = -1;
2917 sqlite3_int64 iHiwtr = -1;
2918 int i, nPercent;
2919 char zLine[200];
2920 sqlite3_status64(iStatusCtrl, &iCur, &iHiwtr, bReset);
2921 for(i=0, nPercent=0; zFormat[i]; i++){
2922 if( zFormat[i]=='%' ) nPercent++;
2923 }
2924 if( nPercent>1 ){
2925 sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
2926 }else{
2927 sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
2928 }
2929 raw_printf(p->out, "%-36s %s\n", zLabel, zLine);
2930}
2931
2932/*
2933** Display memory stats.
2934*/
2935static int display_stats(
2936 sqlite3 *db, /* Database to query */
2937 ShellState *pArg, /* Pointer to ShellState */
2938 int bReset /* True to reset the stats */
2939){
2940 int iCur;
2941 int iHiwtr;
drh393344f2018-03-09 16:37:05 +00002942 FILE *out;
2943 if( pArg==0 || pArg->out==0 ) return 0;
2944 out = pArg->out;
drh2ce15c32017-07-11 13:34:40 +00002945
drha6e6cf22021-01-09 19:10:04 +00002946 if( pArg->pStmt && pArg->statsOn==2 ){
drh393344f2018-03-09 16:37:05 +00002947 int nCol, i, x;
2948 sqlite3_stmt *pStmt = pArg->pStmt;
2949 char z[100];
2950 nCol = sqlite3_column_count(pStmt);
2951 raw_printf(out, "%-36s %d\n", "Number of output columns:", nCol);
2952 for(i=0; i<nCol; i++){
2953 sqlite3_snprintf(sizeof(z),z,"Column %d %nname:", i, &x);
2954 utf8_printf(out, "%-36s %s\n", z, sqlite3_column_name(pStmt,i));
drh929cce82018-03-17 16:26:36 +00002955#ifndef SQLITE_OMIT_DECLTYPE
drh393344f2018-03-09 16:37:05 +00002956 sqlite3_snprintf(30, z+x, "declared type:");
2957 utf8_printf(out, "%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
drh929cce82018-03-17 16:26:36 +00002958#endif
2959#ifdef SQLITE_ENABLE_COLUMN_METADATA
drh393344f2018-03-09 16:37:05 +00002960 sqlite3_snprintf(30, z+x, "database name:");
2961 utf8_printf(out, "%-36s %s\n", z, sqlite3_column_database_name(pStmt,i));
2962 sqlite3_snprintf(30, z+x, "table name:");
2963 utf8_printf(out, "%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
2964 sqlite3_snprintf(30, z+x, "origin name:");
2965 utf8_printf(out, "%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i));
drh929cce82018-03-17 16:26:36 +00002966#endif
drh2ce15c32017-07-11 13:34:40 +00002967 }
drh929cce82018-03-17 16:26:36 +00002968 }
drh2ce15c32017-07-11 13:34:40 +00002969
drha6e6cf22021-01-09 19:10:04 +00002970 if( pArg->statsOn==3 ){
2971 if( pArg->pStmt ){
larrybr0953c532022-12-23 19:04:59 +00002972 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP,bReset);
drha6e6cf22021-01-09 19:10:04 +00002973 raw_printf(pArg->out, "VM-steps: %d\n", iCur);
2974 }
2975 return 0;
2976 }
2977
drh393344f2018-03-09 16:37:05 +00002978 displayStatLine(pArg, "Memory Used:",
2979 "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
2980 displayStatLine(pArg, "Number of Outstanding Allocations:",
2981 "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
2982 if( pArg->shellFlgs & SHFLG_Pagecache ){
2983 displayStatLine(pArg, "Number of Pcache Pages Used:",
2984 "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
2985 }
2986 displayStatLine(pArg, "Number of Pcache Overflow Bytes:",
2987 "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
2988 displayStatLine(pArg, "Largest Allocation:",
2989 "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
2990 displayStatLine(pArg, "Largest Pcache Allocation:",
2991 "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
2992#ifdef YYTRACKMAXSTACKDEPTH
2993 displayStatLine(pArg, "Deepest Parser Stack:",
2994 "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
2995#endif
2996
2997 if( db ){
drh2ce15c32017-07-11 13:34:40 +00002998 if( pArg->shellFlgs & SHFLG_Lookaside ){
2999 iHiwtr = iCur = -1;
3000 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
3001 &iCur, &iHiwtr, bReset);
3002 raw_printf(pArg->out,
3003 "Lookaside Slots Used: %d (max %d)\n",
3004 iCur, iHiwtr);
3005 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
3006 &iCur, &iHiwtr, bReset);
3007 raw_printf(pArg->out, "Successful lookaside attempts: %d\n",
3008 iHiwtr);
3009 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
3010 &iCur, &iHiwtr, bReset);
3011 raw_printf(pArg->out, "Lookaside failures due to size: %d\n",
3012 iHiwtr);
3013 sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
3014 &iCur, &iHiwtr, bReset);
3015 raw_printf(pArg->out, "Lookaside failures due to OOM: %d\n",
3016 iHiwtr);
3017 }
3018 iHiwtr = iCur = -1;
3019 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
3020 raw_printf(pArg->out, "Pager Heap Usage: %d bytes\n",
3021 iCur);
3022 iHiwtr = iCur = -1;
3023 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
3024 raw_printf(pArg->out, "Page cache hits: %d\n", iCur);
3025 iHiwtr = iCur = -1;
3026 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
3027 raw_printf(pArg->out, "Page cache misses: %d\n", iCur);
3028 iHiwtr = iCur = -1;
3029 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
3030 raw_printf(pArg->out, "Page cache writes: %d\n", iCur);
3031 iHiwtr = iCur = -1;
drhffc78a42018-03-14 14:53:50 +00003032 sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1);
3033 raw_printf(pArg->out, "Page cache spills: %d\n", iCur);
3034 iHiwtr = iCur = -1;
drh2ce15c32017-07-11 13:34:40 +00003035 sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
3036 raw_printf(pArg->out, "Schema Heap Usage: %d bytes\n",
3037 iCur);
3038 iHiwtr = iCur = -1;
3039 sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
3040 raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n",
3041 iCur);
3042 }
3043
drh393344f2018-03-09 16:37:05 +00003044 if( pArg->pStmt ){
drh23d41e62021-12-06 21:45:31 +00003045 int iHit, iMiss;
drh2ce15c32017-07-11 13:34:40 +00003046 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
3047 bReset);
3048 raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur);
3049 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
3050 raw_printf(pArg->out, "Sort Operations: %d\n", iCur);
3051 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
3052 raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur);
larrybr0953c532022-12-23 19:04:59 +00003053 iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT,
3054 bReset);
3055 iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS,
3056 bReset);
drh23d41e62021-12-06 21:45:31 +00003057 if( iHit || iMiss ){
3058 raw_printf(pArg->out, "Bloom filter bypass taken: %d/%d\n",
3059 iHit, iHit+iMiss);
3060 }
drh2ce15c32017-07-11 13:34:40 +00003061 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
3062 raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
drhe2754c12019-08-26 12:50:01 +00003063 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
drh393344f2018-03-09 16:37:05 +00003064 raw_printf(pArg->out, "Reprepare operations: %d\n", iCur);
3065 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
3066 raw_printf(pArg->out, "Number of times run: %d\n", iCur);
3067 iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset);
3068 raw_printf(pArg->out, "Memory used by prepared stmt: %d\n", iCur);
drh2ce15c32017-07-11 13:34:40 +00003069 }
3070
3071#ifdef __linux__
3072 displayLinuxIoStats(pArg->out);
3073#endif
3074
3075 /* Do not remove this machine readable comment: extra-stats-output-here */
3076
3077 return 0;
3078}
3079
dan231ff4b2022-12-02 20:32:22 +00003080
3081#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
3082static int scanStatsHeight(sqlite3_stmt *p, int iEntry){
3083 int iPid = 0;
3084 int ret = 1;
larrybr0953c532022-12-23 19:04:59 +00003085 sqlite3_stmt_scanstatus_v2(p, iEntry,
dan231ff4b2022-12-02 20:32:22 +00003086 SQLITE_SCANSTAT_SELECTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iPid
3087 );
3088 while( iPid!=0 ){
3089 int ii;
3090 for(ii=0; 1; ii++){
3091 int iId;
3092 int res;
larrybr0953c532022-12-23 19:04:59 +00003093 res = sqlite3_stmt_scanstatus_v2(p, ii,
dan231ff4b2022-12-02 20:32:22 +00003094 SQLITE_SCANSTAT_SELECTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iId
3095 );
3096 if( res ) break;
3097 if( iId==iPid ){
larrybr0953c532022-12-23 19:04:59 +00003098 sqlite3_stmt_scanstatus_v2(p, ii,
dan231ff4b2022-12-02 20:32:22 +00003099 SQLITE_SCANSTAT_PARENTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iPid
3100 );
3101 }
3102 }
3103 ret++;
3104 }
3105 return ret;
3106}
3107#endif
3108
drh2ce15c32017-07-11 13:34:40 +00003109/*
3110** Display scan stats.
3111*/
3112static void display_scanstats(
3113 sqlite3 *db, /* Database to query */
3114 ShellState *pArg /* Pointer to ShellState */
3115){
3116#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
3117 UNUSED_PARAMETER(db);
3118 UNUSED_PARAMETER(pArg);
3119#else
dan231ff4b2022-12-02 20:32:22 +00003120 static const int f = SQLITE_SCANSTAT_COMPLEX;
3121 sqlite3_stmt *p = pArg->pStmt;
3122 int ii = 0;
3123 i64 nTotal = 0;
3124 int nWidth = 0;
3125 eqp_reset(pArg);
3126
3127 for(ii=0; 1; ii++){
3128 const char *z = 0;
3129 int n = 0;
3130 if( sqlite3_stmt_scanstatus_v2(p,ii,SQLITE_SCANSTAT_EXPLAIN,f,(void*)&z) ){
3131 break;
3132 }
3133 n = strlen(z) + scanStatsHeight(p, ii)*3;
3134 if( n>nWidth ) nWidth = n;
3135 }
3136 nWidth += 4;
3137
3138 sqlite3_stmt_scanstatus_v2(p, -1, SQLITE_SCANSTAT_NCYCLE, f, (void*)&nTotal);
3139 for(ii=0; 1; ii++){
3140 i64 nLoop = 0;
3141 i64 nRow = 0;
3142 i64 nCycle = 0;
3143 int iId = 0;
3144 int iPid = 0;
3145 const char *z = 0;
dan2797ac02022-12-08 21:05:33 +00003146 const char *zName = 0;
dan231ff4b2022-12-02 20:32:22 +00003147 char *zText = 0;
3148 double rEst = 0.0;
3149
3150 if( sqlite3_stmt_scanstatus_v2(p,ii,SQLITE_SCANSTAT_EXPLAIN,f,(void*)&z) ){
3151 break;
3152 }
3153 sqlite3_stmt_scanstatus_v2(p, ii, SQLITE_SCANSTAT_EST,f,(void*)&rEst);
3154 sqlite3_stmt_scanstatus_v2(p, ii, SQLITE_SCANSTAT_NLOOP,f,(void*)&nLoop);
3155 sqlite3_stmt_scanstatus_v2(p, ii, SQLITE_SCANSTAT_NVISIT,f,(void*)&nRow);
3156 sqlite3_stmt_scanstatus_v2(p, ii, SQLITE_SCANSTAT_NCYCLE,f,(void*)&nCycle);
3157 sqlite3_stmt_scanstatus_v2(p, ii, SQLITE_SCANSTAT_SELECTID,f,(void*)&iId);
3158 sqlite3_stmt_scanstatus_v2(p, ii, SQLITE_SCANSTAT_PARENTID,f,(void*)&iPid);
dan2797ac02022-12-08 21:05:33 +00003159 sqlite3_stmt_scanstatus_v2(p, ii, SQLITE_SCANSTAT_NAME,f,(void*)&zName);
dan231ff4b2022-12-02 20:32:22 +00003160
3161 zText = sqlite3_mprintf("%s", z);
3162 if( nCycle>=0 || nLoop>=0 || nRow>=0 ){
3163 char *z = 0;
danad23a472022-12-03 21:24:26 +00003164 if( nCycle>=0 && nTotal>0 ){
dan231ff4b2022-12-02 20:32:22 +00003165 z = sqlite3_mprintf("%zcycles=%lld [%d%%]", z,
3166 nCycle, ((nCycle*100)+nTotal/2) / nTotal
3167 );
drh2ce15c32017-07-11 13:34:40 +00003168 }
dan231ff4b2022-12-02 20:32:22 +00003169 if( nLoop>=0 ){
3170 z = sqlite3_mprintf("%z%sloops=%lld", z, z ? " " : "", nLoop);
drh2ce15c32017-07-11 13:34:40 +00003171 }
dan231ff4b2022-12-02 20:32:22 +00003172 if( nRow>=0 ){
3173 z = sqlite3_mprintf("%z%srows=%lld", z, z ? " " : "", nRow);
3174 }
3175
dan2797ac02022-12-08 21:05:33 +00003176 if( zName && pArg->scanstatsOn>1 ){
3177 double rpl = (double)nRow / (double)nLoop;
3178 z = sqlite3_mprintf("%z rpl=%.1f est=%.1f", z, rpl, rEst);
3179 }
3180
dan231ff4b2022-12-02 20:32:22 +00003181 zText = sqlite3_mprintf(
3182 "% *z (%z)", -1*(nWidth-scanStatsHeight(p, ii)*3), zText, z
drh2ce15c32017-07-11 13:34:40 +00003183 );
3184 }
dan231ff4b2022-12-02 20:32:22 +00003185
3186 eqp_append(pArg, iId, iPid, zText);
3187 sqlite3_free(zText);
drh2ce15c32017-07-11 13:34:40 +00003188 }
dan231ff4b2022-12-02 20:32:22 +00003189
3190 eqp_render(pArg, nTotal);
drh2ce15c32017-07-11 13:34:40 +00003191#endif
3192}
3193
3194/*
3195** Parameter azArray points to a zero-terminated array of strings. zStr
3196** points to a single nul-terminated string. Return non-zero if zStr
3197** is equal, according to strcmp(), to any of the strings in the array.
3198** Otherwise, return zero.
3199*/
3200static int str_in_array(const char *zStr, const char **azArray){
3201 int i;
3202 for(i=0; azArray[i]; i++){
drhbf70f1b2022-10-19 18:04:42 +00003203 if( 0==cli_strcmp(zStr, azArray[i]) ) return 1;
drh2ce15c32017-07-11 13:34:40 +00003204 }
3205 return 0;
3206}
3207
3208/*
3209** If compiled statement pSql appears to be an EXPLAIN statement, allocate
3210** and populate the ShellState.aiIndent[] array with the number of
3211** spaces each opcode should be indented before it is output.
3212**
3213** The indenting rules are:
3214**
3215** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
3216** all opcodes that occur between the p2 jump destination and the opcode
3217** itself by 2 spaces.
3218**
drhe603ab02022-04-07 19:06:31 +00003219** * Do the previous for "Return" instructions for when P2 is positive.
3220** See tag-20220407a in wherecode.c and vdbe.c.
3221**
drh2ce15c32017-07-11 13:34:40 +00003222** * For each "Goto", if the jump destination is earlier in the program
3223** and ends on one of:
3224** Yield SeekGt SeekLt RowSetRead Rewind
3225** or if the P1 parameter is one instead of zero,
3226** then indent all opcodes between the earlier instruction
3227** and "Goto" by 2 spaces.
3228*/
3229static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
3230 const char *zSql; /* The text of the SQL statement */
3231 const char *z; /* Used to check if this is an EXPLAIN */
3232 int *abYield = 0; /* True if op is an OP_Yield */
3233 int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
3234 int iOp; /* Index of operation in p->aiIndent[] */
3235
drhe603ab02022-04-07 19:06:31 +00003236 const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
3237 "Return", 0 };
drh2ce15c32017-07-11 13:34:40 +00003238 const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
3239 "Rewind", 0 };
3240 const char *azGoto[] = { "Goto", 0 };
3241
3242 /* Try to figure out if this is really an EXPLAIN statement. If this
3243 ** cannot be verified, return early. */
3244 if( sqlite3_column_count(pSql)!=8 ){
3245 p->cMode = p->mode;
3246 return;
3247 }
3248 zSql = sqlite3_sql(pSql);
3249 if( zSql==0 ) return;
3250 for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
3251 if( sqlite3_strnicmp(z, "explain", 7) ){
3252 p->cMode = p->mode;
3253 return;
3254 }
3255
3256 for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
3257 int i;
3258 int iAddr = sqlite3_column_int(pSql, 0);
3259 const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
3260
3261 /* Set p2 to the P2 field of the current opcode. Then, assuming that
3262 ** p2 is an instruction address, set variable p2op to the index of that
3263 ** instruction in the aiIndent[] array. p2 and p2op may be different if
3264 ** the current instruction is part of a sub-program generated by an
3265 ** SQL trigger or foreign key. */
3266 int p2 = sqlite3_column_int(pSql, 3);
3267 int p2op = (p2 + (iOp-iAddr));
3268
3269 /* Grow the p->aiIndent array as required */
3270 if( iOp>=nAlloc ){
3271 if( iOp==0 ){
3272 /* Do further verfication that this is explain output. Abort if
3273 ** it is not */
3274 static const char *explainCols[] = {
3275 "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
3276 int jj;
3277 for(jj=0; jj<ArraySize(explainCols); jj++){
drhbf70f1b2022-10-19 18:04:42 +00003278 if( cli_strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
drh2ce15c32017-07-11 13:34:40 +00003279 p->cMode = p->mode;
3280 sqlite3_reset(pSql);
3281 return;
3282 }
3283 }
3284 }
3285 nAlloc += 100;
3286 p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
drhe3e25652021-12-16 13:29:28 +00003287 shell_check_oom(p->aiIndent);
drh2ce15c32017-07-11 13:34:40 +00003288 abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
drhe3e25652021-12-16 13:29:28 +00003289 shell_check_oom(abYield);
drh2ce15c32017-07-11 13:34:40 +00003290 }
3291 abYield[iOp] = str_in_array(zOp, azYield);
3292 p->aiIndent[iOp] = 0;
3293 p->nIndent = iOp+1;
3294
drhe603ab02022-04-07 19:06:31 +00003295 if( str_in_array(zOp, azNext) && p2op>0 ){
drh2ce15c32017-07-11 13:34:40 +00003296 for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
3297 }
3298 if( str_in_array(zOp, azGoto) && p2op<p->nIndent
3299 && (abYield[p2op] || sqlite3_column_int(pSql, 2))
3300 ){
3301 for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
3302 }
3303 }
3304
3305 p->iIndent = 0;
3306 sqlite3_free(abYield);
3307 sqlite3_reset(pSql);
3308}
3309
3310/*
3311** Free the array allocated by explain_data_prepare().
3312*/
3313static void explain_data_delete(ShellState *p){
3314 sqlite3_free(p->aiIndent);
3315 p->aiIndent = 0;
3316 p->nIndent = 0;
3317 p->iIndent = 0;
3318}
3319
3320/*
drh5e431be2022-04-06 11:08:38 +00003321** Disable and restore .wheretrace and .treetrace/.selecttrace settings.
drh2ce15c32017-07-11 13:34:40 +00003322*/
drhc0622a42020-12-04 01:17:57 +00003323static unsigned int savedSelectTrace;
3324static unsigned int savedWhereTrace;
drh2ce15c32017-07-11 13:34:40 +00003325static void disable_debug_trace_modes(void){
drh0a2fb792020-12-04 16:58:20 +00003326 unsigned int zero = 0;
drhc0622a42020-12-04 01:17:57 +00003327 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 0, &savedSelectTrace);
drh0a2fb792020-12-04 16:58:20 +00003328 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &zero);
drhc0622a42020-12-04 01:17:57 +00003329 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 2, &savedWhereTrace);
drh0a2fb792020-12-04 16:58:20 +00003330 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &zero);
drh2ce15c32017-07-11 13:34:40 +00003331}
3332static void restore_debug_trace_modes(void){
drhc0622a42020-12-04 01:17:57 +00003333 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &savedSelectTrace);
3334 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &savedWhereTrace);
drh2ce15c32017-07-11 13:34:40 +00003335}
3336
drh9cb02642019-02-28 20:10:52 +00003337/* Create the TEMP table used to store parameter bindings */
3338static void bind_table_init(ShellState *p){
drh346f4e22019-03-25 21:35:41 +00003339 int wrSchema = 0;
drh4b86e202020-01-19 20:37:26 +00003340 int defensiveMode = 0;
3341 sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, -1, &defensiveMode);
3342 sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
drh346f4e22019-03-25 21:35:41 +00003343 sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema);
3344 sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0);
drh9cb02642019-02-28 20:10:52 +00003345 sqlite3_exec(p->db,
drh65c29fd2019-03-25 21:56:26 +00003346 "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n"
drh9cb02642019-02-28 20:10:52 +00003347 " key TEXT PRIMARY KEY,\n"
larrybrdabada62021-04-04 12:52:58 +00003348 " value\n"
drh9cb02642019-02-28 20:10:52 +00003349 ") WITHOUT ROWID;",
3350 0, 0, 0);
drh346f4e22019-03-25 21:35:41 +00003351 sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0);
drh4b86e202020-01-19 20:37:26 +00003352 sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, defensiveMode, 0);
drh9cb02642019-02-28 20:10:52 +00003353}
3354
drh8b738d02019-02-25 18:43:54 +00003355/*
3356** Bind parameters on a prepared statement.
3357**
3358** Parameter bindings are taken from a TEMP table of the form:
3359**
drh1cb02632019-03-25 22:05:22 +00003360** CREATE TEMP TABLE sqlite_parameters(key TEXT PRIMARY KEY, value)
drh8b738d02019-02-25 18:43:54 +00003361** WITHOUT ROWID;
3362**
drh91654b22020-04-02 13:21:10 +00003363** No bindings occur if this table does not exist. The name of the table
3364** begins with "sqlite_" so that it will not collide with ordinary application
3365** tables. The table must be in the TEMP schema.
drh8b738d02019-02-25 18:43:54 +00003366*/
3367static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
3368 int nVar;
3369 int i;
3370 int rc;
3371 sqlite3_stmt *pQ = 0;
3372
3373 nVar = sqlite3_bind_parameter_count(pStmt);
3374 if( nVar==0 ) return; /* Nothing to do */
drh65c29fd2019-03-25 21:56:26 +00003375 if( sqlite3_table_column_metadata(pArg->db, "TEMP", "sqlite_parameters",
drh8b738d02019-02-25 18:43:54 +00003376 "key", 0, 0, 0, 0, 0)!=SQLITE_OK ){
3377 return; /* Parameter table does not exist */
3378 }
3379 rc = sqlite3_prepare_v2(pArg->db,
drh65c29fd2019-03-25 21:56:26 +00003380 "SELECT value FROM temp.sqlite_parameters"
drh8b738d02019-02-25 18:43:54 +00003381 " WHERE key=?1", -1, &pQ, 0);
3382 if( rc || pQ==0 ) return;
3383 for(i=1; i<=nVar; i++){
3384 char zNum[30];
3385 const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
3386 if( zVar==0 ){
3387 sqlite3_snprintf(sizeof(zNum),zNum,"?%d",i);
3388 zVar = zNum;
3389 }
3390 sqlite3_bind_text(pQ, 1, zVar, -1, SQLITE_STATIC);
3391 if( sqlite3_step(pQ)==SQLITE_ROW ){
3392 sqlite3_bind_value(pStmt, i, sqlite3_column_value(pQ, 0));
3393 }else{
3394 sqlite3_bind_null(pStmt, i);
3395 }
3396 sqlite3_reset(pQ);
3397 }
3398 sqlite3_finalize(pQ);
3399}
3400
drh30c54a02020-05-28 23:49:50 +00003401/*
drh0908e382020-06-04 18:05:39 +00003402** UTF8 box-drawing characters. Imagine box lines like this:
3403**
3404** 1
3405** |
3406** 4 --+-- 2
3407** |
3408** 3
3409**
3410** Each box characters has between 2 and 4 of the lines leading from
3411** the center. The characters are here identified by the numbers of
3412** their corresponding lines.
3413*/
3414#define BOX_24 "\342\224\200" /* U+2500 --- */
3415#define BOX_13 "\342\224\202" /* U+2502 | */
3416#define BOX_23 "\342\224\214" /* U+250c ,- */
3417#define BOX_34 "\342\224\220" /* U+2510 -, */
3418#define BOX_12 "\342\224\224" /* U+2514 '- */
3419#define BOX_14 "\342\224\230" /* U+2518 -' */
3420#define BOX_123 "\342\224\234" /* U+251c |- */
3421#define BOX_134 "\342\224\244" /* U+2524 -| */
3422#define BOX_234 "\342\224\254" /* U+252c -,- */
3423#define BOX_124 "\342\224\264" /* U+2534 -'- */
3424#define BOX_1234 "\342\224\274" /* U+253c -|- */
3425
3426/* Draw horizontal line N characters long using unicode box
3427** characters
3428*/
3429static void print_box_line(FILE *out, int N){
larrybr0953c532022-12-23 19:04:59 +00003430 const char zDash[] =
drh0908e382020-06-04 18:05:39 +00003431 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24
3432 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24;
3433 const int nDash = sizeof(zDash) - 1;
3434 N *= 3;
3435 while( N>nDash ){
3436 utf8_printf(out, zDash);
3437 N -= nDash;
3438 }
3439 utf8_printf(out, "%.*s", N, zDash);
3440}
3441
3442/*
3443** Draw a horizontal separator for a MODE_Box table.
3444*/
3445static void print_box_row_separator(
3446 ShellState *p,
3447 int nArg,
3448 const char *zSep1,
3449 const char *zSep2,
3450 const char *zSep3
3451){
3452 int i;
3453 if( nArg>0 ){
3454 utf8_printf(p->out, "%s", zSep1);
3455 print_box_line(p->out, p->actualWidth[0]+2);
3456 for(i=1; i<nArg; i++){
3457 utf8_printf(p->out, "%s", zSep2);
3458 print_box_line(p->out, p->actualWidth[i]+2);
3459 }
3460 utf8_printf(p->out, "%s", zSep3);
3461 }
3462 fputs("\n", p->out);
3463}
3464
drh09a39ed2022-01-30 21:09:03 +00003465/*
3466** z[] is a line of text that is to be displayed the .mode box or table or
3467** similar tabular formats. z[] might contain control characters such
3468** as \n, \t, \f, or \r.
3469**
3470** Compute characters to display on the first line of z[]. Stop at the
3471** first \r, \n, or \f. Expand \t into spaces. Return a copy (obtained
larrybrcc4d55c2022-02-01 02:50:45 +00003472** from malloc()) of that first line, which caller should free sometime.
3473** Write anything to display on the next line into *pzTail. If this is
3474** the last line, write a NULL into *pzTail. (*pzTail is not allocated.)
drh09a39ed2022-01-30 21:09:03 +00003475*/
3476static char *translateForDisplayAndDup(
drhca1776b2022-02-01 12:28:17 +00003477 const unsigned char *z, /* Input text to be transformed */
3478 const unsigned char **pzTail, /* OUT: Tail of the input for next line */
3479 int mxWidth, /* Max width. 0 means no limit */
3480 u8 bWordWrap /* If true, avoid breaking mid-word */
drh09a39ed2022-01-30 21:09:03 +00003481){
drhca1776b2022-02-01 12:28:17 +00003482 int i; /* Input bytes consumed */
3483 int j; /* Output bytes generated */
3484 int k; /* Input bytes to be displayed */
3485 int n; /* Output column number */
3486 unsigned char *zOut; /* Output text */
3487
drh09a39ed2022-01-30 21:09:03 +00003488 if( z==0 ){
3489 *pzTail = 0;
3490 return 0;
3491 }
3492 if( mxWidth<0 ) mxWidth = -mxWidth;
3493 if( mxWidth==0 ) mxWidth = 1000000;
drhca1776b2022-02-01 12:28:17 +00003494 i = j = n = 0;
drh09a39ed2022-01-30 21:09:03 +00003495 while( n<mxWidth ){
3496 if( z[i]>=' ' ){
3497 n++;
drhb6172192022-01-31 10:55:50 +00003498 do{ i++; j++; }while( (z[i]&0xc0)==0x80 );
drh09a39ed2022-01-30 21:09:03 +00003499 continue;
3500 }
3501 if( z[i]=='\t' ){
drhb6172192022-01-31 10:55:50 +00003502 do{
3503 n++;
3504 j++;
3505 }while( (n&7)!=0 && n<mxWidth );
drh09a39ed2022-01-30 21:09:03 +00003506 i++;
3507 continue;
3508 }
3509 break;
3510 }
drhca1776b2022-02-01 12:28:17 +00003511 if( n>=mxWidth && bWordWrap ){
3512 /* Perhaps try to back up to a better place to break the line */
3513 for(k=i; k>i/2; k--){
3514 if( isspace(z[k-1]) ) break;
3515 }
3516 if( k<=i/2 ){
3517 for(k=i; k>i/2; k--){
drhe66532a2022-02-01 13:17:11 +00003518 if( isalnum(z[k-1])!=isalnum(z[k]) && (z[k]&0xc0)!=0x80 ) break;
drhca1776b2022-02-01 12:28:17 +00003519 }
3520 }
3521 if( k<=i/2 ){
3522 k = i;
3523 }else{
3524 i = k;
3525 while( z[i]==' ' ) i++;
3526 }
3527 }else{
3528 k = i;
larrybrcc4d55c2022-02-01 02:50:45 +00003529 }
drh09a39ed2022-01-30 21:09:03 +00003530 if( n>=mxWidth && z[i]>=' ' ){
3531 *pzTail = &z[i];
3532 }else if( z[i]=='\r' && z[i+1]=='\n' ){
3533 *pzTail = z[i+2] ? &z[i+2] : 0;
drhb6172192022-01-31 10:55:50 +00003534 }else if( z[i]==0 || z[i+1]==0 ){
drh09a39ed2022-01-30 21:09:03 +00003535 *pzTail = 0;
3536 }else{
3537 *pzTail = &z[i+1];
3538 }
drhb6172192022-01-31 10:55:50 +00003539 zOut = malloc( j+1 );
drh09a39ed2022-01-30 21:09:03 +00003540 shell_check_oom(zOut);
drhb6172192022-01-31 10:55:50 +00003541 i = j = n = 0;
drhca1776b2022-02-01 12:28:17 +00003542 while( i<k ){
drh09a39ed2022-01-30 21:09:03 +00003543 if( z[i]>=' ' ){
drhb6172192022-01-31 10:55:50 +00003544 n++;
3545 do{ zOut[j++] = z[i++]; }while( (z[i]&0xc0)==0x80 );
drh09a39ed2022-01-30 21:09:03 +00003546 continue;
3547 }
3548 if( z[i]=='\t' ){
3549 do{
drhb6172192022-01-31 10:55:50 +00003550 n++;
3551 zOut[j++] = ' ';
drh09a39ed2022-01-30 21:09:03 +00003552 }while( (n&7)!=0 && n<mxWidth );
3553 i++;
3554 continue;
3555 }
3556 break;
3557 }
drhb6172192022-01-31 10:55:50 +00003558 zOut[j] = 0;
larrybr0953c532022-12-23 19:04:59 +00003559 return (char*)zOut;
drh09a39ed2022-01-30 21:09:03 +00003560}
3561
drhe40f2862022-01-31 14:14:29 +00003562/* Extract the value of the i-th current column for pStmt as an SQL literal
3563** value. Memory is obtained from sqlite3_malloc64() and must be freed by
3564** the caller.
3565*/
3566static char *quoted_column(sqlite3_stmt *pStmt, int i){
3567 switch( sqlite3_column_type(pStmt, i) ){
3568 case SQLITE_NULL: {
3569 return sqlite3_mprintf("NULL");
3570 }
3571 case SQLITE_INTEGER:
3572 case SQLITE_FLOAT: {
3573 return sqlite3_mprintf("%s",sqlite3_column_text(pStmt,i));
3574 }
3575 case SQLITE_TEXT: {
3576 return sqlite3_mprintf("%Q",sqlite3_column_text(pStmt,i));
3577 }
3578 case SQLITE_BLOB: {
3579 int j;
3580 sqlite3_str *pStr = sqlite3_str_new(0);
3581 const unsigned char *a = sqlite3_column_blob(pStmt,i);
3582 int n = sqlite3_column_bytes(pStmt,i);
3583 sqlite3_str_append(pStr, "x'", 2);
3584 for(j=0; j<n; j++){
3585 sqlite3_str_appendf(pStr, "%02x", a[j]);
3586 }
3587 sqlite3_str_append(pStr, "'", 1);
3588 return sqlite3_str_finish(pStr);
3589 }
3590 }
3591 return 0; /* Not reached */
3592}
drh0908e382020-06-04 18:05:39 +00003593
3594/*
drh30c54a02020-05-28 23:49:50 +00003595** Run a prepared statement and output the result in one of the
drh0908e382020-06-04 18:05:39 +00003596** table-oriented formats: MODE_Column, MODE_Markdown, MODE_Table,
3597** or MODE_Box.
drh30c54a02020-05-28 23:49:50 +00003598**
3599** This is different from ordinary exec_prepared_stmt() in that
3600** it has to run the entire query and gather the results into memory
3601** first, in order to determine column widths, before providing
3602** any output.
3603*/
drh8c748632020-05-29 16:15:58 +00003604static void exec_prepared_stmt_columnar(
3605 ShellState *p, /* Pointer to ShellState */
3606 sqlite3_stmt *pStmt /* Statment to run */
drh30c54a02020-05-28 23:49:50 +00003607){
drhf82ce382020-08-06 16:45:22 +00003608 sqlite3_int64 nRow = 0;
drh8c748632020-05-29 16:15:58 +00003609 int nColumn = 0;
3610 char **azData = 0;
drhf82ce382020-08-06 16:45:22 +00003611 sqlite3_int64 nAlloc = 0;
drh09a39ed2022-01-30 21:09:03 +00003612 char *abRowDiv = 0;
3613 const unsigned char *uz;
drh8c748632020-05-29 16:15:58 +00003614 const char *z;
drhe40f2862022-01-31 14:14:29 +00003615 char **azQuoted = 0;
drh8c748632020-05-29 16:15:58 +00003616 int rc;
drhf82ce382020-08-06 16:45:22 +00003617 sqlite3_int64 i, nData;
3618 int j, nTotal, w, n;
drh0908e382020-06-04 18:05:39 +00003619 const char *colSep = 0;
3620 const char *rowSep = 0;
drh09a39ed2022-01-30 21:09:03 +00003621 const unsigned char **azNextLine = 0;
3622 int bNextLine = 0;
3623 int bMultiLineRowExists = 0;
drhca1776b2022-02-01 12:28:17 +00003624 int bw = p->cmOpts.bWordWrap;
larrybr6403e772022-04-20 22:41:10 +00003625 const char *zEmpty = "";
3626 const char *zShowNull = p->nullValue;
drh30c54a02020-05-28 23:49:50 +00003627
drhf82ce382020-08-06 16:45:22 +00003628 rc = sqlite3_step(pStmt);
3629 if( rc!=SQLITE_ROW ) return;
3630 nColumn = sqlite3_column_count(pStmt);
3631 nAlloc = nColumn*4;
drh01a8ad22021-03-20 23:15:52 +00003632 if( nAlloc<=0 ) nAlloc = 1;
drhf82ce382020-08-06 16:45:22 +00003633 azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
drhe3e25652021-12-16 13:29:28 +00003634 shell_check_oom(azData);
drh09a39ed2022-01-30 21:09:03 +00003635 azNextLine = sqlite3_malloc64( nColumn*sizeof(char*) );
drh5dce6f92022-01-31 16:29:06 +00003636 shell_check_oom((void*)azNextLine);
3637 memset((void*)azNextLine, 0, nColumn*sizeof(char*) );
larrybrcc4d55c2022-02-01 02:50:45 +00003638 if( p->cmOpts.bQuote ){
drhe40f2862022-01-31 14:14:29 +00003639 azQuoted = sqlite3_malloc64( nColumn*sizeof(char*) );
3640 shell_check_oom(azQuoted);
3641 memset(azQuoted, 0, nColumn*sizeof(char*) );
3642 }
drh09a39ed2022-01-30 21:09:03 +00003643 abRowDiv = sqlite3_malloc64( nAlloc/nColumn );
3644 shell_check_oom(abRowDiv);
drh8c748632020-05-29 16:15:58 +00003645 if( nColumn>p->nWidth ){
drh76fc88f2021-10-02 16:39:16 +00003646 p->colWidth = realloc(p->colWidth, (nColumn+1)*2*sizeof(int));
drhe3e25652021-12-16 13:29:28 +00003647 shell_check_oom(p->colWidth);
drh8c748632020-05-29 16:15:58 +00003648 for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
3649 p->nWidth = nColumn;
3650 p->actualWidth = &p->colWidth[nColumn];
3651 }
3652 memset(p->actualWidth, 0, nColumn*sizeof(int));
3653 for(i=0; i<nColumn; i++){
3654 w = p->colWidth[i];
3655 if( w<0 ) w = -w;
3656 p->actualWidth[i] = w;
3657 }
drh09a39ed2022-01-30 21:09:03 +00003658 for(i=0; i<nColumn; i++){
drh47741b82022-01-31 22:14:53 +00003659 const unsigned char *zNotUsed;
3660 int wx = p->colWidth[i];
larrybrcc4d55c2022-02-01 02:50:45 +00003661 if( wx==0 ){
3662 wx = p->cmOpts.iWrap;
larrybrcc4d55c2022-02-01 02:50:45 +00003663 }
drh47741b82022-01-31 22:14:53 +00003664 if( wx<0 ) wx = -wx;
3665 uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
larrybrcc4d55c2022-02-01 02:50:45 +00003666 azData[i] = translateForDisplayAndDup(uz, &zNotUsed, wx, bw);
drh09a39ed2022-01-30 21:09:03 +00003667 }
3668 do{
3669 int useNextLine = bNextLine;
3670 bNextLine = 0;
3671 if( (nRow+2)*nColumn >= nAlloc ){
3672 nAlloc *= 2;
3673 azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
3674 shell_check_oom(azData);
3675 abRowDiv = sqlite3_realloc64(abRowDiv, nAlloc/nColumn);
3676 shell_check_oom(abRowDiv);
3677 }
3678 abRowDiv[nRow] = 1;
3679 nRow++;
3680 for(i=0; i<nColumn; i++){
drh5dce6f92022-01-31 16:29:06 +00003681 int wx = p->colWidth[i];
larrybrcc4d55c2022-02-01 02:50:45 +00003682 if( wx==0 ){
3683 wx = p->cmOpts.iWrap;
larrybrcc4d55c2022-02-01 02:50:45 +00003684 }
drh47741b82022-01-31 22:14:53 +00003685 if( wx<0 ) wx = -wx;
drh09a39ed2022-01-30 21:09:03 +00003686 if( useNextLine ){
3687 uz = azNextLine[i];
drh7e9a56f2022-04-21 19:14:23 +00003688 if( uz==0 ) uz = (u8*)zEmpty;
larrybrcc4d55c2022-02-01 02:50:45 +00003689 }else if( p->cmOpts.bQuote ){
drhe40f2862022-01-31 14:14:29 +00003690 sqlite3_free(azQuoted[i]);
3691 azQuoted[i] = quoted_column(pStmt,i);
3692 uz = (const unsigned char*)azQuoted[i];
drh09a39ed2022-01-30 21:09:03 +00003693 }else{
3694 uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
drh7e9a56f2022-04-21 19:14:23 +00003695 if( uz==0 ) uz = (u8*)zShowNull;
drh09a39ed2022-01-30 21:09:03 +00003696 }
larrybrcc4d55c2022-02-01 02:50:45 +00003697 azData[nRow*nColumn + i]
3698 = translateForDisplayAndDup(uz, &azNextLine[i], wx, bw);
drh09a39ed2022-01-30 21:09:03 +00003699 if( azNextLine[i] ){
3700 bNextLine = 1;
3701 abRowDiv[nRow-1] = 0;
3702 bMultiLineRowExists = 1;
3703 }
3704 }
3705 }while( bNextLine || sqlite3_step(pStmt)==SQLITE_ROW );
drh8c748632020-05-29 16:15:58 +00003706 nTotal = nColumn*(nRow+1);
3707 for(i=0; i<nTotal; i++){
3708 z = azData[i];
larrybr6403e772022-04-20 22:41:10 +00003709 if( z==0 ) z = (char*)zEmpty;
drh8c748632020-05-29 16:15:58 +00003710 n = strlenChar(z);
3711 j = i%nColumn;
3712 if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
3713 }
drh99942982020-06-15 20:05:37 +00003714 if( seenInterrupt ) goto columnar_end;
drh01a8ad22021-03-20 23:15:52 +00003715 if( nColumn==0 ) goto columnar_end;
drh0908e382020-06-04 18:05:39 +00003716 switch( p->cMode ){
3717 case MODE_Column: {
3718 colSep = " ";
3719 rowSep = "\n";
3720 if( p->showHeader ){
3721 for(i=0; i<nColumn; i++){
3722 w = p->actualWidth[i];
3723 if( p->colWidth[i]<0 ) w = -w;
3724 utf8_width_print(p->out, w, azData[i]);
3725 fputs(i==nColumn-1?"\n":" ", p->out);
3726 }
3727 for(i=0; i<nColumn; i++){
3728 print_dashes(p->out, p->actualWidth[i]);
3729 fputs(i==nColumn-1?"\n":" ", p->out);
3730 }
3731 }
3732 break;
3733 }
3734 case MODE_Table: {
3735 colSep = " | ";
3736 rowSep = " |\n";
3737 print_row_separator(p, nColumn, "+");
3738 fputs("| ", p->out);
drh8c748632020-05-29 16:15:58 +00003739 for(i=0; i<nColumn; i++){
3740 w = p->actualWidth[i];
drh0908e382020-06-04 18:05:39 +00003741 n = strlenChar(azData[i]);
3742 utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
3743 fputs(i==nColumn-1?" |\n":" | ", p->out);
drh8c748632020-05-29 16:15:58 +00003744 }
drh0908e382020-06-04 18:05:39 +00003745 print_row_separator(p, nColumn, "+");
3746 break;
3747 }
3748 case MODE_Markdown: {
3749 colSep = " | ";
3750 rowSep = " |\n";
3751 fputs("| ", p->out);
drh8c748632020-05-29 16:15:58 +00003752 for(i=0; i<nColumn; i++){
drh0908e382020-06-04 18:05:39 +00003753 w = p->actualWidth[i];
3754 n = strlenChar(azData[i]);
3755 utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
3756 fputs(i==nColumn-1?" |\n":" | ", p->out);
drh8c748632020-05-29 16:15:58 +00003757 }
drh0908e382020-06-04 18:05:39 +00003758 print_row_separator(p, nColumn, "|");
3759 break;
drh8c748632020-05-29 16:15:58 +00003760 }
drh0908e382020-06-04 18:05:39 +00003761 case MODE_Box: {
3762 colSep = " " BOX_13 " ";
3763 rowSep = " " BOX_13 "\n";
3764 print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
3765 utf8_printf(p->out, BOX_13 " ");
3766 for(i=0; i<nColumn; i++){
3767 w = p->actualWidth[i];
3768 n = strlenChar(azData[i]);
3769 utf8_printf(p->out, "%*s%s%*s%s",
3770 (w-n)/2, "", azData[i], (w-n+1)/2, "",
3771 i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
3772 }
3773 print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
3774 break;
drh8c748632020-05-29 16:15:58 +00003775 }
drh8c748632020-05-29 16:15:58 +00003776 }
3777 for(i=nColumn, j=0; i<nTotal; i++, j++){
drh0908e382020-06-04 18:05:39 +00003778 if( j==0 && p->cMode!=MODE_Column ){
3779 utf8_printf(p->out, "%s", p->cMode==MODE_Box?BOX_13" ":"| ");
3780 }
drh8c748632020-05-29 16:15:58 +00003781 z = azData[i];
3782 if( z==0 ) z = p->nullValue;
3783 w = p->actualWidth[j];
3784 if( p->colWidth[j]<0 ) w = -w;
3785 utf8_width_print(p->out, w, z);
3786 if( j==nColumn-1 ){
drh0908e382020-06-04 18:05:39 +00003787 utf8_printf(p->out, "%s", rowSep);
drh09a39ed2022-01-30 21:09:03 +00003788 if( bMultiLineRowExists && abRowDiv[i/nColumn-1] && i+1<nTotal ){
3789 if( p->cMode==MODE_Table ){
3790 print_row_separator(p, nColumn, "+");
3791 }else if( p->cMode==MODE_Box ){
3792 print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
drh5aabdae2022-02-01 00:00:08 +00003793 }else if( p->cMode==MODE_Column ){
3794 raw_printf(p->out, "\n");
drh09a39ed2022-01-30 21:09:03 +00003795 }
3796 }
drh8c748632020-05-29 16:15:58 +00003797 j = -1;
drhdd853c32020-06-16 17:34:40 +00003798 if( seenInterrupt ) goto columnar_end;
drh8c748632020-05-29 16:15:58 +00003799 }else{
drh0908e382020-06-04 18:05:39 +00003800 utf8_printf(p->out, "%s", colSep);
drh8c748632020-05-29 16:15:58 +00003801 }
3802 }
3803 if( p->cMode==MODE_Table ){
3804 print_row_separator(p, nColumn, "+");
drh0908e382020-06-04 18:05:39 +00003805 }else if( p->cMode==MODE_Box ){
3806 print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14);
drh8c748632020-05-29 16:15:58 +00003807 }
drh99942982020-06-15 20:05:37 +00003808columnar_end:
drhdd853c32020-06-16 17:34:40 +00003809 if( seenInterrupt ){
3810 utf8_printf(p->out, "Interrupt\n");
3811 }
drhf82ce382020-08-06 16:45:22 +00003812 nData = (nRow+1)*nColumn;
larrybr6403e772022-04-20 22:41:10 +00003813 for(i=0; i<nData; i++){
3814 z = azData[i];
drh744c17c2022-05-05 10:02:19 +00003815 if( z!=zEmpty && z!=zShowNull ) free(azData[i]);
larrybr6403e772022-04-20 22:41:10 +00003816 }
drhf82ce382020-08-06 16:45:22 +00003817 sqlite3_free(azData);
drh5dce6f92022-01-31 16:29:06 +00003818 sqlite3_free((void*)azNextLine);
drh09a39ed2022-01-30 21:09:03 +00003819 sqlite3_free(abRowDiv);
drhe40f2862022-01-31 14:14:29 +00003820 if( azQuoted ){
3821 for(i=0; i<nColumn; i++) sqlite3_free(azQuoted[i]);
3822 sqlite3_free(azQuoted);
3823 }
drh30c54a02020-05-28 23:49:50 +00003824}
drh30c54a02020-05-28 23:49:50 +00003825
drh2ce15c32017-07-11 13:34:40 +00003826/*
3827** Run a prepared statement
3828*/
3829static void exec_prepared_stmt(
3830 ShellState *pArg, /* Pointer to ShellState */
drha10b9992018-03-09 15:24:33 +00003831 sqlite3_stmt *pStmt /* Statment to run */
drh2ce15c32017-07-11 13:34:40 +00003832){
3833 int rc;
drh5d88be82021-12-09 16:17:43 +00003834 sqlite3_uint64 nRow = 0;
drh2ce15c32017-07-11 13:34:40 +00003835
drh8c748632020-05-29 16:15:58 +00003836 if( pArg->cMode==MODE_Column
3837 || pArg->cMode==MODE_Table
drh0908e382020-06-04 18:05:39 +00003838 || pArg->cMode==MODE_Box
drh8c748632020-05-29 16:15:58 +00003839 || pArg->cMode==MODE_Markdown
3840 ){
3841 exec_prepared_stmt_columnar(pArg, pStmt);
3842 return;
3843 }
3844
drh2ce15c32017-07-11 13:34:40 +00003845 /* perform the first step. this will tell us if we
3846 ** have a result set or not and how wide it is.
3847 */
3848 rc = sqlite3_step(pStmt);
3849 /* if we have a result set... */
3850 if( SQLITE_ROW == rc ){
drha10b9992018-03-09 15:24:33 +00003851 /* allocate space for col name ptr, value ptr, and type */
3852 int nCol = sqlite3_column_count(pStmt);
3853 void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
3854 if( !pData ){
drhe85e1da2021-10-01 21:01:07 +00003855 shell_out_of_memory();
drh2ce15c32017-07-11 13:34:40 +00003856 }else{
drha10b9992018-03-09 15:24:33 +00003857 char **azCols = (char **)pData; /* Names of result columns */
3858 char **azVals = &azCols[nCol]; /* Results */
3859 int *aiTypes = (int *)&azVals[nCol]; /* Result types */
3860 int i, x;
3861 assert(sizeof(int) <= sizeof(char *));
3862 /* save off ptrs to column names */
3863 for(i=0; i<nCol; i++){
3864 azCols[i] = (char *)sqlite3_column_name(pStmt, i);
3865 }
drh2ce15c32017-07-11 13:34:40 +00003866 do{
drh5d88be82021-12-09 16:17:43 +00003867 nRow++;
drha10b9992018-03-09 15:24:33 +00003868 /* extract the data and data types */
3869 for(i=0; i<nCol; i++){
3870 aiTypes[i] = x = sqlite3_column_type(pStmt, i);
drh5d1bf4f2022-01-02 20:54:33 +00003871 if( x==SQLITE_BLOB
3872 && pArg
3873 && (pArg->cMode==MODE_Insert || pArg->cMode==MODE_Quote)
3874 ){
drha10b9992018-03-09 15:24:33 +00003875 azVals[i] = "";
3876 }else{
3877 azVals[i] = (char*)sqlite3_column_text(pStmt, i);
3878 }
3879 if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
3880 rc = SQLITE_NOMEM;
3881 break; /* from for */
3882 }
3883 } /* end for */
3884
3885 /* if data and types extracted successfully... */
3886 if( SQLITE_ROW == rc ){
3887 /* call the supplied callback with the result row data */
3888 if( shell_callback(pArg, nCol, azVals, azCols, aiTypes) ){
3889 rc = SQLITE_ABORT;
3890 }else{
3891 rc = sqlite3_step(pStmt);
3892 }
3893 }
3894 } while( SQLITE_ROW == rc );
3895 sqlite3_free(pData);
drh0908e382020-06-04 18:05:39 +00003896 if( pArg->cMode==MODE_Json ){
drh30c54a02020-05-28 23:49:50 +00003897 fputs("]\n", pArg->out);
drh5d88be82021-12-09 16:17:43 +00003898 }else if( pArg->cMode==MODE_Count ){
mistachkinc158c072021-12-31 19:08:20 +00003899 char zBuf[200];
3900 sqlite3_snprintf(sizeof(zBuf), zBuf, "%llu row%s\n",
3901 nRow, nRow!=1 ? "s" : "");
3902 printf("%s", zBuf);
drh30c54a02020-05-28 23:49:50 +00003903 }
drh2ce15c32017-07-11 13:34:40 +00003904 }
3905 }
3906}
3907
dan6b046be2018-01-09 15:25:55 +00003908#ifndef SQLITE_OMIT_VIRTUALTABLE
drh2ce15c32017-07-11 13:34:40 +00003909/*
dan43efc182017-12-19 17:42:13 +00003910** This function is called to process SQL if the previous shell command
3911** was ".expert". It passes the SQL in the second argument directly to
3912** the sqlite3expert object.
3913**
3914** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
3915** code. In this case, (*pzErr) may be set to point to a buffer containing
3916** an English language error message. It is the responsibility of the
3917** caller to eventually free this buffer using sqlite3_free().
3918*/
3919static int expertHandleSQL(
larrybr0953c532022-12-23 19:04:59 +00003920 ShellState *pState,
3921 const char *zSql,
dan43efc182017-12-19 17:42:13 +00003922 char **pzErr
3923){
3924 assert( pState->expert.pExpert );
3925 assert( pzErr==0 || *pzErr==0 );
3926 return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr);
3927}
3928
3929/*
3930** This function is called either to silently clean up the object
larrybr0953c532022-12-23 19:04:59 +00003931** created by the ".expert" command (if bCancel==1), or to generate a
dan43efc182017-12-19 17:42:13 +00003932** report from it and then clean it up (if bCancel==0).
3933**
3934** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
3935** code. In this case, (*pzErr) may be set to point to a buffer containing
3936** an English language error message. It is the responsibility of the
3937** caller to eventually free this buffer using sqlite3_free().
3938*/
3939static int expertFinish(
3940 ShellState *pState,
3941 int bCancel,
3942 char **pzErr
3943){
3944 int rc = SQLITE_OK;
3945 sqlite3expert *p = pState->expert.pExpert;
3946 assert( p );
3947 assert( bCancel || pzErr==0 || *pzErr==0 );
3948 if( bCancel==0 ){
3949 FILE *out = pState->out;
3950 int bVerbose = pState->expert.bVerbose;
3951
3952 rc = sqlite3_expert_analyze(p, pzErr);
3953 if( rc==SQLITE_OK ){
3954 int nQuery = sqlite3_expert_count(p);
3955 int i;
3956
3957 if( bVerbose ){
3958 const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
3959 raw_printf(out, "-- Candidates -----------------------------\n");
3960 raw_printf(out, "%s\n", zCand);
3961 }
3962 for(i=0; i<nQuery; i++){
3963 const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
3964 const char *zIdx = sqlite3_expert_report(p, i, EXPERT_REPORT_INDEXES);
3965 const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
3966 if( zIdx==0 ) zIdx = "(no new indexes)\n";
3967 if( bVerbose ){
3968 raw_printf(out, "-- Query %d --------------------------------\n",i+1);
3969 raw_printf(out, "%s\n\n", zSql);
3970 }
3971 raw_printf(out, "%s\n", zIdx);
3972 raw_printf(out, "%s\n", zEQP);
3973 }
3974 }
3975 }
3976 sqlite3_expert_destroy(p);
3977 pState->expert.pExpert = 0;
3978 return rc;
3979}
3980
dan6b046be2018-01-09 15:25:55 +00003981/*
3982** Implementation of ".expert" dot command.
3983*/
3984static int expertDotCommand(
3985 ShellState *pState, /* Current shell tool state */
3986 char **azArg, /* Array of arguments passed to dot command */
3987 int nArg /* Number of entries in azArg[] */
3988){
3989 int rc = SQLITE_OK;
3990 char *zErr = 0;
3991 int i;
3992 int iSample = 0;
3993
3994 assert( pState->expert.pExpert==0 );
3995 memset(&pState->expert, 0, sizeof(ExpertInfo));
3996
3997 for(i=1; rc==SQLITE_OK && i<nArg; i++){
3998 char *z = azArg[i];
3999 int n;
4000 if( z[0]=='-' && z[1]=='-' ) z++;
4001 n = strlen30(z);
drhbf70f1b2022-10-19 18:04:42 +00004002 if( n>=2 && 0==cli_strncmp(z, "-verbose", n) ){
dan6b046be2018-01-09 15:25:55 +00004003 pState->expert.bVerbose = 1;
4004 }
drhbf70f1b2022-10-19 18:04:42 +00004005 else if( n>=2 && 0==cli_strncmp(z, "-sample", n) ){
dan6b046be2018-01-09 15:25:55 +00004006 if( i==(nArg-1) ){
4007 raw_printf(stderr, "option requires an argument: %s\n", z);
4008 rc = SQLITE_ERROR;
4009 }else{
4010 iSample = (int)integerValue(azArg[++i]);
4011 if( iSample<0 || iSample>100 ){
4012 raw_printf(stderr, "value out of range: %s\n", azArg[i]);
4013 rc = SQLITE_ERROR;
4014 }
4015 }
4016 }
4017 else{
4018 raw_printf(stderr, "unknown option: %s\n", z);
4019 rc = SQLITE_ERROR;
4020 }
4021 }
4022
4023 if( rc==SQLITE_OK ){
4024 pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
4025 if( pState->expert.pExpert==0 ){
larrybr0953c532022-12-23 19:04:59 +00004026 raw_printf(stderr, "sqlite3_expert_new: %s\n",
4027 zErr ? zErr : "out of memory");
dan6b046be2018-01-09 15:25:55 +00004028 rc = SQLITE_ERROR;
4029 }else{
4030 sqlite3_expert_config(
4031 pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
4032 );
4033 }
4034 }
drhe0adf602021-12-16 14:26:16 +00004035 sqlite3_free(zErr);
dan6b046be2018-01-09 15:25:55 +00004036
4037 return rc;
4038}
4039#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
dan43efc182017-12-19 17:42:13 +00004040
4041/*
drh2ce15c32017-07-11 13:34:40 +00004042** Execute a statement or set of statements. Print
4043** any result rows/columns depending on the current mode
4044** set via the supplied callback.
4045**
4046** This is very similar to SQLite's built-in sqlite3_exec()
4047** function except it takes a slightly different callback
4048** and callback data argument.
4049*/
4050static int shell_exec(
drh2ce15c32017-07-11 13:34:40 +00004051 ShellState *pArg, /* Pointer to ShellState */
drha10b9992018-03-09 15:24:33 +00004052 const char *zSql, /* SQL to be evaluated */
drh2ce15c32017-07-11 13:34:40 +00004053 char **pzErrMsg /* Error msg written here */
4054){
4055 sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
4056 int rc = SQLITE_OK; /* Return Code */
4057 int rc2;
4058 const char *zLeftover; /* Tail of unprocessed SQL */
drha10b9992018-03-09 15:24:33 +00004059 sqlite3 *db = pArg->db;
drh2ce15c32017-07-11 13:34:40 +00004060
4061 if( pzErrMsg ){
4062 *pzErrMsg = NULL;
4063 }
4064
dan6b046be2018-01-09 15:25:55 +00004065#ifndef SQLITE_OMIT_VIRTUALTABLE
dan43efc182017-12-19 17:42:13 +00004066 if( pArg->expert.pExpert ){
4067 rc = expertHandleSQL(pArg, zSql, pzErrMsg);
4068 return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg);
4069 }
dan6b046be2018-01-09 15:25:55 +00004070#endif
dan43efc182017-12-19 17:42:13 +00004071
drh2ce15c32017-07-11 13:34:40 +00004072 while( zSql[0] && (SQLITE_OK == rc) ){
4073 static const char *zStmtSql;
4074 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
4075 if( SQLITE_OK != rc ){
4076 if( pzErrMsg ){
drh633c7982022-02-08 12:13:16 +00004077 *pzErrMsg = save_err_msg(db, "in prepare", rc, zSql);
drh2ce15c32017-07-11 13:34:40 +00004078 }
4079 }else{
4080 if( !pStmt ){
4081 /* this happens for a comment or white-space */
4082 zSql = zLeftover;
4083 while( IsSpace(zSql[0]) ) zSql++;
4084 continue;
4085 }
4086 zStmtSql = sqlite3_sql(pStmt);
4087 if( zStmtSql==0 ) zStmtSql = "";
4088 while( IsSpace(zStmtSql[0]) ) zStmtSql++;
4089
4090 /* save off the prepared statment handle and reset row count */
4091 if( pArg ){
4092 pArg->pStmt = pStmt;
4093 pArg->cnt = 0;
4094 }
4095
drh2ce15c32017-07-11 13:34:40 +00004096 /* Show the EXPLAIN QUERY PLAN if .eqp is on */
drh39c5c4a2019-03-06 14:53:27 +00004097 if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){
drh2ce15c32017-07-11 13:34:40 +00004098 sqlite3_stmt *pExplain;
4099 char *zEQP;
drhada70452017-12-21 21:02:27 +00004100 int triggerEQP = 0;
drh2ce15c32017-07-11 13:34:40 +00004101 disable_debug_trace_modes();
drhada70452017-12-21 21:02:27 +00004102 sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP);
4103 if( pArg->autoEQP>=AUTOEQP_trigger ){
4104 sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0);
4105 }
drh2ce15c32017-07-11 13:34:40 +00004106 zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
drhe3e25652021-12-16 13:29:28 +00004107 shell_check_oom(zEQP);
drh2ce15c32017-07-11 13:34:40 +00004108 rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
4109 if( rc==SQLITE_OK ){
4110 while( sqlite3_step(pExplain)==SQLITE_ROW ){
drh4b5345c2018-04-24 13:07:40 +00004111 const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3);
drhe2ca99c2018-05-02 00:33:43 +00004112 int iEqpId = sqlite3_column_int(pExplain, 0);
4113 int iParentId = sqlite3_column_int(pExplain, 1);
drh7e088a62020-05-02 00:01:39 +00004114 if( zEQPLine==0 ) zEQPLine = "";
dan231ff4b2022-12-02 20:32:22 +00004115 if( zEQPLine[0]=='-' ) eqp_render(pArg, 0);
drhe2ca99c2018-05-02 00:33:43 +00004116 eqp_append(pArg, iEqpId, iParentId, zEQPLine);
drh2ce15c32017-07-11 13:34:40 +00004117 }
dan231ff4b2022-12-02 20:32:22 +00004118 eqp_render(pArg, 0);
drh2ce15c32017-07-11 13:34:40 +00004119 }
4120 sqlite3_finalize(pExplain);
4121 sqlite3_free(zEQP);
drhada70452017-12-21 21:02:27 +00004122 if( pArg->autoEQP>=AUTOEQP_full ){
drh2ce15c32017-07-11 13:34:40 +00004123 /* Also do an EXPLAIN for ".eqp full" mode */
4124 zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
drhe3e25652021-12-16 13:29:28 +00004125 shell_check_oom(zEQP);
drh2ce15c32017-07-11 13:34:40 +00004126 rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
4127 if( rc==SQLITE_OK ){
4128 pArg->cMode = MODE_Explain;
4129 explain_data_prepare(pArg, pExplain);
drha10b9992018-03-09 15:24:33 +00004130 exec_prepared_stmt(pArg, pExplain);
drh2ce15c32017-07-11 13:34:40 +00004131 explain_data_delete(pArg);
4132 }
4133 sqlite3_finalize(pExplain);
4134 sqlite3_free(zEQP);
4135 }
drh51efe092018-03-20 12:04:38 +00004136 if( pArg->autoEQP>=AUTOEQP_trigger && triggerEQP==0 ){
4137 sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 0, 0);
4138 /* Reprepare pStmt before reactiving trace modes */
4139 sqlite3_finalize(pStmt);
4140 sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
drh3c49eaf2018-06-07 15:23:43 +00004141 if( pArg ) pArg->pStmt = pStmt;
drh51efe092018-03-20 12:04:38 +00004142 }
drh2ce15c32017-07-11 13:34:40 +00004143 restore_debug_trace_modes();
4144 }
4145
4146 if( pArg ){
4147 pArg->cMode = pArg->mode;
drh4b5345c2018-04-24 13:07:40 +00004148 if( pArg->autoExplain ){
drh39c5c4a2019-03-06 14:53:27 +00004149 if( sqlite3_stmt_isexplain(pStmt)==1 ){
drh4b5345c2018-04-24 13:07:40 +00004150 pArg->cMode = MODE_Explain;
4151 }
drh39c5c4a2019-03-06 14:53:27 +00004152 if( sqlite3_stmt_isexplain(pStmt)==2 ){
drh4b5345c2018-04-24 13:07:40 +00004153 pArg->cMode = MODE_EQP;
4154 }
drh2ce15c32017-07-11 13:34:40 +00004155 }
4156
4157 /* If the shell is currently in ".explain" mode, gather the extra
4158 ** data required to add indents to the output.*/
4159 if( pArg->cMode==MODE_Explain ){
4160 explain_data_prepare(pArg, pStmt);
4161 }
4162 }
4163
drh8b738d02019-02-25 18:43:54 +00004164 bind_prepared_stmt(pArg, pStmt);
drha10b9992018-03-09 15:24:33 +00004165 exec_prepared_stmt(pArg, pStmt);
drh2ce15c32017-07-11 13:34:40 +00004166 explain_data_delete(pArg);
dan231ff4b2022-12-02 20:32:22 +00004167 eqp_render(pArg, 0);
drh2ce15c32017-07-11 13:34:40 +00004168
4169 /* print usage stats if stats on */
4170 if( pArg && pArg->statsOn ){
4171 display_stats(db, pArg, 0);
4172 }
4173
4174 /* print loop-counters if required */
4175 if( pArg && pArg->scanstatsOn ){
4176 display_scanstats(db, pArg);
4177 }
4178
4179 /* Finalize the statement just executed. If this fails, save a
4180 ** copy of the error message. Otherwise, set zSql to point to the
4181 ** next statement to execute. */
4182 rc2 = sqlite3_finalize(pStmt);
4183 if( rc!=SQLITE_NOMEM ) rc = rc2;
4184 if( rc==SQLITE_OK ){
4185 zSql = zLeftover;
4186 while( IsSpace(zSql[0]) ) zSql++;
4187 }else if( pzErrMsg ){
drh633c7982022-02-08 12:13:16 +00004188 *pzErrMsg = save_err_msg(db, "stepping", rc, 0);
drh2ce15c32017-07-11 13:34:40 +00004189 }
4190
4191 /* clear saved stmt handle */
4192 if( pArg ){
4193 pArg->pStmt = NULL;
4194 }
4195 }
4196 } /* end while */
4197
4198 return rc;
4199}
4200
4201/*
4202** Release memory previously allocated by tableColumnList().
4203*/
4204static void freeColumnList(char **azCol){
4205 int i;
4206 for(i=1; azCol[i]; i++){
4207 sqlite3_free(azCol[i]);
4208 }
4209 /* azCol[0] is a static string */
4210 sqlite3_free(azCol);
4211}
4212
4213/*
4214** Return a list of pointers to strings which are the names of all
4215** columns in table zTab. The memory to hold the names is dynamically
4216** allocated and must be released by the caller using a subsequent call
4217** to freeColumnList().
4218**
4219** The azCol[0] entry is usually NULL. However, if zTab contains a rowid
4220** value that needs to be preserved, then azCol[0] is filled in with the
4221** name of the rowid column.
4222**
4223** The first regular column in the table is azCol[1]. The list is terminated
4224** by an entry with azCol[i]==0.
4225*/
4226static char **tableColumnList(ShellState *p, const char *zTab){
4227 char **azCol = 0;
4228 sqlite3_stmt *pStmt;
4229 char *zSql;
4230 int nCol = 0;
4231 int nAlloc = 0;
4232 int nPK = 0; /* Number of PRIMARY KEY columns seen */
4233 int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */
4234 int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid);
4235 int rc;
4236
4237 zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
drhe3e25652021-12-16 13:29:28 +00004238 shell_check_oom(zSql);
drh2ce15c32017-07-11 13:34:40 +00004239 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
4240 sqlite3_free(zSql);
4241 if( rc ) return 0;
4242 while( sqlite3_step(pStmt)==SQLITE_ROW ){
4243 if( nCol>=nAlloc-2 ){
4244 nAlloc = nAlloc*2 + nCol + 10;
4245 azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
drhe3e25652021-12-16 13:29:28 +00004246 shell_check_oom(azCol);
drh2ce15c32017-07-11 13:34:40 +00004247 }
4248 azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
drhe3e25652021-12-16 13:29:28 +00004249 shell_check_oom(azCol[nCol]);
drh2ce15c32017-07-11 13:34:40 +00004250 if( sqlite3_column_int(pStmt, 5) ){
4251 nPK++;
4252 if( nPK==1
4253 && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2),
4254 "INTEGER")==0
4255 ){
4256 isIPK = 1;
4257 }else{
4258 isIPK = 0;
4259 }
4260 }
4261 }
4262 sqlite3_finalize(pStmt);
drh4c6cddc2017-10-12 10:28:30 +00004263 if( azCol==0 ) return 0;
drh2ce15c32017-07-11 13:34:40 +00004264 azCol[0] = 0;
4265 azCol[nCol+1] = 0;
4266
4267 /* The decision of whether or not a rowid really needs to be preserved
4268 ** is tricky. We never need to preserve a rowid for a WITHOUT ROWID table
4269 ** or a table with an INTEGER PRIMARY KEY. We are unable to preserve
4270 ** rowids on tables where the rowid is inaccessible because there are other
4271 ** columns in the table named "rowid", "_rowid_", and "oid".
4272 */
4273 if( preserveRowid && isIPK ){
4274 /* If a single PRIMARY KEY column with type INTEGER was seen, then it
4275 ** might be an alise for the ROWID. But it might also be a WITHOUT ROWID
4276 ** table or a INTEGER PRIMARY KEY DESC column, neither of which are
4277 ** ROWID aliases. To distinguish these cases, check to see if
4278 ** there is a "pk" entry in "PRAGMA index_list". There will be
4279 ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID.
4280 */
4281 zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
4282 " WHERE origin='pk'", zTab);
drhe3e25652021-12-16 13:29:28 +00004283 shell_check_oom(zSql);
drh2ce15c32017-07-11 13:34:40 +00004284 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
4285 sqlite3_free(zSql);
4286 if( rc ){
4287 freeColumnList(azCol);
4288 return 0;
4289 }
4290 rc = sqlite3_step(pStmt);
4291 sqlite3_finalize(pStmt);
4292 preserveRowid = rc==SQLITE_ROW;
4293 }
4294 if( preserveRowid ){
4295 /* Only preserve the rowid if we can find a name to use for the
4296 ** rowid */
4297 static char *azRowid[] = { "rowid", "_rowid_", "oid" };
4298 int i, j;
4299 for(j=0; j<3; j++){
4300 for(i=1; i<=nCol; i++){
4301 if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break;
4302 }
4303 if( i>nCol ){
4304 /* At this point, we know that azRowid[j] is not the name of any
4305 ** ordinary column in the table. Verify that azRowid[j] is a valid
4306 ** name for the rowid before adding it to azCol[0]. WITHOUT ROWID
4307 ** tables will fail this last check */
4308 rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
4309 if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
4310 break;
4311 }
4312 }
4313 }
4314 return azCol;
4315}
4316
4317/*
4318** Toggle the reverse_unordered_selects setting.
4319*/
4320static void toggleSelectOrder(sqlite3 *db){
4321 sqlite3_stmt *pStmt = 0;
4322 int iSetting = 0;
4323 char zStmt[100];
4324 sqlite3_prepare_v2(db, "PRAGMA reverse_unordered_selects", -1, &pStmt, 0);
4325 if( sqlite3_step(pStmt)==SQLITE_ROW ){
4326 iSetting = sqlite3_column_int(pStmt, 0);
4327 }
4328 sqlite3_finalize(pStmt);
4329 sqlite3_snprintf(sizeof(zStmt), zStmt,
4330 "PRAGMA reverse_unordered_selects(%d)", !iSetting);
4331 sqlite3_exec(db, zStmt, 0, 0, 0);
4332}
4333
4334/*
4335** This is a different callback routine used for dumping the database.
4336** Each row received by this callback consists of a table name,
4337** the table type ("index" or "table") and SQL to create the table.
4338** This routine should print text sufficient to recreate the table.
4339*/
4340static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
4341 int rc;
4342 const char *zTable;
4343 const char *zType;
4344 const char *zSql;
4345 ShellState *p = (ShellState *)pArg;
mistachkina00a0162020-10-18 18:35:34 +00004346 int dataOnly;
4347 int noSys;
drh2ce15c32017-07-11 13:34:40 +00004348
4349 UNUSED_PARAMETER(azNotUsed);
drhb3c45232017-08-28 14:33:27 +00004350 if( nArg!=3 || azArg==0 ) return 0;
drh2ce15c32017-07-11 13:34:40 +00004351 zTable = azArg[0];
4352 zType = azArg[1];
4353 zSql = azArg[2];
drhd5ca2c42022-10-25 13:42:10 +00004354 if( zTable==0 ) return 0;
4355 if( zType==0 ) return 0;
mistachkina00a0162020-10-18 18:35:34 +00004356 dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0;
4357 noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
drh2ce15c32017-07-11 13:34:40 +00004358
drhbf70f1b2022-10-19 18:04:42 +00004359 if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
drhc1962192020-10-12 16:54:28 +00004360 if( !dataOnly ) raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
4361 }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
4362 if( !dataOnly ) raw_printf(p->out, "ANALYZE sqlite_schema;\n");
drhbf70f1b2022-10-19 18:04:42 +00004363 }else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){
drh2ce15c32017-07-11 13:34:40 +00004364 return 0;
drhc1962192020-10-12 16:54:28 +00004365 }else if( dataOnly ){
4366 /* no-op */
drhbf70f1b2022-10-19 18:04:42 +00004367 }else if( cli_strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
drh2ce15c32017-07-11 13:34:40 +00004368 char *zIns;
4369 if( !p->writableSchema ){
4370 raw_printf(p->out, "PRAGMA writable_schema=ON;\n");
4371 p->writableSchema = 1;
4372 }
4373 zIns = sqlite3_mprintf(
drh067b92b2020-06-19 15:24:12 +00004374 "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
drh2ce15c32017-07-11 13:34:40 +00004375 "VALUES('table','%q','%q',0,'%q');",
4376 zTable, zTable, zSql);
drhe3e25652021-12-16 13:29:28 +00004377 shell_check_oom(zIns);
drh2ce15c32017-07-11 13:34:40 +00004378 utf8_printf(p->out, "%s\n", zIns);
4379 sqlite3_free(zIns);
4380 return 0;
4381 }else{
4382 printSchemaLine(p->out, zSql, ";\n");
4383 }
4384
drhbf70f1b2022-10-19 18:04:42 +00004385 if( cli_strcmp(zType, "table")==0 ){
drh2ce15c32017-07-11 13:34:40 +00004386 ShellText sSelect;
4387 ShellText sTable;
4388 char **azCol;
4389 int i;
4390 char *savedDestTable;
4391 int savedMode;
4392
4393 azCol = tableColumnList(p, zTable);
4394 if( azCol==0 ){
4395 p->nErr++;
4396 return 0;
4397 }
4398
4399 /* Always quote the table name, even if it appears to be pure ascii,
4400 ** in case it is a keyword. Ex: INSERT INTO "table" ... */
4401 initText(&sTable);
4402 appendText(&sTable, zTable, quoteChar(zTable));
4403 /* If preserving the rowid, add a column list after the table name.
4404 ** In other words: "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
4405 ** instead of the usual "INSERT INTO tab VALUES(...)".
4406 */
4407 if( azCol[0] ){
4408 appendText(&sTable, "(", 0);
4409 appendText(&sTable, azCol[0], 0);
4410 for(i=1; azCol[i]; i++){
4411 appendText(&sTable, ",", 0);
4412 appendText(&sTable, azCol[i], quoteChar(azCol[i]));
4413 }
4414 appendText(&sTable, ")", 0);
4415 }
4416
4417 /* Build an appropriate SELECT statement */
4418 initText(&sSelect);
4419 appendText(&sSelect, "SELECT ", 0);
4420 if( azCol[0] ){
4421 appendText(&sSelect, azCol[0], 0);
4422 appendText(&sSelect, ",", 0);
4423 }
4424 for(i=1; azCol[i]; i++){
4425 appendText(&sSelect, azCol[i], quoteChar(azCol[i]));
4426 if( azCol[i+1] ){
4427 appendText(&sSelect, ",", 0);
4428 }
4429 }
4430 freeColumnList(azCol);
4431 appendText(&sSelect, " FROM ", 0);
4432 appendText(&sSelect, zTable, quoteChar(zTable));
4433
4434 savedDestTable = p->zDestTable;
4435 savedMode = p->mode;
4436 p->zDestTable = sTable.z;
4437 p->mode = p->cMode = MODE_Insert;
drha10b9992018-03-09 15:24:33 +00004438 rc = shell_exec(p, sSelect.z, 0);
drh2ce15c32017-07-11 13:34:40 +00004439 if( (rc&0xff)==SQLITE_CORRUPT ){
4440 raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
4441 toggleSelectOrder(p->db);
drha10b9992018-03-09 15:24:33 +00004442 shell_exec(p, sSelect.z, 0);
drh2ce15c32017-07-11 13:34:40 +00004443 toggleSelectOrder(p->db);
4444 }
4445 p->zDestTable = savedDestTable;
4446 p->mode = savedMode;
4447 freeText(&sTable);
4448 freeText(&sSelect);
4449 if( rc ) p->nErr++;
4450 }
4451 return 0;
4452}
4453
4454/*
4455** Run zQuery. Use dump_callback() as the callback routine so that
4456** the contents of the query are output as SQL statements.
4457**
4458** If we get a SQLITE_CORRUPT error, rerun the query after appending
4459** "ORDER BY rowid DESC" to the end.
4460*/
4461static int run_schema_dump_query(
4462 ShellState *p,
4463 const char *zQuery
4464){
4465 int rc;
4466 char *zErr = 0;
4467 rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
4468 if( rc==SQLITE_CORRUPT ){
4469 char *zQ2;
4470 int len = strlen30(zQuery);
4471 raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
4472 if( zErr ){
4473 utf8_printf(p->out, "/****** %s ******/\n", zErr);
4474 sqlite3_free(zErr);
4475 zErr = 0;
4476 }
4477 zQ2 = malloc( len+100 );
4478 if( zQ2==0 ) return rc;
4479 sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
4480 rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
4481 if( rc ){
4482 utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr);
4483 }else{
4484 rc = SQLITE_CORRUPT;
4485 }
4486 sqlite3_free(zErr);
4487 free(zQ2);
4488 }
4489 return rc;
4490}
4491
4492/*
drh98aa2ab2018-09-26 16:53:51 +00004493** Text of help messages.
4494**
4495** The help text for each individual command begins with a line that starts
stephan02520cc2022-05-18 22:58:34 +00004496** with ".". Subsequent lines are supplemental information.
drh98aa2ab2018-09-26 16:53:51 +00004497**
4498** There must be two or more spaces between the end of the command and the
4499** start of the description of what that command does.
drh2ce15c32017-07-11 13:34:40 +00004500*/
drh98aa2ab2018-09-26 16:53:51 +00004501static const char *(azHelp[]) = {
stephan02520cc2022-05-18 22:58:34 +00004502#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) \
stephan4413ec72022-07-12 15:53:02 +00004503 && !defined(SQLITE_SHELL_FIDDLE)
drh98aa2ab2018-09-26 16:53:51 +00004504 ".archive ... Manage SQL archives",
4505 " Each command must have exactly one of the following options:",
4506 " -c, --create Create a new archive",
drhe2754c12019-08-26 12:50:01 +00004507 " -u, --update Add or update files with changed mtime",
4508 " -i, --insert Like -u but always add even if unchanged",
larrybr47061b92021-11-01 17:22:52 +00004509 " -r, --remove Remove files from archive",
drh98aa2ab2018-09-26 16:53:51 +00004510 " -t, --list List contents of archive",
4511 " -x, --extract Extract files from archive",
4512 " Optional arguments:",
4513 " -v, --verbose Print each filename as it is processed",
drhe2754c12019-08-26 12:50:01 +00004514 " -f FILE, --file FILE Use archive FILE (default is current db)",
4515 " -a FILE, --append FILE Open FILE using the apndvfs VFS",
4516 " -C DIR, --directory DIR Read/extract files from directory DIR",
larrybr8f09f4b2021-11-02 00:18:11 +00004517 " -g, --glob Use glob matching for names in archive",
drh98aa2ab2018-09-26 16:53:51 +00004518 " -n, --dryrun Show the SQL that would have occurred",
4519 " Examples:",
drhe2754c12019-08-26 12:50:01 +00004520 " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar",
4521 " .ar -tf ARCHIVE # List members of ARCHIVE",
4522 " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE",
drh98aa2ab2018-09-26 16:53:51 +00004523 " See also:",
larrybrbd0d62c2021-06-13 08:23:28 +00004524 " http://sqlite.org/cli.html#sqlite_archive_support",
drhe37c0e12018-01-06 19:19:50 +00004525#endif
drh2ce15c32017-07-11 13:34:40 +00004526#ifndef SQLITE_OMIT_AUTHORIZATION
drh98aa2ab2018-09-26 16:53:51 +00004527 ".auth ON|OFF Show authorizer callbacks",
drh2ce15c32017-07-11 13:34:40 +00004528#endif
stephan4413ec72022-07-12 15:53:02 +00004529#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004530 ".backup ?DB? FILE Backup DB (default \"main\") to FILE",
larrybra7919ad2022-02-19 21:25:48 +00004531 " Options:",
drh98aa2ab2018-09-26 16:53:51 +00004532 " --append Use the appendvfs",
drhe2754c12019-08-26 12:50:01 +00004533 " --async Write to FILE without journal and fsync()",
stephan02520cc2022-05-18 22:58:34 +00004534#endif
drh98aa2ab2018-09-26 16:53:51 +00004535 ".bail on|off Stop after hitting an error. Default OFF",
4536 ".binary on|off Turn binary output on or off. Default OFF",
stephan4413ec72022-07-12 15:53:02 +00004537#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004538 ".cd DIRECTORY Change the working directory to DIRECTORY",
stephan1c0dcec2022-05-19 21:56:50 +00004539#endif
drh98aa2ab2018-09-26 16:53:51 +00004540 ".changes on|off Show number of rows changed by SQL",
stephan4413ec72022-07-12 15:53:02 +00004541#ifndef SQLITE_SHELL_FIDDLE
stephane26d1622022-05-19 22:04:23 +00004542 ".check GLOB Fail if output since .testcase does not match",
drh98aa2ab2018-09-26 16:53:51 +00004543 ".clone NEWDB Clone data into NEWDB from the existing database",
stephan1c0dcec2022-05-19 21:56:50 +00004544#endif
drh37407122021-07-23 18:43:58 +00004545 ".connection [close] [#] Open or close an auxiliary database connection",
drh98aa2ab2018-09-26 16:53:51 +00004546 ".databases List names and files of attached databases",
4547 ".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
stephan3d420832022-10-27 03:56:01 +00004548#if SQLITE_SHELL_HAVE_RECOVER
drh98aa2ab2018-09-26 16:53:51 +00004549 ".dbinfo ?DB? Show status information about the database",
larrybrf3d6e8f2022-06-05 22:58:40 +00004550#endif
larrybr7bdbe592021-03-15 12:56:00 +00004551 ".dump ?OBJECTS? Render database content as SQL",
drheb7f2a02018-09-26 18:02:32 +00004552 " Options:",
drhc1962192020-10-12 16:54:28 +00004553 " --data-only Output only INSERT statements",
drheb7f2a02018-09-26 18:02:32 +00004554 " --newlines Allow unescaped newline characters in output",
drhc1962192020-10-12 16:54:28 +00004555 " --nosys Omit system tables (ex: \"sqlite_stat1\")",
4556 " --preserve-rowids Include ROWID values in the output",
larrybr7bdbe592021-03-15 12:56:00 +00004557 " OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump",
drh8e9297f2020-03-25 12:50:13 +00004558 " Additional LIKE patterns can be given in subsequent arguments",
drh98aa2ab2018-09-26 16:53:51 +00004559 ".echo on|off Turn command echo on or off",
drhb4e50392019-01-26 15:40:04 +00004560 ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN",
4561 " Other Modes:",
4562#ifdef SQLITE_DEBUG
4563 " test Show raw EXPLAIN QUERY PLAN output",
drhe2754c12019-08-26 12:50:01 +00004564 " trace Like \"full\" but enable \"PRAGMA vdbe_trace\"",
drhb4e50392019-01-26 15:40:04 +00004565#endif
4566 " trigger Like \"full\" but also show trigger bytecode",
stephan4413ec72022-07-12 15:53:02 +00004567#ifndef SQLITE_SHELL_FIDDLE
drhe2754c12019-08-26 12:50:01 +00004568 ".excel Display the output of next command in spreadsheet",
drh7a431002020-04-18 14:12:00 +00004569 " --bom Put a UTF8 byte-order mark on intermediate file",
stephan02520cc2022-05-18 22:58:34 +00004570#endif
stephan4413ec72022-07-12 15:53:02 +00004571#ifndef SQLITE_SHELL_FIDDLE
drheb7f2a02018-09-26 18:02:32 +00004572 ".exit ?CODE? Exit this program with return-code CODE",
stephan02520cc2022-05-18 22:58:34 +00004573#endif
drhe2754c12019-08-26 12:50:01 +00004574 ".expert EXPERIMENTAL. Suggest indexes for queries",
drh978256f2019-11-02 00:00:14 +00004575 ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto",
drhd985f722019-06-05 14:29:53 +00004576 ".filectrl CMD ... Run various sqlite3_file_control() operations",
drh541ef2c2020-04-20 16:21:30 +00004577 " --schema SCHEMA Use SCHEMA instead of \"main\"",
4578 " --help Show CMD details",
drh98aa2ab2018-09-26 16:53:51 +00004579 ".fullschema ?--indent? Show schema and the content of sqlite_stat tables",
4580 ".headers on|off Turn display of headers on or off",
4581 ".help ?-all? ?PATTERN? Show help text for PATTERN",
stephan4413ec72022-07-12 15:53:02 +00004582#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004583 ".import FILE TABLE Import data from FILE into TABLE",
drhccb37812020-03-09 15:39:39 +00004584 " Options:",
4585 " --ascii Use \\037 and \\036 as column and row separators",
4586 " --csv Use , and \\n as column and row separators",
4587 " --skip N Skip the first N rows of input",
larrybr738d7b92022-01-13 21:22:54 +00004588 " --schema S Target table to be S.TABLE",
drhccb37812020-03-09 15:39:39 +00004589 " -v \"Verbose\" - increase auxiliary output",
4590 " Notes:",
4591 " * If TABLE does not exist, it is created. The first row of input",
4592 " determines the column names.",
4593 " * If neither --csv or --ascii are used, the input mode is derived",
4594 " from the \".mode\" output mode",
4595 " * If FILE begins with \"|\" then it is a command that generates the",
4596 " input text.",
stephan29f24582022-05-19 00:38:34 +00004597#endif
drh2ce15c32017-07-11 13:34:40 +00004598#ifndef SQLITE_OMIT_TEST_CONTROL
drh98aa2ab2018-09-26 16:53:51 +00004599 ".imposter INDEX TABLE Create imposter table TABLE on index INDEX",
drh2ce15c32017-07-11 13:34:40 +00004600#endif
drh98aa2ab2018-09-26 16:53:51 +00004601 ".indexes ?TABLE? Show names of indexes",
4602 " If TABLE is specified, only show indexes for",
4603 " tables matching TABLE using the LIKE operator.",
drh2ce15c32017-07-11 13:34:40 +00004604#ifdef SQLITE_ENABLE_IOTRACE
drh98aa2ab2018-09-26 16:53:51 +00004605 ".iotrace FILE Enable I/O diagnostic logging to FILE",
drh2ce15c32017-07-11 13:34:40 +00004606#endif
drh98aa2ab2018-09-26 16:53:51 +00004607 ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT",
4608 ".lint OPTIONS Report potential schema issues.",
4609 " Options:",
4610 " fkey-indexes Find missing foreign key indexes",
stephan4413ec72022-07-12 15:53:02 +00004611#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_FIDDLE)
drh98aa2ab2018-09-26 16:53:51 +00004612 ".load FILE ?ENTRY? Load an extension library",
drh2ce15c32017-07-11 13:34:40 +00004613#endif
stephan4413ec72022-07-12 15:53:02 +00004614#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004615 ".log FILE|off Turn logging on or off. FILE can be stderr/stdout",
stephan618a3752022-05-19 10:24:50 +00004616#endif
drh47741b82022-01-31 22:14:53 +00004617 ".mode MODE ?OPTIONS? Set output mode",
drh98aa2ab2018-09-26 16:53:51 +00004618 " MODE is one of:",
drhe40f2862022-01-31 14:14:29 +00004619 " ascii Columns/rows delimited by 0x1F and 0x1E",
4620 " box Tables using unicode box-drawing characters",
4621 " csv Comma-separated values",
4622 " column Output in columns. (See .width)",
4623 " html HTML <table> code",
4624 " insert SQL insert statements for TABLE",
4625 " json Results in a JSON array",
4626 " line One value per line",
4627 " list Values delimited by \"|\"",
4628 " markdown Markdown table format",
drh1f41a8c2022-10-24 11:10:40 +00004629 " qbox Shorthand for \"box --wrap 60 --quote\"",
drhe40f2862022-01-31 14:14:29 +00004630 " quote Escape answers as for SQL",
4631 " table ASCII-art table",
4632 " tabs Tab-separated values",
4633 " tcl TCL list elements",
larrybrcc4d55c2022-02-01 02:50:45 +00004634 " OPTIONS: (for columnar modes or insert mode):",
4635 " --wrap N Wrap output lines to no longer than N characters",
drhca1776b2022-02-01 12:28:17 +00004636 " --wordwrap B Wrap or not at word boundaries per B (on/off)",
4637 " --ww Shorthand for \"--wordwrap 1\"",
larrybrcc4d55c2022-02-01 02:50:45 +00004638 " --quote Quote output text as SQL literals",
4639 " --noquote Do not quote output text",
4640 " TABLE The name of SQL table used for \"insert\" mode",
stephan4413ec72022-07-12 15:53:02 +00004641#ifndef SQLITE_SHELL_FIDDLE
larrybrcc4d55c2022-02-01 02:50:45 +00004642 ".nonce STRING Suspend safe mode for one command if nonce matches",
stephane26d1622022-05-19 22:04:23 +00004643#endif
drh98aa2ab2018-09-26 16:53:51 +00004644 ".nullvalue STRING Use STRING in place of NULL values",
stephan4413ec72022-07-12 15:53:02 +00004645#ifndef SQLITE_SHELL_FIDDLE
drh7a431002020-04-18 14:12:00 +00004646 ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
drh98aa2ab2018-09-26 16:53:51 +00004647 " If FILE begins with '|' then open as a pipe",
drh7a431002020-04-18 14:12:00 +00004648 " --bom Put a UTF8 byte-order mark at the beginning",
4649 " -e Send output to the system text editor",
4650 " -x Send output as CSV to a spreadsheet (same as \".excel\")",
stephande1e02e2022-05-24 19:01:21 +00004651 /* Note that .open is (partially) available in WASM builds but is
stephan085c5c62022-05-25 04:35:22 +00004652 ** currently only intended to be used by the fiddle tool, not
4653 ** end users, so is "undocumented." */
drh98aa2ab2018-09-26 16:53:51 +00004654 ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
4655 " Options:",
drh60f34ae2018-10-30 13:19:49 +00004656 " --append Use appendvfs to append database to the end of FILE",
stephan02520cc2022-05-18 22:58:34 +00004657#endif
drh8d889af2021-05-08 17:18:23 +00004658#ifndef SQLITE_OMIT_DESERIALIZE
drhd10c3ca2021-05-08 11:57:35 +00004659 " --deserialize Load into memory using sqlite3_deserialize()",
drhe2754c12019-08-26 12:50:01 +00004660 " --hexdb Load the output of \"dbtotxt\" as an in-memory db",
drh6ca64482019-01-22 16:06:20 +00004661 " --maxsize N Maximum size for --hexdb or --deserialized database",
drha751f392018-10-30 15:31:22 +00004662#endif
drh60f34ae2018-10-30 13:19:49 +00004663 " --new Initialize FILE to an empty database",
drh0933aad2019-11-18 17:46:38 +00004664 " --nofollow Do not follow symbolic links",
drh60f34ae2018-10-30 13:19:49 +00004665 " --readonly Open FILE readonly",
4666 " --zip FILE is a ZIP archive",
stephan4413ec72022-07-12 15:53:02 +00004667#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004668 ".output ?FILE? Send output to FILE or stdout if FILE is omitted",
drh7a431002020-04-18 14:12:00 +00004669 " If FILE begins with '|' then open it as a pipe.",
4670 " Options:",
4671 " --bom Prefix output with a UTF8 byte-order mark",
4672 " -e Send output to the system text editor",
4673 " -x Send output as CSV to a spreadsheet",
stephande1e02e2022-05-24 19:01:21 +00004674#endif
drh9cb02642019-02-28 20:10:52 +00004675 ".parameter CMD ... Manage SQL parameter bindings",
4676 " clear Erase all bindings",
4677 " init Initialize the TEMP table that holds bindings",
4678 " list List the current parameter bindings",
4679 " set PARAMETER VALUE Given SQL parameter PARAMETER a value of VALUE",
drhe2754c12019-08-26 12:50:01 +00004680 " PARAMETER should start with one of: $ : @ ?",
drh9cb02642019-02-28 20:10:52 +00004681 " unset PARAMETER Remove PARAMETER from the binding table",
drh98aa2ab2018-09-26 16:53:51 +00004682 ".print STRING... Print literal STRING",
drh569b1d92019-02-05 20:51:41 +00004683#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
drh3f83f592019-02-04 14:53:18 +00004684 ".progress N Invoke progress handler after every N opcodes",
4685 " --limit N Interrupt after N progress callbacks",
4686 " --once Do no more than one progress interrupt",
4687 " --quiet|-q No output except at interrupts",
4688 " --reset Reset the count for each input and interrupt",
drh569b1d92019-02-05 20:51:41 +00004689#endif
drh98aa2ab2018-09-26 16:53:51 +00004690 ".prompt MAIN CONTINUE Replace the standard prompts",
stephan4413ec72022-07-12 15:53:02 +00004691#ifndef SQLITE_SHELL_FIDDLE
larrybrbf395ec2023-01-09 18:42:28 +00004692 ".quit Stop interpreting input stream, exit if primary.",
larrybra2ba25b2021-12-28 05:08:38 +00004693 ".read FILE Read input from FILE or command output",
4694 " If FILE begins with \"|\", it is a command that generates the input.",
stephan02520cc2022-05-18 22:58:34 +00004695#endif
stephan3d420832022-10-27 03:56:01 +00004696#if SQLITE_SHELL_HAVE_RECOVER
dan42ebb012019-04-27 18:47:03 +00004697 ".recover Recover as much data as possible from corrupt db.",
danf7fea5b2022-10-27 18:19:45 +00004698 " --ignore-freelist Ignore pages that appear to be on db freelist",
drhe2754c12019-08-26 12:50:01 +00004699 " --lost-and-found TABLE Alternative name for the lost-and-found table",
dan8cce6b82019-09-14 16:44:51 +00004700 " --no-rowids Do not attempt to recover rowid values",
4701 " that are not also INTEGER PRIMARY KEYs",
dan1b162162019-04-27 20:15:15 +00004702#endif
stephan4413ec72022-07-12 15:53:02 +00004703#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004704 ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE",
larrybra7919ad2022-02-19 21:25:48 +00004705 ".save ?OPTIONS? FILE Write database to FILE (an alias for .backup ...)",
stephan02520cc2022-05-18 22:58:34 +00004706#endif
dan2797ac02022-12-08 21:05:33 +00004707 ".scanstats on|off|est Turn sqlite3_stmt_scanstatus() metrics on or off",
drh98aa2ab2018-09-26 16:53:51 +00004708 ".schema ?PATTERN? Show the CREATE statements matching PATTERN",
drhbbb29ec2020-10-12 14:56:47 +00004709 " Options:",
4710 " --indent Try to pretty-print the schema",
4711 " --nosys Omit objects whose names start with \"sqlite_\"",
drheb7f2a02018-09-26 18:02:32 +00004712 ".selftest ?OPTIONS? Run tests defined in the SELFTEST table",
4713 " Options:",
4714 " --init Create a new SELFTEST table",
4715 " -v Verbose output",
drh98aa2ab2018-09-26 16:53:51 +00004716 ".separator COL ?ROW? Change the column and row separators",
drh2ce15c32017-07-11 13:34:40 +00004717#if defined(SQLITE_ENABLE_SESSION)
drheb7f2a02018-09-26 18:02:32 +00004718 ".session ?NAME? CMD ... Create or control sessions",
4719 " Subcommands:",
4720 " attach TABLE Attach TABLE",
4721 " changeset FILE Write a changeset into FILE",
4722 " close Close one session",
4723 " enable ?BOOLEAN? Set or query the enable bit",
4724 " filter GLOB... Reject tables matching GLOBs",
4725 " indirect ?BOOLEAN? Mark or query the indirect status",
4726 " isempty Query whether the session is empty",
4727 " list List currently open session names",
4728 " open DB NAME Open a new session on DB",
4729 " patchset FILE Write a patchset into FILE",
4730 " If ?NAME? is omitted, the first defined session is used.",
drh2ce15c32017-07-11 13:34:40 +00004731#endif
drheb7f2a02018-09-26 18:02:32 +00004732 ".sha3sum ... Compute a SHA3 hash of database content",
4733 " Options:",
drh067b92b2020-06-19 15:24:12 +00004734 " --schema Also hash the sqlite_schema table",
drheb7f2a02018-09-26 18:02:32 +00004735 " --sha3-224 Use the sha3-224 algorithm",
drhe2754c12019-08-26 12:50:01 +00004736 " --sha3-256 Use the sha3-256 algorithm (default)",
drheb7f2a02018-09-26 18:02:32 +00004737 " --sha3-384 Use the sha3-384 algorithm",
4738 " --sha3-512 Use the sha3-512 algorithm",
4739 " Any other argument is a LIKE pattern for tables to hash",
stephan4413ec72022-07-12 15:53:02 +00004740#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
drh98aa2ab2018-09-26 16:53:51 +00004741 ".shell CMD ARGS... Run CMD ARGS... in a system shell",
drh04a28c32018-01-31 01:38:44 +00004742#endif
drh98aa2ab2018-09-26 16:53:51 +00004743 ".show Show the current values for various settings",
drha6e6cf22021-01-09 19:10:04 +00004744 ".stats ?ARG? Show stats or turn stats on or off",
4745 " off Turn off automatic stat display",
4746 " on Turn on automatic stat display",
4747 " stmt Show statement stats",
4748 " vmstep Show the virtual machine step count only",
stephan4413ec72022-07-12 15:53:02 +00004749#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
drh98aa2ab2018-09-26 16:53:51 +00004750 ".system CMD ARGS... Run CMD ARGS... in a system shell",
drh04a28c32018-01-31 01:38:44 +00004751#endif
drh98aa2ab2018-09-26 16:53:51 +00004752 ".tables ?TABLE? List names of tables matching LIKE pattern TABLE",
stephan4413ec72022-07-12 15:53:02 +00004753#ifndef SQLITE_SHELL_FIDDLE
drh98aa2ab2018-09-26 16:53:51 +00004754 ".testcase NAME Begin redirecting output to 'testcase-out.txt'",
stephan02520cc2022-05-18 22:58:34 +00004755#endif
drhd985f722019-06-05 14:29:53 +00004756 ".testctrl CMD ... Run various sqlite3_test_control() operations",
4757 " Run \".testctrl\" with no arguments for details",
drh98aa2ab2018-09-26 16:53:51 +00004758 ".timeout MS Try opening locked tables for MS milliseconds",
4759 ".timer on|off Turn SQL timer on or off",
drh707821f2018-12-05 13:39:06 +00004760#ifndef SQLITE_OMIT_TRACE
4761 ".trace ?OPTIONS? Output each SQL statement as it is run",
4762 " FILE Send output to FILE",
4763 " stdout Send output to stdout",
4764 " stderr Send output to stderr",
4765 " off Disable tracing",
4766 " --expanded Expand query parameters",
4767#ifdef SQLITE_ENABLE_NORMALIZE
4768 " --normalized Normal the SQL statements",
4769#endif
4770 " --plain Show SQL as it is input",
4771 " --stmt Trace statement execution (SQLITE_TRACE_STMT)",
4772 " --profile Profile statements (SQLITE_TRACE_PROFILE)",
4773 " --row Trace each row (SQLITE_TRACE_ROW)",
4774 " --close Trace connection close (SQLITE_TRACE_CLOSE)",
4775#endif /* SQLITE_OMIT_TRACE */
drhcc5979d2019-08-16 22:58:29 +00004776#ifdef SQLITE_DEBUG
4777 ".unmodule NAME ... Unregister virtual table modules",
drh5df84282019-08-17 19:45:25 +00004778 " --allexcept Unregister everything except those named",
drhcc5979d2019-08-16 22:58:29 +00004779#endif
drh98aa2ab2018-09-26 16:53:51 +00004780 ".vfsinfo ?AUX? Information about the top-level VFS",
4781 ".vfslist List all available VFSes",
4782 ".vfsname ?AUX? Print the name of the VFS stack",
drh7da29a32020-05-29 19:17:20 +00004783 ".width NUM1 NUM2 ... Set minimum column widths for columnar output",
drh98aa2ab2018-09-26 16:53:51 +00004784 " Negative values right-justify",
4785};
4786
4787/*
4788** Output help text.
4789**
4790** zPattern describes the set of commands for which help text is provided.
4791** If zPattern is NULL, then show all commands, but only give a one-line
4792** description of each.
4793**
4794** Return the number of matches.
4795*/
4796static int showHelp(FILE *out, const char *zPattern){
drhe93f8262018-10-11 16:53:37 +00004797 int i = 0;
4798 int j = 0;
drh98aa2ab2018-09-26 16:53:51 +00004799 int n = 0;
4800 char *zPat;
drh488cddf2018-10-06 14:38:17 +00004801 if( zPattern==0
4802 || zPattern[0]=='0'
drhbf70f1b2022-10-19 18:04:42 +00004803 || cli_strcmp(zPattern,"-a")==0
4804 || cli_strcmp(zPattern,"-all")==0
4805 || cli_strcmp(zPattern,"--all")==0
drh488cddf2018-10-06 14:38:17 +00004806 ){
drh98aa2ab2018-09-26 16:53:51 +00004807 /* Show all commands, but only one line per command */
drh488cddf2018-10-06 14:38:17 +00004808 if( zPattern==0 ) zPattern = "";
drh98aa2ab2018-09-26 16:53:51 +00004809 for(i=0; i<ArraySize(azHelp); i++){
drh488cddf2018-10-06 14:38:17 +00004810 if( azHelp[i][0]=='.' || zPattern[0] ){
drh98aa2ab2018-09-26 16:53:51 +00004811 utf8_printf(out, "%s\n", azHelp[i]);
4812 n++;
4813 }
4814 }
4815 }else{
4816 /* Look for commands that for which zPattern is an exact prefix */
4817 zPat = sqlite3_mprintf(".%s*", zPattern);
drhe3e25652021-12-16 13:29:28 +00004818 shell_check_oom(zPat);
drh98aa2ab2018-09-26 16:53:51 +00004819 for(i=0; i<ArraySize(azHelp); i++){
4820 if( sqlite3_strglob(zPat, azHelp[i])==0 ){
4821 utf8_printf(out, "%s\n", azHelp[i]);
drheb7f2a02018-09-26 18:02:32 +00004822 j = i+1;
drh98aa2ab2018-09-26 16:53:51 +00004823 n++;
4824 }
4825 }
4826 sqlite3_free(zPat);
drheb7f2a02018-09-26 18:02:32 +00004827 if( n ){
4828 if( n==1 ){
4829 /* when zPattern is a prefix of exactly one command, then include the
4830 ** details of that command, which should begin at offset j */
4831 while( j<ArraySize(azHelp)-1 && azHelp[j][0]!='.' ){
4832 utf8_printf(out, "%s\n", azHelp[j]);
4833 j++;
4834 }
4835 }
4836 return n;
4837 }
4838 /* Look for commands that contain zPattern anywhere. Show the complete
4839 ** text of all commands that match. */
drh98aa2ab2018-09-26 16:53:51 +00004840 zPat = sqlite3_mprintf("%%%s%%", zPattern);
drhe3e25652021-12-16 13:29:28 +00004841 shell_check_oom(zPat);
drh98aa2ab2018-09-26 16:53:51 +00004842 for(i=0; i<ArraySize(azHelp); i++){
4843 if( azHelp[i][0]=='.' ) j = i;
4844 if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
4845 utf8_printf(out, "%s\n", azHelp[j]);
4846 while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]!='.' ){
4847 j++;
4848 utf8_printf(out, "%s\n", azHelp[j]);
4849 }
4850 i = j;
4851 n++;
4852 }
4853 }
4854 sqlite3_free(zPat);
4855 }
4856 return n;
4857}
drh2ce15c32017-07-11 13:34:40 +00004858
drh2ce15c32017-07-11 13:34:40 +00004859/* Forward reference */
drh60379d42018-12-13 18:30:01 +00004860static int process_input(ShellState *p);
drh2ce15c32017-07-11 13:34:40 +00004861
4862/*
4863** Read the content of file zName into memory obtained from sqlite3_malloc64()
4864** and return a pointer to the buffer. The caller is responsible for freeing
4865** the memory.
4866**
4867** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
4868** read.
4869**
4870** For convenience, a nul-terminator byte is always appended to the data read
4871** from the file before the buffer is returned. This byte is not included in
4872** the final value of (*pnByte), if applicable.
4873**
4874** NULL is returned if any error is encountered. The final value of *pnByte
4875** is undefined in this case.
4876*/
4877static char *readFile(const char *zName, int *pnByte){
4878 FILE *in = fopen(zName, "rb");
4879 long nIn;
4880 size_t nRead;
4881 char *pBuf;
4882 if( in==0 ) return 0;
4883 fseek(in, 0, SEEK_END);
4884 nIn = ftell(in);
4885 rewind(in);
4886 pBuf = sqlite3_malloc64( nIn+1 );
drh1dbb1472018-10-11 10:37:24 +00004887 if( pBuf==0 ){ fclose(in); return 0; }
drh2ce15c32017-07-11 13:34:40 +00004888 nRead = fread(pBuf, nIn, 1, in);
4889 fclose(in);
4890 if( nRead!=1 ){
4891 sqlite3_free(pBuf);
4892 return 0;
4893 }
4894 pBuf[nIn] = 0;
4895 if( pnByte ) *pnByte = nIn;
4896 return pBuf;
4897}
4898
4899#if defined(SQLITE_ENABLE_SESSION)
4900/*
4901** Close a single OpenSession object and release all of its associated
4902** resources.
4903*/
4904static void session_close(OpenSession *pSession){
4905 int i;
4906 sqlite3session_delete(pSession->p);
4907 sqlite3_free(pSession->zName);
4908 for(i=0; i<pSession->nFilter; i++){
4909 sqlite3_free(pSession->azFilter[i]);
4910 }
4911 sqlite3_free(pSession->azFilter);
4912 memset(pSession, 0, sizeof(OpenSession));
4913}
4914#endif
4915
4916/*
4917** Close all OpenSession objects and release all associated resources.
4918*/
4919#if defined(SQLITE_ENABLE_SESSION)
drh37407122021-07-23 18:43:58 +00004920static void session_close_all(ShellState *p, int i){
4921 int j;
4922 struct AuxDb *pAuxDb = i<0 ? p->pAuxDb : &p->aAuxDb[i];
4923 for(j=0; j<pAuxDb->nSession; j++){
4924 session_close(&pAuxDb->aSession[j]);
drh2ce15c32017-07-11 13:34:40 +00004925 }
drh37407122021-07-23 18:43:58 +00004926 pAuxDb->nSession = 0;
drh2ce15c32017-07-11 13:34:40 +00004927}
4928#else
drh37407122021-07-23 18:43:58 +00004929# define session_close_all(X,Y)
drh2ce15c32017-07-11 13:34:40 +00004930#endif
4931
4932/*
4933** Implementation of the xFilter function for an open session. Omit
4934** any tables named by ".session filter" but let all other table through.
4935*/
4936#if defined(SQLITE_ENABLE_SESSION)
4937static int session_filter(void *pCtx, const char *zTab){
4938 OpenSession *pSession = (OpenSession*)pCtx;
4939 int i;
4940 for(i=0; i<pSession->nFilter; i++){
4941 if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
4942 }
4943 return 1;
4944}
4945#endif
4946
4947/*
drh1fa6d9f2018-01-06 21:46:01 +00004948** Try to deduce the type of file for zName based on its content. Return
4949** one of the SHELL_OPEN_* constants.
drh1bf208c2018-03-09 21:54:01 +00004950**
4951** If the file does not exist or is empty but its name looks like a ZIP
4952** archive and the dfltZip flag is true, then assume it is a ZIP archive.
4953** Otherwise, assume an ordinary database regardless of the filename if
4954** the type cannot be determined from content.
drh1fa6d9f2018-01-06 21:46:01 +00004955*/
drhfc97c1c2018-05-14 00:41:12 +00004956int deduceDatabaseType(const char *zName, int dfltZip){
drh1fa6d9f2018-01-06 21:46:01 +00004957 FILE *f = fopen(zName, "rb");
4958 size_t n;
4959 int rc = SHELL_OPEN_UNSPEC;
4960 char zBuf[100];
drh1bf208c2018-03-09 21:54:01 +00004961 if( f==0 ){
drhbe4ccb22018-05-17 20:04:24 +00004962 if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
4963 return SHELL_OPEN_ZIPFILE;
4964 }else{
4965 return SHELL_OPEN_NORMAL;
4966 }
drh1bf208c2018-03-09 21:54:01 +00004967 }
drh2b3c4af2018-10-30 14:36:21 +00004968 n = fread(zBuf, 16, 1, f);
4969 if( n==1 && memcmp(zBuf, "SQLite format 3", 16)==0 ){
4970 fclose(f);
4971 return SHELL_OPEN_NORMAL;
4972 }
drh1fa6d9f2018-01-06 21:46:01 +00004973 fseek(f, -25, SEEK_END);
4974 n = fread(zBuf, 25, 1, f);
4975 if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){
4976 rc = SHELL_OPEN_APPENDVFS;
4977 }else{
4978 fseek(f, -22, SEEK_END);
4979 n = fread(zBuf, 22, 1, f);
4980 if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05
4981 && zBuf[3]==0x06 ){
4982 rc = SHELL_OPEN_ZIPFILE;
drh1bf208c2018-03-09 21:54:01 +00004983 }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
mistachkina3926f42018-05-14 12:23:04 +00004984 rc = SHELL_OPEN_ZIPFILE;
drh1fa6d9f2018-01-06 21:46:01 +00004985 }
4986 }
4987 fclose(f);
larrybr0953c532022-12-23 19:04:59 +00004988 return rc;
drh1fa6d9f2018-01-06 21:46:01 +00004989}
4990
drh8d889af2021-05-08 17:18:23 +00004991#ifndef SQLITE_OMIT_DESERIALIZE
drh33746482018-12-13 15:06:26 +00004992/*
4993** Reconstruct an in-memory database using the output from the "dbtotxt"
drh37407122021-07-23 18:43:58 +00004994** program. Read content from the file in p->aAuxDb[].zDbFilename.
4995** If p->aAuxDb[].zDbFilename is 0, then read from standard input.
drh33746482018-12-13 15:06:26 +00004996*/
4997static unsigned char *readHexDb(ShellState *p, int *pnData){
4998 unsigned char *a = 0;
drh2c8ee022018-12-13 18:59:30 +00004999 int nLine;
drh33746482018-12-13 15:06:26 +00005000 int n = 0;
5001 int pgsz = 0;
5002 int iOffset = 0;
5003 int j, k;
5004 int rc;
5005 FILE *in;
drh37407122021-07-23 18:43:58 +00005006 const char *zDbFilename = p->pAuxDb->zDbFilename;
drh3ea557e2019-04-23 15:30:58 +00005007 unsigned int x[16];
drh2c8ee022018-12-13 18:59:30 +00005008 char zLine[1000];
drh37407122021-07-23 18:43:58 +00005009 if( zDbFilename ){
5010 in = fopen(zDbFilename, "r");
drh33746482018-12-13 15:06:26 +00005011 if( in==0 ){
drh37407122021-07-23 18:43:58 +00005012 utf8_printf(stderr, "cannot open \"%s\" for reading\n", zDbFilename);
drh33746482018-12-13 15:06:26 +00005013 return 0;
5014 }
drh2c8ee022018-12-13 18:59:30 +00005015 nLine = 0;
drh33746482018-12-13 15:06:26 +00005016 }else{
drh60379d42018-12-13 18:30:01 +00005017 in = p->in;
drh2c8ee022018-12-13 18:59:30 +00005018 nLine = p->lineno;
drh5bf46442019-05-03 02:41:36 +00005019 if( in==0 ) in = stdin;
drh33746482018-12-13 15:06:26 +00005020 }
5021 *pnData = 0;
drh2c8ee022018-12-13 18:59:30 +00005022 nLine++;
drh33746482018-12-13 15:06:26 +00005023 if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
5024 rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
5025 if( rc!=2 ) goto readHexDb_error;
drh68feae52019-05-09 11:18:41 +00005026 if( n<0 ) goto readHexDb_error;
drh09ea1252019-07-17 15:05:16 +00005027 if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error;
5028 n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */
drh68feae52019-05-09 11:18:41 +00005029 a = sqlite3_malloc( n ? n : 1 );
drhe3e25652021-12-16 13:29:28 +00005030 shell_check_oom(a);
drh33746482018-12-13 15:06:26 +00005031 memset(a, 0, n);
5032 if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
5033 utf8_printf(stderr, "invalid pagesize\n");
5034 goto readHexDb_error;
5035 }
drh2c8ee022018-12-13 18:59:30 +00005036 for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
drh33746482018-12-13 15:06:26 +00005037 rc = sscanf(zLine, "| page %d offset %d", &j, &k);
5038 if( rc==2 ){
5039 iOffset = k;
5040 continue;
5041 }
drhbf70f1b2022-10-19 18:04:42 +00005042 if( cli_strncmp(zLine, "| end ", 6)==0 ){
drh33746482018-12-13 15:06:26 +00005043 break;
5044 }
drh3ea557e2019-04-23 15:30:58 +00005045 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 +00005046 &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
5047 &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
5048 if( rc==17 ){
5049 k = iOffset+j;
drh82978ac2021-10-01 17:06:44 +00005050 if( k+16<=n && k>=0 ){
drh3ea557e2019-04-23 15:30:58 +00005051 int ii;
5052 for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff;
drh33746482018-12-13 15:06:26 +00005053 }
drh33746482018-12-13 15:06:26 +00005054 }
5055 }
5056 *pnData = n;
drh2c8ee022018-12-13 18:59:30 +00005057 if( in!=p->in ){
5058 fclose(in);
5059 }else{
5060 p->lineno = nLine;
5061 }
drh33746482018-12-13 15:06:26 +00005062 return a;
5063
5064readHexDb_error:
drh68feae52019-05-09 11:18:41 +00005065 if( in!=p->in ){
drh33746482018-12-13 15:06:26 +00005066 fclose(in);
5067 }else{
drh60379d42018-12-13 18:30:01 +00005068 while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
drh2c8ee022018-12-13 18:59:30 +00005069 nLine++;
drhbf70f1b2022-10-19 18:04:42 +00005070 if(cli_strncmp(zLine, "| end ", 6)==0 ) break;
drh33746482018-12-13 15:06:26 +00005071 }
drh2c8ee022018-12-13 18:59:30 +00005072 p->lineno = nLine;
drh33746482018-12-13 15:06:26 +00005073 }
5074 sqlite3_free(a);
5075 utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine);
5076 return 0;
5077}
drh8d889af2021-05-08 17:18:23 +00005078#endif /* SQLITE_OMIT_DESERIALIZE */
drh33746482018-12-13 15:06:26 +00005079
danb1825882019-04-23 20:48:32 +00005080/*
dan9c014f82019-04-25 19:23:15 +00005081** Scalar function "shell_int32". The first argument to this function
5082** must be a blob. The second a non-negative integer. This function
5083** reads and returns a 32-bit big-endian integer from byte
5084** offset (4*<arg2>) of the blob.
5085*/
5086static void shellInt32(
larrybr0953c532022-12-23 19:04:59 +00005087 sqlite3_context *context,
5088 int argc,
dan9c014f82019-04-25 19:23:15 +00005089 sqlite3_value **argv
5090){
5091 const unsigned char *pBlob;
5092 int nBlob;
5093 int iInt;
drh9546c762019-05-10 17:50:33 +00005094
5095 UNUSED_PARAMETER(argc);
dan9c014f82019-04-25 19:23:15 +00005096 nBlob = sqlite3_value_bytes(argv[0]);
5097 pBlob = (const unsigned char*)sqlite3_value_blob(argv[0]);
5098 iInt = sqlite3_value_int(argv[1]);
5099
5100 if( iInt>=0 && (iInt+1)*4<=nBlob ){
5101 const unsigned char *a = &pBlob[iInt*4];
5102 sqlite3_int64 iVal = ((sqlite3_int64)a[0]<<24)
5103 + ((sqlite3_int64)a[1]<<16)
5104 + ((sqlite3_int64)a[2]<< 8)
5105 + ((sqlite3_int64)a[3]<< 0);
5106 sqlite3_result_int64(context, iVal);
5107 }
5108}
5109
5110/*
drha2de66c2019-08-06 20:26:17 +00005111** Scalar function "shell_idquote(X)" returns string X quoted as an identifier,
5112** using "..." with internal double-quote characters doubled.
5113*/
5114static void shellIdQuote(
larrybr0953c532022-12-23 19:04:59 +00005115 sqlite3_context *context,
5116 int argc,
drha2de66c2019-08-06 20:26:17 +00005117 sqlite3_value **argv
5118){
5119 const char *zName = (const char*)sqlite3_value_text(argv[0]);
drh51755a72019-08-08 19:40:29 +00005120 UNUSED_PARAMETER(argc);
drha2de66c2019-08-06 20:26:17 +00005121 if( zName ){
5122 char *z = sqlite3_mprintf("\"%w\"", zName);
5123 sqlite3_result_text(context, z, -1, sqlite3_free);
5124 }
5125}
5126
5127/*
drhddcfe922020-09-15 12:29:35 +00005128** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X.
5129*/
5130static void shellUSleepFunc(
larrybr0953c532022-12-23 19:04:59 +00005131 sqlite3_context *context,
5132 int argcUnused,
drhddcfe922020-09-15 12:29:35 +00005133 sqlite3_value **argv
5134){
5135 int sleep = sqlite3_value_int(argv[0]);
drhd36f5882020-11-25 16:28:04 +00005136 (void)argcUnused;
drhddcfe922020-09-15 12:29:35 +00005137 sqlite3_sleep(sleep/1000);
5138 sqlite3_result_int(context, sleep);
5139}
5140
5141/*
danb1825882019-04-23 20:48:32 +00005142** Scalar function "shell_escape_crnl" used by the .recover command.
5143** The argument passed to this function is the output of built-in
larrybr0953c532022-12-23 19:04:59 +00005144** function quote(). If the first character of the input is "'",
danb1825882019-04-23 20:48:32 +00005145** indicating that the value passed to quote() was a text value,
5146** then this function searches the input for "\n" and "\r" characters
5147** and adds a wrapper similar to the following:
5148**
5149** replace(replace(<input>, '\n', char(10), '\r', char(13));
5150**
5151** Or, if the first character of the input is not "'", then a copy
5152** of the input is returned.
5153*/
5154static void shellEscapeCrnl(
larrybr0953c532022-12-23 19:04:59 +00005155 sqlite3_context *context,
5156 int argc,
danb1825882019-04-23 20:48:32 +00005157 sqlite3_value **argv
5158){
5159 const char *zText = (const char*)sqlite3_value_text(argv[0]);
drh9546c762019-05-10 17:50:33 +00005160 UNUSED_PARAMETER(argc);
drh621a5e02021-12-16 17:35:27 +00005161 if( zText && zText[0]=='\'' ){
drh7d23d152022-10-11 12:02:42 +00005162 i64 nText = sqlite3_value_bytes(argv[0]);
5163 i64 i;
danb1825882019-04-23 20:48:32 +00005164 char zBuf1[20];
5165 char zBuf2[20];
5166 const char *zNL = 0;
5167 const char *zCR = 0;
drh7d23d152022-10-11 12:02:42 +00005168 i64 nCR = 0;
5169 i64 nNL = 0;
danb1825882019-04-23 20:48:32 +00005170
5171 for(i=0; zText[i]; i++){
5172 if( zNL==0 && zText[i]=='\n' ){
5173 zNL = unused_string(zText, "\\n", "\\012", zBuf1);
drh7d23d152022-10-11 12:02:42 +00005174 nNL = strlen(zNL);
danb1825882019-04-23 20:48:32 +00005175 }
5176 if( zCR==0 && zText[i]=='\r' ){
5177 zCR = unused_string(zText, "\\r", "\\015", zBuf2);
drh7d23d152022-10-11 12:02:42 +00005178 nCR = strlen(zCR);
danb1825882019-04-23 20:48:32 +00005179 }
5180 }
5181
5182 if( zNL || zCR ){
drh7d23d152022-10-11 12:02:42 +00005183 i64 iOut = 0;
danb1825882019-04-23 20:48:32 +00005184 i64 nMax = (nNL > nCR) ? nNL : nCR;
dan51f5ffa2019-04-29 11:41:46 +00005185 i64 nAlloc = nMax * nText + (nMax+64)*2;
danb1825882019-04-23 20:48:32 +00005186 char *zOut = (char*)sqlite3_malloc64(nAlloc);
5187 if( zOut==0 ){
5188 sqlite3_result_error_nomem(context);
5189 return;
5190 }
5191
5192 if( zNL && zCR ){
5193 memcpy(&zOut[iOut], "replace(replace(", 16);
5194 iOut += 16;
5195 }else{
5196 memcpy(&zOut[iOut], "replace(", 8);
5197 iOut += 8;
5198 }
5199 for(i=0; zText[i]; i++){
5200 if( zText[i]=='\n' ){
5201 memcpy(&zOut[iOut], zNL, nNL);
5202 iOut += nNL;
5203 }else if( zText[i]=='\r' ){
5204 memcpy(&zOut[iOut], zCR, nCR);
5205 iOut += nCR;
5206 }else{
5207 zOut[iOut] = zText[i];
5208 iOut++;
5209 }
5210 }
5211
5212 if( zNL ){
5213 memcpy(&zOut[iOut], ",'", 2); iOut += 2;
5214 memcpy(&zOut[iOut], zNL, nNL); iOut += nNL;
5215 memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12;
5216 }
5217 if( zCR ){
5218 memcpy(&zOut[iOut], ",'", 2); iOut += 2;
5219 memcpy(&zOut[iOut], zCR, nCR); iOut += nCR;
5220 memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12;
5221 }
5222
5223 sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT);
5224 sqlite3_free(zOut);
5225 return;
5226 }
5227 }
5228
5229 sqlite3_result_value(context, argv[0]);
5230}
5231
drhbe4ccb22018-05-17 20:04:24 +00005232/* Flags for open_db().
5233**
5234** The default behavior of open_db() is to exit(1) if the database fails to
5235** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error
5236** but still returns without calling exit.
5237**
5238** The OPEN_DB_ZIPFILE flag causes open_db() to prefer to open files as a
5239** ZIP archive if the file does not exist or is empty and its name matches
5240** the *.zip pattern.
5241*/
5242#define OPEN_DB_KEEPALIVE 0x001 /* Return after error if true */
5243#define OPEN_DB_ZIPFILE 0x002 /* Open as ZIP if name matches *.zip */
5244
drh1fa6d9f2018-01-06 21:46:01 +00005245/*
drh2ce15c32017-07-11 13:34:40 +00005246** Make sure the database is open. If it is not, then open it. If
5247** the database fails to open, print an error message and exit.
5248*/
drhbe4ccb22018-05-17 20:04:24 +00005249static void open_db(ShellState *p, int openFlags){
drh2ce15c32017-07-11 13:34:40 +00005250 if( p->db==0 ){
drh37407122021-07-23 18:43:58 +00005251 const char *zDbFilename = p->pAuxDb->zDbFilename;
drhf2072d12018-05-11 15:10:11 +00005252 if( p->openMode==SHELL_OPEN_UNSPEC ){
drh37407122021-07-23 18:43:58 +00005253 if( zDbFilename==0 || zDbFilename[0]==0 ){
drhf2072d12018-05-11 15:10:11 +00005254 p->openMode = SHELL_OPEN_NORMAL;
drhbe4ccb22018-05-17 20:04:24 +00005255 }else{
larrybr0953c532022-12-23 19:04:59 +00005256 p->openMode = (u8)deduceDatabaseType(zDbFilename,
drhbe4ccb22018-05-17 20:04:24 +00005257 (openFlags & OPEN_DB_ZIPFILE)!=0);
drhf2072d12018-05-11 15:10:11 +00005258 }
drh1fa6d9f2018-01-06 21:46:01 +00005259 }
5260 switch( p->openMode ){
5261 case SHELL_OPEN_APPENDVFS: {
larrybr0953c532022-12-23 19:04:59 +00005262 sqlite3_open_v2(zDbFilename, &p->db,
drh0933aad2019-11-18 17:46:38 +00005263 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs");
drh1fa6d9f2018-01-06 21:46:01 +00005264 break;
5265 }
drh33746482018-12-13 15:06:26 +00005266 case SHELL_OPEN_HEXDB:
drh60f34ae2018-10-30 13:19:49 +00005267 case SHELL_OPEN_DESERIALIZE: {
5268 sqlite3_open(0, &p->db);
5269 break;
5270 }
drh1fa6d9f2018-01-06 21:46:01 +00005271 case SHELL_OPEN_ZIPFILE: {
5272 sqlite3_open(":memory:", &p->db);
5273 break;
5274 }
drhee269a62018-02-14 23:27:43 +00005275 case SHELL_OPEN_READONLY: {
drh37407122021-07-23 18:43:58 +00005276 sqlite3_open_v2(zDbFilename, &p->db,
drh0933aad2019-11-18 17:46:38 +00005277 SQLITE_OPEN_READONLY|p->openFlags, 0);
drhee269a62018-02-14 23:27:43 +00005278 break;
5279 }
drh1fa6d9f2018-01-06 21:46:01 +00005280 case SHELL_OPEN_UNSPEC:
5281 case SHELL_OPEN_NORMAL: {
drh37407122021-07-23 18:43:58 +00005282 sqlite3_open_v2(zDbFilename, &p->db,
drh0933aad2019-11-18 17:46:38 +00005283 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
drh1fa6d9f2018-01-06 21:46:01 +00005284 break;
5285 }
5286 }
drh2ce15c32017-07-11 13:34:40 +00005287 globalDb = p->db;
5288 if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
5289 utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
drh37407122021-07-23 18:43:58 +00005290 zDbFilename, sqlite3_errmsg(p->db));
drhf25cc4f2019-01-04 14:29:21 +00005291 if( openFlags & OPEN_DB_KEEPALIVE ){
5292 sqlite3_open(":memory:", &p->db);
5293 return;
5294 }
drh2ce15c32017-07-11 13:34:40 +00005295 exit(1);
5296 }
larrybr423003d2022-11-21 00:11:09 +00005297
drh2ce15c32017-07-11 13:34:40 +00005298#ifndef SQLITE_OMIT_LOAD_EXTENSION
5299 sqlite3_enable_load_extension(p->db, 1);
5300#endif
drh2ce15c32017-07-11 13:34:40 +00005301 sqlite3_shathree_init(p->db, 0, 0);
drhf05dd032020-04-14 15:53:58 +00005302 sqlite3_uint_init(p->db, 0, 0);
drhbeb9def2020-06-22 19:12:23 +00005303 sqlite3_decimal_init(p->db, 0, 0);
larrybr0953c532022-12-23 19:04:59 +00005304 sqlite3_base64_init(p->db, 0, 0);
5305 sqlite3_base85_init(p->db, 0, 0);
drh64689902021-06-03 13:51:31 +00005306 sqlite3_regexp_init(p->db, 0, 0);
drh8cda77d2020-06-24 15:06:29 +00005307 sqlite3_ieee_init(p->db, 0, 0);
mistachkin72c38d82020-08-28 18:47:39 +00005308 sqlite3_series_init(p->db, 0, 0);
stephan4413ec72022-07-12 15:53:02 +00005309#ifndef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +00005310 sqlite3_fileio_init(p->db, 0, 0);
5311 sqlite3_completion_init(p->db, 0, 0);
5312#endif
stephan3d420832022-10-27 03:56:01 +00005313#if SQLITE_SHELL_HAVE_RECOVER
dan68cb86e2019-04-20 20:57:28 +00005314 sqlite3_dbdata_init(p->db, 0, 0);
dan1b162162019-04-27 20:15:15 +00005315#endif
dan72afc3c2017-12-05 18:32:40 +00005316#ifdef SQLITE_HAVE_ZLIB
drh9198f5a2022-03-19 15:19:35 +00005317 if( !p->bSafeModePersist ){
5318 sqlite3_zipfile_init(p->db, 0, 0);
5319 sqlite3_sqlar_init(p->db, 0, 0);
5320 }
dan72afc3c2017-12-05 18:32:40 +00005321#endif
larrybr423003d2022-11-21 00:11:09 +00005322#ifdef SQLITE_SHELL_EXTFUNCS
5323 /* Create a preprocessing mechanism for extensions to make
5324 * their own provisions for being built into the shell.
5325 * This is a short-span macro. See further below for usage.
5326 */
5327#define SHELL_SUB_MACRO(base, variant) base ## _ ## variant
5328#define SHELL_SUBMACRO(base, variant) SHELL_SUB_MACRO(base, variant)
5329 /* Let custom-included extensions get their ..._init() called.
5330 * The WHATEVER_INIT( db, pzErrorMsg, pApi ) macro should cause
5331 * the extension's sqlite3_*_init( db, pzErrorMsg, pApi )
5332 * inititialization routine to be called.
5333 */
5334 {
5335 int irc = SHELL_SUBMACRO(SQLITE_SHELL_EXTFUNCS, INIT)(p->db);
5336 /* Let custom-included extensions expose their functionality.
5337 * The WHATEVER_EXPOSE( db, pzErrorMsg ) macro should cause
5338 * the SQL functions, virtual tables, collating sequences or
5339 * VFS's implemented by the extension to be registered.
5340 */
5341 if( irc==SQLITE_OK
5342 || irc==SQLITE_OK_LOAD_PERMANENTLY ){
5343 SHELL_SUBMACRO(SQLITE_SHELL_EXTFUNCS, EXPOSE)(p->db, 0);
5344 }
5345#undef SHELL_SUB_MACRO
5346#undef SHELL_SUBMACRO
5347 }
5348#endif
5349
drhceba7922018-01-01 21:28:25 +00005350 sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
drh2ce15c32017-07-11 13:34:40 +00005351 shellAddSchemaName, 0, 0);
drh667a2a22018-01-02 00:04:37 +00005352 sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
5353 shellModuleSchema, 0, 0);
drh634c70f2018-01-10 16:50:18 +00005354 sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
5355 shellPutsFunc, 0, 0);
danb1825882019-04-23 20:48:32 +00005356 sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0,
5357 shellEscapeCrnl, 0, 0);
dan9c014f82019-04-25 19:23:15 +00005358 sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0,
5359 shellInt32, 0, 0);
drha2de66c2019-08-06 20:26:17 +00005360 sqlite3_create_function(p->db, "shell_idquote", 1, SQLITE_UTF8, 0,
5361 shellIdQuote, 0, 0);
drhddcfe922020-09-15 12:29:35 +00005362 sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0,
5363 shellUSleepFunc, 0, 0);
drh04a28c32018-01-31 01:38:44 +00005364#ifndef SQLITE_NOHAVE_SYSTEM
drh97913132018-01-11 00:04:00 +00005365 sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
5366 editFunc, 0, 0);
5367 sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
5368 editFunc, 0, 0);
drh04a28c32018-01-31 01:38:44 +00005369#endif
larrybr423003d2022-11-21 00:11:09 +00005370
drh1fa6d9f2018-01-06 21:46:01 +00005371 if( p->openMode==SHELL_OPEN_ZIPFILE ){
5372 char *zSql = sqlite3_mprintf(
drh37407122021-07-23 18:43:58 +00005373 "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename);
drhe3e25652021-12-16 13:29:28 +00005374 shell_check_oom(zSql);
drh1fa6d9f2018-01-06 21:46:01 +00005375 sqlite3_exec(p->db, zSql, 0, 0, 0);
5376 sqlite3_free(zSql);
drha751f392018-10-30 15:31:22 +00005377 }
drh8d889af2021-05-08 17:18:23 +00005378#ifndef SQLITE_OMIT_DESERIALIZE
drh33746482018-12-13 15:06:26 +00005379 else
5380 if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){
mistachkin99490932018-12-17 22:19:57 +00005381 int rc;
drh60f34ae2018-10-30 13:19:49 +00005382 int nData = 0;
drh33746482018-12-13 15:06:26 +00005383 unsigned char *aData;
5384 if( p->openMode==SHELL_OPEN_DESERIALIZE ){
drh37407122021-07-23 18:43:58 +00005385 aData = (unsigned char*)readFile(zDbFilename, &nData);
drh33746482018-12-13 15:06:26 +00005386 }else{
5387 aData = readHexDb(p, &nData);
5388 if( aData==0 ){
drh33746482018-12-13 15:06:26 +00005389 return;
5390 }
5391 }
mistachkin99490932018-12-17 22:19:57 +00005392 rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
drh60f34ae2018-10-30 13:19:49 +00005393 SQLITE_DESERIALIZE_RESIZEABLE |
5394 SQLITE_DESERIALIZE_FREEONCLOSE);
5395 if( rc ){
5396 utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc);
5397 }
drh6ca64482019-01-22 16:06:20 +00005398 if( p->szMax>0 ){
5399 sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
5400 }
drh1fa6d9f2018-01-06 21:46:01 +00005401 }
drha751f392018-10-30 15:31:22 +00005402#endif
drh2ce15c32017-07-11 13:34:40 +00005403 }
drhb97e2ad2021-08-26 18:31:39 +00005404 if( p->bSafeModePersist && p->db!=0 ){
5405 sqlite3_set_authorizer(p->db, safeModeAuth, p);
5406 }
drh2ce15c32017-07-11 13:34:40 +00005407}
5408
drh9e804032018-05-18 17:11:50 +00005409/*
5410** Attempt to close the databaes connection. Report errors.
5411*/
5412void close_db(sqlite3 *db){
5413 int rc = sqlite3_close(db);
5414 if( rc ){
5415 utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n",
5416 rc, sqlite3_errmsg(db));
larrybr0953c532022-12-23 19:04:59 +00005417 }
drh9e804032018-05-18 17:11:50 +00005418}
5419
drh56eb09b2017-07-11 13:59:07 +00005420#if HAVE_READLINE || HAVE_EDITLINE
5421/*
5422** Readline completion callbacks
5423*/
5424static char *readline_completion_generator(const char *text, int state){
5425 static sqlite3_stmt *pStmt = 0;
5426 char *zRet;
5427 if( state==0 ){
5428 char *zSql;
drh56eb09b2017-07-11 13:59:07 +00005429 sqlite3_finalize(pStmt);
5430 zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
5431 " FROM completion(%Q) ORDER BY 1", text);
drhe3e25652021-12-16 13:29:28 +00005432 shell_check_oom(zSql);
drh56eb09b2017-07-11 13:59:07 +00005433 sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
5434 sqlite3_free(zSql);
5435 }
5436 if( sqlite3_step(pStmt)==SQLITE_ROW ){
drh621a5e02021-12-16 17:35:27 +00005437 const char *z = (const char*)sqlite3_column_text(pStmt,0);
5438 zRet = z ? strdup(z) : 0;
drh56eb09b2017-07-11 13:59:07 +00005439 }else{
5440 sqlite3_finalize(pStmt);
5441 pStmt = 0;
5442 zRet = 0;
5443 }
5444 return zRet;
5445}
5446static char **readline_completion(const char *zText, int iStart, int iEnd){
drh3547e492022-12-23 14:49:24 +00005447 (void)iStart;
5448 (void)iEnd;
drh56eb09b2017-07-11 13:59:07 +00005449 rl_attempted_completion_over = 1;
5450 return rl_completion_matches(zText, readline_completion_generator);
5451}
5452
5453#elif HAVE_LINENOISE
5454/*
5455** Linenoise completion callback
5456*/
5457static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
drh7d23d152022-10-11 12:02:42 +00005458 i64 nLine = strlen(zLine);
5459 i64 i, iStart;
drh56eb09b2017-07-11 13:59:07 +00005460 sqlite3_stmt *pStmt = 0;
5461 char *zSql;
5462 char zBuf[1000];
5463
5464 if( nLine>sizeof(zBuf)-30 ) return;
drh1615c372018-05-12 23:56:22 +00005465 if( zLine[0]=='.' || zLine[0]=='#') return;
drh56eb09b2017-07-11 13:59:07 +00005466 for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
5467 if( i==nLine-1 ) return;
5468 iStart = i+1;
5469 memcpy(zBuf, zLine, iStart);
5470 zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
5471 " FROM completion(%Q,%Q) ORDER BY 1",
5472 &zLine[iStart], zLine);
drhe3e25652021-12-16 13:29:28 +00005473 shell_check_oom(zSql);
drh56eb09b2017-07-11 13:59:07 +00005474 sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
5475 sqlite3_free(zSql);
5476 sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
5477 while( sqlite3_step(pStmt)==SQLITE_ROW ){
5478 const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
5479 int nCompletion = sqlite3_column_bytes(pStmt, 0);
drh621a5e02021-12-16 17:35:27 +00005480 if( iStart+nCompletion < sizeof(zBuf)-1 && zCompletion ){
drh56eb09b2017-07-11 13:59:07 +00005481 memcpy(zBuf+iStart, zCompletion, nCompletion+1);
5482 linenoiseAddCompletion(lc, zBuf);
5483 }
5484 }
5485 sqlite3_finalize(pStmt);
5486}
5487#endif
5488
drh2ce15c32017-07-11 13:34:40 +00005489/*
5490** Do C-language style dequoting.
5491**
5492** \a -> alarm
5493** \b -> backspace
5494** \t -> tab
5495** \n -> newline
5496** \v -> vertical tab
5497** \f -> form feed
5498** \r -> carriage return
5499** \s -> space
5500** \" -> "
5501** \' -> '
5502** \\ -> backslash
5503** \NNN -> ascii character NNN in octal
5504*/
5505static void resolve_backslashes(char *z){
5506 int i, j;
5507 char c;
5508 while( *z && *z!='\\' ) z++;
5509 for(i=j=0; (c = z[i])!=0; i++, j++){
5510 if( c=='\\' && z[i+1]!=0 ){
5511 c = z[++i];
5512 if( c=='a' ){
5513 c = '\a';
5514 }else if( c=='b' ){
5515 c = '\b';
5516 }else if( c=='t' ){
5517 c = '\t';
5518 }else if( c=='n' ){
5519 c = '\n';
5520 }else if( c=='v' ){
5521 c = '\v';
5522 }else if( c=='f' ){
5523 c = '\f';
5524 }else if( c=='r' ){
5525 c = '\r';
5526 }else if( c=='"' ){
5527 c = '"';
5528 }else if( c=='\'' ){
5529 c = '\'';
5530 }else if( c=='\\' ){
5531 c = '\\';
5532 }else if( c>='0' && c<='7' ){
5533 c -= '0';
5534 if( z[i+1]>='0' && z[i+1]<='7' ){
5535 i++;
5536 c = (c<<3) + z[i] - '0';
5537 if( z[i+1]>='0' && z[i+1]<='7' ){
5538 i++;
5539 c = (c<<3) + z[i] - '0';
5540 }
5541 }
5542 }
5543 }
5544 z[j] = c;
5545 }
5546 if( j<i ) z[j] = 0;
5547}
5548
5549/*
drh2ce15c32017-07-11 13:34:40 +00005550** Interpret zArg as either an integer or a boolean value. Return 1 or 0
5551** for TRUE and FALSE. Return the integer value if appropriate.
5552*/
5553static int booleanValue(const char *zArg){
5554 int i;
5555 if( zArg[0]=='0' && zArg[1]=='x' ){
5556 for(i=2; hexDigitValue(zArg[i])>=0; i++){}
5557 }else{
5558 for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
5559 }
5560 if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
5561 if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
5562 return 1;
5563 }
5564 if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
5565 return 0;
5566 }
5567 utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
5568 zArg);
5569 return 0;
5570}
5571
5572/*
5573** Set or clear a shell flag according to a boolean value.
5574*/
5575static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){
5576 if( booleanValue(zArg) ){
5577 ShellSetFlag(p, mFlag);
5578 }else{
5579 ShellClearFlag(p, mFlag);
5580 }
5581}
5582
5583/*
5584** Close an output file, assuming it is not stderr or stdout
5585*/
5586static void output_file_close(FILE *f){
5587 if( f && f!=stdout && f!=stderr ) fclose(f);
5588}
5589
5590/*
5591** Try to open an output file. The names "stdout" and "stderr" are
5592** recognized and do the right thing. NULL is returned if the output
5593** filename is "off".
5594*/
drha92a01a2018-01-10 22:15:37 +00005595static FILE *output_file_open(const char *zFile, int bTextMode){
drh2ce15c32017-07-11 13:34:40 +00005596 FILE *f;
drhbf70f1b2022-10-19 18:04:42 +00005597 if( cli_strcmp(zFile,"stdout")==0 ){
drh2ce15c32017-07-11 13:34:40 +00005598 f = stdout;
drhbf70f1b2022-10-19 18:04:42 +00005599 }else if( cli_strcmp(zFile, "stderr")==0 ){
drh2ce15c32017-07-11 13:34:40 +00005600 f = stderr;
drhbf70f1b2022-10-19 18:04:42 +00005601 }else if( cli_strcmp(zFile, "off")==0 ){
drh2ce15c32017-07-11 13:34:40 +00005602 f = 0;
5603 }else{
drha92a01a2018-01-10 22:15:37 +00005604 f = fopen(zFile, bTextMode ? "w" : "wb");
drh2ce15c32017-07-11 13:34:40 +00005605 if( f==0 ){
5606 utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
5607 }
5608 }
5609 return f;
5610}
5611
drh707821f2018-12-05 13:39:06 +00005612#ifndef SQLITE_OMIT_TRACE
drh2ce15c32017-07-11 13:34:40 +00005613/*
5614** A routine for handling output from sqlite3_trace().
5615*/
5616static int sql_trace_callback(
drh707821f2018-12-05 13:39:06 +00005617 unsigned mType, /* The trace type */
5618 void *pArg, /* The ShellState pointer */
5619 void *pP, /* Usually a pointer to sqlite_stmt */
5620 void *pX /* Auxiliary output */
drh2ce15c32017-07-11 13:34:40 +00005621){
drh707821f2018-12-05 13:39:06 +00005622 ShellState *p = (ShellState*)pArg;
5623 sqlite3_stmt *pStmt;
5624 const char *zSql;
drh7d23d152022-10-11 12:02:42 +00005625 i64 nSql;
drh707821f2018-12-05 13:39:06 +00005626 if( p->traceOut==0 ) return 0;
5627 if( mType==SQLITE_TRACE_CLOSE ){
5628 utf8_printf(p->traceOut, "-- closing database connection\n");
5629 return 0;
5630 }
5631 if( mType!=SQLITE_TRACE_ROW && ((const char*)pX)[0]=='-' ){
5632 zSql = (const char*)pX;
5633 }else{
5634 pStmt = (sqlite3_stmt*)pP;
5635 switch( p->eTraceType ){
5636 case SHELL_TRACE_EXPANDED: {
5637 zSql = sqlite3_expanded_sql(pStmt);
5638 break;
5639 }
5640#ifdef SQLITE_ENABLE_NORMALIZE
5641 case SHELL_TRACE_NORMALIZED: {
5642 zSql = sqlite3_normalized_sql(pStmt);
5643 break;
5644 }
5645#endif
5646 default: {
5647 zSql = sqlite3_sql(pStmt);
5648 break;
5649 }
5650 }
5651 }
5652 if( zSql==0 ) return 0;
drh7d23d152022-10-11 12:02:42 +00005653 nSql = strlen(zSql);
5654 if( nSql>1000000000 ) nSql = 1000000000;
drh707821f2018-12-05 13:39:06 +00005655 while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
5656 switch( mType ){
5657 case SQLITE_TRACE_ROW:
5658 case SQLITE_TRACE_STMT: {
drh7d23d152022-10-11 12:02:42 +00005659 utf8_printf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
drh707821f2018-12-05 13:39:06 +00005660 break;
5661 }
5662 case SQLITE_TRACE_PROFILE: {
5663 sqlite3_int64 nNanosec = *(sqlite3_int64*)pX;
drh7d23d152022-10-11 12:02:42 +00005664 utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
drh707821f2018-12-05 13:39:06 +00005665 break;
5666 }
drh2ce15c32017-07-11 13:34:40 +00005667 }
5668 return 0;
5669}
5670#endif
drh2ce15c32017-07-11 13:34:40 +00005671
5672/*
5673** A no-op routine that runs with the ".breakpoint" doc-command. This is
5674** a useful spot to set a debugger breakpoint.
5675*/
5676static void test_breakpoint(void){
5677 static int nCall = 0;
5678 nCall++;
5679}
5680
5681/*
5682** An object used to read a CSV and other files for import.
5683*/
5684typedef struct ImportCtx ImportCtx;
5685struct ImportCtx {
5686 const char *zFile; /* Name of the input file */
5687 FILE *in; /* Read the CSV text from this input stream */
drh97767842020-05-29 19:39:35 +00005688 int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close in */
drh2ce15c32017-07-11 13:34:40 +00005689 char *z; /* Accumulated text for a field */
5690 int n; /* Number of bytes in z */
5691 int nAlloc; /* Space allocated for z[] */
5692 int nLine; /* Current line number */
drhccb37812020-03-09 15:39:39 +00005693 int nRow; /* Number of rows imported */
5694 int nErr; /* Number of errors encountered */
drh2ce15c32017-07-11 13:34:40 +00005695 int bNotFirst; /* True if one or more bytes already read */
5696 int cTerm; /* Character that terminated the most recent field */
5697 int cColSep; /* The column separator character. (Usually ",") */
5698 int cRowSep; /* The row separator character. (Usually "\n") */
5699};
5700
drh97767842020-05-29 19:39:35 +00005701/* Clean up resourced used by an ImportCtx */
5702static void import_cleanup(ImportCtx *p){
drh42c2a042020-05-29 20:16:19 +00005703 if( p->in!=0 && p->xCloser!=0 ){
drh97767842020-05-29 19:39:35 +00005704 p->xCloser(p->in);
5705 p->in = 0;
5706 }
5707 sqlite3_free(p->z);
5708 p->z = 0;
5709}
5710
drh2ce15c32017-07-11 13:34:40 +00005711/* Append a single byte to z[] */
5712static void import_append_char(ImportCtx *p, int c){
5713 if( p->n+1>=p->nAlloc ){
5714 p->nAlloc += p->nAlloc + 100;
5715 p->z = sqlite3_realloc64(p->z, p->nAlloc);
drhe3e25652021-12-16 13:29:28 +00005716 shell_check_oom(p->z);
drh2ce15c32017-07-11 13:34:40 +00005717 }
5718 p->z[p->n++] = (char)c;
5719}
5720
5721/* Read a single field of CSV text. Compatible with rfc4180 and extended
5722** with the option of having a separator other than ",".
5723**
5724** + Input comes from p->in.
5725** + Store results in p->z of length p->n. Space to hold p->z comes
5726** from sqlite3_malloc64().
5727** + Use p->cSep as the column separator. The default is ",".
5728** + Use p->rSep as the row separator. The default is "\n".
5729** + Keep track of the line number in p->nLine.
5730** + Store the character that terminates the field in p->cTerm. Store
5731** EOF on end-of-file.
5732** + Report syntax errors on stderr
5733*/
5734static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
5735 int c;
5736 int cSep = p->cColSep;
5737 int rSep = p->cRowSep;
5738 p->n = 0;
5739 c = fgetc(p->in);
5740 if( c==EOF || seenInterrupt ){
5741 p->cTerm = EOF;
5742 return 0;
5743 }
5744 if( c=='"' ){
5745 int pc, ppc;
5746 int startLine = p->nLine;
5747 int cQuote = c;
5748 pc = ppc = 0;
5749 while( 1 ){
5750 c = fgetc(p->in);
5751 if( c==rSep ) p->nLine++;
5752 if( c==cQuote ){
5753 if( pc==cQuote ){
5754 pc = 0;
5755 continue;
5756 }
5757 }
5758 if( (c==cSep && pc==cQuote)
5759 || (c==rSep && pc==cQuote)
5760 || (c==rSep && pc=='\r' && ppc==cQuote)
5761 || (c==EOF && pc==cQuote)
5762 ){
5763 do{ p->n--; }while( p->z[p->n]!=cQuote );
5764 p->cTerm = c;
5765 break;
5766 }
5767 if( pc==cQuote && c!='\r' ){
5768 utf8_printf(stderr, "%s:%d: unescaped %c character\n",
5769 p->zFile, p->nLine, cQuote);
5770 }
5771 if( c==EOF ){
5772 utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n",
5773 p->zFile, startLine, cQuote);
5774 p->cTerm = c;
5775 break;
5776 }
5777 import_append_char(p, c);
5778 ppc = pc;
5779 pc = c;
5780 }
5781 }else{
5782 /* If this is the first field being parsed and it begins with the
5783 ** UTF-8 BOM (0xEF BB BF) then skip the BOM */
5784 if( (c&0xff)==0xef && p->bNotFirst==0 ){
5785 import_append_char(p, c);
5786 c = fgetc(p->in);
5787 if( (c&0xff)==0xbb ){
5788 import_append_char(p, c);
5789 c = fgetc(p->in);
5790 if( (c&0xff)==0xbf ){
5791 p->bNotFirst = 1;
5792 p->n = 0;
5793 return csv_read_one_field(p);
5794 }
5795 }
5796 }
5797 while( c!=EOF && c!=cSep && c!=rSep ){
5798 import_append_char(p, c);
5799 c = fgetc(p->in);
5800 }
5801 if( c==rSep ){
5802 p->nLine++;
5803 if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
5804 }
5805 p->cTerm = c;
5806 }
5807 if( p->z ) p->z[p->n] = 0;
5808 p->bNotFirst = 1;
5809 return p->z;
5810}
5811
5812/* Read a single field of ASCII delimited text.
5813**
5814** + Input comes from p->in.
5815** + Store results in p->z of length p->n. Space to hold p->z comes
5816** from sqlite3_malloc64().
5817** + Use p->cSep as the column separator. The default is "\x1F".
5818** + Use p->rSep as the row separator. The default is "\x1E".
5819** + Keep track of the row number in p->nLine.
5820** + Store the character that terminates the field in p->cTerm. Store
5821** EOF on end-of-file.
5822** + Report syntax errors on stderr
5823*/
5824static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
5825 int c;
5826 int cSep = p->cColSep;
5827 int rSep = p->cRowSep;
5828 p->n = 0;
5829 c = fgetc(p->in);
5830 if( c==EOF || seenInterrupt ){
5831 p->cTerm = EOF;
5832 return 0;
5833 }
5834 while( c!=EOF && c!=cSep && c!=rSep ){
5835 import_append_char(p, c);
5836 c = fgetc(p->in);
5837 }
5838 if( c==rSep ){
5839 p->nLine++;
5840 }
5841 p->cTerm = c;
5842 if( p->z ) p->z[p->n] = 0;
5843 return p->z;
5844}
5845
5846/*
5847** Try to transfer data for table zTable. If an error is seen while
5848** moving forward, try to go backwards. The backwards movement won't
5849** work for WITHOUT ROWID tables.
5850*/
5851static void tryToCloneData(
5852 ShellState *p,
5853 sqlite3 *newDb,
5854 const char *zTable
5855){
5856 sqlite3_stmt *pQuery = 0;
5857 sqlite3_stmt *pInsert = 0;
5858 char *zQuery = 0;
5859 char *zInsert = 0;
5860 int rc;
5861 int i, j, n;
drhaf2770f2018-01-05 14:55:43 +00005862 int nTable = strlen30(zTable);
drh2ce15c32017-07-11 13:34:40 +00005863 int k = 0;
5864 int cnt = 0;
5865 const int spinRate = 10000;
5866
5867 zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
drhe3e25652021-12-16 13:29:28 +00005868 shell_check_oom(zQuery);
drh2ce15c32017-07-11 13:34:40 +00005869 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
5870 if( rc ){
5871 utf8_printf(stderr, "Error %d: %s on [%s]\n",
5872 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
5873 zQuery);
5874 goto end_data_xfer;
5875 }
5876 n = sqlite3_column_count(pQuery);
5877 zInsert = sqlite3_malloc64(200 + nTable + n*3);
drhe3e25652021-12-16 13:29:28 +00005878 shell_check_oom(zInsert);
drh2ce15c32017-07-11 13:34:40 +00005879 sqlite3_snprintf(200+nTable,zInsert,
5880 "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
drhaf2770f2018-01-05 14:55:43 +00005881 i = strlen30(zInsert);
drh2ce15c32017-07-11 13:34:40 +00005882 for(j=1; j<n; j++){
5883 memcpy(zInsert+i, ",?", 2);
5884 i += 2;
5885 }
5886 memcpy(zInsert+i, ");", 3);
5887 rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
5888 if( rc ){
5889 utf8_printf(stderr, "Error %d: %s on [%s]\n",
5890 sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
5891 zQuery);
5892 goto end_data_xfer;
5893 }
5894 for(k=0; k<2; k++){
5895 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
5896 for(i=0; i<n; i++){
5897 switch( sqlite3_column_type(pQuery, i) ){
5898 case SQLITE_NULL: {
5899 sqlite3_bind_null(pInsert, i+1);
5900 break;
5901 }
5902 case SQLITE_INTEGER: {
5903 sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
5904 break;
5905 }
5906 case SQLITE_FLOAT: {
5907 sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
5908 break;
5909 }
5910 case SQLITE_TEXT: {
5911 sqlite3_bind_text(pInsert, i+1,
5912 (const char*)sqlite3_column_text(pQuery,i),
5913 -1, SQLITE_STATIC);
5914 break;
5915 }
5916 case SQLITE_BLOB: {
5917 sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
5918 sqlite3_column_bytes(pQuery,i),
5919 SQLITE_STATIC);
5920 break;
5921 }
5922 }
5923 } /* End for */
5924 rc = sqlite3_step(pInsert);
5925 if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
5926 utf8_printf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
5927 sqlite3_errmsg(newDb));
5928 }
5929 sqlite3_reset(pInsert);
5930 cnt++;
5931 if( (cnt%spinRate)==0 ){
5932 printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
5933 fflush(stdout);
5934 }
5935 } /* End while */
5936 if( rc==SQLITE_DONE ) break;
5937 sqlite3_finalize(pQuery);
5938 sqlite3_free(zQuery);
5939 zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
5940 zTable);
drhe3e25652021-12-16 13:29:28 +00005941 shell_check_oom(zQuery);
drh2ce15c32017-07-11 13:34:40 +00005942 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
5943 if( rc ){
5944 utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
5945 break;
5946 }
5947 } /* End for(k=0...) */
5948
5949end_data_xfer:
5950 sqlite3_finalize(pQuery);
5951 sqlite3_finalize(pInsert);
5952 sqlite3_free(zQuery);
5953 sqlite3_free(zInsert);
5954}
5955
5956
5957/*
5958** Try to transfer all rows of the schema that match zWhere. For
5959** each row, invoke xForEach() on the object defined by that row.
5960** If an error is encountered while moving forward through the
drh067b92b2020-06-19 15:24:12 +00005961** sqlite_schema table, try again moving backwards.
drh2ce15c32017-07-11 13:34:40 +00005962*/
5963static void tryToCloneSchema(
5964 ShellState *p,
5965 sqlite3 *newDb,
5966 const char *zWhere,
5967 void (*xForEach)(ShellState*,sqlite3*,const char*)
5968){
5969 sqlite3_stmt *pQuery = 0;
5970 char *zQuery = 0;
5971 int rc;
5972 const unsigned char *zName;
5973 const unsigned char *zSql;
5974 char *zErrMsg = 0;
5975
drh067b92b2020-06-19 15:24:12 +00005976 zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +00005977 " WHERE %s", zWhere);
drhe3e25652021-12-16 13:29:28 +00005978 shell_check_oom(zQuery);
drh2ce15c32017-07-11 13:34:40 +00005979 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
5980 if( rc ){
5981 utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
5982 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
5983 zQuery);
5984 goto end_schema_xfer;
5985 }
5986 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
5987 zName = sqlite3_column_text(pQuery, 0);
5988 zSql = sqlite3_column_text(pQuery, 1);
drh621a5e02021-12-16 17:35:27 +00005989 if( zName==0 || zSql==0 ) continue;
drh2ce15c32017-07-11 13:34:40 +00005990 printf("%s... ", zName); fflush(stdout);
5991 sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
5992 if( zErrMsg ){
5993 utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
5994 sqlite3_free(zErrMsg);
5995 zErrMsg = 0;
5996 }
5997 if( xForEach ){
5998 xForEach(p, newDb, (const char*)zName);
5999 }
6000 printf("done\n");
6001 }
6002 if( rc!=SQLITE_DONE ){
6003 sqlite3_finalize(pQuery);
6004 sqlite3_free(zQuery);
drh067b92b2020-06-19 15:24:12 +00006005 zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +00006006 " WHERE %s ORDER BY rowid DESC", zWhere);
drhe3e25652021-12-16 13:29:28 +00006007 shell_check_oom(zQuery);
drh2ce15c32017-07-11 13:34:40 +00006008 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
6009 if( rc ){
6010 utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
6011 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
6012 zQuery);
6013 goto end_schema_xfer;
6014 }
drh76fc88f2021-10-02 16:39:16 +00006015 while( sqlite3_step(pQuery)==SQLITE_ROW ){
drh2ce15c32017-07-11 13:34:40 +00006016 zName = sqlite3_column_text(pQuery, 0);
6017 zSql = sqlite3_column_text(pQuery, 1);
drh621a5e02021-12-16 17:35:27 +00006018 if( zName==0 || zSql==0 ) continue;
drh2ce15c32017-07-11 13:34:40 +00006019 printf("%s... ", zName); fflush(stdout);
6020 sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
6021 if( zErrMsg ){
6022 utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
6023 sqlite3_free(zErrMsg);
6024 zErrMsg = 0;
6025 }
6026 if( xForEach ){
6027 xForEach(p, newDb, (const char*)zName);
6028 }
6029 printf("done\n");
6030 }
6031 }
6032end_schema_xfer:
6033 sqlite3_finalize(pQuery);
6034 sqlite3_free(zQuery);
6035}
6036
6037/*
6038** Open a new database file named "zNewDb". Try to recover as much information
6039** as possible out of the main database (which might be corrupt) and write it
6040** into zNewDb.
6041*/
6042static void tryToClone(ShellState *p, const char *zNewDb){
6043 int rc;
6044 sqlite3 *newDb = 0;
6045 if( access(zNewDb,0)==0 ){
6046 utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb);
6047 return;
6048 }
6049 rc = sqlite3_open(zNewDb, &newDb);
6050 if( rc ){
6051 utf8_printf(stderr, "Cannot create output database: %s\n",
6052 sqlite3_errmsg(newDb));
6053 }else{
6054 sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
6055 sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
6056 tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
6057 tryToCloneSchema(p, newDb, "type!='table'", 0);
6058 sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
6059 sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
6060 }
drh9e804032018-05-18 17:11:50 +00006061 close_db(newDb);
drh2ce15c32017-07-11 13:34:40 +00006062}
6063
6064/*
drh13c20932018-01-10 21:41:55 +00006065** Change the output file back to stdout.
6066**
6067** If the p->doXdgOpen flag is set, that means the output was being
6068** redirected to a temporary file named by p->zTempFile. In that case,
6069** launch start/open/xdg-open on that temporary file.
drh2ce15c32017-07-11 13:34:40 +00006070*/
6071static void output_reset(ShellState *p){
6072 if( p->outfile[0]=='|' ){
6073#ifndef SQLITE_OMIT_POPEN
6074 pclose(p->out);
6075#endif
6076 }else{
6077 output_file_close(p->out);
drh04a28c32018-01-31 01:38:44 +00006078#ifndef SQLITE_NOHAVE_SYSTEM
drh13c20932018-01-10 21:41:55 +00006079 if( p->doXdgOpen ){
6080 const char *zXdgOpenCmd =
6081#if defined(_WIN32)
6082 "start";
6083#elif defined(__APPLE__)
6084 "open";
6085#else
6086 "xdg-open";
6087#endif
6088 char *zCmd;
6089 zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
drha92a01a2018-01-10 22:15:37 +00006090 if( system(zCmd) ){
6091 utf8_printf(stderr, "Failed: [%s]\n", zCmd);
drh1d9ea272020-04-17 23:46:54 +00006092 }else{
6093 /* Give the start/open/xdg-open command some time to get
6094 ** going before we continue, and potential delete the
6095 ** p->zTempFile data file out from under it */
6096 sqlite3_sleep(2000);
drha92a01a2018-01-10 22:15:37 +00006097 }
drh13c20932018-01-10 21:41:55 +00006098 sqlite3_free(zCmd);
drh3c484e82018-01-10 22:27:21 +00006099 outputModePop(p);
drh13c20932018-01-10 21:41:55 +00006100 p->doXdgOpen = 0;
6101 }
drh04a28c32018-01-31 01:38:44 +00006102#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
drh2ce15c32017-07-11 13:34:40 +00006103 }
6104 p->outfile[0] = 0;
6105 p->out = stdout;
6106}
6107
6108/*
6109** Run an SQL command and return the single integer result.
6110*/
larrybr58a53d62022-02-10 03:21:48 +00006111static int db_int(sqlite3 *db, const char *zSql){
drh2ce15c32017-07-11 13:34:40 +00006112 sqlite3_stmt *pStmt;
6113 int res = 0;
larrybr58a53d62022-02-10 03:21:48 +00006114 sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
drh2ce15c32017-07-11 13:34:40 +00006115 if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
6116 res = sqlite3_column_int(pStmt,0);
6117 }
6118 sqlite3_finalize(pStmt);
6119 return res;
6120}
6121
drh04836682022-06-08 18:29:23 +00006122#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
drh2ce15c32017-07-11 13:34:40 +00006123/*
6124** Convert a 2-byte or 4-byte big-endian integer into a native integer
6125*/
6126static unsigned int get2byteInt(unsigned char *a){
6127 return (a[0]<<8) + a[1];
6128}
6129static unsigned int get4byteInt(unsigned char *a){
6130 return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
6131}
6132
6133/*
drh76c12062020-01-14 13:13:19 +00006134** Implementation of the ".dbinfo" command.
drh2ce15c32017-07-11 13:34:40 +00006135**
6136** Return 1 on error, 2 to exit, and 0 otherwise.
6137*/
6138static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
6139 static const struct { const char *zName; int ofst; } aField[] = {
6140 { "file change counter:", 24 },
6141 { "database page count:", 28 },
6142 { "freelist page count:", 36 },
6143 { "schema cookie:", 40 },
6144 { "schema format:", 44 },
6145 { "default cache size:", 48 },
6146 { "autovacuum top root:", 52 },
6147 { "incremental vacuum:", 64 },
6148 { "text encoding:", 56 },
6149 { "user version:", 60 },
6150 { "application id:", 68 },
6151 { "software version:", 96 },
6152 };
6153 static const struct { const char *zName; const char *zSql; } aQuery[] = {
6154 { "number of tables:",
6155 "SELECT count(*) FROM %s WHERE type='table'" },
6156 { "number of indexes:",
6157 "SELECT count(*) FROM %s WHERE type='index'" },
6158 { "number of triggers:",
6159 "SELECT count(*) FROM %s WHERE type='trigger'" },
6160 { "number of views:",
6161 "SELECT count(*) FROM %s WHERE type='view'" },
6162 { "schema size:",
6163 "SELECT total(length(sql)) FROM %s" },
6164 };
drh87c889c2019-03-20 18:22:51 +00006165 int i, rc;
drhea99a312018-07-18 19:09:07 +00006166 unsigned iDataVersion;
drh2ce15c32017-07-11 13:34:40 +00006167 char *zSchemaTab;
6168 char *zDb = nArg>=2 ? azArg[1] : "main";
drh512e6c32017-10-11 17:51:08 +00006169 sqlite3_stmt *pStmt = 0;
drh2ce15c32017-07-11 13:34:40 +00006170 unsigned char aHdr[100];
6171 open_db(p, 0);
6172 if( p->db==0 ) return 1;
drh87c889c2019-03-20 18:22:51 +00006173 rc = sqlite3_prepare_v2(p->db,
6174 "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
6175 -1, &pStmt, 0);
6176 if( rc ){
drh451f89a2020-04-28 23:09:56 +00006177 utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db));
drh87c889c2019-03-20 18:22:51 +00006178 sqlite3_finalize(pStmt);
6179 return 1;
6180 }
drh512e6c32017-10-11 17:51:08 +00006181 sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
6182 if( sqlite3_step(pStmt)==SQLITE_ROW
6183 && sqlite3_column_bytes(pStmt,0)>100
6184 ){
6185 memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
6186 sqlite3_finalize(pStmt);
6187 }else{
drh2ce15c32017-07-11 13:34:40 +00006188 raw_printf(stderr, "unable to read database header\n");
drh512e6c32017-10-11 17:51:08 +00006189 sqlite3_finalize(pStmt);
drh2ce15c32017-07-11 13:34:40 +00006190 return 1;
6191 }
6192 i = get2byteInt(aHdr+16);
6193 if( i==1 ) i = 65536;
6194 utf8_printf(p->out, "%-20s %d\n", "database page size:", i);
6195 utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
6196 utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
6197 utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
6198 for(i=0; i<ArraySize(aField); i++){
6199 int ofst = aField[i].ofst;
6200 unsigned int val = get4byteInt(aHdr + ofst);
6201 utf8_printf(p->out, "%-20s %u", aField[i].zName, val);
6202 switch( ofst ){
6203 case 56: {
6204 if( val==1 ) raw_printf(p->out, " (utf8)");
6205 if( val==2 ) raw_printf(p->out, " (utf16le)");
6206 if( val==3 ) raw_printf(p->out, " (utf16be)");
6207 }
6208 }
6209 raw_printf(p->out, "\n");
6210 }
6211 if( zDb==0 ){
drh067b92b2020-06-19 15:24:12 +00006212 zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
drhbf70f1b2022-10-19 18:04:42 +00006213 }else if( cli_strcmp(zDb,"temp")==0 ){
drh067b92b2020-06-19 15:24:12 +00006214 zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema");
drh2ce15c32017-07-11 13:34:40 +00006215 }else{
drh067b92b2020-06-19 15:24:12 +00006216 zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
drh2ce15c32017-07-11 13:34:40 +00006217 }
6218 for(i=0; i<ArraySize(aQuery); i++){
6219 char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
larrybr58a53d62022-02-10 03:21:48 +00006220 int val = db_int(p->db, zSql);
drh2ce15c32017-07-11 13:34:40 +00006221 sqlite3_free(zSql);
6222 utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
6223 }
6224 sqlite3_free(zSchemaTab);
drhea99a312018-07-18 19:09:07 +00006225 sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
6226 utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion);
drh2ce15c32017-07-11 13:34:40 +00006227 return 0;
6228}
stephan3d420832022-10-27 03:56:01 +00006229#endif /* SQLITE_SHELL_HAVE_RECOVER */
drh2ce15c32017-07-11 13:34:40 +00006230
6231/*
6232** Print the current sqlite3_errmsg() value to stderr and return 1.
6233*/
6234static int shellDatabaseError(sqlite3 *db){
6235 const char *zErr = sqlite3_errmsg(db);
6236 utf8_printf(stderr, "Error: %s\n", zErr);
6237 return 1;
6238}
6239
6240/*
drh2ce15c32017-07-11 13:34:40 +00006241** Compare the pattern in zGlob[] against the text in z[]. Return TRUE
6242** if they match and FALSE (0) if they do not match.
6243**
6244** Globbing rules:
6245**
6246** '*' Matches any sequence of zero or more characters.
6247**
6248** '?' Matches exactly one character.
6249**
6250** [...] Matches one character from the enclosed list of
6251** characters.
6252**
6253** [^...] Matches one character not in the enclosed list.
6254**
6255** '#' Matches any sequence of one or more digits with an
6256** optional + or - sign in front
6257**
6258** ' ' Any span of whitespace matches any other span of
6259** whitespace.
6260**
6261** Extra whitespace at the end of z[] is ignored.
6262*/
6263static int testcase_glob(const char *zGlob, const char *z){
6264 int c, c2;
6265 int invert;
6266 int seen;
6267
6268 while( (c = (*(zGlob++)))!=0 ){
6269 if( IsSpace(c) ){
6270 if( !IsSpace(*z) ) return 0;
6271 while( IsSpace(*zGlob) ) zGlob++;
6272 while( IsSpace(*z) ) z++;
6273 }else if( c=='*' ){
6274 while( (c=(*(zGlob++))) == '*' || c=='?' ){
6275 if( c=='?' && (*(z++))==0 ) return 0;
6276 }
6277 if( c==0 ){
6278 return 1;
6279 }else if( c=='[' ){
6280 while( *z && testcase_glob(zGlob-1,z)==0 ){
6281 z++;
6282 }
6283 return (*z)!=0;
6284 }
6285 while( (c2 = (*(z++)))!=0 ){
6286 while( c2!=c ){
6287 c2 = *(z++);
6288 if( c2==0 ) return 0;
6289 }
6290 if( testcase_glob(zGlob,z) ) return 1;
6291 }
6292 return 0;
6293 }else if( c=='?' ){
6294 if( (*(z++))==0 ) return 0;
6295 }else if( c=='[' ){
6296 int prior_c = 0;
6297 seen = 0;
6298 invert = 0;
6299 c = *(z++);
6300 if( c==0 ) return 0;
6301 c2 = *(zGlob++);
6302 if( c2=='^' ){
6303 invert = 1;
6304 c2 = *(zGlob++);
6305 }
6306 if( c2==']' ){
6307 if( c==']' ) seen = 1;
6308 c2 = *(zGlob++);
6309 }
6310 while( c2 && c2!=']' ){
6311 if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
6312 c2 = *(zGlob++);
6313 if( c>=prior_c && c<=c2 ) seen = 1;
6314 prior_c = 0;
6315 }else{
6316 if( c==c2 ){
6317 seen = 1;
6318 }
6319 prior_c = c2;
6320 }
6321 c2 = *(zGlob++);
6322 }
6323 if( c2==0 || (seen ^ invert)==0 ) return 0;
6324 }else if( c=='#' ){
6325 if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++;
6326 if( !IsDigit(z[0]) ) return 0;
6327 z++;
6328 while( IsDigit(z[0]) ){ z++; }
6329 }else{
6330 if( c!=(*(z++)) ) return 0;
6331 }
6332 }
6333 while( IsSpace(*z) ){ z++; }
6334 return *z==0;
6335}
6336
6337
6338/*
6339** Compare the string as a command-line option with either one or two
6340** initial "-" characters.
6341*/
6342static int optionMatch(const char *zStr, const char *zOpt){
6343 if( zStr[0]!='-' ) return 0;
6344 zStr++;
6345 if( zStr[0]=='-' ) zStr++;
drhbf70f1b2022-10-19 18:04:42 +00006346 return cli_strcmp(zStr, zOpt)==0;
drh2ce15c32017-07-11 13:34:40 +00006347}
6348
6349/*
6350** Delete a file.
6351*/
6352int shellDeleteFile(const char *zFilename){
6353 int rc;
6354#ifdef _WIN32
6355 wchar_t *z = sqlite3_win32_utf8_to_unicode(zFilename);
6356 rc = _wunlink(z);
6357 sqlite3_free(z);
6358#else
6359 rc = unlink(zFilename);
6360#endif
6361 return rc;
6362}
6363
drh13c20932018-01-10 21:41:55 +00006364/*
6365** Try to delete the temporary file (if there is one) and free the
6366** memory used to hold the name of the temp file.
6367*/
6368static void clearTempFile(ShellState *p){
6369 if( p->zTempFile==0 ) return;
drh536c3452018-01-11 00:38:39 +00006370 if( p->doXdgOpen ) return;
drh13c20932018-01-10 21:41:55 +00006371 if( shellDeleteFile(p->zTempFile) ) return;
6372 sqlite3_free(p->zTempFile);
6373 p->zTempFile = 0;
6374}
6375
6376/*
6377** Create a new temp file name with the given suffix.
6378*/
6379static void newTempFile(ShellState *p, const char *zSuffix){
6380 clearTempFile(p);
6381 sqlite3_free(p->zTempFile);
6382 p->zTempFile = 0;
drh7f3bf8a2018-01-10 21:50:08 +00006383 if( p->db ){
6384 sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
6385 }
drh13c20932018-01-10 21:41:55 +00006386 if( p->zTempFile==0 ){
drh1d9ea272020-04-17 23:46:54 +00006387 /* If p->db is an in-memory database then the TEMPFILENAME file-control
6388 ** will not work and we will need to fallback to guessing */
6389 char *zTemp;
drh13c20932018-01-10 21:41:55 +00006390 sqlite3_uint64 r;
6391 sqlite3_randomness(sizeof(r), &r);
drh1d9ea272020-04-17 23:46:54 +00006392 zTemp = getenv("TEMP");
6393 if( zTemp==0 ) zTemp = getenv("TMP");
6394 if( zTemp==0 ){
6395#ifdef _WIN32
6396 zTemp = "\\tmp";
6397#else
6398 zTemp = "/tmp";
6399#endif
6400 }
6401 p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
drh13c20932018-01-10 21:41:55 +00006402 }else{
6403 p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
6404 }
drhe3e25652021-12-16 13:29:28 +00006405 shell_check_oom(p->zTempFile);
drh13c20932018-01-10 21:41:55 +00006406}
6407
drh2ce15c32017-07-11 13:34:40 +00006408
6409/*
6410** The implementation of SQL scalar function fkey_collate_clause(), used
6411** by the ".lint fkey-indexes" command. This scalar function is always
6412** called with four arguments - the parent table name, the parent column name,
6413** the child table name and the child column name.
6414**
6415** fkey_collate_clause('parent-tab', 'parent-col', 'child-tab', 'child-col')
6416**
6417** If either of the named tables or columns do not exist, this function
6418** returns an empty string. An empty string is also returned if both tables
6419** and columns exist but have the same default collation sequence. Or,
6420** if both exist but the default collation sequences are different, this
6421** function returns the string " COLLATE <parent-collation>", where
6422** <parent-collation> is the default collation sequence of the parent column.
6423*/
6424static void shellFkeyCollateClause(
6425 sqlite3_context *pCtx,
6426 int nVal,
6427 sqlite3_value **apVal
6428){
6429 sqlite3 *db = sqlite3_context_db_handle(pCtx);
6430 const char *zParent;
6431 const char *zParentCol;
6432 const char *zParentSeq;
6433 const char *zChild;
6434 const char *zChildCol;
6435 const char *zChildSeq = 0; /* Initialize to avoid false-positive warning */
6436 int rc;
6437
6438 assert( nVal==4 );
6439 zParent = (const char*)sqlite3_value_text(apVal[0]);
6440 zParentCol = (const char*)sqlite3_value_text(apVal[1]);
6441 zChild = (const char*)sqlite3_value_text(apVal[2]);
6442 zChildCol = (const char*)sqlite3_value_text(apVal[3]);
6443
6444 sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
6445 rc = sqlite3_table_column_metadata(
6446 db, "main", zParent, zParentCol, 0, &zParentSeq, 0, 0, 0
6447 );
6448 if( rc==SQLITE_OK ){
6449 rc = sqlite3_table_column_metadata(
6450 db, "main", zChild, zChildCol, 0, &zChildSeq, 0, 0, 0
6451 );
6452 }
6453
6454 if( rc==SQLITE_OK && sqlite3_stricmp(zParentSeq, zChildSeq) ){
6455 char *z = sqlite3_mprintf(" COLLATE %s", zParentSeq);
6456 sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
6457 sqlite3_free(z);
6458 }
6459}
6460
6461
6462/*
6463** The implementation of dot-command ".lint fkey-indexes".
6464*/
6465static int lintFkeyIndexes(
6466 ShellState *pState, /* Current shell tool state */
6467 char **azArg, /* Array of arguments passed to dot command */
6468 int nArg /* Number of entries in azArg[] */
6469){
6470 sqlite3 *db = pState->db; /* Database handle to query "main" db of */
6471 FILE *out = pState->out; /* Stream to write non-error output to */
6472 int bVerbose = 0; /* If -verbose is present */
6473 int bGroupByParent = 0; /* If -groupbyparent is present */
6474 int i; /* To iterate through azArg[] */
6475 const char *zIndent = ""; /* How much to indent CREATE INDEX by */
6476 int rc; /* Return code */
6477 sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
6478
6479 /*
6480 ** This SELECT statement returns one row for each foreign key constraint
6481 ** in the schema of the main database. The column values are:
6482 **
6483 ** 0. The text of an SQL statement similar to:
6484 **
danf9679312017-12-01 18:40:18 +00006485 ** "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
drh2ce15c32017-07-11 13:34:40 +00006486 **
danf9679312017-12-01 18:40:18 +00006487 ** This SELECT is similar to the one that the foreign keys implementation
6488 ** needs to run internally on child tables. If there is an index that can
drh2ce15c32017-07-11 13:34:40 +00006489 ** be used to optimize this query, then it can also be used by the FK
6490 ** implementation to optimize DELETE or UPDATE statements on the parent
6491 ** table.
6492 **
6493 ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
6494 ** the EXPLAIN QUERY PLAN command matches this pattern, then the schema
6495 ** contains an index that can be used to optimize the query.
6496 **
6497 ** 2. Human readable text that describes the child table and columns. e.g.
6498 **
6499 ** "child_table(child_key1, child_key2)"
6500 **
6501 ** 3. Human readable text that describes the parent table and columns. e.g.
6502 **
6503 ** "parent_table(parent_key1, parent_key2)"
6504 **
6505 ** 4. A full CREATE INDEX statement for an index that could be used to
6506 ** optimize DELETE or UPDATE statements on the parent table. e.g.
6507 **
6508 ** "CREATE INDEX child_table_child_key ON child_table(child_key)"
6509 **
6510 ** 5. The name of the parent table.
6511 **
6512 ** These six values are used by the C logic below to generate the report.
6513 */
6514 const char *zSql =
6515 "SELECT "
danf9679312017-12-01 18:40:18 +00006516 " 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
drh2ce15c32017-07-11 13:34:40 +00006517 " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
6518 " || fkey_collate_clause("
6519 " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
6520 ", "
drh82102332021-03-20 15:11:29 +00006521 " 'SEARCH ' || s.name || ' USING COVERING INDEX*('"
drh2ce15c32017-07-11 13:34:40 +00006522 " || group_concat('*=?', ' AND ') || ')'"
6523 ", "
6524 " s.name || '(' || group_concat(f.[from], ', ') || ')'"
6525 ", "
6526 " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
6527 ", "
6528 " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
6529 " || ' ON ' || quote(s.name) || '('"
6530 " || group_concat(quote(f.[from]) ||"
6531 " fkey_collate_clause("
6532 " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
6533 " || ');'"
6534 ", "
6535 " f.[table] "
drh067b92b2020-06-19 15:24:12 +00006536 "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f "
drh2ce15c32017-07-11 13:34:40 +00006537 "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
6538 "GROUP BY s.name, f.id "
6539 "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
6540 ;
drh82102332021-03-20 15:11:29 +00006541 const char *zGlobIPK = "SEARCH * USING INTEGER PRIMARY KEY (rowid=?)";
drh2ce15c32017-07-11 13:34:40 +00006542
6543 for(i=2; i<nArg; i++){
drhaf2770f2018-01-05 14:55:43 +00006544 int n = strlen30(azArg[i]);
drh2ce15c32017-07-11 13:34:40 +00006545 if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
6546 bVerbose = 1;
6547 }
6548 else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
6549 bGroupByParent = 1;
6550 zIndent = " ";
6551 }
6552 else{
6553 raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
6554 azArg[0], azArg[1]
6555 );
6556 return SQLITE_ERROR;
6557 }
6558 }
6559
6560 /* Register the fkey_collate_clause() SQL function */
6561 rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
6562 0, shellFkeyCollateClause, 0, 0
6563 );
6564
6565
6566 if( rc==SQLITE_OK ){
6567 rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
6568 }
6569 if( rc==SQLITE_OK ){
6570 sqlite3_bind_int(pSql, 1, bGroupByParent);
6571 }
6572
6573 if( rc==SQLITE_OK ){
6574 int rc2;
6575 char *zPrev = 0;
6576 while( SQLITE_ROW==sqlite3_step(pSql) ){
6577 int res = -1;
6578 sqlite3_stmt *pExplain = 0;
6579 const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
6580 const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
6581 const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
6582 const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
6583 const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
6584 const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
6585
drh621a5e02021-12-16 17:35:27 +00006586 if( zEQP==0 ) continue;
6587 if( zGlob==0 ) continue;
drh2ce15c32017-07-11 13:34:40 +00006588 rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
6589 if( rc!=SQLITE_OK ) break;
6590 if( SQLITE_ROW==sqlite3_step(pExplain) ){
6591 const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
drh621a5e02021-12-16 17:35:27 +00006592 res = zPlan!=0 && ( 0==sqlite3_strglob(zGlob, zPlan)
6593 || 0==sqlite3_strglob(zGlobIPK, zPlan));
drh2ce15c32017-07-11 13:34:40 +00006594 }
6595 rc = sqlite3_finalize(pExplain);
6596 if( rc!=SQLITE_OK ) break;
6597
6598 if( res<0 ){
6599 raw_printf(stderr, "Error: internal error");
6600 break;
6601 }else{
6602 if( bGroupByParent
6603 && (bVerbose || res==0)
6604 && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
6605 ){
6606 raw_printf(out, "-- Parent table %s\n", zParent);
6607 sqlite3_free(zPrev);
6608 zPrev = sqlite3_mprintf("%s", zParent);
6609 }
6610
6611 if( res==0 ){
6612 raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
6613 }else if( bVerbose ){
6614 raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
6615 zIndent, zFrom, zTarget
6616 );
6617 }
6618 }
6619 }
6620 sqlite3_free(zPrev);
6621
6622 if( rc!=SQLITE_OK ){
6623 raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
6624 }
6625
6626 rc2 = sqlite3_finalize(pSql);
6627 if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
6628 rc = rc2;
6629 raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
6630 }
6631 }else{
6632 raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
6633 }
6634
6635 return rc;
6636}
6637
6638/*
6639** Implementation of ".lint" dot command.
6640*/
6641static int lintDotCommand(
6642 ShellState *pState, /* Current shell tool state */
6643 char **azArg, /* Array of arguments passed to dot command */
6644 int nArg /* Number of entries in azArg[] */
6645){
6646 int n;
drhaf2770f2018-01-05 14:55:43 +00006647 n = (nArg>=2 ? strlen30(azArg[1]) : 0);
drh2ce15c32017-07-11 13:34:40 +00006648 if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
6649 return lintFkeyIndexes(pState, azArg, nArg);
6650
6651 usage:
6652 raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
6653 raw_printf(stderr, "Where sub-commands are:\n");
6654 raw_printf(stderr, " fkey-indexes\n");
6655 return SQLITE_ERROR;
6656}
6657
dan1b162162019-04-27 20:15:15 +00006658#if !defined SQLITE_OMIT_VIRTUALTABLE
danfd0245d2017-12-07 15:44:29 +00006659static void shellPrepare(
larrybr0953c532022-12-23 19:04:59 +00006660 sqlite3 *db,
6661 int *pRc,
6662 const char *zSql,
danfd0245d2017-12-07 15:44:29 +00006663 sqlite3_stmt **ppStmt
6664){
6665 *ppStmt = 0;
6666 if( *pRc==SQLITE_OK ){
dand4b56e52017-12-12 20:04:59 +00006667 int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
danfd0245d2017-12-07 15:44:29 +00006668 if( rc!=SQLITE_OK ){
larrybr0953c532022-12-23 19:04:59 +00006669 raw_printf(stderr, "sql error: %s (%d)\n",
dand4b56e52017-12-12 20:04:59 +00006670 sqlite3_errmsg(db), sqlite3_errcode(db)
danfd0245d2017-12-07 15:44:29 +00006671 );
6672 *pRc = rc;
6673 }
6674 }
6675}
6676
drh9546c762019-05-10 17:50:33 +00006677/*
6678** Create a prepared statement using printf-style arguments for the SQL.
6679**
6680** This routine is could be marked "static". But it is not always used,
6681** depending on compile-time options. By omitting the "static", we avoid
6682** nuisance compiler warnings about "defined but not used".
6683*/
6684void shellPreparePrintf(
larrybr0953c532022-12-23 19:04:59 +00006685 sqlite3 *db,
6686 int *pRc,
danac15e2d2017-12-14 19:15:07 +00006687 sqlite3_stmt **ppStmt,
larrybr0953c532022-12-23 19:04:59 +00006688 const char *zFmt,
danac15e2d2017-12-14 19:15:07 +00006689 ...
dan3f67ddf2017-12-13 20:04:53 +00006690){
danac15e2d2017-12-14 19:15:07 +00006691 *ppStmt = 0;
6692 if( *pRc==SQLITE_OK ){
6693 va_list ap;
6694 char *z;
6695 va_start(ap, zFmt);
6696 z = sqlite3_vmprintf(zFmt, ap);
drh1dbb1472018-10-11 10:37:24 +00006697 va_end(ap);
dan3f67ddf2017-12-13 20:04:53 +00006698 if( z==0 ){
6699 *pRc = SQLITE_NOMEM;
6700 }else{
6701 shellPrepare(db, pRc, z, ppStmt);
6702 sqlite3_free(z);
6703 }
dan3f67ddf2017-12-13 20:04:53 +00006704 }
6705}
6706
drh9546c762019-05-10 17:50:33 +00006707/* Finalize the prepared statement created using shellPreparePrintf().
6708**
6709** This routine is could be marked "static". But it is not always used,
6710** depending on compile-time options. By omitting the "static", we avoid
6711** nuisance compiler warnings about "defined but not used".
6712*/
6713void shellFinalize(
larrybr0953c532022-12-23 19:04:59 +00006714 int *pRc,
danfd0245d2017-12-07 15:44:29 +00006715 sqlite3_stmt *pStmt
6716){
dan25c12182017-12-07 21:03:33 +00006717 if( pStmt ){
6718 sqlite3 *db = sqlite3_db_handle(pStmt);
6719 int rc = sqlite3_finalize(pStmt);
6720 if( *pRc==SQLITE_OK ){
6721 if( rc!=SQLITE_OK ){
6722 raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
6723 }
6724 *pRc = rc;
6725 }
6726 }
danfd0245d2017-12-07 15:44:29 +00006727}
6728
drh9546c762019-05-10 17:50:33 +00006729/* Reset the prepared statement created using shellPreparePrintf().
6730**
6731** This routine is could be marked "static". But it is not always used,
6732** depending on compile-time options. By omitting the "static", we avoid
6733** nuisance compiler warnings about "defined but not used".
6734*/
6735void shellReset(
larrybr0953c532022-12-23 19:04:59 +00006736 int *pRc,
danfd0245d2017-12-07 15:44:29 +00006737 sqlite3_stmt *pStmt
6738){
6739 int rc = sqlite3_reset(pStmt);
dan5a78b812017-12-27 18:54:11 +00006740 if( *pRc==SQLITE_OK ){
6741 if( rc!=SQLITE_OK ){
6742 sqlite3 *db = sqlite3_db_handle(pStmt);
6743 raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
6744 }
6745 *pRc = rc;
6746 }
danfd0245d2017-12-07 15:44:29 +00006747}
dan1b162162019-04-27 20:15:15 +00006748#endif /* !defined SQLITE_OMIT_VIRTUALTABLE */
6749
6750#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
drhe2754c12019-08-26 12:50:01 +00006751/******************************************************************************
dan1b162162019-04-27 20:15:15 +00006752** The ".archive" or ".ar" command.
6753*/
drhe37c0e12018-01-06 19:19:50 +00006754/*
dan88be0202017-12-09 17:58:02 +00006755** Structure representing a single ".ar" command.
6756*/
6757typedef struct ArCommand ArCommand;
6758struct ArCommand {
drhb376b3d2018-01-10 13:11:51 +00006759 u8 eCmd; /* An AR_CMD_* value */
6760 u8 bVerbose; /* True if --verbose */
drha5676c42018-01-10 15:17:34 +00006761 u8 bZip; /* True if the archive is a ZIP */
drhb376b3d2018-01-10 13:11:51 +00006762 u8 bDryRun; /* True if --dry-run */
drha5676c42018-01-10 15:17:34 +00006763 u8 bAppend; /* True if --append */
larrybr8f09f4b2021-11-02 00:18:11 +00006764 u8 bGlob; /* True if --glob */
drhd0f9cdc2018-05-17 14:09:06 +00006765 u8 fromCmdLine; /* Run from -A instead of .archive */
drhb376b3d2018-01-10 13:11:51 +00006766 int nArg; /* Number of command arguments */
drha5676c42018-01-10 15:17:34 +00006767 char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */
dan88be0202017-12-09 17:58:02 +00006768 const char *zFile; /* --file argument, or NULL */
6769 const char *zDir; /* --directory argument, or NULL */
dan88be0202017-12-09 17:58:02 +00006770 char **azArg; /* Array of command arguments */
drhb376b3d2018-01-10 13:11:51 +00006771 ShellState *p; /* Shell state */
6772 sqlite3 *db; /* Database containing the archive */
dan88be0202017-12-09 17:58:02 +00006773};
6774
6775/*
6776** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
6777*/
dan0d0547f2017-12-14 15:40:42 +00006778static int arUsage(FILE *f){
drh98aa2ab2018-09-26 16:53:51 +00006779 showHelp(f,"archive");
dan0d0547f2017-12-14 15:40:42 +00006780 return SQLITE_ERROR;
6781}
6782
6783/*
larrybr0953c532022-12-23 19:04:59 +00006784** Print an error message for the .ar command to stderr and return
dan0d0547f2017-12-14 15:40:42 +00006785** SQLITE_ERROR.
6786*/
drhd0f9cdc2018-05-17 14:09:06 +00006787static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){
dan0d0547f2017-12-14 15:40:42 +00006788 va_list ap;
6789 char *z;
6790 va_start(ap, zFmt);
6791 z = sqlite3_vmprintf(zFmt, ap);
6792 va_end(ap);
drhd0f9cdc2018-05-17 14:09:06 +00006793 utf8_printf(stderr, "Error: %s\n", z);
6794 if( pAr->fromCmdLine ){
6795 utf8_printf(stderr, "Use \"-A\" for more help\n");
6796 }else{
6797 utf8_printf(stderr, "Use \".archive --help\" for more help\n");
6798 }
dan0d0547f2017-12-14 15:40:42 +00006799 sqlite3_free(z);
dan88be0202017-12-09 17:58:02 +00006800 return SQLITE_ERROR;
6801}
6802
6803/*
6804** Values for ArCommand.eCmd.
6805*/
dand4b56e52017-12-12 20:04:59 +00006806#define AR_CMD_CREATE 1
drhb17ea912019-03-25 14:24:19 +00006807#define AR_CMD_UPDATE 2
6808#define AR_CMD_INSERT 3
6809#define AR_CMD_EXTRACT 4
6810#define AR_CMD_LIST 5
6811#define AR_CMD_HELP 6
larrybr47061b92021-11-01 17:22:52 +00006812#define AR_CMD_REMOVE 7
dand4b56e52017-12-12 20:04:59 +00006813
6814/*
6815** Other (non-command) switches.
6816*/
larrybr47061b92021-11-01 17:22:52 +00006817#define AR_SWITCH_VERBOSE 8
6818#define AR_SWITCH_FILE 9
6819#define AR_SWITCH_DIRECTORY 10
6820#define AR_SWITCH_APPEND 11
larrybr719506f2021-11-01 22:33:20 +00006821#define AR_SWITCH_DRYRUN 12
larrybr8f09f4b2021-11-02 00:18:11 +00006822#define AR_SWITCH_GLOB 13
dand4b56e52017-12-12 20:04:59 +00006823
6824static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
6825 switch( eSwitch ){
6826 case AR_CMD_CREATE:
6827 case AR_CMD_EXTRACT:
6828 case AR_CMD_LIST:
larrybr47061b92021-11-01 17:22:52 +00006829 case AR_CMD_REMOVE:
dand4b56e52017-12-12 20:04:59 +00006830 case AR_CMD_UPDATE:
drhb17ea912019-03-25 14:24:19 +00006831 case AR_CMD_INSERT:
dan0d0547f2017-12-14 15:40:42 +00006832 case AR_CMD_HELP:
6833 if( pAr->eCmd ){
drhd0f9cdc2018-05-17 14:09:06 +00006834 return arErrorMsg(pAr, "multiple command options");
dan0d0547f2017-12-14 15:40:42 +00006835 }
dand4b56e52017-12-12 20:04:59 +00006836 pAr->eCmd = eSwitch;
6837 break;
6838
drhb376b3d2018-01-10 13:11:51 +00006839 case AR_SWITCH_DRYRUN:
6840 pAr->bDryRun = 1;
6841 break;
larrybr8f09f4b2021-11-02 00:18:11 +00006842 case AR_SWITCH_GLOB:
6843 pAr->bGlob = 1;
6844 break;
dand4b56e52017-12-12 20:04:59 +00006845 case AR_SWITCH_VERBOSE:
6846 pAr->bVerbose = 1;
6847 break;
drha5676c42018-01-10 15:17:34 +00006848 case AR_SWITCH_APPEND:
6849 pAr->bAppend = 1;
larrybrfd318932023-01-04 16:54:55 +00006850 deliberate_fall_through;
dand4b56e52017-12-12 20:04:59 +00006851 case AR_SWITCH_FILE:
6852 pAr->zFile = zArg;
6853 break;
6854 case AR_SWITCH_DIRECTORY:
6855 pAr->zDir = zArg;
6856 break;
6857 }
6858
6859 return SQLITE_OK;
6860}
dan88be0202017-12-09 17:58:02 +00006861
6862/*
6863** Parse the command line for an ".ar" command. The results are written into
6864** structure (*pAr). SQLITE_OK is returned if the command line is parsed
larrybr0953c532022-12-23 19:04:59 +00006865** successfully, otherwise an error message is written to stderr and
dan88be0202017-12-09 17:58:02 +00006866** SQLITE_ERROR returned.
6867*/
6868static int arParseCommand(
6869 char **azArg, /* Array of arguments passed to dot command */
6870 int nArg, /* Number of entries in azArg[] */
6871 ArCommand *pAr /* Populate this object */
6872){
dand4b56e52017-12-12 20:04:59 +00006873 struct ArSwitch {
dand4b56e52017-12-12 20:04:59 +00006874 const char *zLong;
drhb376b3d2018-01-10 13:11:51 +00006875 char cShort;
6876 u8 eSwitch;
6877 u8 bArg;
dand4b56e52017-12-12 20:04:59 +00006878 } aSwitch[] = {
drhb376b3d2018-01-10 13:11:51 +00006879 { "create", 'c', AR_CMD_CREATE, 0 },
6880 { "extract", 'x', AR_CMD_EXTRACT, 0 },
drhb17ea912019-03-25 14:24:19 +00006881 { "insert", 'i', AR_CMD_INSERT, 0 },
drhb376b3d2018-01-10 13:11:51 +00006882 { "list", 't', AR_CMD_LIST, 0 },
larrybr47061b92021-11-01 17:22:52 +00006883 { "remove", 'r', AR_CMD_REMOVE, 0 },
drhb376b3d2018-01-10 13:11:51 +00006884 { "update", 'u', AR_CMD_UPDATE, 0 },
6885 { "help", 'h', AR_CMD_HELP, 0 },
6886 { "verbose", 'v', AR_SWITCH_VERBOSE, 0 },
6887 { "file", 'f', AR_SWITCH_FILE, 1 },
drhca7733b2018-01-10 18:09:20 +00006888 { "append", 'a', AR_SWITCH_APPEND, 1 },
drhb376b3d2018-01-10 13:11:51 +00006889 { "directory", 'C', AR_SWITCH_DIRECTORY, 1 },
drhb376b3d2018-01-10 13:11:51 +00006890 { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 },
larrybr8f09f4b2021-11-02 00:18:11 +00006891 { "glob", 'g', AR_SWITCH_GLOB, 0 },
dand4b56e52017-12-12 20:04:59 +00006892 };
6893 int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
6894 struct ArSwitch *pEnd = &aSwitch[nSwitch];
6895
dan88be0202017-12-09 17:58:02 +00006896 if( nArg<=1 ){
drh98aa2ab2018-09-26 16:53:51 +00006897 utf8_printf(stderr, "Wrong number of arguments. Usage:\n");
dan0d0547f2017-12-14 15:40:42 +00006898 return arUsage(stderr);
dan88be0202017-12-09 17:58:02 +00006899 }else{
6900 char *z = azArg[1];
dan88be0202017-12-09 17:58:02 +00006901 if( z[0]!='-' ){
6902 /* Traditional style [tar] invocation */
6903 int i;
6904 int iArg = 2;
6905 for(i=0; z[i]; i++){
dand4b56e52017-12-12 20:04:59 +00006906 const char *zArg = 0;
6907 struct ArSwitch *pOpt;
6908 for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
6909 if( z[i]==pOpt->cShort ) break;
dan88be0202017-12-09 17:58:02 +00006910 }
dan0d0547f2017-12-14 15:40:42 +00006911 if( pOpt==pEnd ){
drhd0f9cdc2018-05-17 14:09:06 +00006912 return arErrorMsg(pAr, "unrecognized option: %c", z[i]);
dan0d0547f2017-12-14 15:40:42 +00006913 }
dand4b56e52017-12-12 20:04:59 +00006914 if( pOpt->bArg ){
dan0d0547f2017-12-14 15:40:42 +00006915 if( iArg>=nArg ){
drhd0f9cdc2018-05-17 14:09:06 +00006916 return arErrorMsg(pAr, "option requires an argument: %c",z[i]);
dan0d0547f2017-12-14 15:40:42 +00006917 }
dand4b56e52017-12-12 20:04:59 +00006918 zArg = azArg[iArg++];
6919 }
6920 if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
dan88be0202017-12-09 17:58:02 +00006921 }
dan88be0202017-12-09 17:58:02 +00006922 pAr->nArg = nArg-iArg;
6923 if( pAr->nArg>0 ){
6924 pAr->azArg = &azArg[iArg];
6925 }
dand4b56e52017-12-12 20:04:59 +00006926 }else{
6927 /* Non-traditional invocation */
6928 int iArg;
6929 for(iArg=1; iArg<nArg; iArg++){
6930 int n;
6931 z = azArg[iArg];
6932 if( z[0]!='-' ){
6933 /* All remaining command line words are command arguments. */
6934 pAr->azArg = &azArg[iArg];
6935 pAr->nArg = nArg-iArg;
6936 break;
6937 }
drhaf2770f2018-01-05 14:55:43 +00006938 n = strlen30(z);
dand4b56e52017-12-12 20:04:59 +00006939
6940 if( z[1]!='-' ){
6941 int i;
6942 /* One or more short options */
6943 for(i=1; i<n; i++){
6944 const char *zArg = 0;
6945 struct ArSwitch *pOpt;
6946 for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
6947 if( z[i]==pOpt->cShort ) break;
6948 }
dan0d0547f2017-12-14 15:40:42 +00006949 if( pOpt==pEnd ){
drhd0f9cdc2018-05-17 14:09:06 +00006950 return arErrorMsg(pAr, "unrecognized option: %c", z[i]);
dan0d0547f2017-12-14 15:40:42 +00006951 }
dand4b56e52017-12-12 20:04:59 +00006952 if( pOpt->bArg ){
6953 if( i<(n-1) ){
6954 zArg = &z[i+1];
6955 i = n;
6956 }else{
dan0d0547f2017-12-14 15:40:42 +00006957 if( iArg>=(nArg-1) ){
drhe2754c12019-08-26 12:50:01 +00006958 return arErrorMsg(pAr, "option requires an argument: %c",
6959 z[i]);
dan0d0547f2017-12-14 15:40:42 +00006960 }
dand4b56e52017-12-12 20:04:59 +00006961 zArg = azArg[++iArg];
6962 }
6963 }
6964 if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
6965 }
6966 }else if( z[2]=='\0' ){
6967 /* A -- option, indicating that all remaining command line words
6968 ** are command arguments. */
6969 pAr->azArg = &azArg[iArg+1];
6970 pAr->nArg = nArg-iArg-1;
6971 break;
6972 }else{
6973 /* A long option */
6974 const char *zArg = 0; /* Argument for option, if any */
6975 struct ArSwitch *pMatch = 0; /* Matching option */
6976 struct ArSwitch *pOpt; /* Iterator */
6977 for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
6978 const char *zLong = pOpt->zLong;
drhaf2770f2018-01-05 14:55:43 +00006979 if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){
dand4b56e52017-12-12 20:04:59 +00006980 if( pMatch ){
drhd0f9cdc2018-05-17 14:09:06 +00006981 return arErrorMsg(pAr, "ambiguous option: %s",z);
dand4b56e52017-12-12 20:04:59 +00006982 }else{
6983 pMatch = pOpt;
6984 }
6985 }
6986 }
6987
6988 if( pMatch==0 ){
drhd0f9cdc2018-05-17 14:09:06 +00006989 return arErrorMsg(pAr, "unrecognized option: %s", z);
dand4b56e52017-12-12 20:04:59 +00006990 }
6991 if( pMatch->bArg ){
dan0d0547f2017-12-14 15:40:42 +00006992 if( iArg>=(nArg-1) ){
drhd0f9cdc2018-05-17 14:09:06 +00006993 return arErrorMsg(pAr, "option requires an argument: %s", z);
dan0d0547f2017-12-14 15:40:42 +00006994 }
dand4b56e52017-12-12 20:04:59 +00006995 zArg = azArg[++iArg];
6996 }
6997 if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR;
6998 }
6999 }
dan88be0202017-12-09 17:58:02 +00007000 }
7001 }
7002
7003 return SQLITE_OK;
7004}
7005
7006/*
dan3f67ddf2017-12-13 20:04:53 +00007007** This function assumes that all arguments within the ArCommand.azArg[]
larrybr47061b92021-11-01 17:22:52 +00007008** array refer to archive members, as for the --extract, --list or --remove
larrybr8f09f4b2021-11-02 00:18:11 +00007009** commands. It checks that each of them are "present". If any specified
7010** file is not present in the archive, an error is printed to stderr and an
larrybr47061b92021-11-01 17:22:52 +00007011** error code returned. Otherwise, if all specified arguments are present
larrybr8f09f4b2021-11-02 00:18:11 +00007012** in the archive, SQLITE_OK is returned. Here, "present" means either an
7013** exact equality when pAr->bGlob is false or a "name GLOB pattern" match
drh0c0fb9c2021-11-02 10:54:39 +00007014** when pAr->bGlob is true.
dan3f67ddf2017-12-13 20:04:53 +00007015**
7016** This function strips any trailing '/' characters from each argument.
7017** This is consistent with the way the [tar] command seems to work on
7018** Linux.
7019*/
drhb376b3d2018-01-10 13:11:51 +00007020static int arCheckEntries(ArCommand *pAr){
dan3f67ddf2017-12-13 20:04:53 +00007021 int rc = SQLITE_OK;
7022 if( pAr->nArg ){
drhb376b3d2018-01-10 13:11:51 +00007023 int i, j;
dan3f67ddf2017-12-13 20:04:53 +00007024 sqlite3_stmt *pTest = 0;
larrybr8f09f4b2021-11-02 00:18:11 +00007025 const char *zSel = (pAr->bGlob)
7026 ? "SELECT name FROM %s WHERE glob($name,name)"
7027 : "SELECT name FROM %s WHERE name=$name";
dan3f67ddf2017-12-13 20:04:53 +00007028
larrybr8f09f4b2021-11-02 00:18:11 +00007029 shellPreparePrintf(pAr->db, &rc, &pTest, zSel, pAr->zSrcTable);
drhb376b3d2018-01-10 13:11:51 +00007030 j = sqlite3_bind_parameter_index(pTest, "$name");
dan3f67ddf2017-12-13 20:04:53 +00007031 for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
7032 char *z = pAr->azArg[i];
drhaf2770f2018-01-05 14:55:43 +00007033 int n = strlen30(z);
dan3f67ddf2017-12-13 20:04:53 +00007034 int bOk = 0;
7035 while( n>0 && z[n-1]=='/' ) n--;
7036 z[n] = '\0';
drhb376b3d2018-01-10 13:11:51 +00007037 sqlite3_bind_text(pTest, j, z, -1, SQLITE_STATIC);
dan3f67ddf2017-12-13 20:04:53 +00007038 if( SQLITE_ROW==sqlite3_step(pTest) ){
7039 bOk = 1;
7040 }
7041 shellReset(&rc, pTest);
7042 if( rc==SQLITE_OK && bOk==0 ){
drhb376b3d2018-01-10 13:11:51 +00007043 utf8_printf(stderr, "not found in archive: %s\n", z);
dan3f67ddf2017-12-13 20:04:53 +00007044 rc = SQLITE_ERROR;
7045 }
7046 }
7047 shellFinalize(&rc, pTest);
7048 }
dan3f67ddf2017-12-13 20:04:53 +00007049 return rc;
7050}
7051
7052/*
7053** Format a WHERE clause that can be used against the "sqlar" table to
7054** identify all archive members that match the command arguments held
7055** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning.
7056** The caller is responsible for eventually calling sqlite3_free() on
larrybr8f09f4b2021-11-02 00:18:11 +00007057** any non-NULL (*pzWhere) value. Here, "match" means strict equality
7058** when pAr->bGlob is false and GLOB match when pAr->bGlob is true.
dan3f67ddf2017-12-13 20:04:53 +00007059*/
7060static void arWhereClause(
larrybr0953c532022-12-23 19:04:59 +00007061 int *pRc,
larrybr8f09f4b2021-11-02 00:18:11 +00007062 ArCommand *pAr,
danac15e2d2017-12-14 19:15:07 +00007063 char **pzWhere /* OUT: New WHERE clause */
dan3f67ddf2017-12-13 20:04:53 +00007064){
7065 char *zWhere = 0;
larrybr8f09f4b2021-11-02 00:18:11 +00007066 const char *zSameOp = (pAr->bGlob)? "GLOB" : "=";
dan3f67ddf2017-12-13 20:04:53 +00007067 if( *pRc==SQLITE_OK ){
danac15e2d2017-12-14 19:15:07 +00007068 if( pAr->nArg==0 ){
7069 zWhere = sqlite3_mprintf("1");
7070 }else{
7071 int i;
7072 const char *zSep = "";
7073 for(i=0; i<pAr->nArg; i++){
7074 const char *z = pAr->azArg[i];
7075 zWhere = sqlite3_mprintf(
larrybr0953c532022-12-23 19:04:59 +00007076 "%z%s name %s '%q' OR substr(name,1,%d) %s '%q/'",
larrybr8f09f4b2021-11-02 00:18:11 +00007077 zWhere, zSep, zSameOp, z, strlen30(z)+1, zSameOp, z
drhb376b3d2018-01-10 13:11:51 +00007078 );
danac15e2d2017-12-14 19:15:07 +00007079 if( zWhere==0 ){
7080 *pRc = SQLITE_NOMEM;
7081 break;
7082 }
7083 zSep = " OR ";
dan3f67ddf2017-12-13 20:04:53 +00007084 }
dan3f67ddf2017-12-13 20:04:53 +00007085 }
7086 }
7087 *pzWhere = zWhere;
7088}
7089
7090/*
larrybr0953c532022-12-23 19:04:59 +00007091** Implementation of .ar "lisT" command.
dan88be0202017-12-09 17:58:02 +00007092*/
drhb376b3d2018-01-10 13:11:51 +00007093static int arListCommand(ArCommand *pAr){
larrybr0953c532022-12-23 19:04:59 +00007094 const char *zSql = "SELECT %s FROM %s WHERE %s";
danb5090e42017-12-27 21:13:21 +00007095 const char *azCols[] = {
7096 "name",
drh410cad92018-01-10 17:19:16 +00007097 "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name"
danb5090e42017-12-27 21:13:21 +00007098 };
dan5a78b812017-12-27 18:54:11 +00007099
dan3f67ddf2017-12-13 20:04:53 +00007100 char *zWhere = 0;
7101 sqlite3_stmt *pSql = 0;
7102 int rc;
7103
drhb376b3d2018-01-10 13:11:51 +00007104 rc = arCheckEntries(pAr);
dan3f67ddf2017-12-13 20:04:53 +00007105 arWhereClause(&rc, pAr, &zWhere);
7106
drhb376b3d2018-01-10 13:11:51 +00007107 shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
7108 pAr->zSrcTable, zWhere);
drhb376b3d2018-01-10 13:11:51 +00007109 if( pAr->bDryRun ){
7110 utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
7111 }else{
7112 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
7113 if( pAr->bVerbose ){
drh410cad92018-01-10 17:19:16 +00007114 utf8_printf(pAr->p->out, "%s % 10d %s %s\n",
7115 sqlite3_column_text(pSql, 0),
larrybr0953c532022-12-23 19:04:59 +00007116 sqlite3_column_int(pSql, 1),
drhb376b3d2018-01-10 13:11:51 +00007117 sqlite3_column_text(pSql, 2),
7118 sqlite3_column_text(pSql, 3)
7119 );
7120 }else{
7121 utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
7122 }
danb5090e42017-12-27 21:13:21 +00007123 }
dan3f67ddf2017-12-13 20:04:53 +00007124 }
dan5a78b812017-12-27 18:54:11 +00007125 shellFinalize(&rc, pSql);
drhd0f9cdc2018-05-17 14:09:06 +00007126 sqlite3_free(zWhere);
dan3f67ddf2017-12-13 20:04:53 +00007127 return rc;
dan88be0202017-12-09 17:58:02 +00007128}
7129
7130
danfd0245d2017-12-07 15:44:29 +00007131/*
larrybr47061b92021-11-01 17:22:52 +00007132** Implementation of .ar "Remove" command.
7133*/
7134static int arRemoveCommand(ArCommand *pAr){
larrybr7774fc02021-11-01 22:30:24 +00007135 int rc = 0;
larrybr47061b92021-11-01 17:22:52 +00007136 char *zSql = 0;
7137 char *zWhere = 0;
7138
7139 if( pAr->nArg ){
7140 /* Verify that args actually exist within the archive before proceeding.
7141 ** And formulate a WHERE clause to match them. */
7142 rc = arCheckEntries(pAr);
7143 arWhereClause(&rc, pAr, &zWhere);
7144 }
7145 if( rc==SQLITE_OK ){
7146 zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;",
7147 pAr->zSrcTable, zWhere);
7148 if( pAr->bDryRun ){
7149 utf8_printf(pAr->p->out, "%s\n", zSql);
7150 }else{
7151 char *zErr = 0;
7152 rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0);
7153 if( rc==SQLITE_OK ){
7154 rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
7155 if( rc!=SQLITE_OK ){
7156 sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0);
7157 }else{
7158 rc = sqlite3_exec(pAr->db, "RELEASE ar;", 0, 0, 0);
7159 }
7160 }
7161 if( zErr ){
7162 utf8_printf(stdout, "ERROR: %s\n", zErr);
7163 sqlite3_free(zErr);
7164 }
7165 }
7166 }
7167 sqlite3_free(zWhere);
7168 sqlite3_free(zSql);
7169 return rc;
7170}
7171
7172/*
larrybr0953c532022-12-23 19:04:59 +00007173** Implementation of .ar "eXtract" command.
danfd0245d2017-12-07 15:44:29 +00007174*/
drhb376b3d2018-01-10 13:11:51 +00007175static int arExtractCommand(ArCommand *pAr){
larrybr0953c532022-12-23 19:04:59 +00007176 const char *zSql1 =
dand1b51d42017-12-16 19:11:26 +00007177 "SELECT "
drhb376b3d2018-01-10 13:11:51 +00007178 " ($dir || name),"
7179 " writefile(($dir || name), %s, mode, mtime) "
drh0cfd46a2018-06-06 01:18:01 +00007180 "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)"
7181 " AND name NOT GLOB '*..[/\\]*'";
dan5a78b812017-12-27 18:54:11 +00007182
larrybr0953c532022-12-23 19:04:59 +00007183 const char *azExtraArg[] = {
dan5a78b812017-12-27 18:54:11 +00007184 "sqlar_uncompress(data, sz)",
dan7c15ac12018-01-08 19:59:59 +00007185 "data"
dan5a78b812017-12-27 18:54:11 +00007186 };
dan5a78b812017-12-27 18:54:11 +00007187
danfd0245d2017-12-07 15:44:29 +00007188 sqlite3_stmt *pSql = 0;
7189 int rc = SQLITE_OK;
dan2ad09492017-12-09 18:28:22 +00007190 char *zDir = 0;
dan3f67ddf2017-12-13 20:04:53 +00007191 char *zWhere = 0;
drhb376b3d2018-01-10 13:11:51 +00007192 int i, j;
dan2ad09492017-12-09 18:28:22 +00007193
dan3f67ddf2017-12-13 20:04:53 +00007194 /* If arguments are specified, check that they actually exist within
7195 ** the archive before proceeding. And formulate a WHERE clause to
7196 ** match them. */
drhb376b3d2018-01-10 13:11:51 +00007197 rc = arCheckEntries(pAr);
dan3f67ddf2017-12-13 20:04:53 +00007198 arWhereClause(&rc, pAr, &zWhere);
7199
7200 if( rc==SQLITE_OK ){
7201 if( pAr->zDir ){
7202 zDir = sqlite3_mprintf("%s/", pAr->zDir);
7203 }else{
7204 zDir = sqlite3_mprintf("");
7205 }
7206 if( zDir==0 ) rc = SQLITE_NOMEM;
dan2ad09492017-12-09 18:28:22 +00007207 }
danfd0245d2017-12-07 15:44:29 +00007208
larrybr0953c532022-12-23 19:04:59 +00007209 shellPreparePrintf(pAr->db, &rc, &pSql, zSql1,
drhb376b3d2018-01-10 13:11:51 +00007210 azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere
dan5a78b812017-12-27 18:54:11 +00007211 );
7212
dan2ad09492017-12-09 18:28:22 +00007213 if( rc==SQLITE_OK ){
drhb376b3d2018-01-10 13:11:51 +00007214 j = sqlite3_bind_parameter_index(pSql, "$dir");
7215 sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC);
dan25c12182017-12-07 21:03:33 +00007216
danac15e2d2017-12-14 19:15:07 +00007217 /* Run the SELECT statement twice. The first time, writefile() is called
7218 ** for all archive members that should be extracted. The second time,
7219 ** only for the directories. This is because the timestamps for
7220 ** extracted directories must be reset after they are populated (as
7221 ** populating them changes the timestamp). */
7222 for(i=0; i<2; i++){
drhb376b3d2018-01-10 13:11:51 +00007223 j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
7224 sqlite3_bind_int(pSql, j, i);
7225 if( pAr->bDryRun ){
7226 utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
7227 }else{
7228 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
7229 if( i==0 && pAr->bVerbose ){
7230 utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
7231 }
danac15e2d2017-12-14 19:15:07 +00007232 }
7233 }
7234 shellReset(&rc, pSql);
dan25c12182017-12-07 21:03:33 +00007235 }
danac15e2d2017-12-14 19:15:07 +00007236 shellFinalize(&rc, pSql);
dan25c12182017-12-07 21:03:33 +00007237 }
dan25c12182017-12-07 21:03:33 +00007238
dan2ad09492017-12-09 18:28:22 +00007239 sqlite3_free(zDir);
dan3f67ddf2017-12-13 20:04:53 +00007240 sqlite3_free(zWhere);
danfd0245d2017-12-07 15:44:29 +00007241 return rc;
7242}
7243
drhb376b3d2018-01-10 13:11:51 +00007244/*
7245** Run the SQL statement in zSql. Or if doing a --dryrun, merely print it out.
7246*/
7247static int arExecSql(ArCommand *pAr, const char *zSql){
7248 int rc;
7249 if( pAr->bDryRun ){
7250 utf8_printf(pAr->p->out, "%s\n", zSql);
7251 rc = SQLITE_OK;
7252 }else{
drh410cad92018-01-10 17:19:16 +00007253 char *zErr = 0;
7254 rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
7255 if( zErr ){
7256 utf8_printf(stdout, "ERROR: %s\n", zErr);
7257 sqlite3_free(zErr);
7258 }
drhb376b3d2018-01-10 13:11:51 +00007259 }
7260 return rc;
7261}
7262
dan1ad3f612017-12-11 20:22:02 +00007263
danfd0245d2017-12-07 15:44:29 +00007264/*
drhb17ea912019-03-25 14:24:19 +00007265** Implementation of .ar "create", "insert", and "update" commands.
7266**
7267** create -> Create a new SQL archive
7268** insert -> Insert or reinsert all files listed
7269** update -> Insert files that have changed or that were not
7270** previously in the archive
danfd0245d2017-12-07 15:44:29 +00007271**
7272** Create the "sqlar" table in the database if it does not already exist.
7273** Then add each file in the azFile[] array to the archive. Directories
7274** are added recursively. If argument bVerbose is non-zero, a message is
7275** printed on stdout for each file archived.
dan06741a32017-12-13 20:17:18 +00007276**
7277** The create command is the same as update, except that it drops
drhb17ea912019-03-25 14:24:19 +00007278** any existing "sqlar" table before beginning. The "insert" command
7279** always overwrites every file named on the command-line, where as
7280** "update" only overwrites if the size or mtime or mode has changed.
danfd0245d2017-12-07 15:44:29 +00007281*/
drhb376b3d2018-01-10 13:11:51 +00007282static int arCreateOrUpdateCommand(
dan06741a32017-12-13 20:17:18 +00007283 ArCommand *pAr, /* Command arguments and options */
drhb17ea912019-03-25 14:24:19 +00007284 int bUpdate, /* true for a --create. */
7285 int bOnlyIfChanged /* Only update if file has changed */
danfd0245d2017-12-07 15:44:29 +00007286){
larrybr0953c532022-12-23 19:04:59 +00007287 const char *zCreate =
drhafba1802018-01-06 15:49:57 +00007288 "CREATE TABLE IF NOT EXISTS sqlar(\n"
7289 " name TEXT PRIMARY KEY, -- name of the file\n"
7290 " mode INT, -- access permissions\n"
7291 " mtime INT, -- last modification time\n"
7292 " sz INT, -- original file size\n"
7293 " data BLOB -- compressed content\n"
7294 ")";
dand4b56e52017-12-12 20:04:59 +00007295 const char *zDrop = "DROP TABLE IF EXISTS sqlar";
drh1bf208c2018-03-09 21:54:01 +00007296 const char *zInsertFmt[2] = {
7297 "REPLACE INTO %s(name,mode,mtime,sz,data)\n"
drh634c70f2018-01-10 16:50:18 +00007298 " SELECT\n"
7299 " %s,\n"
7300 " mode,\n"
7301 " mtime,\n"
drh410cad92018-01-10 17:19:16 +00007302 " CASE substr(lsmode(mode),1,1)\n"
7303 " WHEN '-' THEN length(data)\n"
7304 " WHEN 'd' THEN 0\n"
drh634c70f2018-01-10 16:50:18 +00007305 " ELSE -1 END,\n"
drh69d2d352018-03-09 22:18:53 +00007306 " sqlar_compress(data)\n"
drhb17ea912019-03-25 14:24:19 +00007307 " FROM fsdir(%Q,%Q) AS disk\n"
7308 " WHERE lsmode(mode) NOT LIKE '?%%'%s;"
7309 ,
drh1bf208c2018-03-09 21:54:01 +00007310 "REPLACE INTO %s(name,mode,mtime,data)\n"
7311 " SELECT\n"
7312 " %s,\n"
7313 " mode,\n"
7314 " mtime,\n"
7315 " data\n"
drhb17ea912019-03-25 14:24:19 +00007316 " FROM fsdir(%Q,%Q) AS disk\n"
7317 " WHERE lsmode(mode) NOT LIKE '?%%'%s;"
drh1bf208c2018-03-09 21:54:01 +00007318 };
danfd0245d2017-12-07 15:44:29 +00007319 int i; /* For iterating through azFile[] */
7320 int rc; /* Return code */
drh1bf208c2018-03-09 21:54:01 +00007321 const char *zTab = 0; /* SQL table into which to insert */
7322 char *zSql;
7323 char zTemp[50];
drhb17ea912019-03-25 14:24:19 +00007324 char *zExists = 0;
danfd0245d2017-12-07 15:44:29 +00007325
drh1bf208c2018-03-09 21:54:01 +00007326 arExecSql(pAr, "PRAGMA page_size=512");
drhb376b3d2018-01-10 13:11:51 +00007327 rc = arExecSql(pAr, "SAVEPOINT ar;");
danfd0245d2017-12-07 15:44:29 +00007328 if( rc!=SQLITE_OK ) return rc;
larrybr0953c532022-12-23 19:04:59 +00007329 zTemp[0] = 0;
drh1bf208c2018-03-09 21:54:01 +00007330 if( pAr->bZip ){
7331 /* Initialize the zipfile virtual table, if necessary */
7332 if( pAr->zFile ){
7333 sqlite3_uint64 r;
7334 sqlite3_randomness(sizeof(r),&r);
7335 sqlite3_snprintf(sizeof(zTemp),zTemp,"zip%016llx",r);
7336 zTab = zTemp;
7337 zSql = sqlite3_mprintf(
7338 "CREATE VIRTUAL TABLE temp.%s USING zipfile(%Q)",
7339 zTab, pAr->zFile
7340 );
7341 rc = arExecSql(pAr, zSql);
7342 sqlite3_free(zSql);
7343 }else{
7344 zTab = "zip";
7345 }
7346 }else{
7347 /* Initialize the table for an SQLAR */
7348 zTab = "sqlar";
7349 if( bUpdate==0 ){
7350 rc = arExecSql(pAr, zDrop);
7351 if( rc!=SQLITE_OK ) goto end_ar_transaction;
7352 }
7353 rc = arExecSql(pAr, zCreate);
dan06741a32017-12-13 20:17:18 +00007354 }
drhb17ea912019-03-25 14:24:19 +00007355 if( bOnlyIfChanged ){
7356 zExists = sqlite3_mprintf(
7357 " AND NOT EXISTS("
7358 "SELECT 1 FROM %s AS mem"
7359 " WHERE mem.name=disk.name"
7360 " AND mem.mtime=disk.mtime"
7361 " AND mem.mode=disk.mode)", zTab);
7362 }else{
7363 zExists = sqlite3_mprintf("");
7364 }
7365 if( zExists==0 ) rc = SQLITE_NOMEM;
dan88be0202017-12-09 17:58:02 +00007366 for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
mistachkince2052b2018-03-23 00:31:53 +00007367 char *zSql2 = sqlite3_mprintf(zInsertFmt[pAr->bZip], zTab,
drh634c70f2018-01-10 16:50:18 +00007368 pAr->bVerbose ? "shell_putsnl(name)" : "name",
drhb17ea912019-03-25 14:24:19 +00007369 pAr->azArg[i], pAr->zDir, zExists);
mistachkince2052b2018-03-23 00:31:53 +00007370 rc = arExecSql(pAr, zSql2);
7371 sqlite3_free(zSql2);
danfd0245d2017-12-07 15:44:29 +00007372 }
drh1bf208c2018-03-09 21:54:01 +00007373end_ar_transaction:
danfd0245d2017-12-07 15:44:29 +00007374 if( rc!=SQLITE_OK ){
drh2bd207f2019-01-11 17:19:59 +00007375 sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0);
danfd0245d2017-12-07 15:44:29 +00007376 }else{
drhb376b3d2018-01-10 13:11:51 +00007377 rc = arExecSql(pAr, "RELEASE ar;");
drh1bf208c2018-03-09 21:54:01 +00007378 if( pAr->bZip && pAr->zFile ){
7379 zSql = sqlite3_mprintf("DROP TABLE %s", zTemp);
7380 arExecSql(pAr, zSql);
7381 sqlite3_free(zSql);
7382 }
danfd0245d2017-12-07 15:44:29 +00007383 }
drhb17ea912019-03-25 14:24:19 +00007384 sqlite3_free(zExists);
danfd0245d2017-12-07 15:44:29 +00007385 return rc;
7386}
7387
7388/*
7389** Implementation of ".ar" dot command.
7390*/
7391static int arDotCommand(
drhe2754c12019-08-26 12:50:01 +00007392 ShellState *pState, /* Current shell tool state */
7393 int fromCmdLine, /* True if -A command-line option, not .ar cmd */
7394 char **azArg, /* Array of arguments passed to dot command */
7395 int nArg /* Number of entries in azArg[] */
danfd0245d2017-12-07 15:44:29 +00007396){
dan88be0202017-12-09 17:58:02 +00007397 ArCommand cmd;
7398 int rc;
drh34660642018-01-10 17:39:54 +00007399 memset(&cmd, 0, sizeof(cmd));
drhd0f9cdc2018-05-17 14:09:06 +00007400 cmd.fromCmdLine = fromCmdLine;
dan88be0202017-12-09 17:58:02 +00007401 rc = arParseCommand(azArg, nArg, &cmd);
7402 if( rc==SQLITE_OK ){
drha5676c42018-01-10 15:17:34 +00007403 int eDbType = SHELL_OPEN_UNSPEC;
drhb376b3d2018-01-10 13:11:51 +00007404 cmd.p = pState;
7405 cmd.db = pState->db;
drha5676c42018-01-10 15:17:34 +00007406 if( cmd.zFile ){
drh1bf208c2018-03-09 21:54:01 +00007407 eDbType = deduceDatabaseType(cmd.zFile, 1);
drha5676c42018-01-10 15:17:34 +00007408 }else{
7409 eDbType = pState->openMode;
7410 }
7411 if( eDbType==SHELL_OPEN_ZIPFILE ){
drh1bf208c2018-03-09 21:54:01 +00007412 if( cmd.eCmd==AR_CMD_EXTRACT || cmd.eCmd==AR_CMD_LIST ){
7413 if( cmd.zFile==0 ){
7414 cmd.zSrcTable = sqlite3_mprintf("zip");
7415 }else{
7416 cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile);
7417 }
dan5a78b812017-12-27 18:54:11 +00007418 }
drha5676c42018-01-10 15:17:34 +00007419 cmd.bZip = 1;
dan5a78b812017-12-27 18:54:11 +00007420 }else if( cmd.zFile ){
dand4b56e52017-12-12 20:04:59 +00007421 int flags;
drha5676c42018-01-10 15:17:34 +00007422 if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS;
larrybr0953c532022-12-23 19:04:59 +00007423 if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT
larrybr47061b92021-11-01 17:22:52 +00007424 || cmd.eCmd==AR_CMD_REMOVE || cmd.eCmd==AR_CMD_UPDATE ){
dand4b56e52017-12-12 20:04:59 +00007425 flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
7426 }else{
7427 flags = SQLITE_OPEN_READONLY;
7428 }
drha82c95b2018-01-10 14:00:00 +00007429 cmd.db = 0;
drha5676c42018-01-10 15:17:34 +00007430 if( cmd.bDryRun ){
7431 utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile,
7432 eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
7433 }
larrybr0953c532022-12-23 19:04:59 +00007434 rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags,
drha5676c42018-01-10 15:17:34 +00007435 eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
dand4b56e52017-12-12 20:04:59 +00007436 if( rc!=SQLITE_OK ){
larrybr0953c532022-12-23 19:04:59 +00007437 utf8_printf(stderr, "cannot open file: %s (%s)\n",
drhb376b3d2018-01-10 13:11:51 +00007438 cmd.zFile, sqlite3_errmsg(cmd.db)
dand4b56e52017-12-12 20:04:59 +00007439 );
drha5676c42018-01-10 15:17:34 +00007440 goto end_ar_command;
dand4b56e52017-12-12 20:04:59 +00007441 }
drhb376b3d2018-01-10 13:11:51 +00007442 sqlite3_fileio_init(cmd.db, 0, 0);
drhb376b3d2018-01-10 13:11:51 +00007443 sqlite3_sqlar_init(cmd.db, 0, 0);
drh34660642018-01-10 17:39:54 +00007444 sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
7445 shellPutsFunc, 0, 0);
7446
dand4b56e52017-12-12 20:04:59 +00007447 }
drhd0f9cdc2018-05-17 14:09:06 +00007448 if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){
drh634c70f2018-01-10 16:50:18 +00007449 if( cmd.eCmd!=AR_CMD_CREATE
7450 && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
7451 ){
drha5676c42018-01-10 15:17:34 +00007452 utf8_printf(stderr, "database does not contain an 'sqlar' table\n");
7453 rc = SQLITE_ERROR;
7454 goto end_ar_command;
7455 }
7456 cmd.zSrcTable = sqlite3_mprintf("sqlar");
7457 }
dand4b56e52017-12-12 20:04:59 +00007458
dan88be0202017-12-09 17:58:02 +00007459 switch( cmd.eCmd ){
7460 case AR_CMD_CREATE:
drhb17ea912019-03-25 14:24:19 +00007461 rc = arCreateOrUpdateCommand(&cmd, 0, 0);
dan88be0202017-12-09 17:58:02 +00007462 break;
danfd0245d2017-12-07 15:44:29 +00007463
dan88be0202017-12-09 17:58:02 +00007464 case AR_CMD_EXTRACT:
drhb376b3d2018-01-10 13:11:51 +00007465 rc = arExtractCommand(&cmd);
dan88be0202017-12-09 17:58:02 +00007466 break;
7467
7468 case AR_CMD_LIST:
drhb376b3d2018-01-10 13:11:51 +00007469 rc = arListCommand(&cmd);
dan88be0202017-12-09 17:58:02 +00007470 break;
7471
dan0d0547f2017-12-14 15:40:42 +00007472 case AR_CMD_HELP:
7473 arUsage(pState->out);
7474 break;
7475
drhb17ea912019-03-25 14:24:19 +00007476 case AR_CMD_INSERT:
7477 rc = arCreateOrUpdateCommand(&cmd, 1, 0);
7478 break;
7479
larrybr47061b92021-11-01 17:22:52 +00007480 case AR_CMD_REMOVE:
7481 rc = arRemoveCommand(&cmd);
7482 break;
7483
dan88be0202017-12-09 17:58:02 +00007484 default:
7485 assert( cmd.eCmd==AR_CMD_UPDATE );
drhb17ea912019-03-25 14:24:19 +00007486 rc = arCreateOrUpdateCommand(&cmd, 1, 1);
dan88be0202017-12-09 17:58:02 +00007487 break;
danfd0245d2017-12-07 15:44:29 +00007488 }
7489 }
drha5676c42018-01-10 15:17:34 +00007490end_ar_command:
7491 if( cmd.db!=pState->db ){
drh9e804032018-05-18 17:11:50 +00007492 close_db(cmd.db);
drha5676c42018-01-10 15:17:34 +00007493 }
7494 sqlite3_free(cmd.zSrcTable);
danfd0245d2017-12-07 15:44:29 +00007495
dan88be0202017-12-09 17:58:02 +00007496 return rc;
danfd0245d2017-12-07 15:44:29 +00007497}
drhe37c0e12018-01-06 19:19:50 +00007498/* End of the ".archive" or ".ar" command logic
drhe2754c12019-08-26 12:50:01 +00007499*******************************************************************************/
drhe37c0e12018-01-06 19:19:50 +00007500#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
danfd0245d2017-12-07 15:44:29 +00007501
stephan3d420832022-10-27 03:56:01 +00007502#if SQLITE_SHELL_HAVE_RECOVER
dan68cb86e2019-04-20 20:57:28 +00007503
dan42ebb012019-04-27 18:47:03 +00007504/*
dan9a27d652022-09-08 19:22:29 +00007505** This function is used as a callback by the recover extension. Simply
7506** print the supplied SQL statement to stdout.
dan42ebb012019-04-27 18:47:03 +00007507*/
dan9a27d652022-09-08 19:22:29 +00007508static int recoverSqlCb(void *pCtx, const char *zSql){
7509 ShellState *pState = (ShellState*)pCtx;
dan80b1f6f2022-09-23 11:40:43 +00007510 utf8_printf(pState->out, "%s;\n", zSql);
dan9a27d652022-09-08 19:22:29 +00007511 return SQLITE_OK;
dan68cb86e2019-04-20 20:57:28 +00007512}
7513
7514/*
7515** This function is called to recover data from the database. A script
7516** to construct a new database containing all recovered data is output
7517** on stream pState->out.
7518*/
danb9b71db2019-04-25 16:20:40 +00007519static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
dan68cb86e2019-04-20 20:57:28 +00007520 int rc = SQLITE_OK;
drh2cdcc7f2022-11-02 14:08:26 +00007521 const char *zRecoveryDb = ""; /* Name of "recovery" database. Debug only */
dan9a27d652022-09-08 19:22:29 +00007522 const char *zLAF = "lost_and_found";
danf7fea5b2022-10-27 18:19:45 +00007523 int bFreelist = 1; /* 0 if --ignore-freelist is specified */
dan8cce6b82019-09-14 16:44:51 +00007524 int bRowids = 1; /* 0 if --no-rowids */
dan9a27d652022-09-08 19:22:29 +00007525 sqlite3_recover *p = 0;
7526 int i = 0;
7527
dan9c014f82019-04-25 19:23:15 +00007528 for(i=1; i<nArg; i++){
7529 char *z = azArg[i];
7530 int n;
7531 if( z[0]=='-' && z[1]=='-' ) z++;
drh4245e042019-06-13 13:52:46 +00007532 n = strlen30(z);
danf7fea5b2022-10-27 18:19:45 +00007533 if( n<=17 && memcmp("-ignore-freelist", z, n)==0 ){
dan9c014f82019-04-25 19:23:15 +00007534 bFreelist = 0;
dan42ebb012019-04-27 18:47:03 +00007535 }else
danc0b42432019-04-26 15:14:53 +00007536 if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){
drh2cdcc7f2022-11-02 14:08:26 +00007537 /* This option determines the name of the ATTACH-ed database used
7538 ** internally by the recovery extension. The default is "" which
7539 ** means to use a temporary database that is automatically deleted
7540 ** when closed. This option is undocumented and might disappear at
7541 ** any moment. */
danc0b42432019-04-26 15:14:53 +00007542 i++;
7543 zRecoveryDb = azArg[i];
dan42ebb012019-04-27 18:47:03 +00007544 }else
7545 if( n<=15 && memcmp("-lost-and-found", z, n)==0 && i<(nArg-1) ){
7546 i++;
dan9a27d652022-09-08 19:22:29 +00007547 zLAF = azArg[i];
dan8cce6b82019-09-14 16:44:51 +00007548 }else
7549 if( n<=10 && memcmp("-no-rowids", z, n)==0 ){
7550 bRowids = 0;
danc0b42432019-04-26 15:14:53 +00007551 }
dan9c014f82019-04-25 19:23:15 +00007552 else{
larrybr0953c532022-12-23 19:04:59 +00007553 utf8_printf(stderr, "unexpected option: %s\n", azArg[i]);
drhe2754c12019-08-26 12:50:01 +00007554 showHelp(pState->out, azArg[0]);
dan9c014f82019-04-25 19:23:15 +00007555 return 1;
7556 }
7557 }
dan68cb86e2019-04-20 20:57:28 +00007558
dan9a27d652022-09-08 19:22:29 +00007559 p = sqlite3_recover_init_sql(
7560 pState->db, "main", recoverSqlCb, (void*)pState
dan9c014f82019-04-25 19:23:15 +00007561 );
7562
drh2cdcc7f2022-11-02 14:08:26 +00007563 sqlite3_recover_config(p, 789, (void*)zRecoveryDb); /* Debug use only */
dan9a27d652022-09-08 19:22:29 +00007564 sqlite3_recover_config(p, SQLITE_RECOVER_LOST_AND_FOUND, (void*)zLAF);
7565 sqlite3_recover_config(p, SQLITE_RECOVER_ROWIDS, (void*)&bRowids);
7566 sqlite3_recover_config(p, SQLITE_RECOVER_FREELIST_CORRUPT,(void*)&bFreelist);
7567
dan46d43982022-09-08 21:43:18 +00007568 sqlite3_recover_run(p);
dan9a27d652022-09-08 19:22:29 +00007569 if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
7570 const char *zErr = sqlite3_recover_errmsg(p);
7571 int errCode = sqlite3_recover_errcode(p);
7572 raw_printf(stderr, "sql error: %s (%d)\n", zErr, errCode);
dan9c014f82019-04-25 19:23:15 +00007573 }
dan9a27d652022-09-08 19:22:29 +00007574 rc = sqlite3_recover_finish(p);
dan68cb86e2019-04-20 20:57:28 +00007575 return rc;
7576}
stephan3d420832022-10-27 03:56:01 +00007577#endif /* SQLITE_SHELL_HAVE_RECOVER */
dan68cb86e2019-04-20 20:57:28 +00007578
larrybr42de1c52022-02-13 22:18:22 +00007579
larrybr2d27d362022-04-16 17:53:25 +00007580/*
larrybr42de1c52022-02-13 22:18:22 +00007581 * zAutoColumn(zCol, &db, ?) => Maybe init db, add column zCol to it.
7582 * zAutoColumn(0, &db, ?) => (db!=0) Form columns spec for CREATE TABLE,
7583 * close db and set it to 0, and return the columns spec, to later
7584 * be sqlite3_free()'ed by the caller.
7585 * The return is 0 when either:
7586 * (a) The db was not initialized and zCol==0 (There are no columns.)
7587 * (b) zCol!=0 (Column was added, db initialized as needed.)
7588 * The 3rd argument, pRenamed, references an out parameter. If the
larrybr33633862022-02-14 01:12:46 +00007589 * pointer is non-zero, its referent will be set to a summary of renames
7590 * done if renaming was necessary, or set to 0 if none was done. The out
7591 * string (if any) must be sqlite3_free()'ed by the caller.
larrybr42de1c52022-02-13 22:18:22 +00007592 */
7593#ifdef SHELL_DEBUG
7594#define rc_err_oom_die(rc) \
7595 if( rc==SQLITE_NOMEM ) shell_check_oom(0); \
7596 else if(!(rc==SQLITE_OK||rc==SQLITE_DONE)) \
7597 fprintf(stderr,"E:%d\n",rc), assert(0)
7598#else
7599static void rc_err_oom_die(int rc){
7600 if( rc==SQLITE_NOMEM ) shell_check_oom(0);
7601 assert(rc==SQLITE_OK||rc==SQLITE_DONE);
7602}
7603#endif
7604
7605#ifdef SHELL_COLFIX_DB /* If this is set, the DB can be in a file. */
7606static char zCOL_DB[] = SHELL_STRINGIFY(SHELL_COLFIX_DB);
7607#else /* Otherwise, memory is faster/better for the transient DB. */
7608static const char *zCOL_DB = ":memory:";
7609#endif
7610
7611/* Define character (as C string) to separate generated column ordinal
7612 * from protected part of incoming column names. This defaults to "_"
7613 * so that incoming column identifiers that did not need not be quoted
7614 * remain usable without being quoted. It must be one character.
7615 */
7616#ifndef SHELL_AUTOCOLUMN_SEP
7617# define AUTOCOLUMN_SEP "_"
7618#else
7619# define AUTOCOLUMN_SEP SHELL_STRINGIFY(SHELL_AUTOCOLUMN_SEP)
7620#endif
7621
larrybr33633862022-02-14 01:12:46 +00007622static char *zAutoColumn(const char *zColNew, sqlite3 **pDb, char **pzRenamed){
larrybr42de1c52022-02-13 22:18:22 +00007623 /* Queries and D{D,M}L used here */
7624 static const char * const zTabMake = "\
7625CREATE TABLE ColNames(\
7626 cpos INTEGER PRIMARY KEY,\
larrybr33633862022-02-14 01:12:46 +00007627 name TEXT, nlen INT, chop INT, reps INT, suff TEXT);\
7628CREATE VIEW RepeatedNames AS \
7629SELECT DISTINCT t.name FROM ColNames t \
7630WHERE t.name COLLATE NOCASE IN (\
7631 SELECT o.name FROM ColNames o WHERE o.cpos<>t.cpos\
7632);\
larrybr42de1c52022-02-13 22:18:22 +00007633";
7634 static const char * const zTabFill = "\
7635INSERT INTO ColNames(name,nlen,chop,reps,suff)\
7636 VALUES(iif(length(?1)>0,?1,'?'),max(length(?1),1),0,0,'')\
7637";
7638 static const char * const zHasDupes = "\
7639SELECT count(DISTINCT (substring(name,1,nlen-chop)||suff) COLLATE NOCASE)\
7640 <count(name) FROM ColNames\
7641";
larrybr33633862022-02-14 01:12:46 +00007642#ifdef SHELL_COLUMN_RENAME_CLEAN
larrybr42de1c52022-02-13 22:18:22 +00007643 static const char * const zDedoctor = "\
7644UPDATE ColNames SET chop=iif(\
7645 (substring(name,nlen,1) BETWEEN '0' AND '9')\
7646 AND (rtrim(name,'0123456790') glob '*"AUTOCOLUMN_SEP"'),\
7647 nlen-length(rtrim(name, '"AUTOCOLUMN_SEP"0123456789')),\
7648 0\
7649)\
7650";
larrybr33633862022-02-14 01:12:46 +00007651#endif
larrybr42de1c52022-02-13 22:18:22 +00007652 static const char * const zSetReps = "\
7653UPDATE ColNames AS t SET reps=\
7654(SELECT count(*) FROM ColNames d \
7655 WHERE substring(t.name,1,t.nlen-t.chop)=substring(d.name,1,d.nlen-d.chop)\
7656 COLLATE NOCASE\
7657)\
7658";
7659#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
7660 static const char * const zColDigits = "\
7661SELECT CAST(ceil(log(count(*)+0.5)) AS INT) FROM ColNames \
7662";
larrybr2d27d362022-04-16 17:53:25 +00007663#else
7664 /* Counting on SQLITE_MAX_COLUMN < 100,000 here. (32767 is the hard limit.) */
7665 static const char * const zColDigits = "\
7666SELECT CASE WHEN (nc < 10) THEN 1 WHEN (nc < 100) THEN 2 \
7667 WHEN (nc < 1000) THEN 3 WHEN (nc < 10000) THEN 4 \
7668 ELSE 5 FROM (SELECT count(*) AS nc FROM ColNames) \
7669";
larrybr42de1c52022-02-13 22:18:22 +00007670#endif
7671 static const char * const zRenameRank =
larrybr33633862022-02-14 01:12:46 +00007672#ifdef SHELL_COLUMN_RENAME_CLEAN
larrybr42de1c52022-02-13 22:18:22 +00007673 "UPDATE ColNames AS t SET suff="
7674 "iif(reps>1, printf('%c%0*d', '"AUTOCOLUMN_SEP"', $1, cpos), '')"
larrybr33633862022-02-14 01:12:46 +00007675#else /* ...RENAME_MINIMAL_ONE_PASS */
7676"WITH Lzn(nlz) AS (" /* Find minimum extraneous leading 0's for uniqueness */
7677" SELECT 0 AS nlz"
7678" UNION"
7679" SELECT nlz+1 AS nlz FROM Lzn"
7680" WHERE EXISTS("
7681" SELECT 1"
7682" FROM ColNames t, ColNames o"
7683" WHERE"
7684" iif(t.name IN (SELECT * FROM RepeatedNames),"
7685" printf('%s"AUTOCOLUMN_SEP"%s',"
7686" t.name, substring(printf('%.*c%0.*d',nlz+1,'0',$1,t.cpos),2)),"
7687" t.name"
7688" )"
7689" ="
7690" iif(o.name IN (SELECT * FROM RepeatedNames),"
7691" printf('%s"AUTOCOLUMN_SEP"%s',"
7692" o.name, substring(printf('%.*c%0.*d',nlz+1,'0',$1,o.cpos),2)),"
7693" o.name"
7694" )"
7695" COLLATE NOCASE"
7696" AND o.cpos<>t.cpos"
7697" GROUP BY t.cpos"
7698" )"
7699") UPDATE Colnames AS t SET"
7700" chop = 0," /* No chopping, never touch incoming names. */
7701" suff = iif(name IN (SELECT * FROM RepeatedNames),"
7702" printf('"AUTOCOLUMN_SEP"%s', substring("
7703" printf('%.*c%0.*d',(SELECT max(nlz) FROM Lzn)+1,'0',1,t.cpos),2)),"
7704" ''"
7705" )"
larrybr42de1c52022-02-13 22:18:22 +00007706#endif
7707 ;
7708 static const char * const zCollectVar = "\
7709SELECT\
7710 '('||x'0a'\
7711 || group_concat(\
7712 cname||' TEXT',\
7713 ','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\
7714 ||')' AS ColsSpec \
7715FROM (\
larrybr039132b2022-04-09 18:51:49 +00007716 SELECT cpos, printf('\"%w\"',printf('%!.*s%s', nlen-chop,name,suff)) AS cname \
larrybr42de1c52022-02-13 22:18:22 +00007717 FROM ColNames ORDER BY cpos\
7718)";
larrybr33633862022-02-14 01:12:46 +00007719 static const char * const zRenamesDone =
7720 "SELECT group_concat("
larrybr039132b2022-04-09 18:51:49 +00007721 " printf('\"%w\" to \"%w\"',name,printf('%!.*s%s', nlen-chop, name, suff)),"
larrybr33633862022-02-14 01:12:46 +00007722 " ','||x'0a')"
7723 "FROM ColNames WHERE suff<>'' OR chop!=0"
7724 ;
larrybr42de1c52022-02-13 22:18:22 +00007725 int rc;
7726 sqlite3_stmt *pStmt = 0;
7727 assert(pDb!=0);
7728 if( zColNew ){
7729 /* Add initial or additional column. Init db if necessary. */
7730 if( *pDb==0 ){
7731 if( SQLITE_OK!=sqlite3_open(zCOL_DB, pDb) ) return 0;
7732#ifdef SHELL_COLFIX_DB
7733 if(*zCOL_DB!=':')
larrybr33633862022-02-14 01:12:46 +00007734 sqlite3_exec(*pDb,"drop table if exists ColNames;"
7735 "drop view if exists RepeatedNames;",0,0,0);
larrybr42de1c52022-02-13 22:18:22 +00007736#endif
7737 rc = sqlite3_exec(*pDb, zTabMake, 0, 0, 0);
7738 rc_err_oom_die(rc);
7739 }
7740 assert(*pDb!=0);
7741 rc = sqlite3_prepare_v2(*pDb, zTabFill, -1, &pStmt, 0);
7742 rc_err_oom_die(rc);
7743 rc = sqlite3_bind_text(pStmt, 1, zColNew, -1, 0);
7744 rc_err_oom_die(rc);
7745 rc = sqlite3_step(pStmt);
7746 rc_err_oom_die(rc);
7747 sqlite3_finalize(pStmt);
7748 return 0;
7749 }else if( *pDb==0 ){
7750 return 0;
7751 }else{
7752 /* Formulate the columns spec, close the DB, zero *pDb. */
7753 char *zColsSpec = 0;
7754 int hasDupes = db_int(*pDb, zHasDupes);
larrybr42de1c52022-02-13 22:18:22 +00007755 int nDigits = (hasDupes)? db_int(*pDb, zColDigits) : 0;
larrybr42de1c52022-02-13 22:18:22 +00007756 if( hasDupes ){
larrybr33633862022-02-14 01:12:46 +00007757#ifdef SHELL_COLUMN_RENAME_CLEAN
larrybr42de1c52022-02-13 22:18:22 +00007758 rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
7759 rc_err_oom_die(rc);
larrybr33633862022-02-14 01:12:46 +00007760#endif
larrybr42de1c52022-02-13 22:18:22 +00007761 rc = sqlite3_exec(*pDb, zSetReps, 0, 0, 0);
7762 rc_err_oom_die(rc);
7763 rc = sqlite3_prepare_v2(*pDb, zRenameRank, -1, &pStmt, 0);
7764 rc_err_oom_die(rc);
7765 sqlite3_bind_int(pStmt, 1, nDigits);
7766 rc = sqlite3_step(pStmt);
7767 sqlite3_finalize(pStmt);
7768 assert(rc==SQLITE_DONE);
7769 }
7770 assert(db_int(*pDb, zHasDupes)==0); /* Consider: remove this */
7771 rc = sqlite3_prepare_v2(*pDb, zCollectVar, -1, &pStmt, 0);
7772 rc_err_oom_die(rc);
7773 rc = sqlite3_step(pStmt);
7774 if( rc==SQLITE_ROW ){
7775 zColsSpec = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
7776 }else{
7777 zColsSpec = 0;
7778 }
larrybr33633862022-02-14 01:12:46 +00007779 if( pzRenamed!=0 ){
7780 if( !hasDupes ) *pzRenamed = 0;
7781 else{
7782 sqlite3_finalize(pStmt);
7783 if( SQLITE_OK==sqlite3_prepare_v2(*pDb, zRenamesDone, -1, &pStmt, 0)
7784 && SQLITE_ROW==sqlite3_step(pStmt) ){
7785 *pzRenamed = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
7786 }else
7787 *pzRenamed = 0;
7788 }
7789 }
larrybr42de1c52022-02-13 22:18:22 +00007790 sqlite3_finalize(pStmt);
7791 sqlite3_close(*pDb);
7792 *pDb = 0;
7793 return zColsSpec;
7794 }
7795}
7796
drh2ce15c32017-07-11 13:34:40 +00007797/*
7798** If an input line begins with "." then invoke this routine to
7799** process that line.
7800**
7801** Return 1 on error, 2 to exit, and 0 otherwise.
7802*/
7803static int do_meta_command(char *zLine, ShellState *p){
7804 int h = 1;
7805 int nArg = 0;
7806 int n, c;
7807 int rc = 0;
drh5df84282019-08-17 19:45:25 +00007808 char *azArg[52];
drh2ce15c32017-07-11 13:34:40 +00007809
dan6b046be2018-01-09 15:25:55 +00007810#ifndef SQLITE_OMIT_VIRTUALTABLE
dan43efc182017-12-19 17:42:13 +00007811 if( p->expert.pExpert ){
7812 expertFinish(p, 1, 0);
7813 }
dan6b046be2018-01-09 15:25:55 +00007814#endif
dan43efc182017-12-19 17:42:13 +00007815
drh2ce15c32017-07-11 13:34:40 +00007816 /* Parse the input line into tokens.
7817 */
drh5df84282019-08-17 19:45:25 +00007818 while( zLine[h] && nArg<ArraySize(azArg)-1 ){
drh2ce15c32017-07-11 13:34:40 +00007819 while( IsSpace(zLine[h]) ){ h++; }
7820 if( zLine[h]==0 ) break;
7821 if( zLine[h]=='\'' || zLine[h]=='"' ){
7822 int delim = zLine[h++];
7823 azArg[nArg++] = &zLine[h];
7824 while( zLine[h] && zLine[h]!=delim ){
7825 if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
7826 h++;
7827 }
7828 if( zLine[h]==delim ){
7829 zLine[h++] = 0;
7830 }
7831 if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
7832 }else{
7833 azArg[nArg++] = &zLine[h];
7834 while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
7835 if( zLine[h] ) zLine[h++] = 0;
7836 resolve_backslashes(azArg[nArg-1]);
7837 }
7838 }
drh5df84282019-08-17 19:45:25 +00007839 azArg[nArg] = 0;
drh2ce15c32017-07-11 13:34:40 +00007840
7841 /* Process the input line.
7842 */
7843 if( nArg==0 ) return 0; /* no tokens, no error */
7844 n = strlen30(azArg[0]);
7845 c = azArg[0][0];
drh13c20932018-01-10 21:41:55 +00007846 clearTempFile(p);
drh2ce15c32017-07-11 13:34:40 +00007847
7848#ifndef SQLITE_OMIT_AUTHORIZATION
drhbf70f1b2022-10-19 18:04:42 +00007849 if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00007850 if( nArg!=2 ){
7851 raw_printf(stderr, "Usage: .auth ON|OFF\n");
7852 rc = 1;
7853 goto meta_command_exit;
7854 }
7855 open_db(p, 0);
7856 if( booleanValue(azArg[1]) ){
7857 sqlite3_set_authorizer(p->db, shellAuth, p);
drhb97e2ad2021-08-26 18:31:39 +00007858 }else if( p->bSafeModePersist ){
7859 sqlite3_set_authorizer(p->db, safeModeAuth, p);
drh2ce15c32017-07-11 13:34:40 +00007860 }else{
7861 sqlite3_set_authorizer(p->db, 0, 0);
7862 }
7863 }else
7864#endif
7865
stephan02520cc2022-05-18 22:58:34 +00007866#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) \
stephan4413ec72022-07-12 15:53:02 +00007867 && !defined(SQLITE_SHELL_FIDDLE)
drhbf70f1b2022-10-19 18:04:42 +00007868 if( c=='a' && cli_strncmp(azArg[0], "archive", n)==0 ){
danfd0245d2017-12-07 15:44:29 +00007869 open_db(p, 0);
drhb97e2ad2021-08-26 18:31:39 +00007870 failIfSafeMode(p, "cannot run .archive in safe mode");
drhd0f9cdc2018-05-17 14:09:06 +00007871 rc = arDotCommand(p, 0, azArg, nArg);
danfd0245d2017-12-07 15:44:29 +00007872 }else
7873#endif
7874
stephan4413ec72022-07-12 15:53:02 +00007875#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00007876 if( (c=='b' && n>=3 && cli_strncmp(azArg[0], "backup", n)==0)
7877 || (c=='s' && n>=3 && cli_strncmp(azArg[0], "save", n)==0)
drh2ce15c32017-07-11 13:34:40 +00007878 ){
7879 const char *zDestFile = 0;
7880 const char *zDb = 0;
7881 sqlite3 *pDest;
7882 sqlite3_backup *pBackup;
7883 int j;
drha50bffb2018-12-08 01:09:14 +00007884 int bAsync = 0;
drh69ed38a2018-05-14 00:23:08 +00007885 const char *zVfs = 0;
drhb97e2ad2021-08-26 18:31:39 +00007886 failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
drh2ce15c32017-07-11 13:34:40 +00007887 for(j=1; j<nArg; j++){
7888 const char *z = azArg[j];
7889 if( z[0]=='-' ){
drh69ed38a2018-05-14 00:23:08 +00007890 if( z[1]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +00007891 if( cli_strcmp(z, "-append")==0 ){
drh69ed38a2018-05-14 00:23:08 +00007892 zVfs = "apndvfs";
7893 }else
drhbf70f1b2022-10-19 18:04:42 +00007894 if( cli_strcmp(z, "-async")==0 ){
drha50bffb2018-12-08 01:09:14 +00007895 bAsync = 1;
7896 }else
drh2ce15c32017-07-11 13:34:40 +00007897 {
7898 utf8_printf(stderr, "unknown option: %s\n", azArg[j]);
7899 return 1;
7900 }
7901 }else if( zDestFile==0 ){
7902 zDestFile = azArg[j];
7903 }else if( zDb==0 ){
7904 zDb = zDestFile;
7905 zDestFile = azArg[j];
7906 }else{
drha50bffb2018-12-08 01:09:14 +00007907 raw_printf(stderr, "Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
drh2ce15c32017-07-11 13:34:40 +00007908 return 1;
7909 }
7910 }
7911 if( zDestFile==0 ){
7912 raw_printf(stderr, "missing FILENAME argument on .backup\n");
7913 return 1;
7914 }
7915 if( zDb==0 ) zDb = "main";
larrybr0953c532022-12-23 19:04:59 +00007916 rc = sqlite3_open_v2(zDestFile, &pDest,
drh69ed38a2018-05-14 00:23:08 +00007917 SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs);
drh2ce15c32017-07-11 13:34:40 +00007918 if( rc!=SQLITE_OK ){
7919 utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
drh9e804032018-05-18 17:11:50 +00007920 close_db(pDest);
drh2ce15c32017-07-11 13:34:40 +00007921 return 1;
7922 }
drha50bffb2018-12-08 01:09:14 +00007923 if( bAsync ){
7924 sqlite3_exec(pDest, "PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF;",
7925 0, 0, 0);
7926 }
drh2ce15c32017-07-11 13:34:40 +00007927 open_db(p, 0);
7928 pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
7929 if( pBackup==0 ){
7930 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
drh9e804032018-05-18 17:11:50 +00007931 close_db(pDest);
drh2ce15c32017-07-11 13:34:40 +00007932 return 1;
7933 }
7934 while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
7935 sqlite3_backup_finish(pBackup);
7936 if( rc==SQLITE_DONE ){
7937 rc = 0;
7938 }else{
7939 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
7940 rc = 1;
7941 }
drh9e804032018-05-18 17:11:50 +00007942 close_db(pDest);
drh2ce15c32017-07-11 13:34:40 +00007943 }else
stephan4413ec72022-07-12 15:53:02 +00007944#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00007945
drhbf70f1b2022-10-19 18:04:42 +00007946 if( c=='b' && n>=3 && cli_strncmp(azArg[0], "bail", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00007947 if( nArg==2 ){
7948 bail_on_error = booleanValue(azArg[1]);
7949 }else{
7950 raw_printf(stderr, "Usage: .bail on|off\n");
7951 rc = 1;
7952 }
7953 }else
7954
drhbf70f1b2022-10-19 18:04:42 +00007955 if( c=='b' && n>=3 && cli_strncmp(azArg[0], "binary", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00007956 if( nArg==2 ){
7957 if( booleanValue(azArg[1]) ){
7958 setBinaryMode(p->out, 1);
7959 }else{
7960 setTextMode(p->out, 1);
7961 }
7962 }else{
7963 raw_printf(stderr, "Usage: .binary on|off\n");
7964 rc = 1;
7965 }
7966 }else
7967
drh37407122021-07-23 18:43:58 +00007968 /* The undocumented ".breakpoint" command causes a call to the no-op
7969 ** routine named test_breakpoint().
7970 */
drhbf70f1b2022-10-19 18:04:42 +00007971 if( c=='b' && n>=3 && cli_strncmp(azArg[0], "breakpoint", n)==0 ){
drh37407122021-07-23 18:43:58 +00007972 test_breakpoint();
7973 }else
7974
stephan4413ec72022-07-12 15:53:02 +00007975#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00007976 if( c=='c' && cli_strcmp(azArg[0],"cd")==0 ){
drhb97e2ad2021-08-26 18:31:39 +00007977 failIfSafeMode(p, "cannot run .cd in safe mode");
drh2ce15c32017-07-11 13:34:40 +00007978 if( nArg==2 ){
7979#if defined(_WIN32) || defined(WIN32)
7980 wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
7981 rc = !SetCurrentDirectoryW(z);
7982 sqlite3_free(z);
7983#else
7984 rc = chdir(azArg[1]);
7985#endif
7986 if( rc ){
7987 utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
7988 rc = 1;
7989 }
7990 }else{
7991 raw_printf(stderr, "Usage: .cd DIRECTORY\n");
7992 rc = 1;
7993 }
7994 }else
stephan4413ec72022-07-12 15:53:02 +00007995#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00007996
drhbf70f1b2022-10-19 18:04:42 +00007997 if( c=='c' && n>=3 && cli_strncmp(azArg[0], "changes", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00007998 if( nArg==2 ){
7999 setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
8000 }else{
8001 raw_printf(stderr, "Usage: .changes on|off\n");
8002 rc = 1;
8003 }
8004 }else
8005
stephan4413ec72022-07-12 15:53:02 +00008006#ifndef SQLITE_SHELL_FIDDLE
drh2ce15c32017-07-11 13:34:40 +00008007 /* Cancel output redirection, if it is currently set (by .testcase)
8008 ** Then read the content of the testcase-out.txt file and compare against
8009 ** azArg[1]. If there are differences, report an error and exit.
8010 */
drhbf70f1b2022-10-19 18:04:42 +00008011 if( c=='c' && n>=3 && cli_strncmp(azArg[0], "check", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008012 char *zRes = 0;
8013 output_reset(p);
8014 if( nArg!=2 ){
8015 raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
8016 rc = 2;
8017 }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
8018 raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
8019 rc = 2;
8020 }else if( testcase_glob(azArg[1],zRes)==0 ){
8021 utf8_printf(stderr,
8022 "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
8023 p->zTestcase, azArg[1], zRes);
drhf30d3452017-10-17 13:44:46 +00008024 rc = 1;
drh2ce15c32017-07-11 13:34:40 +00008025 }else{
8026 utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
8027 p->nCheck++;
8028 }
8029 sqlite3_free(zRes);
8030 }else
stephan4413ec72022-07-12 15:53:02 +00008031#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00008032
stephan4413ec72022-07-12 15:53:02 +00008033#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00008034 if( c=='c' && cli_strncmp(azArg[0], "clone", n)==0 ){
drhb97e2ad2021-08-26 18:31:39 +00008035 failIfSafeMode(p, "cannot run .clone in safe mode");
drh2ce15c32017-07-11 13:34:40 +00008036 if( nArg==2 ){
8037 tryToClone(p, azArg[1]);
8038 }else{
8039 raw_printf(stderr, "Usage: .clone FILENAME\n");
8040 rc = 1;
8041 }
8042 }else
stephan4413ec72022-07-12 15:53:02 +00008043#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00008044
drhbf70f1b2022-10-19 18:04:42 +00008045 if( c=='c' && cli_strncmp(azArg[0], "connection", n)==0 ){
drh37407122021-07-23 18:43:58 +00008046 if( nArg==1 ){
8047 /* List available connections */
8048 int i;
8049 for(i=0; i<ArraySize(p->aAuxDb); i++){
8050 const char *zFile = p->aAuxDb[i].zDbFilename;
8051 if( p->aAuxDb[i].db==0 && p->pAuxDb!=&p->aAuxDb[i] ){
8052 zFile = "(not open)";
8053 }else if( zFile==0 ){
8054 zFile = "(memory)";
8055 }else if( zFile[0]==0 ){
8056 zFile = "(temporary-file)";
8057 }
8058 if( p->pAuxDb == &p->aAuxDb[i] ){
8059 utf8_printf(stdout, "ACTIVE %d: %s\n", i, zFile);
8060 }else if( p->aAuxDb[i].db!=0 ){
8061 utf8_printf(stdout, " %d: %s\n", i, zFile);
8062 }
8063 }
8064 }else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){
8065 int i = azArg[1][0] - '0';
8066 if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && i<ArraySize(p->aAuxDb) ){
8067 p->pAuxDb->db = p->db;
8068 p->pAuxDb = &p->aAuxDb[i];
8069 globalDb = p->db = p->pAuxDb->db;
8070 p->pAuxDb->db = 0;
8071 }
drhbf70f1b2022-10-19 18:04:42 +00008072 }else if( nArg==3 && cli_strcmp(azArg[1], "close")==0
drh37407122021-07-23 18:43:58 +00008073 && IsDigit(azArg[2][0]) && azArg[2][1]==0 ){
8074 int i = azArg[2][0] - '0';
8075 if( i<0 || i>=ArraySize(p->aAuxDb) ){
8076 /* No-op */
8077 }else if( p->pAuxDb == &p->aAuxDb[i] ){
8078 raw_printf(stderr, "cannot close the active database connection\n");
8079 rc = 1;
8080 }else if( p->aAuxDb[i].db ){
8081 session_close_all(p, i);
8082 close_db(p->aAuxDb[i].db);
8083 p->aAuxDb[i].db = 0;
8084 }
8085 }else{
8086 raw_printf(stderr, "Usage: .connection [close] [CONNECTION-NUMBER]\n");
8087 rc = 1;
8088 }
8089 }else
8090
drhbf70f1b2022-10-19 18:04:42 +00008091 if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){
drh60081a02020-08-26 19:07:18 +00008092 char **azName = 0;
8093 int nName = 0;
8094 sqlite3_stmt *pStmt;
drh60081a02020-08-26 19:07:18 +00008095 int i;
drh2ce15c32017-07-11 13:34:40 +00008096 open_db(p, 0);
drh60081a02020-08-26 19:07:18 +00008097 rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
8098 if( rc ){
8099 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
drh2ce15c32017-07-11 13:34:40 +00008100 rc = 1;
drh60081a02020-08-26 19:07:18 +00008101 }else{
8102 while( sqlite3_step(pStmt)==SQLITE_ROW ){
8103 const char *zSchema = (const char *)sqlite3_column_text(pStmt,1);
8104 const char *zFile = (const char*)sqlite3_column_text(pStmt,2);
drh621a5e02021-12-16 17:35:27 +00008105 if( zSchema==0 || zFile==0 ) continue;
drh60081a02020-08-26 19:07:18 +00008106 azName = sqlite3_realloc(azName, (nName+1)*2*sizeof(char*));
drhe3e25652021-12-16 13:29:28 +00008107 shell_check_oom(azName);
drh60081a02020-08-26 19:07:18 +00008108 azName[nName*2] = strdup(zSchema);
8109 azName[nName*2+1] = strdup(zFile);
8110 nName++;
8111 }
drh2ce15c32017-07-11 13:34:40 +00008112 }
drh60081a02020-08-26 19:07:18 +00008113 sqlite3_finalize(pStmt);
8114 for(i=0; i<nName; i++){
8115 int eTxn = sqlite3_txn_state(p->db, azName[i*2]);
8116 int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]);
8117 const char *z = azName[i*2+1];
8118 utf8_printf(p->out, "%s: %s %s%s\n",
8119 azName[i*2],
8120 z && z[0] ? z : "\"\"",
8121 bRdonly ? "r/o" : "r/w",
8122 eTxn==SQLITE_TXN_NONE ? "" :
8123 eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn");
8124 free(azName[i*2]);
8125 free(azName[i*2+1]);
8126 }
8127 sqlite3_free(azName);
drh2ce15c32017-07-11 13:34:40 +00008128 }else
8129
drhbf70f1b2022-10-19 18:04:42 +00008130 if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbconfig", n)==0 ){
drheb7f2a02018-09-26 18:02:32 +00008131 static const struct DbConfigChoices {
8132 const char *zName;
8133 int op;
8134 } aDbConfig[] = {
drhb945bcd2019-12-31 22:52:10 +00008135 { "defensive", SQLITE_DBCONFIG_DEFENSIVE },
8136 { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
8137 { "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
drh0a6873b2019-06-14 21:25:25 +00008138 { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
drhb945bcd2019-12-31 22:52:10 +00008139 { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
drh0a6873b2019-06-14 21:25:25 +00008140 { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
drh11d88e62019-08-15 21:27:20 +00008141 { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
drh0a6873b2019-06-14 21:25:25 +00008142 { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
drhb945bcd2019-12-31 22:52:10 +00008143 { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
8144 { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT },
drh0a6873b2019-06-14 21:25:25 +00008145 { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
8146 { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
drh0a6873b2019-06-14 21:25:25 +00008147 { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE },
drhb945bcd2019-12-31 22:52:10 +00008148 { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
drhb77da372020-01-07 16:09:11 +00008149 { "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA },
dan07312a62019-06-21 14:05:27 +00008150 { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
drh7df01192018-04-28 12:43:16 +00008151 };
8152 int ii, v;
8153 open_db(p, 0);
8154 for(ii=0; ii<ArraySize(aDbConfig); ii++){
drhbf70f1b2022-10-19 18:04:42 +00008155 if( nArg>1 && cli_strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
drh7df01192018-04-28 12:43:16 +00008156 if( nArg>=3 ){
8157 sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
8158 }
8159 sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
drhb945bcd2019-12-31 22:52:10 +00008160 utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
drh7df01192018-04-28 12:43:16 +00008161 if( nArg>1 ) break;
8162 }
8163 if( nArg>1 && ii==ArraySize(aDbConfig) ){
8164 utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]);
8165 utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n");
larrybr0953c532022-12-23 19:04:59 +00008166 }
drh7df01192018-04-28 12:43:16 +00008167 }else
8168
stephan3d420832022-10-27 03:56:01 +00008169#if SQLITE_SHELL_HAVE_RECOVER
drhbf70f1b2022-10-19 18:04:42 +00008170 if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008171 rc = shell_dbinfo_command(p, nArg, azArg);
8172 }else
8173
drhbf70f1b2022-10-19 18:04:42 +00008174 if( c=='r' && cli_strncmp(azArg[0], "recover", n)==0 ){
dan68cb86e2019-04-20 20:57:28 +00008175 open_db(p, 0);
danb9b71db2019-04-25 16:20:40 +00008176 rc = recoverDatabaseCmd(p, nArg, azArg);
dan68cb86e2019-04-20 20:57:28 +00008177 }else
stephan3d420832022-10-27 03:56:01 +00008178#endif /* SQLITE_SHELL_HAVE_RECOVER */
dan68cb86e2019-04-20 20:57:28 +00008179
drhbf70f1b2022-10-19 18:04:42 +00008180 if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){
drh8e9297f2020-03-25 12:50:13 +00008181 char *zLike = 0;
8182 char *zSql;
drh2ce15c32017-07-11 13:34:40 +00008183 int i;
8184 int savedShowHeader = p->showHeader;
drhf213b332018-07-05 17:35:46 +00008185 int savedShellFlags = p->shellFlgs;
larrybr527c39d2022-05-10 14:55:45 +00008186 ShellClearFlag(p,
drhc1962192020-10-12 16:54:28 +00008187 SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo
8188 |SHFLG_DumpDataOnly|SHFLG_DumpNoSys);
drh2ce15c32017-07-11 13:34:40 +00008189 for(i=1; i<nArg; i++){
8190 if( azArg[i][0]=='-' ){
8191 const char *z = azArg[i]+1;
8192 if( z[0]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +00008193 if( cli_strcmp(z,"preserve-rowids")==0 ){
drh2ce15c32017-07-11 13:34:40 +00008194#ifdef SQLITE_OMIT_VIRTUALTABLE
8195 raw_printf(stderr, "The --preserve-rowids option is not compatible"
8196 " with SQLITE_OMIT_VIRTUALTABLE\n");
8197 rc = 1;
drh1d29fd82020-05-29 19:03:03 +00008198 sqlite3_free(zLike);
drh2ce15c32017-07-11 13:34:40 +00008199 goto meta_command_exit;
8200#else
8201 ShellSetFlag(p, SHFLG_PreserveRowid);
8202#endif
8203 }else
drhbf70f1b2022-10-19 18:04:42 +00008204 if( cli_strcmp(z,"newlines")==0 ){
drh2ce15c32017-07-11 13:34:40 +00008205 ShellSetFlag(p, SHFLG_Newlines);
8206 }else
drhbf70f1b2022-10-19 18:04:42 +00008207 if( cli_strcmp(z,"data-only")==0 ){
drhc1962192020-10-12 16:54:28 +00008208 ShellSetFlag(p, SHFLG_DumpDataOnly);
8209 }else
drhbf70f1b2022-10-19 18:04:42 +00008210 if( cli_strcmp(z,"nosys")==0 ){
drhc1962192020-10-12 16:54:28 +00008211 ShellSetFlag(p, SHFLG_DumpNoSys);
8212 }else
drh2ce15c32017-07-11 13:34:40 +00008213 {
8214 raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
8215 rc = 1;
drh1d29fd82020-05-29 19:03:03 +00008216 sqlite3_free(zLike);
drh2ce15c32017-07-11 13:34:40 +00008217 goto meta_command_exit;
8218 }
drh2ce15c32017-07-11 13:34:40 +00008219 }else{
dan78a9d752021-05-25 11:39:14 +00008220 /* azArg[i] contains a LIKE pattern. This ".dump" request should
8221 ** only dump data for tables for which either the table name matches
8222 ** the LIKE pattern, or the table appears to be a shadow table of
8223 ** a virtual table for which the name matches the LIKE pattern.
8224 */
8225 char *zExpr = sqlite3_mprintf(
8226 "name LIKE %Q ESCAPE '\\' OR EXISTS ("
8227 " SELECT 1 FROM sqlite_schema WHERE "
8228 " name LIKE %Q ESCAPE '\\' AND"
8229 " sql LIKE 'CREATE VIRTUAL TABLE%%' AND"
8230 " substr(o.name, 1, length(name)+1) == (name||'_')"
8231 ")", azArg[i], azArg[i]
8232 );
larrybr0953c532022-12-23 19:04:59 +00008233
dan78a9d752021-05-25 11:39:14 +00008234 if( zLike ){
8235 zLike = sqlite3_mprintf("%z OR %z", zLike, zExpr);
8236 }else{
8237 zLike = zExpr;
8238 }
drh2ce15c32017-07-11 13:34:40 +00008239 }
8240 }
dan68cb86e2019-04-20 20:57:28 +00008241
drh2ce15c32017-07-11 13:34:40 +00008242 open_db(p, 0);
dan68cb86e2019-04-20 20:57:28 +00008243
drhc1962192020-10-12 16:54:28 +00008244 if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
8245 /* When playing back a "dump", the content might appear in an order
8246 ** which causes immediate foreign key constraints to be violated.
8247 ** So disable foreign-key constraint enforcement to prevent problems. */
8248 raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
8249 raw_printf(p->out, "BEGIN TRANSACTION;\n");
8250 }
drh2ce15c32017-07-11 13:34:40 +00008251 p->writableSchema = 0;
8252 p->showHeader = 0;
8253 /* Set writable_schema=ON since doing so forces SQLite to initialize
drh067b92b2020-06-19 15:24:12 +00008254 ** as much of the schema as it can even if the sqlite_schema table is
drh2ce15c32017-07-11 13:34:40 +00008255 ** corrupt. */
8256 sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
8257 p->nErr = 0;
drh8e9297f2020-03-25 12:50:13 +00008258 if( zLike==0 ) zLike = sqlite3_mprintf("true");
8259 zSql = sqlite3_mprintf(
dan78a9d752021-05-25 11:39:14 +00008260 "SELECT name, type, sql FROM sqlite_schema AS o "
drh8e9297f2020-03-25 12:50:13 +00008261 "WHERE (%s) AND type=='table'"
8262 " AND sql NOT NULL"
8263 " ORDER BY tbl_name='sqlite_sequence', rowid",
8264 zLike
8265 );
8266 run_schema_dump_query(p,zSql);
8267 sqlite3_free(zSql);
drhc1962192020-10-12 16:54:28 +00008268 if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
8269 zSql = sqlite3_mprintf(
dan78a9d752021-05-25 11:39:14 +00008270 "SELECT sql FROM sqlite_schema AS o "
drhc1962192020-10-12 16:54:28 +00008271 "WHERE (%s) AND sql NOT NULL"
8272 " AND type IN ('index','trigger','view')",
8273 zLike
8274 );
8275 run_table_dump_query(p, zSql);
8276 sqlite3_free(zSql);
8277 }
drh8e9297f2020-03-25 12:50:13 +00008278 sqlite3_free(zLike);
drh2ce15c32017-07-11 13:34:40 +00008279 if( p->writableSchema ){
8280 raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
8281 p->writableSchema = 0;
8282 }
8283 sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
8284 sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
drhc1962192020-10-12 16:54:28 +00008285 if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
8286 raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
8287 }
drh2ce15c32017-07-11 13:34:40 +00008288 p->showHeader = savedShowHeader;
drhf213b332018-07-05 17:35:46 +00008289 p->shellFlgs = savedShellFlags;
drh2ce15c32017-07-11 13:34:40 +00008290 }else
8291
drhbf70f1b2022-10-19 18:04:42 +00008292 if( c=='e' && cli_strncmp(azArg[0], "echo", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008293 if( nArg==2 ){
8294 setOrClearFlag(p, SHFLG_Echo, azArg[1]);
8295 }else{
8296 raw_printf(stderr, "Usage: .echo on|off\n");
8297 rc = 1;
8298 }
8299 }else
8300
drhbf70f1b2022-10-19 18:04:42 +00008301 if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008302 if( nArg==2 ){
drhe2ca99c2018-05-02 00:33:43 +00008303 p->autoEQPtest = 0;
drhb4e50392019-01-26 15:40:04 +00008304 if( p->autoEQPtrace ){
8305 if( p->db ) sqlite3_exec(p->db, "PRAGMA vdbe_trace=OFF;", 0, 0, 0);
8306 p->autoEQPtrace = 0;
8307 }
drhbf70f1b2022-10-19 18:04:42 +00008308 if( cli_strcmp(azArg[1],"full")==0 ){
drhada70452017-12-21 21:02:27 +00008309 p->autoEQP = AUTOEQP_full;
drhbf70f1b2022-10-19 18:04:42 +00008310 }else if( cli_strcmp(azArg[1],"trigger")==0 ){
drhada70452017-12-21 21:02:27 +00008311 p->autoEQP = AUTOEQP_trigger;
drhb4e50392019-01-26 15:40:04 +00008312#ifdef SQLITE_DEBUG
drhbf70f1b2022-10-19 18:04:42 +00008313 }else if( cli_strcmp(azArg[1],"test")==0 ){
drhe2ca99c2018-05-02 00:33:43 +00008314 p->autoEQP = AUTOEQP_on;
8315 p->autoEQPtest = 1;
drhbf70f1b2022-10-19 18:04:42 +00008316 }else if( cli_strcmp(azArg[1],"trace")==0 ){
drhb4e50392019-01-26 15:40:04 +00008317 p->autoEQP = AUTOEQP_full;
8318 p->autoEQPtrace = 1;
8319 open_db(p, 0);
drh067b92b2020-06-19 15:24:12 +00008320 sqlite3_exec(p->db, "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0);
drhb4e50392019-01-26 15:40:04 +00008321 sqlite3_exec(p->db, "PRAGMA vdbe_trace=ON;", 0, 0, 0);
8322#endif
drh2ce15c32017-07-11 13:34:40 +00008323 }else{
mistachkinb71aa092018-01-23 00:05:18 +00008324 p->autoEQP = (u8)booleanValue(azArg[1]);
drh2ce15c32017-07-11 13:34:40 +00008325 }
8326 }else{
drhb4e50392019-01-26 15:40:04 +00008327 raw_printf(stderr, "Usage: .eqp off|on|trace|trigger|full\n");
drh2ce15c32017-07-11 13:34:40 +00008328 rc = 1;
8329 }
8330 }else
8331
stephan4413ec72022-07-12 15:53:02 +00008332#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00008333 if( c=='e' && cli_strncmp(azArg[0], "exit", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008334 if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
8335 rc = 2;
8336 }else
stephan02520cc2022-05-18 22:58:34 +00008337#endif
drh2ce15c32017-07-11 13:34:40 +00008338
8339 /* The ".explain" command is automatic now. It is largely pointless. It
8340 ** retained purely for backwards compatibility */
drhbf70f1b2022-10-19 18:04:42 +00008341 if( c=='e' && cli_strncmp(azArg[0], "explain", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008342 int val = 1;
8343 if( nArg>=2 ){
drhbf70f1b2022-10-19 18:04:42 +00008344 if( cli_strcmp(azArg[1],"auto")==0 ){
drh2ce15c32017-07-11 13:34:40 +00008345 val = 99;
8346 }else{
8347 val = booleanValue(azArg[1]);
8348 }
8349 }
8350 if( val==1 && p->mode!=MODE_Explain ){
8351 p->normalMode = p->mode;
8352 p->mode = MODE_Explain;
8353 p->autoExplain = 0;
8354 }else if( val==0 ){
8355 if( p->mode==MODE_Explain ) p->mode = p->normalMode;
8356 p->autoExplain = 0;
8357 }else if( val==99 ){
8358 if( p->mode==MODE_Explain ) p->mode = p->normalMode;
8359 p->autoExplain = 1;
8360 }
8361 }else
8362
dan6b046be2018-01-09 15:25:55 +00008363#ifndef SQLITE_OMIT_VIRTUALTABLE
drhbf70f1b2022-10-19 18:04:42 +00008364 if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){
drhfe463172021-12-16 17:57:21 +00008365 if( p->bSafeMode ){
larrybr0953c532022-12-23 19:04:59 +00008366 raw_printf(stderr,
drhfe463172021-12-16 17:57:21 +00008367 "Cannot run experimental commands such as \"%s\" in safe mode\n",
8368 azArg[0]);
8369 rc = 1;
8370 }else{
8371 open_db(p, 0);
8372 expertDotCommand(p, azArg, nArg);
8373 }
dan43efc182017-12-19 17:42:13 +00008374 }else
dan6b046be2018-01-09 15:25:55 +00008375#endif
dan43efc182017-12-19 17:42:13 +00008376
drhbf70f1b2022-10-19 18:04:42 +00008377 if( c=='f' && cli_strncmp(azArg[0], "filectrl", n)==0 ){
drhd985f722019-06-05 14:29:53 +00008378 static const struct {
8379 const char *zCtrlName; /* Name of a test-control option */
8380 int ctrlCode; /* Integer code for that option */
8381 const char *zUsage; /* Usage notes */
8382 } aCtrl[] = {
drhd985f722019-06-05 14:29:53 +00008383 { "chunk_size", SQLITE_FCNTL_CHUNK_SIZE, "SIZE" },
drh18a4bbd2020-12-17 15:17:42 +00008384 { "data_version", SQLITE_FCNTL_DATA_VERSION, "" },
larrybr0953c532022-12-23 19:04:59 +00008385 { "has_moved", SQLITE_FCNTL_HAS_MOVED, "" },
drhd985f722019-06-05 14:29:53 +00008386 { "lock_timeout", SQLITE_FCNTL_LOCK_TIMEOUT, "MILLISEC" },
drh18a4bbd2020-12-17 15:17:42 +00008387 { "persist_wal", SQLITE_FCNTL_PERSIST_WAL, "[BOOLEAN]" },
8388 /* { "pragma", SQLITE_FCNTL_PRAGMA, "NAME ARG" },*/
8389 { "psow", SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]" },
drh541ef2c2020-04-20 16:21:30 +00008390 { "reserve_bytes", SQLITE_FCNTL_RESERVE_BYTES, "[N]" },
drh18a4bbd2020-12-17 15:17:42 +00008391 { "size_limit", SQLITE_FCNTL_SIZE_LIMIT, "[LIMIT]" },
8392 { "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" },
8393 /* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY, "COUNT DELAY" },*/
drhd985f722019-06-05 14:29:53 +00008394 };
8395 int filectrl = -1;
8396 int iCtrl = -1;
drh4245e042019-06-13 13:52:46 +00008397 sqlite3_int64 iRes = 0; /* Integer result to display if rc2==1 */
8398 int isOk = 0; /* 0: usage 1: %lld 2: no-result */
drhd985f722019-06-05 14:29:53 +00008399 int n2, i;
8400 const char *zCmd = 0;
drh541ef2c2020-04-20 16:21:30 +00008401 const char *zSchema = 0;
drhd985f722019-06-05 14:29:53 +00008402
8403 open_db(p, 0);
8404 zCmd = nArg>=2 ? azArg[1] : "help";
8405
larrybr0953c532022-12-23 19:04:59 +00008406 if( zCmd[0]=='-'
drhbf70f1b2022-10-19 18:04:42 +00008407 && (cli_strcmp(zCmd,"--schema")==0 || cli_strcmp(zCmd,"-schema")==0)
drh541ef2c2020-04-20 16:21:30 +00008408 && nArg>=4
8409 ){
8410 zSchema = azArg[2];
8411 for(i=3; i<nArg; i++) azArg[i-2] = azArg[i];
8412 nArg -= 2;
8413 zCmd = azArg[1];
8414 }
8415
drhd985f722019-06-05 14:29:53 +00008416 /* The argument can optionally begin with "-" or "--" */
8417 if( zCmd[0]=='-' && zCmd[1] ){
8418 zCmd++;
8419 if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
8420 }
8421
8422 /* --help lists all file-controls */
drhbf70f1b2022-10-19 18:04:42 +00008423 if( cli_strcmp(zCmd,"help")==0 ){
drhd985f722019-06-05 14:29:53 +00008424 utf8_printf(p->out, "Available file-controls:\n");
8425 for(i=0; i<ArraySize(aCtrl); i++){
8426 utf8_printf(p->out, " .filectrl %s %s\n",
8427 aCtrl[i].zCtrlName, aCtrl[i].zUsage);
8428 }
8429 rc = 1;
8430 goto meta_command_exit;
8431 }
8432
8433 /* convert filectrl text option to value. allow any unique prefix
8434 ** of the option name, or a numerical value. */
8435 n2 = strlen30(zCmd);
8436 for(i=0; i<ArraySize(aCtrl); i++){
drhbf70f1b2022-10-19 18:04:42 +00008437 if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
drhd985f722019-06-05 14:29:53 +00008438 if( filectrl<0 ){
8439 filectrl = aCtrl[i].ctrlCode;
8440 iCtrl = i;
8441 }else{
8442 utf8_printf(stderr, "Error: ambiguous file-control: \"%s\"\n"
8443 "Use \".filectrl --help\" for help\n", zCmd);
8444 rc = 1;
8445 goto meta_command_exit;
8446 }
8447 }
8448 }
8449 if( filectrl<0 ){
8450 utf8_printf(stderr,"Error: unknown file-control: %s\n"
8451 "Use \".filectrl --help\" for help\n", zCmd);
8452 }else{
8453 switch(filectrl){
8454 case SQLITE_FCNTL_SIZE_LIMIT: {
8455 if( nArg!=2 && nArg!=3 ) break;
8456 iRes = nArg==3 ? integerValue(azArg[2]) : -1;
drh541ef2c2020-04-20 16:21:30 +00008457 sqlite3_file_control(p->db, zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
drhd985f722019-06-05 14:29:53 +00008458 isOk = 1;
8459 break;
8460 }
8461 case SQLITE_FCNTL_LOCK_TIMEOUT:
8462 case SQLITE_FCNTL_CHUNK_SIZE: {
8463 int x;
8464 if( nArg!=3 ) break;
8465 x = (int)integerValue(azArg[2]);
drh541ef2c2020-04-20 16:21:30 +00008466 sqlite3_file_control(p->db, zSchema, filectrl, &x);
drhd985f722019-06-05 14:29:53 +00008467 isOk = 2;
8468 break;
8469 }
8470 case SQLITE_FCNTL_PERSIST_WAL:
8471 case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
8472 int x;
8473 if( nArg!=2 && nArg!=3 ) break;
8474 x = nArg==3 ? booleanValue(azArg[2]) : -1;
drh541ef2c2020-04-20 16:21:30 +00008475 sqlite3_file_control(p->db, zSchema, filectrl, &x);
drhd985f722019-06-05 14:29:53 +00008476 iRes = x;
8477 isOk = 1;
8478 break;
8479 }
drh18a4bbd2020-12-17 15:17:42 +00008480 case SQLITE_FCNTL_DATA_VERSION:
drhd985f722019-06-05 14:29:53 +00008481 case SQLITE_FCNTL_HAS_MOVED: {
8482 int x;
8483 if( nArg!=2 ) break;
drh541ef2c2020-04-20 16:21:30 +00008484 sqlite3_file_control(p->db, zSchema, filectrl, &x);
drhd985f722019-06-05 14:29:53 +00008485 iRes = x;
8486 isOk = 1;
8487 break;
8488 }
8489 case SQLITE_FCNTL_TEMPFILENAME: {
8490 char *z = 0;
8491 if( nArg!=2 ) break;
drh541ef2c2020-04-20 16:21:30 +00008492 sqlite3_file_control(p->db, zSchema, filectrl, &z);
drhd985f722019-06-05 14:29:53 +00008493 if( z ){
8494 utf8_printf(p->out, "%s\n", z);
8495 sqlite3_free(z);
8496 }
8497 isOk = 2;
8498 break;
8499 }
drh541ef2c2020-04-20 16:21:30 +00008500 case SQLITE_FCNTL_RESERVE_BYTES: {
8501 int x;
8502 if( nArg>=3 ){
8503 x = atoi(azArg[2]);
8504 sqlite3_file_control(p->db, zSchema, filectrl, &x);
8505 }
8506 x = -1;
8507 sqlite3_file_control(p->db, zSchema, filectrl, &x);
8508 utf8_printf(p->out,"%d\n", x);
8509 isOk = 2;
8510 break;
8511 }
drhd985f722019-06-05 14:29:53 +00008512 }
8513 }
8514 if( isOk==0 && iCtrl>=0 ){
8515 utf8_printf(p->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
8516 rc = 1;
8517 }else if( isOk==1 ){
drhe2500762019-06-13 14:07:41 +00008518 char zBuf[100];
8519 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
8520 raw_printf(p->out, "%s\n", zBuf);
drhd985f722019-06-05 14:29:53 +00008521 }
8522 }else
8523
drhbf70f1b2022-10-19 18:04:42 +00008524 if( c=='f' && cli_strncmp(azArg[0], "fullschema", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008525 ShellState data;
drh2ce15c32017-07-11 13:34:40 +00008526 int doStats = 0;
8527 memcpy(&data, p, sizeof(data));
8528 data.showHeader = 0;
8529 data.cMode = data.mode = MODE_Semi;
8530 if( nArg==2 && optionMatch(azArg[1], "indent") ){
8531 data.cMode = data.mode = MODE_Pretty;
8532 nArg = 1;
8533 }
8534 if( nArg!=1 ){
8535 raw_printf(stderr, "Usage: .fullschema ?--indent?\n");
8536 rc = 1;
8537 goto meta_command_exit;
8538 }
8539 open_db(p, 0);
8540 rc = sqlite3_exec(p->db,
8541 "SELECT sql FROM"
8542 " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
drh067b92b2020-06-19 15:24:12 +00008543 " FROM sqlite_schema UNION ALL"
8544 " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) "
drh2ce15c32017-07-11 13:34:40 +00008545 "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
drh69935c02021-06-25 11:14:10 +00008546 "ORDER BY x",
drhf83d5012021-05-03 13:35:00 +00008547 callback, &data, 0
drh2ce15c32017-07-11 13:34:40 +00008548 );
8549 if( rc==SQLITE_OK ){
8550 sqlite3_stmt *pStmt;
8551 rc = sqlite3_prepare_v2(p->db,
drh067b92b2020-06-19 15:24:12 +00008552 "SELECT rowid FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +00008553 " WHERE name GLOB 'sqlite_stat[134]'",
8554 -1, &pStmt, 0);
8555 doStats = sqlite3_step(pStmt)==SQLITE_ROW;
8556 sqlite3_finalize(pStmt);
8557 }
8558 if( doStats==0 ){
8559 raw_printf(p->out, "/* No STAT tables available */\n");
8560 }else{
drh067b92b2020-06-19 15:24:12 +00008561 raw_printf(p->out, "ANALYZE sqlite_schema;\n");
drh2ce15c32017-07-11 13:34:40 +00008562 data.cMode = data.mode = MODE_Insert;
8563 data.zDestTable = "sqlite_stat1";
drhf83d5012021-05-03 13:35:00 +00008564 shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
drh2ce15c32017-07-11 13:34:40 +00008565 data.zDestTable = "sqlite_stat4";
drhf83d5012021-05-03 13:35:00 +00008566 shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
drh067b92b2020-06-19 15:24:12 +00008567 raw_printf(p->out, "ANALYZE sqlite_schema;\n");
drh2ce15c32017-07-11 13:34:40 +00008568 }
8569 }else
8570
drhbf70f1b2022-10-19 18:04:42 +00008571 if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008572 if( nArg==2 ){
8573 p->showHeader = booleanValue(azArg[1]);
drhc0605082020-06-05 00:54:27 +00008574 p->shellFlgs |= SHFLG_HeaderSet;
drh2ce15c32017-07-11 13:34:40 +00008575 }else{
8576 raw_printf(stderr, "Usage: .headers on|off\n");
8577 rc = 1;
8578 }
8579 }else
8580
drhbf70f1b2022-10-19 18:04:42 +00008581 if( c=='h' && cli_strncmp(azArg[0], "help", n)==0 ){
drh98aa2ab2018-09-26 16:53:51 +00008582 if( nArg>=2 ){
drhe93f8262018-10-11 16:53:37 +00008583 n = showHelp(p->out, azArg[1]);
drh98aa2ab2018-09-26 16:53:51 +00008584 if( n==0 ){
8585 utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]);
8586 }
8587 }else{
8588 showHelp(p->out, 0);
8589 }
drh2ce15c32017-07-11 13:34:40 +00008590 }else
8591
stephan4413ec72022-07-12 15:53:02 +00008592#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00008593 if( c=='i' && cli_strncmp(azArg[0], "import", n)==0 ){
drhccb37812020-03-09 15:39:39 +00008594 char *zTable = 0; /* Insert data into this table */
larrybr53e11862022-03-06 23:41:21 +00008595 char *zSchema = 0; /* within this schema (may default to "main") */
drhccb37812020-03-09 15:39:39 +00008596 char *zFile = 0; /* Name of file to extra content from */
drh2ce15c32017-07-11 13:34:40 +00008597 sqlite3_stmt *pStmt = NULL; /* A statement */
8598 int nCol; /* Number of columns in the table */
8599 int nByte; /* Number of bytes in an SQL string */
8600 int i, j; /* Loop counters */
8601 int needCommit; /* True to COMMIT or ROLLBACK at end */
8602 int nSep; /* Number of bytes in p->colSeparator[] */
8603 char *zSql; /* An SQL statement */
larrybr41f46702022-03-07 00:14:52 +00008604 char *zFullTabName; /* Table name with schema if applicable */
drh2ce15c32017-07-11 13:34:40 +00008605 ImportCtx sCtx; /* Reader context */
8606 char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
drhccb37812020-03-09 15:39:39 +00008607 int eVerbose = 0; /* Larger for more console output */
8608 int nSkip = 0; /* Initial lines to skip */
8609 int useOutputMode = 1; /* Use output mode to determine separators */
drhe684ac62022-03-08 13:59:46 +00008610 char *zCreate = 0; /* CREATE TABLE statement text */
drh2ce15c32017-07-11 13:34:40 +00008611
drhb97e2ad2021-08-26 18:31:39 +00008612 failIfSafeMode(p, "cannot run .import in safe mode");
drhccb37812020-03-09 15:39:39 +00008613 memset(&sCtx, 0, sizeof(sCtx));
8614 if( p->mode==MODE_Ascii ){
8615 xRead = ascii_read_one_field;
8616 }else{
8617 xRead = csv_read_one_field;
8618 }
larrybr2f5f6742022-05-09 12:29:47 +00008619 rc = 1;
drhccb37812020-03-09 15:39:39 +00008620 for(i=1; i<nArg; i++){
8621 char *z = azArg[i];
8622 if( z[0]=='-' && z[1]=='-' ) z++;
8623 if( z[0]!='-' ){
8624 if( zFile==0 ){
8625 zFile = z;
8626 }else if( zTable==0 ){
8627 zTable = z;
8628 }else{
8629 utf8_printf(p->out, "ERROR: extra argument: \"%s\". Usage:\n", z);
8630 showHelp(p->out, "import");
drhccb37812020-03-09 15:39:39 +00008631 goto meta_command_exit;
8632 }
drhbf70f1b2022-10-19 18:04:42 +00008633 }else if( cli_strcmp(z,"-v")==0 ){
drhccb37812020-03-09 15:39:39 +00008634 eVerbose++;
drhbf70f1b2022-10-19 18:04:42 +00008635 }else if( cli_strcmp(z,"-schema")==0 && i<nArg-1 ){
larrybr738d7b92022-01-13 21:22:54 +00008636 zSchema = azArg[++i];
drhbf70f1b2022-10-19 18:04:42 +00008637 }else if( cli_strcmp(z,"-skip")==0 && i<nArg-1 ){
drhccb37812020-03-09 15:39:39 +00008638 nSkip = integerValue(azArg[++i]);
drhbf70f1b2022-10-19 18:04:42 +00008639 }else if( cli_strcmp(z,"-ascii")==0 ){
drhccb37812020-03-09 15:39:39 +00008640 sCtx.cColSep = SEP_Unit[0];
8641 sCtx.cRowSep = SEP_Record[0];
8642 xRead = ascii_read_one_field;
8643 useOutputMode = 0;
drhbf70f1b2022-10-19 18:04:42 +00008644 }else if( cli_strcmp(z,"-csv")==0 ){
drhccb37812020-03-09 15:39:39 +00008645 sCtx.cColSep = ',';
8646 sCtx.cRowSep = '\n';
8647 xRead = csv_read_one_field;
8648 useOutputMode = 0;
8649 }else{
8650 utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z);
8651 showHelp(p->out, "import");
drhccb37812020-03-09 15:39:39 +00008652 goto meta_command_exit;
8653 }
8654 }
8655 if( zTable==0 ){
8656 utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n",
8657 zFile==0 ? "FILE" : "TABLE");
8658 showHelp(p->out, "import");
drh2ce15c32017-07-11 13:34:40 +00008659 goto meta_command_exit;
8660 }
drh2ce15c32017-07-11 13:34:40 +00008661 seenInterrupt = 0;
drh2ce15c32017-07-11 13:34:40 +00008662 open_db(p, 0);
drhccb37812020-03-09 15:39:39 +00008663 if( useOutputMode ){
8664 /* If neither the --csv or --ascii options are specified, then set
8665 ** the column and row separator characters from the output mode. */
8666 nSep = strlen30(p->colSeparator);
8667 if( nSep==0 ){
8668 raw_printf(stderr,
8669 "Error: non-null column separator required for import\n");
drhccb37812020-03-09 15:39:39 +00008670 goto meta_command_exit;
8671 }
8672 if( nSep>1 ){
larrybr2f5f6742022-05-09 12:29:47 +00008673 raw_printf(stderr,
drhccb37812020-03-09 15:39:39 +00008674 "Error: multi-character column separators not allowed"
8675 " for import\n");
drhccb37812020-03-09 15:39:39 +00008676 goto meta_command_exit;
8677 }
drh2ce15c32017-07-11 13:34:40 +00008678 nSep = strlen30(p->rowSeparator);
drhccb37812020-03-09 15:39:39 +00008679 if( nSep==0 ){
8680 raw_printf(stderr,
8681 "Error: non-null row separator required for import\n");
drhccb37812020-03-09 15:39:39 +00008682 goto meta_command_exit;
8683 }
drhbf70f1b2022-10-19 18:04:42 +00008684 if( nSep==2 && p->mode==MODE_Csv
8685 && cli_strcmp(p->rowSeparator,SEP_CrLf)==0
8686 ){
drhccb37812020-03-09 15:39:39 +00008687 /* When importing CSV (only), if the row separator is set to the
8688 ** default output row separator, change it to the default input
8689 ** row separator. This avoids having to maintain different input
8690 ** and output row separators. */
8691 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
8692 nSep = strlen30(p->rowSeparator);
8693 }
8694 if( nSep>1 ){
8695 raw_printf(stderr, "Error: multi-character row separators not allowed"
8696 " for import\n");
drhccb37812020-03-09 15:39:39 +00008697 goto meta_command_exit;
8698 }
8699 sCtx.cColSep = p->colSeparator[0];
8700 sCtx.cRowSep = p->rowSeparator[0];
drh2ce15c32017-07-11 13:34:40 +00008701 }
8702 sCtx.zFile = zFile;
8703 sCtx.nLine = 1;
8704 if( sCtx.zFile[0]=='|' ){
8705#ifdef SQLITE_OMIT_POPEN
8706 raw_printf(stderr, "Error: pipes are not supported in this OS\n");
drhccb37812020-03-09 15:39:39 +00008707 goto meta_command_exit;
drh2ce15c32017-07-11 13:34:40 +00008708#else
8709 sCtx.in = popen(sCtx.zFile+1, "r");
8710 sCtx.zFile = "<pipe>";
drh97767842020-05-29 19:39:35 +00008711 sCtx.xCloser = pclose;
drh2ce15c32017-07-11 13:34:40 +00008712#endif
8713 }else{
8714 sCtx.in = fopen(sCtx.zFile, "rb");
drh97767842020-05-29 19:39:35 +00008715 sCtx.xCloser = fclose;
drh2ce15c32017-07-11 13:34:40 +00008716 }
drh2ce15c32017-07-11 13:34:40 +00008717 if( sCtx.in==0 ){
8718 utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
drhccb37812020-03-09 15:39:39 +00008719 goto meta_command_exit;
drh2ce15c32017-07-11 13:34:40 +00008720 }
drhccb37812020-03-09 15:39:39 +00008721 if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
8722 char zSep[2];
8723 zSep[1] = 0;
8724 zSep[0] = sCtx.cColSep;
8725 utf8_printf(p->out, "Column separator ");
8726 output_c_string(p->out, zSep);
8727 utf8_printf(p->out, ", row separator ");
8728 zSep[0] = sCtx.cRowSep;
8729 output_c_string(p->out, zSep);
8730 utf8_printf(p->out, "\n");
8731 }
larrybr2f5f6742022-05-09 12:29:47 +00008732 sCtx.z = sqlite3_malloc64(120);
8733 if( sCtx.z==0 ){
8734 import_cleanup(&sCtx);
8735 shell_out_of_memory();
8736 }
larrybr53e11862022-03-06 23:41:21 +00008737 /* Below, resources must be freed before exit. */
drhccb37812020-03-09 15:39:39 +00008738 while( (nSkip--)>0 ){
8739 while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
drhccb37812020-03-09 15:39:39 +00008740 }
larrybr53e11862022-03-06 23:41:21 +00008741 if( zSchema!=0 ){
larrybr41f46702022-03-07 00:14:52 +00008742 zFullTabName = sqlite3_mprintf("\"%w\".\"%w\"", zSchema, zTable);
larrybr53e11862022-03-06 23:41:21 +00008743 }else{
larrybr41f46702022-03-07 00:14:52 +00008744 zFullTabName = sqlite3_mprintf("\"%w\"", zTable);
larrybr53e11862022-03-06 23:41:21 +00008745 }
larrybr41f46702022-03-07 00:14:52 +00008746 zSql = sqlite3_mprintf("SELECT * FROM %s", zFullTabName);
8747 if( zSql==0 || zFullTabName==0 ){
drh97767842020-05-29 19:39:35 +00008748 import_cleanup(&sCtx);
drh4b5345c2018-04-24 13:07:40 +00008749 shell_out_of_memory();
drh2ce15c32017-07-11 13:34:40 +00008750 }
8751 nByte = strlen30(zSql);
8752 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
8753 import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
8754 if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
larrybr58a53d62022-02-10 03:21:48 +00008755 sqlite3 *dbCols = 0;
larrybr33633862022-02-14 01:12:46 +00008756 char *zRenames = 0;
larrybr58a53d62022-02-10 03:21:48 +00008757 char *zColDefs;
drhe684ac62022-03-08 13:59:46 +00008758 zCreate = sqlite3_mprintf("CREATE TABLE %s", zFullTabName);
drh2ce15c32017-07-11 13:34:40 +00008759 while( xRead(&sCtx) ){
larrybra0337272022-02-11 13:40:25 +00008760 zAutoColumn(sCtx.z, &dbCols, 0);
drh2ce15c32017-07-11 13:34:40 +00008761 if( sCtx.cTerm!=sCtx.cColSep ) break;
larrybr4c5c6212022-02-11 01:21:09 +00008762 }
larrybr33633862022-02-14 01:12:46 +00008763 zColDefs = zAutoColumn(0, &dbCols, &zRenames);
8764 if( zRenames!=0 ){
larrybra0337272022-02-11 13:40:25 +00008765 utf8_printf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
larrybr33633862022-02-14 01:12:46 +00008766 "Columns renamed during .import %s due to duplicates:\n"
8767 "%s\n", sCtx.zFile, zRenames);
8768 sqlite3_free(zRenames);
larrybra0337272022-02-11 13:40:25 +00008769 }
larrybr58a53d62022-02-10 03:21:48 +00008770 assert(dbCols==0);
8771 if( zColDefs==0 ){
drh2ce15c32017-07-11 13:34:40 +00008772 utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
larrybr53e11862022-03-06 23:41:21 +00008773 import_fail:
8774 sqlite3_free(zCreate);
8775 sqlite3_free(zSql);
larrybr41f46702022-03-07 00:14:52 +00008776 sqlite3_free(zFullTabName);
larrybr53e11862022-03-06 23:41:21 +00008777 import_cleanup(&sCtx);
drhccb37812020-03-09 15:39:39 +00008778 rc = 1;
8779 goto meta_command_exit;
drh2ce15c32017-07-11 13:34:40 +00008780 }
larrybr58a53d62022-02-10 03:21:48 +00008781 zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs);
drhccb37812020-03-09 15:39:39 +00008782 if( eVerbose>=1 ){
8783 utf8_printf(p->out, "%s\n", zCreate);
8784 }
drh2ce15c32017-07-11 13:34:40 +00008785 rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
drh2ce15c32017-07-11 13:34:40 +00008786 if( rc ){
larrybrce0b5e42022-01-14 16:29:45 +00008787 utf8_printf(stderr, "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
larrybr53e11862022-03-06 23:41:21 +00008788 goto import_fail;
drh2ce15c32017-07-11 13:34:40 +00008789 }
larrybrce0b5e42022-01-14 16:29:45 +00008790 sqlite3_free(zCreate);
larrybr53e11862022-03-06 23:41:21 +00008791 zCreate = 0;
drh2ce15c32017-07-11 13:34:40 +00008792 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
8793 }
drh2ce15c32017-07-11 13:34:40 +00008794 if( rc ){
8795 if (pStmt) sqlite3_finalize(pStmt);
8796 utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
larrybr53e11862022-03-06 23:41:21 +00008797 goto import_fail;
drh2ce15c32017-07-11 13:34:40 +00008798 }
larrybr53e11862022-03-06 23:41:21 +00008799 sqlite3_free(zSql);
drh2ce15c32017-07-11 13:34:40 +00008800 nCol = sqlite3_column_count(pStmt);
8801 sqlite3_finalize(pStmt);
8802 pStmt = 0;
8803 if( nCol==0 ) return 0; /* no columns, no error */
8804 zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
8805 if( zSql==0 ){
drh97767842020-05-29 19:39:35 +00008806 import_cleanup(&sCtx);
drh4b5345c2018-04-24 13:07:40 +00008807 shell_out_of_memory();
drh2ce15c32017-07-11 13:34:40 +00008808 }
larrybr41f46702022-03-07 00:14:52 +00008809 sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zFullTabName);
drh2ce15c32017-07-11 13:34:40 +00008810 j = strlen30(zSql);
8811 for(i=1; i<nCol; i++){
8812 zSql[j++] = ',';
8813 zSql[j++] = '?';
8814 }
8815 zSql[j++] = ')';
8816 zSql[j] = 0;
drhccb37812020-03-09 15:39:39 +00008817 if( eVerbose>=2 ){
8818 utf8_printf(p->out, "Insert using: %s\n", zSql);
8819 }
drh2ce15c32017-07-11 13:34:40 +00008820 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
drh2ce15c32017-07-11 13:34:40 +00008821 if( rc ){
8822 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
8823 if (pStmt) sqlite3_finalize(pStmt);
larrybr53e11862022-03-06 23:41:21 +00008824 goto import_fail;
drh2ce15c32017-07-11 13:34:40 +00008825 }
larrybr53e11862022-03-06 23:41:21 +00008826 sqlite3_free(zSql);
larrybr41f46702022-03-07 00:14:52 +00008827 sqlite3_free(zFullTabName);
drh2ce15c32017-07-11 13:34:40 +00008828 needCommit = sqlite3_get_autocommit(p->db);
8829 if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
8830 do{
8831 int startLine = sCtx.nLine;
8832 for(i=0; i<nCol; i++){
8833 char *z = xRead(&sCtx);
8834 /*
8835 ** Did we reach end-of-file before finding any columns?
8836 ** If so, stop instead of NULL filling the remaining columns.
8837 */
8838 if( z==0 && i==0 ) break;
8839 /*
8840 ** Did we reach end-of-file OR end-of-line before finding any
8841 ** columns in ASCII mode? If so, stop instead of NULL filling
8842 ** the remaining columns.
8843 */
8844 if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
8845 sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
8846 if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
8847 utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
8848 "filling the rest with NULL\n",
8849 sCtx.zFile, startLine, nCol, i+1);
8850 i += 2;
8851 while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
8852 }
8853 }
8854 if( sCtx.cTerm==sCtx.cColSep ){
8855 do{
8856 xRead(&sCtx);
8857 i++;
8858 }while( sCtx.cTerm==sCtx.cColSep );
8859 utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
8860 "extras ignored\n",
8861 sCtx.zFile, startLine, nCol, i);
8862 }
8863 if( i>=nCol ){
8864 sqlite3_step(pStmt);
8865 rc = sqlite3_reset(pStmt);
8866 if( rc!=SQLITE_OK ){
8867 utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
8868 startLine, sqlite3_errmsg(p->db));
drhccb37812020-03-09 15:39:39 +00008869 sCtx.nErr++;
8870 }else{
8871 sCtx.nRow++;
drh2ce15c32017-07-11 13:34:40 +00008872 }
8873 }
8874 }while( sCtx.cTerm!=EOF );
8875
drh97767842020-05-29 19:39:35 +00008876 import_cleanup(&sCtx);
drh2ce15c32017-07-11 13:34:40 +00008877 sqlite3_finalize(pStmt);
8878 if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
drhccb37812020-03-09 15:39:39 +00008879 if( eVerbose>0 ){
8880 utf8_printf(p->out,
8881 "Added %d rows with %d errors using %d lines of input\n",
8882 sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
8883 }
drh2ce15c32017-07-11 13:34:40 +00008884 }else
stephan4413ec72022-07-12 15:53:02 +00008885#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00008886
8887#ifndef SQLITE_UNTESTABLE
drhbf70f1b2022-10-19 18:04:42 +00008888 if( c=='i' && cli_strncmp(azArg[0], "imposter", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008889 char *zSql;
8890 char *zCollist = 0;
8891 sqlite3_stmt *pStmt;
8892 int tnum = 0;
drh491c5be2019-10-18 15:58:50 +00008893 int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */
8894 int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
drh2ce15c32017-07-11 13:34:40 +00008895 int i;
drh48d219a2018-04-23 18:38:48 +00008896 if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
8897 utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n"
8898 " .imposter off\n");
drh491c5be2019-10-18 15:58:50 +00008899 /* Also allowed, but not documented:
8900 **
8901 ** .imposter TABLE IMPOSTER
8902 **
8903 ** where TABLE is a WITHOUT ROWID table. In that case, the
8904 ** imposter is another WITHOUT ROWID table with the columns in
8905 ** storage order. */
drh2ce15c32017-07-11 13:34:40 +00008906 rc = 1;
8907 goto meta_command_exit;
8908 }
8909 open_db(p, 0);
drh48d219a2018-04-23 18:38:48 +00008910 if( nArg==2 ){
8911 sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1);
8912 goto meta_command_exit;
8913 }
drh491c5be2019-10-18 15:58:50 +00008914 zSql = sqlite3_mprintf(
drh067b92b2020-06-19 15:24:12 +00008915 "SELECT rootpage, 0 FROM sqlite_schema"
drh491c5be2019-10-18 15:58:50 +00008916 " WHERE name='%q' AND type='index'"
8917 "UNION ALL "
drh067b92b2020-06-19 15:24:12 +00008918 "SELECT rootpage, 1 FROM sqlite_schema"
drh491c5be2019-10-18 15:58:50 +00008919 " WHERE name='%q' AND type='table'"
8920 " AND sql LIKE '%%without%%rowid%%'",
8921 azArg[1], azArg[1]
8922 );
drh2ce15c32017-07-11 13:34:40 +00008923 sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
8924 sqlite3_free(zSql);
8925 if( sqlite3_step(pStmt)==SQLITE_ROW ){
8926 tnum = sqlite3_column_int(pStmt, 0);
drh491c5be2019-10-18 15:58:50 +00008927 isWO = sqlite3_column_int(pStmt, 1);
drh2ce15c32017-07-11 13:34:40 +00008928 }
8929 sqlite3_finalize(pStmt);
drh2ce15c32017-07-11 13:34:40 +00008930 zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
8931 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
8932 sqlite3_free(zSql);
8933 i = 0;
drhe85e1da2021-10-01 21:01:07 +00008934 while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
drh2ce15c32017-07-11 13:34:40 +00008935 char zLabel[20];
8936 const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
8937 i++;
8938 if( zCol==0 ){
8939 if( sqlite3_column_int(pStmt,1)==-1 ){
8940 zCol = "_ROWID_";
8941 }else{
8942 sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i);
8943 zCol = zLabel;
8944 }
8945 }
drh491c5be2019-10-18 15:58:50 +00008946 if( isWO && lenPK==0 && sqlite3_column_int(pStmt,5)==0 && zCollist ){
8947 lenPK = (int)strlen(zCollist);
8948 }
drh2ce15c32017-07-11 13:34:40 +00008949 if( zCollist==0 ){
8950 zCollist = sqlite3_mprintf("\"%w\"", zCol);
8951 }else{
8952 zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
8953 }
8954 }
8955 sqlite3_finalize(pStmt);
drh491c5be2019-10-18 15:58:50 +00008956 if( i==0 || tnum==0 ){
8957 utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
8958 rc = 1;
8959 sqlite3_free(zCollist);
8960 goto meta_command_exit;
8961 }
8962 if( lenPK==0 ) lenPK = 100000;
drh2ce15c32017-07-11 13:34:40 +00008963 zSql = sqlite3_mprintf(
drh491c5be2019-10-18 15:58:50 +00008964 "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))WITHOUT ROWID",
8965 azArg[2], zCollist, lenPK, zCollist);
drh2ce15c32017-07-11 13:34:40 +00008966 sqlite3_free(zCollist);
8967 rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
8968 if( rc==SQLITE_OK ){
8969 rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
8970 sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
8971 if( rc ){
8972 utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
8973 }else{
8974 utf8_printf(stdout, "%s;\n", zSql);
8975 raw_printf(stdout,
drh491c5be2019-10-18 15:58:50 +00008976 "WARNING: writing to an imposter table will corrupt the \"%s\" %s!\n",
8977 azArg[1], isWO ? "table" : "index"
drh2ce15c32017-07-11 13:34:40 +00008978 );
8979 }
8980 }else{
8981 raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
8982 rc = 1;
8983 }
8984 sqlite3_free(zSql);
8985 }else
8986#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
8987
8988#ifdef SQLITE_ENABLE_IOTRACE
drhbf70f1b2022-10-19 18:04:42 +00008989 if( c=='i' && cli_strncmp(azArg[0], "iotrace", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00008990 SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
8991 if( iotrace && iotrace!=stdout ) fclose(iotrace);
8992 iotrace = 0;
8993 if( nArg<2 ){
8994 sqlite3IoTrace = 0;
drhbf70f1b2022-10-19 18:04:42 +00008995 }else if( cli_strcmp(azArg[1], "-")==0 ){
drh2ce15c32017-07-11 13:34:40 +00008996 sqlite3IoTrace = iotracePrintf;
8997 iotrace = stdout;
8998 }else{
8999 iotrace = fopen(azArg[1], "w");
9000 if( iotrace==0 ){
9001 utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
9002 sqlite3IoTrace = 0;
9003 rc = 1;
9004 }else{
9005 sqlite3IoTrace = iotracePrintf;
9006 }
9007 }
9008 }else
9009#endif
9010
drhbf70f1b2022-10-19 18:04:42 +00009011 if( c=='l' && n>=5 && cli_strncmp(azArg[0], "limits", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009012 static const struct {
9013 const char *zLimitName; /* Name of a limit */
9014 int limitCode; /* Integer code for that limit */
9015 } aLimit[] = {
9016 { "length", SQLITE_LIMIT_LENGTH },
9017 { "sql_length", SQLITE_LIMIT_SQL_LENGTH },
9018 { "column", SQLITE_LIMIT_COLUMN },
9019 { "expr_depth", SQLITE_LIMIT_EXPR_DEPTH },
9020 { "compound_select", SQLITE_LIMIT_COMPOUND_SELECT },
9021 { "vdbe_op", SQLITE_LIMIT_VDBE_OP },
9022 { "function_arg", SQLITE_LIMIT_FUNCTION_ARG },
9023 { "attached", SQLITE_LIMIT_ATTACHED },
9024 { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH },
9025 { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER },
9026 { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH },
9027 { "worker_threads", SQLITE_LIMIT_WORKER_THREADS },
9028 };
9029 int i, n2;
9030 open_db(p, 0);
9031 if( nArg==1 ){
9032 for(i=0; i<ArraySize(aLimit); i++){
9033 printf("%20s %d\n", aLimit[i].zLimitName,
9034 sqlite3_limit(p->db, aLimit[i].limitCode, -1));
9035 }
9036 }else if( nArg>3 ){
9037 raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
9038 rc = 1;
9039 goto meta_command_exit;
9040 }else{
9041 int iLimit = -1;
9042 n2 = strlen30(azArg[1]);
9043 for(i=0; i<ArraySize(aLimit); i++){
9044 if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
9045 if( iLimit<0 ){
9046 iLimit = i;
9047 }else{
9048 utf8_printf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
9049 rc = 1;
9050 goto meta_command_exit;
9051 }
9052 }
9053 }
9054 if( iLimit<0 ){
9055 utf8_printf(stderr, "unknown limit: \"%s\"\n"
9056 "enter \".limits\" with no arguments for a list.\n",
9057 azArg[1]);
9058 rc = 1;
9059 goto meta_command_exit;
9060 }
9061 if( nArg==3 ){
9062 sqlite3_limit(p->db, aLimit[iLimit].limitCode,
9063 (int)integerValue(azArg[2]));
9064 }
9065 printf("%20s %d\n", aLimit[iLimit].zLimitName,
9066 sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
9067 }
9068 }else
9069
drhbf70f1b2022-10-19 18:04:42 +00009070 if( c=='l' && n>2 && cli_strncmp(azArg[0], "lint", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009071 open_db(p, 0);
9072 lintDotCommand(p, azArg, nArg);
9073 }else
9074
stephan4413ec72022-07-12 15:53:02 +00009075#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_FIDDLE)
drhbf70f1b2022-10-19 18:04:42 +00009076 if( c=='l' && cli_strncmp(azArg[0], "load", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009077 const char *zFile, *zProc;
9078 char *zErrMsg = 0;
drhb97e2ad2021-08-26 18:31:39 +00009079 failIfSafeMode(p, "cannot run .load in safe mode");
drh2ce15c32017-07-11 13:34:40 +00009080 if( nArg<2 ){
9081 raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
9082 rc = 1;
9083 goto meta_command_exit;
9084 }
9085 zFile = azArg[1];
9086 zProc = nArg>=3 ? azArg[2] : 0;
9087 open_db(p, 0);
9088 rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
9089 if( rc!=SQLITE_OK ){
9090 utf8_printf(stderr, "Error: %s\n", zErrMsg);
9091 sqlite3_free(zErrMsg);
9092 rc = 1;
9093 }
9094 }else
9095#endif
9096
stephan4413ec72022-07-12 15:53:02 +00009097#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00009098 if( c=='l' && cli_strncmp(azArg[0], "log", n)==0 ){
drhb97e2ad2021-08-26 18:31:39 +00009099 failIfSafeMode(p, "cannot run .log in safe mode");
drh2ce15c32017-07-11 13:34:40 +00009100 if( nArg!=2 ){
9101 raw_printf(stderr, "Usage: .log FILENAME\n");
9102 rc = 1;
9103 }else{
9104 const char *zFile = azArg[1];
9105 output_file_close(p->pLog);
drha92a01a2018-01-10 22:15:37 +00009106 p->pLog = output_file_open(zFile, 0);
drh2ce15c32017-07-11 13:34:40 +00009107 }
9108 }else
stephan618a3752022-05-19 10:24:50 +00009109#endif
drh2ce15c32017-07-11 13:34:40 +00009110
drhbf70f1b2022-10-19 18:04:42 +00009111 if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
drhe40f2862022-01-31 14:14:29 +00009112 const char *zMode = 0;
9113 const char *zTabname = 0;
9114 int i, n2;
larrybrcc4d55c2022-02-01 02:50:45 +00009115 ColModeOpts cmOpts = ColModeOpts_default;
drhe40f2862022-01-31 14:14:29 +00009116 for(i=1; i<nArg; i++){
9117 const char *z = azArg[i];
9118 if( optionMatch(z,"wrap") && i+1<nArg ){
larrybrcc4d55c2022-02-01 02:50:45 +00009119 cmOpts.iWrap = integerValue(azArg[++i]);
drhca1776b2022-02-01 12:28:17 +00009120 }else if( optionMatch(z,"ww") ){
9121 cmOpts.bWordWrap = 1;
larrybrcc4d55c2022-02-01 02:50:45 +00009122 }else if( optionMatch(z,"wordwrap") && i+1<nArg ){
9123 cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
drhe40f2862022-01-31 14:14:29 +00009124 }else if( optionMatch(z,"quote") ){
larrybrcc4d55c2022-02-01 02:50:45 +00009125 cmOpts.bQuote = 1;
drhe40f2862022-01-31 14:14:29 +00009126 }else if( optionMatch(z,"noquote") ){
larrybrcc4d55c2022-02-01 02:50:45 +00009127 cmOpts.bQuote = 0;
drhe40f2862022-01-31 14:14:29 +00009128 }else if( zMode==0 ){
9129 zMode = z;
drh1f41a8c2022-10-24 11:10:40 +00009130 /* Apply defaults for qbox pseudo-mode. If that
larrybrcc4d55c2022-02-01 02:50:45 +00009131 * overwrites already-set values, user was informed of this.
9132 */
drhbf70f1b2022-10-19 18:04:42 +00009133 if( cli_strcmp(z, "qbox")==0 ){
larrybrcc4d55c2022-02-01 02:50:45 +00009134 ColModeOpts cmo = ColModeOpts_default_qbox;
9135 zMode = "box";
9136 cmOpts = cmo;
larrybrcc4d55c2022-02-01 02:50:45 +00009137 }
drhe40f2862022-01-31 14:14:29 +00009138 }else if( zTabname==0 ){
9139 zTabname = z;
9140 }else if( z[0]=='-' ){
9141 utf8_printf(stderr, "unknown option: %s\n", z);
9142 utf8_printf(stderr, "options:\n"
9143 " --noquote\n"
9144 " --quote\n"
larrybrcc4d55c2022-02-01 02:50:45 +00009145 " --wordwrap on/off\n"
drhca1776b2022-02-01 12:28:17 +00009146 " --wrap N\n"
9147 " --ww\n");
drhe40f2862022-01-31 14:14:29 +00009148 rc = 1;
9149 goto meta_command_exit;
9150 }else{
9151 utf8_printf(stderr, "extra argument: \"%s\"\n", z);
9152 rc = 1;
9153 goto meta_command_exit;
9154 }
9155 }
9156 if( zMode==0 ){
9157 if( p->mode==MODE_Column
9158 || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
9159 ){
larrybrcc4d55c2022-02-01 02:50:45 +00009160 raw_printf
9161 (p->out,
9162 "current output mode: %s --wrap %d --wordwrap %s --%squote\n",
9163 modeDescr[p->mode], p->cmOpts.iWrap,
9164 p->cmOpts.bWordWrap ? "on" : "off",
9165 p->cmOpts.bQuote ? "" : "no");
drhe40f2862022-01-31 14:14:29 +00009166 }else{
9167 raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
9168 }
drhe40f2862022-01-31 14:14:29 +00009169 zMode = modeDescr[p->mode];
9170 }
9171 n2 = strlen30(zMode);
drhbf70f1b2022-10-19 18:04:42 +00009172 if( cli_strncmp(zMode,"lines",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009173 p->mode = MODE_Line;
9174 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +00009175 }else if( cli_strncmp(zMode,"columns",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009176 p->mode = MODE_Column;
drhc0605082020-06-05 00:54:27 +00009177 if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
9178 p->showHeader = 1;
9179 }
drh2ce15c32017-07-11 13:34:40 +00009180 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
larrybrcc4d55c2022-02-01 02:50:45 +00009181 p->cmOpts = cmOpts;
drhbf70f1b2022-10-19 18:04:42 +00009182 }else if( cli_strncmp(zMode,"list",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009183 p->mode = MODE_List;
9184 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
9185 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +00009186 }else if( cli_strncmp(zMode,"html",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009187 p->mode = MODE_Html;
drhbf70f1b2022-10-19 18:04:42 +00009188 }else if( cli_strncmp(zMode,"tcl",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009189 p->mode = MODE_Tcl;
9190 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
9191 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +00009192 }else if( cli_strncmp(zMode,"csv",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009193 p->mode = MODE_Csv;
9194 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
9195 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
drhbf70f1b2022-10-19 18:04:42 +00009196 }else if( cli_strncmp(zMode,"tabs",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009197 p->mode = MODE_List;
9198 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
drhbf70f1b2022-10-19 18:04:42 +00009199 }else if( cli_strncmp(zMode,"insert",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009200 p->mode = MODE_Insert;
drhe40f2862022-01-31 14:14:29 +00009201 set_table_name(p, zTabname ? zTabname : "table");
drhbf70f1b2022-10-19 18:04:42 +00009202 }else if( cli_strncmp(zMode,"quote",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009203 p->mode = MODE_Quote;
drhc6835732020-05-28 20:37:17 +00009204 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
9205 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +00009206 }else if( cli_strncmp(zMode,"ascii",n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009207 p->mode = MODE_Ascii;
9208 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
9209 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
drhbf70f1b2022-10-19 18:04:42 +00009210 }else if( cli_strncmp(zMode,"markdown",n2)==0 ){
drh30c54a02020-05-28 23:49:50 +00009211 p->mode = MODE_Markdown;
larrybrcc4d55c2022-02-01 02:50:45 +00009212 p->cmOpts = cmOpts;
drhbf70f1b2022-10-19 18:04:42 +00009213 }else if( cli_strncmp(zMode,"table",n2)==0 ){
drh30c54a02020-05-28 23:49:50 +00009214 p->mode = MODE_Table;
larrybrcc4d55c2022-02-01 02:50:45 +00009215 p->cmOpts = cmOpts;
drhbf70f1b2022-10-19 18:04:42 +00009216 }else if( cli_strncmp(zMode,"box",n2)==0 ){
drh0908e382020-06-04 18:05:39 +00009217 p->mode = MODE_Box;
larrybrcc4d55c2022-02-01 02:50:45 +00009218 p->cmOpts = cmOpts;
drhbf70f1b2022-10-19 18:04:42 +00009219 }else if( cli_strncmp(zMode,"count",n2)==0 ){
drh5d88be82021-12-09 16:17:43 +00009220 p->mode = MODE_Count;
drhbf70f1b2022-10-19 18:04:42 +00009221 }else if( cli_strncmp(zMode,"off",n2)==0 ){
drh5d88be82021-12-09 16:17:43 +00009222 p->mode = MODE_Off;
drhbf70f1b2022-10-19 18:04:42 +00009223 }else if( cli_strncmp(zMode,"json",n2)==0 ){
drh30c54a02020-05-28 23:49:50 +00009224 p->mode = MODE_Json;
drh2ce15c32017-07-11 13:34:40 +00009225 }else{
9226 raw_printf(stderr, "Error: mode should be one of: "
drh0908e382020-06-04 18:05:39 +00009227 "ascii box column csv html insert json line list markdown "
drhca1776b2022-02-01 12:28:17 +00009228 "qbox quote table tabs tcl\n");
drh2ce15c32017-07-11 13:34:40 +00009229 rc = 1;
9230 }
9231 p->cMode = p->mode;
9232 }else
9233
stephan4413ec72022-07-12 15:53:02 +00009234#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00009235 if( c=='n' && cli_strcmp(azArg[0], "nonce")==0 ){
drhb97e2ad2021-08-26 18:31:39 +00009236 if( nArg!=2 ){
9237 raw_printf(stderr, "Usage: .nonce NONCE\n");
9238 rc = 1;
drhbf70f1b2022-10-19 18:04:42 +00009239 }else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){
drhfe463172021-12-16 17:57:21 +00009240 raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n",
9241 p->lineno, azArg[1]);
drhb97e2ad2021-08-26 18:31:39 +00009242 exit(1);
drhe85e1da2021-10-01 21:01:07 +00009243 }else{
9244 p->bSafeMode = 0;
9245 return 0; /* Return immediately to bypass the safe mode reset
9246 ** at the end of this procedure */
drhb97e2ad2021-08-26 18:31:39 +00009247 }
drhb97e2ad2021-08-26 18:31:39 +00009248 }else
stephan4413ec72022-07-12 15:53:02 +00009249#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drhb97e2ad2021-08-26 18:31:39 +00009250
drhbf70f1b2022-10-19 18:04:42 +00009251 if( c=='n' && cli_strncmp(azArg[0], "nullvalue", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009252 if( nArg==2 ){
9253 sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
9254 "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
9255 }else{
9256 raw_printf(stderr, "Usage: .nullvalue STRING\n");
9257 rc = 1;
9258 }
9259 }else
9260
drhbf70f1b2022-10-19 18:04:42 +00009261 if( c=='o' && cli_strncmp(azArg[0], "open", n)==0 && n>=2 ){
drh61fd4b92021-12-16 14:59:25 +00009262 const char *zFN = 0; /* Pointer to constant filename */
drhf30bbce2020-12-02 18:27:48 +00009263 char *zNewFilename = 0; /* Name of the database file to open */
9264 int iName = 1; /* Index in azArg[] of the filename */
9265 int newFlag = 0; /* True to delete file before opening */
dan1872c5b2021-12-02 14:16:30 +00009266 int openMode = SHELL_OPEN_UNSPEC;
9267
drh2ce15c32017-07-11 13:34:40 +00009268 /* Check for command-line arguments */
drhf30bbce2020-12-02 18:27:48 +00009269 for(iName=1; iName<nArg; iName++){
drh2ce15c32017-07-11 13:34:40 +00009270 const char *z = azArg[iName];
stephan4413ec72022-07-12 15:53:02 +00009271#ifndef SQLITE_SHELL_FIDDLE
drh2ce15c32017-07-11 13:34:40 +00009272 if( optionMatch(z,"new") ){
9273 newFlag = 1;
drh3baed312018-03-08 18:14:41 +00009274#ifdef SQLITE_HAVE_ZLIB
drh1fa6d9f2018-01-06 21:46:01 +00009275 }else if( optionMatch(z, "zip") ){
dan1872c5b2021-12-02 14:16:30 +00009276 openMode = SHELL_OPEN_ZIPFILE;
drh1fa6d9f2018-01-06 21:46:01 +00009277#endif
9278 }else if( optionMatch(z, "append") ){
dan1872c5b2021-12-02 14:16:30 +00009279 openMode = SHELL_OPEN_APPENDVFS;
drhee269a62018-02-14 23:27:43 +00009280 }else if( optionMatch(z, "readonly") ){
dan1872c5b2021-12-02 14:16:30 +00009281 openMode = SHELL_OPEN_READONLY;
drh0933aad2019-11-18 17:46:38 +00009282 }else if( optionMatch(z, "nofollow") ){
9283 p->openFlags |= SQLITE_OPEN_NOFOLLOW;
drh8d889af2021-05-08 17:18:23 +00009284#ifndef SQLITE_OMIT_DESERIALIZE
drh60f34ae2018-10-30 13:19:49 +00009285 }else if( optionMatch(z, "deserialize") ){
dan1872c5b2021-12-02 14:16:30 +00009286 openMode = SHELL_OPEN_DESERIALIZE;
drh33746482018-12-13 15:06:26 +00009287 }else if( optionMatch(z, "hexdb") ){
dan1872c5b2021-12-02 14:16:30 +00009288 openMode = SHELL_OPEN_HEXDB;
drh6ca64482019-01-22 16:06:20 +00009289 }else if( optionMatch(z, "maxsize") && iName+1<nArg ){
9290 p->szMax = integerValue(azArg[++iName]);
drh8d889af2021-05-08 17:18:23 +00009291#endif /* SQLITE_OMIT_DESERIALIZE */
stephande1e02e2022-05-24 19:01:21 +00009292 }else
stephan4413ec72022-07-12 15:53:02 +00009293#endif /* !SQLITE_SHELL_FIDDLE */
stephande1e02e2022-05-24 19:01:21 +00009294 if( z[0]=='-' ){
drh2ce15c32017-07-11 13:34:40 +00009295 utf8_printf(stderr, "unknown option: %s\n", z);
9296 rc = 1;
9297 goto meta_command_exit;
drh61fd4b92021-12-16 14:59:25 +00009298 }else if( zFN ){
drhf30bbce2020-12-02 18:27:48 +00009299 utf8_printf(stderr, "extra argument: \"%s\"\n", z);
9300 rc = 1;
9301 goto meta_command_exit;
9302 }else{
drh61fd4b92021-12-16 14:59:25 +00009303 zFN = z;
drh2ce15c32017-07-11 13:34:40 +00009304 }
9305 }
dan1872c5b2021-12-02 14:16:30 +00009306
9307 /* Close the existing database */
9308 session_close_all(p, -1);
9309 close_db(p->db);
9310 p->db = 0;
9311 p->pAuxDb->zDbFilename = 0;
9312 sqlite3_free(p->pAuxDb->zFreeOnClose);
9313 p->pAuxDb->zFreeOnClose = 0;
9314 p->openMode = openMode;
9315 p->openFlags = 0;
9316 p->szMax = 0;
9317
drh2ce15c32017-07-11 13:34:40 +00009318 /* If a filename is specified, try to open it first */
drh61fd4b92021-12-16 14:59:25 +00009319 if( zFN || p->openMode==SHELL_OPEN_HEXDB ){
drhc320e062021-12-24 19:44:11 +00009320 if( newFlag && zFN && !p->bSafeMode ) shellDeleteFile(zFN);
stephan4413ec72022-07-12 15:53:02 +00009321#ifndef SQLITE_SHELL_FIDDLE
drhb97e2ad2021-08-26 18:31:39 +00009322 if( p->bSafeMode
9323 && p->openMode!=SHELL_OPEN_HEXDB
drhc320e062021-12-24 19:44:11 +00009324 && zFN
drhbf70f1b2022-10-19 18:04:42 +00009325 && cli_strcmp(zFN,":memory:")!=0
drhb97e2ad2021-08-26 18:31:39 +00009326 ){
9327 failIfSafeMode(p, "cannot open disk-based database files in safe mode");
9328 }
stephande1e02e2022-05-24 19:01:21 +00009329#else
9330 /* WASM mode has its own sandboxed pseudo-filesystem. */
9331#endif
drh61fd4b92021-12-16 14:59:25 +00009332 if( zFN ){
9333 zNewFilename = sqlite3_mprintf("%s", zFN);
9334 shell_check_oom(zNewFilename);
9335 }else{
9336 zNewFilename = 0;
9337 }
drh37407122021-07-23 18:43:58 +00009338 p->pAuxDb->zDbFilename = zNewFilename;
drhbe4ccb22018-05-17 20:04:24 +00009339 open_db(p, OPEN_DB_KEEPALIVE);
drh2ce15c32017-07-11 13:34:40 +00009340 if( p->db==0 ){
9341 utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename);
9342 sqlite3_free(zNewFilename);
9343 }else{
drh37407122021-07-23 18:43:58 +00009344 p->pAuxDb->zFreeOnClose = zNewFilename;
drh2ce15c32017-07-11 13:34:40 +00009345 }
9346 }
9347 if( p->db==0 ){
9348 /* As a fall-back open a TEMP database */
drh37407122021-07-23 18:43:58 +00009349 p->pAuxDb->zDbFilename = 0;
drh2ce15c32017-07-11 13:34:40 +00009350 open_db(p, 0);
9351 }
9352 }else
9353
stephan4413ec72022-07-12 15:53:02 +00009354#ifndef SQLITE_SHELL_FIDDLE
drh13c20932018-01-10 21:41:55 +00009355 if( (c=='o'
drhbf70f1b2022-10-19 18:04:42 +00009356 && (cli_strncmp(azArg[0], "output", n)==0
9357 || cli_strncmp(azArg[0], "once", n)==0))
9358 || (c=='e' && n==5 && cli_strcmp(azArg[0],"excel")==0)
drh2ce15c32017-07-11 13:34:40 +00009359 ){
drh4b0229a2021-02-17 13:19:22 +00009360 char *zFile = 0;
drha92a01a2018-01-10 22:15:37 +00009361 int bTxtMode = 0;
drh7a431002020-04-18 14:12:00 +00009362 int i;
9363 int eMode = 0;
drh8ad3c432022-03-23 10:04:52 +00009364 int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
9365 unsigned char zBOM[4]; /* Byte-order mark to using if --bom is present */
drh7a431002020-04-18 14:12:00 +00009366
drh8ad3c432022-03-23 10:04:52 +00009367 zBOM[0] = 0;
drhb97e2ad2021-08-26 18:31:39 +00009368 failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
drh7a431002020-04-18 14:12:00 +00009369 if( c=='e' ){
9370 eMode = 'x';
9371 bOnce = 2;
drhbf70f1b2022-10-19 18:04:42 +00009372 }else if( cli_strncmp(azArg[0],"once",n)==0 ){
drh7a431002020-04-18 14:12:00 +00009373 bOnce = 1;
drh13c20932018-01-10 21:41:55 +00009374 }
drh7a431002020-04-18 14:12:00 +00009375 for(i=1; i<nArg; i++){
9376 char *z = azArg[i];
9377 if( z[0]=='-' ){
9378 if( z[1]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +00009379 if( cli_strcmp(z,"-bom")==0 ){
drh8ad3c432022-03-23 10:04:52 +00009380 zBOM[0] = 0xef;
9381 zBOM[1] = 0xbb;
9382 zBOM[2] = 0xbf;
9383 zBOM[3] = 0;
drhbf70f1b2022-10-19 18:04:42 +00009384 }else if( c!='e' && cli_strcmp(z,"-x")==0 ){
drh7a431002020-04-18 14:12:00 +00009385 eMode = 'x'; /* spreadsheet */
drhbf70f1b2022-10-19 18:04:42 +00009386 }else if( c!='e' && cli_strcmp(z,"-e")==0 ){
drh7a431002020-04-18 14:12:00 +00009387 eMode = 'e'; /* text editor */
9388 }else{
9389 utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n",
9390 azArg[i]);
9391 showHelp(p->out, azArg[0]);
9392 rc = 1;
9393 goto meta_command_exit;
9394 }
drh4b0229a2021-02-17 13:19:22 +00009395 }else if( zFile==0 && eMode!='e' && eMode!='x' ){
9396 zFile = sqlite3_mprintf("%s", z);
drhe3e25652021-12-16 13:29:28 +00009397 if( zFile && zFile[0]=='|' ){
drh4b0229a2021-02-17 13:19:22 +00009398 while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]);
9399 break;
9400 }
drh7a431002020-04-18 14:12:00 +00009401 }else{
9402 utf8_printf(p->out,"ERROR: extra parameter: \"%s\". Usage:\n",
9403 azArg[i]);
9404 showHelp(p->out, azArg[0]);
drh2ce15c32017-07-11 13:34:40 +00009405 rc = 1;
drh4b0229a2021-02-17 13:19:22 +00009406 sqlite3_free(zFile);
drh2ce15c32017-07-11 13:34:40 +00009407 goto meta_command_exit;
9408 }
drh7a431002020-04-18 14:12:00 +00009409 }
drhe3e25652021-12-16 13:29:28 +00009410 if( zFile==0 ){
9411 zFile = sqlite3_mprintf("stdout");
9412 }
drh7a431002020-04-18 14:12:00 +00009413 if( bOnce ){
drh2ce15c32017-07-11 13:34:40 +00009414 p->outCount = 2;
9415 }else{
9416 p->outCount = 0;
9417 }
9418 output_reset(p);
drh04a28c32018-01-31 01:38:44 +00009419#ifndef SQLITE_NOHAVE_SYSTEM
drh7a431002020-04-18 14:12:00 +00009420 if( eMode=='e' || eMode=='x' ){
drh3c484e82018-01-10 22:27:21 +00009421 p->doXdgOpen = 1;
9422 outputModePush(p);
drh7a431002020-04-18 14:12:00 +00009423 if( eMode=='x' ){
9424 /* spreadsheet mode. Output as CSV. */
drh13c20932018-01-10 21:41:55 +00009425 newTempFile(p, "csv");
drh7a431002020-04-18 14:12:00 +00009426 ShellClearFlag(p, SHFLG_Echo);
drh13c20932018-01-10 21:41:55 +00009427 p->mode = MODE_Csv;
9428 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
9429 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
9430 }else{
drh7a431002020-04-18 14:12:00 +00009431 /* text editor mode */
drh13c20932018-01-10 21:41:55 +00009432 newTempFile(p, "txt");
drha92a01a2018-01-10 22:15:37 +00009433 bTxtMode = 1;
drh13c20932018-01-10 21:41:55 +00009434 }
drh4b0229a2021-02-17 13:19:22 +00009435 sqlite3_free(zFile);
9436 zFile = sqlite3_mprintf("%s", p->zTempFile);
drh13c20932018-01-10 21:41:55 +00009437 }
drh04a28c32018-01-31 01:38:44 +00009438#endif /* SQLITE_NOHAVE_SYSTEM */
drhe3e25652021-12-16 13:29:28 +00009439 shell_check_oom(zFile);
drh2ce15c32017-07-11 13:34:40 +00009440 if( zFile[0]=='|' ){
9441#ifdef SQLITE_OMIT_POPEN
9442 raw_printf(stderr, "Error: pipes are not supported in this OS\n");
9443 rc = 1;
9444 p->out = stdout;
9445#else
9446 p->out = popen(zFile + 1, "w");
9447 if( p->out==0 ){
9448 utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
9449 p->out = stdout;
9450 rc = 1;
9451 }else{
drh8ad3c432022-03-23 10:04:52 +00009452 if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
drh2ce15c32017-07-11 13:34:40 +00009453 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
9454 }
9455#endif
9456 }else{
drha92a01a2018-01-10 22:15:37 +00009457 p->out = output_file_open(zFile, bTxtMode);
drh2ce15c32017-07-11 13:34:40 +00009458 if( p->out==0 ){
drhbf70f1b2022-10-19 18:04:42 +00009459 if( cli_strcmp(zFile,"off")!=0 ){
drh2ce15c32017-07-11 13:34:40 +00009460 utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
9461 }
9462 p->out = stdout;
9463 rc = 1;
9464 } else {
drh8ad3c432022-03-23 10:04:52 +00009465 if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
drh2ce15c32017-07-11 13:34:40 +00009466 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
9467 }
9468 }
drh4b0229a2021-02-17 13:19:22 +00009469 sqlite3_free(zFile);
drh2ce15c32017-07-11 13:34:40 +00009470 }else
stephan4413ec72022-07-12 15:53:02 +00009471#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00009472
drhbf70f1b2022-10-19 18:04:42 +00009473 if( c=='p' && n>=3 && cli_strncmp(azArg[0], "parameter", n)==0 ){
drh9cb02642019-02-28 20:10:52 +00009474 open_db(p,0);
9475 if( nArg<=1 ) goto parameter_syntax_error;
9476
9477 /* .parameter clear
9478 ** Clear all bind parameters by dropping the TEMP table that holds them.
9479 */
drhbf70f1b2022-10-19 18:04:42 +00009480 if( nArg==2 && cli_strcmp(azArg[1],"clear")==0 ){
drh65c29fd2019-03-25 21:56:26 +00009481 sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;",
drh9cb02642019-02-28 20:10:52 +00009482 0, 0, 0);
9483 }else
9484
9485 /* .parameter list
9486 ** List all bind parameters.
9487 */
drhbf70f1b2022-10-19 18:04:42 +00009488 if( nArg==2 && cli_strcmp(azArg[1],"list")==0 ){
drh9cb02642019-02-28 20:10:52 +00009489 sqlite3_stmt *pStmt = 0;
9490 int rx;
9491 int len = 0;
9492 rx = sqlite3_prepare_v2(p->db,
9493 "SELECT max(length(key)) "
drh65c29fd2019-03-25 21:56:26 +00009494 "FROM temp.sqlite_parameters;", -1, &pStmt, 0);
drh9cb02642019-02-28 20:10:52 +00009495 if( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
9496 len = sqlite3_column_int(pStmt, 0);
9497 if( len>40 ) len = 40;
9498 }
9499 sqlite3_finalize(pStmt);
9500 pStmt = 0;
9501 if( len ){
9502 rx = sqlite3_prepare_v2(p->db,
9503 "SELECT key, quote(value) "
drh65c29fd2019-03-25 21:56:26 +00009504 "FROM temp.sqlite_parameters;", -1, &pStmt, 0);
drhe85e1da2021-10-01 21:01:07 +00009505 while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
drh9cb02642019-02-28 20:10:52 +00009506 utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
9507 sqlite3_column_text(pStmt,1));
9508 }
9509 sqlite3_finalize(pStmt);
9510 }
9511 }else
9512
9513 /* .parameter init
9514 ** Make sure the TEMP table used to hold bind parameters exists.
9515 ** Create it if necessary.
9516 */
drhbf70f1b2022-10-19 18:04:42 +00009517 if( nArg==2 && cli_strcmp(azArg[1],"init")==0 ){
drh9cb02642019-02-28 20:10:52 +00009518 bind_table_init(p);
9519 }else
9520
9521 /* .parameter set NAME VALUE
9522 ** Set or reset a bind parameter. NAME should be the full parameter
9523 ** name exactly as it appears in the query. (ex: $abc, @def). The
9524 ** VALUE can be in either SQL literal notation, or if not it will be
9525 ** understood to be a text string.
9526 */
drhbf70f1b2022-10-19 18:04:42 +00009527 if( nArg==4 && cli_strcmp(azArg[1],"set")==0 ){
drh9cb02642019-02-28 20:10:52 +00009528 int rx;
9529 char *zSql;
9530 sqlite3_stmt *pStmt;
9531 const char *zKey = azArg[2];
9532 const char *zValue = azArg[3];
9533 bind_table_init(p);
9534 zSql = sqlite3_mprintf(
drh65c29fd2019-03-25 21:56:26 +00009535 "REPLACE INTO temp.sqlite_parameters(key,value)"
drh9cb02642019-02-28 20:10:52 +00009536 "VALUES(%Q,%s);", zKey, zValue);
drhe3e25652021-12-16 13:29:28 +00009537 shell_check_oom(zSql);
drh9cb02642019-02-28 20:10:52 +00009538 pStmt = 0;
9539 rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
9540 sqlite3_free(zSql);
9541 if( rx!=SQLITE_OK ){
9542 sqlite3_finalize(pStmt);
9543 pStmt = 0;
9544 zSql = sqlite3_mprintf(
drh65c29fd2019-03-25 21:56:26 +00009545 "REPLACE INTO temp.sqlite_parameters(key,value)"
drh9cb02642019-02-28 20:10:52 +00009546 "VALUES(%Q,%Q);", zKey, zValue);
drhe3e25652021-12-16 13:29:28 +00009547 shell_check_oom(zSql);
drh9cb02642019-02-28 20:10:52 +00009548 rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
9549 sqlite3_free(zSql);
9550 if( rx!=SQLITE_OK ){
9551 utf8_printf(p->out, "Error: %s\n", sqlite3_errmsg(p->db));
9552 sqlite3_finalize(pStmt);
9553 pStmt = 0;
9554 rc = 1;
9555 }
9556 }
9557 sqlite3_step(pStmt);
9558 sqlite3_finalize(pStmt);
9559 }else
9560
9561 /* .parameter unset NAME
9562 ** Remove the NAME binding from the parameter binding table, if it
9563 ** exists.
9564 */
drhbf70f1b2022-10-19 18:04:42 +00009565 if( nArg==3 && cli_strcmp(azArg[1],"unset")==0 ){
drh9cb02642019-02-28 20:10:52 +00009566 char *zSql = sqlite3_mprintf(
drh65c29fd2019-03-25 21:56:26 +00009567 "DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]);
drhe3e25652021-12-16 13:29:28 +00009568 shell_check_oom(zSql);
drh9cb02642019-02-28 20:10:52 +00009569 sqlite3_exec(p->db, zSql, 0, 0, 0);
9570 sqlite3_free(zSql);
9571 }else
9572 /* If no command name matches, show a syntax error */
9573 parameter_syntax_error:
9574 showHelp(p->out, "parameter");
9575 }else
9576
drhbf70f1b2022-10-19 18:04:42 +00009577 if( c=='p' && n>=3 && cli_strncmp(azArg[0], "print", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009578 int i;
9579 for(i=1; i<nArg; i++){
9580 if( i>1 ) raw_printf(p->out, " ");
9581 utf8_printf(p->out, "%s", azArg[i]);
9582 }
9583 raw_printf(p->out, "\n");
9584 }else
9585
drh569b1d92019-02-05 20:51:41 +00009586#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
drhbf70f1b2022-10-19 18:04:42 +00009587 if( c=='p' && n>=3 && cli_strncmp(azArg[0], "progress", n)==0 ){
drh3f83f592019-02-04 14:53:18 +00009588 int i;
drhfc4eeef2019-02-05 19:48:46 +00009589 int nn = 0;
drh3f83f592019-02-04 14:53:18 +00009590 p->flgProgress = 0;
9591 p->mxProgress = 0;
9592 p->nProgress = 0;
9593 for(i=1; i<nArg; i++){
9594 const char *z = azArg[i];
9595 if( z[0]=='-' ){
9596 z++;
9597 if( z[0]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +00009598 if( cli_strcmp(z,"quiet")==0 || cli_strcmp(z,"q")==0 ){
drhfc4eeef2019-02-05 19:48:46 +00009599 p->flgProgress |= SHELL_PROGRESS_QUIET;
drh3f83f592019-02-04 14:53:18 +00009600 continue;
9601 }
drhbf70f1b2022-10-19 18:04:42 +00009602 if( cli_strcmp(z,"reset")==0 ){
drhfc4eeef2019-02-05 19:48:46 +00009603 p->flgProgress |= SHELL_PROGRESS_RESET;
drh3f83f592019-02-04 14:53:18 +00009604 continue;
9605 }
drhbf70f1b2022-10-19 18:04:42 +00009606 if( cli_strcmp(z,"once")==0 ){
drhfc4eeef2019-02-05 19:48:46 +00009607 p->flgProgress |= SHELL_PROGRESS_ONCE;
drh3f83f592019-02-04 14:53:18 +00009608 continue;
9609 }
drhbf70f1b2022-10-19 18:04:42 +00009610 if( cli_strcmp(z,"limit")==0 ){
drh3f83f592019-02-04 14:53:18 +00009611 if( i+1>=nArg ){
9612 utf8_printf(stderr, "Error: missing argument on --limit\n");
9613 rc = 1;
9614 goto meta_command_exit;
9615 }else{
9616 p->mxProgress = (int)integerValue(azArg[++i]);
9617 }
9618 continue;
9619 }
9620 utf8_printf(stderr, "Error: unknown option: \"%s\"\n", azArg[i]);
9621 rc = 1;
9622 goto meta_command_exit;
9623 }else{
drhfc4eeef2019-02-05 19:48:46 +00009624 nn = (int)integerValue(z);
drh3f83f592019-02-04 14:53:18 +00009625 }
9626 }
9627 open_db(p, 0);
drhfc4eeef2019-02-05 19:48:46 +00009628 sqlite3_progress_handler(p->db, nn, progress_handler, p);
drh3f83f592019-02-04 14:53:18 +00009629 }else
drh569b1d92019-02-05 20:51:41 +00009630#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
drh3f83f592019-02-04 14:53:18 +00009631
drhbf70f1b2022-10-19 18:04:42 +00009632 if( c=='p' && cli_strncmp(azArg[0], "prompt", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009633 if( nArg >= 2) {
9634 strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
9635 }
9636 if( nArg >= 3) {
9637 strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
9638 }
9639 }else
9640
stephan4413ec72022-07-12 15:53:02 +00009641#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00009642 if( c=='q' && cli_strncmp(azArg[0], "quit", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009643 rc = 2;
9644 }else
stephan02520cc2022-05-18 22:58:34 +00009645#endif
drh2ce15c32017-07-11 13:34:40 +00009646
stephan4413ec72022-07-12 15:53:02 +00009647#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00009648 if( c=='r' && n>=3 && cli_strncmp(azArg[0], "read", n)==0 ){
drh60379d42018-12-13 18:30:01 +00009649 FILE *inSaved = p->in;
drh2c8ee022018-12-13 18:59:30 +00009650 int savedLineno = p->lineno;
drhb97e2ad2021-08-26 18:31:39 +00009651 failIfSafeMode(p, "cannot run .read in safe mode");
drh2ce15c32017-07-11 13:34:40 +00009652 if( nArg!=2 ){
9653 raw_printf(stderr, "Usage: .read FILE\n");
9654 rc = 1;
9655 goto meta_command_exit;
9656 }
drh30497f42020-08-26 10:50:48 +00009657 if( azArg[1][0]=='|' ){
drh9d59e3b2021-03-12 01:49:08 +00009658#ifdef SQLITE_OMIT_POPEN
9659 raw_printf(stderr, "Error: pipes are not supported in this OS\n");
9660 rc = 1;
9661 p->out = stdout;
9662#else
drh30497f42020-08-26 10:50:48 +00009663 p->in = popen(azArg[1]+1, "r");
9664 if( p->in==0 ){
9665 utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
9666 rc = 1;
9667 }else{
9668 rc = process_input(p);
9669 pclose(p->in);
9670 }
drh9d59e3b2021-03-12 01:49:08 +00009671#endif
larrybrd96bcc72021-09-17 21:12:47 +00009672 }else if( (p->in = openChrSource(azArg[1]))==0 ){
drh2ce15c32017-07-11 13:34:40 +00009673 utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
9674 rc = 1;
9675 }else{
drh60379d42018-12-13 18:30:01 +00009676 rc = process_input(p);
9677 fclose(p->in);
drh2ce15c32017-07-11 13:34:40 +00009678 }
drh60379d42018-12-13 18:30:01 +00009679 p->in = inSaved;
drh2c8ee022018-12-13 18:59:30 +00009680 p->lineno = savedLineno;
drh2ce15c32017-07-11 13:34:40 +00009681 }else
stephan4413ec72022-07-12 15:53:02 +00009682#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00009683
stephan4413ec72022-07-12 15:53:02 +00009684#ifndef SQLITE_SHELL_FIDDLE
drhbf70f1b2022-10-19 18:04:42 +00009685 if( c=='r' && n>=3 && cli_strncmp(azArg[0], "restore", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009686 const char *zSrcFile;
9687 const char *zDb;
9688 sqlite3 *pSrc;
9689 sqlite3_backup *pBackup;
9690 int nTimeout = 0;
9691
drhb97e2ad2021-08-26 18:31:39 +00009692 failIfSafeMode(p, "cannot run .restore in safe mode");
drh2ce15c32017-07-11 13:34:40 +00009693 if( nArg==2 ){
9694 zSrcFile = azArg[1];
9695 zDb = "main";
9696 }else if( nArg==3 ){
9697 zSrcFile = azArg[2];
9698 zDb = azArg[1];
9699 }else{
9700 raw_printf(stderr, "Usage: .restore ?DB? FILE\n");
9701 rc = 1;
9702 goto meta_command_exit;
9703 }
9704 rc = sqlite3_open(zSrcFile, &pSrc);
9705 if( rc!=SQLITE_OK ){
9706 utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
drh9e804032018-05-18 17:11:50 +00009707 close_db(pSrc);
drh2ce15c32017-07-11 13:34:40 +00009708 return 1;
9709 }
9710 open_db(p, 0);
9711 pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
9712 if( pBackup==0 ){
9713 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
drh9e804032018-05-18 17:11:50 +00009714 close_db(pSrc);
drh2ce15c32017-07-11 13:34:40 +00009715 return 1;
9716 }
9717 while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
9718 || rc==SQLITE_BUSY ){
9719 if( rc==SQLITE_BUSY ){
9720 if( nTimeout++ >= 3 ) break;
9721 sqlite3_sleep(100);
9722 }
9723 }
9724 sqlite3_backup_finish(pBackup);
9725 if( rc==SQLITE_DONE ){
9726 rc = 0;
9727 }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
9728 raw_printf(stderr, "Error: source database is busy\n");
9729 rc = 1;
9730 }else{
9731 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
9732 rc = 1;
9733 }
drh9e804032018-05-18 17:11:50 +00009734 close_db(pSrc);
drh2ce15c32017-07-11 13:34:40 +00009735 }else
stephan4413ec72022-07-12 15:53:02 +00009736#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +00009737
drhbf70f1b2022-10-19 18:04:42 +00009738 if( c=='s' && cli_strncmp(azArg[0], "scanstats", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009739 if( nArg==2 ){
dan2797ac02022-12-08 21:05:33 +00009740 if( cli_strcmp(azArg[1], "est")==0 ){
9741 p->scanstatsOn = 2;
9742 }else{
9743 p->scanstatsOn = (u8)booleanValue(azArg[1]);
9744 }
drh2ce15c32017-07-11 13:34:40 +00009745#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
9746 raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
9747#endif
9748 }else{
dan2797ac02022-12-08 21:05:33 +00009749 raw_printf(stderr, "Usage: .scanstats on|off|est\n");
drh2ce15c32017-07-11 13:34:40 +00009750 rc = 1;
9751 }
9752 }else
9753
drhbf70f1b2022-10-19 18:04:42 +00009754 if( c=='s' && cli_strncmp(azArg[0], "schema", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +00009755 ShellText sSelect;
9756 ShellState data;
9757 char *zErrMsg = 0;
drh667a2a22018-01-02 00:04:37 +00009758 const char *zDiv = "(";
drhceba7922018-01-01 21:28:25 +00009759 const char *zName = 0;
drh2ce15c32017-07-11 13:34:40 +00009760 int iSchema = 0;
drhceba7922018-01-01 21:28:25 +00009761 int bDebug = 0;
drhbbb29ec2020-10-12 14:56:47 +00009762 int bNoSystemTabs = 0;
drhceba7922018-01-01 21:28:25 +00009763 int ii;
drh2ce15c32017-07-11 13:34:40 +00009764
9765 open_db(p, 0);
9766 memcpy(&data, p, sizeof(data));
9767 data.showHeader = 0;
9768 data.cMode = data.mode = MODE_Semi;
9769 initText(&sSelect);
drhceba7922018-01-01 21:28:25 +00009770 for(ii=1; ii<nArg; ii++){
9771 if( optionMatch(azArg[ii],"indent") ){
9772 data.cMode = data.mode = MODE_Pretty;
9773 }else if( optionMatch(azArg[ii],"debug") ){
9774 bDebug = 1;
drhbbb29ec2020-10-12 14:56:47 +00009775 }else if( optionMatch(azArg[ii],"nosys") ){
9776 bNoSystemTabs = 1;
9777 }else if( azArg[ii][0]=='-' ){
9778 utf8_printf(stderr, "Unknown option: \"%s\"\n", azArg[ii]);
9779 rc = 1;
9780 goto meta_command_exit;
drhceba7922018-01-01 21:28:25 +00009781 }else if( zName==0 ){
9782 zName = azArg[ii];
drh2ce15c32017-07-11 13:34:40 +00009783 }else{
larrybr0953c532022-12-23 19:04:59 +00009784 raw_printf(stderr,
9785 "Usage: .schema ?--indent? ?--nosys? ?LIKE-PATTERN?\n");
drhceba7922018-01-01 21:28:25 +00009786 rc = 1;
9787 goto meta_command_exit;
drh2ce15c32017-07-11 13:34:40 +00009788 }
drh2ce15c32017-07-11 13:34:40 +00009789 }
drhceba7922018-01-01 21:28:25 +00009790 if( zName!=0 ){
drh067b92b2020-06-19 15:24:12 +00009791 int isSchema = sqlite3_strlike(zName, "sqlite_master", '\\')==0
drh346a70c2020-06-15 20:27:35 +00009792 || sqlite3_strlike(zName, "sqlite_schema", '\\')==0
9793 || sqlite3_strlike(zName,"sqlite_temp_master", '\\')==0
9794 || sqlite3_strlike(zName,"sqlite_temp_schema", '\\')==0;
drh067b92b2020-06-19 15:24:12 +00009795 if( isSchema ){
drh2ce15c32017-07-11 13:34:40 +00009796 char *new_argv[2], *new_colv[2];
drhc22b7162018-01-01 20:11:23 +00009797 new_argv[0] = sqlite3_mprintf(
9798 "CREATE TABLE %s (\n"
drh2ce15c32017-07-11 13:34:40 +00009799 " type text,\n"
9800 " name text,\n"
9801 " tbl_name text,\n"
9802 " rootpage integer,\n"
9803 " sql text\n"
drh346a70c2020-06-15 20:27:35 +00009804 ")", zName);
drhe3e25652021-12-16 13:29:28 +00009805 shell_check_oom(new_argv[0]);
drh2ce15c32017-07-11 13:34:40 +00009806 new_argv[1] = 0;
9807 new_colv[0] = "sql";
9808 new_colv[1] = 0;
9809 callback(&data, 1, new_argv, new_colv);
drhc22b7162018-01-01 20:11:23 +00009810 sqlite3_free(new_argv[0]);
drh2ce15c32017-07-11 13:34:40 +00009811 }
drh2ce15c32017-07-11 13:34:40 +00009812 }
9813 if( zDiv ){
9814 sqlite3_stmt *pStmt = 0;
9815 rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
9816 -1, &pStmt, 0);
9817 if( rc ){
9818 utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
9819 sqlite3_finalize(pStmt);
9820 rc = 1;
9821 goto meta_command_exit;
9822 }
9823 appendText(&sSelect, "SELECT sql FROM", 0);
9824 iSchema = 0;
9825 while( sqlite3_step(pStmt)==SQLITE_ROW ){
9826 const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
9827 char zScNum[30];
9828 sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
9829 appendText(&sSelect, zDiv, 0);
9830 zDiv = " UNION ALL ";
drhceba7922018-01-01 21:28:25 +00009831 appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
9832 if( sqlite3_stricmp(zDb, "main")!=0 ){
drhea38f4f2019-07-13 17:21:47 +00009833 appendText(&sSelect, zDb, '\'');
drh2ce15c32017-07-11 13:34:40 +00009834 }else{
drhceba7922018-01-01 21:28:25 +00009835 appendText(&sSelect, "NULL", 0);
drh2ce15c32017-07-11 13:34:40 +00009836 }
drhceba7922018-01-01 21:28:25 +00009837 appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0);
9838 appendText(&sSelect, zScNum, 0);
9839 appendText(&sSelect, " AS snum, ", 0);
9840 appendText(&sSelect, zDb, '\'');
9841 appendText(&sSelect, " AS sname FROM ", 0);
drhea38f4f2019-07-13 17:21:47 +00009842 appendText(&sSelect, zDb, quoteChar(zDb));
drh067b92b2020-06-19 15:24:12 +00009843 appendText(&sSelect, ".sqlite_schema", 0);
drh2ce15c32017-07-11 13:34:40 +00009844 }
9845 sqlite3_finalize(pStmt);
drhcc3f3d12019-08-17 15:27:58 +00009846#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
drh667a2a22018-01-02 00:04:37 +00009847 if( zName ){
9848 appendText(&sSelect,
9849 " UNION ALL SELECT shell_module_schema(name),"
drhe2754c12019-08-26 12:50:01 +00009850 " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list",
9851 0);
drh667a2a22018-01-02 00:04:37 +00009852 }
drhcde7b772018-01-02 12:50:40 +00009853#endif
drh2ce15c32017-07-11 13:34:40 +00009854 appendText(&sSelect, ") WHERE ", 0);
drhceba7922018-01-01 21:28:25 +00009855 if( zName ){
9856 char *zQarg = sqlite3_mprintf("%Q", zName);
mistachkinc158c072021-12-31 19:08:20 +00009857 int bGlob;
drhe3e25652021-12-16 13:29:28 +00009858 shell_check_oom(zQarg);
mistachkinc158c072021-12-31 19:08:20 +00009859 bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 ||
9860 strchr(zName, '[') != 0;
drhceba7922018-01-01 21:28:25 +00009861 if( strchr(zName, '.') ){
drh2ce15c32017-07-11 13:34:40 +00009862 appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
9863 }else{
9864 appendText(&sSelect, "lower(tbl_name)", 0);
9865 }
mistachkin9d107262018-03-23 14:24:34 +00009866 appendText(&sSelect, bGlob ? " GLOB " : " LIKE ", 0);
drh2ce15c32017-07-11 13:34:40 +00009867 appendText(&sSelect, zQarg, 0);
mistachkin9d107262018-03-23 14:24:34 +00009868 if( !bGlob ){
9869 appendText(&sSelect, " ESCAPE '\\' ", 0);
9870 }
drh2ce15c32017-07-11 13:34:40 +00009871 appendText(&sSelect, " AND ", 0);
9872 sqlite3_free(zQarg);
9873 }
drhbbb29ec2020-10-12 14:56:47 +00009874 if( bNoSystemTabs ){
9875 appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0);
9876 }
9877 appendText(&sSelect, "sql IS NOT NULL"
drh2ce15c32017-07-11 13:34:40 +00009878 " ORDER BY snum, rowid", 0);
drhceba7922018-01-01 21:28:25 +00009879 if( bDebug ){
9880 utf8_printf(p->out, "SQL: %s;\n", sSelect.z);
9881 }else{
9882 rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
9883 }
drh2ce15c32017-07-11 13:34:40 +00009884 freeText(&sSelect);
9885 }
9886 if( zErrMsg ){
9887 utf8_printf(stderr,"Error: %s\n", zErrMsg);
9888 sqlite3_free(zErrMsg);
9889 rc = 1;
9890 }else if( rc != SQLITE_OK ){
9891 raw_printf(stderr,"Error: querying schema information\n");
9892 rc = 1;
9893 }else{
9894 rc = 0;
9895 }
9896 }else
9897
drhbf70f1b2022-10-19 18:04:42 +00009898 if( (c=='s' && n==11 && cli_strncmp(azArg[0], "selecttrace", n)==0)
9899 || (c=='t' && n==9 && cli_strncmp(azArg[0], "treetrace", n)==0)
drh5e431be2022-04-06 11:08:38 +00009900 ){
larrybr0953c532022-12-23 19:04:59 +00009901 unsigned int x = nArg>=2? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
drhc0622a42020-12-04 01:17:57 +00009902 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x);
drh2ce15c32017-07-11 13:34:40 +00009903 }else
drh2ce15c32017-07-11 13:34:40 +00009904
9905#if defined(SQLITE_ENABLE_SESSION)
drhbf70f1b2022-10-19 18:04:42 +00009906 if( c=='s' && cli_strncmp(azArg[0],"session",n)==0 && n>=3 ){
drh37407122021-07-23 18:43:58 +00009907 struct AuxDb *pAuxDb = p->pAuxDb;
9908 OpenSession *pSession = &pAuxDb->aSession[0];
drh2ce15c32017-07-11 13:34:40 +00009909 char **azCmd = &azArg[1];
9910 int iSes = 0;
9911 int nCmd = nArg - 1;
9912 int i;
9913 if( nArg<=1 ) goto session_syntax_error;
9914 open_db(p, 0);
9915 if( nArg>=3 ){
drh37407122021-07-23 18:43:58 +00009916 for(iSes=0; iSes<pAuxDb->nSession; iSes++){
drhbf70f1b2022-10-19 18:04:42 +00009917 if( cli_strcmp(pAuxDb->aSession[iSes].zName, azArg[1])==0 ) break;
drh2ce15c32017-07-11 13:34:40 +00009918 }
drh37407122021-07-23 18:43:58 +00009919 if( iSes<pAuxDb->nSession ){
9920 pSession = &pAuxDb->aSession[iSes];
drh2ce15c32017-07-11 13:34:40 +00009921 azCmd++;
9922 nCmd--;
9923 }else{
drh37407122021-07-23 18:43:58 +00009924 pSession = &pAuxDb->aSession[0];
drh2ce15c32017-07-11 13:34:40 +00009925 iSes = 0;
9926 }
9927 }
9928
9929 /* .session attach TABLE
9930 ** Invoke the sqlite3session_attach() interface to attach a particular
9931 ** table so that it is never filtered.
9932 */
drhbf70f1b2022-10-19 18:04:42 +00009933 if( cli_strcmp(azCmd[0],"attach")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009934 if( nCmd!=2 ) goto session_syntax_error;
9935 if( pSession->p==0 ){
9936 session_not_open:
9937 raw_printf(stderr, "ERROR: No sessions are open\n");
9938 }else{
9939 rc = sqlite3session_attach(pSession->p, azCmd[1]);
9940 if( rc ){
9941 raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc);
9942 rc = 0;
9943 }
9944 }
9945 }else
9946
9947 /* .session changeset FILE
9948 ** .session patchset FILE
9949 ** Write a changeset or patchset into a file. The file is overwritten.
9950 */
drhbf70f1b2022-10-19 18:04:42 +00009951 if( cli_strcmp(azCmd[0],"changeset")==0
9952 || cli_strcmp(azCmd[0],"patchset")==0
9953 ){
drh2ce15c32017-07-11 13:34:40 +00009954 FILE *out = 0;
drhb97e2ad2021-08-26 18:31:39 +00009955 failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]);
drh2ce15c32017-07-11 13:34:40 +00009956 if( nCmd!=2 ) goto session_syntax_error;
9957 if( pSession->p==0 ) goto session_not_open;
9958 out = fopen(azCmd[1], "wb");
9959 if( out==0 ){
drhe2754c12019-08-26 12:50:01 +00009960 utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n",
9961 azCmd[1]);
drh2ce15c32017-07-11 13:34:40 +00009962 }else{
9963 int szChng;
9964 void *pChng;
9965 if( azCmd[0][0]=='c' ){
9966 rc = sqlite3session_changeset(pSession->p, &szChng, &pChng);
9967 }else{
9968 rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
9969 }
9970 if( rc ){
9971 printf("Error: error code %d\n", rc);
9972 rc = 0;
9973 }
9974 if( pChng
9975 && fwrite(pChng, szChng, 1, out)!=1 ){
9976 raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n",
9977 szChng);
9978 }
9979 sqlite3_free(pChng);
9980 fclose(out);
9981 }
9982 }else
9983
9984 /* .session close
9985 ** Close the identified session
9986 */
drhbf70f1b2022-10-19 18:04:42 +00009987 if( cli_strcmp(azCmd[0], "close")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009988 if( nCmd!=1 ) goto session_syntax_error;
drh37407122021-07-23 18:43:58 +00009989 if( pAuxDb->nSession ){
drh2ce15c32017-07-11 13:34:40 +00009990 session_close(pSession);
drh37407122021-07-23 18:43:58 +00009991 pAuxDb->aSession[iSes] = pAuxDb->aSession[--pAuxDb->nSession];
drh2ce15c32017-07-11 13:34:40 +00009992 }
9993 }else
9994
9995 /* .session enable ?BOOLEAN?
9996 ** Query or set the enable flag
9997 */
drhbf70f1b2022-10-19 18:04:42 +00009998 if( cli_strcmp(azCmd[0], "enable")==0 ){
drh2ce15c32017-07-11 13:34:40 +00009999 int ii;
10000 if( nCmd>2 ) goto session_syntax_error;
10001 ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
drh37407122021-07-23 18:43:58 +000010002 if( pAuxDb->nSession ){
drh2ce15c32017-07-11 13:34:40 +000010003 ii = sqlite3session_enable(pSession->p, ii);
10004 utf8_printf(p->out, "session %s enable flag = %d\n",
10005 pSession->zName, ii);
10006 }
10007 }else
10008
10009 /* .session filter GLOB ....
10010 ** Set a list of GLOB patterns of table names to be excluded.
10011 */
drhbf70f1b2022-10-19 18:04:42 +000010012 if( cli_strcmp(azCmd[0], "filter")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010013 int ii, nByte;
10014 if( nCmd<2 ) goto session_syntax_error;
drh37407122021-07-23 18:43:58 +000010015 if( pAuxDb->nSession ){
drh2ce15c32017-07-11 13:34:40 +000010016 for(ii=0; ii<pSession->nFilter; ii++){
10017 sqlite3_free(pSession->azFilter[ii]);
10018 }
10019 sqlite3_free(pSession->azFilter);
10020 nByte = sizeof(pSession->azFilter[0])*(nCmd-1);
10021 pSession->azFilter = sqlite3_malloc( nByte );
10022 if( pSession->azFilter==0 ){
10023 raw_printf(stderr, "Error: out or memory\n");
10024 exit(1);
10025 }
10026 for(ii=1; ii<nCmd; ii++){
drhe3e25652021-12-16 13:29:28 +000010027 char *x = pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]);
10028 shell_check_oom(x);
drh2ce15c32017-07-11 13:34:40 +000010029 }
10030 pSession->nFilter = ii-1;
10031 }
10032 }else
10033
10034 /* .session indirect ?BOOLEAN?
10035 ** Query or set the indirect flag
10036 */
drhbf70f1b2022-10-19 18:04:42 +000010037 if( cli_strcmp(azCmd[0], "indirect")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010038 int ii;
10039 if( nCmd>2 ) goto session_syntax_error;
10040 ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
drh37407122021-07-23 18:43:58 +000010041 if( pAuxDb->nSession ){
drh2ce15c32017-07-11 13:34:40 +000010042 ii = sqlite3session_indirect(pSession->p, ii);
10043 utf8_printf(p->out, "session %s indirect flag = %d\n",
10044 pSession->zName, ii);
10045 }
10046 }else
10047
10048 /* .session isempty
10049 ** Determine if the session is empty
10050 */
drhbf70f1b2022-10-19 18:04:42 +000010051 if( cli_strcmp(azCmd[0], "isempty")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010052 int ii;
10053 if( nCmd!=1 ) goto session_syntax_error;
drh37407122021-07-23 18:43:58 +000010054 if( pAuxDb->nSession ){
drh2ce15c32017-07-11 13:34:40 +000010055 ii = sqlite3session_isempty(pSession->p);
10056 utf8_printf(p->out, "session %s isempty flag = %d\n",
10057 pSession->zName, ii);
10058 }
10059 }else
10060
10061 /* .session list
10062 ** List all currently open sessions
10063 */
drhbf70f1b2022-10-19 18:04:42 +000010064 if( cli_strcmp(azCmd[0],"list")==0 ){
drh37407122021-07-23 18:43:58 +000010065 for(i=0; i<pAuxDb->nSession; i++){
10066 utf8_printf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName);
drh2ce15c32017-07-11 13:34:40 +000010067 }
10068 }else
10069
10070 /* .session open DB NAME
10071 ** Open a new session called NAME on the attached database DB.
10072 ** DB is normally "main".
10073 */
drhbf70f1b2022-10-19 18:04:42 +000010074 if( cli_strcmp(azCmd[0],"open")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010075 char *zName;
10076 if( nCmd!=3 ) goto session_syntax_error;
10077 zName = azCmd[2];
10078 if( zName[0]==0 ) goto session_syntax_error;
drh37407122021-07-23 18:43:58 +000010079 for(i=0; i<pAuxDb->nSession; i++){
drhbf70f1b2022-10-19 18:04:42 +000010080 if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010081 utf8_printf(stderr, "Session \"%s\" already exists\n", zName);
10082 goto meta_command_exit;
10083 }
10084 }
drh37407122021-07-23 18:43:58 +000010085 if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){
larrybr0953c532022-12-23 19:04:59 +000010086 raw_printf(stderr,
10087 "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
drh2ce15c32017-07-11 13:34:40 +000010088 goto meta_command_exit;
10089 }
drh37407122021-07-23 18:43:58 +000010090 pSession = &pAuxDb->aSession[pAuxDb->nSession];
drh2ce15c32017-07-11 13:34:40 +000010091 rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
10092 if( rc ){
10093 raw_printf(stderr, "Cannot open session: error code=%d\n", rc);
10094 rc = 0;
10095 goto meta_command_exit;
10096 }
10097 pSession->nFilter = 0;
10098 sqlite3session_table_filter(pSession->p, session_filter, pSession);
drh37407122021-07-23 18:43:58 +000010099 pAuxDb->nSession++;
drh2ce15c32017-07-11 13:34:40 +000010100 pSession->zName = sqlite3_mprintf("%s", zName);
drhe3e25652021-12-16 13:29:28 +000010101 shell_check_oom(pSession->zName);
drh2ce15c32017-07-11 13:34:40 +000010102 }else
10103 /* If no command name matches, show a syntax error */
10104 session_syntax_error:
drheb7f2a02018-09-26 18:02:32 +000010105 showHelp(p->out, "session");
drh2ce15c32017-07-11 13:34:40 +000010106 }else
10107#endif
10108
10109#ifdef SQLITE_DEBUG
10110 /* Undocumented commands for internal testing. Subject to change
10111 ** without notice. */
drhbf70f1b2022-10-19 18:04:42 +000010112 if( c=='s' && n>=10 && cli_strncmp(azArg[0], "selftest-", 9)==0 ){
10113 if( cli_strncmp(azArg[0]+9, "boolean", n-9)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010114 int i, v;
10115 for(i=1; i<nArg; i++){
10116 v = booleanValue(azArg[i]);
10117 utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
10118 }
10119 }
drhbf70f1b2022-10-19 18:04:42 +000010120 if( cli_strncmp(azArg[0]+9, "integer", n-9)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010121 int i; sqlite3_int64 v;
10122 for(i=1; i<nArg; i++){
10123 char zBuf[200];
10124 v = integerValue(azArg[i]);
10125 sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
10126 utf8_printf(p->out, "%s", zBuf);
10127 }
10128 }
10129 }else
10130#endif
10131
drhbf70f1b2022-10-19 18:04:42 +000010132 if( c=='s' && n>=4 && cli_strncmp(azArg[0],"selftest",n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010133 int bIsInit = 0; /* True to initialize the SELFTEST table */
10134 int bVerbose = 0; /* Verbose output */
10135 int bSelftestExists; /* True if SELFTEST already exists */
10136 int i, k; /* Loop counters */
10137 int nTest = 0; /* Number of tests runs */
10138 int nErr = 0; /* Number of errors seen */
10139 ShellText str; /* Answer for a query */
10140 sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
10141
10142 open_db(p,0);
10143 for(i=1; i<nArg; i++){
10144 const char *z = azArg[i];
10145 if( z[0]=='-' && z[1]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +000010146 if( cli_strcmp(z,"-init")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010147 bIsInit = 1;
10148 }else
drhbf70f1b2022-10-19 18:04:42 +000010149 if( cli_strcmp(z,"-v")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010150 bVerbose++;
10151 }else
10152 {
10153 utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
10154 azArg[i], azArg[0]);
10155 raw_printf(stderr, "Should be one of: --init -v\n");
10156 rc = 1;
10157 goto meta_command_exit;
10158 }
10159 }
10160 if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
10161 != SQLITE_OK ){
10162 bSelftestExists = 0;
10163 }else{
10164 bSelftestExists = 1;
10165 }
10166 if( bIsInit ){
10167 createSelftestTable(p);
10168 bSelftestExists = 1;
10169 }
10170 initText(&str);
10171 appendText(&str, "x", 0);
10172 for(k=bSelftestExists; k>=0; k--){
10173 if( k==1 ){
10174 rc = sqlite3_prepare_v2(p->db,
10175 "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
10176 -1, &pStmt, 0);
10177 }else{
10178 rc = sqlite3_prepare_v2(p->db,
10179 "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
10180 " (1,'run','PRAGMA integrity_check','ok')",
10181 -1, &pStmt, 0);
10182 }
10183 if( rc ){
10184 raw_printf(stderr, "Error querying the selftest table\n");
10185 rc = 1;
10186 sqlite3_finalize(pStmt);
10187 goto meta_command_exit;
10188 }
10189 for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
10190 int tno = sqlite3_column_int(pStmt, 0);
10191 const char *zOp = (const char*)sqlite3_column_text(pStmt, 1);
10192 const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
10193 const char *zAns = (const char*)sqlite3_column_text(pStmt, 3);
10194
drh621a5e02021-12-16 17:35:27 +000010195 if( zOp==0 ) continue;
10196 if( zSql==0 ) continue;
10197 if( zAns==0 ) continue;
drh2ce15c32017-07-11 13:34:40 +000010198 k = 0;
10199 if( bVerbose>0 ){
drh2ce15c32017-07-11 13:34:40 +000010200 printf("%d: %s %s\n", tno, zOp, zSql);
drh2ce15c32017-07-11 13:34:40 +000010201 }
drhbf70f1b2022-10-19 18:04:42 +000010202 if( cli_strcmp(zOp,"memo")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010203 utf8_printf(p->out, "%s\n", zSql);
10204 }else
drhbf70f1b2022-10-19 18:04:42 +000010205 if( cli_strcmp(zOp,"run")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010206 char *zErrMsg = 0;
10207 str.n = 0;
10208 str.z[0] = 0;
10209 rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
10210 nTest++;
10211 if( bVerbose ){
10212 utf8_printf(p->out, "Result: %s\n", str.z);
10213 }
10214 if( rc || zErrMsg ){
10215 nErr++;
10216 rc = 1;
10217 utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
10218 sqlite3_free(zErrMsg);
drhbf70f1b2022-10-19 18:04:42 +000010219 }else if( cli_strcmp(zAns,str.z)!=0 ){
drh2ce15c32017-07-11 13:34:40 +000010220 nErr++;
10221 rc = 1;
10222 utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
10223 utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
10224 }
10225 }else
10226 {
10227 utf8_printf(stderr,
10228 "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
10229 rc = 1;
10230 break;
10231 }
10232 } /* End loop over rows of content from SELFTEST */
10233 sqlite3_finalize(pStmt);
10234 } /* End loop over k */
10235 freeText(&str);
10236 utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
10237 }else
10238
drhbf70f1b2022-10-19 18:04:42 +000010239 if( c=='s' && cli_strncmp(azArg[0], "separator", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010240 if( nArg<2 || nArg>3 ){
10241 raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
10242 rc = 1;
10243 }
10244 if( nArg>=2 ){
10245 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
10246 "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
10247 }
10248 if( nArg>=3 ){
10249 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
10250 "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
10251 }
10252 }else
10253
drhbf70f1b2022-10-19 18:04:42 +000010254 if( c=='s' && n>=4 && cli_strncmp(azArg[0],"sha3sum",n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010255 const char *zLike = 0; /* Which table to checksum. 0 means everything */
10256 int i; /* Loop counter */
10257 int bSchema = 0; /* Also hash the schema */
10258 int bSeparate = 0; /* Hash each table separately */
10259 int iSize = 224; /* Hash algorithm to use */
10260 int bDebug = 0; /* Only show the query that would have run */
10261 sqlite3_stmt *pStmt; /* For querying tables names */
10262 char *zSql; /* SQL to be run */
10263 char *zSep; /* Separator */
10264 ShellText sSql; /* Complete SQL for the query to run the hash */
10265 ShellText sQuery; /* Set of queries used to read all content */
10266 open_db(p, 0);
10267 for(i=1; i<nArg; i++){
10268 const char *z = azArg[i];
10269 if( z[0]=='-' ){
10270 z++;
10271 if( z[0]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +000010272 if( cli_strcmp(z,"schema")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010273 bSchema = 1;
10274 }else
drhbf70f1b2022-10-19 18:04:42 +000010275 if( cli_strcmp(z,"sha3-224")==0 || cli_strcmp(z,"sha3-256")==0
10276 || cli_strcmp(z,"sha3-384")==0 || cli_strcmp(z,"sha3-512")==0
drh2ce15c32017-07-11 13:34:40 +000010277 ){
10278 iSize = atoi(&z[5]);
10279 }else
drhbf70f1b2022-10-19 18:04:42 +000010280 if( cli_strcmp(z,"debug")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010281 bDebug = 1;
10282 }else
10283 {
10284 utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
10285 azArg[i], azArg[0]);
drhe2754c12019-08-26 12:50:01 +000010286 showHelp(p->out, azArg[0]);
drh2ce15c32017-07-11 13:34:40 +000010287 rc = 1;
10288 goto meta_command_exit;
10289 }
10290 }else if( zLike ){
10291 raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n");
10292 rc = 1;
10293 goto meta_command_exit;
10294 }else{
10295 zLike = z;
10296 bSeparate = 1;
drhcedfecf2018-03-23 12:59:10 +000010297 if( sqlite3_strlike("sqlite\\_%", zLike, '\\')==0 ) bSchema = 1;
drh2ce15c32017-07-11 13:34:40 +000010298 }
10299 }
10300 if( bSchema ){
larrybr30cbcc02022-12-03 16:09:32 +000010301 zSql = "SELECT lower(name) as tname FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +000010302 " WHERE type='table' AND coalesce(rootpage,0)>1"
drh067b92b2020-06-19 15:24:12 +000010303 " UNION ALL SELECT 'sqlite_schema'"
drh2ce15c32017-07-11 13:34:40 +000010304 " ORDER BY 1 collate nocase";
10305 }else{
larrybr30cbcc02022-12-03 16:09:32 +000010306 zSql = "SELECT lower(name) as tname FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +000010307 " WHERE type='table' AND coalesce(rootpage,0)>1"
10308 " AND name NOT LIKE 'sqlite_%'"
10309 " ORDER BY 1 collate nocase";
10310 }
10311 sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
10312 initText(&sQuery);
10313 initText(&sSql);
10314 appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
10315 zSep = "VALUES(";
10316 while( SQLITE_ROW==sqlite3_step(pStmt) ){
10317 const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
drh621a5e02021-12-16 17:35:27 +000010318 if( zTab==0 ) continue;
drh2ce15c32017-07-11 13:34:40 +000010319 if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
drhbf70f1b2022-10-19 18:04:42 +000010320 if( cli_strncmp(zTab, "sqlite_",7)!=0 ){
drh2ce15c32017-07-11 13:34:40 +000010321 appendText(&sQuery,"SELECT * FROM ", 0);
10322 appendText(&sQuery,zTab,'"');
10323 appendText(&sQuery," NOT INDEXED;", 0);
drhbf70f1b2022-10-19 18:04:42 +000010324 }else if( cli_strcmp(zTab, "sqlite_schema")==0 ){
drh067b92b2020-06-19 15:24:12 +000010325 appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_schema"
drh2ce15c32017-07-11 13:34:40 +000010326 " ORDER BY name;", 0);
drhbf70f1b2022-10-19 18:04:42 +000010327 }else if( cli_strcmp(zTab, "sqlite_sequence")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010328 appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
10329 " ORDER BY name;", 0);
drhbf70f1b2022-10-19 18:04:42 +000010330 }else if( cli_strcmp(zTab, "sqlite_stat1")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010331 appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1"
10332 " ORDER BY tbl,idx;", 0);
drhbf70f1b2022-10-19 18:04:42 +000010333 }else if( cli_strcmp(zTab, "sqlite_stat4")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010334 appendText(&sQuery, "SELECT * FROM ", 0);
10335 appendText(&sQuery, zTab, 0);
10336 appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0);
10337 }
10338 appendText(&sSql, zSep, 0);
10339 appendText(&sSql, sQuery.z, '\'');
10340 sQuery.n = 0;
10341 appendText(&sSql, ",", 0);
10342 appendText(&sSql, zTab, '\'');
10343 zSep = "),(";
10344 }
10345 sqlite3_finalize(pStmt);
10346 if( bSeparate ){
10347 zSql = sqlite3_mprintf(
10348 "%s))"
10349 " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label"
10350 " FROM [sha3sum$query]",
10351 sSql.z, iSize);
10352 }else{
10353 zSql = sqlite3_mprintf(
10354 "%s))"
10355 " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash"
10356 " FROM [sha3sum$query]",
10357 sSql.z, iSize);
10358 }
drhe3e25652021-12-16 13:29:28 +000010359 shell_check_oom(zSql);
drh2ce15c32017-07-11 13:34:40 +000010360 freeText(&sQuery);
10361 freeText(&sSql);
10362 if( bDebug ){
10363 utf8_printf(p->out, "%s\n", zSql);
10364 }else{
drha10b9992018-03-09 15:24:33 +000010365 shell_exec(p, zSql, 0);
drh2ce15c32017-07-11 13:34:40 +000010366 }
larrybr7474de72022-12-07 19:29:13 +000010367#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && !defined(SQLITE_OMIT_VIRTUALTABLE)
larrybr30cbcc02022-12-03 16:09:32 +000010368 {
larrybr09d95372022-12-06 18:48:37 +000010369 int lrc;
10370 char *zRevText = /* Query for reversible to-blob-to-text check */
larrybr88fbe1612022-12-17 19:56:28 +000010371 "SELECT lower(name) as tname FROM sqlite_schema\n"
10372 "WHERE type='table' AND coalesce(rootpage,0)>1\n"
10373 "AND name NOT LIKE 'sqlite_%%'%s\n"
10374 "ORDER BY 1 collate nocase";
larrybr09d95372022-12-06 18:48:37 +000010375 zRevText = sqlite3_mprintf(zRevText, zLike? " AND name LIKE $tspec" : "");
10376 zRevText = sqlite3_mprintf(
larrybr88fbe1612022-12-17 19:56:28 +000010377 /* lower-case query is first run, producing upper-case query. */
10378 "with tabcols as materialized(\n"
10379 "select tname, cname\n"
10380 "from ("
10381 " select ss.tname as tname, ti.name as cname\n"
10382 " from (%z) ss\n inner join pragma_table_info(tname) ti))\n"
10383 "select 'SELECT total(bad_text_count) AS bad_text_count\n"
10384 "FROM ('||group_concat(query, ' UNION ALL ')||')' as btc_query\n"
10385 " from (select 'SELECT COUNT(*) AS bad_text_count\n"
10386 "FROM '||tname||' WHERE '\n"
10387 "||group_concat('CAST(CAST('||cname||' AS BLOB) AS TEXT)<>'||cname\n"
10388 "|| ' AND typeof('||cname||')=''text'' ',\n"
10389 "' OR ') as query, tname from tabcols group by tname)"
10390 , zRevText);
larrybr09d95372022-12-06 18:48:37 +000010391 shell_check_oom(zRevText);
larrybr30cbcc02022-12-03 16:09:32 +000010392 if( bDebug ) utf8_printf(p->out, "%s\n", zRevText);
larrybr09d95372022-12-06 18:48:37 +000010393 lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0);
larrybr30cbcc02022-12-03 16:09:32 +000010394 assert(lrc==SQLITE_OK);
larrybr09d95372022-12-06 18:48:37 +000010395 if( zLike ) sqlite3_bind_text(pStmt,1,zLike,-1,SQLITE_STATIC);
larrybr30cbcc02022-12-03 16:09:32 +000010396 lrc = SQLITE_ROW==sqlite3_step(pStmt);
larrybr30cbcc02022-12-03 16:09:32 +000010397 if( lrc ){
larrybr1751f872022-12-06 19:25:07 +000010398 const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0);
larrybr30cbcc02022-12-03 16:09:32 +000010399 sqlite3_stmt *pCheckStmt;
larrybr30cbcc02022-12-03 16:09:32 +000010400 lrc = sqlite3_prepare_v2(p->db, zGenQuery, -1, &pCheckStmt, 0);
10401 if( bDebug ) utf8_printf(p->out, "%s\n", zGenQuery);
larrybr09d95372022-12-06 18:48:37 +000010402 if( SQLITE_OK==lrc ){
larrybr88fbe1612022-12-17 19:56:28 +000010403 if( SQLITE_ROW==sqlite3_step(pCheckStmt) ){
10404 double countIrreversible = sqlite3_column_double(pCheckStmt, 0);
10405 if( countIrreversible>0 ){
10406 int sz = (int)(countIrreversible + 0.5);
10407 utf8_printf(stderr,
10408 "Digest includes %d invalidly encoded text field%s.\n",
10409 sz, (sz>1)? "s": "");
10410 }
10411 }
10412 sqlite3_finalize(pCheckStmt);
larrybr30cbcc02022-12-03 16:09:32 +000010413 }
larrybr09d95372022-12-06 18:48:37 +000010414 sqlite3_finalize(pStmt);
larrybr30cbcc02022-12-03 16:09:32 +000010415 }
larrybr09d95372022-12-06 18:48:37 +000010416 sqlite3_free(zRevText);
larrybr30cbcc02022-12-03 16:09:32 +000010417 }
larrybr7474de72022-12-07 19:29:13 +000010418#endif /* !defined(*_OMIT_SCHEMA_PRAGMAS) && !defined(*_OMIT_VIRTUALTABLE) */
drh2ce15c32017-07-11 13:34:40 +000010419 sqlite3_free(zSql);
10420 }else
10421
stephan4413ec72022-07-12 15:53:02 +000010422#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
drh2ce15c32017-07-11 13:34:40 +000010423 if( c=='s'
drhbf70f1b2022-10-19 18:04:42 +000010424 && (cli_strncmp(azArg[0], "shell", n)==0
10425 || cli_strncmp(azArg[0],"system",n)==0)
drh2ce15c32017-07-11 13:34:40 +000010426 ){
10427 char *zCmd;
10428 int i, x;
drhb97e2ad2021-08-26 18:31:39 +000010429 failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
drh2ce15c32017-07-11 13:34:40 +000010430 if( nArg<2 ){
10431 raw_printf(stderr, "Usage: .system COMMAND\n");
10432 rc = 1;
10433 goto meta_command_exit;
10434 }
10435 zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
drhe3e25652021-12-16 13:29:28 +000010436 for(i=2; i<nArg && zCmd!=0; i++){
drh2ce15c32017-07-11 13:34:40 +000010437 zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
10438 zCmd, azArg[i]);
10439 }
drhe3e25652021-12-16 13:29:28 +000010440 x = zCmd!=0 ? system(zCmd) : 1;
drh2ce15c32017-07-11 13:34:40 +000010441 sqlite3_free(zCmd);
10442 if( x ) raw_printf(stderr, "System command returns %d\n", x);
10443 }else
stephan4413ec72022-07-12 15:53:02 +000010444#endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +000010445
drhbf70f1b2022-10-19 18:04:42 +000010446 if( c=='s' && cli_strncmp(azArg[0], "show", n)==0 ){
drhada70452017-12-21 21:02:27 +000010447 static const char *azBool[] = { "off", "on", "trigger", "full"};
drha6e6cf22021-01-09 19:10:04 +000010448 const char *zOut;
drh2ce15c32017-07-11 13:34:40 +000010449 int i;
10450 if( nArg!=1 ){
10451 raw_printf(stderr, "Usage: .show\n");
10452 rc = 1;
10453 goto meta_command_exit;
10454 }
10455 utf8_printf(p->out, "%12.12s: %s\n","echo",
larrybrf4874812022-05-11 19:59:31 +000010456 azBool[ShellHasFlag(p, SHFLG_Echo)]);
drh2ce15c32017-07-11 13:34:40 +000010457 utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
10458 utf8_printf(p->out, "%12.12s: %s\n","explain",
10459 p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
10460 utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
drhe40f2862022-01-31 14:14:29 +000010461 if( p->mode==MODE_Column
10462 || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
10463 ){
larrybrcc4d55c2022-02-01 02:50:45 +000010464 utf8_printf
10465 (p->out, "%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
10466 modeDescr[p->mode], p->cmOpts.iWrap,
10467 p->cmOpts.bWordWrap ? "on" : "off",
10468 p->cmOpts.bQuote ? "" : "no");
drhe40f2862022-01-31 14:14:29 +000010469 }else{
10470 utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
10471 }
drh2ce15c32017-07-11 13:34:40 +000010472 utf8_printf(p->out, "%12.12s: ", "nullvalue");
10473 output_c_string(p->out, p->nullValue);
10474 raw_printf(p->out, "\n");
10475 utf8_printf(p->out,"%12.12s: %s\n","output",
10476 strlen30(p->outfile) ? p->outfile : "stdout");
10477 utf8_printf(p->out,"%12.12s: ", "colseparator");
10478 output_c_string(p->out, p->colSeparator);
10479 raw_printf(p->out, "\n");
10480 utf8_printf(p->out,"%12.12s: ", "rowseparator");
10481 output_c_string(p->out, p->rowSeparator);
10482 raw_printf(p->out, "\n");
drha6e6cf22021-01-09 19:10:04 +000010483 switch( p->statsOn ){
10484 case 0: zOut = "off"; break;
10485 default: zOut = "on"; break;
10486 case 2: zOut = "stmt"; break;
10487 case 3: zOut = "vmstep"; break;
10488 }
10489 utf8_printf(p->out, "%12.12s: %s\n","stats", zOut);
drh2ce15c32017-07-11 13:34:40 +000010490 utf8_printf(p->out, "%12.12s: ", "width");
drh0285d982020-05-29 14:38:43 +000010491 for (i=0;i<p->nWidth;i++) {
drh2ce15c32017-07-11 13:34:40 +000010492 raw_printf(p->out, "%d ", p->colWidth[i]);
10493 }
10494 raw_printf(p->out, "\n");
10495 utf8_printf(p->out, "%12.12s: %s\n", "filename",
drh37407122021-07-23 18:43:58 +000010496 p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : "");
drh2ce15c32017-07-11 13:34:40 +000010497 }else
10498
drhbf70f1b2022-10-19 18:04:42 +000010499 if( c=='s' && cli_strncmp(azArg[0], "stats", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010500 if( nArg==2 ){
drhbf70f1b2022-10-19 18:04:42 +000010501 if( cli_strcmp(azArg[1],"stmt")==0 ){
drha6e6cf22021-01-09 19:10:04 +000010502 p->statsOn = 2;
drhbf70f1b2022-10-19 18:04:42 +000010503 }else if( cli_strcmp(azArg[1],"vmstep")==0 ){
drha6e6cf22021-01-09 19:10:04 +000010504 p->statsOn = 3;
10505 }else{
10506 p->statsOn = (u8)booleanValue(azArg[1]);
10507 }
drh2ce15c32017-07-11 13:34:40 +000010508 }else if( nArg==1 ){
10509 display_stats(p->db, p, 0);
10510 }else{
drha6e6cf22021-01-09 19:10:04 +000010511 raw_printf(stderr, "Usage: .stats ?on|off|stmt|vmstep?\n");
drh2ce15c32017-07-11 13:34:40 +000010512 rc = 1;
10513 }
10514 }else
10515
drhbf70f1b2022-10-19 18:04:42 +000010516 if( (c=='t' && n>1 && cli_strncmp(azArg[0], "tables", n)==0)
10517 || (c=='i' && (cli_strncmp(azArg[0], "indices", n)==0
10518 || cli_strncmp(azArg[0], "indexes", n)==0) )
drh2ce15c32017-07-11 13:34:40 +000010519 ){
10520 sqlite3_stmt *pStmt;
10521 char **azResult;
10522 int nRow, nAlloc;
10523 int ii;
10524 ShellText s;
10525 initText(&s);
10526 open_db(p, 0);
10527 rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
drh9e804032018-05-18 17:11:50 +000010528 if( rc ){
10529 sqlite3_finalize(pStmt);
10530 return shellDatabaseError(p->db);
10531 }
drh2ce15c32017-07-11 13:34:40 +000010532
10533 if( nArg>2 && c=='i' ){
10534 /* It is an historical accident that the .indexes command shows an error
10535 ** when called with the wrong number of arguments whereas the .tables
10536 ** command does not. */
10537 raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
10538 rc = 1;
drh9e804032018-05-18 17:11:50 +000010539 sqlite3_finalize(pStmt);
drh2ce15c32017-07-11 13:34:40 +000010540 goto meta_command_exit;
10541 }
10542 for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
10543 const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
10544 if( zDbName==0 ) continue;
10545 if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0);
10546 if( sqlite3_stricmp(zDbName, "main")==0 ){
10547 appendText(&s, "SELECT name FROM ", 0);
10548 }else{
10549 appendText(&s, "SELECT ", 0);
10550 appendText(&s, zDbName, '\'');
10551 appendText(&s, "||'.'||name FROM ", 0);
10552 }
10553 appendText(&s, zDbName, '"');
drh067b92b2020-06-19 15:24:12 +000010554 appendText(&s, ".sqlite_schema ", 0);
drh2ce15c32017-07-11 13:34:40 +000010555 if( c=='t' ){
10556 appendText(&s," WHERE type IN ('table','view')"
10557 " AND name NOT LIKE 'sqlite_%'"
10558 " AND name LIKE ?1", 0);
10559 }else{
10560 appendText(&s," WHERE type='index'"
10561 " AND tbl_name LIKE ?1", 0);
10562 }
10563 }
10564 rc = sqlite3_finalize(pStmt);
drhe85e1da2021-10-01 21:01:07 +000010565 if( rc==SQLITE_OK ){
10566 appendText(&s, " ORDER BY 1", 0);
10567 rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
10568 }
drh2ce15c32017-07-11 13:34:40 +000010569 freeText(&s);
10570 if( rc ) return shellDatabaseError(p->db);
10571
10572 /* Run the SQL statement prepared by the above block. Store the results
10573 ** as an array of nul-terminated strings in azResult[]. */
10574 nRow = nAlloc = 0;
10575 azResult = 0;
10576 if( nArg>1 ){
10577 sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT);
10578 }else{
10579 sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
10580 }
10581 while( sqlite3_step(pStmt)==SQLITE_ROW ){
10582 if( nRow>=nAlloc ){
10583 char **azNew;
10584 int n2 = nAlloc*2 + 10;
10585 azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
drhe3e25652021-12-16 13:29:28 +000010586 shell_check_oom(azNew);
drh2ce15c32017-07-11 13:34:40 +000010587 nAlloc = n2;
10588 azResult = azNew;
10589 }
10590 azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
drhe3e25652021-12-16 13:29:28 +000010591 shell_check_oom(azResult[nRow]);
drh2ce15c32017-07-11 13:34:40 +000010592 nRow++;
10593 }
10594 if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
10595 rc = shellDatabaseError(p->db);
10596 }
10597
10598 /* Pretty-print the contents of array azResult[] to the output */
10599 if( rc==0 && nRow>0 ){
10600 int len, maxlen = 0;
10601 int i, j;
10602 int nPrintCol, nPrintRow;
10603 for(i=0; i<nRow; i++){
10604 len = strlen30(azResult[i]);
10605 if( len>maxlen ) maxlen = len;
10606 }
10607 nPrintCol = 80/(maxlen+2);
10608 if( nPrintCol<1 ) nPrintCol = 1;
10609 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
10610 for(i=0; i<nPrintRow; i++){
10611 for(j=i; j<nRow; j+=nPrintRow){
10612 char *zSp = j<nPrintRow ? "" : " ";
10613 utf8_printf(p->out, "%s%-*s", zSp, maxlen,
10614 azResult[j] ? azResult[j]:"");
10615 }
10616 raw_printf(p->out, "\n");
10617 }
10618 }
10619
10620 for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
10621 sqlite3_free(azResult);
10622 }else
10623
stephan4413ec72022-07-12 15:53:02 +000010624#ifndef SQLITE_SHELL_FIDDLE
drh2ce15c32017-07-11 13:34:40 +000010625 /* Begin redirecting output to the file "testcase-out.txt" */
drhbf70f1b2022-10-19 18:04:42 +000010626 if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010627 output_reset(p);
drha92a01a2018-01-10 22:15:37 +000010628 p->out = output_file_open("testcase-out.txt", 0);
drh2ce15c32017-07-11 13:34:40 +000010629 if( p->out==0 ){
10630 raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
10631 }
10632 if( nArg>=2 ){
10633 sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
10634 }else{
10635 sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
10636 }
10637 }else
stephan4413ec72022-07-12 15:53:02 +000010638#endif /* !defined(SQLITE_SHELL_FIDDLE) */
drh2ce15c32017-07-11 13:34:40 +000010639
10640#ifndef SQLITE_UNTESTABLE
drhbf70f1b2022-10-19 18:04:42 +000010641 if( c=='t' && n>=8 && cli_strncmp(azArg[0], "testctrl", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010642 static const struct {
10643 const char *zCtrlName; /* Name of a test-control option */
10644 int ctrlCode; /* Integer code for that option */
drh38ed1ce2021-12-06 15:24:36 +000010645 int unSafe; /* Not valid for --safe mode */
drhef302e82017-11-15 19:14:08 +000010646 const char *zUsage; /* Usage notes */
drh2ce15c32017-07-11 13:34:40 +000010647 } aCtrl[] = {
larrybr0953c532022-12-23 19:04:59 +000010648 {"always", SQLITE_TESTCTRL_ALWAYS, 1, "BOOLEAN" },
10649 {"assert", SQLITE_TESTCTRL_ASSERT, 1, "BOOLEAN" },
10650 /*{"benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,1, "" },*/
10651 /*{"bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/
10652 {"byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" },
10653 {"extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" },
10654 /*{"fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"" },*/
10655 {"imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"},
10656 {"internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" },
10657 {"localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" },
10658 {"never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" },
10659 {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" },
drh0d9de992017-12-26 18:04:23 +000010660#ifdef YYCOVERAGE
larrybr0953c532022-12-23 19:04:59 +000010661 {"parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" },
drh0d9de992017-12-26 18:04:23 +000010662#endif
larrybr0953c532022-12-23 19:04:59 +000010663 {"pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,0, "OFFSET " },
10664 {"prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" },
10665 {"prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" },
10666 {"prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" },
10667 {"seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" },
10668 {"sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" },
10669 {"tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" },
drh2ce15c32017-07-11 13:34:40 +000010670 };
10671 int testctrl = -1;
drhef302e82017-11-15 19:14:08 +000010672 int iCtrl = -1;
10673 int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */
10674 int isOk = 0;
drh2ce15c32017-07-11 13:34:40 +000010675 int i, n2;
mistachkinc6bc15a2017-11-21 21:14:32 +000010676 const char *zCmd = 0;
10677
drh2ce15c32017-07-11 13:34:40 +000010678 open_db(p, 0);
mistachkinc6bc15a2017-11-21 21:14:32 +000010679 zCmd = nArg>=2 ? azArg[1] : "help";
drh35f51a42017-11-15 17:07:22 +000010680
10681 /* The argument can optionally begin with "-" or "--" */
10682 if( zCmd[0]=='-' && zCmd[1] ){
10683 zCmd++;
10684 if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
10685 }
10686
10687 /* --help lists all test-controls */
drhbf70f1b2022-10-19 18:04:42 +000010688 if( cli_strcmp(zCmd,"help")==0 ){
drh35f51a42017-11-15 17:07:22 +000010689 utf8_printf(p->out, "Available test-controls:\n");
10690 for(i=0; i<ArraySize(aCtrl); i++){
drhef302e82017-11-15 19:14:08 +000010691 utf8_printf(p->out, " .testctrl %s %s\n",
10692 aCtrl[i].zCtrlName, aCtrl[i].zUsage);
drh35f51a42017-11-15 17:07:22 +000010693 }
10694 rc = 1;
10695 goto meta_command_exit;
10696 }
drh2ce15c32017-07-11 13:34:40 +000010697
10698 /* convert testctrl text option to value. allow any unique prefix
10699 ** of the option name, or a numerical value. */
drh35f51a42017-11-15 17:07:22 +000010700 n2 = strlen30(zCmd);
drh2ce15c32017-07-11 13:34:40 +000010701 for(i=0; i<ArraySize(aCtrl); i++){
drhbf70f1b2022-10-19 18:04:42 +000010702 if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010703 if( testctrl<0 ){
10704 testctrl = aCtrl[i].ctrlCode;
drhef302e82017-11-15 19:14:08 +000010705 iCtrl = i;
drh2ce15c32017-07-11 13:34:40 +000010706 }else{
drh35f51a42017-11-15 17:07:22 +000010707 utf8_printf(stderr, "Error: ambiguous test-control: \"%s\"\n"
10708 "Use \".testctrl --help\" for help\n", zCmd);
10709 rc = 1;
10710 goto meta_command_exit;
drh2ce15c32017-07-11 13:34:40 +000010711 }
10712 }
10713 }
drhef302e82017-11-15 19:14:08 +000010714 if( testctrl<0 ){
drh35f51a42017-11-15 17:07:22 +000010715 utf8_printf(stderr,"Error: unknown test-control: %s\n"
10716 "Use \".testctrl --help\" for help\n", zCmd);
drh38ed1ce2021-12-06 15:24:36 +000010717 }else if( aCtrl[iCtrl].unSafe && p->bSafeMode ){
10718 utf8_printf(stderr,
10719 "line %d: \".testctrl %s\" may not be used in safe mode\n",
10720 p->lineno, aCtrl[iCtrl].zCtrlName);
10721 exit(1);
drh2ce15c32017-07-11 13:34:40 +000010722 }else{
10723 switch(testctrl){
10724
10725 /* sqlite3_test_control(int, db, int) */
10726 case SQLITE_TESTCTRL_OPTIMIZATIONS:
drh2ce15c32017-07-11 13:34:40 +000010727 if( nArg==3 ){
drhaf7b7652021-01-13 19:28:17 +000010728 unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0);
drh2ce15c32017-07-11 13:34:40 +000010729 rc2 = sqlite3_test_control(testctrl, p->db, opt);
drhef302e82017-11-15 19:14:08 +000010730 isOk = 3;
drh2ce15c32017-07-11 13:34:40 +000010731 }
10732 break;
10733
10734 /* sqlite3_test_control(int) */
10735 case SQLITE_TESTCTRL_PRNG_SAVE:
10736 case SQLITE_TESTCTRL_PRNG_RESTORE:
drh2ce15c32017-07-11 13:34:40 +000010737 case SQLITE_TESTCTRL_BYTEORDER:
10738 if( nArg==2 ){
10739 rc2 = sqlite3_test_control(testctrl);
drhef302e82017-11-15 19:14:08 +000010740 isOk = testctrl==SQLITE_TESTCTRL_BYTEORDER ? 1 : 3;
drh2ce15c32017-07-11 13:34:40 +000010741 }
10742 break;
10743
10744 /* sqlite3_test_control(int, uint) */
10745 case SQLITE_TESTCTRL_PENDING_BYTE:
10746 if( nArg==3 ){
10747 unsigned int opt = (unsigned int)integerValue(azArg[2]);
10748 rc2 = sqlite3_test_control(testctrl, opt);
drhef302e82017-11-15 19:14:08 +000010749 isOk = 3;
drh2ce15c32017-07-11 13:34:40 +000010750 }
10751 break;
10752
drh2e6d83b2019-08-03 01:39:20 +000010753 /* sqlite3_test_control(int, int, sqlite3*) */
10754 case SQLITE_TESTCTRL_PRNG_SEED:
10755 if( nArg==3 || nArg==4 ){
drh51755a72019-08-08 19:40:29 +000010756 int ii = (int)integerValue(azArg[2]);
drh2e6d83b2019-08-03 01:39:20 +000010757 sqlite3 *db;
drhbf70f1b2022-10-19 18:04:42 +000010758 if( ii==0 && cli_strcmp(azArg[2],"random")==0 ){
drh41428a92019-08-12 16:25:11 +000010759 sqlite3_randomness(sizeof(ii),&ii);
10760 printf("-- random seed: %d\n", ii);
10761 }
drh2e6d83b2019-08-03 01:39:20 +000010762 if( nArg==3 ){
10763 db = 0;
10764 }else{
10765 db = p->db;
10766 /* Make sure the schema has been loaded */
10767 sqlite3_table_column_metadata(db, 0, "x", 0, 0, 0, 0, 0, 0);
10768 }
drh51755a72019-08-08 19:40:29 +000010769 rc2 = sqlite3_test_control(testctrl, ii, db);
drh2e6d83b2019-08-03 01:39:20 +000010770 isOk = 3;
10771 }
10772 break;
10773
drh2ce15c32017-07-11 13:34:40 +000010774 /* sqlite3_test_control(int, int) */
10775 case SQLITE_TESTCTRL_ASSERT:
10776 case SQLITE_TESTCTRL_ALWAYS:
drhef302e82017-11-15 19:14:08 +000010777 if( nArg==3 ){
10778 int opt = booleanValue(azArg[2]);
10779 rc2 = sqlite3_test_control(testctrl, opt);
10780 isOk = 1;
10781 }
10782 break;
10783
10784 /* sqlite3_test_control(int, int) */
10785 case SQLITE_TESTCTRL_LOCALTIME_FAULT:
drh2ce15c32017-07-11 13:34:40 +000010786 case SQLITE_TESTCTRL_NEVER_CORRUPT:
10787 if( nArg==3 ){
10788 int opt = booleanValue(azArg[2]);
10789 rc2 = sqlite3_test_control(testctrl, opt);
drhef302e82017-11-15 19:14:08 +000010790 isOk = 3;
drh2ce15c32017-07-11 13:34:40 +000010791 }
10792 break;
10793
drh171c50e2020-01-01 15:43:30 +000010794 /* sqlite3_test_control(sqlite3*) */
10795 case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
10796 rc2 = sqlite3_test_control(testctrl, p->db);
drh2a83c102020-01-01 23:02:35 +000010797 isOk = 3;
drh171c50e2020-01-01 15:43:30 +000010798 break;
10799
drh2ce15c32017-07-11 13:34:40 +000010800 case SQLITE_TESTCTRL_IMPOSTER:
10801 if( nArg==5 ){
10802 rc2 = sqlite3_test_control(testctrl, p->db,
10803 azArg[2],
10804 integerValue(azArg[3]),
10805 integerValue(azArg[4]));
drhef302e82017-11-15 19:14:08 +000010806 isOk = 3;
drh2ce15c32017-07-11 13:34:40 +000010807 }
10808 break;
drh0d9de992017-12-26 18:04:23 +000010809
drh37ccfcf2020-08-31 18:49:04 +000010810 case SQLITE_TESTCTRL_SEEK_COUNT: {
10811 u64 x = 0;
10812 rc2 = sqlite3_test_control(testctrl, p->db, &x);
10813 utf8_printf(p->out, "%llu\n", x);
10814 isOk = 3;
10815 break;
10816 }
10817
drh0d9de992017-12-26 18:04:23 +000010818#ifdef YYCOVERAGE
drhf3c12562021-06-04 13:16:46 +000010819 case SQLITE_TESTCTRL_PARSER_COVERAGE: {
drh0d9de992017-12-26 18:04:23 +000010820 if( nArg==2 ){
10821 sqlite3_test_control(testctrl, p->out);
10822 isOk = 3;
10823 }
drhf3c12562021-06-04 13:16:46 +000010824 break;
10825 }
10826#endif
10827#ifdef SQLITE_DEBUG
10828 case SQLITE_TESTCTRL_TUNE: {
10829 if( nArg==4 ){
10830 int id = (int)integerValue(azArg[2]);
drh2d26cfc2021-06-04 13:40:26 +000010831 int val = (int)integerValue(azArg[3]);
10832 sqlite3_test_control(testctrl, id, &val);
10833 isOk = 3;
10834 }else if( nArg==3 ){
10835 int id = (int)integerValue(azArg[2]);
10836 sqlite3_test_control(testctrl, -id, &rc2);
10837 isOk = 1;
10838 }else if( nArg==2 ){
10839 int id = 1;
10840 while(1){
10841 int val = 0;
10842 rc2 = sqlite3_test_control(testctrl, -id, &val);
10843 if( rc2!=SQLITE_OK ) break;
10844 if( id>1 ) utf8_printf(p->out, " ");
10845 utf8_printf(p->out, "%d: %d", id, val);
10846 id++;
10847 }
10848 if( id>1 ) utf8_printf(p->out, "\n");
drhf3c12562021-06-04 13:16:46 +000010849 isOk = 3;
10850 }
10851 break;
10852 }
drh0d9de992017-12-26 18:04:23 +000010853#endif
dan779e9902021-07-28 18:13:28 +000010854 case SQLITE_TESTCTRL_SORTER_MMAP:
10855 if( nArg==3 ){
10856 int opt = (unsigned int)integerValue(azArg[2]);
10857 rc2 = sqlite3_test_control(testctrl, p->db, opt);
10858 isOk = 3;
10859 }
10860 break;
drh2ce15c32017-07-11 13:34:40 +000010861 }
10862 }
drhef302e82017-11-15 19:14:08 +000010863 if( isOk==0 && iCtrl>=0 ){
drhe2754c12019-08-26 12:50:01 +000010864 utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
drhef302e82017-11-15 19:14:08 +000010865 rc = 1;
10866 }else if( isOk==1 ){
10867 raw_printf(p->out, "%d\n", rc2);
10868 }else if( isOk==2 ){
10869 raw_printf(p->out, "0x%08x\n", rc2);
10870 }
drh2ce15c32017-07-11 13:34:40 +000010871 }else
10872#endif /* !defined(SQLITE_UNTESTABLE) */
10873
drhbf70f1b2022-10-19 18:04:42 +000010874 if( c=='t' && n>4 && cli_strncmp(azArg[0], "timeout", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010875 open_db(p, 0);
10876 sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
10877 }else
10878
drhbf70f1b2022-10-19 18:04:42 +000010879 if( c=='t' && n>=5 && cli_strncmp(azArg[0], "timer", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010880 if( nArg==2 ){
10881 enableTimer = booleanValue(azArg[1]);
10882 if( enableTimer && !HAS_TIMER ){
10883 raw_printf(stderr, "Error: timer not available on this system.\n");
10884 enableTimer = 0;
10885 }
10886 }else{
10887 raw_printf(stderr, "Usage: .timer on|off\n");
10888 rc = 1;
10889 }
10890 }else
10891
drh707821f2018-12-05 13:39:06 +000010892#ifndef SQLITE_OMIT_TRACE
drhbf70f1b2022-10-19 18:04:42 +000010893 if( c=='t' && cli_strncmp(azArg[0], "trace", n)==0 ){
drh707821f2018-12-05 13:39:06 +000010894 int mType = 0;
10895 int jj;
drh2ce15c32017-07-11 13:34:40 +000010896 open_db(p, 0);
drh707821f2018-12-05 13:39:06 +000010897 for(jj=1; jj<nArg; jj++){
10898 const char *z = azArg[jj];
10899 if( z[0]=='-' ){
10900 if( optionMatch(z, "expanded") ){
10901 p->eTraceType = SHELL_TRACE_EXPANDED;
10902 }
10903#ifdef SQLITE_ENABLE_NORMALIZE
10904 else if( optionMatch(z, "normalized") ){
10905 p->eTraceType = SHELL_TRACE_NORMALIZED;
10906 }
10907#endif
10908 else if( optionMatch(z, "plain") ){
10909 p->eTraceType = SHELL_TRACE_PLAIN;
10910 }
10911 else if( optionMatch(z, "profile") ){
10912 mType |= SQLITE_TRACE_PROFILE;
10913 }
10914 else if( optionMatch(z, "row") ){
10915 mType |= SQLITE_TRACE_ROW;
10916 }
10917 else if( optionMatch(z, "stmt") ){
10918 mType |= SQLITE_TRACE_STMT;
10919 }
10920 else if( optionMatch(z, "close") ){
10921 mType |= SQLITE_TRACE_CLOSE;
10922 }
10923 else {
10924 raw_printf(stderr, "Unknown option \"%s\" on \".trace\"\n", z);
10925 rc = 1;
10926 goto meta_command_exit;
10927 }
10928 }else{
10929 output_file_close(p->traceOut);
larrybrc1ca1832022-11-28 02:28:44 +000010930 p->traceOut = output_file_open(z, 0);
drh707821f2018-12-05 13:39:06 +000010931 }
drh2ce15c32017-07-11 13:34:40 +000010932 }
drh2ce15c32017-07-11 13:34:40 +000010933 if( p->traceOut==0 ){
10934 sqlite3_trace_v2(p->db, 0, 0, 0);
10935 }else{
drh707821f2018-12-05 13:39:06 +000010936 if( mType==0 ) mType = SQLITE_TRACE_STMT;
10937 sqlite3_trace_v2(p->db, mType, sql_trace_callback, p);
drh2ce15c32017-07-11 13:34:40 +000010938 }
drh2ce15c32017-07-11 13:34:40 +000010939 }else
drh707821f2018-12-05 13:39:06 +000010940#endif /* !defined(SQLITE_OMIT_TRACE) */
drh2ce15c32017-07-11 13:34:40 +000010941
drhe2b7a762019-10-02 00:25:08 +000010942#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE)
drhbf70f1b2022-10-19 18:04:42 +000010943 if( c=='u' && cli_strncmp(azArg[0], "unmodule", n)==0 ){
drhcc5979d2019-08-16 22:58:29 +000010944 int ii;
drh8c754a32019-08-19 20:35:30 +000010945 int lenOpt;
drh5df84282019-08-17 19:45:25 +000010946 char *zOpt;
drhcc5979d2019-08-16 22:58:29 +000010947 if( nArg<2 ){
drh5df84282019-08-17 19:45:25 +000010948 raw_printf(stderr, "Usage: .unmodule [--allexcept] NAME ...\n");
drhcc5979d2019-08-16 22:58:29 +000010949 rc = 1;
10950 goto meta_command_exit;
10951 }
10952 open_db(p, 0);
drh5df84282019-08-17 19:45:25 +000010953 zOpt = azArg[1];
10954 if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++;
drh8c754a32019-08-19 20:35:30 +000010955 lenOpt = (int)strlen(zOpt);
drhbf70f1b2022-10-19 18:04:42 +000010956 if( lenOpt>=3 && cli_strncmp(zOpt, "-allexcept",lenOpt)==0 ){
drh5df84282019-08-17 19:45:25 +000010957 assert( azArg[nArg]==0 );
drh8c754a32019-08-19 20:35:30 +000010958 sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0);
drh5df84282019-08-17 19:45:25 +000010959 }else{
10960 for(ii=1; ii<nArg; ii++){
10961 sqlite3_create_module(p->db, azArg[ii], 0, 0);
10962 }
drhcc5979d2019-08-16 22:58:29 +000010963 }
10964 }else
10965#endif
10966
drh2ce15c32017-07-11 13:34:40 +000010967#if SQLITE_USER_AUTHENTICATION
drhbf70f1b2022-10-19 18:04:42 +000010968 if( c=='u' && cli_strncmp(azArg[0], "user", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000010969 if( nArg<2 ){
10970 raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n");
10971 rc = 1;
10972 goto meta_command_exit;
10973 }
10974 open_db(p, 0);
drhbf70f1b2022-10-19 18:04:42 +000010975 if( cli_strcmp(azArg[1],"login")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010976 if( nArg!=4 ){
10977 raw_printf(stderr, "Usage: .user login USER PASSWORD\n");
10978 rc = 1;
10979 goto meta_command_exit;
10980 }
drhe2754c12019-08-26 12:50:01 +000010981 rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
10982 strlen30(azArg[3]));
drh2ce15c32017-07-11 13:34:40 +000010983 if( rc ){
10984 utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
10985 rc = 1;
10986 }
drhbf70f1b2022-10-19 18:04:42 +000010987 }else if( cli_strcmp(azArg[1],"add")==0 ){
drh2ce15c32017-07-11 13:34:40 +000010988 if( nArg!=5 ){
10989 raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
10990 rc = 1;
10991 goto meta_command_exit;
10992 }
drhaf2770f2018-01-05 14:55:43 +000010993 rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
drh2ce15c32017-07-11 13:34:40 +000010994 booleanValue(azArg[4]));
10995 if( rc ){
10996 raw_printf(stderr, "User-Add failed: %d\n", rc);
10997 rc = 1;
10998 }
drhbf70f1b2022-10-19 18:04:42 +000010999 }else if( cli_strcmp(azArg[1],"edit")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011000 if( nArg!=5 ){
11001 raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
11002 rc = 1;
11003 goto meta_command_exit;
11004 }
drhaf2770f2018-01-05 14:55:43 +000011005 rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
drh2ce15c32017-07-11 13:34:40 +000011006 booleanValue(azArg[4]));
11007 if( rc ){
11008 raw_printf(stderr, "User-Edit failed: %d\n", rc);
11009 rc = 1;
11010 }
drhbf70f1b2022-10-19 18:04:42 +000011011 }else if( cli_strcmp(azArg[1],"delete")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011012 if( nArg!=3 ){
11013 raw_printf(stderr, "Usage: .user delete USER\n");
11014 rc = 1;
11015 goto meta_command_exit;
11016 }
11017 rc = sqlite3_user_delete(p->db, azArg[2]);
11018 if( rc ){
11019 raw_printf(stderr, "User-Delete failed: %d\n", rc);
11020 rc = 1;
11021 }
11022 }else{
11023 raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n");
11024 rc = 1;
11025 goto meta_command_exit;
11026 }
11027 }else
11028#endif /* SQLITE_USER_AUTHENTICATION */
11029
drhbf70f1b2022-10-19 18:04:42 +000011030 if( c=='v' && cli_strncmp(azArg[0], "version", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000011031 utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
11032 sqlite3_libversion(), sqlite3_sourceid());
drh0ed2fd82018-01-16 20:05:27 +000011033#if SQLITE_HAVE_ZLIB
11034 utf8_printf(p->out, "zlib version %s\n", zlibVersion());
11035#endif
11036#define CTIMEOPT_VAL_(opt) #opt
11037#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
11038#if defined(__clang__) && defined(__clang_major__)
11039 utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
11040 CTIMEOPT_VAL(__clang_minor__) "."
11041 CTIMEOPT_VAL(__clang_patchlevel__) "\n");
11042#elif defined(_MSC_VER)
11043 utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n");
11044#elif defined(__GNUC__) && defined(__VERSION__)
11045 utf8_printf(p->out, "gcc-" __VERSION__ "\n");
11046#endif
drh2ce15c32017-07-11 13:34:40 +000011047 }else
11048
drhbf70f1b2022-10-19 18:04:42 +000011049 if( c=='v' && cli_strncmp(azArg[0], "vfsinfo", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000011050 const char *zDbName = nArg==2 ? azArg[1] : "main";
11051 sqlite3_vfs *pVfs = 0;
11052 if( p->db ){
11053 sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
11054 if( pVfs ){
11055 utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
11056 raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
11057 raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
11058 raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
11059 }
11060 }
11061 }else
11062
drhbf70f1b2022-10-19 18:04:42 +000011063 if( c=='v' && cli_strncmp(azArg[0], "vfslist", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000011064 sqlite3_vfs *pVfs;
11065 sqlite3_vfs *pCurrent = 0;
11066 if( p->db ){
11067 sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
11068 }
11069 for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
11070 utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
11071 pVfs==pCurrent ? " <--- CURRENT" : "");
11072 raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
11073 raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
11074 raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
11075 if( pVfs->pNext ){
11076 raw_printf(p->out, "-----------------------------------\n");
11077 }
11078 }
11079 }else
11080
drhbf70f1b2022-10-19 18:04:42 +000011081 if( c=='v' && cli_strncmp(azArg[0], "vfsname", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000011082 const char *zDbName = nArg==2 ? azArg[1] : "main";
11083 char *zVfsName = 0;
11084 if( p->db ){
11085 sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
11086 if( zVfsName ){
11087 utf8_printf(p->out, "%s\n", zVfsName);
11088 sqlite3_free(zVfsName);
11089 }
11090 }
11091 }else
11092
drhbf70f1b2022-10-19 18:04:42 +000011093 if( c=='w' && cli_strncmp(azArg[0], "wheretrace", n)==0 ){
larrybr0953c532022-12-23 19:04:59 +000011094 unsigned int x = nArg>=2? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
drhc0622a42020-12-04 01:17:57 +000011095 sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x);
drh2ce15c32017-07-11 13:34:40 +000011096 }else
drh2ce15c32017-07-11 13:34:40 +000011097
drhbf70f1b2022-10-19 18:04:42 +000011098 if( c=='w' && cli_strncmp(azArg[0], "width", n)==0 ){
drh2ce15c32017-07-11 13:34:40 +000011099 int j;
11100 assert( nArg<=ArraySize(azArg) );
drh0285d982020-05-29 14:38:43 +000011101 p->nWidth = nArg-1;
drh76fc88f2021-10-02 16:39:16 +000011102 p->colWidth = realloc(p->colWidth, (p->nWidth+1)*sizeof(int)*2);
drh0285d982020-05-29 14:38:43 +000011103 if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory();
11104 if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth];
11105 for(j=1; j<nArg; j++){
drh2ce15c32017-07-11 13:34:40 +000011106 p->colWidth[j-1] = (int)integerValue(azArg[j]);
11107 }
11108 }else
11109
11110 {
11111 utf8_printf(stderr, "Error: unknown command or invalid arguments: "
11112 " \"%s\". Enter \".help\" for help\n", azArg[0]);
11113 rc = 1;
11114 }
11115
11116meta_command_exit:
11117 if( p->outCount ){
11118 p->outCount--;
11119 if( p->outCount==0 ) output_reset(p);
11120 }
drhb97e2ad2021-08-26 18:31:39 +000011121 p->bSafeMode = p->bSafeModePersist;
drh2ce15c32017-07-11 13:34:40 +000011122 return rc;
11123}
11124
larrybr8bc4cbc2021-09-10 00:58:46 +000011125/* Line scan result and intermediate states (supporting scan resumption)
drh2ce15c32017-07-11 13:34:40 +000011126*/
drh68911c22021-09-22 14:26:22 +000011127#ifndef CHAR_BIT
11128# define CHAR_BIT 8
11129#endif
larrybr8bc4cbc2021-09-10 00:58:46 +000011130typedef enum {
larrybr7e009842021-09-18 21:35:22 +000011131 QSS_HasDark = 1<<CHAR_BIT, QSS_EndingSemi = 2<<CHAR_BIT,
11132 QSS_CharMask = (1<<CHAR_BIT)-1, QSS_ScanMask = 3<<CHAR_BIT,
larrybra96bbe92021-09-10 19:45:22 +000011133 QSS_Start = 0
larrybr8bc4cbc2021-09-10 00:58:46 +000011134} QuickScanState;
larrybr7e009842021-09-18 21:35:22 +000011135#define QSS_SETV(qss, newst) ((newst) | ((qss) & QSS_ScanMask))
11136#define QSS_INPLAIN(qss) (((qss)&QSS_CharMask)==QSS_Start)
11137#define QSS_PLAINWHITE(qss) (((qss)&~QSS_EndingSemi)==QSS_Start)
larrybra96bbe92021-09-10 19:45:22 +000011138#define QSS_PLAINDARK(qss) (((qss)&~QSS_EndingSemi)==QSS_HasDark)
larrybr7e009842021-09-18 21:35:22 +000011139#define QSS_SEMITERM(qss) (((qss)&~QSS_HasDark)==QSS_EndingSemi)
drh2ce15c32017-07-11 13:34:40 +000011140
11141/*
larrybr8bc4cbc2021-09-10 00:58:46 +000011142** Scan line for classification to guide shell's handling.
11143** The scan is resumable for subsequent lines when prior
11144** return values are passed as the 2nd argument.
drh2ce15c32017-07-11 13:34:40 +000011145*/
larrybr9ab15982022-12-06 05:09:51 +000011146static QuickScanState quickscan(char *zLine, QuickScanState qss,
larrybr88fbe1612022-12-17 19:56:28 +000011147 SCAN_TRACKER_REFTYPE pst){
larrybr8bc4cbc2021-09-10 00:58:46 +000011148 char cin;
larrybr7e009842021-09-18 21:35:22 +000011149 char cWait = (char)qss; /* intentional narrowing loss */
11150 if( cWait==0 ){
11151 PlainScan:
drhe85e1da2021-10-01 21:01:07 +000011152 assert( cWait==0 );
drhfd7abcd2021-09-22 13:43:16 +000011153 while( (cin = *zLine++)!=0 ){
larrybr8bc4cbc2021-09-10 00:58:46 +000011154 if( IsSpace(cin) )
11155 continue;
11156 switch (cin){
11157 case '-':
larrybr7e009842021-09-18 21:35:22 +000011158 if( *zLine!='-' )
11159 break;
11160 while((cin = *++zLine)!=0 )
11161 if( cin=='\n')
11162 goto PlainScan;
11163 return qss;
larrybr8bc4cbc2021-09-10 00:58:46 +000011164 case ';':
larrybra96bbe92021-09-10 19:45:22 +000011165 qss |= QSS_EndingSemi;
11166 continue;
larrybr8bc4cbc2021-09-10 00:58:46 +000011167 case '/':
11168 if( *zLine=='*' ){
11169 ++zLine;
larrybr7e009842021-09-18 21:35:22 +000011170 cWait = '*';
larrybr88fbe1612022-12-17 19:56:28 +000011171 CONTINUE_PROMPT_AWAITS(pst, "/*");
larrybr7e009842021-09-18 21:35:22 +000011172 qss = QSS_SETV(qss, cWait);
11173 goto TermScan;
larrybr8bc4cbc2021-09-10 00:58:46 +000011174 }
11175 break;
larrybra96bbe92021-09-10 19:45:22 +000011176 case '[':
11177 cin = ']';
larrybrfd318932023-01-04 16:54:55 +000011178 deliberate_fall_through;
larrybra96bbe92021-09-10 19:45:22 +000011179 case '`': case '\'': case '"':
larrybr7e009842021-09-18 21:35:22 +000011180 cWait = cin;
11181 qss = QSS_HasDark | cWait;
larrybr88fbe1612022-12-17 19:56:28 +000011182 CONTINUE_PROMPT_AWAITC(pst, cin);
larrybr7e009842021-09-18 21:35:22 +000011183 goto TermScan;
larrybr9ab15982022-12-06 05:09:51 +000011184 case '(':
larrybr88fbe1612022-12-17 19:56:28 +000011185 CONTINUE_PAREN_INCR(pst, 1);
11186 break;
larrybr9ab15982022-12-06 05:09:51 +000011187 case ')':
larrybr88fbe1612022-12-17 19:56:28 +000011188 CONTINUE_PAREN_INCR(pst, -1);
11189 break;
larrybr8bc4cbc2021-09-10 00:58:46 +000011190 default:
11191 break;
11192 }
larrybr7e009842021-09-18 21:35:22 +000011193 qss = (qss & ~QSS_EndingSemi) | QSS_HasDark;
drh2ce15c32017-07-11 13:34:40 +000011194 }
larrybr7e009842021-09-18 21:35:22 +000011195 }else{
11196 TermScan:
drhfd7abcd2021-09-22 13:43:16 +000011197 while( (cin = *zLine++)!=0 ){
larrybr7e009842021-09-18 21:35:22 +000011198 if( cin==cWait ){
11199 switch( cWait ){
11200 case '*':
11201 if( *zLine != '/' )
11202 continue;
11203 ++zLine;
11204 cWait = 0;
larrybr88fbe1612022-12-17 19:56:28 +000011205 CONTINUE_PROMPT_AWAITC(pst, 0);
larrybr7e009842021-09-18 21:35:22 +000011206 qss = QSS_SETV(qss, 0);
11207 goto PlainScan;
11208 case '`': case '\'': case '"':
11209 if(*zLine==cWait){
larrybr88fbe1612022-12-17 19:56:28 +000011210 /* Swallow doubled end-delimiter.*/
larrybr8d463ce2021-09-11 02:42:04 +000011211 ++zLine;
larrybr7e009842021-09-18 21:35:22 +000011212 continue;
11213 }
larrybrfd318932023-01-04 16:54:55 +000011214 deliberate_fall_through;
larrybr7e009842021-09-18 21:35:22 +000011215 case ']':
11216 cWait = 0;
larrybr88fbe1612022-12-17 19:56:28 +000011217 CONTINUE_PROMPT_AWAITC(pst, 0);
larrybr7e009842021-09-18 21:35:22 +000011218 qss = QSS_SETV(qss, 0);
11219 goto PlainScan;
larrybr527c39d2022-05-10 14:55:45 +000011220 default: assert(0);
larrybr8bc4cbc2021-09-10 00:58:46 +000011221 }
11222 }
11223 }
drh2ce15c32017-07-11 13:34:40 +000011224 }
larrybr8bc4cbc2021-09-10 00:58:46 +000011225 return qss;
drh2ce15c32017-07-11 13:34:40 +000011226}
11227
11228/*
11229** Return TRUE if the line typed in is an SQL command terminator other
11230** than a semi-colon. The SQL Server style "go" command is understood
11231** as is the Oracle "/".
11232*/
larrybr8bc4cbc2021-09-10 00:58:46 +000011233static int line_is_command_terminator(char *zLine){
drh2ce15c32017-07-11 13:34:40 +000011234 while( IsSpace(zLine[0]) ){ zLine++; };
larrybr8bc4cbc2021-09-10 00:58:46 +000011235 if( zLine[0]=='/' )
11236 zLine += 1; /* Oracle */
11237 else if ( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' )
11238 zLine += 2; /* SQL Server */
11239 else
11240 return 0;
larrybr9ab15982022-12-06 05:09:51 +000011241 return quickscan(zLine, QSS_Start, 0)==QSS_Start;
drh2ce15c32017-07-11 13:34:40 +000011242}
11243
11244/*
drh841c98e2022-11-17 01:24:06 +000011245** The CLI needs a working sqlite3_complete() to work properly. So error
11246** out of the build if compiling with SQLITE_OMIT_COMPLETE.
drh56f17742018-01-24 01:58:49 +000011247*/
11248#ifdef SQLITE_OMIT_COMPLETE
drh841c98e2022-11-17 01:24:06 +000011249# error the CLI application is imcompatable with SQLITE_OMIT_COMPLETE.
drh56f17742018-01-24 01:58:49 +000011250#endif
11251
11252/*
drh2ce15c32017-07-11 13:34:40 +000011253** Return true if zSql is a complete SQL statement. Return false if it
11254** ends in the middle of a string literal or C-style comment.
11255*/
11256static int line_is_complete(char *zSql, int nSql){
11257 int rc;
11258 if( zSql==0 ) return 1;
11259 zSql[nSql] = ';';
11260 zSql[nSql+1] = 0;
11261 rc = sqlite3_complete(zSql);
11262 zSql[nSql] = 0;
11263 return rc;
11264}
11265
11266/*
drhfc29a862018-05-11 19:11:18 +000011267** Run a single line of SQL. Return the number of errors.
drh2ce15c32017-07-11 13:34:40 +000011268*/
11269static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
11270 int rc;
11271 char *zErrMsg = 0;
11272
11273 open_db(p, 0);
11274 if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
drhfc4eeef2019-02-05 19:48:46 +000011275 if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
drh2ce15c32017-07-11 13:34:40 +000011276 BEGIN_TIMER;
drha10b9992018-03-09 15:24:33 +000011277 rc = shell_exec(p, zSql, &zErrMsg);
drh2ce15c32017-07-11 13:34:40 +000011278 END_TIMER;
11279 if( rc || zErrMsg ){
11280 char zPrefix[100];
drh3e46db22022-02-08 11:52:45 +000011281 const char *zErrorTail;
11282 const char *zErrorType;
11283 if( zErrMsg==0 ){
11284 zErrorType = "Error";
11285 zErrorTail = sqlite3_errmsg(p->db);
drhbf70f1b2022-10-19 18:04:42 +000011286 }else if( cli_strncmp(zErrMsg, "in prepare, ",12)==0 ){
drh3e46db22022-02-08 11:52:45 +000011287 zErrorType = "Parse error";
11288 zErrorTail = &zErrMsg[12];
drhbf70f1b2022-10-19 18:04:42 +000011289 }else if( cli_strncmp(zErrMsg, "stepping, ", 10)==0 ){
drh3e46db22022-02-08 11:52:45 +000011290 zErrorType = "Runtime error";
11291 zErrorTail = &zErrMsg[10];
11292 }else{
11293 zErrorType = "Error";
11294 zErrorTail = zErrMsg;
11295 }
drh2ce15c32017-07-11 13:34:40 +000011296 if( in!=0 || !stdin_is_interactive ){
11297 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
drh3e46db22022-02-08 11:52:45 +000011298 "%s near line %d:", zErrorType, startline);
drh2ce15c32017-07-11 13:34:40 +000011299 }else{
drh3e46db22022-02-08 11:52:45 +000011300 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType);
drh2ce15c32017-07-11 13:34:40 +000011301 }
drh3e46db22022-02-08 11:52:45 +000011302 utf8_printf(stderr, "%s %s\n", zPrefix, zErrorTail);
11303 sqlite3_free(zErrMsg);
11304 zErrMsg = 0;
drh2ce15c32017-07-11 13:34:40 +000011305 return 1;
11306 }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
drh6d9f0342021-09-22 10:28:50 +000011307 char zLineBuf[2000];
11308 sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
11309 "changes: %lld total_changes: %lld",
larrybr10496f72021-06-23 16:07:20 +000011310 sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
drh6d9f0342021-09-22 10:28:50 +000011311 raw_printf(p->out, "%s\n", zLineBuf);
drh2ce15c32017-07-11 13:34:40 +000011312 }
11313 return 0;
11314}
11315
larrybrf4874812022-05-11 19:59:31 +000011316static void echo_group_input(ShellState *p, const char *zDo){
11317 if( ShellHasFlag(p, SHFLG_Echo) ) utf8_printf(p->out, "%s\n", zDo);
11318}
drh2ce15c32017-07-11 13:34:40 +000011319
stephan4413ec72022-07-12 15:53:02 +000011320#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +000011321/*
larrybr0953c532022-12-23 19:04:59 +000011322** Alternate one_input_line() impl for wasm mode. This is not in the primary
11323** impl because we need the global shellState and cannot access it from that
11324** function without moving lots of code around (creating a larger/messier diff).
stephanf8cd3d22022-05-18 17:14:24 +000011325*/
11326static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
11327 /* Parse the next line from shellState.wasm.zInput. */
11328 const char *zBegin = shellState.wasm.zPos;
11329 const char *z = zBegin;
11330 char *zLine = 0;
drh7d23d152022-10-11 12:02:42 +000011331 i64 nZ = 0;
stephanf8cd3d22022-05-18 17:14:24 +000011332
11333 UNUSED_PARAMETER(in);
11334 UNUSED_PARAMETER(isContinuation);
11335 if(!z || !*z){
11336 return 0;
11337 }
11338 while(*z && isspace(*z)) ++z;
11339 zBegin = z;
11340 for(; *z && '\n'!=*z; ++nZ, ++z){}
11341 if(nZ>0 && '\r'==zBegin[nZ-1]){
11342 --nZ;
11343 }
11344 shellState.wasm.zPos = z;
11345 zLine = realloc(zPrior, nZ+1);
11346 shell_check_oom(zLine);
drh7d23d152022-10-11 12:02:42 +000011347 memcpy(zLine, zBegin, nZ);
stephanf8cd3d22022-05-18 17:14:24 +000011348 zLine[nZ] = 0;
11349 return zLine;
11350}
stephan4413ec72022-07-12 15:53:02 +000011351#endif /* SQLITE_SHELL_FIDDLE */
stephanf8cd3d22022-05-18 17:14:24 +000011352
drh2ce15c32017-07-11 13:34:40 +000011353/*
11354** Read input from *in and process it. If *in==0 then input
11355** is interactive - the user is typing it it. Otherwise, input
11356** is coming from a file or device. A prompt is issued and history
11357** is saved only if input is interactive. An interrupt signal will
11358** cause this routine to exit immediately, unless input is interactive.
11359**
11360** Return the number of errors.
11361*/
drh60379d42018-12-13 18:30:01 +000011362static int process_input(ShellState *p){
drh2ce15c32017-07-11 13:34:40 +000011363 char *zLine = 0; /* A single input line */
11364 char *zSql = 0; /* Accumulated SQL text */
drh7d23d152022-10-11 12:02:42 +000011365 i64 nLine; /* Length of current line */
11366 i64 nSql = 0; /* Bytes of zSql[] used */
11367 i64 nAlloc = 0; /* Allocated zSql[] space */
drh2ce15c32017-07-11 13:34:40 +000011368 int rc; /* Error code */
11369 int errCnt = 0; /* Number of errors seen */
drh7d23d152022-10-11 12:02:42 +000011370 i64 startline = 0; /* Line number for start of current input */
larrybr7e009842021-09-18 21:35:22 +000011371 QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
drh2ce15c32017-07-11 13:34:40 +000011372
larrybrd48e88e2022-01-24 06:36:16 +000011373 if( p->inputNesting==MAX_INPUT_NESTING ){
11374 /* This will be more informative in a later version. */
11375 utf8_printf(stderr,"Input nesting limit (%d) reached at line %d."
11376 " Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
11377 return 1;
11378 }
11379 ++p->inputNesting;
drh2c8ee022018-12-13 18:59:30 +000011380 p->lineno = 0;
larrybr29226fc2022-12-06 17:59:05 +000011381 CONTINUE_PROMPT_RESET;
drh60379d42018-12-13 18:30:01 +000011382 while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
drh2ce15c32017-07-11 13:34:40 +000011383 fflush(p->out);
drh60379d42018-12-13 18:30:01 +000011384 zLine = one_input_line(p->in, zLine, nSql>0);
drh2ce15c32017-07-11 13:34:40 +000011385 if( zLine==0 ){
11386 /* End of input */
drh60379d42018-12-13 18:30:01 +000011387 if( p->in==0 && stdin_is_interactive ) printf("\n");
drh2ce15c32017-07-11 13:34:40 +000011388 break;
11389 }
11390 if( seenInterrupt ){
drh60379d42018-12-13 18:30:01 +000011391 if( p->in!=0 ) break;
drh2ce15c32017-07-11 13:34:40 +000011392 seenInterrupt = 0;
11393 }
drh2c8ee022018-12-13 18:59:30 +000011394 p->lineno++;
larrybr7e009842021-09-18 21:35:22 +000011395 if( QSS_INPLAIN(qss)
larrybr8bc4cbc2021-09-10 00:58:46 +000011396 && line_is_command_terminator(zLine)
11397 && line_is_complete(zSql, nSql) ){
11398 memcpy(zLine,";",2);
11399 }
larrybr29226fc2022-12-06 17:59:05 +000011400 qss = quickscan(zLine, qss, CONTINUE_PROMPT_PSTATE);
larrybr8bc4cbc2021-09-10 00:58:46 +000011401 if( QSS_PLAINWHITE(qss) && nSql==0 ){
larrybrd797d6b2021-10-03 22:03:59 +000011402 /* Just swallow single-line whitespace */
larrybrf4874812022-05-11 19:59:31 +000011403 echo_group_input(p, zLine);
larrybrd797d6b2021-10-03 22:03:59 +000011404 qss = QSS_Start;
larrybr8bc4cbc2021-09-10 00:58:46 +000011405 continue;
drh2ce15c32017-07-11 13:34:40 +000011406 }
drh1615c372018-05-12 23:56:22 +000011407 if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){
larrybr29226fc2022-12-06 17:59:05 +000011408 CONTINUE_PROMPT_RESET;
larrybrf4874812022-05-11 19:59:31 +000011409 echo_group_input(p, zLine);
drh1615c372018-05-12 23:56:22 +000011410 if( zLine[0]=='.' ){
11411 rc = do_meta_command(zLine, p);
11412 if( rc==2 ){ /* exit requested */
11413 break;
11414 }else if( rc ){
11415 errCnt++;
11416 }
drh2ce15c32017-07-11 13:34:40 +000011417 }
larrybr81012162021-10-02 15:34:52 +000011418 qss = QSS_Start;
drh2ce15c32017-07-11 13:34:40 +000011419 continue;
11420 }
larrybrd797d6b2021-10-03 22:03:59 +000011421 /* No single-line dispositions remain; accumulate line(s). */
drh7d23d152022-10-11 12:02:42 +000011422 nLine = strlen(zLine);
drh2ce15c32017-07-11 13:34:40 +000011423 if( nSql+nLine+2>=nAlloc ){
larrybr31bffb42021-09-08 21:49:03 +000011424 /* Grow buffer by half-again increments when big. */
11425 nAlloc = nSql+(nSql>>1)+nLine+100;
drh2ce15c32017-07-11 13:34:40 +000011426 zSql = realloc(zSql, nAlloc);
drhe3e25652021-12-16 13:29:28 +000011427 shell_check_oom(zSql);
drh2ce15c32017-07-11 13:34:40 +000011428 }
drh2ce15c32017-07-11 13:34:40 +000011429 if( nSql==0 ){
drh7d23d152022-10-11 12:02:42 +000011430 i64 i;
drh2ce15c32017-07-11 13:34:40 +000011431 for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
11432 assert( nAlloc>0 && zSql!=0 );
11433 memcpy(zSql, zLine+i, nLine+1-i);
drh2c8ee022018-12-13 18:59:30 +000011434 startline = p->lineno;
drh2ce15c32017-07-11 13:34:40 +000011435 nSql = nLine-i;
11436 }else{
11437 zSql[nSql++] = '\n';
11438 memcpy(zSql+nSql, zLine, nLine+1);
11439 nSql += nLine;
11440 }
larrybra96bbe92021-09-10 19:45:22 +000011441 if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){
larrybrf4874812022-05-11 19:59:31 +000011442 echo_group_input(p, zSql);
drh60379d42018-12-13 18:30:01 +000011443 errCnt += runOneSqlLine(p, zSql, p->in, startline);
larrybr29226fc2022-12-06 17:59:05 +000011444 CONTINUE_PROMPT_RESET;
drh2ce15c32017-07-11 13:34:40 +000011445 nSql = 0;
11446 if( p->outCount ){
11447 output_reset(p);
11448 p->outCount = 0;
drh13c20932018-01-10 21:41:55 +000011449 }else{
11450 clearTempFile(p);
drh2ce15c32017-07-11 13:34:40 +000011451 }
drhb97e2ad2021-08-26 18:31:39 +000011452 p->bSafeMode = p->bSafeModePersist;
larrybrd797d6b2021-10-03 22:03:59 +000011453 qss = QSS_Start;
larrybr8bc4cbc2021-09-10 00:58:46 +000011454 }else if( nSql && QSS_PLAINWHITE(qss) ){
larrybrf4874812022-05-11 19:59:31 +000011455 echo_group_input(p, zSql);
drh2ce15c32017-07-11 13:34:40 +000011456 nSql = 0;
larrybrd797d6b2021-10-03 22:03:59 +000011457 qss = QSS_Start;
drh2ce15c32017-07-11 13:34:40 +000011458 }
11459 }
larrybrc6e2f2e2022-03-15 17:57:42 +000011460 if( nSql ){
11461 /* This may be incomplete. Let the SQL parser deal with that. */
larrybrf4874812022-05-11 19:59:31 +000011462 echo_group_input(p, zSql);
drh60379d42018-12-13 18:30:01 +000011463 errCnt += runOneSqlLine(p, zSql, p->in, startline);
larrybr29226fc2022-12-06 17:59:05 +000011464 CONTINUE_PROMPT_RESET;
drh2ce15c32017-07-11 13:34:40 +000011465 }
11466 free(zSql);
11467 free(zLine);
larrybrd48e88e2022-01-24 06:36:16 +000011468 --p->inputNesting;
drh2ce15c32017-07-11 13:34:40 +000011469 return errCnt>0;
11470}
11471
11472/*
11473** Return a pathname which is the user's home directory. A
11474** 0 return indicates an error of some kind.
11475*/
11476static char *find_home_dir(int clearFlag){
11477 static char *home_dir = NULL;
11478 if( clearFlag ){
11479 free(home_dir);
11480 home_dir = 0;
11481 return 0;
11482 }
11483 if( home_dir ) return home_dir;
11484
11485#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
11486 && !defined(__RTP__) && !defined(_WRS_KERNEL)
11487 {
11488 struct passwd *pwent;
11489 uid_t uid = getuid();
11490 if( (pwent=getpwuid(uid)) != NULL) {
11491 home_dir = pwent->pw_dir;
11492 }
11493 }
11494#endif
11495
11496#if defined(_WIN32_WCE)
11497 /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
11498 */
11499 home_dir = "/";
11500#else
11501
11502#if defined(_WIN32) || defined(WIN32)
11503 if (!home_dir) {
11504 home_dir = getenv("USERPROFILE");
11505 }
11506#endif
11507
11508 if (!home_dir) {
11509 home_dir = getenv("HOME");
11510 }
11511
11512#if defined(_WIN32) || defined(WIN32)
11513 if (!home_dir) {
11514 char *zDrive, *zPath;
11515 int n;
11516 zDrive = getenv("HOMEDRIVE");
11517 zPath = getenv("HOMEPATH");
11518 if( zDrive && zPath ){
11519 n = strlen30(zDrive) + strlen30(zPath) + 1;
11520 home_dir = malloc( n );
11521 if( home_dir==0 ) return 0;
11522 sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
11523 return home_dir;
11524 }
11525 home_dir = "c:\\";
11526 }
11527#endif
11528
11529#endif /* !_WIN32_WCE */
11530
11531 if( home_dir ){
drh7d23d152022-10-11 12:02:42 +000011532 i64 n = strlen(home_dir) + 1;
drh2ce15c32017-07-11 13:34:40 +000011533 char *z = malloc( n );
11534 if( z ) memcpy(z, home_dir, n);
11535 home_dir = z;
11536 }
11537
11538 return home_dir;
11539}
11540
11541/*
stephan6e8a3342022-11-06 13:12:11 +000011542** On non-Windows platforms, look for $XDG_CONFIG_HOME.
11543** If ${XDG_CONFIG_HOME}/sqlite3/sqliterc is found, return
11544** the path to it, else return 0. The result is cached for
11545** subsequent calls.
11546*/
11547static const char *find_xdg_config(void){
11548#if defined(_WIN32) || defined(WIN32) || defined(_WIN32_WCE) \
11549 || defined(__RTP__) || defined(_WRS_KERNEL)
11550 return 0;
11551#else
11552 static int alreadyTried = 0;
11553 static char *zConfig = 0;
11554 const char *zXdgHome;
11555
11556 if( alreadyTried!=0 ){
11557 return zConfig;
11558 }
11559 alreadyTried = 1;
11560 zXdgHome = getenv("XDG_CONFIG_HOME");
11561 if( zXdgHome==0 ){
11562 return 0;
11563 }
11564 zConfig = sqlite3_mprintf("%s/sqlite3/sqliterc", zXdgHome);
11565 shell_check_oom(zConfig);
11566 if( access(zConfig,0)!=0 ){
11567 sqlite3_free(zConfig);
11568 zConfig = 0;
11569 }
11570 return zConfig;
11571#endif
11572}
11573
11574/*
drh2ce15c32017-07-11 13:34:40 +000011575** Read input from the file given by sqliterc_override. Or if that
stephan6e8a3342022-11-06 13:12:11 +000011576** parameter is NULL, take input from the first of find_xdg_config()
11577** or ~/.sqliterc which is found.
drh2ce15c32017-07-11 13:34:40 +000011578**
11579** Returns the number of errors.
11580*/
11581static void process_sqliterc(
11582 ShellState *p, /* Configuration data */
11583 const char *sqliterc_override /* Name of config file. NULL to use default */
11584){
11585 char *home_dir = NULL;
11586 const char *sqliterc = sqliterc_override;
11587 char *zBuf = 0;
drh60379d42018-12-13 18:30:01 +000011588 FILE *inSaved = p->in;
drh2c8ee022018-12-13 18:59:30 +000011589 int savedLineno = p->lineno;
drh2ce15c32017-07-11 13:34:40 +000011590
stephan6e8a3342022-11-06 13:12:11 +000011591 if( sqliterc == NULL ){
11592 sqliterc = find_xdg_config();
11593 }
11594 if( sqliterc == NULL ){
drh2ce15c32017-07-11 13:34:40 +000011595 home_dir = find_home_dir(0);
11596 if( home_dir==0 ){
11597 raw_printf(stderr, "-- warning: cannot find home directory;"
11598 " cannot read ~/.sqliterc\n");
11599 return;
11600 }
drh2ce15c32017-07-11 13:34:40 +000011601 zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
drhe3e25652021-12-16 13:29:28 +000011602 shell_check_oom(zBuf);
drh2ce15c32017-07-11 13:34:40 +000011603 sqliterc = zBuf;
11604 }
drh60379d42018-12-13 18:30:01 +000011605 p->in = fopen(sqliterc,"rb");
11606 if( p->in ){
drh2ce15c32017-07-11 13:34:40 +000011607 if( stdin_is_interactive ){
11608 utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
11609 }
drhb7c46aa2020-11-25 13:59:47 +000011610 if( process_input(p) && bail_on_error ) exit(1);
drh60379d42018-12-13 18:30:01 +000011611 fclose(p->in);
drhb7c46aa2020-11-25 13:59:47 +000011612 }else if( sqliterc_override!=0 ){
11613 utf8_printf(stderr,"cannot open: \"%s\"\n", sqliterc);
11614 if( bail_on_error ) exit(1);
drh2ce15c32017-07-11 13:34:40 +000011615 }
drh60379d42018-12-13 18:30:01 +000011616 p->in = inSaved;
drh2c8ee022018-12-13 18:59:30 +000011617 p->lineno = savedLineno;
drh2ce15c32017-07-11 13:34:40 +000011618 sqlite3_free(zBuf);
11619}
11620
11621/*
11622** Show available command line options
11623*/
11624static const char zOptions[] =
drhda57d962018-03-05 19:34:05 +000011625#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
drhad7fd5d2018-03-05 20:21:50 +000011626 " -A ARGS... run \".archive ARGS\" and exit\n"
drhda57d962018-03-05 19:34:05 +000011627#endif
drh3baed312018-03-08 18:14:41 +000011628 " -append append the database to the end of the file\n"
drh2ce15c32017-07-11 13:34:40 +000011629 " -ascii set output mode to 'ascii'\n"
11630 " -bail stop after hitting an error\n"
11631 " -batch force batch I/O\n"
drh0908e382020-06-04 18:05:39 +000011632 " -box set output mode to 'box'\n"
drh2ce15c32017-07-11 13:34:40 +000011633 " -column set output mode to 'column'\n"
11634 " -cmd COMMAND run \"COMMAND\" before reading stdin\n"
11635 " -csv set output mode to 'csv'\n"
drh8d889af2021-05-08 17:18:23 +000011636#if !defined(SQLITE_OMIT_DESERIALIZE)
drh6ca64482019-01-22 16:06:20 +000011637 " -deserialize open the database using sqlite3_deserialize()\n"
11638#endif
larrybr527c39d2022-05-10 14:55:45 +000011639 " -echo print inputs before execution\n"
drh2ce15c32017-07-11 13:34:40 +000011640 " -init FILENAME read/process named file\n"
11641 " -[no]header turn headers on or off\n"
11642#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
11643 " -heap SIZE Size of heap for memsys3 or memsys5\n"
11644#endif
11645 " -help show this message\n"
11646 " -html set output mode to HTML\n"
11647 " -interactive force interactive I/O\n"
drh30c54a02020-05-28 23:49:50 +000011648 " -json set output mode to 'json'\n"
drh2ce15c32017-07-11 13:34:40 +000011649 " -line set output mode to 'line'\n"
11650 " -list set output mode to 'list'\n"
11651 " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
drh30c54a02020-05-28 23:49:50 +000011652 " -markdown set output mode to 'markdown'\n"
drh8d889af2021-05-08 17:18:23 +000011653#if !defined(SQLITE_OMIT_DESERIALIZE)
drh6ca64482019-01-22 16:06:20 +000011654 " -maxsize N maximum size for a --deserialize database\n"
11655#endif
drhaf482572019-02-04 19:52:39 +000011656 " -memtrace trace all memory allocations and deallocations\n"
drh2ce15c32017-07-11 13:34:40 +000011657 " -mmap N default mmap size set to N\n"
11658#ifdef SQLITE_ENABLE_MULTIPLEX
11659 " -multiplex enable the multiplexor VFS\n"
11660#endif
11661 " -newline SEP set output row separator. Default: '\\n'\n"
drh0933aad2019-11-18 17:46:38 +000011662 " -nofollow refuse to open symbolic links to database files\n"
drhb97e2ad2021-08-26 18:31:39 +000011663 " -nonce STRING set the safe-mode escape nonce\n"
drh2ce15c32017-07-11 13:34:40 +000011664 " -nullvalue TEXT set text string for NULL values. Default ''\n"
11665 " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
11666 " -quote set output mode to 'quote'\n"
drhee269a62018-02-14 23:27:43 +000011667 " -readonly open the database read-only\n"
drhb97e2ad2021-08-26 18:31:39 +000011668 " -safe enable safe-mode\n"
drh2ce15c32017-07-11 13:34:40 +000011669 " -separator SEP set output column separator. Default: '|'\n"
drha90d84f2018-04-18 15:21:13 +000011670#ifdef SQLITE_ENABLE_SORTER_REFERENCES
11671 " -sorterref SIZE sorter references threshold size\n"
11672#endif
drh2ce15c32017-07-11 13:34:40 +000011673 " -stats print memory stats before each finalize\n"
drh30c54a02020-05-28 23:49:50 +000011674 " -table set output mode to 'table'\n"
drh2fa78182020-10-31 18:58:37 +000011675 " -tabs set output mode to 'tabs'\n"
drh2ce15c32017-07-11 13:34:40 +000011676 " -version show SQLite version\n"
11677 " -vfs NAME use NAME as the default VFS\n"
11678#ifdef SQLITE_ENABLE_VFSTRACE
11679 " -vfstrace enable tracing of all VFS calls\n"
11680#endif
drh3baed312018-03-08 18:14:41 +000011681#ifdef SQLITE_HAVE_ZLIB
11682 " -zip open the file as a ZIP Archive\n"
11683#endif
drh2ce15c32017-07-11 13:34:40 +000011684;
11685static void usage(int showDetail){
11686 utf8_printf(stderr,
11687 "Usage: %s [OPTIONS] FILENAME [SQL]\n"
11688 "FILENAME is the name of an SQLite database. A new database is created\n"
11689 "if the file does not previously exist.\n", Argv0);
11690 if( showDetail ){
11691 utf8_printf(stderr, "OPTIONS include:\n%s", zOptions);
11692 }else{
11693 raw_printf(stderr, "Use the -help option for additional information\n");
11694 }
11695 exit(1);
11696}
11697
11698/*
drhe7df8922018-04-18 10:44:58 +000011699** Internal check: Verify that the SQLite is uninitialized. Print a
11700** error message if it is initialized.
11701*/
11702static void verify_uninitialized(void){
11703 if( sqlite3_config(-1)==SQLITE_MISUSE ){
drh8e02a182018-05-30 07:24:41 +000011704 utf8_printf(stdout, "WARNING: attempt to configure SQLite after"
drhe7df8922018-04-18 10:44:58 +000011705 " initialization.\n");
11706 }
11707}
11708
11709/*
drh2ce15c32017-07-11 13:34:40 +000011710** Initialize the state information in data
11711*/
11712static void main_init(ShellState *data) {
11713 memset(data, 0, sizeof(*data));
11714 data->normalMode = data->cMode = data->mode = MODE_List;
11715 data->autoExplain = 1;
drh37407122021-07-23 18:43:58 +000011716 data->pAuxDb = &data->aAuxDb[0];
drh2ce15c32017-07-11 13:34:40 +000011717 memcpy(data->colSeparator,SEP_Column, 2);
11718 memcpy(data->rowSeparator,SEP_Row, 2);
11719 data->showHeader = 0;
11720 data->shellFlgs = SHFLG_Lookaside;
drhe7df8922018-04-18 10:44:58 +000011721 verify_uninitialized();
drh2ce15c32017-07-11 13:34:40 +000011722 sqlite3_config(SQLITE_CONFIG_URI, 1);
11723 sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
11724 sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
11725 sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
11726 sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
11727}
11728
11729/*
11730** Output text to the console in a font that attracts extra attention.
11731*/
11732#ifdef _WIN32
11733static void printBold(const char *zText){
mistachkin43e86272020-04-09 15:31:22 +000011734#if !SQLITE_OS_WINRT
drh2ce15c32017-07-11 13:34:40 +000011735 HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
11736 CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
11737 GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
11738 SetConsoleTextAttribute(out,
11739 FOREGROUND_RED|FOREGROUND_INTENSITY
11740 );
mistachkin43e86272020-04-09 15:31:22 +000011741#endif
drh2ce15c32017-07-11 13:34:40 +000011742 printf("%s", zText);
mistachkin43e86272020-04-09 15:31:22 +000011743#if !SQLITE_OS_WINRT
drh2ce15c32017-07-11 13:34:40 +000011744 SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
mistachkin43e86272020-04-09 15:31:22 +000011745#endif
drh2ce15c32017-07-11 13:34:40 +000011746}
11747#else
11748static void printBold(const char *zText){
11749 printf("\033[1m%s\033[0m", zText);
11750}
11751#endif
11752
11753/*
11754** Get the argument to an --option. Throw an error and die if no argument
11755** is available.
11756*/
11757static char *cmdline_option_value(int argc, char **argv, int i){
11758 if( i==argc ){
11759 utf8_printf(stderr, "%s: Error: missing argument to %s\n",
11760 argv[0], argv[argc-1]);
11761 exit(1);
11762 }
11763 return argv[i];
11764}
11765
11766#ifndef SQLITE_SHELL_IS_UTF8
dan39b6bd52021-03-04 18:31:07 +000011767# if (defined(_WIN32) || defined(WIN32)) \
11768 && (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
drh2ce15c32017-07-11 13:34:40 +000011769# define SQLITE_SHELL_IS_UTF8 (0)
11770# else
11771# define SQLITE_SHELL_IS_UTF8 (1)
11772# endif
11773#endif
11774
stephan4413ec72022-07-12 15:53:02 +000011775#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +000011776# define main fiddle_main
11777#endif
11778
drh2ce15c32017-07-11 13:34:40 +000011779#if SQLITE_SHELL_IS_UTF8
11780int SQLITE_CDECL main(int argc, char **argv){
11781#else
11782int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
11783 char **argv;
11784#endif
larrybrfa5dfa82022-05-07 03:53:14 +000011785#ifdef SQLITE_DEBUG
mistachkin07fae322022-07-06 23:50:01 +000011786 sqlite3_int64 mem_main_enter = sqlite3_memory_used();
larrybrfa5dfa82022-05-07 03:53:14 +000011787#endif
drh2ce15c32017-07-11 13:34:40 +000011788 char *zErrMsg = 0;
stephan4413ec72022-07-12 15:53:02 +000011789#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +000011790# define data shellState
11791#else
drh2ce15c32017-07-11 13:34:40 +000011792 ShellState data;
stephanf8cd3d22022-05-18 17:14:24 +000011793#endif
drh2ce15c32017-07-11 13:34:40 +000011794 const char *zInitFile = 0;
11795 int i;
11796 int rc = 0;
11797 int warnInmemoryDb = 0;
11798 int readStdin = 1;
11799 int nCmd = 0;
11800 char **azCmd = 0;
dan16a47422018-04-18 09:16:11 +000011801 const char *zVfs = 0; /* Value of -vfs command-line option */
drh1f22f622018-05-17 13:29:14 +000011802#if !SQLITE_SHELL_IS_UTF8
11803 char **argvToFree = 0;
11804 int argcToFree = 0;
11805#endif
drh2ce15c32017-07-11 13:34:40 +000011806
11807 setBinaryMode(stdin, 0);
11808 setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
stephan4413ec72022-07-12 15:53:02 +000011809#ifdef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +000011810 stdin_is_interactive = 0;
11811 stdout_is_console = 1;
stephan60d9aa72022-09-24 07:36:45 +000011812 data.wasm.zDefaultDbName = "/fiddle.sqlite3";
stephanf8cd3d22022-05-18 17:14:24 +000011813#else
drh2ce15c32017-07-11 13:34:40 +000011814 stdin_is_interactive = isatty(0);
11815 stdout_is_console = isatty(1);
stephanf8cd3d22022-05-18 17:14:24 +000011816#endif
drh2ce15c32017-07-11 13:34:40 +000011817
mistachkin1e8487d2018-07-22 06:25:35 +000011818#if !defined(_WIN32_WCE)
11819 if( getenv("SQLITE_DEBUG_BREAK") ){
11820 if( isatty(0) && isatty(2) ){
11821 fprintf(stderr,
11822 "attach debugger to process %d and press any key to continue.\n",
11823 GETPID());
11824 fgetc(stdin);
11825 }else{
11826#if defined(_WIN32) || defined(WIN32)
mistachkin43e86272020-04-09 15:31:22 +000011827#if SQLITE_OS_WINRT
11828 __debugbreak();
11829#else
mistachkin1e8487d2018-07-22 06:25:35 +000011830 DebugBreak();
mistachkin43e86272020-04-09 15:31:22 +000011831#endif
mistachkin1e8487d2018-07-22 06:25:35 +000011832#elif defined(SIGTRAP)
11833 raise(SIGTRAP);
11834#endif
11835 }
11836 }
11837#endif
11838
drh2ce15c32017-07-11 13:34:40 +000011839#if USE_SYSTEM_SQLITE+0!=1
drhbf70f1b2022-10-19 18:04:42 +000011840 if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
drh2ce15c32017-07-11 13:34:40 +000011841 utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
11842 sqlite3_sourceid(), SQLITE_SOURCE_ID);
11843 exit(1);
11844 }
11845#endif
11846 main_init(&data);
drh501ea052018-02-15 01:03:37 +000011847
11848 /* On Windows, we must translate command-line arguments into UTF-8.
11849 ** The SQLite memory allocator subsystem has to be enabled in order to
11850 ** do this. But we want to run an sqlite3_shutdown() afterwards so that
11851 ** subsequent sqlite3_config() calls will work. So copy all results into
11852 ** memory that does not come from the SQLite memory allocator.
11853 */
drh4b18c1d2018-02-04 20:33:13 +000011854#if !SQLITE_SHELL_IS_UTF8
drh501ea052018-02-15 01:03:37 +000011855 sqlite3_initialize();
drh1f22f622018-05-17 13:29:14 +000011856 argvToFree = malloc(sizeof(argv[0])*argc*2);
drhe3e25652021-12-16 13:29:28 +000011857 shell_check_oom(argvToFree);
drh1f22f622018-05-17 13:29:14 +000011858 argcToFree = argc;
11859 argv = argvToFree + argc;
drh2ce15c32017-07-11 13:34:40 +000011860 for(i=0; i<argc; i++){
drh501ea052018-02-15 01:03:37 +000011861 char *z = sqlite3_win32_unicode_to_utf8(wargv[i]);
drh7d23d152022-10-11 12:02:42 +000011862 i64 n;
drhe3e25652021-12-16 13:29:28 +000011863 shell_check_oom(z);
drh7d23d152022-10-11 12:02:42 +000011864 n = strlen(z);
drh501ea052018-02-15 01:03:37 +000011865 argv[i] = malloc( n+1 );
drhe3e25652021-12-16 13:29:28 +000011866 shell_check_oom(argv[i]);
drh501ea052018-02-15 01:03:37 +000011867 memcpy(argv[i], z, n+1);
drh1f22f622018-05-17 13:29:14 +000011868 argvToFree[i] = argv[i];
drh501ea052018-02-15 01:03:37 +000011869 sqlite3_free(z);
drh2ce15c32017-07-11 13:34:40 +000011870 }
drh501ea052018-02-15 01:03:37 +000011871 sqlite3_shutdown();
drh2ce15c32017-07-11 13:34:40 +000011872#endif
drh501ea052018-02-15 01:03:37 +000011873
drh2ce15c32017-07-11 13:34:40 +000011874 assert( argc>=1 && argv && argv[0] );
11875 Argv0 = argv[0];
11876
11877 /* Make sure we have a valid signal handler early, before anything
11878 ** else is done.
11879 */
11880#ifdef SIGINT
11881 signal(SIGINT, interrupt_handler);
mistachkinb4bab902017-10-27 17:09:44 +000011882#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
11883 SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
drh2ce15c32017-07-11 13:34:40 +000011884#endif
11885
11886#ifdef SQLITE_SHELL_DBNAME_PROC
11887 {
11888 /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
11889 ** of a C-function that will provide the name of the database file. Use
11890 ** this compile-time option to embed this shell program in larger
11891 ** applications. */
11892 extern void SQLITE_SHELL_DBNAME_PROC(const char**);
drh37407122021-07-23 18:43:58 +000011893 SQLITE_SHELL_DBNAME_PROC(&data.pAuxDb->zDbFilename);
drh2ce15c32017-07-11 13:34:40 +000011894 warnInmemoryDb = 0;
11895 }
11896#endif
11897
11898 /* Do an initial pass through the command-line argument to locate
11899 ** the name of the database file, the name of the initialization file,
11900 ** the size of the alternative malloc heap,
11901 ** and the first command to execute.
11902 */
drhe7df8922018-04-18 10:44:58 +000011903 verify_uninitialized();
drh2ce15c32017-07-11 13:34:40 +000011904 for(i=1; i<argc; i++){
11905 char *z;
11906 z = argv[i];
11907 if( z[0]!='-' ){
drh37407122021-07-23 18:43:58 +000011908 if( data.aAuxDb->zDbFilename==0 ){
11909 data.aAuxDb->zDbFilename = z;
drh2ce15c32017-07-11 13:34:40 +000011910 }else{
11911 /* Excesss arguments are interpreted as SQL (or dot-commands) and
11912 ** mean that nothing is read from stdin */
11913 readStdin = 0;
11914 nCmd++;
11915 azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
drhe3e25652021-12-16 13:29:28 +000011916 shell_check_oom(azCmd);
drh2ce15c32017-07-11 13:34:40 +000011917 azCmd[nCmd-1] = z;
11918 }
11919 }
11920 if( z[1]=='-' ) z++;
drhbf70f1b2022-10-19 18:04:42 +000011921 if( cli_strcmp(z,"-separator")==0
11922 || cli_strcmp(z,"-nullvalue")==0
11923 || cli_strcmp(z,"-newline")==0
11924 || cli_strcmp(z,"-cmd")==0
drh2ce15c32017-07-11 13:34:40 +000011925 ){
11926 (void)cmdline_option_value(argc, argv, ++i);
drhbf70f1b2022-10-19 18:04:42 +000011927 }else if( cli_strcmp(z,"-init")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011928 zInitFile = cmdline_option_value(argc, argv, ++i);
drhbf70f1b2022-10-19 18:04:42 +000011929 }else if( cli_strcmp(z,"-batch")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011930 /* Need to check for batch mode here to so we can avoid printing
11931 ** informational messages (like from process_sqliterc) before
11932 ** we do the actual processing of arguments later in a second pass.
11933 */
11934 stdin_is_interactive = 0;
drhbf70f1b2022-10-19 18:04:42 +000011935 }else if( cli_strcmp(z,"-heap")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011936#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
11937 const char *zSize;
11938 sqlite3_int64 szHeap;
11939
11940 zSize = cmdline_option_value(argc, argv, ++i);
11941 szHeap = integerValue(zSize);
11942 if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
11943 sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
11944#else
11945 (void)cmdline_option_value(argc, argv, ++i);
11946#endif
drhbf70f1b2022-10-19 18:04:42 +000011947 }else if( cli_strcmp(z,"-pagecache")==0 ){
drhf573b4f2020-09-28 13:34:05 +000011948 sqlite3_int64 n, sz;
11949 sz = integerValue(cmdline_option_value(argc,argv,++i));
drh2ce15c32017-07-11 13:34:40 +000011950 if( sz>70000 ) sz = 70000;
11951 if( sz<0 ) sz = 0;
drhf573b4f2020-09-28 13:34:05 +000011952 n = integerValue(cmdline_option_value(argc,argv,++i));
11953 if( sz>0 && n>0 && 0xffffffffffffLL/sz<n ){
11954 n = 0xffffffffffffLL/sz;
11955 }
drh2ce15c32017-07-11 13:34:40 +000011956 sqlite3_config(SQLITE_CONFIG_PAGECACHE,
11957 (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
11958 data.shellFlgs |= SHFLG_Pagecache;
drhbf70f1b2022-10-19 18:04:42 +000011959 }else if( cli_strcmp(z,"-lookaside")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011960 int n, sz;
11961 sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
11962 if( sz<0 ) sz = 0;
11963 n = (int)integerValue(cmdline_option_value(argc,argv,++i));
11964 if( n<0 ) n = 0;
11965 sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
11966 if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
drhbf70f1b2022-10-19 18:04:42 +000011967 }else if( cli_strcmp(z,"-threadsafe")==0 ){
drh9d16fb12021-08-09 17:45:00 +000011968 int n;
11969 n = (int)integerValue(cmdline_option_value(argc,argv,++i));
11970 switch( n ){
drhaf6d1af2021-08-09 17:37:58 +000011971 case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break;
11972 case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break;
11973 default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break;
11974 }
drh2ce15c32017-07-11 13:34:40 +000011975#ifdef SQLITE_ENABLE_VFSTRACE
drhbf70f1b2022-10-19 18:04:42 +000011976 }else if( cli_strcmp(z,"-vfstrace")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011977 extern int vfstrace_register(
11978 const char *zTraceName,
11979 const char *zOldVfsName,
11980 int (*xOut)(const char*,void*),
11981 void *pOutArg,
11982 int makeDefault
11983 );
11984 vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
11985#endif
11986#ifdef SQLITE_ENABLE_MULTIPLEX
drhbf70f1b2022-10-19 18:04:42 +000011987 }else if( cli_strcmp(z,"-multiplex")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011988 extern int sqlite3_multiple_initialize(const char*,int);
11989 sqlite3_multiplex_initialize(0, 1);
11990#endif
drhbf70f1b2022-10-19 18:04:42 +000011991 }else if( cli_strcmp(z,"-mmap")==0 ){
drh2ce15c32017-07-11 13:34:40 +000011992 sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
11993 sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
drha90d84f2018-04-18 15:21:13 +000011994#ifdef SQLITE_ENABLE_SORTER_REFERENCES
drhbf70f1b2022-10-19 18:04:42 +000011995 }else if( cli_strcmp(z,"-sorterref")==0 ){
drha90d84f2018-04-18 15:21:13 +000011996 sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
11997 sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, (int)sz);
11998#endif
drhbf70f1b2022-10-19 18:04:42 +000011999 }else if( cli_strcmp(z,"-vfs")==0 ){
dan16a47422018-04-18 09:16:11 +000012000 zVfs = cmdline_option_value(argc, argv, ++i);
drh3baed312018-03-08 18:14:41 +000012001#ifdef SQLITE_HAVE_ZLIB
drhbf70f1b2022-10-19 18:04:42 +000012002 }else if( cli_strcmp(z,"-zip")==0 ){
drh8682e122018-01-07 20:38:10 +000012003 data.openMode = SHELL_OPEN_ZIPFILE;
12004#endif
drhbf70f1b2022-10-19 18:04:42 +000012005 }else if( cli_strcmp(z,"-append")==0 ){
drh8682e122018-01-07 20:38:10 +000012006 data.openMode = SHELL_OPEN_APPENDVFS;
drh8d889af2021-05-08 17:18:23 +000012007#ifndef SQLITE_OMIT_DESERIALIZE
drhbf70f1b2022-10-19 18:04:42 +000012008 }else if( cli_strcmp(z,"-deserialize")==0 ){
drh60f34ae2018-10-30 13:19:49 +000012009 data.openMode = SHELL_OPEN_DESERIALIZE;
drhbf70f1b2022-10-19 18:04:42 +000012010 }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){
drh6ca64482019-01-22 16:06:20 +000012011 data.szMax = integerValue(argv[++i]);
drha751f392018-10-30 15:31:22 +000012012#endif
drhbf70f1b2022-10-19 18:04:42 +000012013 }else if( cli_strcmp(z,"-readonly")==0 ){
drhee269a62018-02-14 23:27:43 +000012014 data.openMode = SHELL_OPEN_READONLY;
drhbf70f1b2022-10-19 18:04:42 +000012015 }else if( cli_strcmp(z,"-nofollow")==0 ){
drh0933aad2019-11-18 17:46:38 +000012016 data.openFlags = SQLITE_OPEN_NOFOLLOW;
drhda57d962018-03-05 19:34:05 +000012017#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
drhbf70f1b2022-10-19 18:04:42 +000012018 }else if( cli_strncmp(z, "-A",2)==0 ){
drhda57d962018-03-05 19:34:05 +000012019 /* All remaining command-line arguments are passed to the ".archive"
12020 ** command, so ignore them */
12021 break;
12022#endif
drhbf70f1b2022-10-19 18:04:42 +000012023 }else if( cli_strcmp(z, "-memtrace")==0 ){
drh50b910a2019-01-21 14:55:03 +000012024 sqlite3MemTraceActivate(stderr);
drhbf70f1b2022-10-19 18:04:42 +000012025 }else if( cli_strcmp(z,"-bail")==0 ){
drhb7c46aa2020-11-25 13:59:47 +000012026 bail_on_error = 1;
drhbf70f1b2022-10-19 18:04:42 +000012027 }else if( cli_strcmp(z,"-nonce")==0 ){
drhb97e2ad2021-08-26 18:31:39 +000012028 free(data.zNonce);
12029 data.zNonce = strdup(argv[++i]);
drhbf70f1b2022-10-19 18:04:42 +000012030 }else if( cli_strcmp(z,"-safe")==0 ){
drhb97e2ad2021-08-26 18:31:39 +000012031 /* no-op - catch this on the second pass */
drh2ce15c32017-07-11 13:34:40 +000012032 }
12033 }
drhe7df8922018-04-18 10:44:58 +000012034 verify_uninitialized();
12035
dan16a47422018-04-18 09:16:11 +000012036
drhd11b8f62018-04-25 13:27:07 +000012037#ifdef SQLITE_SHELL_INIT_PROC
12038 {
12039 /* If the SQLITE_SHELL_INIT_PROC macro is defined, then it is the name
12040 ** of a C-function that will perform initialization actions on SQLite that
12041 ** occur just before or after sqlite3_initialize(). Use this compile-time
12042 ** option to embed this shell program in larger applications. */
12043 extern void SQLITE_SHELL_INIT_PROC(void);
12044 SQLITE_SHELL_INIT_PROC();
12045 }
12046#else
dan16a47422018-04-18 09:16:11 +000012047 /* All the sqlite3_config() calls have now been made. So it is safe
12048 ** to call sqlite3_initialize() and process any command line -vfs option. */
12049 sqlite3_initialize();
drhd11b8f62018-04-25 13:27:07 +000012050#endif
12051
dan16a47422018-04-18 09:16:11 +000012052 if( zVfs ){
12053 sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs);
12054 if( pVfs ){
12055 sqlite3_vfs_register(pVfs, 1);
12056 }else{
drhc9b7d942022-11-22 18:24:07 +000012057 utf8_printf(stderr, "no such VFS: \"%s\"\n", zVfs);
dan16a47422018-04-18 09:16:11 +000012058 exit(1);
12059 }
12060 }
12061
drh37407122021-07-23 18:43:58 +000012062 if( data.pAuxDb->zDbFilename==0 ){
drh2ce15c32017-07-11 13:34:40 +000012063#ifndef SQLITE_OMIT_MEMORYDB
drh37407122021-07-23 18:43:58 +000012064 data.pAuxDb->zDbFilename = ":memory:";
drh2ce15c32017-07-11 13:34:40 +000012065 warnInmemoryDb = argc==1;
12066#else
12067 utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
12068 return 1;
12069#endif
12070 }
12071 data.out = stdout;
stephan4413ec72022-07-12 15:53:02 +000012072#ifndef SQLITE_SHELL_FIDDLE
drh8682e122018-01-07 20:38:10 +000012073 sqlite3_appendvfs_init(0,0,0);
stephanf8cd3d22022-05-18 17:14:24 +000012074#endif
drh2ce15c32017-07-11 13:34:40 +000012075
12076 /* Go ahead and open the database file if it already exists. If the
12077 ** file does not exist, delay opening it. This prevents empty database
12078 ** files from being created if a user mistypes the database name argument
12079 ** to the sqlite command-line tool.
12080 */
drh37407122021-07-23 18:43:58 +000012081 if( access(data.pAuxDb->zDbFilename, 0)==0 ){
drh2ce15c32017-07-11 13:34:40 +000012082 open_db(&data, 0);
12083 }
12084
12085 /* Process the initialization file if there is one. If no -init option
12086 ** is given on the command line, look for a file named ~/.sqliterc and
12087 ** try to process it.
12088 */
12089 process_sqliterc(&data,zInitFile);
12090
12091 /* Make a second pass through the command-line argument and set
12092 ** options. This second pass is delayed until after the initialization
12093 ** file is processed so that the command-line arguments will override
12094 ** settings in the initialization file.
12095 */
12096 for(i=1; i<argc; i++){
12097 char *z = argv[i];
12098 if( z[0]!='-' ) continue;
12099 if( z[1]=='-' ){ z++; }
drhbf70f1b2022-10-19 18:04:42 +000012100 if( cli_strcmp(z,"-init")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012101 i++;
drhbf70f1b2022-10-19 18:04:42 +000012102 }else if( cli_strcmp(z,"-html")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012103 data.mode = MODE_Html;
drhbf70f1b2022-10-19 18:04:42 +000012104 }else if( cli_strcmp(z,"-list")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012105 data.mode = MODE_List;
drhbf70f1b2022-10-19 18:04:42 +000012106 }else if( cli_strcmp(z,"-quote")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012107 data.mode = MODE_Quote;
drh9191c702020-08-17 09:11:21 +000012108 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Comma);
12109 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +000012110 }else if( cli_strcmp(z,"-line")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012111 data.mode = MODE_Line;
drhbf70f1b2022-10-19 18:04:42 +000012112 }else if( cli_strcmp(z,"-column")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012113 data.mode = MODE_Column;
drhbf70f1b2022-10-19 18:04:42 +000012114 }else if( cli_strcmp(z,"-json")==0 ){
drh30c54a02020-05-28 23:49:50 +000012115 data.mode = MODE_Json;
drhbf70f1b2022-10-19 18:04:42 +000012116 }else if( cli_strcmp(z,"-markdown")==0 ){
drh30c54a02020-05-28 23:49:50 +000012117 data.mode = MODE_Markdown;
drhbf70f1b2022-10-19 18:04:42 +000012118 }else if( cli_strcmp(z,"-table")==0 ){
drh30c54a02020-05-28 23:49:50 +000012119 data.mode = MODE_Table;
drhbf70f1b2022-10-19 18:04:42 +000012120 }else if( cli_strcmp(z,"-box")==0 ){
drh0908e382020-06-04 18:05:39 +000012121 data.mode = MODE_Box;
drhbf70f1b2022-10-19 18:04:42 +000012122 }else if( cli_strcmp(z,"-csv")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012123 data.mode = MODE_Csv;
12124 memcpy(data.colSeparator,",",2);
drh3baed312018-03-08 18:14:41 +000012125#ifdef SQLITE_HAVE_ZLIB
drhbf70f1b2022-10-19 18:04:42 +000012126 }else if( cli_strcmp(z,"-zip")==0 ){
drh1fa6d9f2018-01-06 21:46:01 +000012127 data.openMode = SHELL_OPEN_ZIPFILE;
12128#endif
drhbf70f1b2022-10-19 18:04:42 +000012129 }else if( cli_strcmp(z,"-append")==0 ){
drh1fa6d9f2018-01-06 21:46:01 +000012130 data.openMode = SHELL_OPEN_APPENDVFS;
drh8d889af2021-05-08 17:18:23 +000012131#ifndef SQLITE_OMIT_DESERIALIZE
drhbf70f1b2022-10-19 18:04:42 +000012132 }else if( cli_strcmp(z,"-deserialize")==0 ){
drh60f34ae2018-10-30 13:19:49 +000012133 data.openMode = SHELL_OPEN_DESERIALIZE;
drhbf70f1b2022-10-19 18:04:42 +000012134 }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){
drh6ca64482019-01-22 16:06:20 +000012135 data.szMax = integerValue(argv[++i]);
drha751f392018-10-30 15:31:22 +000012136#endif
drhbf70f1b2022-10-19 18:04:42 +000012137 }else if( cli_strcmp(z,"-readonly")==0 ){
drh4aafe592018-03-23 16:08:30 +000012138 data.openMode = SHELL_OPEN_READONLY;
drhbf70f1b2022-10-19 18:04:42 +000012139 }else if( cli_strcmp(z,"-nofollow")==0 ){
drh0933aad2019-11-18 17:46:38 +000012140 data.openFlags |= SQLITE_OPEN_NOFOLLOW;
drhbf70f1b2022-10-19 18:04:42 +000012141 }else if( cli_strcmp(z,"-ascii")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012142 data.mode = MODE_Ascii;
larrybr0953c532022-12-23 19:04:59 +000012143 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,SEP_Unit);
12144 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,SEP_Record);
drhbf70f1b2022-10-19 18:04:42 +000012145 }else if( cli_strcmp(z,"-tabs")==0 ){
drh2fa78182020-10-31 18:58:37 +000012146 data.mode = MODE_List;
larrybr0953c532022-12-23 19:04:59 +000012147 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,SEP_Tab);
12148 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,SEP_Row);
drhbf70f1b2022-10-19 18:04:42 +000012149 }else if( cli_strcmp(z,"-separator")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012150 sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
12151 "%s",cmdline_option_value(argc,argv,++i));
drhbf70f1b2022-10-19 18:04:42 +000012152 }else if( cli_strcmp(z,"-newline")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012153 sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
12154 "%s",cmdline_option_value(argc,argv,++i));
drhbf70f1b2022-10-19 18:04:42 +000012155 }else if( cli_strcmp(z,"-nullvalue")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012156 sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
12157 "%s",cmdline_option_value(argc,argv,++i));
drhbf70f1b2022-10-19 18:04:42 +000012158 }else if( cli_strcmp(z,"-header")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012159 data.showHeader = 1;
larrybrae509122021-09-10 01:45:20 +000012160 ShellSetFlag(&data, SHFLG_HeaderSet);
drhbf70f1b2022-10-19 18:04:42 +000012161 }else if( cli_strcmp(z,"-noheader")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012162 data.showHeader = 0;
larrybrae509122021-09-10 01:45:20 +000012163 ShellSetFlag(&data, SHFLG_HeaderSet);
drhbf70f1b2022-10-19 18:04:42 +000012164 }else if( cli_strcmp(z,"-echo")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012165 ShellSetFlag(&data, SHFLG_Echo);
drhbf70f1b2022-10-19 18:04:42 +000012166 }else if( cli_strcmp(z,"-eqp")==0 ){
drhada70452017-12-21 21:02:27 +000012167 data.autoEQP = AUTOEQP_on;
drhbf70f1b2022-10-19 18:04:42 +000012168 }else if( cli_strcmp(z,"-eqpfull")==0 ){
drhada70452017-12-21 21:02:27 +000012169 data.autoEQP = AUTOEQP_full;
drhbf70f1b2022-10-19 18:04:42 +000012170 }else if( cli_strcmp(z,"-stats")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012171 data.statsOn = 1;
drhbf70f1b2022-10-19 18:04:42 +000012172 }else if( cli_strcmp(z,"-scanstats")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012173 data.scanstatsOn = 1;
drhbf70f1b2022-10-19 18:04:42 +000012174 }else if( cli_strcmp(z,"-backslash")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012175 /* Undocumented command-line option: -backslash
12176 ** Causes C-style backslash escapes to be evaluated in SQL statements
12177 ** prior to sending the SQL into SQLite. Useful for injecting
12178 ** crazy bytes in the middle of SQL statements for testing and debugging.
12179 */
12180 ShellSetFlag(&data, SHFLG_Backslash);
drhbf70f1b2022-10-19 18:04:42 +000012181 }else if( cli_strcmp(z,"-bail")==0 ){
drhb7c46aa2020-11-25 13:59:47 +000012182 /* No-op. The bail_on_error flag should already be set. */
drhbf70f1b2022-10-19 18:04:42 +000012183 }else if( cli_strcmp(z,"-version")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012184 printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
12185 return 0;
drhbf70f1b2022-10-19 18:04:42 +000012186 }else if( cli_strcmp(z,"-interactive")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012187 stdin_is_interactive = 1;
drhbf70f1b2022-10-19 18:04:42 +000012188 }else if( cli_strcmp(z,"-batch")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012189 stdin_is_interactive = 0;
drhbf70f1b2022-10-19 18:04:42 +000012190 }else if( cli_strcmp(z,"-heap")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012191 i++;
drhbf70f1b2022-10-19 18:04:42 +000012192 }else if( cli_strcmp(z,"-pagecache")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012193 i+=2;
drhbf70f1b2022-10-19 18:04:42 +000012194 }else if( cli_strcmp(z,"-lookaside")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012195 i+=2;
drhbf70f1b2022-10-19 18:04:42 +000012196 }else if( cli_strcmp(z,"-threadsafe")==0 ){
drhaf6d1af2021-08-09 17:37:58 +000012197 i+=2;
drhbf70f1b2022-10-19 18:04:42 +000012198 }else if( cli_strcmp(z,"-nonce")==0 ){
drhb97e2ad2021-08-26 18:31:39 +000012199 i += 2;
drhbf70f1b2022-10-19 18:04:42 +000012200 }else if( cli_strcmp(z,"-mmap")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012201 i++;
drhbf70f1b2022-10-19 18:04:42 +000012202 }else if( cli_strcmp(z,"-memtrace")==0 ){
drh50b910a2019-01-21 14:55:03 +000012203 i++;
drha90d84f2018-04-18 15:21:13 +000012204#ifdef SQLITE_ENABLE_SORTER_REFERENCES
drhbf70f1b2022-10-19 18:04:42 +000012205 }else if( cli_strcmp(z,"-sorterref")==0 ){
drha90d84f2018-04-18 15:21:13 +000012206 i++;
12207#endif
drhbf70f1b2022-10-19 18:04:42 +000012208 }else if( cli_strcmp(z,"-vfs")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012209 i++;
12210#ifdef SQLITE_ENABLE_VFSTRACE
drhbf70f1b2022-10-19 18:04:42 +000012211 }else if( cli_strcmp(z,"-vfstrace")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012212 i++;
12213#endif
12214#ifdef SQLITE_ENABLE_MULTIPLEX
drhbf70f1b2022-10-19 18:04:42 +000012215 }else if( cli_strcmp(z,"-multiplex")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012216 i++;
12217#endif
drhbf70f1b2022-10-19 18:04:42 +000012218 }else if( cli_strcmp(z,"-help")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012219 usage(1);
drhbf70f1b2022-10-19 18:04:42 +000012220 }else if( cli_strcmp(z,"-cmd")==0 ){
drh2ce15c32017-07-11 13:34:40 +000012221 /* Run commands that follow -cmd first and separately from commands
12222 ** that simply appear on the command-line. This seems goofy. It would
12223 ** be better if all commands ran in the order that they appear. But
12224 ** we retain the goofy behavior for historical compatibility. */
12225 if( i==argc-1 ) break;
12226 z = cmdline_option_value(argc,argv,++i);
12227 if( z[0]=='.' ){
12228 rc = do_meta_command(z, &data);
12229 if( rc && bail_on_error ) return rc==2 ? 0 : rc;
12230 }else{
12231 open_db(&data, 0);
drha10b9992018-03-09 15:24:33 +000012232 rc = shell_exec(&data, z, &zErrMsg);
drh2ce15c32017-07-11 13:34:40 +000012233 if( zErrMsg!=0 ){
12234 utf8_printf(stderr,"Error: %s\n", zErrMsg);
12235 if( bail_on_error ) return rc!=0 ? rc : 1;
12236 }else if( rc!=0 ){
12237 utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z);
12238 if( bail_on_error ) return rc;
12239 }
12240 }
drhda57d962018-03-05 19:34:05 +000012241#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
drhbf70f1b2022-10-19 18:04:42 +000012242 }else if( cli_strncmp(z, "-A", 2)==0 ){
drhda57d962018-03-05 19:34:05 +000012243 if( nCmd>0 ){
12244 utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands"
12245 " with \"%s\"\n", z);
12246 return 1;
12247 }
drhbe4ccb22018-05-17 20:04:24 +000012248 open_db(&data, OPEN_DB_ZIPFILE);
drh93b77312018-03-05 20:20:22 +000012249 if( z[2] ){
12250 argv[i] = &z[2];
drhd0f9cdc2018-05-17 14:09:06 +000012251 arDotCommand(&data, 1, argv+(i-1), argc-(i-1));
drh93b77312018-03-05 20:20:22 +000012252 }else{
drhd0f9cdc2018-05-17 14:09:06 +000012253 arDotCommand(&data, 1, argv+i, argc-i);
drh93b77312018-03-05 20:20:22 +000012254 }
drhda57d962018-03-05 19:34:05 +000012255 readStdin = 0;
12256 break;
12257#endif
drhbf70f1b2022-10-19 18:04:42 +000012258 }else if( cli_strcmp(z,"-safe")==0 ){
drhb97e2ad2021-08-26 18:31:39 +000012259 data.bSafeMode = data.bSafeModePersist = 1;
drh2ce15c32017-07-11 13:34:40 +000012260 }else{
12261 utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
12262 raw_printf(stderr,"Use -help for a list of options.\n");
12263 return 1;
12264 }
12265 data.cMode = data.mode;
12266 }
12267
12268 if( !readStdin ){
12269 /* Run all arguments that do not begin with '-' as if they were separate
12270 ** command-line inputs, except for the argToSkip argument which contains
12271 ** the database filename.
12272 */
12273 for(i=0; i<nCmd; i++){
12274 if( azCmd[i][0]=='.' ){
12275 rc = do_meta_command(azCmd[i], &data);
danaff1a572020-11-17 21:09:56 +000012276 if( rc ){
12277 free(azCmd);
12278 return rc==2 ? 0 : rc;
12279 }
drh2ce15c32017-07-11 13:34:40 +000012280 }else{
12281 open_db(&data, 0);
drha10b9992018-03-09 15:24:33 +000012282 rc = shell_exec(&data, azCmd[i], &zErrMsg);
danaff1a572020-11-17 21:09:56 +000012283 if( zErrMsg || rc ){
12284 if( zErrMsg!=0 ){
12285 utf8_printf(stderr,"Error: %s\n", zErrMsg);
12286 }else{
12287 utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
12288 }
12289 sqlite3_free(zErrMsg);
12290 free(azCmd);
drh2ce15c32017-07-11 13:34:40 +000012291 return rc!=0 ? rc : 1;
drh2ce15c32017-07-11 13:34:40 +000012292 }
12293 }
12294 }
drh2ce15c32017-07-11 13:34:40 +000012295 }else{
12296 /* Run commands received from standard input
12297 */
12298 if( stdin_is_interactive ){
12299 char *zHome;
drha9e4be32018-10-10 18:56:40 +000012300 char *zHistory;
drh2ce15c32017-07-11 13:34:40 +000012301 int nHistory;
12302 printf(
12303 "SQLite version %s %.19s\n" /*extra-version-info*/
12304 "Enter \".help\" for usage hints.\n",
12305 sqlite3_libversion(), sqlite3_sourceid()
12306 );
12307 if( warnInmemoryDb ){
12308 printf("Connected to a ");
12309 printBold("transient in-memory database");
12310 printf(".\nUse \".open FILENAME\" to reopen on a "
12311 "persistent database.\n");
12312 }
drha9e4be32018-10-10 18:56:40 +000012313 zHistory = getenv("SQLITE_HISTORY");
12314 if( zHistory ){
12315 zHistory = strdup(zHistory);
12316 }else if( (zHome = find_home_dir(0))!=0 ){
drh2ce15c32017-07-11 13:34:40 +000012317 nHistory = strlen30(zHome) + 20;
12318 if( (zHistory = malloc(nHistory))!=0 ){
12319 sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
12320 }
12321 }
12322 if( zHistory ){ shell_read_history(zHistory); }
drh56eb09b2017-07-11 13:59:07 +000012323#if HAVE_READLINE || HAVE_EDITLINE
12324 rl_attempted_completion_function = readline_completion;
12325#elif HAVE_LINENOISE
12326 linenoiseSetCompletionCallback(linenoise_completion);
12327#endif
drh60379d42018-12-13 18:30:01 +000012328 data.in = 0;
12329 rc = process_input(&data);
drh2ce15c32017-07-11 13:34:40 +000012330 if( zHistory ){
drh5a75dd82017-07-18 20:59:40 +000012331 shell_stifle_history(2000);
drh2ce15c32017-07-11 13:34:40 +000012332 shell_write_history(zHistory);
12333 free(zHistory);
12334 }
12335 }else{
drh60379d42018-12-13 18:30:01 +000012336 data.in = stdin;
12337 rc = process_input(&data);
drh2ce15c32017-07-11 13:34:40 +000012338 }
12339 }
stephan4413ec72022-07-12 15:53:02 +000012340#ifndef SQLITE_SHELL_FIDDLE
stephanf8cd3d22022-05-18 17:14:24 +000012341 /* In WASM mode we have to leave the db state in place so that
12342 ** client code can "push" SQL into it after this call returns. */
danaff1a572020-11-17 21:09:56 +000012343 free(azCmd);
drh2ce15c32017-07-11 13:34:40 +000012344 set_table_name(&data, 0);
12345 if( data.db ){
drh37407122021-07-23 18:43:58 +000012346 session_close_all(&data, -1);
drh9e804032018-05-18 17:11:50 +000012347 close_db(data.db);
drh2ce15c32017-07-11 13:34:40 +000012348 }
drh37407122021-07-23 18:43:58 +000012349 for(i=0; i<ArraySize(data.aAuxDb); i++){
12350 sqlite3_free(data.aAuxDb[i].zFreeOnClose);
12351 if( data.aAuxDb[i].db ){
12352 session_close_all(&data, i);
12353 close_db(data.aAuxDb[i].db);
12354 }
12355 }
drh2ce15c32017-07-11 13:34:40 +000012356 find_home_dir(1);
drh536c3452018-01-11 00:38:39 +000012357 output_reset(&data);
12358 data.doXdgOpen = 0;
drh13c20932018-01-10 21:41:55 +000012359 clearTempFile(&data);
drh2ce15c32017-07-11 13:34:40 +000012360#if !SQLITE_SHELL_IS_UTF8
drh1f22f622018-05-17 13:29:14 +000012361 for(i=0; i<argcToFree; i++) free(argvToFree[i]);
12362 free(argvToFree);
drh2ce15c32017-07-11 13:34:40 +000012363#endif
drh0285d982020-05-29 14:38:43 +000012364 free(data.colWidth);
drhb97e2ad2021-08-26 18:31:39 +000012365 free(data.zNonce);
drh9e804032018-05-18 17:11:50 +000012366 /* Clear the global data structure so that valgrind will detect memory
12367 ** leaks */
12368 memset(&data, 0, sizeof(data));
larrybrfa5dfa82022-05-07 03:53:14 +000012369#ifdef SQLITE_DEBUG
12370 if( sqlite3_memory_used()>mem_main_enter ){
12371 utf8_printf(stderr, "Memory leaked: %u bytes\n",
12372 (unsigned int)(sqlite3_memory_used()-mem_main_enter));
12373 }
12374#endif
stephan4413ec72022-07-12 15:53:02 +000012375#endif /* !SQLITE_SHELL_FIDDLE */
drh2ce15c32017-07-11 13:34:40 +000012376 return rc;
12377}
stephanf8cd3d22022-05-18 17:14:24 +000012378
12379
stephan4413ec72022-07-12 15:53:02 +000012380#ifdef SQLITE_SHELL_FIDDLE
stephan2eb45412022-05-21 00:01:45 +000012381/* Only for emcc experimentation purposes. */
12382int fiddle_experiment(int a,int b){
stephan278d3fa2022-09-26 13:55:10 +000012383 return a + b;
stephan2eb45412022-05-21 00:01:45 +000012384}
12385
stephan1f095d42022-09-26 11:38:58 +000012386/*
12387** Returns a pointer to the current DB handle.
stephan2eb45412022-05-21 00:01:45 +000012388*/
stephan1f095d42022-09-26 11:38:58 +000012389sqlite3 * fiddle_db_handle(){
stephan278d3fa2022-09-26 13:55:10 +000012390 return globalDb;
stephan2eb45412022-05-21 00:01:45 +000012391}
stephan278d3fa2022-09-26 13:55:10 +000012392
12393/*
12394** Returns a pointer to the given DB name's VFS. If zDbName is 0 then
12395** "main" is assumed. Returns 0 if no db with the given name is
12396** open.
12397*/
12398sqlite3_vfs * fiddle_db_vfs(const char *zDbName){
12399 sqlite3_vfs * pVfs = 0;
12400 if(globalDb){
12401 sqlite3_file_control(globalDb, zDbName ? zDbName : "main",
12402 SQLITE_FCNTL_VFS_POINTER, &pVfs);
12403 }
12404 return pVfs;
stephan2eb45412022-05-21 00:01:45 +000012405}
stephan1f095d42022-09-26 11:38:58 +000012406
stephan2eb45412022-05-21 00:01:45 +000012407/* Only for emcc experimentation purposes. */
12408sqlite3 * fiddle_db_arg(sqlite3 *arg){
12409 printf("fiddle_db_arg(%p)\n", (const void*)arg);
12410 return arg;
12411}
12412
stephanf8cd3d22022-05-18 17:14:24 +000012413/*
stephan42573732022-05-21 14:19:05 +000012414** Intended to be called via a SharedWorker() while a separate
12415** SharedWorker() (which manages the wasm module) is performing work
stephan085c5c62022-05-25 04:35:22 +000012416** which should be interrupted. Unfortunately, SharedWorker is not
12417** portable enough to make real use of.
stephan42573732022-05-21 14:19:05 +000012418*/
12419void fiddle_interrupt(void){
stephan278d3fa2022-09-26 13:55:10 +000012420 if( globalDb ) sqlite3_interrupt(globalDb);
stephan42573732022-05-21 14:19:05 +000012421}
12422
12423/*
stephan085c5c62022-05-25 04:35:22 +000012424** Returns the filename of the given db name, assuming "main" if
12425** zDbName is NULL. Returns NULL if globalDb is not opened.
stephan80bf8692022-05-24 22:16:12 +000012426*/
12427const char * fiddle_db_filename(const char * zDbName){
12428 return globalDb
12429 ? sqlite3_db_filename(globalDb, zDbName ? zDbName : "main")
12430 : NULL;
12431}
12432
12433/*
stephana4c357f2022-10-03 11:42:45 +000012434** Completely wipes out the contents of the currently-opened database
12435** but leaves its storage intact for reuse.
stephancd697842022-05-27 03:27:10 +000012436*/
12437void fiddle_reset_db(void){
stephana4c357f2022-10-03 11:42:45 +000012438 if( globalDb ){
12439 int rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
12440 if( 0==rc ) rc = sqlite3_exec(globalDb, "VACUUM", 0, 0, 0);
12441 sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
stephancd697842022-05-27 03:27:10 +000012442 }
stephancd697842022-05-27 03:27:10 +000012443}
12444
12445/*
stephan278d3fa2022-09-26 13:55:10 +000012446** Uses the current database's VFS xRead to stream the db file's
12447** contents out to the given callback. The callback gets a single
12448** chunk of size n (its 2nd argument) on each call and must return 0
12449** on success, non-0 on error. This function returns 0 on success,
12450** SQLITE_NOTFOUND if no db is open, or propagates any other non-0
12451** code from the callback. Note that this is not thread-friendly: it
12452** expects that it will be the only thread reading the db file and
12453** takes no measures to ensure that is the case.
stephan1f095d42022-09-26 11:38:58 +000012454*/
stephan278d3fa2022-09-26 13:55:10 +000012455int fiddle_export_db( int (*xCallback)(unsigned const char *zOut, int n) ){
stephan1f095d42022-09-26 11:38:58 +000012456 sqlite3_int64 nSize = 0;
12457 sqlite3_int64 nPos = 0;
stephan1f095d42022-09-26 11:38:58 +000012458 sqlite3_file * pFile = 0;
stephan278d3fa2022-09-26 13:55:10 +000012459 unsigned char buf[1024 * 8];
12460 int nBuf = (int)sizeof(buf);
stephan1f095d42022-09-26 11:38:58 +000012461 int rc = shellState.db
12462 ? sqlite3_file_control(shellState.db, "main",
stephan278d3fa2022-09-26 13:55:10 +000012463 SQLITE_FCNTL_FILE_POINTER, &pFile)
12464 : SQLITE_NOTFOUND;
stephan1f095d42022-09-26 11:38:58 +000012465 if( rc ) return rc;
12466 rc = pFile->pMethods->xFileSize(pFile, &nSize);
stephan278d3fa2022-09-26 13:55:10 +000012467 if( rc ) return rc;
12468 if(nSize % nBuf){
12469 /* DB size is not an even multiple of the buffer size. Reduce
12470 ** buffer size so that we do not unduly inflate the db size when
12471 ** exporting. */
12472 if(0 == nSize % 4096) nBuf = 4096;
12473 else if(0 == nSize % 2048) nBuf = 2048;
12474 else if(0 == nSize % 1024) nBuf = 1024;
12475 else nBuf = 512;
12476 }
stephan1f095d42022-09-26 11:38:58 +000012477 for( ; 0==rc && nPos<nSize; nPos += nBuf ){
12478 rc = pFile->pMethods->xRead(pFile, buf, nBuf, nPos);
12479 if(SQLITE_IOERR_SHORT_READ == rc){
12480 rc = (nPos + nBuf) < nSize ? rc : 0/*assume EOF*/;
12481 }
stephan278d3fa2022-09-26 13:55:10 +000012482 if( 0==rc ) rc = xCallback(buf, nBuf);
stephan1f095d42022-09-26 11:38:58 +000012483 }
12484 return rc;
12485}
stephan1f095d42022-09-26 11:38:58 +000012486
12487/*
stephan60d9aa72022-09-24 07:36:45 +000012488** Trivial exportable function for emscripten. It processes zSql as if
12489** it were input to the sqlite3 shell and redirects all output to the
stephan842c5ee2022-10-20 05:14:37 +000012490** wasm binding. fiddle_main() must have been called before this
12491** is called, or results are undefined.
stephanf8cd3d22022-05-18 17:14:24 +000012492*/
stephan0076e492022-05-18 18:10:17 +000012493void fiddle_exec(const char * zSql){
stephan60d9aa72022-09-24 07:36:45 +000012494 if(zSql && *zSql){
12495 if('.'==*zSql) puts(zSql);
stephanf8cd3d22022-05-18 17:14:24 +000012496 shellState.wasm.zInput = zSql;
12497 shellState.wasm.zPos = zSql;
12498 process_input(&shellState);
stephan60d9aa72022-09-24 07:36:45 +000012499 shellState.wasm.zInput = shellState.wasm.zPos = 0;
stephanf8cd3d22022-05-18 17:14:24 +000012500 }
12501}
stephan4413ec72022-07-12 15:53:02 +000012502#endif /* SQLITE_SHELL_FIDDLE */