1251883Speter/*
2251883Speter** 2001 September 15
3251883Speter**
4251883Speter** The author disclaims copyright to this source code.  In place of
5251883Speter** a legal notice, here is a blessing:
6251883Speter**
7251883Speter**    May you do good and not evil.
8251883Speter**    May you find forgiveness for yourself and forgive others.
9251883Speter**    May you share freely, never taking more than you give.
10251883Speter**
11251883Speter*************************************************************************
12251883Speter** This file contains code to implement the "sqlite" command line
13251883Speter** utility for accessing SQLite databases.
14251883Speter*/
15251883Speter#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
16251883Speter/* This needs to come before any includes for MSVC compiler */
17251883Speter#define _CRT_SECURE_NO_WARNINGS
18251883Speter#endif
19251883Speter
20251883Speter/*
21289166Speter** If requested, include the SQLite compiler options file for MSVC.
22289166Speter*/
23289166Speter#if defined(INCLUDE_MSVC_H)
24289166Speter#include "msvc.h"
25289166Speter#endif
26289166Speter
27289166Speter/*
28289166Speter** No support for loadable extensions in VxWorks.
29289166Speter*/
30289166Speter#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION
31289166Speter# define SQLITE_OMIT_LOAD_EXTENSION 1
32289166Speter#endif
33289166Speter
34289166Speter/*
35251883Speter** Enable large-file support for fopen() and friends on unix.
36251883Speter*/
37251883Speter#ifndef SQLITE_DISABLE_LFS
38251883Speter# define _LARGE_FILE       1
39251883Speter# ifndef _FILE_OFFSET_BITS
40251883Speter#   define _FILE_OFFSET_BITS 64
41251883Speter# endif
42251883Speter# define _LARGEFILE_SOURCE 1
43251883Speter#endif
44251883Speter
45251883Speter#include <stdlib.h>
46251883Speter#include <string.h>
47251883Speter#include <stdio.h>
48251883Speter#include <assert.h>
49251883Speter#include "sqlite3.h"
50289166Speter#if SQLITE_USER_AUTHENTICATION
51289166Speter# include "sqlite3userauth.h"
52289166Speter#endif
53251883Speter#include <ctype.h>
54251883Speter#include <stdarg.h>
55251883Speter
56251883Speter#if !defined(_WIN32) && !defined(WIN32)
57251883Speter# include <signal.h>
58251883Speter# if !defined(__RTP__) && !defined(_WRS_KERNEL)
59251883Speter#  include <pwd.h>
60251883Speter# endif
61251883Speter# include <unistd.h>
62251883Speter# include <sys/types.h>
63251883Speter#endif
64251883Speter
65289166Speter#if HAVE_READLINE
66251883Speter# include <readline/readline.h>
67251883Speter# include <readline/history.h>
68251883Speter#endif
69289166Speter
70289166Speter#if HAVE_EDITLINE
71289166Speter# include <editline/readline.h>
72251883Speter#endif
73251883Speter
74289166Speter#if HAVE_EDITLINE || HAVE_READLINE
75289166Speter
76289166Speter# define shell_add_history(X) add_history(X)
77289166Speter# define shell_read_history(X) read_history(X)
78289166Speter# define shell_write_history(X) write_history(X)
79289166Speter# define shell_stifle_history(X) stifle_history(X)
80289166Speter# define shell_readline(X) readline(X)
81289166Speter
82289166Speter#elif HAVE_LINENOISE
83289166Speter
84289166Speter# include "linenoise.h"
85289166Speter# define shell_add_history(X) linenoiseHistoryAdd(X)
86289166Speter# define shell_read_history(X) linenoiseHistoryLoad(X)
87289166Speter# define shell_write_history(X) linenoiseHistorySave(X)
88289166Speter# define shell_stifle_history(X) linenoiseHistorySetMaxLen(X)
89289166Speter# define shell_readline(X) linenoise(X)
90289166Speter
91289166Speter#else
92289166Speter
93305003Scy# define shell_read_history(X)
94289166Speter# define shell_write_history(X)
95289166Speter# define shell_stifle_history(X)
96289166Speter
97289166Speter# define SHELL_USE_LOCAL_GETLINE 1
98289166Speter#endif
99289166Speter
100289166Speter
101251883Speter#if defined(_WIN32) || defined(WIN32)
102251883Speter# include <io.h>
103289166Speter# include <fcntl.h>
104289166Speter# define isatty(h) _isatty(h)
105289166Speter# ifndef access
106289166Speter#  define access(f,m) _access((f),(m))
107289166Speter# endif
108289166Speter# undef popen
109289166Speter# define popen _popen
110289166Speter# undef pclose
111289166Speter# define pclose _pclose
112251883Speter#else
113289166Speter /* Make sure isatty() has a prototype. */
114289166Speter extern int isatty(int);
115289166Speter
116289166Speter# if !defined(__RTP__) && !defined(_WRS_KERNEL)
117289166Speter  /* popen and pclose are not C89 functions and so are
118289166Speter  ** sometimes omitted from the <stdio.h> header */
119289166Speter   extern FILE *popen(const char*,const char*);
120289166Speter   extern int pclose(FILE*);
121289166Speter# else
122289166Speter#  define SQLITE_OMIT_POPEN 1
123289166Speter# endif
124251883Speter#endif
125251883Speter
126251883Speter#if defined(_WIN32_WCE)
127251883Speter/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
128251883Speter * thus we always assume that we have a console. That can be
129251883Speter * overridden with the -batch command line option.
130251883Speter */
131251883Speter#define isatty(x) 1
132251883Speter#endif
133251883Speter
134251883Speter/* ctype macros that work with signed characters */
135251883Speter#define IsSpace(X)  isspace((unsigned char)X)
136251883Speter#define IsDigit(X)  isdigit((unsigned char)X)
137251883Speter#define ToLower(X)  (char)tolower((unsigned char)X)
138251883Speter
139305003Scy#if defined(_WIN32) || defined(WIN32)
140305003Scy#include <windows.h>
141305003Scy
142305003Scy/* string conversion routines only needed on Win32 */
143305003Scyextern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
144305003Scyextern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
145305003Scyextern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
146305003Scy#endif
147305003Scy
148289166Speter/* On Windows, we normally run with output mode of TEXT so that \n characters
149289166Speter** are automatically translated into \r\n.  However, this behavior needs
150289166Speter** to be disabled in some cases (ex: when generating CSV output and when
151289166Speter** rendering quoted strings that contain \n characters).  The following
152289166Speter** routines take care of that.
153289166Speter*/
154289166Speter#if defined(_WIN32) || defined(WIN32)
155305003Scystatic void setBinaryMode(FILE *file, int isOutput){
156305003Scy  if( isOutput ) fflush(file);
157305003Scy  _setmode(_fileno(file), _O_BINARY);
158289166Speter}
159305003Scystatic void setTextMode(FILE *file, int isOutput){
160305003Scy  if( isOutput ) fflush(file);
161305003Scy  _setmode(_fileno(file), _O_TEXT);
162289166Speter}
163289166Speter#else
164305003Scy# define setBinaryMode(X,Y)
165305003Scy# define setTextMode(X,Y)
166289166Speter#endif
167289166Speter
168289166Speter
169289166Speter/* True if the timer is enabled */
170289166Speterstatic int enableTimer = 0;
171289166Speter
172289166Speter/* Return the current wall-clock time */
173289166Speterstatic sqlite3_int64 timeOfDay(void){
174289166Speter  static sqlite3_vfs *clockVfs = 0;
175289166Speter  sqlite3_int64 t;
176289166Speter  if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
177305003Scy  if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
178289166Speter    clockVfs->xCurrentTimeInt64(clockVfs, &t);
179289166Speter  }else{
180289166Speter    double r;
181289166Speter    clockVfs->xCurrentTime(clockVfs, &r);
182289166Speter    t = (sqlite3_int64)(r*86400000.0);
183289166Speter  }
184289166Speter  return t;
185289166Speter}
186289166Speter
187289166Speter#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
188251883Speter#include <sys/time.h>
189251883Speter#include <sys/resource.h>
190251883Speter
191289166Speter/* VxWorks does not support getrusage() as far as we can determine */
192289166Speter#if defined(_WRS_KERNEL) || defined(__RTP__)
193289166Speterstruct rusage {
194289166Speter  struct timeval ru_utime; /* user CPU time used */
195289166Speter  struct timeval ru_stime; /* system CPU time used */
196289166Speter};
197289166Speter#define getrusage(A,B) memset(B,0,sizeof(*B))
198289166Speter#endif
199289166Speter
200251883Speter/* Saved resource information for the beginning of an operation */
201289166Speterstatic struct rusage sBegin;  /* CPU time at start */
202289166Speterstatic sqlite3_int64 iBegin;  /* Wall-clock time at start */
203251883Speter
204251883Speter/*
205251883Speter** Begin timing an operation
206251883Speter*/
207251883Speterstatic void beginTimer(void){
208251883Speter  if( enableTimer ){
209251883Speter    getrusage(RUSAGE_SELF, &sBegin);
210289166Speter    iBegin = timeOfDay();
211251883Speter  }
212251883Speter}
213251883Speter
214251883Speter/* Return the difference of two time_structs in seconds */
215251883Speterstatic double timeDiff(struct timeval *pStart, struct timeval *pEnd){
216305003Scy  return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
217251883Speter         (double)(pEnd->tv_sec - pStart->tv_sec);
218251883Speter}
219251883Speter
220251883Speter/*
221251883Speter** Print the timing results.
222251883Speter*/
223251883Speterstatic void endTimer(void){
224251883Speter  if( enableTimer ){
225289166Speter    sqlite3_int64 iEnd = timeOfDay();
226251883Speter    struct rusage sEnd;
227251883Speter    getrusage(RUSAGE_SELF, &sEnd);
228289166Speter    printf("Run Time: real %.3f user %f sys %f\n",
229289166Speter       (iEnd - iBegin)*0.001,
230251883Speter       timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
231251883Speter       timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
232251883Speter  }
233251883Speter}
234251883Speter
235251883Speter#define BEGIN_TIMER beginTimer()
236251883Speter#define END_TIMER endTimer()
237251883Speter#define HAS_TIMER 1
238251883Speter
239251883Speter#elif (defined(_WIN32) || defined(WIN32))
240251883Speter
241251883Speter/* Saved resource information for the beginning of an operation */
242251883Speterstatic HANDLE hProcess;
243251883Speterstatic FILETIME ftKernelBegin;
244251883Speterstatic FILETIME ftUserBegin;
245289166Speterstatic sqlite3_int64 ftWallBegin;
246289166Spetertypedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME,
247289166Speter                                    LPFILETIME, LPFILETIME);
248251883Speterstatic GETPROCTIMES getProcessTimesAddr = NULL;
249251883Speter
250251883Speter/*
251251883Speter** Check to see if we have timer support.  Return 1 if necessary
252251883Speter** support found (or found previously).
253251883Speter*/
254251883Speterstatic int hasTimer(void){
255251883Speter  if( getProcessTimesAddr ){
256251883Speter    return 1;
257251883Speter  } else {
258289166Speter    /* GetProcessTimes() isn't supported in WIN95 and some other Windows
259289166Speter    ** versions. See if the version we are running on has it, and if it
260289166Speter    ** does, save off a pointer to it and the current process handle.
261251883Speter    */
262251883Speter    hProcess = GetCurrentProcess();
263251883Speter    if( hProcess ){
264251883Speter      HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
265251883Speter      if( NULL != hinstLib ){
266289166Speter        getProcessTimesAddr =
267289166Speter            (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
268251883Speter        if( NULL != getProcessTimesAddr ){
269251883Speter          return 1;
270251883Speter        }
271305003Scy        FreeLibrary(hinstLib);
272251883Speter      }
273251883Speter    }
274251883Speter  }
275251883Speter  return 0;
276251883Speter}
277251883Speter
278251883Speter/*
279251883Speter** Begin timing an operation
280251883Speter*/
281251883Speterstatic void beginTimer(void){
282251883Speter  if( enableTimer && getProcessTimesAddr ){
283251883Speter    FILETIME ftCreation, ftExit;
284289166Speter    getProcessTimesAddr(hProcess,&ftCreation,&ftExit,
285289166Speter                        &ftKernelBegin,&ftUserBegin);
286289166Speter    ftWallBegin = timeOfDay();
287251883Speter  }
288251883Speter}
289251883Speter
290251883Speter/* Return the difference of two FILETIME structs in seconds */
291251883Speterstatic double timeDiff(FILETIME *pStart, FILETIME *pEnd){
292251883Speter  sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
293251883Speter  sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
294251883Speter  return (double) ((i64End - i64Start) / 10000000.0);
295251883Speter}
296251883Speter
297251883Speter/*
298251883Speter** Print the timing results.
299251883Speter*/
300251883Speterstatic void endTimer(void){
301251883Speter  if( enableTimer && getProcessTimesAddr){
302251883Speter    FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
303289166Speter    sqlite3_int64 ftWallEnd = timeOfDay();
304289166Speter    getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
305289166Speter    printf("Run Time: real %.3f user %f sys %f\n",
306289166Speter       (ftWallEnd - ftWallBegin)*0.001,
307251883Speter       timeDiff(&ftUserBegin, &ftUserEnd),
308251883Speter       timeDiff(&ftKernelBegin, &ftKernelEnd));
309251883Speter  }
310251883Speter}
311251883Speter
312251883Speter#define BEGIN_TIMER beginTimer()
313251883Speter#define END_TIMER endTimer()
314251883Speter#define HAS_TIMER hasTimer()
315251883Speter
316251883Speter#else
317305003Scy#define BEGIN_TIMER
318251883Speter#define END_TIMER
319251883Speter#define HAS_TIMER 0
320251883Speter#endif
321251883Speter
322251883Speter/*
323251883Speter** Used to prevent warnings about unused parameters
324251883Speter*/
325251883Speter#define UNUSED_PARAMETER(x) (void)(x)
326251883Speter
327251883Speter/*
328251883Speter** If the following flag is set, then command execution stops
329251883Speter** at an error if we are not interactive.
330251883Speter*/
331251883Speterstatic int bail_on_error = 0;
332251883Speter
333251883Speter/*
334251883Speter** Threat stdin as an interactive input if the following variable
335251883Speter** is true.  Otherwise, assume stdin is connected to a file or pipe.
336251883Speter*/
337251883Speterstatic int stdin_is_interactive = 1;
338251883Speter
339251883Speter/*
340305003Scy** On Windows systems we have to know if standard output is a console
341305003Scy** in order to translate UTF-8 into MBCS.  The following variable is
342305003Scy** true if translation is required.
343305003Scy*/
344305003Scystatic int stdout_is_console = 1;
345305003Scy
346305003Scy/*
347251883Speter** The following is the open SQLite database.  We make a pointer
348251883Speter** to this database a static variable so that it can be accessed
349251883Speter** by the SIGINT handler to interrupt database processing.
350251883Speter*/
351289166Speterstatic sqlite3 *globalDb = 0;
352251883Speter
353251883Speter/*
354251883Speter** True if an interrupt (Control-C) has been received.
355251883Speter*/
356251883Speterstatic volatile int seenInterrupt = 0;
357251883Speter
358251883Speter/*
359251883Speter** This is the name of our program. It is set in main(), used
360251883Speter** in a number of other places, mostly for error messages.
361251883Speter*/
362251883Speterstatic char *Argv0;
363251883Speter
364251883Speter/*
365251883Speter** Prompt strings. Initialized in main. Settable with
366251883Speter**   .prompt main continue
367251883Speter*/
368251883Speterstatic char mainPrompt[20];     /* First line prompt. default: "sqlite> "*/
369251883Speterstatic char continuePrompt[20]; /* Continuation prompt. default: "   ...> " */
370251883Speter
371251883Speter/*
372305003Scy** Render output like fprintf().  Except, if the output is going to the
373305003Scy** console and if this is running on a Windows machine, translate the
374305003Scy** output from UTF-8 into MBCS.
375305003Scy*/
376305003Scy#if defined(_WIN32) || defined(WIN32)
377305003Scyvoid utf8_printf(FILE *out, const char *zFormat, ...){
378305003Scy  va_list ap;
379305003Scy  va_start(ap, zFormat);
380305003Scy  if( stdout_is_console && (out==stdout || out==stderr) ){
381305003Scy    char *z1 = sqlite3_vmprintf(zFormat, ap);
382305003Scy    char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
383305003Scy    sqlite3_free(z1);
384305003Scy    fputs(z2, out);
385305003Scy    sqlite3_free(z2);
386305003Scy  }else{
387305003Scy    vfprintf(out, zFormat, ap);
388305003Scy  }
389305003Scy  va_end(ap);
390305003Scy}
391305003Scy#elif !defined(utf8_printf)
392305003Scy# define utf8_printf fprintf
393305003Scy#endif
394305003Scy
395305003Scy/*
396305003Scy** Render output like fprintf().  This should not be used on anything that
397305003Scy** includes string formatting (e.g. "%s").
398305003Scy*/
399305003Scy#if !defined(raw_printf)
400305003Scy# define raw_printf fprintf
401305003Scy#endif
402305003Scy
403305003Scy/*
404251883Speter** Write I/O traces to the following stream.
405251883Speter*/
406251883Speter#ifdef SQLITE_ENABLE_IOTRACE
407251883Speterstatic FILE *iotrace = 0;
408251883Speter#endif
409251883Speter
410251883Speter/*
411251883Speter** This routine works like printf in that its first argument is a
412251883Speter** format string and subsequent arguments are values to be substituted
413251883Speter** in place of % fields.  The result of formatting this string
414251883Speter** is written to iotrace.
415251883Speter*/
416251883Speter#ifdef SQLITE_ENABLE_IOTRACE
417289166Speterstatic void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
418251883Speter  va_list ap;
419251883Speter  char *z;
420251883Speter  if( iotrace==0 ) return;
421251883Speter  va_start(ap, zFormat);
422251883Speter  z = sqlite3_vmprintf(zFormat, ap);
423251883Speter  va_end(ap);
424305003Scy  utf8_printf(iotrace, "%s", z);
425251883Speter  sqlite3_free(z);
426251883Speter}
427251883Speter#endif
428251883Speter
429251883Speter
430251883Speter/*
431251883Speter** Determines if a string is a number of not.
432251883Speter*/
433251883Speterstatic int isNumber(const char *z, int *realnum){
434251883Speter  if( *z=='-' || *z=='+' ) z++;
435251883Speter  if( !IsDigit(*z) ){
436251883Speter    return 0;
437251883Speter  }
438251883Speter  z++;
439251883Speter  if( realnum ) *realnum = 0;
440251883Speter  while( IsDigit(*z) ){ z++; }
441251883Speter  if( *z=='.' ){
442251883Speter    z++;
443251883Speter    if( !IsDigit(*z) ) return 0;
444251883Speter    while( IsDigit(*z) ){ z++; }
445251883Speter    if( realnum ) *realnum = 1;
446251883Speter  }
447251883Speter  if( *z=='e' || *z=='E' ){
448251883Speter    z++;
449251883Speter    if( *z=='+' || *z=='-' ) z++;
450251883Speter    if( !IsDigit(*z) ) return 0;
451251883Speter    while( IsDigit(*z) ){ z++; }
452251883Speter    if( realnum ) *realnum = 1;
453251883Speter  }
454251883Speter  return *z==0;
455251883Speter}
456251883Speter
457251883Speter/*
458305003Scy** A global char* and an SQL function to access its current value
459305003Scy** from within an SQL statement. This program used to use the
460251883Speter** sqlite_exec_printf() API to substitue a string into an SQL statement.
461251883Speter** The correct way to do this with sqlite3 is to use the bind API, but
462251883Speter** since the shell is built around the callback paradigm it would be a lot
463251883Speter** of work. Instead just use this hack, which is quite harmless.
464251883Speter*/
465251883Speterstatic const char *zShellStatic = 0;
466251883Speterstatic void shellstaticFunc(
467251883Speter  sqlite3_context *context,
468251883Speter  int argc,
469251883Speter  sqlite3_value **argv
470251883Speter){
471251883Speter  assert( 0==argc );
472251883Speter  assert( zShellStatic );
473251883Speter  UNUSED_PARAMETER(argc);
474251883Speter  UNUSED_PARAMETER(argv);
475251883Speter  sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
476251883Speter}
477251883Speter
478251883Speter
479251883Speter/*
480305003Scy** Compute a string length that is limited to what can be stored in
481305003Scy** lower 30 bits of a 32-bit signed integer.
482305003Scy*/
483305003Scystatic int strlen30(const char *z){
484305003Scy  const char *z2 = z;
485305003Scy  while( *z2 ){ z2++; }
486305003Scy  return 0x3fffffff & (int)(z2 - z);
487305003Scy}
488305003Scy
489305003Scy/*
490251883Speter** This routine reads a line of text from FILE in, stores
491251883Speter** the text in memory obtained from malloc() and returns a pointer
492251883Speter** to the text.  NULL is returned at end of file, or if malloc()
493251883Speter** fails.
494251883Speter**
495289166Speter** If zLine is not NULL then it is a malloced buffer returned from
496289166Speter** a previous call to this routine that may be reused.
497251883Speter*/
498289166Speterstatic char *local_getline(char *zLine, FILE *in){
499289166Speter  int nLine = zLine==0 ? 0 : 100;
500289166Speter  int n = 0;
501251883Speter
502251883Speter  while( 1 ){
503251883Speter    if( n+100>nLine ){
504251883Speter      nLine = nLine*2 + 100;
505251883Speter      zLine = realloc(zLine, nLine);
506251883Speter      if( zLine==0 ) return 0;
507251883Speter    }
508251883Speter    if( fgets(&zLine[n], nLine - n, in)==0 ){
509251883Speter      if( n==0 ){
510251883Speter        free(zLine);
511251883Speter        return 0;
512251883Speter      }
513251883Speter      zLine[n] = 0;
514251883Speter      break;
515251883Speter    }
516289166Speter    while( zLine[n] ) n++;
517289166Speter    if( n>0 && zLine[n-1]=='\n' ){
518251883Speter      n--;
519251883Speter      if( n>0 && zLine[n-1]=='\r' ) n--;
520251883Speter      zLine[n] = 0;
521251883Speter      break;
522251883Speter    }
523251883Speter  }
524305003Scy#if defined(_WIN32) || defined(WIN32)
525305003Scy  /* For interactive input on Windows systems, translate the
526305003Scy  ** multi-byte characterset characters into UTF-8. */
527305003Scy  if( stdin_is_interactive ){
528305003Scy    char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
529305003Scy    if( zTrans ){
530305003Scy      int nTrans = strlen30(zTrans)+1;
531305003Scy      if( nTrans>nLine ){
532305003Scy        zLine = realloc(zLine, nTrans);
533305003Scy        if( zLine==0 ){
534305003Scy          sqlite3_free(zTrans);
535305003Scy          return 0;
536305003Scy        }
537305003Scy      }
538305003Scy      memcpy(zLine, zTrans, nTrans);
539305003Scy      sqlite3_free(zTrans);
540305003Scy    }
541305003Scy  }
542305003Scy#endif /* defined(_WIN32) || defined(WIN32) */
543251883Speter  return zLine;
544251883Speter}
545251883Speter
546251883Speter/*
547251883Speter** Retrieve a single line of input text.
548251883Speter**
549289166Speter** If in==0 then read from standard input and prompt before each line.
550289166Speter** If isContinuation is true, then a continuation prompt is appropriate.
551289166Speter** If isContinuation is zero, then the main prompt should be used.
552289166Speter**
553289166Speter** If zPrior is not NULL then it is a buffer from a prior call to this
554289166Speter** routine that can be reused.
555289166Speter**
556289166Speter** The result is stored in space obtained from malloc() and must either
557289166Speter** be freed by the caller or else passed back into this routine via the
558289166Speter** zPrior argument for reuse.
559251883Speter*/
560289166Speterstatic char *one_input_line(FILE *in, char *zPrior, int isContinuation){
561251883Speter  char *zPrompt;
562251883Speter  char *zResult;
563251883Speter  if( in!=0 ){
564289166Speter    zResult = local_getline(zPrior, in);
565251883Speter  }else{
566289166Speter    zPrompt = isContinuation ? continuePrompt : mainPrompt;
567289166Speter#if SHELL_USE_LOCAL_GETLINE
568289166Speter    printf("%s", zPrompt);
569289166Speter    fflush(stdout);
570289166Speter    zResult = local_getline(zPrior, stdin);
571289166Speter#else
572289166Speter    free(zPrior);
573289166Speter    zResult = shell_readline(zPrompt);
574289166Speter    if( zResult && *zResult ) shell_add_history(zResult);
575289166Speter#endif
576251883Speter  }
577251883Speter  return zResult;
578251883Speter}
579251883Speter
580305003Scy#if defined(SQLITE_ENABLE_SESSION)
581289166Speter/*
582305003Scy** State information for a single open session
583305003Scy*/
584305003Scytypedef struct OpenSession OpenSession;
585305003Scystruct OpenSession {
586305003Scy  char *zName;             /* Symbolic name for this session */
587305003Scy  int nFilter;             /* Number of xFilter rejection GLOB patterns */
588305003Scy  char **azFilter;         /* Array of xFilter rejection GLOB patterns */
589305003Scy  sqlite3_session *p;      /* The open session */
590305003Scy};
591305003Scy#endif
592305003Scy
593305003Scy/*
594305003Scy** Shell output mode information from before ".explain on",
595289166Speter** saved so that it can be restored by ".explain off"
596289166Speter*/
597289166Spetertypedef struct SavedModeInfo SavedModeInfo;
598289166Speterstruct SavedModeInfo {
599289166Speter  int valid;          /* Is there legit data in here? */
600289166Speter  int mode;           /* Mode prior to ".explain on" */
601289166Speter  int showHeader;     /* The ".header" setting prior to ".explain on" */
602289166Speter  int colWidth[100];  /* Column widths prior to ".explain on" */
603251883Speter};
604251883Speter
605251883Speter/*
606289166Speter** State information about the database connection is contained in an
607289166Speter** instance of the following structure.
608251883Speter*/
609289166Spetertypedef struct ShellState ShellState;
610289166Speterstruct ShellState {
611251883Speter  sqlite3 *db;           /* The database */
612251883Speter  int echoOn;            /* True to echo input commands */
613305003Scy  int autoExplain;       /* Automatically turn on .explain mode */
614289166Speter  int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
615251883Speter  int statsOn;           /* True to display memory stats before each finalize */
616289166Speter  int scanstatsOn;       /* True to display scan stats before each finalize */
617305003Scy  int countChanges;      /* True to display change counts */
618289166Speter  int backslashOn;       /* Resolve C-style \x escapes in SQL input text */
619289166Speter  int outCount;          /* Revert to stdout when reaching zero */
620251883Speter  int cnt;               /* Number of records displayed so far */
621251883Speter  FILE *out;             /* Write results here */
622251883Speter  FILE *traceOut;        /* Output for sqlite3_trace() */
623251883Speter  int nErr;              /* Number of errors seen */
624251883Speter  int mode;              /* An output mode setting */
625305003Scy  int cMode;             /* temporary output mode for the current query */
626305003Scy  int normalMode;        /* Output mode before ".explain on" */
627251883Speter  int writableSchema;    /* True if PRAGMA writable_schema=ON */
628251883Speter  int showHeader;        /* True to show column names in List or Column mode */
629289166Speter  unsigned shellFlgs;    /* Various flags */
630251883Speter  char *zDestTable;      /* Name of destination table when MODE_Insert */
631289166Speter  char colSeparator[20]; /* Column separator character for several modes */
632289166Speter  char rowSeparator[20]; /* Row separator character for MODE_Ascii */
633251883Speter  int colWidth[100];     /* Requested width of each column when in column mode*/
634251883Speter  int actualWidth[100];  /* Actual width of each column */
635289166Speter  char nullValue[20];    /* The text to print when a NULL comes back from
636251883Speter                         ** the database */
637251883Speter  char outfile[FILENAME_MAX]; /* Filename for *out */
638251883Speter  const char *zDbFilename;    /* name of the database file */
639289166Speter  char *zFreeOnClose;         /* Filename to free when closing */
640251883Speter  const char *zVfs;           /* Name of VFS to use */
641251883Speter  sqlite3_stmt *pStmt;   /* Current statement if any. */
642251883Speter  FILE *pLog;            /* Write log output here */
643289166Speter  int *aiIndent;         /* Array of indents used in MODE_Explain */
644289166Speter  int nIndent;           /* Size of array aiIndent[] */
645289166Speter  int iIndent;           /* Index of current op in aiIndent[] */
646305003Scy#if defined(SQLITE_ENABLE_SESSION)
647305003Scy  int nSession;             /* Number of active sessions */
648305003Scy  OpenSession aSession[4];  /* Array of sessions.  [0] is in focus. */
649305003Scy#endif
650251883Speter};
651251883Speter
652251883Speter/*
653289166Speter** These are the allowed shellFlgs values
654289166Speter*/
655289166Speter#define SHFLG_Scratch     0x00001     /* The --scratch option is used */
656289166Speter#define SHFLG_Pagecache   0x00002     /* The --pagecache option is used */
657289166Speter#define SHFLG_Lookaside   0x00004     /* Lookaside memory is used */
658289166Speter
659289166Speter/*
660251883Speter** These are the allowed modes.
661251883Speter*/
662251883Speter#define MODE_Line     0  /* One column per line.  Blank line between records */
663251883Speter#define MODE_Column   1  /* One record per line in neat columns */
664251883Speter#define MODE_List     2  /* One record per line with a separator */
665251883Speter#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
666251883Speter#define MODE_Html     4  /* Generate an XHTML table */
667251883Speter#define MODE_Insert   5  /* Generate SQL "insert" statements */
668251883Speter#define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
669251883Speter#define MODE_Csv      7  /* Quote strings, numbers are plain */
670251883Speter#define MODE_Explain  8  /* Like MODE_Column, but do not truncate data */
671289166Speter#define MODE_Ascii    9  /* Use ASCII unit and record separators (0x1F/0x1E) */
672305003Scy#define MODE_Pretty  10  /* Pretty-print schemas */
673251883Speter
674251883Speterstatic const char *modeDescr[] = {
675251883Speter  "line",
676251883Speter  "column",
677251883Speter  "list",
678251883Speter  "semi",
679251883Speter  "html",
680251883Speter  "insert",
681251883Speter  "tcl",
682251883Speter  "csv",
683251883Speter  "explain",
684289166Speter  "ascii",
685305003Scy  "prettyprint",
686251883Speter};
687251883Speter
688251883Speter/*
689289166Speter** These are the column/row/line separators used by the various
690289166Speter** import/export modes.
691289166Speter*/
692289166Speter#define SEP_Column    "|"
693289166Speter#define SEP_Row       "\n"
694289166Speter#define SEP_Tab       "\t"
695289166Speter#define SEP_Space     " "
696289166Speter#define SEP_Comma     ","
697289166Speter#define SEP_CrLf      "\r\n"
698289166Speter#define SEP_Unit      "\x1F"
699289166Speter#define SEP_Record    "\x1E"
700289166Speter
701289166Speter/*
702251883Speter** Number of elements in an array
703251883Speter*/
704251883Speter#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))
705251883Speter
706251883Speter/*
707251883Speter** A callback for the sqlite3_log() interface.
708251883Speter*/
709251883Speterstatic void shellLog(void *pArg, int iErrCode, const char *zMsg){
710289166Speter  ShellState *p = (ShellState*)pArg;
711251883Speter  if( p->pLog==0 ) return;
712305003Scy  utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
713251883Speter  fflush(p->pLog);
714251883Speter}
715251883Speter
716251883Speter/*
717251883Speter** Output the given string as a hex-encoded blob (eg. X'1234' )
718251883Speter*/
719251883Speterstatic void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
720251883Speter  int i;
721251883Speter  char *zBlob = (char *)pBlob;
722305003Scy  raw_printf(out,"X'");
723305003Scy  for(i=0; i<nBlob; i++){ raw_printf(out,"%02x",zBlob[i]&0xff); }
724305003Scy  raw_printf(out,"'");
725251883Speter}
726251883Speter
727251883Speter/*
728251883Speter** Output the given string as a quoted string using SQL quoting conventions.
729251883Speter*/
730251883Speterstatic void output_quoted_string(FILE *out, const char *z){
731251883Speter  int i;
732251883Speter  int nSingle = 0;
733305003Scy  setBinaryMode(out, 1);
734251883Speter  for(i=0; z[i]; i++){
735251883Speter    if( z[i]=='\'' ) nSingle++;
736251883Speter  }
737251883Speter  if( nSingle==0 ){
738305003Scy    utf8_printf(out,"'%s'",z);
739251883Speter  }else{
740305003Scy    raw_printf(out,"'");
741251883Speter    while( *z ){
742251883Speter      for(i=0; z[i] && z[i]!='\''; i++){}
743251883Speter      if( i==0 ){
744305003Scy        raw_printf(out,"''");
745251883Speter        z++;
746251883Speter      }else if( z[i]=='\'' ){
747305003Scy        utf8_printf(out,"%.*s''",i,z);
748251883Speter        z += i+1;
749251883Speter      }else{
750305003Scy        utf8_printf(out,"%s",z);
751251883Speter        break;
752251883Speter      }
753251883Speter    }
754305003Scy    raw_printf(out,"'");
755251883Speter  }
756305003Scy  setTextMode(out, 1);
757251883Speter}
758251883Speter
759251883Speter/*
760251883Speter** Output the given string as a quoted according to C or TCL quoting rules.
761251883Speter*/
762251883Speterstatic void output_c_string(FILE *out, const char *z){
763251883Speter  unsigned int c;
764251883Speter  fputc('"', out);
765251883Speter  while( (c = *(z++))!=0 ){
766251883Speter    if( c=='\\' ){
767251883Speter      fputc(c, out);
768251883Speter      fputc(c, out);
769251883Speter    }else if( c=='"' ){
770251883Speter      fputc('\\', out);
771251883Speter      fputc('"', out);
772251883Speter    }else if( c=='\t' ){
773251883Speter      fputc('\\', out);
774251883Speter      fputc('t', out);
775251883Speter    }else if( c=='\n' ){
776251883Speter      fputc('\\', out);
777251883Speter      fputc('n', out);
778251883Speter    }else if( c=='\r' ){
779251883Speter      fputc('\\', out);
780251883Speter      fputc('r', out);
781289166Speter    }else if( !isprint(c&0xff) ){
782305003Scy      raw_printf(out, "\\%03o", c&0xff);
783251883Speter    }else{
784251883Speter      fputc(c, out);
785251883Speter    }
786251883Speter  }
787251883Speter  fputc('"', out);
788251883Speter}
789251883Speter
790251883Speter/*
791251883Speter** Output the given string with characters that are special to
792251883Speter** HTML escaped.
793251883Speter*/
794251883Speterstatic void output_html_string(FILE *out, const char *z){
795251883Speter  int i;
796289166Speter  if( z==0 ) z = "";
797251883Speter  while( *z ){
798305003Scy    for(i=0;   z[i]
799305003Scy            && z[i]!='<'
800305003Scy            && z[i]!='&'
801305003Scy            && z[i]!='>'
802305003Scy            && z[i]!='\"'
803251883Speter            && z[i]!='\'';
804251883Speter        i++){}
805251883Speter    if( i>0 ){
806305003Scy      utf8_printf(out,"%.*s",i,z);
807251883Speter    }
808251883Speter    if( z[i]=='<' ){
809305003Scy      raw_printf(out,"&lt;");
810251883Speter    }else if( z[i]=='&' ){
811305003Scy      raw_printf(out,"&amp;");
812251883Speter    }else if( z[i]=='>' ){
813305003Scy      raw_printf(out,"&gt;");
814251883Speter    }else if( z[i]=='\"' ){
815305003Scy      raw_printf(out,"&quot;");
816251883Speter    }else if( z[i]=='\'' ){
817305003Scy      raw_printf(out,"&#39;");
818251883Speter    }else{
819251883Speter      break;
820251883Speter    }
821251883Speter    z += i + 1;
822251883Speter  }
823251883Speter}
824251883Speter
825251883Speter/*
826251883Speter** If a field contains any character identified by a 1 in the following
827251883Speter** array, then the string must be quoted for CSV.
828251883Speter*/
829251883Speterstatic const char needCsvQuote[] = {
830305003Scy  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
831305003Scy  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
832305003Scy  1, 0, 1, 0, 0, 0, 0, 1,   0, 0, 0, 0, 0, 0, 0, 0,
833305003Scy  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
834305003Scy  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
835305003Scy  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
836305003Scy  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
837305003Scy  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 1,
838305003Scy  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
839305003Scy  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
840305003Scy  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
841305003Scy  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
842305003Scy  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
843305003Scy  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
844305003Scy  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
845305003Scy  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
846251883Speter};
847251883Speter
848251883Speter/*
849289166Speter** Output a single term of CSV.  Actually, p->colSeparator is used for
850289166Speter** the separator, which may or may not be a comma.  p->nullValue is
851289166Speter** the null value.  Strings are quoted if necessary.  The separator
852289166Speter** is only issued if bSep is true.
853251883Speter*/
854289166Speterstatic void output_csv(ShellState *p, const char *z, int bSep){
855251883Speter  FILE *out = p->out;
856251883Speter  if( z==0 ){
857305003Scy    utf8_printf(out,"%s",p->nullValue);
858251883Speter  }else{
859251883Speter    int i;
860289166Speter    int nSep = strlen30(p->colSeparator);
861251883Speter    for(i=0; z[i]; i++){
862305003Scy      if( needCsvQuote[((unsigned char*)z)[i]]
863305003Scy         || (z[i]==p->colSeparator[0] &&
864289166Speter             (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
865251883Speter        i = 0;
866251883Speter        break;
867251883Speter      }
868251883Speter    }
869251883Speter    if( i==0 ){
870251883Speter      putc('"', out);
871251883Speter      for(i=0; z[i]; i++){
872251883Speter        if( z[i]=='"' ) putc('"', out);
873251883Speter        putc(z[i], out);
874251883Speter      }
875251883Speter      putc('"', out);
876251883Speter    }else{
877305003Scy      utf8_printf(out, "%s", z);
878251883Speter    }
879251883Speter  }
880251883Speter  if( bSep ){
881305003Scy    utf8_printf(p->out, "%s", p->colSeparator);
882251883Speter  }
883251883Speter}
884251883Speter
885251883Speter#ifdef SIGINT
886251883Speter/*
887251883Speter** This routine runs when the user presses Ctrl-C
888251883Speter*/
889251883Speterstatic void interrupt_handler(int NotUsed){
890251883Speter  UNUSED_PARAMETER(NotUsed);
891289166Speter  seenInterrupt++;
892289166Speter  if( seenInterrupt>2 ) exit(1);
893289166Speter  if( globalDb ) sqlite3_interrupt(globalDb);
894251883Speter}
895251883Speter#endif
896251883Speter
897251883Speter/*
898305003Scy** When the ".auth ON" is set, the following authorizer callback is
899305003Scy** invoked.  It always returns SQLITE_OK.
900305003Scy*/
901305003Scystatic int shellAuth(
902305003Scy  void *pClientData,
903305003Scy  int op,
904305003Scy  const char *zA1,
905305003Scy  const char *zA2,
906305003Scy  const char *zA3,
907305003Scy  const char *zA4
908305003Scy){
909305003Scy  ShellState *p = (ShellState*)pClientData;
910305003Scy  static const char *azAction[] = { 0,
911305003Scy     "CREATE_INDEX",         "CREATE_TABLE",         "CREATE_TEMP_INDEX",
912305003Scy     "CREATE_TEMP_TABLE",    "CREATE_TEMP_TRIGGER",  "CREATE_TEMP_VIEW",
913305003Scy     "CREATE_TRIGGER",       "CREATE_VIEW",          "DELETE",
914305003Scy     "DROP_INDEX",           "DROP_TABLE",           "DROP_TEMP_INDEX",
915305003Scy     "DROP_TEMP_TABLE",      "DROP_TEMP_TRIGGER",    "DROP_TEMP_VIEW",
916305003Scy     "DROP_TRIGGER",         "DROP_VIEW",            "INSERT",
917305003Scy     "PRAGMA",               "READ",                 "SELECT",
918305003Scy     "TRANSACTION",          "UPDATE",               "ATTACH",
919305003Scy     "DETACH",               "ALTER_TABLE",          "REINDEX",
920305003Scy     "ANALYZE",              "CREATE_VTABLE",        "DROP_VTABLE",
921305003Scy     "FUNCTION",             "SAVEPOINT",            "RECURSIVE"
922305003Scy  };
923305003Scy  int i;
924305003Scy  const char *az[4];
925305003Scy  az[0] = zA1;
926305003Scy  az[1] = zA2;
927305003Scy  az[2] = zA3;
928305003Scy  az[3] = zA4;
929305003Scy  raw_printf(p->out, "authorizer: %s", azAction[op]);
930305003Scy  for(i=0; i<4; i++){
931305003Scy    raw_printf(p->out, " ");
932305003Scy    if( az[i] ){
933305003Scy      output_c_string(p->out, az[i]);
934305003Scy    }else{
935305003Scy      raw_printf(p->out, "NULL");
936305003Scy    }
937305003Scy  }
938305003Scy  raw_printf(p->out, "\n");
939305003Scy  return SQLITE_OK;
940305003Scy}
941305003Scy
942305003Scy
943305003Scy/*
944251883Speter** This is the callback routine that the shell
945251883Speter** invokes for each row of a query result.
946251883Speter*/
947289166Speterstatic int shell_callback(
948289166Speter  void *pArg,
949289166Speter  int nArg,        /* Number of result columns */
950289166Speter  char **azArg,    /* Text of each result column */
951289166Speter  char **azCol,    /* Column names */
952289166Speter  int *aiType      /* Column types */
953289166Speter){
954251883Speter  int i;
955289166Speter  ShellState *p = (ShellState*)pArg;
956251883Speter
957305003Scy  switch( p->cMode ){
958251883Speter    case MODE_Line: {
959251883Speter      int w = 5;
960251883Speter      if( azArg==0 ) break;
961251883Speter      for(i=0; i<nArg; i++){
962251883Speter        int len = strlen30(azCol[i] ? azCol[i] : "");
963251883Speter        if( len>w ) w = len;
964251883Speter      }
965305003Scy      if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator);
966251883Speter      for(i=0; i<nArg; i++){
967305003Scy        utf8_printf(p->out,"%*s = %s%s", w, azCol[i],
968289166Speter                azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
969251883Speter      }
970251883Speter      break;
971251883Speter    }
972251883Speter    case MODE_Explain:
973251883Speter    case MODE_Column: {
974305003Scy      static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
975305003Scy      const int *colWidth;
976305003Scy      int showHdr;
977305003Scy      char *rowSep;
978305003Scy      if( p->cMode==MODE_Column ){
979305003Scy        colWidth = p->colWidth;
980305003Scy        showHdr = p->showHeader;
981305003Scy        rowSep = p->rowSeparator;
982305003Scy      }else{
983305003Scy        colWidth = aExplainWidths;
984305003Scy        showHdr = 1;
985305003Scy        rowSep = SEP_Row;
986305003Scy      }
987251883Speter      if( p->cnt++==0 ){
988251883Speter        for(i=0; i<nArg; i++){
989251883Speter          int w, n;
990251883Speter          if( i<ArraySize(p->colWidth) ){
991305003Scy            w = colWidth[i];
992251883Speter          }else{
993251883Speter            w = 0;
994251883Speter          }
995251883Speter          if( w==0 ){
996251883Speter            w = strlen30(azCol[i] ? azCol[i] : "");
997251883Speter            if( w<10 ) w = 10;
998289166Speter            n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue);
999251883Speter            if( w<n ) w = n;
1000251883Speter          }
1001251883Speter          if( i<ArraySize(p->actualWidth) ){
1002251883Speter            p->actualWidth[i] = w;
1003251883Speter          }
1004305003Scy          if( showHdr ){
1005251883Speter            if( w<0 ){
1006305003Scy              utf8_printf(p->out,"%*.*s%s",-w,-w,azCol[i],
1007305003Scy                      i==nArg-1 ? rowSep : "  ");
1008251883Speter            }else{
1009305003Scy              utf8_printf(p->out,"%-*.*s%s",w,w,azCol[i],
1010305003Scy                      i==nArg-1 ? rowSep : "  ");
1011251883Speter            }
1012251883Speter          }
1013251883Speter        }
1014305003Scy        if( showHdr ){
1015251883Speter          for(i=0; i<nArg; i++){
1016251883Speter            int w;
1017251883Speter            if( i<ArraySize(p->actualWidth) ){
1018251883Speter               w = p->actualWidth[i];
1019251883Speter               if( w<0 ) w = -w;
1020251883Speter            }else{
1021251883Speter               w = 10;
1022251883Speter            }
1023305003Scy            utf8_printf(p->out,"%-*.*s%s",w,w,
1024305003Scy                   "----------------------------------------------------------"
1025251883Speter                   "----------------------------------------------------------",
1026305003Scy                    i==nArg-1 ? rowSep : "  ");
1027251883Speter          }
1028251883Speter        }
1029251883Speter      }
1030251883Speter      if( azArg==0 ) break;
1031251883Speter      for(i=0; i<nArg; i++){
1032251883Speter        int w;
1033251883Speter        if( i<ArraySize(p->actualWidth) ){
1034251883Speter           w = p->actualWidth[i];
1035251883Speter        }else{
1036251883Speter           w = 10;
1037251883Speter        }
1038305003Scy        if( p->cMode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
1039251883Speter          w = strlen30(azArg[i]);
1040251883Speter        }
1041289166Speter        if( i==1 && p->aiIndent && p->pStmt ){
1042289166Speter          if( p->iIndent<p->nIndent ){
1043305003Scy            utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
1044289166Speter          }
1045289166Speter          p->iIndent++;
1046289166Speter        }
1047251883Speter        if( w<0 ){
1048305003Scy          utf8_printf(p->out,"%*.*s%s",-w,-w,
1049289166Speter              azArg[i] ? azArg[i] : p->nullValue,
1050305003Scy              i==nArg-1 ? rowSep : "  ");
1051251883Speter        }else{
1052305003Scy          utf8_printf(p->out,"%-*.*s%s",w,w,
1053289166Speter              azArg[i] ? azArg[i] : p->nullValue,
1054305003Scy              i==nArg-1 ? rowSep : "  ");
1055251883Speter        }
1056251883Speter      }
1057251883Speter      break;
1058251883Speter    }
1059305003Scy    case MODE_Semi: {   /* .schema and .fullschema output */
1060305003Scy      utf8_printf(p->out, "%s;\n", azArg[0]);
1061305003Scy      break;
1062305003Scy    }
1063305003Scy    case MODE_Pretty: {  /* .schema and .fullschema with --indent */
1064305003Scy      char *z;
1065305003Scy      int j;
1066305003Scy      int nParen = 0;
1067305003Scy      char cEnd = 0;
1068305003Scy      char c;
1069305003Scy      int nLine = 0;
1070305003Scy      assert( nArg==1 );
1071305003Scy      if( azArg[0]==0 ) break;
1072305003Scy      if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
1073305003Scy       || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
1074305003Scy      ){
1075305003Scy        utf8_printf(p->out, "%s;\n", azArg[0]);
1076305003Scy        break;
1077305003Scy      }
1078305003Scy      z = sqlite3_mprintf("%s", azArg[0]);
1079305003Scy      j = 0;
1080305003Scy      for(i=0; IsSpace(z[i]); i++){}
1081305003Scy      for(; (c = z[i])!=0; i++){
1082305003Scy        if( IsSpace(c) ){
1083305003Scy          if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
1084305003Scy        }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
1085305003Scy          j--;
1086305003Scy        }
1087305003Scy        z[j++] = c;
1088305003Scy      }
1089305003Scy      while( j>0 && IsSpace(z[j-1]) ){ j--; }
1090305003Scy      z[j] = 0;
1091305003Scy      if( strlen30(z)>=79 ){
1092305003Scy        for(i=j=0; (c = z[i])!=0; i++){
1093305003Scy          if( c==cEnd ){
1094305003Scy            cEnd = 0;
1095305003Scy          }else if( c=='"' || c=='\'' || c=='`' ){
1096305003Scy            cEnd = c;
1097305003Scy          }else if( c=='[' ){
1098305003Scy            cEnd = ']';
1099305003Scy          }else if( c=='(' ){
1100305003Scy            nParen++;
1101305003Scy          }else if( c==')' ){
1102305003Scy            nParen--;
1103305003Scy            if( nLine>0 && nParen==0 && j>0 ){
1104305003Scy              utf8_printf(p->out, "%.*s\n", j, z);
1105305003Scy              j = 0;
1106305003Scy            }
1107305003Scy          }
1108305003Scy          z[j++] = c;
1109305003Scy          if( nParen==1 && (c=='(' || c==',' || c=='\n') ){
1110305003Scy            if( c=='\n' ) j--;
1111305003Scy            utf8_printf(p->out, "%.*s\n  ", j, z);
1112305003Scy            j = 0;
1113305003Scy            nLine++;
1114305003Scy            while( IsSpace(z[i+1]) ){ i++; }
1115305003Scy          }
1116305003Scy        }
1117305003Scy        z[j] = 0;
1118305003Scy      }
1119305003Scy      utf8_printf(p->out, "%s;\n", z);
1120305003Scy      sqlite3_free(z);
1121305003Scy      break;
1122305003Scy    }
1123251883Speter    case MODE_List: {
1124251883Speter      if( p->cnt++==0 && p->showHeader ){
1125251883Speter        for(i=0; i<nArg; i++){
1126305003Scy          utf8_printf(p->out,"%s%s",azCol[i],
1127289166Speter                  i==nArg-1 ? p->rowSeparator : p->colSeparator);
1128251883Speter        }
1129251883Speter      }
1130251883Speter      if( azArg==0 ) break;
1131251883Speter      for(i=0; i<nArg; i++){
1132251883Speter        char *z = azArg[i];
1133289166Speter        if( z==0 ) z = p->nullValue;
1134305003Scy        utf8_printf(p->out, "%s", z);
1135251883Speter        if( i<nArg-1 ){
1136305003Scy          utf8_printf(p->out, "%s", p->colSeparator);
1137251883Speter        }else{
1138305003Scy          utf8_printf(p->out, "%s", p->rowSeparator);
1139251883Speter        }
1140251883Speter      }
1141251883Speter      break;
1142251883Speter    }
1143251883Speter    case MODE_Html: {
1144251883Speter      if( p->cnt++==0 && p->showHeader ){
1145305003Scy        raw_printf(p->out,"<TR>");
1146251883Speter        for(i=0; i<nArg; i++){
1147305003Scy          raw_printf(p->out,"<TH>");
1148251883Speter          output_html_string(p->out, azCol[i]);
1149305003Scy          raw_printf(p->out,"</TH>\n");
1150251883Speter        }
1151305003Scy        raw_printf(p->out,"</TR>\n");
1152251883Speter      }
1153251883Speter      if( azArg==0 ) break;
1154305003Scy      raw_printf(p->out,"<TR>");
1155251883Speter      for(i=0; i<nArg; i++){
1156305003Scy        raw_printf(p->out,"<TD>");
1157289166Speter        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
1158305003Scy        raw_printf(p->out,"</TD>\n");
1159251883Speter      }
1160305003Scy      raw_printf(p->out,"</TR>\n");
1161251883Speter      break;
1162251883Speter    }
1163251883Speter    case MODE_Tcl: {
1164251883Speter      if( p->cnt++==0 && p->showHeader ){
1165251883Speter        for(i=0; i<nArg; i++){
1166251883Speter          output_c_string(p->out,azCol[i] ? azCol[i] : "");
1167305003Scy          if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
1168251883Speter        }
1169305003Scy        utf8_printf(p->out, "%s", p->rowSeparator);
1170251883Speter      }
1171251883Speter      if( azArg==0 ) break;
1172251883Speter      for(i=0; i<nArg; i++){
1173289166Speter        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
1174305003Scy        if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
1175251883Speter      }
1176305003Scy      utf8_printf(p->out, "%s", p->rowSeparator);
1177251883Speter      break;
1178251883Speter    }
1179251883Speter    case MODE_Csv: {
1180305003Scy      setBinaryMode(p->out, 1);
1181251883Speter      if( p->cnt++==0 && p->showHeader ){
1182251883Speter        for(i=0; i<nArg; i++){
1183251883Speter          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
1184251883Speter        }
1185305003Scy        utf8_printf(p->out, "%s", p->rowSeparator);
1186251883Speter      }
1187289166Speter      if( nArg>0 ){
1188289166Speter        for(i=0; i<nArg; i++){
1189289166Speter          output_csv(p, azArg[i], i<nArg-1);
1190289166Speter        }
1191305003Scy        utf8_printf(p->out, "%s", p->rowSeparator);
1192251883Speter      }
1193305003Scy      setTextMode(p->out, 1);
1194251883Speter      break;
1195251883Speter    }
1196251883Speter    case MODE_Insert: {
1197251883Speter      p->cnt++;
1198251883Speter      if( azArg==0 ) break;
1199305003Scy      utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
1200289166Speter      if( p->showHeader ){
1201305003Scy        raw_printf(p->out,"(");
1202289166Speter        for(i=0; i<nArg; i++){
1203289166Speter          char *zSep = i>0 ? ",": "";
1204305003Scy          utf8_printf(p->out, "%s%s", zSep, azCol[i]);
1205289166Speter        }
1206305003Scy        raw_printf(p->out,")");
1207289166Speter      }
1208305003Scy      raw_printf(p->out," VALUES(");
1209251883Speter      for(i=0; i<nArg; i++){
1210251883Speter        char *zSep = i>0 ? ",": "";
1211251883Speter        if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
1212305003Scy          utf8_printf(p->out,"%sNULL",zSep);
1213251883Speter        }else if( aiType && aiType[i]==SQLITE_TEXT ){
1214305003Scy          if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
1215251883Speter          output_quoted_string(p->out, azArg[i]);
1216289166Speter        }else if( aiType && (aiType[i]==SQLITE_INTEGER
1217289166Speter                             || aiType[i]==SQLITE_FLOAT) ){
1218305003Scy          utf8_printf(p->out,"%s%s",zSep, azArg[i]);
1219251883Speter        }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
1220251883Speter          const void *pBlob = sqlite3_column_blob(p->pStmt, i);
1221251883Speter          int nBlob = sqlite3_column_bytes(p->pStmt, i);
1222305003Scy          if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
1223251883Speter          output_hex_blob(p->out, pBlob, nBlob);
1224251883Speter        }else if( isNumber(azArg[i], 0) ){
1225305003Scy          utf8_printf(p->out,"%s%s",zSep, azArg[i]);
1226251883Speter        }else{
1227305003Scy          if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
1228251883Speter          output_quoted_string(p->out, azArg[i]);
1229251883Speter        }
1230251883Speter      }
1231305003Scy      raw_printf(p->out,");\n");
1232251883Speter      break;
1233251883Speter    }
1234289166Speter    case MODE_Ascii: {
1235289166Speter      if( p->cnt++==0 && p->showHeader ){
1236289166Speter        for(i=0; i<nArg; i++){
1237305003Scy          if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
1238305003Scy          utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : "");
1239289166Speter        }
1240305003Scy        utf8_printf(p->out, "%s", p->rowSeparator);
1241289166Speter      }
1242289166Speter      if( azArg==0 ) break;
1243289166Speter      for(i=0; i<nArg; i++){
1244305003Scy        if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
1245305003Scy        utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
1246289166Speter      }
1247305003Scy      utf8_printf(p->out, "%s", p->rowSeparator);
1248289166Speter      break;
1249289166Speter    }
1250251883Speter  }
1251251883Speter  return 0;
1252251883Speter}
1253251883Speter
1254251883Speter/*
1255251883Speter** This is the callback routine that the SQLite library
1256251883Speter** invokes for each row of a query result.
1257251883Speter*/
1258251883Speterstatic int callback(void *pArg, int nArg, char **azArg, char **azCol){
1259251883Speter  /* since we don't have type info, call the shell_callback with a NULL value */
1260251883Speter  return shell_callback(pArg, nArg, azArg, azCol, NULL);
1261251883Speter}
1262251883Speter
1263251883Speter/*
1264289166Speter** Set the destination table field of the ShellState structure to
1265251883Speter** the name of the table given.  Escape any quote characters in the
1266251883Speter** table name.
1267251883Speter*/
1268289166Speterstatic void set_table_name(ShellState *p, const char *zName){
1269251883Speter  int i, n;
1270251883Speter  int needQuote;
1271251883Speter  char *z;
1272251883Speter
1273251883Speter  if( p->zDestTable ){
1274251883Speter    free(p->zDestTable);
1275251883Speter    p->zDestTable = 0;
1276251883Speter  }
1277251883Speter  if( zName==0 ) return;
1278251883Speter  needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
1279251883Speter  for(i=n=0; zName[i]; i++, n++){
1280251883Speter    if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
1281251883Speter      needQuote = 1;
1282251883Speter      if( zName[i]=='\'' ) n++;
1283251883Speter    }
1284251883Speter  }
1285251883Speter  if( needQuote ) n += 2;
1286251883Speter  z = p->zDestTable = malloc( n+1 );
1287251883Speter  if( z==0 ){
1288305003Scy    raw_printf(stderr,"Error: out of memory\n");
1289251883Speter    exit(1);
1290251883Speter  }
1291251883Speter  n = 0;
1292251883Speter  if( needQuote ) z[n++] = '\'';
1293251883Speter  for(i=0; zName[i]; i++){
1294251883Speter    z[n++] = zName[i];
1295251883Speter    if( zName[i]=='\'' ) z[n++] = '\'';
1296251883Speter  }
1297251883Speter  if( needQuote ) z[n++] = '\'';
1298251883Speter  z[n] = 0;
1299251883Speter}
1300251883Speter
1301251883Speter/* zIn is either a pointer to a NULL-terminated string in memory obtained
1302251883Speter** from malloc(), or a NULL pointer. The string pointed to by zAppend is
1303251883Speter** added to zIn, and the result returned in memory obtained from malloc().
1304251883Speter** zIn, if it was not NULL, is freed.
1305251883Speter**
1306305003Scy** If the third argument, quote, is not '\0', then it is used as a
1307251883Speter** quote character for zAppend.
1308251883Speter*/
1309251883Speterstatic char *appendText(char *zIn, char const *zAppend, char quote){
1310251883Speter  int len;
1311251883Speter  int i;
1312251883Speter  int nAppend = strlen30(zAppend);
1313251883Speter  int nIn = (zIn?strlen30(zIn):0);
1314251883Speter
1315251883Speter  len = nAppend+nIn+1;
1316251883Speter  if( quote ){
1317251883Speter    len += 2;
1318251883Speter    for(i=0; i<nAppend; i++){
1319251883Speter      if( zAppend[i]==quote ) len++;
1320251883Speter    }
1321251883Speter  }
1322251883Speter
1323251883Speter  zIn = (char *)realloc(zIn, len);
1324251883Speter  if( !zIn ){
1325251883Speter    return 0;
1326251883Speter  }
1327251883Speter
1328251883Speter  if( quote ){
1329251883Speter    char *zCsr = &zIn[nIn];
1330251883Speter    *zCsr++ = quote;
1331251883Speter    for(i=0; i<nAppend; i++){
1332251883Speter      *zCsr++ = zAppend[i];
1333251883Speter      if( zAppend[i]==quote ) *zCsr++ = quote;
1334251883Speter    }
1335251883Speter    *zCsr++ = quote;
1336251883Speter    *zCsr++ = '\0';
1337251883Speter    assert( (zCsr-zIn)==len );
1338251883Speter  }else{
1339251883Speter    memcpy(&zIn[nIn], zAppend, nAppend);
1340251883Speter    zIn[len-1] = '\0';
1341251883Speter  }
1342251883Speter
1343251883Speter  return zIn;
1344251883Speter}
1345251883Speter
1346251883Speter
1347251883Speter/*
1348251883Speter** Execute a query statement that will generate SQL output.  Print
1349251883Speter** the result columns, comma-separated, on a line and then add a
1350251883Speter** semicolon terminator to the end of that line.
1351251883Speter**
1352251883Speter** If the number of columns is 1 and that column contains text "--"
1353305003Scy** then write the semicolon on a separate line.  That way, if a
1354251883Speter** "--" comment occurs at the end of the statement, the comment
1355251883Speter** won't consume the semicolon terminator.
1356251883Speter*/
1357251883Speterstatic int run_table_dump_query(
1358289166Speter  ShellState *p,           /* Query context */
1359251883Speter  const char *zSelect,     /* SELECT statement to extract content */
1360251883Speter  const char *zFirstRow    /* Print before first row, if not NULL */
1361251883Speter){
1362251883Speter  sqlite3_stmt *pSelect;
1363251883Speter  int rc;
1364251883Speter  int nResult;
1365251883Speter  int i;
1366251883Speter  const char *z;
1367289166Speter  rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
1368251883Speter  if( rc!=SQLITE_OK || !pSelect ){
1369305003Scy    utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
1370305003Scy                sqlite3_errmsg(p->db));
1371289166Speter    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
1372251883Speter    return rc;
1373251883Speter  }
1374251883Speter  rc = sqlite3_step(pSelect);
1375251883Speter  nResult = sqlite3_column_count(pSelect);
1376251883Speter  while( rc==SQLITE_ROW ){
1377251883Speter    if( zFirstRow ){
1378305003Scy      utf8_printf(p->out, "%s", zFirstRow);
1379251883Speter      zFirstRow = 0;
1380251883Speter    }
1381251883Speter    z = (const char*)sqlite3_column_text(pSelect, 0);
1382305003Scy    utf8_printf(p->out, "%s", z);
1383305003Scy    for(i=1; i<nResult; i++){
1384305003Scy      utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
1385251883Speter    }
1386251883Speter    if( z==0 ) z = "";
1387251883Speter    while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
1388251883Speter    if( z[0] ){
1389305003Scy      raw_printf(p->out, "\n;\n");
1390251883Speter    }else{
1391305003Scy      raw_printf(p->out, ";\n");
1392305003Scy    }
1393251883Speter    rc = sqlite3_step(pSelect);
1394251883Speter  }
1395251883Speter  rc = sqlite3_finalize(pSelect);
1396251883Speter  if( rc!=SQLITE_OK ){
1397305003Scy    utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
1398305003Scy                sqlite3_errmsg(p->db));
1399289166Speter    if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
1400251883Speter  }
1401251883Speter  return rc;
1402251883Speter}
1403251883Speter
1404251883Speter/*
1405251883Speter** Allocate space and save off current error string.
1406251883Speter*/
1407251883Speterstatic char *save_err_msg(
1408251883Speter  sqlite3 *db            /* Database to query */
1409251883Speter){
1410251883Speter  int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
1411289166Speter  char *zErrMsg = sqlite3_malloc64(nErrMsg);
1412251883Speter  if( zErrMsg ){
1413251883Speter    memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
1414251883Speter  }
1415251883Speter  return zErrMsg;
1416251883Speter}
1417251883Speter
1418305003Scy#ifdef __linux__
1419251883Speter/*
1420305003Scy** Attempt to display I/O stats on Linux using /proc/PID/io
1421305003Scy*/
1422305003Scystatic void displayLinuxIoStats(FILE *out){
1423305003Scy  FILE *in;
1424305003Scy  char z[200];
1425305003Scy  sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
1426305003Scy  in = fopen(z, "rb");
1427305003Scy  if( in==0 ) return;
1428305003Scy  while( fgets(z, sizeof(z), in)!=0 ){
1429305003Scy    static const struct {
1430305003Scy      const char *zPattern;
1431305003Scy      const char *zDesc;
1432305003Scy    } aTrans[] = {
1433305003Scy      { "rchar: ",                  "Bytes received by read():" },
1434305003Scy      { "wchar: ",                  "Bytes sent to write():"    },
1435305003Scy      { "syscr: ",                  "Read() system calls:"      },
1436305003Scy      { "syscw: ",                  "Write() system calls:"     },
1437305003Scy      { "read_bytes: ",             "Bytes read from storage:"  },
1438305003Scy      { "write_bytes: ",            "Bytes written to storage:" },
1439305003Scy      { "cancelled_write_bytes: ",  "Cancelled write bytes:"    },
1440305003Scy    };
1441305003Scy    int i;
1442305003Scy    for(i=0; i<ArraySize(aTrans); i++){
1443305003Scy      int n = (int)strlen(aTrans[i].zPattern);
1444305003Scy      if( strncmp(aTrans[i].zPattern, z, n)==0 ){
1445305003Scy        raw_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
1446305003Scy        break;
1447305003Scy      }
1448305003Scy    }
1449305003Scy  }
1450305003Scy  fclose(in);
1451305003Scy}
1452305003Scy#endif
1453305003Scy
1454305003Scy
1455305003Scy/*
1456251883Speter** Display memory stats.
1457251883Speter*/
1458251883Speterstatic int display_stats(
1459251883Speter  sqlite3 *db,                /* Database to query */
1460289166Speter  ShellState *pArg,           /* Pointer to ShellState */
1461251883Speter  int bReset                  /* True to reset the stats */
1462251883Speter){
1463251883Speter  int iCur;
1464251883Speter  int iHiwtr;
1465251883Speter
1466251883Speter  if( pArg && pArg->out ){
1467305003Scy
1468251883Speter    iHiwtr = iCur = -1;
1469251883Speter    sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
1470305003Scy    raw_printf(pArg->out,
1471289166Speter            "Memory Used:                         %d (max %d) bytes\n",
1472289166Speter            iCur, iHiwtr);
1473251883Speter    iHiwtr = iCur = -1;
1474251883Speter    sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
1475305003Scy    raw_printf(pArg->out, "Number of Outstanding Allocations:   %d (max %d)\n",
1476289166Speter            iCur, iHiwtr);
1477289166Speter    if( pArg->shellFlgs & SHFLG_Pagecache ){
1478289166Speter      iHiwtr = iCur = -1;
1479289166Speter      sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
1480305003Scy      raw_printf(pArg->out,
1481289166Speter              "Number of Pcache Pages Used:         %d (max %d) pages\n",
1482289166Speter              iCur, iHiwtr);
1483289166Speter    }
1484251883Speter    iHiwtr = iCur = -1;
1485251883Speter    sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
1486305003Scy    raw_printf(pArg->out,
1487289166Speter            "Number of Pcache Overflow Bytes:     %d (max %d) bytes\n",
1488289166Speter            iCur, iHiwtr);
1489289166Speter    if( pArg->shellFlgs & SHFLG_Scratch ){
1490289166Speter      iHiwtr = iCur = -1;
1491289166Speter      sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
1492305003Scy      raw_printf(pArg->out,
1493305003Scy              "Number of Scratch Allocations Used:  %d (max %d)\n",
1494289166Speter              iCur, iHiwtr);
1495289166Speter    }
1496251883Speter    iHiwtr = iCur = -1;
1497251883Speter    sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
1498305003Scy    raw_printf(pArg->out,
1499289166Speter            "Number of Scratch Overflow Bytes:    %d (max %d) bytes\n",
1500289166Speter            iCur, iHiwtr);
1501251883Speter    iHiwtr = iCur = -1;
1502251883Speter    sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
1503305003Scy    raw_printf(pArg->out, "Largest Allocation:                  %d bytes\n",
1504289166Speter            iHiwtr);
1505251883Speter    iHiwtr = iCur = -1;
1506251883Speter    sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
1507305003Scy    raw_printf(pArg->out, "Largest Pcache Allocation:           %d bytes\n",
1508289166Speter            iHiwtr);
1509251883Speter    iHiwtr = iCur = -1;
1510251883Speter    sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
1511305003Scy    raw_printf(pArg->out, "Largest Scratch Allocation:          %d bytes\n",
1512289166Speter            iHiwtr);
1513251883Speter#ifdef YYTRACKMAXSTACKDEPTH
1514251883Speter    iHiwtr = iCur = -1;
1515251883Speter    sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
1516305003Scy    raw_printf(pArg->out, "Deepest Parser Stack:                %d (max %d)\n",
1517289166Speter            iCur, iHiwtr);
1518251883Speter#endif
1519251883Speter  }
1520251883Speter
1521251883Speter  if( pArg && pArg->out && db ){
1522289166Speter    if( pArg->shellFlgs & SHFLG_Lookaside ){
1523289166Speter      iHiwtr = iCur = -1;
1524289166Speter      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
1525289166Speter                        &iCur, &iHiwtr, bReset);
1526305003Scy      raw_printf(pArg->out,
1527305003Scy              "Lookaside Slots Used:                %d (max %d)\n",
1528289166Speter              iCur, iHiwtr);
1529289166Speter      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
1530289166Speter                        &iCur, &iHiwtr, bReset);
1531305003Scy      raw_printf(pArg->out, "Successful lookaside attempts:       %d\n",
1532305003Scy              iHiwtr);
1533289166Speter      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
1534289166Speter                        &iCur, &iHiwtr, bReset);
1535305003Scy      raw_printf(pArg->out, "Lookaside failures due to size:      %d\n",
1536305003Scy              iHiwtr);
1537289166Speter      sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
1538289166Speter                        &iCur, &iHiwtr, bReset);
1539305003Scy      raw_printf(pArg->out, "Lookaside failures due to OOM:       %d\n",
1540305003Scy              iHiwtr);
1541289166Speter    }
1542251883Speter    iHiwtr = iCur = -1;
1543289166Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
1544305003Scy    raw_printf(pArg->out, "Pager Heap Usage:                    %d bytes\n",
1545305003Scy            iCur);
1546251883Speter    iHiwtr = iCur = -1;
1547251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
1548305003Scy    raw_printf(pArg->out, "Page cache hits:                     %d\n", iCur);
1549251883Speter    iHiwtr = iCur = -1;
1550251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
1551305003Scy    raw_printf(pArg->out, "Page cache misses:                   %d\n", iCur);
1552251883Speter    iHiwtr = iCur = -1;
1553251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
1554305003Scy    raw_printf(pArg->out, "Page cache writes:                   %d\n", iCur);
1555251883Speter    iHiwtr = iCur = -1;
1556251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
1557305003Scy    raw_printf(pArg->out, "Schema Heap Usage:                   %d bytes\n",
1558305003Scy            iCur);
1559251883Speter    iHiwtr = iCur = -1;
1560251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
1561305003Scy    raw_printf(pArg->out, "Statement Heap/Lookaside Usage:      %d bytes\n",
1562305003Scy            iCur);
1563251883Speter  }
1564251883Speter
1565251883Speter  if( pArg && pArg->out && db && pArg->pStmt ){
1566289166Speter    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
1567289166Speter                               bReset);
1568305003Scy    raw_printf(pArg->out, "Fullscan Steps:                      %d\n", iCur);
1569251883Speter    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
1570305003Scy    raw_printf(pArg->out, "Sort Operations:                     %d\n", iCur);
1571289166Speter    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
1572305003Scy    raw_printf(pArg->out, "Autoindex Inserts:                   %d\n", iCur);
1573289166Speter    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
1574305003Scy    raw_printf(pArg->out, "Virtual Machine Steps:               %d\n", iCur);
1575251883Speter  }
1576251883Speter
1577305003Scy#ifdef __linux__
1578305003Scy  displayLinuxIoStats(pArg->out);
1579305003Scy#endif
1580305003Scy
1581305003Scy  /* Do not remove this machine readable comment: extra-stats-output-here */
1582305003Scy
1583251883Speter  return 0;
1584251883Speter}
1585251883Speter
1586251883Speter/*
1587289166Speter** Display scan stats.
1588289166Speter*/
1589289166Speterstatic void display_scanstats(
1590289166Speter  sqlite3 *db,                    /* Database to query */
1591289166Speter  ShellState *pArg                /* Pointer to ShellState */
1592289166Speter){
1593289166Speter#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
1594289166Speter  UNUSED_PARAMETER(db);
1595289166Speter  UNUSED_PARAMETER(pArg);
1596289166Speter#else
1597289166Speter  int i, k, n, mx;
1598305003Scy  raw_printf(pArg->out, "-------- scanstats --------\n");
1599289166Speter  mx = 0;
1600289166Speter  for(k=0; k<=mx; k++){
1601289166Speter    double rEstLoop = 1.0;
1602289166Speter    for(i=n=0; 1; i++){
1603289166Speter      sqlite3_stmt *p = pArg->pStmt;
1604289166Speter      sqlite3_int64 nLoop, nVisit;
1605289166Speter      double rEst;
1606289166Speter      int iSid;
1607289166Speter      const char *zExplain;
1608289166Speter      if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){
1609289166Speter        break;
1610289166Speter      }
1611289166Speter      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid);
1612289166Speter      if( iSid>mx ) mx = iSid;
1613289166Speter      if( iSid!=k ) continue;
1614289166Speter      if( n==0 ){
1615289166Speter        rEstLoop = (double)nLoop;
1616305003Scy        if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k);
1617289166Speter      }
1618289166Speter      n++;
1619289166Speter      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
1620289166Speter      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
1621289166Speter      sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
1622305003Scy      utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain);
1623289166Speter      rEstLoop *= rEst;
1624305003Scy      raw_printf(pArg->out,
1625289166Speter          "         nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
1626289166Speter          nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
1627289166Speter      );
1628289166Speter    }
1629289166Speter  }
1630305003Scy  raw_printf(pArg->out, "---------------------------\n");
1631289166Speter#endif
1632289166Speter}
1633289166Speter
1634289166Speter/*
1635289166Speter** Parameter azArray points to a zero-terminated array of strings. zStr
1636289166Speter** points to a single nul-terminated string. Return non-zero if zStr
1637289166Speter** is equal, according to strcmp(), to any of the strings in the array.
1638289166Speter** Otherwise, return zero.
1639289166Speter*/
1640289166Speterstatic int str_in_array(const char *zStr, const char **azArray){
1641289166Speter  int i;
1642289166Speter  for(i=0; azArray[i]; i++){
1643289166Speter    if( 0==strcmp(zStr, azArray[i]) ) return 1;
1644289166Speter  }
1645289166Speter  return 0;
1646289166Speter}
1647289166Speter
1648289166Speter/*
1649289166Speter** If compiled statement pSql appears to be an EXPLAIN statement, allocate
1650289166Speter** and populate the ShellState.aiIndent[] array with the number of
1651305003Scy** spaces each opcode should be indented before it is output.
1652289166Speter**
1653289166Speter** The indenting rules are:
1654289166Speter**
1655289166Speter**     * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
1656289166Speter**       all opcodes that occur between the p2 jump destination and the opcode
1657289166Speter**       itself by 2 spaces.
1658289166Speter**
1659289166Speter**     * For each "Goto", if the jump destination is earlier in the program
1660289166Speter**       and ends on one of:
1661289166Speter**          Yield  SeekGt  SeekLt  RowSetRead  Rewind
1662289166Speter**       or if the P1 parameter is one instead of zero,
1663289166Speter**       then indent all opcodes between the earlier instruction
1664289166Speter**       and "Goto" by 2 spaces.
1665289166Speter*/
1666289166Speterstatic void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
1667289166Speter  const char *zSql;               /* The text of the SQL statement */
1668289166Speter  const char *z;                  /* Used to check if this is an EXPLAIN */
1669289166Speter  int *abYield = 0;               /* True if op is an OP_Yield */
1670289166Speter  int nAlloc = 0;                 /* Allocated size of p->aiIndent[], abYield */
1671289166Speter  int iOp;                        /* Index of operation in p->aiIndent[] */
1672289166Speter
1673289166Speter  const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
1674289166Speter                           "NextIfOpen", "PrevIfOpen", 0 };
1675289166Speter  const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
1676289166Speter                            "Rewind", 0 };
1677289166Speter  const char *azGoto[] = { "Goto", 0 };
1678289166Speter
1679289166Speter  /* Try to figure out if this is really an EXPLAIN statement. If this
1680289166Speter  ** cannot be verified, return early.  */
1681305003Scy  if( sqlite3_column_count(pSql)!=8 ){
1682305003Scy    p->cMode = p->mode;
1683305003Scy    return;
1684305003Scy  }
1685289166Speter  zSql = sqlite3_sql(pSql);
1686289166Speter  if( zSql==0 ) return;
1687289166Speter  for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
1688305003Scy  if( sqlite3_strnicmp(z, "explain", 7) ){
1689305003Scy    p->cMode = p->mode;
1690305003Scy    return;
1691305003Scy  }
1692289166Speter
1693289166Speter  for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
1694289166Speter    int i;
1695289166Speter    int iAddr = sqlite3_column_int(pSql, 0);
1696289166Speter    const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
1697289166Speter
1698289166Speter    /* Set p2 to the P2 field of the current opcode. Then, assuming that
1699289166Speter    ** p2 is an instruction address, set variable p2op to the index of that
1700289166Speter    ** instruction in the aiIndent[] array. p2 and p2op may be different if
1701289166Speter    ** the current instruction is part of a sub-program generated by an
1702289166Speter    ** SQL trigger or foreign key.  */
1703289166Speter    int p2 = sqlite3_column_int(pSql, 3);
1704289166Speter    int p2op = (p2 + (iOp-iAddr));
1705289166Speter
1706289166Speter    /* Grow the p->aiIndent array as required */
1707289166Speter    if( iOp>=nAlloc ){
1708305003Scy      if( iOp==0 ){
1709305003Scy        /* Do further verfication that this is explain output.  Abort if
1710305003Scy        ** it is not */
1711305003Scy        static const char *explainCols[] = {
1712305003Scy           "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
1713305003Scy        int jj;
1714305003Scy        for(jj=0; jj<ArraySize(explainCols); jj++){
1715305003Scy          if( strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
1716305003Scy            p->cMode = p->mode;
1717305003Scy            sqlite3_reset(pSql);
1718305003Scy            return;
1719305003Scy          }
1720305003Scy        }
1721305003Scy      }
1722289166Speter      nAlloc += 100;
1723289166Speter      p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
1724289166Speter      abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
1725289166Speter    }
1726289166Speter    abYield[iOp] = str_in_array(zOp, azYield);
1727289166Speter    p->aiIndent[iOp] = 0;
1728289166Speter    p->nIndent = iOp+1;
1729289166Speter
1730289166Speter    if( str_in_array(zOp, azNext) ){
1731289166Speter      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
1732289166Speter    }
1733289166Speter    if( str_in_array(zOp, azGoto) && p2op<p->nIndent
1734289166Speter     && (abYield[p2op] || sqlite3_column_int(pSql, 2))
1735289166Speter    ){
1736305003Scy      for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
1737289166Speter    }
1738289166Speter  }
1739289166Speter
1740289166Speter  p->iIndent = 0;
1741289166Speter  sqlite3_free(abYield);
1742289166Speter  sqlite3_reset(pSql);
1743289166Speter}
1744289166Speter
1745289166Speter/*
1746289166Speter** Free the array allocated by explain_data_prepare().
1747289166Speter*/
1748289166Speterstatic void explain_data_delete(ShellState *p){
1749289166Speter  sqlite3_free(p->aiIndent);
1750289166Speter  p->aiIndent = 0;
1751289166Speter  p->nIndent = 0;
1752289166Speter  p->iIndent = 0;
1753289166Speter}
1754289166Speter
1755289166Speter/*
1756305003Scy** Disable and restore .wheretrace and .selecttrace settings.
1757305003Scy*/
1758305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
1759305003Scyextern int sqlite3SelectTrace;
1760305003Scystatic int savedSelectTrace;
1761305003Scy#endif
1762305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
1763305003Scyextern int sqlite3WhereTrace;
1764305003Scystatic int savedWhereTrace;
1765305003Scy#endif
1766305003Scystatic void disable_debug_trace_modes(void){
1767305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
1768305003Scy  savedSelectTrace = sqlite3SelectTrace;
1769305003Scy  sqlite3SelectTrace = 0;
1770305003Scy#endif
1771305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
1772305003Scy  savedWhereTrace = sqlite3WhereTrace;
1773305003Scy  sqlite3WhereTrace = 0;
1774305003Scy#endif
1775305003Scy}
1776305003Scystatic void restore_debug_trace_modes(void){
1777305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
1778305003Scy  sqlite3SelectTrace = savedSelectTrace;
1779305003Scy#endif
1780305003Scy#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
1781305003Scy  sqlite3WhereTrace = savedWhereTrace;
1782305003Scy#endif
1783305003Scy}
1784305003Scy
1785305003Scy/*
1786305003Scy** Run a prepared statement
1787305003Scy*/
1788305003Scystatic void exec_prepared_stmt(
1789305003Scy  ShellState *pArg,                                /* Pointer to ShellState */
1790305003Scy  sqlite3_stmt *pStmt,                             /* Statment to run */
1791305003Scy  int (*xCallback)(void*,int,char**,char**,int*)   /* Callback function */
1792305003Scy){
1793305003Scy  int rc;
1794305003Scy
1795305003Scy  /* perform the first step.  this will tell us if we
1796305003Scy  ** have a result set or not and how wide it is.
1797305003Scy  */
1798305003Scy  rc = sqlite3_step(pStmt);
1799305003Scy  /* if we have a result set... */
1800305003Scy  if( SQLITE_ROW == rc ){
1801305003Scy    /* if we have a callback... */
1802305003Scy    if( xCallback ){
1803305003Scy      /* allocate space for col name ptr, value ptr, and type */
1804305003Scy      int nCol = sqlite3_column_count(pStmt);
1805305003Scy      void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
1806305003Scy      if( !pData ){
1807305003Scy        rc = SQLITE_NOMEM;
1808305003Scy      }else{
1809305003Scy        char **azCols = (char **)pData;      /* Names of result columns */
1810305003Scy        char **azVals = &azCols[nCol];       /* Results */
1811305003Scy        int *aiTypes = (int *)&azVals[nCol]; /* Result types */
1812305003Scy        int i, x;
1813305003Scy        assert(sizeof(int) <= sizeof(char *));
1814305003Scy        /* save off ptrs to column names */
1815305003Scy        for(i=0; i<nCol; i++){
1816305003Scy          azCols[i] = (char *)sqlite3_column_name(pStmt, i);
1817305003Scy        }
1818305003Scy        do{
1819305003Scy          /* extract the data and data types */
1820305003Scy          for(i=0; i<nCol; i++){
1821305003Scy            aiTypes[i] = x = sqlite3_column_type(pStmt, i);
1822305003Scy            if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){
1823305003Scy              azVals[i] = "";
1824305003Scy            }else{
1825305003Scy              azVals[i] = (char*)sqlite3_column_text(pStmt, i);
1826305003Scy            }
1827305003Scy            if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
1828305003Scy              rc = SQLITE_NOMEM;
1829305003Scy              break; /* from for */
1830305003Scy            }
1831305003Scy          } /* end for */
1832305003Scy
1833305003Scy          /* if data and types extracted successfully... */
1834305003Scy          if( SQLITE_ROW == rc ){
1835305003Scy            /* call the supplied callback with the result row data */
1836305003Scy            if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
1837305003Scy              rc = SQLITE_ABORT;
1838305003Scy            }else{
1839305003Scy              rc = sqlite3_step(pStmt);
1840305003Scy            }
1841305003Scy          }
1842305003Scy        } while( SQLITE_ROW == rc );
1843305003Scy        sqlite3_free(pData);
1844305003Scy      }
1845305003Scy    }else{
1846305003Scy      do{
1847305003Scy        rc = sqlite3_step(pStmt);
1848305003Scy      } while( rc == SQLITE_ROW );
1849305003Scy    }
1850305003Scy  }
1851305003Scy}
1852305003Scy
1853305003Scy/*
1854305003Scy** Execute a statement or set of statements.  Print
1855305003Scy** any result rows/columns depending on the current mode
1856251883Speter** set via the supplied callback.
1857251883Speter**
1858305003Scy** This is very similar to SQLite's built-in sqlite3_exec()
1859305003Scy** function except it takes a slightly different callback
1860251883Speter** and callback data argument.
1861251883Speter*/
1862251883Speterstatic int shell_exec(
1863289166Speter  sqlite3 *db,                              /* An open database */
1864289166Speter  const char *zSql,                         /* SQL to be evaluated */
1865251883Speter  int (*xCallback)(void*,int,char**,char**,int*),   /* Callback function */
1866289166Speter                                            /* (not the same as sqlite3_exec) */
1867289166Speter  ShellState *pArg,                         /* Pointer to ShellState */
1868289166Speter  char **pzErrMsg                           /* Error msg written here */
1869251883Speter){
1870251883Speter  sqlite3_stmt *pStmt = NULL;     /* Statement to execute. */
1871251883Speter  int rc = SQLITE_OK;             /* Return Code */
1872251883Speter  int rc2;
1873251883Speter  const char *zLeftover;          /* Tail of unprocessed SQL */
1874251883Speter
1875251883Speter  if( pzErrMsg ){
1876251883Speter    *pzErrMsg = NULL;
1877251883Speter  }
1878251883Speter
1879251883Speter  while( zSql[0] && (SQLITE_OK == rc) ){
1880305003Scy    static const char *zStmtSql;
1881251883Speter    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
1882251883Speter    if( SQLITE_OK != rc ){
1883251883Speter      if( pzErrMsg ){
1884251883Speter        *pzErrMsg = save_err_msg(db);
1885251883Speter      }
1886251883Speter    }else{
1887251883Speter      if( !pStmt ){
1888251883Speter        /* this happens for a comment or white-space */
1889251883Speter        zSql = zLeftover;
1890251883Speter        while( IsSpace(zSql[0]) ) zSql++;
1891251883Speter        continue;
1892251883Speter      }
1893305003Scy      zStmtSql = sqlite3_sql(pStmt);
1894305003Scy      while( IsSpace(zStmtSql[0]) ) zStmtSql++;
1895251883Speter
1896251883Speter      /* save off the prepared statment handle and reset row count */
1897251883Speter      if( pArg ){
1898251883Speter        pArg->pStmt = pStmt;
1899251883Speter        pArg->cnt = 0;
1900251883Speter      }
1901251883Speter
1902251883Speter      /* echo the sql statement if echo on */
1903251883Speter      if( pArg && pArg->echoOn ){
1904305003Scy        utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
1905251883Speter      }
1906251883Speter
1907289166Speter      /* Show the EXPLAIN QUERY PLAN if .eqp is on */
1908305003Scy      if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){
1909289166Speter        sqlite3_stmt *pExplain;
1910305003Scy        char *zEQP;
1911305003Scy        disable_debug_trace_modes();
1912305003Scy        zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
1913289166Speter        rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
1914289166Speter        if( rc==SQLITE_OK ){
1915289166Speter          while( sqlite3_step(pExplain)==SQLITE_ROW ){
1916305003Scy            raw_printf(pArg->out,"--EQP-- %d,",sqlite3_column_int(pExplain, 0));
1917305003Scy            raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
1918305003Scy            raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
1919305003Scy            utf8_printf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
1920289166Speter          }
1921251883Speter        }
1922289166Speter        sqlite3_finalize(pExplain);
1923289166Speter        sqlite3_free(zEQP);
1924305003Scy        if( pArg->autoEQP>=2 ){
1925305003Scy          /* Also do an EXPLAIN for ".eqp full" mode */
1926305003Scy          zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
1927305003Scy          rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
1928305003Scy          if( rc==SQLITE_OK ){
1929305003Scy            pArg->cMode = MODE_Explain;
1930305003Scy            explain_data_prepare(pArg, pExplain);
1931305003Scy            exec_prepared_stmt(pArg, pExplain, xCallback);
1932305003Scy            explain_data_delete(pArg);
1933305003Scy          }
1934305003Scy          sqlite3_finalize(pExplain);
1935305003Scy          sqlite3_free(zEQP);
1936305003Scy        }
1937305003Scy        restore_debug_trace_modes();
1938251883Speter      }
1939251883Speter
1940305003Scy      if( pArg ){
1941305003Scy        pArg->cMode = pArg->mode;
1942305003Scy        if( pArg->autoExplain
1943305003Scy         && sqlite3_column_count(pStmt)==8
1944305003Scy         && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0
1945305003Scy        ){
1946305003Scy          pArg->cMode = MODE_Explain;
1947305003Scy        }
1948289166Speter
1949305003Scy        /* If the shell is currently in ".explain" mode, gather the extra
1950305003Scy        ** data required to add indents to the output.*/
1951305003Scy        if( pArg->cMode==MODE_Explain ){
1952305003Scy          explain_data_prepare(pArg, pStmt);
1953251883Speter        }
1954251883Speter      }
1955251883Speter
1956305003Scy      exec_prepared_stmt(pArg, pStmt, xCallback);
1957289166Speter      explain_data_delete(pArg);
1958289166Speter
1959251883Speter      /* print usage stats if stats on */
1960251883Speter      if( pArg && pArg->statsOn ){
1961251883Speter        display_stats(db, pArg, 0);
1962251883Speter      }
1963251883Speter
1964289166Speter      /* print loop-counters if required */
1965289166Speter      if( pArg && pArg->scanstatsOn ){
1966289166Speter        display_scanstats(db, pArg);
1967289166Speter      }
1968289166Speter
1969305003Scy      /* Finalize the statement just executed. If this fails, save a
1970251883Speter      ** copy of the error message. Otherwise, set zSql to point to the
1971251883Speter      ** next statement to execute. */
1972251883Speter      rc2 = sqlite3_finalize(pStmt);
1973251883Speter      if( rc!=SQLITE_NOMEM ) rc = rc2;
1974251883Speter      if( rc==SQLITE_OK ){
1975251883Speter        zSql = zLeftover;
1976251883Speter        while( IsSpace(zSql[0]) ) zSql++;
1977251883Speter      }else if( pzErrMsg ){
1978251883Speter        *pzErrMsg = save_err_msg(db);
1979251883Speter      }
1980251883Speter
1981251883Speter      /* clear saved stmt handle */
1982251883Speter      if( pArg ){
1983251883Speter        pArg->pStmt = NULL;
1984251883Speter      }
1985251883Speter    }
1986251883Speter  } /* end while */
1987251883Speter
1988251883Speter  return rc;
1989251883Speter}
1990251883Speter
1991251883Speter
1992251883Speter/*
1993251883Speter** This is a different callback routine used for dumping the database.
1994251883Speter** Each row received by this callback consists of a table name,
1995251883Speter** the table type ("index" or "table") and SQL to create the table.
1996251883Speter** This routine should print text sufficient to recreate the table.
1997251883Speter*/
1998251883Speterstatic int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
1999251883Speter  int rc;
2000251883Speter  const char *zTable;
2001251883Speter  const char *zType;
2002251883Speter  const char *zSql;
2003251883Speter  const char *zPrepStmt = 0;
2004289166Speter  ShellState *p = (ShellState *)pArg;
2005251883Speter
2006251883Speter  UNUSED_PARAMETER(azCol);
2007251883Speter  if( nArg!=3 ) return 1;
2008251883Speter  zTable = azArg[0];
2009251883Speter  zType = azArg[1];
2010251883Speter  zSql = azArg[2];
2011305003Scy
2012251883Speter  if( strcmp(zTable, "sqlite_sequence")==0 ){
2013251883Speter    zPrepStmt = "DELETE FROM sqlite_sequence;\n";
2014289166Speter  }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
2015305003Scy    raw_printf(p->out, "ANALYZE sqlite_master;\n");
2016251883Speter  }else if( strncmp(zTable, "sqlite_", 7)==0 ){
2017251883Speter    return 0;
2018251883Speter  }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
2019251883Speter    char *zIns;
2020251883Speter    if( !p->writableSchema ){
2021305003Scy      raw_printf(p->out, "PRAGMA writable_schema=ON;\n");
2022251883Speter      p->writableSchema = 1;
2023251883Speter    }
2024251883Speter    zIns = sqlite3_mprintf(
2025251883Speter       "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
2026251883Speter       "VALUES('table','%q','%q',0,'%q');",
2027251883Speter       zTable, zTable, zSql);
2028305003Scy    utf8_printf(p->out, "%s\n", zIns);
2029251883Speter    sqlite3_free(zIns);
2030251883Speter    return 0;
2031251883Speter  }else{
2032305003Scy    utf8_printf(p->out, "%s;\n", zSql);
2033251883Speter  }
2034251883Speter
2035251883Speter  if( strcmp(zType, "table")==0 ){
2036251883Speter    sqlite3_stmt *pTableInfo = 0;
2037251883Speter    char *zSelect = 0;
2038251883Speter    char *zTableInfo = 0;
2039251883Speter    char *zTmp = 0;
2040251883Speter    int nRow = 0;
2041305003Scy
2042251883Speter    zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
2043251883Speter    zTableInfo = appendText(zTableInfo, zTable, '"');
2044251883Speter    zTableInfo = appendText(zTableInfo, ");", 0);
2045251883Speter
2046289166Speter    rc = sqlite3_prepare_v2(p->db, zTableInfo, -1, &pTableInfo, 0);
2047251883Speter    free(zTableInfo);
2048251883Speter    if( rc!=SQLITE_OK || !pTableInfo ){
2049251883Speter      return 1;
2050251883Speter    }
2051251883Speter
2052251883Speter    zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
2053251883Speter    /* Always quote the table name, even if it appears to be pure ascii,
2054251883Speter    ** in case it is a keyword. Ex:  INSERT INTO "table" ... */
2055251883Speter    zTmp = appendText(zTmp, zTable, '"');
2056251883Speter    if( zTmp ){
2057251883Speter      zSelect = appendText(zSelect, zTmp, '\'');
2058251883Speter      free(zTmp);
2059251883Speter    }
2060251883Speter    zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
2061251883Speter    rc = sqlite3_step(pTableInfo);
2062251883Speter    while( rc==SQLITE_ROW ){
2063251883Speter      const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
2064251883Speter      zSelect = appendText(zSelect, "quote(", 0);
2065251883Speter      zSelect = appendText(zSelect, zText, '"');
2066251883Speter      rc = sqlite3_step(pTableInfo);
2067251883Speter      if( rc==SQLITE_ROW ){
2068251883Speter        zSelect = appendText(zSelect, "), ", 0);
2069251883Speter      }else{
2070251883Speter        zSelect = appendText(zSelect, ") ", 0);
2071251883Speter      }
2072251883Speter      nRow++;
2073251883Speter    }
2074251883Speter    rc = sqlite3_finalize(pTableInfo);
2075251883Speter    if( rc!=SQLITE_OK || nRow==0 ){
2076251883Speter      free(zSelect);
2077251883Speter      return 1;
2078251883Speter    }
2079251883Speter    zSelect = appendText(zSelect, "|| ')' FROM  ", 0);
2080251883Speter    zSelect = appendText(zSelect, zTable, '"');
2081251883Speter
2082251883Speter    rc = run_table_dump_query(p, zSelect, zPrepStmt);
2083251883Speter    if( rc==SQLITE_CORRUPT ){
2084251883Speter      zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
2085251883Speter      run_table_dump_query(p, zSelect, 0);
2086251883Speter    }
2087251883Speter    free(zSelect);
2088251883Speter  }
2089251883Speter  return 0;
2090251883Speter}
2091251883Speter
2092251883Speter/*
2093251883Speter** Run zQuery.  Use dump_callback() as the callback routine so that
2094251883Speter** the contents of the query are output as SQL statements.
2095251883Speter**
2096251883Speter** If we get a SQLITE_CORRUPT error, rerun the query after appending
2097251883Speter** "ORDER BY rowid DESC" to the end.
2098251883Speter*/
2099251883Speterstatic int run_schema_dump_query(
2100305003Scy  ShellState *p,
2101251883Speter  const char *zQuery
2102251883Speter){
2103251883Speter  int rc;
2104251883Speter  char *zErr = 0;
2105251883Speter  rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
2106251883Speter  if( rc==SQLITE_CORRUPT ){
2107251883Speter    char *zQ2;
2108251883Speter    int len = strlen30(zQuery);
2109305003Scy    raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
2110251883Speter    if( zErr ){
2111305003Scy      utf8_printf(p->out, "/****** %s ******/\n", zErr);
2112251883Speter      sqlite3_free(zErr);
2113251883Speter      zErr = 0;
2114251883Speter    }
2115251883Speter    zQ2 = malloc( len+100 );
2116251883Speter    if( zQ2==0 ) return rc;
2117251883Speter    sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
2118251883Speter    rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
2119251883Speter    if( rc ){
2120305003Scy      utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr);
2121251883Speter    }else{
2122251883Speter      rc = SQLITE_CORRUPT;
2123251883Speter    }
2124251883Speter    sqlite3_free(zErr);
2125251883Speter    free(zQ2);
2126251883Speter  }
2127251883Speter  return rc;
2128251883Speter}
2129251883Speter
2130251883Speter/*
2131251883Speter** Text of a help message
2132251883Speter*/
2133251883Speterstatic char zHelp[] =
2134305003Scy  ".auth ON|OFF           Show authorizer callbacks\n"
2135251883Speter  ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
2136289166Speter  ".bail on|off           Stop after hitting an error.  Default OFF\n"
2137289166Speter  ".binary on|off         Turn binary output on or off.  Default OFF\n"
2138305003Scy  ".changes on|off        Show number of rows changed by SQL\n"
2139289166Speter  ".clone NEWDB           Clone data into NEWDB from the existing database\n"
2140251883Speter  ".databases             List names and files of attached databases\n"
2141289166Speter  ".dbinfo ?DB?           Show status information about the database\n"
2142251883Speter  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
2143251883Speter  "                         If TABLE specified, only dump tables matching\n"
2144251883Speter  "                         LIKE pattern TABLE.\n"
2145289166Speter  ".echo on|off           Turn command echo on or off\n"
2146305003Scy  ".eqp on|off|full       Enable or disable automatic EXPLAIN QUERY PLAN\n"
2147251883Speter  ".exit                  Exit this program\n"
2148305003Scy  ".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"
2149305003Scy  ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
2150289166Speter  ".headers on|off        Turn display of headers on or off\n"
2151251883Speter  ".help                  Show this message\n"
2152251883Speter  ".import FILE TABLE     Import data from FILE into TABLE\n"
2153289166Speter  ".indexes ?TABLE?       Show names of all indexes\n"
2154289166Speter  "                         If TABLE specified, only show indexes for tables\n"
2155251883Speter  "                         matching LIKE pattern TABLE.\n"
2156251883Speter#ifdef SQLITE_ENABLE_IOTRACE
2157251883Speter  ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
2158251883Speter#endif
2159289166Speter  ".limit ?LIMIT? ?VAL?   Display or change the value of an SQLITE_LIMIT\n"
2160251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION
2161251883Speter  ".load FILE ?ENTRY?     Load an extension library\n"
2162251883Speter#endif
2163251883Speter  ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"
2164251883Speter  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"
2165289166Speter  "                         ascii    Columns/rows delimited by 0x1F and 0x1E\n"
2166251883Speter  "                         csv      Comma-separated values\n"
2167251883Speter  "                         column   Left-aligned columns.  (See .width)\n"
2168251883Speter  "                         html     HTML <table> code\n"
2169251883Speter  "                         insert   SQL insert statements for TABLE\n"
2170251883Speter  "                         line     One value per line\n"
2171289166Speter  "                         list     Values delimited by .separator strings\n"
2172251883Speter  "                         tabs     Tab-separated values\n"
2173251883Speter  "                         tcl      TCL list elements\n"
2174251883Speter  ".nullvalue STRING      Use STRING in place of NULL values\n"
2175289166Speter  ".once FILENAME         Output for the next SQL command only to FILENAME\n"
2176289166Speter  ".open ?FILENAME?       Close existing database and reopen FILENAME\n"
2177289166Speter  ".output ?FILENAME?     Send output to FILENAME or stdout\n"
2178251883Speter  ".print STRING...       Print literal STRING\n"
2179251883Speter  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
2180251883Speter  ".quit                  Exit this program\n"
2181251883Speter  ".read FILENAME         Execute SQL in FILENAME\n"
2182251883Speter  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
2183289166Speter  ".save FILE             Write in-memory database into FILE\n"
2184289166Speter  ".scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off\n"
2185305003Scy  ".schema ?PATTERN?      Show the CREATE statements matching PATTERN\n"
2186305003Scy  "                          Add --indent for pretty-printing\n"
2187289166Speter  ".separator COL ?ROW?   Change the column separator and optionally the row\n"
2188289166Speter  "                         separator for both the output mode and .import\n"
2189305003Scy#if defined(SQLITE_ENABLE_SESSION)
2190305003Scy  ".session CMD ...       Create or control sessions\n"
2191305003Scy#endif
2192289166Speter  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
2193251883Speter  ".show                  Show the current values for various settings\n"
2194305003Scy  ".stats ?on|off?        Show stats or turn stats on or off\n"
2195289166Speter  ".system CMD ARGS...    Run CMD ARGS... in a system shell\n"
2196251883Speter  ".tables ?TABLE?        List names of tables\n"
2197251883Speter  "                         If TABLE specified, only list tables matching\n"
2198251883Speter  "                         LIKE pattern TABLE.\n"
2199251883Speter  ".timeout MS            Try opening locked tables for MS milliseconds\n"
2200289166Speter  ".timer on|off          Turn SQL timer on or off\n"
2201251883Speter  ".trace FILE|off        Output each SQL statement as it is run\n"
2202305003Scy  ".vfsinfo ?AUX?         Information about the top-level VFS\n"
2203305003Scy  ".vfslist               List all available VFSes\n"
2204251883Speter  ".vfsname ?AUX?         Print the name of the VFS stack\n"
2205251883Speter  ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
2206289166Speter  "                         Negative values right-justify\n"
2207251883Speter;
2208251883Speter
2209305003Scy#if defined(SQLITE_ENABLE_SESSION)
2210305003Scy/*
2211305003Scy** Print help information for the ".sessions" command
2212305003Scy*/
2213305003Scyvoid session_help(ShellState *p){
2214305003Scy  raw_printf(p->out,
2215305003Scy    ".session ?NAME? SUBCOMMAND ?ARGS...?\n"
2216305003Scy    "If ?NAME? is omitted, the first defined session is used.\n"
2217305003Scy    "Subcommands:\n"
2218305003Scy    "   attach TABLE             Attach TABLE\n"
2219305003Scy    "   changeset FILE           Write a changeset into FILE\n"
2220305003Scy    "   close                    Close one session\n"
2221305003Scy    "   enable ?BOOLEAN?         Set or query the enable bit\n"
2222305003Scy    "   filter GLOB...           Reject tables matching GLOBs\n"
2223305003Scy    "   indirect ?BOOLEAN?       Mark or query the indirect status\n"
2224305003Scy    "   isempty                  Query whether the session is empty\n"
2225305003Scy    "   list                     List currently open session names\n"
2226305003Scy    "   open DB NAME             Open a new session on DB\n"
2227305003Scy    "   patchset FILE            Write a patchset into FILE\n"
2228305003Scy  );
2229305003Scy}
2230305003Scy#endif
2231305003Scy
2232305003Scy
2233251883Speter/* Forward reference */
2234289166Speterstatic int process_input(ShellState *p, FILE *in);
2235289166Speter/*
2236289166Speter** Implementation of the "readfile(X)" SQL function.  The entire content
2237289166Speter** of the file named X is read and returned as a BLOB.  NULL is returned
2238289166Speter** if the file does not exist or is unreadable.
2239289166Speter*/
2240289166Speterstatic void readfileFunc(
2241289166Speter  sqlite3_context *context,
2242289166Speter  int argc,
2243289166Speter  sqlite3_value **argv
2244289166Speter){
2245289166Speter  const char *zName;
2246289166Speter  FILE *in;
2247289166Speter  long nIn;
2248289166Speter  void *pBuf;
2249251883Speter
2250289166Speter  UNUSED_PARAMETER(argc);
2251289166Speter  zName = (const char*)sqlite3_value_text(argv[0]);
2252289166Speter  if( zName==0 ) return;
2253289166Speter  in = fopen(zName, "rb");
2254289166Speter  if( in==0 ) return;
2255289166Speter  fseek(in, 0, SEEK_END);
2256289166Speter  nIn = ftell(in);
2257289166Speter  rewind(in);
2258289166Speter  pBuf = sqlite3_malloc64( nIn );
2259289166Speter  if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
2260289166Speter    sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
2261289166Speter  }else{
2262289166Speter    sqlite3_free(pBuf);
2263289166Speter  }
2264289166Speter  fclose(in);
2265289166Speter}
2266289166Speter
2267251883Speter/*
2268289166Speter** Implementation of the "writefile(X,Y)" SQL function.  The argument Y
2269289166Speter** is written into file X.  The number of bytes written is returned.  Or
2270289166Speter** NULL is returned if something goes wrong, such as being unable to open
2271289166Speter** file X for writing.
2272289166Speter*/
2273289166Speterstatic void writefileFunc(
2274289166Speter  sqlite3_context *context,
2275289166Speter  int argc,
2276289166Speter  sqlite3_value **argv
2277289166Speter){
2278289166Speter  FILE *out;
2279289166Speter  const char *z;
2280289166Speter  sqlite3_int64 rc;
2281289166Speter  const char *zFile;
2282289166Speter
2283289166Speter  UNUSED_PARAMETER(argc);
2284289166Speter  zFile = (const char*)sqlite3_value_text(argv[0]);
2285289166Speter  if( zFile==0 ) return;
2286289166Speter  out = fopen(zFile, "wb");
2287289166Speter  if( out==0 ) return;
2288289166Speter  z = (const char*)sqlite3_value_blob(argv[1]);
2289289166Speter  if( z==0 ){
2290289166Speter    rc = 0;
2291289166Speter  }else{
2292289166Speter    rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
2293289166Speter  }
2294289166Speter  fclose(out);
2295289166Speter  sqlite3_result_int64(context, rc);
2296289166Speter}
2297289166Speter
2298305003Scy#if defined(SQLITE_ENABLE_SESSION)
2299289166Speter/*
2300305003Scy** Close a single OpenSession object and release all of its associated
2301305003Scy** resources.
2302305003Scy*/
2303305003Scystatic void session_close(OpenSession *pSession){
2304305003Scy  int i;
2305305003Scy  sqlite3session_delete(pSession->p);
2306305003Scy  sqlite3_free(pSession->zName);
2307305003Scy  for(i=0; i<pSession->nFilter; i++){
2308305003Scy    sqlite3_free(pSession->azFilter[i]);
2309305003Scy  }
2310305003Scy  sqlite3_free(pSession->azFilter);
2311305003Scy  memset(pSession, 0, sizeof(OpenSession));
2312305003Scy}
2313305003Scy#endif
2314305003Scy
2315305003Scy/*
2316305003Scy** Close all OpenSession objects and release all associated resources.
2317305003Scy*/
2318305003Scy#if defined(SQLITE_ENABLE_SESSION)
2319305003Scystatic void session_close_all(ShellState *p){
2320305003Scy  int i;
2321305003Scy  for(i=0; i<p->nSession; i++){
2322305003Scy    session_close(&p->aSession[i]);
2323305003Scy  }
2324305003Scy  p->nSession = 0;
2325305003Scy}
2326305003Scy#else
2327305003Scy# define session_close_all(X)
2328305003Scy#endif
2329305003Scy
2330305003Scy/*
2331305003Scy** Implementation of the xFilter function for an open session.  Omit
2332305003Scy** any tables named by ".session filter" but let all other table through.
2333305003Scy*/
2334305003Scy#if defined(SQLITE_ENABLE_SESSION)
2335305003Scystatic int session_filter(void *pCtx, const char *zTab){
2336305003Scy  OpenSession *pSession = (OpenSession*)pCtx;
2337305003Scy  int i;
2338305003Scy  for(i=0; i<pSession->nFilter; i++){
2339305003Scy    if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
2340305003Scy  }
2341305003Scy  return 1;
2342305003Scy}
2343305003Scy#endif
2344305003Scy
2345305003Scy/*
2346251883Speter** Make sure the database is open.  If it is not, then open it.  If
2347251883Speter** the database fails to open, print an error message and exit.
2348251883Speter*/
2349289166Speterstatic void open_db(ShellState *p, int keepAlive){
2350251883Speter  if( p->db==0 ){
2351251883Speter    sqlite3_initialize();
2352251883Speter    sqlite3_open(p->zDbFilename, &p->db);
2353289166Speter    globalDb = p->db;
2354289166Speter    if( p->db && sqlite3_errcode(p->db)==SQLITE_OK ){
2355289166Speter      sqlite3_create_function(p->db, "shellstatic", 0, SQLITE_UTF8, 0,
2356251883Speter          shellstaticFunc, 0, 0);
2357251883Speter    }
2358289166Speter    if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
2359305003Scy      utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
2360289166Speter          p->zDbFilename, sqlite3_errmsg(p->db));
2361289166Speter      if( keepAlive ) return;
2362251883Speter      exit(1);
2363251883Speter    }
2364251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION
2365251883Speter    sqlite3_enable_load_extension(p->db, 1);
2366251883Speter#endif
2367289166Speter    sqlite3_create_function(p->db, "readfile", 1, SQLITE_UTF8, 0,
2368289166Speter                            readfileFunc, 0, 0);
2369289166Speter    sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0,
2370289166Speter                            writefileFunc, 0, 0);
2371251883Speter  }
2372251883Speter}
2373251883Speter
2374251883Speter/*
2375251883Speter** Do C-language style dequoting.
2376251883Speter**
2377289166Speter**    \a    -> alarm
2378289166Speter**    \b    -> backspace
2379251883Speter**    \t    -> tab
2380251883Speter**    \n    -> newline
2381289166Speter**    \v    -> vertical tab
2382289166Speter**    \f    -> form feed
2383251883Speter**    \r    -> carriage return
2384289166Speter**    \s    -> space
2385289166Speter**    \"    -> "
2386289166Speter**    \'    -> '
2387289166Speter**    \\    -> backslash
2388251883Speter**    \NNN  -> ascii character NNN in octal
2389251883Speter*/
2390251883Speterstatic void resolve_backslashes(char *z){
2391251883Speter  int i, j;
2392251883Speter  char c;
2393289166Speter  while( *z && *z!='\\' ) z++;
2394251883Speter  for(i=j=0; (c = z[i])!=0; i++, j++){
2395289166Speter    if( c=='\\' && z[i+1]!=0 ){
2396251883Speter      c = z[++i];
2397289166Speter      if( c=='a' ){
2398289166Speter        c = '\a';
2399289166Speter      }else if( c=='b' ){
2400289166Speter        c = '\b';
2401251883Speter      }else if( c=='t' ){
2402251883Speter        c = '\t';
2403289166Speter      }else if( c=='n' ){
2404289166Speter        c = '\n';
2405289166Speter      }else if( c=='v' ){
2406289166Speter        c = '\v';
2407289166Speter      }else if( c=='f' ){
2408289166Speter        c = '\f';
2409251883Speter      }else if( c=='r' ){
2410251883Speter        c = '\r';
2411289166Speter      }else if( c=='"' ){
2412289166Speter        c = '"';
2413289166Speter      }else if( c=='\'' ){
2414289166Speter        c = '\'';
2415289166Speter      }else if( c=='\\' ){
2416289166Speter        c = '\\';
2417251883Speter      }else if( c>='0' && c<='7' ){
2418251883Speter        c -= '0';
2419251883Speter        if( z[i+1]>='0' && z[i+1]<='7' ){
2420251883Speter          i++;
2421251883Speter          c = (c<<3) + z[i] - '0';
2422251883Speter          if( z[i+1]>='0' && z[i+1]<='7' ){
2423251883Speter            i++;
2424251883Speter            c = (c<<3) + z[i] - '0';
2425251883Speter          }
2426251883Speter        }
2427251883Speter      }
2428251883Speter    }
2429251883Speter    z[j] = c;
2430251883Speter  }
2431289166Speter  if( j<i ) z[j] = 0;
2432251883Speter}
2433251883Speter
2434251883Speter/*
2435289166Speter** Return the value of a hexadecimal digit.  Return -1 if the input
2436289166Speter** is not a hex digit.
2437251883Speter*/
2438289166Speterstatic int hexDigitValue(char c){
2439289166Speter  if( c>='0' && c<='9' ) return c - '0';
2440289166Speter  if( c>='a' && c<='f' ) return c - 'a' + 10;
2441289166Speter  if( c>='A' && c<='F' ) return c - 'A' + 10;
2442289166Speter  return -1;
2443251883Speter}
2444251883Speter
2445251883Speter/*
2446251883Speter** Interpret zArg as an integer value, possibly with suffixes.
2447251883Speter*/
2448251883Speterstatic sqlite3_int64 integerValue(const char *zArg){
2449251883Speter  sqlite3_int64 v = 0;
2450251883Speter  static const struct { char *zSuffix; int iMult; } aMult[] = {
2451251883Speter    { "KiB", 1024 },
2452251883Speter    { "MiB", 1024*1024 },
2453251883Speter    { "GiB", 1024*1024*1024 },
2454251883Speter    { "KB",  1000 },
2455251883Speter    { "MB",  1000000 },
2456251883Speter    { "GB",  1000000000 },
2457251883Speter    { "K",   1000 },
2458251883Speter    { "M",   1000000 },
2459251883Speter    { "G",   1000000000 },
2460251883Speter  };
2461251883Speter  int i;
2462251883Speter  int isNeg = 0;
2463251883Speter  if( zArg[0]=='-' ){
2464251883Speter    isNeg = 1;
2465251883Speter    zArg++;
2466251883Speter  }else if( zArg[0]=='+' ){
2467251883Speter    zArg++;
2468251883Speter  }
2469289166Speter  if( zArg[0]=='0' && zArg[1]=='x' ){
2470289166Speter    int x;
2471289166Speter    zArg += 2;
2472289166Speter    while( (x = hexDigitValue(zArg[0]))>=0 ){
2473289166Speter      v = (v<<4) + x;
2474289166Speter      zArg++;
2475289166Speter    }
2476289166Speter  }else{
2477289166Speter    while( IsDigit(zArg[0]) ){
2478289166Speter      v = v*10 + zArg[0] - '0';
2479289166Speter      zArg++;
2480289166Speter    }
2481251883Speter  }
2482289166Speter  for(i=0; i<ArraySize(aMult); i++){
2483251883Speter    if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
2484251883Speter      v *= aMult[i].iMult;
2485251883Speter      break;
2486251883Speter    }
2487251883Speter  }
2488251883Speter  return isNeg? -v : v;
2489251883Speter}
2490251883Speter
2491251883Speter/*
2492289166Speter** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
2493289166Speter** for TRUE and FALSE.  Return the integer value if appropriate.
2494289166Speter*/
2495289166Speterstatic int booleanValue(char *zArg){
2496289166Speter  int i;
2497289166Speter  if( zArg[0]=='0' && zArg[1]=='x' ){
2498289166Speter    for(i=2; hexDigitValue(zArg[i])>=0; i++){}
2499289166Speter  }else{
2500289166Speter    for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
2501289166Speter  }
2502289166Speter  if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
2503289166Speter  if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
2504289166Speter    return 1;
2505289166Speter  }
2506289166Speter  if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
2507289166Speter    return 0;
2508289166Speter  }
2509305003Scy  utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
2510289166Speter          zArg);
2511289166Speter  return 0;
2512289166Speter}
2513289166Speter
2514289166Speter/*
2515251883Speter** Close an output file, assuming it is not stderr or stdout
2516251883Speter*/
2517251883Speterstatic void output_file_close(FILE *f){
2518251883Speter  if( f && f!=stdout && f!=stderr ) fclose(f);
2519251883Speter}
2520251883Speter
2521251883Speter/*
2522251883Speter** Try to open an output file.   The names "stdout" and "stderr" are
2523305003Scy** recognized and do the right thing.  NULL is returned if the output
2524251883Speter** filename is "off".
2525251883Speter*/
2526251883Speterstatic FILE *output_file_open(const char *zFile){
2527251883Speter  FILE *f;
2528251883Speter  if( strcmp(zFile,"stdout")==0 ){
2529251883Speter    f = stdout;
2530251883Speter  }else if( strcmp(zFile, "stderr")==0 ){
2531251883Speter    f = stderr;
2532251883Speter  }else if( strcmp(zFile, "off")==0 ){
2533251883Speter    f = 0;
2534251883Speter  }else{
2535251883Speter    f = fopen(zFile, "wb");
2536251883Speter    if( f==0 ){
2537305003Scy      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
2538251883Speter    }
2539251883Speter  }
2540251883Speter  return f;
2541251883Speter}
2542251883Speter
2543251883Speter/*
2544251883Speter** A routine for handling output from sqlite3_trace().
2545251883Speter*/
2546305003Scystatic int sql_trace_callback(
2547305003Scy  unsigned mType,
2548305003Scy  void *pArg,
2549305003Scy  void *pP,
2550305003Scy  void *pX
2551305003Scy){
2552251883Speter  FILE *f = (FILE*)pArg;
2553305003Scy  UNUSED_PARAMETER(mType);
2554305003Scy  UNUSED_PARAMETER(pP);
2555289166Speter  if( f ){
2556305003Scy    const char *z = (const char*)pX;
2557289166Speter    int i = (int)strlen(z);
2558289166Speter    while( i>0 && z[i-1]==';' ){ i--; }
2559305003Scy    utf8_printf(f, "%.*s;\n", i, z);
2560289166Speter  }
2561305003Scy  return 0;
2562251883Speter}
2563251883Speter
2564251883Speter/*
2565251883Speter** A no-op routine that runs with the ".breakpoint" doc-command.  This is
2566251883Speter** a useful spot to set a debugger breakpoint.
2567251883Speter*/
2568251883Speterstatic void test_breakpoint(void){
2569251883Speter  static int nCall = 0;
2570251883Speter  nCall++;
2571251883Speter}
2572251883Speter
2573251883Speter/*
2574289166Speter** An object used to read a CSV and other files for import.
2575289166Speter*/
2576289166Spetertypedef struct ImportCtx ImportCtx;
2577289166Speterstruct ImportCtx {
2578289166Speter  const char *zFile;  /* Name of the input file */
2579289166Speter  FILE *in;           /* Read the CSV text from this input stream */
2580289166Speter  char *z;            /* Accumulated text for a field */
2581289166Speter  int n;              /* Number of bytes in z */
2582289166Speter  int nAlloc;         /* Space allocated for z[] */
2583289166Speter  int nLine;          /* Current line number */
2584289166Speter  int cTerm;          /* Character that terminated the most recent field */
2585289166Speter  int cColSep;        /* The column separator character.  (Usually ",") */
2586289166Speter  int cRowSep;        /* The row separator character.  (Usually "\n") */
2587289166Speter};
2588289166Speter
2589289166Speter/* Append a single byte to z[] */
2590289166Speterstatic void import_append_char(ImportCtx *p, int c){
2591289166Speter  if( p->n+1>=p->nAlloc ){
2592289166Speter    p->nAlloc += p->nAlloc + 100;
2593289166Speter    p->z = sqlite3_realloc64(p->z, p->nAlloc);
2594289166Speter    if( p->z==0 ){
2595305003Scy      raw_printf(stderr, "out of memory\n");
2596289166Speter      exit(1);
2597289166Speter    }
2598289166Speter  }
2599289166Speter  p->z[p->n++] = (char)c;
2600289166Speter}
2601289166Speter
2602289166Speter/* Read a single field of CSV text.  Compatible with rfc4180 and extended
2603289166Speter** with the option of having a separator other than ",".
2604289166Speter**
2605289166Speter**   +  Input comes from p->in.
2606289166Speter**   +  Store results in p->z of length p->n.  Space to hold p->z comes
2607289166Speter**      from sqlite3_malloc64().
2608289166Speter**   +  Use p->cSep as the column separator.  The default is ",".
2609289166Speter**   +  Use p->rSep as the row separator.  The default is "\n".
2610289166Speter**   +  Keep track of the line number in p->nLine.
2611289166Speter**   +  Store the character that terminates the field in p->cTerm.  Store
2612289166Speter**      EOF on end-of-file.
2613289166Speter**   +  Report syntax errors on stderr
2614289166Speter*/
2615289166Speterstatic char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
2616289166Speter  int c;
2617289166Speter  int cSep = p->cColSep;
2618289166Speter  int rSep = p->cRowSep;
2619289166Speter  p->n = 0;
2620289166Speter  c = fgetc(p->in);
2621289166Speter  if( c==EOF || seenInterrupt ){
2622289166Speter    p->cTerm = EOF;
2623289166Speter    return 0;
2624289166Speter  }
2625289166Speter  if( c=='"' ){
2626289166Speter    int pc, ppc;
2627289166Speter    int startLine = p->nLine;
2628289166Speter    int cQuote = c;
2629289166Speter    pc = ppc = 0;
2630289166Speter    while( 1 ){
2631289166Speter      c = fgetc(p->in);
2632289166Speter      if( c==rSep ) p->nLine++;
2633289166Speter      if( c==cQuote ){
2634289166Speter        if( pc==cQuote ){
2635289166Speter          pc = 0;
2636289166Speter          continue;
2637289166Speter        }
2638289166Speter      }
2639289166Speter      if( (c==cSep && pc==cQuote)
2640289166Speter       || (c==rSep && pc==cQuote)
2641289166Speter       || (c==rSep && pc=='\r' && ppc==cQuote)
2642289166Speter       || (c==EOF && pc==cQuote)
2643289166Speter      ){
2644289166Speter        do{ p->n--; }while( p->z[p->n]!=cQuote );
2645289166Speter        p->cTerm = c;
2646289166Speter        break;
2647289166Speter      }
2648289166Speter      if( pc==cQuote && c!='\r' ){
2649305003Scy        utf8_printf(stderr, "%s:%d: unescaped %c character\n",
2650289166Speter                p->zFile, p->nLine, cQuote);
2651289166Speter      }
2652289166Speter      if( c==EOF ){
2653305003Scy        utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n",
2654289166Speter                p->zFile, startLine, cQuote);
2655289166Speter        p->cTerm = c;
2656289166Speter        break;
2657289166Speter      }
2658289166Speter      import_append_char(p, c);
2659289166Speter      ppc = pc;
2660289166Speter      pc = c;
2661289166Speter    }
2662289166Speter  }else{
2663289166Speter    while( c!=EOF && c!=cSep && c!=rSep ){
2664289166Speter      import_append_char(p, c);
2665289166Speter      c = fgetc(p->in);
2666289166Speter    }
2667289166Speter    if( c==rSep ){
2668289166Speter      p->nLine++;
2669289166Speter      if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
2670289166Speter    }
2671289166Speter    p->cTerm = c;
2672289166Speter  }
2673289166Speter  if( p->z ) p->z[p->n] = 0;
2674289166Speter  return p->z;
2675289166Speter}
2676289166Speter
2677289166Speter/* Read a single field of ASCII delimited text.
2678289166Speter**
2679289166Speter**   +  Input comes from p->in.
2680289166Speter**   +  Store results in p->z of length p->n.  Space to hold p->z comes
2681289166Speter**      from sqlite3_malloc64().
2682289166Speter**   +  Use p->cSep as the column separator.  The default is "\x1F".
2683289166Speter**   +  Use p->rSep as the row separator.  The default is "\x1E".
2684289166Speter**   +  Keep track of the row number in p->nLine.
2685289166Speter**   +  Store the character that terminates the field in p->cTerm.  Store
2686289166Speter**      EOF on end-of-file.
2687289166Speter**   +  Report syntax errors on stderr
2688289166Speter*/
2689289166Speterstatic char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
2690289166Speter  int c;
2691289166Speter  int cSep = p->cColSep;
2692289166Speter  int rSep = p->cRowSep;
2693289166Speter  p->n = 0;
2694289166Speter  c = fgetc(p->in);
2695289166Speter  if( c==EOF || seenInterrupt ){
2696289166Speter    p->cTerm = EOF;
2697289166Speter    return 0;
2698289166Speter  }
2699289166Speter  while( c!=EOF && c!=cSep && c!=rSep ){
2700289166Speter    import_append_char(p, c);
2701289166Speter    c = fgetc(p->in);
2702289166Speter  }
2703289166Speter  if( c==rSep ){
2704289166Speter    p->nLine++;
2705289166Speter  }
2706289166Speter  p->cTerm = c;
2707289166Speter  if( p->z ) p->z[p->n] = 0;
2708289166Speter  return p->z;
2709289166Speter}
2710289166Speter
2711289166Speter/*
2712289166Speter** Try to transfer data for table zTable.  If an error is seen while
2713289166Speter** moving forward, try to go backwards.  The backwards movement won't
2714289166Speter** work for WITHOUT ROWID tables.
2715289166Speter*/
2716289166Speterstatic void tryToCloneData(
2717289166Speter  ShellState *p,
2718289166Speter  sqlite3 *newDb,
2719289166Speter  const char *zTable
2720289166Speter){
2721305003Scy  sqlite3_stmt *pQuery = 0;
2722289166Speter  sqlite3_stmt *pInsert = 0;
2723289166Speter  char *zQuery = 0;
2724289166Speter  char *zInsert = 0;
2725289166Speter  int rc;
2726289166Speter  int i, j, n;
2727289166Speter  int nTable = (int)strlen(zTable);
2728289166Speter  int k = 0;
2729289166Speter  int cnt = 0;
2730289166Speter  const int spinRate = 10000;
2731289166Speter
2732289166Speter  zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
2733289166Speter  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2734289166Speter  if( rc ){
2735305003Scy    utf8_printf(stderr, "Error %d: %s on [%s]\n",
2736289166Speter            sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
2737289166Speter            zQuery);
2738289166Speter    goto end_data_xfer;
2739289166Speter  }
2740289166Speter  n = sqlite3_column_count(pQuery);
2741289166Speter  zInsert = sqlite3_malloc64(200 + nTable + n*3);
2742289166Speter  if( zInsert==0 ){
2743305003Scy    raw_printf(stderr, "out of memory\n");
2744289166Speter    goto end_data_xfer;
2745289166Speter  }
2746289166Speter  sqlite3_snprintf(200+nTable,zInsert,
2747289166Speter                   "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
2748289166Speter  i = (int)strlen(zInsert);
2749289166Speter  for(j=1; j<n; j++){
2750289166Speter    memcpy(zInsert+i, ",?", 2);
2751289166Speter    i += 2;
2752289166Speter  }
2753289166Speter  memcpy(zInsert+i, ");", 3);
2754289166Speter  rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
2755289166Speter  if( rc ){
2756305003Scy    utf8_printf(stderr, "Error %d: %s on [%s]\n",
2757289166Speter            sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
2758289166Speter            zQuery);
2759289166Speter    goto end_data_xfer;
2760289166Speter  }
2761289166Speter  for(k=0; k<2; k++){
2762289166Speter    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
2763289166Speter      for(i=0; i<n; i++){
2764289166Speter        switch( sqlite3_column_type(pQuery, i) ){
2765289166Speter          case SQLITE_NULL: {
2766289166Speter            sqlite3_bind_null(pInsert, i+1);
2767289166Speter            break;
2768289166Speter          }
2769289166Speter          case SQLITE_INTEGER: {
2770289166Speter            sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
2771289166Speter            break;
2772289166Speter          }
2773289166Speter          case SQLITE_FLOAT: {
2774289166Speter            sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
2775289166Speter            break;
2776289166Speter          }
2777289166Speter          case SQLITE_TEXT: {
2778289166Speter            sqlite3_bind_text(pInsert, i+1,
2779289166Speter                             (const char*)sqlite3_column_text(pQuery,i),
2780289166Speter                             -1, SQLITE_STATIC);
2781289166Speter            break;
2782289166Speter          }
2783289166Speter          case SQLITE_BLOB: {
2784289166Speter            sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
2785289166Speter                                            sqlite3_column_bytes(pQuery,i),
2786289166Speter                                            SQLITE_STATIC);
2787289166Speter            break;
2788289166Speter          }
2789289166Speter        }
2790289166Speter      } /* End for */
2791289166Speter      rc = sqlite3_step(pInsert);
2792289166Speter      if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
2793305003Scy        utf8_printf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
2794289166Speter                        sqlite3_errmsg(newDb));
2795289166Speter      }
2796289166Speter      sqlite3_reset(pInsert);
2797289166Speter      cnt++;
2798289166Speter      if( (cnt%spinRate)==0 ){
2799289166Speter        printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
2800289166Speter        fflush(stdout);
2801289166Speter      }
2802289166Speter    } /* End while */
2803289166Speter    if( rc==SQLITE_DONE ) break;
2804289166Speter    sqlite3_finalize(pQuery);
2805289166Speter    sqlite3_free(zQuery);
2806289166Speter    zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
2807289166Speter                             zTable);
2808289166Speter    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2809289166Speter    if( rc ){
2810305003Scy      utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
2811289166Speter      break;
2812289166Speter    }
2813289166Speter  } /* End for(k=0...) */
2814289166Speter
2815289166Speterend_data_xfer:
2816289166Speter  sqlite3_finalize(pQuery);
2817289166Speter  sqlite3_finalize(pInsert);
2818289166Speter  sqlite3_free(zQuery);
2819289166Speter  sqlite3_free(zInsert);
2820289166Speter}
2821289166Speter
2822289166Speter
2823289166Speter/*
2824289166Speter** Try to transfer all rows of the schema that match zWhere.  For
2825289166Speter** each row, invoke xForEach() on the object defined by that row.
2826289166Speter** If an error is encountered while moving forward through the
2827289166Speter** sqlite_master table, try again moving backwards.
2828289166Speter*/
2829289166Speterstatic void tryToCloneSchema(
2830289166Speter  ShellState *p,
2831289166Speter  sqlite3 *newDb,
2832289166Speter  const char *zWhere,
2833289166Speter  void (*xForEach)(ShellState*,sqlite3*,const char*)
2834289166Speter){
2835289166Speter  sqlite3_stmt *pQuery = 0;
2836289166Speter  char *zQuery = 0;
2837289166Speter  int rc;
2838289166Speter  const unsigned char *zName;
2839289166Speter  const unsigned char *zSql;
2840289166Speter  char *zErrMsg = 0;
2841289166Speter
2842289166Speter  zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
2843289166Speter                           " WHERE %s", zWhere);
2844289166Speter  rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2845289166Speter  if( rc ){
2846305003Scy    utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
2847289166Speter                    sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
2848289166Speter                    zQuery);
2849289166Speter    goto end_schema_xfer;
2850289166Speter  }
2851289166Speter  while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
2852289166Speter    zName = sqlite3_column_text(pQuery, 0);
2853289166Speter    zSql = sqlite3_column_text(pQuery, 1);
2854289166Speter    printf("%s... ", zName); fflush(stdout);
2855289166Speter    sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
2856289166Speter    if( zErrMsg ){
2857305003Scy      utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
2858289166Speter      sqlite3_free(zErrMsg);
2859289166Speter      zErrMsg = 0;
2860289166Speter    }
2861289166Speter    if( xForEach ){
2862289166Speter      xForEach(p, newDb, (const char*)zName);
2863289166Speter    }
2864289166Speter    printf("done\n");
2865289166Speter  }
2866289166Speter  if( rc!=SQLITE_DONE ){
2867289166Speter    sqlite3_finalize(pQuery);
2868289166Speter    sqlite3_free(zQuery);
2869289166Speter    zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
2870289166Speter                             " WHERE %s ORDER BY rowid DESC", zWhere);
2871289166Speter    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2872289166Speter    if( rc ){
2873305003Scy      utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
2874289166Speter                      sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
2875289166Speter                      zQuery);
2876289166Speter      goto end_schema_xfer;
2877289166Speter    }
2878289166Speter    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
2879289166Speter      zName = sqlite3_column_text(pQuery, 0);
2880289166Speter      zSql = sqlite3_column_text(pQuery, 1);
2881289166Speter      printf("%s... ", zName); fflush(stdout);
2882289166Speter      sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
2883289166Speter      if( zErrMsg ){
2884305003Scy        utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
2885289166Speter        sqlite3_free(zErrMsg);
2886289166Speter        zErrMsg = 0;
2887289166Speter      }
2888289166Speter      if( xForEach ){
2889289166Speter        xForEach(p, newDb, (const char*)zName);
2890289166Speter      }
2891289166Speter      printf("done\n");
2892289166Speter    }
2893289166Speter  }
2894289166Speterend_schema_xfer:
2895289166Speter  sqlite3_finalize(pQuery);
2896289166Speter  sqlite3_free(zQuery);
2897289166Speter}
2898289166Speter
2899289166Speter/*
2900289166Speter** Open a new database file named "zNewDb".  Try to recover as much information
2901289166Speter** as possible out of the main database (which might be corrupt) and write it
2902289166Speter** into zNewDb.
2903289166Speter*/
2904289166Speterstatic void tryToClone(ShellState *p, const char *zNewDb){
2905289166Speter  int rc;
2906289166Speter  sqlite3 *newDb = 0;
2907289166Speter  if( access(zNewDb,0)==0 ){
2908305003Scy    utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb);
2909289166Speter    return;
2910289166Speter  }
2911289166Speter  rc = sqlite3_open(zNewDb, &newDb);
2912289166Speter  if( rc ){
2913305003Scy    utf8_printf(stderr, "Cannot create output database: %s\n",
2914289166Speter            sqlite3_errmsg(newDb));
2915289166Speter  }else{
2916289166Speter    sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
2917289166Speter    sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
2918289166Speter    tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
2919289166Speter    tryToCloneSchema(p, newDb, "type!='table'", 0);
2920289166Speter    sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
2921289166Speter    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
2922289166Speter  }
2923289166Speter  sqlite3_close(newDb);
2924289166Speter}
2925289166Speter
2926289166Speter/*
2927289166Speter** Change the output file back to stdout
2928289166Speter*/
2929289166Speterstatic void output_reset(ShellState *p){
2930289166Speter  if( p->outfile[0]=='|' ){
2931289166Speter#ifndef SQLITE_OMIT_POPEN
2932289166Speter    pclose(p->out);
2933289166Speter#endif
2934289166Speter  }else{
2935289166Speter    output_file_close(p->out);
2936289166Speter  }
2937289166Speter  p->outfile[0] = 0;
2938289166Speter  p->out = stdout;
2939289166Speter}
2940289166Speter
2941289166Speter/*
2942289166Speter** Run an SQL command and return the single integer result.
2943289166Speter*/
2944289166Speterstatic int db_int(ShellState *p, const char *zSql){
2945289166Speter  sqlite3_stmt *pStmt;
2946289166Speter  int res = 0;
2947289166Speter  sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2948289166Speter  if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
2949289166Speter    res = sqlite3_column_int(pStmt,0);
2950289166Speter  }
2951289166Speter  sqlite3_finalize(pStmt);
2952289166Speter  return res;
2953289166Speter}
2954289166Speter
2955289166Speter/*
2956289166Speter** Convert a 2-byte or 4-byte big-endian integer into a native integer
2957289166Speter*/
2958305003Scystatic unsigned int get2byteInt(unsigned char *a){
2959289166Speter  return (a[0]<<8) + a[1];
2960289166Speter}
2961305003Scystatic unsigned int get4byteInt(unsigned char *a){
2962289166Speter  return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
2963289166Speter}
2964289166Speter
2965289166Speter/*
2966289166Speter** Implementation of the ".info" command.
2967289166Speter**
2968289166Speter** Return 1 on error, 2 to exit, and 0 otherwise.
2969289166Speter*/
2970289166Speterstatic int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
2971289166Speter  static const struct { const char *zName; int ofst; } aField[] = {
2972289166Speter     { "file change counter:",  24  },
2973289166Speter     { "database page count:",  28  },
2974289166Speter     { "freelist page count:",  36  },
2975289166Speter     { "schema cookie:",        40  },
2976289166Speter     { "schema format:",        44  },
2977289166Speter     { "default cache size:",   48  },
2978289166Speter     { "autovacuum top root:",  52  },
2979289166Speter     { "incremental vacuum:",   64  },
2980289166Speter     { "text encoding:",        56  },
2981289166Speter     { "user version:",         60  },
2982289166Speter     { "application id:",       68  },
2983289166Speter     { "software version:",     96  },
2984289166Speter  };
2985289166Speter  static const struct { const char *zName; const char *zSql; } aQuery[] = {
2986289166Speter     { "number of tables:",
2987289166Speter       "SELECT count(*) FROM %s WHERE type='table'" },
2988289166Speter     { "number of indexes:",
2989289166Speter       "SELECT count(*) FROM %s WHERE type='index'" },
2990289166Speter     { "number of triggers:",
2991289166Speter       "SELECT count(*) FROM %s WHERE type='trigger'" },
2992289166Speter     { "number of views:",
2993289166Speter       "SELECT count(*) FROM %s WHERE type='view'" },
2994289166Speter     { "schema size:",
2995289166Speter       "SELECT total(length(sql)) FROM %s" },
2996289166Speter  };
2997305003Scy  sqlite3_file *pFile = 0;
2998289166Speter  int i;
2999289166Speter  char *zSchemaTab;
3000289166Speter  char *zDb = nArg>=2 ? azArg[1] : "main";
3001289166Speter  unsigned char aHdr[100];
3002289166Speter  open_db(p, 0);
3003289166Speter  if( p->db==0 ) return 1;
3004289166Speter  sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
3005289166Speter  if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
3006289166Speter    return 1;
3007289166Speter  }
3008289166Speter  i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
3009289166Speter  if( i!=SQLITE_OK ){
3010305003Scy    raw_printf(stderr, "unable to read database header\n");
3011289166Speter    return 1;
3012289166Speter  }
3013289166Speter  i = get2byteInt(aHdr+16);
3014289166Speter  if( i==1 ) i = 65536;
3015305003Scy  utf8_printf(p->out, "%-20s %d\n", "database page size:", i);
3016305003Scy  utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
3017305003Scy  utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
3018305003Scy  utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
3019289166Speter  for(i=0; i<ArraySize(aField); i++){
3020289166Speter    int ofst = aField[i].ofst;
3021289166Speter    unsigned int val = get4byteInt(aHdr + ofst);
3022305003Scy    utf8_printf(p->out, "%-20s %u", aField[i].zName, val);
3023289166Speter    switch( ofst ){
3024289166Speter      case 56: {
3025305003Scy        if( val==1 ) raw_printf(p->out, " (utf8)");
3026305003Scy        if( val==2 ) raw_printf(p->out, " (utf16le)");
3027305003Scy        if( val==3 ) raw_printf(p->out, " (utf16be)");
3028289166Speter      }
3029289166Speter    }
3030305003Scy    raw_printf(p->out, "\n");
3031289166Speter  }
3032289166Speter  if( zDb==0 ){
3033289166Speter    zSchemaTab = sqlite3_mprintf("main.sqlite_master");
3034289166Speter  }else if( strcmp(zDb,"temp")==0 ){
3035289166Speter    zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
3036289166Speter  }else{
3037289166Speter    zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
3038289166Speter  }
3039289166Speter  for(i=0; i<ArraySize(aQuery); i++){
3040289166Speter    char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
3041289166Speter    int val = db_int(p, zSql);
3042289166Speter    sqlite3_free(zSql);
3043305003Scy    utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
3044289166Speter  }
3045289166Speter  sqlite3_free(zSchemaTab);
3046289166Speter  return 0;
3047289166Speter}
3048289166Speter
3049305003Scy/*
3050305003Scy** Print the current sqlite3_errmsg() value to stderr and return 1.
3051305003Scy*/
3052305003Scystatic int shellDatabaseError(sqlite3 *db){
3053305003Scy  const char *zErr = sqlite3_errmsg(db);
3054305003Scy  utf8_printf(stderr, "Error: %s\n", zErr);
3055305003Scy  return 1;
3056305003Scy}
3057289166Speter
3058289166Speter/*
3059305003Scy** Print an out-of-memory message to stderr and return 1.
3060305003Scy*/
3061305003Scystatic int shellNomemError(void){
3062305003Scy  raw_printf(stderr, "Error: out of memory\n");
3063305003Scy  return 1;
3064305003Scy}
3065305003Scy
3066305003Scy/*
3067305003Scy** Compare the string as a command-line option with either one or two
3068305003Scy** initial "-" characters.
3069305003Scy*/
3070305003Scystatic int optionMatch(const char *zStr, const char *zOpt){
3071305003Scy  if( zStr[0]!='-' ) return 0;
3072305003Scy  zStr++;
3073305003Scy  if( zStr[0]=='-' ) zStr++;
3074305003Scy  return strcmp(zStr, zOpt)==0;
3075305003Scy}
3076305003Scy
3077305003Scy/*
3078251883Speter** If an input line begins with "." then invoke this routine to
3079251883Speter** process that line.
3080251883Speter**
3081251883Speter** Return 1 on error, 2 to exit, and 0 otherwise.
3082251883Speter*/
3083289166Speterstatic int do_meta_command(char *zLine, ShellState *p){
3084289166Speter  int h = 1;
3085251883Speter  int nArg = 0;
3086251883Speter  int n, c;
3087251883Speter  int rc = 0;
3088251883Speter  char *azArg[50];
3089251883Speter
3090251883Speter  /* Parse the input line into tokens.
3091251883Speter  */
3092289166Speter  while( zLine[h] && nArg<ArraySize(azArg) ){
3093289166Speter    while( IsSpace(zLine[h]) ){ h++; }
3094289166Speter    if( zLine[h]==0 ) break;
3095289166Speter    if( zLine[h]=='\'' || zLine[h]=='"' ){
3096289166Speter      int delim = zLine[h++];
3097289166Speter      azArg[nArg++] = &zLine[h];
3098305003Scy      while( zLine[h] && zLine[h]!=delim ){
3099289166Speter        if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
3100305003Scy        h++;
3101251883Speter      }
3102289166Speter      if( zLine[h]==delim ){
3103289166Speter        zLine[h++] = 0;
3104289166Speter      }
3105251883Speter      if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
3106251883Speter    }else{
3107289166Speter      azArg[nArg++] = &zLine[h];
3108289166Speter      while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
3109289166Speter      if( zLine[h] ) zLine[h++] = 0;
3110251883Speter      resolve_backslashes(azArg[nArg-1]);
3111251883Speter    }
3112251883Speter  }
3113251883Speter
3114251883Speter  /* Process the input line.
3115251883Speter  */
3116251883Speter  if( nArg==0 ) return 0; /* no tokens, no error */
3117251883Speter  n = strlen30(azArg[0]);
3118251883Speter  c = azArg[0][0];
3119305003Scy
3120305003Scy  if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){
3121305003Scy    if( nArg!=2 ){
3122305003Scy      raw_printf(stderr, "Usage: .auth ON|OFF\n");
3123305003Scy      rc = 1;
3124305003Scy      goto meta_command_exit;
3125305003Scy    }
3126305003Scy    open_db(p, 0);
3127305003Scy    if( booleanValue(azArg[1]) ){
3128305003Scy      sqlite3_set_authorizer(p->db, shellAuth, p);
3129305003Scy    }else{
3130305003Scy      sqlite3_set_authorizer(p->db, 0, 0);
3131305003Scy    }
3132305003Scy  }else
3133305003Scy
3134289166Speter  if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
3135289166Speter   || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
3136289166Speter  ){
3137251883Speter    const char *zDestFile = 0;
3138251883Speter    const char *zDb = 0;
3139251883Speter    sqlite3 *pDest;
3140251883Speter    sqlite3_backup *pBackup;
3141251883Speter    int j;
3142251883Speter    for(j=1; j<nArg; j++){
3143251883Speter      const char *z = azArg[j];
3144251883Speter      if( z[0]=='-' ){
3145251883Speter        while( z[0]=='-' ) z++;
3146289166Speter        /* No options to process at this time */
3147251883Speter        {
3148305003Scy          utf8_printf(stderr, "unknown option: %s\n", azArg[j]);
3149251883Speter          return 1;
3150251883Speter        }
3151251883Speter      }else if( zDestFile==0 ){
3152251883Speter        zDestFile = azArg[j];
3153251883Speter      }else if( zDb==0 ){
3154251883Speter        zDb = zDestFile;
3155251883Speter        zDestFile = azArg[j];
3156251883Speter      }else{
3157305003Scy        raw_printf(stderr, "too many arguments to .backup\n");
3158251883Speter        return 1;
3159251883Speter      }
3160251883Speter    }
3161251883Speter    if( zDestFile==0 ){
3162305003Scy      raw_printf(stderr, "missing FILENAME argument on .backup\n");
3163251883Speter      return 1;
3164251883Speter    }
3165251883Speter    if( zDb==0 ) zDb = "main";
3166251883Speter    rc = sqlite3_open(zDestFile, &pDest);
3167251883Speter    if( rc!=SQLITE_OK ){
3168305003Scy      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
3169251883Speter      sqlite3_close(pDest);
3170251883Speter      return 1;
3171251883Speter    }
3172289166Speter    open_db(p, 0);
3173251883Speter    pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
3174251883Speter    if( pBackup==0 ){
3175305003Scy      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
3176251883Speter      sqlite3_close(pDest);
3177251883Speter      return 1;
3178251883Speter    }
3179251883Speter    while(  (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
3180251883Speter    sqlite3_backup_finish(pBackup);
3181251883Speter    if( rc==SQLITE_DONE ){
3182251883Speter      rc = 0;
3183251883Speter    }else{
3184305003Scy      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
3185251883Speter      rc = 1;
3186251883Speter    }
3187251883Speter    sqlite3_close(pDest);
3188251883Speter  }else
3189251883Speter
3190289166Speter  if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
3191289166Speter    if( nArg==2 ){
3192289166Speter      bail_on_error = booleanValue(azArg[1]);
3193289166Speter    }else{
3194305003Scy      raw_printf(stderr, "Usage: .bail on|off\n");
3195289166Speter      rc = 1;
3196289166Speter    }
3197251883Speter  }else
3198251883Speter
3199289166Speter  if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){
3200289166Speter    if( nArg==2 ){
3201289166Speter      if( booleanValue(azArg[1]) ){
3202305003Scy        setBinaryMode(p->out, 1);
3203289166Speter      }else{
3204305003Scy        setTextMode(p->out, 1);
3205289166Speter      }
3206289166Speter    }else{
3207305003Scy      raw_printf(stderr, "Usage: .binary on|off\n");
3208289166Speter      rc = 1;
3209289166Speter    }
3210289166Speter  }else
3211289166Speter
3212251883Speter  /* The undocumented ".breakpoint" command causes a call to the no-op
3213251883Speter  ** routine named test_breakpoint().
3214251883Speter  */
3215251883Speter  if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
3216251883Speter    test_breakpoint();
3217251883Speter  }else
3218251883Speter
3219305003Scy  if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){
3220305003Scy    if( nArg==2 ){
3221305003Scy      p->countChanges = booleanValue(azArg[1]);
3222305003Scy    }else{
3223305003Scy      raw_printf(stderr, "Usage: .changes on|off\n");
3224305003Scy      rc = 1;
3225305003Scy    }
3226305003Scy  }else
3227305003Scy
3228289166Speter  if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
3229289166Speter    if( nArg==2 ){
3230289166Speter      tryToClone(p, azArg[1]);
3231289166Speter    }else{
3232305003Scy      raw_printf(stderr, "Usage: .clone FILENAME\n");
3233289166Speter      rc = 1;
3234289166Speter    }
3235289166Speter  }else
3236289166Speter
3237289166Speter  if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
3238289166Speter    ShellState data;
3239251883Speter    char *zErrMsg = 0;
3240289166Speter    open_db(p, 0);
3241251883Speter    memcpy(&data, p, sizeof(data));
3242251883Speter    data.showHeader = 1;
3243305003Scy    data.cMode = data.mode = MODE_Column;
3244251883Speter    data.colWidth[0] = 3;
3245251883Speter    data.colWidth[1] = 15;
3246251883Speter    data.colWidth[2] = 58;
3247251883Speter    data.cnt = 0;
3248251883Speter    sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
3249251883Speter    if( zErrMsg ){
3250305003Scy      utf8_printf(stderr,"Error: %s\n", zErrMsg);
3251251883Speter      sqlite3_free(zErrMsg);
3252251883Speter      rc = 1;
3253251883Speter    }
3254251883Speter  }else
3255251883Speter
3256289166Speter  if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
3257289166Speter    rc = shell_dbinfo_command(p, nArg, azArg);
3258289166Speter  }else
3259289166Speter
3260289166Speter  if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
3261289166Speter    open_db(p, 0);
3262251883Speter    /* When playing back a "dump", the content might appear in an order
3263251883Speter    ** which causes immediate foreign key constraints to be violated.
3264251883Speter    ** So disable foreign-key constraint enforcement to prevent problems. */
3265289166Speter    if( nArg!=1 && nArg!=2 ){
3266305003Scy      raw_printf(stderr, "Usage: .dump ?LIKE-PATTERN?\n");
3267289166Speter      rc = 1;
3268289166Speter      goto meta_command_exit;
3269289166Speter    }
3270305003Scy    raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
3271305003Scy    raw_printf(p->out, "BEGIN TRANSACTION;\n");
3272251883Speter    p->writableSchema = 0;
3273251883Speter    sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
3274251883Speter    p->nErr = 0;
3275251883Speter    if( nArg==1 ){
3276305003Scy      run_schema_dump_query(p,
3277251883Speter        "SELECT name, type, sql FROM sqlite_master "
3278251883Speter        "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
3279251883Speter      );
3280305003Scy      run_schema_dump_query(p,
3281251883Speter        "SELECT name, type, sql FROM sqlite_master "
3282251883Speter        "WHERE name=='sqlite_sequence'"
3283251883Speter      );
3284251883Speter      run_table_dump_query(p,
3285251883Speter        "SELECT sql FROM sqlite_master "
3286251883Speter        "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
3287251883Speter      );
3288251883Speter    }else{
3289251883Speter      int i;
3290251883Speter      for(i=1; i<nArg; i++){
3291251883Speter        zShellStatic = azArg[i];
3292251883Speter        run_schema_dump_query(p,
3293251883Speter          "SELECT name, type, sql FROM sqlite_master "
3294251883Speter          "WHERE tbl_name LIKE shellstatic() AND type=='table'"
3295251883Speter          "  AND sql NOT NULL");
3296251883Speter        run_table_dump_query(p,
3297251883Speter          "SELECT sql FROM sqlite_master "
3298251883Speter          "WHERE sql NOT NULL"
3299251883Speter          "  AND type IN ('index','trigger','view')"
3300251883Speter          "  AND tbl_name LIKE shellstatic()", 0
3301251883Speter        );
3302251883Speter        zShellStatic = 0;
3303251883Speter      }
3304251883Speter    }
3305251883Speter    if( p->writableSchema ){
3306305003Scy      raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
3307251883Speter      p->writableSchema = 0;
3308251883Speter    }
3309251883Speter    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
3310251883Speter    sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
3311305003Scy    raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
3312251883Speter  }else
3313251883Speter
3314289166Speter  if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
3315289166Speter    if( nArg==2 ){
3316289166Speter      p->echoOn = booleanValue(azArg[1]);
3317289166Speter    }else{
3318305003Scy      raw_printf(stderr, "Usage: .echo on|off\n");
3319289166Speter      rc = 1;
3320289166Speter    }
3321251883Speter  }else
3322251883Speter
3323289166Speter  if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
3324289166Speter    if( nArg==2 ){
3325305003Scy      if( strcmp(azArg[1],"full")==0 ){
3326305003Scy        p->autoEQP = 2;
3327305003Scy      }else{
3328305003Scy        p->autoEQP = booleanValue(azArg[1]);
3329305003Scy      }
3330289166Speter    }else{
3331305003Scy      raw_printf(stderr, "Usage: .eqp on|off|full\n");
3332289166Speter      rc = 1;
3333305003Scy    }
3334289166Speter  }else
3335289166Speter
3336251883Speter  if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
3337289166Speter    if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
3338251883Speter    rc = 2;
3339251883Speter  }else
3340251883Speter
3341289166Speter  if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
3342305003Scy    int val = 1;
3343305003Scy    if( nArg>=2 ){
3344305003Scy      if( strcmp(azArg[1],"auto")==0 ){
3345305003Scy        val = 99;
3346305003Scy      }else{
3347305003Scy        val =  booleanValue(azArg[1]);
3348251883Speter      }
3349305003Scy    }
3350305003Scy    if( val==1 && p->mode!=MODE_Explain ){
3351305003Scy      p->normalMode = p->mode;
3352251883Speter      p->mode = MODE_Explain;
3353305003Scy      p->autoExplain = 0;
3354305003Scy    }else if( val==0 ){
3355305003Scy      if( p->mode==MODE_Explain ) p->mode = p->normalMode;
3356305003Scy      p->autoExplain = 0;
3357305003Scy    }else if( val==99 ){
3358305003Scy      if( p->mode==MODE_Explain ) p->mode = p->normalMode;
3359305003Scy      p->autoExplain = 1;
3360251883Speter    }
3361251883Speter  }else
3362251883Speter
3363289166Speter  if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){
3364289166Speter    ShellState data;
3365289166Speter    char *zErrMsg = 0;
3366289166Speter    int doStats = 0;
3367305003Scy    memcpy(&data, p, sizeof(data));
3368305003Scy    data.showHeader = 0;
3369305003Scy    data.cMode = data.mode = MODE_Semi;
3370305003Scy    if( nArg==2 && optionMatch(azArg[1], "indent") ){
3371305003Scy      data.cMode = data.mode = MODE_Pretty;
3372305003Scy      nArg = 1;
3373305003Scy    }
3374289166Speter    if( nArg!=1 ){
3375305003Scy      raw_printf(stderr, "Usage: .fullschema ?--indent?\n");
3376289166Speter      rc = 1;
3377289166Speter      goto meta_command_exit;
3378289166Speter    }
3379289166Speter    open_db(p, 0);
3380289166Speter    rc = sqlite3_exec(p->db,
3381289166Speter       "SELECT sql FROM"
3382289166Speter       "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
3383289166Speter       "     FROM sqlite_master UNION ALL"
3384289166Speter       "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
3385289166Speter       "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
3386289166Speter       "ORDER BY rowid",
3387289166Speter       callback, &data, &zErrMsg
3388289166Speter    );
3389289166Speter    if( rc==SQLITE_OK ){
3390289166Speter      sqlite3_stmt *pStmt;
3391289166Speter      rc = sqlite3_prepare_v2(p->db,
3392289166Speter               "SELECT rowid FROM sqlite_master"
3393289166Speter               " WHERE name GLOB 'sqlite_stat[134]'",
3394289166Speter               -1, &pStmt, 0);
3395289166Speter      doStats = sqlite3_step(pStmt)==SQLITE_ROW;
3396289166Speter      sqlite3_finalize(pStmt);
3397289166Speter    }
3398289166Speter    if( doStats==0 ){
3399305003Scy      raw_printf(p->out, "/* No STAT tables available */\n");
3400289166Speter    }else{
3401305003Scy      raw_printf(p->out, "ANALYZE sqlite_master;\n");
3402289166Speter      sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'",
3403289166Speter                   callback, &data, &zErrMsg);
3404305003Scy      data.cMode = data.mode = MODE_Insert;
3405289166Speter      data.zDestTable = "sqlite_stat1";
3406289166Speter      shell_exec(p->db, "SELECT * FROM sqlite_stat1",
3407289166Speter                 shell_callback, &data,&zErrMsg);
3408289166Speter      data.zDestTable = "sqlite_stat3";
3409289166Speter      shell_exec(p->db, "SELECT * FROM sqlite_stat3",
3410289166Speter                 shell_callback, &data,&zErrMsg);
3411289166Speter      data.zDestTable = "sqlite_stat4";
3412289166Speter      shell_exec(p->db, "SELECT * FROM sqlite_stat4",
3413289166Speter                 shell_callback, &data, &zErrMsg);
3414305003Scy      raw_printf(p->out, "ANALYZE sqlite_master;\n");
3415289166Speter    }
3416251883Speter  }else
3417251883Speter
3418289166Speter  if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){
3419289166Speter    if( nArg==2 ){
3420289166Speter      p->showHeader = booleanValue(azArg[1]);
3421289166Speter    }else{
3422305003Scy      raw_printf(stderr, "Usage: .headers on|off\n");
3423289166Speter      rc = 1;
3424251883Speter    }
3425251883Speter  }else
3426251883Speter
3427289166Speter  if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
3428305003Scy    utf8_printf(p->out, "%s", zHelp);
3429289166Speter  }else
3430289166Speter
3431289166Speter  if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
3432289166Speter    char *zTable;               /* Insert data into this table */
3433289166Speter    char *zFile;                /* Name of file to extra content from */
3434251883Speter    sqlite3_stmt *pStmt = NULL; /* A statement */
3435251883Speter    int nCol;                   /* Number of columns in the table */
3436251883Speter    int nByte;                  /* Number of bytes in an SQL string */
3437251883Speter    int i, j;                   /* Loop counters */
3438289166Speter    int needCommit;             /* True to COMMIT or ROLLBACK at end */
3439289166Speter    int nSep;                   /* Number of bytes in p->colSeparator[] */
3440251883Speter    char *zSql;                 /* An SQL statement */
3441289166Speter    ImportCtx sCtx;             /* Reader context */
3442289166Speter    char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
3443289166Speter    int (SQLITE_CDECL *xCloser)(FILE*);      /* Func to close file */
3444251883Speter
3445289166Speter    if( nArg!=3 ){
3446305003Scy      raw_printf(stderr, "Usage: .import FILE TABLE\n");
3447289166Speter      goto meta_command_exit;
3448289166Speter    }
3449289166Speter    zFile = azArg[1];
3450289166Speter    zTable = azArg[2];
3451289166Speter    seenInterrupt = 0;
3452289166Speter    memset(&sCtx, 0, sizeof(sCtx));
3453289166Speter    open_db(p, 0);
3454289166Speter    nSep = strlen30(p->colSeparator);
3455251883Speter    if( nSep==0 ){
3456305003Scy      raw_printf(stderr,
3457305003Scy                 "Error: non-null column separator required for import\n");
3458251883Speter      return 1;
3459251883Speter    }
3460289166Speter    if( nSep>1 ){
3461305003Scy      raw_printf(stderr, "Error: multi-character column separators not allowed"
3462289166Speter                      " for import\n");
3463289166Speter      return 1;
3464289166Speter    }
3465289166Speter    nSep = strlen30(p->rowSeparator);
3466289166Speter    if( nSep==0 ){
3467305003Scy      raw_printf(stderr, "Error: non-null row separator required for import\n");
3468289166Speter      return 1;
3469289166Speter    }
3470289166Speter    if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
3471289166Speter      /* When importing CSV (only), if the row separator is set to the
3472289166Speter      ** default output row separator, change it to the default input
3473289166Speter      ** row separator.  This avoids having to maintain different input
3474289166Speter      ** and output row separators. */
3475289166Speter      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
3476289166Speter      nSep = strlen30(p->rowSeparator);
3477289166Speter    }
3478289166Speter    if( nSep>1 ){
3479305003Scy      raw_printf(stderr, "Error: multi-character row separators not allowed"
3480289166Speter                      " for import\n");
3481289166Speter      return 1;
3482289166Speter    }
3483289166Speter    sCtx.zFile = zFile;
3484289166Speter    sCtx.nLine = 1;
3485289166Speter    if( sCtx.zFile[0]=='|' ){
3486289166Speter#ifdef SQLITE_OMIT_POPEN
3487305003Scy      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
3488289166Speter      return 1;
3489289166Speter#else
3490289166Speter      sCtx.in = popen(sCtx.zFile+1, "r");
3491289166Speter      sCtx.zFile = "<pipe>";
3492289166Speter      xCloser = pclose;
3493289166Speter#endif
3494289166Speter    }else{
3495289166Speter      sCtx.in = fopen(sCtx.zFile, "rb");
3496289166Speter      xCloser = fclose;
3497289166Speter    }
3498289166Speter    if( p->mode==MODE_Ascii ){
3499289166Speter      xRead = ascii_read_one_field;
3500289166Speter    }else{
3501289166Speter      xRead = csv_read_one_field;
3502289166Speter    }
3503289166Speter    if( sCtx.in==0 ){
3504305003Scy      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
3505289166Speter      return 1;
3506289166Speter    }
3507289166Speter    sCtx.cColSep = p->colSeparator[0];
3508289166Speter    sCtx.cRowSep = p->rowSeparator[0];
3509251883Speter    zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
3510251883Speter    if( zSql==0 ){
3511305003Scy      raw_printf(stderr, "Error: out of memory\n");
3512289166Speter      xCloser(sCtx.in);
3513251883Speter      return 1;
3514251883Speter    }
3515251883Speter    nByte = strlen30(zSql);
3516289166Speter    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
3517289166Speter    import_append_char(&sCtx, 0);    /* To ensure sCtx.z is allocated */
3518289166Speter    if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
3519289166Speter      char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
3520289166Speter      char cSep = '(';
3521289166Speter      while( xRead(&sCtx) ){
3522305003Scy        zCreate = sqlite3_mprintf("%z%c\n  \"%w\" TEXT", zCreate, cSep, sCtx.z);
3523289166Speter        cSep = ',';
3524289166Speter        if( sCtx.cTerm!=sCtx.cColSep ) break;
3525289166Speter      }
3526289166Speter      if( cSep=='(' ){
3527289166Speter        sqlite3_free(zCreate);
3528289166Speter        sqlite3_free(sCtx.z);
3529289166Speter        xCloser(sCtx.in);
3530305003Scy        utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
3531289166Speter        return 1;
3532289166Speter      }
3533289166Speter      zCreate = sqlite3_mprintf("%z\n)", zCreate);
3534289166Speter      rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
3535289166Speter      sqlite3_free(zCreate);
3536289166Speter      if( rc ){
3537305003Scy        utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
3538289166Speter                sqlite3_errmsg(p->db));
3539289166Speter        sqlite3_free(sCtx.z);
3540289166Speter        xCloser(sCtx.in);
3541289166Speter        return 1;
3542289166Speter      }
3543289166Speter      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
3544289166Speter    }
3545251883Speter    sqlite3_free(zSql);
3546251883Speter    if( rc ){
3547251883Speter      if (pStmt) sqlite3_finalize(pStmt);
3548305003Scy      utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
3549289166Speter      xCloser(sCtx.in);
3550251883Speter      return 1;
3551251883Speter    }
3552251883Speter    nCol = sqlite3_column_count(pStmt);
3553251883Speter    sqlite3_finalize(pStmt);
3554251883Speter    pStmt = 0;
3555251883Speter    if( nCol==0 ) return 0; /* no columns, no error */
3556289166Speter    zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
3557251883Speter    if( zSql==0 ){
3558305003Scy      raw_printf(stderr, "Error: out of memory\n");
3559289166Speter      xCloser(sCtx.in);
3560251883Speter      return 1;
3561251883Speter    }
3562289166Speter    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
3563251883Speter    j = strlen30(zSql);
3564251883Speter    for(i=1; i<nCol; i++){
3565251883Speter      zSql[j++] = ',';
3566251883Speter      zSql[j++] = '?';
3567251883Speter    }
3568251883Speter    zSql[j++] = ')';
3569251883Speter    zSql[j] = 0;
3570289166Speter    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
3571289166Speter    sqlite3_free(zSql);
3572251883Speter    if( rc ){
3573305003Scy      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
3574251883Speter      if (pStmt) sqlite3_finalize(pStmt);
3575289166Speter      xCloser(sCtx.in);
3576251883Speter      return 1;
3577251883Speter    }
3578289166Speter    needCommit = sqlite3_get_autocommit(p->db);
3579289166Speter    if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
3580289166Speter    do{
3581289166Speter      int startLine = sCtx.nLine;
3582289166Speter      for(i=0; i<nCol; i++){
3583289166Speter        char *z = xRead(&sCtx);
3584289166Speter        /*
3585289166Speter        ** Did we reach end-of-file before finding any columns?
3586289166Speter        ** If so, stop instead of NULL filling the remaining columns.
3587289166Speter        */
3588289166Speter        if( z==0 && i==0 ) break;
3589289166Speter        /*
3590289166Speter        ** Did we reach end-of-file OR end-of-line before finding any
3591289166Speter        ** columns in ASCII mode?  If so, stop instead of NULL filling
3592289166Speter        ** the remaining columns.
3593289166Speter        */
3594289166Speter        if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
3595289166Speter        sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
3596289166Speter        if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
3597305003Scy          utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
3598289166Speter                          "filling the rest with NULL\n",
3599289166Speter                          sCtx.zFile, startLine, nCol, i+1);
3600289166Speter          i += 2;
3601289166Speter          while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
3602251883Speter        }
3603251883Speter      }
3604289166Speter      if( sCtx.cTerm==sCtx.cColSep ){
3605289166Speter        do{
3606289166Speter          xRead(&sCtx);
3607289166Speter          i++;
3608289166Speter        }while( sCtx.cTerm==sCtx.cColSep );
3609305003Scy        utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
3610289166Speter                        "extras ignored\n",
3611289166Speter                        sCtx.zFile, startLine, nCol, i);
3612289166Speter      }
3613289166Speter      if( i>=nCol ){
3614289166Speter        sqlite3_step(pStmt);
3615289166Speter        rc = sqlite3_reset(pStmt);
3616289166Speter        if( rc!=SQLITE_OK ){
3617305003Scy          utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
3618305003Scy                      startLine, sqlite3_errmsg(p->db));
3619251883Speter        }
3620251883Speter      }
3621289166Speter    }while( sCtx.cTerm!=EOF );
3622289166Speter
3623289166Speter    xCloser(sCtx.in);
3624289166Speter    sqlite3_free(sCtx.z);
3625251883Speter    sqlite3_finalize(pStmt);
3626289166Speter    if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
3627251883Speter  }else
3628251883Speter
3629289166Speter  if( c=='i' && (strncmp(azArg[0], "indices", n)==0
3630289166Speter                 || strncmp(azArg[0], "indexes", n)==0) ){
3631289166Speter    ShellState data;
3632251883Speter    char *zErrMsg = 0;
3633289166Speter    open_db(p, 0);
3634251883Speter    memcpy(&data, p, sizeof(data));
3635251883Speter    data.showHeader = 0;
3636305003Scy    data.cMode = data.mode = MODE_List;
3637251883Speter    if( nArg==1 ){
3638251883Speter      rc = sqlite3_exec(p->db,
3639251883Speter        "SELECT name FROM sqlite_master "
3640251883Speter        "WHERE type='index' AND name NOT LIKE 'sqlite_%' "
3641251883Speter        "UNION ALL "
3642251883Speter        "SELECT name FROM sqlite_temp_master "
3643251883Speter        "WHERE type='index' "
3644251883Speter        "ORDER BY 1",
3645251883Speter        callback, &data, &zErrMsg
3646251883Speter      );
3647289166Speter    }else if( nArg==2 ){
3648251883Speter      zShellStatic = azArg[1];
3649251883Speter      rc = sqlite3_exec(p->db,
3650251883Speter        "SELECT name FROM sqlite_master "
3651251883Speter        "WHERE type='index' AND tbl_name LIKE shellstatic() "
3652251883Speter        "UNION ALL "
3653251883Speter        "SELECT name FROM sqlite_temp_master "
3654251883Speter        "WHERE type='index' AND tbl_name LIKE shellstatic() "
3655251883Speter        "ORDER BY 1",
3656251883Speter        callback, &data, &zErrMsg
3657251883Speter      );
3658251883Speter      zShellStatic = 0;
3659289166Speter    }else{
3660305003Scy      raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
3661289166Speter      rc = 1;
3662289166Speter      goto meta_command_exit;
3663251883Speter    }
3664251883Speter    if( zErrMsg ){
3665305003Scy      utf8_printf(stderr,"Error: %s\n", zErrMsg);
3666251883Speter      sqlite3_free(zErrMsg);
3667251883Speter      rc = 1;
3668251883Speter    }else if( rc != SQLITE_OK ){
3669305003Scy      raw_printf(stderr,
3670305003Scy                 "Error: querying sqlite_master and sqlite_temp_master\n");
3671251883Speter      rc = 1;
3672251883Speter    }
3673251883Speter  }else
3674251883Speter
3675251883Speter#ifdef SQLITE_ENABLE_IOTRACE
3676251883Speter  if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
3677289166Speter    SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
3678251883Speter    if( iotrace && iotrace!=stdout ) fclose(iotrace);
3679251883Speter    iotrace = 0;
3680251883Speter    if( nArg<2 ){
3681251883Speter      sqlite3IoTrace = 0;
3682251883Speter    }else if( strcmp(azArg[1], "-")==0 ){
3683251883Speter      sqlite3IoTrace = iotracePrintf;
3684251883Speter      iotrace = stdout;
3685251883Speter    }else{
3686251883Speter      iotrace = fopen(azArg[1], "w");
3687251883Speter      if( iotrace==0 ){
3688305003Scy        utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
3689251883Speter        sqlite3IoTrace = 0;
3690251883Speter        rc = 1;
3691251883Speter      }else{
3692251883Speter        sqlite3IoTrace = iotracePrintf;
3693251883Speter      }
3694251883Speter    }
3695251883Speter  }else
3696251883Speter#endif
3697289166Speter  if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){
3698289166Speter    static const struct {
3699289166Speter       const char *zLimitName;   /* Name of a limit */
3700289166Speter       int limitCode;            /* Integer code for that limit */
3701289166Speter    } aLimit[] = {
3702289166Speter      { "length",                SQLITE_LIMIT_LENGTH                    },
3703289166Speter      { "sql_length",            SQLITE_LIMIT_SQL_LENGTH                },
3704289166Speter      { "column",                SQLITE_LIMIT_COLUMN                    },
3705289166Speter      { "expr_depth",            SQLITE_LIMIT_EXPR_DEPTH                },
3706289166Speter      { "compound_select",       SQLITE_LIMIT_COMPOUND_SELECT           },
3707289166Speter      { "vdbe_op",               SQLITE_LIMIT_VDBE_OP                   },
3708289166Speter      { "function_arg",          SQLITE_LIMIT_FUNCTION_ARG              },
3709289166Speter      { "attached",              SQLITE_LIMIT_ATTACHED                  },
3710289166Speter      { "like_pattern_length",   SQLITE_LIMIT_LIKE_PATTERN_LENGTH       },
3711289166Speter      { "variable_number",       SQLITE_LIMIT_VARIABLE_NUMBER           },
3712289166Speter      { "trigger_depth",         SQLITE_LIMIT_TRIGGER_DEPTH             },
3713289166Speter      { "worker_threads",        SQLITE_LIMIT_WORKER_THREADS            },
3714289166Speter    };
3715289166Speter    int i, n2;
3716289166Speter    open_db(p, 0);
3717289166Speter    if( nArg==1 ){
3718289166Speter      for(i=0; i<ArraySize(aLimit); i++){
3719305003Scy        printf("%20s %d\n", aLimit[i].zLimitName,
3720289166Speter               sqlite3_limit(p->db, aLimit[i].limitCode, -1));
3721289166Speter      }
3722289166Speter    }else if( nArg>3 ){
3723305003Scy      raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
3724289166Speter      rc = 1;
3725289166Speter      goto meta_command_exit;
3726289166Speter    }else{
3727289166Speter      int iLimit = -1;
3728289166Speter      n2 = strlen30(azArg[1]);
3729289166Speter      for(i=0; i<ArraySize(aLimit); i++){
3730289166Speter        if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
3731289166Speter          if( iLimit<0 ){
3732289166Speter            iLimit = i;
3733289166Speter          }else{
3734305003Scy            utf8_printf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
3735289166Speter            rc = 1;
3736289166Speter            goto meta_command_exit;
3737289166Speter          }
3738289166Speter        }
3739289166Speter      }
3740289166Speter      if( iLimit<0 ){
3741305003Scy        utf8_printf(stderr, "unknown limit: \"%s\"\n"
3742289166Speter                        "enter \".limits\" with no arguments for a list.\n",
3743289166Speter                         azArg[1]);
3744289166Speter        rc = 1;
3745289166Speter        goto meta_command_exit;
3746289166Speter      }
3747289166Speter      if( nArg==3 ){
3748289166Speter        sqlite3_limit(p->db, aLimit[iLimit].limitCode,
3749289166Speter                      (int)integerValue(azArg[2]));
3750289166Speter      }
3751289166Speter      printf("%20s %d\n", aLimit[iLimit].zLimitName,
3752289166Speter             sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
3753289166Speter    }
3754289166Speter  }else
3755251883Speter
3756251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION
3757289166Speter  if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
3758251883Speter    const char *zFile, *zProc;
3759251883Speter    char *zErrMsg = 0;
3760289166Speter    if( nArg<2 ){
3761305003Scy      raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
3762289166Speter      rc = 1;
3763289166Speter      goto meta_command_exit;
3764289166Speter    }
3765251883Speter    zFile = azArg[1];
3766251883Speter    zProc = nArg>=3 ? azArg[2] : 0;
3767289166Speter    open_db(p, 0);
3768251883Speter    rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
3769251883Speter    if( rc!=SQLITE_OK ){
3770305003Scy      utf8_printf(stderr, "Error: %s\n", zErrMsg);
3771251883Speter      sqlite3_free(zErrMsg);
3772251883Speter      rc = 1;
3773251883Speter    }
3774251883Speter  }else
3775251883Speter#endif
3776251883Speter
3777289166Speter  if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
3778289166Speter    if( nArg!=2 ){
3779305003Scy      raw_printf(stderr, "Usage: .log FILENAME\n");
3780289166Speter      rc = 1;
3781289166Speter    }else{
3782289166Speter      const char *zFile = azArg[1];
3783289166Speter      output_file_close(p->pLog);
3784289166Speter      p->pLog = output_file_open(zFile);
3785289166Speter    }
3786251883Speter  }else
3787251883Speter
3788289166Speter  if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
3789289166Speter    const char *zMode = nArg>=2 ? azArg[1] : "";
3790289166Speter    int n2 = (int)strlen(zMode);
3791289166Speter    int c2 = zMode[0];
3792289166Speter    if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
3793251883Speter      p->mode = MODE_Line;
3794289166Speter    }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
3795251883Speter      p->mode = MODE_Column;
3796289166Speter    }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
3797251883Speter      p->mode = MODE_List;
3798289166Speter    }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
3799251883Speter      p->mode = MODE_Html;
3800289166Speter    }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
3801251883Speter      p->mode = MODE_Tcl;
3802289166Speter      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
3803289166Speter    }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
3804251883Speter      p->mode = MODE_Csv;
3805289166Speter      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
3806289166Speter      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
3807289166Speter    }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
3808251883Speter      p->mode = MODE_List;
3809289166Speter      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
3810289166Speter    }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
3811251883Speter      p->mode = MODE_Insert;
3812289166Speter      set_table_name(p, nArg>=3 ? azArg[2] : "table");
3813289166Speter    }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
3814289166Speter      p->mode = MODE_Ascii;
3815289166Speter      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
3816289166Speter      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
3817251883Speter    }else {
3818305003Scy      raw_printf(stderr, "Error: mode should be one of: "
3819289166Speter         "ascii column csv html insert line list tabs tcl\n");
3820251883Speter      rc = 1;
3821251883Speter    }
3822305003Scy    p->cMode = p->mode;
3823251883Speter  }else
3824251883Speter
3825289166Speter  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
3826289166Speter    if( nArg==2 ){
3827289166Speter      sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
3828289166Speter                       "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
3829289166Speter    }else{
3830305003Scy      raw_printf(stderr, "Usage: .nullvalue STRING\n");
3831251883Speter      rc = 1;
3832251883Speter    }
3833251883Speter  }else
3834251883Speter
3835289166Speter  if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
3836289166Speter    sqlite3 *savedDb = p->db;
3837289166Speter    const char *zSavedFilename = p->zDbFilename;
3838289166Speter    char *zNewFilename = 0;
3839289166Speter    p->db = 0;
3840289166Speter    if( nArg>=2 ) zNewFilename = sqlite3_mprintf("%s", azArg[1]);
3841289166Speter    p->zDbFilename = zNewFilename;
3842289166Speter    open_db(p, 1);
3843289166Speter    if( p->db!=0 ){
3844305003Scy      session_close_all(p);
3845289166Speter      sqlite3_close(savedDb);
3846289166Speter      sqlite3_free(p->zFreeOnClose);
3847289166Speter      p->zFreeOnClose = zNewFilename;
3848289166Speter    }else{
3849289166Speter      sqlite3_free(zNewFilename);
3850289166Speter      p->db = savedDb;
3851289166Speter      p->zDbFilename = zSavedFilename;
3852289166Speter    }
3853251883Speter  }else
3854251883Speter
3855289166Speter  if( c=='o'
3856289166Speter   && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0)
3857289166Speter  ){
3858289166Speter    const char *zFile = nArg>=2 ? azArg[1] : "stdout";
3859289166Speter    if( nArg>2 ){
3860305003Scy      utf8_printf(stderr, "Usage: .%s FILE\n", azArg[0]);
3861289166Speter      rc = 1;
3862289166Speter      goto meta_command_exit;
3863289166Speter    }
3864289166Speter    if( n>1 && strncmp(azArg[0], "once", n)==0 ){
3865289166Speter      if( nArg<2 ){
3866305003Scy        raw_printf(stderr, "Usage: .once FILE\n");
3867289166Speter        rc = 1;
3868289166Speter        goto meta_command_exit;
3869289166Speter      }
3870289166Speter      p->outCount = 2;
3871251883Speter    }else{
3872289166Speter      p->outCount = 0;
3873251883Speter    }
3874289166Speter    output_reset(p);
3875289166Speter    if( zFile[0]=='|' ){
3876289166Speter#ifdef SQLITE_OMIT_POPEN
3877305003Scy      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
3878289166Speter      rc = 1;
3879289166Speter      p->out = stdout;
3880289166Speter#else
3881289166Speter      p->out = popen(zFile + 1, "w");
3882251883Speter      if( p->out==0 ){
3883305003Scy        utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
3884251883Speter        p->out = stdout;
3885251883Speter        rc = 1;
3886251883Speter      }else{
3887289166Speter        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
3888251883Speter      }
3889289166Speter#endif
3890251883Speter    }else{
3891289166Speter      p->out = output_file_open(zFile);
3892251883Speter      if( p->out==0 ){
3893289166Speter        if( strcmp(zFile,"off")!=0 ){
3894305003Scy          utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
3895251883Speter        }
3896251883Speter        p->out = stdout;
3897251883Speter        rc = 1;
3898251883Speter      } else {
3899289166Speter        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
3900251883Speter      }
3901251883Speter    }
3902251883Speter  }else
3903251883Speter
3904251883Speter  if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){
3905251883Speter    int i;
3906251883Speter    for(i=1; i<nArg; i++){
3907305003Scy      if( i>1 ) raw_printf(p->out, " ");
3908305003Scy      utf8_printf(p->out, "%s", azArg[i]);
3909251883Speter    }
3910305003Scy    raw_printf(p->out, "\n");
3911251883Speter  }else
3912251883Speter
3913289166Speter  if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){
3914251883Speter    if( nArg >= 2) {
3915251883Speter      strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
3916251883Speter    }
3917251883Speter    if( nArg >= 3) {
3918251883Speter      strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
3919251883Speter    }
3920251883Speter  }else
3921251883Speter
3922289166Speter  if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
3923251883Speter    rc = 2;
3924251883Speter  }else
3925251883Speter
3926289166Speter  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
3927289166Speter    FILE *alt;
3928289166Speter    if( nArg!=2 ){
3929305003Scy      raw_printf(stderr, "Usage: .read FILE\n");
3930289166Speter      rc = 1;
3931289166Speter      goto meta_command_exit;
3932289166Speter    }
3933289166Speter    alt = fopen(azArg[1], "rb");
3934251883Speter    if( alt==0 ){
3935305003Scy      utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
3936251883Speter      rc = 1;
3937251883Speter    }else{
3938251883Speter      rc = process_input(p, alt);
3939251883Speter      fclose(alt);
3940251883Speter    }
3941251883Speter  }else
3942251883Speter
3943289166Speter  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
3944251883Speter    const char *zSrcFile;
3945251883Speter    const char *zDb;
3946251883Speter    sqlite3 *pSrc;
3947251883Speter    sqlite3_backup *pBackup;
3948251883Speter    int nTimeout = 0;
3949251883Speter
3950251883Speter    if( nArg==2 ){
3951251883Speter      zSrcFile = azArg[1];
3952251883Speter      zDb = "main";
3953289166Speter    }else if( nArg==3 ){
3954251883Speter      zSrcFile = azArg[2];
3955251883Speter      zDb = azArg[1];
3956289166Speter    }else{
3957305003Scy      raw_printf(stderr, "Usage: .restore ?DB? FILE\n");
3958289166Speter      rc = 1;
3959289166Speter      goto meta_command_exit;
3960251883Speter    }
3961251883Speter    rc = sqlite3_open(zSrcFile, &pSrc);
3962251883Speter    if( rc!=SQLITE_OK ){
3963305003Scy      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
3964251883Speter      sqlite3_close(pSrc);
3965251883Speter      return 1;
3966251883Speter    }
3967289166Speter    open_db(p, 0);
3968251883Speter    pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
3969251883Speter    if( pBackup==0 ){
3970305003Scy      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
3971251883Speter      sqlite3_close(pSrc);
3972251883Speter      return 1;
3973251883Speter    }
3974251883Speter    while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
3975251883Speter          || rc==SQLITE_BUSY  ){
3976251883Speter      if( rc==SQLITE_BUSY ){
3977251883Speter        if( nTimeout++ >= 3 ) break;
3978251883Speter        sqlite3_sleep(100);
3979251883Speter      }
3980251883Speter    }
3981251883Speter    sqlite3_backup_finish(pBackup);
3982251883Speter    if( rc==SQLITE_DONE ){
3983251883Speter      rc = 0;
3984251883Speter    }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
3985305003Scy      raw_printf(stderr, "Error: source database is busy\n");
3986251883Speter      rc = 1;
3987251883Speter    }else{
3988305003Scy      utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
3989251883Speter      rc = 1;
3990251883Speter    }
3991251883Speter    sqlite3_close(pSrc);
3992251883Speter  }else
3993251883Speter
3994289166Speter
3995289166Speter  if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
3996289166Speter    if( nArg==2 ){
3997289166Speter      p->scanstatsOn = booleanValue(azArg[1]);
3998289166Speter#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
3999305003Scy      raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
4000289166Speter#endif
4001289166Speter    }else{
4002305003Scy      raw_printf(stderr, "Usage: .scanstats on|off\n");
4003289166Speter      rc = 1;
4004289166Speter    }
4005289166Speter  }else
4006289166Speter
4007289166Speter  if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
4008289166Speter    ShellState data;
4009251883Speter    char *zErrMsg = 0;
4010289166Speter    open_db(p, 0);
4011251883Speter    memcpy(&data, p, sizeof(data));
4012251883Speter    data.showHeader = 0;
4013305003Scy    data.cMode = data.mode = MODE_Semi;
4014305003Scy    if( nArg>=2 && optionMatch(azArg[1], "indent") ){
4015305003Scy      data.cMode = data.mode = MODE_Pretty;
4016305003Scy      nArg--;
4017305003Scy      if( nArg==2 ) azArg[1] = azArg[2];
4018305003Scy    }
4019305003Scy    if( nArg==2 && azArg[1][0]!='-' ){
4020251883Speter      int i;
4021251883Speter      for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
4022251883Speter      if( strcmp(azArg[1],"sqlite_master")==0 ){
4023251883Speter        char *new_argv[2], *new_colv[2];
4024251883Speter        new_argv[0] = "CREATE TABLE sqlite_master (\n"
4025251883Speter                      "  type text,\n"
4026251883Speter                      "  name text,\n"
4027251883Speter                      "  tbl_name text,\n"
4028251883Speter                      "  rootpage integer,\n"
4029251883Speter                      "  sql text\n"
4030251883Speter                      ")";
4031251883Speter        new_argv[1] = 0;
4032251883Speter        new_colv[0] = "sql";
4033251883Speter        new_colv[1] = 0;
4034251883Speter        callback(&data, 1, new_argv, new_colv);
4035251883Speter        rc = SQLITE_OK;
4036251883Speter      }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
4037251883Speter        char *new_argv[2], *new_colv[2];
4038251883Speter        new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
4039251883Speter                      "  type text,\n"
4040251883Speter                      "  name text,\n"
4041251883Speter                      "  tbl_name text,\n"
4042251883Speter                      "  rootpage integer,\n"
4043251883Speter                      "  sql text\n"
4044251883Speter                      ")";
4045251883Speter        new_argv[1] = 0;
4046251883Speter        new_colv[0] = "sql";
4047251883Speter        new_colv[1] = 0;
4048251883Speter        callback(&data, 1, new_argv, new_colv);
4049251883Speter        rc = SQLITE_OK;
4050251883Speter      }else{
4051251883Speter        zShellStatic = azArg[1];
4052251883Speter        rc = sqlite3_exec(p->db,
4053251883Speter          "SELECT sql FROM "
4054251883Speter          "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
4055251883Speter          "     FROM sqlite_master UNION ALL"
4056251883Speter          "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
4057251883Speter          "WHERE lower(tbl_name) LIKE shellstatic()"
4058251883Speter          "  AND type!='meta' AND sql NOTNULL "
4059251883Speter          "ORDER BY rowid",
4060251883Speter          callback, &data, &zErrMsg);
4061251883Speter        zShellStatic = 0;
4062251883Speter      }
4063289166Speter    }else if( nArg==1 ){
4064251883Speter      rc = sqlite3_exec(p->db,
4065251883Speter         "SELECT sql FROM "
4066251883Speter         "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
4067251883Speter         "     FROM sqlite_master UNION ALL"
4068251883Speter         "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
4069289166Speter         "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
4070251883Speter         "ORDER BY rowid",
4071251883Speter         callback, &data, &zErrMsg
4072251883Speter      );
4073289166Speter    }else{
4074305003Scy      raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
4075289166Speter      rc = 1;
4076289166Speter      goto meta_command_exit;
4077251883Speter    }
4078251883Speter    if( zErrMsg ){
4079305003Scy      utf8_printf(stderr,"Error: %s\n", zErrMsg);
4080251883Speter      sqlite3_free(zErrMsg);
4081251883Speter      rc = 1;
4082251883Speter    }else if( rc != SQLITE_OK ){
4083305003Scy      raw_printf(stderr,"Error: querying schema information\n");
4084251883Speter      rc = 1;
4085251883Speter    }else{
4086251883Speter      rc = 0;
4087251883Speter    }
4088251883Speter  }else
4089251883Speter
4090289166Speter#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
4091289166Speter  if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
4092289166Speter    sqlite3SelectTrace = integerValue(azArg[1]);
4093251883Speter  }else
4094289166Speter#endif
4095251883Speter
4096305003Scy#if defined(SQLITE_ENABLE_SESSION)
4097305003Scy  if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){
4098305003Scy    OpenSession *pSession = &p->aSession[0];
4099305003Scy    char **azCmd = &azArg[1];
4100305003Scy    int iSes = 0;
4101305003Scy    int nCmd = nArg - 1;
4102305003Scy    int i;
4103305003Scy    if( nArg<=1 ) goto session_syntax_error;
4104305003Scy    open_db(p, 0);
4105305003Scy    if( nArg>=3 ){
4106305003Scy      for(iSes=0; iSes<p->nSession; iSes++){
4107305003Scy        if( strcmp(p->aSession[iSes].zName, azArg[1])==0 ) break;
4108305003Scy      }
4109305003Scy      if( iSes<p->nSession ){
4110305003Scy        pSession = &p->aSession[iSes];
4111305003Scy        azCmd++;
4112305003Scy        nCmd--;
4113305003Scy      }else{
4114305003Scy        pSession = &p->aSession[0];
4115305003Scy        iSes = 0;
4116305003Scy      }
4117305003Scy    }
4118289166Speter
4119305003Scy    /* .session attach TABLE
4120305003Scy    ** Invoke the sqlite3session_attach() interface to attach a particular
4121305003Scy    ** table so that it is never filtered.
4122305003Scy    */
4123305003Scy    if( strcmp(azCmd[0],"attach")==0 ){
4124305003Scy      if( nCmd!=2 ) goto session_syntax_error;
4125305003Scy      if( pSession->p==0 ){
4126305003Scy        session_not_open:
4127305003Scy        raw_printf(stderr, "ERROR: No sessions are open\n");
4128305003Scy      }else{
4129305003Scy        rc = sqlite3session_attach(pSession->p, azCmd[1]);
4130305003Scy        if( rc ){
4131305003Scy          raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc);
4132305003Scy          rc = 0;
4133305003Scy        }
4134305003Scy      }
4135305003Scy    }else
4136305003Scy
4137305003Scy    /* .session changeset FILE
4138305003Scy    ** .session patchset FILE
4139305003Scy    ** Write a changeset or patchset into a file.  The file is overwritten.
4140305003Scy    */
4141305003Scy    if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){
4142305003Scy      FILE *out = 0;
4143305003Scy      if( nCmd!=2 ) goto session_syntax_error;
4144305003Scy      if( pSession->p==0 ) goto session_not_open;
4145305003Scy      out = fopen(azCmd[1], "wb");
4146305003Scy      if( out==0 ){
4147305003Scy        utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", azCmd[1]);
4148305003Scy      }else{
4149305003Scy        int szChng;
4150305003Scy        void *pChng;
4151305003Scy        if( azCmd[0][0]=='c' ){
4152305003Scy          rc = sqlite3session_changeset(pSession->p, &szChng, &pChng);
4153305003Scy        }else{
4154305003Scy          rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
4155305003Scy        }
4156305003Scy        if( rc ){
4157305003Scy          printf("Error: error code %d\n", rc);
4158305003Scy          rc = 0;
4159305003Scy        }
4160305003Scy        if( pChng
4161305003Scy          && fwrite(pChng, szChng, 1, out)!=1 ){
4162305003Scy          raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n",
4163305003Scy                  szChng);
4164305003Scy        }
4165305003Scy        sqlite3_free(pChng);
4166305003Scy        fclose(out);
4167305003Scy      }
4168305003Scy    }else
4169305003Scy
4170305003Scy    /* .session close
4171305003Scy    ** Close the identified session
4172305003Scy    */
4173305003Scy    if( strcmp(azCmd[0], "close")==0 ){
4174305003Scy      if( nCmd!=1 ) goto session_syntax_error;
4175305003Scy      if( p->nSession ){
4176305003Scy        session_close(pSession);
4177305003Scy        p->aSession[iSes] = p->aSession[--p->nSession];
4178305003Scy      }
4179305003Scy    }else
4180305003Scy
4181305003Scy    /* .session enable ?BOOLEAN?
4182305003Scy    ** Query or set the enable flag
4183305003Scy    */
4184305003Scy    if( strcmp(azCmd[0], "enable")==0 ){
4185305003Scy      int ii;
4186305003Scy      if( nCmd>2 ) goto session_syntax_error;
4187305003Scy      ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
4188305003Scy      if( p->nSession ){
4189305003Scy        ii = sqlite3session_enable(pSession->p, ii);
4190305003Scy        utf8_printf(p->out, "session %s enable flag = %d\n",
4191305003Scy                    pSession->zName, ii);
4192305003Scy      }
4193305003Scy    }else
4194305003Scy
4195305003Scy    /* .session filter GLOB ....
4196305003Scy    ** Set a list of GLOB patterns of table names to be excluded.
4197305003Scy    */
4198305003Scy    if( strcmp(azCmd[0], "filter")==0 ){
4199305003Scy      int ii, nByte;
4200305003Scy      if( nCmd<2 ) goto session_syntax_error;
4201305003Scy      if( p->nSession ){
4202305003Scy        for(ii=0; ii<pSession->nFilter; ii++){
4203305003Scy          sqlite3_free(pSession->azFilter[ii]);
4204305003Scy        }
4205305003Scy        sqlite3_free(pSession->azFilter);
4206305003Scy        nByte = sizeof(pSession->azFilter[0])*(nCmd-1);
4207305003Scy        pSession->azFilter = sqlite3_malloc( nByte );
4208305003Scy        if( pSession->azFilter==0 ){
4209305003Scy          raw_printf(stderr, "Error: out or memory\n");
4210305003Scy          exit(1);
4211305003Scy        }
4212305003Scy        for(ii=1; ii<nCmd; ii++){
4213305003Scy          pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]);
4214305003Scy        }
4215305003Scy        pSession->nFilter = ii-1;
4216305003Scy      }
4217305003Scy    }else
4218305003Scy
4219305003Scy    /* .session indirect ?BOOLEAN?
4220305003Scy    ** Query or set the indirect flag
4221305003Scy    */
4222305003Scy    if( strcmp(azCmd[0], "indirect")==0 ){
4223305003Scy      int ii;
4224305003Scy      if( nCmd>2 ) goto session_syntax_error;
4225305003Scy      ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
4226305003Scy      if( p->nSession ){
4227305003Scy        ii = sqlite3session_indirect(pSession->p, ii);
4228305003Scy        utf8_printf(p->out, "session %s indirect flag = %d\n",
4229305003Scy                    pSession->zName, ii);
4230305003Scy      }
4231305003Scy    }else
4232305003Scy
4233305003Scy    /* .session isempty
4234305003Scy    ** Determine if the session is empty
4235305003Scy    */
4236305003Scy    if( strcmp(azCmd[0], "isempty")==0 ){
4237305003Scy      int ii;
4238305003Scy      if( nCmd!=1 ) goto session_syntax_error;
4239305003Scy      if( p->nSession ){
4240305003Scy        ii = sqlite3session_isempty(pSession->p);
4241305003Scy        utf8_printf(p->out, "session %s isempty flag = %d\n",
4242305003Scy                    pSession->zName, ii);
4243305003Scy      }
4244305003Scy    }else
4245305003Scy
4246305003Scy    /* .session list
4247305003Scy    ** List all currently open sessions
4248305003Scy    */
4249305003Scy    if( strcmp(azCmd[0],"list")==0 ){
4250305003Scy      for(i=0; i<p->nSession; i++){
4251305003Scy        utf8_printf(p->out, "%d %s\n", i, p->aSession[i].zName);
4252305003Scy      }
4253305003Scy    }else
4254305003Scy
4255305003Scy    /* .session open DB NAME
4256305003Scy    ** Open a new session called NAME on the attached database DB.
4257305003Scy    ** DB is normally "main".
4258305003Scy    */
4259305003Scy    if( strcmp(azCmd[0],"open")==0 ){
4260305003Scy      char *zName;
4261305003Scy      if( nCmd!=3 ) goto session_syntax_error;
4262305003Scy      zName = azCmd[2];
4263305003Scy      if( zName[0]==0 ) goto session_syntax_error;
4264305003Scy      for(i=0; i<p->nSession; i++){
4265305003Scy        if( strcmp(p->aSession[i].zName,zName)==0 ){
4266305003Scy          utf8_printf(stderr, "Session \"%s\" already exists\n", zName);
4267305003Scy          goto meta_command_exit;
4268305003Scy        }
4269305003Scy      }
4270305003Scy      if( p->nSession>=ArraySize(p->aSession) ){
4271305003Scy        raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(p->aSession));
4272305003Scy        goto meta_command_exit;
4273305003Scy      }
4274305003Scy      pSession = &p->aSession[p->nSession];
4275305003Scy      rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
4276305003Scy      if( rc ){
4277305003Scy        raw_printf(stderr, "Cannot open session: error code=%d\n", rc);
4278305003Scy        rc = 0;
4279305003Scy        goto meta_command_exit;
4280305003Scy      }
4281305003Scy      pSession->nFilter = 0;
4282305003Scy      sqlite3session_table_filter(pSession->p, session_filter, pSession);
4283305003Scy      p->nSession++;
4284305003Scy      pSession->zName = sqlite3_mprintf("%s", zName);
4285305003Scy    }else
4286305003Scy    /* If no command name matches, show a syntax error */
4287305003Scy    session_syntax_error:
4288305003Scy    session_help(p);
4289305003Scy  }else
4290305003Scy#endif
4291305003Scy
4292289166Speter#ifdef SQLITE_DEBUG
4293289166Speter  /* Undocumented commands for internal testing.  Subject to change
4294289166Speter  ** without notice. */
4295289166Speter  if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){
4296289166Speter    if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){
4297289166Speter      int i, v;
4298289166Speter      for(i=1; i<nArg; i++){
4299289166Speter        v = booleanValue(azArg[i]);
4300305003Scy        utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
4301289166Speter      }
4302289166Speter    }
4303289166Speter    if( strncmp(azArg[0]+9, "integer", n-9)==0 ){
4304289166Speter      int i; sqlite3_int64 v;
4305289166Speter      for(i=1; i<nArg; i++){
4306289166Speter        char zBuf[200];
4307289166Speter        v = integerValue(azArg[i]);
4308289166Speter        sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
4309305003Scy        utf8_printf(p->out, "%s", zBuf);
4310289166Speter      }
4311289166Speter    }
4312289166Speter  }else
4313289166Speter#endif
4314289166Speter
4315289166Speter  if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
4316289166Speter    if( nArg<2 || nArg>3 ){
4317305003Scy      raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
4318289166Speter      rc = 1;
4319289166Speter    }
4320289166Speter    if( nArg>=2 ){
4321289166Speter      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
4322289166Speter                       "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
4323289166Speter    }
4324289166Speter    if( nArg>=3 ){
4325289166Speter      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
4326289166Speter                       "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
4327289166Speter    }
4328289166Speter  }else
4329289166Speter
4330289166Speter  if( c=='s'
4331289166Speter   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
4332289166Speter  ){
4333289166Speter    char *zCmd;
4334289166Speter    int i, x;
4335289166Speter    if( nArg<2 ){
4336305003Scy      raw_printf(stderr, "Usage: .system COMMAND\n");
4337289166Speter      rc = 1;
4338289166Speter      goto meta_command_exit;
4339289166Speter    }
4340289166Speter    zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
4341289166Speter    for(i=2; i<nArg; i++){
4342289166Speter      zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
4343289166Speter                             zCmd, azArg[i]);
4344289166Speter    }
4345289166Speter    x = system(zCmd);
4346289166Speter    sqlite3_free(zCmd);
4347305003Scy    if( x ) raw_printf(stderr, "System command returns %d\n", x);
4348289166Speter  }else
4349289166Speter
4350289166Speter  if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
4351305003Scy    static const char *azBool[] = { "off", "on", "full", "unk" };
4352251883Speter    int i;
4353289166Speter    if( nArg!=1 ){
4354305003Scy      raw_printf(stderr, "Usage: .show\n");
4355289166Speter      rc = 1;
4356289166Speter      goto meta_command_exit;
4357289166Speter    }
4358305003Scy    utf8_printf(p->out, "%12.12s: %s\n","echo", azBool[p->echoOn!=0]);
4359305003Scy    utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
4360305003Scy    utf8_printf(p->out, "%12.12s: %s\n","explain",
4361305003Scy         p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
4362305003Scy    utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
4363305003Scy    utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
4364305003Scy    utf8_printf(p->out, "%12.12s: ", "nullvalue");
4365289166Speter      output_c_string(p->out, p->nullValue);
4366305003Scy      raw_printf(p->out, "\n");
4367305003Scy    utf8_printf(p->out,"%12.12s: %s\n","output",
4368251883Speter            strlen30(p->outfile) ? p->outfile : "stdout");
4369305003Scy    utf8_printf(p->out,"%12.12s: ", "colseparator");
4370289166Speter      output_c_string(p->out, p->colSeparator);
4371305003Scy      raw_printf(p->out, "\n");
4372305003Scy    utf8_printf(p->out,"%12.12s: ", "rowseparator");
4373289166Speter      output_c_string(p->out, p->rowSeparator);
4374305003Scy      raw_printf(p->out, "\n");
4375305003Scy    utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
4376305003Scy    utf8_printf(p->out, "%12.12s: ", "width");
4377251883Speter    for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
4378305003Scy      raw_printf(p->out, "%d ", p->colWidth[i]);
4379251883Speter    }
4380305003Scy    raw_printf(p->out, "\n");
4381251883Speter  }else
4382251883Speter
4383289166Speter  if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
4384289166Speter    if( nArg==2 ){
4385289166Speter      p->statsOn = booleanValue(azArg[1]);
4386305003Scy    }else if( nArg==1 ){
4387305003Scy      display_stats(p->db, p, 0);
4388289166Speter    }else{
4389305003Scy      raw_printf(stderr, "Usage: .stats ?on|off?\n");
4390289166Speter      rc = 1;
4391289166Speter    }
4392251883Speter  }else
4393251883Speter
4394289166Speter  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
4395251883Speter    sqlite3_stmt *pStmt;
4396251883Speter    char **azResult;
4397251883Speter    int nRow, nAlloc;
4398251883Speter    char *zSql = 0;
4399251883Speter    int ii;
4400289166Speter    open_db(p, 0);
4401251883Speter    rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
4402305003Scy    if( rc ) return shellDatabaseError(p->db);
4403305003Scy
4404305003Scy    /* Create an SQL statement to query for the list of tables in the
4405305003Scy    ** main and all attached databases where the table name matches the
4406305003Scy    ** LIKE pattern bound to variable "?1". */
4407251883Speter    zSql = sqlite3_mprintf(
4408251883Speter        "SELECT name FROM sqlite_master"
4409251883Speter        " WHERE type IN ('table','view')"
4410251883Speter        "   AND name NOT LIKE 'sqlite_%%'"
4411251883Speter        "   AND name LIKE ?1");
4412305003Scy    while( zSql && sqlite3_step(pStmt)==SQLITE_ROW ){
4413251883Speter      const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
4414251883Speter      if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue;
4415251883Speter      if( strcmp(zDbName,"temp")==0 ){
4416251883Speter        zSql = sqlite3_mprintf(
4417251883Speter                 "%z UNION ALL "
4418251883Speter                 "SELECT 'temp.' || name FROM sqlite_temp_master"
4419251883Speter                 " WHERE type IN ('table','view')"
4420251883Speter                 "   AND name NOT LIKE 'sqlite_%%'"
4421251883Speter                 "   AND name LIKE ?1", zSql);
4422251883Speter      }else{
4423251883Speter        zSql = sqlite3_mprintf(
4424251883Speter                 "%z UNION ALL "
4425251883Speter                 "SELECT '%q.' || name FROM \"%w\".sqlite_master"
4426251883Speter                 " WHERE type IN ('table','view')"
4427251883Speter                 "   AND name NOT LIKE 'sqlite_%%'"
4428251883Speter                 "   AND name LIKE ?1", zSql, zDbName, zDbName);
4429251883Speter      }
4430251883Speter    }
4431305003Scy    rc = sqlite3_finalize(pStmt);
4432305003Scy    if( zSql && rc==SQLITE_OK ){
4433305003Scy      zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
4434305003Scy      if( zSql ) rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
4435305003Scy    }
4436251883Speter    sqlite3_free(zSql);
4437305003Scy    if( !zSql ) return shellNomemError();
4438305003Scy    if( rc ) return shellDatabaseError(p->db);
4439305003Scy
4440305003Scy    /* Run the SQL statement prepared by the above block. Store the results
4441305003Scy    ** as an array of nul-terminated strings in azResult[].  */
4442251883Speter    nRow = nAlloc = 0;
4443251883Speter    azResult = 0;
4444251883Speter    if( nArg>1 ){
4445251883Speter      sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT);
4446251883Speter    }else{
4447251883Speter      sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
4448251883Speter    }
4449251883Speter    while( sqlite3_step(pStmt)==SQLITE_ROW ){
4450251883Speter      if( nRow>=nAlloc ){
4451251883Speter        char **azNew;
4452289166Speter        int n2 = nAlloc*2 + 10;
4453289166Speter        azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
4454251883Speter        if( azNew==0 ){
4455305003Scy          rc = shellNomemError();
4456251883Speter          break;
4457251883Speter        }
4458289166Speter        nAlloc = n2;
4459251883Speter        azResult = azNew;
4460251883Speter      }
4461251883Speter      azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
4462305003Scy      if( 0==azResult[nRow] ){
4463305003Scy        rc = shellNomemError();
4464305003Scy        break;
4465305003Scy      }
4466305003Scy      nRow++;
4467251883Speter    }
4468305003Scy    if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
4469305003Scy      rc = shellDatabaseError(p->db);
4470305003Scy    }
4471305003Scy
4472305003Scy    /* Pretty-print the contents of array azResult[] to the output */
4473305003Scy    if( rc==0 && nRow>0 ){
4474251883Speter      int len, maxlen = 0;
4475251883Speter      int i, j;
4476251883Speter      int nPrintCol, nPrintRow;
4477251883Speter      for(i=0; i<nRow; i++){
4478251883Speter        len = strlen30(azResult[i]);
4479251883Speter        if( len>maxlen ) maxlen = len;
4480251883Speter      }
4481251883Speter      nPrintCol = 80/(maxlen+2);
4482251883Speter      if( nPrintCol<1 ) nPrintCol = 1;
4483251883Speter      nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
4484251883Speter      for(i=0; i<nPrintRow; i++){
4485251883Speter        for(j=i; j<nRow; j+=nPrintRow){
4486251883Speter          char *zSp = j<nPrintRow ? "" : "  ";
4487305003Scy          utf8_printf(p->out, "%s%-*s", zSp, maxlen,
4488305003Scy                      azResult[j] ? azResult[j]:"");
4489251883Speter        }
4490305003Scy        raw_printf(p->out, "\n");
4491251883Speter      }
4492251883Speter    }
4493305003Scy
4494251883Speter    for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
4495251883Speter    sqlite3_free(azResult);
4496251883Speter  }else
4497251883Speter
4498251883Speter  if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
4499251883Speter    static const struct {
4500251883Speter       const char *zCtrlName;   /* Name of a test-control option */
4501251883Speter       int ctrlCode;            /* Integer code for that option */
4502251883Speter    } aCtrl[] = {
4503251883Speter      { "prng_save",             SQLITE_TESTCTRL_PRNG_SAVE              },
4504251883Speter      { "prng_restore",          SQLITE_TESTCTRL_PRNG_RESTORE           },
4505251883Speter      { "prng_reset",            SQLITE_TESTCTRL_PRNG_RESET             },
4506251883Speter      { "bitvec_test",           SQLITE_TESTCTRL_BITVEC_TEST            },
4507251883Speter      { "fault_install",         SQLITE_TESTCTRL_FAULT_INSTALL          },
4508251883Speter      { "benign_malloc_hooks",   SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS    },
4509251883Speter      { "pending_byte",          SQLITE_TESTCTRL_PENDING_BYTE           },
4510251883Speter      { "assert",                SQLITE_TESTCTRL_ASSERT                 },
4511251883Speter      { "always",                SQLITE_TESTCTRL_ALWAYS                 },
4512251883Speter      { "reserve",               SQLITE_TESTCTRL_RESERVE                },
4513251883Speter      { "optimizations",         SQLITE_TESTCTRL_OPTIMIZATIONS          },
4514251883Speter      { "iskeyword",             SQLITE_TESTCTRL_ISKEYWORD              },
4515251883Speter      { "scratchmalloc",         SQLITE_TESTCTRL_SCRATCHMALLOC          },
4516289166Speter      { "byteorder",             SQLITE_TESTCTRL_BYTEORDER              },
4517289166Speter      { "never_corrupt",         SQLITE_TESTCTRL_NEVER_CORRUPT          },
4518289166Speter      { "imposter",              SQLITE_TESTCTRL_IMPOSTER               },
4519251883Speter    };
4520251883Speter    int testctrl = -1;
4521289166Speter    int rc2 = 0;
4522289166Speter    int i, n2;
4523289166Speter    open_db(p, 0);
4524251883Speter
4525251883Speter    /* convert testctrl text option to value. allow any unique prefix
4526251883Speter    ** of the option name, or a numerical value. */
4527289166Speter    n2 = strlen30(azArg[1]);
4528289166Speter    for(i=0; i<ArraySize(aCtrl); i++){
4529289166Speter      if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
4530251883Speter        if( testctrl<0 ){
4531251883Speter          testctrl = aCtrl[i].ctrlCode;
4532251883Speter        }else{
4533305003Scy          utf8_printf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
4534251883Speter          testctrl = -1;
4535251883Speter          break;
4536251883Speter        }
4537251883Speter      }
4538251883Speter    }
4539289166Speter    if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]);
4540251883Speter    if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
4541305003Scy      utf8_printf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
4542251883Speter    }else{
4543251883Speter      switch(testctrl){
4544251883Speter
4545251883Speter        /* sqlite3_test_control(int, db, int) */
4546251883Speter        case SQLITE_TESTCTRL_OPTIMIZATIONS:
4547305003Scy        case SQLITE_TESTCTRL_RESERVE:
4548251883Speter          if( nArg==3 ){
4549305003Scy            int opt = (int)strtol(azArg[2], 0, 0);
4550289166Speter            rc2 = sqlite3_test_control(testctrl, p->db, opt);
4551305003Scy            raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
4552251883Speter          } else {
4553305003Scy            utf8_printf(stderr,"Error: testctrl %s takes a single int option\n",
4554251883Speter                    azArg[1]);
4555251883Speter          }
4556251883Speter          break;
4557251883Speter
4558251883Speter        /* sqlite3_test_control(int) */
4559289166Speter        case SQLITE_TESTCTRL_PRNG_SAVE:
4560289166Speter        case SQLITE_TESTCTRL_PRNG_RESTORE:
4561251883Speter        case SQLITE_TESTCTRL_PRNG_RESET:
4562289166Speter        case SQLITE_TESTCTRL_BYTEORDER:
4563251883Speter          if( nArg==2 ){
4564289166Speter            rc2 = sqlite3_test_control(testctrl);
4565305003Scy            raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
4566251883Speter          } else {
4567305003Scy            utf8_printf(stderr,"Error: testctrl %s takes no options\n",
4568305003Scy                        azArg[1]);
4569251883Speter          }
4570251883Speter          break;
4571251883Speter
4572251883Speter        /* sqlite3_test_control(int, uint) */
4573305003Scy        case SQLITE_TESTCTRL_PENDING_BYTE:
4574251883Speter          if( nArg==3 ){
4575289166Speter            unsigned int opt = (unsigned int)integerValue(azArg[2]);
4576289166Speter            rc2 = sqlite3_test_control(testctrl, opt);
4577305003Scy            raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
4578251883Speter          } else {
4579305003Scy            utf8_printf(stderr,"Error: testctrl %s takes a single unsigned"
4580251883Speter                           " int option\n", azArg[1]);
4581251883Speter          }
4582251883Speter          break;
4583305003Scy
4584251883Speter        /* sqlite3_test_control(int, int) */
4585305003Scy        case SQLITE_TESTCTRL_ASSERT:
4586305003Scy        case SQLITE_TESTCTRL_ALWAYS:
4587305003Scy        case SQLITE_TESTCTRL_NEVER_CORRUPT:
4588251883Speter          if( nArg==3 ){
4589305003Scy            int opt = booleanValue(azArg[2]);
4590289166Speter            rc2 = sqlite3_test_control(testctrl, opt);
4591305003Scy            raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
4592251883Speter          } else {
4593305003Scy            utf8_printf(stderr,"Error: testctrl %s takes a single int option\n",
4594251883Speter                            azArg[1]);
4595251883Speter          }
4596251883Speter          break;
4597251883Speter
4598251883Speter        /* sqlite3_test_control(int, char *) */
4599251883Speter#ifdef SQLITE_N_KEYWORD
4600305003Scy        case SQLITE_TESTCTRL_ISKEYWORD:
4601251883Speter          if( nArg==3 ){
4602305003Scy            const char *opt = azArg[2];
4603289166Speter            rc2 = sqlite3_test_control(testctrl, opt);
4604305003Scy            raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
4605251883Speter          } else {
4606305003Scy            utf8_printf(stderr,
4607305003Scy                        "Error: testctrl %s takes a single char * option\n",
4608305003Scy                        azArg[1]);
4609251883Speter          }
4610251883Speter          break;
4611251883Speter#endif
4612251883Speter
4613289166Speter        case SQLITE_TESTCTRL_IMPOSTER:
4614289166Speter          if( nArg==5 ){
4615305003Scy            rc2 = sqlite3_test_control(testctrl, p->db,
4616289166Speter                          azArg[2],
4617289166Speter                          integerValue(azArg[3]),
4618289166Speter                          integerValue(azArg[4]));
4619305003Scy            raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
4620289166Speter          }else{
4621305003Scy            raw_printf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
4622289166Speter          }
4623289166Speter          break;
4624289166Speter
4625305003Scy        case SQLITE_TESTCTRL_BITVEC_TEST:
4626305003Scy        case SQLITE_TESTCTRL_FAULT_INSTALL:
4627305003Scy        case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
4628305003Scy        case SQLITE_TESTCTRL_SCRATCHMALLOC:
4629251883Speter        default:
4630305003Scy          utf8_printf(stderr,
4631305003Scy                      "Error: CLI support for testctrl %s not implemented\n",
4632305003Scy                      azArg[1]);
4633251883Speter          break;
4634251883Speter      }
4635251883Speter    }
4636251883Speter  }else
4637251883Speter
4638289166Speter  if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){
4639289166Speter    open_db(p, 0);
4640289166Speter    sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
4641251883Speter  }else
4642305003Scy
4643289166Speter  if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){
4644289166Speter    if( nArg==2 ){
4645289166Speter      enableTimer = booleanValue(azArg[1]);
4646289166Speter      if( enableTimer && !HAS_TIMER ){
4647305003Scy        raw_printf(stderr, "Error: timer not available on this system.\n");
4648289166Speter        enableTimer = 0;
4649289166Speter      }
4650289166Speter    }else{
4651305003Scy      raw_printf(stderr, "Usage: .timer on|off\n");
4652289166Speter      rc = 1;
4653289166Speter    }
4654251883Speter  }else
4655305003Scy
4656289166Speter  if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
4657289166Speter    open_db(p, 0);
4658289166Speter    if( nArg!=2 ){
4659305003Scy      raw_printf(stderr, "Usage: .trace FILE|off\n");
4660289166Speter      rc = 1;
4661289166Speter      goto meta_command_exit;
4662289166Speter    }
4663251883Speter    output_file_close(p->traceOut);
4664251883Speter    p->traceOut = output_file_open(azArg[1]);
4665251883Speter#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
4666251883Speter    if( p->traceOut==0 ){
4667305003Scy      sqlite3_trace_v2(p->db, 0, 0, 0);
4668251883Speter    }else{
4669305003Scy      sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut);
4670251883Speter    }
4671251883Speter#endif
4672251883Speter  }else
4673251883Speter
4674289166Speter#if SQLITE_USER_AUTHENTICATION
4675289166Speter  if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
4676289166Speter    if( nArg<2 ){
4677305003Scy      raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n");
4678289166Speter      rc = 1;
4679289166Speter      goto meta_command_exit;
4680289166Speter    }
4681289166Speter    open_db(p, 0);
4682289166Speter    if( strcmp(azArg[1],"login")==0 ){
4683289166Speter      if( nArg!=4 ){
4684305003Scy        raw_printf(stderr, "Usage: .user login USER PASSWORD\n");
4685289166Speter        rc = 1;
4686289166Speter        goto meta_command_exit;
4687289166Speter      }
4688289166Speter      rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
4689289166Speter                                    (int)strlen(azArg[3]));
4690289166Speter      if( rc ){
4691305003Scy        utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
4692289166Speter        rc = 1;
4693289166Speter      }
4694289166Speter    }else if( strcmp(azArg[1],"add")==0 ){
4695289166Speter      if( nArg!=5 ){
4696305003Scy        raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
4697289166Speter        rc = 1;
4698289166Speter        goto meta_command_exit;
4699289166Speter      }
4700289166Speter      rc = sqlite3_user_add(p->db, azArg[2],
4701289166Speter                            azArg[3], (int)strlen(azArg[3]),
4702289166Speter                            booleanValue(azArg[4]));
4703289166Speter      if( rc ){
4704305003Scy        raw_printf(stderr, "User-Add failed: %d\n", rc);
4705289166Speter        rc = 1;
4706289166Speter      }
4707289166Speter    }else if( strcmp(azArg[1],"edit")==0 ){
4708289166Speter      if( nArg!=5 ){
4709305003Scy        raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
4710289166Speter        rc = 1;
4711289166Speter        goto meta_command_exit;
4712289166Speter      }
4713289166Speter      rc = sqlite3_user_change(p->db, azArg[2],
4714289166Speter                              azArg[3], (int)strlen(azArg[3]),
4715289166Speter                              booleanValue(azArg[4]));
4716289166Speter      if( rc ){
4717305003Scy        raw_printf(stderr, "User-Edit failed: %d\n", rc);
4718289166Speter        rc = 1;
4719289166Speter      }
4720289166Speter    }else if( strcmp(azArg[1],"delete")==0 ){
4721289166Speter      if( nArg!=3 ){
4722305003Scy        raw_printf(stderr, "Usage: .user delete USER\n");
4723289166Speter        rc = 1;
4724289166Speter        goto meta_command_exit;
4725289166Speter      }
4726289166Speter      rc = sqlite3_user_delete(p->db, azArg[2]);
4727289166Speter      if( rc ){
4728305003Scy        raw_printf(stderr, "User-Delete failed: %d\n", rc);
4729289166Speter        rc = 1;
4730289166Speter      }
4731289166Speter    }else{
4732305003Scy      raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n");
4733289166Speter      rc = 1;
4734289166Speter      goto meta_command_exit;
4735305003Scy    }
4736289166Speter  }else
4737289166Speter#endif /* SQLITE_USER_AUTHENTICATION */
4738289166Speter
4739251883Speter  if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
4740305003Scy    utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
4741251883Speter        sqlite3_libversion(), sqlite3_sourceid());
4742251883Speter  }else
4743251883Speter
4744305003Scy  if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){
4745305003Scy    const char *zDbName = nArg==2 ? azArg[1] : "main";
4746305003Scy    sqlite3_vfs *pVfs;
4747305003Scy    if( p->db ){
4748305003Scy      sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
4749305003Scy      if( pVfs ){
4750305003Scy        utf8_printf(p->out, "vfs.zName      = \"%s\"\n", pVfs->zName);
4751305003Scy        raw_printf(p->out, "vfs.iVersion   = %d\n", pVfs->iVersion);
4752305003Scy        raw_printf(p->out, "vfs.szOsFile   = %d\n", pVfs->szOsFile);
4753305003Scy        raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
4754305003Scy      }
4755305003Scy    }
4756305003Scy  }else
4757305003Scy
4758305003Scy  if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){
4759305003Scy    sqlite3_vfs *pVfs;
4760305003Scy    sqlite3_vfs *pCurrent = 0;
4761305003Scy    if( p->db ){
4762305003Scy      sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
4763305003Scy    }
4764305003Scy    for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
4765305003Scy      utf8_printf(p->out, "vfs.zName      = \"%s\"%s\n", pVfs->zName,
4766305003Scy           pVfs==pCurrent ? "  <--- CURRENT" : "");
4767305003Scy      raw_printf(p->out, "vfs.iVersion   = %d\n", pVfs->iVersion);
4768305003Scy      raw_printf(p->out, "vfs.szOsFile   = %d\n", pVfs->szOsFile);
4769305003Scy      raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
4770305003Scy      if( pVfs->pNext ){
4771305003Scy        raw_printf(p->out, "-----------------------------------\n");
4772305003Scy      }
4773305003Scy    }
4774305003Scy  }else
4775305003Scy
4776251883Speter  if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
4777251883Speter    const char *zDbName = nArg==2 ? azArg[1] : "main";
4778251883Speter    char *zVfsName = 0;
4779251883Speter    if( p->db ){
4780251883Speter      sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
4781251883Speter      if( zVfsName ){
4782305003Scy        utf8_printf(p->out, "%s\n", zVfsName);
4783251883Speter        sqlite3_free(zVfsName);
4784251883Speter      }
4785251883Speter    }
4786251883Speter  }else
4787251883Speter
4788251883Speter#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
4789251883Speter  if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
4790289166Speter    sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
4791251883Speter  }else
4792251883Speter#endif
4793251883Speter
4794289166Speter  if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
4795251883Speter    int j;
4796251883Speter    assert( nArg<=ArraySize(azArg) );
4797251883Speter    for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
4798289166Speter      p->colWidth[j-1] = (int)integerValue(azArg[j]);
4799251883Speter    }
4800251883Speter  }else
4801251883Speter
4802251883Speter  {
4803305003Scy    utf8_printf(stderr, "Error: unknown command or invalid arguments: "
4804251883Speter      " \"%s\". Enter \".help\" for help\n", azArg[0]);
4805251883Speter    rc = 1;
4806251883Speter  }
4807251883Speter
4808289166Spetermeta_command_exit:
4809289166Speter  if( p->outCount ){
4810289166Speter    p->outCount--;
4811289166Speter    if( p->outCount==0 ) output_reset(p);
4812289166Speter  }
4813251883Speter  return rc;
4814251883Speter}
4815251883Speter
4816251883Speter/*
4817251883Speter** Return TRUE if a semicolon occurs anywhere in the first N characters
4818251883Speter** of string z[].
4819251883Speter*/
4820289166Speterstatic int line_contains_semicolon(const char *z, int N){
4821251883Speter  int i;
4822251883Speter  for(i=0; i<N; i++){  if( z[i]==';' ) return 1; }
4823251883Speter  return 0;
4824251883Speter}
4825251883Speter
4826251883Speter/*
4827251883Speter** Test to see if a line consists entirely of whitespace.
4828251883Speter*/
4829251883Speterstatic int _all_whitespace(const char *z){
4830251883Speter  for(; *z; z++){
4831251883Speter    if( IsSpace(z[0]) ) continue;
4832251883Speter    if( *z=='/' && z[1]=='*' ){
4833251883Speter      z += 2;
4834251883Speter      while( *z && (*z!='*' || z[1]!='/') ){ z++; }
4835251883Speter      if( *z==0 ) return 0;
4836251883Speter      z++;
4837251883Speter      continue;
4838251883Speter    }
4839251883Speter    if( *z=='-' && z[1]=='-' ){
4840251883Speter      z += 2;
4841251883Speter      while( *z && *z!='\n' ){ z++; }
4842251883Speter      if( *z==0 ) return 1;
4843251883Speter      continue;
4844251883Speter    }
4845251883Speter    return 0;
4846251883Speter  }
4847251883Speter  return 1;
4848251883Speter}
4849251883Speter
4850251883Speter/*
4851251883Speter** Return TRUE if the line typed in is an SQL command terminator other
4852251883Speter** than a semi-colon.  The SQL Server style "go" command is understood
4853251883Speter** as is the Oracle "/".
4854251883Speter*/
4855289166Speterstatic int line_is_command_terminator(const char *zLine){
4856251883Speter  while( IsSpace(zLine[0]) ){ zLine++; };
4857251883Speter  if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
4858251883Speter    return 1;  /* Oracle */
4859251883Speter  }
4860251883Speter  if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
4861251883Speter         && _all_whitespace(&zLine[2]) ){
4862251883Speter    return 1;  /* SQL Server */
4863251883Speter  }
4864251883Speter  return 0;
4865251883Speter}
4866251883Speter
4867251883Speter/*
4868251883Speter** Return true if zSql is a complete SQL statement.  Return false if it
4869251883Speter** ends in the middle of a string literal or C-style comment.
4870251883Speter*/
4871289166Speterstatic int line_is_complete(char *zSql, int nSql){
4872251883Speter  int rc;
4873251883Speter  if( zSql==0 ) return 1;
4874251883Speter  zSql[nSql] = ';';
4875251883Speter  zSql[nSql+1] = 0;
4876251883Speter  rc = sqlite3_complete(zSql);
4877251883Speter  zSql[nSql] = 0;
4878251883Speter  return rc;
4879251883Speter}
4880251883Speter
4881251883Speter/*
4882251883Speter** Read input from *in and process it.  If *in==0 then input
4883251883Speter** is interactive - the user is typing it it.  Otherwise, input
4884251883Speter** is coming from a file or device.  A prompt is issued and history
4885251883Speter** is saved only if input is interactive.  An interrupt signal will
4886251883Speter** cause this routine to exit immediately, unless input is interactive.
4887251883Speter**
4888251883Speter** Return the number of errors.
4889251883Speter*/
4890289166Speterstatic int process_input(ShellState *p, FILE *in){
4891289166Speter  char *zLine = 0;          /* A single input line */
4892289166Speter  char *zSql = 0;           /* Accumulated SQL text */
4893289166Speter  int nLine;                /* Length of current line */
4894289166Speter  int nSql = 0;             /* Bytes of zSql[] used */
4895289166Speter  int nAlloc = 0;           /* Allocated zSql[] space */
4896289166Speter  int nSqlPrior = 0;        /* Bytes of zSql[] used by prior line */
4897289166Speter  char *zErrMsg;            /* Error message returned */
4898289166Speter  int rc;                   /* Error code */
4899289166Speter  int errCnt = 0;           /* Number of errors seen */
4900289166Speter  int lineno = 0;           /* Current line number */
4901289166Speter  int startline = 0;        /* Line number for start of current input */
4902251883Speter
4903251883Speter  while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
4904251883Speter    fflush(p->out);
4905289166Speter    zLine = one_input_line(in, zLine, nSql>0);
4906251883Speter    if( zLine==0 ){
4907251883Speter      /* End of input */
4908251883Speter      if( stdin_is_interactive ) printf("\n");
4909251883Speter      break;
4910251883Speter    }
4911251883Speter    if( seenInterrupt ){
4912251883Speter      if( in!=0 ) break;
4913251883Speter      seenInterrupt = 0;
4914251883Speter    }
4915251883Speter    lineno++;
4916289166Speter    if( nSql==0 && _all_whitespace(zLine) ){
4917289166Speter      if( p->echoOn ) printf("%s\n", zLine);
4918289166Speter      continue;
4919289166Speter    }
4920251883Speter    if( zLine && zLine[0]=='.' && nSql==0 ){
4921251883Speter      if( p->echoOn ) printf("%s\n", zLine);
4922251883Speter      rc = do_meta_command(zLine, p);
4923251883Speter      if( rc==2 ){ /* exit requested */
4924251883Speter        break;
4925251883Speter      }else if( rc ){
4926251883Speter        errCnt++;
4927251883Speter      }
4928251883Speter      continue;
4929251883Speter    }
4930289166Speter    if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){
4931251883Speter      memcpy(zLine,";",2);
4932251883Speter    }
4933289166Speter    nLine = strlen30(zLine);
4934289166Speter    if( nSql+nLine+2>=nAlloc ){
4935289166Speter      nAlloc = nSql+nLine+100;
4936289166Speter      zSql = realloc(zSql, nAlloc);
4937289166Speter      if( zSql==0 ){
4938305003Scy        raw_printf(stderr, "Error: out of memory\n");
4939289166Speter        exit(1);
4940289166Speter      }
4941289166Speter    }
4942251883Speter    nSqlPrior = nSql;
4943289166Speter    if( nSql==0 ){
4944251883Speter      int i;
4945251883Speter      for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
4946289166Speter      assert( nAlloc>0 && zSql!=0 );
4947289166Speter      memcpy(zSql, zLine+i, nLine+1-i);
4948289166Speter      startline = lineno;
4949289166Speter      nSql = nLine-i;
4950251883Speter    }else{
4951251883Speter      zSql[nSql++] = '\n';
4952289166Speter      memcpy(zSql+nSql, zLine, nLine+1);
4953289166Speter      nSql += nLine;
4954251883Speter    }
4955289166Speter    if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
4956251883Speter                && sqlite3_complete(zSql) ){
4957251883Speter      p->cnt = 0;
4958289166Speter      open_db(p, 0);
4959289166Speter      if( p->backslashOn ) resolve_backslashes(zSql);
4960251883Speter      BEGIN_TIMER;
4961251883Speter      rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
4962251883Speter      END_TIMER;
4963251883Speter      if( rc || zErrMsg ){
4964251883Speter        char zPrefix[100];
4965251883Speter        if( in!=0 || !stdin_is_interactive ){
4966305003Scy          sqlite3_snprintf(sizeof(zPrefix), zPrefix,
4967251883Speter                           "Error: near line %d:", startline);
4968251883Speter        }else{
4969251883Speter          sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
4970251883Speter        }
4971251883Speter        if( zErrMsg!=0 ){
4972305003Scy          utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg);
4973251883Speter          sqlite3_free(zErrMsg);
4974251883Speter          zErrMsg = 0;
4975251883Speter        }else{
4976305003Scy          utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
4977251883Speter        }
4978251883Speter        errCnt++;
4979305003Scy      }else if( p->countChanges ){
4980305003Scy        raw_printf(p->out, "changes: %3d   total_changes: %d\n",
4981305003Scy                sqlite3_changes(p->db), sqlite3_total_changes(p->db));
4982251883Speter      }
4983251883Speter      nSql = 0;
4984289166Speter      if( p->outCount ){
4985289166Speter        output_reset(p);
4986289166Speter        p->outCount = 0;
4987289166Speter      }
4988289166Speter    }else if( nSql && _all_whitespace(zSql) ){
4989289166Speter      if( p->echoOn ) printf("%s\n", zSql);
4990251883Speter      nSql = 0;
4991251883Speter    }
4992251883Speter  }
4993289166Speter  if( nSql ){
4994251883Speter    if( !_all_whitespace(zSql) ){
4995305003Scy      utf8_printf(stderr, "Error: incomplete SQL: %s\n", zSql);
4996289166Speter      errCnt++;
4997251883Speter    }
4998251883Speter  }
4999305003Scy  free(zSql);
5000251883Speter  free(zLine);
5001251883Speter  return errCnt>0;
5002251883Speter}
5003251883Speter
5004251883Speter/*
5005251883Speter** Return a pathname which is the user's home directory.  A
5006251883Speter** 0 return indicates an error of some kind.
5007251883Speter*/
5008251883Speterstatic char *find_home_dir(void){
5009251883Speter  static char *home_dir = NULL;
5010251883Speter  if( home_dir ) return home_dir;
5011251883Speter
5012289166Speter#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
5013289166Speter     && !defined(__RTP__) && !defined(_WRS_KERNEL)
5014251883Speter  {
5015251883Speter    struct passwd *pwent;
5016251883Speter    uid_t uid = getuid();
5017251883Speter    if( (pwent=getpwuid(uid)) != NULL) {
5018251883Speter      home_dir = pwent->pw_dir;
5019251883Speter    }
5020251883Speter  }
5021251883Speter#endif
5022251883Speter
5023251883Speter#if defined(_WIN32_WCE)
5024251883Speter  /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
5025251883Speter   */
5026251883Speter  home_dir = "/";
5027251883Speter#else
5028251883Speter
5029251883Speter#if defined(_WIN32) || defined(WIN32)
5030251883Speter  if (!home_dir) {
5031251883Speter    home_dir = getenv("USERPROFILE");
5032251883Speter  }
5033251883Speter#endif
5034251883Speter
5035251883Speter  if (!home_dir) {
5036251883Speter    home_dir = getenv("HOME");
5037251883Speter  }
5038251883Speter
5039251883Speter#if defined(_WIN32) || defined(WIN32)
5040251883Speter  if (!home_dir) {
5041251883Speter    char *zDrive, *zPath;
5042251883Speter    int n;
5043251883Speter    zDrive = getenv("HOMEDRIVE");
5044251883Speter    zPath = getenv("HOMEPATH");
5045251883Speter    if( zDrive && zPath ){
5046251883Speter      n = strlen30(zDrive) + strlen30(zPath) + 1;
5047251883Speter      home_dir = malloc( n );
5048251883Speter      if( home_dir==0 ) return 0;
5049251883Speter      sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
5050251883Speter      return home_dir;
5051251883Speter    }
5052251883Speter    home_dir = "c:\\";
5053251883Speter  }
5054251883Speter#endif
5055251883Speter
5056251883Speter#endif /* !_WIN32_WCE */
5057251883Speter
5058251883Speter  if( home_dir ){
5059251883Speter    int n = strlen30(home_dir) + 1;
5060251883Speter    char *z = malloc( n );
5061251883Speter    if( z ) memcpy(z, home_dir, n);
5062251883Speter    home_dir = z;
5063251883Speter  }
5064251883Speter
5065251883Speter  return home_dir;
5066251883Speter}
5067251883Speter
5068251883Speter/*
5069251883Speter** Read input from the file given by sqliterc_override.  Or if that
5070251883Speter** parameter is NULL, take input from ~/.sqliterc
5071251883Speter**
5072251883Speter** Returns the number of errors.
5073251883Speter*/
5074289166Speterstatic void process_sqliterc(
5075289166Speter  ShellState *p,                  /* Configuration data */
5076251883Speter  const char *sqliterc_override   /* Name of config file. NULL to use default */
5077251883Speter){
5078251883Speter  char *home_dir = NULL;
5079251883Speter  const char *sqliterc = sqliterc_override;
5080251883Speter  char *zBuf = 0;
5081251883Speter  FILE *in = NULL;
5082251883Speter
5083251883Speter  if (sqliterc == NULL) {
5084251883Speter    home_dir = find_home_dir();
5085251883Speter    if( home_dir==0 ){
5086305003Scy      raw_printf(stderr, "-- warning: cannot find home directory;"
5087289166Speter                      " cannot read ~/.sqliterc\n");
5088289166Speter      return;
5089251883Speter    }
5090251883Speter    sqlite3_initialize();
5091251883Speter    zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
5092251883Speter    sqliterc = zBuf;
5093251883Speter  }
5094251883Speter  in = fopen(sqliterc,"rb");
5095251883Speter  if( in ){
5096251883Speter    if( stdin_is_interactive ){
5097305003Scy      utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
5098251883Speter    }
5099289166Speter    process_input(p,in);
5100251883Speter    fclose(in);
5101251883Speter  }
5102251883Speter  sqlite3_free(zBuf);
5103251883Speter}
5104251883Speter
5105251883Speter/*
5106251883Speter** Show available command line options
5107251883Speter*/
5108305003Scystatic const char zOptions[] =
5109289166Speter  "   -ascii               set output mode to 'ascii'\n"
5110251883Speter  "   -bail                stop after hitting an error\n"
5111251883Speter  "   -batch               force batch I/O\n"
5112251883Speter  "   -column              set output mode to 'column'\n"
5113251883Speter  "   -cmd COMMAND         run \"COMMAND\" before reading stdin\n"
5114251883Speter  "   -csv                 set output mode to 'csv'\n"
5115251883Speter  "   -echo                print commands before execution\n"
5116251883Speter  "   -init FILENAME       read/process named file\n"
5117251883Speter  "   -[no]header          turn headers on or off\n"
5118251883Speter#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
5119251883Speter  "   -heap SIZE           Size of heap for memsys3 or memsys5\n"
5120251883Speter#endif
5121251883Speter  "   -help                show this message\n"
5122251883Speter  "   -html                set output mode to HTML\n"
5123251883Speter  "   -interactive         force interactive I/O\n"
5124251883Speter  "   -line                set output mode to 'line'\n"
5125251883Speter  "   -list                set output mode to 'list'\n"
5126289166Speter  "   -lookaside SIZE N    use N entries of SZ bytes for lookaside memory\n"
5127251883Speter  "   -mmap N              default mmap size set to N\n"
5128251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX
5129251883Speter  "   -multiplex           enable the multiplexor VFS\n"
5130251883Speter#endif
5131289166Speter  "   -newline SEP         set output row separator. Default: '\\n'\n"
5132251883Speter  "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
5133289166Speter  "   -pagecache SIZE N    use N slots of SZ bytes each for page cache memory\n"
5134289166Speter  "   -scratch SIZE N      use N slots of SZ bytes each for scratch memory\n"
5135289166Speter  "   -separator SEP       set output column separator. Default: '|'\n"
5136251883Speter  "   -stats               print memory stats before each finalize\n"
5137251883Speter  "   -version             show SQLite version\n"
5138251883Speter  "   -vfs NAME            use NAME as the default VFS\n"
5139251883Speter#ifdef SQLITE_ENABLE_VFSTRACE
5140251883Speter  "   -vfstrace            enable tracing of all VFS calls\n"
5141251883Speter#endif
5142251883Speter;
5143251883Speterstatic void usage(int showDetail){
5144305003Scy  utf8_printf(stderr,
5145305003Scy      "Usage: %s [OPTIONS] FILENAME [SQL]\n"
5146251883Speter      "FILENAME is the name of an SQLite database. A new database is created\n"
5147251883Speter      "if the file does not previously exist.\n", Argv0);
5148251883Speter  if( showDetail ){
5149305003Scy    utf8_printf(stderr, "OPTIONS include:\n%s", zOptions);
5150251883Speter  }else{
5151305003Scy    raw_printf(stderr, "Use the -help option for additional information\n");
5152251883Speter  }
5153251883Speter  exit(1);
5154251883Speter}
5155251883Speter
5156251883Speter/*
5157251883Speter** Initialize the state information in data
5158251883Speter*/
5159289166Speterstatic void main_init(ShellState *data) {
5160251883Speter  memset(data, 0, sizeof(*data));
5161305003Scy  data->normalMode = data->cMode = data->mode = MODE_List;
5162305003Scy  data->autoExplain = 1;
5163289166Speter  memcpy(data->colSeparator,SEP_Column, 2);
5164289166Speter  memcpy(data->rowSeparator,SEP_Row, 2);
5165251883Speter  data->showHeader = 0;
5166289166Speter  data->shellFlgs = SHFLG_Lookaside;
5167251883Speter  sqlite3_config(SQLITE_CONFIG_URI, 1);
5168251883Speter  sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
5169289166Speter  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
5170251883Speter  sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
5171251883Speter  sqlite3_snprintf(sizeof(continuePrompt), continuePrompt,"   ...> ");
5172251883Speter}
5173251883Speter
5174251883Speter/*
5175289166Speter** Output text to the console in a font that attracts extra attention.
5176289166Speter*/
5177289166Speter#ifdef _WIN32
5178289166Speterstatic void printBold(const char *zText){
5179289166Speter  HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
5180289166Speter  CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
5181289166Speter  GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
5182289166Speter  SetConsoleTextAttribute(out,
5183289166Speter         FOREGROUND_RED|FOREGROUND_INTENSITY
5184289166Speter  );
5185289166Speter  printf("%s", zText);
5186289166Speter  SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
5187289166Speter}
5188289166Speter#else
5189289166Speterstatic void printBold(const char *zText){
5190289166Speter  printf("\033[1m%s\033[0m", zText);
5191289166Speter}
5192289166Speter#endif
5193289166Speter
5194289166Speter/*
5195251883Speter** Get the argument to an --option.  Throw an error and die if no argument
5196251883Speter** is available.
5197251883Speter*/
5198251883Speterstatic char *cmdline_option_value(int argc, char **argv, int i){
5199251883Speter  if( i==argc ){
5200305003Scy    utf8_printf(stderr, "%s: Error: missing argument to %s\n",
5201251883Speter            argv[0], argv[argc-1]);
5202251883Speter    exit(1);
5203251883Speter  }
5204251883Speter  return argv[i];
5205251883Speter}
5206251883Speter
5207305003Scy#ifndef SQLITE_SHELL_IS_UTF8
5208305003Scy#  if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
5209305003Scy#    define SQLITE_SHELL_IS_UTF8          (0)
5210305003Scy#  else
5211305003Scy#    define SQLITE_SHELL_IS_UTF8          (1)
5212305003Scy#  endif
5213305003Scy#endif
5214305003Scy
5215305003Scy#if SQLITE_SHELL_IS_UTF8
5216289166Speterint SQLITE_CDECL main(int argc, char **argv){
5217305003Scy#else
5218305003Scyint SQLITE_CDECL wmain(int argc, wchar_t **wargv){
5219305003Scy  char **argv;
5220305003Scy#endif
5221251883Speter  char *zErrMsg = 0;
5222289166Speter  ShellState data;
5223251883Speter  const char *zInitFile = 0;
5224251883Speter  int i;
5225251883Speter  int rc = 0;
5226289166Speter  int warnInmemoryDb = 0;
5227289166Speter  int readStdin = 1;
5228289166Speter  int nCmd = 0;
5229289166Speter  char **azCmd = 0;
5230251883Speter
5231305003Scy  setBinaryMode(stdin, 0);
5232305003Scy  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
5233305003Scy  stdin_is_interactive = isatty(0);
5234305003Scy  stdout_is_console = isatty(1);
5235305003Scy
5236289166Speter#if USE_SYSTEM_SQLITE+0!=1
5237251883Speter  if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
5238305003Scy    utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
5239251883Speter            sqlite3_sourceid(), SQLITE_SOURCE_ID);
5240251883Speter    exit(1);
5241251883Speter  }
5242289166Speter#endif
5243305003Scy  main_init(&data);
5244305003Scy#if !SQLITE_SHELL_IS_UTF8
5245305003Scy  sqlite3_initialize();
5246305003Scy  argv = sqlite3_malloc64(sizeof(argv[0])*argc);
5247305003Scy  if( argv==0 ){
5248305003Scy    raw_printf(stderr, "out of memory\n");
5249305003Scy    exit(1);
5250305003Scy  }
5251305003Scy  for(i=0; i<argc; i++){
5252305003Scy    argv[i] = sqlite3_win32_unicode_to_utf8(wargv[i]);
5253305003Scy    if( argv[i]==0 ){
5254305003Scy      raw_printf(stderr, "out of memory\n");
5255305003Scy      exit(1);
5256305003Scy    }
5257305003Scy  }
5258305003Scy#endif
5259305003Scy  assert( argc>=1 && argv && argv[0] );
5260251883Speter  Argv0 = argv[0];
5261251883Speter
5262251883Speter  /* Make sure we have a valid signal handler early, before anything
5263251883Speter  ** else is done.
5264251883Speter  */
5265251883Speter#ifdef SIGINT
5266251883Speter  signal(SIGINT, interrupt_handler);
5267251883Speter#endif
5268251883Speter
5269289166Speter#ifdef SQLITE_SHELL_DBNAME_PROC
5270289166Speter  {
5271289166Speter    /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
5272289166Speter    ** of a C-function that will provide the name of the database file.  Use
5273289166Speter    ** this compile-time option to embed this shell program in larger
5274289166Speter    ** applications. */
5275289166Speter    extern void SQLITE_SHELL_DBNAME_PROC(const char**);
5276289166Speter    SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename);
5277289166Speter    warnInmemoryDb = 0;
5278289166Speter  }
5279289166Speter#endif
5280289166Speter
5281251883Speter  /* Do an initial pass through the command-line argument to locate
5282251883Speter  ** the name of the database file, the name of the initialization file,
5283251883Speter  ** the size of the alternative malloc heap,
5284251883Speter  ** and the first command to execute.
5285251883Speter  */
5286251883Speter  for(i=1; i<argc; i++){
5287251883Speter    char *z;
5288251883Speter    z = argv[i];
5289251883Speter    if( z[0]!='-' ){
5290251883Speter      if( data.zDbFilename==0 ){
5291251883Speter        data.zDbFilename = z;
5292289166Speter      }else{
5293289166Speter        /* Excesss arguments are interpreted as SQL (or dot-commands) and
5294289166Speter        ** mean that nothing is read from stdin */
5295289166Speter        readStdin = 0;
5296289166Speter        nCmd++;
5297289166Speter        azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
5298289166Speter        if( azCmd==0 ){
5299305003Scy          raw_printf(stderr, "out of memory\n");
5300289166Speter          exit(1);
5301289166Speter        }
5302289166Speter        azCmd[nCmd-1] = z;
5303251883Speter      }
5304251883Speter    }
5305251883Speter    if( z[1]=='-' ) z++;
5306251883Speter    if( strcmp(z,"-separator")==0
5307251883Speter     || strcmp(z,"-nullvalue")==0
5308289166Speter     || strcmp(z,"-newline")==0
5309251883Speter     || strcmp(z,"-cmd")==0
5310251883Speter    ){
5311251883Speter      (void)cmdline_option_value(argc, argv, ++i);
5312251883Speter    }else if( strcmp(z,"-init")==0 ){
5313251883Speter      zInitFile = cmdline_option_value(argc, argv, ++i);
5314251883Speter    }else if( strcmp(z,"-batch")==0 ){
5315251883Speter      /* Need to check for batch mode here to so we can avoid printing
5316305003Scy      ** informational messages (like from process_sqliterc) before
5317251883Speter      ** we do the actual processing of arguments later in a second pass.
5318251883Speter      */
5319251883Speter      stdin_is_interactive = 0;
5320251883Speter    }else if( strcmp(z,"-heap")==0 ){
5321251883Speter#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
5322251883Speter      const char *zSize;
5323251883Speter      sqlite3_int64 szHeap;
5324251883Speter
5325251883Speter      zSize = cmdline_option_value(argc, argv, ++i);
5326251883Speter      szHeap = integerValue(zSize);
5327251883Speter      if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
5328251883Speter      sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
5329305003Scy#else
5330305003Scy      (void)cmdline_option_value(argc, argv, ++i);
5331251883Speter#endif
5332289166Speter    }else if( strcmp(z,"-scratch")==0 ){
5333289166Speter      int n, sz;
5334289166Speter      sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
5335289166Speter      if( sz>400000 ) sz = 400000;
5336289166Speter      if( sz<2500 ) sz = 2500;
5337289166Speter      n = (int)integerValue(cmdline_option_value(argc,argv,++i));
5338289166Speter      if( n>10 ) n = 10;
5339289166Speter      if( n<1 ) n = 1;
5340289166Speter      sqlite3_config(SQLITE_CONFIG_SCRATCH, malloc(n*sz+1), sz, n);
5341289166Speter      data.shellFlgs |= SHFLG_Scratch;
5342289166Speter    }else if( strcmp(z,"-pagecache")==0 ){
5343289166Speter      int n, sz;
5344289166Speter      sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
5345289166Speter      if( sz>70000 ) sz = 70000;
5346305003Scy      if( sz<0 ) sz = 0;
5347289166Speter      n = (int)integerValue(cmdline_option_value(argc,argv,++i));
5348305003Scy      sqlite3_config(SQLITE_CONFIG_PAGECACHE,
5349305003Scy                    (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
5350289166Speter      data.shellFlgs |= SHFLG_Pagecache;
5351289166Speter    }else if( strcmp(z,"-lookaside")==0 ){
5352289166Speter      int n, sz;
5353289166Speter      sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
5354289166Speter      if( sz<0 ) sz = 0;
5355289166Speter      n = (int)integerValue(cmdline_option_value(argc,argv,++i));
5356289166Speter      if( n<0 ) n = 0;
5357289166Speter      sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
5358289166Speter      if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
5359251883Speter#ifdef SQLITE_ENABLE_VFSTRACE
5360251883Speter    }else if( strcmp(z,"-vfstrace")==0 ){
5361251883Speter      extern int vfstrace_register(
5362251883Speter         const char *zTraceName,
5363251883Speter         const char *zOldVfsName,
5364251883Speter         int (*xOut)(const char*,void*),
5365251883Speter         void *pOutArg,
5366251883Speter         int makeDefault
5367251883Speter      );
5368251883Speter      vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
5369251883Speter#endif
5370251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX
5371251883Speter    }else if( strcmp(z,"-multiplex")==0 ){
5372251883Speter      extern int sqlite3_multiple_initialize(const char*,int);
5373251883Speter      sqlite3_multiplex_initialize(0, 1);
5374251883Speter#endif
5375251883Speter    }else if( strcmp(z,"-mmap")==0 ){
5376251883Speter      sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
5377251883Speter      sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
5378251883Speter    }else if( strcmp(z,"-vfs")==0 ){
5379251883Speter      sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i));
5380251883Speter      if( pVfs ){
5381251883Speter        sqlite3_vfs_register(pVfs, 1);
5382251883Speter      }else{
5383305003Scy        utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]);
5384251883Speter        exit(1);
5385251883Speter      }
5386251883Speter    }
5387251883Speter  }
5388251883Speter  if( data.zDbFilename==0 ){
5389251883Speter#ifndef SQLITE_OMIT_MEMORYDB
5390251883Speter    data.zDbFilename = ":memory:";
5391289166Speter    warnInmemoryDb = argc==1;
5392251883Speter#else
5393305003Scy    utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
5394251883Speter    return 1;
5395251883Speter#endif
5396251883Speter  }
5397251883Speter  data.out = stdout;
5398251883Speter
5399251883Speter  /* Go ahead and open the database file if it already exists.  If the
5400251883Speter  ** file does not exist, delay opening it.  This prevents empty database
5401251883Speter  ** files from being created if a user mistypes the database name argument
5402251883Speter  ** to the sqlite command-line tool.
5403251883Speter  */
5404251883Speter  if( access(data.zDbFilename, 0)==0 ){
5405289166Speter    open_db(&data, 0);
5406251883Speter  }
5407251883Speter
5408251883Speter  /* Process the initialization file if there is one.  If no -init option
5409251883Speter  ** is given on the command line, look for a file named ~/.sqliterc and
5410251883Speter  ** try to process it.
5411251883Speter  */
5412289166Speter  process_sqliterc(&data,zInitFile);
5413251883Speter
5414251883Speter  /* Make a second pass through the command-line argument and set
5415251883Speter  ** options.  This second pass is delayed until after the initialization
5416251883Speter  ** file is processed so that the command-line arguments will override
5417251883Speter  ** settings in the initialization file.
5418251883Speter  */
5419251883Speter  for(i=1; i<argc; i++){
5420251883Speter    char *z = argv[i];
5421251883Speter    if( z[0]!='-' ) continue;
5422251883Speter    if( z[1]=='-' ){ z++; }
5423251883Speter    if( strcmp(z,"-init")==0 ){
5424251883Speter      i++;
5425251883Speter    }else if( strcmp(z,"-html")==0 ){
5426251883Speter      data.mode = MODE_Html;
5427251883Speter    }else if( strcmp(z,"-list")==0 ){
5428251883Speter      data.mode = MODE_List;
5429251883Speter    }else if( strcmp(z,"-line")==0 ){
5430251883Speter      data.mode = MODE_Line;
5431251883Speter    }else if( strcmp(z,"-column")==0 ){
5432251883Speter      data.mode = MODE_Column;
5433251883Speter    }else if( strcmp(z,"-csv")==0 ){
5434251883Speter      data.mode = MODE_Csv;
5435289166Speter      memcpy(data.colSeparator,",",2);
5436289166Speter    }else if( strcmp(z,"-ascii")==0 ){
5437289166Speter      data.mode = MODE_Ascii;
5438289166Speter      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
5439289166Speter                       SEP_Unit);
5440289166Speter      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
5441289166Speter                       SEP_Record);
5442251883Speter    }else if( strcmp(z,"-separator")==0 ){
5443289166Speter      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
5444251883Speter                       "%s",cmdline_option_value(argc,argv,++i));
5445289166Speter    }else if( strcmp(z,"-newline")==0 ){
5446289166Speter      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
5447289166Speter                       "%s",cmdline_option_value(argc,argv,++i));
5448251883Speter    }else if( strcmp(z,"-nullvalue")==0 ){
5449289166Speter      sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
5450251883Speter                       "%s",cmdline_option_value(argc,argv,++i));
5451251883Speter    }else if( strcmp(z,"-header")==0 ){
5452251883Speter      data.showHeader = 1;
5453251883Speter    }else if( strcmp(z,"-noheader")==0 ){
5454251883Speter      data.showHeader = 0;
5455251883Speter    }else if( strcmp(z,"-echo")==0 ){
5456251883Speter      data.echoOn = 1;
5457289166Speter    }else if( strcmp(z,"-eqp")==0 ){
5458289166Speter      data.autoEQP = 1;
5459305003Scy    }else if( strcmp(z,"-eqpfull")==0 ){
5460305003Scy      data.autoEQP = 2;
5461251883Speter    }else if( strcmp(z,"-stats")==0 ){
5462251883Speter      data.statsOn = 1;
5463289166Speter    }else if( strcmp(z,"-scanstats")==0 ){
5464289166Speter      data.scanstatsOn = 1;
5465289166Speter    }else if( strcmp(z,"-backslash")==0 ){
5466289166Speter      /* Undocumented command-line option: -backslash
5467289166Speter      ** Causes C-style backslash escapes to be evaluated in SQL statements
5468289166Speter      ** prior to sending the SQL into SQLite.  Useful for injecting
5469289166Speter      ** crazy bytes in the middle of SQL statements for testing and debugging.
5470289166Speter      */
5471289166Speter      data.backslashOn = 1;
5472251883Speter    }else if( strcmp(z,"-bail")==0 ){
5473251883Speter      bail_on_error = 1;
5474251883Speter    }else if( strcmp(z,"-version")==0 ){
5475251883Speter      printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
5476251883Speter      return 0;
5477251883Speter    }else if( strcmp(z,"-interactive")==0 ){
5478251883Speter      stdin_is_interactive = 1;
5479251883Speter    }else if( strcmp(z,"-batch")==0 ){
5480251883Speter      stdin_is_interactive = 0;
5481251883Speter    }else if( strcmp(z,"-heap")==0 ){
5482251883Speter      i++;
5483289166Speter    }else if( strcmp(z,"-scratch")==0 ){
5484289166Speter      i+=2;
5485289166Speter    }else if( strcmp(z,"-pagecache")==0 ){
5486289166Speter      i+=2;
5487289166Speter    }else if( strcmp(z,"-lookaside")==0 ){
5488289166Speter      i+=2;
5489251883Speter    }else if( strcmp(z,"-mmap")==0 ){
5490251883Speter      i++;
5491251883Speter    }else if( strcmp(z,"-vfs")==0 ){
5492251883Speter      i++;
5493251883Speter#ifdef SQLITE_ENABLE_VFSTRACE
5494251883Speter    }else if( strcmp(z,"-vfstrace")==0 ){
5495251883Speter      i++;
5496251883Speter#endif
5497251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX
5498251883Speter    }else if( strcmp(z,"-multiplex")==0 ){
5499251883Speter      i++;
5500251883Speter#endif
5501251883Speter    }else if( strcmp(z,"-help")==0 ){
5502251883Speter      usage(1);
5503251883Speter    }else if( strcmp(z,"-cmd")==0 ){
5504289166Speter      /* Run commands that follow -cmd first and separately from commands
5505289166Speter      ** that simply appear on the command-line.  This seems goofy.  It would
5506289166Speter      ** be better if all commands ran in the order that they appear.  But
5507289166Speter      ** we retain the goofy behavior for historical compatibility. */
5508251883Speter      if( i==argc-1 ) break;
5509251883Speter      z = cmdline_option_value(argc,argv,++i);
5510251883Speter      if( z[0]=='.' ){
5511251883Speter        rc = do_meta_command(z, &data);
5512251883Speter        if( rc && bail_on_error ) return rc==2 ? 0 : rc;
5513251883Speter      }else{
5514289166Speter        open_db(&data, 0);
5515251883Speter        rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
5516251883Speter        if( zErrMsg!=0 ){
5517305003Scy          utf8_printf(stderr,"Error: %s\n", zErrMsg);
5518251883Speter          if( bail_on_error ) return rc!=0 ? rc : 1;
5519251883Speter        }else if( rc!=0 ){
5520305003Scy          utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z);
5521251883Speter          if( bail_on_error ) return rc;
5522251883Speter        }
5523251883Speter      }
5524251883Speter    }else{
5525305003Scy      utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
5526305003Scy      raw_printf(stderr,"Use -help for a list of options.\n");
5527251883Speter      return 1;
5528251883Speter    }
5529305003Scy    data.cMode = data.mode;
5530251883Speter  }
5531251883Speter
5532289166Speter  if( !readStdin ){
5533289166Speter    /* Run all arguments that do not begin with '-' as if they were separate
5534289166Speter    ** command-line inputs, except for the argToSkip argument which contains
5535289166Speter    ** the database filename.
5536251883Speter    */
5537289166Speter    for(i=0; i<nCmd; i++){
5538289166Speter      if( azCmd[i][0]=='.' ){
5539289166Speter        rc = do_meta_command(azCmd[i], &data);
5540289166Speter        if( rc ) return rc==2 ? 0 : rc;
5541289166Speter      }else{
5542289166Speter        open_db(&data, 0);
5543289166Speter        rc = shell_exec(data.db, azCmd[i], shell_callback, &data, &zErrMsg);
5544289166Speter        if( zErrMsg!=0 ){
5545305003Scy          utf8_printf(stderr,"Error: %s\n", zErrMsg);
5546289166Speter          return rc!=0 ? rc : 1;
5547289166Speter        }else if( rc!=0 ){
5548305003Scy          utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
5549289166Speter          return rc;
5550289166Speter        }
5551251883Speter      }
5552251883Speter    }
5553289166Speter    free(azCmd);
5554251883Speter  }else{
5555251883Speter    /* Run commands received from standard input
5556251883Speter    */
5557251883Speter    if( stdin_is_interactive ){
5558251883Speter      char *zHome;
5559251883Speter      char *zHistory = 0;
5560251883Speter      int nHistory;
5561251883Speter      printf(
5562251883Speter        "SQLite version %s %.19s\n" /*extra-version-info*/
5563289166Speter        "Enter \".help\" for usage hints.\n",
5564251883Speter        sqlite3_libversion(), sqlite3_sourceid()
5565251883Speter      );
5566289166Speter      if( warnInmemoryDb ){
5567289166Speter        printf("Connected to a ");
5568289166Speter        printBold("transient in-memory database");
5569289166Speter        printf(".\nUse \".open FILENAME\" to reopen on a "
5570289166Speter               "persistent database.\n");
5571289166Speter      }
5572251883Speter      zHome = find_home_dir();
5573251883Speter      if( zHome ){
5574251883Speter        nHistory = strlen30(zHome) + 20;
5575251883Speter        if( (zHistory = malloc(nHistory))!=0 ){
5576251883Speter          sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
5577251883Speter        }
5578251883Speter      }
5579289166Speter      if( zHistory ){ shell_read_history(zHistory); }
5580251883Speter      rc = process_input(&data, 0);
5581251883Speter      if( zHistory ){
5582289166Speter        shell_stifle_history(100);
5583289166Speter        shell_write_history(zHistory);
5584251883Speter        free(zHistory);
5585251883Speter      }
5586251883Speter    }else{
5587251883Speter      rc = process_input(&data, stdin);
5588251883Speter    }
5589251883Speter  }
5590251883Speter  set_table_name(&data, 0);
5591251883Speter  if( data.db ){
5592305003Scy    session_close_all(&data);
5593251883Speter    sqlite3_close(data.db);
5594251883Speter  }
5595305003Scy  sqlite3_free(data.zFreeOnClose);
5596305003Scy#if !SQLITE_SHELL_IS_UTF8
5597305003Scy  for(i=0; i<argc; i++) sqlite3_free(argv[i]);
5598305003Scy  sqlite3_free(argv);
5599305003Scy#endif
5600251883Speter  return rc;
5601251883Speter}
5602