version 1.1.1.9, 2014/09/29 22:58:46 |
version 1.1.1.10, 2015/03/16 00:08:48 |
|
|
#include <stdio.h> |
#include <stdio.h> |
#include <assert.h> |
#include <assert.h> |
#include "sqlite3.h" |
#include "sqlite3.h" |
|
#if SQLITE_USER_AUTHENTICATION |
|
# include "sqlite3userauth.h" |
|
#endif |
#include <ctype.h> |
#include <ctype.h> |
#include <stdarg.h> |
#include <stdarg.h> |
|
|
|
|
return zResult; |
return zResult; |
} |
} |
|
|
struct previous_mode_data { |
/* |
int valid; /* Is there legit data in here? */ |
** Shell output mode information from before ".explain on", |
int mode; |
** saved so that it can be restored by ".explain off" |
int showHeader; |
*/ |
int colWidth[100]; |
typedef struct SavedModeInfo SavedModeInfo; |
|
struct SavedModeInfo { |
|
int valid; /* Is there legit data in here? */ |
|
int mode; /* Mode prior to ".explain on" */ |
|
int showHeader; /* The ".header" setting prior to ".explain on" */ |
|
int colWidth[100]; /* Column widths prior to ".explain on" */ |
}; |
}; |
|
|
/* |
/* |
** An pointer to an instance of this structure is passed from |
** State information about the database connection is contained in an |
** the main program to the callback. This is used to communicate |
** instance of the following structure. |
** state and mode information. |
|
*/ |
*/ |
struct callback_data { |
typedef struct ShellState ShellState; |
|
struct ShellState { |
sqlite3 *db; /* The database */ |
sqlite3 *db; /* The database */ |
int echoOn; /* True to echo input commands */ |
int echoOn; /* True to echo input commands */ |
int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ |
int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ |
|
|
int mode; /* An output mode setting */ |
int mode; /* An output mode setting */ |
int writableSchema; /* True if PRAGMA writable_schema=ON */ |
int writableSchema; /* True if PRAGMA writable_schema=ON */ |
int showHeader; /* True to show column names in List or Column mode */ |
int showHeader; /* True to show column names in List or Column mode */ |
|
unsigned shellFlgs; /* Various flags */ |
char *zDestTable; /* Name of destination table when MODE_Insert */ |
char *zDestTable; /* Name of destination table when MODE_Insert */ |
char separator[20]; /* Separator character for MODE_List */ |
char separator[20]; /* Separator character for MODE_List */ |
char newline[20]; /* Record separator in MODE_Csv */ |
char newline[20]; /* Record separator in MODE_Csv */ |
|
|
int actualWidth[100]; /* Actual width of each column */ |
int actualWidth[100]; /* Actual width of each column */ |
char nullvalue[20]; /* The text to print when a NULL comes back from |
char nullvalue[20]; /* The text to print when a NULL comes back from |
** the database */ |
** the database */ |
struct previous_mode_data explainPrev; |
SavedModeInfo normalMode;/* Holds the mode just before .explain ON */ |
/* Holds the mode information just before |
|
** .explain ON */ |
|
char outfile[FILENAME_MAX]; /* Filename for *out */ |
char outfile[FILENAME_MAX]; /* Filename for *out */ |
const char *zDbFilename; /* name of the database file */ |
const char *zDbFilename; /* name of the database file */ |
char *zFreeOnClose; /* Filename to free when closing */ |
char *zFreeOnClose; /* Filename to free when closing */ |
|
|
}; |
}; |
|
|
/* |
/* |
|
** These are the allowed shellFlgs values |
|
*/ |
|
#define SHFLG_Scratch 0x00001 /* The --scratch option is used */ |
|
#define SHFLG_Pagecache 0x00002 /* The --pagecache option is used */ |
|
#define SHFLG_Lookaside 0x00004 /* Lookaside memory is used */ |
|
|
|
/* |
** These are the allowed modes. |
** These are the allowed modes. |
*/ |
*/ |
#define MODE_Line 0 /* One column per line. Blank line between records */ |
#define MODE_Line 0 /* One column per line. Blank line between records */ |
|
|
** A callback for the sqlite3_log() interface. |
** A callback for the sqlite3_log() interface. |
*/ |
*/ |
static void shellLog(void *pArg, int iErrCode, const char *zMsg){ |
static void shellLog(void *pArg, int iErrCode, const char *zMsg){ |
struct callback_data *p = (struct callback_data*)pArg; |
ShellState *p = (ShellState*)pArg; |
if( p->pLog==0 ) return; |
if( p->pLog==0 ) return; |
fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg); |
fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg); |
fflush(p->pLog); |
fflush(p->pLog); |
|
|
** the null value. Strings are quoted if necessary. The separator |
** the null value. Strings are quoted if necessary. The separator |
** is only issued if bSep is true. |
** is only issued if bSep is true. |
*/ |
*/ |
static void output_csv(struct callback_data *p, const char *z, int bSep){ |
static void output_csv(ShellState *p, const char *z, int bSep){ |
FILE *out = p->out; |
FILE *out = p->out; |
if( z==0 ){ |
if( z==0 ){ |
fprintf(out,"%s",p->nullvalue); |
fprintf(out,"%s",p->nullvalue); |
|
|
*/ |
*/ |
static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){ |
static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){ |
int i; |
int i; |
struct callback_data *p = (struct callback_data*)pArg; |
ShellState *p = (ShellState*)pArg; |
|
|
switch( p->mode ){ |
switch( p->mode ){ |
case MODE_Line: { |
case MODE_Line: { |
|
|
} |
} |
|
|
/* |
/* |
** Set the destination table field of the callback_data structure to |
** Set the destination table field of the ShellState structure to |
** the name of the table given. Escape any quote characters in the |
** the name of the table given. Escape any quote characters in the |
** table name. |
** table name. |
*/ |
*/ |
static void set_table_name(struct callback_data *p, const char *zName){ |
static void set_table_name(ShellState *p, const char *zName){ |
int i, n; |
int i, n; |
int needQuote; |
int needQuote; |
char *z; |
char *z; |
|
|
** won't consume the semicolon terminator. |
** won't consume the semicolon terminator. |
*/ |
*/ |
static int run_table_dump_query( |
static int run_table_dump_query( |
struct callback_data *p, /* Query context */ |
ShellState *p, /* Query context */ |
const char *zSelect, /* SELECT statement to extract content */ |
const char *zSelect, /* SELECT statement to extract content */ |
const char *zFirstRow /* Print before first row, if not NULL */ |
const char *zFirstRow /* Print before first row, if not NULL */ |
){ |
){ |
|
|
*/ |
*/ |
static int display_stats( |
static int display_stats( |
sqlite3 *db, /* Database to query */ |
sqlite3 *db, /* Database to query */ |
struct callback_data *pArg, /* Pointer to struct callback_data */ |
ShellState *pArg, /* Pointer to ShellState */ |
int bReset /* True to reset the stats */ |
int bReset /* True to reset the stats */ |
){ |
){ |
int iCur; |
int iCur; |
|
|
iHiwtr = iCur = -1; |
iHiwtr = iCur = -1; |
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset); |
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset); |
fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr); |
fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr); |
/* |
if( pArg->shellFlgs & SHFLG_Pagecache ){ |
** Not currently used by the CLI. |
iHiwtr = iCur = -1; |
** iHiwtr = iCur = -1; |
sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset); |
** sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset); |
fprintf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr); |
** fprintf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr); |
} |
*/ |
|
iHiwtr = iCur = -1; |
iHiwtr = iCur = -1; |
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset); |
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset); |
fprintf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); |
fprintf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); |
/* |
if( pArg->shellFlgs & SHFLG_Scratch ){ |
** Not currently used by the CLI. |
iHiwtr = iCur = -1; |
** iHiwtr = iCur = -1; |
sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset); |
** sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset); |
fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr); |
** fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr); |
} |
*/ |
|
iHiwtr = iCur = -1; |
iHiwtr = iCur = -1; |
sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset); |
sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset); |
fprintf(pArg->out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); |
fprintf(pArg->out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); |
|
|
} |
} |
|
|
if( pArg && pArg->out && db ){ |
if( pArg && pArg->out && db ){ |
|
if( pArg->shellFlgs & SHFLG_Lookaside ){ |
|
iHiwtr = iCur = -1; |
|
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset); |
|
fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr); |
|
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset); |
|
fprintf(pArg->out, "Successful lookaside attempts: %d\n", iHiwtr); |
|
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset); |
|
fprintf(pArg->out, "Lookaside failures due to size: %d\n", iHiwtr); |
|
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset); |
|
fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr); |
|
} |
iHiwtr = iCur = -1; |
iHiwtr = iCur = -1; |
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset); |
|
fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr); |
|
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset); |
|
fprintf(pArg->out, "Successful lookaside attempts: %d\n", iHiwtr); |
|
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset); |
|
fprintf(pArg->out, "Lookaside failures due to size: %d\n", iHiwtr); |
|
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset); |
|
fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr); |
|
iHiwtr = iCur = -1; |
|
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); |
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); |
fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1; |
fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1; |
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); |
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); |
|
|
|
|
/* |
/* |
** If compiled statement pSql appears to be an EXPLAIN statement, allocate |
** If compiled statement pSql appears to be an EXPLAIN statement, allocate |
** and populate the callback_data.aiIndent[] array with the number of |
** and populate the ShellState.aiIndent[] array with the number of |
** spaces each opcode should be indented before it is output. |
** spaces each opcode should be indented before it is output. |
** |
** |
** The indenting rules are: |
** The indenting rules are: |
|
|
** then indent all opcodes between the earlier instruction |
** then indent all opcodes between the earlier instruction |
** and "Goto" by 2 spaces. |
** and "Goto" by 2 spaces. |
*/ |
*/ |
static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){ |
static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){ |
const char *zSql; /* The text of the SQL statement */ |
const char *zSql; /* The text of the SQL statement */ |
const char *z; /* Used to check if this is an EXPLAIN */ |
const char *z; /* Used to check if this is an EXPLAIN */ |
int *abYield = 0; /* True if op is an OP_Yield */ |
int *abYield = 0; /* True if op is an OP_Yield */ |
|
|
/* |
/* |
** Free the array allocated by explain_data_prepare(). |
** Free the array allocated by explain_data_prepare(). |
*/ |
*/ |
static void explain_data_delete(struct callback_data *p){ |
static void explain_data_delete(ShellState *p){ |
sqlite3_free(p->aiIndent); |
sqlite3_free(p->aiIndent); |
p->aiIndent = 0; |
p->aiIndent = 0; |
p->nIndent = 0; |
p->nIndent = 0; |
|
|
** and callback data argument. |
** and callback data argument. |
*/ |
*/ |
static int shell_exec( |
static int shell_exec( |
sqlite3 *db, /* An open database */ |
sqlite3 *db, /* An open database */ |
const char *zSql, /* SQL to be evaluated */ |
const char *zSql, /* SQL to be evaluated */ |
int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */ |
int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */ |
/* (not the same as sqlite3_exec) */ |
/* (not the same as sqlite3_exec) */ |
struct callback_data *pArg, /* Pointer to struct callback_data */ |
ShellState *pArg, /* Pointer to ShellState */ |
char **pzErrMsg /* Error msg written here */ |
char **pzErrMsg /* Error msg written here */ |
){ |
){ |
sqlite3_stmt *pStmt = NULL; /* Statement to execute. */ |
sqlite3_stmt *pStmt = NULL; /* Statement to execute. */ |
int rc = SQLITE_OK; /* Return Code */ |
int rc = SQLITE_OK; /* Return Code */ |
|
|
sqlite3_free(zEQP); |
sqlite3_free(zEQP); |
} |
} |
|
|
/* Output TESTCTRL_EXPLAIN text of requested */ |
|
if( pArg && pArg->mode==MODE_Explain ){ |
|
const char *zExplain = 0; |
|
sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain); |
|
if( zExplain && zExplain[0] ){ |
|
fprintf(pArg->out, "%s", zExplain); |
|
} |
|
} |
|
|
|
/* If the shell is currently in ".explain" mode, gather the extra |
/* If the shell is currently in ".explain" mode, gather the extra |
** data required to add indents to the output.*/ |
** data required to add indents to the output.*/ |
if( pArg && pArg->mode==MODE_Explain ){ |
if( pArg && pArg->mode==MODE_Explain ){ |
|
|
const char *zType; |
const char *zType; |
const char *zSql; |
const char *zSql; |
const char *zPrepStmt = 0; |
const char *zPrepStmt = 0; |
struct callback_data *p = (struct callback_data *)pArg; |
ShellState *p = (ShellState *)pArg; |
|
|
UNUSED_PARAMETER(azCol); |
UNUSED_PARAMETER(azCol); |
if( nArg!=3 ) return 1; |
if( nArg!=3 ) return 1; |
|
|
** "ORDER BY rowid DESC" to the end. |
** "ORDER BY rowid DESC" to the end. |
*/ |
*/ |
static int run_schema_dump_query( |
static int run_schema_dump_query( |
struct callback_data *p, |
ShellState *p, |
const char *zQuery |
const char *zQuery |
){ |
){ |
int rc; |
int rc; |
|
|
; |
; |
|
|
/* Forward reference */ |
/* Forward reference */ |
static int process_input(struct callback_data *p, FILE *in); |
static int process_input(ShellState *p, FILE *in); |
/* |
/* |
** Implementation of the "readfile(X)" SQL function. The entire content |
** Implementation of the "readfile(X)" SQL function. The entire content |
** of the file named X is read and returned as a BLOB. NULL is returned |
** of the file named X is read and returned as a BLOB. NULL is returned |
|
|
** Make sure the database is open. If it is not, then open it. If |
** Make sure the database is open. If it is not, then open it. If |
** the database fails to open, print an error message and exit. |
** the database fails to open, print an error message and exit. |
*/ |
*/ |
static void open_db(struct callback_data *p, int keepAlive){ |
static void open_db(ShellState *p, int keepAlive){ |
if( p->db==0 ){ |
if( p->db==0 ){ |
sqlite3_initialize(); |
sqlite3_initialize(); |
sqlite3_open(p->zDbFilename, &p->db); |
sqlite3_open(p->zDbFilename, &p->db); |
|
|
*/ |
*/ |
static void sql_trace_callback(void *pArg, const char *z){ |
static void sql_trace_callback(void *pArg, const char *z){ |
FILE *f = (FILE*)pArg; |
FILE *f = (FILE*)pArg; |
if( f ) fprintf(f, "%s\n", z); |
if( f ){ |
|
int i = (int)strlen(z); |
|
while( i>0 && z[i-1]==';' ){ i--; } |
|
fprintf(f, "%.*s;\n", i, z); |
|
} |
} |
} |
|
|
/* |
/* |
|
|
** work for WITHOUT ROWID tables. |
** work for WITHOUT ROWID tables. |
*/ |
*/ |
static void tryToCloneData( |
static void tryToCloneData( |
struct callback_data *p, |
ShellState *p, |
sqlite3 *newDb, |
sqlite3 *newDb, |
const char *zTable |
const char *zTable |
){ |
){ |
|
|
** sqlite_master table, try again moving backwards. |
** sqlite_master table, try again moving backwards. |
*/ |
*/ |
static void tryToCloneSchema( |
static void tryToCloneSchema( |
struct callback_data *p, |
ShellState *p, |
sqlite3 *newDb, |
sqlite3 *newDb, |
const char *zWhere, |
const char *zWhere, |
void (*xForEach)(struct callback_data*,sqlite3*,const char*) |
void (*xForEach)(ShellState*,sqlite3*,const char*) |
){ |
){ |
sqlite3_stmt *pQuery = 0; |
sqlite3_stmt *pQuery = 0; |
char *zQuery = 0; |
char *zQuery = 0; |
|
|
** as possible out of the main database (which might be corrupt) and write it |
** as possible out of the main database (which might be corrupt) and write it |
** into zNewDb. |
** into zNewDb. |
*/ |
*/ |
static void tryToClone(struct callback_data *p, const char *zNewDb){ |
static void tryToClone(ShellState *p, const char *zNewDb){ |
int rc; |
int rc; |
sqlite3 *newDb = 0; |
sqlite3 *newDb = 0; |
if( access(zNewDb,0)==0 ){ |
if( access(zNewDb,0)==0 ){ |
|
|
/* |
/* |
** Change the output file back to stdout |
** Change the output file back to stdout |
*/ |
*/ |
static void output_reset(struct callback_data *p){ |
static void output_reset(ShellState *p){ |
if( p->outfile[0]=='|' ){ |
if( p->outfile[0]=='|' ){ |
pclose(p->out); |
pclose(p->out); |
}else{ |
}else{ |
|
|
** |
** |
** Return 1 on error, 2 to exit, and 0 otherwise. |
** Return 1 on error, 2 to exit, and 0 otherwise. |
*/ |
*/ |
static int do_meta_command(char *zLine, struct callback_data *p){ |
static int do_meta_command(char *zLine, ShellState *p){ |
int i = 1; |
int i = 1; |
int nArg = 0; |
int nArg = 0; |
int n, c; |
int n, c; |
|
|
}else |
}else |
|
|
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ |
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ |
struct callback_data data; |
ShellState data; |
char *zErrMsg = 0; |
char *zErrMsg = 0; |
open_db(p, 0); |
open_db(p, 0); |
memcpy(&data, p, sizeof(data)); |
memcpy(&data, p, sizeof(data)); |
|
|
if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ |
if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ |
int val = nArg>=2 ? booleanValue(azArg[1]) : 1; |
int val = nArg>=2 ? booleanValue(azArg[1]) : 1; |
if(val == 1) { |
if(val == 1) { |
if(!p->explainPrev.valid) { |
if(!p->normalMode.valid) { |
p->explainPrev.valid = 1; |
p->normalMode.valid = 1; |
p->explainPrev.mode = p->mode; |
p->normalMode.mode = p->mode; |
p->explainPrev.showHeader = p->showHeader; |
p->normalMode.showHeader = p->showHeader; |
memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth)); |
memcpy(p->normalMode.colWidth,p->colWidth,sizeof(p->colWidth)); |
} |
} |
/* We could put this code under the !p->explainValid |
/* We could put this code under the !p->explainValid |
** condition so that it does not execute if we are already in |
** condition so that it does not execute if we are already in |
|
|
p->colWidth[5] = 13; /* P4 */ |
p->colWidth[5] = 13; /* P4 */ |
p->colWidth[6] = 2; /* P5 */ |
p->colWidth[6] = 2; /* P5 */ |
p->colWidth[7] = 13; /* Comment */ |
p->colWidth[7] = 13; /* Comment */ |
}else if (p->explainPrev.valid) { |
}else if (p->normalMode.valid) { |
p->explainPrev.valid = 0; |
p->normalMode.valid = 0; |
p->mode = p->explainPrev.mode; |
p->mode = p->normalMode.mode; |
p->showHeader = p->explainPrev.showHeader; |
p->showHeader = p->normalMode.showHeader; |
memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth)); |
memcpy(p->colWidth,p->normalMode.colWidth,sizeof(p->colWidth)); |
} |
} |
}else |
}else |
|
|
if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ |
if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ |
struct callback_data data; |
ShellState data; |
char *zErrMsg = 0; |
char *zErrMsg = 0; |
int doStats = 0; |
int doStats = 0; |
if( nArg!=1 ){ |
if( nArg!=1 ){ |
|
|
" (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" |
" (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" |
" FROM sqlite_master UNION ALL" |
" FROM sqlite_master UNION ALL" |
" SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " |
" SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " |
"WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" |
"WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " |
"ORDER BY rowid", |
"ORDER BY rowid", |
callback, &data, &zErrMsg |
callback, &data, &zErrMsg |
); |
); |
|
|
}else |
}else |
|
|
if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){ |
if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){ |
struct callback_data data; |
ShellState data; |
char *zErrMsg = 0; |
char *zErrMsg = 0; |
open_db(p, 0); |
open_db(p, 0); |
memcpy(&data, p, sizeof(data)); |
memcpy(&data, p, sizeof(data)); |
|
|
}else |
}else |
|
|
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ |
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ |
struct callback_data data; |
ShellState data; |
char *zErrMsg = 0; |
char *zErrMsg = 0; |
open_db(p, 0); |
open_db(p, 0); |
memcpy(&data, p, sizeof(data)); |
memcpy(&data, p, sizeof(data)); |
|
|
" (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" |
" (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" |
" FROM sqlite_master UNION ALL" |
" FROM sqlite_master UNION ALL" |
" SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " |
" SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " |
"WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" |
"WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " |
"ORDER BY rowid", |
"ORDER BY rowid", |
callback, &data, &zErrMsg |
callback, &data, &zErrMsg |
); |
); |
|
|
} |
} |
}else |
}else |
|
|
|
|
|
#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; |
|
}else |
|
#endif |
|
|
|
|
#ifdef SQLITE_DEBUG |
#ifdef SQLITE_DEBUG |
/* Undocumented commands for internal testing. Subject to change |
/* Undocumented commands for internal testing. Subject to change |
** without notice. */ |
** without notice. */ |
|
|
} |
} |
fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off"); |
fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off"); |
fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off"); |
fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off"); |
fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off"); |
fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off"); |
fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off"); |
fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off"); |
fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]); |
fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]); |
fprintf(p->out,"%9.9s: ", "nullvalue"); |
fprintf(p->out,"%9.9s: ", "nullvalue"); |
|
|
#endif |
#endif |
}else |
}else |
|
|
|
#if SQLITE_USER_AUTHENTICATION |
|
if( c=='u' && strncmp(azArg[0], "user", n)==0 ){ |
|
if( nArg<2 ){ |
|
fprintf(stderr, "Usage: .user SUBCOMMAND ...\n"); |
|
rc = 1; |
|
goto meta_command_exit; |
|
} |
|
open_db(p, 0); |
|
if( strcmp(azArg[1],"login")==0 ){ |
|
if( nArg!=4 ){ |
|
fprintf(stderr, "Usage: .user login USER PASSWORD\n"); |
|
rc = 1; |
|
goto meta_command_exit; |
|
} |
|
rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], |
|
(int)strlen(azArg[3])); |
|
if( rc ){ |
|
fprintf(stderr, "Authentication failed for user %s\n", azArg[2]); |
|
rc = 1; |
|
} |
|
}else if( strcmp(azArg[1],"add")==0 ){ |
|
if( nArg!=5 ){ |
|
fprintf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n"); |
|
rc = 1; |
|
goto meta_command_exit; |
|
} |
|
rc = sqlite3_user_add(p->db, azArg[2], |
|
azArg[3], (int)strlen(azArg[3]), |
|
booleanValue(azArg[4])); |
|
if( rc ){ |
|
fprintf(stderr, "User-Add failed: %d\n", rc); |
|
rc = 1; |
|
} |
|
}else if( strcmp(azArg[1],"edit")==0 ){ |
|
if( nArg!=5 ){ |
|
fprintf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n"); |
|
rc = 1; |
|
goto meta_command_exit; |
|
} |
|
rc = sqlite3_user_change(p->db, azArg[2], |
|
azArg[3], (int)strlen(azArg[3]), |
|
booleanValue(azArg[4])); |
|
if( rc ){ |
|
fprintf(stderr, "User-Edit failed: %d\n", rc); |
|
rc = 1; |
|
} |
|
}else if( strcmp(azArg[1],"delete")==0 ){ |
|
if( nArg!=3 ){ |
|
fprintf(stderr, "Usage: .user delete USER\n"); |
|
rc = 1; |
|
goto meta_command_exit; |
|
} |
|
rc = sqlite3_user_delete(p->db, azArg[2]); |
|
if( rc ){ |
|
fprintf(stderr, "User-Delete failed: %d\n", rc); |
|
rc = 1; |
|
} |
|
}else{ |
|
fprintf(stderr, "Usage: .user login|add|edit|delete ...\n"); |
|
rc = 1; |
|
goto meta_command_exit; |
|
} |
|
}else |
|
#endif /* SQLITE_USER_AUTHENTICATION */ |
|
|
if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ |
if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ |
fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/, |
fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/, |
sqlite3_libversion(), sqlite3_sourceid()); |
sqlite3_libversion(), sqlite3_sourceid()); |
|
|
** |
** |
** Return the number of errors. |
** Return the number of errors. |
*/ |
*/ |
static int process_input(struct callback_data *p, FILE *in){ |
static int process_input(ShellState *p, FILE *in){ |
char *zLine = 0; /* A single input line */ |
char *zLine = 0; /* A single input line */ |
char *zSql = 0; /* Accumulated SQL text */ |
char *zSql = 0; /* Accumulated SQL text */ |
int nLine; /* Length of current line */ |
int nLine; /* Length of current line */ |
|
|
if( nSql ){ |
if( nSql ){ |
if( !_all_whitespace(zSql) ){ |
if( !_all_whitespace(zSql) ){ |
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); |
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); |
|
errCnt++; |
} |
} |
free(zSql); |
free(zSql); |
} |
} |
|
|
** Returns the number of errors. |
** Returns the number of errors. |
*/ |
*/ |
static int process_sqliterc( |
static int process_sqliterc( |
struct callback_data *p, /* Configuration data */ |
ShellState *p, /* Configuration data */ |
const char *sqliterc_override /* Name of config file. NULL to use default */ |
const char *sqliterc_override /* Name of config file. NULL to use default */ |
){ |
){ |
char *home_dir = NULL; |
char *home_dir = NULL; |
|
|
" -interactive force interactive I/O\n" |
" -interactive force interactive I/O\n" |
" -line set output mode to 'line'\n" |
" -line set output mode to 'line'\n" |
" -list set output mode to 'list'\n" |
" -list set output mode to 'list'\n" |
|
" -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" |
" -mmap N default mmap size set to N\n" |
" -mmap N default mmap size set to N\n" |
#ifdef SQLITE_ENABLE_MULTIPLEX |
#ifdef SQLITE_ENABLE_MULTIPLEX |
" -multiplex enable the multiplexor VFS\n" |
" -multiplex enable the multiplexor VFS\n" |
#endif |
#endif |
" -newline SEP set newline character(s) for CSV\n" |
" -newline SEP set newline character(s) for CSV\n" |
" -nullvalue TEXT set text string for NULL values. Default ''\n" |
" -nullvalue TEXT set text string for NULL values. Default ''\n" |
|
" -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" |
|
" -scratch SIZE N use N slots of SZ bytes each for scratch memory\n" |
" -separator SEP set output field separator. Default: '|'\n" |
" -separator SEP set output field separator. Default: '|'\n" |
" -stats print memory stats before each finalize\n" |
" -stats print memory stats before each finalize\n" |
" -version show SQLite version\n" |
" -version show SQLite version\n" |
|
|
/* |
/* |
** Initialize the state information in data |
** Initialize the state information in data |
*/ |
*/ |
static void main_init(struct callback_data *data) { |
static void main_init(ShellState *data) { |
memset(data, 0, sizeof(*data)); |
memset(data, 0, sizeof(*data)); |
data->mode = MODE_List; |
data->mode = MODE_List; |
memcpy(data->separator,"|", 2); |
memcpy(data->separator,"|", 2); |
memcpy(data->newline,"\r\n", 3); |
memcpy(data->newline,"\r\n", 3); |
data->showHeader = 0; |
data->showHeader = 0; |
|
data->shellFlgs = SHFLG_Lookaside; |
sqlite3_config(SQLITE_CONFIG_URI, 1); |
sqlite3_config(SQLITE_CONFIG_URI, 1); |
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); |
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); |
|
sqlite3_config(SQLITE_CONFIG_MULTITHREAD); |
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); |
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); |
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); |
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); |
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
|
} |
} |
|
|
/* |
/* |
|
|
|
|
int main(int argc, char **argv){ |
int main(int argc, char **argv){ |
char *zErrMsg = 0; |
char *zErrMsg = 0; |
struct callback_data data; |
ShellState data; |
const char *zInitFile = 0; |
const char *zInitFile = 0; |
char *zFirstCmd = 0; |
char *zFirstCmd = 0; |
int i; |
int i; |
|
|
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; |
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; |
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); |
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); |
#endif |
#endif |
|
}else if( strcmp(z,"-scratch")==0 ){ |
|
int n, sz; |
|
sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); |
|
if( sz>400000 ) sz = 400000; |
|
if( sz<2500 ) sz = 2500; |
|
n = (int)integerValue(cmdline_option_value(argc,argv,++i)); |
|
if( n>10 ) n = 10; |
|
if( n<1 ) n = 1; |
|
sqlite3_config(SQLITE_CONFIG_SCRATCH, malloc(n*sz+1), sz, n); |
|
data.shellFlgs |= SHFLG_Scratch; |
|
}else if( strcmp(z,"-pagecache")==0 ){ |
|
int n, sz; |
|
sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); |
|
if( sz>70000 ) sz = 70000; |
|
if( sz<800 ) sz = 800; |
|
n = (int)integerValue(cmdline_option_value(argc,argv,++i)); |
|
if( n<10 ) n = 10; |
|
sqlite3_config(SQLITE_CONFIG_PAGECACHE, malloc(n*sz+1), sz, n); |
|
data.shellFlgs |= SHFLG_Pagecache; |
|
}else if( strcmp(z,"-lookaside")==0 ){ |
|
int n, sz; |
|
sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); |
|
if( sz<0 ) sz = 0; |
|
n = (int)integerValue(cmdline_option_value(argc,argv,++i)); |
|
if( n<0 ) n = 0; |
|
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n); |
|
if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside; |
#ifdef SQLITE_ENABLE_VFSTRACE |
#ifdef SQLITE_ENABLE_VFSTRACE |
}else if( strcmp(z,"-vfstrace")==0 ){ |
}else if( strcmp(z,"-vfstrace")==0 ){ |
extern int vfstrace_register( |
extern int vfstrace_register( |
|
|
stdin_is_interactive = 0; |
stdin_is_interactive = 0; |
}else if( strcmp(z,"-heap")==0 ){ |
}else if( strcmp(z,"-heap")==0 ){ |
i++; |
i++; |
|
}else if( strcmp(z,"-scratch")==0 ){ |
|
i+=2; |
|
}else if( strcmp(z,"-pagecache")==0 ){ |
|
i+=2; |
|
}else if( strcmp(z,"-lookaside")==0 ){ |
|
i+=2; |
}else if( strcmp(z,"-mmap")==0 ){ |
}else if( strcmp(z,"-mmap")==0 ){ |
i++; |
i++; |
}else if( strcmp(z,"-vfs")==0 ){ |
}else if( strcmp(z,"-vfs")==0 ){ |