summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/sqlite/shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/sqlite/shell.c')
-rw-r--r--src/3rdparty/sqlite/shell.c548
1 files changed, 425 insertions, 123 deletions
diff --git a/src/3rdparty/sqlite/shell.c b/src/3rdparty/sqlite/shell.c
index 9c0481c0dd..7db8dbda0a 100644
--- a/src/3rdparty/sqlite/shell.c
+++ b/src/3rdparty/sqlite/shell.c
@@ -25,6 +25,13 @@
#endif
/*
+** No support for loadable extensions in VxWorks.
+*/
+#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION
+# define SQLITE_OMIT_LOAD_EXTENSION 1
+#endif
+
+/*
** Enable large-file support for fopen() and friends on unix.
*/
#ifndef SQLITE_DISABLE_LFS
@@ -59,18 +66,38 @@
# include <readline/readline.h>
# include <readline/history.h>
#endif
+
#if HAVE_EDITLINE
-# undef HAVE_READLINE
-# define HAVE_READLINE 1
# include <editline/readline.h>
#endif
-#if !HAVE_READLINE
-# define add_history(X)
-# define read_history(X)
-# define write_history(X)
-# define stifle_history(X)
+
+#if HAVE_EDITLINE || HAVE_READLINE
+
+# define shell_add_history(X) add_history(X)
+# define shell_read_history(X) read_history(X)
+# define shell_write_history(X) write_history(X)
+# define shell_stifle_history(X) stifle_history(X)
+# define shell_readline(X) readline(X)
+
+#elif HAVE_LINENOISE
+
+# include "linenoise.h"
+# define shell_add_history(X) linenoiseHistoryAdd(X)
+# define shell_read_history(X) linenoiseHistoryLoad(X)
+# define shell_write_history(X) linenoiseHistorySave(X)
+# define shell_stifle_history(X) linenoiseHistorySetMaxLen(X)
+# define shell_readline(X) linenoise(X)
+
+#else
+
+# define shell_read_history(X)
+# define shell_write_history(X)
+# define shell_stifle_history(X)
+
+# define SHELL_USE_LOCAL_GETLINE 1
#endif
+
#if defined(_WIN32) || defined(WIN32)
# include <io.h>
# include <fcntl.h>
@@ -87,10 +114,15 @@
*/
extern int isatty(int);
-/* popen and pclose are not C89 functions and so are sometimes omitted from
-** the <stdio.h> header */
-extern FILE *popen(const char*,const char*);
-extern int pclose(FILE*);
+#if !defined(__RTP__) && !defined(_WRS_KERNEL)
+ /* popen and pclose are not C89 functions and so are sometimes omitted from
+ ** the <stdio.h> header */
+ extern FILE *popen(const char*,const char*);
+ extern int pclose(FILE*);
+#else
+# define SQLITE_OMIT_POPEN 1
+#endif
+
#endif
#if defined(_WIN32_WCE)
@@ -106,6 +138,26 @@ extern int pclose(FILE*);
#define IsDigit(X) isdigit((unsigned char)X)
#define ToLower(X) (char)tolower((unsigned char)X)
+/* On Windows, we normally run with output mode of TEXT so that \n characters
+** are automatically translated into \r\n. However, this behavior needs
+** to be disabled in some cases (ex: when generating CSV output and when
+** rendering quoted strings that contain \n characters). The following
+** routines take care of that.
+*/
+#if defined(_WIN32) || defined(WIN32)
+static void setBinaryMode(FILE *out){
+ fflush(out);
+ _setmode(_fileno(out), _O_BINARY);
+}
+static void setTextMode(FILE *out){
+ fflush(out);
+ _setmode(_fileno(out), _O_TEXT);
+}
+#else
+# define setBinaryMode(X)
+# define setTextMode(X)
+#endif
+
/* True if the timer is enabled */
static int enableTimer = 0;
@@ -125,11 +177,19 @@ static sqlite3_int64 timeOfDay(void){
return t;
}
-#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \
- && !defined(__minux)
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
#include <sys/time.h>
#include <sys/resource.h>
+/* VxWorks does not support getrusage() as far as we can determine */
+#if defined(_WRS_KERNEL) || defined(__RTP__)
+struct rusage {
+ struct timeval ru_utime; /* user CPU time used */
+ struct timeval ru_stime; /* system CPU time used */
+};
+#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 */
@@ -155,8 +215,8 @@ static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
*/
static void endTimer(void){
if( enableTimer ){
- struct rusage sEnd;
sqlite3_int64 iEnd = timeOfDay();
+ struct rusage sEnd;
getrusage(RUSAGE_SELF, &sEnd);
printf("Run Time: real %.3f user %f sys %f\n",
(iEnd - iBegin)*0.001,
@@ -276,7 +336,7 @@ static int stdin_is_interactive = 1;
** to this database a static variable so that it can be accessed
** by the SIGINT handler to interrupt database processing.
*/
-static sqlite3 *db = 0;
+static sqlite3 *globalDb = 0;
/*
** True if an interrupt (Control-C) has been received.
@@ -310,7 +370,7 @@ static FILE *iotrace = 0;
** is written to iotrace.
*/
#ifdef SQLITE_ENABLE_IOTRACE
-static void iotracePrintf(const char *zFormat, ...){
+static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
va_list ap;
char *z;
if( iotrace==0 ) return;
@@ -431,14 +491,14 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
zResult = local_getline(zPrior, in);
}else{
zPrompt = isContinuation ? continuePrompt : mainPrompt;
-#if HAVE_READLINE
- free(zPrior);
- zResult = readline(zPrompt);
- if( zResult && *zResult ) add_history(zResult);
-#else
+#if SHELL_USE_LOCAL_GETLINE
printf("%s", zPrompt);
fflush(stdout);
zResult = local_getline(zPrior, stdin);
+#else
+ free(zPrior);
+ zResult = shell_readline(zPrompt);
+ if( zResult && *zResult ) shell_add_history(zResult);
#endif
}
return zResult;
@@ -467,6 +527,7 @@ struct ShellState {
int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
int statsOn; /* True to display memory stats before each finalize */
int scanstatsOn; /* True to display scan stats before each finalize */
+ int backslashOn; /* Resolve C-style \x escapes in SQL input text */
int outCount; /* Revert to stdout when reaching zero */
int cnt; /* Number of records displayed so far */
FILE *out; /* Write results here */
@@ -584,6 +645,7 @@ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
static void output_quoted_string(FILE *out, const char *z){
int i;
int nSingle = 0;
+ setBinaryMode(out);
for(i=0; z[i]; i++){
if( z[i]=='\'' ) nSingle++;
}
@@ -606,6 +668,7 @@ static void output_quoted_string(FILE *out, const char *z){
}
fprintf(out,"'");
}
+ setTextMode(out);
}
/*
@@ -742,7 +805,7 @@ static void interrupt_handler(int NotUsed){
UNUSED_PARAMETER(NotUsed);
seenInterrupt++;
if( seenInterrupt>2 ) exit(1);
- if( db ) sqlite3_interrupt(db);
+ if( globalDb ) sqlite3_interrupt(globalDb);
}
#endif
@@ -908,10 +971,7 @@ static int shell_callback(
break;
}
case MODE_Csv: {
-#if defined(WIN32) || defined(_WIN32)
- fflush(p->out);
- _setmode(_fileno(p->out), _O_BINARY);
-#endif
+ setBinaryMode(p->out);
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
@@ -924,16 +984,22 @@ static int shell_callback(
}
fprintf(p->out, "%s", p->rowSeparator);
}
-#if defined(WIN32) || defined(_WIN32)
- fflush(p->out);
- _setmode(_fileno(p->out), _O_TEXT);
-#endif
+ setTextMode(p->out);
break;
}
case MODE_Insert: {
p->cnt++;
if( azArg==0 ) break;
- fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
+ fprintf(p->out,"INSERT INTO %s",p->zDestTable);
+ if( p->showHeader ){
+ fprintf(p->out,"(");
+ for(i=0; i<nArg; i++){
+ char *zSep = i>0 ? ",": "";
+ fprintf(p->out, "%s%s", zSep, azCol[i]);
+ }
+ fprintf(p->out,")");
+ }
+ fprintf(p->out," VALUES(");
for(i=0; i<nArg; i++){
char *zSep = i>0 ? ",": "";
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
@@ -1134,7 +1200,7 @@ static char *save_err_msg(
sqlite3 *db /* Database to query */
){
int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
- char *zErrMsg = sqlite3_malloc(nErrMsg);
+ char *zErrMsg = sqlite3_malloc64(nErrMsg);
if( zErrMsg ){
memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
}
@@ -1371,8 +1437,8 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
/* Grow the p->aiIndent array as required */
if( iOp>=nAlloc ){
nAlloc += 100;
- p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int));
- abYield = (int*)sqlite3_realloc(abYield, nAlloc*sizeof(int));
+ p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
+ abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
}
abYield[iOp] = str_in_array(zOp, azYield);
p->aiIndent[iOp] = 0;
@@ -1489,7 +1555,7 @@ static int shell_exec(
if( xCallback ){
/* allocate space for col name ptr, value ptr, and type */
int nCol = sqlite3_column_count(pStmt);
- void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1);
+ void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
if( !pData ){
rc = SQLITE_NOMEM;
}else{
@@ -1715,8 +1781,10 @@ static int run_schema_dump_query(
static char zHelp[] =
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
".bail on|off Stop after hitting an error. Default OFF\n"
+ ".binary on|off Turn binary output on or off. Default OFF\n"
".clone NEWDB Clone data into NEWDB from the existing database\n"
".databases List names and files of attached databases\n"
+ ".dbinfo ?DB? Show status information about the database\n"
".dump ?TABLE? ... Dump the database in an SQL text format\n"
" If TABLE specified, only dump tables matching\n"
" LIKE pattern TABLE.\n"
@@ -1729,12 +1797,13 @@ static char zHelp[] =
".headers on|off Turn display of headers on or off\n"
".help Show this message\n"
".import FILE TABLE Import data from FILE into TABLE\n"
- ".indices ?TABLE? Show names of all indices\n"
- " If TABLE specified, only show indices for tables\n"
+ ".indexes ?TABLE? Show names of all indexes\n"
+ " If TABLE specified, only show indexes for tables\n"
" matching LIKE pattern TABLE.\n"
#ifdef SQLITE_ENABLE_IOTRACE
".iotrace FILE Enable I/O diagnostic logging to FILE\n"
#endif
+ ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT\n"
#ifndef SQLITE_OMIT_LOAD_EXTENSION
".load FILE ?ENTRY? Load an extension library\n"
#endif
@@ -1804,7 +1873,7 @@ static void readfileFunc(
fseek(in, 0, SEEK_END);
nIn = ftell(in);
rewind(in);
- pBuf = sqlite3_malloc( nIn );
+ pBuf = sqlite3_malloc64( nIn );
if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
}else{
@@ -1851,23 +1920,23 @@ static void open_db(ShellState *p, int keepAlive){
if( p->db==0 ){
sqlite3_initialize();
sqlite3_open(p->zDbFilename, &p->db);
- db = p->db;
- if( db && sqlite3_errcode(db)==SQLITE_OK ){
- sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
+ globalDb = p->db;
+ if( p->db && sqlite3_errcode(p->db)==SQLITE_OK ){
+ sqlite3_create_function(p->db, "shellstatic", 0, SQLITE_UTF8, 0,
shellstaticFunc, 0, 0);
}
- if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
+ if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
- p->zDbFilename, sqlite3_errmsg(db));
+ p->zDbFilename, sqlite3_errmsg(p->db));
if( keepAlive ) return;
exit(1);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
- sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
+ sqlite3_create_function(p->db, "readfile", 1, SQLITE_UTF8, 0,
readfileFunc, 0, 0);
- sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
+ sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0,
writefileFunc, 0, 0);
}
}
@@ -1875,26 +1944,44 @@ static void open_db(ShellState *p, int keepAlive){
/*
** Do C-language style dequoting.
**
+** \a -> alarm
+** \b -> backspace
** \t -> tab
** \n -> newline
+** \v -> vertical tab
+** \f -> form feed
** \r -> carriage return
+** \s -> space
** \" -> "
-** \NNN -> ascii character NNN in octal
+** \' -> '
** \\ -> backslash
+** \NNN -> ascii character NNN in octal
*/
static void resolve_backslashes(char *z){
int i, j;
char c;
while( *z && *z!='\\' ) z++;
for(i=j=0; (c = z[i])!=0; i++, j++){
- if( c=='\\' ){
+ if( c=='\\' && z[i+1]!=0 ){
c = z[++i];
- if( c=='n' ){
- c = '\n';
+ if( c=='a' ){
+ c = '\a';
+ }else if( c=='b' ){
+ c = '\b';
}else if( c=='t' ){
c = '\t';
+ }else if( c=='n' ){
+ c = '\n';
+ }else if( c=='v' ){
+ c = '\v';
+ }else if( c=='f' ){
+ c = '\f';
}else if( c=='r' ){
c = '\r';
+ }else if( c=='"' ){
+ c = '"';
+ }else if( c=='\'' ){
+ c = '\'';
}else if( c=='\\' ){
c = '\\';
}else if( c>='0' && c<='7' ){
@@ -2064,7 +2151,7 @@ struct ImportCtx {
static void import_append_char(ImportCtx *p, int c){
if( p->n+1>=p->nAlloc ){
p->nAlloc += p->nAlloc + 100;
- p->z = sqlite3_realloc(p->z, p->nAlloc);
+ p->z = sqlite3_realloc64(p->z, p->nAlloc);
if( p->z==0 ){
fprintf(stderr, "out of memory\n");
exit(1);
@@ -2078,7 +2165,7 @@ static void import_append_char(ImportCtx *p, int c){
**
** + Input comes from p->in.
** + Store results in p->z of length p->n. Space to hold p->z comes
-** from sqlite3_malloc().
+** from sqlite3_malloc64().
** + Use p->cSep as the column separator. The default is ",".
** + Use p->rSep as the row separator. The default is "\n".
** + Keep track of the line number in p->nLine.
@@ -2086,7 +2173,7 @@ static void import_append_char(ImportCtx *p, int c){
** EOF on end-of-file.
** + Report syntax errors on stderr
*/
-static char *csv_read_one_field(ImportCtx *p){
+static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
int c;
int cSep = p->cColSep;
int rSep = p->cRowSep;
@@ -2152,7 +2239,7 @@ static char *csv_read_one_field(ImportCtx *p){
**
** + Input comes from p->in.
** + Store results in p->z of length p->n. Space to hold p->z comes
-** from sqlite3_malloc().
+** from sqlite3_malloc64().
** + Use p->cSep as the column separator. The default is "\x1F".
** + Use p->rSep as the row separator. The default is "\x1E".
** + Keep track of the row number in p->nLine.
@@ -2160,7 +2247,7 @@ static char *csv_read_one_field(ImportCtx *p){
** EOF on end-of-file.
** + Report syntax errors on stderr
*/
-static char *ascii_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;
@@ -2212,7 +2299,7 @@ static void tryToCloneData(
goto end_data_xfer;
}
n = sqlite3_column_count(pQuery);
- zInsert = sqlite3_malloc(200 + nTable + n*3);
+ zInsert = sqlite3_malloc64(200 + nTable + n*3);
if( zInsert==0 ){
fprintf(stderr, "out of memory\n");
goto end_data_xfer;
@@ -2402,7 +2489,9 @@ static void tryToClone(ShellState *p, const char *zNewDb){
*/
static void output_reset(ShellState *p){
if( p->outfile[0]=='|' ){
+#ifndef SQLITE_OMIT_POPEN
pclose(p->out);
+#endif
}else{
output_file_close(p->out);
}
@@ -2411,13 +2500,122 @@ static void output_reset(ShellState *p){
}
/*
+** Run an SQL command and return the single integer result.
+*/
+static int db_int(ShellState *p, const char *zSql){
+ sqlite3_stmt *pStmt;
+ int res = 0;
+ sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
+ res = sqlite3_column_int(pStmt,0);
+ }
+ sqlite3_finalize(pStmt);
+ return res;
+}
+
+/*
+** Convert a 2-byte or 4-byte big-endian integer into a native integer
+*/
+unsigned int get2byteInt(unsigned char *a){
+ return (a[0]<<8) + a[1];
+}
+unsigned int get4byteInt(unsigned char *a){
+ return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
+}
+
+/*
+** Implementation of the ".info" command.
+**
+** Return 1 on error, 2 to exit, and 0 otherwise.
+*/
+static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
+ static const struct { const char *zName; int ofst; } aField[] = {
+ { "file change counter:", 24 },
+ { "database page count:", 28 },
+ { "freelist page count:", 36 },
+ { "schema cookie:", 40 },
+ { "schema format:", 44 },
+ { "default cache size:", 48 },
+ { "autovacuum top root:", 52 },
+ { "incremental vacuum:", 64 },
+ { "text encoding:", 56 },
+ { "user version:", 60 },
+ { "application id:", 68 },
+ { "software version:", 96 },
+ };
+ static const struct { const char *zName; const char *zSql; } aQuery[] = {
+ { "number of tables:",
+ "SELECT count(*) FROM %s WHERE type='table'" },
+ { "number of indexes:",
+ "SELECT count(*) FROM %s WHERE type='index'" },
+ { "number of triggers:",
+ "SELECT count(*) FROM %s WHERE type='trigger'" },
+ { "number of views:",
+ "SELECT count(*) FROM %s WHERE type='view'" },
+ { "schema size:",
+ "SELECT total(length(sql)) FROM %s" },
+ };
+ sqlite3_file *pFile;
+ int i;
+ char *zSchemaTab;
+ char *zDb = nArg>=2 ? azArg[1] : "main";
+ unsigned char aHdr[100];
+ open_db(p, 0);
+ if( p->db==0 ) return 1;
+ sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
+ if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
+ return 1;
+ }
+ i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
+ if( i!=SQLITE_OK ){
+ fprintf(stderr, "unable to read database header\n");
+ return 1;
+ }
+ i = get2byteInt(aHdr+16);
+ if( i==1 ) i = 65536;
+ fprintf(p->out, "%-20s %d\n", "database page size:", i);
+ fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
+ fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
+ fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
+ for(i=0; i<sizeof(aField)/sizeof(aField[0]); i++){
+ int ofst = aField[i].ofst;
+ unsigned int val = get4byteInt(aHdr + ofst);
+ fprintf(p->out, "%-20s %u", aField[i].zName, val);
+ switch( ofst ){
+ case 56: {
+ if( val==1 ) fprintf(p->out, " (utf8)");
+ if( val==2 ) fprintf(p->out, " (utf16le)");
+ if( val==3 ) fprintf(p->out, " (utf16be)");
+ }
+ }
+ fprintf(p->out, "\n");
+ }
+ if( zDb==0 ){
+ zSchemaTab = sqlite3_mprintf("main.sqlite_master");
+ }else if( strcmp(zDb,"temp")==0 ){
+ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
+ }else{
+ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
+ }
+ for(i=0; i<sizeof(aQuery)/sizeof(aQuery[0]); i++){
+ char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
+ int val = db_int(p, zSql);
+ sqlite3_free(zSql);
+ fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
+ }
+ sqlite3_free(zSchemaTab);
+ return 0;
+}
+
+
+/*
** If an input line begins with "." then invoke this routine to
** process that line.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
static int do_meta_command(char *zLine, ShellState *p){
- int i = 1;
+ int h = 1;
int nArg = 0;
int n, c;
int rc = 0;
@@ -2425,24 +2623,24 @@ static int do_meta_command(char *zLine, ShellState *p){
/* Parse the input line into tokens.
*/
- while( zLine[i] && nArg<ArraySize(azArg) ){
- while( IsSpace(zLine[i]) ){ i++; }
- if( zLine[i]==0 ) break;
- if( zLine[i]=='\'' || zLine[i]=='"' ){
- int delim = zLine[i++];
- azArg[nArg++] = &zLine[i];
- while( zLine[i] && zLine[i]!=delim ){
- if( zLine[i]=='\\' && delim=='"' && zLine[i+1]!=0 ) i++;
- i++;
+ while( zLine[h] && nArg<ArraySize(azArg) ){
+ while( IsSpace(zLine[h]) ){ h++; }
+ if( zLine[h]==0 ) break;
+ if( zLine[h]=='\'' || zLine[h]=='"' ){
+ int delim = zLine[h++];
+ azArg[nArg++] = &zLine[h];
+ while( zLine[h] && zLine[h]!=delim ){
+ if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
+ h++;
}
- if( zLine[i]==delim ){
- zLine[i++] = 0;
+ if( zLine[h]==delim ){
+ zLine[h++] = 0;
}
if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
}else{
- azArg[nArg++] = &zLine[i];
- while( zLine[i] && !IsSpace(zLine[i]) ){ i++; }
- if( zLine[i] ) zLine[i++] = 0;
+ azArg[nArg++] = &zLine[h];
+ while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
+ if( zLine[h] ) zLine[h++] = 0;
resolve_backslashes(azArg[nArg-1]);
}
}
@@ -2517,6 +2715,19 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+ if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){
+ if( nArg==2 ){
+ if( booleanValue(azArg[1]) ){
+ setBinaryMode(p->out);
+ }else{
+ setTextMode(p->out);
+ }
+ }else{
+ fprintf(stderr, "Usage: .binary on|off\n");
+ rc = 1;
+ }
+ }else
+
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
@@ -2552,6 +2763,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+ if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
+ rc = shell_dbinfo_command(p, nArg, azArg);
+ }else
+
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
open_db(p, 0);
/* When playing back a "dump", the content might appear in an order
@@ -2739,8 +2954,8 @@ static int do_meta_command(char *zLine, ShellState *p){
int nSep; /* Number of bytes in p->colSeparator[] */
char *zSql; /* An SQL statement */
ImportCtx sCtx; /* Reader context */
- char *(*xRead)(ImportCtx*); /* Procedure to read one value */
- int (*xCloser)(FILE*); /* Procedure to close th3 connection */
+ char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
+ int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */
if( nArg!=3 ){
fprintf(stderr, "Usage: .import FILE TABLE\n");
@@ -2782,9 +2997,14 @@ static int do_meta_command(char *zLine, ShellState *p){
sCtx.zFile = zFile;
sCtx.nLine = 1;
if( sCtx.zFile[0]=='|' ){
+#ifdef SQLITE_OMIT_POPEN
+ fprintf(stderr, "Error: pipes are not supported in this OS\n");
+ return 1;
+#else
sCtx.in = popen(sCtx.zFile+1, "r");
sCtx.zFile = "<pipe>";
xCloser = pclose;
+#endif
}else{
sCtx.in = fopen(sCtx.zFile, "rb");
xCloser = fclose;
@@ -2809,7 +3029,7 @@ static int do_meta_command(char *zLine, ShellState *p){
nByte = strlen30(zSql);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
- if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
+ if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
char cSep = '(';
while( xRead(&sCtx) ){
@@ -2829,7 +3049,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(zCreate);
if( rc ){
fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
- sqlite3_errmsg(db));
+ sqlite3_errmsg(p->db));
sqlite3_free(sCtx.z);
xCloser(sCtx.in);
return 1;
@@ -2839,7 +3059,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(zSql);
if( rc ){
if (pStmt) sqlite3_finalize(pStmt);
- fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
+ fprintf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
xCloser(sCtx.in);
return 1;
}
@@ -2847,7 +3067,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_finalize(pStmt);
pStmt = 0;
if( nCol==0 ) return 0; /* no columns, no error */
- zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
+ zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
if( zSql==0 ){
fprintf(stderr, "Error: out of memory\n");
xCloser(sCtx.in);
@@ -2864,13 +3084,13 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
- fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
+ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
if (pStmt) sqlite3_finalize(pStmt);
xCloser(sCtx.in);
return 1;
}
- needCommit = sqlite3_get_autocommit(db);
- if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
+ needCommit = sqlite3_get_autocommit(p->db);
+ if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
do{
int startLine = sCtx.nLine;
for(i=0; i<nCol; i++){
@@ -2891,7 +3111,7 @@ static int do_meta_command(char *zLine, ShellState *p){
fprintf(stderr, "%s:%d: expected %d columns but found %d - "
"filling the rest with NULL\n",
sCtx.zFile, startLine, nCol, i+1);
- i++;
+ i += 2;
while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
}
}
@@ -2909,7 +3129,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_reset(pStmt);
if( rc!=SQLITE_OK ){
fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
- sqlite3_errmsg(db));
+ sqlite3_errmsg(p->db));
}
}
}while( sCtx.cTerm!=EOF );
@@ -2917,10 +3137,11 @@ static int do_meta_command(char *zLine, ShellState *p){
xCloser(sCtx.in);
sqlite3_free(sCtx.z);
sqlite3_finalize(pStmt);
- if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
+ if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
}else
- if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
+ if( c=='i' && (strncmp(azArg[0], "indices", n)==0
+ || strncmp(azArg[0], "indexes", n)==0) ){
ShellState data;
char *zErrMsg = 0;
open_db(p, 0);
@@ -2950,7 +3171,7 @@ static int do_meta_command(char *zLine, ShellState *p){
);
zShellStatic = 0;
}else{
- fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n");
+ fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
rc = 1;
goto meta_command_exit;
}
@@ -2966,7 +3187,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifdef SQLITE_ENABLE_IOTRACE
if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
- extern void (*sqlite3IoTrace)(const char*, ...);
+ SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
if( iotrace && iotrace!=stdout ) fclose(iotrace);
iotrace = 0;
if( nArg<2 ){
@@ -2986,6 +3207,64 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
#endif
+ if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){
+ static const struct {
+ const char *zLimitName; /* Name of a limit */
+ int limitCode; /* Integer code for that limit */
+ } aLimit[] = {
+ { "length", SQLITE_LIMIT_LENGTH },
+ { "sql_length", SQLITE_LIMIT_SQL_LENGTH },
+ { "column", SQLITE_LIMIT_COLUMN },
+ { "expr_depth", SQLITE_LIMIT_EXPR_DEPTH },
+ { "compound_select", SQLITE_LIMIT_COMPOUND_SELECT },
+ { "vdbe_op", SQLITE_LIMIT_VDBE_OP },
+ { "function_arg", SQLITE_LIMIT_FUNCTION_ARG },
+ { "attached", SQLITE_LIMIT_ATTACHED },
+ { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH },
+ { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER },
+ { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH },
+ { "worker_threads", SQLITE_LIMIT_WORKER_THREADS },
+ };
+ int i, n2;
+ open_db(p, 0);
+ if( nArg==1 ){
+ for(i=0; i<sizeof(aLimit)/sizeof(aLimit[0]); i++){
+ printf("%20s %d\n", aLimit[i].zLimitName,
+ sqlite3_limit(p->db, aLimit[i].limitCode, -1));
+ }
+ }else if( nArg>3 ){
+ fprintf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }else{
+ int iLimit = -1;
+ n2 = strlen30(azArg[1]);
+ for(i=0; i<sizeof(aLimit)/sizeof(aLimit[0]); i++){
+ if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
+ if( iLimit<0 ){
+ iLimit = i;
+ }else{
+ fprintf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }
+ }
+ if( iLimit<0 ){
+ fprintf(stderr, "unknown limit: \"%s\"\n"
+ "enter \".limits\" with no arguments for a list.\n",
+ azArg[1]);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( nArg==3 ){
+ sqlite3_limit(p->db, aLimit[iLimit].limitCode,
+ (int)integerValue(azArg[2]));
+ }
+ printf("%20s %d\n", aLimit[iLimit].zLimitName,
+ sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
+ }
+ }else
#ifndef SQLITE_OMIT_LOAD_EXTENSION
if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
@@ -3106,6 +3385,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}
output_reset(p);
if( zFile[0]=='|' ){
+#ifdef SQLITE_OMIT_POPEN
+ fprintf(stderr,"Error: pipes are not supported in this OS\n");
+ rc = 1;
+ p->out = stdout;
+#else
p->out = popen(zFile + 1, "w");
if( p->out==0 ){
fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
@@ -3114,6 +3398,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
+#endif
}else{
p->out = output_file_open(zFile);
if( p->out==0 ){
@@ -3313,7 +3598,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
extern int sqlite3SelectTrace;
- sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
+ sqlite3SelectTrace = integerValue(azArg[1]);
}else
#endif
@@ -3464,13 +3749,13 @@ static int do_meta_command(char *zLine, ShellState *p){
while( sqlite3_step(pStmt)==SQLITE_ROW ){
if( nRow>=nAlloc ){
char **azNew;
- int n = nAlloc*2 + 10;
- azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n);
+ int n2 = nAlloc*2 + 10;
+ azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
if( azNew==0 ){
fprintf(stderr, "Error: out of memory\n");
break;
}
- nAlloc = n;
+ nAlloc = n2;
azResult = azNew;
}
azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
@@ -3519,17 +3804,19 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
+ { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
+ { "imposter", SQLITE_TESTCTRL_IMPOSTER },
};
int testctrl = -1;
- int rc = 0;
- int i, n;
+ int rc2 = 0;
+ int i, n2;
open_db(p, 0);
/* convert testctrl text option to value. allow any unique prefix
** of the option name, or a numerical value. */
- n = strlen30(azArg[1]);
+ n2 = strlen30(azArg[1]);
for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
- if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
+ if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
if( testctrl<0 ){
testctrl = aCtrl[i].ctrlCode;
}else{
@@ -3550,8 +3837,8 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_TESTCTRL_RESERVE:
if( nArg==3 ){
int opt = (int)strtol(azArg[2], 0, 0);
- rc = sqlite3_test_control(testctrl, p->db, opt);
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
+ rc2 = sqlite3_test_control(testctrl, p->db, opt);
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
} else {
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
azArg[1]);
@@ -3564,8 +3851,8 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_TESTCTRL_PRNG_RESET:
case SQLITE_TESTCTRL_BYTEORDER:
if( nArg==2 ){
- rc = sqlite3_test_control(testctrl);
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
+ rc2 = sqlite3_test_control(testctrl);
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
} else {
fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
}
@@ -3575,8 +3862,8 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_TESTCTRL_PENDING_BYTE:
if( nArg==3 ){
unsigned int opt = (unsigned int)integerValue(azArg[2]);
- rc = sqlite3_test_control(testctrl, opt);
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
+ rc2 = sqlite3_test_control(testctrl, opt);
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
} else {
fprintf(stderr,"Error: testctrl %s takes a single unsigned"
" int option\n", azArg[1]);
@@ -3585,11 +3872,12 @@ static int do_meta_command(char *zLine, ShellState *p){
/* sqlite3_test_control(int, int) */
case SQLITE_TESTCTRL_ASSERT:
- case SQLITE_TESTCTRL_ALWAYS:
+ case SQLITE_TESTCTRL_ALWAYS:
+ case SQLITE_TESTCTRL_NEVER_CORRUPT:
if( nArg==3 ){
int opt = booleanValue(azArg[2]);
- rc = sqlite3_test_control(testctrl, opt);
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
+ rc2 = sqlite3_test_control(testctrl, opt);
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
} else {
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
azArg[1]);
@@ -3601,8 +3889,8 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_TESTCTRL_ISKEYWORD:
if( nArg==3 ){
const char *opt = azArg[2];
- rc = sqlite3_test_control(testctrl, opt);
- fprintf(p->out, "%d (0x%08x)\n", rc, rc);
+ rc2 = sqlite3_test_control(testctrl, opt);
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
} else {
fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
azArg[1]);
@@ -3610,6 +3898,18 @@ static int do_meta_command(char *zLine, ShellState *p){
break;
#endif
+ case SQLITE_TESTCTRL_IMPOSTER:
+ if( nArg==5 ){
+ rc2 = sqlite3_test_control(testctrl, p->db,
+ azArg[2],
+ integerValue(azArg[3]),
+ integerValue(azArg[4]));
+ fprintf(p->out, "%d (0x%08x)\n", rc2, rc2);
+ }else{
+ fprintf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
+ }
+ break;
+
case SQLITE_TESTCTRL_BITVEC_TEST:
case SQLITE_TESTCTRL_FAULT_INSTALL:
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
@@ -3642,12 +3942,12 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
open_db(p, 0);
- output_file_close(p->traceOut);
if( nArg!=2 ){
fprintf(stderr, "Usage: .trace FILE|off\n");
rc = 1;
goto meta_command_exit;
}
+ output_file_close(p->traceOut);
p->traceOut = output_file_open(azArg[1]);
#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
if( p->traceOut==0 ){
@@ -3912,6 +4212,7 @@ static int process_input(ShellState *p, FILE *in){
&& sqlite3_complete(zSql) ){
p->cnt = 0;
open_db(p, 0);
+ if( p->backslashOn ) resolve_backslashes(zSql);
BEGIN_TIMER;
rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
END_TIMER;
@@ -4023,7 +4324,7 @@ static char *find_home_dir(void){
**
** Returns the number of errors.
*/
-static int process_sqliterc(
+static void process_sqliterc(
ShellState *p, /* Configuration data */
const char *sqliterc_override /* Name of config file. NULL to use default */
){
@@ -4031,15 +4332,13 @@ static int process_sqliterc(
const char *sqliterc = sqliterc_override;
char *zBuf = 0;
FILE *in = NULL;
- int rc = 0;
if (sqliterc == NULL) {
home_dir = find_home_dir();
if( home_dir==0 ){
-#if !defined(__RTP__) && !defined(_WRS_KERNEL)
- fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0);
-#endif
- return 1;
+ fprintf(stderr, "-- warning: cannot find home directory;"
+ " cannot read ~/.sqliterc\n");
+ return;
}
sqlite3_initialize();
zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
@@ -4050,11 +4349,10 @@ static int process_sqliterc(
if( stdin_is_interactive ){
fprintf(stderr,"-- Loading resources from %s\n",sqliterc);
}
- rc = process_input(p,in);
+ process_input(p,in);
fclose(in);
}
sqlite3_free(zBuf);
- return rc;
}
/*
@@ -4158,7 +4456,7 @@ static char *cmdline_option_value(int argc, char **argv, int i){
return argv[i];
}
-int main(int argc, char **argv){
+int SQLITE_CDECL main(int argc, char **argv){
char *zErrMsg = 0;
ShellState data;
const char *zInitFile = 0;
@@ -4176,6 +4474,8 @@ int main(int argc, char **argv){
exit(1);
}
#endif
+ setBinaryMode(stdin);
+ setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
Argv0 = argv[0];
main_init(&data);
stdin_is_interactive = isatty(0);
@@ -4328,10 +4628,7 @@ int main(int argc, char **argv){
** is given on the command line, look for a file named ~/.sqliterc and
** try to process it.
*/
- rc = process_sqliterc(&data,zInitFile);
- if( rc>0 ){
- return rc;
- }
+ process_sqliterc(&data,zInitFile);
/* Make a second pass through the command-line argument and set
** options. This second pass is delayed until after the initialization
@@ -4382,6 +4679,13 @@ int main(int argc, char **argv){
data.statsOn = 1;
}else if( strcmp(z,"-scanstats")==0 ){
data.scanstatsOn = 1;
+ }else if( strcmp(z,"-backslash")==0 ){
+ /* Undocumented command-line option: -backslash
+ ** Causes C-style backslash escapes to be evaluated in SQL statements
+ ** prior to sending the SQL into SQLite. Useful for injecting
+ ** crazy bytes in the middle of SQL statements for testing and debugging.
+ */
+ data.backslashOn = 1;
}else if( strcmp(z,"-bail")==0 ){
bail_on_error = 1;
}else if( strcmp(z,"-version")==0 ){
@@ -4488,13 +4792,11 @@ int main(int argc, char **argv){
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
}
}
-#if HAVE_READLINE
- if( zHistory ) read_history(zHistory);
-#endif
+ if( zHistory ) shell_read_history(zHistory);
rc = process_input(&data, 0);
if( zHistory ){
- stifle_history(100);
- write_history(zHistory);
+ shell_stifle_history(100);
+ shell_write_history(zHistory);
free(zHistory);
}
}else{