aboutsummaryrefslogtreecommitdiff
path: root/contrib/sqlite3/shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/sqlite3/shell.c')
-rw-r--r--contrib/sqlite3/shell.c1016
1 files changed, 688 insertions, 328 deletions
diff --git a/contrib/sqlite3/shell.c b/contrib/sqlite3/shell.c
index e6495d75128e..647a214226cc 100644
--- a/contrib/sqlite3/shell.c
+++ b/contrib/sqlite3/shell.c
@@ -117,6 +117,7 @@ typedef unsigned short int u16;
#include <string.h>
#include <stdio.h>
#include <assert.h>
+#include <math.h>
#include "sqlite3.h"
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
@@ -245,6 +246,7 @@ typedef unsigned char u8;
#if SQLITE_OS_WINRT
#include <intrin.h>
#endif
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/* string conversion routines only needed on Win32 */
@@ -459,11 +461,25 @@ static void endTimer(void){
static int bail_on_error = 0;
/*
-** Threat stdin as an interactive input if the following variable
+** Treat stdin as an interactive input if the following variable
** is true. Otherwise, assume stdin is connected to a file or pipe.
*/
static int stdin_is_interactive = 1;
+#if (defined(_WIN32) || defined(WIN32)) && SHELL_USE_LOCAL_GETLINE \
+ && !defined(SHELL_OMIT_WIN_UTF8)
+# define SHELL_WIN_UTF8_OPT 1
+#else
+# define SHELL_WIN_UTF8_OPT 0
+#endif
+
+#if SHELL_WIN_UTF8_OPT
+/*
+** Setup console for UTF-8 input/output when following variable true.
+*/
+static int console_utf8 = 0;
+#endif
+
/*
** On Windows systems we have to know if standard output is a console
** in order to translate UTF-8 into MBCS. The following variable is
@@ -596,16 +612,150 @@ static char *dynamicContinuePrompt(void){
}
#endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */
+#if SHELL_WIN_UTF8_OPT
+/* Following struct is used for -utf8 operation. */
+static struct ConsoleState {
+ int stdinEof; /* EOF has been seen on console input */
+ int infsMode; /* Input file stream mode upon shell start */
+ UINT inCodePage; /* Input code page upon shell start */
+ UINT outCodePage; /* Output code page upon shell start */
+ HANDLE hConsoleIn; /* Console input handle */
+ DWORD consoleMode; /* Console mode upon shell start */
+} conState = { 0, 0, 0, 0, INVALID_HANDLE_VALUE, 0 };
+
+#ifndef _O_U16TEXT /* For build environments lacking this constant: */
+# define _O_U16TEXT 0x20000
+#endif
+
+/*
+** Prepare console, (if known to be a WIN32 console), for UTF-8
+** input (from either typing or suitable paste operations) and for
+** UTF-8 rendering. This may "fail" with a message to stderr, where
+** the preparation is not done and common "code page" issues occur.
+*/
+static void console_prepare(void){
+ HANDLE hCI = GetStdHandle(STD_INPUT_HANDLE);
+ DWORD consoleMode = 0;
+ if( isatty(0) && GetFileType(hCI)==FILE_TYPE_CHAR
+ && GetConsoleMode( hCI, &consoleMode) ){
+ if( !IsValidCodePage(CP_UTF8) ){
+ fprintf(stderr, "Cannot use UTF-8 code page.\n");
+ console_utf8 = 0;
+ return;
+ }
+ conState.hConsoleIn = hCI;
+ conState.consoleMode = consoleMode;
+ conState.inCodePage = GetConsoleCP();
+ conState.outCodePage = GetConsoleOutputCP();
+ SetConsoleCP(CP_UTF8);
+ SetConsoleOutputCP(CP_UTF8);
+ consoleMode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
+ SetConsoleMode(conState.hConsoleIn, consoleMode);
+ conState.infsMode = _setmode(_fileno(stdin), _O_U16TEXT);
+ console_utf8 = 1;
+ }else{
+ console_utf8 = 0;
+ }
+}
+
+/*
+** Undo the effects of console_prepare(), if any.
+*/
+static void SQLITE_CDECL console_restore(void){
+ if( console_utf8 && conState.inCodePage!=0
+ && conState.hConsoleIn!=INVALID_HANDLE_VALUE ){
+ _setmode(_fileno(stdin), conState.infsMode);
+ SetConsoleCP(conState.inCodePage);
+ SetConsoleOutputCP(conState.outCodePage);
+ SetConsoleMode(conState.hConsoleIn, conState.consoleMode);
+ /* Avoid multiple calls. */
+ conState.hConsoleIn = INVALID_HANDLE_VALUE;
+ conState.consoleMode = 0;
+ console_utf8 = 0;
+ }
+}
+
+/*
+** Collect input like fgets(...) with special provisions for input
+** from the Windows console to get around its strange coding issues.
+** Defers to plain fgets() when input is not interactive or when the
+** startup option, -utf8, has not been provided or taken effect.
+*/
+static char* utf8_fgets(char *buf, int ncmax, FILE *fin){
+ if( fin==0 ) fin = stdin;
+ if( fin==stdin && stdin_is_interactive && console_utf8 ){
+# define SQLITE_IALIM 150
+ wchar_t wbuf[SQLITE_IALIM];
+ int lend = 0;
+ int noc = 0;
+ if( ncmax==0 || conState.stdinEof ) return 0;
+ buf[0] = 0;
+ while( noc<ncmax-7-1 && !lend ){
+ /* There is room for at least 2 more characters and a 0-terminator. */
+ int na = (ncmax > SQLITE_IALIM*4+1 + noc)
+ ? SQLITE_IALIM : (ncmax-1 - noc)/4;
+# undef SQLITE_IALIM
+ DWORD nbr = 0;
+ BOOL bRC = ReadConsoleW(conState.hConsoleIn, wbuf, na, &nbr, 0);
+ if( !bRC || (noc==0 && nbr==0) ) return 0;
+ if( nbr > 0 ){
+ int nmb = WideCharToMultiByte(CP_UTF8,WC_COMPOSITECHECK|WC_DEFAULTCHAR,
+ wbuf,nbr,0,0,0,0);
+ if( nmb !=0 && noc+nmb <= ncmax ){
+ int iseg = noc;
+ nmb = WideCharToMultiByte(CP_UTF8,WC_COMPOSITECHECK|WC_DEFAULTCHAR,
+ wbuf,nbr,buf+noc,nmb,0,0);
+ noc += nmb;
+ /* Fixup line-ends as coded by Windows for CR (or "Enter".)*/
+ if( noc > 0 ){
+ if( buf[noc-1]=='\n' ){
+ lend = 1;
+ if( noc > 1 && buf[noc-2]=='\r' ){
+ buf[noc-2] = '\n';
+ --noc;
+ }
+ }
+ }
+ /* Check for ^Z (anywhere in line) too. */
+ while( iseg < noc ){
+ if( buf[iseg]==0x1a ){
+ conState.stdinEof = 1;
+ noc = iseg; /* Chop ^Z and anything following. */
+ break;
+ }
+ ++iseg;
+ }
+ }else break; /* Drop apparent garbage in. (Could assert.) */
+ }else break;
+ }
+ /* If got nothing, (after ^Z chop), must be at end-of-file. */
+ if( noc == 0 ) return 0;
+ buf[noc] = 0;
+ return buf;
+ }else{
+ return fgets(buf, ncmax, fin);
+ }
+}
+
+# define fgets(b,n,f) utf8_fgets(b,n,f)
+#endif /* SHELL_WIN_UTF8_OPT */
+
/*
** Render output like fprintf(). Except, if the output is going to the
-** console and if this is running on a Windows machine, translate the
-** output from UTF-8 into MBCS.
+** console and if this is running on a Windows machine, and if the -utf8
+** option is unavailable or (available and inactive), translate the
+** output from UTF-8 into MBCS for output through 8-bit stdout stream.
+** (With -utf8 active, no translation is needed and must not be done.)
*/
#if defined(_WIN32) || defined(WIN32)
void utf8_printf(FILE *out, const char *zFormat, ...){
va_list ap;
va_start(ap, zFormat);
- if( stdout_is_console && (out==stdout || out==stderr) ){
+ if( stdout_is_console && (out==stdout || out==stderr)
+# if SHELL_WIN_UTF8_OPT
+ && !console_utf8
+# endif
+ ){
char *z1 = sqlite3_vmprintf(zFormat, ap);
char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
sqlite3_free(z1);
@@ -637,7 +787,7 @@ static void shell_out_of_memory(void){
/* Check a pointer to see if it is NULL. If it is NULL, exit with an
** out-of-memory error.
*/
-static void shell_check_oom(void *p){
+static void shell_check_oom(const void *p){
if( p==0 ) shell_out_of_memory();
}
@@ -816,9 +966,14 @@ static char *local_getline(char *zLine, FILE *in){
}
}
#if defined(_WIN32) || defined(WIN32)
- /* For interactive input on Windows systems, translate the
- ** multi-byte characterset characters into UTF-8. */
- if( stdin_is_interactive && in==stdin ){
+ /* For interactive input on Windows systems, without -utf8,
+ ** translate the multi-byte characterset characters into UTF-8.
+ ** This is the translation that predates the -utf8 option. */
+ if( stdin_is_interactive && in==stdin
+# if SHELL_WIN_UTF8_OPT
+ && !console_utf8
+# endif /* SHELL_WIN_UTF8_OPT */
+ ){
char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
if( zTrans ){
i64 nTrans = strlen(zTrans)+1;
@@ -859,10 +1014,21 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
#if SHELL_USE_LOCAL_GETLINE
printf("%s", zPrompt);
fflush(stdout);
- zResult = local_getline(zPrior, stdin);
+ do{
+ zResult = local_getline(zPrior, stdin);
+ zPrior = 0;
+ /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
+ if( zResult==0 ) sqlite3_sleep(50);
+ }while( zResult==0 && seenInterrupt>0 );
#else
free(zPrior);
zResult = shell_readline(zPrompt);
+ while( zResult==0 ){
+ /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
+ sqlite3_sleep(50);
+ if( seenInterrupt==0 ) break;
+ zResult = shell_readline("");
+ }
if( zResult && *zResult ) shell_add_history(zResult);
#endif
}
@@ -1002,6 +1168,7 @@ 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 '"';
for(i=0; zName[i]; i++){
if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
@@ -1645,7 +1812,8 @@ int sqlite3MemTraceDeactivate(void){
**
******************************************************************************
**
-** This SQLite extension implements functions that compute SHA3 hashes.
+** This SQLite extension implements functions that compute SHA3 hashes
+** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard.
** Two SQL functions are implemented:
**
** sha3(X,SIZE)
@@ -3173,6 +3341,7 @@ SQLITE_EXTENSION_INIT1;
#define U8_TYPEDEF
#endif
+/* Decoding table, ASCII (7-bit) value to base 64 digit value or other */
static const u8 b64DigitValues[128] = {
/* HT LF VT FF CR */
ND,ND,ND,ND, ND,ND,ND,ND, ND,WS,WS,WS, WS,WS,ND,ND,
@@ -3244,9 +3413,9 @@ static char* toBase64( u8 *pIn, int nbIn, char *pOut ){
}
/* Skip over text which is not base64 numeral(s). */
-static char * skipNonB64( char *s ){
+static char * skipNonB64( char *s, int nc ){
char c;
- while( (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s;
+ while( nc-- > 0 && (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s;
return s;
}
@@ -3255,7 +3424,7 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){
if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn;
while( ncIn>0 && *pIn!=PAD_CHAR ){
static signed char nboi[] = { 0, 0, 1, 2, 3 };
- char *pUse = skipNonB64(pIn);
+ char *pUse = skipNonB64(pIn, ncIn);
unsigned long qv = 0L;
int nti, nbo, nac;
ncIn -= (pUse - pIn);
@@ -3315,9 +3484,16 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_error(context, "blob expanded to base64 too big", -1);
return;
}
+ bBuf = (u8*)sqlite3_value_blob(av[0]);
+ if( !bBuf ){
+ if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){
+ goto memFail;
+ }
+ sqlite3_result_text(context,"",-1,SQLITE_STATIC);
+ break;
+ }
cBuf = sqlite3_malloc(nc);
if( !cBuf ) goto memFail;
- bBuf = (u8*)sqlite3_value_blob(av[0]);
nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf);
sqlite3_result_text(context, cBuf, nc, sqlite3_free);
break;
@@ -3330,9 +3506,16 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
}else if( nb<1 ){
nb = 1;
}
+ cBuf = (char *)sqlite3_value_text(av[0]);
+ if( !cBuf ){
+ if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){
+ goto memFail;
+ }
+ sqlite3_result_zeroblob(context, 0);
+ break;
+ }
bBuf = sqlite3_malloc(nb);
if( !bBuf ) goto memFail;
- cBuf = (char *)sqlite3_value_text(av[0]);
nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf);
sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
break;
@@ -3520,9 +3703,9 @@ static u8 base85DigitValue( char c ){
#define B85_DARK_MAX 80
-static char * skipNonB85( char *s ){
+static char * skipNonB85( char *s, int nc ){
char c;
- while( (c = *s) && !IS_B85(c) ) ++s;
+ while( nc-- > 0 && (c = *s) && !IS_B85(c) ) ++s;
return s;
}
@@ -3592,7 +3775,7 @@ static u8* fromBase85( char *pIn, int ncIn, u8 *pOut ){
if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn;
while( ncIn>0 ){
static signed char nboi[] = { 0, 0, 1, 2, 3, 4 };
- char *pUse = skipNonB85(pIn);
+ char *pUse = skipNonB85(pIn, ncIn);
unsigned long qv = 0L;
int nti, nbo;
ncIn -= (pUse - pIn);
@@ -3677,9 +3860,16 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_error(context, "blob expanded to base85 too big", -1);
return;
}
+ bBuf = (u8*)sqlite3_value_blob(av[0]);
+ if( !bBuf ){
+ if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){
+ goto memFail;
+ }
+ sqlite3_result_text(context,"",-1,SQLITE_STATIC);
+ break;
+ }
cBuf = sqlite3_malloc(nc);
if( !cBuf ) goto memFail;
- bBuf = (u8*)sqlite3_value_blob(av[0]);
nc = (int)(toBase85(bBuf, nb, cBuf, "\n") - cBuf);
sqlite3_result_text(context, cBuf, nc, sqlite3_free);
break;
@@ -3692,9 +3882,16 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
}else if( nb<1 ){
nb = 1;
}
+ cBuf = (char *)sqlite3_value_text(av[0]);
+ if( !cBuf ){
+ if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){
+ goto memFail;
+ }
+ sqlite3_result_zeroblob(context, 0);
+ break;
+ }
bBuf = sqlite3_malloc(nb);
if( !bBuf ) goto memFail;
- cBuf = (char *)sqlite3_value_text(av[0]);
nb = (int)(fromBase85(cBuf, nc, bBuf) - bBuf);
sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
break;
@@ -4114,7 +4311,7 @@ int sqlite3_ieee_init(
/************************* End ../ext/misc/ieee754.c ********************/
/************************* Begin ../ext/misc/series.c ******************/
/*
-** 2015-08-18
+** 2015-08-18, 2023-04-28
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -4127,7 +4324,19 @@ int sqlite3_ieee_init(
**
** This file demonstrates how to create a table-valued-function using
** a virtual table. This demo implements the generate_series() function
-** which gives similar results to the eponymous function in PostgreSQL.
+** which gives the same results as the eponymous function in PostgreSQL,
+** within the limitation that its arguments are signed 64-bit integers.
+**
+** Considering its equivalents to generate_series(start,stop,step): A
+** value V[n] sequence is produced for integer n ascending from 0 where
+** ( V[n] == start + n * step && sgn(V[n] - stop) * sgn(step) >= 0 )
+** for each produced value (independent of production time ordering.)
+**
+** All parameters must be either integer or convertable to integer.
+** The start parameter is required.
+** The stop parameter defaults to (1<<32)-1 (aka 4294967295 or 0xffffffff)
+** The step parameter defaults to 1 and 0 is treated as 1.
+**
** Examples:
**
** SELECT * FROM generate_series(0,100,5);
@@ -4143,6 +4352,14 @@ int sqlite3_ieee_init(
**
** Integers 20 through 29.
**
+** SELECT * FROM generate_series(0,-100,-5);
+**
+** Integers 0 -5 -10 ... -100.
+**
+** SELECT * FROM generate_series(0,-1);
+**
+** Empty sequence.
+**
** HOW IT WORKS
**
** The generate_series "function" is really a virtual table with the
@@ -4155,6 +4372,9 @@ int sqlite3_ieee_init(
** step HIDDEN
** );
**
+** The virtual table also has a rowid, logically equivalent to n+1 where
+** "n" is the ascending integer in the aforesaid production definition.
+**
** Function arguments in queries against this virtual table are translated
** into equality constraints against successive hidden columns. In other
** words, the following pairs of queries are equivalent to each other:
@@ -4187,9 +4407,126 @@ int sqlite3_ieee_init(
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
+#include <limits.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Return that member of a generate_series(...) sequence whose 0-based
+** index is ix. The 0th member is given by smBase. The sequence members
+** progress per ix increment by smStep.
+*/
+static sqlite3_int64 genSeqMember(sqlite3_int64 smBase,
+ sqlite3_int64 smStep,
+ sqlite3_uint64 ix){
+ if( ix>=(sqlite3_uint64)LLONG_MAX ){
+ /* Get ix into signed i64 range. */
+ ix -= (sqlite3_uint64)LLONG_MAX;
+ /* With 2's complement ALU, this next can be 1 step, but is split into
+ * 2 for UBSAN's satisfaction (and hypothetical 1's complement ALUs.) */
+ smBase += (LLONG_MAX/2) * smStep;
+ smBase += (LLONG_MAX - LLONG_MAX/2) * smStep;
+ }
+ /* Under UBSAN (or on 1's complement machines), must do this last term
+ * in steps to avoid the dreaded (and harmless) signed multiply overlow. */
+ if( ix>=2 ){
+ sqlite3_int64 ix2 = (sqlite3_int64)ix/2;
+ smBase += ix2*smStep;
+ ix -= ix2;
+ }
+ return smBase + ((sqlite3_int64)ix)*smStep;
+}
+
+/* typedef unsigned char u8; */
+
+typedef struct SequenceSpec {
+ sqlite3_int64 iBase; /* Starting value ("start") */
+ sqlite3_int64 iTerm; /* Given terminal value ("stop") */
+ sqlite3_int64 iStep; /* Increment ("step") */
+ sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */
+ sqlite3_uint64 uSeqIndexNow; /* Current index during generation */
+ sqlite3_int64 iValueNow; /* Current value during generation */
+ u8 isNotEOF; /* Sequence generation not exhausted */
+ u8 isReversing; /* Sequence is being reverse generated */
+} SequenceSpec;
+
+/*
+** Prepare a SequenceSpec for use in generating an integer series
+** given initialized iBase, iTerm and iStep values. Sequence is
+** initialized per given isReversing. Other members are computed.
+*/
+static void setupSequence( SequenceSpec *pss ){
+ int bSameSigns;
+ pss->uSeqIndexMax = 0;
+ pss->isNotEOF = 0;
+ bSameSigns = (pss->iBase < 0)==(pss->iTerm < 0);
+ if( pss->iTerm < pss->iBase ){
+ sqlite3_uint64 nuspan = 0;
+ if( bSameSigns ){
+ nuspan = (sqlite3_uint64)(pss->iBase - pss->iTerm);
+ }else{
+ /* Under UBSAN (or on 1's complement machines), must do this in steps.
+ * In this clause, iBase>=0 and iTerm<0 . */
+ nuspan = 1;
+ nuspan += pss->iBase;
+ nuspan += -(pss->iTerm+1);
+ }
+ if( pss->iStep<0 ){
+ pss->isNotEOF = 1;
+ if( nuspan==ULONG_MAX ){
+ pss->uSeqIndexMax = ( pss->iStep>LLONG_MIN )? nuspan/-pss->iStep : 1;
+ }else if( pss->iStep>LLONG_MIN ){
+ pss->uSeqIndexMax = nuspan/-pss->iStep;
+ }
+ }
+ }else if( pss->iTerm > pss->iBase ){
+ sqlite3_uint64 puspan = 0;
+ if( bSameSigns ){
+ puspan = (sqlite3_uint64)(pss->iTerm - pss->iBase);
+ }else{
+ /* Under UBSAN (or on 1's complement machines), must do this in steps.
+ * In this clause, iTerm>=0 and iBase<0 . */
+ puspan = 1;
+ puspan += pss->iTerm;
+ puspan += -(pss->iBase+1);
+ }
+ if( pss->iStep>0 ){
+ pss->isNotEOF = 1;
+ pss->uSeqIndexMax = puspan/pss->iStep;
+ }
+ }else if( pss->iTerm == pss->iBase ){
+ pss->isNotEOF = 1;
+ pss->uSeqIndexMax = 0;
+ }
+ pss->uSeqIndexNow = (pss->isReversing)? pss->uSeqIndexMax : 0;
+ pss->iValueNow = (pss->isReversing)
+ ? genSeqMember(pss->iBase, pss->iStep, pss->uSeqIndexMax)
+ : pss->iBase;
+}
+/*
+** Progress sequence generator to yield next value, if any.
+** Leave its state to either yield next value or be at EOF.
+** Return whether there is a next value, or 0 at EOF.
+*/
+static int progressSequence( SequenceSpec *pss ){
+ if( !pss->isNotEOF ) return 0;
+ if( pss->isReversing ){
+ if( pss->uSeqIndexNow > 0 ){
+ pss->uSeqIndexNow--;
+ pss->iValueNow -= pss->iStep;
+ }else{
+ pss->isNotEOF = 0;
+ }
+ }else{
+ if( pss->uSeqIndexNow < pss->uSeqIndexMax ){
+ pss->uSeqIndexNow++;
+ pss->iValueNow += pss->iStep;
+ }else{
+ pss->isNotEOF = 0;
+ }
+ }
+ return pss->isNotEOF;
+}
/* series_cursor is a subclass of sqlite3_vtab_cursor which will
** serve as the underlying representation of a cursor that scans
@@ -4198,12 +4535,7 @@ SQLITE_EXTENSION_INIT1
typedef struct series_cursor series_cursor;
struct series_cursor {
sqlite3_vtab_cursor base; /* Base class - must be first */
- int isDesc; /* True to count down rather than up */
- sqlite3_int64 iRowid; /* The rowid */
- sqlite3_int64 iValue; /* Current value ("value") */
- sqlite3_int64 mnValue; /* Mimimum value ("start") */
- sqlite3_int64 mxValue; /* Maximum value ("stop") */
- sqlite3_int64 iStep; /* Increment ("step") */
+ SequenceSpec ss; /* (this) Derived class data */
};
/*
@@ -4285,12 +4617,7 @@ static int seriesClose(sqlite3_vtab_cursor *cur){
*/
static int seriesNext(sqlite3_vtab_cursor *cur){
series_cursor *pCur = (series_cursor*)cur;
- if( pCur->isDesc ){
- pCur->iValue -= pCur->iStep;
- }else{
- pCur->iValue += pCur->iStep;
- }
- pCur->iRowid++;
+ progressSequence( & pCur->ss );
return SQLITE_OK;
}
@@ -4306,23 +4633,23 @@ static int seriesColumn(
series_cursor *pCur = (series_cursor*)cur;
sqlite3_int64 x = 0;
switch( i ){
- case SERIES_COLUMN_START: x = pCur->mnValue; break;
- case SERIES_COLUMN_STOP: x = pCur->mxValue; break;
- case SERIES_COLUMN_STEP: x = pCur->iStep; break;
- default: x = pCur->iValue; break;
+ case SERIES_COLUMN_START: x = pCur->ss.iBase; break;
+ case SERIES_COLUMN_STOP: x = pCur->ss.iTerm; break;
+ case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
+ default: x = pCur->ss.iValueNow; break;
}
sqlite3_result_int64(ctx, x);
return SQLITE_OK;
}
/*
-** Return the rowid for the current row. In this implementation, the
-** first row returned is assigned rowid value 1, and each subsequent
-** row a value 1 more than that of the previous.
+** Return the rowid for the current row, logically equivalent to n+1 where
+** "n" is the ascending integer in the aforesaid production definition.
*/
static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
series_cursor *pCur = (series_cursor*)cur;
- *pRowid = pCur->iRowid;
+ sqlite3_uint64 n = pCur->ss.uSeqIndexNow;
+ *pRowid = (sqlite3_int64)((n<0xffffffffffffffff)? n+1 : 0);
return SQLITE_OK;
}
@@ -4332,14 +4659,10 @@ static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
*/
static int seriesEof(sqlite3_vtab_cursor *cur){
series_cursor *pCur = (series_cursor*)cur;
- if( pCur->isDesc ){
- return pCur->iValue < pCur->mnValue;
- }else{
- return pCur->iValue > pCur->mxValue;
- }
+ return !pCur->ss.isNotEOF;
}
-/* True to cause run-time checking of the start=, stop=, and/or step=
+/* True to cause run-time checking of the start=, stop=, and/or step=
** parameters. The only reason to do this is for testing the
** constraint checking logic for virtual tables in the SQLite core.
*/
@@ -4350,7 +4673,7 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
/*
** This method is called to "rewind" the series_cursor object back
** to the first row of output. This method is always called at least
-** once prior to any call to seriesColumn() or seriesRowid() or
+** once prior to any call to seriesColumn() or seriesRowid() or
** seriesEof().
**
** The query plan selected by seriesBestIndex is passed in the idxNum
@@ -4370,7 +4693,7 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
** (so that seriesEof() will return true) if the table is empty.
*/
static int seriesFilter(
- sqlite3_vtab_cursor *pVtabCursor,
+ sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStrUnused,
int argc, sqlite3_value **argv
){
@@ -4378,46 +4701,41 @@ static int seriesFilter(
int i = 0;
(void)idxStrUnused;
if( idxNum & 1 ){
- pCur->mnValue = sqlite3_value_int64(argv[i++]);
+ pCur->ss.iBase = sqlite3_value_int64(argv[i++]);
}else{
- pCur->mnValue = 0;
+ pCur->ss.iBase = 0;
}
if( idxNum & 2 ){
- pCur->mxValue = sqlite3_value_int64(argv[i++]);
+ pCur->ss.iTerm = sqlite3_value_int64(argv[i++]);
}else{
- pCur->mxValue = 0xffffffff;
+ pCur->ss.iTerm = 0xffffffff;
}
if( idxNum & 4 ){
- pCur->iStep = sqlite3_value_int64(argv[i++]);
- if( pCur->iStep==0 ){
- pCur->iStep = 1;
- }else if( pCur->iStep<0 ){
- pCur->iStep = -pCur->iStep;
+ pCur->ss.iStep = sqlite3_value_int64(argv[i++]);
+ if( pCur->ss.iStep==0 ){
+ pCur->ss.iStep = 1;
+ }else if( pCur->ss.iStep<0 ){
if( (idxNum & 16)==0 ) idxNum |= 8;
}
}else{
- pCur->iStep = 1;
+ pCur->ss.iStep = 1;
}
for(i=0; i<argc; i++){
if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
/* If any of the constraints have a NULL value, then return no rows.
** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */
- pCur->mnValue = 1;
- pCur->mxValue = 0;
+ pCur->ss.iBase = 1;
+ pCur->ss.iTerm = 0;
+ pCur->ss.iStep = 1;
break;
}
}
if( idxNum & 8 ){
- pCur->isDesc = 1;
- pCur->iValue = pCur->mxValue;
- if( pCur->iStep>0 ){
- pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep;
- }
+ pCur->ss.isReversing = pCur->ss.iStep > 0;
}else{
- pCur->isDesc = 0;
- pCur->iValue = pCur->mnValue;
+ pCur->ss.isReversing = pCur->ss.iStep < 0;
}
- pCur->iRowid = 1;
+ setupSequence( &pCur->ss );
return SQLITE_OK;
}
@@ -5172,7 +5490,7 @@ static const char *re_subcompile_string(ReCompiled *p){
break;
}
case '[': {
- int iFirst = p->nState;
+ unsigned int iFirst = p->nState;
if( rePeek(p)=='^' ){
re_append(p, RE_OP_CC_EXC, 0);
p->sIn.i++;
@@ -5196,7 +5514,7 @@ static const char *re_subcompile_string(ReCompiled *p){
if( rePeek(p)==']' ){ p->sIn.i++; break; }
}
if( c==0 ) return "unclosed '['";
- p->aArg[iFirst] = p->nState - iFirst;
+ if( p->nState>iFirst ) p->aArg[iFirst] = p->nState - iFirst;
break;
}
case '\\': {
@@ -8773,7 +9091,10 @@ static int zipfileColumn(
** it to be a directory either if the mode suggests so, or if
** the final character in the name is '/'. */
u32 mode = pCDS->iExternalAttr >> 16;
- if( !(mode & S_IFDIR) && pCDS->zFile[pCDS->nFile-1]!='/' ){
+ if( !(mode & S_IFDIR)
+ && pCDS->nFile>=1
+ && pCDS->zFile[pCDS->nFile-1]!='/'
+ ){
sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC);
}
}
@@ -9210,9 +9531,19 @@ static u32 zipfileGetTime(sqlite3_value *pVal){
*/
static void zipfileRemoveEntryFromList(ZipfileTab *pTab, ZipfileEntry *pOld){
if( pOld ){
- ZipfileEntry **pp;
- for(pp=&pTab->pFirstEntry; (*pp)!=pOld; pp=&((*pp)->pNext));
- *pp = (*pp)->pNext;
+ if( pTab->pFirstEntry==pOld ){
+ pTab->pFirstEntry = pOld->pNext;
+ if( pTab->pLastEntry==pOld ) pTab->pLastEntry = 0;
+ }else{
+ ZipfileEntry *p;
+ for(p=pTab->pFirstEntry; p; p=p->pNext){
+ if( p->pNext==pOld ){
+ p->pNext = pOld->pNext;
+ if( pTab->pLastEntry==pOld ) pTab->pLastEntry = p;
+ break;
+ }
+ }
+ }
zipfileEntryFree(pOld);
}
}
@@ -12678,6 +13009,7 @@ static int dbdataConnect(
(void)argc;
(void)argv;
(void)pzErr;
+ sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS);
if( rc==SQLITE_OK ){
pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable));
if( pTab==0 ){
@@ -13323,8 +13655,6 @@ static int dbdataFilter(
}
if( rc==SQLITE_OK ){
rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT);
- }else{
- pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
}
/* Try to determine the encoding of the db by inspecting the header
@@ -13333,6 +13663,10 @@ static int dbdataFilter(
rc = dbdataGetEncoding(pCsr);
}
+ if( rc!=SQLITE_OK ){
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
+ }
+
if( rc==SQLITE_OK ){
rc = dbdataNext(pCursor);
}
@@ -14571,7 +14905,7 @@ static void recoverAddTable(
int iField = sqlite3_column_int(pStmt, 0);
int iCol = sqlite3_column_int(pStmt, 1);
- assert( iField<pNew->nCol && iCol<pNew->nCol );
+ assert( iCol<pNew->nCol );
pNew->aCol[iCol].iField = iField;
pNew->bIntkey = 0;
@@ -16335,7 +16669,7 @@ int sqlite3_recover_finish(sqlite3_recover *p){
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
/************************* End ../ext/recover/sqlite3recover.c ********************/
-# endif
+# endif /* SQLITE_HAVE_SQLITE3R */
#endif
#ifdef SQLITE_SHELL_EXTSRC
# include SHELL_STRINGIFY(SQLITE_SHELL_EXTSRC)
@@ -16517,6 +16851,7 @@ static ShellState shellState;
#define SHFLG_HeaderSet 0x00000080 /* showHeader has been specified */
#define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */
#define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */
+#define SHFLG_TestingMode 0x00000400 /* allow unsafe testing features */
/*
** Macros for testing and setting shellFlgs
@@ -16760,6 +17095,7 @@ static void editFunc(
}else{
/* If the file did not originally contain \r\n then convert any new
** \r\n back into \n */
+ p[sz] = 0;
for(i=j=0; i<sz; i++){
if( p[i]=='\r' && p[i+1]=='\n' ) i++;
p[j++] = p[i];
@@ -16850,6 +17186,7 @@ static void output_quoted_string(FILE *out, const char *z){
int i;
char c;
setBinaryMode(out, 1);
+ if( z==0 ) return;
for(i=0; (c = z[i])!=0 && c!='\''; i++){}
if( c==0 ){
utf8_printf(out,"'%s'",z);
@@ -16979,6 +17316,7 @@ static void output_c_string(FILE *out, const char *z){
*/
static void output_json_string(FILE *out, const char *z, i64 n){
unsigned int c;
+ if( z==0 ) z = "";
if( n<0 ) n = strlen(z);
fputc('"', out);
while( n-- ){
@@ -17103,8 +17441,7 @@ static void output_csv(ShellState *p, const char *z, int bSep){
*/
static void interrupt_handler(int NotUsed){
UNUSED_PARAMETER(NotUsed);
- seenInterrupt++;
- if( seenInterrupt>2 ) exit(1);
+ if( ++seenInterrupt>1 ) exit(1);
if( globalDb ) sqlite3_interrupt(globalDb);
}
@@ -17238,6 +17575,7 @@ static void printSchemaLine(FILE *out, const char *z, const char *zTail){
int i;
for(i=0; i<ArraySize(azTerm); i++){
char *zNew = sqlite3_mprintf("%s%s;", zOrig, azTerm[i]);
+ shell_check_oom(zNew);
if( sqlite3_complete(zNew) ){
size_t n = strlen(zNew);
zNew[n-1] = 0;
@@ -17672,9 +18010,9 @@ static int shell_callback(
sqlite3_uint64 ur;
memcpy(&ur,&r,sizeof(r));
if( ur==0x7ff0000000000000LL ){
- raw_printf(p->out, "1e999");
+ raw_printf(p->out, "9.0e+999");
}else if( ur==0xfff0000000000000LL ){
- raw_printf(p->out, "-1e999");
+ raw_printf(p->out, "-9.0e+999");
}else{
sqlite3_int64 ir = (sqlite3_int64)r;
if( r==(double)ir ){
@@ -17718,9 +18056,9 @@ static int shell_callback(
sqlite3_uint64 ur;
memcpy(&ur,&r,sizeof(r));
if( ur==0x7ff0000000000000LL ){
- raw_printf(p->out, "1e999");
+ raw_printf(p->out, "9.0e+999");
}else if( ur==0xfff0000000000000LL ){
- raw_printf(p->out, "-1e999");
+ raw_printf(p->out, "-9.0e+999");
}else{
sqlite3_snprintf(50,z,"%!.20g", r);
raw_printf(p->out, "%s", z);
@@ -17924,7 +18262,7 @@ static char *shell_error_context(const char *zSql, sqlite3 *db){
if( db==0
|| zSql==0
|| (iOffset = sqlite3_error_offset(db))<0
- || iOffset>=strlen(zSql)
+ || iOffset>=(int)strlen(zSql)
){
return sqlite3_mprintf("");
}
@@ -17936,7 +18274,7 @@ static char *shell_error_context(const char *zSql, sqlite3 *db){
len = strlen(zSql);
if( len>78 ){
len = 78;
- while( (zSql[len]&0xc0)==0x80 ) len--;
+ while( len>0 && (zSql[len]&0xc0)==0x80 ) len--;
}
zCode = sqlite3_mprintf("%.*s", len, zSql);
shell_check_oom(zCode);
@@ -18537,12 +18875,13 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
if( nVar==0 ) return; /* Nothing to do */
if( sqlite3_table_column_metadata(pArg->db, "TEMP", "sqlite_parameters",
"key", 0, 0, 0, 0, 0)!=SQLITE_OK ){
- return; /* Parameter table does not exist */
+ rc = SQLITE_NOTFOUND;
+ pQ = 0;
+ }else{
+ rc = sqlite3_prepare_v2(pArg->db,
+ "SELECT value FROM temp.sqlite_parameters"
+ " WHERE key=?1", -1, &pQ, 0);
}
- rc = sqlite3_prepare_v2(pArg->db,
- "SELECT value FROM temp.sqlite_parameters"
- " WHERE key=?1", -1, &pQ, 0);
- if( rc || pQ==0 ) return;
for(i=1; i<=nVar; i++){
char zNum[30];
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
@@ -18551,8 +18890,16 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
zVar = zNum;
}
sqlite3_bind_text(pQ, 1, zVar, -1, SQLITE_STATIC);
- if( sqlite3_step(pQ)==SQLITE_ROW ){
+ if( rc==SQLITE_OK && pQ && sqlite3_step(pQ)==SQLITE_ROW ){
sqlite3_bind_value(pStmt, i, sqlite3_column_value(pQ, 0));
+#ifdef NAN
+ }else if( sqlite3_strlike("_NAN", zVar, 0)==0 ){
+ sqlite3_bind_double(pStmt, i, NAN);
+#endif
+#ifdef INFINITY
+ }else if( sqlite3_strlike("_INF", zVar, 0)==0 ){
+ sqlite3_bind_double(pStmt, i, INFINITY);
+#endif
}else{
sqlite3_bind_null(pStmt, i);
}
@@ -18796,7 +19143,7 @@ static void exec_prepared_stmt_columnar(
azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
shell_check_oom(azData);
azNextLine = sqlite3_malloc64( nColumn*sizeof(char*) );
- shell_check_oom((void*)azNextLine);
+ shell_check_oom(azNextLine);
memset((void*)azNextLine, 0, nColumn*sizeof(char*) );
if( p->cmOpts.bQuote ){
azQuoted = sqlite3_malloc64( nColumn*sizeof(char*) );
@@ -18826,6 +19173,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);
}
do{
@@ -19759,13 +20107,13 @@ static const char *(azHelp[]) = {
" input text.",
#endif
#ifndef SQLITE_OMIT_TEST_CONTROL
- ".imposter INDEX TABLE Create imposter table TABLE on index INDEX",
+ ",imposter INDEX TABLE Create imposter table TABLE on index INDEX",
#endif
".indexes ?TABLE? Show names of indexes",
" If TABLE is specified, only show indexes for",
" tables matching TABLE using the LIKE operator.",
#ifdef SQLITE_ENABLE_IOTRACE
- ".iotrace FILE Enable I/O diagnostic logging to FILE",
+ ",iotrace FILE Enable I/O diagnostic logging to FILE",
#endif
".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT",
".lint OPTIONS Report potential schema issues.",
@@ -19774,8 +20122,10 @@ static const char *(azHelp[]) = {
#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_FIDDLE)
".load FILE ?ENTRY? Load an extension library",
#endif
-#ifndef SQLITE_SHELL_FIDDLE
- ".log FILE|off Turn logging on or off. FILE can be stderr/stdout",
+#if !defined(SQLITE_SHELL_FIDDLE)
+ ".log FILE|on|off Turn logging on or off. FILE can be stderr/stdout",
+#else
+ ".log on|off Turn logging on or off.",
#endif
".mode MODE ?OPTIONS? Set output mode",
" MODE is one of:",
@@ -19872,7 +20222,7 @@ static const char *(azHelp[]) = {
" Options:",
" --indent Try to pretty-print the schema",
" --nosys Omit objects whose names start with \"sqlite_\"",
- ".selftest ?OPTIONS? Run tests defined in the SELFTEST table",
+ ",selftest ?OPTIONS? Run tests defined in the SELFTEST table",
" Options:",
" --init Create a new SELFTEST table",
" -v Verbose output",
@@ -19914,9 +20264,9 @@ static const char *(azHelp[]) = {
#endif
".tables ?TABLE? List names of tables matching LIKE pattern TABLE",
#ifndef SQLITE_SHELL_FIDDLE
- ".testcase NAME Begin redirecting output to 'testcase-out.txt'",
+ ",testcase NAME Begin redirecting output to 'testcase-out.txt'",
#endif
- ".testctrl CMD ... Run various sqlite3_test_control() operations",
+ ",testctrl CMD ... Run various sqlite3_test_control() operations",
" Run \".testctrl\" with no arguments for details",
".timeout MS Try opening locked tables for MS milliseconds",
".timer on|off Turn SQL timer on or off",
@@ -19968,16 +20318,41 @@ static int showHelp(FILE *out, const char *zPattern){
|| cli_strcmp(zPattern,"-all")==0
|| cli_strcmp(zPattern,"--all")==0
){
- /* Show all commands, but only one line per command */
- if( zPattern==0 ) zPattern = "";
+ 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++){
- if( azHelp[i][0]=='.' || zPattern[0] ){
- utf8_printf(out, "%s\n", azHelp[i]);
- n++;
+ 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 ){
+ utf8_printf(out, ".%s\n", azHelp[i]+1);
+ ++n;
+ }else if( (hw&HW_SummaryOnly)==0 ){
+ utf8_printf(out, "%s\n", azHelp[i]);
+ }
}
}
}else{
- /* Look for commands that for which zPattern is an exact prefix */
+ /* 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++){
@@ -19990,24 +20365,28 @@ static int showHelp(FILE *out, const char *zPattern){
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]!='.' ){
+ /* 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]==' ' ){
utf8_printf(out, "%s\n", azHelp[j]);
j++;
}
}
return n;
}
- /* Look for commands that contain zPattern anywhere. Show the complete
- ** text of all commands that match. */
+ /* 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 ){
utf8_printf(out, "%s\n", azHelp[j]);
- while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]!='.' ){
+ while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){
j++;
utf8_printf(out, "%s\n", azHelp[j]);
}
@@ -20043,16 +20422,27 @@ static char *readFile(const char *zName, int *pnByte){
long nIn;
size_t nRead;
char *pBuf;
+ int rc;
if( in==0 ) return 0;
- fseek(in, 0, SEEK_END);
+ rc = fseek(in, 0, SEEK_END);
+ if( rc!=0 ){
+ raw_printf(stderr, "Error: '%s' not seekable\n", zName);
+ fclose(in);
+ return 0;
+ }
nIn = ftell(in);
rewind(in);
pBuf = sqlite3_malloc64( nIn+1 );
- if( pBuf==0 ){ fclose(in); return 0; }
+ if( pBuf==0 ){
+ raw_printf(stderr, "Error: out of memory\n");
+ fclose(in);
+ return 0;
+ }
nRead = fread(pBuf, nIn, 1, in);
fclose(in);
if( nRead!=1 ){
sqlite3_free(pBuf);
+ raw_printf(stderr, "Error: cannot read '%s'\n", zName);
return 0;
}
pBuf[nIn] = 0;
@@ -20242,53 +20632,6 @@ readHexDb_error:
#endif /* SQLITE_OMIT_DESERIALIZE */
/*
-** Scalar function "shell_int32". The first argument to this function
-** must be a blob. The second a non-negative integer. This function
-** reads and returns a 32-bit big-endian integer from byte
-** offset (4*<arg2>) of the blob.
-*/
-static void shellInt32(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- const unsigned char *pBlob;
- int nBlob;
- int iInt;
-
- UNUSED_PARAMETER(argc);
- nBlob = sqlite3_value_bytes(argv[0]);
- pBlob = (const unsigned char*)sqlite3_value_blob(argv[0]);
- iInt = sqlite3_value_int(argv[1]);
-
- if( iInt>=0 && (iInt+1)*4<=nBlob ){
- const unsigned char *a = &pBlob[iInt*4];
- sqlite3_int64 iVal = ((sqlite3_int64)a[0]<<24)
- + ((sqlite3_int64)a[1]<<16)
- + ((sqlite3_int64)a[2]<< 8)
- + ((sqlite3_int64)a[3]<< 0);
- sqlite3_result_int64(context, iVal);
- }
-}
-
-/*
-** Scalar function "shell_idquote(X)" returns string X quoted as an identifier,
-** using "..." with internal double-quote characters doubled.
-*/
-static void shellIdQuote(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- const char *zName = (const char*)sqlite3_value_text(argv[0]);
- UNUSED_PARAMETER(argc);
- if( zName ){
- char *z = sqlite3_mprintf("\"%w\"", zName);
- sqlite3_result_text(context, z, -1, sqlite3_free);
- }
-}
-
-/*
** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X.
*/
static void shellUSleepFunc(
@@ -20302,97 +20645,6 @@ static void shellUSleepFunc(
sqlite3_result_int(context, sleep);
}
-/*
-** Scalar function "shell_escape_crnl" used by the .recover command.
-** The argument passed to this function is the output of built-in
-** function quote(). If the first character of the input is "'",
-** indicating that the value passed to quote() was a text value,
-** then this function searches the input for "\n" and "\r" characters
-** and adds a wrapper similar to the following:
-**
-** replace(replace(<input>, '\n', char(10), '\r', char(13));
-**
-** Or, if the first character of the input is not "'", then a copy
-** of the input is returned.
-*/
-static void shellEscapeCrnl(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- const char *zText = (const char*)sqlite3_value_text(argv[0]);
- UNUSED_PARAMETER(argc);
- if( zText && zText[0]=='\'' ){
- i64 nText = sqlite3_value_bytes(argv[0]);
- i64 i;
- char zBuf1[20];
- char zBuf2[20];
- const char *zNL = 0;
- const char *zCR = 0;
- i64 nCR = 0;
- i64 nNL = 0;
-
- for(i=0; zText[i]; i++){
- if( zNL==0 && zText[i]=='\n' ){
- zNL = unused_string(zText, "\\n", "\\012", zBuf1);
- nNL = strlen(zNL);
- }
- if( zCR==0 && zText[i]=='\r' ){
- zCR = unused_string(zText, "\\r", "\\015", zBuf2);
- nCR = strlen(zCR);
- }
- }
-
- if( zNL || zCR ){
- i64 iOut = 0;
- i64 nMax = (nNL > nCR) ? nNL : nCR;
- i64 nAlloc = nMax * nText + (nMax+64)*2;
- char *zOut = (char*)sqlite3_malloc64(nAlloc);
- if( zOut==0 ){
- sqlite3_result_error_nomem(context);
- return;
- }
-
- if( zNL && zCR ){
- memcpy(&zOut[iOut], "replace(replace(", 16);
- iOut += 16;
- }else{
- memcpy(&zOut[iOut], "replace(", 8);
- iOut += 8;
- }
- for(i=0; zText[i]; i++){
- if( zText[i]=='\n' ){
- memcpy(&zOut[iOut], zNL, nNL);
- iOut += nNL;
- }else if( zText[i]=='\r' ){
- memcpy(&zOut[iOut], zCR, nCR);
- iOut += nCR;
- }else{
- zOut[iOut] = zText[i];
- iOut++;
- }
- }
-
- if( zNL ){
- memcpy(&zOut[iOut], ",'", 2); iOut += 2;
- memcpy(&zOut[iOut], zNL, nNL); iOut += nNL;
- memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12;
- }
- if( zCR ){
- memcpy(&zOut[iOut], ",'", 2); iOut += 2;
- memcpy(&zOut[iOut], zCR, nCR); iOut += nCR;
- memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12;
- }
-
- sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT);
- sqlite3_free(zOut);
- return;
- }
- }
-
- sqlite3_result_value(context, argv[0]);
-}
-
/* Flags for open_db().
**
** The default behavior of open_db() is to exit(1) if the database fails to
@@ -20452,11 +20704,29 @@ static void open_db(ShellState *p, int openFlags){
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
zDbFilename, sqlite3_errmsg(p->db));
- if( openFlags & OPEN_DB_KEEPALIVE ){
- sqlite3_open(":memory:", &p->db);
- return;
+ if( (openFlags & OPEN_DB_KEEPALIVE)==0 ){
+ exit(1);
}
- exit(1);
+ sqlite3_close(p->db);
+ sqlite3_open(":memory:", &p->db);
+ if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
+ utf8_printf(stderr,
+ "Also: unable to open substitute in-memory database.\n"
+ );
+ exit(1);
+ }else{
+ utf8_printf(stderr,
+ "Notice: using substitute in-memory database instead of \"%s\"\n",
+ zDbFilename);
+ }
+ }
+ sqlite3_db_config(p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, (int)0, (int*)0);
+
+ /* Reflect the use or absence of --unsafe-testing invocation. */
+ {
+ int testmode_on = ShellHasFlag(p,SHFLG_TestingMode);
+ sqlite3_db_config(p->db, SQLITE_DBCONFIG_TRUSTED_SCHEMA, testmode_on,0);
+ sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, !testmode_on,0);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
@@ -20474,9 +20744,6 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_fileio_init(p->db, 0, 0);
sqlite3_completion_init(p->db, 0, 0);
#endif
-#if SQLITE_SHELL_HAVE_RECOVER
- sqlite3_dbdata_init(p->db, 0, 0);
-#endif
#ifdef SQLITE_HAVE_ZLIB
if( !p->bSafeModePersist ){
sqlite3_zipfile_init(p->db, 0, 0);
@@ -20517,12 +20784,6 @@ static void open_db(ShellState *p, int openFlags){
shellModuleSchema, 0, 0);
sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
shellPutsFunc, 0, 0);
- sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0,
- shellEscapeCrnl, 0, 0);
- sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0,
- shellInt32, 0, 0);
- sqlite3_create_function(p->db, "shell_idquote", 1, SQLITE_UTF8, 0,
- shellIdQuote, 0, 0);
sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0,
shellUSleepFunc, 0, 0);
#ifndef SQLITE_NOHAVE_SYSTEM
@@ -20549,9 +20810,9 @@ static void open_db(ShellState *p, int openFlags){
aData = (unsigned char*)readFile(zDbFilename, &nData);
}else{
aData = readHexDb(p, &nData);
- if( aData==0 ){
- return;
- }
+ }
+ if( aData==0 ){
+ return;
}
rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
SQLITE_DESERIALIZE_RESIZEABLE |
@@ -20565,8 +20826,13 @@ static void open_db(ShellState *p, int openFlags){
}
#endif
}
- if( p->bSafeModePersist && p->db!=0 ){
- sqlite3_set_authorizer(p->db, safeModeAuth, p);
+ if( p->db!=0 ){
+ if( p->bSafeModePersist ){
+ sqlite3_set_authorizer(p->db, safeModeAuth, p);
+ }
+ sqlite3_db_config(
+ p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, p->scanstatsOn, (int*)0
+ );
}
}
@@ -20665,6 +20931,7 @@ static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
** \' -> '
** \\ -> backslash
** \NNN -> ascii character NNN in octal
+** \xHH -> ascii character HH in hexadecimal
*/
static void resolve_backslashes(char *z){
int i, j;
@@ -20693,6 +20960,15 @@ static void resolve_backslashes(char *z){
c = '\'';
}else if( c=='\\' ){
c = '\\';
+ }else if( c=='x' ){
+ int nhd = 0, hdv;
+ u8 hv = 0;
+ while( nhd<2 && (c=z[i+1+nhd])!=0 && (hdv=hexDigitValue(c))>=0 ){
+ hv = (u8)((hv<<4)|hdv);
+ ++nhd;
+ }
+ i += nhd;
+ c = (u8)hv;
}else if( c>='0' && c<='7' ){
c -= '0';
if( z[i+1]>='0' && z[i+1]<='7' ){
@@ -20792,7 +21068,7 @@ static int sql_trace_callback(
utf8_printf(p->traceOut, "-- closing database connection\n");
return 0;
}
- if( mType!=SQLITE_TRACE_ROW && ((const char*)pX)[0]=='-' ){
+ if( mType!=SQLITE_TRACE_ROW && pX!=0 && ((const char*)pX)[0]=='-' ){
zSql = (const char*)pX;
}else{
pStmt = (sqlite3_stmt*)pP;
@@ -20824,7 +21100,7 @@ static int sql_trace_callback(
break;
}
case SQLITE_TRACE_PROFILE: {
- sqlite3_int64 nNanosec = *(sqlite3_int64*)pX;
+ sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0;
utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
break;
}
@@ -20900,8 +21176,8 @@ static void import_append_char(ImportCtx *p, int c){
*/
static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
int c;
- int cSep = p->cColSep;
- int rSep = p->cRowSep;
+ int cSep = (u8)p->cColSep;
+ int rSep = (u8)p->cRowSep;
p->n = 0;
c = fgetc(p->in);
if( c==EOF || seenInterrupt ){
@@ -20990,8 +21266,8 @@ static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
*/
static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
int c;
- int cSep = p->cColSep;
- int rSep = p->cRowSep;
+ int cSep = (u8)p->cColSep;
+ int rSep = (u8)p->cRowSep;
p->n = 0;
c = fgetc(p->in);
if( c==EOF || seenInterrupt ){
@@ -21185,7 +21461,7 @@ static void tryToCloneSchema(
zName = sqlite3_column_text(pQuery, 0);
zSql = sqlite3_column_text(pQuery, 1);
if( zName==0 || zSql==0 ) continue;
- if( sqlite3_stricmp((char*)zName, "sqlite_sequence")!=0 ) continue;
+ if( sqlite3_stricmp((char*)zName, "sqlite_sequence")==0 ) continue;
printf("%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
@@ -21289,7 +21565,7 @@ static int db_int(sqlite3 *db, const char *zSql){
return res;
}
-#if defined(SQLITE_SHELL_HAVE_RECOVER)
+#if SQLITE_SHELL_HAVE_RECOVER
/*
** Convert a 2-byte or 4-byte big-endian integer into a native integer
*/
@@ -21352,7 +21628,9 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
if( sqlite3_step(pStmt)==SQLITE_ROW
&& sqlite3_column_bytes(pStmt,0)>100
){
- memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
+ const u8 *pb = sqlite3_column_blob(pStmt,0);
+ shell_check_oom(pb);
+ memcpy(aHdr, pb, 100);
sqlite3_finalize(pStmt);
}else{
raw_printf(stderr, "unable to read database header\n");
@@ -22169,7 +22447,10 @@ static int arParseCommand(
}
}
}
-
+ if( pAr->eCmd==0 ){
+ utf8_printf(stderr, "Required argument missing. Usage:\n");
+ return arUsage(stderr);
+ }
return SQLITE_OK;
}
@@ -22935,7 +23216,7 @@ FROM (\
sqlite3_bind_int(pStmt, 1, nDigits);
rc = sqlite3_step(pStmt);
sqlite3_finalize(pStmt);
- assert(rc==SQLITE_DONE);
+ if( rc!=SQLITE_DONE ) rc_err_oom_die(SQLITE_NOMEM);
}
assert(db_int(*pDb, zHasDupes)==0); /* Consider: remove this */
rc = sqlite3_prepare_v2(*pDb, zCollectVar, -1, &pStmt, 0);
@@ -23185,7 +23466,6 @@ static int do_meta_command(char *zLine, ShellState *p){
raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
rc = 2;
}else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
- raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
rc = 2;
}else if( testcase_glob(azArg[1],zRes)==0 ){
utf8_printf(stderr,
@@ -23315,6 +23595,8 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
{ "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
{ "reset_database", SQLITE_DBCONFIG_RESET_DATABASE },
+ { "reverse_scanorder", SQLITE_DBCONFIG_REVERSE_SCANORDER },
+ { "stmt_scanstatus", SQLITE_DBCONFIG_STMT_SCANSTATUS },
{ "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
{ "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA },
{ "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
@@ -23866,8 +24148,8 @@ static int do_meta_command(char *zLine, ShellState *p){
" for import\n");
goto meta_command_exit;
}
- sCtx.cColSep = p->colSeparator[0];
- sCtx.cRowSep = p->rowSeparator[0];
+ sCtx.cColSep = (u8)p->colSeparator[0];
+ sCtx.cRowSep = (u8)p->rowSeparator[0];
}
sCtx.zFile = zFile;
sCtx.nLine = 1;
@@ -24063,6 +24345,12 @@ static int do_meta_command(char *zLine, ShellState *p){
int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */
int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
int i;
+ if( !ShellHasFlag(p,SHFLG_TestingMode) ){
+ utf8_printf(stderr, ".%s unavailable without --unsafe-testing\n",
+ "imposter");
+ rc = 1;
+ goto meta_command_exit;
+ }
if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n"
" .imposter off\n");
@@ -24247,7 +24535,8 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zFile, *zProc;
char *zErrMsg = 0;
failIfSafeMode(p, "cannot run .load in safe mode");
- if( nArg<2 ){
+ if( nArg<2 || azArg[1][0]==0 ){
+ /* Must have a non-empty FILE. (Will not load self.) */
raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
rc = 1;
goto meta_command_exit;
@@ -24264,19 +24553,25 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif
-#ifndef SQLITE_SHELL_FIDDLE
if( c=='l' && cli_strncmp(azArg[0], "log", n)==0 ){
- failIfSafeMode(p, "cannot run .log in safe mode");
if( nArg!=2 ){
raw_printf(stderr, "Usage: .log FILENAME\n");
rc = 1;
}else{
const char *zFile = azArg[1];
+ if( p->bSafeMode
+ && cli_strcmp(zFile,"on")!=0
+ && cli_strcmp(zFile,"off")!=0
+ ){
+ raw_printf(stdout, "cannot set .log to anything other "
+ "than \"on\" or \"off\"\n");
+ zFile = "off";
+ }
output_file_close(p->pLog);
+ if( cli_strcmp(zFile,"on")==0 ) zFile = "stdout";
p->pLog = output_file_open(zFile, 0);
}
}else
-#endif
if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
const char *zMode = 0;
@@ -24912,6 +25207,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{
p->scanstatsOn = (u8)booleanValue(azArg[1]);
}
+ open_db(p, 0);
+ sqlite3_db_config(
+ p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, p->scanstatsOn, (int*)0
+ );
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
#endif
@@ -25561,28 +25860,36 @@ static int do_meta_command(char *zLine, ShellState *p){
shell_check_oom(zRevText);
if( bDebug ) utf8_printf(p->out, "%s\n", zRevText);
lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0);
- assert(lrc==SQLITE_OK);
- if( zLike ) sqlite3_bind_text(pStmt,1,zLike,-1,SQLITE_STATIC);
- lrc = SQLITE_ROW==sqlite3_step(pStmt);
- if( lrc ){
- const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0);
- sqlite3_stmt *pCheckStmt;
- lrc = sqlite3_prepare_v2(p->db, zGenQuery, -1, &pCheckStmt, 0);
- if( bDebug ) utf8_printf(p->out, "%s\n", zGenQuery);
- if( SQLITE_OK==lrc ){
- if( SQLITE_ROW==sqlite3_step(pCheckStmt) ){
- double countIrreversible = sqlite3_column_double(pCheckStmt, 0);
- if( countIrreversible>0 ){
- int sz = (int)(countIrreversible + 0.5);
- utf8_printf(stderr,
- "Digest includes %d invalidly encoded text field%s.\n",
- sz, (sz>1)? "s": "");
+ if( lrc!=SQLITE_OK ){
+ /* assert(lrc==SQLITE_NOMEM); // might also be SQLITE_ERROR if the
+ ** user does cruel and unnatural things like ".limit expr_depth 0". */
+ rc = 1;
+ }else{
+ if( zLike ) sqlite3_bind_text(pStmt,1,zLike,-1,SQLITE_STATIC);
+ lrc = SQLITE_ROW==sqlite3_step(pStmt);
+ if( lrc ){
+ const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0);
+ sqlite3_stmt *pCheckStmt;
+ lrc = sqlite3_prepare_v2(p->db, zGenQuery, -1, &pCheckStmt, 0);
+ if( bDebug ) utf8_printf(p->out, "%s\n", zGenQuery);
+ if( lrc!=SQLITE_OK ){
+ rc = 1;
+ }else{
+ if( SQLITE_ROW==sqlite3_step(pCheckStmt) ){
+ double countIrreversible = sqlite3_column_double(pCheckStmt, 0);
+ if( countIrreversible>0 ){
+ int sz = (int)(countIrreversible + 0.5);
+ utf8_printf(stderr,
+ "Digest includes %d invalidly encoded text field%s.\n",
+ sz, (sz>1)? "s": "");
+ }
}
+ sqlite3_finalize(pCheckStmt);
}
- sqlite3_finalize(pCheckStmt);
+ sqlite3_finalize(pStmt);
}
- sqlite3_finalize(pStmt);
}
+ if( rc ) utf8_printf(stderr, ".sha3sum failed.\n");
sqlite3_free(zRevText);
}
#endif /* !defined(*_OMIT_SCHEMA_PRAGMAS) && !defined(*_OMIT_VIRTUALTABLE) */
@@ -25845,6 +26152,12 @@ static int do_meta_command(char *zLine, ShellState *p){
int i, n2;
const char *zCmd = 0;
+ if( !ShellHasFlag(p,SHFLG_TestingMode) ){
+ utf8_printf(stderr, ".%s unavailable without --unsafe-testing\n",
+ "testctrl");
+ rc = 1;
+ goto meta_command_exit;
+ }
open_db(p, 0);
zCmd = nArg>=2 ? azArg[1] : "help";
@@ -26792,6 +27105,7 @@ static void process_sqliterc(
** Show available command line options
*/
static const char zOptions[] =
+ " -- treat no subsequent arguments as options\n"
#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
" -A ARGS... run \".archive ARGS\" and exit\n"
#endif
@@ -26843,6 +27157,10 @@ static const char zOptions[] =
" -stats print memory stats before each finalize\n"
" -table set output mode to 'table'\n"
" -tabs set output mode to 'tabs'\n"
+ " -unsafe-testing allow unsafe commands and modes for testing\n"
+#if SHELL_WIN_UTF8_OPT
+ " -utf8 setup interactive console code page for UTF-8\n"
+#endif
" -version show SQLite version\n"
" -vfs NAME use NAME as the default VFS\n"
#ifdef SQLITE_ENABLE_VFSTRACE
@@ -26854,9 +27172,9 @@ static const char zOptions[] =
;
static void usage(int showDetail){
utf8_printf(stderr,
- "Usage: %s [OPTIONS] FILENAME [SQL]\n"
+ "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.\n", Argv0);
+ "if the file does not previously exist. Defaults to :memory:.\n", Argv0);
if( showDetail ){
utf8_printf(stderr, "OPTIONS include:\n%s", zOptions);
}else{
@@ -26888,9 +27206,11 @@ static void main_init(ShellState *data) {
memcpy(data->rowSeparator,SEP_Row, 2);
data->showHeader = 0;
data->shellFlgs = SHFLG_Lookaside;
+ sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
+#if !defined(SQLITE_SHELL_FIDDLE)
verify_uninitialized();
+#endif
sqlite3_config(SQLITE_CONFIG_URI, 1);
- sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
@@ -26933,6 +27253,10 @@ static char *cmdline_option_value(int argc, char **argv, int i){
return argv[i];
}
+static void sayAbnormalExit(void){
+ if( seenInterrupt ) fprintf(stderr, "Program interrupted.\n");
+}
+
#ifndef SQLITE_SHELL_IS_UTF8
# if (defined(_WIN32) || defined(WIN32)) \
&& (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
@@ -26953,7 +27277,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
char **argv;
#endif
#ifdef SQLITE_DEBUG
- sqlite3_int64 mem_main_enter = sqlite3_memory_used();
+ sqlite3_int64 mem_main_enter = 0;
#endif
char *zErrMsg = 0;
#ifdef SQLITE_SHELL_FIDDLE
@@ -26967,15 +27291,15 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
int warnInmemoryDb = 0;
int readStdin = 1;
int nCmd = 0;
+ int nOptsEnd = argc;
char **azCmd = 0;
const char *zVfs = 0; /* Value of -vfs command-line option */
#if !SQLITE_SHELL_IS_UTF8
char **argvToFree = 0;
int argcToFree = 0;
#endif
-
- setBinaryMode(stdin, 0);
setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
+
#ifdef SQLITE_SHELL_FIDDLE
stdin_is_interactive = 0;
stdout_is_console = 1;
@@ -26984,7 +27308,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
stdin_is_interactive = isatty(0);
stdout_is_console = isatty(1);
#endif
-
+#if SHELL_WIN_UTF8_OPT
+ atexit(console_restore); /* Needs revision for CLI as library call */
+#endif
+ atexit(sayAbnormalExit);
+#ifdef SQLITE_DEBUG
+ mem_main_enter = sqlite3_memory_used();
+#endif
#if !defined(_WIN32_WCE)
if( getenv("SQLITE_DEBUG_BREAK") ){
if( isatty(0) && isatty(2) ){
@@ -27005,6 +27335,14 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}
}
#endif
+ /* Register a valid signal handler early, before much else is done. */
+#ifdef SIGINT
+ signal(SIGINT, interrupt_handler);
+#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
+ if( !SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE) ){
+ fprintf(stderr, "No ^C handler.\n");
+ }
+#endif
#if USE_SYSTEM_SQLITE+0!=1
if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
@@ -27044,15 +27382,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
assert( argc>=1 && argv && argv[0] );
Argv0 = argv[0];
- /* Make sure we have a valid signal handler early, before anything
- ** else is done.
- */
-#ifdef SIGINT
- signal(SIGINT, interrupt_handler);
-#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
- SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
-#endif
-
#ifdef SQLITE_SHELL_DBNAME_PROC
{
/* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
@@ -27070,11 +27399,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
** the size of the alternative malloc heap,
** and the first command to execute.
*/
+#ifndef SQLITE_SHELL_FIDDLE
verify_uninitialized();
+#endif
for(i=1; i<argc; i++){
char *z;
z = argv[i];
- if( z[0]!='-' ){
+ if( z[0]!='-' || i>nOptsEnd ){
if( data.aAuxDb->zDbFilename==0 ){
data.aAuxDb->zDbFilename = z;
}else{
@@ -27086,9 +27417,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
shell_check_oom(azCmd);
azCmd[nCmd-1] = z;
}
+ continue;
}
if( z[1]=='-' ) z++;
- if( cli_strcmp(z,"-separator")==0
+ if( cli_strcmp(z, "-")==0 ){
+ nOptsEnd = i;
+ continue;
+ }else if( cli_strcmp(z,"-separator")==0
|| cli_strcmp(z,"-nullvalue")==0
|| cli_strcmp(z,"-newline")==0
|| cli_strcmp(z,"-cmd")==0
@@ -27110,6 +27445,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
zSize = cmdline_option_value(argc, argv, ++i);
szHeap = integerValue(zSize);
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
+ verify_uninitialized();
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
#else
(void)cmdline_option_value(argc, argv, ++i);
@@ -27123,6 +27459,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
if( sz>0 && n>0 && 0xffffffffffffLL/sz<n ){
n = 0xffffffffffffLL/sz;
}
+ verify_uninitialized();
sqlite3_config(SQLITE_CONFIG_PAGECACHE,
(n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
data.shellFlgs |= SHFLG_Pagecache;
@@ -27132,11 +27469,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
if( sz<0 ) sz = 0;
n = (int)integerValue(cmdline_option_value(argc,argv,++i));
if( n<0 ) n = 0;
+ verify_uninitialized();
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
}else if( cli_strcmp(z,"-threadsafe")==0 ){
int n;
n = (int)integerValue(cmdline_option_value(argc,argv,++i));
+ verify_uninitialized();
switch( n ){
case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break;
case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break;
@@ -27160,10 +27499,12 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( cli_strcmp(z,"-mmap")==0 ){
sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
+ verify_uninitialized();
sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
-#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+#if defined(SQLITE_ENABLE_SORTER_REFERENCES)
}else if( cli_strcmp(z,"-sorterref")==0 ){
sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
+ verify_uninitialized();
sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, (int)sz);
#endif
}else if( cli_strcmp(z,"-vfs")==0 ){
@@ -27197,11 +27538,15 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( cli_strcmp(z,"-nonce")==0 ){
free(data.zNonce);
data.zNonce = strdup(argv[++i]);
+ }else if( cli_strcmp(z,"-unsafe-testing")==0 ){
+ ShellSetFlag(&data,SHFLG_TestingMode);
}else if( cli_strcmp(z,"-safe")==0 ){
/* no-op - catch this on the second pass */
}
}
+#ifndef SQLITE_SHELL_FIDDLE
verify_uninitialized();
+#endif
#ifdef SQLITE_SHELL_INIT_PROC
@@ -27265,7 +27610,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
*/
for(i=1; i<argc; i++){
char *z = argv[i];
- if( z[0]!='-' ) continue;
+ if( z[0]!='-' || i>=nOptsEnd ) continue;
if( z[1]=='-' ){ z++; }
if( cli_strcmp(z,"-init")==0 ){
i++;
@@ -27357,6 +27702,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
stdin_is_interactive = 1;
}else if( cli_strcmp(z,"-batch")==0 ){
stdin_is_interactive = 0;
+ }else if( cli_strcmp(z,"-utf8")==0 ){
+#if SHELL_WIN_UTF8_OPT
+ console_utf8 = 1;
+#endif /* SHELL_WIN_UTF8_OPT */
}else if( cli_strcmp(z,"-heap")==0 ){
i++;
}else if( cli_strcmp(z,"-pagecache")==0 ){
@@ -27427,6 +27776,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( cli_strcmp(z,"-safe")==0 ){
data.bSafeMode = data.bSafeModePersist = 1;
+ }else if( cli_strcmp(z,"-unsafe-testing")==0 ){
+ /* Acted upon in first pass. */
}else{
utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
raw_printf(stderr,"Use -help for a list of options.\n");
@@ -27434,6 +27785,14 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}
data.cMode = data.mode;
}
+#if SHELL_WIN_UTF8_OPT
+ if( console_utf8 && stdin_is_interactive ){
+ console_prepare();
+ }else{
+ setBinaryMode(stdin, 0);
+ console_utf8 = 0;
+ }
+#endif
if( !readStdin ){
/* Run all arguments that do not begin with '-' as if they were separate
@@ -27449,6 +27808,7 @@ 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 ){