typedef unsigned int u32;
typedef unsigned short int u16;
+/*
+** Limit input nesting via .read or any other input redirect.
+** It's not too expensive, so a generous allowance can be made.
+*/
+#define MAX_INPUT_NESTING 25
+
+/*
+** Used to prevent warnings about unused parameters
+*/
+#define UNUSED_PARAMETER(x) (void)(x)
+
+/*
+** Number of elements in an array
+*/
+#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
+
/*
** Optionally #include a user-defined header, whereby compilation options
** may be set prior to where they take effect, but after platform setup.
#endif
/*
-** Output routines that are able to redirect to memory rather than
-** doing actually I/O.
-** Works like.
-** --------------
-** cli_printf(FILE*, const char*, ...); fprintf()
-** cli_puts(const char*, FILE*); fputs()
-** cli_vprintf(FILE*, const char*, va_list); vfprintf()
-**
-** These are just thin wrappers with the following added semantics:
-** If the file-scope variable cli_output_capture is not NULL, and
-** if the FILE* argument is stdout or stderr, then rather than
-** writing to stdout/stdout, append the text to the cli_output_capture
-** variable.
-**
-** The cli_exit(int) routine works like exit() except that it
-** first dumps any capture output to stdout.
+** The source code for several run-time loadable extensions is inserted
+** below by the ../tool/mkshellc.tcl script. Before processing that included
+** code, we need to override some macros to make the included program code
+** work here in the middle of this regular program.
*/
-static sqlite3_str *cli_output_capture = 0;
-static int cli_printf(FILE *out, const char *zFormat, ...){
- va_list ap;
- int rc;
- va_start(ap,zFormat);
- if( cli_output_capture && (out==stdout || out==stderr) ){
- sqlite3_str_vappendf(cli_output_capture, zFormat, ap);
- rc = 1;
- }else{
- rc = sqlite3_vfprintf(out, zFormat, ap);
- }
- va_end(ap);
- return rc;
-}
-static int cli_puts(const char *zText, FILE *out){
- if( cli_output_capture && (out==stdout || out==stderr) ){
- sqlite3_str_appendall(cli_output_capture, zText);
- return 1;
- }
- return sqlite3_fputs(zText, out);
-}
-#if 0 /* Not currently used - available if we need it later */
-static int cli_vprintf(FILE *out, const char *zFormat, va_list ap){
- if( cli_output_capture && (out==stdout || out==stderr) ){
- sqlite3_str_vappendf(cli_output_capture, zFormat, ap);
- return 1;
- }else{
- return sqlite3_vfprintf(out, zFormat, ap);
- }
-}
-#endif
-static void cli_exit(int rc){
- if( cli_output_capture ){
- char *z = sqlite3_str_finish(cli_output_capture);
- sqlite3_fputs(z, stdout);
- fflush(stdout);
- }
- exit(rc);
-}
-
-
-#define eputz(z) cli_puts(z,stderr)
-#define sputz(fp,z) cli_puts(z,fp)
+#define SQLITE_EXTENSION_INIT1
+#define SQLITE_EXTENSION_INIT2(X) (void)(X)
-/* A version of strcmp() that works with NULL values */
-static int cli_strcmp(const char *a, const char *b){
- if( a==0 ) a = "";
- if( b==0 ) b = "";
- return strcmp(a,b);
-}
-static int cli_strncmp(const char *a, const char *b, size_t n){
- if( a==0 ) a = "";
- if( b==0 ) b = "";
- return strncmp(a,b,n);
-}
+INCLUDE ../ext/misc/windirent.h
+INCLUDE ../ext/misc/memtrace.c
+INCLUDE ../ext/misc/pcachetrace.c
+INCLUDE ../ext/misc/shathree.c
+INCLUDE ../ext/misc/sha1.c
+INCLUDE ../ext/misc/uint.c
+INCLUDE ../ext/misc/decimal.c
+INCLUDE ../ext/misc/base64.c
+INCLUDE ../ext/misc/base85.c
+INCLUDE ../ext/misc/ieee754.c
+INCLUDE ../ext/misc/series.c
+INCLUDE ../ext/misc/regexp.c
+#ifndef SQLITE_SHELL_FIDDLE
+INCLUDE ../ext/misc/fileio.c
+INCLUDE ../ext/misc/completion.c
+INCLUDE ../ext/misc/appendvfs.c
+#endif
+#ifdef SQLITE_HAVE_ZLIB
+INCLUDE ../ext/misc/zipfile.c
+INCLUDE ../ext/misc/sqlar.c
+#endif
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION)
+INCLUDE ../ext/expert/sqlite3expert.h
+INCLUDE ../ext/expert/sqlite3expert.c
+#endif
+INCLUDE ../ext/intck/sqlite3intck.h
+INCLUDE ../ext/intck/sqlite3intck.c
+INCLUDE ../ext/misc/stmtrand.c
+INCLUDE ../ext/misc/vfstrace.c
-/* Return the current wall-clock time in microseconds since the
-** Unix epoch (1970-01-01T00:00:00Z)
-*/
-static sqlite3_int64 timeOfDay(void){
-#if defined(_WIN64) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
- sqlite3_uint64 t;
- FILETIME tm;
- GetSystemTimePreciseAsFileTime(&tm);
- t = ((u64)tm.dwHighDateTime<<32) | (u64)tm.dwLowDateTime;
- t += 116444736000000000LL;
- t /= 10;
- return t;
-#elif defined(_WIN32)
- static sqlite3_vfs *clockVfs = 0;
- sqlite3_int64 t;
- if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
- if( clockVfs==0 ) return 0; /* Never actually happens */
- if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
- clockVfs->xCurrentTimeInt64(clockVfs, &t);
- }else{
- double r;
- clockVfs->xCurrentTime(clockVfs, &r);
- t = (sqlite3_int64)(r*86400000.0);
- }
- return t*1000;
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
+#define SQLITE_SHELL_HAVE_RECOVER 1
#else
- struct timeval sNow;
- (void)gettimeofday(&sNow,0);
- return ((i64)sNow.tv_sec)*1000000 + sNow.tv_usec;
+#define SQLITE_SHELL_HAVE_RECOVER 0
+#endif
+#if SQLITE_SHELL_HAVE_RECOVER
+INCLUDE ../ext/recover/sqlite3recover.h
+# ifndef SQLITE_HAVE_SQLITE3R
+INCLUDE ../ext/recover/dbdata.c
+INCLUDE ../ext/recover/sqlite3recover.c
+# endif /* SQLITE_HAVE_SQLITE3R */
+#endif
+#ifdef SQLITE_SHELL_EXTSRC
+# include SHELL_STRINGIFY(SQLITE_SHELL_EXTSRC)
#endif
-}
-
-
-/*
-** Used to prevent warnings about unused parameters
-*/
-#define UNUSED_PARAMETER(x) (void)(x)
-
-/*
-** Number of elements in an array
-*/
-#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
-
-/*
-** If the following flag is set, then command execution stops
-** at an error if we are not interactive.
-*/
-static int bail_on_error = 0;
-
-/*
-** Treat stdin as an interactive input if the following variable
-** is true. Otherwise, assume stdin is connected to a file or pipe.
-*/
-static int stdin_is_interactive = 1;
-
-/*
-** Treat stdout like a TTY if true.
-*/
-static int stdout_is_console = 1;
+#if defined(SQLITE_ENABLE_SESSION)
/*
-** Use this value as the width of the output device. Or, figure it
-** out at runtime if the value is negative. Or use a default width
-** if this value is zero.
+** State information for a single open session
*/
-static int stdout_tty_width = -1;
+typedef struct OpenSession OpenSession;
+struct OpenSession {
+ char *zName; /* Symbolic name for this session */
+ int nFilter; /* Number of xFilter rejection GLOB patterns */
+ char **azFilter; /* Array of xFilter rejection GLOB patterns */
+ sqlite3_session *p; /* The open session */
+};
+#endif
-/*
-** The following is the open SQLite database. We make a pointer
-** to this database a static variable so that it can be accessed
-** by the SIGINT handler to interrupt database processing.
-*/
-static sqlite3 *globalDb = 0;
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION)
+typedef struct ExpertInfo ExpertInfo;
+struct ExpertInfo {
+ sqlite3expert *pExpert;
+ int bVerbose;
+};
+#endif
-/*
-** True if an interrupt (Control-C) has been received.
+/* All the parameters that determine how to render query results.
*/
-static volatile int seenInterrupt = 0;
+typedef struct Mode {
+ u8 autoExplain; /* Automatically turn on .explain mode */
+ u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to each SQL stmt */
+ u8 autoEQPtrace; /* autoEQP is in trace mode */
+ u8 scanstatsOn; /* True to display scan stats before each finalize */
+ u8 bAutoScreenWidth; /* Using the TTY to determine screen width */
+ u8 mFlags; /* MFLG_ECHO, MFLG_CRLF, etc. */
+ u8 eMode; /* One of the MODE_ values */
+ sqlite3_qrf_spec spec; /* Spec to be passed into QRF */
+} Mode;
-/*
-** This is the name of our program. It is set in main(), used
-** in a number of other places, mostly for error messages.
-*/
-static char *Argv0;
+/* Flags for Mode.mFlags */
+#define MFLG_ECHO 0x01 /* Echo inputs to output */
+#define MFLG_CRLF 0x02 /* Use CR/LF output line endings */
+#define MFLG_HDR 0x04 /* .header used to change headers on/off */
-/*
-** Prompt strings. Initialized in main. Settable with
-** .prompt main continue
-*/
-#define PROMPT_LEN_MAX 128
-/* First line prompt. default: "sqlite> " */
-static char mainPrompt[PROMPT_LEN_MAX];
-/* Continuation prompt. default: " ...> " */
-static char continuePrompt[PROMPT_LEN_MAX];
/*
-** Write I/O traces to the following stream.
+** State information about the database connection is contained in an
+** instance of the following structure.
*/
-#ifdef SQLITE_ENABLE_IOTRACE
-static FILE *iotrace = 0;
-#endif
+typedef struct ShellState ShellState;
+struct ShellState {
+ sqlite3 *db; /* The database */
+ u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
+ u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */
+ u8 nEqpLevel; /* Depth of the EQP output graph */
+ u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
+ u8 bSafeMode; /* True to prohibit unsafe operations */
+ u8 bSafeModePersist; /* The long-term value of bSafeMode */
+ u8 eRestoreState; /* See comments above doAutoDetectRestore() */
+ unsigned statsOn; /* True to display memory stats before each finalize */
+ unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
+ u8 nPopOutput; /* Revert .output settings when reaching zero */
+ u8 nPopMode; /* Revert .mode settings when reaching zero */
+ u8 enableTimer; /* Enable the timer. 2: permanently 1: only once */
+ int inputNesting; /* Track nesting level of .read and other redirects */
+ double prevTimer; /* Last reported timer value */
+ double tmProgress; /* --timeout option for .progress */
+ i64 lineno; /* Line number of last line read from in */
+ const char *zInFile; /* Name of the input file */
+ int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */
+ FILE *in; /* Read commands from this stream */
+ FILE *out; /* Write results here */
+ FILE *traceOut; /* Output for sqlite3_trace() */
+ int nErr; /* Number of errors seen */
+ int writableSchema; /* True if PRAGMA writable_schema=ON */
+ int nCheck; /* Number of ".check" commands run */
+ unsigned nProgress; /* Number of progress callbacks encountered */
+ unsigned mxProgress; /* Maximum progress callbacks before failing */
+ unsigned flgProgress; /* Flags for the progress callback */
+ unsigned shellFlgs; /* Various flags */
+ unsigned nTestRun; /* Number of test cases run */
+ unsigned nTestErr; /* Number of test cases that failed */
+ sqlite3_int64 szMax; /* --maxsize argument to .open */
+ char *zDestTable; /* Name of destination table when MODE_Insert */
+ char *zTempFile; /* Temporary file that might need deleting */
+ char *zErrPrefix; /* Alternative error message prefix */
+ char zTestcase[30]; /* Name of current test case */
+ char outfile[FILENAME_MAX]; /* Filename for *out */
+ sqlite3_stmt *pStmt; /* Current statement if any. */
+ FILE *pLog; /* Write log output here */
+ Mode mode; /* Current display mode */
+ Mode modePrior; /* Backup */
+ struct SavedMode { /* Ability to define custom mode configurations */
+ char *zTag; /* Name of this saved mode */
+ Mode mode; /* The saved mode */
+ } *aSavedModes; /* Array of saved .mode settings. system malloc() */
+ int nSavedModes; /* Number of saved .mode settings */
+ struct AuxDb { /* Storage space for auxiliary database connections */
+ sqlite3 *db; /* Connection pointer */
+ const char *zDbFilename; /* Filename used to open the connection */
+ char *zFreeOnClose; /* Free this memory allocation on close */
+#if defined(SQLITE_ENABLE_SESSION)
+ int nSession; /* Number of active sessions */
+ OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */
+#endif
+ } aAuxDb[5], /* Array of all database connections */
+ *pAuxDb; /* Currently active database connection */
+ char *zNonce; /* Nonce for temporary safe-mode escapes */
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION)
+ ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */
+#endif
+ struct DotCmdLine { /* Info about arguments to a dot-command */
+ const char *zOrig; /* Original text of the dot-command */
+ char *zCopy; /* Copy of zOrig, from malloc() */
+ int nAlloc; /* Size of allocates for arrays below */
+ int nArg; /* Number of argument slots actually used */
+ char **azArg; /* Pointer to each argument, dequoted */
+ int *aiOfst; /* Offset into zOrig[] for start of each arg */
+ char *abQuot; /* True if the argment was originally quoted */
+ } dot;
+#ifdef SQLITE_SHELL_FIDDLE
+ struct {
+ const char * zInput; /* Input string from wasm/JS proxy */
+ const char * zPos; /* Cursor pos into zInput */
+ const char * zDefaultDbName; /* Default name for db file */
+ } wasm;
+#endif
+};
+#ifdef SQLITE_SHELL_FIDDLE
+static ShellState shellState;
+#endif
-/* This is variant of the standard-library strncpy() routine with the
-** one change that the destination string is always zero-terminated, even
-** if there is no zero-terminator in the first n-1 characters of the source
-** string.
-*/
-static char *shell_strncpy(char *dest, const char *src, size_t n){
- size_t i;
- for(i=0; i<n-1 && src[i]!=0; i++) dest[i] = src[i];
- dest[i] = 0;
- return dest;
-}
-/*
-** strcpy() workalike to squelch an unwarranted link-time warning
-** from OpenBSD.
+/* Allowed values for ShellState.mode.autoEQP
*/
-static void shell_strcpy(char *dest, const char *src){
- while( (*(dest++) = *(src++))!=0 ){}
-}
+#define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */
+#define AUTOEQP_on 1 /* Automatic EQP is on */
+#define AUTOEQP_trigger 2 /* On and also show plans for triggers */
+#define AUTOEQP_full 3 /* Show full EXPLAIN */
-/*
-** Optionally disable dynamic continuation prompt.
-** Unless disabled, the continuation prompt shows open SQL lexemes if any,
-** or open parentheses level if non-zero, or continuation prompt as set.
-** This facility interacts with the scanner and process_input() where the
-** below 5 macros are used.
+/* Allowed values for ShellState.openMode
*/
-#ifdef SQLITE_OMIT_DYNAPROMPT
-# define CONTINUATION_PROMPT continuePrompt
-# define CONTINUE_PROMPT_RESET
-# define CONTINUE_PROMPT_AWAITS(p,s)
-# define CONTINUE_PROMPT_AWAITC(p,c)
-# define CONTINUE_PAREN_INCR(p,n)
-# define CONTINUE_PROMPT_PSTATE 0
-typedef void *t_NoDynaPrompt;
-# define SCAN_TRACKER_REFTYPE t_NoDynaPrompt
-#else
-# define CONTINUATION_PROMPT dynamicContinuePrompt()
-# define CONTINUE_PROMPT_RESET \
- do {setLexemeOpen(&dynPrompt,0,0); trackParenLevel(&dynPrompt,0);} while(0)
-# define CONTINUE_PROMPT_AWAITS(p,s) \
- if(p && stdin_is_interactive) setLexemeOpen(p, s, 0)
-# define CONTINUE_PROMPT_AWAITC(p,c) \
- if(p && stdin_is_interactive) setLexemeOpen(p, 0, c)
-# define CONTINUE_PAREN_INCR(p,n) \
- if(p && stdin_is_interactive) (trackParenLevel(p,n))
-# define CONTINUE_PROMPT_PSTATE (&dynPrompt)
-typedef struct DynaPrompt *t_DynaPromptRef;
-# define SCAN_TRACKER_REFTYPE t_DynaPromptRef
-
-static struct DynaPrompt {
- char dynamicPrompt[PROMPT_LEN_MAX];
- char acAwait[2];
- int inParenLevel;
- char *zScannerAwaits;
-} dynPrompt = { {0}, {0}, 0, 0 };
-
-/* Record parenthesis nesting level change, or force level to 0. */
-static void trackParenLevel(struct DynaPrompt *p, int ni){
- p->inParenLevel += ni;
- if( ni==0 ) p->inParenLevel = 0;
- p->zScannerAwaits = 0;
-}
+#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */
+#define SHELL_OPEN_NORMAL 1 /* Normal database file */
+#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */
+#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */
+#define SHELL_OPEN_DESERIALIZE 4 /* Open using sqlite3_deserialize() */
+#define SHELL_OPEN_HEXDB 5 /* Use "dbtotxt" output as data source */
-/* Record that a lexeme is opened, or closed with args==0. */
-static void setLexemeOpen(struct DynaPrompt *p, char *s, char c){
- if( s!=0 || c==0 ){
- p->zScannerAwaits = s;
- p->acAwait[0] = 0;
- }else{
- p->acAwait[0] = c;
- p->zScannerAwaits = p->acAwait;
- }
-}
+/* Allowed values for ShellState.eTraceType
+*/
+#define SHELL_TRACE_PLAIN 0 /* Show input SQL text */
+#define SHELL_TRACE_EXPANDED 1 /* Show expanded SQL text */
+#define SHELL_TRACE_NORMALIZED 2 /* Show normalized SQL text */
-/* Upon demand, derive the continuation prompt to display. */
-static char *dynamicContinuePrompt(void){
- if( continuePrompt[0]==0
- || (dynPrompt.zScannerAwaits==0 && dynPrompt.inParenLevel == 0) ){
- return continuePrompt;
- }else{
- if( dynPrompt.zScannerAwaits ){
- size_t ncp = strlen(continuePrompt);
- size_t ndp = strlen(dynPrompt.zScannerAwaits);
- if( ndp > ncp-3 ) return continuePrompt;
- shell_strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
- while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' ';
- shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
- PROMPT_LEN_MAX-4);
- }else{
- if( dynPrompt.inParenLevel>9 ){
- shell_strncpy(dynPrompt.dynamicPrompt, "(..", 4);
- }else if( dynPrompt.inParenLevel<0 ){
- shell_strncpy(dynPrompt.dynamicPrompt, ")x!", 4);
- }else{
- shell_strncpy(dynPrompt.dynamicPrompt, "(x.", 4);
- dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel);
- }
- shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
- PROMPT_LEN_MAX-4);
- }
- }
- return dynPrompt.dynamicPrompt;
-}
-#endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */
+/* Bits in the ShellState.flgProgress variable */
+#define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */
+#define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progress
+ ** callback limit is reached, and for each
+ ** top-level SQL statement */
+#define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
+#define SHELL_PROGRESS_TMOUT 0x08 /* Stop after tmProgress seconds */
-/* Indicate out-of-memory and exit. */
-static void shell_out_of_memory(void){
- eputz("Error: out of memory\n");
- cli_exit(1);
-}
+/* Names of values for Mode.spec.eEsc and Mode.spec.eText
+*/
+static const char *qrfEscNames[] = { "auto", "off", "ascii", "symbol" };
+static const char *qrfQuoteNames[] =
+ { "off","off","sql","hex","csv","tcl","json","relaxed"};
-/* Check a pointer to see if it is NULL. If it is NULL, exit with an
-** out-of-memory error.
+/*
+** These are the allowed shellFlgs values
*/
-static void shell_check_oom(const void *p){
- if( p==0 ) shell_out_of_memory();
-}
+#define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
+#define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
+#define SHFLG_Backslash 0x00000004 /* The --backslash option is used */
+#define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */
+#define SHFLG_NoErrLineno 0x00000010 /* Omit line numbers from error msgs */
+#define SHFLG_CountChanges 0x00000020 /* .changes setting */
+#define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */
+#define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */
+#define SHFLG_TestingMode 0x00000400 /* allow unsafe testing features */
/*
-** This routine works like printf in that its first argument is a
-** format string and subsequent arguments are values to be substituted
-** in place of % fields. The result of formatting this string
-** is written to iotrace.
+** Macros for testing and setting shellFlgs
*/
-#ifdef SQLITE_ENABLE_IOTRACE
-static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
- va_list ap;
- char *z;
- if( iotrace==0 ) return;
- va_start(ap, zFormat);
- z = sqlite3_vmprintf(zFormat, ap);
- va_end(ap);
- cli_printf(iotrace, "%s", z);
- sqlite3_free(z);
-}
-#endif
+#define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0)
+#define ShellSetFlag(P,X) ((P)->shellFlgs|=(X))
+#define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X)))
/*
-** Compute a string length that is limited to what can be stored in
-** lower 30 bits of a 32-bit signed integer.
+** These are the allowed values for Mode.eMode. There is a lot of overlap
+** between these values and the Mode.spec.eStyle values, but they are not
+** one-to-one, and thus need to be tracked separately.
*/
-static int strlen30(const char *z){
- size_t n;
- if( z==0 ) return 0;
- n = strlen(z);
- return n>0x3fffffff ? 0x3fffffff : (int)n;
-}
+#define MODE_Ascii 0 /* Use ASCII unit and record separators (0x1F/0x1E) */
+#define MODE_Box 1 /* Unicode box-drawing characters */
+#define MODE_C 2 /* Comma-separated list of C-strings */
+#define MODE_Column 3 /* One record per line in neat columns */
+#define MODE_Count 4 /* Output only a count of the rows of output */
+#define MODE_Csv 5 /* Quote strings, numbers are plain */
+#define MODE_Html 6 /* Generate an XHTML table */
+#define MODE_Insert 7 /* Generate SQL "insert" statements */
+#define MODE_JAtom 8 /* Comma-separated list of JSON atoms */
+#define MODE_JObject 9 /* One JSON object per row */
+#define MODE_Json 10 /* Output JSON */
+#define MODE_Line 11 /* One column per line. Blank line between records */
+#define MODE_List 12 /* One record per line with a separator */
+#define MODE_Markdown 13 /* Markdown formatting */
+#define MODE_Off 14 /* No query output shown */
+#define MODE_Psql 15 /* Similar to psql */
+#define MODE_QBox 16 /* BOX with SQL-quoted content */
+#define MODE_Quote 17 /* Quote values as for SQL */
+#define MODE_Split 18 /* Split-column mode */
+#define MODE_Table 19 /* MySQL-style table formatting */
+#define MODE_Tabs 20 /* Tab-separated values */
+#define MODE_Tcl 21 /* Space-separated list of TCL strings */
+#define MODE_Www 22 /* Full web-page output */
+
+#define MODE_BUILTIN 22 /* Maximum built-in mode */
+#define MODE_BATCH 50 /* Default mode for batch processing */
+#define MODE_TTY 51 /* Default mode for interactive processing */
+#define MODE_USER 75 /* First user-defined mode */
+#define MODE_N_USER 25 /* Maximum number of user-defined modes */
/*
-** Return open FILE * if zFile exists, can be opened for read
-** and is an ordinary file or a character stream source.
-** Otherwise return 0.
+** Information about built-in display modes
*/
-static FILE * openChrSource(const char *zFile){
-#if defined(_WIN32) || defined(WIN32)
- struct __stat64 x = {0};
-# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
- /* On Windows, open first, then check the stream nature. This order
- ** is necessary because _stat() and sibs, when checking a named pipe,
- ** effectively break the pipe as its supplier sees it. */
- FILE *rv = sqlite3_fopen(zFile, "rb");
- if( rv==0 ) return 0;
- if( _fstat64(_fileno(rv), &x) != 0
- || !STAT_CHR_SRC(x.st_mode)){
- fclose(rv);
- rv = 0;
- }
- return rv;
-#else
- struct stat x = {0};
- int rc = stat(zFile, &x);
-# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
- if( rc!=0 ) return 0;
- if( STAT_CHR_SRC(x.st_mode) ){
- return sqlite3_fopen(zFile, "rb");
- }else{
- return 0;
- }
-#endif
-#undef STAT_CHR_SRC
-}
+typedef struct ModeInfo ModeInfo;
+struct ModeInfo {
+ char zName[9]; /* Symbolic name of the mode */
+ unsigned char eCSep; /* Column separator */
+ unsigned char eRSep; /* Row separator */
+ unsigned char eNull; /* Null representation */
+ unsigned char eText; /* Default text encoding */
+ unsigned char eHdr; /* Default header encoding. */
+ unsigned char eBlob; /* Default blob encoding. */
+ unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */
+ unsigned char eStyle; /* Underlying QRF style */
+ unsigned char eCx; /* 0: other, 1: line, 2: columnar */
+ unsigned char mFlg; /* Flags. 1=border-off 2=split-column */
+};
+
+/* String constants used by built-in modes */
+static const char *aModeStr[] =
+ /* 0 1 2 3 4 5 6 7 8 */
+ { 0, "\n", "|", " ", ",", "\r\n", "\036", "\037", "\t",
+ "", "NULL", "null", "\"\"", ": ", };
+ /* 9 10 11 12 13 */
+static const ModeInfo aModeInfo[] = {
+/* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */
+ { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 },
+ { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2, 0 },
+ { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 },
+ { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2, 0 },
+ { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
+ { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 },
+ { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 },
+ { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 },
+ { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 },
+ { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 },
+ { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 },
+ { "line", 13, 1, 9, 1, 1, 0, 0, 11, 1, 0 },
+ { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 },
+ { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2, 0 },
+ { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 },
+ { "psql", 0, 0, 9, 1, 1, 0, 2, 19, 2, 1 },
+ { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2, 0 },
+ { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 },
+ { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 },
+ { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2, 0 },
+ { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 },
+ { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 },
+ { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 }
+}; /* | / / | / / | | \
+ ** | / / | / / | | \_ 2: columnar
+ ** Index into aModeStr[] | / / | | 1: line
+ ** | / / | | 0: other
+ ** | / / | \
+ ** text encoding |/ | show | \
+ ** v-------------------' | hdrs? | The QRF style
+ ** 0: n/a blob | v-----'
+ ** 1: plain v_---------' 0: n/a
+ ** 2: sql 0: auto 1: no
+ ** 3: csv 1: as-text 2: yes
+ ** 4: html 2: sql
+ ** 5: c 3: hex
+ ** 6: json 4: c
+ ** 5: json
+ ** 6: size
+ ******************************************************************/
/*
-** This routine reads a line of text from FILE in, stores
-** the text in memory obtained from malloc() and returns a pointer
-** to the text. NULL is returned at end of file, or if malloc()
-** fails, or if the length of the line is longer than about a gigabyte.
-**
-** If zLine is not NULL then it is a malloced buffer returned from
-** a previous call to this routine that may be reused.
+** These are the column/row/line separators used by the various
+** import/export modes.
*/
-static char *local_getline(char *zLine, FILE *in){
- int nLine = zLine==0 ? 0 : 100;
- int n = 0;
-
- while( 1 ){
- if( n+100>nLine ){
- if( nLine>=1073741773 ){
- free(zLine);
- return 0;
- }
- nLine = nLine*2 + 100;
- zLine = realloc(zLine, nLine);
- shell_check_oom(zLine);
- }
- if( sqlite3_fgets(&zLine[n], nLine - n, in)==0 ){
- if( n==0 ){
- free(zLine);
- return 0;
- }
- zLine[n] = 0;
- break;
- }
- while( zLine[n] ) n++;
- if( n>0 && zLine[n-1]=='\n' ){
- n--;
- if( n>0 && zLine[n-1]=='\r' ) n--;
- zLine[n] = 0;
- break;
- }
- }
- return zLine;
-}
+#define SEP_Column "|"
+#define SEP_Row "\n"
+#define SEP_Tab "\t"
+#define SEP_Space " "
+#define SEP_Comma ","
+#define SEP_CrLf "\r\n"
+#define SEP_Unit "\x1F"
+#define SEP_Record "\x1E"
/*
-** Retrieve a single line of input text.
-**
-** If in==0 then read from standard input and prompt before each line.
-** If isContinuation is true, then a continuation prompt is appropriate.
-** If isContinuation is zero, then the main prompt should be used.
-**
-** If zPrior is not NULL then it is a buffer from a prior call to this
-** routine that can be reused.
-**
-** The result is stored in space obtained from malloc() and must either
-** be freed by the caller or else passed back into this routine via the
-** zPrior argument for reuse.
+** Default values for the various QRF limits
*/
-#ifndef SQLITE_SHELL_FIDDLE
-static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
- char *zPrompt;
- char *zResult;
- if( in!=0 ){
- zResult = local_getline(zPrior, in);
- }else{
- zPrompt = isContinuation ? CONTINUATION_PROMPT : mainPrompt;
-#if SHELL_USE_LOCAL_GETLINE
- sputz(stdout, zPrompt);
- fflush(stdout);
- do{
- zResult = local_getline(zPrior, stdin);
- zPrior = 0;
- /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
- if( zResult==0 ) sqlite3_sleep(50);
- }while( zResult==0 && seenInterrupt>0 );
-#else
- free(zPrior);
- zResult = shell_readline(zPrompt);
- while( zResult==0 ){
- /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
- sqlite3_sleep(50);
- if( seenInterrupt==0 ) break;
- zResult = shell_readline("");
- }
- if( zResult && *zResult ) shell_add_history(zResult);
+#ifndef DFLT_CHAR_LIMIT
+# define DFLT_CHAR_LIMIT 300
+#endif
+#ifndef DFLT_LINE_LIMIT
+# define DFLT_LINE_LIMIT 5
+#endif
+#ifndef DFLT_TITLE_LIMIT
+# define DFLT_TITLE_LIMIT 20
+#endif
+#ifndef DFLT_MULTI_INSERT
+# define DFLT_MULTI_INSERT 3000
#endif
- }
- return zResult;
-}
-#endif /* !SQLITE_SHELL_FIDDLE */
/*
-** Return the value of a hexadecimal digit. Return -1 if the input
-** is not a hex digit.
+** If the following flag is set, then command execution stops
+** at an error if we are not interactive.
*/
-static int hexDigitValue(char c){
- if( c>='0' && c<='9' ) return c - '0';
- if( c>='a' && c<='f' ) return c - 'a' + 10;
- if( c>='A' && c<='F' ) return c - 'A' + 10;
- return -1;
-}
+static int bail_on_error = 0;
/*
-** Interpret zArg as an integer value, possibly with suffixes.
-**
-** If the value specified by zArg is outside the range of values that
-** can be represented using a 64-bit twos-complement integer, then return
-** the nearest representable value.
+** Treat stdin as an interactive input if the following variable
+** is true. Otherwise, assume stdin is connected to a file or pipe.
*/
-static sqlite3_int64 integerValue(const char *zArg){
- sqlite3_uint64 v = 0;
- static const struct { char *zSuffix; unsigned int iMult; } aMult[] = {
- { "KiB", 1024 },
- { "MiB", 1024*1024 },
- { "GiB", 1024*1024*1024 },
- { "KB", 1000 },
- { "MB", 1000000 },
- { "GB", 1000000000 },
- { "K", 1000 },
- { "M", 1000000 },
- { "G", 1000000000 },
- };
- int i;
- int isNeg = 0;
- if( zArg[0]=='-' ){
- isNeg = 1;
- zArg++;
- }else if( zArg[0]=='+' ){
- zArg++;
- }
- if( zArg[0]=='0' && zArg[1]=='x' ){
- int x;
- zArg += 2;
- while( (x = hexDigitValue(zArg[0]))>=0 ){
- if( v > 0x0fffffffffffffffULL ) goto integer_overflow;
- v = (v<<4) + x;
- zArg++;
- }
- }else{
- while( IsDigit(zArg[0]) ){
- if( v>=922337203685477580LL ){
- if( v>922337203685477580LL || zArg[0]>='8' ) goto integer_overflow;
- }
- v = v*10 + (zArg[0] - '0');
- zArg++;
- }
- }
- for(i=0; i<ArraySize(aMult); i++){
- if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
- if( 0x7fffffffffffffffULL/aMult[i].iMult < v ) goto integer_overflow;
- v *= aMult[i].iMult;
- break;
- }
- }
- if( isNeg && v>0x7fffffffffffffffULL ) goto integer_overflow;
- return isNeg? -(sqlite3_int64)v : (sqlite3_int64)v;
-integer_overflow:
- return isNeg ? (i64)0x8000000000000000LL : 0x7fffffffffffffffLL;
-}
+static int stdin_is_interactive = 1;
/*
-** A variable length string to which one can append text.
+** Treat stdout like a TTY if true.
*/
-typedef struct ShellText ShellText;
-struct ShellText {
- char *zTxt; /* The text */
- i64 n; /* Number of bytes of zTxt[] actually used */
- i64 nAlloc; /* Number of bytes allocated for zTxt[] */
-};
+static int stdout_is_console = 1;
/*
-** Initialize and destroy a ShellText object
+** Use this value as the width of the output device. Or, figure it
+** out at runtime if the value is negative. Or use a default width
+** if this value is zero.
*/
-static void initText(ShellText *p){
- memset(p, 0, sizeof(*p));
-}
-static void freeText(ShellText *p){
- sqlite3_free(p->zTxt);
- initText(p);
-}
+static int stdout_tty_width = -1;
-/* zIn is either a pointer to a NULL-terminated string in memory obtained
-** from malloc(), or a NULL pointer. The string pointed to by zAppend is
-** added to zIn, and the result returned in memory obtained from malloc().
-** zIn, if it was not NULL, is freed.
-**
-** If the third argument, quote, is not '\0', then it is used as a
-** quote character for zAppend.
+/*
+** The following is the open SQLite database. We make a pointer
+** to this database a static variable so that it can be accessed
+** by the SIGINT handler to interrupt database processing.
*/
-static void appendText(ShellText *p, const char *zAppend, char quote){
- i64 len;
- i64 i;
- i64 nAppend = strlen30(zAppend);
-
- len = nAppend+p->n+1;
- if( quote ){
- len += 2;
- for(i=0; i<nAppend; i++){
- if( zAppend[i]==quote ) len++;
- }
- }
-
- if( p->zTxt==0 || p->n+len>=p->nAlloc ){
- p->nAlloc = p->nAlloc*2 + len + 20;
- p->zTxt = sqlite3_realloc64(p->zTxt, p->nAlloc);
- shell_check_oom(p->zTxt);
- }
-
- if( quote ){
- char *zCsr = p->zTxt+p->n;
- *zCsr++ = quote;
- for(i=0; i<nAppend; i++){
- *zCsr++ = zAppend[i];
- if( zAppend[i]==quote ) *zCsr++ = quote;
- }
- *zCsr++ = quote;
- p->n = (i64)(zCsr - p->zTxt);
- *zCsr = '\0';
- }else{
- memcpy(p->zTxt+p->n, zAppend, nAppend);
- p->n += nAppend;
- p->zTxt[p->n] = '\0';
- }
-}
+static sqlite3 *globalDb = 0;
/*
-** Attempt to determine if identifier zName needs to be quoted, either
-** because it contains non-alphanumeric characters, or because it is an
-** SQLite keyword. Be conservative in this estimate: When in doubt assume
-** that quoting is required.
-**
-** Return '"' if quoting is required. Return 0 if no quoting is required.
+** True if an interrupt (Control-C) has been received.
*/
-static char quoteChar(const char *zName){
- int i;
- if( zName==0 ) return '"';
- if( !IsAlpha(zName[0]) && zName[0]!='_' ) return '"';
- for(i=0; zName[i]; i++){
- if( !IsAlnum(zName[i]) && zName[i]!='_' ) return '"';
- }
- return sqlite3_keyword_check(zName, i) ? '"' : 0;
-}
+static volatile int seenInterrupt = 0;
/*
-** Construct a fake object name and column list to describe the structure
-** of the view, virtual table, or table valued function zSchema.zName.
-**
-** The returned string comes from sqlite3_mprintf() and should be freed
-** by the caller using sqlite3_free().
+** This is the name of our program. It is set in main(), used
+** in a number of other places, mostly for error messages.
*/
-static char *shellFakeSchema(
- sqlite3 *db, /* The database connection containing the vtab */
- const char *zSchema, /* Schema of the database holding the vtab */
- const char *zName /* The name of the virtual table */
-){
- sqlite3_stmt *pStmt = 0;
- char *zSql;
- ShellText s;
- char cQuote;
- char *zDiv = "(";
- int nRow = 0;
-
- zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
- zSchema ? zSchema : "main", zName);
- shell_check_oom(zSql);
- sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
- sqlite3_free(zSql);
- initText(&s);
- if( zSchema ){
- cQuote = quoteChar(zSchema);
- if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0;
- appendText(&s, zSchema, cQuote);
- appendText(&s, ".", 0);
- }
- cQuote = quoteChar(zName);
- appendText(&s, zName, cQuote);
- while( sqlite3_step(pStmt)==SQLITE_ROW ){
- const char *zCol = (const char*)sqlite3_column_text(pStmt, 1);
- nRow++;
- appendText(&s, zDiv, 0);
- zDiv = ",";
- if( zCol==0 ) zCol = "";
- cQuote = quoteChar(zCol);
- appendText(&s, zCol, cQuote);
- }
- appendText(&s, ")", 0);
- sqlite3_finalize(pStmt);
- if( nRow==0 ){
- freeText(&s);
- s.zTxt = 0;
- }
- return s.zTxt;
-}
+static char *Argv0;
/*
-** SQL function: strtod(X)
-**
-** Use the C-library strtod() function to convert string X into a double.
-** Used for comparing the accuracy of SQLite's internal text-to-float conversion
-** routines against the C-library.
+** Prompt strings. Initialized in main. Settable with
+** .prompt main continue
*/
-static void shellStrtod(
- sqlite3_context *pCtx,
- int nVal,
- sqlite3_value **apVal
-){
- char *z = (char*)sqlite3_value_text(apVal[0]);
- UNUSED_PARAMETER(nVal);
- if( z==0 ) return;
- sqlite3_result_double(pCtx, strtod(z,0));
-}
+#define PROMPT_LEN_MAX 128
+/* First line prompt. default: "sqlite> " */
+static char mainPrompt[PROMPT_LEN_MAX];
+/* Continuation prompt. default: " ...> " */
+static char continuePrompt[PROMPT_LEN_MAX];
/*
-** SQL function: dtostr(X)
-**
-** Use the C-library printf() function to convert real value X into a string.
-** Used for comparing the accuracy of SQLite's internal float-to-text conversion
-** routines against the C-library.
+** Write I/O traces to the following stream.
*/
-static void shellDtostr(
- sqlite3_context *pCtx,
- int nVal,
- sqlite3_value **apVal
-){
- double r = sqlite3_value_double(apVal[0]);
- int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26;
- char z[400];
- if( n<1 ) n = 1;
- if( n>350 ) n = 350;
- sprintf(z, "%#+.*e", n, r);
- sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
-}
+#ifdef SQLITE_ENABLE_IOTRACE
+static FILE *iotrace = 0;
+#endif
/*
-** SQL function: shell_add_schema(S,X)
-**
-** Add the schema name X to the CREATE statement in S and return the result.
-** Examples:
-**
-** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x);
-**
-** Also works on
+** Output routines that are able to redirect to memory rather than
+** doing actually I/O.
+** Works like.
+** --------------
+** cli_printf(FILE*, const char*, ...); fprintf()
+** cli_puts(const char*, FILE*); fputs()
+** cli_vprintf(FILE*, const char*, va_list); vfprintf()
**
-** CREATE INDEX
-** CREATE UNIQUE INDEX
-** CREATE VIEW
-** CREATE TRIGGER
-** CREATE VIRTUAL TABLE
+** These are just thin wrappers with the following added semantics:
+** If the file-scope variable cli_output_capture is not NULL, and
+** if the FILE* argument is stdout or stderr, then rather than
+** writing to stdout/stdout, append the text to the cli_output_capture
+** variable.
**
-** This UDF is used by the .schema command to insert the schema name of
-** attached databases into the middle of the sqlite_schema.sql field.
+** The cli_exit(int) routine works like exit() except that it
+** first dumps any capture output to stdout.
*/
-static void shellAddSchemaName(
- sqlite3_context *pCtx,
- int nVal,
- sqlite3_value **apVal
-){
- static const char *aPrefix[] = {
- "TABLE",
- "INDEX",
- "UNIQUE INDEX",
- "VIEW",
- "TRIGGER",
- "VIRTUAL TABLE"
- };
- int i = 0;
- const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
- const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
- const char *zName = (const char*)sqlite3_value_text(apVal[2]);
- sqlite3 *db = sqlite3_context_db_handle(pCtx);
- UNUSED_PARAMETER(nVal);
- if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){
- for(i=0; i<ArraySize(aPrefix); i++){
- int n = strlen30(aPrefix[i]);
- if( cli_strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
- char *z = 0;
- char *zFake = 0;
- if( zSchema ){
- char cQuote = quoteChar(zSchema);
- if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
- z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
- }else{
- z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
- }
- }
- if( zName
- && aPrefix[i][0]=='V'
- && (zFake = shellFakeSchema(db, zSchema, zName))!=0
- ){
- if( z==0 ){
- z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake);
- }else{
- z = sqlite3_mprintf("%z\n/* %s */", z, zFake);
- }
- sqlite3_free(zFake);
- }
- if( z ){
- sqlite3_result_text(pCtx, z, -1, sqlite3_free);
- return;
- }
- }
- }
+static sqlite3_str *cli_output_capture = 0;
+static int cli_printf(FILE *out, const char *zFormat, ...){
+ va_list ap;
+ int rc;
+ va_start(ap,zFormat);
+ if( cli_output_capture && (out==stdout || out==stderr) ){
+ sqlite3_str_vappendf(cli_output_capture, zFormat, ap);
+ rc = 1;
+ }else{
+ rc = sqlite3_vfprintf(out, zFormat, ap);
}
- sqlite3_result_value(pCtx, apVal[0]);
+ va_end(ap);
+ return rc;
+}
+static int cli_puts(const char *zText, FILE *out){
+ if( cli_output_capture && (out==stdout || out==stderr) ){
+ sqlite3_str_appendall(cli_output_capture, zText);
+ return 1;
+ }
+ return sqlite3_fputs(zText, out);
+}
+#if 0 /* Not currently used - available if we need it later */
+static int cli_vprintf(FILE *out, const char *zFormat, va_list ap){
+ if( cli_output_capture && (out==stdout || out==stderr) ){
+ sqlite3_str_vappendf(cli_output_capture, zFormat, ap);
+ return 1;
+ }else{
+ return sqlite3_vfprintf(out, zFormat, ap);
+ }
+}
+#endif
+static void cli_exit(int rc){
+ if( cli_output_capture ){
+ char *z = sqlite3_str_finish(cli_output_capture);
+ sqlite3_fputs(z, stdout);
+ fflush(stdout);
+ }
+ exit(rc);
}
-/*
-** The source code for several run-time loadable extensions is inserted
-** below by the ../tool/mkshellc.tcl script. Before processing that included
-** code, we need to override some macros to make the included program code
-** work here in the middle of this regular program.
-*/
-#define SQLITE_EXTENSION_INIT1
-#define SQLITE_EXTENSION_INIT2(X) (void)(X)
-INCLUDE ../ext/misc/windirent.h
-INCLUDE ../ext/misc/memtrace.c
-INCLUDE ../ext/misc/pcachetrace.c
-INCLUDE ../ext/misc/shathree.c
-INCLUDE ../ext/misc/sha1.c
-INCLUDE ../ext/misc/uint.c
-INCLUDE ../ext/misc/decimal.c
-INCLUDE ../ext/misc/base64.c
-INCLUDE ../ext/misc/base85.c
-INCLUDE ../ext/misc/ieee754.c
-INCLUDE ../ext/misc/series.c
-INCLUDE ../ext/misc/regexp.c
-#ifndef SQLITE_SHELL_FIDDLE
-INCLUDE ../ext/misc/fileio.c
-INCLUDE ../ext/misc/completion.c
-INCLUDE ../ext/misc/appendvfs.c
-#endif
-#ifdef SQLITE_HAVE_ZLIB
-INCLUDE ../ext/misc/zipfile.c
-INCLUDE ../ext/misc/sqlar.c
-#endif
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION)
-INCLUDE ../ext/expert/sqlite3expert.h
-INCLUDE ../ext/expert/sqlite3expert.c
-#endif
-INCLUDE ../ext/intck/sqlite3intck.h
-INCLUDE ../ext/intck/sqlite3intck.c
-INCLUDE ../ext/misc/stmtrand.c
-INCLUDE ../ext/misc/vfstrace.c
+#define eputz(z) cli_puts(z,stderr)
+#define sputz(fp,z) cli_puts(z,fp)
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
-#define SQLITE_SHELL_HAVE_RECOVER 1
-#else
-#define SQLITE_SHELL_HAVE_RECOVER 0
-#endif
-#if SQLITE_SHELL_HAVE_RECOVER
-INCLUDE ../ext/recover/sqlite3recover.h
-# ifndef SQLITE_HAVE_SQLITE3R
-INCLUDE ../ext/recover/dbdata.c
-INCLUDE ../ext/recover/sqlite3recover.c
-# endif /* SQLITE_HAVE_SQLITE3R */
-#endif
-#ifdef SQLITE_SHELL_EXTSRC
-# include SHELL_STRINGIFY(SQLITE_SHELL_EXTSRC)
-#endif
+/* A version of strcmp() that works with NULL values */
+static int cli_strcmp(const char *a, const char *b){
+ if( a==0 ) a = "";
+ if( b==0 ) b = "";
+ return strcmp(a,b);
+}
+static int cli_strncmp(const char *a, const char *b, size_t n){
+ if( a==0 ) a = "";
+ if( b==0 ) b = "";
+ return strncmp(a,b,n);
+}
-#if defined(SQLITE_ENABLE_SESSION)
-/*
-** State information for a single open session
+/* Return the current wall-clock time in microseconds since the
+** Unix epoch (1970-01-01T00:00:00Z)
*/
-typedef struct OpenSession OpenSession;
-struct OpenSession {
- char *zName; /* Symbolic name for this session */
- int nFilter; /* Number of xFilter rejection GLOB patterns */
- char **azFilter; /* Array of xFilter rejection GLOB patterns */
- sqlite3_session *p; /* The open session */
-};
+static sqlite3_int64 timeOfDay(void){
+#if defined(_WIN64) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
+ sqlite3_uint64 t;
+ FILETIME tm;
+ GetSystemTimePreciseAsFileTime(&tm);
+ t = ((u64)tm.dwHighDateTime<<32) | (u64)tm.dwLowDateTime;
+ t += 116444736000000000LL;
+ t /= 10;
+ return t;
+#elif defined(_WIN32)
+ static sqlite3_vfs *clockVfs = 0;
+ sqlite3_int64 t;
+ if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
+ if( clockVfs==0 ) return 0; /* Never actually happens */
+ if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
+ clockVfs->xCurrentTimeInt64(clockVfs, &t);
+ }else{
+ double r;
+ clockVfs->xCurrentTime(clockVfs, &r);
+ t = (sqlite3_int64)(r*86400000.0);
+ }
+ return t*1000;
+#else
+ struct timeval sNow;
+ (void)gettimeofday(&sNow,0);
+ return ((i64)sNow.tv_sec)*1000000 + sNow.tv_usec;
#endif
+}
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION)
-typedef struct ExpertInfo ExpertInfo;
-struct ExpertInfo {
- sqlite3expert *pExpert;
- int bVerbose;
-};
-#endif
-/* All the parameters that determine how to render query results.
-*/
-typedef struct Mode {
- u8 autoExplain; /* Automatically turn on .explain mode */
- u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to each SQL stmt */
- u8 autoEQPtrace; /* autoEQP is in trace mode */
- u8 scanstatsOn; /* True to display scan stats before each finalize */
- u8 bAutoScreenWidth; /* Using the TTY to determine screen width */
- u8 mFlags; /* MFLG_ECHO, MFLG_CRLF, etc. */
- u8 eMode; /* One of the MODE_ values */
- sqlite3_qrf_spec spec; /* Spec to be passed into QRF */
-} Mode;
-/* Flags for Mode.mFlags */
-#define MFLG_ECHO 0x01 /* Echo inputs to output */
-#define MFLG_CRLF 0x02 /* Use CR/LF output line endings */
-#define MFLG_HDR 0x04 /* .header used to change headers on/off */
+/* This is variant of the standard-library strncpy() routine with the
+** one change that the destination string is always zero-terminated, even
+** if there is no zero-terminator in the first n-1 characters of the source
+** string.
+*/
+static char *shell_strncpy(char *dest, const char *src, size_t n){
+ size_t i;
+ for(i=0; i<n-1 && src[i]!=0; i++) dest[i] = src[i];
+ dest[i] = 0;
+ return dest;
+}
+/*
+** strcpy() workalike to squelch an unwarranted link-time warning
+** from OpenBSD.
+*/
+static void shell_strcpy(char *dest, const char *src){
+ while( (*(dest++) = *(src++))!=0 ){}
+}
/*
-** State information about the database connection is contained in an
-** instance of the following structure.
+** Optionally disable dynamic continuation prompt.
+** Unless disabled, the continuation prompt shows open SQL lexemes if any,
+** or open parentheses level if non-zero, or continuation prompt as set.
+** This facility interacts with the scanner and process_input() where the
+** below 5 macros are used.
*/
-typedef struct ShellState ShellState;
-struct ShellState {
- sqlite3 *db; /* The database */
- u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
- u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */
- u8 nEqpLevel; /* Depth of the EQP output graph */
- u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
- u8 bSafeMode; /* True to prohibit unsafe operations */
- u8 bSafeModePersist; /* The long-term value of bSafeMode */
- u8 eRestoreState; /* See comments above doAutoDetectRestore() */
- unsigned statsOn; /* True to display memory stats before each finalize */
- unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
- u8 nPopOutput; /* Revert .output settings when reaching zero */
- u8 nPopMode; /* Revert .mode settings when reaching zero */
- u8 enableTimer; /* Enable the timer. 2: permanently 1: only once */
- int inputNesting; /* Track nesting level of .read and other redirects */
- double prevTimer; /* Last reported timer value */
- double tmProgress; /* --timeout option for .progress */
- i64 lineno; /* Line number of last line read from in */
- const char *zInFile; /* Name of the input file */
- int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */
- FILE *in; /* Read commands from this stream */
- FILE *out; /* Write results here */
- FILE *traceOut; /* Output for sqlite3_trace() */
- int nErr; /* Number of errors seen */
- int writableSchema; /* True if PRAGMA writable_schema=ON */
- int nCheck; /* Number of ".check" commands run */
- unsigned nProgress; /* Number of progress callbacks encountered */
- unsigned mxProgress; /* Maximum progress callbacks before failing */
- unsigned flgProgress; /* Flags for the progress callback */
- unsigned shellFlgs; /* Various flags */
- unsigned nTestRun; /* Number of test cases run */
- unsigned nTestErr; /* Number of test cases that failed */
- sqlite3_int64 szMax; /* --maxsize argument to .open */
- char *zDestTable; /* Name of destination table when MODE_Insert */
- char *zTempFile; /* Temporary file that might need deleting */
- char *zErrPrefix; /* Alternative error message prefix */
- char zTestcase[30]; /* Name of current test case */
- char outfile[FILENAME_MAX]; /* Filename for *out */
- sqlite3_stmt *pStmt; /* Current statement if any. */
- FILE *pLog; /* Write log output here */
- Mode mode; /* Current display mode */
- Mode modePrior; /* Backup */
- struct SavedMode { /* Ability to define custom mode configurations */
- char *zTag; /* Name of this saved mode */
- Mode mode; /* The saved mode */
- } *aSavedModes; /* Array of saved .mode settings. system malloc() */
- int nSavedModes; /* Number of saved .mode settings */
- struct AuxDb { /* Storage space for auxiliary database connections */
- sqlite3 *db; /* Connection pointer */
- const char *zDbFilename; /* Filename used to open the connection */
- char *zFreeOnClose; /* Free this memory allocation on close */
-#if defined(SQLITE_ENABLE_SESSION)
- int nSession; /* Number of active sessions */
- OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */
-#endif
- } aAuxDb[5], /* Array of all database connections */
- *pAuxDb; /* Currently active database connection */
- char *zNonce; /* Nonce for temporary safe-mode escapes */
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION)
- ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */
-#endif
- struct DotCmdLine { /* Info about arguments to a dot-command */
- const char *zOrig; /* Original text of the dot-command */
- char *zCopy; /* Copy of zOrig, from malloc() */
- int nAlloc; /* Size of allocates for arrays below */
- int nArg; /* Number of argument slots actually used */
- char **azArg; /* Pointer to each argument, dequoted */
- int *aiOfst; /* Offset into zOrig[] for start of each arg */
- char *abQuot; /* True if the argment was originally quoted */
- } dot;
-#ifdef SQLITE_SHELL_FIDDLE
- struct {
- const char * zInput; /* Input string from wasm/JS proxy */
- const char * zPos; /* Cursor pos into zInput */
- const char * zDefaultDbName; /* Default name for db file */
- } wasm;
-#endif
-};
-
-#ifdef SQLITE_SHELL_FIDDLE
-static ShellState shellState;
-#endif
+#ifdef SQLITE_OMIT_DYNAPROMPT
+# define CONTINUATION_PROMPT continuePrompt
+# define CONTINUE_PROMPT_RESET
+# define CONTINUE_PROMPT_AWAITS(p,s)
+# define CONTINUE_PROMPT_AWAITC(p,c)
+# define CONTINUE_PAREN_INCR(p,n)
+# define CONTINUE_PROMPT_PSTATE 0
+typedef void *t_NoDynaPrompt;
+# define SCAN_TRACKER_REFTYPE t_NoDynaPrompt
+#else
+# define CONTINUATION_PROMPT dynamicContinuePrompt()
+# define CONTINUE_PROMPT_RESET \
+ do {setLexemeOpen(&dynPrompt,0,0); trackParenLevel(&dynPrompt,0);} while(0)
+# define CONTINUE_PROMPT_AWAITS(p,s) \
+ if(p && stdin_is_interactive) setLexemeOpen(p, s, 0)
+# define CONTINUE_PROMPT_AWAITC(p,c) \
+ if(p && stdin_is_interactive) setLexemeOpen(p, 0, c)
+# define CONTINUE_PAREN_INCR(p,n) \
+ if(p && stdin_is_interactive) (trackParenLevel(p,n))
+# define CONTINUE_PROMPT_PSTATE (&dynPrompt)
+typedef struct DynaPrompt *t_DynaPromptRef;
+# define SCAN_TRACKER_REFTYPE t_DynaPromptRef
+static struct DynaPrompt {
+ char dynamicPrompt[PROMPT_LEN_MAX];
+ char acAwait[2];
+ int inParenLevel;
+ char *zScannerAwaits;
+} dynPrompt = { {0}, {0}, 0, 0 };
-/* Allowed values for ShellState.mode.autoEQP
-*/
-#define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */
-#define AUTOEQP_on 1 /* Automatic EQP is on */
-#define AUTOEQP_trigger 2 /* On and also show plans for triggers */
-#define AUTOEQP_full 3 /* Show full EXPLAIN */
+/* Record parenthesis nesting level change, or force level to 0. */
+static void trackParenLevel(struct DynaPrompt *p, int ni){
+ p->inParenLevel += ni;
+ if( ni==0 ) p->inParenLevel = 0;
+ p->zScannerAwaits = 0;
+}
-/* Allowed values for ShellState.openMode
-*/
-#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */
-#define SHELL_OPEN_NORMAL 1 /* Normal database file */
-#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */
-#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */
-#define SHELL_OPEN_DESERIALIZE 4 /* Open using sqlite3_deserialize() */
-#define SHELL_OPEN_HEXDB 5 /* Use "dbtotxt" output as data source */
+/* Record that a lexeme is opened, or closed with args==0. */
+static void setLexemeOpen(struct DynaPrompt *p, char *s, char c){
+ if( s!=0 || c==0 ){
+ p->zScannerAwaits = s;
+ p->acAwait[0] = 0;
+ }else{
+ p->acAwait[0] = c;
+ p->zScannerAwaits = p->acAwait;
+ }
+}
-/* Allowed values for ShellState.eTraceType
-*/
-#define SHELL_TRACE_PLAIN 0 /* Show input SQL text */
-#define SHELL_TRACE_EXPANDED 1 /* Show expanded SQL text */
-#define SHELL_TRACE_NORMALIZED 2 /* Show normalized SQL text */
+/* Upon demand, derive the continuation prompt to display. */
+static char *dynamicContinuePrompt(void){
+ if( continuePrompt[0]==0
+ || (dynPrompt.zScannerAwaits==0 && dynPrompt.inParenLevel == 0) ){
+ return continuePrompt;
+ }else{
+ if( dynPrompt.zScannerAwaits ){
+ size_t ncp = strlen(continuePrompt);
+ size_t ndp = strlen(dynPrompt.zScannerAwaits);
+ if( ndp > ncp-3 ) return continuePrompt;
+ shell_strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
+ while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' ';
+ shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
+ PROMPT_LEN_MAX-4);
+ }else{
+ if( dynPrompt.inParenLevel>9 ){
+ shell_strncpy(dynPrompt.dynamicPrompt, "(..", 4);
+ }else if( dynPrompt.inParenLevel<0 ){
+ shell_strncpy(dynPrompt.dynamicPrompt, ")x!", 4);
+ }else{
+ shell_strncpy(dynPrompt.dynamicPrompt, "(x.", 4);
+ dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel);
+ }
+ shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
+ PROMPT_LEN_MAX-4);
+ }
+ }
+ return dynPrompt.dynamicPrompt;
+}
+#endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */
-/* Bits in the ShellState.flgProgress variable */
-#define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */
-#define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progress
- ** callback limit is reached, and for each
- ** top-level SQL statement */
-#define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
-#define SHELL_PROGRESS_TMOUT 0x08 /* Stop after tmProgress seconds */
+/* Indicate out-of-memory and exit. */
+static void shell_out_of_memory(void){
+ eputz("Error: out of memory\n");
+ cli_exit(1);
+}
-/* Names of values for Mode.spec.eEsc and Mode.spec.eText
+/* Check a pointer to see if it is NULL. If it is NULL, exit with an
+** out-of-memory error.
*/
-static const char *qrfEscNames[] = { "auto", "off", "ascii", "symbol" };
-static const char *qrfQuoteNames[] =
- { "off","off","sql","hex","csv","tcl","json","relaxed"};
+static void shell_check_oom(const void *p){
+ if( p==0 ) shell_out_of_memory();
+}
/*
-** These are the allowed shellFlgs values
+** This routine works like printf in that its first argument is a
+** format string and subsequent arguments are values to be substituted
+** in place of % fields. The result of formatting this string
+** is written to iotrace.
*/
-#define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
-#define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
-#define SHFLG_Backslash 0x00000004 /* The --backslash option is used */
-#define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */
-#define SHFLG_NoErrLineno 0x00000010 /* Omit line numbers from error msgs */
-#define SHFLG_CountChanges 0x00000020 /* .changes setting */
-#define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */
-#define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */
-#define SHFLG_TestingMode 0x00000400 /* allow unsafe testing features */
+#ifdef SQLITE_ENABLE_IOTRACE
+static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
+ va_list ap;
+ char *z;
+ if( iotrace==0 ) return;
+ va_start(ap, zFormat);
+ z = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ cli_printf(iotrace, "%s", z);
+ sqlite3_free(z);
+}
+#endif
/*
-** Macros for testing and setting shellFlgs
+** Compute a string length that is limited to what can be stored in
+** lower 30 bits of a 32-bit signed integer.
*/
-#define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0)
-#define ShellSetFlag(P,X) ((P)->shellFlgs|=(X))
-#define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X)))
+static int strlen30(const char *z){
+ size_t n;
+ if( z==0 ) return 0;
+ n = strlen(z);
+ return n>0x3fffffff ? 0x3fffffff : (int)n;
+}
/*
-** These are the allowed values for Mode.eMode. There is a lot of overlap
-** between these values and the Mode.spec.eStyle values, but they are not
-** one-to-one, and thus need to be tracked separately.
+** Return open FILE * if zFile exists, can be opened for read
+** and is an ordinary file or a character stream source.
+** Otherwise return 0.
*/
-#define MODE_Ascii 0 /* Use ASCII unit and record separators (0x1F/0x1E) */
-#define MODE_Box 1 /* Unicode box-drawing characters */
-#define MODE_C 2 /* Comma-separated list of C-strings */
-#define MODE_Column 3 /* One record per line in neat columns */
-#define MODE_Count 4 /* Output only a count of the rows of output */
-#define MODE_Csv 5 /* Quote strings, numbers are plain */
-#define MODE_Html 6 /* Generate an XHTML table */
-#define MODE_Insert 7 /* Generate SQL "insert" statements */
-#define MODE_JAtom 8 /* Comma-separated list of JSON atoms */
-#define MODE_JObject 9 /* One JSON object per row */
-#define MODE_Json 10 /* Output JSON */
-#define MODE_Line 11 /* One column per line. Blank line between records */
-#define MODE_List 12 /* One record per line with a separator */
-#define MODE_Markdown 13 /* Markdown formatting */
-#define MODE_Off 14 /* No query output shown */
-#define MODE_Psql 15 /* Similar to psql */
-#define MODE_QBox 16 /* BOX with SQL-quoted content */
-#define MODE_Quote 17 /* Quote values as for SQL */
-#define MODE_Split 18 /* Split-column mode */
-#define MODE_Table 19 /* MySQL-style table formatting */
-#define MODE_Tabs 20 /* Tab-separated values */
-#define MODE_Tcl 21 /* Space-separated list of TCL strings */
-#define MODE_Www 22 /* Full web-page output */
-
-#define MODE_BUILTIN 22 /* Maximum built-in mode */
-#define MODE_BATCH 50 /* Default mode for batch processing */
-#define MODE_TTY 51 /* Default mode for interactive processing */
-#define MODE_USER 75 /* First user-defined mode */
-#define MODE_N_USER 25 /* Maximum number of user-defined modes */
-
-/*
-** Information about built-in display modes
+static FILE * openChrSource(const char *zFile){
+#if defined(_WIN32) || defined(WIN32)
+ struct __stat64 x = {0};
+# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
+ /* On Windows, open first, then check the stream nature. This order
+ ** is necessary because _stat() and sibs, when checking a named pipe,
+ ** effectively break the pipe as its supplier sees it. */
+ FILE *rv = sqlite3_fopen(zFile, "rb");
+ if( rv==0 ) return 0;
+ if( _fstat64(_fileno(rv), &x) != 0
+ || !STAT_CHR_SRC(x.st_mode)){
+ fclose(rv);
+ rv = 0;
+ }
+ return rv;
+#else
+ struct stat x = {0};
+ int rc = stat(zFile, &x);
+# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
+ if( rc!=0 ) return 0;
+ if( STAT_CHR_SRC(x.st_mode) ){
+ return sqlite3_fopen(zFile, "rb");
+ }else{
+ return 0;
+ }
+#endif
+#undef STAT_CHR_SRC
+}
+
+/*
+** This routine reads a line of text from FILE in, stores
+** the text in memory obtained from malloc() and returns a pointer
+** to the text. NULL is returned at end of file, or if malloc()
+** fails, or if the length of the line is longer than about a gigabyte.
+**
+** If zLine is not NULL then it is a malloced buffer returned from
+** a previous call to this routine that may be reused.
*/
-typedef struct ModeInfo ModeInfo;
-struct ModeInfo {
- char zName[9]; /* Symbolic name of the mode */
- unsigned char eCSep; /* Column separator */
- unsigned char eRSep; /* Row separator */
- unsigned char eNull; /* Null representation */
- unsigned char eText; /* Default text encoding */
- unsigned char eHdr; /* Default header encoding. */
- unsigned char eBlob; /* Default blob encoding. */
- unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */
- unsigned char eStyle; /* Underlying QRF style */
- unsigned char eCx; /* 0: other, 1: line, 2: columnar */
- unsigned char mFlg; /* Flags. 1=border-off 2=split-column */
+static char *local_getline(char *zLine, FILE *in){
+ int nLine = zLine==0 ? 0 : 100;
+ int n = 0;
+
+ while( 1 ){
+ if( n+100>nLine ){
+ if( nLine>=1073741773 ){
+ free(zLine);
+ return 0;
+ }
+ nLine = nLine*2 + 100;
+ zLine = realloc(zLine, nLine);
+ shell_check_oom(zLine);
+ }
+ if( sqlite3_fgets(&zLine[n], nLine - n, in)==0 ){
+ if( n==0 ){
+ free(zLine);
+ return 0;
+ }
+ zLine[n] = 0;
+ break;
+ }
+ while( zLine[n] ) n++;
+ if( n>0 && zLine[n-1]=='\n' ){
+ n--;
+ if( n>0 && zLine[n-1]=='\r' ) n--;
+ zLine[n] = 0;
+ break;
+ }
+ }
+ return zLine;
+}
+
+/*
+** Retrieve a single line of input text.
+**
+** If in==0 then read from standard input and prompt before each line.
+** If isContinuation is true, then a continuation prompt is appropriate.
+** If isContinuation is zero, then the main prompt should be used.
+**
+** If zPrior is not NULL then it is a buffer from a prior call to this
+** routine that can be reused.
+**
+** The result is stored in space obtained from malloc() and must either
+** be freed by the caller or else passed back into this routine via the
+** zPrior argument for reuse.
+*/
+#ifndef SQLITE_SHELL_FIDDLE
+static char *one_input_line(ShellState *p, char *zPrior, int isContinuation){
+ char *zPrompt;
+ char *zResult;
+ FILE *in = p->in;
+ if( in!=0 ){
+ zResult = local_getline(zPrior, in);
+ }else{
+ zPrompt = isContinuation ? CONTINUATION_PROMPT : mainPrompt;
+#if SHELL_USE_LOCAL_GETLINE
+ sputz(stdout, zPrompt);
+ fflush(stdout);
+ do{
+ zResult = local_getline(zPrior, stdin);
+ zPrior = 0;
+ /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
+ if( zResult==0 ) sqlite3_sleep(50);
+ }while( zResult==0 && seenInterrupt>0 );
+#else
+ free(zPrior);
+ zResult = shell_readline(zPrompt);
+ while( zResult==0 ){
+ /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
+ sqlite3_sleep(50);
+ if( seenInterrupt==0 ) break;
+ zResult = shell_readline("");
+ }
+ if( zResult && *zResult ) shell_add_history(zResult);
+#endif
+ }
+ return zResult;
+}
+#endif /* !SQLITE_SHELL_FIDDLE */
+
+/*
+** Return the value of a hexadecimal digit. Return -1 if the input
+** is not a hex digit.
+*/
+static int hexDigitValue(char c){
+ if( c>='0' && c<='9' ) return c - '0';
+ if( c>='a' && c<='f' ) return c - 'a' + 10;
+ if( c>='A' && c<='F' ) return c - 'A' + 10;
+ return -1;
+}
+
+/*
+** Interpret zArg as an integer value, possibly with suffixes.
+**
+** If the value specified by zArg is outside the range of values that
+** can be represented using a 64-bit twos-complement integer, then return
+** the nearest representable value.
+*/
+static sqlite3_int64 integerValue(const char *zArg){
+ sqlite3_uint64 v = 0;
+ static const struct { char *zSuffix; unsigned int iMult; } aMult[] = {
+ { "KiB", 1024 },
+ { "MiB", 1024*1024 },
+ { "GiB", 1024*1024*1024 },
+ { "KB", 1000 },
+ { "MB", 1000000 },
+ { "GB", 1000000000 },
+ { "K", 1000 },
+ { "M", 1000000 },
+ { "G", 1000000000 },
+ };
+ int i;
+ int isNeg = 0;
+ if( zArg[0]=='-' ){
+ isNeg = 1;
+ zArg++;
+ }else if( zArg[0]=='+' ){
+ zArg++;
+ }
+ if( zArg[0]=='0' && zArg[1]=='x' ){
+ int x;
+ zArg += 2;
+ while( (x = hexDigitValue(zArg[0]))>=0 ){
+ if( v > 0x0fffffffffffffffULL ) goto integer_overflow;
+ v = (v<<4) + x;
+ zArg++;
+ }
+ }else{
+ while( IsDigit(zArg[0]) ){
+ if( v>=922337203685477580LL ){
+ if( v>922337203685477580LL || zArg[0]>='8' ) goto integer_overflow;
+ }
+ v = v*10 + (zArg[0] - '0');
+ zArg++;
+ }
+ }
+ for(i=0; i<ArraySize(aMult); i++){
+ if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
+ if( 0x7fffffffffffffffULL/aMult[i].iMult < v ) goto integer_overflow;
+ v *= aMult[i].iMult;
+ break;
+ }
+ }
+ if( isNeg && v>0x7fffffffffffffffULL ) goto integer_overflow;
+ return isNeg? -(sqlite3_int64)v : (sqlite3_int64)v;
+integer_overflow:
+ return isNeg ? (i64)0x8000000000000000LL : 0x7fffffffffffffffLL;
+}
+
+/*
+** A variable length string to which one can append text.
+*/
+typedef struct ShellText ShellText;
+struct ShellText {
+ char *zTxt; /* The text */
+ i64 n; /* Number of bytes of zTxt[] actually used */
+ i64 nAlloc; /* Number of bytes allocated for zTxt[] */
};
-/* String constants used by built-in modes */
-static const char *aModeStr[] =
- /* 0 1 2 3 4 5 6 7 8 */
- { 0, "\n", "|", " ", ",", "\r\n", "\036", "\037", "\t",
- "", "NULL", "null", "\"\"", ": ", };
- /* 9 10 11 12 13 */
+/*
+** Initialize and destroy a ShellText object
+*/
+static void initText(ShellText *p){
+ memset(p, 0, sizeof(*p));
+}
+static void freeText(ShellText *p){
+ sqlite3_free(p->zTxt);
+ initText(p);
+}
+
+/* zIn is either a pointer to a NULL-terminated string in memory obtained
+** from malloc(), or a NULL pointer. The string pointed to by zAppend is
+** added to zIn, and the result returned in memory obtained from malloc().
+** zIn, if it was not NULL, is freed.
+**
+** If the third argument, quote, is not '\0', then it is used as a
+** quote character for zAppend.
+*/
+static void appendText(ShellText *p, const char *zAppend, char quote){
+ i64 len;
+ i64 i;
+ i64 nAppend = strlen30(zAppend);
+
+ len = nAppend+p->n+1;
+ if( quote ){
+ len += 2;
+ for(i=0; i<nAppend; i++){
+ if( zAppend[i]==quote ) len++;
+ }
+ }
+
+ if( p->zTxt==0 || p->n+len>=p->nAlloc ){
+ p->nAlloc = p->nAlloc*2 + len + 20;
+ p->zTxt = sqlite3_realloc64(p->zTxt, p->nAlloc);
+ shell_check_oom(p->zTxt);
+ }
+
+ if( quote ){
+ char *zCsr = p->zTxt+p->n;
+ *zCsr++ = quote;
+ for(i=0; i<nAppend; i++){
+ *zCsr++ = zAppend[i];
+ if( zAppend[i]==quote ) *zCsr++ = quote;
+ }
+ *zCsr++ = quote;
+ p->n = (i64)(zCsr - p->zTxt);
+ *zCsr = '\0';
+ }else{
+ memcpy(p->zTxt+p->n, zAppend, nAppend);
+ p->n += nAppend;
+ p->zTxt[p->n] = '\0';
+ }
+}
-static const ModeInfo aModeInfo[] = {
-/* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */
- { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 },
- { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2, 0 },
- { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 },
- { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2, 0 },
- { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
- { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 },
- { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 },
- { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 },
- { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 },
- { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 },
- { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 },
- { "line", 13, 1, 9, 1, 1, 0, 0, 11, 1, 0 },
- { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 },
- { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2, 0 },
- { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 },
- { "psql", 0, 0, 9, 1, 1, 0, 2, 19, 2, 1 },
- { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2, 0 },
- { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 },
- { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 },
- { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2, 0 },
- { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 },
- { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 },
- { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 }
-}; /* | / / | / / | | \
- ** | / / | / / | | \_ 2: columnar
- ** Index into aModeStr[] | / / | | 1: line
- ** | / / | | 0: other
- ** | / / | \
- ** text encoding |/ | show | \
- ** v-------------------' | hdrs? | The QRF style
- ** 0: n/a blob | v-----'
- ** 1: plain v_---------' 0: n/a
- ** 2: sql 0: auto 1: no
- ** 3: csv 1: as-text 2: yes
- ** 4: html 2: sql
- ** 5: c 3: hex
- ** 6: json 4: c
- ** 5: json
- ** 6: size
- ******************************************************************/
/*
-** These are the column/row/line separators used by the various
-** import/export modes.
+** Attempt to determine if identifier zName needs to be quoted, either
+** because it contains non-alphanumeric characters, or because it is an
+** SQLite keyword. Be conservative in this estimate: When in doubt assume
+** that quoting is required.
+**
+** Return '"' if quoting is required. Return 0 if no quoting is required.
*/
-#define SEP_Column "|"
-#define SEP_Row "\n"
-#define SEP_Tab "\t"
-#define SEP_Space " "
-#define SEP_Comma ","
-#define SEP_CrLf "\r\n"
-#define SEP_Unit "\x1F"
-#define SEP_Record "\x1E"
+static char quoteChar(const char *zName){
+ int i;
+ if( zName==0 ) return '"';
+ if( !IsAlpha(zName[0]) && zName[0]!='_' ) return '"';
+ for(i=0; zName[i]; i++){
+ if( !IsAlnum(zName[i]) && zName[i]!='_' ) return '"';
+ }
+ return sqlite3_keyword_check(zName, i) ? '"' : 0;
+}
/*
-** Default values for the various QRF limits
+** Construct a fake object name and column list to describe the structure
+** of the view, virtual table, or table valued function zSchema.zName.
+**
+** The returned string comes from sqlite3_mprintf() and should be freed
+** by the caller using sqlite3_free().
*/
-#ifndef DFLT_CHAR_LIMIT
-# define DFLT_CHAR_LIMIT 300
-#endif
-#ifndef DFLT_LINE_LIMIT
-# define DFLT_LINE_LIMIT 5
-#endif
-#ifndef DFLT_TITLE_LIMIT
-# define DFLT_TITLE_LIMIT 20
-#endif
-#ifndef DFLT_MULTI_INSERT
-# define DFLT_MULTI_INSERT 3000
-#endif
+static char *shellFakeSchema(
+ sqlite3 *db, /* The database connection containing the vtab */
+ const char *zSchema, /* Schema of the database holding the vtab */
+ const char *zName /* The name of the virtual table */
+){
+ sqlite3_stmt *pStmt = 0;
+ char *zSql;
+ ShellText s;
+ char cQuote;
+ char *zDiv = "(";
+ int nRow = 0;
+
+ zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
+ zSchema ? zSchema : "main", zName);
+ shell_check_oom(zSql);
+ sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ initText(&s);
+ if( zSchema ){
+ cQuote = quoteChar(zSchema);
+ if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0;
+ appendText(&s, zSchema, cQuote);
+ appendText(&s, ".", 0);
+ }
+ cQuote = quoteChar(zName);
+ appendText(&s, zName, cQuote);
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *zCol = (const char*)sqlite3_column_text(pStmt, 1);
+ nRow++;
+ appendText(&s, zDiv, 0);
+ zDiv = ",";
+ if( zCol==0 ) zCol = "";
+ cQuote = quoteChar(zCol);
+ appendText(&s, zCol, cQuote);
+ }
+ appendText(&s, ")", 0);
+ sqlite3_finalize(pStmt);
+ if( nRow==0 ){
+ freeText(&s);
+ s.zTxt = 0;
+ }
+ return s.zTxt;
+}
/*
-** Limit input nesting via .read or any other input redirect.
-** It's not too expensive, so a generous allowance can be made.
+** SQL function: strtod(X)
+**
+** Use the C-library strtod() function to convert string X into a double.
+** Used for comparing the accuracy of SQLite's internal text-to-float conversion
+** routines against the C-library.
*/
-#define MAX_INPUT_NESTING 25
+static void shellStrtod(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ char *z = (char*)sqlite3_value_text(apVal[0]);
+ UNUSED_PARAMETER(nVal);
+ if( z==0 ) return;
+ sqlite3_result_double(pCtx, strtod(z,0));
+}
+
+/*
+** SQL function: dtostr(X)
+**
+** Use the C-library printf() function to convert real value X into a string.
+** Used for comparing the accuracy of SQLite's internal float-to-text conversion
+** routines against the C-library.
+*/
+static void shellDtostr(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ double r = sqlite3_value_double(apVal[0]);
+ int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26;
+ char z[400];
+ if( n<1 ) n = 1;
+ if( n>350 ) n = 350;
+ sprintf(z, "%#+.*e", n, r);
+ sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
+}
+
+/*
+** SQL function: shell_add_schema(S,X)
+**
+** Add the schema name X to the CREATE statement in S and return the result.
+** Examples:
+**
+** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x);
+**
+** Also works on
+**
+** CREATE INDEX
+** CREATE UNIQUE INDEX
+** CREATE VIEW
+** CREATE TRIGGER
+** CREATE VIRTUAL TABLE
+**
+** This UDF is used by the .schema command to insert the schema name of
+** attached databases into the middle of the sqlite_schema.sql field.
+*/
+static void shellAddSchemaName(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ static const char *aPrefix[] = {
+ "TABLE",
+ "INDEX",
+ "UNIQUE INDEX",
+ "VIEW",
+ "TRIGGER",
+ "VIRTUAL TABLE"
+ };
+ int i = 0;
+ const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
+ const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
+ const char *zName = (const char*)sqlite3_value_text(apVal[2]);
+ sqlite3 *db = sqlite3_context_db_handle(pCtx);
+ UNUSED_PARAMETER(nVal);
+ if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){
+ for(i=0; i<ArraySize(aPrefix); i++){
+ int n = strlen30(aPrefix[i]);
+ if( cli_strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
+ char *z = 0;
+ char *zFake = 0;
+ if( zSchema ){
+ char cQuote = quoteChar(zSchema);
+ if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
+ z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
+ }else{
+ z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
+ }
+ }
+ if( zName
+ && aPrefix[i][0]=='V'
+ && (zFake = shellFakeSchema(db, zSchema, zName))!=0
+ ){
+ if( z==0 ){
+ z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake);
+ }else{
+ z = sqlite3_mprintf("%z\n/* %s */", z, zFake);
+ }
+ sqlite3_free(zFake);
+ }
+ if( z ){
+ sqlite3_result_text(pCtx, z, -1, sqlite3_free);
+ return;
+ }
+ }
+ }
+ }
+ sqlite3_result_value(pCtx, apVal[0]);
+}
+
/************************* BEGIN PERFORMANCE TIMER *****************************/
#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
** impl because we need the global shellState and cannot access it from that
** function without moving lots of code around (creating a larger/messier diff).
*/
-static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
+static char *one_input_line(ShellState *p, char *zPrior, int isContinuation){
/* Parse the next line from shellState.wasm.zInput. */
const char *zBegin = shellState.wasm.zPos;
const char *z = zBegin;
char *zLine = 0;
i64 nZ = 0;
+ FILE *in = p->in;
UNUSED_PARAMETER(in);
UNUSED_PARAMETER(isContinuation);
CONTINUE_PROMPT_RESET;
while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
fflush(p->out);
- zLine = one_input_line(p->in, zLine, nSql>0);
+ zLine = one_input_line(p, zLine, nSql>0);
if( zLine==0 ){
/* End of input */
if( p->in==0 && stdin_is_interactive ) cli_puts("\n", p->out);