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/*
21251883Speter** Enable large-file support for fopen() and friends on unix.
22251883Speter*/
23251883Speter#ifndef SQLITE_DISABLE_LFS
24251883Speter# define _LARGE_FILE       1
25251883Speter# ifndef _FILE_OFFSET_BITS
26251883Speter#   define _FILE_OFFSET_BITS 64
27251883Speter# endif
28251883Speter# define _LARGEFILE_SOURCE 1
29251883Speter#endif
30251883Speter
31251883Speter#include <stdlib.h>
32251883Speter#include <string.h>
33251883Speter#include <stdio.h>
34251883Speter#include <assert.h>
35251883Speter#include "sqlite3.h"
36251883Speter#include <ctype.h>
37251883Speter#include <stdarg.h>
38251883Speter
39251883Speter#if !defined(_WIN32) && !defined(WIN32)
40251883Speter# include <signal.h>
41251883Speter# if !defined(__RTP__) && !defined(_WRS_KERNEL)
42251883Speter#  include <pwd.h>
43251883Speter# endif
44251883Speter# include <unistd.h>
45251883Speter# include <sys/types.h>
46251883Speter#endif
47251883Speter
48251883Speter#ifdef HAVE_EDITLINE
49251883Speter# include <editline/editline.h>
50251883Speter#endif
51251883Speter#if defined(HAVE_READLINE) && HAVE_READLINE==1
52251883Speter# include <readline/readline.h>
53251883Speter# include <readline/history.h>
54251883Speter#endif
55251883Speter#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
56251883Speter# define readline(p) local_getline(p,stdin,0)
57251883Speter# define add_history(X)
58251883Speter# define read_history(X)
59251883Speter# define write_history(X)
60251883Speter# define stifle_history(X)
61251883Speter#endif
62251883Speter
63251883Speter#if defined(_WIN32) || defined(WIN32)
64251883Speter# include <io.h>
65251883Speter#define isatty(h) _isatty(h)
66251883Speter#define access(f,m) _access((f),(m))
67251883Speter#undef popen
68251883Speter#define popen(a,b) _popen((a),(b))
69251883Speter#undef pclose
70251883Speter#define pclose(x) _pclose(x)
71251883Speter#else
72251883Speter/* Make sure isatty() has a prototype.
73251883Speter*/
74251883Speterextern int isatty(int);
75251883Speter#endif
76251883Speter
77251883Speter#if defined(_WIN32_WCE)
78251883Speter/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
79251883Speter * thus we always assume that we have a console. That can be
80251883Speter * overridden with the -batch command line option.
81251883Speter */
82251883Speter#define isatty(x) 1
83251883Speter#endif
84251883Speter
85251883Speter/* True if the timer is enabled */
86251883Speterstatic int enableTimer = 0;
87251883Speter
88251883Speter/* ctype macros that work with signed characters */
89251883Speter#define IsSpace(X)  isspace((unsigned char)X)
90251883Speter#define IsDigit(X)  isdigit((unsigned char)X)
91251883Speter#define ToLower(X)  (char)tolower((unsigned char)X)
92251883Speter
93251883Speter#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \
94251883Speter && !defined(__minux)
95251883Speter#include <sys/time.h>
96251883Speter#include <sys/resource.h>
97251883Speter
98251883Speter/* Saved resource information for the beginning of an operation */
99251883Speterstatic struct rusage sBegin;
100251883Speter
101251883Speter/*
102251883Speter** Begin timing an operation
103251883Speter*/
104251883Speterstatic void beginTimer(void){
105251883Speter  if( enableTimer ){
106251883Speter    getrusage(RUSAGE_SELF, &sBegin);
107251883Speter  }
108251883Speter}
109251883Speter
110251883Speter/* Return the difference of two time_structs in seconds */
111251883Speterstatic double timeDiff(struct timeval *pStart, struct timeval *pEnd){
112251883Speter  return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
113251883Speter         (double)(pEnd->tv_sec - pStart->tv_sec);
114251883Speter}
115251883Speter
116251883Speter/*
117251883Speter** Print the timing results.
118251883Speter*/
119251883Speterstatic void endTimer(void){
120251883Speter  if( enableTimer ){
121251883Speter    struct rusage sEnd;
122251883Speter    getrusage(RUSAGE_SELF, &sEnd);
123251883Speter    printf("CPU Time: user %f sys %f\n",
124251883Speter       timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
125251883Speter       timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
126251883Speter  }
127251883Speter}
128251883Speter
129251883Speter#define BEGIN_TIMER beginTimer()
130251883Speter#define END_TIMER endTimer()
131251883Speter#define HAS_TIMER 1
132251883Speter
133251883Speter#elif (defined(_WIN32) || defined(WIN32))
134251883Speter
135251883Speter#include <windows.h>
136251883Speter
137251883Speter/* Saved resource information for the beginning of an operation */
138251883Speterstatic HANDLE hProcess;
139251883Speterstatic FILETIME ftKernelBegin;
140251883Speterstatic FILETIME ftUserBegin;
141251883Spetertypedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
142251883Speterstatic GETPROCTIMES getProcessTimesAddr = NULL;
143251883Speter
144251883Speter/*
145251883Speter** Check to see if we have timer support.  Return 1 if necessary
146251883Speter** support found (or found previously).
147251883Speter*/
148251883Speterstatic int hasTimer(void){
149251883Speter  if( getProcessTimesAddr ){
150251883Speter    return 1;
151251883Speter  } else {
152251883Speter    /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions.
153251883Speter    ** See if the version we are running on has it, and if it does, save off
154251883Speter    ** a pointer to it and the current process handle.
155251883Speter    */
156251883Speter    hProcess = GetCurrentProcess();
157251883Speter    if( hProcess ){
158251883Speter      HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
159251883Speter      if( NULL != hinstLib ){
160251883Speter        getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
161251883Speter        if( NULL != getProcessTimesAddr ){
162251883Speter          return 1;
163251883Speter        }
164251883Speter        FreeLibrary(hinstLib);
165251883Speter      }
166251883Speter    }
167251883Speter  }
168251883Speter  return 0;
169251883Speter}
170251883Speter
171251883Speter/*
172251883Speter** Begin timing an operation
173251883Speter*/
174251883Speterstatic void beginTimer(void){
175251883Speter  if( enableTimer && getProcessTimesAddr ){
176251883Speter    FILETIME ftCreation, ftExit;
177251883Speter    getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);
178251883Speter  }
179251883Speter}
180251883Speter
181251883Speter/* Return the difference of two FILETIME structs in seconds */
182251883Speterstatic double timeDiff(FILETIME *pStart, FILETIME *pEnd){
183251883Speter  sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
184251883Speter  sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
185251883Speter  return (double) ((i64End - i64Start) / 10000000.0);
186251883Speter}
187251883Speter
188251883Speter/*
189251883Speter** Print the timing results.
190251883Speter*/
191251883Speterstatic void endTimer(void){
192251883Speter  if( enableTimer && getProcessTimesAddr){
193251883Speter    FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
194251883Speter    getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
195251883Speter    printf("CPU Time: user %f sys %f\n",
196251883Speter       timeDiff(&ftUserBegin, &ftUserEnd),
197251883Speter       timeDiff(&ftKernelBegin, &ftKernelEnd));
198251883Speter  }
199251883Speter}
200251883Speter
201251883Speter#define BEGIN_TIMER beginTimer()
202251883Speter#define END_TIMER endTimer()
203251883Speter#define HAS_TIMER hasTimer()
204251883Speter
205251883Speter#else
206251883Speter#define BEGIN_TIMER
207251883Speter#define END_TIMER
208251883Speter#define HAS_TIMER 0
209251883Speter#endif
210251883Speter
211251883Speter/*
212251883Speter** Used to prevent warnings about unused parameters
213251883Speter*/
214251883Speter#define UNUSED_PARAMETER(x) (void)(x)
215251883Speter
216251883Speter/*
217251883Speter** If the following flag is set, then command execution stops
218251883Speter** at an error if we are not interactive.
219251883Speter*/
220251883Speterstatic int bail_on_error = 0;
221251883Speter
222251883Speter/*
223251883Speter** Threat stdin as an interactive input if the following variable
224251883Speter** is true.  Otherwise, assume stdin is connected to a file or pipe.
225251883Speter*/
226251883Speterstatic int stdin_is_interactive = 1;
227251883Speter
228251883Speter/*
229251883Speter** The following is the open SQLite database.  We make a pointer
230251883Speter** to this database a static variable so that it can be accessed
231251883Speter** by the SIGINT handler to interrupt database processing.
232251883Speter*/
233251883Speterstatic sqlite3 *db = 0;
234251883Speter
235251883Speter/*
236251883Speter** True if an interrupt (Control-C) has been received.
237251883Speter*/
238251883Speterstatic volatile int seenInterrupt = 0;
239251883Speter
240251883Speter/*
241251883Speter** This is the name of our program. It is set in main(), used
242251883Speter** in a number of other places, mostly for error messages.
243251883Speter*/
244251883Speterstatic char *Argv0;
245251883Speter
246251883Speter/*
247251883Speter** Prompt strings. Initialized in main. Settable with
248251883Speter**   .prompt main continue
249251883Speter*/
250251883Speterstatic char mainPrompt[20];     /* First line prompt. default: "sqlite> "*/
251251883Speterstatic char continuePrompt[20]; /* Continuation prompt. default: "   ...> " */
252251883Speter
253251883Speter/*
254251883Speter** Write I/O traces to the following stream.
255251883Speter*/
256251883Speter#ifdef SQLITE_ENABLE_IOTRACE
257251883Speterstatic FILE *iotrace = 0;
258251883Speter#endif
259251883Speter
260251883Speter/*
261251883Speter** This routine works like printf in that its first argument is a
262251883Speter** format string and subsequent arguments are values to be substituted
263251883Speter** in place of % fields.  The result of formatting this string
264251883Speter** is written to iotrace.
265251883Speter*/
266251883Speter#ifdef SQLITE_ENABLE_IOTRACE
267251883Speterstatic void iotracePrintf(const char *zFormat, ...){
268251883Speter  va_list ap;
269251883Speter  char *z;
270251883Speter  if( iotrace==0 ) return;
271251883Speter  va_start(ap, zFormat);
272251883Speter  z = sqlite3_vmprintf(zFormat, ap);
273251883Speter  va_end(ap);
274251883Speter  fprintf(iotrace, "%s", z);
275251883Speter  sqlite3_free(z);
276251883Speter}
277251883Speter#endif
278251883Speter
279251883Speter
280251883Speter/*
281251883Speter** Determines if a string is a number of not.
282251883Speter*/
283251883Speterstatic int isNumber(const char *z, int *realnum){
284251883Speter  if( *z=='-' || *z=='+' ) z++;
285251883Speter  if( !IsDigit(*z) ){
286251883Speter    return 0;
287251883Speter  }
288251883Speter  z++;
289251883Speter  if( realnum ) *realnum = 0;
290251883Speter  while( IsDigit(*z) ){ z++; }
291251883Speter  if( *z=='.' ){
292251883Speter    z++;
293251883Speter    if( !IsDigit(*z) ) return 0;
294251883Speter    while( IsDigit(*z) ){ z++; }
295251883Speter    if( realnum ) *realnum = 1;
296251883Speter  }
297251883Speter  if( *z=='e' || *z=='E' ){
298251883Speter    z++;
299251883Speter    if( *z=='+' || *z=='-' ) z++;
300251883Speter    if( !IsDigit(*z) ) return 0;
301251883Speter    while( IsDigit(*z) ){ z++; }
302251883Speter    if( realnum ) *realnum = 1;
303251883Speter  }
304251883Speter  return *z==0;
305251883Speter}
306251883Speter
307251883Speter/*
308251883Speter** A global char* and an SQL function to access its current value
309251883Speter** from within an SQL statement. This program used to use the
310251883Speter** sqlite_exec_printf() API to substitue a string into an SQL statement.
311251883Speter** The correct way to do this with sqlite3 is to use the bind API, but
312251883Speter** since the shell is built around the callback paradigm it would be a lot
313251883Speter** of work. Instead just use this hack, which is quite harmless.
314251883Speter*/
315251883Speterstatic const char *zShellStatic = 0;
316251883Speterstatic void shellstaticFunc(
317251883Speter  sqlite3_context *context,
318251883Speter  int argc,
319251883Speter  sqlite3_value **argv
320251883Speter){
321251883Speter  assert( 0==argc );
322251883Speter  assert( zShellStatic );
323251883Speter  UNUSED_PARAMETER(argc);
324251883Speter  UNUSED_PARAMETER(argv);
325251883Speter  sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
326251883Speter}
327251883Speter
328251883Speter
329251883Speter/*
330251883Speter** This routine reads a line of text from FILE in, stores
331251883Speter** the text in memory obtained from malloc() and returns a pointer
332251883Speter** to the text.  NULL is returned at end of file, or if malloc()
333251883Speter** fails.
334251883Speter**
335251883Speter** The interface is like "readline" but no command-line editing
336251883Speter** is done.
337251883Speter*/
338251883Speterstatic char *local_getline(char *zPrompt, FILE *in, int csvFlag){
339251883Speter  char *zLine;
340251883Speter  int nLine;
341251883Speter  int n;
342251883Speter  int inQuote = 0;
343251883Speter
344251883Speter  if( zPrompt && *zPrompt ){
345251883Speter    printf("%s",zPrompt);
346251883Speter    fflush(stdout);
347251883Speter  }
348251883Speter  nLine = 100;
349251883Speter  zLine = malloc( nLine );
350251883Speter  if( zLine==0 ) return 0;
351251883Speter  n = 0;
352251883Speter  while( 1 ){
353251883Speter    if( n+100>nLine ){
354251883Speter      nLine = nLine*2 + 100;
355251883Speter      zLine = realloc(zLine, nLine);
356251883Speter      if( zLine==0 ) return 0;
357251883Speter    }
358251883Speter    if( fgets(&zLine[n], nLine - n, in)==0 ){
359251883Speter      if( n==0 ){
360251883Speter        free(zLine);
361251883Speter        return 0;
362251883Speter      }
363251883Speter      zLine[n] = 0;
364251883Speter      break;
365251883Speter    }
366251883Speter    while( zLine[n] ){
367251883Speter      if( zLine[n]=='"' ) inQuote = !inQuote;
368251883Speter      n++;
369251883Speter    }
370251883Speter    if( n>0 && zLine[n-1]=='\n' && (!inQuote || !csvFlag) ){
371251883Speter      n--;
372251883Speter      if( n>0 && zLine[n-1]=='\r' ) n--;
373251883Speter      zLine[n] = 0;
374251883Speter      break;
375251883Speter    }
376251883Speter  }
377251883Speter  zLine = realloc( zLine, n+1 );
378251883Speter  return zLine;
379251883Speter}
380251883Speter
381251883Speter/*
382251883Speter** Retrieve a single line of input text.
383251883Speter**
384251883Speter** zPrior is a string of prior text retrieved.  If not the empty
385251883Speter** string, then issue a continuation prompt.
386251883Speter*/
387251883Speterstatic char *one_input_line(const char *zPrior, FILE *in){
388251883Speter  char *zPrompt;
389251883Speter  char *zResult;
390251883Speter  if( in!=0 ){
391251883Speter    return local_getline(0, in, 0);
392251883Speter  }
393251883Speter  if( zPrior && zPrior[0] ){
394251883Speter    zPrompt = continuePrompt;
395251883Speter  }else{
396251883Speter    zPrompt = mainPrompt;
397251883Speter  }
398251883Speter  zResult = readline(zPrompt);
399251883Speter#if defined(HAVE_READLINE) && HAVE_READLINE==1
400251883Speter  if( zResult && *zResult ) add_history(zResult);
401251883Speter#endif
402251883Speter  return zResult;
403251883Speter}
404251883Speter
405251883Speterstruct previous_mode_data {
406251883Speter  int valid;        /* Is there legit data in here? */
407251883Speter  int mode;
408251883Speter  int showHeader;
409251883Speter  int colWidth[100];
410251883Speter};
411251883Speter
412251883Speter/*
413251883Speter** An pointer to an instance of this structure is passed from
414251883Speter** the main program to the callback.  This is used to communicate
415251883Speter** state and mode information.
416251883Speter*/
417251883Speterstruct callback_data {
418251883Speter  sqlite3 *db;           /* The database */
419251883Speter  int echoOn;            /* True to echo input commands */
420251883Speter  int statsOn;           /* True to display memory stats before each finalize */
421251883Speter  int cnt;               /* Number of records displayed so far */
422251883Speter  FILE *out;             /* Write results here */
423251883Speter  FILE *traceOut;        /* Output for sqlite3_trace() */
424251883Speter  int nErr;              /* Number of errors seen */
425251883Speter  int mode;              /* An output mode setting */
426251883Speter  int writableSchema;    /* True if PRAGMA writable_schema=ON */
427251883Speter  int showHeader;        /* True to show column names in List or Column mode */
428251883Speter  char *zDestTable;      /* Name of destination table when MODE_Insert */
429251883Speter  char separator[20];    /* Separator character for MODE_List */
430251883Speter  int colWidth[100];     /* Requested width of each column when in column mode*/
431251883Speter  int actualWidth[100];  /* Actual width of each column */
432251883Speter  char nullvalue[20];    /* The text to print when a NULL comes back from
433251883Speter                         ** the database */
434251883Speter  struct previous_mode_data explainPrev;
435251883Speter                         /* Holds the mode information just before
436251883Speter                         ** .explain ON */
437251883Speter  char outfile[FILENAME_MAX]; /* Filename for *out */
438251883Speter  const char *zDbFilename;    /* name of the database file */
439251883Speter  const char *zVfs;           /* Name of VFS to use */
440251883Speter  sqlite3_stmt *pStmt;   /* Current statement if any. */
441251883Speter  FILE *pLog;            /* Write log output here */
442251883Speter};
443251883Speter
444251883Speter/*
445251883Speter** These are the allowed modes.
446251883Speter*/
447251883Speter#define MODE_Line     0  /* One column per line.  Blank line between records */
448251883Speter#define MODE_Column   1  /* One record per line in neat columns */
449251883Speter#define MODE_List     2  /* One record per line with a separator */
450251883Speter#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
451251883Speter#define MODE_Html     4  /* Generate an XHTML table */
452251883Speter#define MODE_Insert   5  /* Generate SQL "insert" statements */
453251883Speter#define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
454251883Speter#define MODE_Csv      7  /* Quote strings, numbers are plain */
455251883Speter#define MODE_Explain  8  /* Like MODE_Column, but do not truncate data */
456251883Speter
457251883Speterstatic const char *modeDescr[] = {
458251883Speter  "line",
459251883Speter  "column",
460251883Speter  "list",
461251883Speter  "semi",
462251883Speter  "html",
463251883Speter  "insert",
464251883Speter  "tcl",
465251883Speter  "csv",
466251883Speter  "explain",
467251883Speter};
468251883Speter
469251883Speter/*
470251883Speter** Number of elements in an array
471251883Speter*/
472251883Speter#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))
473251883Speter
474251883Speter/*
475251883Speter** Compute a string length that is limited to what can be stored in
476251883Speter** lower 30 bits of a 32-bit signed integer.
477251883Speter*/
478251883Speterstatic int strlen30(const char *z){
479251883Speter  const char *z2 = z;
480251883Speter  while( *z2 ){ z2++; }
481251883Speter  return 0x3fffffff & (int)(z2 - z);
482251883Speter}
483251883Speter
484251883Speter/*
485251883Speter** A callback for the sqlite3_log() interface.
486251883Speter*/
487251883Speterstatic void shellLog(void *pArg, int iErrCode, const char *zMsg){
488251883Speter  struct callback_data *p = (struct callback_data*)pArg;
489251883Speter  if( p->pLog==0 ) return;
490251883Speter  fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
491251883Speter  fflush(p->pLog);
492251883Speter}
493251883Speter
494251883Speter/*
495251883Speter** Output the given string as a hex-encoded blob (eg. X'1234' )
496251883Speter*/
497251883Speterstatic void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
498251883Speter  int i;
499251883Speter  char *zBlob = (char *)pBlob;
500251883Speter  fprintf(out,"X'");
501251883Speter  for(i=0; i<nBlob; i++){ fprintf(out,"%02x",zBlob[i]&0xff); }
502251883Speter  fprintf(out,"'");
503251883Speter}
504251883Speter
505251883Speter/*
506251883Speter** Output the given string as a quoted string using SQL quoting conventions.
507251883Speter*/
508251883Speterstatic void output_quoted_string(FILE *out, const char *z){
509251883Speter  int i;
510251883Speter  int nSingle = 0;
511251883Speter  for(i=0; z[i]; i++){
512251883Speter    if( z[i]=='\'' ) nSingle++;
513251883Speter  }
514251883Speter  if( nSingle==0 ){
515251883Speter    fprintf(out,"'%s'",z);
516251883Speter  }else{
517251883Speter    fprintf(out,"'");
518251883Speter    while( *z ){
519251883Speter      for(i=0; z[i] && z[i]!='\''; i++){}
520251883Speter      if( i==0 ){
521251883Speter        fprintf(out,"''");
522251883Speter        z++;
523251883Speter      }else if( z[i]=='\'' ){
524251883Speter        fprintf(out,"%.*s''",i,z);
525251883Speter        z += i+1;
526251883Speter      }else{
527251883Speter        fprintf(out,"%s",z);
528251883Speter        break;
529251883Speter      }
530251883Speter    }
531251883Speter    fprintf(out,"'");
532251883Speter  }
533251883Speter}
534251883Speter
535251883Speter/*
536251883Speter** Output the given string as a quoted according to C or TCL quoting rules.
537251883Speter*/
538251883Speterstatic void output_c_string(FILE *out, const char *z){
539251883Speter  unsigned int c;
540251883Speter  fputc('"', out);
541251883Speter  while( (c = *(z++))!=0 ){
542251883Speter    if( c=='\\' ){
543251883Speter      fputc(c, out);
544251883Speter      fputc(c, out);
545251883Speter    }else if( c=='"' ){
546251883Speter      fputc('\\', out);
547251883Speter      fputc('"', out);
548251883Speter    }else if( c=='\t' ){
549251883Speter      fputc('\\', out);
550251883Speter      fputc('t', out);
551251883Speter    }else if( c=='\n' ){
552251883Speter      fputc('\\', out);
553251883Speter      fputc('n', out);
554251883Speter    }else if( c=='\r' ){
555251883Speter      fputc('\\', out);
556251883Speter      fputc('r', out);
557251883Speter    }else if( !isprint(c) ){
558251883Speter      fprintf(out, "\\%03o", c&0xff);
559251883Speter    }else{
560251883Speter      fputc(c, out);
561251883Speter    }
562251883Speter  }
563251883Speter  fputc('"', out);
564251883Speter}
565251883Speter
566251883Speter/*
567251883Speter** Output the given string with characters that are special to
568251883Speter** HTML escaped.
569251883Speter*/
570251883Speterstatic void output_html_string(FILE *out, const char *z){
571251883Speter  int i;
572251883Speter  while( *z ){
573251883Speter    for(i=0;   z[i]
574251883Speter            && z[i]!='<'
575251883Speter            && z[i]!='&'
576251883Speter            && z[i]!='>'
577251883Speter            && z[i]!='\"'
578251883Speter            && z[i]!='\'';
579251883Speter        i++){}
580251883Speter    if( i>0 ){
581251883Speter      fprintf(out,"%.*s",i,z);
582251883Speter    }
583251883Speter    if( z[i]=='<' ){
584251883Speter      fprintf(out,"&lt;");
585251883Speter    }else if( z[i]=='&' ){
586251883Speter      fprintf(out,"&amp;");
587251883Speter    }else if( z[i]=='>' ){
588251883Speter      fprintf(out,"&gt;");
589251883Speter    }else if( z[i]=='\"' ){
590251883Speter      fprintf(out,"&quot;");
591251883Speter    }else if( z[i]=='\'' ){
592251883Speter      fprintf(out,"&#39;");
593251883Speter    }else{
594251883Speter      break;
595251883Speter    }
596251883Speter    z += i + 1;
597251883Speter  }
598251883Speter}
599251883Speter
600251883Speter/*
601251883Speter** If a field contains any character identified by a 1 in the following
602251883Speter** array, then the string must be quoted for CSV.
603251883Speter*/
604251883Speterstatic const char needCsvQuote[] = {
605251883Speter  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
606251883Speter  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
607251883Speter  1, 0, 1, 0, 0, 0, 0, 1,   0, 0, 0, 0, 0, 0, 0, 0,
608251883Speter  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
609251883Speter  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
610251883Speter  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
611251883Speter  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
612251883Speter  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 1,
613251883Speter  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
614251883Speter  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
615251883Speter  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
616251883Speter  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
617251883Speter  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
618251883Speter  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
619251883Speter  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
620251883Speter  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
621251883Speter};
622251883Speter
623251883Speter/*
624251883Speter** Output a single term of CSV.  Actually, p->separator is used for
625251883Speter** the separator, which may or may not be a comma.  p->nullvalue is
626251883Speter** the null value.  Strings are quoted if necessary.
627251883Speter*/
628251883Speterstatic void output_csv(struct callback_data *p, const char *z, int bSep){
629251883Speter  FILE *out = p->out;
630251883Speter  if( z==0 ){
631251883Speter    fprintf(out,"%s",p->nullvalue);
632251883Speter  }else{
633251883Speter    int i;
634251883Speter    int nSep = strlen30(p->separator);
635251883Speter    for(i=0; z[i]; i++){
636251883Speter      if( needCsvQuote[((unsigned char*)z)[i]]
637251883Speter         || (z[i]==p->separator[0] &&
638251883Speter             (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
639251883Speter        i = 0;
640251883Speter        break;
641251883Speter      }
642251883Speter    }
643251883Speter    if( i==0 ){
644251883Speter      putc('"', out);
645251883Speter      for(i=0; z[i]; i++){
646251883Speter        if( z[i]=='"' ) putc('"', out);
647251883Speter        putc(z[i], out);
648251883Speter      }
649251883Speter      putc('"', out);
650251883Speter    }else{
651251883Speter      fprintf(out, "%s", z);
652251883Speter    }
653251883Speter  }
654251883Speter  if( bSep ){
655251883Speter    fprintf(p->out, "%s", p->separator);
656251883Speter  }
657251883Speter}
658251883Speter
659251883Speter#ifdef SIGINT
660251883Speter/*
661251883Speter** This routine runs when the user presses Ctrl-C
662251883Speter*/
663251883Speterstatic void interrupt_handler(int NotUsed){
664251883Speter  UNUSED_PARAMETER(NotUsed);
665251883Speter  seenInterrupt = 1;
666251883Speter  if( db ) sqlite3_interrupt(db);
667251883Speter}
668251883Speter#endif
669251883Speter
670251883Speter/*
671251883Speter** This is the callback routine that the shell
672251883Speter** invokes for each row of a query result.
673251883Speter*/
674251883Speterstatic int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){
675251883Speter  int i;
676251883Speter  struct callback_data *p = (struct callback_data*)pArg;
677251883Speter
678251883Speter  switch( p->mode ){
679251883Speter    case MODE_Line: {
680251883Speter      int w = 5;
681251883Speter      if( azArg==0 ) break;
682251883Speter      for(i=0; i<nArg; i++){
683251883Speter        int len = strlen30(azCol[i] ? azCol[i] : "");
684251883Speter        if( len>w ) w = len;
685251883Speter      }
686251883Speter      if( p->cnt++>0 ) fprintf(p->out,"\n");
687251883Speter      for(i=0; i<nArg; i++){
688251883Speter        fprintf(p->out,"%*s = %s\n", w, azCol[i],
689251883Speter                azArg[i] ? azArg[i] : p->nullvalue);
690251883Speter      }
691251883Speter      break;
692251883Speter    }
693251883Speter    case MODE_Explain:
694251883Speter    case MODE_Column: {
695251883Speter      if( p->cnt++==0 ){
696251883Speter        for(i=0; i<nArg; i++){
697251883Speter          int w, n;
698251883Speter          if( i<ArraySize(p->colWidth) ){
699251883Speter            w = p->colWidth[i];
700251883Speter          }else{
701251883Speter            w = 0;
702251883Speter          }
703251883Speter          if( w==0 ){
704251883Speter            w = strlen30(azCol[i] ? azCol[i] : "");
705251883Speter            if( w<10 ) w = 10;
706251883Speter            n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue);
707251883Speter            if( w<n ) w = n;
708251883Speter          }
709251883Speter          if( i<ArraySize(p->actualWidth) ){
710251883Speter            p->actualWidth[i] = w;
711251883Speter          }
712251883Speter          if( p->showHeader ){
713251883Speter            if( w<0 ){
714251883Speter              fprintf(p->out,"%*.*s%s",-w,-w,azCol[i], i==nArg-1 ? "\n": "  ");
715251883Speter            }else{
716251883Speter              fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": "  ");
717251883Speter            }
718251883Speter          }
719251883Speter        }
720251883Speter        if( p->showHeader ){
721251883Speter          for(i=0; i<nArg; i++){
722251883Speter            int w;
723251883Speter            if( i<ArraySize(p->actualWidth) ){
724251883Speter               w = p->actualWidth[i];
725251883Speter               if( w<0 ) w = -w;
726251883Speter            }else{
727251883Speter               w = 10;
728251883Speter            }
729251883Speter            fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
730251883Speter                   "----------------------------------------------------------",
731251883Speter                    i==nArg-1 ? "\n": "  ");
732251883Speter          }
733251883Speter        }
734251883Speter      }
735251883Speter      if( azArg==0 ) break;
736251883Speter      for(i=0; i<nArg; i++){
737251883Speter        int w;
738251883Speter        if( i<ArraySize(p->actualWidth) ){
739251883Speter           w = p->actualWidth[i];
740251883Speter        }else{
741251883Speter           w = 10;
742251883Speter        }
743251883Speter        if( p->mode==MODE_Explain && azArg[i] &&
744251883Speter           strlen30(azArg[i])>w ){
745251883Speter          w = strlen30(azArg[i]);
746251883Speter        }
747251883Speter        if( w<0 ){
748251883Speter          fprintf(p->out,"%*.*s%s",-w,-w,
749251883Speter              azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": "  ");
750251883Speter        }else{
751251883Speter          fprintf(p->out,"%-*.*s%s",w,w,
752251883Speter              azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": "  ");
753251883Speter        }
754251883Speter      }
755251883Speter      break;
756251883Speter    }
757251883Speter    case MODE_Semi:
758251883Speter    case MODE_List: {
759251883Speter      if( p->cnt++==0 && p->showHeader ){
760251883Speter        for(i=0; i<nArg; i++){
761251883Speter          fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
762251883Speter        }
763251883Speter      }
764251883Speter      if( azArg==0 ) break;
765251883Speter      for(i=0; i<nArg; i++){
766251883Speter        char *z = azArg[i];
767251883Speter        if( z==0 ) z = p->nullvalue;
768251883Speter        fprintf(p->out, "%s", z);
769251883Speter        if( i<nArg-1 ){
770251883Speter          fprintf(p->out, "%s", p->separator);
771251883Speter        }else if( p->mode==MODE_Semi ){
772251883Speter          fprintf(p->out, ";\n");
773251883Speter        }else{
774251883Speter          fprintf(p->out, "\n");
775251883Speter        }
776251883Speter      }
777251883Speter      break;
778251883Speter    }
779251883Speter    case MODE_Html: {
780251883Speter      if( p->cnt++==0 && p->showHeader ){
781251883Speter        fprintf(p->out,"<TR>");
782251883Speter        for(i=0; i<nArg; i++){
783251883Speter          fprintf(p->out,"<TH>");
784251883Speter          output_html_string(p->out, azCol[i]);
785251883Speter          fprintf(p->out,"</TH>\n");
786251883Speter        }
787251883Speter        fprintf(p->out,"</TR>\n");
788251883Speter      }
789251883Speter      if( azArg==0 ) break;
790251883Speter      fprintf(p->out,"<TR>");
791251883Speter      for(i=0; i<nArg; i++){
792251883Speter        fprintf(p->out,"<TD>");
793251883Speter        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
794251883Speter        fprintf(p->out,"</TD>\n");
795251883Speter      }
796251883Speter      fprintf(p->out,"</TR>\n");
797251883Speter      break;
798251883Speter    }
799251883Speter    case MODE_Tcl: {
800251883Speter      if( p->cnt++==0 && p->showHeader ){
801251883Speter        for(i=0; i<nArg; i++){
802251883Speter          output_c_string(p->out,azCol[i] ? azCol[i] : "");
803251883Speter          if(i<nArg-1) fprintf(p->out, "%s", p->separator);
804251883Speter        }
805251883Speter        fprintf(p->out,"\n");
806251883Speter      }
807251883Speter      if( azArg==0 ) break;
808251883Speter      for(i=0; i<nArg; i++){
809251883Speter        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
810251883Speter        if(i<nArg-1) fprintf(p->out, "%s", p->separator);
811251883Speter      }
812251883Speter      fprintf(p->out,"\n");
813251883Speter      break;
814251883Speter    }
815251883Speter    case MODE_Csv: {
816251883Speter      if( p->cnt++==0 && p->showHeader ){
817251883Speter        for(i=0; i<nArg; i++){
818251883Speter          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
819251883Speter        }
820251883Speter        fprintf(p->out,"\n");
821251883Speter      }
822251883Speter      if( azArg==0 ) break;
823251883Speter      for(i=0; i<nArg; i++){
824251883Speter        output_csv(p, azArg[i], i<nArg-1);
825251883Speter      }
826251883Speter      fprintf(p->out,"\n");
827251883Speter      break;
828251883Speter    }
829251883Speter    case MODE_Insert: {
830251883Speter      p->cnt++;
831251883Speter      if( azArg==0 ) break;
832251883Speter      fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
833251883Speter      for(i=0; i<nArg; i++){
834251883Speter        char *zSep = i>0 ? ",": "";
835251883Speter        if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
836251883Speter          fprintf(p->out,"%sNULL",zSep);
837251883Speter        }else if( aiType && aiType[i]==SQLITE_TEXT ){
838251883Speter          if( zSep[0] ) fprintf(p->out,"%s",zSep);
839251883Speter          output_quoted_string(p->out, azArg[i]);
840251883Speter        }else if( aiType && (aiType[i]==SQLITE_INTEGER || aiType[i]==SQLITE_FLOAT) ){
841251883Speter          fprintf(p->out,"%s%s",zSep, azArg[i]);
842251883Speter        }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
843251883Speter          const void *pBlob = sqlite3_column_blob(p->pStmt, i);
844251883Speter          int nBlob = sqlite3_column_bytes(p->pStmt, i);
845251883Speter          if( zSep[0] ) fprintf(p->out,"%s",zSep);
846251883Speter          output_hex_blob(p->out, pBlob, nBlob);
847251883Speter        }else if( isNumber(azArg[i], 0) ){
848251883Speter          fprintf(p->out,"%s%s",zSep, azArg[i]);
849251883Speter        }else{
850251883Speter          if( zSep[0] ) fprintf(p->out,"%s",zSep);
851251883Speter          output_quoted_string(p->out, azArg[i]);
852251883Speter        }
853251883Speter      }
854251883Speter      fprintf(p->out,");\n");
855251883Speter      break;
856251883Speter    }
857251883Speter  }
858251883Speter  return 0;
859251883Speter}
860251883Speter
861251883Speter/*
862251883Speter** This is the callback routine that the SQLite library
863251883Speter** invokes for each row of a query result.
864251883Speter*/
865251883Speterstatic int callback(void *pArg, int nArg, char **azArg, char **azCol){
866251883Speter  /* since we don't have type info, call the shell_callback with a NULL value */
867251883Speter  return shell_callback(pArg, nArg, azArg, azCol, NULL);
868251883Speter}
869251883Speter
870251883Speter/*
871251883Speter** Set the destination table field of the callback_data structure to
872251883Speter** the name of the table given.  Escape any quote characters in the
873251883Speter** table name.
874251883Speter*/
875251883Speterstatic void set_table_name(struct callback_data *p, const char *zName){
876251883Speter  int i, n;
877251883Speter  int needQuote;
878251883Speter  char *z;
879251883Speter
880251883Speter  if( p->zDestTable ){
881251883Speter    free(p->zDestTable);
882251883Speter    p->zDestTable = 0;
883251883Speter  }
884251883Speter  if( zName==0 ) return;
885251883Speter  needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
886251883Speter  for(i=n=0; zName[i]; i++, n++){
887251883Speter    if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
888251883Speter      needQuote = 1;
889251883Speter      if( zName[i]=='\'' ) n++;
890251883Speter    }
891251883Speter  }
892251883Speter  if( needQuote ) n += 2;
893251883Speter  z = p->zDestTable = malloc( n+1 );
894251883Speter  if( z==0 ){
895251883Speter    fprintf(stderr,"Error: out of memory\n");
896251883Speter    exit(1);
897251883Speter  }
898251883Speter  n = 0;
899251883Speter  if( needQuote ) z[n++] = '\'';
900251883Speter  for(i=0; zName[i]; i++){
901251883Speter    z[n++] = zName[i];
902251883Speter    if( zName[i]=='\'' ) z[n++] = '\'';
903251883Speter  }
904251883Speter  if( needQuote ) z[n++] = '\'';
905251883Speter  z[n] = 0;
906251883Speter}
907251883Speter
908251883Speter/* zIn is either a pointer to a NULL-terminated string in memory obtained
909251883Speter** from malloc(), or a NULL pointer. The string pointed to by zAppend is
910251883Speter** added to zIn, and the result returned in memory obtained from malloc().
911251883Speter** zIn, if it was not NULL, is freed.
912251883Speter**
913251883Speter** If the third argument, quote, is not '\0', then it is used as a
914251883Speter** quote character for zAppend.
915251883Speter*/
916251883Speterstatic char *appendText(char *zIn, char const *zAppend, char quote){
917251883Speter  int len;
918251883Speter  int i;
919251883Speter  int nAppend = strlen30(zAppend);
920251883Speter  int nIn = (zIn?strlen30(zIn):0);
921251883Speter
922251883Speter  len = nAppend+nIn+1;
923251883Speter  if( quote ){
924251883Speter    len += 2;
925251883Speter    for(i=0; i<nAppend; i++){
926251883Speter      if( zAppend[i]==quote ) len++;
927251883Speter    }
928251883Speter  }
929251883Speter
930251883Speter  zIn = (char *)realloc(zIn, len);
931251883Speter  if( !zIn ){
932251883Speter    return 0;
933251883Speter  }
934251883Speter
935251883Speter  if( quote ){
936251883Speter    char *zCsr = &zIn[nIn];
937251883Speter    *zCsr++ = quote;
938251883Speter    for(i=0; i<nAppend; i++){
939251883Speter      *zCsr++ = zAppend[i];
940251883Speter      if( zAppend[i]==quote ) *zCsr++ = quote;
941251883Speter    }
942251883Speter    *zCsr++ = quote;
943251883Speter    *zCsr++ = '\0';
944251883Speter    assert( (zCsr-zIn)==len );
945251883Speter  }else{
946251883Speter    memcpy(&zIn[nIn], zAppend, nAppend);
947251883Speter    zIn[len-1] = '\0';
948251883Speter  }
949251883Speter
950251883Speter  return zIn;
951251883Speter}
952251883Speter
953251883Speter
954251883Speter/*
955251883Speter** Execute a query statement that will generate SQL output.  Print
956251883Speter** the result columns, comma-separated, on a line and then add a
957251883Speter** semicolon terminator to the end of that line.
958251883Speter**
959251883Speter** If the number of columns is 1 and that column contains text "--"
960251883Speter** then write the semicolon on a separate line.  That way, if a
961251883Speter** "--" comment occurs at the end of the statement, the comment
962251883Speter** won't consume the semicolon terminator.
963251883Speter*/
964251883Speterstatic int run_table_dump_query(
965251883Speter  struct callback_data *p, /* Query context */
966251883Speter  const char *zSelect,     /* SELECT statement to extract content */
967251883Speter  const char *zFirstRow    /* Print before first row, if not NULL */
968251883Speter){
969251883Speter  sqlite3_stmt *pSelect;
970251883Speter  int rc;
971251883Speter  int nResult;
972251883Speter  int i;
973251883Speter  const char *z;
974251883Speter  rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
975251883Speter  if( rc!=SQLITE_OK || !pSelect ){
976251883Speter    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
977251883Speter    p->nErr++;
978251883Speter    return rc;
979251883Speter  }
980251883Speter  rc = sqlite3_step(pSelect);
981251883Speter  nResult = sqlite3_column_count(pSelect);
982251883Speter  while( rc==SQLITE_ROW ){
983251883Speter    if( zFirstRow ){
984251883Speter      fprintf(p->out, "%s", zFirstRow);
985251883Speter      zFirstRow = 0;
986251883Speter    }
987251883Speter    z = (const char*)sqlite3_column_text(pSelect, 0);
988251883Speter    fprintf(p->out, "%s", z);
989251883Speter    for(i=1; i<nResult; i++){
990251883Speter      fprintf(p->out, ",%s", sqlite3_column_text(pSelect, i));
991251883Speter    }
992251883Speter    if( z==0 ) z = "";
993251883Speter    while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
994251883Speter    if( z[0] ){
995251883Speter      fprintf(p->out, "\n;\n");
996251883Speter    }else{
997251883Speter      fprintf(p->out, ";\n");
998251883Speter    }
999251883Speter    rc = sqlite3_step(pSelect);
1000251883Speter  }
1001251883Speter  rc = sqlite3_finalize(pSelect);
1002251883Speter  if( rc!=SQLITE_OK ){
1003251883Speter    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
1004251883Speter    p->nErr++;
1005251883Speter  }
1006251883Speter  return rc;
1007251883Speter}
1008251883Speter
1009251883Speter/*
1010251883Speter** Allocate space and save off current error string.
1011251883Speter*/
1012251883Speterstatic char *save_err_msg(
1013251883Speter  sqlite3 *db            /* Database to query */
1014251883Speter){
1015251883Speter  int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
1016251883Speter  char *zErrMsg = sqlite3_malloc(nErrMsg);
1017251883Speter  if( zErrMsg ){
1018251883Speter    memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
1019251883Speter  }
1020251883Speter  return zErrMsg;
1021251883Speter}
1022251883Speter
1023251883Speter/*
1024251883Speter** Display memory stats.
1025251883Speter*/
1026251883Speterstatic int display_stats(
1027251883Speter  sqlite3 *db,                /* Database to query */
1028251883Speter  struct callback_data *pArg, /* Pointer to struct callback_data */
1029251883Speter  int bReset                  /* True to reset the stats */
1030251883Speter){
1031251883Speter  int iCur;
1032251883Speter  int iHiwtr;
1033251883Speter
1034251883Speter  if( pArg && pArg->out ){
1035251883Speter
1036251883Speter    iHiwtr = iCur = -1;
1037251883Speter    sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
1038251883Speter    fprintf(pArg->out, "Memory Used:                         %d (max %d) bytes\n", iCur, iHiwtr);
1039251883Speter    iHiwtr = iCur = -1;
1040251883Speter    sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
1041251883Speter    fprintf(pArg->out, "Number of Outstanding Allocations:   %d (max %d)\n", iCur, iHiwtr);
1042251883Speter/*
1043251883Speter** Not currently used by the CLI.
1044251883Speter**    iHiwtr = iCur = -1;
1045251883Speter**    sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
1046251883Speter**    fprintf(pArg->out, "Number of Pcache Pages Used:         %d (max %d) pages\n", iCur, iHiwtr);
1047251883Speter*/
1048251883Speter    iHiwtr = iCur = -1;
1049251883Speter    sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
1050251883Speter    fprintf(pArg->out, "Number of Pcache Overflow Bytes:     %d (max %d) bytes\n", iCur, iHiwtr);
1051251883Speter/*
1052251883Speter** Not currently used by the CLI.
1053251883Speter**    iHiwtr = iCur = -1;
1054251883Speter**    sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
1055251883Speter**    fprintf(pArg->out, "Number of Scratch Allocations Used:  %d (max %d)\n", iCur, iHiwtr);
1056251883Speter*/
1057251883Speter    iHiwtr = iCur = -1;
1058251883Speter    sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
1059251883Speter    fprintf(pArg->out, "Number of Scratch Overflow Bytes:    %d (max %d) bytes\n", iCur, iHiwtr);
1060251883Speter    iHiwtr = iCur = -1;
1061251883Speter    sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
1062251883Speter    fprintf(pArg->out, "Largest Allocation:                  %d bytes\n", iHiwtr);
1063251883Speter    iHiwtr = iCur = -1;
1064251883Speter    sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
1065251883Speter    fprintf(pArg->out, "Largest Pcache Allocation:           %d bytes\n", iHiwtr);
1066251883Speter    iHiwtr = iCur = -1;
1067251883Speter    sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
1068251883Speter    fprintf(pArg->out, "Largest Scratch Allocation:          %d bytes\n", iHiwtr);
1069251883Speter#ifdef YYTRACKMAXSTACKDEPTH
1070251883Speter    iHiwtr = iCur = -1;
1071251883Speter    sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
1072251883Speter    fprintf(pArg->out, "Deepest Parser Stack:                %d (max %d)\n", iCur, iHiwtr);
1073251883Speter#endif
1074251883Speter  }
1075251883Speter
1076251883Speter  if( pArg && pArg->out && db ){
1077251883Speter    iHiwtr = iCur = -1;
1078251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset);
1079251883Speter    fprintf(pArg->out, "Lookaside Slots Used:                %d (max %d)\n", iCur, iHiwtr);
1080251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset);
1081251883Speter    fprintf(pArg->out, "Successful lookaside attempts:       %d\n", iHiwtr);
1082251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset);
1083251883Speter    fprintf(pArg->out, "Lookaside failures due to size:      %d\n", iHiwtr);
1084251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset);
1085251883Speter    fprintf(pArg->out, "Lookaside failures due to OOM:       %d\n", iHiwtr);
1086251883Speter    iHiwtr = iCur = -1;
1087251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
1088251883Speter    fprintf(pArg->out, "Pager Heap Usage:                    %d bytes\n", iCur);    iHiwtr = iCur = -1;
1089251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
1090251883Speter    fprintf(pArg->out, "Page cache hits:                     %d\n", iCur);
1091251883Speter    iHiwtr = iCur = -1;
1092251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
1093251883Speter    fprintf(pArg->out, "Page cache misses:                   %d\n", iCur);
1094251883Speter    iHiwtr = iCur = -1;
1095251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
1096251883Speter    fprintf(pArg->out, "Page cache writes:                   %d\n", iCur);
1097251883Speter    iHiwtr = iCur = -1;
1098251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
1099251883Speter    fprintf(pArg->out, "Schema Heap Usage:                   %d bytes\n", iCur);
1100251883Speter    iHiwtr = iCur = -1;
1101251883Speter    sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
1102251883Speter    fprintf(pArg->out, "Statement Heap/Lookaside Usage:      %d bytes\n", iCur);
1103251883Speter  }
1104251883Speter
1105251883Speter  if( pArg && pArg->out && db && pArg->pStmt ){
1106251883Speter    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset);
1107251883Speter    fprintf(pArg->out, "Fullscan Steps:                      %d\n", iCur);
1108251883Speter    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
1109251883Speter    fprintf(pArg->out, "Sort Operations:                     %d\n", iCur);
1110251883Speter    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset);
1111251883Speter    fprintf(pArg->out, "Autoindex Inserts:                   %d\n", iCur);
1112251883Speter  }
1113251883Speter
1114251883Speter  return 0;
1115251883Speter}
1116251883Speter
1117251883Speter/*
1118251883Speter** Execute a statement or set of statements.  Print
1119251883Speter** any result rows/columns depending on the current mode
1120251883Speter** set via the supplied callback.
1121251883Speter**
1122251883Speter** This is very similar to SQLite's built-in sqlite3_exec()
1123251883Speter** function except it takes a slightly different callback
1124251883Speter** and callback data argument.
1125251883Speter*/
1126251883Speterstatic int shell_exec(
1127251883Speter  sqlite3 *db,                                /* An open database */
1128251883Speter  const char *zSql,                           /* SQL to be evaluated */
1129251883Speter  int (*xCallback)(void*,int,char**,char**,int*),   /* Callback function */
1130251883Speter                                              /* (not the same as sqlite3_exec) */
1131251883Speter  struct callback_data *pArg,                 /* Pointer to struct callback_data */
1132251883Speter  char **pzErrMsg                             /* Error msg written here */
1133251883Speter){
1134251883Speter  sqlite3_stmt *pStmt = NULL;     /* Statement to execute. */
1135251883Speter  int rc = SQLITE_OK;             /* Return Code */
1136251883Speter  int rc2;
1137251883Speter  const char *zLeftover;          /* Tail of unprocessed SQL */
1138251883Speter
1139251883Speter  if( pzErrMsg ){
1140251883Speter    *pzErrMsg = NULL;
1141251883Speter  }
1142251883Speter
1143251883Speter  while( zSql[0] && (SQLITE_OK == rc) ){
1144251883Speter    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
1145251883Speter    if( SQLITE_OK != rc ){
1146251883Speter      if( pzErrMsg ){
1147251883Speter        *pzErrMsg = save_err_msg(db);
1148251883Speter      }
1149251883Speter    }else{
1150251883Speter      if( !pStmt ){
1151251883Speter        /* this happens for a comment or white-space */
1152251883Speter        zSql = zLeftover;
1153251883Speter        while( IsSpace(zSql[0]) ) zSql++;
1154251883Speter        continue;
1155251883Speter      }
1156251883Speter
1157251883Speter      /* save off the prepared statment handle and reset row count */
1158251883Speter      if( pArg ){
1159251883Speter        pArg->pStmt = pStmt;
1160251883Speter        pArg->cnt = 0;
1161251883Speter      }
1162251883Speter
1163251883Speter      /* echo the sql statement if echo on */
1164251883Speter      if( pArg && pArg->echoOn ){
1165251883Speter        const char *zStmtSql = sqlite3_sql(pStmt);
1166251883Speter        fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
1167251883Speter      }
1168251883Speter
1169251883Speter      /* Output TESTCTRL_EXPLAIN text of requested */
1170251883Speter      if( pArg && pArg->mode==MODE_Explain ){
1171251883Speter        const char *zExplain = 0;
1172251883Speter        sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain);
1173251883Speter        if( zExplain && zExplain[0] ){
1174251883Speter          fprintf(pArg->out, "%s", zExplain);
1175251883Speter        }
1176251883Speter      }
1177251883Speter
1178251883Speter      /* perform the first step.  this will tell us if we
1179251883Speter      ** have a result set or not and how wide it is.
1180251883Speter      */
1181251883Speter      rc = sqlite3_step(pStmt);
1182251883Speter      /* if we have a result set... */
1183251883Speter      if( SQLITE_ROW == rc ){
1184251883Speter        /* if we have a callback... */
1185251883Speter        if( xCallback ){
1186251883Speter          /* allocate space for col name ptr, value ptr, and type */
1187251883Speter          int nCol = sqlite3_column_count(pStmt);
1188251883Speter          void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1);
1189251883Speter          if( !pData ){
1190251883Speter            rc = SQLITE_NOMEM;
1191251883Speter          }else{
1192251883Speter            char **azCols = (char **)pData;      /* Names of result columns */
1193251883Speter            char **azVals = &azCols[nCol];       /* Results */
1194251883Speter            int *aiTypes = (int *)&azVals[nCol]; /* Result types */
1195251883Speter            int i;
1196251883Speter            assert(sizeof(int) <= sizeof(char *));
1197251883Speter            /* save off ptrs to column names */
1198251883Speter            for(i=0; i<nCol; i++){
1199251883Speter              azCols[i] = (char *)sqlite3_column_name(pStmt, i);
1200251883Speter            }
1201251883Speter            do{
1202251883Speter              /* extract the data and data types */
1203251883Speter              for(i=0; i<nCol; i++){
1204251883Speter                azVals[i] = (char *)sqlite3_column_text(pStmt, i);
1205251883Speter                aiTypes[i] = sqlite3_column_type(pStmt, i);
1206251883Speter                if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
1207251883Speter                  rc = SQLITE_NOMEM;
1208251883Speter                  break; /* from for */
1209251883Speter                }
1210251883Speter              } /* end for */
1211251883Speter
1212251883Speter              /* if data and types extracted successfully... */
1213251883Speter              if( SQLITE_ROW == rc ){
1214251883Speter                /* call the supplied callback with the result row data */
1215251883Speter                if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
1216251883Speter                  rc = SQLITE_ABORT;
1217251883Speter                }else{
1218251883Speter                  rc = sqlite3_step(pStmt);
1219251883Speter                }
1220251883Speter              }
1221251883Speter            } while( SQLITE_ROW == rc );
1222251883Speter            sqlite3_free(pData);
1223251883Speter          }
1224251883Speter        }else{
1225251883Speter          do{
1226251883Speter            rc = sqlite3_step(pStmt);
1227251883Speter          } while( rc == SQLITE_ROW );
1228251883Speter        }
1229251883Speter      }
1230251883Speter
1231251883Speter      /* print usage stats if stats on */
1232251883Speter      if( pArg && pArg->statsOn ){
1233251883Speter        display_stats(db, pArg, 0);
1234251883Speter      }
1235251883Speter
1236251883Speter      /* Finalize the statement just executed. If this fails, save a
1237251883Speter      ** copy of the error message. Otherwise, set zSql to point to the
1238251883Speter      ** next statement to execute. */
1239251883Speter      rc2 = sqlite3_finalize(pStmt);
1240251883Speter      if( rc!=SQLITE_NOMEM ) rc = rc2;
1241251883Speter      if( rc==SQLITE_OK ){
1242251883Speter        zSql = zLeftover;
1243251883Speter        while( IsSpace(zSql[0]) ) zSql++;
1244251883Speter      }else if( pzErrMsg ){
1245251883Speter        *pzErrMsg = save_err_msg(db);
1246251883Speter      }
1247251883Speter
1248251883Speter      /* clear saved stmt handle */
1249251883Speter      if( pArg ){
1250251883Speter        pArg->pStmt = NULL;
1251251883Speter      }
1252251883Speter    }
1253251883Speter  } /* end while */
1254251883Speter
1255251883Speter  return rc;
1256251883Speter}
1257251883Speter
1258251883Speter
1259251883Speter/*
1260251883Speter** This is a different callback routine used for dumping the database.
1261251883Speter** Each row received by this callback consists of a table name,
1262251883Speter** the table type ("index" or "table") and SQL to create the table.
1263251883Speter** This routine should print text sufficient to recreate the table.
1264251883Speter*/
1265251883Speterstatic int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
1266251883Speter  int rc;
1267251883Speter  const char *zTable;
1268251883Speter  const char *zType;
1269251883Speter  const char *zSql;
1270251883Speter  const char *zPrepStmt = 0;
1271251883Speter  struct callback_data *p = (struct callback_data *)pArg;
1272251883Speter
1273251883Speter  UNUSED_PARAMETER(azCol);
1274251883Speter  if( nArg!=3 ) return 1;
1275251883Speter  zTable = azArg[0];
1276251883Speter  zType = azArg[1];
1277251883Speter  zSql = azArg[2];
1278251883Speter
1279251883Speter  if( strcmp(zTable, "sqlite_sequence")==0 ){
1280251883Speter    zPrepStmt = "DELETE FROM sqlite_sequence;\n";
1281251883Speter  }else if( strcmp(zTable, "sqlite_stat1")==0 ){
1282251883Speter    fprintf(p->out, "ANALYZE sqlite_master;\n");
1283251883Speter  }else if( strncmp(zTable, "sqlite_", 7)==0 ){
1284251883Speter    return 0;
1285251883Speter  }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
1286251883Speter    char *zIns;
1287251883Speter    if( !p->writableSchema ){
1288251883Speter      fprintf(p->out, "PRAGMA writable_schema=ON;\n");
1289251883Speter      p->writableSchema = 1;
1290251883Speter    }
1291251883Speter    zIns = sqlite3_mprintf(
1292251883Speter       "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
1293251883Speter       "VALUES('table','%q','%q',0,'%q');",
1294251883Speter       zTable, zTable, zSql);
1295251883Speter    fprintf(p->out, "%s\n", zIns);
1296251883Speter    sqlite3_free(zIns);
1297251883Speter    return 0;
1298251883Speter  }else{
1299251883Speter    fprintf(p->out, "%s;\n", zSql);
1300251883Speter  }
1301251883Speter
1302251883Speter  if( strcmp(zType, "table")==0 ){
1303251883Speter    sqlite3_stmt *pTableInfo = 0;
1304251883Speter    char *zSelect = 0;
1305251883Speter    char *zTableInfo = 0;
1306251883Speter    char *zTmp = 0;
1307251883Speter    int nRow = 0;
1308251883Speter
1309251883Speter    zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
1310251883Speter    zTableInfo = appendText(zTableInfo, zTable, '"');
1311251883Speter    zTableInfo = appendText(zTableInfo, ");", 0);
1312251883Speter
1313251883Speter    rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
1314251883Speter    free(zTableInfo);
1315251883Speter    if( rc!=SQLITE_OK || !pTableInfo ){
1316251883Speter      return 1;
1317251883Speter    }
1318251883Speter
1319251883Speter    zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
1320251883Speter    /* Always quote the table name, even if it appears to be pure ascii,
1321251883Speter    ** in case it is a keyword. Ex:  INSERT INTO "table" ... */
1322251883Speter    zTmp = appendText(zTmp, zTable, '"');
1323251883Speter    if( zTmp ){
1324251883Speter      zSelect = appendText(zSelect, zTmp, '\'');
1325251883Speter      free(zTmp);
1326251883Speter    }
1327251883Speter    zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
1328251883Speter    rc = sqlite3_step(pTableInfo);
1329251883Speter    while( rc==SQLITE_ROW ){
1330251883Speter      const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
1331251883Speter      zSelect = appendText(zSelect, "quote(", 0);
1332251883Speter      zSelect = appendText(zSelect, zText, '"');
1333251883Speter      rc = sqlite3_step(pTableInfo);
1334251883Speter      if( rc==SQLITE_ROW ){
1335251883Speter        zSelect = appendText(zSelect, "), ", 0);
1336251883Speter      }else{
1337251883Speter        zSelect = appendText(zSelect, ") ", 0);
1338251883Speter      }
1339251883Speter      nRow++;
1340251883Speter    }
1341251883Speter    rc = sqlite3_finalize(pTableInfo);
1342251883Speter    if( rc!=SQLITE_OK || nRow==0 ){
1343251883Speter      free(zSelect);
1344251883Speter      return 1;
1345251883Speter    }
1346251883Speter    zSelect = appendText(zSelect, "|| ')' FROM  ", 0);
1347251883Speter    zSelect = appendText(zSelect, zTable, '"');
1348251883Speter
1349251883Speter    rc = run_table_dump_query(p, zSelect, zPrepStmt);
1350251883Speter    if( rc==SQLITE_CORRUPT ){
1351251883Speter      zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
1352251883Speter      run_table_dump_query(p, zSelect, 0);
1353251883Speter    }
1354251883Speter    free(zSelect);
1355251883Speter  }
1356251883Speter  return 0;
1357251883Speter}
1358251883Speter
1359251883Speter/*
1360251883Speter** Run zQuery.  Use dump_callback() as the callback routine so that
1361251883Speter** the contents of the query are output as SQL statements.
1362251883Speter**
1363251883Speter** If we get a SQLITE_CORRUPT error, rerun the query after appending
1364251883Speter** "ORDER BY rowid DESC" to the end.
1365251883Speter*/
1366251883Speterstatic int run_schema_dump_query(
1367251883Speter  struct callback_data *p,
1368251883Speter  const char *zQuery
1369251883Speter){
1370251883Speter  int rc;
1371251883Speter  char *zErr = 0;
1372251883Speter  rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
1373251883Speter  if( rc==SQLITE_CORRUPT ){
1374251883Speter    char *zQ2;
1375251883Speter    int len = strlen30(zQuery);
1376251883Speter    fprintf(p->out, "/****** CORRUPTION ERROR *******/\n");
1377251883Speter    if( zErr ){
1378251883Speter      fprintf(p->out, "/****** %s ******/\n", zErr);
1379251883Speter      sqlite3_free(zErr);
1380251883Speter      zErr = 0;
1381251883Speter    }
1382251883Speter    zQ2 = malloc( len+100 );
1383251883Speter    if( zQ2==0 ) return rc;
1384251883Speter    sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
1385251883Speter    rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
1386251883Speter    if( rc ){
1387251883Speter      fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
1388251883Speter    }else{
1389251883Speter      rc = SQLITE_CORRUPT;
1390251883Speter    }
1391251883Speter    sqlite3_free(zErr);
1392251883Speter    free(zQ2);
1393251883Speter  }
1394251883Speter  return rc;
1395251883Speter}
1396251883Speter
1397251883Speter/*
1398251883Speter** Text of a help message
1399251883Speter*/
1400251883Speterstatic char zHelp[] =
1401251883Speter  ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
1402251883Speter  ".bail ON|OFF           Stop after hitting an error.  Default OFF\n"
1403251883Speter  ".databases             List names and files of attached databases\n"
1404251883Speter  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
1405251883Speter  "                         If TABLE specified, only dump tables matching\n"
1406251883Speter  "                         LIKE pattern TABLE.\n"
1407251883Speter  ".echo ON|OFF           Turn command echo on or off\n"
1408251883Speter  ".exit                  Exit this program\n"
1409251883Speter  ".explain ?ON|OFF?      Turn output mode suitable for EXPLAIN on or off.\n"
1410251883Speter  "                         With no args, it turns EXPLAIN on.\n"
1411251883Speter  ".header(s) ON|OFF      Turn display of headers on or off\n"
1412251883Speter  ".help                  Show this message\n"
1413251883Speter  ".import FILE TABLE     Import data from FILE into TABLE\n"
1414251883Speter  ".indices ?TABLE?       Show names of all indices\n"
1415251883Speter  "                         If TABLE specified, only show indices for tables\n"
1416251883Speter  "                         matching LIKE pattern TABLE.\n"
1417251883Speter#ifdef SQLITE_ENABLE_IOTRACE
1418251883Speter  ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
1419251883Speter#endif
1420251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION
1421251883Speter  ".load FILE ?ENTRY?     Load an extension library\n"
1422251883Speter#endif
1423251883Speter  ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"
1424251883Speter  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"
1425251883Speter  "                         csv      Comma-separated values\n"
1426251883Speter  "                         column   Left-aligned columns.  (See .width)\n"
1427251883Speter  "                         html     HTML <table> code\n"
1428251883Speter  "                         insert   SQL insert statements for TABLE\n"
1429251883Speter  "                         line     One value per line\n"
1430251883Speter  "                         list     Values delimited by .separator string\n"
1431251883Speter  "                         tabs     Tab-separated values\n"
1432251883Speter  "                         tcl      TCL list elements\n"
1433251883Speter  ".nullvalue STRING      Use STRING in place of NULL values\n"
1434251883Speter  ".output FILENAME       Send output to FILENAME\n"
1435251883Speter  ".output stdout         Send output to the screen\n"
1436251883Speter  ".print STRING...       Print literal STRING\n"
1437251883Speter  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
1438251883Speter  ".quit                  Exit this program\n"
1439251883Speter  ".read FILENAME         Execute SQL in FILENAME\n"
1440251883Speter  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
1441251883Speter  ".schema ?TABLE?        Show the CREATE statements\n"
1442251883Speter  "                         If TABLE specified, only show tables matching\n"
1443251883Speter  "                         LIKE pattern TABLE.\n"
1444251883Speter  ".separator STRING      Change separator used by output mode and .import\n"
1445251883Speter  ".show                  Show the current values for various settings\n"
1446251883Speter  ".stats ON|OFF          Turn stats on or off\n"
1447251883Speter  ".tables ?TABLE?        List names of tables\n"
1448251883Speter  "                         If TABLE specified, only list tables matching\n"
1449251883Speter  "                         LIKE pattern TABLE.\n"
1450251883Speter  ".timeout MS            Try opening locked tables for MS milliseconds\n"
1451251883Speter  ".trace FILE|off        Output each SQL statement as it is run\n"
1452251883Speter  ".vfsname ?AUX?         Print the name of the VFS stack\n"
1453251883Speter  ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
1454251883Speter;
1455251883Speter
1456251883Speterstatic char zTimerHelp[] =
1457251883Speter  ".timer ON|OFF          Turn the CPU timer measurement on or off\n"
1458251883Speter;
1459251883Speter
1460251883Speter/* Forward reference */
1461251883Speterstatic int process_input(struct callback_data *p, FILE *in);
1462251883Speter
1463251883Speter/*
1464251883Speter** Make sure the database is open.  If it is not, then open it.  If
1465251883Speter** the database fails to open, print an error message and exit.
1466251883Speter*/
1467251883Speterstatic void open_db(struct callback_data *p){
1468251883Speter  if( p->db==0 ){
1469251883Speter    sqlite3_initialize();
1470251883Speter    sqlite3_open(p->zDbFilename, &p->db);
1471251883Speter    db = p->db;
1472251883Speter    if( db && sqlite3_errcode(db)==SQLITE_OK ){
1473251883Speter      sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
1474251883Speter          shellstaticFunc, 0, 0);
1475251883Speter    }
1476251883Speter    if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
1477251883Speter      fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
1478251883Speter          p->zDbFilename, sqlite3_errmsg(db));
1479251883Speter      exit(1);
1480251883Speter    }
1481251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION
1482251883Speter    sqlite3_enable_load_extension(p->db, 1);
1483251883Speter#endif
1484251883Speter  }
1485251883Speter}
1486251883Speter
1487251883Speter/*
1488251883Speter** Do C-language style dequoting.
1489251883Speter**
1490251883Speter**    \t    -> tab
1491251883Speter**    \n    -> newline
1492251883Speter**    \r    -> carriage return
1493251883Speter**    \NNN  -> ascii character NNN in octal
1494251883Speter**    \\    -> backslash
1495251883Speter*/
1496251883Speterstatic void resolve_backslashes(char *z){
1497251883Speter  int i, j;
1498251883Speter  char c;
1499251883Speter  for(i=j=0; (c = z[i])!=0; i++, j++){
1500251883Speter    if( c=='\\' ){
1501251883Speter      c = z[++i];
1502251883Speter      if( c=='n' ){
1503251883Speter        c = '\n';
1504251883Speter      }else if( c=='t' ){
1505251883Speter        c = '\t';
1506251883Speter      }else if( c=='r' ){
1507251883Speter        c = '\r';
1508251883Speter      }else if( c>='0' && c<='7' ){
1509251883Speter        c -= '0';
1510251883Speter        if( z[i+1]>='0' && z[i+1]<='7' ){
1511251883Speter          i++;
1512251883Speter          c = (c<<3) + z[i] - '0';
1513251883Speter          if( z[i+1]>='0' && z[i+1]<='7' ){
1514251883Speter            i++;
1515251883Speter            c = (c<<3) + z[i] - '0';
1516251883Speter          }
1517251883Speter        }
1518251883Speter      }
1519251883Speter    }
1520251883Speter    z[j] = c;
1521251883Speter  }
1522251883Speter  z[j] = 0;
1523251883Speter}
1524251883Speter
1525251883Speter/*
1526251883Speter** Interpret zArg as a boolean value.  Return either 0 or 1.
1527251883Speter*/
1528251883Speterstatic int booleanValue(char *zArg){
1529251883Speter  int i;
1530251883Speter  for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
1531251883Speter  if( i>0 && zArg[i]==0 ) return atoi(zArg);
1532251883Speter  if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
1533251883Speter    return 1;
1534251883Speter  }
1535251883Speter  if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
1536251883Speter    return 0;
1537251883Speter  }
1538251883Speter  fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
1539251883Speter          zArg);
1540251883Speter  return 0;
1541251883Speter}
1542251883Speter
1543251883Speter/*
1544251883Speter** Interpret zArg as an integer value, possibly with suffixes.
1545251883Speter*/
1546251883Speterstatic sqlite3_int64 integerValue(const char *zArg){
1547251883Speter  sqlite3_int64 v = 0;
1548251883Speter  static const struct { char *zSuffix; int iMult; } aMult[] = {
1549251883Speter    { "KiB", 1024 },
1550251883Speter    { "MiB", 1024*1024 },
1551251883Speter    { "GiB", 1024*1024*1024 },
1552251883Speter    { "KB",  1000 },
1553251883Speter    { "MB",  1000000 },
1554251883Speter    { "GB",  1000000000 },
1555251883Speter    { "K",   1000 },
1556251883Speter    { "M",   1000000 },
1557251883Speter    { "G",   1000000000 },
1558251883Speter  };
1559251883Speter  int i;
1560251883Speter  int isNeg = 0;
1561251883Speter  if( zArg[0]=='-' ){
1562251883Speter    isNeg = 1;
1563251883Speter    zArg++;
1564251883Speter  }else if( zArg[0]=='+' ){
1565251883Speter    zArg++;
1566251883Speter  }
1567251883Speter  while( isdigit(zArg[0]) ){
1568251883Speter    v = v*10 + zArg[0] - '0';
1569251883Speter    zArg++;
1570251883Speter  }
1571251883Speter  for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
1572251883Speter    if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
1573251883Speter      v *= aMult[i].iMult;
1574251883Speter      break;
1575251883Speter    }
1576251883Speter  }
1577251883Speter  return isNeg? -v : v;
1578251883Speter}
1579251883Speter
1580251883Speter/*
1581251883Speter** Close an output file, assuming it is not stderr or stdout
1582251883Speter*/
1583251883Speterstatic void output_file_close(FILE *f){
1584251883Speter  if( f && f!=stdout && f!=stderr ) fclose(f);
1585251883Speter}
1586251883Speter
1587251883Speter/*
1588251883Speter** Try to open an output file.   The names "stdout" and "stderr" are
1589251883Speter** recognized and do the right thing.  NULL is returned if the output
1590251883Speter** filename is "off".
1591251883Speter*/
1592251883Speterstatic FILE *output_file_open(const char *zFile){
1593251883Speter  FILE *f;
1594251883Speter  if( strcmp(zFile,"stdout")==0 ){
1595251883Speter    f = stdout;
1596251883Speter  }else if( strcmp(zFile, "stderr")==0 ){
1597251883Speter    f = stderr;
1598251883Speter  }else if( strcmp(zFile, "off")==0 ){
1599251883Speter    f = 0;
1600251883Speter  }else{
1601251883Speter    f = fopen(zFile, "wb");
1602251883Speter    if( f==0 ){
1603251883Speter      fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
1604251883Speter    }
1605251883Speter  }
1606251883Speter  return f;
1607251883Speter}
1608251883Speter
1609251883Speter/*
1610251883Speter** A routine for handling output from sqlite3_trace().
1611251883Speter*/
1612251883Speterstatic void sql_trace_callback(void *pArg, const char *z){
1613251883Speter  FILE *f = (FILE*)pArg;
1614251883Speter  if( f ) fprintf(f, "%s\n", z);
1615251883Speter}
1616251883Speter
1617251883Speter/*
1618251883Speter** A no-op routine that runs with the ".breakpoint" doc-command.  This is
1619251883Speter** a useful spot to set a debugger breakpoint.
1620251883Speter*/
1621251883Speterstatic void test_breakpoint(void){
1622251883Speter  static int nCall = 0;
1623251883Speter  nCall++;
1624251883Speter}
1625251883Speter
1626251883Speter/*
1627251883Speter** If an input line begins with "." then invoke this routine to
1628251883Speter** process that line.
1629251883Speter**
1630251883Speter** Return 1 on error, 2 to exit, and 0 otherwise.
1631251883Speter*/
1632251883Speterstatic int do_meta_command(char *zLine, struct callback_data *p){
1633251883Speter  int i = 1;
1634251883Speter  int nArg = 0;
1635251883Speter  int n, c;
1636251883Speter  int rc = 0;
1637251883Speter  char *azArg[50];
1638251883Speter
1639251883Speter  /* Parse the input line into tokens.
1640251883Speter  */
1641251883Speter  while( zLine[i] && nArg<ArraySize(azArg) ){
1642251883Speter    while( IsSpace(zLine[i]) ){ i++; }
1643251883Speter    if( zLine[i]==0 ) break;
1644251883Speter    if( zLine[i]=='\'' || zLine[i]=='"' ){
1645251883Speter      int delim = zLine[i++];
1646251883Speter      azArg[nArg++] = &zLine[i];
1647251883Speter      while( zLine[i] && zLine[i]!=delim ){ i++; }
1648251883Speter      if( zLine[i]==delim ){
1649251883Speter        zLine[i++] = 0;
1650251883Speter      }
1651251883Speter      if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
1652251883Speter    }else{
1653251883Speter      azArg[nArg++] = &zLine[i];
1654251883Speter      while( zLine[i] && !IsSpace(zLine[i]) ){ i++; }
1655251883Speter      if( zLine[i] ) zLine[i++] = 0;
1656251883Speter      resolve_backslashes(azArg[nArg-1]);
1657251883Speter    }
1658251883Speter  }
1659251883Speter
1660251883Speter  /* Process the input line.
1661251883Speter  */
1662251883Speter  if( nArg==0 ) return 0; /* no tokens, no error */
1663251883Speter  n = strlen30(azArg[0]);
1664251883Speter  c = azArg[0][0];
1665251883Speter  if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){
1666251883Speter    const char *zDestFile = 0;
1667251883Speter    const char *zDb = 0;
1668251883Speter    const char *zKey = 0;
1669251883Speter    sqlite3 *pDest;
1670251883Speter    sqlite3_backup *pBackup;
1671251883Speter    int j;
1672251883Speter    for(j=1; j<nArg; j++){
1673251883Speter      const char *z = azArg[j];
1674251883Speter      if( z[0]=='-' ){
1675251883Speter        while( z[0]=='-' ) z++;
1676251883Speter        if( strcmp(z,"key")==0 && j<nArg-1 ){
1677251883Speter          zKey = azArg[++j];
1678251883Speter        }else
1679251883Speter        {
1680251883Speter          fprintf(stderr, "unknown option: %s\n", azArg[j]);
1681251883Speter          return 1;
1682251883Speter        }
1683251883Speter      }else if( zDestFile==0 ){
1684251883Speter        zDestFile = azArg[j];
1685251883Speter      }else if( zDb==0 ){
1686251883Speter        zDb = zDestFile;
1687251883Speter        zDestFile = azArg[j];
1688251883Speter      }else{
1689251883Speter        fprintf(stderr, "too many arguments to .backup\n");
1690251883Speter        return 1;
1691251883Speter      }
1692251883Speter    }
1693251883Speter    if( zDestFile==0 ){
1694251883Speter      fprintf(stderr, "missing FILENAME argument on .backup\n");
1695251883Speter      return 1;
1696251883Speter    }
1697251883Speter    if( zDb==0 ) zDb = "main";
1698251883Speter    rc = sqlite3_open(zDestFile, &pDest);
1699251883Speter    if( rc!=SQLITE_OK ){
1700251883Speter      fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
1701251883Speter      sqlite3_close(pDest);
1702251883Speter      return 1;
1703251883Speter    }
1704251883Speter#ifdef SQLITE_HAS_CODEC
1705251883Speter    sqlite3_key(pDest, zKey, (int)strlen(zKey));
1706251883Speter#else
1707251883Speter    (void)zKey;
1708251883Speter#endif
1709251883Speter    open_db(p);
1710251883Speter    pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
1711251883Speter    if( pBackup==0 ){
1712251883Speter      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
1713251883Speter      sqlite3_close(pDest);
1714251883Speter      return 1;
1715251883Speter    }
1716251883Speter    while(  (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
1717251883Speter    sqlite3_backup_finish(pBackup);
1718251883Speter    if( rc==SQLITE_DONE ){
1719251883Speter      rc = 0;
1720251883Speter    }else{
1721251883Speter      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
1722251883Speter      rc = 1;
1723251883Speter    }
1724251883Speter    sqlite3_close(pDest);
1725251883Speter  }else
1726251883Speter
1727251883Speter  if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){
1728251883Speter    bail_on_error = booleanValue(azArg[1]);
1729251883Speter  }else
1730251883Speter
1731251883Speter  /* The undocumented ".breakpoint" command causes a call to the no-op
1732251883Speter  ** routine named test_breakpoint().
1733251883Speter  */
1734251883Speter  if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
1735251883Speter    test_breakpoint();
1736251883Speter  }else
1737251883Speter
1738251883Speter  if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
1739251883Speter    struct callback_data data;
1740251883Speter    char *zErrMsg = 0;
1741251883Speter    open_db(p);
1742251883Speter    memcpy(&data, p, sizeof(data));
1743251883Speter    data.showHeader = 1;
1744251883Speter    data.mode = MODE_Column;
1745251883Speter    data.colWidth[0] = 3;
1746251883Speter    data.colWidth[1] = 15;
1747251883Speter    data.colWidth[2] = 58;
1748251883Speter    data.cnt = 0;
1749251883Speter    sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
1750251883Speter    if( zErrMsg ){
1751251883Speter      fprintf(stderr,"Error: %s\n", zErrMsg);
1752251883Speter      sqlite3_free(zErrMsg);
1753251883Speter      rc = 1;
1754251883Speter    }
1755251883Speter  }else
1756251883Speter
1757251883Speter  if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){
1758251883Speter    open_db(p);
1759251883Speter    /* When playing back a "dump", the content might appear in an order
1760251883Speter    ** which causes immediate foreign key constraints to be violated.
1761251883Speter    ** So disable foreign-key constraint enforcement to prevent problems. */
1762251883Speter    fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
1763251883Speter    fprintf(p->out, "BEGIN TRANSACTION;\n");
1764251883Speter    p->writableSchema = 0;
1765251883Speter    sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
1766251883Speter    p->nErr = 0;
1767251883Speter    if( nArg==1 ){
1768251883Speter      run_schema_dump_query(p,
1769251883Speter        "SELECT name, type, sql FROM sqlite_master "
1770251883Speter        "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
1771251883Speter      );
1772251883Speter      run_schema_dump_query(p,
1773251883Speter        "SELECT name, type, sql FROM sqlite_master "
1774251883Speter        "WHERE name=='sqlite_sequence'"
1775251883Speter      );
1776251883Speter      run_table_dump_query(p,
1777251883Speter        "SELECT sql FROM sqlite_master "
1778251883Speter        "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
1779251883Speter      );
1780251883Speter    }else{
1781251883Speter      int i;
1782251883Speter      for(i=1; i<nArg; i++){
1783251883Speter        zShellStatic = azArg[i];
1784251883Speter        run_schema_dump_query(p,
1785251883Speter          "SELECT name, type, sql FROM sqlite_master "
1786251883Speter          "WHERE tbl_name LIKE shellstatic() AND type=='table'"
1787251883Speter          "  AND sql NOT NULL");
1788251883Speter        run_table_dump_query(p,
1789251883Speter          "SELECT sql FROM sqlite_master "
1790251883Speter          "WHERE sql NOT NULL"
1791251883Speter          "  AND type IN ('index','trigger','view')"
1792251883Speter          "  AND tbl_name LIKE shellstatic()", 0
1793251883Speter        );
1794251883Speter        zShellStatic = 0;
1795251883Speter      }
1796251883Speter    }
1797251883Speter    if( p->writableSchema ){
1798251883Speter      fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
1799251883Speter      p->writableSchema = 0;
1800251883Speter    }
1801251883Speter    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
1802251883Speter    sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
1803251883Speter    fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
1804251883Speter  }else
1805251883Speter
1806251883Speter  if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
1807251883Speter    p->echoOn = booleanValue(azArg[1]);
1808251883Speter  }else
1809251883Speter
1810251883Speter  if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
1811251883Speter    if( nArg>1 && (rc = atoi(azArg[1]))!=0 ) exit(rc);
1812251883Speter    rc = 2;
1813251883Speter  }else
1814251883Speter
1815251883Speter  if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){
1816251883Speter    int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
1817251883Speter    if(val == 1) {
1818251883Speter      if(!p->explainPrev.valid) {
1819251883Speter        p->explainPrev.valid = 1;
1820251883Speter        p->explainPrev.mode = p->mode;
1821251883Speter        p->explainPrev.showHeader = p->showHeader;
1822251883Speter        memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
1823251883Speter      }
1824251883Speter      /* We could put this code under the !p->explainValid
1825251883Speter      ** condition so that it does not execute if we are already in
1826251883Speter      ** explain mode. However, always executing it allows us an easy
1827251883Speter      ** was to reset to explain mode in case the user previously
1828251883Speter      ** did an .explain followed by a .width, .mode or .header
1829251883Speter      ** command.
1830251883Speter      */
1831251883Speter      p->mode = MODE_Explain;
1832251883Speter      p->showHeader = 1;
1833251883Speter      memset(p->colWidth,0,ArraySize(p->colWidth));
1834251883Speter      p->colWidth[0] = 4;                  /* addr */
1835251883Speter      p->colWidth[1] = 13;                 /* opcode */
1836251883Speter      p->colWidth[2] = 4;                  /* P1 */
1837251883Speter      p->colWidth[3] = 4;                  /* P2 */
1838251883Speter      p->colWidth[4] = 4;                  /* P3 */
1839251883Speter      p->colWidth[5] = 13;                 /* P4 */
1840251883Speter      p->colWidth[6] = 2;                  /* P5 */
1841251883Speter      p->colWidth[7] = 13;                  /* Comment */
1842251883Speter    }else if (p->explainPrev.valid) {
1843251883Speter      p->explainPrev.valid = 0;
1844251883Speter      p->mode = p->explainPrev.mode;
1845251883Speter      p->showHeader = p->explainPrev.showHeader;
1846251883Speter      memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
1847251883Speter    }
1848251883Speter  }else
1849251883Speter
1850251883Speter  if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
1851251883Speter                 strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){
1852251883Speter    p->showHeader = booleanValue(azArg[1]);
1853251883Speter  }else
1854251883Speter
1855251883Speter  if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
1856251883Speter    fprintf(stderr,"%s",zHelp);
1857251883Speter    if( HAS_TIMER ){
1858251883Speter      fprintf(stderr,"%s",zTimerHelp);
1859251883Speter    }
1860251883Speter  }else
1861251883Speter
1862251883Speter  if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){
1863251883Speter    char *zTable = azArg[2];    /* Insert data into this table */
1864251883Speter    char *zFile = azArg[1];     /* The file from which to extract data */
1865251883Speter    sqlite3_stmt *pStmt = NULL; /* A statement */
1866251883Speter    int nCol;                   /* Number of columns in the table */
1867251883Speter    int nByte;                  /* Number of bytes in an SQL string */
1868251883Speter    int i, j;                   /* Loop counters */
1869251883Speter    int nSep;                   /* Number of bytes in p->separator[] */
1870251883Speter    char *zSql;                 /* An SQL statement */
1871251883Speter    char *zLine;                /* A single line of input from the file */
1872251883Speter    char **azCol;               /* zLine[] broken up into columns */
1873251883Speter    char *zCommit;              /* How to commit changes */
1874251883Speter    FILE *in;                   /* The input file */
1875251883Speter    int lineno = 0;             /* Line number of input file */
1876251883Speter
1877251883Speter    open_db(p);
1878251883Speter    nSep = strlen30(p->separator);
1879251883Speter    if( nSep==0 ){
1880251883Speter      fprintf(stderr, "Error: non-null separator required for import\n");
1881251883Speter      return 1;
1882251883Speter    }
1883251883Speter    zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
1884251883Speter    if( zSql==0 ){
1885251883Speter      fprintf(stderr, "Error: out of memory\n");
1886251883Speter      return 1;
1887251883Speter    }
1888251883Speter    nByte = strlen30(zSql);
1889251883Speter    rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
1890251883Speter    sqlite3_free(zSql);
1891251883Speter    if( rc ){
1892251883Speter      if (pStmt) sqlite3_finalize(pStmt);
1893251883Speter      fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
1894251883Speter      return 1;
1895251883Speter    }
1896251883Speter    nCol = sqlite3_column_count(pStmt);
1897251883Speter    sqlite3_finalize(pStmt);
1898251883Speter    pStmt = 0;
1899251883Speter    if( nCol==0 ) return 0; /* no columns, no error */
1900251883Speter    zSql = malloc( nByte + 20 + nCol*2 );
1901251883Speter    if( zSql==0 ){
1902251883Speter      fprintf(stderr, "Error: out of memory\n");
1903251883Speter      return 1;
1904251883Speter    }
1905251883Speter    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zTable);
1906251883Speter    j = strlen30(zSql);
1907251883Speter    for(i=1; i<nCol; i++){
1908251883Speter      zSql[j++] = ',';
1909251883Speter      zSql[j++] = '?';
1910251883Speter    }
1911251883Speter    zSql[j++] = ')';
1912251883Speter    zSql[j] = 0;
1913251883Speter    rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
1914251883Speter    free(zSql);
1915251883Speter    if( rc ){
1916251883Speter      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
1917251883Speter      if (pStmt) sqlite3_finalize(pStmt);
1918251883Speter      return 1;
1919251883Speter    }
1920251883Speter    in = fopen(zFile, "rb");
1921251883Speter    if( in==0 ){
1922251883Speter      fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
1923251883Speter      sqlite3_finalize(pStmt);
1924251883Speter      return 1;
1925251883Speter    }
1926251883Speter    azCol = malloc( sizeof(azCol[0])*(nCol+1) );
1927251883Speter    if( azCol==0 ){
1928251883Speter      fprintf(stderr, "Error: out of memory\n");
1929251883Speter      fclose(in);
1930251883Speter      sqlite3_finalize(pStmt);
1931251883Speter      return 1;
1932251883Speter    }
1933251883Speter    sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
1934251883Speter    zCommit = "COMMIT";
1935251883Speter    while( (zLine = local_getline(0, in, 1))!=0 ){
1936251883Speter      char *z, c;
1937251883Speter      int inQuote = 0;
1938251883Speter      lineno++;
1939251883Speter      azCol[0] = zLine;
1940251883Speter      for(i=0, z=zLine; (c = *z)!=0; z++){
1941251883Speter        if( c=='"' ) inQuote = !inQuote;
1942251883Speter        if( c=='\n' ) lineno++;
1943251883Speter        if( !inQuote && c==p->separator[0] && strncmp(z,p->separator,nSep)==0 ){
1944251883Speter          *z = 0;
1945251883Speter          i++;
1946251883Speter          if( i<nCol ){
1947251883Speter            azCol[i] = &z[nSep];
1948251883Speter            z += nSep-1;
1949251883Speter          }
1950251883Speter        }
1951251883Speter      } /* end for */
1952251883Speter      *z = 0;
1953251883Speter      if( i+1!=nCol ){
1954251883Speter        fprintf(stderr,
1955251883Speter                "Error: %s line %d: expected %d columns of data but found %d\n",
1956251883Speter                zFile, lineno, nCol, i+1);
1957251883Speter        zCommit = "ROLLBACK";
1958251883Speter        free(zLine);
1959251883Speter        rc = 1;
1960251883Speter        break; /* from while */
1961251883Speter      }
1962251883Speter      for(i=0; i<nCol; i++){
1963251883Speter        if( azCol[i][0]=='"' ){
1964251883Speter          int k;
1965251883Speter          for(z=azCol[i], j=1, k=0; z[j]; j++){
1966251883Speter            if( z[j]=='"' ){ j++; if( z[j]==0 ) break; }
1967251883Speter            z[k++] = z[j];
1968251883Speter          }
1969251883Speter          z[k] = 0;
1970251883Speter        }
1971251883Speter        sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
1972251883Speter      }
1973251883Speter      sqlite3_step(pStmt);
1974251883Speter      rc = sqlite3_reset(pStmt);
1975251883Speter      free(zLine);
1976251883Speter      if( rc!=SQLITE_OK ){
1977251883Speter        fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
1978251883Speter        zCommit = "ROLLBACK";
1979251883Speter        rc = 1;
1980251883Speter        break; /* from while */
1981251883Speter      }
1982251883Speter    } /* end while */
1983251883Speter    free(azCol);
1984251883Speter    fclose(in);
1985251883Speter    sqlite3_finalize(pStmt);
1986251883Speter    sqlite3_exec(p->db, zCommit, 0, 0, 0);
1987251883Speter  }else
1988251883Speter
1989251883Speter  if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
1990251883Speter    struct callback_data data;
1991251883Speter    char *zErrMsg = 0;
1992251883Speter    open_db(p);
1993251883Speter    memcpy(&data, p, sizeof(data));
1994251883Speter    data.showHeader = 0;
1995251883Speter    data.mode = MODE_List;
1996251883Speter    if( nArg==1 ){
1997251883Speter      rc = sqlite3_exec(p->db,
1998251883Speter        "SELECT name FROM sqlite_master "
1999251883Speter        "WHERE type='index' AND name NOT LIKE 'sqlite_%' "
2000251883Speter        "UNION ALL "
2001251883Speter        "SELECT name FROM sqlite_temp_master "
2002251883Speter        "WHERE type='index' "
2003251883Speter        "ORDER BY 1",
2004251883Speter        callback, &data, &zErrMsg
2005251883Speter      );
2006251883Speter    }else{
2007251883Speter      zShellStatic = azArg[1];
2008251883Speter      rc = sqlite3_exec(p->db,
2009251883Speter        "SELECT name FROM sqlite_master "
2010251883Speter        "WHERE type='index' AND tbl_name LIKE shellstatic() "
2011251883Speter        "UNION ALL "
2012251883Speter        "SELECT name FROM sqlite_temp_master "
2013251883Speter        "WHERE type='index' AND tbl_name LIKE shellstatic() "
2014251883Speter        "ORDER BY 1",
2015251883Speter        callback, &data, &zErrMsg
2016251883Speter      );
2017251883Speter      zShellStatic = 0;
2018251883Speter    }
2019251883Speter    if( zErrMsg ){
2020251883Speter      fprintf(stderr,"Error: %s\n", zErrMsg);
2021251883Speter      sqlite3_free(zErrMsg);
2022251883Speter      rc = 1;
2023251883Speter    }else if( rc != SQLITE_OK ){
2024251883Speter      fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n");
2025251883Speter      rc = 1;
2026251883Speter    }
2027251883Speter  }else
2028251883Speter
2029251883Speter#ifdef SQLITE_ENABLE_IOTRACE
2030251883Speter  if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
2031251883Speter    extern void (*sqlite3IoTrace)(const char*, ...);
2032251883Speter    if( iotrace && iotrace!=stdout ) fclose(iotrace);
2033251883Speter    iotrace = 0;
2034251883Speter    if( nArg<2 ){
2035251883Speter      sqlite3IoTrace = 0;
2036251883Speter    }else if( strcmp(azArg[1], "-")==0 ){
2037251883Speter      sqlite3IoTrace = iotracePrintf;
2038251883Speter      iotrace = stdout;
2039251883Speter    }else{
2040251883Speter      iotrace = fopen(azArg[1], "w");
2041251883Speter      if( iotrace==0 ){
2042251883Speter        fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
2043251883Speter        sqlite3IoTrace = 0;
2044251883Speter        rc = 1;
2045251883Speter      }else{
2046251883Speter        sqlite3IoTrace = iotracePrintf;
2047251883Speter      }
2048251883Speter    }
2049251883Speter  }else
2050251883Speter#endif
2051251883Speter
2052251883Speter#ifndef SQLITE_OMIT_LOAD_EXTENSION
2053251883Speter  if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
2054251883Speter    const char *zFile, *zProc;
2055251883Speter    char *zErrMsg = 0;
2056251883Speter    zFile = azArg[1];
2057251883Speter    zProc = nArg>=3 ? azArg[2] : 0;
2058251883Speter    open_db(p);
2059251883Speter    rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
2060251883Speter    if( rc!=SQLITE_OK ){
2061251883Speter      fprintf(stderr, "Error: %s\n", zErrMsg);
2062251883Speter      sqlite3_free(zErrMsg);
2063251883Speter      rc = 1;
2064251883Speter    }
2065251883Speter  }else
2066251883Speter#endif
2067251883Speter
2068251883Speter  if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){
2069251883Speter    const char *zFile = azArg[1];
2070251883Speter    output_file_close(p->pLog);
2071251883Speter    p->pLog = output_file_open(zFile);
2072251883Speter  }else
2073251883Speter
2074251883Speter  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
2075251883Speter    int n2 = strlen30(azArg[1]);
2076251883Speter    if( (n2==4 && strncmp(azArg[1],"line",n2)==0)
2077251883Speter        ||
2078251883Speter        (n2==5 && strncmp(azArg[1],"lines",n2)==0) ){
2079251883Speter      p->mode = MODE_Line;
2080251883Speter    }else if( (n2==6 && strncmp(azArg[1],"column",n2)==0)
2081251883Speter              ||
2082251883Speter              (n2==7 && strncmp(azArg[1],"columns",n2)==0) ){
2083251883Speter      p->mode = MODE_Column;
2084251883Speter    }else if( n2==4 && strncmp(azArg[1],"list",n2)==0 ){
2085251883Speter      p->mode = MODE_List;
2086251883Speter    }else if( n2==4 && strncmp(azArg[1],"html",n2)==0 ){
2087251883Speter      p->mode = MODE_Html;
2088251883Speter    }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){
2089251883Speter      p->mode = MODE_Tcl;
2090251883Speter      sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
2091251883Speter    }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){
2092251883Speter      p->mode = MODE_Csv;
2093251883Speter      sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
2094251883Speter    }else if( n2==4 && strncmp(azArg[1],"tabs",n2)==0 ){
2095251883Speter      p->mode = MODE_List;
2096251883Speter      sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
2097251883Speter    }else if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
2098251883Speter      p->mode = MODE_Insert;
2099251883Speter      set_table_name(p, "table");
2100251883Speter    }else {
2101251883Speter      fprintf(stderr,"Error: mode should be one of: "
2102251883Speter         "column csv html insert line list tabs tcl\n");
2103251883Speter      rc = 1;
2104251883Speter    }
2105251883Speter  }else
2106251883Speter
2107251883Speter  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==3 ){
2108251883Speter    int n2 = strlen30(azArg[1]);
2109251883Speter    if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
2110251883Speter      p->mode = MODE_Insert;
2111251883Speter      set_table_name(p, azArg[2]);
2112251883Speter    }else {
2113251883Speter      fprintf(stderr, "Error: invalid arguments: "
2114251883Speter        " \"%s\". Enter \".help\" for help\n", azArg[2]);
2115251883Speter      rc = 1;
2116251883Speter    }
2117251883Speter  }else
2118251883Speter
2119251883Speter  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
2120251883Speter    sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
2121251883Speter                     "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
2122251883Speter  }else
2123251883Speter
2124251883Speter  if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
2125251883Speter    if( p->outfile[0]=='|' ){
2126251883Speter      pclose(p->out);
2127251883Speter    }else{
2128251883Speter      output_file_close(p->out);
2129251883Speter    }
2130251883Speter    p->outfile[0] = 0;
2131251883Speter    if( azArg[1][0]=='|' ){
2132251883Speter      p->out = popen(&azArg[1][1], "w");
2133251883Speter      if( p->out==0 ){
2134251883Speter        fprintf(stderr,"Error: cannot open pipe \"%s\"\n", &azArg[1][1]);
2135251883Speter        p->out = stdout;
2136251883Speter        rc = 1;
2137251883Speter      }else{
2138251883Speter        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
2139251883Speter      }
2140251883Speter    }else{
2141251883Speter      p->out = output_file_open(azArg[1]);
2142251883Speter      if( p->out==0 ){
2143251883Speter        if( strcmp(azArg[1],"off")!=0 ){
2144251883Speter          fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]);
2145251883Speter        }
2146251883Speter        p->out = stdout;
2147251883Speter        rc = 1;
2148251883Speter      } else {
2149251883Speter        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
2150251883Speter      }
2151251883Speter    }
2152251883Speter  }else
2153251883Speter
2154251883Speter  if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){
2155251883Speter    int i;
2156251883Speter    for(i=1; i<nArg; i++){
2157251883Speter      if( i>1 ) fprintf(p->out, " ");
2158251883Speter      fprintf(p->out, "%s", azArg[i]);
2159251883Speter    }
2160251883Speter    fprintf(p->out, "\n");
2161251883Speter  }else
2162251883Speter
2163251883Speter  if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
2164251883Speter    if( nArg >= 2) {
2165251883Speter      strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
2166251883Speter    }
2167251883Speter    if( nArg >= 3) {
2168251883Speter      strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
2169251883Speter    }
2170251883Speter  }else
2171251883Speter
2172251883Speter  if( c=='q' && strncmp(azArg[0], "quit", n)==0 && nArg==1 ){
2173251883Speter    rc = 2;
2174251883Speter  }else
2175251883Speter
2176251883Speter  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
2177251883Speter    FILE *alt = fopen(azArg[1], "rb");
2178251883Speter    if( alt==0 ){
2179251883Speter      fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
2180251883Speter      rc = 1;
2181251883Speter    }else{
2182251883Speter      rc = process_input(p, alt);
2183251883Speter      fclose(alt);
2184251883Speter    }
2185251883Speter  }else
2186251883Speter
2187251883Speter  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){
2188251883Speter    const char *zSrcFile;
2189251883Speter    const char *zDb;
2190251883Speter    sqlite3 *pSrc;
2191251883Speter    sqlite3_backup *pBackup;
2192251883Speter    int nTimeout = 0;
2193251883Speter
2194251883Speter    if( nArg==2 ){
2195251883Speter      zSrcFile = azArg[1];
2196251883Speter      zDb = "main";
2197251883Speter    }else{
2198251883Speter      zSrcFile = azArg[2];
2199251883Speter      zDb = azArg[1];
2200251883Speter    }
2201251883Speter    rc = sqlite3_open(zSrcFile, &pSrc);
2202251883Speter    if( rc!=SQLITE_OK ){
2203251883Speter      fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
2204251883Speter      sqlite3_close(pSrc);
2205251883Speter      return 1;
2206251883Speter    }
2207251883Speter    open_db(p);
2208251883Speter    pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
2209251883Speter    if( pBackup==0 ){
2210251883Speter      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
2211251883Speter      sqlite3_close(pSrc);
2212251883Speter      return 1;
2213251883Speter    }
2214251883Speter    while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
2215251883Speter          || rc==SQLITE_BUSY  ){
2216251883Speter      if( rc==SQLITE_BUSY ){
2217251883Speter        if( nTimeout++ >= 3 ) break;
2218251883Speter        sqlite3_sleep(100);
2219251883Speter      }
2220251883Speter    }
2221251883Speter    sqlite3_backup_finish(pBackup);
2222251883Speter    if( rc==SQLITE_DONE ){
2223251883Speter      rc = 0;
2224251883Speter    }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
2225251883Speter      fprintf(stderr, "Error: source database is busy\n");
2226251883Speter      rc = 1;
2227251883Speter    }else{
2228251883Speter      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
2229251883Speter      rc = 1;
2230251883Speter    }
2231251883Speter    sqlite3_close(pSrc);
2232251883Speter  }else
2233251883Speter
2234251883Speter  if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
2235251883Speter    struct callback_data data;
2236251883Speter    char *zErrMsg = 0;
2237251883Speter    open_db(p);
2238251883Speter    memcpy(&data, p, sizeof(data));
2239251883Speter    data.showHeader = 0;
2240251883Speter    data.mode = MODE_Semi;
2241251883Speter    if( nArg>1 ){
2242251883Speter      int i;
2243251883Speter      for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
2244251883Speter      if( strcmp(azArg[1],"sqlite_master")==0 ){
2245251883Speter        char *new_argv[2], *new_colv[2];
2246251883Speter        new_argv[0] = "CREATE TABLE sqlite_master (\n"
2247251883Speter                      "  type text,\n"
2248251883Speter                      "  name text,\n"
2249251883Speter                      "  tbl_name text,\n"
2250251883Speter                      "  rootpage integer,\n"
2251251883Speter                      "  sql text\n"
2252251883Speter                      ")";
2253251883Speter        new_argv[1] = 0;
2254251883Speter        new_colv[0] = "sql";
2255251883Speter        new_colv[1] = 0;
2256251883Speter        callback(&data, 1, new_argv, new_colv);
2257251883Speter        rc = SQLITE_OK;
2258251883Speter      }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
2259251883Speter        char *new_argv[2], *new_colv[2];
2260251883Speter        new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
2261251883Speter                      "  type text,\n"
2262251883Speter                      "  name text,\n"
2263251883Speter                      "  tbl_name text,\n"
2264251883Speter                      "  rootpage integer,\n"
2265251883Speter                      "  sql text\n"
2266251883Speter                      ")";
2267251883Speter        new_argv[1] = 0;
2268251883Speter        new_colv[0] = "sql";
2269251883Speter        new_colv[1] = 0;
2270251883Speter        callback(&data, 1, new_argv, new_colv);
2271251883Speter        rc = SQLITE_OK;
2272251883Speter      }else{
2273251883Speter        zShellStatic = azArg[1];
2274251883Speter        rc = sqlite3_exec(p->db,
2275251883Speter          "SELECT sql FROM "
2276251883Speter          "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
2277251883Speter          "     FROM sqlite_master UNION ALL"
2278251883Speter          "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
2279251883Speter          "WHERE lower(tbl_name) LIKE shellstatic()"
2280251883Speter          "  AND type!='meta' AND sql NOTNULL "
2281251883Speter          "ORDER BY rowid",
2282251883Speter          callback, &data, &zErrMsg);
2283251883Speter        zShellStatic = 0;
2284251883Speter      }
2285251883Speter    }else{
2286251883Speter      rc = sqlite3_exec(p->db,
2287251883Speter         "SELECT sql FROM "
2288251883Speter         "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
2289251883Speter         "     FROM sqlite_master UNION ALL"
2290251883Speter         "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
2291251883Speter         "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
2292251883Speter         "ORDER BY rowid",
2293251883Speter         callback, &data, &zErrMsg
2294251883Speter      );
2295251883Speter    }
2296251883Speter    if( zErrMsg ){
2297251883Speter      fprintf(stderr,"Error: %s\n", zErrMsg);
2298251883Speter      sqlite3_free(zErrMsg);
2299251883Speter      rc = 1;
2300251883Speter    }else if( rc != SQLITE_OK ){
2301251883Speter      fprintf(stderr,"Error: querying schema information\n");
2302251883Speter      rc = 1;
2303251883Speter    }else{
2304251883Speter      rc = 0;
2305251883Speter    }
2306251883Speter  }else
2307251883Speter
2308251883Speter  if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
2309251883Speter    sqlite3_snprintf(sizeof(p->separator), p->separator,
2310251883Speter                     "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
2311251883Speter  }else
2312251883Speter
2313251883Speter  if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){
2314251883Speter    int i;
2315251883Speter    fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
2316251883Speter    fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
2317251883Speter    fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
2318251883Speter    fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
2319251883Speter    fprintf(p->out,"%9.9s: ", "nullvalue");
2320251883Speter      output_c_string(p->out, p->nullvalue);
2321251883Speter      fprintf(p->out, "\n");
2322251883Speter    fprintf(p->out,"%9.9s: %s\n","output",
2323251883Speter            strlen30(p->outfile) ? p->outfile : "stdout");
2324251883Speter    fprintf(p->out,"%9.9s: ", "separator");
2325251883Speter      output_c_string(p->out, p->separator);
2326251883Speter      fprintf(p->out, "\n");
2327251883Speter    fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
2328251883Speter    fprintf(p->out,"%9.9s: ","width");
2329251883Speter    for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
2330251883Speter      fprintf(p->out,"%d ",p->colWidth[i]);
2331251883Speter    }
2332251883Speter    fprintf(p->out,"\n");
2333251883Speter  }else
2334251883Speter
2335251883Speter  if( c=='s' && strncmp(azArg[0], "stats", n)==0 && nArg>1 && nArg<3 ){
2336251883Speter    p->statsOn = booleanValue(azArg[1]);
2337251883Speter  }else
2338251883Speter
2339251883Speter  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
2340251883Speter    sqlite3_stmt *pStmt;
2341251883Speter    char **azResult;
2342251883Speter    int nRow, nAlloc;
2343251883Speter    char *zSql = 0;
2344251883Speter    int ii;
2345251883Speter    open_db(p);
2346251883Speter    rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
2347251883Speter    if( rc ) return rc;
2348251883Speter    zSql = sqlite3_mprintf(
2349251883Speter        "SELECT name FROM sqlite_master"
2350251883Speter        " WHERE type IN ('table','view')"
2351251883Speter        "   AND name NOT LIKE 'sqlite_%%'"
2352251883Speter        "   AND name LIKE ?1");
2353251883Speter    while( sqlite3_step(pStmt)==SQLITE_ROW ){
2354251883Speter      const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
2355251883Speter      if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue;
2356251883Speter      if( strcmp(zDbName,"temp")==0 ){
2357251883Speter        zSql = sqlite3_mprintf(
2358251883Speter                 "%z UNION ALL "
2359251883Speter                 "SELECT 'temp.' || name FROM sqlite_temp_master"
2360251883Speter                 " WHERE type IN ('table','view')"
2361251883Speter                 "   AND name NOT LIKE 'sqlite_%%'"
2362251883Speter                 "   AND name LIKE ?1", zSql);
2363251883Speter      }else{
2364251883Speter        zSql = sqlite3_mprintf(
2365251883Speter                 "%z UNION ALL "
2366251883Speter                 "SELECT '%q.' || name FROM \"%w\".sqlite_master"
2367251883Speter                 " WHERE type IN ('table','view')"
2368251883Speter                 "   AND name NOT LIKE 'sqlite_%%'"
2369251883Speter                 "   AND name LIKE ?1", zSql, zDbName, zDbName);
2370251883Speter      }
2371251883Speter    }
2372251883Speter    sqlite3_finalize(pStmt);
2373251883Speter    zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
2374251883Speter    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2375251883Speter    sqlite3_free(zSql);
2376251883Speter    if( rc ) return rc;
2377251883Speter    nRow = nAlloc = 0;
2378251883Speter    azResult = 0;
2379251883Speter    if( nArg>1 ){
2380251883Speter      sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT);
2381251883Speter    }else{
2382251883Speter      sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
2383251883Speter    }
2384251883Speter    while( sqlite3_step(pStmt)==SQLITE_ROW ){
2385251883Speter      if( nRow>=nAlloc ){
2386251883Speter        char **azNew;
2387251883Speter        int n = nAlloc*2 + 10;
2388251883Speter        azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n);
2389251883Speter        if( azNew==0 ){
2390251883Speter          fprintf(stderr, "Error: out of memory\n");
2391251883Speter          break;
2392251883Speter        }
2393251883Speter        nAlloc = n;
2394251883Speter        azResult = azNew;
2395251883Speter      }
2396251883Speter      azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
2397251883Speter      if( azResult[nRow] ) nRow++;
2398251883Speter    }
2399251883Speter    sqlite3_finalize(pStmt);
2400251883Speter    if( nRow>0 ){
2401251883Speter      int len, maxlen = 0;
2402251883Speter      int i, j;
2403251883Speter      int nPrintCol, nPrintRow;
2404251883Speter      for(i=0; i<nRow; i++){
2405251883Speter        len = strlen30(azResult[i]);
2406251883Speter        if( len>maxlen ) maxlen = len;
2407251883Speter      }
2408251883Speter      nPrintCol = 80/(maxlen+2);
2409251883Speter      if( nPrintCol<1 ) nPrintCol = 1;
2410251883Speter      nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
2411251883Speter      for(i=0; i<nPrintRow; i++){
2412251883Speter        for(j=i; j<nRow; j+=nPrintRow){
2413251883Speter          char *zSp = j<nPrintRow ? "" : "  ";
2414251883Speter          fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
2415251883Speter        }
2416251883Speter        fprintf(p->out, "\n");
2417251883Speter      }
2418251883Speter    }
2419251883Speter    for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
2420251883Speter    sqlite3_free(azResult);
2421251883Speter  }else
2422251883Speter
2423251883Speter  if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
2424251883Speter    static const struct {
2425251883Speter       const char *zCtrlName;   /* Name of a test-control option */
2426251883Speter       int ctrlCode;            /* Integer code for that option */
2427251883Speter    } aCtrl[] = {
2428251883Speter      { "prng_save",             SQLITE_TESTCTRL_PRNG_SAVE              },
2429251883Speter      { "prng_restore",          SQLITE_TESTCTRL_PRNG_RESTORE           },
2430251883Speter      { "prng_reset",            SQLITE_TESTCTRL_PRNG_RESET             },
2431251883Speter      { "bitvec_test",           SQLITE_TESTCTRL_BITVEC_TEST            },
2432251883Speter      { "fault_install",         SQLITE_TESTCTRL_FAULT_INSTALL          },
2433251883Speter      { "benign_malloc_hooks",   SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS    },
2434251883Speter      { "pending_byte",          SQLITE_TESTCTRL_PENDING_BYTE           },
2435251883Speter      { "assert",                SQLITE_TESTCTRL_ASSERT                 },
2436251883Speter      { "always",                SQLITE_TESTCTRL_ALWAYS                 },
2437251883Speter      { "reserve",               SQLITE_TESTCTRL_RESERVE                },
2438251883Speter      { "optimizations",         SQLITE_TESTCTRL_OPTIMIZATIONS          },
2439251883Speter      { "iskeyword",             SQLITE_TESTCTRL_ISKEYWORD              },
2440251883Speter      { "scratchmalloc",         SQLITE_TESTCTRL_SCRATCHMALLOC          },
2441251883Speter    };
2442251883Speter    int testctrl = -1;
2443251883Speter    int rc = 0;
2444251883Speter    int i, n;
2445251883Speter    open_db(p);
2446251883Speter
2447251883Speter    /* convert testctrl text option to value. allow any unique prefix
2448251883Speter    ** of the option name, or a numerical value. */
2449251883Speter    n = strlen30(azArg[1]);
2450251883Speter    for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
2451251883Speter      if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
2452251883Speter        if( testctrl<0 ){
2453251883Speter          testctrl = aCtrl[i].ctrlCode;
2454251883Speter        }else{
2455251883Speter          fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
2456251883Speter          testctrl = -1;
2457251883Speter          break;
2458251883Speter        }
2459251883Speter      }
2460251883Speter    }
2461251883Speter    if( testctrl<0 ) testctrl = atoi(azArg[1]);
2462251883Speter    if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
2463251883Speter      fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
2464251883Speter    }else{
2465251883Speter      switch(testctrl){
2466251883Speter
2467251883Speter        /* sqlite3_test_control(int, db, int) */
2468251883Speter        case SQLITE_TESTCTRL_OPTIMIZATIONS:
2469251883Speter        case SQLITE_TESTCTRL_RESERVE:
2470251883Speter          if( nArg==3 ){
2471251883Speter            int opt = (int)strtol(azArg[2], 0, 0);
2472251883Speter            rc = sqlite3_test_control(testctrl, p->db, opt);
2473251883Speter            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
2474251883Speter          } else {
2475251883Speter            fprintf(stderr,"Error: testctrl %s takes a single int option\n",
2476251883Speter                    azArg[1]);
2477251883Speter          }
2478251883Speter          break;
2479251883Speter
2480251883Speter        /* sqlite3_test_control(int) */
2481251883Speter        case SQLITE_TESTCTRL_PRNG_SAVE:
2482251883Speter        case SQLITE_TESTCTRL_PRNG_RESTORE:
2483251883Speter        case SQLITE_TESTCTRL_PRNG_RESET:
2484251883Speter          if( nArg==2 ){
2485251883Speter            rc = sqlite3_test_control(testctrl);
2486251883Speter            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
2487251883Speter          } else {
2488251883Speter            fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
2489251883Speter          }
2490251883Speter          break;
2491251883Speter
2492251883Speter        /* sqlite3_test_control(int, uint) */
2493251883Speter        case SQLITE_TESTCTRL_PENDING_BYTE:
2494251883Speter          if( nArg==3 ){
2495251883Speter            unsigned int opt = (unsigned int)integerValue(azArg[2]);
2496251883Speter            rc = sqlite3_test_control(testctrl, opt);
2497251883Speter            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
2498251883Speter          } else {
2499251883Speter            fprintf(stderr,"Error: testctrl %s takes a single unsigned"
2500251883Speter                           " int option\n", azArg[1]);
2501251883Speter          }
2502251883Speter          break;
2503251883Speter
2504251883Speter        /* sqlite3_test_control(int, int) */
2505251883Speter        case SQLITE_TESTCTRL_ASSERT:
2506251883Speter        case SQLITE_TESTCTRL_ALWAYS:
2507251883Speter          if( nArg==3 ){
2508251883Speter            int opt = atoi(azArg[2]);
2509251883Speter            rc = sqlite3_test_control(testctrl, opt);
2510251883Speter            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
2511251883Speter          } else {
2512251883Speter            fprintf(stderr,"Error: testctrl %s takes a single int option\n",
2513251883Speter                            azArg[1]);
2514251883Speter          }
2515251883Speter          break;
2516251883Speter
2517251883Speter        /* sqlite3_test_control(int, char *) */
2518251883Speter#ifdef SQLITE_N_KEYWORD
2519251883Speter        case SQLITE_TESTCTRL_ISKEYWORD:
2520251883Speter          if( nArg==3 ){
2521251883Speter            const char *opt = azArg[2];
2522251883Speter            rc = sqlite3_test_control(testctrl, opt);
2523251883Speter            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
2524251883Speter          } else {
2525251883Speter            fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
2526251883Speter                            azArg[1]);
2527251883Speter          }
2528251883Speter          break;
2529251883Speter#endif
2530251883Speter
2531251883Speter        case SQLITE_TESTCTRL_BITVEC_TEST:
2532251883Speter        case SQLITE_TESTCTRL_FAULT_INSTALL:
2533251883Speter        case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
2534251883Speter        case SQLITE_TESTCTRL_SCRATCHMALLOC:
2535251883Speter        default:
2536251883Speter          fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n",
2537251883Speter                  azArg[1]);
2538251883Speter          break;
2539251883Speter      }
2540251883Speter    }
2541251883Speter  }else
2542251883Speter
2543251883Speter  if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
2544251883Speter    open_db(p);
2545251883Speter    sqlite3_busy_timeout(p->db, atoi(azArg[1]));
2546251883Speter  }else
2547251883Speter
2548251883Speter  if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0
2549251883Speter   && nArg==2
2550251883Speter  ){
2551251883Speter    enableTimer = booleanValue(azArg[1]);
2552251883Speter  }else
2553251883Speter
2554251883Speter  if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){
2555251883Speter    open_db(p);
2556251883Speter    output_file_close(p->traceOut);
2557251883Speter    p->traceOut = output_file_open(azArg[1]);
2558251883Speter#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
2559251883Speter    if( p->traceOut==0 ){
2560251883Speter      sqlite3_trace(p->db, 0, 0);
2561251883Speter    }else{
2562251883Speter      sqlite3_trace(p->db, sql_trace_callback, p->traceOut);
2563251883Speter    }
2564251883Speter#endif
2565251883Speter  }else
2566251883Speter
2567251883Speter  if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
2568251883Speter    fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
2569251883Speter        sqlite3_libversion(), sqlite3_sourceid());
2570251883Speter  }else
2571251883Speter
2572251883Speter  if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
2573251883Speter    const char *zDbName = nArg==2 ? azArg[1] : "main";
2574251883Speter    char *zVfsName = 0;
2575251883Speter    if( p->db ){
2576251883Speter      sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
2577251883Speter      if( zVfsName ){
2578251883Speter        fprintf(p->out, "%s\n", zVfsName);
2579251883Speter        sqlite3_free(zVfsName);
2580251883Speter      }
2581251883Speter    }
2582251883Speter  }else
2583251883Speter
2584251883Speter#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
2585251883Speter  if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
2586251883Speter    extern int sqlite3WhereTrace;
2587251883Speter    sqlite3WhereTrace = booleanValue(azArg[1]);
2588251883Speter  }else
2589251883Speter#endif
2590251883Speter
2591251883Speter  if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
2592251883Speter    int j;
2593251883Speter    assert( nArg<=ArraySize(azArg) );
2594251883Speter    for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
2595251883Speter      p->colWidth[j-1] = atoi(azArg[j]);
2596251883Speter    }
2597251883Speter  }else
2598251883Speter
2599251883Speter  {
2600251883Speter    fprintf(stderr, "Error: unknown command or invalid arguments: "
2601251883Speter      " \"%s\". Enter \".help\" for help\n", azArg[0]);
2602251883Speter    rc = 1;
2603251883Speter  }
2604251883Speter
2605251883Speter  return rc;
2606251883Speter}
2607251883Speter
2608251883Speter/*
2609251883Speter** Return TRUE if a semicolon occurs anywhere in the first N characters
2610251883Speter** of string z[].
2611251883Speter*/
2612251883Speterstatic int _contains_semicolon(const char *z, int N){
2613251883Speter  int i;
2614251883Speter  for(i=0; i<N; i++){  if( z[i]==';' ) return 1; }
2615251883Speter  return 0;
2616251883Speter}
2617251883Speter
2618251883Speter/*
2619251883Speter** Test to see if a line consists entirely of whitespace.
2620251883Speter*/
2621251883Speterstatic int _all_whitespace(const char *z){
2622251883Speter  for(; *z; z++){
2623251883Speter    if( IsSpace(z[0]) ) continue;
2624251883Speter    if( *z=='/' && z[1]=='*' ){
2625251883Speter      z += 2;
2626251883Speter      while( *z && (*z!='*' || z[1]!='/') ){ z++; }
2627251883Speter      if( *z==0 ) return 0;
2628251883Speter      z++;
2629251883Speter      continue;
2630251883Speter    }
2631251883Speter    if( *z=='-' && z[1]=='-' ){
2632251883Speter      z += 2;
2633251883Speter      while( *z && *z!='\n' ){ z++; }
2634251883Speter      if( *z==0 ) return 1;
2635251883Speter      continue;
2636251883Speter    }
2637251883Speter    return 0;
2638251883Speter  }
2639251883Speter  return 1;
2640251883Speter}
2641251883Speter
2642251883Speter/*
2643251883Speter** Return TRUE if the line typed in is an SQL command terminator other
2644251883Speter** than a semi-colon.  The SQL Server style "go" command is understood
2645251883Speter** as is the Oracle "/".
2646251883Speter*/
2647251883Speterstatic int _is_command_terminator(const char *zLine){
2648251883Speter  while( IsSpace(zLine[0]) ){ zLine++; };
2649251883Speter  if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
2650251883Speter    return 1;  /* Oracle */
2651251883Speter  }
2652251883Speter  if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
2653251883Speter         && _all_whitespace(&zLine[2]) ){
2654251883Speter    return 1;  /* SQL Server */
2655251883Speter  }
2656251883Speter  return 0;
2657251883Speter}
2658251883Speter
2659251883Speter/*
2660251883Speter** Return true if zSql is a complete SQL statement.  Return false if it
2661251883Speter** ends in the middle of a string literal or C-style comment.
2662251883Speter*/
2663251883Speterstatic int _is_complete(char *zSql, int nSql){
2664251883Speter  int rc;
2665251883Speter  if( zSql==0 ) return 1;
2666251883Speter  zSql[nSql] = ';';
2667251883Speter  zSql[nSql+1] = 0;
2668251883Speter  rc = sqlite3_complete(zSql);
2669251883Speter  zSql[nSql] = 0;
2670251883Speter  return rc;
2671251883Speter}
2672251883Speter
2673251883Speter/*
2674251883Speter** Read input from *in and process it.  If *in==0 then input
2675251883Speter** is interactive - the user is typing it it.  Otherwise, input
2676251883Speter** is coming from a file or device.  A prompt is issued and history
2677251883Speter** is saved only if input is interactive.  An interrupt signal will
2678251883Speter** cause this routine to exit immediately, unless input is interactive.
2679251883Speter**
2680251883Speter** Return the number of errors.
2681251883Speter*/
2682251883Speterstatic int process_input(struct callback_data *p, FILE *in){
2683251883Speter  char *zLine = 0;
2684251883Speter  char *zSql = 0;
2685251883Speter  int nSql = 0;
2686251883Speter  int nSqlPrior = 0;
2687251883Speter  char *zErrMsg;
2688251883Speter  int rc;
2689251883Speter  int errCnt = 0;
2690251883Speter  int lineno = 0;
2691251883Speter  int startline = 0;
2692251883Speter
2693251883Speter  while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
2694251883Speter    fflush(p->out);
2695251883Speter    free(zLine);
2696251883Speter    zLine = one_input_line(zSql, in);
2697251883Speter    if( zLine==0 ){
2698251883Speter      /* End of input */
2699251883Speter      if( stdin_is_interactive ) printf("\n");
2700251883Speter      break;
2701251883Speter    }
2702251883Speter    if( seenInterrupt ){
2703251883Speter      if( in!=0 ) break;
2704251883Speter      seenInterrupt = 0;
2705251883Speter    }
2706251883Speter    lineno++;
2707251883Speter    if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
2708251883Speter    if( zLine && zLine[0]=='.' && nSql==0 ){
2709251883Speter      if( p->echoOn ) printf("%s\n", zLine);
2710251883Speter      rc = do_meta_command(zLine, p);
2711251883Speter      if( rc==2 ){ /* exit requested */
2712251883Speter        break;
2713251883Speter      }else if( rc ){
2714251883Speter        errCnt++;
2715251883Speter      }
2716251883Speter      continue;
2717251883Speter    }
2718251883Speter    if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){
2719251883Speter      memcpy(zLine,";",2);
2720251883Speter    }
2721251883Speter    nSqlPrior = nSql;
2722251883Speter    if( zSql==0 ){
2723251883Speter      int i;
2724251883Speter      for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
2725251883Speter      if( zLine[i]!=0 ){
2726251883Speter        nSql = strlen30(zLine);
2727251883Speter        zSql = malloc( nSql+3 );
2728251883Speter        if( zSql==0 ){
2729251883Speter          fprintf(stderr, "Error: out of memory\n");
2730251883Speter          exit(1);
2731251883Speter        }
2732251883Speter        memcpy(zSql, zLine, nSql+1);
2733251883Speter        startline = lineno;
2734251883Speter      }
2735251883Speter    }else{
2736251883Speter      int len = strlen30(zLine);
2737251883Speter      zSql = realloc( zSql, nSql + len + 4 );
2738251883Speter      if( zSql==0 ){
2739251883Speter        fprintf(stderr,"Error: out of memory\n");
2740251883Speter        exit(1);
2741251883Speter      }
2742251883Speter      zSql[nSql++] = '\n';
2743251883Speter      memcpy(&zSql[nSql], zLine, len+1);
2744251883Speter      nSql += len;
2745251883Speter    }
2746251883Speter    if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
2747251883Speter                && sqlite3_complete(zSql) ){
2748251883Speter      p->cnt = 0;
2749251883Speter      open_db(p);
2750251883Speter      BEGIN_TIMER;
2751251883Speter      rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
2752251883Speter      END_TIMER;
2753251883Speter      if( rc || zErrMsg ){
2754251883Speter        char zPrefix[100];
2755251883Speter        if( in!=0 || !stdin_is_interactive ){
2756251883Speter          sqlite3_snprintf(sizeof(zPrefix), zPrefix,
2757251883Speter                           "Error: near line %d:", startline);
2758251883Speter        }else{
2759251883Speter          sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
2760251883Speter        }
2761251883Speter        if( zErrMsg!=0 ){
2762251883Speter          fprintf(stderr, "%s %s\n", zPrefix, zErrMsg);
2763251883Speter          sqlite3_free(zErrMsg);
2764251883Speter          zErrMsg = 0;
2765251883Speter        }else{
2766251883Speter          fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
2767251883Speter        }
2768251883Speter        errCnt++;
2769251883Speter      }
2770251883Speter      free(zSql);
2771251883Speter      zSql = 0;
2772251883Speter      nSql = 0;
2773251883Speter    }else if( zSql && _all_whitespace(zSql) ){
2774251883Speter      free(zSql);
2775251883Speter      zSql = 0;
2776251883Speter      nSql = 0;
2777251883Speter    }
2778251883Speter  }
2779251883Speter  if( zSql ){
2780251883Speter    if( !_all_whitespace(zSql) ){
2781251883Speter      fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
2782251883Speter    }
2783251883Speter    free(zSql);
2784251883Speter  }
2785251883Speter  free(zLine);
2786251883Speter  return errCnt>0;
2787251883Speter}
2788251883Speter
2789251883Speter/*
2790251883Speter** Return a pathname which is the user's home directory.  A
2791251883Speter** 0 return indicates an error of some kind.
2792251883Speter*/
2793251883Speterstatic char *find_home_dir(void){
2794251883Speter  static char *home_dir = NULL;
2795251883Speter  if( home_dir ) return home_dir;
2796251883Speter
2797251883Speter#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL)
2798251883Speter  {
2799251883Speter    struct passwd *pwent;
2800251883Speter    uid_t uid = getuid();
2801251883Speter    if( (pwent=getpwuid(uid)) != NULL) {
2802251883Speter      home_dir = pwent->pw_dir;
2803251883Speter    }
2804251883Speter  }
2805251883Speter#endif
2806251883Speter
2807251883Speter#if defined(_WIN32_WCE)
2808251883Speter  /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
2809251883Speter   */
2810251883Speter  home_dir = "/";
2811251883Speter#else
2812251883Speter
2813251883Speter#if defined(_WIN32) || defined(WIN32)
2814251883Speter  if (!home_dir) {
2815251883Speter    home_dir = getenv("USERPROFILE");
2816251883Speter  }
2817251883Speter#endif
2818251883Speter
2819251883Speter  if (!home_dir) {
2820251883Speter    home_dir = getenv("HOME");
2821251883Speter  }
2822251883Speter
2823251883Speter#if defined(_WIN32) || defined(WIN32)
2824251883Speter  if (!home_dir) {
2825251883Speter    char *zDrive, *zPath;
2826251883Speter    int n;
2827251883Speter    zDrive = getenv("HOMEDRIVE");
2828251883Speter    zPath = getenv("HOMEPATH");
2829251883Speter    if( zDrive && zPath ){
2830251883Speter      n = strlen30(zDrive) + strlen30(zPath) + 1;
2831251883Speter      home_dir = malloc( n );
2832251883Speter      if( home_dir==0 ) return 0;
2833251883Speter      sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
2834251883Speter      return home_dir;
2835251883Speter    }
2836251883Speter    home_dir = "c:\\";
2837251883Speter  }
2838251883Speter#endif
2839251883Speter
2840251883Speter#endif /* !_WIN32_WCE */
2841251883Speter
2842251883Speter  if( home_dir ){
2843251883Speter    int n = strlen30(home_dir) + 1;
2844251883Speter    char *z = malloc( n );
2845251883Speter    if( z ) memcpy(z, home_dir, n);
2846251883Speter    home_dir = z;
2847251883Speter  }
2848251883Speter
2849251883Speter  return home_dir;
2850251883Speter}
2851251883Speter
2852251883Speter/*
2853251883Speter** Read input from the file given by sqliterc_override.  Or if that
2854251883Speter** parameter is NULL, take input from ~/.sqliterc
2855251883Speter**
2856251883Speter** Returns the number of errors.
2857251883Speter*/
2858251883Speterstatic int process_sqliterc(
2859251883Speter  struct callback_data *p,        /* Configuration data */
2860251883Speter  const char *sqliterc_override   /* Name of config file. NULL to use default */
2861251883Speter){
2862251883Speter  char *home_dir = NULL;
2863251883Speter  const char *sqliterc = sqliterc_override;
2864251883Speter  char *zBuf = 0;
2865251883Speter  FILE *in = NULL;
2866251883Speter  int rc = 0;
2867251883Speter
2868251883Speter  if (sqliterc == NULL) {
2869251883Speter    home_dir = find_home_dir();
2870251883Speter    if( home_dir==0 ){
2871251883Speter#if !defined(__RTP__) && !defined(_WRS_KERNEL)
2872251883Speter      fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0);
2873251883Speter#endif
2874251883Speter      return 1;
2875251883Speter    }
2876251883Speter    sqlite3_initialize();
2877251883Speter    zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
2878251883Speter    sqliterc = zBuf;
2879251883Speter  }
2880251883Speter  in = fopen(sqliterc,"rb");
2881251883Speter  if( in ){
2882251883Speter    if( stdin_is_interactive ){
2883251883Speter      fprintf(stderr,"-- Loading resources from %s\n",sqliterc);
2884251883Speter    }
2885251883Speter    rc = process_input(p,in);
2886251883Speter    fclose(in);
2887251883Speter  }
2888251883Speter  sqlite3_free(zBuf);
2889251883Speter  return rc;
2890251883Speter}
2891251883Speter
2892251883Speter/*
2893251883Speter** Show available command line options
2894251883Speter*/
2895251883Speterstatic const char zOptions[] =
2896251883Speter  "   -bail                stop after hitting an error\n"
2897251883Speter  "   -batch               force batch I/O\n"
2898251883Speter  "   -column              set output mode to 'column'\n"
2899251883Speter  "   -cmd COMMAND         run \"COMMAND\" before reading stdin\n"
2900251883Speter  "   -csv                 set output mode to 'csv'\n"
2901251883Speter  "   -echo                print commands before execution\n"
2902251883Speter  "   -init FILENAME       read/process named file\n"
2903251883Speter  "   -[no]header          turn headers on or off\n"
2904251883Speter#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
2905251883Speter  "   -heap SIZE           Size of heap for memsys3 or memsys5\n"
2906251883Speter#endif
2907251883Speter  "   -help                show this message\n"
2908251883Speter  "   -html                set output mode to HTML\n"
2909251883Speter  "   -interactive         force interactive I/O\n"
2910251883Speter  "   -line                set output mode to 'line'\n"
2911251883Speter  "   -list                set output mode to 'list'\n"
2912251883Speter  "   -mmap N              default mmap size set to N\n"
2913251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX
2914251883Speter  "   -multiplex           enable the multiplexor VFS\n"
2915251883Speter#endif
2916251883Speter  "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
2917251883Speter  "   -separator SEP       set output field separator. Default: '|'\n"
2918251883Speter  "   -stats               print memory stats before each finalize\n"
2919251883Speter  "   -version             show SQLite version\n"
2920251883Speter  "   -vfs NAME            use NAME as the default VFS\n"
2921251883Speter#ifdef SQLITE_ENABLE_VFSTRACE
2922251883Speter  "   -vfstrace            enable tracing of all VFS calls\n"
2923251883Speter#endif
2924251883Speter;
2925251883Speterstatic void usage(int showDetail){
2926251883Speter  fprintf(stderr,
2927251883Speter      "Usage: %s [OPTIONS] FILENAME [SQL]\n"
2928251883Speter      "FILENAME is the name of an SQLite database. A new database is created\n"
2929251883Speter      "if the file does not previously exist.\n", Argv0);
2930251883Speter  if( showDetail ){
2931251883Speter    fprintf(stderr, "OPTIONS include:\n%s", zOptions);
2932251883Speter  }else{
2933251883Speter    fprintf(stderr, "Use the -help option for additional information\n");
2934251883Speter  }
2935251883Speter  exit(1);
2936251883Speter}
2937251883Speter
2938251883Speter/*
2939251883Speter** Initialize the state information in data
2940251883Speter*/
2941251883Speterstatic void main_init(struct callback_data *data) {
2942251883Speter  memset(data, 0, sizeof(*data));
2943251883Speter  data->mode = MODE_List;
2944251883Speter  memcpy(data->separator,"|", 2);
2945251883Speter  data->showHeader = 0;
2946251883Speter  sqlite3_config(SQLITE_CONFIG_URI, 1);
2947251883Speter  sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
2948251883Speter  sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
2949251883Speter  sqlite3_snprintf(sizeof(continuePrompt), continuePrompt,"   ...> ");
2950251883Speter  sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
2951251883Speter}
2952251883Speter
2953251883Speter/*
2954251883Speter** Get the argument to an --option.  Throw an error and die if no argument
2955251883Speter** is available.
2956251883Speter*/
2957251883Speterstatic char *cmdline_option_value(int argc, char **argv, int i){
2958251883Speter  if( i==argc ){
2959251883Speter    fprintf(stderr, "%s: Error: missing argument to %s\n",
2960251883Speter            argv[0], argv[argc-1]);
2961251883Speter    exit(1);
2962251883Speter  }
2963251883Speter  return argv[i];
2964251883Speter}
2965251883Speter
2966251883Speterint main(int argc, char **argv){
2967251883Speter  char *zErrMsg = 0;
2968251883Speter  struct callback_data data;
2969251883Speter  const char *zInitFile = 0;
2970251883Speter  char *zFirstCmd = 0;
2971251883Speter  int i;
2972251883Speter  int rc = 0;
2973251883Speter
2974251883Speter  if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
2975251883Speter    fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
2976251883Speter            sqlite3_sourceid(), SQLITE_SOURCE_ID);
2977251883Speter    exit(1);
2978251883Speter  }
2979251883Speter  Argv0 = argv[0];
2980251883Speter  main_init(&data);
2981251883Speter  stdin_is_interactive = isatty(0);
2982251883Speter
2983251883Speter  /* Make sure we have a valid signal handler early, before anything
2984251883Speter  ** else is done.
2985251883Speter  */
2986251883Speter#ifdef SIGINT
2987251883Speter  signal(SIGINT, interrupt_handler);
2988251883Speter#endif
2989251883Speter
2990251883Speter  /* Do an initial pass through the command-line argument to locate
2991251883Speter  ** the name of the database file, the name of the initialization file,
2992251883Speter  ** the size of the alternative malloc heap,
2993251883Speter  ** and the first command to execute.
2994251883Speter  */
2995251883Speter  for(i=1; i<argc; i++){
2996251883Speter    char *z;
2997251883Speter    z = argv[i];
2998251883Speter    if( z[0]!='-' ){
2999251883Speter      if( data.zDbFilename==0 ){
3000251883Speter        data.zDbFilename = z;
3001251883Speter        continue;
3002251883Speter      }
3003251883Speter      if( zFirstCmd==0 ){
3004251883Speter        zFirstCmd = z;
3005251883Speter        continue;
3006251883Speter      }
3007251883Speter      fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]);
3008251883Speter      fprintf(stderr,"Use -help for a list of options.\n");
3009251883Speter      return 1;
3010251883Speter    }
3011251883Speter    if( z[1]=='-' ) z++;
3012251883Speter    if( strcmp(z,"-separator")==0
3013251883Speter     || strcmp(z,"-nullvalue")==0
3014251883Speter     || strcmp(z,"-cmd")==0
3015251883Speter    ){
3016251883Speter      (void)cmdline_option_value(argc, argv, ++i);
3017251883Speter    }else if( strcmp(z,"-init")==0 ){
3018251883Speter      zInitFile = cmdline_option_value(argc, argv, ++i);
3019251883Speter    }else if( strcmp(z,"-batch")==0 ){
3020251883Speter      /* Need to check for batch mode here to so we can avoid printing
3021251883Speter      ** informational messages (like from process_sqliterc) before
3022251883Speter      ** we do the actual processing of arguments later in a second pass.
3023251883Speter      */
3024251883Speter      stdin_is_interactive = 0;
3025251883Speter    }else if( strcmp(z,"-heap")==0 ){
3026251883Speter#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
3027251883Speter      int j, c;
3028251883Speter      const char *zSize;
3029251883Speter      sqlite3_int64 szHeap;
3030251883Speter
3031251883Speter      zSize = cmdline_option_value(argc, argv, ++i);
3032251883Speter      szHeap = integerValue(zSize);
3033251883Speter      if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
3034251883Speter      sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
3035251883Speter#endif
3036251883Speter#ifdef SQLITE_ENABLE_VFSTRACE
3037251883Speter    }else if( strcmp(z,"-vfstrace")==0 ){
3038251883Speter      extern int vfstrace_register(
3039251883Speter         const char *zTraceName,
3040251883Speter         const char *zOldVfsName,
3041251883Speter         int (*xOut)(const char*,void*),
3042251883Speter         void *pOutArg,
3043251883Speter         int makeDefault
3044251883Speter      );
3045251883Speter      vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
3046251883Speter#endif
3047251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX
3048251883Speter    }else if( strcmp(z,"-multiplex")==0 ){
3049251883Speter      extern int sqlite3_multiple_initialize(const char*,int);
3050251883Speter      sqlite3_multiplex_initialize(0, 1);
3051251883Speter#endif
3052251883Speter    }else if( strcmp(z,"-mmap")==0 ){
3053251883Speter      sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
3054251883Speter      sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
3055251883Speter    }else if( strcmp(z,"-vfs")==0 ){
3056251883Speter      sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i));
3057251883Speter      if( pVfs ){
3058251883Speter        sqlite3_vfs_register(pVfs, 1);
3059251883Speter      }else{
3060251883Speter        fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
3061251883Speter        exit(1);
3062251883Speter      }
3063251883Speter    }
3064251883Speter  }
3065251883Speter  if( data.zDbFilename==0 ){
3066251883Speter#ifndef SQLITE_OMIT_MEMORYDB
3067251883Speter    data.zDbFilename = ":memory:";
3068251883Speter#else
3069251883Speter    fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
3070251883Speter    return 1;
3071251883Speter#endif
3072251883Speter  }
3073251883Speter  data.out = stdout;
3074251883Speter
3075251883Speter  /* Go ahead and open the database file if it already exists.  If the
3076251883Speter  ** file does not exist, delay opening it.  This prevents empty database
3077251883Speter  ** files from being created if a user mistypes the database name argument
3078251883Speter  ** to the sqlite command-line tool.
3079251883Speter  */
3080251883Speter  if( access(data.zDbFilename, 0)==0 ){
3081251883Speter    open_db(&data);
3082251883Speter  }
3083251883Speter
3084251883Speter  /* Process the initialization file if there is one.  If no -init option
3085251883Speter  ** is given on the command line, look for a file named ~/.sqliterc and
3086251883Speter  ** try to process it.
3087251883Speter  */
3088251883Speter  rc = process_sqliterc(&data,zInitFile);
3089251883Speter  if( rc>0 ){
3090251883Speter    return rc;
3091251883Speter  }
3092251883Speter
3093251883Speter  /* Make a second pass through the command-line argument and set
3094251883Speter  ** options.  This second pass is delayed until after the initialization
3095251883Speter  ** file is processed so that the command-line arguments will override
3096251883Speter  ** settings in the initialization file.
3097251883Speter  */
3098251883Speter  for(i=1; i<argc; i++){
3099251883Speter    char *z = argv[i];
3100251883Speter    if( z[0]!='-' ) continue;
3101251883Speter    if( z[1]=='-' ){ z++; }
3102251883Speter    if( strcmp(z,"-init")==0 ){
3103251883Speter      i++;
3104251883Speter    }else if( strcmp(z,"-html")==0 ){
3105251883Speter      data.mode = MODE_Html;
3106251883Speter    }else if( strcmp(z,"-list")==0 ){
3107251883Speter      data.mode = MODE_List;
3108251883Speter    }else if( strcmp(z,"-line")==0 ){
3109251883Speter      data.mode = MODE_Line;
3110251883Speter    }else if( strcmp(z,"-column")==0 ){
3111251883Speter      data.mode = MODE_Column;
3112251883Speter    }else if( strcmp(z,"-csv")==0 ){
3113251883Speter      data.mode = MODE_Csv;
3114251883Speter      memcpy(data.separator,",",2);
3115251883Speter    }else if( strcmp(z,"-separator")==0 ){
3116251883Speter      sqlite3_snprintf(sizeof(data.separator), data.separator,
3117251883Speter                       "%s",cmdline_option_value(argc,argv,++i));
3118251883Speter    }else if( strcmp(z,"-nullvalue")==0 ){
3119251883Speter      sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
3120251883Speter                       "%s",cmdline_option_value(argc,argv,++i));
3121251883Speter    }else if( strcmp(z,"-header")==0 ){
3122251883Speter      data.showHeader = 1;
3123251883Speter    }else if( strcmp(z,"-noheader")==0 ){
3124251883Speter      data.showHeader = 0;
3125251883Speter    }else if( strcmp(z,"-echo")==0 ){
3126251883Speter      data.echoOn = 1;
3127251883Speter    }else if( strcmp(z,"-stats")==0 ){
3128251883Speter      data.statsOn = 1;
3129251883Speter    }else if( strcmp(z,"-bail")==0 ){
3130251883Speter      bail_on_error = 1;
3131251883Speter    }else if( strcmp(z,"-version")==0 ){
3132251883Speter      printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
3133251883Speter      return 0;
3134251883Speter    }else if( strcmp(z,"-interactive")==0 ){
3135251883Speter      stdin_is_interactive = 1;
3136251883Speter    }else if( strcmp(z,"-batch")==0 ){
3137251883Speter      stdin_is_interactive = 0;
3138251883Speter    }else if( strcmp(z,"-heap")==0 ){
3139251883Speter      i++;
3140251883Speter    }else if( strcmp(z,"-mmap")==0 ){
3141251883Speter      i++;
3142251883Speter    }else if( strcmp(z,"-vfs")==0 ){
3143251883Speter      i++;
3144251883Speter#ifdef SQLITE_ENABLE_VFSTRACE
3145251883Speter    }else if( strcmp(z,"-vfstrace")==0 ){
3146251883Speter      i++;
3147251883Speter#endif
3148251883Speter#ifdef SQLITE_ENABLE_MULTIPLEX
3149251883Speter    }else if( strcmp(z,"-multiplex")==0 ){
3150251883Speter      i++;
3151251883Speter#endif
3152251883Speter    }else if( strcmp(z,"-help")==0 ){
3153251883Speter      usage(1);
3154251883Speter    }else if( strcmp(z,"-cmd")==0 ){
3155251883Speter      if( i==argc-1 ) break;
3156251883Speter      z = cmdline_option_value(argc,argv,++i);
3157251883Speter      if( z[0]=='.' ){
3158251883Speter        rc = do_meta_command(z, &data);
3159251883Speter        if( rc && bail_on_error ) return rc==2 ? 0 : rc;
3160251883Speter      }else{
3161251883Speter        open_db(&data);
3162251883Speter        rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
3163251883Speter        if( zErrMsg!=0 ){
3164251883Speter          fprintf(stderr,"Error: %s\n", zErrMsg);
3165251883Speter          if( bail_on_error ) return rc!=0 ? rc : 1;
3166251883Speter        }else if( rc!=0 ){
3167251883Speter          fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
3168251883Speter          if( bail_on_error ) return rc;
3169251883Speter        }
3170251883Speter      }
3171251883Speter    }else{
3172251883Speter      fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
3173251883Speter      fprintf(stderr,"Use -help for a list of options.\n");
3174251883Speter      return 1;
3175251883Speter    }
3176251883Speter  }
3177251883Speter
3178251883Speter  if( zFirstCmd ){
3179251883Speter    /* Run just the command that follows the database name
3180251883Speter    */
3181251883Speter    if( zFirstCmd[0]=='.' ){
3182251883Speter      rc = do_meta_command(zFirstCmd, &data);
3183251883Speter      if( rc==2 ) rc = 0;
3184251883Speter    }else{
3185251883Speter      open_db(&data);
3186251883Speter      rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
3187251883Speter      if( zErrMsg!=0 ){
3188251883Speter        fprintf(stderr,"Error: %s\n", zErrMsg);
3189251883Speter        return rc!=0 ? rc : 1;
3190251883Speter      }else if( rc!=0 ){
3191251883Speter        fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd);
3192251883Speter        return rc;
3193251883Speter      }
3194251883Speter    }
3195251883Speter  }else{
3196251883Speter    /* Run commands received from standard input
3197251883Speter    */
3198251883Speter    if( stdin_is_interactive ){
3199251883Speter      char *zHome;
3200251883Speter      char *zHistory = 0;
3201251883Speter      int nHistory;
3202251883Speter      printf(
3203251883Speter        "SQLite version %s %.19s\n" /*extra-version-info*/
3204251883Speter        "Enter \".help\" for instructions\n"
3205251883Speter        "Enter SQL statements terminated with a \";\"\n",
3206251883Speter        sqlite3_libversion(), sqlite3_sourceid()
3207251883Speter      );
3208251883Speter      zHome = find_home_dir();
3209251883Speter      if( zHome ){
3210251883Speter        nHistory = strlen30(zHome) + 20;
3211251883Speter        if( (zHistory = malloc(nHistory))!=0 ){
3212251883Speter          sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
3213251883Speter        }
3214251883Speter      }
3215251883Speter#if defined(HAVE_READLINE) && HAVE_READLINE==1
3216251883Speter      if( zHistory ) read_history(zHistory);
3217251883Speter#endif
3218251883Speter      rc = process_input(&data, 0);
3219251883Speter      if( zHistory ){
3220251883Speter        stifle_history(100);
3221251883Speter        write_history(zHistory);
3222251883Speter        free(zHistory);
3223251883Speter      }
3224251883Speter    }else{
3225251883Speter      rc = process_input(&data, stdin);
3226251883Speter    }
3227251883Speter  }
3228251883Speter  set_table_name(&data, 0);
3229251883Speter  if( data.db ){
3230251883Speter    sqlite3_close(data.db);
3231251883Speter  }
3232251883Speter  return rc;
3233251883Speter}
3234