mirror of
https://github.com/status-im/sqlcipher.git
synced 2026-08-31 06:21:07 +00:00
Merge sqlite-release(3.8.10.2) into prerelease-integration
This commit is contained in:
+390
-106
@@ -24,6 +24,13 @@
|
||||
#include "msvc.h"
|
||||
#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.
|
||||
*/
|
||||
@@ -107,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)
|
||||
@@ -126,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;
|
||||
@@ -145,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 */
|
||||
@@ -175,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,
|
||||
@@ -296,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.
|
||||
@@ -330,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;
|
||||
@@ -487,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 */
|
||||
@@ -604,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++;
|
||||
}
|
||||
@@ -626,6 +668,7 @@ static void output_quoted_string(FILE *out, const char *z){
|
||||
}
|
||||
fprintf(out,"'");
|
||||
}
|
||||
setTextMode(out);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -762,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
|
||||
|
||||
@@ -928,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);
|
||||
@@ -944,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) ){
|
||||
@@ -1154,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);
|
||||
}
|
||||
@@ -1391,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;
|
||||
@@ -1509,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{
|
||||
@@ -1735,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"
|
||||
@@ -1749,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
|
||||
@@ -1824,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{
|
||||
@@ -1871,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);
|
||||
}
|
||||
}
|
||||
@@ -1895,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' ){
|
||||
@@ -2084,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);
|
||||
@@ -2098,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.
|
||||
@@ -2106,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;
|
||||
@@ -2172,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.
|
||||
@@ -2180,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;
|
||||
@@ -2232,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;
|
||||
@@ -2422,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);
|
||||
}
|
||||
@@ -2430,6 +2499,115 @@ static void output_reset(ShellState *p){
|
||||
p->out = stdout;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
@@ -2437,7 +2615,7 @@ static void output_reset(ShellState *p){
|
||||
** 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;
|
||||
@@ -2445,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]);
|
||||
}
|
||||
}
|
||||
@@ -2537,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().
|
||||
*/
|
||||
@@ -2572,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
|
||||
@@ -2759,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");
|
||||
@@ -2802,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;
|
||||
@@ -2829,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) ){
|
||||
@@ -2849,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;
|
||||
@@ -2859,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;
|
||||
}
|
||||
@@ -2867,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);
|
||||
@@ -2884,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++){
|
||||
@@ -2911,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++; }
|
||||
}
|
||||
}
|
||||
@@ -2929,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 );
|
||||
@@ -2937,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);
|
||||
@@ -2970,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;
|
||||
}
|
||||
@@ -2986,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 ){
|
||||
@@ -3006,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 ){
|
||||
@@ -3126,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);
|
||||
@@ -3134,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 ){
|
||||
@@ -3333,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
|
||||
|
||||
@@ -3484,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));
|
||||
@@ -3539,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{
|
||||
@@ -3570,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]);
|
||||
@@ -3584,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]);
|
||||
}
|
||||
@@ -3595,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]);
|
||||
@@ -3605,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]);
|
||||
@@ -3621,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]);
|
||||
@@ -3630,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:
|
||||
@@ -3662,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 ){
|
||||
@@ -3932,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;
|
||||
@@ -4043,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 */
|
||||
){
|
||||
@@ -4051,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);
|
||||
@@ -4070,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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4178,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;
|
||||
@@ -4196,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);
|
||||
@@ -4348,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
|
||||
@@ -4402,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 ){
|
||||
|
||||
Reference in New Issue
Block a user