aboutsummaryrefslogtreecommitdiff
path: root/src/shell.c.in
diff options
context:
space:
mode:
Diffstat (limited to 'src/shell.c.in')
-rw-r--r--src/shell.c.in2961
1 files changed, 1890 insertions, 1071 deletions
diff --git a/src/shell.c.in b/src/shell.c.in
index f389c1f47..33dd30697 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -104,9 +104,6 @@ typedef unsigned short int u16;
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
typedef unsigned char u8;
-#if SQLITE_USER_AUTHENTICATION
-# include "sqlite3userauth.h"
-#endif
#include <ctype.h>
#include <stdarg.h>
@@ -192,8 +189,6 @@ typedef unsigned char u8;
# ifndef strdup
# define strdup _strdup
# endif
-# undef popen
-# define popen _popen
# undef pclose
# define pclose _pclose
# endif
@@ -223,6 +218,8 @@ typedef unsigned char u8;
#define IsSpace(X) isspace((unsigned char)X)
#define IsDigit(X) isdigit((unsigned char)X)
#define ToLower(X) (char)tolower((unsigned char)X)
+#define IsAlnum(X) isalnum((unsigned char)X)
+#define IsAlpha(X) isalpha((unsigned char)X)
#if defined(_WIN32) || defined(WIN32)
#if SQLITE_OS_WINRT
@@ -237,6 +234,9 @@ extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
#endif
+INCLUDE ../ext/misc/sqlite3_stdio.h
+INCLUDE ../ext/misc/sqlite3_stdio.c
+
/* Use console I/O package as a direct INCLUDE. */
#define SQLITE_INTERNAL_LINKAGE static
@@ -246,56 +246,11 @@ extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
# define SQLITE_CIO_NO_CLASSIFY
# define SQLITE_CIO_NO_TRANSLATE
# define SQLITE_CIO_NO_SETMODE
+# define SQLITE_CIO_NO_FLUSH
#endif
-INCLUDE ../ext/consio/console_io.h
-INCLUDE ../ext/consio/console_io.c
-
-#ifndef SQLITE_SHELL_FIDDLE
-/* From here onward, fgets() is redirected to the console_io library. */
-# define fgets(b,n,f) fGetsUtf8(b,n,f)
-/*
- * Define macros for emitting output text in various ways:
- * sputz(s, z) => emit 0-terminated string z to given stream s
- * sputf(s, f, ...) => emit varargs per format f to given stream s
- * oputz(z) => emit 0-terminated string z to default stream
- * oputf(f, ...) => emit varargs per format f to default stream
- * eputz(z) => emit 0-terminated string z to error stream
- * eputf(f, ...) => emit varargs per format f to error stream
- * oputb(b, n) => emit char buffer b[0..n-1] to default stream
- *
- * Note that the default stream is whatever has been last set via:
- * setOutputStream(FILE *pf)
- * This is normally the stream that CLI normal output goes to.
- * For the stand-alone CLI, it is stdout with no .output redirect.
- *
- * The ?putz(z) forms are required for the Fiddle builds for string literal
- * output, in aid of enforcing format string to argument correspondence.
- */
-# define sputz(s,z) fPutsUtf8(z,s)
-# define sputf fPrintfUtf8
-# define oputz(z) oPutsUtf8(z)
-# define oputf oPrintfUtf8
-# define eputz(z) ePutsUtf8(z)
-# define eputf ePrintfUtf8
-# define oputb(buf,na) oPutbUtf8(buf,na)
-
-#else
-/* For Fiddle, all console handling and emit redirection is omitted. */
-/* These next 3 macros are for emitting formatted output. When complaints
- * from the WASM build are issued for non-formatted output, (when a mere
- * string literal is to be emitted, the ?putz(z) forms should be used.
- * (This permits compile-time checking of format string / argument mismatch.)
- */
-# define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
-# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
-# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__)
-/* These next 3 macros are for emitting simple string literals. */
-# define oputz(z) fputs(z,stdout)
-# define eputz(z) fputs(z,stderr)
-# define sputz(fp,z) fputs(z,fp)
-# define oputb(buf,na) fwrite(buf,1,na,stdout)
-#endif
+#define eputz(z) sqlite3_fputs(z,stderr)
+#define sputz(fp,z) sqlite3_fputs(z,fp)
/* True if the timer is enabled */
static int enableTimer = 0;
@@ -341,6 +296,7 @@ struct rusage {
#define getrusage(A,B) memset(B,0,sizeof(*B))
#endif
+
/* Saved resource information for the beginning of an operation */
static struct rusage sBegin; /* CPU time at start */
static sqlite3_int64 iBegin; /* Wall-clock time at start */
@@ -364,12 +320,12 @@ static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
/*
** Print the timing results.
*/
-static void endTimer(void){
+static void endTimer(FILE *out){
if( enableTimer ){
sqlite3_int64 iEnd = timeOfDay();
struct rusage sEnd;
getrusage(RUSAGE_SELF, &sEnd);
- sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
+ sqlite3_fprintf(out, "Run Time: real %.3f user %f sys %f\n",
(iEnd - iBegin)*0.001,
timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
@@ -377,7 +333,7 @@ static void endTimer(void){
}
#define BEGIN_TIMER beginTimer()
-#define END_TIMER endTimer()
+#define END_TIMER(X) endTimer(X)
#define HAS_TIMER 1
#elif (defined(_WIN32) || defined(WIN32))
@@ -443,12 +399,12 @@ static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
/*
** Print the timing results.
*/
-static void endTimer(void){
+static void endTimer(FILE *out){
if( enableTimer && getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
sqlite3_int64 ftWallEnd = timeOfDay();
getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
- sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
+ sqlite3_fprintf(out, "Run Time: real %.3f user %f sys %f\n",
(ftWallEnd - ftWallBegin)*0.001,
timeDiff(&ftUserBegin, &ftUserEnd),
timeDiff(&ftKernelBegin, &ftKernelEnd));
@@ -456,12 +412,12 @@ static void endTimer(void){
}
#define BEGIN_TIMER beginTimer()
-#define END_TIMER endTimer()
+#define END_TIMER(X) endTimer(X)
#define HAS_TIMER hasTimer()
#else
#define BEGIN_TIMER
-#define END_TIMER
+#define END_TIMER(X) /*no-op*/
#define HAS_TIMER 0
#endif
@@ -516,7 +472,7 @@ static char *Argv0;
** Prompt strings. Initialized in main. Settable with
** .prompt main continue
*/
-#define PROMPT_LEN_MAX 20
+#define PROMPT_LEN_MAX 128
/* First line prompt. default: "sqlite> " */
static char mainPrompt[PROMPT_LEN_MAX];
/* Continuation prompt. default: " ...> " */
@@ -535,6 +491,14 @@ static char *shell_strncpy(char *dest, const char *src, size_t n){
}
/*
+** strcpy() workalike to squelch an unwarranted link-time warning
+** from OpenBSD.
+*/
+static void shell_strcpy(char *dest, const char *src){
+ while( (*(dest++) = *(src++))!=0 ){}
+}
+
+/*
** 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.
@@ -599,7 +563,7 @@ static char *dynamicContinuePrompt(void){
size_t ncp = strlen(continuePrompt);
size_t ndp = strlen(dynPrompt.zScannerAwaits);
if( ndp > ncp-3 ) return continuePrompt;
- strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
+ shell_strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' ';
shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
PROMPT_LEN_MAX-4);
@@ -654,37 +618,232 @@ static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
va_start(ap, zFormat);
z = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
- sputf(iotrace, "%s", z);
+ sqlite3_fprintf(iotrace, "%s", z);
sqlite3_free(z);
}
#endif
+/* Lookup table to estimate the number of columns consumed by a Unicode
+** character.
+*/
+static const struct {
+ unsigned char w; /* Width of the character in columns */
+ int iFirst; /* First character in a span having this width */
+} aUWidth[] = {
+ /* {1, 0x00000}, */
+ {0, 0x00300}, {1, 0x00370}, {0, 0x00483}, {1, 0x00487}, {0, 0x00488},
+ {1, 0x0048a}, {0, 0x00591}, {1, 0x005be}, {0, 0x005bf}, {1, 0x005c0},
+ {0, 0x005c1}, {1, 0x005c3}, {0, 0x005c4}, {1, 0x005c6}, {0, 0x005c7},
+ {1, 0x005c8}, {0, 0x00600}, {1, 0x00604}, {0, 0x00610}, {1, 0x00616},
+ {0, 0x0064b}, {1, 0x0065f}, {0, 0x00670}, {1, 0x00671}, {0, 0x006d6},
+ {1, 0x006e5}, {0, 0x006e7}, {1, 0x006e9}, {0, 0x006ea}, {1, 0x006ee},
+ {0, 0x0070f}, {1, 0x00710}, {0, 0x00711}, {1, 0x00712}, {0, 0x00730},
+ {1, 0x0074b}, {0, 0x007a6}, {1, 0x007b1}, {0, 0x007eb}, {1, 0x007f4},
+ {0, 0x00901}, {1, 0x00903}, {0, 0x0093c}, {1, 0x0093d}, {0, 0x00941},
+ {1, 0x00949}, {0, 0x0094d}, {1, 0x0094e}, {0, 0x00951}, {1, 0x00955},
+ {0, 0x00962}, {1, 0x00964}, {0, 0x00981}, {1, 0x00982}, {0, 0x009bc},
+ {1, 0x009bd}, {0, 0x009c1}, {1, 0x009c5}, {0, 0x009cd}, {1, 0x009ce},
+ {0, 0x009e2}, {1, 0x009e4}, {0, 0x00a01}, {1, 0x00a03}, {0, 0x00a3c},
+ {1, 0x00a3d}, {0, 0x00a41}, {1, 0x00a43}, {0, 0x00a47}, {1, 0x00a49},
+ {0, 0x00a4b}, {1, 0x00a4e}, {0, 0x00a70}, {1, 0x00a72}, {0, 0x00a81},
+ {1, 0x00a83}, {0, 0x00abc}, {1, 0x00abd}, {0, 0x00ac1}, {1, 0x00ac6},
+ {0, 0x00ac7}, {1, 0x00ac9}, {0, 0x00acd}, {1, 0x00ace}, {0, 0x00ae2},
+ {1, 0x00ae4}, {0, 0x00b01}, {1, 0x00b02}, {0, 0x00b3c}, {1, 0x00b3d},
+ {0, 0x00b3f}, {1, 0x00b40}, {0, 0x00b41}, {1, 0x00b44}, {0, 0x00b4d},
+ {1, 0x00b4e}, {0, 0x00b56}, {1, 0x00b57}, {0, 0x00b82}, {1, 0x00b83},
+ {0, 0x00bc0}, {1, 0x00bc1}, {0, 0x00bcd}, {1, 0x00bce}, {0, 0x00c3e},
+ {1, 0x00c41}, {0, 0x00c46}, {1, 0x00c49}, {0, 0x00c4a}, {1, 0x00c4e},
+ {0, 0x00c55}, {1, 0x00c57}, {0, 0x00cbc}, {1, 0x00cbd}, {0, 0x00cbf},
+ {1, 0x00cc0}, {0, 0x00cc6}, {1, 0x00cc7}, {0, 0x00ccc}, {1, 0x00cce},
+ {0, 0x00ce2}, {1, 0x00ce4}, {0, 0x00d41}, {1, 0x00d44}, {0, 0x00d4d},
+ {1, 0x00d4e}, {0, 0x00dca}, {1, 0x00dcb}, {0, 0x00dd2}, {1, 0x00dd5},
+ {0, 0x00dd6}, {1, 0x00dd7}, {0, 0x00e31}, {1, 0x00e32}, {0, 0x00e34},
+ {1, 0x00e3b}, {0, 0x00e47}, {1, 0x00e4f}, {0, 0x00eb1}, {1, 0x00eb2},
+ {0, 0x00eb4}, {1, 0x00eba}, {0, 0x00ebb}, {1, 0x00ebd}, {0, 0x00ec8},
+ {1, 0x00ece}, {0, 0x00f18}, {1, 0x00f1a}, {0, 0x00f35}, {1, 0x00f36},
+ {0, 0x00f37}, {1, 0x00f38}, {0, 0x00f39}, {1, 0x00f3a}, {0, 0x00f71},
+ {1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88},
+ {0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6},
+ {1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033},
+ {0, 0x01036}, {1, 0x01038}, {0, 0x01039}, {1, 0x0103a}, {0, 0x01058},
+ {1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f},
+ {1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735},
+ {0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4},
+ {1, 0x017b6}, {0, 0x017b7}, {1, 0x017be}, {0, 0x017c6}, {1, 0x017c7},
+ {0, 0x017c9}, {1, 0x017d4}, {0, 0x017dd}, {1, 0x017de}, {0, 0x0180b},
+ {1, 0x0180e}, {0, 0x018a9}, {1, 0x018aa}, {0, 0x01920}, {1, 0x01923},
+ {0, 0x01927}, {1, 0x01929}, {0, 0x01932}, {1, 0x01933}, {0, 0x01939},
+ {1, 0x0193c}, {0, 0x01a17}, {1, 0x01a19}, {0, 0x01b00}, {1, 0x01b04},
+ {0, 0x01b34}, {1, 0x01b35}, {0, 0x01b36}, {1, 0x01b3b}, {0, 0x01b3c},
+ {1, 0x01b3d}, {0, 0x01b42}, {1, 0x01b43}, {0, 0x01b6b}, {1, 0x01b74},
+ {0, 0x01dc0}, {1, 0x01dcb}, {0, 0x01dfe}, {1, 0x01e00}, {0, 0x0200b},
+ {1, 0x02010}, {0, 0x0202a}, {1, 0x0202f}, {0, 0x02060}, {1, 0x02064},
+ {0, 0x0206a}, {1, 0x02070}, {0, 0x020d0}, {1, 0x020f0}, {2, 0x02329},
+ {1, 0x0232b}, {2, 0x02e80}, {0, 0x0302a}, {2, 0x03030}, {1, 0x0303f},
+ {2, 0x03040}, {0, 0x03099}, {2, 0x0309b}, {1, 0x0a4d0}, {0, 0x0a806},
+ {1, 0x0a807}, {0, 0x0a80b}, {1, 0x0a80c}, {0, 0x0a825}, {1, 0x0a827},
+ {2, 0x0ac00}, {1, 0x0d7a4}, {2, 0x0f900}, {1, 0x0fb00}, {0, 0x0fb1e},
+ {1, 0x0fb1f}, {0, 0x0fe00}, {2, 0x0fe10}, {1, 0x0fe1a}, {0, 0x0fe20},
+ {1, 0x0fe24}, {2, 0x0fe30}, {1, 0x0fe70}, {0, 0x0feff}, {2, 0x0ff00},
+ {1, 0x0ff61}, {2, 0x0ffe0}, {1, 0x0ffe7}, {0, 0x0fff9}, {1, 0x0fffc},
+ {0, 0x10a01}, {1, 0x10a04}, {0, 0x10a05}, {1, 0x10a07}, {0, 0x10a0c},
+ {1, 0x10a10}, {0, 0x10a38}, {1, 0x10a3b}, {0, 0x10a3f}, {1, 0x10a40},
+ {0, 0x1d167}, {1, 0x1d16a}, {0, 0x1d173}, {1, 0x1d183}, {0, 0x1d185},
+ {1, 0x1d18c}, {0, 0x1d1aa}, {1, 0x1d1ae}, {0, 0x1d242}, {1, 0x1d245},
+ {2, 0x20000}, {1, 0x2fffe}, {2, 0x30000}, {1, 0x3fffe}, {0, 0xe0001},
+ {1, 0xe0002}, {0, 0xe0020}, {1, 0xe0080}, {0, 0xe0100}, {1, 0xe01f0}
+};
+
/*
-** Output string zUtf to Out stream as w characters. If w is negative,
+** Return an estimate of the width, in columns, for the single Unicode
+** character c. For normal characters, the answer is always 1. But the
+** estimate might be 0 or 2 for zero-width and double-width characters.
+**
+** Different display devices display unicode using different widths. So
+** it is impossible to know that true display width with 100% accuracy.
+** Inaccuracies in the width estimates might cause columns to be misaligned.
+** Unfortunately, there is nothing we can do about that.
+*/
+int cli_wcwidth(int c){
+ int iFirst, iLast;
+
+ /* Fast path for common characters */
+ if( c<=0x300 ) return 1;
+
+ /* The general case */
+ iFirst = 0;
+ iLast = sizeof(aUWidth)/sizeof(aUWidth[0]) - 1;
+ while( iFirst<iLast-1 ){
+ int iMid = (iFirst+iLast)/2;
+ int cMid = aUWidth[iMid].iFirst;
+ if( cMid < c ){
+ iFirst = iMid;
+ }else if( cMid > c ){
+ iLast = iMid - 1;
+ }else{
+ return aUWidth[iMid].w;
+ }
+ }
+ if( aUWidth[iLast].iFirst > c ) return aUWidth[iFirst].w;
+ return aUWidth[iLast].w;
+}
+
+/*
+** Compute the value and length of a multi-byte UTF-8 character that
+** begins at z[0]. Return the length. Write the Unicode value into *pU.
+**
+** This routine only works for *multi-byte* UTF-8 characters.
+*/
+static int decodeUtf8(const unsigned char *z, int *pU){
+ if( (z[0] & 0xe0)==0xc0 && (z[1] & 0xc0)==0x80 ){
+ *pU = ((z[0] & 0x1f)<<6) | (z[1] & 0x3f);
+ return 2;
+ }
+ if( (z[0] & 0xf0)==0xe0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 ){
+ *pU = ((z[0] & 0x0f)<<12) | ((z[1] & 0x3f)<<6) | (z[2] & 0x3f);
+ return 3;
+ }
+ if( (z[0] & 0xf8)==0xf0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80
+ && (z[3] & 0xc0)==0x80
+ ){
+ *pU = ((z[0] & 0x0f)<<18) | ((z[1] & 0x3f)<<12) | ((z[2] & 0x3f))<<6
+ | (z[4] & 0x3f);
+ return 4;
+ }
+ *pU = 0;
+ return 1;
+}
+
+
+#if 0 /* NOT USED */
+/*
+** Return the width, in display columns, of a UTF-8 string.
+**
+** Each normal character counts as 1. Zero-width characters count
+** as zero, and double-width characters count as 2.
+*/
+int cli_wcswidth(const char *z){
+ const unsigned char *a = (const unsigned char*)z;
+ int n = 0;
+ int i = 0;
+ unsigned char c;
+ while( (c = a[i])!=0 ){
+ if( c>=0xc0 ){
+ int u;
+ int len = decodeUtf8(&a[i], &u);
+ i += len;
+ n += cli_wcwidth(u);
+ }else if( c>=' ' ){
+ n++;
+ i++;
+ }else{
+ i++;
+ }
+ }
+ return n;
+}
+#endif
+
+/*
+** Check to see if z[] is a valid VT100 escape. If it is, then
+** return the number of bytes in the escape sequence. Return 0 if
+** z[] is not a VT100 escape.
+**
+** This routine assumes that z[0] is \033 (ESC).
+*/
+static int isVt100(const unsigned char *z){
+ int i;
+ if( z[1]!='[' ) return 0;
+ i = 2;
+ while( z[i]>=0x30 && z[i]<=0x3f ){ i++; }
+ while( z[i]>=0x20 && z[i]<=0x2f ){ i++; }
+ if( z[i]<0x40 || z[i]>0x7e ) return 0;
+ return i+1;
+}
+
+/*
+** Output string zUtf to stdout as w characters. If w is negative,
** then right-justify the text. W is the width in UTF-8 characters, not
** in bytes. This is different from the %*.*s specification in printf
** since with %*.*s the width is measured in bytes, not characters.
+**
+** Take into account zero-width and double-width Unicode characters.
+** In other words, a zero-width character does not count toward the
+** the w limit. A double-width character counts as two.
*/
-static void utf8_width_print(int w, const char *zUtf){
- int i;
- int n;
+static void utf8_width_print(FILE *out, int w, const char *zUtf){
+ const unsigned char *a = (const unsigned char*)zUtf;
+ unsigned char c;
+ int i = 0;
+ int n = 0;
+ int k;
int aw = w<0 ? -w : w;
if( zUtf==0 ) zUtf = "";
- for(i=n=0; zUtf[i]; i++){
- if( (zUtf[i]&0xc0)!=0x80 ){
- n++;
- if( n==aw ){
- do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
+ while( (c = a[i])!=0 ){
+ if( (c&0xc0)==0xc0 ){
+ int u;
+ int len = decodeUtf8(a+i, &u);
+ int x = cli_wcwidth(u);
+ if( x+n>aw ){
break;
}
+ i += len;
+ n += x;
+ }else if( c==0x1b && (k = isVt100(&a[i]))>0 ){
+ i += k;
+ }else if( n>=aw ){
+ break;
+ }else{
+ n++;
+ i++;
}
}
if( n>=aw ){
- oputf("%.*s", i, zUtf);
+ sqlite3_fprintf(out, "%.*s", i, zUtf);
}else if( w<0 ){
- oputf("%*s%s", aw-n, "", zUtf);
+ sqlite3_fprintf(out, "%*s%s", aw-n, "", zUtf);
}else{
- oputf("%s%*s", zUtf, aw-n, "");
+ sqlite3_fprintf(out, "%s%*s", zUtf, aw-n, "");
}
}
@@ -728,12 +887,21 @@ static int strlen30(const char *z){
/*
** Return the length of a string in characters. Multibyte UTF8 characters
-** count as a single character.
+** count as a single character for single-width characters, or as two
+** characters for double-width characters.
*/
static int strlenChar(const char *z){
int n = 0;
while( *z ){
- if( (0xc0&*(z++))!=0x80 ) n++;
+ if( (0x80&z[0])==0 ){
+ n++;
+ z++;
+ }else{
+ int u = 0;
+ int len = decodeUtf8((const u8*)z, &u);
+ z += len;
+ n += cli_wcwidth(u);
+ }
}
return n;
}
@@ -750,7 +918,7 @@ static FILE * openChrSource(const char *zFile){
/* 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 = fopen(zFile, "rb");
+ FILE *rv = sqlite3_fopen(zFile, "rb");
if( rv==0 ) return 0;
if( _fstat64(_fileno(rv), &x) != 0
|| !STAT_CHR_SRC(x.st_mode)){
@@ -764,7 +932,7 @@ static FILE * openChrSource(const char *zFile){
# 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 fopen(zFile, "rb");
+ return sqlite3_fopen(zFile, "rb");
}else{
return 0;
}
@@ -791,7 +959,7 @@ static char *local_getline(char *zLine, FILE *in){
zLine = realloc(zLine, nLine);
shell_check_oom(zLine);
}
- if( fgets(&zLine[n], nLine - n, in)==0 ){
+ if( sqlite3_fgets(&zLine[n], nLine - n, in)==0 ){
if( n==0 ){
free(zLine);
return 0;
@@ -990,9 +1158,9 @@ static void appendText(ShellText *p, const char *zAppend, char quote){
static char quoteChar(const char *zName){
int i;
if( zName==0 ) return '"';
- if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
+ if( !IsAlpha(zName[0]) && zName[0]!='_' ) return '"';
for(i=0; zName[i]; i++){
- if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
+ if( !IsAlnum(zName[i]) && zName[i]!='_' ) return '"';
}
return sqlite3_keyword_check(zName, i) ? '"' : 0;
}
@@ -1084,30 +1252,6 @@ static void shellDtostr(
sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
}
-
-/*
-** SQL function: shell_module_schema(X)
-**
-** Return a fake schema for the table-valued function or eponymous virtual
-** table X.
-*/
-static void shellModuleSchema(
- sqlite3_context *pCtx,
- int nVal,
- sqlite3_value **apVal
-){
- const char *zName;
- char *zFake;
- UNUSED_PARAMETER(nVal);
- zName = (const char*)sqlite3_value_text(apVal[0]);
- zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0;
- if( zFake ){
- sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
- -1, sqlite3_free);
- free(zFake);
- }
-}
-
/*
** SQL function: shell_add_schema(S,X)
**
@@ -1190,14 +1334,11 @@ static void shellAddSchemaName(
#define SQLITE_EXTENSION_INIT1
#define SQLITE_EXTENSION_INIT2(X) (void)(X)
-#if defined(_WIN32) && defined(_MSC_VER)
-INCLUDE test_windirent.h
-INCLUDE test_windirent.c
-#define dirent DIRENT
-#endif
+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/percentile.c
@@ -1225,6 +1366,7 @@ INCLUDE ../ext/expert/sqlite3expert.c
INCLUDE ../ext/intck/sqlite3intck.h
INCLUDE ../ext/intck/sqlite3intck.c
INCLUDE ../ext/misc/stmtrand.c
+INCLUDE ../ext/misc/vfstrace.c
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
#define SQLITE_SHELL_HAVE_RECOVER 1
@@ -1306,6 +1448,8 @@ struct ShellState {
u8 bSafeMode; /* True to prohibit unsafe operations */
u8 bSafeModePersist; /* The long-term value of bSafeMode */
u8 eRestoreState; /* See comments above doAutoDetectRestore() */
+ u8 crlfMode; /* Do NL-to-CRLF translations when enabled (maybe) */
+ u8 eEscMode; /* Escape mode for text output */
ColModeOpts cmOpts; /* Option values affecting columnar mode output */
unsigned statsOn; /* True to display memory stats before each finalize */
unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
@@ -1406,6 +1550,15 @@ static ShellState shellState;
** top-level SQL statement */
#define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
+/* Allowed values for ShellState.eEscMode. The default value should
+** be 0, so to change the default, reorder the names.
+*/
+#define SHELL_ESC_ASCII 0 /* Substitute ^Y for X where Y=X+0x40 */
+#define SHELL_ESC_SYMBOL 1 /* Substitute U+2400 graphics */
+#define SHELL_ESC_OFF 2 /* Send characters verbatim */
+
+static const char *shell_EscModeNames[] = { "ascii", "symbol", "off" };
+
/*
** These are the allowed shellFlgs values
*/
@@ -1451,6 +1604,7 @@ static ShellState shellState;
#define MODE_Count 17 /* Output only a count of the rows of output */
#define MODE_Off 18 /* No query output shown */
#define MODE_ScanExp 19 /* Like MODE_Explain, but for ".scanstats vm" */
+#define MODE_Www 20 /* Full web-page output */
static const char *modeDescr[] = {
"line",
@@ -1471,7 +1625,9 @@ static const char *modeDescr[] = {
"table",
"box",
"count",
- "off"
+ "off",
+ "scanexp",
+ "www",
};
/*
@@ -1499,7 +1655,7 @@ static const char *modeDescr[] = {
static void shellLog(void *pArg, int iErrCode, const char *zMsg){
ShellState *p = (ShellState*)pArg;
if( p->pLog==0 ) return;
- sputf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
+ sqlite3_fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
fflush(p->pLog);
}
@@ -1514,9 +1670,9 @@ static void shellPutsFunc(
int nVal,
sqlite3_value **apVal
){
- /* Unused: (ShellState*)sqlite3_user_data(pCtx); */
+ ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
(void)nVal;
- oputf("%s\n", sqlite3_value_text(apVal[0]));
+ sqlite3_fprintf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
sqlite3_result_value(pCtx, apVal[0]);
}
@@ -1535,7 +1691,7 @@ static void failIfSafeMode(
va_start(ap, zErrMsg);
zMsg = sqlite3_vmprintf(zErrMsg, ap);
va_end(ap);
- eputf("line %d: %s\n", p->lineno, zMsg);
+ sqlite3_fprintf(stderr, "line %d: %s\n", p->lineno, zMsg);
exit(1);
}
}
@@ -1568,7 +1724,7 @@ static void editFunc(
char *zCmd = 0;
int bBin;
int rc;
- int hasCRNL = 0;
+ int hasCRLF = 0;
FILE *f = 0;
sqlite3_int64 sz;
sqlite3_int64 x;
@@ -1602,7 +1758,7 @@ static void editFunc(
bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
/* When writing the file to be edited, do \n to \r\n conversions on systems
** that want \r\n line endings */
- f = fopen(zTempFile, bBin ? "wb" : "w");
+ f = sqlite3_fopen(zTempFile, bBin ? "wb" : "w");
if( f==0 ){
sqlite3_result_error(context, "edit() cannot open temp file", -1);
goto edit_func_end;
@@ -1613,7 +1769,7 @@ static void editFunc(
}else{
const char *z = (const char*)sqlite3_value_text(argv[0]);
/* Remember whether or not the value originally contained \r\n */
- if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1;
+ if( z && strstr(z,"\r\n")!=0 ) hasCRLF = 1;
x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
}
fclose(f);
@@ -1633,7 +1789,7 @@ static void editFunc(
sqlite3_result_error(context, "EDITOR returned non-zero", -1);
goto edit_func_end;
}
- f = fopen(zTempFile, "rb");
+ f = sqlite3_fopen(zTempFile, "rb");
if( f==0 ){
sqlite3_result_error(context,
"edit() cannot reopen temp file after edit", -1);
@@ -1658,7 +1814,7 @@ static void editFunc(
sqlite3_result_blob64(context, p, sz, sqlite3_free);
}else{
sqlite3_int64 i, j;
- if( hasCRNL ){
+ if( hasCRLF ){
/* If the original contains \r\n then do no conversions back to \n */
}else{
/* If the file did not originally contain \r\n then convert any new
@@ -1701,9 +1857,24 @@ static void outputModePop(ShellState *p){
}
/*
+** Set output mode to text or binary for Windows.
+*/
+static void setCrlfMode(ShellState *p){
+#ifdef _WIN32
+ if( p->crlfMode ){
+ sqlite3_fsetmode(p->out, _O_TEXT);
+ }else{
+ sqlite3_fsetmode(p->out, _O_BINARY);
+ }
+#else
+ UNUSED_PARAMETER(p);
+#endif
+}
+
+/*
** Output the given string as a hex-encoded blob (eg. X'1234' )
*/
-static void output_hex_blob(const void *pBlob, int nBlob){
+static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
int i;
unsigned char *aBlob = (unsigned char*)pBlob;
@@ -1720,72 +1891,82 @@ static void output_hex_blob(const void *pBlob, int nBlob){
}
zStr[i*2] = '\0';
- oputf("X'%s'", zStr);
+ sqlite3_fprintf(out, "X'%s'", zStr);
sqlite3_free(zStr);
}
/*
-** Find a string that is not found anywhere in z[]. Return a pointer
-** to that string.
+** Output the given string as a quoted string using SQL quoting conventions:
**
-** Try to use zA and zB first. If both of those are already found in z[]
-** then make up some string and store it in the buffer zBuf.
-*/
-static const char *unused_string(
- const char *z, /* Result must not appear anywhere in z */
- const char *zA, const char *zB, /* Try these first */
- char *zBuf /* Space to store a generated string */
-){
- unsigned i = 0;
- if( strstr(z, zA)==0 ) return zA;
- if( strstr(z, zB)==0 ) return zB;
- do{
- sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
- }while( strstr(z,zBuf)!=0 );
- return zBuf;
-}
-
-/*
-** Output the given string as a quoted string using SQL quoting conventions.
+** (1) Single quotes (') within the string are doubled
+** (2) The whle string is enclosed in '...'
+** (3) Control characters other than \n, \t, and \r\n are escaped
+** using \u00XX notation and if such substitutions occur,
+** the whole string is enclosed in unistr('...') instead of '...'.
+**
+** Step (3) is omitted if the control-character escape mode is OFF.
**
-** See also: output_quoted_escaped_string()
+** See also: output_quoted_escaped_string() which does the same except
+** that it does not make exceptions for \n, \t, and \r\n in step (3).
*/
-static void output_quoted_string(const char *z){
+static void output_quoted_string(ShellState *p, const char *zInX){
int i;
- char c;
-#ifndef SQLITE_SHELL_FIDDLE
- FILE *pfO = setOutputStream(invalidFileStream);
- setBinaryMode(pfO, 1);
-#endif
+ int needUnistr = 0;
+ int needDblQuote = 0;
+ const unsigned char *z = (const unsigned char*)zInX;
+ unsigned char c;
+ FILE *out = p->out;
+ sqlite3_fsetmode(out, _O_BINARY);
if( z==0 ) return;
- for(i=0; (c = z[i])!=0 && c!='\''; i++){}
- if( c==0 ){
- oputf("'%s'",z);
+ for(i=0; (c = z[i])!=0; i++){
+ if( c=='\'' ){ needDblQuote = 1; }
+ if( c>0x1f ) continue;
+ if( c=='\t' || c=='\n' ) continue;
+ if( c=='\r' && z[i+1]=='\n' ) continue;
+ needUnistr = 1;
+ break;
+ }
+ if( (needDblQuote==0 && needUnistr==0)
+ || (needDblQuote==0 && p->eEscMode==SHELL_ESC_OFF)
+ ){
+ sqlite3_fprintf(out, "'%s'",z);
+ }else if( p->eEscMode==SHELL_ESC_OFF ){
+ char *zEncoded = sqlite3_mprintf("%Q", z);
+ sqlite3_fputs(zEncoded, out);
+ sqlite3_free(zEncoded);
}else{
- oputz("'");
+ if( needUnistr ){
+ sqlite3_fputs("unistr('", out);
+ }else{
+ sqlite3_fputs("'", out);
+ }
while( *z ){
- for(i=0; (c = z[i])!=0 && c!='\''; i++){}
- if( c=='\'' ) i++;
+ for(i=0; (c = z[i])!=0; i++){
+ if( c=='\'' ) break;
+ if( c>0x1f ) continue;
+ if( c=='\t' || c=='\n' ) continue;
+ if( c=='\r' && z[i+1]=='\n' ) continue;
+ break;
+ }
if( i ){
- oputf("%.*s", i, z);
+ sqlite3_fprintf(out, "%.*s", i, z);
z += i;
}
+ if( c==0 ) break;
if( c=='\'' ){
- oputz("'");
- continue;
- }
- if( c==0 ){
- break;
+ sqlite3_fputs("''", out);
+ }else{
+ sqlite3_fprintf(out, "\\u%04x", c);
}
z++;
}
- oputz("'");
+ if( needUnistr ){
+ sqlite3_fputs("')", out);
+ }else{
+ sqlite3_fputs("'", out);
+ }
}
-#ifndef SQLITE_SHELL_FIDDLE
- setTextMode(pfO, 1);
-#else
- setTextMode(stdout, 1);
-#endif
+ setCrlfMode(p);
}
/*
@@ -1797,69 +1978,17 @@ static void output_quoted_string(const char *z){
** This is like output_quoted_string() but with the addition of the \r\n
** escape mechanism.
*/
-static void output_quoted_escaped_string(const char *z){
- int i;
- char c;
-#ifndef SQLITE_SHELL_FIDDLE
- FILE *pfO = setOutputStream(invalidFileStream);
- setBinaryMode(pfO, 1);
-#endif
- for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
- if( c==0 ){
- oputf("'%s'",z);
+static void output_quoted_escaped_string(ShellState *p, const char *z){
+ char *zEscaped;
+ sqlite3_fsetmode(p->out, _O_BINARY);
+ if( p->eEscMode==SHELL_ESC_OFF ){
+ zEscaped = sqlite3_mprintf("%Q", z);
}else{
- const char *zNL = 0;
- const char *zCR = 0;
- int nNL = 0;
- int nCR = 0;
- char zBuf1[20], zBuf2[20];
- for(i=0; z[i]; i++){
- if( z[i]=='\n' ) nNL++;
- if( z[i]=='\r' ) nCR++;
- }
- if( nNL ){
- oputz("replace(");
- zNL = unused_string(z, "\\n", "\\012", zBuf1);
- }
- if( nCR ){
- oputz("replace(");
- zCR = unused_string(z, "\\r", "\\015", zBuf2);
- }
- oputz("'");
- while( *z ){
- for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
- if( c=='\'' ) i++;
- if( i ){
- oputf("%.*s", i, z);
- z += i;
- }
- if( c=='\'' ){
- oputz("'");
- continue;
- }
- if( c==0 ){
- break;
- }
- z++;
- if( c=='\n' ){
- oputz(zNL);
- continue;
- }
- oputz(zCR);
- }
- oputz("'");
- if( nCR ){
- oputf(",'%s',char(13))", zCR);
- }
- if( nNL ){
- oputf(",'%s',char(10))", zNL);
- }
+ zEscaped = sqlite3_mprintf("%#Q", z);
}
-#ifndef SQLITE_SHELL_FIDDLE
- setTextMode(pfO, 1);
-#else
- setTextMode(stdout, 1);
-#endif
+ sqlite3_fputs(zEscaped, p->out);
+ sqlite3_free(zEscaped);
+ setCrlfMode(p);
}
/*
@@ -1879,22 +2008,60 @@ static const char *anyOfInStr(const char *s, const char *zAny, size_t ns){
}
return pcFirst;
}
+
+/* Skip over as much z[] input char sequence as is valid UTF-8,
+** limited per nAccept char's or whole characters and containing
+** no char cn such that ((1<<cn) & ccm)!=0. On return, the
+** sequence z:return (inclusive:exclusive) is validated UTF-8.
+** Limit: nAccept>=0 => char count, nAccept<0 => character
+ */
+const char *zSkipValidUtf8(const char *z, int nAccept, long ccm){
+ int ng = (nAccept<0)? -nAccept : 0;
+ const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
+ assert(z!=0);
+ while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
+ unsigned char c = *(u8*)z;
+ if( c<0x7f ){
+ if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
+ ++z; /* ASCII */
+ }else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
+ else{
+ const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
+ do{
+ if( pcLimit && zt >= pcLimit ) return z;
+ else{
+ char ct = *zt++;
+ if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
+ /* Trailing bytes are too few, too many, or invalid. */
+ return z;
+ }
+ }
+ } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
+ z = zt;
+ }
+ }
+ return z;
+}
+
+
/*
** Output the given string as a quoted according to C or TCL quoting rules.
*/
-static void output_c_string(const char *z){
+static void output_c_string(FILE *out, const char *z){
char c;
static const char *zq = "\"";
static long ctrlMask = ~0L;
static const char *zDQBSRO = "\"\\\x7f"; /* double-quote, backslash, rubout */
char ace[3] = "\\?";
char cbsSay;
- oputz(zq);
+ sqlite3_fputs(zq, out);
while( *z!=0 ){
const char *pcDQBSRO = anyOfInStr(z, zDQBSRO, ~(size_t)0);
const char *pcPast = zSkipValidUtf8(z, INT_MAX, ctrlMask);
const char *pcEnd = (pcDQBSRO && pcDQBSRO < pcPast)? pcDQBSRO : pcPast;
- if( pcEnd > z ) oputb(z, (int)(pcEnd-z));
+ if( pcEnd > z ){
+ sqlite3_fprintf(out, "%.*s", (int)(pcEnd-z), z);
+ }
if( (c = *pcEnd)==0 ) break;
++pcEnd;
switch( c ){
@@ -1909,23 +2076,23 @@ static void output_c_string(const char *z){
}
if( cbsSay ){
ace[1] = cbsSay;
- oputz(ace);
+ sqlite3_fputs(ace, out);
}else if( !isprint(c&0xff) ){
- oputf("\\%03o", c&0xff);
+ sqlite3_fprintf(out, "\\%03o", c&0xff);
}else{
ace[1] = (char)c;
- oputz(ace+1);
+ sqlite3_fputs(ace+1, out);
}
z = pcEnd;
}
- oputz(zq);
+ sqlite3_fputs(zq, out);
}
/*
-** Output the given string as a quoted according to JSON quoting rules.
+** Output the given string as quoted according to JSON quoting rules.
*/
-static void output_json_string(const char *z, i64 n){
- char c;
+static void output_json_string(FILE *out, const char *z, i64 n){
+ unsigned char c;
static const char *zq = "\"";
static long ctrlMask = ~0L;
static const char *zDQBS = "\"\\";
@@ -1935,17 +2102,17 @@ static void output_json_string(const char *z, i64 n){
if( z==0 ) z = "";
pcLimit = z + ((n<0)? strlen(z) : (size_t)n);
- oputz(zq);
+ sqlite3_fputs(zq, out);
while( z < pcLimit ){
const char *pcDQBS = anyOfInStr(z, zDQBS, pcLimit-z);
const char *pcPast = zSkipValidUtf8(z, (int)(pcLimit-z), ctrlMask);
const char *pcEnd = (pcDQBS && pcDQBS < pcPast)? pcDQBS : pcPast;
if( pcEnd > z ){
- oputb(z, (int)(pcEnd-z));
+ sqlite3_fprintf(out, "%.*s", (int)(pcEnd-z), z);
z = pcEnd;
}
if( z >= pcLimit ) break;
- c = *(z++);
+ c = (unsigned char)*(z++);
switch( c ){
case '"': case '\\':
cbsSay = (char)c;
@@ -1959,22 +2126,109 @@ static void output_json_string(const char *z, i64 n){
}
if( cbsSay ){
ace[1] = cbsSay;
- oputz(ace);
- }else if( c<=0x1f ){
- oputf("u%04x", c);
+ sqlite3_fputs(ace, out);
+ }else if( c<=0x1f || c>=0x7f ){
+ sqlite3_fprintf(out, "\\u%04x", c);
}else{
ace[1] = (char)c;
- oputz(ace+1);
+ sqlite3_fputs(ace+1, out);
}
}
- oputz(zq);
+ sqlite3_fputs(zq, out);
+}
+
+/*
+** Escape the input string if it is needed and in accordance with
+** eEscMode.
+**
+** Escaping is needed if the string contains any control characters
+** other than \t, \n, and \r\n
+**
+** If no escaping is needed (the common case) then set *ppFree to NULL
+** and return the original string. If escapingn is needed, write the
+** escaped string into memory obtained from sqlite3_malloc64() or the
+** equivalent, and return the new string and set *ppFree to the new string
+** as well.
+**
+** The caller is responsible for freeing *ppFree if it is non-NULL in order
+** to reclaim memory.
+*/
+static const char *escapeOutput(
+ ShellState *p,
+ const char *zInX,
+ char **ppFree
+){
+ i64 i, j;
+ i64 nCtrl = 0;
+ unsigned char *zIn;
+ unsigned char c;
+ unsigned char *zOut;
+
+
+ /* No escaping if disabled */
+ if( p->eEscMode==SHELL_ESC_OFF ){
+ *ppFree = 0;
+ return zInX;
+ }
+
+ /* Count the number of control characters in the string. */
+ zIn = (unsigned char*)zInX;
+ for(i=0; (c = zIn[i])!=0; i++){
+ if( c<=0x1f
+ && c!='\t'
+ && c!='\n'
+ && (c!='\r' || zIn[i+1]!='\n')
+ ){
+ nCtrl++;
+ }
+ }
+ if( nCtrl==0 ){
+ *ppFree = 0;
+ return zInX;
+ }
+ if( p->eEscMode==SHELL_ESC_SYMBOL ) nCtrl *= 2;
+ zOut = sqlite3_malloc64( i + nCtrl + 1 );
+ shell_check_oom(zOut);
+ for(i=j=0; (c = zIn[i])!=0; i++){
+ if( c>0x1f
+ || c=='\t'
+ || c=='\n'
+ || (c=='\r' && zIn[i+1]=='\n')
+ ){
+ continue;
+ }
+ if( i>0 ){
+ memcpy(&zOut[j], zIn, i);
+ j += i;
+ }
+ zIn += i+1;
+ i = -1;
+ switch( p->eEscMode ){
+ case SHELL_ESC_SYMBOL:
+ zOut[j++] = 0xe2;
+ zOut[j++] = 0x90;
+ zOut[j++] = 0x80+c;
+ break;
+ case SHELL_ESC_ASCII:
+ zOut[j++] = '^';
+ zOut[j++] = 0x40+c;
+ break;
+ }
+ }
+ if( i>0 ){
+ memcpy(&zOut[j], zIn, i);
+ j += i;
+ }
+ zOut[j] = 0;
+ *ppFree = (char*)zOut;
+ return (char*)zOut;
}
/*
** Output the given string with characters that are special to
** HTML escaped.
*/
-static void output_html_string(const char *z){
+static void output_html_string(FILE *out, const char *z){
int i;
if( z==0 ) z = "";
while( *z ){
@@ -1986,18 +2240,18 @@ static void output_html_string(const char *z){
&& z[i]!='\'';
i++){}
if( i>0 ){
- oputf("%.*s",i,z);
+ sqlite3_fprintf(out, "%.*s",i,z);
}
if( z[i]=='<' ){
- oputz("&lt;");
+ sqlite3_fputs("&lt;", out);
}else if( z[i]=='&' ){
- oputz("&amp;");
+ sqlite3_fputs("&amp;", out);
}else if( z[i]=='>' ){
- oputz("&gt;");
+ sqlite3_fputs("&gt;", out);
}else if( z[i]=='\"' ){
- oputz("&quot;");
+ sqlite3_fputs("&quot;", out);
}else if( z[i]=='\'' ){
- oputz("&#39;");
+ sqlite3_fputs("&#39;", out);
}else{
break;
}
@@ -2036,7 +2290,7 @@ static const char needCsvQuote[] = {
*/
static void output_csv(ShellState *p, const char *z, int bSep){
if( z==0 ){
- oputf("%s",p->nullValue);
+ sqlite3_fprintf(p->out, "%s",p->nullValue);
}else{
unsigned i;
for(i=0; z[i]; i++){
@@ -2048,14 +2302,14 @@ static void output_csv(ShellState *p, const char *z, int bSep){
if( i==0 || strstr(z, p->colSeparator)!=0 ){
char *zQuoted = sqlite3_mprintf("\"%w\"", z);
shell_check_oom(zQuoted);
- oputz(zQuoted);
+ sqlite3_fputs(zQuoted, p->out);
sqlite3_free(zQuoted);
}else{
- oputz(z);
+ sqlite3_fputs(z, p->out);
}
}
if( bSep ){
- oputz(p->colSeparator);
+ sqlite3_fputs(p->colSeparator, p->out);
}
}
@@ -2163,16 +2417,16 @@ static int shellAuth(
az[1] = zA2;
az[2] = zA3;
az[3] = zA4;
- oputf("authorizer: %s", azAction[op]);
+ sqlite3_fprintf(p->out, "authorizer: %s", azAction[op]);
for(i=0; i<4; i++){
- oputz(" ");
+ sqlite3_fputs(" ", p->out);
if( az[i] ){
- output_c_string(az[i]);
+ output_c_string(p->out, az[i]);
}else{
- oputz("NULL");
+ sqlite3_fputs("NULL", p->out);
}
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
return SQLITE_OK;
}
@@ -2188,7 +2442,7 @@ static int shellAuth(
** sqlite3_complete() returns false, try to terminate the comment before
** printing the result. https://sqlite.org/forum/forumpost/d7be961c5c
*/
-static void printSchemaLine(const char *z, const char *zTail){
+static void printSchemaLine(FILE *out, const char *z, const char *zTail){
char *zToFree = 0;
if( z==0 ) return;
if( zTail==0 ) return;
@@ -2210,16 +2464,16 @@ static void printSchemaLine(const char *z, const char *zTail){
}
}
if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
- oputf("CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
+ sqlite3_fprintf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
}else{
- oputf("%s%s", z, zTail);
+ sqlite3_fprintf(out, "%s%s", z, zTail);
}
sqlite3_free(zToFree);
}
-static void printSchemaLineN(char *z, int n, const char *zTail){
+static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
char c = z[n];
z[n] = 0;
- printSchemaLine(z, zTail);
+ printSchemaLine(out, z, zTail);
z[n] = c;
}
@@ -2247,7 +2501,7 @@ static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){
if( zText==0 ) return;
nText = strlen(zText);
if( p->autoEQPtest ){
- oputf("%d,%d,%s\n", iEqpId, p2, zText);
+ sqlite3_fprintf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
}
pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
shell_check_oom(pNew);
@@ -2295,7 +2549,8 @@ static void eqp_render_level(ShellState *p, int iEqpId){
for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
pNext = eqp_next_row(p, iEqpId, pRow);
z = pRow->zText;
- oputf("%s%s%s\n", p->sGraph.zPrefix, pNext ? "|--" : "`--", z);
+ sqlite3_fprintf(p->out, "%s%s%s\n", p->sGraph.zPrefix,
+ pNext ? "|--" : "`--", z);
if( n<(i64)sizeof(p->sGraph.zPrefix)-7 ){
memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
eqp_render_level(p, pRow->iEqpId);
@@ -2315,13 +2570,13 @@ static void eqp_render(ShellState *p, i64 nCycle){
eqp_reset(p);
return;
}
- oputf("%s\n", pRow->zText+3);
+ sqlite3_fprintf(p->out, "%s\n", pRow->zText+3);
p->sGraph.pRow = pRow->pNext;
sqlite3_free(pRow);
}else if( nCycle>0 ){
- oputf("QUERY PLAN (cycles=%lld [100%%])\n", nCycle);
+ sqlite3_fprintf(p->out, "QUERY PLAN (cycles=%lld [100%%])\n", nCycle);
}else{
- oputz("QUERY PLAN\n");
+ sqlite3_fputs("QUERY PLAN\n", p->out);
}
p->sGraph.zPrefix[0] = 0;
eqp_render_level(p, 0);
@@ -2337,13 +2592,13 @@ static int progress_handler(void *pClientData) {
ShellState *p = (ShellState*)pClientData;
p->nProgress++;
if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){
- oputf("Progress limit reached (%u)\n", p->nProgress);
+ sqlite3_fprintf(p->out, "Progress limit reached (%u)\n", p->nProgress);
if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0;
return 1;
}
if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){
- oputf("Progress %u\n", p->nProgress);
+ sqlite3_fprintf(p->out, "Progress %u\n", p->nProgress);
}
return 0;
}
@@ -2352,14 +2607,14 @@ static int progress_handler(void *pClientData) {
/*
** Print N dashes
*/
-static void print_dashes(int N){
+static void print_dashes(FILE *out, int N){
const char zDash[] = "--------------------------------------------------";
const int nDash = sizeof(zDash) - 1;
while( N>nDash ){
- oputz(zDash);
+ sqlite3_fputs(zDash, out);
N -= nDash;
}
- oputf("%.*s", N, zDash);
+ sqlite3_fprintf(out, "%.*s", N, zDash);
}
/*
@@ -2372,15 +2627,15 @@ static void print_row_separator(
){
int i;
if( nArg>0 ){
- oputz(zSep);
- print_dashes(p->actualWidth[0]+2);
+ sqlite3_fputs(zSep, p->out);
+ print_dashes(p->out, p->actualWidth[0]+2);
for(i=1; i<nArg; i++){
- oputz(zSep);
- print_dashes(p->actualWidth[i]+2);
+ sqlite3_fputs(zSep, p->out);
+ print_dashes(p->out, p->actualWidth[i]+2);
}
- oputz(zSep);
+ sqlite3_fputs(zSep, p->out);
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}
/*
@@ -2410,10 +2665,14 @@ static int shell_callback(
int len = strlen30(azCol[i] ? azCol[i] : "");
if( len>w ) w = len;
}
- if( p->cnt++>0 ) oputz(p->rowSeparator);
+ if( p->cnt++>0 ) sqlite3_fputs(p->rowSeparator, p->out);
for(i=0; i<nArg; i++){
- oputf("%*s = %s%s", w, azCol[i],
- azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
+ char *pFree = 0;
+ const char *pDisplay;
+ pDisplay = escapeOutput(p, azArg[i] ? azArg[i] : p->nullValue, &pFree);
+ sqlite3_fprintf(p->out, "%*s = %s%s", w, azCol[i],
+ pDisplay, p->rowSeparator);
+ if( pFree ) sqlite3_free(pFree);
}
break;
}
@@ -2440,12 +2699,12 @@ static int shell_callback(
/* If this is the first row seen, print out the headers */
if( p->cnt++==0 ){
for(i=0; i<nArg; i++){
- utf8_width_print(aWidth[i], azCol[ aMap[i] ]);
- oputz(i==nArg-1 ? "\n" : " ");
+ utf8_width_print(p->out, aWidth[i], azCol[ aMap[i] ]);
+ sqlite3_fputs(i==nArg-1 ? "\n" : " ", p->out);
}
for(i=0; i<nArg; i++){
- print_dashes(aWidth[i]);
- oputz(i==nArg-1 ? "\n" : " ");
+ print_dashes(p->out, aWidth[i]);
+ sqlite3_fputs(i==nArg-1 ? "\n" : " ", p->out);
}
}
@@ -2463,17 +2722,17 @@ static int shell_callback(
}
if( i==iIndent && p->aiIndent && p->pStmt ){
if( p->iIndent<p->nIndent ){
- oputf("%*.s", p->aiIndent[p->iIndent], "");
+ sqlite3_fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
}
p->iIndent++;
}
- utf8_width_print(w, zVal ? zVal : p->nullValue);
- oputz(i==nArg-1 ? "\n" : zSep);
+ utf8_width_print(p->out, w, zVal ? zVal : p->nullValue);
+ sqlite3_fputs(i==nArg-1 ? "\n" : zSep, p->out);
}
break;
}
case MODE_Semi: { /* .schema and .fullschema output */
- printSchemaLine(azArg[0], ";\n");
+ printSchemaLine(p->out, azArg[0], ";\n");
break;
}
case MODE_Pretty: { /* .schema and .fullschema with --indent */
@@ -2483,14 +2742,18 @@ static int shell_callback(
char cEnd = 0;
char c;
int nLine = 0;
+ int isIndex;
+ int isWhere = 0;
assert( nArg==1 );
if( azArg[0]==0 ) break;
if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
|| sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
){
- oputf("%s;\n", azArg[0]);
+ sqlite3_fprintf(p->out, "%s;\n", azArg[0]);
break;
}
+ isIndex = sqlite3_strlike("CREATE INDEX%", azArg[0], 0)==0
+ || sqlite3_strlike("CREATE UNIQUE INDEX%", azArg[0], 0)==0;
z = sqlite3_mprintf("%s", azArg[0]);
shell_check_oom(z);
j = 0;
@@ -2520,17 +2783,29 @@ static int shell_callback(
nParen++;
}else if( c==')' ){
nParen--;
- if( nLine>0 && nParen==0 && j>0 ){
- printSchemaLineN(z, j, "\n");
+ if( nLine>0 && nParen==0 && j>0 && !isWhere ){
+ printSchemaLineN(p->out, z, j, "\n");
j = 0;
}
+ }else if( (c=='w' || c=='W')
+ && nParen==0 && isIndex
+ && sqlite3_strnicmp("WHERE",&z[i],5)==0
+ && !IsAlnum(z[i+5]) && z[i+5]!='_' ){
+ isWhere = 1;
+ }else if( isWhere && (c=='A' || c=='a')
+ && nParen==0
+ && sqlite3_strnicmp("AND",&z[i],3)==0
+ && !IsAlnum(z[i+3]) && z[i+3]!='_' ){
+ printSchemaLineN(p->out, z, j, "\n ");
+ j = 0;
}
z[j++] = c;
if( nParen==1 && cEnd==0
&& (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
+ && !isWhere
){
if( c=='\n' ) j--;
- printSchemaLineN(z, j, "\n ");
+ printSchemaLineN(p->out, z, j, "\n ");
j = 0;
nLine++;
while( IsSpace(z[i+1]) ){ i++; }
@@ -2538,118 +2813,136 @@ static int shell_callback(
}
z[j] = 0;
}
- printSchemaLine(z, ";\n");
+ printSchemaLine(p->out, z, ";\n");
sqlite3_free(z);
break;
}
case MODE_List: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- oputf("%s%s",azCol[i], i==nArg-1 ? p->rowSeparator : p->colSeparator);
+ char *z = azCol[i];
+ char *pFree;
+ const char *zOut = escapeOutput(p, z, &pFree);
+ sqlite3_fprintf(p->out, "%s%s", zOut,
+ i==nArg-1 ? p->rowSeparator : p->colSeparator);
+ if( pFree ) sqlite3_free(pFree);
}
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
char *z = azArg[i];
+ char *pFree;
+ const char *zOut;
if( z==0 ) z = p->nullValue;
- oputz(z);
- oputz((i<nArg-1)? p->colSeparator : p->rowSeparator);
+ zOut = escapeOutput(p, z, &pFree);
+ sqlite3_fputs(zOut, p->out);
+ if( pFree ) sqlite3_free(pFree);
+ sqlite3_fputs((i<nArg-1)? p->colSeparator : p->rowSeparator, p->out);
}
break;
}
+ case MODE_Www:
case MODE_Html: {
- if( p->cnt++==0 && p->showHeader ){
- oputz("<TR>");
+ if( p->cnt==0 && p->cMode==MODE_Www ){
+ sqlite3_fputs(
+ "</PRE>\n"
+ "<TABLE border='1' cellspacing='0' cellpadding='2'>\n"
+ ,p->out
+ );
+ }
+ if( p->cnt==0 && (p->showHeader || p->cMode==MODE_Www) ){
+ sqlite3_fputs("<TR>", p->out);
for(i=0; i<nArg; i++){
- oputz("<TH>");
- output_html_string(azCol[i]);
- oputz("</TH>\n");
+ sqlite3_fputs("<TH>", p->out);
+ output_html_string(p->out, azCol[i]);
+ sqlite3_fputs("</TH>\n", p->out);
}
- oputz("</TR>\n");
+ sqlite3_fputs("</TR>\n", p->out);
}
+ p->cnt++;
if( azArg==0 ) break;
- oputz("<TR>");
+ sqlite3_fputs("<TR>", p->out);
for(i=0; i<nArg; i++){
- oputz("<TD>");
- output_html_string(azArg[i] ? azArg[i] : p->nullValue);
- oputz("</TD>\n");
+ sqlite3_fputs("<TD>", p->out);
+ output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
+ sqlite3_fputs("</TD>\n", p->out);
}
- oputz("</TR>\n");
+ sqlite3_fputs("</TR>\n", p->out);
break;
}
case MODE_Tcl: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- output_c_string(azCol[i] ? azCol[i] : "");
- if(i<nArg-1) oputz(p->colSeparator);
+ output_c_string(p->out, azCol[i] ? azCol[i] : "");
+ if(i<nArg-1) sqlite3_fputs(p->colSeparator, p->out);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- output_c_string(azArg[i] ? azArg[i] : p->nullValue);
- if(i<nArg-1) oputz(p->colSeparator);
+ output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
+ if(i<nArg-1) sqlite3_fputs(p->colSeparator, p->out);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
break;
}
case MODE_Csv: {
- setBinaryMode(p->out, 1);
+ sqlite3_fsetmode(p->out, _O_BINARY);
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
}
if( nArg>0 ){
for(i=0; i<nArg; i++){
output_csv(p, azArg[i], i<nArg-1);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
}
- setTextMode(p->out, 1);
+ setCrlfMode(p);
break;
}
case MODE_Insert: {
if( azArg==0 ) break;
- oputf("INSERT INTO %s",p->zDestTable);
+ sqlite3_fprintf(p->out, "INSERT INTO %s",p->zDestTable);
if( p->showHeader ){
- oputz("(");
+ sqlite3_fputs("(", p->out);
for(i=0; i<nArg; i++){
- if( i>0 ) oputz(",");
+ if( i>0 ) sqlite3_fputs(",", p->out);
if( quoteChar(azCol[i]) ){
char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
shell_check_oom(z);
- oputz(z);
+ sqlite3_fputs(z, p->out);
sqlite3_free(z);
}else{
- oputf("%s", azCol[i]);
+ sqlite3_fprintf(p->out, "%s", azCol[i]);
}
}
- oputz(")");
+ sqlite3_fputs(")", p->out);
}
p->cnt++;
for(i=0; i<nArg; i++){
- oputz(i>0 ? "," : " VALUES(");
+ sqlite3_fputs(i>0 ? "," : " VALUES(", p->out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- oputz("NULL");
+ sqlite3_fputs("NULL", p->out);
}else if( aiType && aiType[i]==SQLITE_TEXT ){
if( ShellHasFlag(p, SHFLG_Newlines) ){
- output_quoted_string(azArg[i]);
+ output_quoted_string(p, azArg[i]);
}else{
- output_quoted_escaped_string(azArg[i]);
+ output_quoted_escaped_string(p, azArg[i]);
}
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
- oputz(azArg[i]);
+ sqlite3_fputs(azArg[i], p->out);
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
char z[50];
double r = sqlite3_column_double(p->pStmt, i);
sqlite3_uint64 ur;
memcpy(&ur,&r,sizeof(r));
if( ur==0x7ff0000000000000LL ){
- oputz("9.0e+999");
+ sqlite3_fputs("9.0e+999", p->out);
}else if( ur==0xfff0000000000000LL ){
- oputz("-9.0e+999");
+ sqlite3_fputs("-9.0e+999", p->out);
}else{
sqlite3_int64 ir = (sqlite3_int64)r;
if( r==(double)ir ){
@@ -2657,115 +2950,115 @@ static int shell_callback(
}else{
sqlite3_snprintf(50,z,"%!.20g", r);
}
- oputz(z);
+ sqlite3_fputs(z, p->out);
}
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
int nBlob = sqlite3_column_bytes(p->pStmt, i);
- output_hex_blob(pBlob, nBlob);
+ output_hex_blob(p->out, pBlob, nBlob);
}else if( isNumber(azArg[i], 0) ){
- oputz(azArg[i]);
+ sqlite3_fputs(azArg[i], p->out);
}else if( ShellHasFlag(p, SHFLG_Newlines) ){
- output_quoted_string(azArg[i]);
+ output_quoted_string(p, azArg[i]);
}else{
- output_quoted_escaped_string(azArg[i]);
+ output_quoted_escaped_string(p, azArg[i]);
}
}
- oputz(");\n");
+ sqlite3_fputs(");\n", p->out);
break;
}
case MODE_Json: {
if( azArg==0 ) break;
if( p->cnt==0 ){
- fputs("[{", p->out);
+ sqlite3_fputs("[{", p->out);
}else{
- fputs(",\n{", p->out);
+ sqlite3_fputs(",\n{", p->out);
}
p->cnt++;
for(i=0; i<nArg; i++){
- output_json_string(azCol[i], -1);
- oputz(":");
+ output_json_string(p->out, azCol[i], -1);
+ sqlite3_fputs(":", p->out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- oputz("null");
+ sqlite3_fputs("null", p->out);
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
char z[50];
double r = sqlite3_column_double(p->pStmt, i);
sqlite3_uint64 ur;
memcpy(&ur,&r,sizeof(r));
if( ur==0x7ff0000000000000LL ){
- oputz("9.0e+999");
+ sqlite3_fputs("9.0e+999", p->out);
}else if( ur==0xfff0000000000000LL ){
- oputz("-9.0e+999");
+ sqlite3_fputs("-9.0e+999", p->out);
}else{
sqlite3_snprintf(50,z,"%!.20g", r);
- oputz(z);
+ sqlite3_fputs(z, p->out);
}
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
int nBlob = sqlite3_column_bytes(p->pStmt, i);
- output_json_string(pBlob, nBlob);
+ output_json_string(p->out, pBlob, nBlob);
}else if( aiType && aiType[i]==SQLITE_TEXT ){
- output_json_string(azArg[i], -1);
+ output_json_string(p->out, azArg[i], -1);
}else{
- oputz(azArg[i]);
+ sqlite3_fputs(azArg[i], p->out);
}
if( i<nArg-1 ){
- oputz(",");
+ sqlite3_fputs(",", p->out);
}
}
- oputz("}");
+ sqlite3_fputs("}", p->out);
break;
}
case MODE_Quote: {
if( azArg==0 ) break;
if( p->cnt==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- if( i>0 ) fputs(p->colSeparator, p->out);
- output_quoted_string(azCol[i]);
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
+ output_quoted_string(p, azCol[i]);
}
- fputs(p->rowSeparator, p->out);
+ sqlite3_fputs(p->rowSeparator, p->out);
}
p->cnt++;
for(i=0; i<nArg; i++){
- if( i>0 ) fputs(p->colSeparator, p->out);
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- oputz("NULL");
+ sqlite3_fputs("NULL", p->out);
}else if( aiType && aiType[i]==SQLITE_TEXT ){
- output_quoted_string(azArg[i]);
+ output_quoted_string(p, azArg[i]);
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
- oputz(azArg[i]);
+ sqlite3_fputs(azArg[i], p->out);
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
char z[50];
double r = sqlite3_column_double(p->pStmt, i);
sqlite3_snprintf(50,z,"%!.20g", r);
- oputz(z);
+ sqlite3_fputs(z, p->out);
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
int nBlob = sqlite3_column_bytes(p->pStmt, i);
- output_hex_blob(pBlob, nBlob);
+ output_hex_blob(p->out, pBlob, nBlob);
}else if( isNumber(azArg[i], 0) ){
- oputz(azArg[i]);
+ sqlite3_fputs(azArg[i], p->out);
}else{
- output_quoted_string(azArg[i]);
+ output_quoted_string(p, azArg[i]);
}
}
- fputs(p->rowSeparator, p->out);
+ sqlite3_fputs(p->rowSeparator, p->out);
break;
}
case MODE_Ascii: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- if( i>0 ) oputz(p->colSeparator);
- oputz(azCol[i] ? azCol[i] : "");
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
+ sqlite3_fputs(azCol[i] ? azCol[i] : "", p->out);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- if( i>0 ) oputz(p->colSeparator);
- oputz(azArg[i] ? azArg[i] : p->nullValue);
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
+ sqlite3_fputs(azArg[i] ? azArg[i] : p->nullValue, p->out);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
break;
}
case MODE_EQP: {
@@ -2844,7 +3137,7 @@ static void createSelftestTable(ShellState *p){
"DROP TABLE [_shell$self];"
,0,0,&zErrMsg);
if( zErrMsg ){
- eputf("SELFTEST initialization failure: %s\n", zErrMsg);
+ sqlite3_fprintf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
@@ -2947,7 +3240,7 @@ static int run_table_dump_query(
rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
if( rc!=SQLITE_OK || !pSelect ){
char *zContext = shell_error_context(zSelect, p->db);
- oputf("/**** ERROR: (%d) %s *****/\n%s",
+ sqlite3_fprintf(p->out, "/**** ERROR: (%d) %s *****/\n%s",
rc, sqlite3_errmsg(p->db), zContext);
sqlite3_free(zContext);
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
@@ -2957,22 +3250,23 @@ static int run_table_dump_query(
nResult = sqlite3_column_count(pSelect);
while( rc==SQLITE_ROW ){
z = (const char*)sqlite3_column_text(pSelect, 0);
- oputf("%s", z);
+ sqlite3_fprintf(p->out, "%s", z);
for(i=1; i<nResult; i++){
- oputf(",%s", sqlite3_column_text(pSelect, i));
+ sqlite3_fprintf(p->out, ",%s", sqlite3_column_text(pSelect, i));
}
if( z==0 ) z = "";
while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
if( z[0] ){
- oputz("\n;\n");
+ sqlite3_fputs("\n;\n", p->out);
}else{
- oputz(";\n");
+ sqlite3_fputs(";\n", p->out);
}
rc = sqlite3_step(pSelect);
}
rc = sqlite3_finalize(pSelect);
if( rc!=SQLITE_OK ){
- oputf("/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
+ sqlite3_fprintf(p->out, "/**** ERROR: (%d) %s *****/\n",
+ rc, sqlite3_errmsg(p->db));
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
}
return rc;
@@ -3008,13 +3302,13 @@ static char *save_err_msg(
/*
** Attempt to display I/O stats on Linux using /proc/PID/io
*/
-static void displayLinuxIoStats(void){
+static void displayLinuxIoStats(FILE *out){
FILE *in;
char z[200];
sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
- in = fopen(z, "rb");
+ in = sqlite3_fopen(z, "rb");
if( in==0 ) return;
- while( fgets(z, sizeof(z), in)!=0 ){
+ while( sqlite3_fgets(z, sizeof(z), in)!=0 ){
static const struct {
const char *zPattern;
const char *zDesc;
@@ -3031,7 +3325,7 @@ static void displayLinuxIoStats(void){
for(i=0; i<ArraySize(aTrans); i++){
int n = strlen30(aTrans[i].zPattern);
if( cli_strncmp(aTrans[i].zPattern, z, n)==0 ){
- oputf("%-36s %s", aTrans[i].zDesc, &z[n]);
+ sqlite3_fprintf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
break;
}
}
@@ -3044,6 +3338,7 @@ static void displayLinuxIoStats(void){
** Display a single line of status using 64-bit values.
*/
static void displayStatLine(
+ FILE *out, /* Write to this channel */
char *zLabel, /* Label for this one line */
char *zFormat, /* Format for the result */
int iStatusCtrl, /* Which status to display */
@@ -3062,7 +3357,7 @@ static void displayStatLine(
}else{
sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
}
- oputf("%-36s %s\n", zLabel, zLine);
+ sqlite3_fprintf(out, "%-36s %s\n", zLabel, zLine);
}
/*
@@ -3075,28 +3370,31 @@ static int display_stats(
){
int iCur;
int iHiwtr;
+ FILE *out;
if( pArg==0 || pArg->out==0 ) return 0;
+ out = pArg->out;
if( pArg->pStmt && pArg->statsOn==2 ){
int nCol, i, x;
sqlite3_stmt *pStmt = pArg->pStmt;
char z[100];
nCol = sqlite3_column_count(pStmt);
- oputf("%-36s %d\n", "Number of output columns:", nCol);
+ sqlite3_fprintf(out, "%-36s %d\n", "Number of output columns:", nCol);
for(i=0; i<nCol; i++){
sqlite3_snprintf(sizeof(z),z,"Column %d %nname:", i, &x);
- oputf("%-36s %s\n", z, sqlite3_column_name(pStmt,i));
+ sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_name(pStmt,i));
#ifndef SQLITE_OMIT_DECLTYPE
sqlite3_snprintf(30, z+x, "declared type:");
- oputf("%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
+ sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
#endif
#ifdef SQLITE_ENABLE_COLUMN_METADATA
sqlite3_snprintf(30, z+x, "database name:");
- oputf("%-36s %s\n", z, sqlite3_column_database_name(pStmt,i));
+ sqlite3_fprintf(out, "%-36s %s\n", z,
+ sqlite3_column_database_name(pStmt,i));
sqlite3_snprintf(30, z+x, "table name:");
- oputf("%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
+ sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
sqlite3_snprintf(30, z+x, "origin name:");
- oputf("%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i));
+ sqlite3_fprintf(out, "%-36s %s\n", z,sqlite3_column_origin_name(pStmt,i));
#endif
}
}
@@ -3104,27 +3402,27 @@ static int display_stats(
if( pArg->statsOn==3 ){
if( pArg->pStmt ){
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP,bReset);
- oputf("VM-steps: %d\n", iCur);
+ sqlite3_fprintf(out, "VM-steps: %d\n", iCur);
}
return 0;
}
- displayStatLine("Memory Used:",
+ displayStatLine(out, "Memory Used:",
"%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
- displayStatLine("Number of Outstanding Allocations:",
+ displayStatLine(out, "Number of Outstanding Allocations:",
"%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
if( pArg->shellFlgs & SHFLG_Pagecache ){
- displayStatLine("Number of Pcache Pages Used:",
+ displayStatLine(out, "Number of Pcache Pages Used:",
"%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
}
- displayStatLine("Number of Pcache Overflow Bytes:",
+ displayStatLine(out, "Number of Pcache Overflow Bytes:",
"%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
- displayStatLine("Largest Allocation:",
+ displayStatLine(out, "Largest Allocation:",
"%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
- displayStatLine("Largest Pcache Allocation:",
+ displayStatLine(out, "Largest Pcache Allocation:",
"%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
#ifdef YYTRACKMAXSTACKDEPTH
- displayStatLine("Deepest Parser Stack:",
+ displayStatLine(out, "Deepest Parser Stack:",
"%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
#endif
@@ -3133,68 +3431,87 @@ static int display_stats(
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
&iCur, &iHiwtr, bReset);
- oputf("Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
+ sqlite3_fprintf(out,
+ "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
&iCur, &iHiwtr, bReset);
- oputf("Successful lookaside attempts: %d\n", iHiwtr);
+ sqlite3_fprintf(out,
+ "Successful lookaside attempts: %d\n", iHiwtr);
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
&iCur, &iHiwtr, bReset);
- oputf("Lookaside failures due to size: %d\n", iHiwtr);
+ sqlite3_fprintf(out,
+ "Lookaside failures due to size: %d\n", iHiwtr);
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
&iCur, &iHiwtr, bReset);
- oputf("Lookaside failures due to OOM: %d\n", iHiwtr);
+ sqlite3_fprintf(out,
+ "Lookaside failures due to OOM: %d\n", iHiwtr);
}
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
- oputf("Pager Heap Usage: %d bytes\n", iCur);
+ sqlite3_fprintf(out,
+ "Pager Heap Usage: %d bytes\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
- oputf("Page cache hits: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Page cache hits: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
- oputf("Page cache misses: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Page cache misses: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
- oputf("Page cache writes: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Page cache writes: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1);
- oputf("Page cache spills: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Page cache spills: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
- oputf("Schema Heap Usage: %d bytes\n", iCur);
+ sqlite3_fprintf(out,
+ "Schema Heap Usage: %d bytes\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
- oputf("Statement Heap/Lookaside Usage: %d bytes\n", iCur);
+ sqlite3_fprintf(out,
+ "Statement Heap/Lookaside Usage: %d bytes\n", iCur);
}
if( pArg->pStmt ){
int iHit, iMiss;
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
bReset);
- oputf("Fullscan Steps: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Fullscan Steps: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
- oputf("Sort Operations: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Sort Operations: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
- oputf("Autoindex Inserts: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Autoindex Inserts: %d\n", iCur);
iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT,
bReset);
iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS,
bReset);
if( iHit || iMiss ){
- oputf("Bloom filter bypass taken: %d/%d\n", iHit, iHit+iMiss);
+ sqlite3_fprintf(out,
+ "Bloom filter bypass taken: %d/%d\n", iHit, iHit+iMiss);
}
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
- oputf("Virtual Machine Steps: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Virtual Machine Steps: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
- oputf("Reprepare operations: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Reprepare operations: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
- oputf("Number of times run: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Number of times run: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset);
- oputf("Memory used by prepared stmt: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Memory used by prepared stmt: %d\n", iCur);
}
#ifdef __linux__
- displayLinuxIoStats();
+ displayLinuxIoStats(pArg->out);
#endif
/* Do not remove this machine readable comment: extra-stats-output-here */
@@ -3545,6 +3862,15 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
}else if( sqlite3_strlike("_INF", zVar, 0)==0 ){
sqlite3_bind_double(pStmt, i, INFINITY);
#endif
+ }else if( strncmp(zVar, "$int_", 5)==0 ){
+ sqlite3_bind_int(pStmt, i, atoi(&zVar[5]));
+ }else if( strncmp(zVar, "$text_", 6)==0 ){
+ size_t szVar = strlen(zVar);
+ char *zBuf = sqlite3_malloc64( szVar-5 );
+ if( zBuf ){
+ memcpy(zBuf, &zVar[6], szVar-5);
+ sqlite3_bind_text64(pStmt, i, zBuf, szVar-6, sqlite3_free, SQLITE_UTF8);
+ }
}else{
sqlite3_bind_null(pStmt, i);
}
@@ -3581,17 +3907,17 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
/* Draw horizontal line N characters long using unicode box
** characters
*/
-static void print_box_line(int N){
+static void print_box_line(FILE *out, int N){
const char zDash[] =
BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24
BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24;
const int nDash = sizeof(zDash) - 1;
N *= 3;
while( N>nDash ){
- oputz(zDash);
+ sqlite3_fputs(zDash, out);
N -= nDash;
}
- oputf("%.*s", N, zDash);
+ sqlite3_fprintf(out, "%.*s", N, zDash);
}
/*
@@ -3606,15 +3932,15 @@ static void print_box_row_separator(
){
int i;
if( nArg>0 ){
- oputz(zSep1);
- print_box_line(p->actualWidth[0]+2);
+ sqlite3_fputs(zSep1, p->out);
+ print_box_line(p->out, p->actualWidth[0]+2);
for(i=1; i<nArg; i++){
- oputz(zSep2);
- print_box_line(p->actualWidth[i]+2);
+ sqlite3_fputs(zSep2, p->out);
+ print_box_line(p->out, p->actualWidth[i]+2);
}
- oputz(zSep3);
+ sqlite3_fputs(zSep3, p->out);
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}
/*
@@ -3629,6 +3955,7 @@ static void print_box_row_separator(
** the last line, write a NULL into *pzTail. (*pzTail is not allocated.)
*/
static char *translateForDisplayAndDup(
+ ShellState *p, /* To access current settings */
const unsigned char *z, /* Input text to be transformed */
const unsigned char **pzTail, /* OUT: Tail of the input for next line */
int mxWidth, /* Max width. 0 means no limit */
@@ -3648,12 +3975,23 @@ static char *translateForDisplayAndDup(
if( mxWidth==0 ) mxWidth = 1000000;
i = j = n = 0;
while( n<mxWidth ){
- if( z[i]>=' ' ){
+ unsigned char c = z[i];
+ if( c>=0xc0 ){
+ int u;
+ int len = decodeUtf8(&z[i], &u);
+ i += len;
+ j += len;
+ n += cli_wcwidth(u);
+ continue;
+ }
+ if( c>=' ' ){
n++;
- do{ i++; j++; }while( (z[i]&0xc0)==0x80 );
+ i++;
+ j++;
continue;
}
- if( z[i]=='\t' ){
+ if( c==0 || c=='\n' || (c=='\r' && z[i+1]=='\n') ) break;
+ if( c=='\t' ){
do{
n++;
j++;
@@ -3661,16 +3999,23 @@ static char *translateForDisplayAndDup(
i++;
continue;
}
- break;
+ if( c==0x1b && p->eEscMode==SHELL_ESC_OFF && (k = isVt100(&z[i]))>0 ){
+ i += k;
+ j += k;
+ }else{
+ n++;
+ j += 3;
+ i++;
+ }
}
if( n>=mxWidth && bWordWrap ){
/* Perhaps try to back up to a better place to break the line */
for(k=i; k>i/2; k--){
- if( isspace(z[k-1]) ) break;
+ if( IsSpace(z[k-1]) ) break;
}
if( k<=i/2 ){
for(k=i; k>i/2; k--){
- if( isalnum(z[k-1])!=isalnum(z[k]) && (z[k]&0xc0)!=0x80 ) break;
+ if( IsAlnum(z[k-1])!=IsAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break;
}
}
if( k<=i/2 ){
@@ -3695,11 +4040,20 @@ static char *translateForDisplayAndDup(
shell_check_oom(zOut);
i = j = n = 0;
while( i<k ){
- if( z[i]>=' ' ){
+ unsigned char c = z[i];
+ if( c>=0xc0 ){
+ int u;
+ int len = decodeUtf8(&z[i], &u);
+ do{ zOut[j++] = z[i++]; }while( (--len)>0 );
+ n += cli_wcwidth(u);
+ continue;
+ }
+ if( c>=' ' ){
n++;
- do{ zOut[j++] = z[i++]; }while( (z[i]&0xc0)==0x80 );
+ zOut[j++] = z[i++];
continue;
}
+ if( c==0 ) break;
if( z[i]=='\t' ){
do{
n++;
@@ -3708,12 +4062,44 @@ static char *translateForDisplayAndDup(
i++;
continue;
}
- break;
+ switch( p->eEscMode ){
+ case SHELL_ESC_SYMBOL:
+ zOut[j++] = 0xe2;
+ zOut[j++] = 0x90;
+ zOut[j++] = 0x80 + c;
+ break;
+ case SHELL_ESC_ASCII:
+ zOut[j++] = '^';
+ zOut[j++] = 0x40 + c;
+ break;
+ case SHELL_ESC_OFF: {
+ int nn;
+ if( c==0x1b && (nn = isVt100(&z[i]))>0 ){
+ memcpy(&zOut[j], &z[i], nn);
+ j += nn;
+ i += nn - 1;
+ }else{
+ zOut[j++] = c;
+ }
+ break;
+ }
+ }
+ i++;
}
zOut[j] = 0;
return (char*)zOut;
}
+/* Return true if the text string z[] contains characters that need
+** unistr() escaping.
+*/
+static int needUnistr(const unsigned char *z){
+ unsigned char c;
+ if( z==0 ) return 0;
+ while( (c = *z)>0x1f || c=='\t' || c=='\n' || (c=='\r' && z[1]=='\n') ){ z++; }
+ return c!=0;
+}
+
/* Extract the value of the i-th current column for pStmt as an SQL literal
** value. Memory is obtained from sqlite3_malloc64() and must be freed by
** the caller.
@@ -3728,7 +4114,8 @@ static char *quoted_column(sqlite3_stmt *pStmt, int i){
return sqlite3_mprintf("%s",sqlite3_column_text(pStmt,i));
}
case SQLITE_TEXT: {
- return sqlite3_mprintf("%Q",sqlite3_column_text(pStmt,i));
+ const unsigned char *zText = sqlite3_column_text(pStmt,i);
+ return sqlite3_mprintf(needUnistr(zText)?"%#Q":"%Q",zText);
}
case SQLITE_BLOB: {
int j;
@@ -3820,7 +4207,7 @@ static void exec_prepared_stmt_columnar(
if( wx<0 ) wx = -wx;
uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
if( uz==0 ) uz = (u8*)"";
- azData[i] = translateForDisplayAndDup(uz, &zNotUsed, wx, bw);
+ azData[i] = translateForDisplayAndDup(p, uz, &zNotUsed, wx, bw);
}
do{
int useNextLine = bNextLine;
@@ -3844,6 +4231,7 @@ static void exec_prepared_stmt_columnar(
uz = azNextLine[i];
if( uz==0 ) uz = (u8*)zEmpty;
}else if( p->cmOpts.bQuote ){
+ assert( azQuoted!=0 );
sqlite3_free(azQuoted[i]);
azQuoted[i] = quoted_column(pStmt,i);
uz = (const unsigned char*)azQuoted[i];
@@ -3852,7 +4240,7 @@ static void exec_prepared_stmt_columnar(
if( uz==0 ) uz = (u8*)zShowNull;
}
azData[nRow*nColumn + i]
- = translateForDisplayAndDup(uz, &azNextLine[i], wx, bw);
+ = translateForDisplayAndDup(p, uz, &azNextLine[i], wx, bw);
if( azNextLine[i] ){
bNextLine = 1;
abRowDiv[nRow-1] = 0;
@@ -3877,12 +4265,12 @@ static void exec_prepared_stmt_columnar(
for(i=0; i<nColumn; i++){
w = p->actualWidth[i];
if( p->colWidth[i]<0 ) w = -w;
- utf8_width_print(w, azData[i]);
- fputs(i==nColumn-1?"\n":" ", p->out);
+ utf8_width_print(p->out, w, azData[i]);
+ sqlite3_fputs(i==nColumn-1?"\n":" ", p->out);
}
for(i=0; i<nColumn; i++){
- print_dashes(p->actualWidth[i]);
- fputs(i==nColumn-1?"\n":" ", p->out);
+ print_dashes(p->out, p->actualWidth[i]);
+ sqlite3_fputs(i==nColumn-1?"\n":" ", p->out);
}
}
break;
@@ -3891,12 +4279,13 @@ static void exec_prepared_stmt_columnar(
colSep = " | ";
rowSep = " |\n";
print_row_separator(p, nColumn, "+");
- fputs("| ", p->out);
+ sqlite3_fputs("| ", p->out);
for(i=0; i<nColumn; i++){
w = p->actualWidth[i];
n = strlenChar(azData[i]);
- oputf("%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
- oputz(i==nColumn-1?" |\n":" | ");
+ sqlite3_fprintf(p->out, "%*s%s%*s", (w-n)/2, "",
+ azData[i], (w-n+1)/2, "");
+ sqlite3_fputs(i==nColumn-1?" |\n":" | ", p->out);
}
print_row_separator(p, nColumn, "+");
break;
@@ -3904,12 +4293,13 @@ static void exec_prepared_stmt_columnar(
case MODE_Markdown: {
colSep = " | ";
rowSep = " |\n";
- fputs("| ", p->out);
+ sqlite3_fputs("| ", p->out);
for(i=0; i<nColumn; i++){
w = p->actualWidth[i];
n = strlenChar(azData[i]);
- oputf("%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
- oputz(i==nColumn-1?" |\n":" | ");
+ sqlite3_fprintf(p->out, "%*s%s%*s", (w-n)/2, "",
+ azData[i], (w-n+1)/2, "");
+ sqlite3_fputs(i==nColumn-1?" |\n":" | ", p->out);
}
print_row_separator(p, nColumn, "|");
break;
@@ -3918,11 +4308,11 @@ static void exec_prepared_stmt_columnar(
colSep = " " BOX_13 " ";
rowSep = " " BOX_13 "\n";
print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
- oputz(BOX_13 " ");
+ sqlite3_fputs(BOX_13 " ", p->out);
for(i=0; i<nColumn; i++){
w = p->actualWidth[i];
n = strlenChar(azData[i]);
- oputf("%*s%s%*s%s",
+ sqlite3_fprintf(p->out, "%*s%s%*s%s",
(w-n)/2, "", azData[i], (w-n+1)/2, "",
i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
}
@@ -3932,28 +4322,28 @@ static void exec_prepared_stmt_columnar(
}
for(i=nColumn, j=0; i<nTotal; i++, j++){
if( j==0 && p->cMode!=MODE_Column ){
- oputz(p->cMode==MODE_Box?BOX_13" ":"| ");
+ sqlite3_fputs(p->cMode==MODE_Box?BOX_13" ":"| ", p->out);
}
z = azData[i];
if( z==0 ) z = p->nullValue;
w = p->actualWidth[j];
if( p->colWidth[j]<0 ) w = -w;
- utf8_width_print(w, z);
+ utf8_width_print(p->out, w, z);
if( j==nColumn-1 ){
- oputz(rowSep);
+ sqlite3_fputs(rowSep, p->out);
if( bMultiLineRowExists && abRowDiv[i/nColumn-1] && i+1<nTotal ){
if( p->cMode==MODE_Table ){
print_row_separator(p, nColumn, "+");
}else if( p->cMode==MODE_Box ){
print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
}else if( p->cMode==MODE_Column ){
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}
}
j = -1;
if( seenInterrupt ) goto columnar_end;
}else{
- oputz(colSep);
+ sqlite3_fputs(colSep, p->out);
}
}
if( p->cMode==MODE_Table ){
@@ -3963,7 +4353,7 @@ static void exec_prepared_stmt_columnar(
}
columnar_end:
if( seenInterrupt ){
- oputz("Interrupt\n");
+ sqlite3_fputs("Interrupt\n", p->out);
}
nData = (nRow+1)*nColumn;
for(i=0; i<nData; i++){
@@ -4050,7 +4440,9 @@ static void exec_prepared_stmt(
} while( SQLITE_ROW == rc );
sqlite3_free(pData);
if( pArg->cMode==MODE_Json ){
- fputs("]\n", pArg->out);
+ sqlite3_fputs("]\n", pArg->out);
+ }else if( pArg->cMode==MODE_Www ){
+ sqlite3_fputs("</TABLE>\n<PRE>\n", pArg->out);
}else if( pArg->cMode==MODE_Count ){
char zBuf[200];
sqlite3_snprintf(sizeof(zBuf), zBuf, "%llu row%s\n",
@@ -4099,6 +4491,7 @@ static int expertFinish(
){
int rc = SQLITE_OK;
sqlite3expert *p = pState->expert.pExpert;
+ FILE *out = pState->out;
assert( p );
assert( bCancel || pzErr==0 || *pzErr==0 );
if( bCancel==0 ){
@@ -4111,8 +4504,8 @@ static int expertFinish(
if( bVerbose ){
const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
- oputz("-- Candidates -----------------------------\n");
- oputf("%s\n", zCand);
+ sqlite3_fputs("-- Candidates -----------------------------\n", out);
+ sqlite3_fprintf(out, "%s\n", zCand);
}
for(i=0; i<nQuery; i++){
const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
@@ -4120,11 +4513,12 @@ static int expertFinish(
const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
if( zIdx==0 ) zIdx = "(no new indexes)\n";
if( bVerbose ){
- oputf("-- Query %d --------------------------------\n",i+1);
- oputf("%s\n\n", zSql);
+ sqlite3_fprintf(out,
+ "-- Query %d --------------------------------\n"
+ "%s\n\n"
+ ,i+1, zSql);
}
- oputf("%s\n", zIdx);
- oputf("%s\n", zEQP);
+ sqlite3_fprintf(out, "%s\n%s\n", zIdx, zEQP);
}
}
}
@@ -4159,18 +4553,18 @@ static int expertDotCommand(
}
else if( n>=2 && 0==cli_strncmp(z, "-sample", n) ){
if( i==(nArg-1) ){
- eputf("option requires an argument: %s\n", z);
+ sqlite3_fprintf(stderr, "option requires an argument: %s\n", z);
rc = SQLITE_ERROR;
}else{
iSample = (int)integerValue(azArg[++i]);
if( iSample<0 || iSample>100 ){
- eputf("value out of range: %s\n", azArg[i]);
+ sqlite3_fprintf(stderr,"value out of range: %s\n", azArg[i]);
rc = SQLITE_ERROR;
}
}
}
else{
- eputf("unknown option: %s\n", z);
+ sqlite3_fprintf(stderr,"unknown option: %s\n", z);
rc = SQLITE_ERROR;
}
}
@@ -4178,7 +4572,8 @@ static int expertDotCommand(
if( rc==SQLITE_OK ){
pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
if( pState->expert.pExpert==0 ){
- eputf("sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory");
+ sqlite3_fprintf(stderr,
+ "sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory");
rc = SQLITE_ERROR;
}else{
sqlite3_expert_config(
@@ -4507,9 +4902,9 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
- if( !dataOnly ) oputz("DELETE FROM sqlite_sequence;\n");
+ /* no-op */
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
- if( !dataOnly ) oputz("ANALYZE sqlite_schema;\n");
+ if( !dataOnly ) sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
}else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( dataOnly ){
@@ -4517,7 +4912,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
}else if( cli_strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
char *zIns;
if( !p->writableSchema ){
- oputz("PRAGMA writable_schema=ON;\n");
+ sqlite3_fputs("PRAGMA writable_schema=ON;\n", p->out);
p->writableSchema = 1;
}
zIns = sqlite3_mprintf(
@@ -4525,11 +4920,11 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
"VALUES('table','%q','%q',0,'%q');",
zTable, zTable, zSql);
shell_check_oom(zIns);
- oputf("%s\n", zIns);
+ sqlite3_fprintf(p->out, "%s\n", zIns);
sqlite3_free(zIns);
return 0;
}else{
- printSchemaLine(zSql, ";\n");
+ printSchemaLine(p->out, zSql, ";\n");
}
if( cli_strcmp(zType, "table")==0 ){
@@ -4587,7 +4982,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
p->mode = p->cMode = MODE_Insert;
rc = shell_exec(p, sSelect.z, 0);
if( (rc&0xff)==SQLITE_CORRUPT ){
- oputz("/****** CORRUPTION ERROR *******/\n");
+ sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out);
toggleSelectOrder(p->db);
shell_exec(p, sSelect.z, 0);
toggleSelectOrder(p->db);
@@ -4618,9 +5013,9 @@ static int run_schema_dump_query(
if( rc==SQLITE_CORRUPT ){
char *zQ2;
int len = strlen30(zQuery);
- oputz("/****** CORRUPTION ERROR *******/\n");
+ sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out);
if( zErr ){
- oputf("/****** %s ******/\n", zErr);
+ sqlite3_fprintf(p->out, "/****** %s ******/\n", zErr);
sqlite3_free(zErr);
zErr = 0;
}
@@ -4629,13 +5024,13 @@ static int run_schema_dump_query(
sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
if( rc ){
- oputf("/****** ERROR: %s ******/\n", zErr);
+ sqlite3_fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
}else{
rc = SQLITE_CORRUPT;
}
- sqlite3_free(zErr);
free(zQ2);
}
+ sqlite3_free(zErr);
return rc;
}
@@ -4692,14 +5087,13 @@ static const char *(azHelp[]) = {
".clone NEWDB Clone data into NEWDB from the existing database",
#endif
".connection [close] [#] Open or close an auxiliary database connection",
-#if defined(_WIN32) || defined(WIN32)
- ".crnl on|off Translate \\n to \\r\\n. Default ON",
-#endif
+ ".crlf ?on|off? Whether or not to use \\r\\n line endings",
".databases List names and files of attached databases",
".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
#if SQLITE_SHELL_HAVE_RECOVER
".dbinfo ?DB? Show status information about the database",
#endif
+ ".dbtotxt Hex dump of the database file",
".dump ?OBJECTS? Render database content as SQL",
" Options:",
" --data-only Output only INSERT statements",
@@ -4769,7 +5163,7 @@ static const char *(azHelp[]) = {
#else
".log on|off Turn logging on or off.",
#endif
- ".mode MODE ?OPTIONS? Set output mode",
+ ".mode ?MODE? ?OPTIONS? Set output mode",
" MODE is one of:",
" ascii Columns/rows delimited by 0x1F and 0x1E",
" box Tables using unicode box-drawing characters",
@@ -4787,6 +5181,7 @@ static const char *(azHelp[]) = {
" tabs Tab-separated values",
" tcl TCL list elements",
" OPTIONS: (for columnar modes or insert mode):",
+ " --escape T ctrl-char escape; T is one of: symbol, ascii, off",
" --wrap N Wrap output lines to no longer than N characters",
" --wordwrap B Wrap or not at word boundaries per B (on/off)",
" --ww Shorthand for \"--wordwrap 1\"",
@@ -4800,9 +5195,11 @@ static const char *(azHelp[]) = {
#ifndef SQLITE_SHELL_FIDDLE
".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
" If FILE begins with '|' then open as a pipe",
- " --bom Put a UTF8 byte-order mark at the beginning",
- " -e Send output to the system text editor",
- " -x Send output as CSV to a spreadsheet (same as \".excel\")",
+ " --bom Put a UTF8 byte-order mark at the beginning",
+ " -e Send output to the system text editor",
+ " --plain Use text/plain output instead of HTML for -w option",
+ " -w Send output as HTML to a web browser (same as \".www\")",
+ " -x Send output as CSV to a spreadsheet (same as \".excel\")",
/* Note that .open is (partially) available in WASM builds but is
** currently only intended to be used by the fiddle tool, not
** end users, so is "undocumented." */
@@ -4822,9 +5219,12 @@ static const char *(azHelp[]) = {
#ifndef SQLITE_SHELL_FIDDLE
".output ?FILE? Send output to FILE or stdout if FILE is omitted",
" If FILE begins with '|' then open it as a pipe.",
+ " If FILE is 'off' then output is disabled.",
" Options:",
" --bom Prefix output with a UTF8 byte-order mark",
" -e Send output to the system text editor",
+ " --plain Use text/plain for -w option",
+ " -w Send output to a web browser",
" -x Send output as CSV to a spreadsheet",
#endif
".parameter CMD ... Manage SQL parameter bindings",
@@ -4938,106 +5338,111 @@ static const char *(azHelp[]) = {
".vfsname ?AUX? Print the name of the VFS stack",
".width NUM1 NUM2 ... Set minimum column widths for columnar output",
" Negative values right-justify",
+#ifndef SQLITE_SHELL_FIDDLE
+ ".www Display output of the next command in web browser",
+ " --plain Show results as text/plain, not as HTML",
+#endif
};
/*
-** Output help text.
+** Output help text for commands that match zPattern.
+**
+** * If zPattern is NULL, then show all documented commands, but
+** only give a one-line summary of each.
+**
+** * If zPattern is "-a" or "-all" or "--all" then show all help text
+** for all commands except undocumented commands.
**
-** zPattern describes the set of commands for which help text is provided.
-** If zPattern is NULL, then show all commands, but only give a one-line
-** description of each.
+** * If zPattern is "0" then show all help for undocumented commands.
+** Undocumented commands begin with "," instead of "." in the azHelp[]
+** array.
**
-** Return the number of matches.
+** * If zPattern is a prefix for one or more documented commands, then
+** show help for those commands. If only a single command matches the
+** prefix, show the full text of the help. If multiple commands match,
+** Only show just the first line of each.
+**
+** * Otherwise, show the complete text of any documented command for which
+** zPattern is a LIKE match for any text within that command help
+** text.
+**
+** Return the number commands that match zPattern.
*/
static int showHelp(FILE *out, const char *zPattern){
int i = 0;
int j = 0;
int n = 0;
char *zPat;
- if( zPattern==0
- || zPattern[0]=='0'
- || cli_strcmp(zPattern,"-a")==0
- || cli_strcmp(zPattern,"-all")==0
- || cli_strcmp(zPattern,"--all")==0
+ if( zPattern==0 ){
+ /* Show just the first line for all help topics */
+ zPattern = "[a-z]";
+ }else if( cli_strcmp(zPattern,"-a")==0
+ || cli_strcmp(zPattern,"-all")==0
+ || cli_strcmp(zPattern,"--all")==0
){
- enum HelpWanted { HW_NoCull = 0, HW_SummaryOnly = 1, HW_Undoc = 2 };
- enum HelpHave { HH_Undoc = 2, HH_Summary = 1, HH_More = 0 };
- /* Show all or most commands
- ** *zPattern==0 => summary of documented commands only
- ** *zPattern=='0' => whole help for undocumented commands
- ** Otherwise => whole help for documented commands
- */
- enum HelpWanted hw = HW_SummaryOnly;
- enum HelpHave hh = HH_More;
- if( zPattern!=0 ){
- hw = (*zPattern=='0')? HW_NoCull|HW_Undoc : HW_NoCull;
- }
- for(i=0; i<ArraySize(azHelp); i++){
- switch( azHelp[i][0] ){
- case ',':
- hh = HH_Summary|HH_Undoc;
- break;
- case '.':
- hh = HH_Summary;
- break;
- default:
- hh &= ~HH_Summary;
- break;
- }
- if( ((hw^hh)&HH_Undoc)==0 ){
- if( (hh&HH_Summary)!=0 ){
- sputf(out, ".%s\n", azHelp[i]+1);
- ++n;
- }else if( (hw&HW_SummaryOnly)==0 ){
- sputf(out, "%s\n", azHelp[i]);
- }
- }
- }
- }else{
- /* Seek documented commands for which zPattern is an exact prefix */
- zPat = sqlite3_mprintf(".%s*", zPattern);
- shell_check_oom(zPat);
+ /* Show everything except undocumented commands */
+ zPattern = ".";
+ }else if( cli_strcmp(zPattern,"0")==0 ){
+ /* Show complete help text of undocumented commands */
+ int show = 0;
for(i=0; i<ArraySize(azHelp); i++){
- if( sqlite3_strglob(zPat, azHelp[i])==0 ){
- sputf(out, "%s\n", azHelp[i]);
- j = i+1;
+ if( azHelp[i][0]=='.' ){
+ show = 0;
+ }else if( azHelp[i][0]==',' ){
+ show = 1;
+ sqlite3_fprintf(out, ".%s\n", &azHelp[i][1]);
n++;
+ }else if( show ){
+ sqlite3_fprintf(out, "%s\n", azHelp[i]);
}
}
- sqlite3_free(zPat);
- if( n ){
- if( n==1 ){
- /* when zPattern is a prefix of exactly one command, then include
- ** the details of that command, which should begin at offset j */
- while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){
- sputf(out, "%s\n", azHelp[j]);
- j++;
- }
- }
- return n;
+ return n;
+ }
+
+ /* Seek documented commands for which zPattern is an exact prefix */
+ zPat = sqlite3_mprintf(".%s*", zPattern);
+ shell_check_oom(zPat);
+ for(i=0; i<ArraySize(azHelp); i++){
+ if( sqlite3_strglob(zPat, azHelp[i])==0 ){
+ sqlite3_fprintf(out, "%s\n", azHelp[i]);
+ j = i+1;
+ n++;
}
- /* Look for documented commands that contain zPattern anywhere.
- ** Show complete text of all documented commands that match. */
- zPat = sqlite3_mprintf("%%%s%%", zPattern);
- shell_check_oom(zPat);
- for(i=0; i<ArraySize(azHelp); i++){
- if( azHelp[i][0]==',' ){
- while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i;
- continue;
+ }
+ sqlite3_free(zPat);
+ if( n ){
+ if( n==1 ){
+ /* when zPattern is a prefix of exactly one command, then include
+ ** the details of that command, which should begin at offset j */
+ while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){
+ sqlite3_fprintf(out, "%s\n", azHelp[j]);
+ j++;
}
- if( azHelp[i][0]=='.' ) j = i;
- if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
- sputf(out, "%s\n", azHelp[j]);
- while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){
- j++;
- sputf(out, "%s\n", azHelp[j]);
- }
- i = j;
- n++;
+ }
+ return n;
+ }
+
+ /* Look for documented commands that contain zPattern anywhere.
+ ** Show complete text of all documented commands that match. */
+ zPat = sqlite3_mprintf("%%%s%%", zPattern);
+ shell_check_oom(zPat);
+ for(i=0; i<ArraySize(azHelp); i++){
+ if( azHelp[i][0]==',' ){
+ while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i;
+ continue;
+ }
+ if( azHelp[i][0]=='.' ) j = i;
+ if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
+ sqlite3_fprintf(out, "%s\n", azHelp[j]);
+ while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){
+ j++;
+ sqlite3_fprintf(out, "%s\n", azHelp[j]);
}
+ i = j;
+ n++;
}
- sqlite3_free(zPat);
}
+ sqlite3_free(zPat);
return n;
}
@@ -5060,7 +5465,7 @@ static int process_input(ShellState *p);
** is undefined in this case.
*/
static char *readFile(const char *zName, int *pnByte){
- FILE *in = fopen(zName, "rb");
+ FILE *in = sqlite3_fopen(zName, "rb");
long nIn;
size_t nRead;
char *pBuf;
@@ -5068,7 +5473,7 @@ static char *readFile(const char *zName, int *pnByte){
if( in==0 ) return 0;
rc = fseek(in, 0, SEEK_END);
if( rc!=0 ){
- eputf("Error: '%s' not seekable\n", zName);
+ sqlite3_fprintf(stderr,"Error: '%s' not seekable\n", zName);
fclose(in);
return 0;
}
@@ -5076,7 +5481,7 @@ static char *readFile(const char *zName, int *pnByte){
rewind(in);
pBuf = sqlite3_malloc64( nIn+1 );
if( pBuf==0 ){
- eputz("Error: out of memory\n");
+ sqlite3_fputs("Error: out of memory\n", stderr);
fclose(in);
return 0;
}
@@ -5084,7 +5489,7 @@ static char *readFile(const char *zName, int *pnByte){
fclose(in);
if( nRead!=1 ){
sqlite3_free(pBuf);
- eputf("Error: cannot read '%s'\n", zName);
+ sqlite3_fprintf(stderr,"Error: cannot read '%s'\n", zName);
return 0;
}
pBuf[nIn] = 0;
@@ -5150,7 +5555,7 @@ static int session_filter(void *pCtx, const char *zTab){
** the type cannot be determined from content.
*/
int deduceDatabaseType(const char *zName, int dfltZip){
- FILE *f = fopen(zName, "rb");
+ FILE *f = sqlite3_fopen(zName, "rb");
size_t n;
int rc = SHELL_OPEN_UNSPEC;
char zBuf[100];
@@ -5203,9 +5608,9 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
unsigned int x[16];
char zLine[1000];
if( zDbFilename ){
- in = fopen(zDbFilename, "r");
+ in = sqlite3_fopen(zDbFilename, "r");
if( in==0 ){
- eputf("cannot open \"%s\" for reading\n", zDbFilename);
+ sqlite3_fprintf(stderr,"cannot open \"%s\" for reading\n", zDbFilename);
return 0;
}
nLine = 0;
@@ -5216,7 +5621,7 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
}
*pnData = 0;
nLine++;
- if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
+ if( sqlite3_fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
if( rc!=2 ) goto readHexDb_error;
if( n<0 ) goto readHexDb_error;
@@ -5226,10 +5631,10 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
shell_check_oom(a);
memset(a, 0, n);
if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
- eputz("invalid pagesize\n");
+ sqlite3_fputs("invalid pagesize\n", stderr);
goto readHexDb_error;
}
- for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
+ for(nLine++; sqlite3_fgets(zLine, sizeof(zLine), in)!=0; nLine++){
rc = sscanf(zLine, "| page %d offset %d", &j, &k);
if( rc==2 ){
iOffset = k;
@@ -5261,14 +5666,14 @@ readHexDb_error:
if( in!=p->in ){
fclose(in);
}else{
- while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
+ while( sqlite3_fgets(zLine, sizeof(zLine), p->in)!=0 ){
nLine++;
if(cli_strncmp(zLine, "| end ", 6)==0 ) break;
}
p->lineno = nLine;
}
sqlite3_free(a);
- eputf("Error on line %d of --hexdb input\n", nLine);
+ sqlite3_fprintf(stderr,"Error on line %d of --hexdb input\n", nLine);
return 0;
}
#endif /* SQLITE_OMIT_DESERIALIZE */
@@ -5287,6 +5692,39 @@ static void shellUSleepFunc(
sqlite3_result_int(context, sleep);
}
+/*
+** SQL function: shell_module_schema(X)
+**
+** Return a fake schema for the table-valued function or eponymous virtual
+** table X.
+*/
+static void shellModuleSchema(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ const char *zName;
+ char *zFake;
+ ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
+ FILE *pSavedLog = p->pLog;
+ UNUSED_PARAMETER(nVal);
+ zName = (const char*)sqlite3_value_text(apVal[0]);
+
+ /* Temporarily disable the ".log" when calling shellFakeSchema() because
+ ** shellFakeSchema() might generate failures for some ephemeral virtual
+ ** tables due to missing arguments. Example: fts4aux.
+ ** https://sqlite.org/forum/forumpost/42fe6520b803be51 */
+ p->pLog = 0;
+ zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0;
+ p->pLog = pSavedLog;
+
+ if( zFake ){
+ sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
+ -1, sqlite3_free);
+ free(zFake);
+ }
+}
+
/* Flags for open_db().
**
** The default behavior of open_db() is to exit(1) if the database fails to
@@ -5343,7 +5781,7 @@ static void open_db(ShellState *p, int openFlags){
}
}
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
- eputf("Error: unable to open database \"%s\": %s\n",
+ sqlite3_fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
zDbFilename, sqlite3_errmsg(p->db));
if( (openFlags & OPEN_DB_KEEPALIVE)==0 ){
exit(1);
@@ -5351,10 +5789,12 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_close(p->db);
sqlite3_open(":memory:", &p->db);
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
- eputz("Also: unable to open substitute in-memory database.\n");
+ sqlite3_fputs("Also: unable to open substitute in-memory database.\n",
+ stderr);
exit(1);
}else{
- eputf("Notice: using substitute in-memory database instead of \"%s\"\n",
+ sqlite3_fprintf(stderr,
+ "Notice: using substitute in-memory database instead of \"%s\"\n",
zDbFilename);
}
}
@@ -5371,6 +5811,7 @@ static void open_db(ShellState *p, int openFlags){
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
+ sqlite3_sha_init(p->db, 0, 0);
sqlite3_shathree_init(p->db, 0, 0);
sqlite3_uint_init(p->db, 0, 0);
sqlite3_stmtrand_init(p->db, 0, 0);
@@ -5427,7 +5868,7 @@ static void open_db(ShellState *p, int openFlags){
shellDtostr, 0, 0);
sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
shellAddSchemaName, 0, 0);
- sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
+ sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, p,
shellModuleSchema, 0, 0);
sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
shellPutsFunc, 0, 0);
@@ -5465,7 +5906,7 @@ static void open_db(ShellState *p, int openFlags){
SQLITE_DESERIALIZE_RESIZEABLE |
SQLITE_DESERIALIZE_FREEONCLOSE);
if( rc ){
- eputf("Error: sqlite3_deserialize() returns %d\n", rc);
+ sqlite3_fprintf(stderr,"Error: sqlite3_deserialize() returns %d\n", rc);
}
if( p->szMax>0 ){
sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
@@ -5489,11 +5930,13 @@ static void open_db(ShellState *p, int openFlags){
void close_db(sqlite3 *db){
int rc = sqlite3_close(db);
if( rc ){
- eputf("Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,
+ "Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db));
}
}
-#if HAVE_READLINE || HAVE_EDITLINE
+#if (HAVE_READLINE || HAVE_EDITLINE) \
+ && !defined(SQLITE_OMIT_READLINE_COMPLETION)
/*
** Readline completion callbacks
*/
@@ -5531,18 +5974,25 @@ static char **readline_completion(const char *zText, int iStart, int iEnd){
** Linenoise completion callback. Note that the 3rd argument is from
** the "msteveb" version of linenoise, not the "antirez" version.
*/
-static void linenoise_completion(const char *zLine, linenoiseCompletions *lc,
- void *pUserData){
+static void linenoise_completion(
+ const char *zLine,
+ linenoiseCompletions *lc
+#if HAVE_LINENOISE==2
+ ,void *pUserData
+#endif
+){
i64 nLine = strlen(zLine);
i64 i, iStart;
sqlite3_stmt *pStmt = 0;
char *zSql;
char zBuf[1000];
+#if HAVE_LINENOISE==2
UNUSED_PARAMETER(pUserData);
+#endif
if( nLine>(i64)sizeof(zBuf)-30 ) return;
if( zLine[0]=='.' || zLine[0]=='#') return;
- for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
+ for(i=nLine-1; i>=0 && (IsAlnum(zLine[i]) || zLine[i]=='_'); i--){}
if( i==nLine-1 ) return;
iStart = i+1;
memcpy(zBuf, zLine, iStart);
@@ -5653,7 +6103,8 @@ static int booleanValue(const char *zArg){
if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
return 0;
}
- eputf("ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg);
+ sqlite3_fprintf(stderr,
+ "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg);
return 0;
}
@@ -5680,7 +6131,7 @@ static void output_file_close(FILE *f){
** recognized and do the right thing. NULL is returned if the output
** filename is "off".
*/
-static FILE *output_file_open(const char *zFile, int bTextMode){
+static FILE *output_file_open(const char *zFile){
FILE *f;
if( cli_strcmp(zFile,"stdout")==0 ){
f = stdout;
@@ -5689,9 +6140,9 @@ static FILE *output_file_open(const char *zFile, int bTextMode){
}else if( cli_strcmp(zFile, "off")==0 ){
f = 0;
}else{
- f = fopen(zFile, bTextMode ? "w" : "wb");
+ f = sqlite3_fopen(zFile, "w");
if( f==0 ){
- eputf("Error: cannot open \"%s\"\n", zFile);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zFile);
}
}
return f;
@@ -5744,12 +6195,13 @@ static int sql_trace_callback(
switch( mType ){
case SQLITE_TRACE_ROW:
case SQLITE_TRACE_STMT: {
- sputf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
+ sqlite3_fprintf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
break;
}
case SQLITE_TRACE_PROFILE: {
sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0;
- sputf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
+ sqlite3_fprintf(p->traceOut,
+ "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
break;
}
}
@@ -5856,10 +6308,11 @@ static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
break;
}
if( pc==cQuote && c!='\r' ){
- eputf("%s:%d: unescaped %c character\n", p->zFile, p->nLine, cQuote);
+ sqlite3_fprintf(stderr,"%s:%d: unescaped %c character\n",
+ p->zFile, p->nLine, cQuote);
}
if( c==EOF ){
- eputf("%s:%d: unterminated %c-quoted field\n",
+ sqlite3_fprintf(stderr,"%s:%d: unterminated %c-quoted field\n",
p->zFile, startLine, cQuote);
p->cTerm = c;
break;
@@ -5958,7 +6411,7 @@ static void tryToCloneData(
shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
- eputf("Error %d: %s on [%s]\n",
+ sqlite3_fprintf(stderr,"Error %d: %s on [%s]\n",
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery);
goto end_data_xfer;
}
@@ -5975,7 +6428,7 @@ static void tryToCloneData(
memcpy(zInsert+i, ");", 3);
rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
if( rc ){
- eputf("Error %d: %s on [%s]\n",
+ sqlite3_fprintf(stderr,"Error %d: %s on [%s]\n",
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb), zInsert);
goto end_data_xfer;
}
@@ -6011,7 +6464,7 @@ static void tryToCloneData(
} /* End for */
rc = sqlite3_step(pInsert);
if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
- eputf("Error %d: %s\n",
+ sqlite3_fprintf(stderr,"Error %d: %s\n",
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb));
}
sqlite3_reset(pInsert);
@@ -6029,7 +6482,7 @@ static void tryToCloneData(
shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
- eputf("Warning: cannot step \"%s\" backwards", zTable);
+ sqlite3_fprintf(stderr,"Warning: cannot step \"%s\" backwards", zTable);
break;
}
} /* End for(k=0...) */
@@ -6066,7 +6519,8 @@ static void tryToCloneSchema(
shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
- eputf("Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db),
+ sqlite3_fprintf(stderr,
+ "Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db),
sqlite3_errmsg(p->db), zQuery);
goto end_schema_xfer;
}
@@ -6075,10 +6529,10 @@ static void tryToCloneSchema(
zSql = sqlite3_column_text(pQuery, 1);
if( zName==0 || zSql==0 ) continue;
if( sqlite3_stricmp((char*)zName, "sqlite_sequence")!=0 ){
- sputf(stdout, "%s... ", zName); fflush(stdout);
+ sqlite3_fprintf(stdout, "%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
- eputf("Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
+ sqlite3_fprintf(stderr,"Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}
@@ -6096,7 +6550,7 @@ static void tryToCloneSchema(
shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
- eputf("Error: (%d) %s on [%s]\n",
+ sqlite3_fprintf(stderr,"Error: (%d) %s on [%s]\n",
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery);
goto end_schema_xfer;
}
@@ -6105,10 +6559,10 @@ static void tryToCloneSchema(
zSql = sqlite3_column_text(pQuery, 1);
if( zName==0 || zSql==0 ) continue;
if( sqlite3_stricmp((char*)zName, "sqlite_sequence")==0 ) continue;
- sputf(stdout, "%s... ", zName); fflush(stdout);
+ sqlite3_fprintf(stdout, "%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
- eputf("Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
+ sqlite3_fprintf(stderr,"Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}
@@ -6132,12 +6586,13 @@ static void tryToClone(ShellState *p, const char *zNewDb){
int rc;
sqlite3 *newDb = 0;
if( access(zNewDb,0)==0 ){
- eputf("File \"%s\" already exists.\n", zNewDb);
+ sqlite3_fprintf(stderr,"File \"%s\" already exists.\n", zNewDb);
return;
}
rc = sqlite3_open(zNewDb, &newDb);
if( rc ){
- eputf("Cannot create output database: %s\n", sqlite3_errmsg(newDb));
+ sqlite3_fprintf(stderr,
+ "Cannot create output database: %s\n", sqlite3_errmsg(newDb));
}else{
sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
@@ -6154,10 +6609,18 @@ static void tryToClone(ShellState *p, const char *zNewDb){
** Change the output stream (file or pipe or console) to something else.
*/
static void output_redir(ShellState *p, FILE *pfNew){
- if( p->out != stdout ) eputz("Output already redirected.\n");
- else{
+ if( p->out != stdout ){
+ sqlite3_fputs("Output already redirected.\n", stderr);
+ }else{
p->out = pfNew;
- setOutputStream(pfNew);
+ setCrlfMode(p);
+ if( p->mode==MODE_Www ){
+ sqlite3_fputs(
+ "<!DOCTYPE html>\n"
+ "<HTML><BODY><PRE>\n",
+ p->out
+ );
+ }
}
}
@@ -6174,6 +6637,9 @@ static void output_reset(ShellState *p){
pclose(p->out);
#endif
}else{
+ if( p->mode==MODE_Www ){
+ sqlite3_fputs("</PRE></BODY></HTML>\n", p->out);
+ }
output_file_close(p->out);
#ifndef SQLITE_NOHAVE_SYSTEM
if( p->doXdgOpen ){
@@ -6188,7 +6654,7 @@ static void output_reset(ShellState *p){
char *zCmd;
zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
if( system(zCmd) ){
- eputf("Failed: [%s]\n", zCmd);
+ sqlite3_fprintf(stderr,"Failed: [%s]\n", zCmd);
}else{
/* Give the start/open/xdg-open command some time to get
** going before we continue, and potential delete the
@@ -6203,7 +6669,7 @@ static void output_reset(ShellState *p){
}
p->outfile[0] = 0;
p->out = stdout;
- setOutputStream(stdout);
+ setCrlfMode(p);
}
#else
# define output_redir(SS,pfO)
@@ -6213,14 +6679,20 @@ static void output_reset(ShellState *p){
/*
** Run an SQL command and return the single integer result.
*/
-static int db_int(sqlite3 *db, const char *zSql){
+static int db_int(sqlite3 *db, const char *zSql, ...){
sqlite3_stmt *pStmt;
int res = 0;
- sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ char *z;
+ va_list ap;
+ va_start(ap, zSql);
+ z = sqlite3_vmprintf(zSql, ap);
+ va_end(ap);
+ sqlite3_prepare_v2(db, z, -1, &pStmt, 0);
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
res = sqlite3_column_int(pStmt,0);
}
sqlite3_finalize(pStmt);
+ sqlite3_free(z);
return res;
}
@@ -6279,7 +6751,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
-1, &pStmt, 0);
if( rc ){
- eputf("error: %s\n", sqlite3_errmsg(p->db));
+ sqlite3_fprintf(stderr,"error: %s\n", sqlite3_errmsg(p->db));
sqlite3_finalize(pStmt);
return 1;
}
@@ -6292,28 +6764,28 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
memcpy(aHdr, pb, 100);
sqlite3_finalize(pStmt);
}else{
- eputz("unable to read database header\n");
+ sqlite3_fputs("unable to read database header\n", stderr);
sqlite3_finalize(pStmt);
return 1;
}
i = get2byteInt(aHdr+16);
if( i==1 ) i = 65536;
- oputf("%-20s %d\n", "database page size:", i);
- oputf("%-20s %d\n", "write format:", aHdr[18]);
- oputf("%-20s %d\n", "read format:", aHdr[19]);
- oputf("%-20s %d\n", "reserved bytes:", aHdr[20]);
+ sqlite3_fprintf(p->out, "%-20s %d\n", "database page size:", i);
+ sqlite3_fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
+ sqlite3_fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
+ sqlite3_fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
for(i=0; i<ArraySize(aField); i++){
int ofst = aField[i].ofst;
unsigned int val = get4byteInt(aHdr + ofst);
- oputf("%-20s %u", aField[i].zName, val);
+ sqlite3_fprintf(p->out, "%-20s %u", aField[i].zName, val);
switch( ofst ){
case 56: {
- if( val==1 ) oputz(" (utf8)");
- if( val==2 ) oputz(" (utf16le)");
- if( val==3 ) oputz(" (utf16be)");
+ if( val==1 ) sqlite3_fputs(" (utf8)", p->out);
+ if( val==2 ) sqlite3_fputs(" (utf16le)", p->out);
+ if( val==3 ) sqlite3_fputs(" (utf16be)", p->out);
}
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}
if( zDb==0 ){
zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
@@ -6323,24 +6795,120 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
}
for(i=0; i<ArraySize(aQuery); i++){
- char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
- int val = db_int(p->db, zSql);
- sqlite3_free(zSql);
- oputf("%-20s %d\n", aQuery[i].zName, val);
+ int val = db_int(p->db, aQuery[i].zSql, zSchemaTab);
+ sqlite3_fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
}
sqlite3_free(zSchemaTab);
sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
- oputf("%-20s %u\n", "data version", iDataVersion);
+ sqlite3_fprintf(p->out, "%-20s %u\n", "data version", iDataVersion);
return 0;
}
#endif /* SQLITE_SHELL_HAVE_RECOVER */
/*
+** Implementation of the ".dbtotxt" command.
+**
+** Return 1 on error, 2 to exit, and 0 otherwise.
+*/
+static int shell_dbtotxt_command(ShellState *p, int nArg, char **azArg){
+ sqlite3_stmt *pStmt = 0;
+ sqlite3_int64 nPage = 0;
+ int pgSz = 0;
+ const char *zTail;
+ char *zName = 0;
+ int rc, i, j;
+ unsigned char bShow[256]; /* Characters ok to display */
+
+ UNUSED_PARAMETER(nArg);
+ UNUSED_PARAMETER(azArg);
+ memset(bShow, '.', sizeof(bShow));
+ for(i=' '; i<='~'; i++){
+ if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = (unsigned char)i;
+ }
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA page_size", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ rc = 0;
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
+ pgSz = sqlite3_column_int(pStmt, 0);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ if( pgSz<512 || pgSz>65536 || (pgSz&(pgSz-1))!=0 ) goto dbtotxt_error;
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA page_count", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ rc = 0;
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
+ nPage = sqlite3_column_int64(pStmt, 0);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ if( nPage<1 ) goto dbtotxt_error;
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA databases", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ){
+ zTail = "unk.db";
+ }else{
+ const char *zFilename = (const char*)sqlite3_column_text(pStmt, 2);
+ if( zFilename==0 || zFilename[0]==0 ) zFilename = "unk.db";
+ zTail = strrchr(zFilename, '/');
+#if defined(_WIN32)
+ if( zTail==0 ) zTail = strrchr(zFilename, '\\');
+#endif
+ }
+ zName = strdup(zTail);
+ shell_check_oom(zName);
+ sqlite3_fprintf(p->out, "| size %lld pagesize %d filename %s\n",
+ nPage*pgSz, pgSz, zName);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ rc = sqlite3_prepare_v2(p->db,
+ "SELECT pgno, data FROM sqlite_dbpage ORDER BY pgno", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ sqlite3_int64 pgno = sqlite3_column_int64(pStmt, 0);
+ const u8 *aData = sqlite3_column_blob(pStmt, 1);
+ int seenPageLabel = 0;
+ for(i=0; i<pgSz; i+=16){
+ const u8 *aLine = aData+i;
+ for(j=0; j<16 && aLine[j]==0; j++){}
+ if( j==16 ) continue;
+ if( !seenPageLabel ){
+ sqlite3_fprintf(p->out, "| page %lld offset %lld\n",pgno,(pgno-1)*pgSz);
+ seenPageLabel = 1;
+ }
+ sqlite3_fprintf(p->out, "| %5d:", i);
+ for(j=0; j<16; j++) sqlite3_fprintf(p->out, " %02x", aLine[j]);
+ sqlite3_fprintf(p->out, " ");
+ for(j=0; j<16; j++){
+ unsigned char c = (unsigned char)aLine[j];
+ sqlite3_fprintf(p->out, "%c", bShow[c]);
+ }
+ sqlite3_fprintf(p->out, "\n");
+ }
+ }
+ sqlite3_finalize(pStmt);
+ sqlite3_fprintf(p->out, "| end %s\n", zName);
+ free(zName);
+ return 0;
+
+dbtotxt_error:
+ if( rc ){
+ sqlite3_fprintf(stderr, "ERROR: %s\n", sqlite3_errmsg(p->db));
+ }
+ sqlite3_finalize(pStmt);
+ free(zName);
+ return 1;
+}
+
+/*
+** Print the given string as an error message.
+*/
+static void shellEmitError(const char *zErr){
+ sqlite3_fprintf(stderr,"Error: %s\n", zErr);
+}
+/*
** Print the current sqlite3_errmsg() value to stderr and return 1.
*/
static int shellDatabaseError(sqlite3 *db){
- const char *zErr = sqlite3_errmsg(db);
- eputf("Error: %s\n", zErr);
+ shellEmitError(sqlite3_errmsg(db));
return 1;
}
@@ -6581,6 +7149,7 @@ static int lintFkeyIndexes(
const char *zIndent = ""; /* How much to indent CREATE INDEX by */
int rc; /* Return code */
sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
+ FILE *out = pState->out; /* Send output here */
/*
** This SELECT statement returns one row for each foreign key constraint
@@ -6656,7 +7225,8 @@ static int lintFkeyIndexes(
zIndent = " ";
}
else{
- eputf("Usage: %s %s ?-verbose? ?-groupbyparent?\n", azArg[0], azArg[1]);
+ sqlite3_fprintf(stderr,
+ "Usage: %s %s ?-verbose? ?-groupbyparent?\n", azArg[0], azArg[1]);
return SQLITE_ERROR;
}
}
@@ -6700,22 +7270,23 @@ static int lintFkeyIndexes(
if( rc!=SQLITE_OK ) break;
if( res<0 ){
- eputz("Error: internal error");
+ sqlite3_fputs("Error: internal error", stderr);
break;
}else{
if( bGroupByParent
&& (bVerbose || res==0)
&& (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
){
- oputf("-- Parent table %s\n", zParent);
+ sqlite3_fprintf(out, "-- Parent table %s\n", zParent);
sqlite3_free(zPrev);
zPrev = sqlite3_mprintf("%s", zParent);
}
if( res==0 ){
- oputf("%s%s --> %s\n", zIndent, zCI, zTarget);
+ sqlite3_fprintf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
}else if( bVerbose ){
- oputf("%s/* no extra indexes required for %s -> %s */\n",
+ sqlite3_fprintf(out,
+ "%s/* no extra indexes required for %s -> %s */\n",
zIndent, zFrom, zTarget
);
}
@@ -6724,16 +7295,16 @@ static int lintFkeyIndexes(
sqlite3_free(zPrev);
if( rc!=SQLITE_OK ){
- eputf("%s\n", sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
}
rc2 = sqlite3_finalize(pSql);
if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
rc = rc2;
- eputf("%s\n", sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
}
}else{
- eputf("%s\n", sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
}
return rc;
@@ -6753,9 +7324,9 @@ static int lintDotCommand(
return lintFkeyIndexes(pState, azArg, nArg);
usage:
- eputf("Usage %s sub-command ?switches...?\n", azArg[0]);
- eputz("Where sub-commands are:\n");
- eputz(" fkey-indexes\n");
+ sqlite3_fprintf(stderr,"Usage %s sub-command ?switches...?\n", azArg[0]);
+ sqlite3_fprintf(stderr, "Where sub-commands are:\n");
+ sqlite3_fprintf(stderr, " fkey-indexes\n");
return SQLITE_ERROR;
}
@@ -6769,7 +7340,8 @@ static void shellPrepare(
if( *pRc==SQLITE_OK ){
int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
if( rc!=SQLITE_OK ){
- eputf("sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
+ sqlite3_fprintf(stderr,
+ "sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
*pRc = rc;
}
}
@@ -6813,7 +7385,7 @@ static void shellFinalize(
int rc = sqlite3_finalize(pStmt);
if( *pRc==SQLITE_OK ){
if( rc!=SQLITE_OK ){
- eputf("SQL error: %s\n", sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,"SQL error: %s\n", sqlite3_errmsg(db));
}
*pRc = rc;
}
@@ -6835,7 +7407,7 @@ void shellReset(
if( *pRc==SQLITE_OK ){
if( rc!=SQLITE_OK ){
sqlite3 *db = sqlite3_db_handle(pStmt);
- eputf("SQL error: %s\n", sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,"SQL error: %s\n", sqlite3_errmsg(db));
}
*pRc = rc;
}
@@ -6864,6 +7436,7 @@ struct ArCommand {
const char *zDir; /* --directory argument, or NULL */
char **azArg; /* Array of command arguments */
ShellState *p; /* Shell state */
+ FILE *out; /* Output to this stream */
sqlite3 *db; /* Database containing the archive */
};
@@ -6885,11 +7458,11 @@ static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){
va_start(ap, zFmt);
z = sqlite3_vmprintf(zFmt, ap);
va_end(ap);
- eputf("Error: %s\n", z);
+ shellEmitError(z);
if( pAr->fromCmdLine ){
- eputz("Use \"-A\" for more help\n");
+ sqlite3_fputs("Use \"-A\" for more help\n", stderr);
}else{
- eputz("Use \".archive --help\" for more help\n");
+ sqlite3_fputs("Use \".archive --help\" for more help\n", stderr);
}
sqlite3_free(z);
return SQLITE_ERROR;
@@ -6942,7 +7515,7 @@ static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
break;
case AR_SWITCH_APPEND:
pAr->bAppend = 1;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case AR_SWITCH_FILE:
pAr->zFile = zArg;
break;
@@ -6989,7 +7562,7 @@ static int arParseCommand(
struct ArSwitch *pEnd = &aSwitch[nSwitch];
if( nArg<=1 ){
- eputz("Wrong number of arguments. Usage:\n");
+ sqlite3_fprintf(stderr, "Wrong number of arguments. Usage:\n");
return arUsage(stderr);
}else{
char *z = azArg[1];
@@ -7095,7 +7668,7 @@ static int arParseCommand(
}
}
if( pAr->eCmd==0 ){
- eputz("Required argument missing. Usage:\n");
+ sqlite3_fprintf(stderr, "Required argument missing. Usage:\n");
return arUsage(stderr);
}
return SQLITE_OK;
@@ -7138,7 +7711,7 @@ static int arCheckEntries(ArCommand *pAr){
}
shellReset(&rc, pTest);
if( rc==SQLITE_OK && bOk==0 ){
- eputf("not found in archive: %s\n", z);
+ sqlite3_fprintf(stderr,"not found in archive: %s\n", z);
rc = SQLITE_ERROR;
}
}
@@ -7205,15 +7778,15 @@ static int arListCommand(ArCommand *pAr){
shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
pAr->zSrcTable, zWhere);
if( pAr->bDryRun ){
- oputf("%s\n", sqlite3_sql(pSql));
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_sql(pSql));
}else{
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
if( pAr->bVerbose ){
- oputf("%s % 10d %s %s\n",
+ sqlite3_fprintf(pAr->out, "%s % 10d %s %s\n",
sqlite3_column_text(pSql, 0), sqlite3_column_int(pSql, 1),
sqlite3_column_text(pSql, 2),sqlite3_column_text(pSql, 3));
}else{
- oputf("%s\n", sqlite3_column_text(pSql, 0));
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
}
}
}
@@ -7240,7 +7813,7 @@ static int arRemoveCommand(ArCommand *pAr){
zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;",
pAr->zSrcTable, zWhere);
if( pAr->bDryRun ){
- oputf("%s\n", zSql);
+ sqlite3_fprintf(pAr->out, "%s\n", zSql);
}else{
char *zErr = 0;
rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0);
@@ -7253,7 +7826,7 @@ static int arRemoveCommand(ArCommand *pAr){
}
}
if( zErr ){
- sputf(stdout, "ERROR: %s\n", zErr); /* stdout? */
+ sqlite3_fprintf(stdout, "ERROR: %s\n", zErr); /* stdout? */
sqlite3_free(zErr);
}
}
@@ -7317,11 +7890,11 @@ static int arExtractCommand(ArCommand *pAr){
j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
sqlite3_bind_int(pSql, j, i);
if( pAr->bDryRun ){
- oputf("%s\n", sqlite3_sql(pSql));
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_sql(pSql));
}else{
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
if( i==0 && pAr->bVerbose ){
- oputf("%s\n", sqlite3_column_text(pSql, 0));
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
}
}
}
@@ -7341,13 +7914,13 @@ static int arExtractCommand(ArCommand *pAr){
static int arExecSql(ArCommand *pAr, const char *zSql){
int rc;
if( pAr->bDryRun ){
- oputf("%s\n", zSql);
+ sqlite3_fprintf(pAr->out, "%s\n", zSql);
rc = SQLITE_OK;
}else{
char *zErr = 0;
rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
if( zErr ){
- sputf(stdout, "ERROR: %s\n", zErr);
+ sqlite3_fprintf(stdout, "ERROR: %s\n", zErr);
sqlite3_free(zErr);
}
}
@@ -7496,6 +8069,7 @@ static int arDotCommand(
if( rc==SQLITE_OK ){
int eDbType = SHELL_OPEN_UNSPEC;
cmd.p = pState;
+ cmd.out = pState->out;
cmd.db = pState->db;
if( cmd.zFile ){
eDbType = deduceDatabaseType(cmd.zFile, 1);
@@ -7522,13 +8096,14 @@ static int arDotCommand(
}
cmd.db = 0;
if( cmd.bDryRun ){
- oputf("-- open database '%s'%s\n", cmd.zFile,
+ sqlite3_fprintf(cmd.out, "-- open database '%s'%s\n", cmd.zFile,
eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
}
rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags,
eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
if( rc!=SQLITE_OK ){
- eputf("cannot open file: %s (%s)\n", cmd.zFile, sqlite3_errmsg(cmd.db));
+ sqlite3_fprintf(stderr, "cannot open file: %s (%s)\n",
+ cmd.zFile, sqlite3_errmsg(cmd.db));
goto end_ar_command;
}
sqlite3_fileio_init(cmd.db, 0, 0);
@@ -7541,7 +8116,7 @@ static int arDotCommand(
if( cmd.eCmd!=AR_CMD_CREATE
&& sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
){
- eputz("database does not contain an 'sqlar' table\n");
+ sqlite3_fprintf(stderr, "database does not contain an 'sqlar' table\n");
rc = SQLITE_ERROR;
goto end_ar_command;
}
@@ -7599,7 +8174,7 @@ end_ar_command:
*/
static int recoverSqlCb(void *pCtx, const char *zSql){
ShellState *pState = (ShellState*)pCtx;
- sputf(pState->out, "%s;\n", zSql);
+ sqlite3_fprintf(pState->out, "%s;\n", zSql);
return SQLITE_OK;
}
@@ -7642,7 +8217,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
bRowids = 0;
}
else{
- eputf("unexpected option: %s\n", azArg[i]);
+ sqlite3_fprintf(stderr,"unexpected option: %s\n", azArg[i]);
showHelp(pState->out, azArg[0]);
return 1;
}
@@ -7657,11 +8232,12 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
sqlite3_recover_config(p, SQLITE_RECOVER_ROWIDS, (void*)&bRowids);
sqlite3_recover_config(p, SQLITE_RECOVER_FREELIST_CORRUPT,(void*)&bFreelist);
+ sqlite3_fprintf(pState->out, ".dbconfig defensive off\n");
sqlite3_recover_run(p);
if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
const char *zErr = sqlite3_recover_errmsg(p);
int errCode = sqlite3_recover_errcode(p);
- eputf("sql error: %s (%d)\n", zErr, errCode);
+ sqlite3_fprintf(stderr,"sql error: %s (%d)\n", zErr, errCode);
}
rc = sqlite3_recover_finish(p);
return rc;
@@ -7683,7 +8259,7 @@ static int intckDatabaseCmd(ShellState *pState, i64 nStepPerUnlock){
while( SQLITE_OK==sqlite3_intck_step(p) ){
const char *zMsg = sqlite3_intck_message(p);
if( zMsg ){
- oputf("%s\n", zMsg);
+ sqlite3_fprintf(pState->out, "%s\n", zMsg);
nError++;
}
nStep++;
@@ -7693,11 +8269,11 @@ static int intckDatabaseCmd(ShellState *pState, i64 nStepPerUnlock){
}
rc = sqlite3_intck_error(p, &zErr);
if( zErr ){
- eputf("%s\n", zErr);
+ sqlite3_fprintf(stderr,"%s\n", zErr);
}
sqlite3_intck_close(p);
- oputf("%lld steps, %lld errors\n", nStep, nError);
+ sqlite3_fprintf(pState->out, "%lld steps, %lld errors\n", nStep, nError);
}
return rc;
@@ -7720,7 +8296,7 @@ static int intckDatabaseCmd(ShellState *pState, i64 nStepPerUnlock){
#define rc_err_oom_die(rc) \
if( rc==SQLITE_NOMEM ) shell_check_oom(0); \
else if(!(rc==SQLITE_OK||rc==SQLITE_DONE)) \
- eputf("E:%d\n",rc), assert(0)
+ sqlite3_fprintf(stderr,"E:%d\n",rc), assert(0)
#else
static void rc_err_oom_die(int rc){
if( rc==SQLITE_NOMEM ) shell_check_oom(0);
@@ -7878,8 +8454,8 @@ FROM (\
}else{
/* Formulate the columns spec, close the DB, zero *pDb. */
char *zColsSpec = 0;
- int hasDupes = db_int(*pDb, zHasDupes);
- int nDigits = (hasDupes)? db_int(*pDb, zColDigits) : 0;
+ int hasDupes = db_int(*pDb, "%s", zHasDupes);
+ int nDigits = (hasDupes)? db_int(*pDb, "%s", zColDigits) : 0;
if( hasDupes ){
#ifdef SHELL_COLUMN_RENAME_CLEAN
rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
@@ -7894,7 +8470,7 @@ FROM (\
sqlite3_finalize(pStmt);
if( rc!=SQLITE_DONE ) rc_err_oom_die(SQLITE_NOMEM);
}
- assert(db_int(*pDb, zHasDupes)==0); /* Consider: remove this */
+ assert(db_int(*pDb, "%s", zHasDupes)==0); /* Consider: remove this */
rc = sqlite3_prepare_v2(*pDb, zCollectVar, -1, &pStmt, 0);
rc_err_oom_die(rc);
rc = sqlite3_step(pStmt);
@@ -7937,8 +8513,9 @@ static int outputDumpWarning(ShellState *p, const char *zLike){
"sql LIKE 'CREATE VIRTUAL TABLE%%' AND %s", zLike ? zLike : "true"
);
if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
- oputz("/* WARNING: "
- "Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */\n"
+ sqlite3_fputs("/* WARNING: "
+ "Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */\n",
+ p->out
);
}
shellFinalize(&rc, pStmt);
@@ -7969,12 +8546,14 @@ static int faultsim_callback(int iArg){
if( faultsim_state.iCnt ){
if( faultsim_state.iCnt>0 ) faultsim_state.iCnt--;
if( faultsim_state.eVerbose>=2 ){
- oputf("FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
+ sqlite3_fprintf(stdout,
+ "FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
}
return SQLITE_OK;
}
if( faultsim_state.eVerbose>=1 ){
- oputf("FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
+ sqlite3_fprintf(stdout,
+ "FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
}
faultsim_state.iCnt = faultsim_state.iInterval;
faultsim_state.nHit++;
@@ -8037,7 +8616,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifndef SQLITE_OMIT_AUTHORIZATION
if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){
if( nArg!=2 ){
- eputz("Usage: .auth ON|OFF\n");
+ sqlite3_fprintf(stderr, "Usage: .auth ON|OFF\n");
rc = 1;
goto meta_command_exit;
}
@@ -8084,7 +8663,7 @@ static int do_meta_command(char *zLine, ShellState *p){
bAsync = 1;
}else
{
- eputf("unknown option: %s\n", azArg[j]);
+ sqlite3_fprintf(stderr,"unknown option: %s\n", azArg[j]);
return 1;
}
}else if( zDestFile==0 ){
@@ -8093,19 +8672,19 @@ static int do_meta_command(char *zLine, ShellState *p){
zDb = zDestFile;
zDestFile = azArg[j];
}else{
- eputz("Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
+ sqlite3_fprintf(stderr, "Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
return 1;
}
}
if( zDestFile==0 ){
- eputz("missing FILENAME argument on .backup\n");
+ sqlite3_fprintf(stderr, "missing FILENAME argument on .backup\n");
return 1;
}
if( zDb==0 ) zDb = "main";
rc = sqlite3_open_v2(zDestFile, &pDest,
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs);
if( rc!=SQLITE_OK ){
- eputf("Error: cannot open \"%s\"\n", zDestFile);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zDestFile);
close_db(pDest);
return 1;
}
@@ -8116,7 +8695,7 @@ static int do_meta_command(char *zLine, ShellState *p){
open_db(p, 0);
pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
if( pBackup==0 ){
- eputf("Error: %s\n", sqlite3_errmsg(pDest));
+ shellDatabaseError(pDest);
close_db(pDest);
return 1;
}
@@ -8125,7 +8704,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc==SQLITE_DONE ){
rc = 0;
}else{
- eputf("Error: %s\n", sqlite3_errmsg(pDest));
+ shellDatabaseError(pDest);
rc = 1;
}
close_db(pDest);
@@ -8141,19 +8720,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- /* Undocumented. Legacy only. See "crnl" below */
+ /* Undocumented. Legacy only. See "crlf" below */
if( c=='b' && n>=3 && cli_strncmp(azArg[0], "binary", n)==0 ){
- if( nArg==2 ){
- if( booleanValue(azArg[1]) ){
- setBinaryMode(p->out, 1);
- }else{
- setTextMode(p->out, 1);
- }
- }else{
- eputz("The \".binary\" command is deprecated. Use \".crnl\" instead.\n"
- "Usage: .binary on|off\n");
- rc = 1;
- }
+ eputz("The \".binary\" command is deprecated.\n");
+ rc = 1;
}else
/* The undocumented ".breakpoint" command causes a call to the no-op
@@ -8175,7 +8745,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = chdir(azArg[1]);
#endif
if( rc ){
- eputf("Cannot change to directory \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"Cannot change to directory \"%s\"\n", azArg[1]);
rc = 1;
}
}else{
@@ -8208,11 +8778,12 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
rc = 2;
}else if( testcase_glob(azArg[1],zRes)==0 ){
- eputf("testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
+ sqlite3_fprintf(stderr,
+ "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
p->zTestcase, azArg[1], zRes);
rc = 1;
}else{
- oputf("testcase-%s ok\n", p->zTestcase);
+ sqlite3_fprintf(p->out, "testcase-%s ok\n", p->zTestcase);
p->nCheck++;
}
sqlite3_free(zRes);
@@ -8245,9 +8816,9 @@ static int do_meta_command(char *zLine, ShellState *p){
zFile = "(temporary-file)";
}
if( p->pAuxDb == &p->aAuxDb[i] ){
- sputf(stdout, "ACTIVE %d: %s\n", i, zFile);
+ sqlite3_fprintf(stdout, "ACTIVE %d: %s\n", i, zFile);
}else if( p->aAuxDb[i].db!=0 ){
- sputf(stdout, " %d: %s\n", i, zFile);
+ sqlite3_fprintf(stdout, " %d: %s\n", i, zFile);
}
}
}else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){
@@ -8277,20 +8848,18 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='c' && n==4 && cli_strncmp(azArg[0], "crnl", n)==0 ){
+ if( c=='c' && n==4
+ && (cli_strncmp(azArg[0], "crlf", n)==0
+ || cli_strncmp(azArg[0], "crnl",n)==0)
+ ){
if( nArg==2 ){
- if( booleanValue(azArg[1]) ){
- setTextMode(p->out, 1);
- }else{
- setBinaryMode(p->out, 1);
- }
- }else{
-#if !defined(_WIN32) && !defined(WIN32)
- eputz("The \".crnl\" is a no-op on non-Windows machines.\n");
+#ifdef _WIN32
+ p->crlfMode = booleanValue(azArg[1]);
+#else
+ p->crlfMode = 0;
#endif
- eputz("Usage: .crnl on|off\n");
- rc = 1;
}
+ sqlite3_fprintf(stderr, "crlf is %s\n", p->crlfMode ? "ON" : "OFF");
}else
if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){
@@ -8301,7 +8870,7 @@ static int do_meta_command(char *zLine, ShellState *p){
open_db(p, 0);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ){
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
rc = 1;
}else{
while( sqlite3_step(pStmt)==SQLITE_ROW ){
@@ -8320,7 +8889,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int eTxn = sqlite3_txn_state(p->db, azName[i*2]);
int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]);
const char *z = azName[i*2+1];
- oputf("%s: %s %s%s\n",
+ sqlite3_fprintf(p->out, "%s: %s %s%s\n",
azName[i*2], z && z[0] ? z : "\"\"", bRdonly ? "r/o" : "r/w",
eTxn==SQLITE_TXN_NONE ? "" :
eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn");
@@ -8335,6 +8904,9 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zName;
int op;
} aDbConfig[] = {
+ { "attach_create", SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE },
+ { "attach_write", SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE },
+ { "comments", SQLITE_DBCONFIG_ENABLE_COMMENTS },
{ "defensive", SQLITE_DBCONFIG_DEFENSIVE },
{ "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
{ "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
@@ -8362,11 +8934,12 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
}
sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
- oputf("%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
+ sqlite3_fprintf(p->out, "%19s %s\n",
+ aDbConfig[ii].zName, v ? "on" : "off");
if( nArg>1 ) break;
}
if( nArg>1 && ii==ArraySize(aDbConfig) ){
- eputf("Error: unknown dbconfig \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"Error: unknown dbconfig \"%s\"\n", azArg[1]);
eputz("Enter \".dbconfig\" with no arguments for a list\n");
}
}else
@@ -8416,7 +8989,8 @@ static int do_meta_command(char *zLine, ShellState *p){
ShellSetFlag(p, SHFLG_DumpNoSys);
}else
{
- eputf("Unknown option \"%s\" on \".dump\"\n", azArg[i]);
+ sqlite3_fprintf(stderr,
+ "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
rc = 1;
sqlite3_free(zLike);
goto meta_command_exit;
@@ -8451,8 +9025,8 @@ static int do_meta_command(char *zLine, ShellState *p){
/* When playing back a "dump", the content might appear in an order
** which causes immediate foreign key constraints to be violated.
** So disable foreign-key constraint enforcement to prevent problems. */
- oputz("PRAGMA foreign_keys=OFF;\n");
- oputz("BEGIN TRANSACTION;\n");
+ sqlite3_fputs("PRAGMA foreign_keys=OFF;\n", p->out);
+ sqlite3_fputs("BEGIN TRANSACTION;\n", p->out);
}
p->writableSchema = 0;
p->showHeader = 0;
@@ -8484,13 +9058,13 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_free(zLike);
if( p->writableSchema ){
- oputz("PRAGMA writable_schema=OFF;\n");
+ sqlite3_fputs("PRAGMA writable_schema=OFF;\n", p->out);
p->writableSchema = 0;
}
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
- oputz(p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
+ sqlite3_fputs(p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n", p->out);
}
p->showHeader = savedShowHeader;
p->shellFlgs = savedShellFlags;
@@ -8505,6 +9079,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+ if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){
+ rc = shell_dbtotxt_command(p, nArg, azArg);
+ }else
+
if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
if( nArg==2 ){
p->autoEQPtest = 0;
@@ -8570,7 +9148,8 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){
if( p->bSafeMode ){
- eputf("Cannot run experimental commands such as \"%s\" in safe mode\n",
+ sqlite3_fprintf(stderr,
+ "Cannot run experimental commands such as \"%s\" in safe mode\n",
azArg[0]);
rc = 1;
}else{
@@ -8627,9 +9206,10 @@ static int do_meta_command(char *zLine, ShellState *p){
/* --help lists all file-controls */
if( cli_strcmp(zCmd,"help")==0 ){
- oputz("Available file-controls:\n");
+ sqlite3_fputs("Available file-controls:\n", p->out);
for(i=0; i<ArraySize(aCtrl); i++){
- oputf(" .filectrl %s %s\n", aCtrl[i].zCtrlName, aCtrl[i].zUsage);
+ sqlite3_fprintf(p->out,
+ " .filectrl %s %s\n", aCtrl[i].zCtrlName, aCtrl[i].zUsage);
}
rc = 1;
goto meta_command_exit;
@@ -8644,7 +9224,7 @@ static int do_meta_command(char *zLine, ShellState *p){
filectrl = aCtrl[i].ctrlCode;
iCtrl = i;
}else{
- eputf("Error: ambiguous file-control: \"%s\"\n"
+ sqlite3_fprintf(stderr,"Error: ambiguous file-control: \"%s\"\n"
"Use \".filectrl --help\" for help\n", zCmd);
rc = 1;
goto meta_command_exit;
@@ -8652,7 +9232,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( filectrl<0 ){
- eputf("Error: unknown file-control: %s\n"
+ sqlite3_fprintf(stderr,"Error: unknown file-control: %s\n"
"Use \".filectrl --help\" for help\n", zCmd);
}else{
switch(filectrl){
@@ -8696,7 +9276,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nArg!=2 ) break;
sqlite3_file_control(p->db, zSchema, filectrl, &z);
if( z ){
- oputf("%s\n", z);
+ sqlite3_fprintf(p->out, "%s\n", z);
sqlite3_free(z);
}
isOk = 2;
@@ -8710,19 +9290,20 @@ static int do_meta_command(char *zLine, ShellState *p){
}
x = -1;
sqlite3_file_control(p->db, zSchema, filectrl, &x);
- oputf("%d\n", x);
+ sqlite3_fprintf(p->out, "%d\n", x);
isOk = 2;
break;
}
}
}
if( isOk==0 && iCtrl>=0 ){
- oputf("Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
+ sqlite3_fprintf(p->out, "Usage: .filectrl %s %s\n",
+ zCmd, aCtrl[iCtrl].zUsage);
rc = 1;
}else if( isOk==1 ){
char zBuf[100];
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
- oputf("%s\n", zBuf);
+ sqlite3_fprintf(p->out, "%s\n", zBuf);
}
}else
@@ -8747,7 +9328,8 @@ static int do_meta_command(char *zLine, ShellState *p){
" (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
" FROM sqlite_schema UNION ALL"
" SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) "
- "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
+ "WHERE type!='meta' AND sql NOTNULL"
+ " AND name NOT LIKE 'sqlite__%' ESCAPE '_' "
"ORDER BY x",
callback, &data, 0
);
@@ -8763,15 +9345,15 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( doStats==0 ){
- oputz("/* No STAT tables available */\n");
+ sqlite3_fputs("/* No STAT tables available */\n", p->out);
}else{
- oputz("ANALYZE sqlite_schema;\n");
+ sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
data.cMode = data.mode = MODE_Insert;
data.zDestTable = "sqlite_stat1";
shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
data.zDestTable = "sqlite_stat4";
shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
- oputz("ANALYZE sqlite_schema;\n");
+ sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
}
}else
@@ -8789,7 +9371,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nArg>=2 ){
n = showHelp(p->out, azArg[1]);
if( n==0 ){
- oputf("Nothing matches '%s'\n", azArg[1]);
+ sqlite3_fprintf(p->out, "Nothing matches '%s'\n", azArg[1]);
}
}else{
showHelp(p->out, 0);
@@ -8832,7 +9414,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( zTable==0 ){
zTable = z;
}else{
- oputf("ERROR: extra argument: \"%s\". Usage:\n", z);
+ sqlite3_fprintf(p->out, "ERROR: extra argument: \"%s\". Usage:\n",z);
showHelp(p->out, "import");
goto meta_command_exit;
}
@@ -8853,13 +9435,13 @@ static int do_meta_command(char *zLine, ShellState *p){
xRead = csv_read_one_field;
useOutputMode = 0;
}else{
- oputf("ERROR: unknown option: \"%s\". Usage:\n", z);
+ sqlite3_fprintf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z);
showHelp(p->out, "import");
goto meta_command_exit;
}
}
if( zTable==0 ){
- oputf("ERROR: missing %s argument. Usage:\n",
+ sqlite3_fprintf(p->out, "ERROR: missing %s argument. Usage:\n",
zFile==0 ? "FILE" : "TABLE");
showHelp(p->out, "import");
goto meta_command_exit;
@@ -8909,28 +9491,28 @@ static int do_meta_command(char *zLine, ShellState *p){
eputz("Error: pipes are not supported in this OS\n");
goto meta_command_exit;
#else
- sCtx.in = popen(sCtx.zFile+1, "r");
+ sCtx.in = sqlite3_popen(sCtx.zFile+1, "r");
sCtx.zFile = "<pipe>";
sCtx.xCloser = pclose;
#endif
}else{
- sCtx.in = fopen(sCtx.zFile, "rb");
+ sCtx.in = sqlite3_fopen(sCtx.zFile, "rb");
sCtx.xCloser = fclose;
}
if( sCtx.in==0 ){
- eputf("Error: cannot open \"%s\"\n", zFile);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zFile);
goto meta_command_exit;
}
if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
char zSep[2];
zSep[1] = 0;
zSep[0] = sCtx.cColSep;
- oputz("Column separator ");
- output_c_string(zSep);
- oputz(", row separator ");
+ sqlite3_fputs("Column separator ", p->out);
+ output_c_string(p->out, zSep);
+ sqlite3_fputs(", row separator ", p->out);
zSep[0] = sCtx.cRowSep;
- output_c_string(zSep);
- oputz("\n");
+ output_c_string(p->out, zSep);
+ sqlite3_fputs("\n", p->out);
}
sCtx.z = sqlite3_malloc64(120);
if( sCtx.z==0 ){
@@ -8942,7 +9524,11 @@ static int do_meta_command(char *zLine, ShellState *p){
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
}
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
- if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0) ){
+ if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0)
+ && 0==db_int(p->db, "SELECT count(*) FROM \"%w\".sqlite_schema"
+ " WHERE name=%Q AND type='view'",
+ zSchema ? zSchema : "main", zTable)
+ ){
/* Table does not exist. Create it. */
sqlite3 *dbCols = 0;
char *zRenames = 0;
@@ -8955,14 +9541,14 @@ static int do_meta_command(char *zLine, ShellState *p){
}
zColDefs = zAutoColumn(0, &dbCols, &zRenames);
if( zRenames!=0 ){
- sputf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
+ sqlite3_fprintf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
"Columns renamed during .import %s due to duplicates:\n"
"%s\n", sCtx.zFile, zRenames);
sqlite3_free(zRenames);
}
assert(dbCols==0);
if( zColDefs==0 ){
- eputf("%s: empty file\n", sCtx.zFile);
+ sqlite3_fprintf(stderr,"%s: empty file\n", sCtx.zFile);
import_cleanup(&sCtx);
rc = 1;
sqlite3_free(zCreate);
@@ -8974,13 +9560,16 @@ static int do_meta_command(char *zLine, ShellState *p){
shell_out_of_memory();
}
if( eVerbose>=1 ){
- oputf("%s\n", zCreate);
+ sqlite3_fprintf(p->out, "%s\n", zCreate);
}
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
+ if( rc ){
+ sqlite3_fprintf(stderr,
+ "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
+ }
sqlite3_free(zCreate);
zCreate = 0;
if( rc ){
- eputf("%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
@@ -8997,7 +9586,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zSql = 0;
if( rc ){
if (pStmt) sqlite3_finalize(pStmt);
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
@@ -9035,13 +9624,13 @@ static int do_meta_command(char *zLine, ShellState *p){
zSql[j] = 0;
assert( j<nByte );
if( eVerbose>=2 ){
- oputf("Insert using: %s\n", zSql);
+ sqlite3_fprintf(p->out, "Insert using: %s\n", zSql);
}
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
zSql = 0;
if( rc ){
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
if (pStmt) sqlite3_finalize(pStmt);
import_cleanup(&sCtx);
rc = 1;
@@ -9074,7 +9663,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
- eputf("%s:%d: expected %d columns but found %d"
+ sqlite3_fprintf(stderr,"%s:%d: expected %d columns but found %d"
" - filling the rest with NULL\n",
sCtx.zFile, startLine, nCol, i+1);
i += 2;
@@ -9086,14 +9675,15 @@ static int do_meta_command(char *zLine, ShellState *p){
xRead(&sCtx);
i++;
}while( sCtx.cTerm==sCtx.cColSep );
- eputf("%s:%d: expected %d columns but found %d - extras ignored\n",
+ sqlite3_fprintf(stderr,
+ "%s:%d: expected %d columns but found %d - extras ignored\n",
sCtx.zFile, startLine, nCol, i);
}
if( i>=nCol ){
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
if( rc!=SQLITE_OK ){
- eputf("%s:%d: INSERT failed: %s\n",
+ sqlite3_fprintf(stderr,"%s:%d: INSERT failed: %s\n",
sCtx.zFile, startLine, sqlite3_errmsg(p->db));
sCtx.nErr++;
}else{
@@ -9106,7 +9696,8 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_finalize(pStmt);
if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
if( eVerbose>0 ){
- oputf("Added %d rows with %d errors using %d lines of input\n",
+ sqlite3_fprintf(p->out,
+ "Added %d rows with %d errors using %d lines of input\n",
sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
}
}else
@@ -9122,7 +9713,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
int i;
if( !ShellHasFlag(p,SHFLG_TestingMode) ){
- eputf(".%s unavailable without --unsafe-testing\n",
+ sqlite3_fprintf(stderr,".%s unavailable without --unsafe-testing\n",
"imposter");
rc = 1;
goto meta_command_exit;
@@ -9188,7 +9779,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_finalize(pStmt);
if( i==0 || tnum==0 ){
- eputf("no such index: \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"no such index: \"%s\"\n", azArg[1]);
rc = 1;
sqlite3_free(zCollist);
goto meta_command_exit;
@@ -9203,14 +9794,16 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
if( rc ){
- eputf("Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
+ sqlite3_fprintf(stderr,
+ "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
}else{
- sputf(stdout, "%s;\n", zSql);
- sputf(stdout, "WARNING: writing to an imposter table will corrupt"
+ sqlite3_fprintf(stdout, "%s;\n", zSql);
+ sqlite3_fprintf(stdout,
+ "WARNING: writing to an imposter table will corrupt"
" the \"%s\" %s!\n", azArg[1], isWO ? "table" : "index");
}
}else{
- eputf("SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
+ sqlite3_fprintf(stderr,"SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
rc = 1;
}
sqlite3_free(zSql);
@@ -9224,7 +9817,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( iArg==0 ) iArg = -1;
}
if( (nArg!=1 && nArg!=2) || iArg<0 ){
- eputf("%s","Usage: .intck STEPS_PER_UNLOCK\n");
+ sqlite3_fprintf(stderr,"%s","Usage: .intck STEPS_PER_UNLOCK\n");
rc = 1;
goto meta_command_exit;
}
@@ -9243,9 +9836,9 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3IoTrace = iotracePrintf;
iotrace = stdout;
}else{
- iotrace = fopen(azArg[1], "w");
+ iotrace = sqlite3_fopen(azArg[1], "w");
if( iotrace==0 ){
- eputf("Error: cannot open \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
sqlite3IoTrace = 0;
rc = 1;
}else{
@@ -9277,7 +9870,7 @@ static int do_meta_command(char *zLine, ShellState *p){
open_db(p, 0);
if( nArg==1 ){
for(i=0; i<ArraySize(aLimit); i++){
- sputf(stdout, "%20s %d\n", aLimit[i].zLimitName,
+ sqlite3_fprintf(stdout, "%20s %d\n", aLimit[i].zLimitName,
sqlite3_limit(p->db, aLimit[i].limitCode, -1));
}
}else if( nArg>3 ){
@@ -9292,14 +9885,14 @@ static int do_meta_command(char *zLine, ShellState *p){
if( iLimit<0 ){
iLimit = i;
}else{
- eputf("ambiguous limit: \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"ambiguous limit: \"%s\"\n", azArg[1]);
rc = 1;
goto meta_command_exit;
}
}
}
if( iLimit<0 ){
- eputf("unknown limit: \"%s\"\n"
+ sqlite3_fprintf(stderr,"unknown limit: \"%s\"\n"
"enter \".limits\" with no arguments for a list.\n",
azArg[1]);
rc = 1;
@@ -9309,7 +9902,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_limit(p->db, aLimit[iLimit].limitCode,
(int)integerValue(azArg[2]));
}
- sputf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName,
+ sqlite3_fprintf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName,
sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
}
}else
@@ -9335,7 +9928,7 @@ static int do_meta_command(char *zLine, ShellState *p){
open_db(p, 0);
rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
if( rc!=SQLITE_OK ){
- eputf("Error: %s\n", zErrMsg);
+ shellEmitError(zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}
@@ -9358,7 +9951,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
output_file_close(p->pLog);
if( cli_strcmp(zFile,"on")==0 ) zFile = "stdout";
- p->pLog = output_file_open(zFile, 0);
+ p->pLog = output_file_open(zFile);
}
}else
@@ -9366,24 +9959,52 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zMode = 0;
const char *zTabname = 0;
int i, n2;
+ int chng = 0; /* 0x01: change to cmopts. 0x02: Any other change */
ColModeOpts cmOpts = ColModeOpts_default;
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( optionMatch(z,"wrap") && i+1<nArg ){
cmOpts.iWrap = integerValue(azArg[++i]);
+ chng |= 1;
}else if( optionMatch(z,"ww") ){
cmOpts.bWordWrap = 1;
+ chng |= 1;
}else if( optionMatch(z,"wordwrap") && i+1<nArg ){
cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
+ chng |= 1;
}else if( optionMatch(z,"quote") ){
cmOpts.bQuote = 1;
+ chng |= 1;
}else if( optionMatch(z,"noquote") ){
cmOpts.bQuote = 0;
+ chng |= 1;
+ }else if( optionMatch(z,"escape") && i+1<nArg ){
+ /* See similar code at tag-20250224-1 */
+ const char *zEsc = azArg[++i];
+ int k;
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
+ if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){
+ p->eEscMode = k;
+ chng |= 2;
+ break;
+ }
+ }
+ if( k>=ArraySize(shell_EscModeNames) ){
+ sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\""
+ " - choices:", zEsc);
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
+ sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]);
+ }
+ sqlite3_fprintf(stderr, "\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
}else if( zMode==0 ){
zMode = z;
/* Apply defaults for qbox pseudo-mode. If that
* overwrites already-set values, user was informed of this.
*/
+ chng |= 1;
if( cli_strcmp(z, "qbox")==0 ){
ColModeOpts cmo = ColModeOpts_default_qbox;
zMode = "box";
@@ -9392,8 +10013,9 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( zTabname==0 ){
zTabname = z;
}else if( z[0]=='-' ){
- eputf("unknown option: %s\n", z);
+ sqlite3_fprintf(stderr,"unknown option: %s\n", z);
eputz("options:\n"
+ " --escape MODE\n"
" --noquote\n"
" --quote\n"
" --wordwrap on/off\n"
@@ -9402,23 +10024,34 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
goto meta_command_exit;
}else{
- eputf("extra argument: \"%s\"\n", z);
+ sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
rc = 1;
goto meta_command_exit;
}
}
- if( zMode==0 ){
+ if( !chng ){
if( p->mode==MODE_Column
|| (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
){
- oputf("current output mode: %s --wrap %d --wordwrap %s --%squote\n",
+ sqlite3_fprintf(p->out,
+ "current output mode: %s --wrap %d --wordwrap %s "
+ "--%squote --escape %s\n",
modeDescr[p->mode], p->cmOpts.iWrap,
p->cmOpts.bWordWrap ? "on" : "off",
- p->cmOpts.bQuote ? "" : "no");
+ p->cmOpts.bQuote ? "" : "no",
+ shell_EscModeNames[p->eEscMode]
+ );
}else{
- oputf("current output mode: %s\n", modeDescr[p->mode]);
+ sqlite3_fprintf(p->out,
+ "current output mode: %s --escape %s\n",
+ modeDescr[p->mode],
+ shell_EscModeNames[p->eEscMode]
+ );
}
+ }
+ if( zMode==0 ){
zMode = modeDescr[p->mode];
+ if( (chng&1)==0 ) cmOpts = p->cmOpts;
}
n2 = strlen30(zMode);
if( cli_strncmp(zMode,"lines",n2)==0 ){
@@ -9451,6 +10084,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( cli_strncmp(zMode,"insert",n2)==0 ){
p->mode = MODE_Insert;
set_table_name(p, zTabname ? zTabname : "table");
+ if( p->eEscMode==SHELL_ESC_OFF ){
+ ShellSetFlag(p, SHFLG_Newlines);
+ }else{
+ ShellClearFlag(p, SHFLG_Newlines);
+ }
}else if( cli_strncmp(zMode,"quote",n2)==0 ){
p->mode = MODE_Quote;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
@@ -9489,7 +10127,7 @@ static int do_meta_command(char *zLine, ShellState *p){
eputz("Usage: .nonce NONCE\n");
rc = 1;
}else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){
- eputf("line %d: incorrect nonce: \"%s\"\n",
+ sqlite3_fprintf(stderr,"line %d: incorrect nonce: \"%s\"\n",
p->lineno, azArg[1]);
exit(1);
}else{
@@ -9544,11 +10182,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif /* !SQLITE_SHELL_FIDDLE */
if( z[0]=='-' ){
- eputf("unknown option: %s\n", z);
+ sqlite3_fprintf(stderr,"unknown option: %s\n", z);
rc = 1;
goto meta_command_exit;
}else if( zFN ){
- eputf("extra argument: \"%s\"\n", z);
+ sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
rc = 1;
goto meta_command_exit;
}else{
@@ -9590,7 +10228,7 @@ static int do_meta_command(char *zLine, ShellState *p){
p->pAuxDb->zDbFilename = zNewFilename;
open_db(p, OPEN_DB_KEEPALIVE);
if( p->db==0 ){
- eputf("Error: cannot open '%s'\n", zNewFilename);
+ sqlite3_fprintf(stderr,"Error: cannot open '%s'\n", zNewFilename);
sqlite3_free(zNewFilename);
}else{
p->pAuxDb->zFreeOnClose = zNewFilename;
@@ -9608,19 +10246,23 @@ static int do_meta_command(char *zLine, ShellState *p){
&& (cli_strncmp(azArg[0], "output", n)==0
|| cli_strncmp(azArg[0], "once", n)==0))
|| (c=='e' && n==5 && cli_strcmp(azArg[0],"excel")==0)
+ || (c=='w' && n==3 && cli_strcmp(azArg[0],"www")==0)
){
char *zFile = 0;
- int bTxtMode = 0;
int i;
- int eMode = 0;
- int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
- static const char *zBomUtf8 = "\xef\xbb\xbf";
+ int eMode = 0; /* 0: .outout/.once, 'x'=.excel, 'w'=.www */
+ int bOnce = 0; /* 0: .output, 1: .once, 2: .excel/.www */
+ int bPlain = 0; /* --plain option */
+ static const char *zBomUtf8 = "\357\273\277";
const char *zBom = 0;
failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
if( c=='e' ){
eMode = 'x';
bOnce = 2;
+ }else if( c=='w' ){
+ eMode = 'w';
+ bOnce = 2;
}else if( cli_strncmp(azArg[0],"once",n)==0 ){
bOnce = 1;
}
@@ -9630,24 +10272,38 @@ static int do_meta_command(char *zLine, ShellState *p){
if( z[1]=='-' ) z++;
if( cli_strcmp(z,"-bom")==0 ){
zBom = zBomUtf8;
- }else if( c!='e' && cli_strcmp(z,"-x")==0 ){
+ }else if( cli_strcmp(z,"-plain")==0 ){
+ bPlain = 1;
+ }else if( c=='o' && cli_strcmp(z,"-x")==0 ){
eMode = 'x'; /* spreadsheet */
- }else if( c!='e' && cli_strcmp(z,"-e")==0 ){
+ }else if( c=='o' && cli_strcmp(z,"-e")==0 ){
eMode = 'e'; /* text editor */
+ }else if( c=='o' && cli_strcmp(z,"-w")==0 ){
+ eMode = 'w'; /* Web browser */
}else{
- oputf("ERROR: unknown option: \"%s\". Usage:\n", azArg[i]);
+ sqlite3_fprintf(p->out,
+ "ERROR: unknown option: \"%s\". Usage:\n", azArg[i]);
showHelp(p->out, azArg[0]);
rc = 1;
goto meta_command_exit;
}
- }else if( zFile==0 && eMode!='e' && eMode!='x' ){
- zFile = sqlite3_mprintf("%s", z);
+ }else if( zFile==0 && eMode==0 ){
+ if( cli_strcmp(z, "off")==0 ){
+#ifdef _WIN32
+ zFile = sqlite3_mprintf("nul");
+#else
+ zFile = sqlite3_mprintf("/dev/null");
+#endif
+ }else{
+ zFile = sqlite3_mprintf("%s", z);
+ }
if( zFile && zFile[0]=='|' ){
while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]);
break;
}
}else{
- oputf("ERROR: extra parameter: \"%s\". Usage:\n", azArg[i]);
+ sqlite3_fprintf(p->out,
+ "ERROR: extra parameter: \"%s\". Usage:\n", azArg[i]);
showHelp(p->out, azArg[0]);
rc = 1;
sqlite3_free(zFile);
@@ -9657,6 +10313,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( zFile==0 ){
zFile = sqlite3_mprintf("stdout");
}
+ shell_check_oom(zFile);
if( bOnce ){
p->outCount = 2;
}else{
@@ -9664,7 +10321,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
output_reset(p);
#ifndef SQLITE_NOHAVE_SYSTEM
- if( eMode=='e' || eMode=='x' ){
+ if( eMode=='e' || eMode=='x' || eMode=='w' ){
p->doXdgOpen = 1;
outputModePush(p);
if( eMode=='x' ){
@@ -9674,10 +10331,17 @@ static int do_meta_command(char *zLine, ShellState *p){
p->mode = MODE_Csv;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
+#ifdef _WIN32
+ zBom = zBomUtf8; /* Always include the BOM on Windows, as Excel does
+ ** not work without it. */
+#endif
+ }else if( eMode=='w' ){
+ /* web-browser mode. */
+ newTempFile(p, "html");
+ if( !bPlain ) p->mode = MODE_Www;
}else{
/* text editor mode */
newTempFile(p, "txt");
- bTxtMode = 1;
}
sqlite3_free(zFile);
zFile = sqlite3_mprintf("%s", p->zTempFile);
@@ -9690,26 +10354,34 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
output_redir(p, stdout);
#else
- FILE *pfPipe = popen(zFile + 1, "w");
+ FILE *pfPipe = sqlite3_popen(zFile + 1, "w");
if( pfPipe==0 ){
- eputf("Error: cannot open pipe \"%s\"\n", zFile + 1);
+ assert( stderr!=NULL );
+ sqlite3_fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
rc = 1;
}else{
output_redir(p, pfPipe);
- if( zBom ) oputz(zBom);
+ if( zBom ) sqlite3_fputs(zBom, pfPipe);
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
#endif
}else{
- FILE *pfFile = output_file_open(zFile, bTxtMode);
+ FILE *pfFile = output_file_open(zFile);
if( pfFile==0 ){
if( cli_strcmp(zFile,"off")!=0 ){
- eputf("Error: cannot write to \"%s\"\n", zFile);
+ assert( stderr!=NULL );
+ sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
}
rc = 1;
} else {
output_redir(p, pfFile);
- if( zBom ) oputz(zBom);
+ if( zBom ) sqlite3_fputs(zBom, pfFile);
+ if( bPlain && eMode=='w' ){
+ sqlite3_fputs(
+ "<!DOCTYPE html>\n<BODY>\n<PLAINTEXT>\n",
+ pfFile
+ );
+ }
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
}
@@ -9750,7 +10422,8 @@ static int do_meta_command(char *zLine, ShellState *p){
"SELECT key, quote(value) "
"FROM temp.sqlite_parameters;", -1, &pStmt, 0);
while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
- oputf("%-*s %s\n", len, sqlite3_column_text(pStmt,0),
+ sqlite3_fprintf(p->out,
+ "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
sqlite3_column_text(pStmt,1));
}
sqlite3_finalize(pStmt);
@@ -9795,12 +10468,13 @@ static int do_meta_command(char *zLine, ShellState *p){
rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rx!=SQLITE_OK ){
- oputf("Error: %s\n", sqlite3_errmsg(p->db));
+ sqlite3_fprintf(p->out, "Error: %s\n", sqlite3_errmsg(p->db));
sqlite3_finalize(pStmt);
pStmt = 0;
rc = 1;
}
}
+ bind_prepared_stmt(p, pStmt);
sqlite3_step(pStmt);
sqlite3_finalize(pStmt);
}else
@@ -9824,10 +10498,10 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='p' && n>=3 && cli_strncmp(azArg[0], "print", n)==0 ){
int i;
for(i=1; i<nArg; i++){
- if( i>1 ) oputz(" ");
- oputz(azArg[i]);
+ if( i>1 ) sqlite3_fputs(" ", p->out);
+ sqlite3_fputs(azArg[i], p->out);
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}else
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
@@ -9864,7 +10538,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
continue;
}
- eputf("Error: unknown option: \"%s\"\n", azArg[i]);
+ sqlite3_fprintf(stderr,"Error: unknown option: \"%s\"\n", azArg[i]);
rc = 1;
goto meta_command_exit;
}else{
@@ -9905,11 +10579,10 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifdef SQLITE_OMIT_POPEN
eputz("Error: pipes are not supported in this OS\n");
rc = 1;
- p->out = stdout;
#else
- p->in = popen(azArg[1]+1, "r");
+ p->in = sqlite3_popen(azArg[1]+1, "r");
if( p->in==0 ){
- eputf("Error: cannot open \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
rc = process_input(p);
@@ -9917,7 +10590,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
#endif
}else if( (p->in = openChrSource(azArg[1]))==0 ){
- eputf("Error: cannot open \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
rc = process_input(p);
@@ -9950,14 +10623,14 @@ static int do_meta_command(char *zLine, ShellState *p){
}
rc = sqlite3_open(zSrcFile, &pSrc);
if( rc!=SQLITE_OK ){
- eputf("Error: cannot open \"%s\"\n", zSrcFile);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zSrcFile);
close_db(pSrc);
return 1;
}
open_db(p, 0);
pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
if( pBackup==0 ){
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
close_db(pSrc);
return 1;
}
@@ -9975,14 +10648,17 @@ static int do_meta_command(char *zLine, ShellState *p){
eputz("Error: source database is busy\n");
rc = 1;
}else{
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
rc = 1;
}
close_db(pSrc);
}else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
- if( c=='s' && cli_strncmp(azArg[0], "scanstats", n)==0 ){
+ if( c=='s' &&
+ (cli_strncmp(azArg[0], "scanstats", n)==0 ||
+ cli_strncmp(azArg[0], "scanstatus", n)==0)
+ ){
if( nArg==2 ){
if( cli_strcmp(azArg[1], "vm")==0 ){
p->scanstatsOn = 3;
@@ -10033,7 +10709,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( optionMatch(azArg[ii],"nosys") ){
bNoSystemTabs = 1;
}else if( azArg[ii][0]=='-' ){
- eputf("Unknown option: \"%s\"\n", azArg[ii]);
+ sqlite3_fprintf(stderr,"Unknown option: \"%s\"\n", azArg[ii]);
rc = 1;
goto meta_command_exit;
}else if( zName==0 ){
@@ -10072,7 +10748,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
-1, &pStmt, 0);
if( rc ){
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
sqlite3_finalize(pStmt);
rc = 1;
goto meta_command_exit;
@@ -10129,19 +10805,19 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(zQarg);
}
if( bNoSystemTabs ){
- appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0);
+ appendText(&sSelect, "name NOT LIKE 'sqlite__%%' ESCAPE '_' AND ", 0);
}
appendText(&sSelect, "sql IS NOT NULL"
" ORDER BY snum, rowid", 0);
if( bDebug ){
- oputf("SQL: %s;\n", sSelect.z);
+ sqlite3_fprintf(p->out, "SQL: %s;\n", sSelect.z);
}else{
rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
}
freeText(&sSelect);
}
if( zErrMsg ){
- eputf("Error: %s\n", zErrMsg);
+ shellEmitError(zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}else if( rc != SQLITE_OK ){
@@ -10195,7 +10871,8 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{
rc = sqlite3session_attach(pSession->p, azCmd[1]);
if( rc ){
- eputf("ERROR: sqlite3session_attach() returns %d\n",rc);
+ sqlite3_fprintf(stderr,
+ "ERROR: sqlite3session_attach() returns %d\n",rc);
rc = 0;
}
}
@@ -10212,9 +10889,9 @@ static int do_meta_command(char *zLine, ShellState *p){
failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]);
if( nCmd!=2 ) goto session_syntax_error;
if( pSession->p==0 ) goto session_not_open;
- out = fopen(azCmd[1], "wb");
+ out = sqlite3_fopen(azCmd[1], "wb");
if( out==0 ){
- eputf("ERROR: cannot open \"%s\" for writing\n",
+ sqlite3_fprintf(stderr,"ERROR: cannot open \"%s\" for writing\n",
azCmd[1]);
}else{
int szChng;
@@ -10225,12 +10902,13 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
}
if( rc ){
- sputf(stdout, "Error: error code %d\n", rc);
+ sqlite3_fprintf(stdout, "Error: error code %d\n", rc);
rc = 0;
}
if( pChng
&& fwrite(pChng, szChng, 1, out)!=1 ){
- eputf("ERROR: Failed to write entire %d-byte output\n", szChng);
+ sqlite3_fprintf(stderr,
+ "ERROR: Failed to write entire %d-byte output\n", szChng);
}
sqlite3_free(pChng);
fclose(out);
@@ -10257,7 +10935,8 @@ static int do_meta_command(char *zLine, ShellState *p){
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
if( pAuxDb->nSession ){
ii = sqlite3session_enable(pSession->p, ii);
- oputf("session %s enable flag = %d\n", pSession->zName, ii);
+ sqlite3_fprintf(p->out,
+ "session %s enable flag = %d\n", pSession->zName, ii);
}
}else
@@ -10292,7 +10971,8 @@ static int do_meta_command(char *zLine, ShellState *p){
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
if( pAuxDb->nSession ){
ii = sqlite3session_indirect(pSession->p, ii);
- oputf("session %s indirect flag = %d\n", pSession->zName, ii);
+ sqlite3_fprintf(p->out,
+ "session %s indirect flag = %d\n", pSession->zName, ii);
}
}else
@@ -10304,7 +10984,8 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nCmd!=1 ) goto session_syntax_error;
if( pAuxDb->nSession ){
ii = sqlite3session_isempty(pSession->p);
- oputf("session %s isempty flag = %d\n", pSession->zName, ii);
+ sqlite3_fprintf(p->out,
+ "session %s isempty flag = %d\n", pSession->zName, ii);
}
}else
@@ -10313,7 +10994,7 @@ static int do_meta_command(char *zLine, ShellState *p){
*/
if( cli_strcmp(azCmd[0],"list")==0 ){
for(i=0; i<pAuxDb->nSession; i++){
- oputf("%d %s\n", i, pAuxDb->aSession[i].zName);
+ sqlite3_fprintf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName);
}
}else
@@ -10328,18 +11009,19 @@ static int do_meta_command(char *zLine, ShellState *p){
if( zName[0]==0 ) goto session_syntax_error;
for(i=0; i<pAuxDb->nSession; i++){
if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
- eputf("Session \"%s\" already exists\n", zName);
+ sqlite3_fprintf(stderr,"Session \"%s\" already exists\n", zName);
goto meta_command_exit;
}
}
if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){
- eputf("Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
+ sqlite3_fprintf(stderr,
+ "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
goto meta_command_exit;
}
pSession = &pAuxDb->aSession[pAuxDb->nSession];
rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
if( rc ){
- eputf("Cannot open session: error code=%d\n", rc);
+ sqlite3_fprintf(stderr,"Cannot open session: error code=%d\n", rc);
rc = 0;
goto meta_command_exit;
}
@@ -10363,7 +11045,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int i, v;
for(i=1; i<nArg; i++){
v = booleanValue(azArg[i]);
- oputf("%s: %d 0x%x\n", azArg[i], v, v);
+ sqlite3_fprintf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
}
}
if( cli_strncmp(azArg[0]+9, "integer", n-9)==0 ){
@@ -10372,7 +11054,7 @@ static int do_meta_command(char *zLine, ShellState *p){
char zBuf[200];
v = integerValue(azArg[i]);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
- oputz(zBuf);
+ sqlite3_fputs(zBuf, p->out);
}
}
}else
@@ -10399,8 +11081,9 @@ static int do_meta_command(char *zLine, ShellState *p){
bVerbose++;
}else
{
- eputf("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
- eputz("Should be one of: --init -v\n");
+ sqlite3_fprintf(stderr,
+ "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
+ sqlite3_fputs("Should be one of: --init -v\n", stderr);
rc = 1;
goto meta_command_exit;
}
@@ -10445,10 +11128,10 @@ static int do_meta_command(char *zLine, ShellState *p){
if( zAns==0 ) continue;
k = 0;
if( bVerbose>0 ){
- sputf(stdout, "%d: %s %s\n", tno, zOp, zSql);
+ sqlite3_fprintf(stdout, "%d: %s %s\n", tno, zOp, zSql);
}
if( cli_strcmp(zOp,"memo")==0 ){
- oputf("%s\n", zSql);
+ sqlite3_fprintf(p->out, "%s\n", zSql);
}else
if( cli_strcmp(zOp,"run")==0 ){
char *zErrMsg = 0;
@@ -10457,22 +11140,23 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
nTest++;
if( bVerbose ){
- oputf("Result: %s\n", str.z);
+ sqlite3_fprintf(p->out, "Result: %s\n", str.z);
}
if( rc || zErrMsg ){
nErr++;
rc = 1;
- oputf("%d: error-code-%d: %s\n", tno, rc, zErrMsg);
+ sqlite3_fprintf(p->out, "%d: error-code-%d: %s\n", tno, rc,zErrMsg);
sqlite3_free(zErrMsg);
}else if( cli_strcmp(zAns,str.z)!=0 ){
nErr++;
rc = 1;
- oputf("%d: Expected: [%s]\n", tno, zAns);
- oputf("%d: Got: [%s]\n", tno, str.z);
+ sqlite3_fprintf(p->out, "%d: Expected: [%s]\n", tno, zAns);
+ sqlite3_fprintf(p->out, "%d: Got: [%s]\n", tno, str.z);
}
}
else{
- eputf("Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
+ sqlite3_fprintf(stderr,
+ "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
rc = 1;
break;
}
@@ -10480,7 +11164,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_finalize(pStmt);
} /* End loop over k */
freeText(&str);
- oputf("%d errors out of %d tests\n", nErr, nTest);
+ sqlite3_fprintf(p->out, "%d errors out of %d tests\n", nErr, nTest);
}else
if( c=='s' && cli_strncmp(azArg[0], "separator", n)==0 ){
@@ -10528,7 +11212,8 @@ static int do_meta_command(char *zLine, ShellState *p){
bDebug = 1;
}else
{
- eputf("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
+ sqlite3_fprintf(stderr,
+ "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
showHelp(p->out, azArg[0]);
rc = 1;
goto meta_command_exit;
@@ -10551,7 +11236,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{
zSql = "SELECT lower(name) as tname FROM sqlite_schema"
" WHERE type='table' AND coalesce(rootpage,0)>1"
- " AND name NOT LIKE 'sqlite_%'"
+ " AND name NOT LIKE 'sqlite__%' ESCAPE '_'"
" ORDER BY 1 collate nocase";
}
sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
@@ -10606,7 +11291,7 @@ static int do_meta_command(char *zLine, ShellState *p){
freeText(&sQuery);
freeText(&sSql);
if( bDebug ){
- oputf("%s\n", zSql);
+ sqlite3_fprintf(p->out, "%s\n", zSql);
}else{
shell_exec(p, zSql, 0);
}
@@ -10616,7 +11301,7 @@ static int do_meta_command(char *zLine, ShellState *p){
char *zRevText = /* Query for reversible to-blob-to-text check */
"SELECT lower(name) as tname FROM sqlite_schema\n"
"WHERE type='table' AND coalesce(rootpage,0)>1\n"
- "AND name NOT LIKE 'sqlite_%%'%s\n"
+ "AND name NOT LIKE 'sqlite__%%' ESCAPE '_'%s\n"
"ORDER BY 1 collate nocase";
zRevText = sqlite3_mprintf(zRevText, zLike? " AND name LIKE $tspec" : "");
zRevText = sqlite3_mprintf(
@@ -10636,7 +11321,7 @@ static int do_meta_command(char *zLine, ShellState *p){
"' OR ') as query, tname from tabcols group by tname)"
, zRevText);
shell_check_oom(zRevText);
- if( bDebug ) oputf("%s\n", zRevText);
+ if( bDebug ) sqlite3_fprintf(p->out, "%s\n", zRevText);
lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0);
if( lrc!=SQLITE_OK ){
/* assert(lrc==SQLITE_NOMEM); // might also be SQLITE_ERROR if the
@@ -10649,7 +11334,7 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0);
sqlite3_stmt *pCheckStmt;
lrc = sqlite3_prepare_v2(p->db, zGenQuery, -1, &pCheckStmt, 0);
- if( bDebug ) oputf("%s\n", zGenQuery);
+ if( bDebug ) sqlite3_fprintf(p->out, "%s\n", zGenQuery);
if( lrc!=SQLITE_OK ){
rc = 1;
}else{
@@ -10657,7 +11342,8 @@ static int do_meta_command(char *zLine, ShellState *p){
double countIrreversible = sqlite3_column_double(pCheckStmt, 0);
if( countIrreversible>0 ){
int sz = (int)(countIrreversible + 0.5);
- eputf("Digest includes %d invalidly encoded text field%s.\n",
+ sqlite3_fprintf(stderr,
+ "Digest includes %d invalidly encoded text field%s.\n",
sz, (sz>1)? "s": "");
}
}
@@ -10691,11 +11377,11 @@ static int do_meta_command(char *zLine, ShellState *p){
zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
zCmd, azArg[i]);
}
- consoleRestore();
+ /*consoleRestore();*/
x = zCmd!=0 ? system(zCmd) : 1;
- consoleRenewSetup();
+ /*consoleRenewSetup();*/
sqlite3_free(zCmd);
- if( x ) eputf("System command returns %d\n", x);
+ if( x ) sqlite3_fprintf(stderr,"System command returns %d\n", x);
}else
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) */
@@ -10708,46 +11394,48 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
goto meta_command_exit;
}
- oputf("%12.12s: %s\n","echo",
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","echo",
azBool[ShellHasFlag(p, SHFLG_Echo)]);
- oputf("%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
- oputf("%12.12s: %s\n","explain",
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","explain",
p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
- oputf("%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","headers",
+ azBool[p->showHeader!=0]);
if( p->mode==MODE_Column
|| (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
){
- oputf("%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
+ sqlite3_fprintf(p->out,
+ "%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
modeDescr[p->mode], p->cmOpts.iWrap,
p->cmOpts.bWordWrap ? "on" : "off",
p->cmOpts.bQuote ? "" : "no");
}else{
- oputf("%12.12s: %s\n","mode", modeDescr[p->mode]);
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
}
- oputf("%12.12s: ", "nullvalue");
- output_c_string(p->nullValue);
- oputz("\n");
- oputf("%12.12s: %s\n","output",
+ sqlite3_fprintf(p->out, "%12.12s: ", "nullvalue");
+ output_c_string(p->out, p->nullValue);
+ sqlite3_fputs("\n", p->out);
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","output",
strlen30(p->outfile) ? p->outfile : "stdout");
- oputf("%12.12s: ", "colseparator");
- output_c_string(p->colSeparator);
- oputz("\n");
- oputf("%12.12s: ", "rowseparator");
- output_c_string(p->rowSeparator);
- oputz("\n");
+ sqlite3_fprintf(p->out, "%12.12s: ", "colseparator");
+ output_c_string(p->out, p->colSeparator);
+ sqlite3_fputs("\n", p->out);
+ sqlite3_fprintf(p->out, "%12.12s: ", "rowseparator");
+ output_c_string(p->out, p->rowSeparator);
+ sqlite3_fputs("\n", p->out);
switch( p->statsOn ){
case 0: zOut = "off"; break;
default: zOut = "on"; break;
case 2: zOut = "stmt"; break;
case 3: zOut = "vmstep"; break;
}
- oputf("%12.12s: %s\n","stats", zOut);
- oputf("%12.12s: ", "width");
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","stats", zOut);
+ sqlite3_fprintf(p->out, "%12.12s: ", "width");
for (i=0;i<p->nWidth;i++) {
- oputf("%d ", p->colWidth[i]);
+ sqlite3_fprintf(p->out, "%d ", p->colWidth[i]);
}
- oputz("\n");
- oputf("%12.12s: %s\n", "filename",
+ sqlite3_fputs("\n", p->out);
+ sqlite3_fprintf(p->out, "%12.12s: %s\n", "filename",
p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : "");
}else
@@ -10809,7 +11497,7 @@ static int do_meta_command(char *zLine, ShellState *p){
appendText(&s, ".sqlite_schema ", 0);
if( c=='t' ){
appendText(&s," WHERE type IN ('table','view')"
- " AND name NOT LIKE 'sqlite_%'"
+ " AND name NOT LIKE 'sqlite__%' ESCAPE '_'"
" AND name LIKE ?1", 0);
}else{
appendText(&s," WHERE type='index'"
@@ -10865,9 +11553,10 @@ static int do_meta_command(char *zLine, ShellState *p){
for(i=0; i<nPrintRow; i++){
for(j=i; j<nRow; j+=nPrintRow){
char *zSp = j<nPrintRow ? "" : " ";
- oputf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
+ sqlite3_fprintf(p->out,
+ "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}
}
@@ -10879,7 +11568,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* Begin redirecting output to the file "testcase-out.txt" */
if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
output_reset(p);
- p->out = output_file_open("testcase-out.txt", 0);
+ p->out = output_file_open("testcase-out.txt");
if( p->out==0 ){
eputz("Error: cannot open 'testcase-out.txt'\n");
}
@@ -10902,7 +11591,7 @@ static int do_meta_command(char *zLine, ShellState *p){
{"always", SQLITE_TESTCTRL_ALWAYS, 1, "BOOLEAN" },
{"assert", SQLITE_TESTCTRL_ASSERT, 1, "BOOLEAN" },
/*{"benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,1, "" },*/
- /*{"bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/
+ {"bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "SIZE INT-ARRAY"},
{"byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" },
{"extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" },
{"fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"args..." },
@@ -10912,7 +11601,7 @@ static int do_meta_command(char *zLine, ShellState *p){
{"json_selfcheck", SQLITE_TESTCTRL_JSON_SELFCHECK ,0,"BOOLEAN" },
{"localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" },
{"never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" },
- {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" },
+ {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK ..."},
#ifdef YYCOVERAGE
{"parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" },
#endif
@@ -10923,7 +11612,6 @@ static int do_meta_command(char *zLine, ShellState *p){
{"seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" },
{"sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" },
{"tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" },
- {"uselongdouble", SQLITE_TESTCTRL_USELONGDOUBLE,0,"?BOOLEAN|\"default\"?"},
};
int testctrl = -1;
int iCtrl = -1;
@@ -10943,10 +11631,10 @@ static int do_meta_command(char *zLine, ShellState *p){
/* --help lists all test-controls */
if( cli_strcmp(zCmd,"help")==0 ){
- oputz("Available test-controls:\n");
+ sqlite3_fputs("Available test-controls:\n", p->out);
for(i=0; i<ArraySize(aCtrl); i++){
if( aCtrl[i].unSafe && !ShellHasFlag(p,SHFLG_TestingMode) ) continue;
- oputf(" .testctrl %s %s\n",
+ sqlite3_fprintf(p->out, " .testctrl %s %s\n",
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
}
rc = 1;
@@ -10963,7 +11651,7 @@ static int do_meta_command(char *zLine, ShellState *p){
testctrl = aCtrl[i].ctrlCode;
iCtrl = i;
}else{
- eputf("Error: ambiguous test-control: \"%s\"\n"
+ sqlite3_fprintf(stderr,"Error: ambiguous test-control: \"%s\"\n"
"Use \".testctrl --help\" for help\n", zCmd);
rc = 1;
goto meta_command_exit;
@@ -10971,13 +11659,131 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( testctrl<0 ){
- eputf("Error: unknown test-control: %s\n"
+ sqlite3_fprintf(stderr,"Error: unknown test-control: %s\n"
"Use \".testctrl --help\" for help\n", zCmd);
}else{
switch(testctrl){
+ /* Special processing for .testctrl opt MASK ...
+ ** Each MASK argument can be one of:
+ **
+ ** +LABEL Enable the named optimization
+ **
+ ** -LABEL Disable the named optimization
+ **
+ ** INTEGER Mask of optimizations to disable
+ */
+ case SQLITE_TESTCTRL_OPTIMIZATIONS: {
+ static const struct {
+ unsigned int mask; /* Mask for this optimization */
+ unsigned int bDsply; /* Display this on output */
+ const char *zLabel; /* Name of optimization */
+ } aLabel[] = {
+ { 0x00000001, 1, "QueryFlattener" },
+ { 0x00000001, 0, "Flatten" },
+ { 0x00000002, 1, "WindowFunc" },
+ { 0x00000004, 1, "GroupByOrder" },
+ { 0x00000008, 1, "FactorOutConst" },
+ { 0x00000010, 1, "DistinctOpt" },
+ { 0x00000020, 1, "CoverIdxScan" },
+ { 0x00000040, 1, "OrderByIdxJoin" },
+ { 0x00000080, 1, "Transitive" },
+ { 0x00000100, 1, "OmitNoopJoin" },
+ { 0x00000200, 1, "CountOfView" },
+ { 0x00000400, 1, "CurosrHints" },
+ { 0x00000800, 1, "Stat4" },
+ { 0x00001000, 1, "PushDown" },
+ { 0x00002000, 1, "SimplifyJoin" },
+ { 0x00004000, 1, "SkipScan" },
+ { 0x00008000, 1, "PropagateConst" },
+ { 0x00010000, 1, "MinMaxOpt" },
+ { 0x00020000, 1, "SeekScan" },
+ { 0x00040000, 1, "OmitOrderBy" },
+ { 0x00080000, 1, "BloomFilter" },
+ { 0x00100000, 1, "BloomPulldown" },
+ { 0x00200000, 1, "BalancedMerge" },
+ { 0x00400000, 1, "ReleaseReg" },
+ { 0x00800000, 1, "FlttnUnionAll" },
+ { 0x01000000, 1, "IndexedEXpr" },
+ { 0x02000000, 1, "Coroutines" },
+ { 0x04000000, 1, "NullUnusedCols" },
+ { 0x08000000, 1, "OnePass" },
+ { 0x10000000, 1, "OrderBySubq" },
+ { 0x20000000, 1, "StarQuery" },
+ { 0xffffffff, 0, "All" },
+ };
+ unsigned int curOpt;
+ unsigned int newOpt;
+ unsigned int m;
+ int ii;
+ int nOff;
+ sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, p->db, &curOpt);
+ newOpt = curOpt;
+ for(ii=2; ii<nArg; ii++){
+ const char *z = azArg[ii];
+ int useLabel = 0;
+ const char *zLabel = 0;
+ if( (z[0]=='+'|| z[0]=='-') && !IsDigit(z[1]) ){
+ useLabel = z[0];
+ zLabel = &z[1];
+ }else if( !IsDigit(z[0]) && z[0]!=0 && !IsDigit(z[1]) ){
+ useLabel = '+';
+ zLabel = z;
+ }else{
+ newOpt = (unsigned int)strtol(z,0,0);
+ }
+ if( useLabel ){
+ int jj;
+ for(jj=0; jj<ArraySize(aLabel); jj++){
+ if( sqlite3_stricmp(zLabel, aLabel[jj].zLabel)==0 ) break;
+ }
+ if( jj>=ArraySize(aLabel) ){
+ sqlite3_fprintf(stderr,
+ "Error: no such optimization: \"%s\"\n", zLabel);
+ sqlite3_fputs("Should be one of:", stderr);
+ for(jj=0; jj<ArraySize(aLabel); jj++){
+ sqlite3_fprintf(stderr," %s", aLabel[jj].zLabel);
+ }
+ sqlite3_fputs("\n", stderr);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( useLabel=='+' ){
+ newOpt &= ~aLabel[jj].mask;
+ }else{
+ newOpt |= aLabel[jj].mask;
+ }
+ }
+ }
+ if( curOpt!=newOpt ){
+ sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,p->db,newOpt);
+ }
+ for(ii=nOff=0, m=1; ii<32; ii++, m <<= 1){
+ if( m & newOpt ) nOff++;
+ }
+ if( nOff<12 ){
+ sqlite3_fputs("+All", p->out);
+ for(ii=0; ii<ArraySize(aLabel); ii++){
+ if( !aLabel[ii].bDsply ) continue;
+ if( (newOpt & aLabel[ii].mask)!=0 ){
+ sqlite3_fprintf(p->out, " -%s", aLabel[ii].zLabel);
+ }
+ }
+ }else{
+ sqlite3_fputs("-All", p->out);
+ for(ii=0; ii<ArraySize(aLabel); ii++){
+ if( !aLabel[ii].bDsply ) continue;
+ if( (newOpt & aLabel[ii].mask)==0 ){
+ sqlite3_fprintf(p->out, " +%s", aLabel[ii].zLabel);
+ }
+ }
+ }
+ sqlite3_fputs("\n", p->out);
+ rc2 = isOk = 3;
+ break;
+ }
+
/* sqlite3_test_control(int, db, int) */
- case SQLITE_TESTCTRL_OPTIMIZATIONS:
case SQLITE_TESTCTRL_FK_NO_ACTION:
if( nArg==3 ){
unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0);
@@ -11012,7 +11818,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3 *db;
if( ii==0 && cli_strcmp(azArg[2],"random")==0 ){
sqlite3_randomness(sizeof(ii),&ii);
- sputf(stdout, "-- random seed: %d\n", ii);
+ sqlite3_fprintf(stdout, "-- random seed: %d\n", ii);
}
if( nArg==3 ){
db = 0;
@@ -11046,21 +11852,6 @@ static int do_meta_command(char *zLine, ShellState *p){
}
break;
- /* sqlite3_test_control(int, int) */
- case SQLITE_TESTCTRL_USELONGDOUBLE: {
- int opt = -1;
- if( nArg==3 ){
- if( cli_strcmp(azArg[2],"default")==0 ){
- opt = 2;
- }else{
- opt = booleanValue(azArg[2]);
- }
- }
- rc2 = sqlite3_test_control(testctrl, opt);
- isOk = 1;
- break;
- }
-
/* sqlite3_test_control(sqlite3*) */
case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
rc2 = sqlite3_test_control(testctrl, p->db);
@@ -11080,7 +11871,7 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_TESTCTRL_SEEK_COUNT: {
u64 x = 0;
rc2 = sqlite3_test_control(testctrl, p->db, &x);
- oputf("%llu\n", x);
+ sqlite3_fprintf(p->out, "%llu\n", x);
isOk = 3;
break;
}
@@ -11111,11 +11902,11 @@ static int do_meta_command(char *zLine, ShellState *p){
int val = 0;
rc2 = sqlite3_test_control(testctrl, -id, &val);
if( rc2!=SQLITE_OK ) break;
- if( id>1 ) oputz(" ");
- oputf("%d: %d", id, val);
+ if( id>1 ) sqlite3_fputs(" ", p->out);
+ sqlite3_fprintf(p->out, "%d: %d", id, val);
id++;
}
- if( id>1 ) oputz("\n");
+ if( id>1 ) sqlite3_fputs("\n", p->out);
isOk = 3;
}
break;
@@ -11138,6 +11929,49 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_test_control(testctrl, &rc2);
break;
+ case SQLITE_TESTCTRL_BITVEC_TEST: {
+ /* Examples:
+ ** .testctrl bitvec_test 100 6,1 -- Show BITVEC constants
+ ** .testctrl bitvec_test 1000 1,12,7,3 -- Simple test
+ ** ---- --------
+ ** size of Bitvec -----^ ^--- aOp array. 0 added at end.
+ **
+ ** See comments on sqlite3BitvecBuiltinTest() for more information
+ ** about the aOp[] array.
+ */
+ int iSize;
+ const char *zTestArg;
+ int nOp;
+ int ii, jj, x;
+ int *aOp;
+ if( nArg!=4 ){
+ sqlite3_fprintf(stderr,
+ "ERROR - should be: \".testctrl bitvec_test SIZE INT-ARRAY\"\n"
+ );
+ rc = 1;
+ goto meta_command_exit;
+ }
+ isOk = 3;
+ iSize = (int)integerValue(azArg[2]);
+ zTestArg = azArg[3];
+ nOp = (int)strlen(zTestArg)+1;
+ aOp = malloc( sizeof(int)*(nOp+1) );
+ shell_check_oom(aOp);
+ memset(aOp, 0, sizeof(int)*(nOp+1) );
+ for(ii = jj = x = 0; zTestArg[ii]!=0; ii++){
+ if( IsDigit(zTestArg[ii]) ){
+ x = x*10 + zTestArg[ii] - '0';
+ }else{
+ aOp[jj++] = x;
+ x = 0;
+ }
+ }
+ aOp[jj] = x;
+ x = sqlite3_test_control(testctrl, iSize, aOp);
+ sqlite3_fprintf(p->out, "result: %d\n", x);
+ free(aOp);
+ break;
+ }
case SQLITE_TESTCTRL_FAULT_INSTALL: {
int kk;
int bShowHelp = nArg<=2;
@@ -11157,14 +11991,22 @@ static int do_meta_command(char *zLine, ShellState *p){
faultsim_state.nHit = 0;
sqlite3_test_control(testctrl, faultsim_callback);
}else if( cli_strcmp(z,"status")==0 ){
- oputf("faultsim.iId: %d\n", faultsim_state.iId);
- oputf("faultsim.iErr: %d\n", faultsim_state.iErr);
- oputf("faultsim.iCnt: %d\n", faultsim_state.iCnt);
- oputf("faultsim.nHit: %d\n", faultsim_state.nHit);
- oputf("faultsim.iInterval: %d\n", faultsim_state.iInterval);
- oputf("faultsim.eVerbose: %d\n", faultsim_state.eVerbose);
- oputf("faultsim.nRepeat: %d\n", faultsim_state.nRepeat);
- oputf("faultsim.nSkip: %d\n", faultsim_state.nSkip);
+ sqlite3_fprintf(p->out, "faultsim.iId: %d\n",
+ faultsim_state.iId);
+ sqlite3_fprintf(p->out, "faultsim.iErr: %d\n",
+ faultsim_state.iErr);
+ sqlite3_fprintf(p->out, "faultsim.iCnt: %d\n",
+ faultsim_state.iCnt);
+ sqlite3_fprintf(p->out, "faultsim.nHit: %d\n",
+ faultsim_state.nHit);
+ sqlite3_fprintf(p->out, "faultsim.iInterval: %d\n",
+ faultsim_state.iInterval);
+ sqlite3_fprintf(p->out, "faultsim.eVerbose: %d\n",
+ faultsim_state.eVerbose);
+ sqlite3_fprintf(p->out, "faultsim.nRepeat: %d\n",
+ faultsim_state.nRepeat);
+ sqlite3_fprintf(p->out, "faultsim.nSkip: %d\n",
+ faultsim_state.nSkip);
}else if( cli_strcmp(z,"-v")==0 ){
if( faultsim_state.eVerbose<2 ) faultsim_state.eVerbose++;
}else if( cli_strcmp(z,"-q")==0 ){
@@ -11182,7 +12024,8 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( cli_strcmp(z,"-?")==0 || sqlite3_strglob("*help*",z)==0){
bShowHelp = 1;
}else{
- eputf("Unrecognized fault_install argument: \"%s\"\n",
+ sqlite3_fprintf(stderr,
+ "Unrecognized fault_install argument: \"%s\"\n",
azArg[kk]);
rc = 1;
bShowHelp = 1;
@@ -11190,7 +12033,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( bShowHelp ){
- oputz(
+ sqlite3_fputs(
"Usage: .testctrl fault_install ARGS\n"
"Possible arguments:\n"
" off Disable faultsim\n"
@@ -11204,6 +12047,7 @@ static int do_meta_command(char *zLine, ShellState *p){
" --interval N Trigger only after every N-th call\n"
" --repeat N Turn off after N hits. 0 means never\n"
" --skip N Skip the first N encounters\n"
+ ,p->out
);
}
break;
@@ -11211,12 +12055,13 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( isOk==0 && iCtrl>=0 ){
- oputf("Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
+ sqlite3_fprintf(p->out,
+ "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
rc = 1;
}else if( isOk==1 ){
- oputf("%d\n", rc2);
+ sqlite3_fprintf(p->out, "%d\n", rc2);
}else if( isOk==2 ){
- oputf("0x%08x\n", rc2);
+ sqlite3_fprintf(p->out, "0x%08x\n", rc2);
}
}else
#endif /* !defined(SQLITE_UNTESTABLE) */
@@ -11271,13 +12116,13 @@ static int do_meta_command(char *zLine, ShellState *p){
mType |= SQLITE_TRACE_CLOSE;
}
else {
- eputf("Unknown option \"%s\" on \".trace\"\n", z);
+ sqlite3_fprintf(stderr,"Unknown option \"%s\" on \".trace\"\n", z);
rc = 1;
goto meta_command_exit;
}
}else{
output_file_close(p->traceOut);
- p->traceOut = output_file_open(z, 0);
+ p->traceOut = output_file_open(z);
}
}
if( p->traceOut==0 ){
@@ -11314,86 +12159,23 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif
-#if SQLITE_USER_AUTHENTICATION
- if( c=='u' && cli_strncmp(azArg[0], "user", n)==0 ){
- if( nArg<2 ){
- eputz("Usage: .user SUBCOMMAND ...\n");
- rc = 1;
- goto meta_command_exit;
- }
- open_db(p, 0);
- if( cli_strcmp(azArg[1],"login")==0 ){
- if( nArg!=4 ){
- eputz("Usage: .user login USER PASSWORD\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
- strlen30(azArg[3]));
- if( rc ){
- eputf("Authentication failed for user %s\n", azArg[2]);
- rc = 1;
- }
- }else if( cli_strcmp(azArg[1],"add")==0 ){
- if( nArg!=5 ){
- eputz("Usage: .user add USER PASSWORD ISADMIN\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
- booleanValue(azArg[4]));
- if( rc ){
- eputf("User-Add failed: %d\n", rc);
- rc = 1;
- }
- }else if( cli_strcmp(azArg[1],"edit")==0 ){
- if( nArg!=5 ){
- eputz("Usage: .user edit USER PASSWORD ISADMIN\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
- booleanValue(azArg[4]));
- if( rc ){
- eputf("User-Edit failed: %d\n", rc);
- rc = 1;
- }
- }else if( cli_strcmp(azArg[1],"delete")==0 ){
- if( nArg!=3 ){
- eputz("Usage: .user delete USER\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_delete(p->db, azArg[2]);
- if( rc ){
- eputf("User-Delete failed: %d\n", rc);
- rc = 1;
- }
- }else{
- eputz("Usage: .user login|add|edit|delete ...\n");
- rc = 1;
- goto meta_command_exit;
- }
- }else
-#endif /* SQLITE_USER_AUTHENTICATION */
-
if( c=='v' && cli_strncmp(azArg[0], "version", n)==0 ){
char *zPtrSz = sizeof(void*)==8 ? "64-bit" : "32-bit";
- oputf("SQLite %s %s\n" /*extra-version-info*/,
+ sqlite3_fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
sqlite3_libversion(), sqlite3_sourceid());
#if SQLITE_HAVE_ZLIB
- oputf("zlib version %s\n", zlibVersion());
+ sqlite3_fprintf(p->out, "zlib version %s\n", zlibVersion());
#endif
#define CTIMEOPT_VAL_(opt) #opt
#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
#if defined(__clang__) && defined(__clang_major__)
- oputf("clang-" CTIMEOPT_VAL(__clang_major__) "."
+ sqlite3_fprintf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
CTIMEOPT_VAL(__clang_minor__) "."
CTIMEOPT_VAL(__clang_patchlevel__) " (%s)\n", zPtrSz);
#elif defined(_MSC_VER)
- oputf("msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz);
+ sqlite3_fprintf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz);
#elif defined(__GNUC__) && defined(__VERSION__)
- oputf("gcc-" __VERSION__ " (%s)\n", zPtrSz);
+ sqlite3_fprintf(p->out, "gcc-" __VERSION__ " (%s)\n", zPtrSz);
#endif
}else
@@ -11403,10 +12185,10 @@ static int do_meta_command(char *zLine, ShellState *p){
if( p->db ){
sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
if( pVfs ){
- oputf("vfs.zName = \"%s\"\n", pVfs->zName);
- oputf("vfs.iVersion = %d\n", pVfs->iVersion);
- oputf("vfs.szOsFile = %d\n", pVfs->szOsFile);
- oputf("vfs.mxPathname = %d\n", pVfs->mxPathname);
+ sqlite3_fprintf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
+ sqlite3_fprintf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
+ sqlite3_fprintf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
+ sqlite3_fprintf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
}
}
}else
@@ -11418,13 +12200,13 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
}
for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
- oputf("vfs.zName = \"%s\"%s\n", pVfs->zName,
+ sqlite3_fprintf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
pVfs==pCurrent ? " <--- CURRENT" : "");
- oputf("vfs.iVersion = %d\n", pVfs->iVersion);
- oputf("vfs.szOsFile = %d\n", pVfs->szOsFile);
- oputf("vfs.mxPathname = %d\n", pVfs->mxPathname);
+ sqlite3_fprintf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
+ sqlite3_fprintf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
+ sqlite3_fprintf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
if( pVfs->pNext ){
- oputz("-----------------------------------\n");
+ sqlite3_fputs("-----------------------------------\n", p->out);
}
}
}else
@@ -11435,7 +12217,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( p->db ){
sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
if( zVfsName ){
- oputf("%s\n", zVfsName);
+ sqlite3_fprintf(p->out, "%s\n", zVfsName);
sqlite3_free(zVfsName);
}
}
@@ -11459,7 +12241,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
{
- eputf("Error: unknown command or invalid arguments: "
+ sqlite3_fprintf(stderr,"Error: unknown command or invalid arguments: "
" \"%s\". Enter \".help\" for help\n", azArg[0]);
rc = 1;
}
@@ -11500,7 +12282,6 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss,
char cWait = (char)qss; /* intentional narrowing loss */
if( cWait==0 ){
PlainScan:
- assert( cWait==0 );
while( (cin = *zLine++)!=0 ){
if( IsSpace(cin) )
continue;
@@ -11526,7 +12307,7 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss,
break;
case '[':
cin = ']';
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case '`': case '\'': case '"':
cWait = cin;
qss = QSS_HasDark | cWait;
@@ -11552,7 +12333,6 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss,
if( *zLine != '/' )
continue;
++zLine;
- cWait = 0;
CONTINUE_PROMPT_AWAITC(pst, 0);
qss = QSS_SETV(qss, 0);
goto PlainScan;
@@ -11562,9 +12342,8 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss,
++zLine;
continue;
}
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case ']':
- cWait = 0;
CONTINUE_PROMPT_AWAITC(pst, 0);
qss = QSS_SETV(qss, 0);
goto PlainScan;
@@ -11597,7 +12376,7 @@ static int line_is_command_terminator(char *zLine){
** out of the build if compiling with SQLITE_OMIT_COMPLETE.
*/
#ifdef SQLITE_OMIT_COMPLETE
-# error the CLI application is imcompatable with SQLITE_OMIT_COMPLETE.
+# error the CLI application is incompatible with SQLITE_OMIT_COMPLETE.
#endif
/*
@@ -11640,7 +12419,10 @@ static int doAutoDetectRestore(ShellState *p, const char *zSql){
case 0: {
const char *zExpect = "PRAGMA foreign_keys=OFF;";
assert( strlen(zExpect)==24 );
- if( p->bSafeMode==0 && memcmp(zSql, zExpect, 25)==0 ){
+ if( p->bSafeMode==0
+ && strlen(zSql)>=24
+ && memcmp(zSql, zExpect, 25)==0
+ ){
p->eRestoreState = 1;
}else{
p->eRestoreState = 7;
@@ -11708,7 +12490,7 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
BEGIN_TIMER;
rc = shell_exec(p, zSql, &zErrMsg);
- END_TIMER;
+ END_TIMER(p->out);
if( rc || zErrMsg ){
char zPrefix[100];
const char *zErrorTail;
@@ -11732,7 +12514,7 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
}else{
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType);
}
- eputf("%s %s\n", zPrefix, zErrorTail);
+ sqlite3_fprintf(stderr,"%s %s\n", zPrefix, zErrorTail);
sqlite3_free(zErrMsg);
zErrMsg = 0;
return 1;
@@ -11741,7 +12523,7 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
"changes: %lld total_changes: %lld",
sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
- oputf("%s\n", zLineBuf);
+ sqlite3_fprintf(p->out, "%s\n", zLineBuf);
}
if( doAutoDetectRestore(p, zSql) ) return 1;
@@ -11749,7 +12531,10 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
}
static void echo_group_input(ShellState *p, const char *zDo){
- if( ShellHasFlag(p, SHFLG_Echo) ) oputf("%s\n", zDo);
+ if( ShellHasFlag(p, SHFLG_Echo) ){
+ sqlite3_fprintf(p->out, "%s\n", zDo);
+ fflush(p->out);
+ }
}
#ifdef SQLITE_SHELL_FIDDLE
@@ -11770,7 +12555,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
if(!z || !*z){
return 0;
}
- while(*z && isspace(*z)) ++z;
+ while(*z && IsSpace(*z)) ++z;
zBegin = z;
for(; *z && '\n'!=*z; ++nZ, ++z){}
if(nZ>0 && '\r'==zBegin[nZ-1]){
@@ -11807,7 +12592,7 @@ static int process_input(ShellState *p){
if( p->inputNesting==MAX_INPUT_NESTING ){
/* This will be more informative in a later version. */
- eputf("Input nesting limit (%d) reached at line %d."
+ sqlite3_fprintf(stderr,"Input nesting limit (%d) reached at line %d."
" Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
return 1;
}
@@ -11819,7 +12604,7 @@ static int process_input(ShellState *p){
zLine = one_input_line(p->in, zLine, nSql>0);
if( zLine==0 ){
/* End of input */
- if( p->in==0 && stdin_is_interactive ) oputz("\n");
+ if( p->in==0 && stdin_is_interactive ) sqlite3_fputs("\n", p->out);
break;
}
if( seenInterrupt ){
@@ -12039,15 +12824,15 @@ static void process_sqliterc(
shell_check_oom(zBuf);
sqliterc = zBuf;
}
- p->in = fopen(sqliterc,"rb");
+ p->in = sqlite3_fopen(sqliterc,"rb");
if( p->in ){
if( stdin_is_interactive ){
- eputf("-- Loading resources from %s\n", sqliterc);
+ sqlite3_fprintf(stderr,"-- Loading resources from %s\n", sqliterc);
}
if( process_input(p) && bail_on_error ) exit(1);
fclose(p->in);
}else if( sqliterc_override!=0 ){
- eputf("cannot open: \"%s\"\n", sqliterc);
+ sqlite3_fprintf(stderr,"cannot open: \"%s\"\n", sqliterc);
if( bail_on_error ) exit(1);
}
p->in = inSaved;
@@ -12075,6 +12860,7 @@ static const char zOptions[] =
" -deserialize open the database using sqlite3_deserialize()\n"
#endif
" -echo print inputs before execution\n"
+ " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n"
" -init FILENAME read/process named file\n"
" -[no]header turn headers on or off\n"
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
@@ -12116,19 +12902,17 @@ static const char zOptions[] =
" -unsafe-testing allow unsafe commands and modes for testing\n"
" -version show SQLite version\n"
" -vfs NAME use NAME as the default VFS\n"
-#ifdef SQLITE_ENABLE_VFSTRACE
" -vfstrace enable tracing of all VFS calls\n"
-#endif
#ifdef SQLITE_HAVE_ZLIB
" -zip open the file as a ZIP Archive\n"
#endif
;
static void usage(int showDetail){
- eputf("Usage: %s [OPTIONS] [FILENAME [SQL]]\n"
+ sqlite3_fprintf(stderr,"Usage: %s [OPTIONS] [FILENAME [SQL...]]\n"
"FILENAME is the name of an SQLite database. A new database is created\n"
"if the file does not previously exist. Defaults to :memory:.\n", Argv0);
if( showDetail ){
- eputf("OPTIONS include:\n%s", zOptions);
+ sqlite3_fprintf(stderr,"OPTIONS include:\n%s", zOptions);
}else{
eputz("Use the -help option for additional information\n");
}
@@ -12153,6 +12937,9 @@ static void main_init(ShellState *data) {
memset(data, 0, sizeof(*data));
data->normalMode = data->cMode = data->mode = MODE_List;
data->autoExplain = 1;
+#ifdef _WIN32
+ data->crlfMode = 1;
+#endif
data->pAuxDb = &data->aAuxDb[0];
memcpy(data->colSeparator,SEP_Column, 2);
memcpy(data->rowSeparator,SEP_Row, 2);
@@ -12188,7 +12975,7 @@ static void printBold(const char *zText){
}
#else
static void printBold(const char *zText){
- sputf(stdout, "\033[1m%s\033[0m", zText);
+ sqlite3_fprintf(stdout, "\033[1m%s\033[0m", zText);
}
#endif
@@ -12198,7 +12985,8 @@ static void printBold(const char *zText){
*/
static char *cmdline_option_value(int argc, char **argv, int i){
if( i==argc ){
- eputf("%s: Error: missing argument to %s\n", argv[0], argv[argc-1]);
+ sqlite3_fprintf(stderr,
+ "%s: Error: missing argument to %s\n", argv[0], argv[argc-1]);
exit(1);
}
return argv[i];
@@ -12208,6 +12996,15 @@ static void sayAbnormalExit(void){
if( seenInterrupt ) eputz("Program interrupted.\n");
}
+/* Routine to output from vfstrace
+*/
+static int vfstraceOut(const char *z, void *pArg){
+ ShellState *p = (ShellState*)pArg;
+ sqlite3_fputs(z, p->out);
+ fflush(p->out);
+ return 1;
+}
+
#ifndef SQLITE_SHELL_IS_UTF8
# if (defined(_WIN32) || defined(WIN32)) \
&& (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
@@ -12235,7 +13032,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
# define data shellState
#else
ShellState data;
- StreamsAreConsole consStreams = SAC_NoConsole;
#endif
const char *zInitFile = 0;
int i;
@@ -12244,6 +13040,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
int readStdin = 1;
int nCmd = 0;
int nOptsEnd = argc;
+ int bEnableVfstrace = 0;
char **azCmd = 0;
const char *zVfs = 0; /* Value of -vfs command-line option */
#if !SQLITE_SHELL_IS_UTF8
@@ -12257,10 +13054,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
stdout_is_console = 1;
data.wasm.zDefaultDbName = "/fiddle.sqlite3";
#else
- consStreams = consoleClassifySetup(stdin, stdout, stderr);
- stdin_is_interactive = (consStreams & SAC_InConsole)!=0;
- stdout_is_console = (consStreams & SAC_OutConsole)!=0;
- atexit(consoleRestore);
+ stdin_is_interactive = isatty(0);
+ stdout_is_console = isatty(1);
#endif
atexit(sayAbnormalExit);
#ifdef SQLITE_DEBUG
@@ -12269,9 +13064,15 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#if !defined(_WIN32_WCE)
if( getenv("SQLITE_DEBUG_BREAK") ){
if( isatty(0) && isatty(2) ){
- eputf("attach debugger to process %d and press any key to continue.\n",
+ char zLine[100];
+ sqlite3_fprintf(stderr,
+ "attach debugger to process %d and press ENTER to continue...",
GETPID());
- fgetc(stdin);
+ if( sqlite3_fgets(zLine, sizeof(zLine), stdin)!=0
+ && cli_strcmp(zLine,"stop")==0
+ ){
+ exit(1);
+ }
}else{
#if defined(_WIN32) || defined(WIN32)
#if SQLITE_OS_WINRT
@@ -12296,7 +13097,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#if USE_SYSTEM_SQLITE+0!=1
if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
- eputf("SQLite header and source version mismatch\n%s\n%s\n",
+ sqlite3_fprintf(stderr,
+ "SQLite header and source version mismatch\n%s\n%s\n",
sqlite3_sourceid(), SQLITE_SOURCE_ID);
exit(1);
}
@@ -12438,17 +13240,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break;
default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break;
}
-#ifdef SQLITE_ENABLE_VFSTRACE
}else if( cli_strcmp(z,"-vfstrace")==0 ){
- extern int vfstrace_register(
- const char *zTraceName,
- const char *zOldVfsName,
- int (*xOut)(const char*,void*),
- void *pOutArg,
- int makeDefault
- );
- vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
-#endif
+ bEnableVfstrace = 1;
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( cli_strcmp(z,"-multiplex")==0 ){
extern int sqlite3_multiplex_initialize(const char*,int);
@@ -12501,10 +13294,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
ShellSetFlag(&data,SHFLG_TestingMode);
}else if( cli_strcmp(z,"-safe")==0 ){
/* no-op - catch this on the second pass */
+ }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){
+ /* skip over the argument */
+ i++;
}
}
#ifndef SQLITE_SHELL_FIDDLE
- verify_uninitialized();
+ if( !bEnableVfstrace ) verify_uninitialized();
#endif
@@ -12528,7 +13324,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
if( pVfs ){
sqlite3_vfs_register(pVfs, 1);
}else{
- eputf("no such VFS: \"%s\"\n", zVfs);
+ sqlite3_fprintf(stderr,"no such VFS: \"%s\"\n", zVfs);
exit(1);
}
}
@@ -12538,11 +13334,15 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
data.pAuxDb->zDbFilename = ":memory:";
warnInmemoryDb = argc==1;
#else
- eputf("%s: Error: no database filename specified\n", Argv0);
+ sqlite3_fprintf(stderr,
+ "%s: Error: no database filename specified\n", Argv0);
return 1;
#endif
}
data.out = stdout;
+ if( bEnableVfstrace ){
+ vfstrace_register("trace",0,vfstraceOut, &data, 1);
+ }
#ifndef SQLITE_SHELL_FIDDLE
sqlite3_appendvfs_init(0,0,0);
#endif
@@ -12596,6 +13396,25 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( cli_strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.colSeparator,",",2);
+ }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){
+ /* See similar code at tag-20250224-1 */
+ const char *zEsc = argv[++i];
+ int k;
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
+ if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){
+ data.eEscMode = k;
+ break;
+ }
+ }
+ if( k>=ArraySize(shell_EscModeNames) ){
+ sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\""
+ " - choices:", zEsc);
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
+ sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]);
+ }
+ sqlite3_fprintf(stderr, "\n");
+ exit(1);
+ }
#ifdef SQLITE_HAVE_ZLIB
}else if( cli_strcmp(z,"-zip")==0 ){
data.openMode = SHELL_OPEN_ZIPFILE;
@@ -12655,7 +13474,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( cli_strcmp(z,"-bail")==0 ){
/* No-op. The bail_on_error flag should already be set. */
}else if( cli_strcmp(z,"-version")==0 ){
- sputf(stdout, "%s %s (%d-bit)\n",
+ sqlite3_fprintf(stdout, "%s %s (%d-bit)\n",
sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*));
return 0;
}else if( cli_strcmp(z,"-interactive")==0 ){
@@ -12693,10 +13512,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( cli_strcmp(z,"-vfs")==0 ){
i++;
-#ifdef SQLITE_ENABLE_VFSTRACE
}else if( cli_strcmp(z,"-vfstrace")==0 ){
i++;
-#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( cli_strcmp(z,"-multiplex")==0 ){
i++;
@@ -12717,17 +13534,17 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
open_db(&data, 0);
rc = shell_exec(&data, z, &zErrMsg);
if( zErrMsg!=0 ){
- eputf("Error: %s\n", zErrMsg);
+ shellEmitError(zErrMsg);
if( bail_on_error ) return rc!=0 ? rc : 1;
}else if( rc!=0 ){
- eputf("Error: unable to process SQL \"%s\"\n", z);
+ sqlite3_fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
if( bail_on_error ) return rc;
}
}
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
}else if( cli_strncmp(z, "-A", 2)==0 ){
if( nCmd>0 ){
- eputf("Error: cannot mix regular SQL or dot-commands"
+ sqlite3_fprintf(stderr,"Error: cannot mix regular SQL or dot-commands"
" with \"%s\"\n", z);
return 1;
}
@@ -12746,7 +13563,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( cli_strcmp(z,"-unsafe-testing")==0 ){
/* Acted upon in first pass. */
}else{
- eputf("%s: Error: unknown option: %s\n", Argv0, z);
+ sqlite3_fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
eputz("Use -help for a list of options.\n");
return 1;
}
@@ -12759,6 +13576,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
** the database filename.
*/
for(i=0; i<nCmd; i++){
+ echo_group_input(&data, azCmd[i]);
if( azCmd[i][0]=='.' ){
rc = do_meta_command(azCmd[i], &data);
if( rc ){
@@ -12767,13 +13585,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}
}else{
open_db(&data, 0);
- echo_group_input(&data, azCmd[i]);
rc = shell_exec(&data, azCmd[i], &zErrMsg);
if( zErrMsg || rc ){
if( zErrMsg!=0 ){
- eputf("Error: %s\n", zErrMsg);
+ shellEmitError(zErrMsg);
}else{
- eputf("Error: unable to process SQL: %s\n", azCmd[i]);
+ sqlite3_fprintf(stderr,
+ "Error: unable to process SQL: %s\n", azCmd[i]);
}
sqlite3_free(zErrMsg);
if( rc==0 ) rc = 1;
@@ -12788,14 +13606,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
char *zHome;
char *zHistory;
int nHistory;
-#if CIO_WIN_WC_XLATE
-# define SHELL_CIO_CHAR_SET (stdout_is_console? " (UTF-16 console I/O)" : "")
-#else
-# define SHELL_CIO_CHAR_SET ""
-#endif
- sputf(stdout, "SQLite version %s %.19s%s\n" /*extra-version-info*/
+ sqlite3_fprintf(stdout,
+ "SQLite version %s %.19s\n" /*extra-version-info*/
"Enter \".help\" for usage hints.\n",
- sqlite3_libversion(), sqlite3_sourceid(), SHELL_CIO_CHAR_SET);
+ sqlite3_libversion(), sqlite3_sourceid());
if( warnInmemoryDb ){
sputz(stdout, "Connected to a ");
printBold("transient in-memory database");
@@ -12812,9 +13626,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}
}
if( zHistory ){ shell_read_history(zHistory); }
-#if HAVE_READLINE || HAVE_EDITLINE
+#if (HAVE_READLINE || HAVE_EDITLINE) && !defined(SQLITE_OMIT_READLINE_COMPLETION)
rl_attempted_completion_function = readline_completion;
-#elif HAVE_LINENOISE
+#elif HAVE_LINENOISE==1
+ linenoiseSetCompletionCallback(linenoise_completion);
+#elif HAVE_LINENOISE==2
linenoiseSetCompletionCallback(linenoise_completion, NULL);
#endif
data.in = 0;
@@ -12864,9 +13680,12 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
/* Clear the global data structure so that valgrind will detect memory
** leaks */
memset(&data, 0, sizeof(data));
+ if( bEnableVfstrace ){
+ vfstrace_unregister("trace");
+ }
#ifdef SQLITE_DEBUG
if( sqlite3_memory_used()>mem_main_enter ){
- eputf("Memory leaked: %u bytes\n",
+ sqlite3_fprintf(stderr,"Memory leaked: %u bytes\n",
(unsigned int)(sqlite3_memory_used()-mem_main_enter));
}
#endif
@@ -12906,7 +13725,7 @@ sqlite3_vfs * fiddle_db_vfs(const char *zDbName){
/* Only for emcc experimentation purposes. */
sqlite3 * fiddle_db_arg(sqlite3 *arg){
- oputf("fiddle_db_arg(%p)\n", (const void*)arg);
+ sqlite3_fprintf(stdout, "fiddle_db_arg(%p)\n", (const void*)arg);
return arg;
}
@@ -12943,7 +13762,7 @@ void fiddle_reset_db(void){
** Resolve problem reported in
** https://sqlite.org/forum/forumpost/0b41a25d65
*/
- oputz("Rolling back in-progress transaction.\n");
+ sqlite3_fputs("Rolling back in-progress transaction.\n", stdout);
sqlite3_exec(globalDb,"ROLLBACK", 0, 0, 0);
}
rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);