#endif
/* Get the shell extension interfaces and structs. */
-INCLUDE shext_linkage.h
+INCLUDE shext_linkage.h
-/* For an embedded shell, allow the 3 standard streams to be specified.
-** If used, these names will have to refer to something globally reachable.
+/* For an embedded shell, allow the 3 standard streams to be specified.
+** If used, these names will have to refer to something globally reachable
+** from the same thread which called the shell's main().
**/
#ifndef STD_IN
# define STD_IN stdin
static const char *(azHelp[]);
static unsigned numCommands;
+static FILE *currentOutputFile(ShellExState *p);
/* True if the timer is enabled */
static int enableTimer = 0;
/*
** Arrange for shell input from either a FILE or a string.
-** For applicable invariants, see str_line_get(...) which is
+** For applicable invariants, see strLineGet(...) which is
** the only modifier of this struct. (3rd and 4th members)
** All other members are simply initialized to select the
** input stream and track input sources, set by whatever
/* This instance's address is taken as part of interactive input test. */
static InSource termInSource = { 0 /*stdin*/, 0, 0, 0, "<terminal>", 0};
static InSource stdInSource = { 0 /*stdin*/, 0, 0, 0, "<stdin>", 0};
-static void init_std_inputs( FILE *pIn ){
+static void init_std_inputs(FILE *pIn ){
termInSource.inFile = pIn;
stdInSource.inFile = pIn;
}
-static char *str_line_get( char *zBuf, int ncMax, InSource *pInSrc){
+static char *strLineGet(char *zBuf, int ncMax, InSource *pInSrc){
if( pInSrc->inFile!=0 ){
char *zRet = fgets(zBuf, ncMax, pInSrc->inFile );
if( zRet!=0 ){
zLine = realloc(zLine, nLine);
shell_check_oom(zLine);
}
- if( str_line_get(&zLine[n], nLine - n, pInSrc)==0 ){
+ if( strLineGet(&zLine[n], nLine - n, pInSrc)==0 ){
if( n==0 ){
free(zLine);
return 0;
/* By default, omit the extension options that are not done yet. */
#ifndef SHELL_OMIT_EXTENSIONS
-# define SHELL_OMIT_EXTENSIONS 6
+# define SHELL_OMIT_EXTENSIONS 4
#endif
/* Selectively omit features with one PP variable. Value is true iff
#define SHEXT_PARSING_BIT 0
#define SHELL_EXTENDED_PARSING \
NOT_IFDEF_BIT(SHELL_OMIT_EXTENSIONS, SHEXT_PARSING_BIT)
-/* Whether build will include dynamic dot-command extension */
-#define SHEXT_DYNCMDS_BIT 1
-#define SHELL_DYNAMIC_COMMANDS \
- NOT_IFDEF_BIT(SHELL_OMIT_EXTENSIONS, SHEXT_DYNCMDS_BIT)
+/* Whether build will include runtime extension via .load -extension */
+#define SHEXT_DYNEXT_BIT 1
+#define SHELL_DYNAMIC_EXTENSION ( !defined(SQLITE_OMIT_LOAD_EXTENSION) \
+ && NOT_IFDEF_BIT(SHELL_OMIT_EXTENSIONS, SHEXT_DYNEXT_BIT) )
/* Whether build will include expansion of variables in dot-commands */
#define SHEXT_VAREXP_BIT 2
#define SHELL_VARIABLE_EXPANSION \
NOT_IFDEF_BIT(SHELL_OMIT_EXTENSIONS, SHEXT_VAREXP_BIT)
#define SHELL_ALL_EXTENSIONS \
- (1<<SHEXT_PARSING_BIT)+(1<<SHEXT_DYNCMDS_BIT)+(1<<SHEXT_VAREXP_BIT)
+ (1<<SHEXT_PARSING_BIT)+(1<<SHEXT_DYNEXT_BIT)+(1<<SHEXT_VAREXP_BIT)
#if !defined(SHELL_OMIT_EXTENSIONS)
# define SHELL_EXTENSIONS SHELL_ALL_EXTENSIONS
#else
# define SHELL_EXTENSIONS ((~SHELL_OMIT_EXTENSIONS) & SHELL_ALL_EXTENSIONS)
#endif
-/* Runtime test for shell extended parsing, given ShellState pointer */
+/* Runtime test for shell extended parsing, given ShellInState pointer */
#if SHELL_EXTENDED_PARSING
-# define SHEXT_PARSING(pSS) ((pSS->bExtendedDotCmds&(1<<SHEXT_PARSING_BIT))!=0)
+# define SHEXT_PARSING(psi) ((psi->bExtendedDotCmds&(1<<SHEXT_PARSING_BIT))!=0)
#else
-# define SHEXT_PARSING(pSS) 0
+# define SHEXT_PARSING(psi) 0
#endif
-/* Runtime test for shell variable expansion, given ShellState pointer */
+/* Runtime test for shell variable expansion, given ShellInState pointer */
#if SHELL_EXTENDED_PARSING
-# define SHEXT_VAREXP(pSS) ((pSS->bExtendedDotCmds&(1<<SHEXT_VAREXP_BIT))!=0)
+# define SHEXT_VAREXP(psi) ((psi->bExtendedDotCmds&(1<<SHEXT_VAREXP_BIT))!=0)
#else
-# define SHEXT_VAREXP(pSS) 0
+# define SHEXT_VAREXP(psi) 0
#endif
/* Parameters affecting columnar mode result display (defaulting together) */
/*
** Stored output mode state, for partial save and later restore.
** Returned by:
-** outputModeSave *outputModeSave(ShellState *p, SaveModeWhat ws).
+** outputModeSave *outputModeSave(ShellInState *p, SaveModeWhat ws).
** Accepted by:
-** outputModeRestore(ShellState *p, OutputModeSave *pSaved).
+** outputModeRestore(ShellInState *p, OutputModeSave *pSaved).
** See enum SaveWhatMode regarding what to save and restore.
** Also see outputModePush(...), outputModePushSome(...) and
** outputModePop(...) for usages spanning more than one call.
#define MODE_STACK_MAX 3 /* How many levels of saved output mode to allow. */
/*
-** State information about the database connection is contained in an
-** instance of the following structure.
+** Shell state information is contained in an instance of the following struct
+** and in a ShellExState struct defined in shext_linkage.h, partitioned thusly:
+**
+** Data not exposed for shell extension use, (and which need not be stable),
+** are kept in a ShellInState instance. These include facts about the database
+** connection, specialized display mode setup, safe mode control, and other
+** data associated with the shell's means of operation.
+**
+** Data which is exposed for shell extension use, (and which should be stable
+** or grown only with new members at the end, to preserve layout), is kept
+** in the ShellExState instance, which contains a ShellInState pointer, pSIS.
*/
-typedef struct ShellState ShellState;
-struct ShellState {
- sqlite3 *db; /* The database */
+
+/* Oft-used macros for transition to internal/external shell state access
+ * ISS(psx) : internal shell state (pointer)
+ * XSS(psi) : external shell state (pointer)
+ * DBI(psi) : DB from internal pointer
+ * DBX(psx) : DB from external pointer
+ */
+#define ISS(psx) (psx)->pSIS
+#define XSS(psi) (psi)->pSXS
+#define DBI(psi) (psi)->pSXS->dbUser
+#define DBX(psx) (psx)->dbUser
+
+typedef struct ShellInState {
+ /* sqlite3 *db; user database moved to ShellExState.dbUser */
int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */
u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
+ sqlite3_int64 szMax; /* --maxsize argument to .open */
u8 autoExplain; /* Automatically turn on .explain mode */
u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
u8 autoEQPtest; /* autoEQP is in test mode */
/* Output mode state-keep for certain ad-hoc save/restore ops: */
u8 cMode; /* temporary output mode for the current query */
u8 normalMode; /* Output mode before ".explain on" */
+#if 0 /* moved to ShellExState and renamed */
int *colWidth; /* Requested width of each column in columnar modes */
int *actualWidth; /* Actual width of each column */
int nWidth; /* Number of slots in colWidth[] and actualWidth[] */
+#endif
char nullValue[20]; /* Text to print for NULL retrieved from database */
unsigned statsOn; /* True to display memory stats before each finalize */
unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */
int outCount; /* Revert to stdout when reaching zero */
+#if 0 /* moved to ShellExState as resultCount */
int cnt; /* Number of records displayed so far */
-
+#endif
int inputNesting; /* Track nesting level of .read and other redirects */
InSource *pInSource; /* Read commands and SQL from this stream source */
FILE *out; /* Write results here */
FILE *traceOut; /* Output for sqlite3_trace() */
+#if 0 /* moved to ShellExState */
int abruptExit; /* Flag for immediate shell exit, exit code */
+#endif
int nErr; /* Number of errors seen */
int writableSchema; /* True if PRAGMA writable_schema=ON */
int nCheck; /* Number of ".check" commands run */
unsigned mxProgress; /* Maximum progress callbacks before failing */
unsigned flgProgress; /* Flags for the progress callback */
- sqlite3_int64 szMax; /* --maxsize argument to .open */
- char *zDestTable; /* Name of destination table when MODE_Insert */
char *zTempFile; /* Temporary file that might need deleting */
char *zEditor; /* Name of editor if non-zero, then deletable */
char zTestcase[30]; /* Name of current test case */
char *zNonce; /* Nonce for temporary safe-mode suspension */
EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */
ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */
-};
+ ShellExState *pSXS; /* Pointer to companion, exposed shell state */
+} ShellInState;
/*
** Limit input nesting via .read or any other input redirect.
** equal 1 => Safe mode is and will remain active.
** N > 1 => Safe mode is suspended for N-1 operations.
*/
-static void updateSafeMode(ShellState *pSS){
- switch( pSS->bSafeModeFuture ){
+static void updateSafeMode(ShellInState *psi){
+ switch( psi->bSafeModeFuture ){
case 2:
default:
- --pSS->bSafeModeFuture;
+ --psi->bSafeModeFuture;
/* Fall thru, suspension is in effect. */
case 0:
- pSS->bSafeMode = 0;
+ psi->bSafeMode = 0;
break;
case 1:
- pSS->bSafeMode = 1;
+ psi->bSafeMode = 1;
}
}
-/* Allowed values for ShellState.autoEQP
+/* Allowed values for ShellInState.autoEQP
*/
#define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */
#define AUTOEQP_on 1 /* Automatic EQP is on */
#define AUTOEQP_trigger 2 /* On and also show plans for triggers */
#define AUTOEQP_full 3 /* Show full EXPLAIN */
-/* Allowed values for ShellState.openMode
+/* Allowed values for ShellInState.openMode
*/
#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */
#define SHELL_OPEN_NORMAL 1 /* Normal database file */
#define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */
#define SHELL_OPEN_HEXDB 6 /* Use "dbtotxt" output as data source */
-/* Allowed values for ShellState.eTraceType
+/* Allowed values for ShellInState.eTraceType
*/
#define SHELL_TRACE_PLAIN 0 /* Show input SQL text */
#define SHELL_TRACE_EXPANDED 1 /* Show expanded SQL text */
#define SHELL_TRACE_NORMALIZED 2 /* Show normalized SQL text */
-/* Bits in the ShellState.flgProgress variable */
+/* Bits in the ShellInState.flgProgress variable */
#define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */
#define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progres
** callback limit is reached, and for each
/*
** Macros for testing and setting shellFlgs
*/
-#define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0)
-#define ShellSetFlag(P,X) ((P)->shellFlgs|=(X))
-#define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X)))
+#define ShellHasFlag(psx,X) (((psx)->pSIS->shellFlgs & (X))!=0)
+#define ShellSetFlag(psx,X) ((psx)->pSIS->shellFlgs|=(X))
+#define ShellClearFlag(psx,X) ((psx)->pSIS->shellFlgs&=(~(X)))
/*
** These are the allowed modes, in search order (for abbreviation matches.)
#define MODE_Explain 17 /* Like MODE_Column, but do not truncate data */
#define MODE_Pretty 18 /* Pretty-print schemas */
#define MODE_Semi 19 /* Same as MODE_List but append ";" to each line */
-#define MODE_COUNT_OF 20 /* also an invalid MODE_x value */
+#define MODE_COUNT_OF 20 /* also a known invalid MODE_x value */
/* Note that some of above ordering is assumed for this mode classification. */
#define MODE_IS_COLUMNAR(m) \
** A callback for the sqlite3_log() interface.
*/
static void shellLog(void *pArg, int iErrCode, const char *zMsg){
- ShellState *p = (ShellState*)pArg;
- if( p->pLog==0 ) return;
- utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
- fflush(p->pLog);
+ ShellInState *psi = (ShellInState*)pArg;
+ if( psi->pLog==0 ) return;
+ utf8_printf(psi->pLog, "(%d) %s\n", iErrCode, zMsg);
+ fflush(psi->pLog);
}
/*
int nVal,
sqlite3_value **apVal
){
- ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
+ ShellExState *psx = (ShellExState*)sqlite3_user_data(pCtx);
(void)nVal;
- utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
+ utf8_printf(ISS(psx)->out, "%s\n", sqlite3_value_text(apVal[0]));
sqlite3_result_value(pCtx, apVal[0]);
}
** The return is true if failing, 0 otherwise.
*/
static int failIfSafeMode(
- ShellState *p,
+ ShellExState *psx,
const char *zErrMsg,
...
){
- if( p->bSafeMode==1 ){
+ if( ISS(psx)->bSafeMode==1 ){
va_list ap;
char *zMsg;
va_start(ap, zErrMsg);
zMsg = sqlite3_vmprintf(zErrMsg, ap);
va_end(ap);
- raw_printf(STD_ERR, "line %d: ", p->pInSource->lineno);
+ raw_printf(STD_ERR, "line %d: ", ISS(psx)->pInSource->lineno);
utf8_printf(STD_ERR, "%s\n", zMsg);
- p->abruptExit = 3;
+ psx->shellAbruptExit = 3;
return 1;
}
return 0;
size_t size;
} outputModeCopy[] = {
#define SS_MEMBER_COPY(mn) \
- { MEMBER_OFFSET(ShellState,mn), MEMBER_SIZEOF(ShellState,mn) }
+ { MEMBER_OFFSET(ShellInState,mn), MEMBER_SIZEOF(ShellInState,mn) }
SS_MEMBER_COPY(showHeader), SS_MEMBER_COPY(shellFlgs),
SS_MEMBER_COPY(mode), SS_MEMBER_COPY(cmOpts),
SS_MEMBER_COPY(colSeparator), SS_MEMBER_COPY(rowSeparator)
};
/* Allocate a buffer, copy requested output mode data to it, and return it. */
-static OutputModeSave *outputModeSave(ShellState *p, SaveWhatMode w){
+static OutputModeSave *outputModeSave(ShellInState *psi, SaveWhatMode w){
u16 what = (u16)w;
int i, nAlloc = sizeof(what)+1, mask = 1;
char *pSaved = 0, *pFill;
for( mask=1, i=0; i<SWM_CountOf; mask<<=1, ++i ){
if( (what & mask)!=0 ){
size_t nb = outputModeCopy[i].size;
- memcpy(pFill, (char*)p+outputModeCopy[i].offset, nb);
+ memcpy(pFill, ((char*)psi)+outputModeCopy[i].offset, nb);
pFill += nb;
}
}
* The buffer is freed and its pointer is invalidated.
* If called with some other buffer, results are undefined, likely bad.
*/
-static void outputModeRestore(ShellState *p, OutputModeSave *pSaved){
+static void outputModeRestore(ShellInState *psi, OutputModeSave *pSaved){
sqlite3_uint64 nA = sqlite3_msize(pSaved);
u16 what = (nA>sizeof(what))? *((u16 *)pSaved) : 0;
int i, nAlloc = sizeof(what)+1, mask = 1;
for( i=0; i<SWM_CountOf && nAlloc<nA; mask<<=1, ++i ){
if( (what & mask)!=0 ){
size_t nb = outputModeCopy[i].size;
- memcpy((char*)p+outputModeCopy[i].offset, pTake, nb);
+ memcpy(((char*)psi)+outputModeCopy[i].offset, pTake, nb);
pTake += nb;
}
}
/*
** Save or restore the current output mode, in whole or in part.
*/
-static void outputModePushSome(ShellState *p, SaveWhatMode w){
+static void outputModePushSome(ShellInState *psi, SaveWhatMode w){
OutputModeSave *pOMS;
- assert(p->nSavedModes<MODE_STACK_MAX); /* Fail hard for this logic error. */
- if( p->nSavedModes>=MODE_STACK_MAX ) return;
- pOMS = outputModeSave(p, w);
+ assert(psi->nSavedModes<MODE_STACK_MAX); /* Fail hard for this logic error. */
+ if( psi->nSavedModes>=MODE_STACK_MAX ) return;
+ pOMS = outputModeSave(psi, w);
shell_check_oom(pOMS);
- p->pModeStack[p->nSavedModes++] = pOMS;
+ psi->pModeStack[psi->nSavedModes++] = pOMS;
}
-static void outputModePush(ShellState *p){
- outputModePushSome(p, SWM_everything);
+static void outputModePush(ShellInState *psi){
+ outputModePushSome(psi, SWM_everything);
}
-static void outputModePop(ShellState *p){
+static void outputModePop(ShellInState *p){
OutputModeSave *pOMS;
assert(p->nSavedModes>0); /* Should not be here unless something pushed. */
if( p->nSavedModes==0 ) return;
** the null value. Strings are quoted if necessary. The separator
** is only issued if bSep is true.
*/
-static void output_csv(ShellState *p, const char *z, int bSep){
- FILE *out = p->out;
+static void output_csv(ShellExState *psx, const char *z, int bSep){
+ FILE *out = ISS(psx)->out;
+ char *zColSep = psx->zFieldSeparator;
if( z==0 ){
- utf8_printf(out,"%s",p->nullValue);
+ utf8_printf(out,"%s",psx->zNullValue);
}else{
unsigned i;
for(i=0; z[i]; i++){
break;
}
}
- if( i==0 || strstr(z, p->colSeparator)!=0 ){
+ if( i==0 || strstr(z, zColSep)!=0 ){
char *zQuoted = sqlite3_mprintf("\"%w\"", z);
shell_check_oom(zQuoted);
utf8_printf(out, "%s", zQuoted);
}
}
if( bSep ){
- utf8_printf(p->out, "%s", p->colSeparator);
+ utf8_printf(out, "%s", zColSep);
}
}
const char *zA3,
const char *zA4
){
- ShellState *p = (ShellState*)pClientData;
+ ShellExState *psx = (ShellExState*)pClientData;
static const char *azProhibitedFunctions[] = {
"edit",
"fts3_tokenizer",
UNUSED_PARAMETER(zA4);
switch( op ){
case SQLITE_ATTACH: {
- if ( failIfSafeMode(p, "cannot run ATTACH in safe mode") )
+ if ( failIfSafeMode(psx, "cannot run ATTACH in safe mode") )
return SQLITE_ERROR;
break;
}
int i;
for(i=0; i<ArraySize(azProhibitedFunctions); i++){
if( sqlite3_stricmp(zA1, azProhibitedFunctions[i])==0 ){
- if( failIfSafeMode(p, "cannot use the %s() function in safe mode",
+ if( failIfSafeMode(psx, "cannot use the %s() function in safe mode",
azProhibitedFunctions[i]) )
return SQLITE_ERROR;
}
const char *zA3,
const char *zA4
){
- ShellState *p = (ShellState*)pClientData;
+ ShellExState *psx = (ShellExState*)pClientData;
+ ShellInState *psi = ISS(psx);
static const char *azAction[] = { 0,
"CREATE_INDEX", "CREATE_TABLE", "CREATE_TEMP_INDEX",
"CREATE_TEMP_TABLE", "CREATE_TEMP_TRIGGER", "CREATE_TEMP_VIEW",
az[1] = zA2;
az[2] = zA3;
az[3] = zA4;
- utf8_printf(p->out, "authorizer: %s", azAction[op]);
+ utf8_printf(psi->out, "authorizer: %s", azAction[op]);
for(i=0; i<4; i++){
- raw_printf(p->out, " ");
+ raw_printf(psi->out, " ");
if( az[i] ){
- output_c_string(p->out, az[i]);
+ output_c_string(psi->out, az[i]);
}else{
- raw_printf(p->out, "NULL");
+ raw_printf(psi->out, "NULL");
}
}
- raw_printf(p->out, "\n");
- if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
+ raw_printf(psi->out, "\n");
+ if( psi->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
return SQLITE_OK;
}
#endif
/*
** Add a new entry to the EXPLAIN QUERY PLAN data
*/
-static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){
+static void eqp_append(ShellInState *psi, int iEqpId, int p2,
+ const char *zText){
EQPGraphRow *pNew;
int nText = strlen30(zText);
- if( p->autoEQPtest ){
- utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
+ if( psi->autoEQPtest ){
+ utf8_printf(psi->out, "%d,%d,%s\n", iEqpId, p2, zText);
}
pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
shell_check_oom(pNew);
pNew->iParentId = p2;
memcpy(pNew->zText, zText, nText+1);
pNew->pNext = 0;
- if( p->sGraph.pLast ){
- p->sGraph.pLast->pNext = pNew;
+ if( psi->sGraph.pLast ){
+ psi->sGraph.pLast->pNext = pNew;
}else{
- p->sGraph.pRow = pNew;
+ psi->sGraph.pRow = pNew;
}
- p->sGraph.pLast = pNew;
+ psi->sGraph.pLast = pNew;
}
/*
** Free and reset the EXPLAIN QUERY PLAN data that has been collected
** in p->sGraph.
*/
-static void eqp_reset(ShellState *p){
+static void eqp_reset(ShellInState *psi){
EQPGraphRow *pRow, *pNext;
- for(pRow = p->sGraph.pRow; pRow; pRow = pNext){
+ for(pRow = psi->sGraph.pRow; pRow; pRow = pNext){
pNext = pRow->pNext;
sqlite3_free(pRow);
}
- memset(&p->sGraph, 0, sizeof(p->sGraph));
+ memset(&psi->sGraph, 0, sizeof(psi->sGraph));
}
/* Return the next EXPLAIN QUERY PLAN line with iEqpId that occurs after
** pOld, or return the first such line if pOld is NULL
*/
-static EQPGraphRow *eqp_next_row(ShellState *p, int iEqpId, EQPGraphRow *pOld){
- EQPGraphRow *pRow = pOld ? pOld->pNext : p->sGraph.pRow;
+static EQPGraphRow *eqp_next_row(ShellInState *psi, int iEqpId,
+ EQPGraphRow *pOld){
+ EQPGraphRow *pRow = pOld ? pOld->pNext : psi->sGraph.pRow;
while( pRow && pRow->iParentId!=iEqpId ) pRow = pRow->pNext;
return pRow;
}
/* Render a single level of the graph that has iEqpId as its parent. Called
** recursively to render sublevels.
*/
-static void eqp_render_level(ShellState *p, int iEqpId){
+static void eqp_render_level(ShellInState *psi, int iEqpId){
EQPGraphRow *pRow, *pNext;
- int n = strlen30(p->sGraph.zPrefix);
+ int n = strlen30(psi->sGraph.zPrefix);
char *z;
- for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
- pNext = eqp_next_row(p, iEqpId, pRow);
+ for(pRow = eqp_next_row(psi, iEqpId, 0); pRow; pRow = pNext){
+ pNext = eqp_next_row(psi, iEqpId, pRow);
z = pRow->zText;
- utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix,
+ utf8_printf(psi->out, "%s%s%s\n", psi->sGraph.zPrefix,
pNext ? "|--" : "`--", z);
- if( n<(int)sizeof(p->sGraph.zPrefix)-7 ){
- memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
- eqp_render_level(p, pRow->iEqpId);
- p->sGraph.zPrefix[n] = 0;
+ if( n<(int)sizeof(psi->sGraph.zPrefix)-7 ){
+ memcpy(&psi->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
+ eqp_render_level(psi, pRow->iEqpId);
+ psi->sGraph.zPrefix[n] = 0;
}
}
}
/*
** Display and reset the EXPLAIN QUERY PLAN data
*/
-static void eqp_render(ShellState *p){
- EQPGraphRow *pRow = p->sGraph.pRow;
+static void eqp_render(ShellInState *psi){
+ EQPGraphRow *pRow = psi->sGraph.pRow;
if( pRow ){
if( pRow->zText[0]=='-' ){
if( pRow->pNext==0 ){
- eqp_reset(p);
+ eqp_reset(psi);
return;
}
- utf8_printf(p->out, "%s\n", pRow->zText+3);
- p->sGraph.pRow = pRow->pNext;
+ utf8_printf(psi->out, "%s\n", pRow->zText+3);
+ psi->sGraph.pRow = pRow->pNext;
sqlite3_free(pRow);
}else{
- utf8_printf(p->out, "QUERY PLAN\n");
+ utf8_printf(psi->out, "QUERY PLAN\n");
}
- p->sGraph.zPrefix[0] = 0;
- eqp_render_level(p, 0);
- eqp_reset(p);
+ psi->sGraph.zPrefix[0] = 0;
+ eqp_render_level(psi, 0);
+ eqp_reset(psi);
}
}
** Progress handler callback.
*/
static int progress_handler(void *pClientData) {
- ShellState *p = (ShellState*)pClientData;
- p->nProgress++;
- if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){
- raw_printf(p->out, "Progress limit reached (%u)\n", p->nProgress);
- if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
- if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0;
+ ShellInState *psi = (ShellInState*)pClientData;
+ psi->nProgress++;
+ if( psi->nProgress>=psi->mxProgress && psi->mxProgress>0 ){
+ raw_printf(psi->out, "Progress limit reached (%u)\n", psi->nProgress);
+ if( psi->flgProgress & SHELL_PROGRESS_RESET ) psi->nProgress = 0;
+ if( psi->flgProgress & SHELL_PROGRESS_ONCE ) psi->mxProgress = 0;
return 1;
}
- if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){
- raw_printf(p->out, "Progress %u\n", p->nProgress);
+ if( (psi->flgProgress & SHELL_PROGRESS_QUIET)==0 ){
+ raw_printf(psi->out, "Progress %u\n", psi->nProgress);
}
return 0;
}
** Print a markdown or table-style row separator using ascii-art
*/
static void print_row_separator(
- ShellState *p,
+ ShellExState *psx,
int nArg,
const char *zSep
){
int i;
if( nArg>0 ){
- fputs(zSep, p->out);
- print_dashes(p->out, p->actualWidth[0]+2);
+ fputs(zSep, ISS(psx)->out);
+ print_dashes(ISS(psx)->out, psx->pHaveWidths[0]+2);
for(i=1; i<nArg; i++){
- fputs(zSep, p->out);
- print_dashes(p->out, p->actualWidth[i]+2);
+ fputs(zSep, ISS(psx)->out);
+ print_dashes(ISS(psx)->out, psx->pHaveWidths[i]+2);
}
- fputs(zSep, p->out);
+ fputs(zSep, ISS(psx)->out);
}
- fputs("\n", p->out);
+ fputs("\n", ISS(psx)->out);
}
/*
int *aiType /* Column types. Might be NULL */
){
int i;
- ShellState *p = (ShellState*)pArg;
+ ShellExState *psx = (ShellExState*)pArg;
+ ShellInState *psi = ISS(psx);
+ FILE *out = psi->out;
if( azArg==0 ) return 0;
- switch( p->cMode ){
+ switch( psi->cMode ){
case MODE_Count:
case MODE_Off: {
break;
int len = strlen30(azCol[i] ? azCol[i] : "");
if( len>w ) w = len;
}
- if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator);
+ if( psx->resultCount++>0 ) utf8_printf(out, "%s", psi->rowSeparator);
for(i=0; i<nArg; i++){
- utf8_printf(p->out,"%*s = %s%s", w, azCol[i],
- azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
+ utf8_printf(out,"%*s = %s%s", w, azCol[i],
+ azArg[i] ? azArg[i] : psi->nullValue, psi->rowSeparator);
}
break;
}
if( nArg>ArraySize(aExplainWidth) ){
nArg = ArraySize(aExplainWidth);
}
- if( p->cnt++==0 ){
+ if( psx->resultCount++==0 ){
for(i=0; i<nArg; i++){
int w = aExplainWidth[i];
- utf8_width_print(p->out, w, azCol[i]);
- fputs(i==nArg-1 ? "\n" : " ", p->out);
+ utf8_width_print(out, w, azCol[i]);
+ fputs(i==nArg-1 ? "\n" : " ", out);
}
for(i=0; i<nArg; i++){
int w = aExplainWidth[i];
- print_dashes(p->out, w);
- fputs(i==nArg-1 ? "\n" : " ", p->out);
+ print_dashes(out, w);
+ fputs(i==nArg-1 ? "\n" : " ", out);
}
}
if( azArg==0 ) break;
if( azArg[i] && strlenChar(azArg[i])>w ){
w = strlenChar(azArg[i]);
}
- if( i==1 && p->aiIndent && p->pStmt ){
- if( p->iIndent<p->nIndent ){
- utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
+ if( i==1 && psi->aiIndent && psi->pStmt ){
+ if( psi->iIndent<psi->nIndent ){
+ utf8_printf(out, "%*.s", psi->aiIndent[psi->iIndent], "");
}
- p->iIndent++;
+ psi->iIndent++;
}
- utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
- fputs(i==nArg-1 ? "\n" : " ", p->out);
+ utf8_width_print(out, w, azArg[i] ? azArg[i] : psi->nullValue);
+ fputs(i==nArg-1 ? "\n" : " ", out);
}
break;
}
case MODE_Semi: { /* .schema and .fullschema output */
- printSchemaLine(p->out, azArg[0], ";\n");
+ printSchemaLine(out, azArg[0], ";\n");
break;
}
case MODE_Pretty: { /* .schema and .fullschema with --indent */
if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
|| sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
){
- utf8_printf(p->out, "%s;\n", azArg[0]);
+ utf8_printf(out, "%s;\n", azArg[0]);
break;
}
z = sqlite3_mprintf("%s", azArg[0]);
}else if( c==')' ){
nParen--;
if( nLine>0 && nParen==0 && j>0 ){
- printSchemaLineN(p->out, z, j, "\n");
+ printSchemaLineN(out, z, j, "\n");
j = 0;
}
}
&& (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
){
if( c=='\n' ) j--;
- printSchemaLineN(p->out, z, j, "\n ");
+ printSchemaLineN(out, z, j, "\n ");
j = 0;
nLine++;
while( IsSpace(z[i+1]) ){ i++; }
}
z[j] = 0;
}
- printSchemaLine(p->out, z, ";\n");
+ printSchemaLine(out, z, ";\n");
sqlite3_free(z);
break;
}
case MODE_List: {
- if( p->cnt++==0 && p->showHeader ){
+ if( psx->resultCount++==0 && psi->showHeader ){
for(i=0; i<nArg; i++){
- utf8_printf(p->out,"%s%s",azCol[i],
- i==nArg-1 ? p->rowSeparator : p->colSeparator);
+ utf8_printf(out,"%s%s",azCol[i],
+ i==nArg-1 ? psi->rowSeparator : psi->colSeparator);
}
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
char *z = azArg[i];
- if( z==0 ) z = p->nullValue;
- utf8_printf(p->out, "%s", z);
+ if( z==0 ) z = psi->nullValue;
+ utf8_printf(out, "%s", z);
if( i<nArg-1 ){
- utf8_printf(p->out, "%s", p->colSeparator);
+ utf8_printf(out, "%s", psi->colSeparator);
}else{
- utf8_printf(p->out, "%s", p->rowSeparator);
+ utf8_printf(out, "%s", psi->rowSeparator);
}
}
break;
}
case MODE_Html: {
- if( p->cnt++==0 && p->showHeader ){
- raw_printf(p->out,"<TR>");
+ if( psx->resultCount++==0 && psi->showHeader ){
+ raw_printf(out,"<TR>");
for(i=0; i<nArg; i++){
- raw_printf(p->out,"<TH>");
- output_html_string(p->out, azCol[i]);
- raw_printf(p->out,"</TH>\n");
+ raw_printf(out,"<TH>");
+ output_html_string(out, azCol[i]);
+ raw_printf(out,"</TH>\n");
}
- raw_printf(p->out,"</TR>\n");
+ raw_printf(out,"</TR>\n");
}
if( azArg==0 ) break;
- raw_printf(p->out,"<TR>");
+ raw_printf(out,"<TR>");
for(i=0; i<nArg; i++){
- raw_printf(p->out,"<TD>");
- output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
- raw_printf(p->out,"</TD>\n");
+ raw_printf(out,"<TD>");
+ output_html_string(out, azArg[i] ? azArg[i] : psi->nullValue);
+ raw_printf(out,"</TD>\n");
}
- raw_printf(p->out,"</TR>\n");
+ raw_printf(out,"</TR>\n");
break;
}
case MODE_Tcl: {
- if( p->cnt++==0 && p->showHeader ){
+ if( psx->resultCount++==0 && psi->showHeader ){
for(i=0; i<nArg; i++){
- output_c_string(p->out,azCol[i] ? azCol[i] : "");
- if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
+ output_c_string(out,azCol[i] ? azCol[i] : "");
+ if(i<nArg-1) utf8_printf(out, "%s", psi->colSeparator);
}
- utf8_printf(p->out, "%s", p->rowSeparator);
+ utf8_printf(out, "%s", psi->rowSeparator);
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
- if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
+ output_c_string(out, azArg[i] ? azArg[i] : psi->nullValue);
+ if(i<nArg-1) utf8_printf(out, "%s", psi->colSeparator);
}
- utf8_printf(p->out, "%s", p->rowSeparator);
+ utf8_printf(out, "%s", psi->rowSeparator);
break;
}
case MODE_Csv: {
- setBinaryMode(p->out, 1);
- if( p->cnt++==0 && p->showHeader ){
+ setBinaryMode(out, 1);
+ if( psx->resultCount++==0 && psi->showHeader ){
for(i=0; i<nArg; i++){
- output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
+ output_csv(psx, azCol[i] ? azCol[i] : "", i<nArg-1);
}
- utf8_printf(p->out, "%s", p->rowSeparator);
+ utf8_printf(out, "%s", psi->rowSeparator);
}
if( nArg>0 ){
for(i=0; i<nArg; i++){
- output_csv(p, azArg[i], i<nArg-1);
+ output_csv(psx, azArg[i], i<nArg-1);
}
- utf8_printf(p->out, "%s", p->rowSeparator);
+ utf8_printf(out, "%s", psi->rowSeparator);
}
- setTextMode(p->out, 1);
+ setTextMode(out, 1);
break;
}
case MODE_Insert: {
if( azArg==0 ) break;
- utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
- if( p->showHeader ){
- raw_printf(p->out,"(");
+ utf8_printf(out,"INSERT INTO %s",psx->zDestTable);
+ if( psi->showHeader ){
+ raw_printf(out,"(");
for(i=0; i<nArg; i++){
- if( i>0 ) raw_printf(p->out, ",");
+ if( i>0 ) raw_printf(out, ",");
if( quoteChar(azCol[i]) ){
char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
shell_check_oom(z);
- utf8_printf(p->out, "%s", z);
+ utf8_printf(out, "%s", z);
sqlite3_free(z);
}else{
- raw_printf(p->out, "%s", azCol[i]);
+ raw_printf(out, "%s", azCol[i]);
}
}
- raw_printf(p->out,")");
+ raw_printf(out,")");
}
- p->cnt++;
+ psx->resultCount++;
for(i=0; i<nArg; i++){
- raw_printf(p->out, i>0 ? "," : " VALUES(");
+ raw_printf(out, i>0 ? "," : " VALUES(");
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- utf8_printf(p->out,"NULL");
+ utf8_printf(out,"NULL");
}else if( aiType && aiType[i]==SQLITE_TEXT ){
- if( ShellHasFlag(p, SHFLG_Newlines) ){
- output_quoted_string(p->out, azArg[i]);
+ if( ShellHasFlag(psx, SHFLG_Newlines) ){
+ output_quoted_string(out, azArg[i]);
}else{
- output_quoted_escaped_string(p->out, azArg[i]);
+ output_quoted_escaped_string(out, azArg[i]);
}
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
- utf8_printf(p->out,"%s", azArg[i]);
+ utf8_printf(out,"%s", azArg[i]);
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
char z[50];
- double r = sqlite3_column_double(p->pStmt, i);
+ double r = sqlite3_column_double(psi->pStmt, i);
sqlite3_uint64 ur;
memcpy(&ur,&r,sizeof(r));
if( ur==0x7ff0000000000000LL ){
- raw_printf(p->out, "1e999");
+ raw_printf(out, "1e999");
}else if( ur==0xfff0000000000000LL ){
- raw_printf(p->out, "-1e999");
+ raw_printf(out, "-1e999");
}else{
sqlite3_int64 ir = (sqlite3_int64)r;
if( r==(double)ir ){
}else{
sqlite3_snprintf(50,z,"%!.20g", r);
}
- raw_printf(p->out, "%s", z);
+ raw_printf(out, "%s", z);
}
- }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
- const void *pBlob = sqlite3_column_blob(p->pStmt, i);
- int nBlob = sqlite3_column_bytes(p->pStmt, i);
- output_hex_blob(p->out, pBlob, nBlob);
+ }else if( aiType && aiType[i]==SQLITE_BLOB && psi->pStmt ){
+ const void *pBlob = sqlite3_column_blob(psi->pStmt, i);
+ int nBlob = sqlite3_column_bytes(psi->pStmt, i);
+ output_hex_blob(out, pBlob, nBlob);
}else if( isNumber(azArg[i], 0) ){
- utf8_printf(p->out,"%s", azArg[i]);
- }else if( ShellHasFlag(p, SHFLG_Newlines) ){
- output_quoted_string(p->out, azArg[i]);
+ utf8_printf(out,"%s", azArg[i]);
+ }else if( ShellHasFlag(psx, SHFLG_Newlines) ){
+ output_quoted_string(out, azArg[i]);
}else{
- output_quoted_escaped_string(p->out, azArg[i]);
+ output_quoted_escaped_string(out, azArg[i]);
}
}
- raw_printf(p->out,");\n");
+ raw_printf(out,");\n");
break;
}
case MODE_Json: {
if( azArg==0 ) break;
- if( p->cnt==0 ){
- fputs("[{", p->out);
+ if( psx->resultCount==0 ){
+ fputs("[{", out);
}else{
- fputs(",\n{", p->out);
+ fputs(",\n{", out);
}
- p->cnt++;
+ psx->resultCount++;
for(i=0; i<nArg; i++){
- output_json_string(p->out, azCol[i], -1);
- putc(':', p->out);
+ output_json_string(out, azCol[i], -1);
+ putc(':', out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- fputs("null",p->out);
+ fputs("null",out);
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
char z[50];
- double r = sqlite3_column_double(p->pStmt, i);
+ double r = sqlite3_column_double(psi->pStmt, i);
sqlite3_uint64 ur;
memcpy(&ur,&r,sizeof(r));
if( ur==0x7ff0000000000000LL ){
- raw_printf(p->out, "1e999");
+ raw_printf(out, "1e999");
}else if( ur==0xfff0000000000000LL ){
- raw_printf(p->out, "-1e999");
+ raw_printf(out, "-1e999");
}else{
sqlite3_snprintf(50,z,"%!.20g", r);
- raw_printf(p->out, "%s", z);
+ raw_printf(out, "%s", z);
}
- }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
- const void *pBlob = sqlite3_column_blob(p->pStmt, i);
- int nBlob = sqlite3_column_bytes(p->pStmt, i);
- output_json_string(p->out, pBlob, nBlob);
+ }else if( aiType && aiType[i]==SQLITE_BLOB && psi->pStmt ){
+ const void *pBlob = sqlite3_column_blob(psi->pStmt, i);
+ int nBlob = sqlite3_column_bytes(psi->pStmt, i);
+ output_json_string(out, pBlob, nBlob);
}else if( aiType && aiType[i]==SQLITE_TEXT ){
- output_json_string(p->out, azArg[i], -1);
+ output_json_string(out, azArg[i], -1);
}else{
- utf8_printf(p->out,"%s", azArg[i]);
+ utf8_printf(out,"%s", azArg[i]);
}
if( i<nArg-1 ){
- putc(',', p->out);
+ putc(',', out);
}
}
- putc('}', p->out);
+ putc('}', out);
break;
}
case MODE_Quote: {
if( azArg==0 ) break;
- if( p->cnt==0 && p->showHeader ){
+ if( psx->resultCount==0 && psi->showHeader ){
for(i=0; i<nArg; i++){
- if( i>0 ) fputs(p->colSeparator, p->out);
- output_quoted_string(p->out, azCol[i]);
+ if( i>0 ) fputs(psi->colSeparator, out);
+ output_quoted_string(out, azCol[i]);
}
- fputs(p->rowSeparator, p->out);
+ fputs(psi->rowSeparator, out);
}
- p->cnt++;
+ psx->resultCount++;
for(i=0; i<nArg; i++){
- if( i>0 ) fputs(p->colSeparator, p->out);
+ if( i>0 ) fputs(psi->colSeparator, out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- utf8_printf(p->out,"NULL");
+ utf8_printf(out,"NULL");
}else if( aiType && aiType[i]==SQLITE_TEXT ){
- output_quoted_string(p->out, azArg[i]);
+ output_quoted_string(out, azArg[i]);
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
- utf8_printf(p->out,"%s", azArg[i]);
+ utf8_printf(out,"%s", azArg[i]);
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
char z[50];
- double r = sqlite3_column_double(p->pStmt, i);
+ double r = sqlite3_column_double(psi->pStmt, i);
sqlite3_snprintf(50,z,"%!.20g", r);
- raw_printf(p->out, "%s", z);
- }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
- const void *pBlob = sqlite3_column_blob(p->pStmt, i);
- int nBlob = sqlite3_column_bytes(p->pStmt, i);
- output_hex_blob(p->out, pBlob, nBlob);
+ raw_printf(out, "%s", z);
+ }else if( aiType && aiType[i]==SQLITE_BLOB && psi->pStmt ){
+ const void *pBlob = sqlite3_column_blob(psi->pStmt, i);
+ int nBlob = sqlite3_column_bytes(psi->pStmt, i);
+ output_hex_blob(out, pBlob, nBlob);
}else if( isNumber(azArg[i], 0) ){
- utf8_printf(p->out,"%s", azArg[i]);
+ utf8_printf(out,"%s", azArg[i]);
}else{
- output_quoted_string(p->out, azArg[i]);
+ output_quoted_string(out, azArg[i]);
}
}
- fputs(p->rowSeparator, p->out);
+ fputs(psi->rowSeparator, out);
break;
}
case MODE_Ascii: {
- if( p->cnt++==0 && p->showHeader ){
+ if( psx->resultCount++==0 && psi->showHeader ){
for(i=0; i<nArg; i++){
- if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
- utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : "");
+ if( i>0 ) utf8_printf(out, "%s", psi->colSeparator);
+ utf8_printf(out,"%s",azCol[i] ? azCol[i] : "");
}
- utf8_printf(p->out, "%s", p->rowSeparator);
+ utf8_printf(out, "%s", psi->rowSeparator);
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
- utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
+ if( i>0 ) utf8_printf(out, "%s", psi->colSeparator);
+ utf8_printf(out,"%s",azArg[i] ? azArg[i] : psi->nullValue);
}
- utf8_printf(p->out, "%s", p->rowSeparator);
+ utf8_printf(out, "%s", psi->rowSeparator);
break;
}
case MODE_EQP: {
- eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]);
+ eqp_append(psi, atoi(azArg[0]), atoi(azArg[1]), azArg[3]);
break;
}
}
/*
** Generate an appropriate SELFTEST table in the main database.
*/
-static void createSelftestTable(ShellState *p){
+static void createSelftestTable(ShellInState *p){
char *zErrMsg = 0;
- sqlite3_exec(p->db,
+ sqlite3_exec(DBI(p),
"SAVEPOINT selftest_init;\n"
"CREATE TABLE IF NOT EXISTS selftest(\n"
" tno INTEGER PRIMARY KEY,\n" /* Test number */
utf8_printf(STD_ERR, "SELFTEST initialization failure: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
- sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
+ sqlite3_exec(DBI(p), "RELEASE selftest_init",0,0,0);
}
/*
-** Set the destination table field of the ShellState structure to
+** Set the destination table field of the shell state structure to
** the name of the table given. Escape any quote characters in the
** table name.
*/
-static void set_table_name(ShellState *p, const char *zName){
+static void set_table_name(ShellExState *psx, const char *zName){
int i, n;
char cQuote;
char *z;
- if( p->zDestTable ){
- free(p->zDestTable);
- p->zDestTable = 0;
+ if( psx->zDestTable ){
+ free((void *)(psx->zDestTable));
+ psx->zDestTable = 0;
}
if( zName==0 ) return;
cQuote = quoteChar(zName);
n = strlen30(zName);
if( cQuote ) n += n+2;
- z = p->zDestTable = malloc( n+1 );
+ psx->zDestTable = (z = malloc( n+1 ));
shell_check_oom(z);
n = 0;
if( cQuote ) z[n++] = cQuote;
** won't consume the semicolon terminator.
*/
static int run_table_dump_query(
- ShellState *p, /* Query context */
+ ShellInState *psi, /* Query context */
const char *zSelect /* SELECT statement to extract content */
){
sqlite3_stmt *pSelect;
int nResult;
int i;
const char *z;
- rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
+ rc = sqlite3_prepare_v2(DBI(psi), zSelect, -1, &pSelect, 0);
if( rc!=SQLITE_OK || !pSelect ){
- char *zContext = shell_error_context(zSelect, p->db);
- utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n%s", rc,
- sqlite3_errmsg(p->db), zContext);
+ char *zContext = shell_error_context(zSelect, DBI(psi));
+ utf8_printf(psi->out, "/**** ERROR: (%d) %s *****/\n%s", rc,
+ sqlite3_errmsg(DBI(psi)), zContext);
sqlite3_free(zContext);
- if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
+ if( (rc&0xff)!=SQLITE_CORRUPT ) psi->nErr++;
return rc;
}
rc = sqlite3_step(pSelect);
nResult = sqlite3_column_count(pSelect);
while( rc==SQLITE_ROW ){
z = (const char*)sqlite3_column_text(pSelect, 0);
- utf8_printf(p->out, "%s", z);
+ utf8_printf(psi->out, "%s", z);
for(i=1; i<nResult; i++){
- utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
+ utf8_printf(psi->out, ",%s", sqlite3_column_text(pSelect, i));
}
if( z==0 ) z = "";
while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
if( z[0] ){
- raw_printf(p->out, "\n;\n");
+ raw_printf(psi->out, "\n;\n");
}else{
- raw_printf(p->out, ";\n");
+ raw_printf(psi->out, ";\n");
}
rc = sqlite3_step(pSelect);
}
rc = sqlite3_finalize(pSelect);
if( rc!=SQLITE_OK ){
- utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
- sqlite3_errmsg(p->db));
- if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
+ utf8_printf(psi->out, "/**** ERROR: (%d) %s *****/\n", rc,
+ sqlite3_errmsg(DBI(psi)));
+ if( (rc&0xff)!=SQLITE_CORRUPT ) psi->nErr++;
}
return rc;
}
** Display a single line of status using 64-bit values.
*/
static void displayStatLine(
- ShellState *p, /* The shell context */
+ ShellInState *psi, /* The shell context (internal) */
char *zLabel, /* Label for this one line */
char *zFormat, /* Format for the result */
int iStatusCtrl, /* Which status to display */
}else{
sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
}
- raw_printf(p->out, "%-36s %s\n", zLabel, zLine);
+ raw_printf(psi->out, "%-36s %s\n", zLabel, zLine);
}
/*
*/
static int display_stats(
sqlite3 *db, /* Database to query */
- ShellState *pArg, /* Pointer to ShellState */
+ ShellInState *psi, /* Pointer to shell internal state */
int bReset /* True to reset the stats */
){
int iCur;
int iHiwtr;
FILE *out;
- if( pArg==0 || pArg->out==0 ) return 0;
- out = pArg->out;
+ if( psi==0 || psi->out==0 ) return 0;
+ out = psi->out;
- if( pArg->pStmt && pArg->statsOn==2 ){
+ if( psi->pStmt && psi->statsOn==2 ){
int nCol, i, x;
- sqlite3_stmt *pStmt = pArg->pStmt;
+ sqlite3_stmt *pStmt = psi->pStmt;
char z[100];
nCol = sqlite3_column_count(pStmt);
raw_printf(out, "%-36s %d\n", "Number of output columns:", nCol);
}
}
- if( pArg->statsOn==3 ){
- if( pArg->pStmt ){
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
- raw_printf(pArg->out, "VM-steps: %d\n", iCur);
+ if( psi->statsOn==3 ){
+ if( psi->pStmt ){
+ iCur = sqlite3_stmt_status(psi->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
+ raw_printf(psi->out, "VM-steps: %d\n", iCur);
}
return 0;
}
- displayStatLine(pArg, "Memory Used:",
+ displayStatLine(psi, "Memory Used:",
"%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
- displayStatLine(pArg, "Number of Outstanding Allocations:",
+ displayStatLine(psi, "Number of Outstanding Allocations:",
"%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
- if( pArg->shellFlgs & SHFLG_Pagecache ){
- displayStatLine(pArg, "Number of Pcache Pages Used:",
+ if( psi->shellFlgs & SHFLG_Pagecache ){
+ displayStatLine(psi, "Number of Pcache Pages Used:",
"%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
}
- displayStatLine(pArg, "Number of Pcache Overflow Bytes:",
+ displayStatLine(psi, "Number of Pcache Overflow Bytes:",
"%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
- displayStatLine(pArg, "Largest Allocation:",
+ displayStatLine(psi, "Largest Allocation:",
"%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
- displayStatLine(pArg, "Largest Pcache Allocation:",
+ displayStatLine(psi, "Largest Pcache Allocation:",
"%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
#ifdef YYTRACKMAXSTACKDEPTH
- displayStatLine(pArg, "Deepest Parser Stack:",
+ displayStatLine(psi, "Deepest Parser Stack:",
"%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
#endif
if( db ){
- if( pArg->shellFlgs & SHFLG_Lookaside ){
+ if( psi->shellFlgs & SHFLG_Lookaside ){
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
&iCur, &iHiwtr, bReset);
- raw_printf(pArg->out,
+ raw_printf(psi->out,
"Lookaside Slots Used: %d (max %d)\n",
iCur, iHiwtr);
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
&iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Successful lookaside attempts: %d\n",
+ raw_printf(psi->out, "Successful lookaside attempts: %d\n",
iHiwtr);
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
&iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Lookaside failures due to size: %d\n",
+ raw_printf(psi->out, "Lookaside failures due to size: %d\n",
iHiwtr);
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
&iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Lookaside failures due to OOM: %d\n",
+ raw_printf(psi->out, "Lookaside failures due to OOM: %d\n",
iHiwtr);
}
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Pager Heap Usage: %d bytes\n",
+ raw_printf(psi->out, "Pager Heap Usage: %d bytes\n",
iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
- raw_printf(pArg->out, "Page cache hits: %d\n", iCur);
+ raw_printf(psi->out, "Page cache hits: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
- raw_printf(pArg->out, "Page cache misses: %d\n", iCur);
+ raw_printf(psi->out, "Page cache misses: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
- raw_printf(pArg->out, "Page cache writes: %d\n", iCur);
+ raw_printf(psi->out, "Page cache writes: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1);
- raw_printf(pArg->out, "Page cache spills: %d\n", iCur);
+ raw_printf(psi->out, "Page cache spills: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Schema Heap Usage: %d bytes\n",
+ raw_printf(psi->out, "Schema Heap Usage: %d bytes\n",
iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n",
+ raw_printf(psi->out, "Statement Heap/Lookaside Usage: %d bytes\n",
iCur);
}
- if( pArg->pStmt ){
+ if( psi->pStmt ){
int iHit, iMiss;
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
+ iCur = sqlite3_stmt_status(psi->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
bReset);
- raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur);
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
- raw_printf(pArg->out, "Sort Operations: %d\n", iCur);
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
- raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur);
- iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT, bReset);
- iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS, bReset);
+ raw_printf(psi->out, "Fullscan Steps: %d\n", iCur);
+ iCur = sqlite3_stmt_status(psi->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
+ raw_printf(psi->out, "Sort Operations: %d\n", iCur);
+ iCur = sqlite3_stmt_status(psi->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
+ raw_printf(psi->out, "Autoindex Inserts: %d\n", iCur);
+ iHit = sqlite3_stmt_status(psi->pStmt, SQLITE_STMTSTATUS_FILTER_HIT, bReset);
+ iMiss = sqlite3_stmt_status(psi->pStmt, SQLITE_STMTSTATUS_FILTER_MISS, bReset);
if( iHit || iMiss ){
- raw_printf(pArg->out, "Bloom filter bypass taken: %d/%d\n",
+ raw_printf(psi->out, "Bloom filter bypass taken: %d/%d\n",
iHit, iHit+iMiss);
}
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
- raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
- raw_printf(pArg->out, "Reprepare operations: %d\n", iCur);
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
- raw_printf(pArg->out, "Number of times run: %d\n", iCur);
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset);
- raw_printf(pArg->out, "Memory used by prepared stmt: %d\n", iCur);
+ iCur = sqlite3_stmt_status(psi->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
+ raw_printf(psi->out, "Virtual Machine Steps: %d\n", iCur);
+ iCur = sqlite3_stmt_status(psi->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
+ raw_printf(psi->out, "Reprepare operations: %d\n", iCur);
+ iCur = sqlite3_stmt_status(psi->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
+ raw_printf(psi->out, "Number of times run: %d\n", iCur);
+ iCur = sqlite3_stmt_status(psi->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset);
+ raw_printf(psi->out, "Memory used by prepared stmt: %d\n", iCur);
}
#ifdef __linux__
- displayLinuxIoStats(pArg->out);
+ displayLinuxIoStats(psi->out);
#endif
/* Do not remove this machine readable comment: extra-stats-output-here */
/*
** Display scan stats.
*/
-static void display_scanstats(
- sqlite3 *db, /* Database to query */
- ShellState *pArg /* Pointer to ShellState */
-){
+static void display_scanstats(ShellInState *psi){
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
- UNUSED_PARAMETER(db);
- UNUSED_PARAMETER(pArg);
+ UNUSED_PARAMETER(psi);
#else
int i, k, n, mx;
- raw_printf(pArg->out, "-------- scanstats --------\n");
+ raw_printf(psi->out, "-------- scanstats --------\n");
mx = 0;
for(k=0; k<=mx; k++){
double rEstLoop = 1.0;
for(i=n=0; 1; i++){
- sqlite3_stmt *p = pArg->pStmt;
+ sqlite3_stmt *p = psi->pStmt;
sqlite3_int64 nLoop, nVisit;
double rEst;
int iSid;
if( iSid!=k ) continue;
if( n==0 ){
rEstLoop = (double)nLoop;
- if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k);
+ if( k>0 ) raw_printf(psi->out, "-------- subquery %d -------\n", k);
}
n++;
sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
- utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain);
+ utf8_printf(psi->out, "Loop %2d: %s\n", n, zExplain);
rEstLoop *= rEst;
- raw_printf(pArg->out,
+ raw_printf(psi->out,
" nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
);
}
}
- raw_printf(pArg->out, "---------------------------\n");
+ raw_printf(psi->out, "---------------------------\n");
#endif
}
/*
** If compiled statement pSql appears to be an EXPLAIN statement, allocate
-** and populate the ShellState.aiIndent[] array with the number of
+** and populate the ShellInState.aiIndent[] array with the number of
** spaces each opcode should be indented before it is output.
**
** The indenting rules are:
** then indent all opcodes between the earlier instruction
** and "Goto" by 2 spaces.
*/
-static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
+static void explain_data_prepare(ShellInState *psi, sqlite3_stmt *pSql){
const char *zSql; /* The text of the SQL statement */
const char *z; /* Used to check if this is an EXPLAIN */
int *abYield = 0; /* True if op is an OP_Yield */
/* Try to figure out if this is really an EXPLAIN statement. If this
** cannot be verified, return early. */
if( sqlite3_column_count(pSql)!=8 ){
- p->cMode = p->mode;
+ psi->cMode = psi->mode;
return;
}
zSql = sqlite3_sql(pSql);
if( zSql==0 ) return;
for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
if( sqlite3_strnicmp(z, "explain", 7) ){
- p->cMode = p->mode;
+ psi->cMode = psi->mode;
return;
}
int jj;
for(jj=0; jj<ArraySize(explainCols); jj++){
if( strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
- p->cMode = p->mode;
+ psi->cMode = psi->mode;
sqlite3_reset(pSql);
return;
}
}
}
nAlloc += 100;
- p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
- shell_check_oom(p->aiIndent);
+ psi->aiIndent =
+ (int*)sqlite3_realloc64(psi->aiIndent, nAlloc*sizeof(int));
+ shell_check_oom(psi->aiIndent);
abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
shell_check_oom(abYield);
}
abYield[iOp] = str_in_array(zOp, azYield);
- p->aiIndent[iOp] = 0;
- p->nIndent = iOp+1;
+ psi->aiIndent[iOp] = 0;
+ psi->nIndent = iOp+1;
if( str_in_array(zOp, azNext) ){
- for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
+ for(i=p2op; i<iOp; i++) psi->aiIndent[i] += 2;
}
- if( str_in_array(zOp, azGoto) && p2op<p->nIndent
+ if( str_in_array(zOp, azGoto) && p2op<psi->nIndent
&& (abYield[p2op] || sqlite3_column_int(pSql, 2))
){
- for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
+ for(i=p2op; i<iOp; i++) psi->aiIndent[i] += 2;
}
}
- p->iIndent = 0;
+ psi->iIndent = 0;
sqlite3_free(abYield);
sqlite3_reset(pSql);
}
/*
** Free the array allocated by explain_data_prepare().
*/
-static void explain_data_delete(ShellState *p){
- sqlite3_free(p->aiIndent);
- p->aiIndent = 0;
- p->nIndent = 0;
- p->iIndent = 0;
+static void explain_data_delete(ShellInState *psi){
+ sqlite3_free(psi->aiIndent);
+ psi->aiIndent = 0;
+ psi->nIndent = 0;
+ psi->iIndent = 0;
}
/*
#define PARAM_STORE_SNAME PARAM_STORE_SCHEMA"."PARAM_STORE_NAME
/* Create the TEMP table used to store parameter bindings and SQL statements */
-static void param_table_init(ShellState *p){
- DbProtectState dps = allow_sys_schema_change(p->db);
- sqlite3_exec(p->db,
+static void param_table_init(sqlite3 *db){
+ DbProtectState dps = allow_sys_schema_change(db);
+ sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS "PARAM_TABLE_SNAME"(\n"
" key TEXT PRIMARY KEY,\n"
" value,\n"
" uses INT DEFAULT (0)" /* aka PTU_Binding */
") WITHOUT ROWID;",
0, 0, 0);
- restore_sys_schema_protection( p->db, &dps );
+ restore_sys_schema_protection( db, &dps );
}
/* Tell whether the above-created table exists, return true iff exists. */
** Draw a horizontal separator for a MODE_Box table.
*/
static void print_box_row_separator(
- ShellState *p,
+ ShellExState *psx,
int nArg,
const char *zSep1,
const char *zSep2,
const char *zSep3
){
int i;
+ FILE *out = ISS(psx)->out;
if( nArg>0 ){
- utf8_printf(p->out, "%s", zSep1);
- print_box_line(p->out, p->actualWidth[0]+2);
+ utf8_printf(out, "%s", zSep1);
+ print_box_line(out, psx->pHaveWidths[0]+2);
for(i=1; i<nArg; i++){
- utf8_printf(p->out, "%s", zSep2);
- print_box_line(p->out, p->actualWidth[i]+2);
+ utf8_printf(out, "%s", zSep2);
+ print_box_line(out, psx->pHaveWidths[i]+2);
}
- utf8_printf(p->out, "%s", zSep3);
+ utf8_printf(out, "%s", zSep3);
}
- fputs("\n", p->out);
+ fputs("\n", out);
}
/*
** any output.
*/
static void exec_prepared_stmt_columnar(
- ShellState *p, /* Pointer to ShellState */
+ ShellExState *psx, /* Pointer to shell state */
sqlite3_stmt *pStmt /* Statment to run */
){
+ ShellInState *psi = ISS(psx);
sqlite3_int64 nRow = 0;
int nColumn = 0;
char **azData = 0;
const unsigned char **azNextLine = 0;
int bNextLine = 0;
int bMultiLineRowExists = 0;
- int bw = p->cmOpts.bWordWrap;
+ int bw = psi->cmOpts.bWordWrap;
rc = sqlite3_step(pStmt);
if( rc!=SQLITE_ROW ) return;
azNextLine = sqlite3_malloc64( nColumn*sizeof(char*) );
shell_check_oom((void*)azNextLine);
memset((void*)azNextLine, 0, nColumn*sizeof(char*) );
- if( p->cmOpts.bQuote ){
+ if( psi->cmOpts.bQuote ){
azQuoted = sqlite3_malloc64( nColumn*sizeof(char*) );
shell_check_oom(azQuoted);
memset(azQuoted, 0, nColumn*sizeof(char*) );
}
abRowDiv = sqlite3_malloc64( nAlloc/nColumn );
shell_check_oom(abRowDiv);
- if( nColumn>p->nWidth ){
- p->colWidth = realloc(p->colWidth, (nColumn+1)*2*sizeof(int));
- shell_check_oom(p->colWidth);
- for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
- p->nWidth = nColumn;
- p->actualWidth = &p->colWidth[nColumn];
- }
- memset(p->actualWidth, 0, nColumn*sizeof(int));
+ if( nColumn>psx->numWidths ){
+ psx->pSpecWidths = realloc(psx->pSpecWidths, (nColumn+1)*2*sizeof(int));
+ shell_check_oom(psx->pSpecWidths);
+ for(i=psx->numWidths; i<nColumn; i++) psx->pSpecWidths[i] = 0;
+ psx->numWidths = nColumn;
+ psx->pHaveWidths = &psx->pSpecWidths[nColumn];
+ }
+ memset(psx->pHaveWidths, 0, nColumn*sizeof(int));
for(i=0; i<nColumn; i++){
- w = p->colWidth[i];
+ w = psx->pSpecWidths[i];
if( w<0 ) w = -w;
- p->actualWidth[i] = w;
+ psx->pHaveWidths[i] = w;
}
for(i=0; i<nColumn; i++){
const unsigned char *zNotUsed;
- int wx = p->colWidth[i];
+ int wx = psx->pSpecWidths[i];
if( wx==0 ){
- wx = p->cmOpts.iWrap;
+ wx = psi->cmOpts.iWrap;
}
if( wx<0 ) wx = -wx;
uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
abRowDiv[nRow] = 1;
nRow++;
for(i=0; i<nColumn; i++){
- int wx = p->colWidth[i];
+ int wx = psx->pSpecWidths[i];
if( wx==0 ){
- wx = p->cmOpts.iWrap;
+ wx = psi->cmOpts.iWrap;
}
if( wx<0 ) wx = -wx;
if( useNextLine ){
uz = azNextLine[i];
- }else if( p->cmOpts.bQuote ){
+ }else if( psi->cmOpts.bQuote ){
sqlite3_free(azQuoted[i]);
azQuoted[i] = quoted_column(pStmt,i);
uz = (const unsigned char*)azQuoted[i];
nTotal = nColumn*(nRow+1);
for(i=0; i<nTotal; i++){
z = azData[i];
- if( z==0 ) z = p->nullValue;
+ if( z==0 ) z = psi->nullValue;
n = strlenChar(z);
j = i%nColumn;
- if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
+ if( n>psx->pHaveWidths[j] ) psx->pHaveWidths[j] = n;
}
if( seenInterrupt ) goto columnar_end;
if( nColumn==0 ) goto columnar_end;
- switch( p->cMode ){
+ switch( psi->cMode ){
case MODE_Column: {
colSep = " ";
rowSep = "\n";
- if( p->showHeader ){
+ if( psi->showHeader ){
for(i=0; i<nColumn; i++){
- w = p->actualWidth[i];
- if( p->colWidth[i]<0 ) w = -w;
- utf8_width_print(p->out, w, azData[i]);
- fputs(i==nColumn-1?"\n":" ", p->out);
+ w = psx->pHaveWidths[i];
+ if( psx->pSpecWidths[i]<0 ) w = -w;
+ utf8_width_print(psi->out, w, azData[i]);
+ fputs(i==nColumn-1?"\n":" ", psi->out);
}
for(i=0; i<nColumn; i++){
- print_dashes(p->out, p->actualWidth[i]);
- fputs(i==nColumn-1?"\n":" ", p->out);
+ print_dashes(psi->out, psx->pHaveWidths[i]);
+ fputs(i==nColumn-1?"\n":" ", psi->out);
}
}
break;
case MODE_Table: {
colSep = " | ";
rowSep = " |\n";
- print_row_separator(p, nColumn, "+");
- fputs("| ", p->out);
+ print_row_separator(psx, nColumn, "+");
+ fputs("| ", psi->out);
for(i=0; i<nColumn; i++){
- w = p->actualWidth[i];
+ w = psx->pHaveWidths[i];
n = strlenChar(azData[i]);
- utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
- fputs(i==nColumn-1?" |\n":" | ", p->out);
+ utf8_printf(psi->out, "%*s%s%*s",
+ (w-n)/2, "", azData[i], (w-n+1)/2, "");
+ fputs(i==nColumn-1?" |\n":" | ", psi->out);
}
- print_row_separator(p, nColumn, "+");
+ print_row_separator(psx, nColumn, "+");
break;
}
case MODE_Markdown: {
colSep = " | ";
rowSep = " |\n";
- fputs("| ", p->out);
+ fputs("| ", psi->out);
for(i=0; i<nColumn; i++){
- w = p->actualWidth[i];
+ w = psx->pHaveWidths[i];
n = strlenChar(azData[i]);
- utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
- fputs(i==nColumn-1?" |\n":" | ", p->out);
+ utf8_printf(psi->out, "%*s%s%*s",
+ (w-n)/2, "", azData[i], (w-n+1)/2, "");
+ fputs(i==nColumn-1?" |\n":" | ", psi->out);
}
- print_row_separator(p, nColumn, "|");
+ print_row_separator(psx, nColumn, "|");
break;
}
case MODE_Box: {
colSep = " " BOX_13 " ";
rowSep = " " BOX_13 "\n";
- print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
- utf8_printf(p->out, BOX_13 " ");
+ print_box_row_separator(psx, nColumn, BOX_23, BOX_234, BOX_34);
+ utf8_printf(psi->out, BOX_13 " ");
for(i=0; i<nColumn; i++){
- w = p->actualWidth[i];
+ w = psx->pHaveWidths[i];
n = strlenChar(azData[i]);
- utf8_printf(p->out, "%*s%s%*s%s",
+ utf8_printf(psi->out, "%*s%s%*s%s",
(w-n)/2, "", azData[i], (w-n+1)/2, "",
i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
}
- print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
+ print_box_row_separator(psx, nColumn, BOX_123, BOX_1234, BOX_134);
break;
}
}
for(i=nColumn, j=0; i<nTotal; i++, j++){
- if( j==0 && p->cMode!=MODE_Column ){
- utf8_printf(p->out, "%s", p->cMode==MODE_Box?BOX_13" ":"| ");
+ if( j==0 && psi->cMode!=MODE_Column ){
+ utf8_printf(psi->out, "%s", psi->cMode==MODE_Box?BOX_13" ":"| ");
}
z = azData[i];
- if( z==0 ) z = p->nullValue;
- w = p->actualWidth[j];
- if( p->colWidth[j]<0 ) w = -w;
- utf8_width_print(p->out, w, z);
+ if( z==0 ) z = psi->nullValue;
+ w = psx->pHaveWidths[j];
+ if( psx->pSpecWidths[j]<0 ) w = -w;
+ utf8_width_print(psi->out, w, z);
if( j==nColumn-1 ){
- utf8_printf(p->out, "%s", rowSep);
+ utf8_printf(psi->out, "%s", rowSep);
if( bMultiLineRowExists && abRowDiv[i/nColumn-1] && i+1<nTotal ){
- if( p->cMode==MODE_Table ){
- print_row_separator(p, nColumn, "+");
- }else if( p->cMode==MODE_Box ){
- print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
- }else if( p->cMode==MODE_Column ){
- raw_printf(p->out, "\n");
+ if( psi->cMode==MODE_Table ){
+ print_row_separator(psx, nColumn, "+");
+ }else if( psi->cMode==MODE_Box ){
+ print_box_row_separator(psx, nColumn, BOX_123, BOX_1234, BOX_134);
+ }else if( psi->cMode==MODE_Column ){
+ raw_printf(psi->out, "\n");
}
}
j = -1;
if( seenInterrupt ) goto columnar_end;
}else{
- utf8_printf(p->out, "%s", colSep);
+ utf8_printf(psi->out, "%s", colSep);
}
}
- if( p->cMode==MODE_Table ){
- print_row_separator(p, nColumn, "+");
- }else if( p->cMode==MODE_Box ){
- print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14);
+ if( psi->cMode==MODE_Table ){
+ print_row_separator(psx, nColumn, "+");
+ }else if( psi->cMode==MODE_Box ){
+ print_box_row_separator(psx, nColumn, BOX_12, BOX_124, BOX_14);
}
columnar_end:
if( seenInterrupt ){
- utf8_printf(p->out, "Interrupt\n");
+ utf8_printf(psi->out, "Interrupt\n");
}
nData = (nRow+1)*nColumn;
for(i=0; i<nData; i++) free(azData[i]);
** Run a prepared statement
*/
static void exec_prepared_stmt(
- ShellState *pArg, /* Pointer to ShellState */
+ ShellExState *pArg, /* Pointer to shell state */
sqlite3_stmt *pStmt /* Statment to run */
){
int rc;
+ ShellInState *psi = ISS(pArg);
sqlite3_uint64 nRow = 0;
- if( MODE_IS_COLUMNAR(pArg->cMode) ){
+ if( MODE_IS_COLUMNAR(psi->cMode) ){
exec_prepared_stmt_columnar(pArg, pStmt);
return;
}
for(i=0; i<nCol; i++){
aiTypes[i] = x = sqlite3_column_type(pStmt, i);
if( x==SQLITE_BLOB && pArg
- && (pArg->cMode==MODE_Insert || pArg->cMode==MODE_Quote) ){
+ && (psi->cMode==MODE_Insert || psi->cMode==MODE_Quote) ){
azVals[i] = "";
}else{
azVals[i] = (char*)sqlite3_column_text(pStmt, i);
}
} while( SQLITE_ROW == rc );
sqlite3_free(pData);
- if( pArg->cMode==MODE_Json ){
- fputs("]\n", pArg->out);
- }else if( pArg->cMode==MODE_Count ){
- printf("%llu row%s\n", nRow, nRow!=1 ? "s" : "");
+ if( psi->cMode==MODE_Json ){
+ fputs("]\n", psi->out);
+ }else if( psi->cMode==MODE_Count ){
+ utf8_printf(psi->out, "%llu row%s\n", nRow, nRow!=1 ? "s" : "");
}
}
}
** caller to eventually free this buffer using sqlite3_free().
*/
static int expertHandleSQL(
- ShellState *pState,
+ ShellInState *psi,
const char *zSql,
char **pzErr
){
- assert( pState->expert.pExpert );
+ assert( psi->expert.pExpert );
assert( pzErr==0 || *pzErr==0 );
- return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr);
+ return sqlite3_expert_sql(psi->expert.pExpert, zSql, pzErr);
}
/*
** caller to eventually free this buffer using sqlite3_free().
*/
static int expertFinish(
- ShellState *pState,
+ ShellInState *psi,
int bCancel,
char **pzErr
){
int rc = SQLITE_OK;
- sqlite3expert *p = pState->expert.pExpert;
+ sqlite3expert *p = psi->expert.pExpert;
assert( p );
assert( bCancel || pzErr==0 || *pzErr==0 );
if( bCancel==0 ){
- FILE *out = pState->out;
- int bVerbose = pState->expert.bVerbose;
+ FILE *out = psi->out;
+ int bVerbose = psi->expert.bVerbose;
rc = sqlite3_expert_analyze(p, pzErr);
if( rc==SQLITE_OK ){
}
}
sqlite3_expert_destroy(p);
- pState->expert.pExpert = 0;
+ psi->expert.pExpert = 0;
return rc;
}
** Implementation of ".expert" dot command.
*/
static int expertDotCommand(
- ShellState *pState, /* Current shell tool state */
+ ShellInState *psi, /* Current shell tool state */
char **azArg, /* Array of arguments passed to dot command */
int nArg /* Number of entries in azArg[] */
){
int i;
int iSample = 0;
- if( pState->bSafeMode ){
+ if( psi->bSafeMode ){
raw_printf(STD_ERR,
"Cannot run experimental commands such as \"%s\" in safe mode\n",
azArg[0]);
return 1;
}
- assert( pState->expert.pExpert==0 );
- memset(&pState->expert, 0, sizeof(ExpertInfo));
+ assert( psi->expert.pExpert==0 );
+ memset(&psi->expert, 0, sizeof(ExpertInfo));
for(i=1; rc==SQLITE_OK && i<nArg; i++){
char *z = azArg[i];
if( z[0]=='-' && z[1]=='-' ) z++;
n = strlen30(z);
if( n>=2 && 0==strncmp(z, "-verbose", n) ){
- pState->expert.bVerbose = 1;
+ psi->expert.bVerbose = 1;
}
else if( n>=2 && 0==strncmp(z, "-sample", n) ){
if( i==(nArg-1) ){
}
if( rc==SQLITE_OK ){
- pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
- if( pState->expert.pExpert==0 ){
+ psi->expert.pExpert = sqlite3_expert_new(DBI(psi), &zErr);
+ if( psi->expert.pExpert==0 ){
raw_printf(STD_ERR, "sqlite3_expert_new: %s\n",
zErr ? zErr : "out of memory");
rc = SQLITE_ERROR;
}else{
sqlite3_expert_config(
- pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
+ psi->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
);
}
}
** not about to dumped as a no-op. Someday, a tracing facility may enhance
** this function's output to show where the input group has originated.
*/
-static void echo_group_input(ShellState *p, const char *zDo){
- if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zDo);
+static void echo_group_input(ShellInState *psi, const char *zDo){
+ if( (psi->shellFlgs & SHFLG_Echo)!=0 ) printf("%s\n", zDo);
}
/*
** and callback data argument.
*/
static int shell_exec(
- ShellState *pArg, /* Pointer to ShellState */
+ ShellExState *psx, /* Pointer to shell state */
const char *zSql, /* SQL to be evaluated */
char **pzErrMsg /* Error msg written here */
){
+ ShellInState *psi = ISS(psx);
sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
int rc = SQLITE_OK; /* Return Code */
int rc2;
const char *zLeftover; /* Tail of unprocessed SQL */
- sqlite3 *db = pArg->db;
+ sqlite3 *db = DBX(psx);
if( pzErrMsg ){
*pzErrMsg = NULL;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( pArg->expert.pExpert ){
- rc = expertHandleSQL(pArg, zSql, pzErrMsg);
- return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg);
+ if( psi->expert.pExpert ){
+ rc = expertHandleSQL(psi, zSql, pzErrMsg);
+ return expertFinish(psi, (rc!=SQLITE_OK), pzErrMsg);
}
#endif
else zStmtSql = skipWhite(zStmtSql);
/* save off the prepared statment handle and reset row count */
- if( pArg ){
- pArg->pStmt = pStmt;
- pArg->cnt = 0;
+ if( psx ){
+ psi->pStmt = pStmt;
+ psx->resultCount = 0;
}
/* echo the sql statement if echo on */
- if( pArg ) echo_group_input( pArg, zStmtSql ? zStmtSql : zSql);
+ if( psx ) echo_group_input( psi, zStmtSql ? zStmtSql : zSql);
/* Show the EXPLAIN QUERY PLAN if .eqp is on */
- if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){
+ if( psx && psi->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){
sqlite3_stmt *pExplain;
char *zEQP;
int triggerEQP = 0;
disable_debug_trace_modes();
sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP);
- if( pArg->autoEQP>=AUTOEQP_trigger ){
+ if( psi->autoEQP>=AUTOEQP_trigger ){
sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0);
}
zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
int iEqpId = sqlite3_column_int(pExplain, 0);
int iParentId = sqlite3_column_int(pExplain, 1);
if( zEQPLine==0 ) zEQPLine = "";
- if( zEQPLine[0]=='-' ) eqp_render(pArg);
- eqp_append(pArg, iEqpId, iParentId, zEQPLine);
+ if( zEQPLine[0]=='-' ) eqp_render(psi);
+ eqp_append(psi, iEqpId, iParentId, zEQPLine);
}
- eqp_render(pArg);
+ eqp_render(psi);
}
sqlite3_finalize(pExplain);
sqlite3_free(zEQP);
- if( pArg->autoEQP>=AUTOEQP_full ){
+ if( psi->autoEQP>=AUTOEQP_full ){
/* Also do an EXPLAIN for ".eqp full" mode */
zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
shell_check_oom(zEQP);
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
if( rc==SQLITE_OK ){
- pArg->cMode = MODE_Explain;
- explain_data_prepare(pArg, pExplain);
- exec_prepared_stmt(pArg, pExplain);
- explain_data_delete(pArg);
+ psi->cMode = MODE_Explain;
+ explain_data_prepare(psi, pExplain);
+ exec_prepared_stmt(psx, pExplain);
+ explain_data_delete(psi);
}
sqlite3_finalize(pExplain);
sqlite3_free(zEQP);
}
- if( pArg->autoEQP>=AUTOEQP_trigger && triggerEQP==0 ){
+ if( psi->autoEQP>=AUTOEQP_trigger && triggerEQP==0 ){
sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 0, 0);
/* Reprepare pStmt before reactiving trace modes */
sqlite3_finalize(pStmt);
sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
- if( pArg ) pArg->pStmt = pStmt;
+ if( psx ) psi->pStmt = pStmt;
}
restore_debug_trace_modes();
}
- if( pArg ){
- pArg->cMode = pArg->mode;
- if( pArg->autoExplain ){
+ if( psx ){
+ psi->cMode = psi->mode;
+ if( psi->autoExplain ){
if( sqlite3_stmt_isexplain(pStmt)==1 ){
- pArg->cMode = MODE_Explain;
+ psi->cMode = MODE_Explain;
}
if( sqlite3_stmt_isexplain(pStmt)==2 ){
- pArg->cMode = MODE_EQP;
+ psi->cMode = MODE_EQP;
}
}
/* If the shell is currently in ".explain" mode, gather the extra
** data required to add indents to the output.*/
- if( pArg->cMode==MODE_Explain ){
- explain_data_prepare(pArg, pStmt);
+ if( psi->cMode==MODE_Explain ){
+ explain_data_prepare(psi, pStmt);
}
}
- bind_prepared_stmt(pArg->db, pStmt);
- exec_prepared_stmt(pArg, pStmt);
- explain_data_delete(pArg);
- eqp_render(pArg);
+ bind_prepared_stmt(DBX(psx), pStmt);
+ exec_prepared_stmt(psx, pStmt);
+ explain_data_delete(psi);
+ eqp_render(psi);
/* print usage stats if stats on */
- if( pArg && pArg->statsOn ){
- display_stats(db, pArg, 0);
+ if( psx && psi->statsOn ){
+ display_stats(db, psi, 0);
}
/* print loop-counters if required */
- if( pArg && pArg->scanstatsOn ){
- display_scanstats(db, pArg);
+ if( psx && psi->scanstatsOn ){
+ display_scanstats(psi);
}
/* Finalize the statement just executed. If this fails, save a
}
/* clear saved stmt handle */
- if( pArg ){
- pArg->pStmt = NULL;
+ if( psx ){
+ psi->pStmt = NULL;
}
}
} /* end while */
/*
** Return a list of pointers to strings which are the names of all
-** columns in table zTab. The memory to hold the names is dynamically
+** columns in table zTab. The memory to hold the names is dynamically
** allocated and must be released by the caller using a subsequent call
** to freeColumnList().
**
** The first regular column in the table is azCol[1]. The list is terminated
** by an entry with azCol[i]==0.
*/
-static char **tableColumnList(ShellState *p, const char *zTab){
+static char **tableColumnList(sqlite3 *db, const char *zTab, int preserveRowid){
char **azCol = 0;
sqlite3_stmt *pStmt;
char *zSql;
int nAlloc = 0;
int nPK = 0; /* Number of PRIMARY KEY columns seen */
int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */
- int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid);
int rc;
zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
shell_check_oom(zSql);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ) return 0;
while( sqlite3_step(pStmt)==SQLITE_ROW ){
zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
" WHERE origin='pk'", zTab);
shell_check_oom(zSql);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
freeColumnList(azCol);
** ordinary column in the table. Verify that azRowid[j] is a valid
** name for the rowid before adding it to azCol[0]. WITHOUT ROWID
** tables will fail this last check */
- rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
+ rc = sqlite3_table_column_metadata(db,0,zTab,azRowid[j],0,0,0,0,0);
if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
break;
}
const char *zTable;
const char *zType;
const char *zSql;
- ShellState *p = (ShellState *)pArg;
+ ShellInState *psi = (ShellInState *)pArg;
+ ShellExState *psx = XSS(psi);
int dataOnly;
int noSys;
zTable = azArg[0];
zType = azArg[1];
zSql = azArg[2];
- dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0;
- noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
+ dataOnly = (psi->shellFlgs & SHFLG_DumpDataOnly)!=0;
+ noSys = (psi->shellFlgs & SHFLG_DumpNoSys)!=0;
if( strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
- if( !dataOnly ) raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
+ if( !dataOnly ) raw_printf(psi->out, "DELETE FROM sqlite_sequence;\n");
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
- if( !dataOnly ) raw_printf(p->out, "ANALYZE sqlite_schema;\n");
- }else if( p->bAllowSysDump==0 && strncmp(zTable, "sqlite_", 7)==0 ){
+ if( !dataOnly ) raw_printf(psi->out, "ANALYZE sqlite_schema;\n");
+ }else if( psi->bAllowSysDump==0 && strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( dataOnly ){
/* no-op */
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
char *zIns;
- if( !p->writableSchema ){
- raw_printf(p->out, "PRAGMA writable_schema=ON;\n");
- p->writableSchema = 1;
+ if( !psi->writableSchema ){
+ raw_printf(psi->out, "PRAGMA writable_schema=ON;\n");
+ psi->writableSchema = 1;
}
zIns = sqlite3_mprintf(
"INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
"VALUES('table','%q','%q',0,'%q');",
zTable, zTable, zSql);
shell_check_oom(zIns);
- utf8_printf(p->out, "%s\n", zIns);
+ utf8_printf(psi->out, "%s\n", zIns);
sqlite3_free(zIns);
return 0;
}else{
- printSchemaLine(p->out, zSql, ";\n");
+ printSchemaLine(psi->out, zSql, ";\n");
}
if( strcmp(zType, "table")==0 ){
ShellText sTable;
char **azCol;
int i;
- char *savedDestTable;
+ const char *savedDestTable;
int savedMode;
+ int preserveRowid = (psi->shellFlgs & SHFLG_PreserveRowid)!=0;
- azCol = tableColumnList(p, zTable);
+ azCol = tableColumnList(DBI(psi), zTable, preserveRowid);
if( azCol==0 ){
- p->nErr++;
+ psi->nErr++;
return 0;
}
appendText(&sSelect, " FROM ", 0);
appendText(&sSelect, zTable, quoteChar(zTable));
- savedDestTable = p->zDestTable;
- savedMode = p->mode;
- p->zDestTable = sTable.z;
- p->mode = p->cMode = MODE_Insert;
- rc = shell_exec(p, sSelect.z, 0);
+ savedDestTable = psx->zDestTable;
+ savedMode = psi->mode;
+ psx->zDestTable = sTable.z;
+ psi->mode = psi->cMode = MODE_Insert;
+ rc = shell_exec(psx, sSelect.z, 0);
if( (rc&0xff)==SQLITE_CORRUPT ){
- raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
- toggleSelectOrder(p->db);
- shell_exec(p, sSelect.z, 0);
- toggleSelectOrder(p->db);
+ raw_printf(psi->out, "/****** CORRUPTION ERROR *******/\n");
+ toggleSelectOrder(DBX(psx));
+ shell_exec(psx, sSelect.z, 0);
+ toggleSelectOrder(DBX(psx));
}
- p->zDestTable = savedDestTable;
- p->mode = savedMode;
+ psx->zDestTable = savedDestTable;
+ psi->mode = savedMode;
freeText(&sTable);
freeText(&sSelect);
- if( rc ) p->nErr++;
+ if( rc ) psi->nErr++;
}
return 0;
}
** "ORDER BY rowid DESC" to the end.
*/
static int run_schema_dump_query(
- ShellState *p,
+ ShellInState *psi,
const char *zQuery
){
int rc;
char *zErr = 0;
- rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
+ rc = sqlite3_exec(DBI(psi), zQuery, dump_callback, psi, &zErr);
if( rc==SQLITE_CORRUPT ){
char *zQ2;
int len = strlen30(zQuery);
- raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
+ raw_printf(psi->out, "/****** CORRUPTION ERROR *******/\n");
if( zErr ){
- utf8_printf(p->out, "/****** %s ******/\n", zErr);
+ utf8_printf(psi->out, "/****** %s ******/\n", zErr);
sqlite3_free(zErr);
zErr = 0;
}
zQ2 = malloc( len+100 );
if( zQ2==0 ) return rc;
sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
- rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
+ rc = sqlite3_exec(DBI(psi), zQ2, dump_callback, psi, &zErr);
if( rc ){
- utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr);
+ utf8_printf(psi->out, "/****** ERROR: %s ******/\n", zErr);
}else{
rc = SQLITE_CORRUPT;
}
return rc;
}
-/* Configure help text generation to have coalesced secondary
- * help lines with trailing newlines on all help lines.
+/* Configure help text generation to have coalesced secondary help lines
+ * with trailing newlines on all help lines. This allow help text to be
+ * representable as an array of two C-strings per meta-command.
*/
DISPATCH_CONFIG[
HELP_COALESCE=1
}
/* Forward reference */
-static int process_input(ShellState *p);
+static int process_input(ShellInState *psx);
/*
** Read the content of file zName into memory obtained from sqlite3_malloc64()
** Close all OpenSession objects and release all associated resources.
*/
#if defined(SQLITE_ENABLE_SESSION)
-static void session_close_all(ShellState *p, int i){
+static void session_close_all(ShellInState *psi, int i){
int j;
- struct AuxDb *pAuxDb = i<0 ? p->pAuxDb : &p->aAuxDb[i];
+ struct AuxDb *pAuxDb = i<0 ? psi->pAuxDb : &psi->aAuxDb[i];
for(j=0; j<pAuxDb->nSession; j++){
session_close(&pAuxDb->aSession[j]);
}
** program. Read content from the file in p->aAuxDb[].zDbFilename.
** If p->aAuxDb[].zDbFilename is 0, then read from the present input.
*/
-static unsigned char *readHexDb(ShellState *p, int *pnData){
+static unsigned char *readHexDb(ShellInState *psi, int *pnData){
unsigned char *a = 0;
int n = 0;
int pgsz = 0;
int j, k, nlError;
int rc;
static const char *zEndMarker = "| end ";
- const char *zDbFilename = p->pAuxDb->zDbFilename;
+ const char *zDbFilename = psi->pAuxDb->zDbFilename;
/* Need next two objects only if redirecting input to get the hex. */
- InSource inRedir = INSOURCE_FILE_REDIR(0, zDbFilename, p->pInSource);
+ InSource inRedir = INSOURCE_FILE_REDIR(0, zDbFilename, psi->pInSource);
unsigned int x[16];
char zLine[1000];
if( zDbFilename ){
utf8_printf(STD_ERR, "cannot open \"%s\" for reading\n", zDbFilename);
return 0;
}
- p->pInSource = &inRedir;
+ psi->pInSource = &inRedir;
}else{
/* Will read hex DB lines inline from present input, without redirect. */
- if( INSOURCE_IS_INTERACTIVE(p->pInSource) ){
+ if( INSOURCE_IS_INTERACTIVE(psi->pInSource) ){
printf("Reading hex DB from \"%s\", until end-marker input like:\n%s\n",
- p->pInSource->zSourceSay, zEndMarker);
+ psi->pInSource->zSourceSay, zEndMarker);
fflush(STD_OUT);
}
}
*pnData = 0;
- if( str_line_get(zLine,sizeof(zLine), p->pInSource)==0 ) goto readHexDb_error;
+ if( strLineGet(zLine,sizeof(zLine), psi->pInSource)==0 ) goto readHexDb_error;
rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
if( rc!=2 ) goto readHexDb_error;
if( n<0 ) goto readHexDb_error;
utf8_printf(STD_ERR, "invalid pagesize\n");
goto readHexDb_error;
}
- while( str_line_get(zLine,sizeof(zLine), p->pInSource)!=0 ){
+ while( strLineGet(zLine,sizeof(zLine), psi->pInSource)!=0 ){
rc = sscanf(zLine, "| page %d offset %d", &j, &k);
if( rc==2 ){
iOffset = k;
}
*pnData = n; /* Record success and size. */
readHexDb_cleanup:
- if( p->pInSource==&inRedir ){
+ if( psi->pInSource==&inRedir ){
fclose( inRedir.inFile );
- p->pInSource = inRedir.pFrom;
+ psi->pInSource = inRedir.pFrom;
}
return a;
readHexDb_error:
- nlError = p->pInSource->lineno;
- if( p->pInSource!=&inRedir ){
+ nlError = psi->pInSource->lineno;
+ if( psi->pInSource!=&inRedir ){
/* Since taking input inline, consume through its end marker. */
- while( str_line_get(zLine, sizeof(zLine), p->pInSource)!=0 ){
-
+ while( strLineGet(zLine, sizeof(zLine), psi->pInSource)!=0 ){
if(strncmp(zLine, zEndMarker, 6)==0 ) break;
}
-
}
sqlite3_free(a);
a = 0;
** 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.
*/
-static void open_db(ShellState *p, int openFlags){
- if( p->db==0 ){
- const char *zDbFilename = p->pAuxDb->zDbFilename;
- if( p->openMode==SHELL_OPEN_UNSPEC ){
+static void open_db(ShellExState *psx, int openFlags){
+ ShellInState *psi = ISS(psx);
+ if( DBX(psx)==0 ){
+ sqlite3 **pDb = &DBX(psx);
+ const char *zDbFilename = psi->pAuxDb->zDbFilename;
+ if( psi->openMode==SHELL_OPEN_UNSPEC ){
if( zDbFilename==0 || zDbFilename[0]==0 ){
- p->openMode = SHELL_OPEN_NORMAL;
+ psi->openMode = SHELL_OPEN_NORMAL;
}else{
- p->openMode = deduceDatabaseType(p->pAuxDb->zDbFilename,
- (openFlags & OPEN_DB_ZIPFILE)!=0);
+ psi->openMode = deduceDatabaseType(psi->pAuxDb->zDbFilename,
+ (openFlags & OPEN_DB_ZIPFILE)!=0);
}
}
- switch( p->openMode ){
+ switch( psi->openMode ){
case SHELL_OPEN_APPENDVFS: {
- sqlite3_open_v2(zDbFilename, &p->db,
- SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs");
+ sqlite3_open_v2
+ (zDbFilename, pDb,
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|psi->openFlags,
+ "apndvfs");
break;
}
case SHELL_OPEN_HEXDB:
case SHELL_OPEN_DESERIALIZE: {
- sqlite3_open(0, &p->db);
+ sqlite3_open(0, pDb);
break;
}
case SHELL_OPEN_ZIPFILE: {
- sqlite3_open(":memory:", &p->db);
+ sqlite3_open(":memory:", pDb);
break;
}
case SHELL_OPEN_READONLY: {
- sqlite3_open_v2(zDbFilename, &p->db,
- SQLITE_OPEN_READONLY|p->openFlags, 0);
+ sqlite3_open_v2(zDbFilename, pDb,
+ SQLITE_OPEN_READONLY|psi->openFlags, 0);
break;
}
case SHELL_OPEN_UNSPEC:
case SHELL_OPEN_NORMAL: {
- sqlite3_open_v2(zDbFilename, &p->db,
- SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
+ sqlite3_open_v2(zDbFilename, pDb,
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|psi->openFlags, 0);
break;
}
}
- globalDb = p->db;
- if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
+ globalDb = DBX(psx);
+ if( DBX(psx)==0 || SQLITE_OK!=sqlite3_errcode(DBX(psx)) ){
+ const char *zWhy = (DBX(psx)==0)? "(?)" : sqlite3_errmsg(DBX(psx));
utf8_printf(STD_ERR,"Error: unable to open database \"%s\": %s\n",
- zDbFilename, sqlite3_errmsg(p->db));
+ zDbFilename, zWhy);
if( openFlags & OPEN_DB_KEEPALIVE ){
- sqlite3_open(":memory:", &p->db);
+ sqlite3_open(":memory:", pDb);
+ globalDb = *pDb;
return;
}
exit(1);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
- sqlite3_enable_load_extension(p->db, 1);
-#endif
- sqlite3_fileio_init(p->db, 0, 0);
- sqlite3_shathree_init(p->db, 0, 0);
- sqlite3_completion_init(p->db, 0, 0);
- sqlite3_uint_init(p->db, 0, 0);
- sqlite3_decimal_init(p->db, 0, 0);
- sqlite3_regexp_init(p->db, 0, 0);
- sqlite3_ieee_init(p->db, 0, 0);
- sqlite3_series_init(p->db, 0, 0);
+ sqlite3_enable_load_extension(globalDb, 1);
+#endif
+ sqlite3_fileio_init(globalDb, 0, 0);
+ sqlite3_shathree_init(globalDb, 0, 0);
+ sqlite3_completion_init(globalDb, 0, 0);
+ sqlite3_uint_init(globalDb, 0, 0);
+ sqlite3_decimal_init(globalDb, 0, 0);
+ sqlite3_regexp_init(globalDb, 0, 0);
+ sqlite3_ieee_init(globalDb, 0, 0);
+ sqlite3_series_init(globalDb, 0, 0);
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
- sqlite3_dbdata_init(p->db, 0, 0);
+ sqlite3_dbdata_init(globalDb, 0, 0);
#endif
#ifdef SQLITE_HAVE_ZLIB
- sqlite3_zipfile_init(p->db, 0, 0);
- sqlite3_sqlar_init(p->db, 0, 0);
+ sqlite3_zipfile_init(globalDb, 0, 0);
+ sqlite3_sqlar_init(globalDb, 0, 0);
#endif
- sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
+ sqlite3_create_function(globalDb, "shell_add_schema", 3, SQLITE_UTF8, 0,
shellAddSchemaName, 0, 0);
- sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
+ sqlite3_create_function(globalDb, "shell_module_schema", 1, SQLITE_UTF8, 0,
shellModuleSchema, 0, 0);
- sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
+ sqlite3_create_function(globalDb, "shell_putsnl", 1, SQLITE_UTF8, psx,
shellPutsFunc, 0, 0);
- sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0,
+ sqlite3_create_function(globalDb, "shell_escape_crnl", 1, SQLITE_UTF8, 0,
shellEscapeCrnl, 0, 0);
- sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0,
+ sqlite3_create_function(globalDb, "shell_int32", 2, SQLITE_UTF8, 0,
shellInt32, 0, 0);
- sqlite3_create_function(p->db, "shell_idquote", 1, SQLITE_UTF8, 0,
+ sqlite3_create_function(globalDb, "shell_idquote", 1, SQLITE_UTF8, 0,
shellIdQuote, 0, 0);
- sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0,
+ sqlite3_create_function(globalDb, "usleep",1,SQLITE_UTF8, 0,
shellUSleepFunc, 0, 0);
#ifndef SQLITE_NOHAVE_SYSTEM
- sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
+ sqlite3_create_function(globalDb, "edit", 1, SQLITE_UTF8, 0,
editFunc, 0, 0);
- sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
+ sqlite3_create_function(globalDb, "edit", 2, SQLITE_UTF8, 0,
editFunc, 0, 0);
#endif
- if( p->openMode==SHELL_OPEN_ZIPFILE ){
+ if( psi->openMode==SHELL_OPEN_ZIPFILE ){
char *zSql = sqlite3_mprintf(
"CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename);
shell_check_oom(zSql);
- sqlite3_exec(p->db, zSql, 0, 0, 0);
+ sqlite3_exec(DBX(psx), zSql, 0, 0, 0);
sqlite3_free(zSql);
}
#ifndef SQLITE_OMIT_DESERIALIZE
else
- if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){
+ if( psi->openMode==SHELL_OPEN_DESERIALIZE
+ || psi->openMode==SHELL_OPEN_HEXDB ){
int rc;
int nData = 0;
unsigned char *aData;
- if( p->openMode==SHELL_OPEN_DESERIALIZE ){
+ if( psi->openMode==SHELL_OPEN_DESERIALIZE ){
aData = (unsigned char*)readFile(zDbFilename, &nData);
}else{
- aData = readHexDb(p, &nData);
+ aData = readHexDb(psi, &nData);
if( aData==0 ){
return;
}
}
- rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
+ rc = sqlite3_deserialize(DBX(psx), "main", aData, nData, nData,
SQLITE_DESERIALIZE_RESIZEABLE |
SQLITE_DESERIALIZE_FREEONCLOSE);
if( rc ){
utf8_printf(STD_ERR, "Error: sqlite3_deserialize() returns %d\n", rc);
}
- if( p->szMax>0 ){
- sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
+ if( psi->szMax>0 ){
+ sqlite3_file_control(DBX(psx), "main", SQLITE_FCNTL_SIZE_LIMIT,
+ &psi->szMax);
}
}
#endif
}
- if( p->bSafeModeFuture && p->db!=0 ){
- sqlite3_set_authorizer(p->db, safeModeAuth, p);
+ if( psi->bSafeModeFuture && DBX(psx)!=0 ){
+ sqlite3_set_authorizer(DBX(psx), safeModeAuth, psx);
}
}
/*
** Set or clear a shell flag according to a boolean value.
*/
-static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){
+static void setOrClearFlag(ShellExState *psx, unsigned mFlag, const char *zArg){
if( booleanValue(zArg) ){
- ShellSetFlag(p, mFlag);
+ ShellSetFlag(psx, mFlag);
}else{
- ShellClearFlag(p, mFlag);
+ ShellClearFlag(psx, mFlag);
}
}
/*
-** Close an output file, assuming it is not stderr or stdout
+** Close an output file, provided it is not stderr or stdout
*/
static void output_file_close(FILE *f){
if( f && f!=STD_OUT && f!=STD_ERR ) fclose(f);
*/
static int sql_trace_callback(
unsigned mType, /* The trace type */
- void *pArg, /* The ShellState pointer */
+ void *pArg, /* The shell state pointer */
void *pP, /* Usually a pointer to sqlite_stmt */
void *pX /* Auxiliary output */
){
- ShellState *p = (ShellState*)pArg;
+ ShellInState *psi = (ShellInState*)pArg;
sqlite3_stmt *pStmt;
const char *zSql;
int nSql;
- if( p->traceOut==0 ) return 0;
+ if( psi->traceOut==0 ) return 0;
if( mType==SQLITE_TRACE_CLOSE ){
- utf8_printf(p->traceOut, "-- closing database connection\n");
+ utf8_printf(psi->traceOut, "-- closing database connection\n");
return 0;
}
if( mType!=SQLITE_TRACE_ROW && ((const char*)pX)[0]=='-' ){
zSql = (const char*)pX;
}else{
pStmt = (sqlite3_stmt*)pP;
- switch( p->eTraceType ){
+ switch( psi->eTraceType ){
case SHELL_TRACE_EXPANDED: {
zSql = sqlite3_expanded_sql(pStmt);
break;
switch( mType ){
case SQLITE_TRACE_ROW:
case SQLITE_TRACE_STMT: {
- utf8_printf(p->traceOut, "%.*s;\n", nSql, zSql);
+ utf8_printf(psi->traceOut, "%.*s;\n", nSql, zSql);
break;
}
case SQLITE_TRACE_PROFILE: {
sqlite3_int64 nNanosec = *(sqlite3_int64*)pX;
- utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", nSql, zSql, nNanosec);
+ utf8_printf(psi->traceOut, "%.*s; -- %lld ns\n", nSql, zSql, nNanosec);
break;
}
}
** work for WITHOUT ROWID tables.
*/
static void tryToCloneData(
- ShellState *p,
+ ShellExState *psx,
sqlite3 *newDb,
const char *zTable
){
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
shell_check_oom(zQuery);
- rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
+ rc = sqlite3_prepare_v2(DBX(psx), zQuery, -1, &pQuery, 0);
if( rc ){
utf8_printf(STD_ERR, "Error %d: %s on [%s]\n",
- sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
+ sqlite3_extended_errcode(DBX(psx)), sqlite3_errmsg(DBX(psx)),
zQuery);
goto end_data_xfer;
}
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
zTable);
shell_check_oom(zQuery);
- rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
+ rc = sqlite3_prepare_v2(DBX(psx), zQuery, -1, &pQuery, 0);
if( rc ){
utf8_printf(STD_ERR, "Warning: cannot step \"%s\" backwards", zTable);
break;
** sqlite_schema table, try again moving backwards.
*/
static void tryToCloneSchema(
- ShellState *p,
+ ShellExState *psx,
sqlite3 *newDb,
const char *zWhere,
- void (*xForEach)(ShellState*,sqlite3*,const char*)
+ void (*xForEach)(ShellExState*,sqlite3*,const char*)
){
sqlite3_stmt *pQuery = 0;
char *zQuery = 0;
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
" WHERE %s", zWhere);
shell_check_oom(zQuery);
- rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
+ rc = sqlite3_prepare_v2(DBX(psx), zQuery, -1, &pQuery, 0);
if( rc ){
utf8_printf(STD_ERR, "Error: (%d) %s on [%s]\n",
- sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
- zQuery);
+ sqlite3_extended_errcode(DBX(psx)),
+ sqlite3_errmsg(DBX(psx)), zQuery);
goto end_schema_xfer;
}
while( sqlite3_step(pQuery)==SQLITE_ROW ){
zName = sqlite3_column_text(pQuery, 0);
zSql = sqlite3_column_text(pQuery, 1);
if( zName==0 || zSql==0 ) continue;
+ /* Consider directing this output to current output. */
fprintf(STD_OUT, "%s... ", zName); fflush(STD_OUT);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
zErrMsg = 0;
}
if( xForEach ){
- xForEach(p, newDb, (const char*)zName);
+ xForEach(psx, newDb, (const char*)zName);
}
+ /* Consider directing this output to current output. */
fprintf(STD_OUT, "done\n");
}
if( rc!=SQLITE_DONE ){
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
" WHERE %s ORDER BY rowid DESC", zWhere);
shell_check_oom(zQuery);
- rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
+ rc = sqlite3_prepare_v2(DBX(psx), zQuery, -1, &pQuery, 0);
if( rc ){
utf8_printf(STD_ERR, "Error: (%d) %s on [%s]\n",
- sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
- zQuery);
+ sqlite3_extended_errcode(DBX(psx)),
+ sqlite3_errmsg(DBX(psx)), zQuery);
goto end_schema_xfer;
}
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
zName = sqlite3_column_text(pQuery, 0);
zSql = sqlite3_column_text(pQuery, 1);
if( zName==0 || zSql==0 ) continue;
+ /* Consider directing ... */
fprintf(STD_OUT, "%s... ", zName); fflush(STD_OUT);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
zErrMsg = 0;
}
if( xForEach ){
- xForEach(p, newDb, (const char*)zName);
+ xForEach(psx, newDb, (const char*)zName);
}
+ /* Consider directing ... */
fprintf(STD_OUT, "done\n");
}
}
** as possible out of the main database (which might be corrupt) and write it
** into zNewDb.
*/
-static void tryToClone(ShellState *p, const char *zNewDb){
+static void tryToClone(ShellExState *psx, const char *zNewDb){
int rc;
sqlite3 *newDb = 0;
if( access(zNewDb,0)==0 ){
utf8_printf(STD_ERR, "Cannot create output database: %s\n",
sqlite3_errmsg(newDb));
}else{
- sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
+ sqlite3_exec(DBX(psx), "PRAGMA writable_schema=ON;", 0, 0, 0);
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
- tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
- tryToCloneSchema(p, newDb, "type!='table'", 0);
+ tryToCloneSchema(psx, newDb, "type='table'", tryToCloneData);
+ tryToCloneSchema(psx, newDb, "type!='table'", 0);
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
- sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
+ sqlite3_exec(DBX(psx), "PRAGMA writable_schema=OFF;", 0, 0, 0);
}
close_db(newDb);
}
/*
** Change the output file back to stdout.
**
-** If the p->doXdgOpen flag is set, that means the output was being
-** redirected to a temporary file named by p->zTempFile. In that case,
+** If the psi->doXdgOpen flag is set, that means the output was being
+** redirected to a temporary file named by psi->zTempFile. In that case,
** launch start/open/xdg-open on that temporary file.
*/
-static void output_reset(ShellState *p){
- if( p->outfile[0]=='|' ){
+static void output_reset(ShellInState *psi){
+ if( psi->outfile[0]=='|' ){
#ifndef SQLITE_OMIT_POPEN
- pclose(p->out);
+ pclose(psi->out);
#endif
}else{
- output_file_close(p->out);
+ output_file_close(psi->out);
#ifndef SQLITE_NOHAVE_SYSTEM
- if( p->doXdgOpen ){
+ if( psi->doXdgOpen ){
const char *zXdgOpenCmd =
#if defined(_WIN32)
"start";
"xdg-open";
#endif
char *zCmd;
- zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
+ zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, psi->zTempFile);
if( system(zCmd) ){
utf8_printf(STD_ERR, "Failed: [%s]\n", zCmd);
}else{
/* Give the start/open/xdg-open command some time to get
** going before we continue, and potential delete the
- ** p->zTempFile data file out from under it */
+ ** psi->zTempFile data file out from under it */
sqlite3_sleep(2000);
}
sqlite3_free(zCmd);
- outputModePop(p);
- p->doXdgOpen = 0;
+ outputModePop(psi);
+ psi->doXdgOpen = 0;
}
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
}
- p->outfile[0] = 0;
- p->out = STD_OUT;
+ psi->outfile[0] = 0;
+ psi->out = STD_OUT;
}
/*
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
-static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
+static int shell_dbinfo_command(ShellExState *psx, int nArg, char **azArg){
static const struct { const char *zName; int ofst; } aField[] = {
{ "file change counter:", 24 },
{ "database page count:", 28 },
char *zDb = nArg>=2 ? azArg[1] : "main";
sqlite3_stmt *pStmt = 0;
unsigned char aHdr[100];
- open_db(p, 0);
- if( p->db==0 ) return 1;
- rc = sqlite3_prepare_v2(p->db,
+ FILE *out = ISS(psx)->out;
+
+ open_db(psx, 0);
+ if( DBX(psx)==0 ) return 1;
+ rc = sqlite3_prepare_v2(DBX(psx),
"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
-1, &pStmt, 0);
if( rc ){
- utf8_printf(STD_ERR, "error: %s\n", sqlite3_errmsg(p->db));
+ utf8_printf(STD_ERR, "error: %s\n", sqlite3_errmsg(DBX(psx)));
sqlite3_finalize(pStmt);
return 1;
}
}
i = get2byteInt(aHdr+16);
if( i==1 ) i = 65536;
- utf8_printf(p->out, "%-20s %d\n", "database page size:", i);
- utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
- utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
- utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
+ utf8_printf(out, "%-20s %d\n", "database page size:", i);
+ utf8_printf(out, "%-20s %d\n", "write format:", aHdr[18]);
+ utf8_printf(out, "%-20s %d\n", "read format:", aHdr[19]);
+ utf8_printf(out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
for(i=0; i<ArraySize(aField); i++){
int ofst = aField[i].ofst;
unsigned int val = get4byteInt(aHdr + ofst);
- utf8_printf(p->out, "%-20s %u", aField[i].zName, val);
+ utf8_printf(out, "%-20s %u", aField[i].zName, val);
switch( ofst ){
case 56: {
- if( val==1 ) raw_printf(p->out, " (utf8)");
- if( val==2 ) raw_printf(p->out, " (utf16le)");
- if( val==3 ) raw_printf(p->out, " (utf16be)");
+ if( val==1 ) raw_printf(out, " (utf8)");
+ if( val==2 ) raw_printf(out, " (utf16le)");
+ if( val==3 ) raw_printf(out, " (utf16be)");
}
}
- raw_printf(p->out, "\n");
+ raw_printf(out, "\n");
}
if( zDb==0 ){
zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
}
for(i=0; i<ArraySize(aQuery); i++){
char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
- int val = db_int(p->db, zSql);
+ int val = db_int(DBX(psx), zSql);
sqlite3_free(zSql);
- utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
+ utf8_printf(out, "%-20s %d\n", aQuery[i].zName, val);
}
sqlite3_free(zSchemaTab);
- sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
- utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion);
+ sqlite3_file_control(DBX(psx), zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
+ utf8_printf(out, "%-20s %u\n", "data version", iDataVersion);
return 0;
}
** Try to delete the temporary file (if there is one) and free the
** memory used to hold the name of the temp file.
*/
-static void clearTempFile(ShellState *p){
- if( p->zTempFile==0 ) return;
- if( p->doXdgOpen ) return;
- if( shellDeleteFile(p->zTempFile) ) return;
- sqlite3_free(p->zTempFile);
- p->zTempFile = 0;
+static void clearTempFile(ShellInState *psi){
+ if( psi->zTempFile==0 ) return;
+ if( psi->doXdgOpen ) return;
+ if( shellDeleteFile(psi->zTempFile) ) return;
+ sqlite3_free(psi->zTempFile);
+ psi->zTempFile = 0;
}
/*
** Create a new temp file name with the given suffix.
*/
-static void newTempFile(ShellState *p, const char *zSuffix){
- clearTempFile(p);
- sqlite3_free(p->zTempFile);
- p->zTempFile = 0;
- if( p->db ){
- sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
+static void newTempFile(ShellInState *psi, const char *zSuffix){
+ clearTempFile(psi);
+ sqlite3_free(psi->zTempFile);
+ psi->zTempFile = 0;
+ if( DBI(psi) ){
+ sqlite3_file_control(DBI(psi), 0, SQLITE_FCNTL_TEMPFILENAME,
+ &psi->zTempFile);
}
- if( p->zTempFile==0 ){
- /* If p->db is an in-memory database then the TEMPFILENAME file-control
+ if( psi->zTempFile==0 ){
+ /* If DB is an in-memory database then the TEMPFILENAME file-control
** will not work and we will need to fallback to guessing */
char *zTemp;
sqlite3_uint64 r;
zTemp = "/tmp";
#endif
}
- p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
+ psi->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
}else{
- p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
+ psi->zTempFile = sqlite3_mprintf("%z.%s", psi->zTempFile, zSuffix);
}
- shell_check_oom(p->zTempFile);
+ shell_check_oom(psi->zTempFile);
}
/*
}
}
-
-/*
-** The implementation of dot-command ".lint fkey-indexes".
-*/
-static int lintFkeyIndexes(
- ShellState *pState, /* Current shell tool state */
- char **azArg, /* Array of arguments passed to dot command */
- int nArg /* Number of entries in azArg[] */
-){
- sqlite3 *db = pState->db; /* Database handle to query "main" db of */
- FILE *out = pState->out; /* Stream to write non-error output to */
- int bVerbose = 0; /* If -verbose is present */
- int bGroupByParent = 0; /* If -groupbyparent is present */
- int i; /* To iterate through azArg[] */
- const char *zIndent = ""; /* How much to indent CREATE INDEX by */
- int rc; /* Return code */
- sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
-
- /*
- ** This SELECT statement returns one row for each foreign key constraint
- ** in the schema of the main database. The column values are:
- **
- ** 0. The text of an SQL statement similar to:
- **
- ** "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
- **
- ** This SELECT is similar to the one that the foreign keys implementation
- ** needs to run internally on child tables. If there is an index that can
- ** be used to optimize this query, then it can also be used by the FK
- ** implementation to optimize DELETE or UPDATE statements on the parent
- ** table.
- **
- ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
- ** the EXPLAIN QUERY PLAN command matches this pattern, then the schema
- ** contains an index that can be used to optimize the query.
- **
- ** 2. Human readable text that describes the child table and columns. e.g.
- **
- ** "child_table(child_key1, child_key2)"
- **
- ** 3. Human readable text that describes the parent table and columns. e.g.
- **
- ** "parent_table(parent_key1, parent_key2)"
- **
- ** 4. A full CREATE INDEX statement for an index that could be used to
- ** optimize DELETE or UPDATE statements on the parent table. e.g.
- **
- ** "CREATE INDEX child_table_child_key ON child_table(child_key)"
- **
- ** 5. The name of the parent table.
- **
- ** These six values are used by the C logic below to generate the report.
- */
- const char *zSql =
- "SELECT "
- " 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
- " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
- " || fkey_collate_clause("
- " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
- ", "
- " 'SEARCH ' || s.name || ' USING COVERING INDEX*('"
- " || group_concat('*=?', ' AND ') || ')'"
- ", "
- " s.name || '(' || group_concat(f.[from], ', ') || ')'"
- ", "
- " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
- ", "
- " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
- " || ' ON ' || quote(s.name) || '('"
- " || group_concat(quote(f.[from]) ||"
- " fkey_collate_clause("
- " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
- " || ');'"
- ", "
- " f.[table] "
- "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f "
- "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
- "GROUP BY s.name, f.id "
- "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
- ;
- const char *zGlobIPK = "SEARCH * USING INTEGER PRIMARY KEY (rowid=?)";
-
- for(i=2; i<nArg; i++){
- int n = strlen30(azArg[i]);
- if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
- bVerbose = 1;
- }
- else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
- bGroupByParent = 1;
- zIndent = " ";
- }
- else{
- raw_printf(STD_ERR, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
- azArg[0], azArg[1]
- );
- return SQLITE_ERROR;
- }
- }
-
- /* Register the fkey_collate_clause() SQL function */
- rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
- 0, shellFkeyCollateClause, 0, 0
- );
-
-
- if( rc==SQLITE_OK ){
- rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
- }
- if( rc==SQLITE_OK ){
- sqlite3_bind_int(pSql, 1, bGroupByParent);
- }
-
- if( rc==SQLITE_OK ){
- int rc2;
- char *zPrev = 0;
- while( SQLITE_ROW==sqlite3_step(pSql) ){
- int res = -1;
- sqlite3_stmt *pExplain = 0;
- const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
- const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
- const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
- const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
- const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
- const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
-
- if( zEQP==0 || zGlob==0 ) continue;
- rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
- if( rc!=SQLITE_OK ) break;
- if( SQLITE_ROW==sqlite3_step(pExplain) ){
- const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
- res = zPlan!=0 && ( 0==sqlite3_strglob(zGlob, zPlan)
- || 0==sqlite3_strglob(zGlobIPK, zPlan));
- }
- rc = sqlite3_finalize(pExplain);
- if( rc!=SQLITE_OK ) break;
-
- if( res<0 ){
- raw_printf(STD_ERR, "Error: internal error");
- break;
- }else{
- if( bGroupByParent
- && (bVerbose || res==0)
- && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
- ){
- raw_printf(out, "-- Parent table %s\n", zParent);
- sqlite3_free(zPrev);
- zPrev = sqlite3_mprintf("%s", zParent);
- }
-
- if( res==0 ){
- raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
- }else if( bVerbose ){
- raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
- zIndent, zFrom, zTarget
- );
- }
- }
- }
- sqlite3_free(zPrev);
-
- if( rc!=SQLITE_OK ){
- raw_printf(STD_ERR, "%s\n", sqlite3_errmsg(db));
- }
-
- rc2 = sqlite3_finalize(pSql);
- if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
- rc = rc2;
- raw_printf(STD_ERR, "%s\n", sqlite3_errmsg(db));
- }
- }else{
- raw_printf(STD_ERR, "%s\n", sqlite3_errmsg(db));
- }
-
- return rc;
-}
-
-
#if !defined SQLITE_OMIT_VIRTUALTABLE
static void shellPrepare(
sqlite3 *db,
const char *zFile; /* --file argument, or NULL */
const char *zDir; /* --directory argument, or NULL */
char **azArg; /* Array of command arguments */
- ShellState *p; /* Shell state */
+ ShellExState *p; /* Shell state */
+ FILE *out; /* Where to put normal messages or info */
sqlite3 *db; /* Database containing the archive */
};
shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
pAr->zSrcTable, zWhere);
if( pAr->bDryRun ){
- utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
+ utf8_printf(pAr->out, "%s\n", sqlite3_sql(pSql));
}else{
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
if( pAr->bVerbose ){
- utf8_printf(pAr->p->out, "%s % 10d %s %s\n",
+ utf8_printf(pAr->out, "%s % 10d %s %s\n",
sqlite3_column_text(pSql, 0),
sqlite3_column_int(pSql, 1),
sqlite3_column_text(pSql, 2),
sqlite3_column_text(pSql, 3)
);
}else{
- utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
+ utf8_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
}
}
}
zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;",
pAr->zSrcTable, zWhere);
if( pAr->bDryRun ){
- utf8_printf(pAr->p->out, "%s\n", zSql);
+ utf8_printf(pAr->out, "%s\n", zSql);
}else{
char *zErr = 0;
rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0);
j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
sqlite3_bind_int(pSql, j, i);
if( pAr->bDryRun ){
- utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
+ utf8_printf(pAr->out, "%s\n", sqlite3_sql(pSql));
}else{
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
if( i==0 && pAr->bVerbose ){
- utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
+ utf8_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
}
}
}
static int arExecSql(ArCommand *pAr, const char *zSql){
int rc;
if( pAr->bDryRun ){
- utf8_printf(pAr->p->out, "%s\n", zSql);
+ utf8_printf(pAr->out, "%s\n", zSql);
rc = SQLITE_OK;
}else{
char *zErr = 0;
** Implementation of ".ar" dot command.
*/
static int arDotCommand(
- ShellState *pState, /* Current shell tool state */
+ ShellExState *pState, /* Current shell tool state */
int fromCmdLine, /* True if -A command-line option, not .ar cmd */
char **azArg, /* Array of arguments passed to dot command */
int nArg /* Number of entries in azArg[] */
memset(&cmd, 0, sizeof(cmd));
cmd.fromCmdLine = fromCmdLine;
rc = arParseCommand(azArg, nArg, &cmd);
+ cmd.out = currentOutputFile(pState);
if( rc==SQLITE_OK ){
int eDbType = SHELL_OPEN_UNSPEC;
cmd.p = pState;
- cmd.db = pState->db;
+ cmd.db = DBX(pState);
if( cmd.zFile ){
eDbType = deduceDatabaseType(cmd.zFile, 1);
}else{
- eDbType = pState->openMode;
+ eDbType = ISS(pState)->openMode;
}
if( eDbType==SHELL_OPEN_ZIPFILE ){
if( cmd.eCmd==AR_CMD_EXTRACT || cmd.eCmd==AR_CMD_LIST ){
}
cmd.db = 0;
if( cmd.bDryRun ){
- utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile,
+ utf8_printf(cmd.out, "-- open database '%s'%s\n", cmd.zFile,
eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
}
rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags,
sqlite3_sqlar_init(cmd.db, 0, 0);
sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
shellPutsFunc, 0, 0);
-
}
if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){
if( cmd.eCmd!=AR_CMD_CREATE
break;
case AR_CMD_HELP:
- arUsage(pState->out);
+ arUsage(cmd.out);
break;
case AR_CMD_INSERT:
}
}
end_ar_command:
- if( cmd.db!=pState->db ){
+ if( cmd.db!=DBX(pState) ){
close_db(cmd.db);
}
sqlite3_free(cmd.zSrcTable);
** the caller should write data to the orphans table.
*/
static RecoverTable *recoverFindTable(
- ShellState *pState, /* Shell state object */
+ sqlite3 *db, /* DB from which to recover */
int *pRc, /* IN/OUT: Error code */
int iRoot, /* Root page of table */
int bIntkey, /* True for an intkey table */
const char *zName = 0;
/* Search the recovered schema for an object with root page iRoot. */
- shellPreparePrintf(pState->db, pRc, &pStmt,
+ shellPreparePrintf(db, pRc, &pStmt,
"SELECT type, name, sql FROM recovery.schema WHERE rootpage=%d", iRoot
);
while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
** Return a RecoverTable object representing the orphans table.
*/
static RecoverTable *recoverOrphanTable(
- ShellState *pState, /* Shell state object */
+ sqlite3 *db, /* DB from which to recover */
+ FILE *out, /* Where to put recovery DDL */
int *pRc, /* IN/OUT: Error code */
const char *zLostAndFound, /* Base name for orphans table */
int nCol /* Number of user data columns */
int iTab = 0;
char *zTab = shellMPrintf(pRc, "%s", zLostAndFound);
sqlite3_stmt *pTest = 0;
- shellPrepare(pState->db, pRc,
+ shellPrepare(db, pRc,
"SELECT 1 FROM recovery.schema WHERE name=?", &pTest
);
if( pTest ) sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT);
recoverFreeTable(pTab);
pTab = 0;
}else{
- raw_printf(pState->out,
+ raw_printf(out,
"CREATE TABLE %s(rootpgno INTEGER, "
"pgno INTEGER, nfield INTEGER, id INTEGER", pTab->zQuoted
);
for(i=0; i<nCol; i++){
- raw_printf(pState->out, ", c%d", i);
+ raw_printf(out, ", c%d", i);
}
- raw_printf(pState->out, ");\n");
+ raw_printf(out, ");\n");
}
}
sqlite3_free(zTab);
}
#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
-static int writeDb( char *azArg[], int nArg, ShellState *p, char **pzErr ){
+static int writeDb( char *azArg[], int nArg, ShellExState *psx, char **pzErr ){
int rc = 0;
const char *zDestFile = 0;
const char *zDb = 0;
int j;
int bAsync = 0;
const char *zVfs = 0;
- if( p->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(psx)->bSafeMode ) return SHELL_FORBIDDEN_OP;
for(j=1; j<nArg; j++){
const char *z = azArg[j];
if( z[0]=='-' ){
sqlite3_exec(pDest, "PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF;",
0, 0, 0);
}
- open_db(p, 0);
- pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
+ open_db(psx, 0);
+ pBackup = sqlite3_backup_init(pDest, "main", DBX(psx), zDb);
if( pBackup==0 ){
utf8_printf(STD_ERR, "Error: %s\n", sqlite3_errmsg(pDest));
close_db(pDest);
}
}
+#if SHELL_DYNAMIC_EXTENSION
+/* Register a meta-command */
+static int register_meta_command(ShellExState *p,
+ ExtensionId eid, MetaCommand *pMC){
+ return SQLITE_ERROR;
+}
+
+/* Register an output data display (or other disposition) mode */
+static int register_out_mode(ShellExState *p,
+ ExtensionId eid, OutModeHandler *pOMH){
+ return SQLITE_ERROR;
+}
+
+/* Register an import variation from (various sources) for .import */
+static int register_importer(ShellExState *p,
+ ExtensionId eid, ImportHandler *pIH){
+ return SQLITE_ERROR;
+}
+
+static FILE *currentOutputFile(ShellExState *p){
+ return ISS(p)->out;
+}
+
+static struct InSource *currentInputSource(ShellExState *p){
+ return ISS(p)->pInSource;
+}
+
+static int nowInteractive(ShellExState *p){
+ return INSOURCE_IS_INTERACTIVE(ISS(p)->pInSource);
+}
+
+static void setColumnWidths(ShellExState *p, char *azWidths[], int nWidths);
+
+static ExtensionHelpers extHelpers = {
+ 6,
+ {
+ failIfSafeMode,
+ currentOutputFile,
+ currentInputSource,
+ strLineGet,
+ setColumnWidths,
+ nowInteractive,
+ 0
+ }
+};
+
+static ShellExtensionAPI shellExtAPI = {
+ &extHelpers, 3, {
+ register_meta_command,
+ register_out_mode,
+ register_importer,
+ 0
+ }
+};
+
+/* This SQL function provides a way for a just-loaded shell extension to
+ * obtain a ShellExtensionLink pointer from the shell core while using
+ * the same sqlite3_load_extension API used for SQLite extensions.
+ * This serves as an alternative to deriving the same pointer from
+ * the pzErr argument passed into that API.
+ */
+static void shell_linkage(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int linkKind = 0;
+ if( argc>0 ){
+ linkKind = sqlite3_value_int(argv[0]);
+ }
+ switch (linkKind){
+ case 0:
+ sqlite3_result_pointer(context, sqlite3_user_data(context),
+ SHELLEXT_API_POINTERS, 0);
+ break;
+ default:
+ sqlite3_result_null(context);
+ }
+}
+
+static int load_shell_extension(ShellExState *psx, const char *zFile,
+ const char *zProc, char **pzErr){
+ ShellExtensionLink shxLink = {
+ sizeof(ShellExtensionLink),
+ &shellExtAPI,
+ 0, /* zErrMsg */
+ 0, /* ExtensionId */
+ 0 /* Extension destructor */
+ };
+ int rc;
+ if( psx->dbShell==0 ){
+ rc = sqlite3_open(":memory:", &psx->dbShell);
+ if( rc!=SQLITE_OK ) return 1;
+ sqlite3_enable_load_extension(psx->dbShell, 1);
+ }
+ sqlite3_create_function(psx->dbShell, "shext_pointer", 1,
+ SQLITE_DIRECTONLY|SQLITE_UTF8,
+ &shxLink, shell_linkage, 0, 0);
+ rc = sqlite3_load_extension(psx->dbShell, zFile, zProc, &shxLink.zErrMsg);
+ sqlite3_create_function(psx->dbShell, "shext_pointer", 1,
+ SQLITE_DIRECTONLY|SQLITE_UTF8,
+ 0, 0, 0, 0); /* deregister */
+ if( pzErr!=0 ) *pzErr = shxLink.zErrMsg;
+ if( rc==SQLITE_OK ){
+ /* Keep extension's id and destructor for later disposal. */
+ }
+ return rc!=SQLITE_OK;
+}
+#endif
+
#ifndef OBJECTIFY_COMMANDS
-# define OBJECTIFY_COMMANDS 1
+# define OBJECTIFY_COMMANDS 1 /* This value required for extensibility. */
#endif
/* Meta-command implementation functions are defined in this section.
COMMENT causes collection of dispatch and help table entries, to be later
COMMENT emitted by certain macros. (See EMIT_* further on.)
** All dispatchable meta-command execute functions have this signature:
-static int someCommand(char *azArg[], int nArg, ShellState *p, char **pzErr);
+static int someCommand(char *azArg[], int nArg, ShellExState *p, char **pzErr);
*/
DISPATCH_CONFIG[
RETURN_TYPE=int
STORAGE_CLASS=static
- ARGS_SIGNATURE=char *$arg4\[\], int $arg5, ShellState *$arg6, char **$arg7
+ ARGS_SIGNATURE=char *$arg4\[\], int $arg5, ShellExState *$arg6, char **$arg7
DISPATCH_ENTRY={ "$cmd", ${cmd}Command, $arg1, $arg2, $arg3 },
+ METACMD_INIT=META_CMD_INFO(${cmd}, $arg1,$arg2,$arg3, <HT0>, <HT1>),
CMD_CAPTURE_RE=^\s*{\s*"(\w+)"
DISPATCHEE_NAME=${cmd}Command
DC_ARG1_DEFAULT=[string length $cmd]
DISPATCHABLE_COMMAND( seeargs ? 0 0 azArg nArg p ){
int rc = 0;
for (rc=1; rc<nArg; ++rc)
- raw_printf(p->out, "%s%s", azArg[rc], (rc==nArg-1)? "|\n" : "|");
+ raw_printf(ISS(p)->out, "%s%s", azArg[rc], (rc==nArg-1)? "|\n" : "|");
return 0;
}
];
DISPATCHABLE_COMMAND( archive ? 0 0 azArg nArg p ){
open_db(p, 0);
- if( p->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
return arDotCommand(p, 0, azArg, nArg);
}
int rc = 0;
open_db(p, 0);
if( booleanValue(azArg[1]) ){
- sqlite3_set_authorizer(p->db, shellAuth, p);
- }else if( p->bSafeModeFuture ){
- sqlite3_set_authorizer(p->db, safeModeAuth, p);
+ sqlite3_set_authorizer(DBX(p), shellAuth, p);
+ }else if( ISS(p)->bSafeModeFuture ){
+ sqlite3_set_authorizer(DBX(p), safeModeAuth, p);
}else{
- sqlite3_set_authorizer(p->db, 0, 0);
+ sqlite3_set_authorizer(DBX(p), 0, 0);
}
return rc;
}
" --append Use the appendvfs",
" --async Write the FILE without journal and fsync()",
];
-COLLECT_DISPATCH( * )[
- { "backup", writeDb, 4, 2, 5 },
- { "save", writeDb, 3, 2, 5 },
-];
+DISPATCHABLE_COMMAND( backup 4 2 5 ){
+ return writeDb( azArg, nArg, p, pzErr);
+}
+DISPATCHABLE_COMMAND( save 3 2 5 ){
+ return writeDb( azArg, nArg, p, pzErr);
+}
/*****************
* The .bail command
];
DISPATCHABLE_COMMAND( binary 3 2 2 ){
if( booleanValue(azArg[1]) ){
- setBinaryMode(p->out, 1);
+ setBinaryMode(ISS(p)->out, 1);
}else{
- setTextMode(p->out, 1);
+ setTextMode(ISS(p)->out, 1);
}
return 0;
}
DISPATCHABLE_COMMAND( cd ? 2 2 ){
int rc=0;
- if( p->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
#if defined(_WIN32) || defined(WIN32)
wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
rc = !SetCurrentDirectoryW(z);
*/
char *zRes = 0;
int rc=0;
- output_reset(p);
+ output_reset(ISS(p));
if( nArg!=2 ){
return SHELL_INVALID_ARGS;
}else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
*pzErr =
shellMPrintf(&rc,
"testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
- p->zTestcase, azArg[1], zRes);
+ ISS(p)->zTestcase, azArg[1], zRes);
rc = 1;
}else{
- utf8_printf(STD_OUT, "testcase-%s ok\n", p->zTestcase);
- p->nCheck++;
+ utf8_printf(STD_OUT, "testcase-%s ok\n", ISS(p)->zTestcase);
+ ISS(p)->nCheck++;
}
sqlite3_free(zRes);
return rc;
}
DISPATCHABLE_COMMAND( clone ? 2 2 ){
- if( p->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
tryToClone(p, azArg[1]);
return 0;
}
DISPATCHABLE_COMMAND( connection ? 1 4 ){
+ ShellInState *psi = ISS(p);
if( nArg==1 ){
/* List available connections */
int i;
- for(i=0; i<ArraySize(p->aAuxDb); i++){
- const char *zFile = p->aAuxDb[i].zDbFilename;
- if( p->aAuxDb[i].db==0 && p->pAuxDb!=&p->aAuxDb[i] ){
- zFile = "(not open)";
+ for(i=0; i<ArraySize(psi->aAuxDb); i++){
+ const char *zFile = psi->aAuxDb[i].zDbFilename;
+ if( psi->aAuxDb[i].db==0 && psi->pAuxDb!=&psi->aAuxDb[i] ){
+ zFile = "(not open)";
}else if( zFile==0 ){
- zFile = "(memory)";
+ zFile = "(memory)";
}else if( zFile[0]==0 ){
- zFile = "(temporary-file)";
+ zFile = "(temporary-file)";
}
- if( p->pAuxDb == &p->aAuxDb[i] ){
- utf8_printf(STD_OUT, "ACTIVE %d: %s\n", i, zFile);
- }else if( p->aAuxDb[i].db!=0 ){
- utf8_printf(STD_OUT, " %d: %s\n", i, zFile);
+ if( psi->pAuxDb == &psi->aAuxDb[i] ){
+ utf8_printf(STD_OUT, "ACTIVE %d: %s\n", i, zFile);
+ }else if( psi->aAuxDb[i].db!=0 ){
+ utf8_printf(STD_OUT, " %d: %s\n", i, zFile);
}
}
}else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){
int i = azArg[1][0] - '0';
- if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && i<ArraySize(p->aAuxDb) ){
- p->pAuxDb->db = p->db;
- p->pAuxDb = &p->aAuxDb[i];
- globalDb = p->db = p->pAuxDb->db;
- p->pAuxDb->db = 0;
+ if( psi->pAuxDb != &psi->aAuxDb[i] && i>=0 && i<ArraySize(psi->aAuxDb) ){
+ psi->pAuxDb->db = DBI(psi);
+ psi->pAuxDb = &psi->aAuxDb[i];
+ globalDb = DBI(psi) = psi->pAuxDb->db;
+ psi->pAuxDb->db = 0;
}
}else if( nArg==3 && strcmp(azArg[1], "close")==0
- && IsDigit(azArg[2][0]) && azArg[2][1]==0 ){
+ && IsDigit(azArg[2][0]) && azArg[2][1]==0 ){
int i = azArg[2][0] - '0';
- if( i<0 || i>=ArraySize(p->aAuxDb) ){
+ if( i<0 || i>=ArraySize(psi->aAuxDb) ){
/* No-op */
- }else if( p->pAuxDb == &p->aAuxDb[i] ){
+ }else if( psi->pAuxDb == &psi->aAuxDb[i] ){
raw_printf(STD_ERR, "cannot close the active database connection\n");
return 1;
- }else if( p->aAuxDb[i].db ){
- session_close_all(p, i);
- close_db(p->aAuxDb[i].db);
- p->aAuxDb[i].db = 0;
+ }else if( psi->aAuxDb[i].db ){
+ session_close_all(psi, i);
+ close_db(psi->aAuxDb[i].db);
+ psi->aAuxDb[i].db = 0;
}
}else{
return SHELL_INVALID_ARGS;
char **azName = 0;
int nName = 0;
sqlite3_stmt *pStmt;
+ sqlite3 *db;
int i;
open_db(p, 0);
- rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
+ db = DBX(p);
+ rc = sqlite3_prepare_v2(db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ){
- *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(p->db));
+ *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(db));
rc = 1;
}else{
while( sqlite3_step(pStmt)==SQLITE_ROW ){
}
sqlite3_finalize(pStmt);
for(i=0; i<nName; i++){
- int eTxn = sqlite3_txn_state(p->db, azName[i*2]);
- int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]);
+ int eTxn = sqlite3_txn_state(db, azName[i*2]);
+ int bRdonly = sqlite3_db_readonly(db, azName[i*2]);
const char *z = azName[i*2+1];
- utf8_printf(p->out, "%s: %s %s%s\n",
+ utf8_printf(ISS(p)->out, "%s: %s %s%s\n",
azName[i*2],
z && z[0] ? z : "\"\"",
bRdonly ? "r/o" : "r/w",
for(ii=0; ii<ArraySize(aDbConfig); ii++){
if( nArg>1 && strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
if( nArg>=3 ){
- sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
+ sqlite3_db_config(DBX(p), aDbConfig[ii].op, booleanValue(azArg[2]), 0);
}
- sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
- utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
+ sqlite3_db_config(DBX(p), aDbConfig[ii].op, -1, &v);
+ utf8_printf(ISS(p)->out, "%19s %s\n",
+ aDbConfig[ii].zName, v ? "on" : "off");
if( nArg>1 ) break;
}
if( nArg>1 && ii==ArraySize(aDbConfig) ){
" trigger Like \"full\" but also show trigger bytecode",
];
DISPATCHABLE_COMMAND( dump ? 1 2 ){
+ ShellInState *psi = ISS(p);
char *zLike = 0;
char *zSchema = "main";
char *zSql;
int i;
- int savedShowHeader = p->showHeader;
- int savedShellFlags = p->shellFlgs;
+ int savedShowHeader = psi->showHeader;
+ int savedShellFlags = psi->shellFlgs;
ShellClearFlag(p,
SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo
|SHFLG_DumpDataOnly|SHFLG_DumpNoSys);
open_db(p, 0);
- if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
+ if( (psi->shellFlgs & SHFLG_DumpDataOnly)==0 ){
/* When playing back a "dump", the content might appear in an order
** which causes immediate foreign key constraints to be violated.
** So disable foreign-key constraint enforcement to prevent problems. */
- raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
- raw_printf(p->out, "BEGIN TRANSACTION;\n");
+ raw_printf(psi->out, "PRAGMA foreign_keys=OFF;\n");
+ raw_printf(psi->out, "BEGIN TRANSACTION;\n");
}
- p->writableSchema = 0;
- p->showHeader = 0;
+ psi->writableSchema = 0;
+ psi->showHeader = 0;
/* Set writable_schema=ON since doing so forces SQLite to initialize
** as much of the schema as it can even if the sqlite_schema table is
** corrupt. */
- sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
- p->nErr = 0;
+ sqlite3_exec(DBX(p), "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
+ psi->nErr = 0;
if( zLike==0 ) zLike = sqlite3_mprintf("true");
zSql = sqlite3_mprintf(
"SELECT name, type, sql FROM %w.sqlite_schema AS o "
" ORDER BY tbl_name='sqlite_sequence', rowid",
zSchema, zLike
);
- run_schema_dump_query(p,zSql);
+ run_schema_dump_query(psi,zSql);
sqlite3_free(zSql);
- if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
+ if( (psi->shellFlgs & SHFLG_DumpDataOnly)==0 ){
zSql = sqlite3_mprintf(
"SELECT sql FROM sqlite_schema AS o "
"WHERE (%s) AND sql NOT NULL"
" AND type IN ('index','trigger','view')",
zLike
);
- run_table_dump_query(p, zSql);
+ run_table_dump_query(psi, zSql);
sqlite3_free(zSql);
}
sqlite3_free(zLike);
- if( p->writableSchema ){
- raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
- p->writableSchema = 0;
+ if( psi->writableSchema ){
+ raw_printf(psi->out, "PRAGMA writable_schema=OFF;\n");
+ psi->writableSchema = 0;
}
- sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
- sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
- if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
- raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
+ sqlite3_exec(DBX(p), "PRAGMA writable_schema=OFF;", 0, 0, 0);
+ sqlite3_exec(DBX(p), "RELEASE dump;", 0, 0, 0);
+ if( (psi->shellFlgs & SHFLG_DumpDataOnly)==0 ){
+ raw_printf(psi->out, psi->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
}
- p->showHeader = savedShowHeader;
- p->shellFlgs = savedShellFlags;
+ psi->showHeader = savedShowHeader;
+ psi->shellFlgs = savedShellFlags;
return 0;
}
return 0;
}
DISPATCHABLE_COMMAND( eqp ? 0 0 ){
+ ShellInState *psi = ISS(p);
if( nArg==2 ){
- p->autoEQPtest = 0;
- if( p->autoEQPtrace ){
- if( p->db ) sqlite3_exec(p->db, "PRAGMA vdbe_trace=OFF;", 0, 0, 0);
- p->autoEQPtrace = 0;
+ psi->autoEQPtest = 0;
+ if( psi->autoEQPtrace ){
+ if( DBX(p) ) sqlite3_exec(DBX(p), "PRAGMA vdbe_trace=OFF;", 0, 0, 0);
+ psi->autoEQPtrace = 0;
}
if( strcmp(azArg[1],"full")==0 ){
- p->autoEQP = AUTOEQP_full;
+ psi->autoEQP = AUTOEQP_full;
}else if( strcmp(azArg[1],"trigger")==0 ){
- p->autoEQP = AUTOEQP_trigger;
+ psi->autoEQP = AUTOEQP_trigger;
#ifdef SQLITE_DEBUG
}else if( strcmp(azArg[1],"test")==0 ){
- p->autoEQP = AUTOEQP_on;
- p->autoEQPtest = 1;
+ psi->autoEQP = AUTOEQP_on;
+ psi->autoEQPtest = 1;
}else if( strcmp(azArg[1],"trace")==0 ){
- p->autoEQP = AUTOEQP_full;
- p->autoEQPtrace = 1;
+ psi->autoEQP = AUTOEQP_full;
+ psi->autoEQPtrace = 1;
open_db(p, 0);
- sqlite3_exec(p->db, "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0);
- sqlite3_exec(p->db, "PRAGMA vdbe_trace=ON;", 0, 0, 0);
+ sqlite3_exec(DBX(p), "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0);
+ sqlite3_exec(DBX(p), "PRAGMA vdbe_trace=ON;", 0, 0, 0);
#endif
}else{
- p->autoEQP = (u8)booleanValue(azArg[1]);
+ psi->autoEQP = (u8)booleanValue(azArg[1]);
}
}else{
return SHELL_INVALID_ARGS;
CONDITION_COMMAND( expert !defined(SQLITE_OMIT_VIRTUALTABLE) );
COLLECT_HELP_TEXT[
".expert Suggest indexes for queries",
- ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto",
+ ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto",
];
DISPATCHABLE_COMMAND( expert ? 1 1 ){
open_db(p, 0);
- expertDotCommand(p, azArg, nArg);
+ expertDotCommand(ISS(p), azArg, nArg);
return 0;
}
DISPATCHABLE_COMMAND( explain ? 1 2 ){
/* The ".explain" command is automatic now. It is largely
** pointless, retained purely for backwards compatibility */
+ ShellInState *psi = ISS(p);
int val = 1;
if( nArg>1 ){
if( strcmp(azArg[1],"auto")==0 ){
val = booleanValue(azArg[1]);
}
}
- if( val==1 && p->mode!=MODE_Explain ){
- p->normalMode = p->mode;
- p->mode = MODE_Explain;
- p->autoExplain = 0;
+ if( val==1 && psi->mode!=MODE_Explain ){
+ psi->normalMode = psi->mode;
+ psi->mode = MODE_Explain;
+ psi->autoExplain = 0;
}else if( val==0 ){
- if( p->mode==MODE_Explain ) p->mode = p->normalMode;
- p->autoExplain = 0;
+ if( psi->mode==MODE_Explain ) psi->mode = psi->normalMode;
+ psi->autoExplain = 0;
}else if( val==99 ){
- if( p->mode==MODE_Explain ) p->mode = p->normalMode;
- p->autoExplain = 1;
+ if( psi->mode==MODE_Explain ) psi->mode = psi->normalMode;
+ psi->autoExplain = 1;
}
return 0;
}
" -e Send output to the system text editor",
" -x Send output as CSV to a spreadsheet (same as \".excel\")",
];
-static int outputRedirs(char *[], int, ShellState *,
+static int outputRedirs(char *[], int, ShellInState *,
char **pzErr, int bOnce, int eMode);
DISPATCHABLE_COMMAND( excel ? 1 2 ){
- return outputRedirs(azArg, nArg, p, pzErr, 2, 'x');
+ return outputRedirs(azArg, nArg, ISS(p), pzErr, 2, 'x');
}
DISPATCHABLE_COMMAND( once ? 1 6 ){
- return outputRedirs(azArg, nArg, p, pzErr, 1, 0);
+ return outputRedirs(azArg, nArg, ISS(p), pzErr, 1, 0);
}
DISPATCHABLE_COMMAND( output ? 1 6 ){
- return outputRedirs(azArg, nArg, p, pzErr, 0, 0);
+ return outputRedirs(azArg, nArg, ISS(p), pzErr, 0, 0);
}
-static int outputRedirs(char *azArg[], int nArg, ShellState *p,
+static int outputRedirs(char *azArg[], int nArg, ShellInState *psi,
char **pzErr, int bOnce, int eMode){
/* bOnce => 0: .output, 1: .once, 2: .excel */
/* eMode => 'x' for excel, else 0 */
int bTxtMode = 0;
int i;
int bBOM = 0;
- if( p->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( psi->bSafeMode ) return SHELL_FORBIDDEN_OP;
for(i=1; i<nArg; i++){
char *z = azArg[i];
if( z[0]=='-' ){
shell_check_oom(zFile);
}
if( bOnce ){
- p->outCount = 2;
+ psi->outCount = 2;
}else{
- p->outCount = 0;
+ psi->outCount = 0;
}
- output_reset(p);
+ output_reset(psi);
#ifndef SQLITE_NOHAVE_SYSTEM
if( eMode=='e' || eMode=='x' ){
- p->doXdgOpen = 1;
- outputModePush(p);
+ psi->doXdgOpen = 1;
+ outputModePush(psi);
if( eMode=='x' ){
/* spreadsheet mode. Output as CSV. */
- newTempFile(p, "csv");
- ShellClearFlag(p, SHFLG_Echo);
- p->mode = MODE_Csv;
- sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
+ newTempFile(psi, "csv");
+ psi->shellFlgs &= ~SHFLG_Echo;
+ psi->mode = MODE_Csv;
+ sqlite3_snprintf(sizeof(psi->colSeparator), psi->colSeparator, SEP_Comma);
+ sqlite3_snprintf(sizeof(psi->rowSeparator), psi->rowSeparator, SEP_CrLf);
}else{
/* text editor mode */
- newTempFile(p, "txt");
+ newTempFile(psi, "txt");
bTxtMode = 1;
}
sqlite3_free(zFile);
- zFile = sqlite3_mprintf("%s", p->zTempFile);
+ zFile = sqlite3_mprintf("%s", psi->zTempFile);
}
#endif /* SQLITE_NOHAVE_SYSTEM */
shell_check_oom(zFile);
#ifdef SQLITE_OMIT_POPEN
*pzErr = shellMPrintf(&rc, "Error: pipes are not supported in this OS\n");
rc = 1;
- p->out = STD_OUT;
+ psi->out = STD_OUT;
#else
- p->out = popen(zFile + 1, "w");
- if( p->out==0 ){
+ psi->out = popen(zFile + 1, "w");
+ if( psi->out==0 ){
*pzErr = shellMPrintf(&rc, "Error: cannot open pipe \"%s\"\n", zFile + 1);
- p->out = STD_OUT;
+ psi->out = STD_OUT;
rc = 1;
}else{
- if( bBOM ) fprintf(p->out,"\357\273\277");
- sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
+ if( bBOM ) fprintf(psi->out,"\357\273\277");
+ sqlite3_snprintf(sizeof(psi->outfile), psi->outfile, "%s", zFile);
}
#endif
}else{
- p->out = output_file_open(zFile, bTxtMode);
- if( p->out==0 ){
+ psi->out = output_file_open(zFile, bTxtMode);
+ if( psi->out==0 ){
if( strcmp(zFile,"off")!=0 ){
*pzErr = shellMPrintf
(&rc, "Error: cannot write to \"%s\"\n", zFile);
}
- p->out = STD_OUT;
+ psi->out = STD_OUT;
rc = 1;
} else {
- if( bBOM ) fprintf(p->out,"\357\273\277");
- sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
+ if( bBOM ) fprintf(psi->out,"\357\273\277");
+ sqlite3_snprintf(sizeof(psi->outfile), psi->outfile, "%s", zFile);
}
}
sqlite3_free(zFile);
{ "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" },
/* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY, "COUNT DELAY" },*/
};
+ ShellInState *psi = ISS(p);
int filectrl = -1;
int iCtrl = -1;
sqlite3_int64 iRes = 0; /* Integer result to display if rc2==1 */
/* --help lists all file-controls */
if( strcmp(zCmd,"help")==0 ){
- utf8_printf(p->out, "Available file-controls:\n");
+ utf8_printf(psi->out, "Available file-controls:\n");
for(i=0; i<ArraySize(aCtrl); i++){
- utf8_printf(p->out, " .filectrl %s %s\n",
+ utf8_printf(psi->out, " .filectrl %s %s\n",
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
}
return 1;
}
-
+
/* Convert filectrl text option to value. Allow any
** unique prefix of the option name, or a numerical value. */
n2 = strlen30(zCmd);
case SQLITE_FCNTL_SIZE_LIMIT: {
if( nArg!=2 && nArg!=3 ) break;
iRes = nArg==3 ? integerValue(azArg[2]) : -1;
- sqlite3_file_control(p->db, zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
+ sqlite3_file_control(DBX(p), zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
isOk = 1;
break;
}
int x;
if( nArg!=3 ) break;
x = (int)integerValue(azArg[2]);
- sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ sqlite3_file_control(DBX(p), zSchema, filectrl, &x);
isOk = 2;
break;
}
int x;
if( nArg!=2 && nArg!=3 ) break;
x = nArg==3 ? booleanValue(azArg[2]) : -1;
- sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ sqlite3_file_control(DBX(p), zSchema, filectrl, &x);
iRes = x;
isOk = 1;
break;
case SQLITE_FCNTL_HAS_MOVED: {
int x;
if( nArg!=2 ) break;
- sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ sqlite3_file_control(DBX(p), zSchema, filectrl, &x);
iRes = x;
isOk = 1;
break;
case SQLITE_FCNTL_TEMPFILENAME: {
char *z = 0;
if( nArg!=2 ) break;
- sqlite3_file_control(p->db, zSchema, filectrl, &z);
+ sqlite3_file_control(DBX(p), zSchema, filectrl, &z);
if( z ){
- utf8_printf(p->out, "%s\n", z);
+ utf8_printf(psi->out, "%s\n", z);
sqlite3_free(z);
}
isOk = 2;
int x;
if( nArg>=3 ){
x = atoi(azArg[2]);
- sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ sqlite3_file_control(DBX(p), zSchema, filectrl, &x);
}
x = -1;
- sqlite3_file_control(p->db, zSchema, filectrl, &x);
- utf8_printf(p->out,"%d\n", x);
+ sqlite3_file_control(DBX(p), zSchema, filectrl, &x);
+ utf8_printf(psi->out,"%d\n", x);
isOk = 2;
break;
}
}
}
if( isOk==0 && iCtrl>=0 ){
- utf8_printf(p->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
+ utf8_printf(psi->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
return 1;
}else if( isOk==1 ){
char zBuf[100];
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
- raw_printf(p->out, "%s\n", zBuf);
+ raw_printf(psi->out, "%s\n", zBuf);
}
return 0;
}
DISPATCHABLE_COMMAND( fullschema ? 1 2 ){
int rc;
- ShellState data;
+ ShellInState data;
+ ShellExState datax;
int doStats = 0;
- memcpy(&data, p, sizeof(data));
+ /* Consider some refactoring to avoid this wholesale copying. */
+ memcpy(&data, ISS(p), sizeof(data));
+ memcpy(&datax, p, sizeof(datax));
+ data.pSXS = &datax;
+ datax.pSIS = &data;
data.showHeader = 0;
data.cMode = data.mode = MODE_Semi;
if( nArg==2 && optionMatch(azArg[1], "indent") ){
return SHELL_INVALID_ARGS;
}
open_db(p, 0);
- rc = sqlite3_exec(p->db,
+ rc = sqlite3_exec(datax.dbUser,
"SELECT sql FROM"
" (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
" FROM sqlite_schema UNION ALL"
" SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) "
"WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
"ORDER BY x",
- callback, &data, 0
+ callback, &datax, 0
);
if( rc==SQLITE_OK ){
sqlite3_stmt *pStmt;
- rc = sqlite3_prepare_v2(p->db,
+ rc = sqlite3_prepare_v2(datax.dbUser,
"SELECT rowid FROM sqlite_schema"
" WHERE name GLOB 'sqlite_stat[134]'",
-1, &pStmt, 0);
sqlite3_finalize(pStmt);
}
if( doStats==0 ){
- raw_printf(p->out, "/* No STAT tables available */\n");
+ raw_printf(data.out, "/* No STAT tables available */\n");
}else{
- raw_printf(p->out, "ANALYZE sqlite_schema;\n");
+ raw_printf(data.out, "ANALYZE sqlite_schema;\n");
data.cMode = data.mode = MODE_Insert;
- data.zDestTable = "sqlite_stat1";
- shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
- data.zDestTable = "sqlite_stat4";
- shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
- raw_printf(p->out, "ANALYZE sqlite_schema;\n");
+ datax.zDestTable = "sqlite_stat1";
+ shell_exec(&datax, "SELECT * FROM sqlite_stat1", 0);
+ datax.zDestTable = "sqlite_stat4";
+ shell_exec(&datax, "SELECT * FROM sqlite_stat4", 0);
+ raw_printf(data.out, "ANALYZE sqlite_schema;\n");
}
return rc > 0;
}
".headers on|off Turn display of headers on or off",
];
DISPATCHABLE_COMMAND( headers 6 2 2 ){
- p->showHeader = booleanValue(azArg[1]);
- p->shellFlgs |= SHFLG_HeaderSet;
+ ISS(p)->showHeader = booleanValue(azArg[1]);
+ ISS(p)->shellFlgs |= SHFLG_HeaderSet;
return 0;
}
zPat = z;
}
}
- if( showHelp(p->out, zPat)==0 ){
- utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]);
+ if( showHelp(ISS(p)->out, zPat)==0 ){
+ utf8_printf(ISS(p)->out, "Nothing matches '%s'\n", azArg[1]);
}
/* Help pleas never fail! */
return 0;
int nByte; /* Number of bytes in an SQL string */
int i, j; /* Loop counters */
int needCommit; /* True to COMMIT or ROLLBACK at end */
- int nSep; /* Number of bytes in p->colSeparator[] */
+ int nSep; /* Number of bytes in psi->colSeparator[] */
char *zSql; /* An SQL statement */
ImportCtx sCtx; /* Reader context */
char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
int eVerbose = 0; /* Larger for more console output */
int nSkip = 0; /* Initial lines to skip */
int useOutputMode = 1; /* Use output mode to determine separators */
+ FILE *out = ISS(p)->out; /* output stream */
+ ShellInState *psi = ISS(p);
int rc = 0;
- if(p->bSafeMode) return SHELL_FORBIDDEN_OP;
+ if(psi->bSafeMode) return SHELL_FORBIDDEN_OP;
memset(&sCtx, 0, sizeof(sCtx));
if( 0==(sCtx.z = sqlite3_malloc64(120)) ){
shell_out_of_memory();
}
- if( p->mode==MODE_Ascii ){
+ if( psi->mode==MODE_Ascii ){
xRead = ascii_read_one_field;
}else{
xRead = csv_read_one_field;
const char *zYap = 0;
/* If neither the --csv or --ascii options are specified, then set
** the column and row separator characters from the output mode. */
- nSep = strlen30(p->colSeparator);
+ nSep = strlen30(psi->colSeparator);
if( nSep==0 ){
zYap = "Error: non-null column separator required for import";
}
zYap = "Error: multi-character or multi-byte column separators"
" not allowed for import";
}
- nSep = strlen30(p->rowSeparator);
+ nSep = strlen30(psi->rowSeparator);
if( nSep==0 ){
zYap = "Error: non-null row separator required for import";
}
*pzErr = shellMPrintf(0,"%s\n", zYap);
return 1;
}
- if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){
+ if( nSep==2 && psi->mode==MODE_Csv
+ && strcmp(psi->rowSeparator,SEP_CrLf)==0 ){
/* When importing CSV (only), if the row separator is set to the
** default output row separator, change it to the default input
** row separator. This avoids having to maintain different input
** and output row separators. */
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- nSep = strlen30(p->rowSeparator);
+ sqlite3_snprintf(sizeof(psi->rowSeparator), psi->rowSeparator, SEP_Row);
+ nSep = strlen30(psi->rowSeparator);
}
if( nSep>1 ){
*pzErr = sqlite3_mprintf
("Error: multi-character row separators not allowed for import\n");
return 1;
}
- sCtx.cColSep = p->colSeparator[0];
- sCtx.cRowSep = p->rowSeparator[0];
+ sCtx.cColSep = psi->colSeparator[0];
+ sCtx.cRowSep = psi->rowSeparator[0];
}
sCtx.zFile = zFile;
sCtx.nLine = 1;
char zSep[2];
zSep[1] = 0;
zSep[0] = sCtx.cColSep;
- utf8_printf(p->out, "Column separator ");
- output_c_string(p->out, zSep);
- utf8_printf(p->out, ", row separator ");
+ utf8_printf(out, "Column separator ");
+ output_c_string(out, zSep);
+ utf8_printf(out, ", row separator ");
zSep[0] = sCtx.cRowSep;
- output_c_string(p->out, zSep);
- utf8_printf(p->out, "\n");
+ output_c_string(out, zSep);
+ utf8_printf(out, "\n");
}
while( (nSkip--)>0 ){
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
shell_out_of_memory();
}
nByte = strlen30(zSql);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(DBX(p), zSql, -1, &pStmt, 0);
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
- if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
+ if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(DBX(p)))==0 ){
char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"",
zSchema, zTable);
sqlite3 *dbCols = 0;
char *zColDefs;
while( xRead(&sCtx) ){
zAutoColumn(sCtx.z, &dbCols, 0);
-
if( sCtx.cTerm!=sCtx.cColSep ) break;
}
zColDefs = zAutoColumn(0, &dbCols, &zRenames);
if( zRenames!=0 ){
- FILE *fh = INSOURCE_IS_INTERACTIVE(p->pInSource)? p->out : STD_ERR;
+ FILE *fh = INSOURCE_IS_INTERACTIVE(psi->pInSource)? out : STD_ERR;
utf8_printf(fh, "Columns renamed during .import %s due to duplicates:\n"
"%s\n", sCtx.zFile, zRenames);
sqlite3_free(zRenames);
}
zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs);
if( eVerbose>=1 ){
- utf8_printf(p->out, "%s\n", zCreate);
+ utf8_printf(out, "%s\n", zCreate);
}
- rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
+ rc = sqlite3_exec(DBX(p), zCreate, 0, 0, 0);
if( rc ){
- utf8_printf(STD_ERR, "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
+ utf8_printf(STD_ERR, "%s failed:\n%s\n", zCreate, sqlite3_errmsg(DBX(p)));
sqlite3_free(zCreate);
import_cleanup(&sCtx);
return 1;
}
sqlite3_free(zCreate);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(DBX(p), zSql, -1, &pStmt, 0);
}
sqlite3_free(zSql);
if( rc ){
if (pStmt) sqlite3_finalize(pStmt);
- *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(p->db));
+ *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(DBX(p)));
import_cleanup(&sCtx);
return 1;
}
zSql[j++] = ')';
zSql[j] = 0;
if( eVerbose>=2 ){
- utf8_printf(p->out, "Insert using: %s\n", zSql);
+ utf8_printf(psi->out, "Insert using: %s\n", zSql);
}
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(DBX(p), zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
- *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(p->db));
+ *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(DBX(p)));
if (pStmt) sqlite3_finalize(pStmt);
import_cleanup(&sCtx);
return 1;
}
- needCommit = sqlite3_get_autocommit(p->db);
- if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
+ needCommit = sqlite3_get_autocommit(DBX(p));
+ if( needCommit ) sqlite3_exec(DBX(p), "BEGIN", 0, 0, 0);
do{
int startLine = sCtx.nLine;
for(i=0; i<nCol; i++){
** columns in ASCII mode? If so, stop instead of NULL filling
** the remaining columns.
*/
- if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
+ if( psi->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
utf8_printf(STD_ERR, "%s:%d: expected %d columns but found %d - "
rc = sqlite3_reset(pStmt);
if( rc!=SQLITE_OK ){
utf8_printf(STD_ERR, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
- startLine, sqlite3_errmsg(p->db));
+ startLine, sqlite3_errmsg(DBX(p)));
sCtx.nErr++;
}else{
sCtx.nRow++;
import_cleanup(&sCtx);
sqlite3_finalize(pStmt);
- if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
+ if( needCommit ) sqlite3_exec(DBX(p), "COMMIT", 0, 0, 0);
if( eVerbose>0 ){
- utf8_printf(p->out,
+ utf8_printf(out,
"Added %d rows with %d errors using %d lines of input\n",
sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
}
".keyword ?KW? List keywords, or say whether KW is one.",
];
DISPATCHABLE_COMMAND( keyword ? 1 2 ){
+ FILE *out = ISS(p)->out;
if( nArg<2 ){
int i = 0;
int nk = sqlite3_keyword_count();
}
memcpy(kwBuf, zKW, szKW);
kwBuf[szKW] = 0;
- utf8_printf(p->out, "%s%s", kwBuf, zSep);
+ utf8_printf(out, "%s%s", kwBuf, zSep);
}
}
}
- if( nCol>0 ) utf8_printf(p->out, "\n");
+ if( nCol>0 ) utf8_printf(out, "\n");
}else{
int szKW = strlen30(azArg[1]);
int isKeyword = sqlite3_keyword_check(azArg[1], szKW);
- utf8_printf(p->out, "%s is%s a keyword\n",
+ utf8_printf(out, "%s is%s a keyword\n",
azArg[1], (isKeyword)? "" : " not");
}
return 0;
" Options:",
" fkey-indexes Find missing foreign key indexes",
".load FILE ?ENTRY? Load an extension library",
+#if SHELL_DYNAMIC_EXTENSION
+ " Option -shellext will load the library as a shell extension.",
+#endif
".log FILE|off Turn logging on or off. FILE can be stderr/stdout",
];
DISPATCHABLE_COMMAND( imposter ? 3 3 ){
char *zSql;
char *zCollist = 0;
sqlite3_stmt *pStmt;
+ sqlite3 *db;
int tnum = 0;
int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */
int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
return 1;
}
open_db(p, 0);
+ db = DBX(p);
if( nArg==2 ){
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1);
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 0, 1);
return 0;
}
zSql = sqlite3_mprintf(
" AND sql LIKE '%%without%%rowid%%'",
azArg[1], azArg[1]
);
- sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( sqlite3_step(pStmt)==SQLITE_ROW ){
tnum = sqlite3_column_int(pStmt, 0);
}
sqlite3_finalize(pStmt);
zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
i = 0;
while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
return 1;
}
if( lenPK==0 ) lenPK = 100000;
- zSql = sqlite3_mprintf(
- "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))WITHOUT ROWID",
- azArg[2], zCollist, lenPK, zCollist);
+ zSql = sqlite3_mprintf("CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))"
+ "WITHOUT ROWID", azArg[2], zCollist, lenPK, zCollist);
sqlite3_free(zCollist);
- rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
+ rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 1, tnum);
if( rc==SQLITE_OK ){
- rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
+ rc = sqlite3_exec(db, zSql, 0, 0, 0);
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 0, 0);
if( rc ){
*pzErr = shellMPrintf(0,"Error in [%s]: %s\n",
- zSql, sqlite3_errmsg(p->db));
+ zSql, sqlite3_errmsg(db));
}else{
utf8_printf(STD_OUT, "%s;\n", zSql);
- raw_printf(STD_OUT,
- "WARNING: writing to an imposter table will corrupt the \"%s\" %s!\n",
+ raw_printf(STD_OUT, "WARNING: "
+ "writing to an imposter table will corrupt the \"%s\" %s!\n",
azArg[1], isWO ? "table" : "index"
);
}
if( nArg==1 ){
for(i=0; i<ArraySize(aLimit); i++){
fprintf(STD_OUT, "%20s %d\n", aLimit[i].zLimitName,
- sqlite3_limit(p->db, aLimit[i].limitCode, -1));
+ sqlite3_limit(DBX(p), aLimit[i].limitCode, -1));
}
}else if( nArg>3 ){
return SHELL_INVALID_ARGS;
return 1;
}
if( nArg==3 ){
- sqlite3_limit(p->db, aLimit[iLimit].limitCode,
+ sqlite3_limit(DBX(p), aLimit[iLimit].limitCode,
(int)integerValue(azArg[2]));
}
fprintf(STD_OUT, "%20s %d\n", aLimit[iLimit].zLimitName,
- sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
+ sqlite3_limit(DBX(p), aLimit[iLimit].limitCode, -1));
}
return 0;
}
DISPATCHABLE_COMMAND( lint 3 1 0 ){
- open_db(p, 0);
- int n = (nArg>=2 ? strlen30(azArg[1]) : 0);
- if( n>0 && !sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ){
- return lintFkeyIndexes(p, azArg, nArg);
- }
- *pzErr = sqlite3_mprintf
- ("Usage %s sub-command ?switches...?\n"
- "Where sub-commands are:\n"
- " fkey-indexes\n", azArg[0]);
- return 1;
-}
+ sqlite3 *db; /* Database handle to query "main" db of */
+ FILE *out = ISS(p)->out; /* Stream to write non-error output to */
+ int bVerbose = 0; /* If -verbose is present */
+ int bGroupByParent = 0; /* If -groupbyparent is present */
+ int i; /* To iterate through azArg[] */
+ const char *zIndent = ""; /* How much to indent CREATE INDEX by */
+ int rc; /* Return code */
+ sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
-DISPATCHABLE_COMMAND( load ? 2 3 ){
- const char *zFile, *zProc;
- char *zErrMsg = 0;
- if( p->bSafeMode ) return SHELL_FORBIDDEN_OP;
- zFile = azArg[1];
- zProc = nArg>=3 ? azArg[2] : 0;
- open_db(p, 0);
- if( SQLITE_OK!=sqlite3_load_extension(p->db, zFile, zProc, pzErr) ){
+ i = (nArg>=2 ? strlen30(azArg[1]) : 0);
+ if( i==0 || 0!=sqlite3_strnicmp(azArg[1], "fkey-indexes", i) ){
+ *pzErr = sqlite3_mprintf
+ ("Usage %s sub-command ?switches...?\n"
+ "Where sub-commands are:\n"
+ " fkey-indexes\n", azArg[0]);
return 1;
}
- return 0;
+ open_db(p, 0);
+ db = DBX(p);
+
+ /*
+ ** This SELECT statement returns one row for each foreign key constraint
+ ** in the schema of the main database. The column values are:
+ **
+ ** 0. The text of an SQL statement similar to:
+ **
+ ** "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
+ **
+ ** This SELECT is similar to the one that the foreign keys implementation
+ ** needs to run internally on child tables. If there is an index that can
+ ** be used to optimize this query, then it can also be used by the FK
+ ** implementation to optimize DELETE or UPDATE statements on the parent
+ ** table.
+ **
+ ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
+ ** the EXPLAIN QUERY PLAN command matches this pattern, then the schema
+ ** contains an index that can be used to optimize the query.
+ **
+ ** 2. Human readable text that describes the child table and columns. e.g.
+ **
+ ** "child_table(child_key1, child_key2)"
+ **
+ ** 3. Human readable text that describes the parent table and columns. e.g.
+ **
+ ** "parent_table(parent_key1, parent_key2)"
+ **
+ ** 4. A full CREATE INDEX statement for an index that could be used to
+ ** optimize DELETE or UPDATE statements on the parent table. e.g.
+ **
+ ** "CREATE INDEX child_table_child_key ON child_table(child_key)"
+ **
+ ** 5. The name of the parent table.
+ **
+ ** These six values are used by the C logic below to generate the report.
+ */
+ const char *zSql =
+ "SELECT "
+ " 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
+ " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
+ " || fkey_collate_clause("
+ " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
+ ", "
+ " 'SEARCH ' || s.name || ' USING COVERING INDEX*('"
+ " || group_concat('*=?', ' AND ') || ')'"
+ ", "
+ " s.name || '(' || group_concat(f.[from], ', ') || ')'"
+ ", "
+ " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
+ ", "
+ " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
+ " || ' ON ' || quote(s.name) || '('"
+ " || group_concat(quote(f.[from]) ||"
+ " fkey_collate_clause("
+ " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
+ " || ');'"
+ ", "
+ " f.[table] "
+ "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f "
+ "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
+ "GROUP BY s.name, f.id "
+ "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
+ ;
+ const char *zGlobIPK = "SEARCH * USING INTEGER PRIMARY KEY (rowid=?)";
+
+ for(i=2; i<nArg; i++){
+ int n = strlen30(azArg[i]);
+ if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
+ bVerbose = 1;
+ }
+ else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
+ bGroupByParent = 1;
+ zIndent = " ";
+ }
+ else{
+ raw_printf(STD_ERR, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
+ azArg[0], azArg[1]
+ );
+ return SQLITE_ERROR;
+ }
+ }
+
+ /* Register the fkey_collate_clause() SQL function */
+ rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
+ 0, shellFkeyCollateClause, 0, 0
+ );
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int(pSql, 1, bGroupByParent);
+ }
+
+ if( rc==SQLITE_OK ){
+ int rc2;
+ char *zPrev = 0;
+ while( SQLITE_ROW==sqlite3_step(pSql) ){
+ int res = -1;
+ sqlite3_stmt *pExplain = 0;
+ const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
+ const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
+ const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
+ const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
+ const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
+ const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
+
+ if( zEQP==0 || zGlob==0 ) continue;
+ rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
+ if( rc!=SQLITE_OK ) break;
+ if( SQLITE_ROW==sqlite3_step(pExplain) ){
+ const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
+ res = zPlan!=0 && ( 0==sqlite3_strglob(zGlob, zPlan)
+ || 0==sqlite3_strglob(zGlobIPK, zPlan));
+ }
+ rc = sqlite3_finalize(pExplain);
+ if( rc!=SQLITE_OK ) break;
+
+ if( res<0 ){
+ raw_printf(STD_ERR, "Error: internal error");
+ break;
+ }else{
+ if( bGroupByParent
+ && (bVerbose || res==0)
+ && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
+ ){
+ raw_printf(out, "-- Parent table %s\n", zParent);
+ sqlite3_free(zPrev);
+ zPrev = sqlite3_mprintf("%s", zParent);
+ }
+
+ if( res==0 ){
+ raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
+ }else if( bVerbose ){
+ raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
+ zIndent, zFrom, zTarget);
+ }
+ }
+ }
+ sqlite3_free(zPrev);
+
+ if( rc!=SQLITE_OK ){
+ raw_printf(STD_ERR, "%s\n", sqlite3_errmsg(db));
+ }
+
+ rc2 = sqlite3_finalize(pSql);
+ if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
+ rc = rc2;
+ raw_printf(STD_ERR, "%s\n", sqlite3_errmsg(db));
+ }
+ }else{
+ raw_printf(STD_ERR, "%s\n", sqlite3_errmsg(db));
+ }
+
+ return rc;
+}
+
+DISPATCHABLE_COMMAND( load ? 2 4 ){
+ const char *zFile = 0, *zProc = 0;
+ char *zErrMsg = 0;
+ int ai = 1, rc;
+#if SHELL_DYNAMIC_EXTENSION
+ u8 bLoadExt = 0;
+#endif
+ if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ while( ai<nArg ){
+ const char *zA = azArg[ai++];
+#if SHELL_DYNAMIC_EXTENSION
+ if( optionMatch(zA, "shellext") ) bLoadExt = 1;
+ else
+#endif
+ if( zFile==0 ) zFile = zA;
+ else if( zProc==0 ) zProc = zA;
+ else return SHELL_INVALID_ARGS;
+ }
+#if SHELL_DYNAMIC_EXTENSION
+ if( bLoadExt ){
+ rc = load_shell_extension(p, zFile, zProc, pzErr);
+ }else
+#endif
+ {
+ open_db(p, 0);
+ rc = sqlite3_load_extension(DBX(p), zFile, zProc, pzErr);
+ }
+ return rc!=SQLITE_OK;
}
DISPATCHABLE_COMMAND( log ? 2 2 ){
const char *zFile = azArg[1];
- if( p->bSafeMode ) return SHELL_FORBIDDEN_OP;
- output_file_close(p->pLog);
- p->pLog = output_file_open(zFile, 0);
+ if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ output_file_close(ISS(p)->pLog);
+ ISS(p)->pLog = output_file_open(zFile, 0);
return 0;
}
-static void effectMode(ShellState *p, u8 modeRequest, u8 modeNominal){
+static void effectMode(ShellInState *psi, u8 modeRequest, u8 modeNominal){
/* Effect the specified mode change. */
const char *zColSep = 0, *zRowSep = 0;
assert(modeNominal!=MODE_COUNT_OF);
zRowSep = SEP_Row;
break;
case MODE_Column:
- if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
- p->showHeader = 1;
+ if( (psi->shellFlgs & SHFLG_HeaderSet)==0 ){
+ psi->showHeader = 1;
}
zRowSep = SEP_Row;
break;
return;
}
if( zRowSep!=0 ){
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, zRowSep);
+ sqlite3_snprintf(sizeof(psi->rowSeparator), psi->rowSeparator, zRowSep);
}
if( zColSep!=0 ){
- sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, zColSep);
+ sqlite3_snprintf(sizeof(psi->colSeparator), psi->colSeparator, zColSep);
}
- p->mode = modeNominal;
+ psi->mode = modeNominal;
}
/*****************
" TABLE The name of SQL table used for \"insert\" mode",
];
DISPATCHABLE_COMMAND( mode ? 1 0 ){
+ ShellInState *psi = ISS(p);
const char *zTabname = 0;
const char *zArg;
int i;
}
} /* Arg loop */
if( foundMode==MODE_COUNT_OF ){
+ FILE *out = psi->out;
const char *zMode;
int nms;
- i = p->mode;
+ i = psi->mode;
assert(i>=0 && i<MODE_COUNT_OF);
zMode = modeDescr[i].zModeName;
nms = strlen30(zMode)-modeDescr[i].bDepluralize;
/* Mode not specified. Show present mode (and toss any options set.) */
- if( MODE_IS_COLUMNAR(p->mode) ){
+ if( MODE_IS_COLUMNAR(psi->mode) ){
raw_printf
- (p->out, "current output mode: %.*s --wrap %d --wordwrap %s --%squote\n",
- nms, zMode, p->cmOpts.iWrap,
- p->cmOpts.bWordWrap ? "on" : "off",
- p->cmOpts.bQuote ? "" : "no");
+ (out, "current output mode: %.*s --wrap %d --wordwrap %s --%squote\n",
+ nms, zMode, psi->cmOpts.iWrap,
+ psi->cmOpts.bWordWrap ? "on" : "off",
+ psi->cmOpts.bQuote ? "" : "no");
}else{
- raw_printf(p->out, "current output mode: %.*s\n", nms, zMode);
+ raw_printf(out, "current output mode: %.*s\n", nms, zMode);
}
}else{
- effectMode(p, foundMode, setMode);
- if( MODE_IS_COLUMNAR(setMode) ) p->cmOpts = cmOpts;
+ effectMode(psi, foundMode, setMode);
+ if( MODE_IS_COLUMNAR(setMode) ) psi->cmOpts = cmOpts;
else if( setMode==MODE_Insert ){
set_table_name(p, zTabname ? zTabname : "table");
}
}
- p->cMode = p->mode;
+ psi->cMode = psi->mode;
return 0;
flag_unknown:
utf8_printf(STD_ERR, "Error: Unknown .mode option: %s\nValid options:\n%s",
".nullvalue STRING Use STRING in place of NULL values",
];
DISPATCHABLE_COMMAND( open 3 1 0 ){
+ ShellInState *psi = ISS(p);
const char *zFN = 0; /* Pointer to constant filename */
char *zNewFilename = 0; /* Name of the database file to open */
int iName = 1; /* Index in azArg[] of the filename */
int newFlag = 0; /* True to delete file before opening */
u8 openMode = SHELL_OPEN_UNSPEC;
+ int openFlags = 0;
+ sqlite3_int64 szMax = 0;
int rc = 0;
/* Check for command-line arguments */
for(iName=1; iName<nArg; iName++){
}else if( optionMatch(z, "readonly") ){
openMode = SHELL_OPEN_READONLY;
}else if( optionMatch(z, "nofollow") ){
- p->openFlags |= SQLITE_OPEN_NOFOLLOW;
+ openFlags |= SQLITE_OPEN_NOFOLLOW;
#ifndef SQLITE_OMIT_DESERIALIZE
}else if( optionMatch(z, "deserialize") ){
openMode = SHELL_OPEN_DESERIALIZE;
}else if( optionMatch(z, "hexdb") ){
openMode = SHELL_OPEN_HEXDB;
}else if( optionMatch(z, "maxsize") && iName+1<nArg ){
- p->szMax = integerValue(azArg[++iName]);
+ szMax = integerValue(azArg[++iName]);
#endif /* SQLITE_OMIT_DESERIALIZE */
}else if( z[0]=='-' ){
*pzErr = shellMPrintf(0,"unknown option: %s\n", z);
}
/* Close the existing database */
- session_close_all(p, -1);
- close_db(p->db);
- p->db = 0;
- p->pAuxDb->zDbFilename = 0;
- sqlite3_free(p->pAuxDb->zFreeOnClose);
- p->pAuxDb->zFreeOnClose = 0;
- p->openMode = openMode;
- p->openFlags = 0;
- p->szMax = 0;
+ session_close_all(psi, -1);
+ close_db(DBX(p));
+ DBX(p) = 0;
+ psi->pAuxDb->zDbFilename = 0;
+ sqlite3_free(psi->pAuxDb->zFreeOnClose);
+ psi->pAuxDb->zFreeOnClose = 0;
+ psi->openMode = openMode;
+ psi->openFlags = 0;
+ psi->szMax = 0;
/* If a filename is specified, try to open it first */
- if( zFN || p->openMode==SHELL_OPEN_HEXDB ){
- if( newFlag && zFN && !p->bSafeMode ) shellDeleteFile(zFN);
- if( p->bSafeMode
- && p->openMode!=SHELL_OPEN_HEXDB
+ if( zFN || psi->openMode==SHELL_OPEN_HEXDB ){
+ if( newFlag && zFN && !psi->bSafeMode ) shellDeleteFile(zFN);
+ if( psi->bSafeMode
+ && psi->openMode!=SHELL_OPEN_HEXDB
&& zFN
&& strcmp(zFN,":memory:")!=0
){
}else{
zNewFilename = 0;
}
- p->pAuxDb->zDbFilename = zNewFilename;
+ psi->pAuxDb->zDbFilename = zNewFilename;
+ psi->openFlags = openFlags;
+ psi->szMax = szMax;
open_db(p, OPEN_DB_KEEPALIVE);
- if( p->db==0 ){
+ if( DBX(p)==0 ){
*pzErr = shellMPrintf(0,"Error: cannot open '%s'\n", zNewFilename);
sqlite3_free(zNewFilename);
rc = 1;
}else{
- p->pAuxDb->zFreeOnClose = zNewFilename;
+ psi->pAuxDb->zFreeOnClose = zNewFilename;
}
}
- if( p->db==0 ){
+ if( DBX(p)==0 ){
/* As a fall-back open a TEMP database */
- p->pAuxDb->zDbFilename = 0;
+ psi->pAuxDb->zDbFilename = 0;
open_db(p, 0);
}
return rc;
}
DISPATCHABLE_COMMAND( nonce ? 2 2 ){
- if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){
+ ShellInState *psi = ISS(p);
+ if( psi->zNonce==0 || strcmp(azArg[1],psi->zNonce)!=0 ){
raw_printf(STD_ERR, "line %d: incorrect nonce: \"%s\"\n",
- p->pInSource->lineno, azArg[1]);
+ psi->pInSource->lineno, azArg[1]);
exit(1);
}
/* Suspend safe mode for 1 meta-command after this. */
- p->bSafeModeFuture = 2;
+ psi->bSafeModeFuture = 2;
return 0;
}
DISPATCHABLE_COMMAND( nullvalue ? 2 2 ){
- sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
- "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
+ sqlite3_snprintf(sizeof(ISS(p)->nullValue), ISS(p)->nullValue, "%.*s",
+ (int)ArraySize(ISS(p)->nullValue)-1, azArg[1]);
return 0;
}
}
/* list or ls subcommand for .parameter dot-command */
-static void list_params(ShellState *p, ParamTableUse ptu, u8 bShort,
+static void list_params(ShellExState *psx, ParamTableUse ptu, u8 bShort,
char **pzArgs, int nArg){
sqlite3_stmt *pStmt = 0;
- sqlite3_str *sbList = sqlite3_str_new(p->db);
+ sqlite3 *db = DBX(psx);
+ sqlite3_str *sbList = sqlite3_str_new(db);
int len = 0, rc;
char *zFromWhere = 0;
char *zSql = 0;
shell_check_oom(zFromWhere);
zSql = sqlite3_mprintf("SELECT max(length(key)) %s", zFromWhere);
shell_check_oom(zSql);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int(pStmt, 1, ptu);
if( sqlite3_step(pStmt)==SQLITE_ROW ){
sqlite3_finalize(pStmt);
pStmt = 0;
if( len ){
+ FILE *out = ISS(psx)->out;
sqlite3_free(zSql);
if( !bShort ){
int nBindings = 0, nScripts = 0;
zSql = sqlite3_mprintf("SELECT key, uses, iif(uses, value, quote(value))"
" %z ORDER BY uses, key", zFromWhere);
shell_check_oom(zSql);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_bind_int(pStmt, 1, ptu);
while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
ParamTableUse ptux = sqlite3_column_int(pStmt,1);
switch( ptux ){
case PTU_Binding:
if( nBindings++ == 0 ){
- utf8_printf(p->out, "Binding Values:\n%-*s %s\n",
+ utf8_printf(out, "Binding Values:\n%-*s %s\n",
len, "name", "value");
}
- utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
+ utf8_printf(out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
sqlite3_column_text(pStmt,2));
break;
case PTU_Script:
if( nScripts++ == 0 ){
- utf8_printf(p->out, "Scripts\n%-*s %s\n", len, "name", "value");
+ utf8_printf(out, "Scripts\n%-*s %s\n", len, "name", "value");
}
- utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
+ utf8_printf(out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
sqlite3_column_text(pStmt,2));
break;
default: break; /* Ignore */
int nc = 0, ncw = 78/(len+2);
zSql = sqlite3_mprintf("SELECT key %z ORDER BY key", zFromWhere);
shell_check_oom(zSql);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_bind_int(pStmt, 1, ptu);
while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
- utf8_printf(p->out, "%s %-*s", ((++nc%ncw==0)? "\n" : ""),
+ utf8_printf(out, "%s %-*s", ((++nc%ncw==0)? "\n" : ""),
len, sqlite3_column_text(pStmt,0));
}
- if( nc>0 ) utf8_printf(p->out, "\n");
+ if( nc>0 ) utf8_printf(out, "\n");
}
sqlite3_finalize(pStmt);
}else{
" clear ?NAMES? Erase all or only given named parameters",
#ifndef SQLITE_NOHAVE_SYSTEM
" edit ?OPT? NAME ... Use edit() to create or alter parameter NAME",
- " OPT may be -t or -e to use edited value as text or evaluate it first.",
+ " OPT may be -t to use edited value as text or -e to evaluate it.",
#endif
" init Initialize TEMP table for bindings and scripts",
" list ?PATTERNS? List parameters table binding and script values",
" If FILE missing, empty or '~', it defaults to ~/sqlite_params.sdb",
" set ?TOPT? NAME VALUE Give SQL parameter NAME a value of VALUE",
" NAME must begin with one of $,:,@,? for bindings, or with a letter",
- " to be executable; the value is following argument list, space-joined.",
+ " to be executable; value is the space-joined argument list.",
" Option TOPT may be one of {-b -i -n -r -t} to cast effective value",
" to BLOB, INT, NUMERIC, REAL or TEXT respectively.",
" unset ?NAMES? Remove named parameter(s) from parameters table",
DISPATCHABLE_COMMAND( parameter 2 2 0 ){
int rc = 0;
open_db(p,0);
+ sqlite3 *db = DBX(p);
/* .parameter clear and .parameter unset ?NAMES?
** Delete some or all parameters from the TEMP table that holds them.
** Without any arguments, clear deletes them all and unset does nothing.
*/
if( strcmp(azArg[1],"clear")==0 || strcmp(azArg[1],"unset")==0 ){
- if( param_table_exists(p->db) && (nArg>2 || azArg[1][0]=='c') ){
- sqlite3_str *sbZap = sqlite3_str_new(p->db);
+ if( param_table_exists(db) && (nArg>2 || azArg[1][0]=='c') ){
+ sqlite3_str *sbZap = sqlite3_str_new(db);
char *zSql;
sqlite3_str_appendf
(sbZap, "DELETE FROM "PARAM_TABLE_SNAME" WHERE key ");
(const char **)&azArg[2], (const char **)&azArg[nArg]);
zSql = sqlite3_str_finish(sbZap);
shell_check_oom(zSql);
- sqlite3_exec(p->db, zSql, 0, 0, 0);
+ sqlite3_exec(db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
}else
** New ones get a uses tag auto-selected by their leading char.
*/
if( strcmp(azArg[1],"edit")==0 ){
+ ShellInState *psi = ISS(p);
int ia = 2;
int eval = 0;
- if( !INSOURCE_IS_INTERACTIVE(p->pInSource) ){
+ if( !INSOURCE_IS_INTERACTIVE(psi->pInSource) ){
utf8_printf(STD_ERR, "Error: "
".parameter edit can only be used interactively.\n");
return 1;
}
- param_table_init(p);
- if( p->zEditor==0 ){
+ param_table_init(db);
+ if( psi->zEditor==0 ){
const char *zE = getenv("VISUAL");
- if( zE!=0 ) p->zEditor = sqlite3_mprintf("%s", zE);
+ if( zE!=0 ) psi->zEditor = sqlite3_mprintf("%s", zE);
}
if( nArg>=3 && azArg[2][0]=='-' ){
char *zArg = (azArg[2][1]=='-')? azArg[2]+2 : azArg[2]+1;
if( strncmp(zArg,"editor=",7)==0 ){
- sqlite3_free(p->zEditor);
+ sqlite3_free(psi->zEditor);
/* Accept an initial -editor=? option. */
- p->zEditor = sqlite3_mprintf("%s", zArg+7);
+ psi->zEditor = sqlite3_mprintf("%s", zArg+7);
++ia;
}
}
- if( p->zEditor==0 ){
+ if( psi->zEditor==0 ){
utf8_printf(STD_ERR,
"Either set env-var VISUAL to name an"
" editor and restart, or rerun\n "
" parameter name.\n", azArg[ia]);
return 1;
}
- rc = edit_one_param(p->db, azArg[ia], eval, ptu, p->zEditor);
+ rc = edit_one_param(db, azArg[ia], eval, ptu, psi->zEditor);
++ia;
if( rc!=0 ) return rc;
}
** Create it if necessary.
*/
if( nArg==2 && strcmp(azArg[1],"init")==0 ){
- param_table_init(p);
+ param_table_init(db);
}else
/* .parameter list|ls
** Load all or named parameters from specified or default (DB) file.
*/
if( strcmp(azArg[1],"load")==0 ){
- param_table_init(p);
- rc = parameters_load(p->db, (const char **)azArg+1, nArg-1);
+ param_table_init(db);
+ rc = parameters_load(db, (const char **)azArg+1, nArg-1);
}else
/* .parameter save
** Save all or named parameters into specified or default (DB) file.
*/
if( strcmp(azArg[1],"save")==0 ){
- rc = parameters_save(p->db, (const char **)azArg+1, nArg-1);
+ rc = parameters_save(db, (const char **)azArg+1, nArg-1);
}else
/* .parameter set NAME VALUE
"Error: %s is not a usable parameter name.\n", azArg[inv]);
rc = 1;
}else{
- param_table_init(p);
- rc = param_set(p->db, cCast, azArg[inv],
+ param_table_init(db);
+ rc = param_set(db, cCast, azArg[inv],
&azArg[inv+1], &azArg[nArg], ptu);
if( rc!=SQLITE_OK ){
- utf8_printf(p->out, "Error: %s\n", sqlite3_errmsg(p->db));
+ utf8_printf(STD_ERR, "Error: %s\n", sqlite3_errmsg(db));
rc = 1;
}
}
}else
{ /* If no command name and arg count matches, show a syntax error */
- showHelp(p->out, "parameter");
+ showHelp(ISS(p)->out, "parameter");
return 1;
}
DISPATCHABLE_COMMAND( print 3 1 0 ){
int i;
for(i=1; i<nArg; i++){
- if( i>1 ) raw_printf(p->out, " ");
- utf8_printf(p->out, "%s", azArg[i]);
+ utf8_printf(ISS(p)->out, "%s%s", azArg[i], (i==nArg-1)? "\n" : " ");
}
- raw_printf(p->out, "\n");
return 0;
}
DISPATCHABLE_COMMAND( progress 3 2 0 ){
+ ShellInState *psi = ISS(p);
int i;
int nn = 0;
- p->flgProgress = 0;
- p->mxProgress = 0;
- p->nProgress = 0;
+ psi->flgProgress = 0;
+ psi->mxProgress = 0;
+ psi->nProgress = 0;
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( z[0]=='-' ){
z++;
if( z[0]=='-' ) z++;
if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){
- p->flgProgress |= SHELL_PROGRESS_QUIET;
+ psi->flgProgress |= SHELL_PROGRESS_QUIET;
continue;
}
if( strcmp(z,"reset")==0 ){
- p->flgProgress |= SHELL_PROGRESS_RESET;
+ psi->flgProgress |= SHELL_PROGRESS_RESET;
continue;
}
if( strcmp(z,"once")==0 ){
- p->flgProgress |= SHELL_PROGRESS_ONCE;
+ psi->flgProgress |= SHELL_PROGRESS_ONCE;
continue;
}
if( strcmp(z,"limit")==0 ){
*pzErr = shellMPrintf(0,"Error: missing argument on --limit\n");
return SHELL_INVALID_ARGS;
}else{
- p->mxProgress = (int)integerValue(azArg[++i]);
+ psi->mxProgress = (int)integerValue(azArg[++i]);
}
continue;
}
- *pzErr = shellMPrintf(0,"Error: unknown option: \"%s\"\n", azArg[i]);
+ *pzErr = shellMPrintf(0, "Error: unknown option: \"%s\"\n", azArg[i]);
return SHELL_INVALID_ARGS;
}else{
nn = (int)integerValue(z);
}
}
open_db(p, 0);
- sqlite3_progress_handler(p->db, nn, progress_handler, p);
+ sqlite3_progress_handler(DBX(p), nn, progress_handler, psi);
return 0;
}
/* Allow too few arguments by tradition, (a form of no-op.) */
int rc = 0;
FILE *inUse = 0;
int (*fCloser)(FILE *) = 0;
- if( p->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
if( azArg[1][0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
*pzErr = shellMPrintf(0,"Error: pipes are not supported in this OS\n");
rc = 1;
- p->out = STD_OUT; /* This is likely not needed. To be investigated. */
+ /* p->out = STD_OUT; This was likely not needed. To be investigated. */
#else
inUse = popen(azArg[1]+1, "r");
if( inUse==0 ){
}
if( inUse!=0 ){
InSource inSourceRedir
- = INSOURCE_FILE_REDIR(inUse, azArg[1], p->pInSource);
- p->pInSource = &inSourceRedir;
- rc = process_input(p);
+ = INSOURCE_FILE_REDIR(inUse, azArg[1], ISS(p)->pInSource);
+ ISS(p)->pInSource = &inSourceRedir;
+ rc = process_input(ISS(p));
assert(fCloser!=0);
fCloser(inUse);
- p->pInSource = p->pInSource->pFrom;
+ ISS(p)->pInSource = inSourceRedir.pFrom;
}
return rc;
}
** on stream pState->out.
*/
DISPATCHABLE_COMMAND( recover ? 1 7 ){
- open_db(p, 0);
+ FILE *out = ISS(p)->out;
+ sqlite3 *db;
int rc = SQLITE_OK;
sqlite3_stmt *pLoop = 0; /* Loop through all root pages */
sqlite3_stmt *pPages = 0; /* Loop through all pages in a group */
int nOrphan = -1;
RecoverTable *pOrphan = 0;
+ open_db(p, 0);
+ db = DBX(p);
+
int bFreelist = 1; /* 0 if --freelist-corrupt is specified */
int bRowids = 1; /* 0 if --no-rowids */
for(i=1; i<nArg; i++){
}
else{
*pzErr = shellMPrintf(0,"unexpected option: %s\n", azArg[i]);
- showHelp(p->out, azArg[0]);
+ showHelp(out, azArg[0]);
return 1;
}
}
- shellExecPrintf(p->db, &rc,
+ shellExecPrintf(db, &rc,
/* Attach an in-memory database named 'recovery'. Create an indexed
** cache of the sqlite_dbptr virtual table. */
"PRAGMA writable_schema = on;"
);
if( bFreelist ){
- shellExec(p->db, &rc,
+ shellExec(db, &rc,
"WITH trunk(pgno) AS ("
" SELECT shell_int32("
" (SELECT data FROM sqlite_dbpage WHERE pgno=1), 8) AS x "
/* If this is an auto-vacuum database, add all pointer-map pages to
** the freelist table. Do this regardless of whether or not
** --freelist-corrupt was specified. */
- shellExec(p->db, &rc,
+ shellExec(db, &rc,
"WITH ptrmap(pgno) AS ("
" SELECT 2 WHERE shell_int32("
" (SELECT data FROM sqlite_dbpage WHERE pgno=1), 13"
"REPLACE INTO recovery.freelist SELECT pgno FROM ptrmap"
);
- shellExec(p->db, &rc,
+ shellExec(db, &rc,
"CREATE TABLE recovery.dbptr("
" pgno, child, PRIMARY KEY(child, pgno)"
") WITHOUT ROWID;"
** foreign key constraints to be violated. So disable foreign-key
** constraint enforcement to prevent problems when running the output
** script. */
- raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
- raw_printf(p->out, "BEGIN;\n");
- raw_printf(p->out, "PRAGMA writable_schema = on;\n");
- shellPrepare(p->db, &rc,
+ raw_printf(out, "PRAGMA foreign_keys=OFF;\n");
+ raw_printf(out, "BEGIN;\n");
+ raw_printf(out, "PRAGMA writable_schema = on;\n");
+ shellPrepare(db, &rc,
"SELECT sql FROM recovery.schema "
"WHERE type='table' AND sql LIKE 'create table%'", &pStmt
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
const char *zCreateTable = (const char*)sqlite3_column_text(pStmt, 0);
- raw_printf(p->out, "CREATE TABLE IF NOT EXISTS %s;\n",
- &zCreateTable[12]
- );
+ raw_printf(out, "CREATE TABLE IF NOT EXISTS %s;\n", &zCreateTable[12]);
}
shellFinalize(&rc, pStmt);
}
/* Figure out if an orphan table will be required. And if so, how many
** user columns it should contain */
- shellPrepare(p->db, &rc,
+ shellPrepare(db, &rc,
"SELECT coalesce(max(maxlen), -2) FROM recovery.map WHERE root>1"
, &pLoop
);
shellFinalize(&rc, pLoop);
pLoop = 0;
- shellPrepare(p->db, &rc,
+ shellPrepare(db, &rc,
"SELECT pgno FROM recovery.map WHERE root=?", &pPages
);
- shellPrepare(p->db, &rc,
+ shellPrepare(db, &rc,
"SELECT max(field), group_concat(shell_escape_crnl(quote"
"(case when (? AND field<0) then NULL else value end)"
"), ', ')"
);
/* Loop through each root page. */
- shellPrepare(p->db, &rc,
+ shellPrepare(db, &rc,
"SELECT root, intkey, max(maxlen) FROM recovery.map"
" WHERE root>1 GROUP BY root, intkey ORDER BY root=("
" SELECT rootpage FROM recovery.schema WHERE name='sqlite_sequence'"
RecoverTable *pTab;
assert( bIntkey==0 || bIntkey==1 );
- pTab = recoverFindTable(p, &rc, iRoot, bIntkey, nCol, &bNoop);
+ pTab = recoverFindTable(db, &rc, iRoot, bIntkey, nCol, &bNoop);
if( bNoop || rc ) continue;
if( pTab==0 ){
if( pOrphan==0 ){
- pOrphan = recoverOrphanTable(p, &rc, zLostAndFound, nOrphan);
+ pOrphan = recoverOrphanTable(db, out, &rc, zLostAndFound, nOrphan);
}
pTab = pOrphan;
if( pTab==0 ) break;
}
if( 0==sqlite3_stricmp(pTab->zQuoted, "\"sqlite_sequence\"") ){
- raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
+ raw_printf(out, "DELETE FROM sqlite_sequence;\n");
}
sqlite3_bind_int(pPages, 1, iRoot);
if( bRowids==0 && pTab->iPk<0 ){
RecoverTable *pTab2 = pTab;
if( pTab!=pOrphan && (iMin<0)!=bIntkey ){
if( pOrphan==0 ){
- pOrphan = recoverOrphanTable(p, &rc, zLostAndFound, nOrphan);
+ pOrphan = recoverOrphanTable(db, out, &rc, zLostAndFound, nOrphan);
}
pTab2 = pOrphan;
if( pTab2==0 ) break;
nField = nField+1;
if( pTab2==pOrphan ){
- raw_printf(p->out,
+ raw_printf(out,
"INSERT INTO %s VALUES(%d, %d, %d, %s%s%s);\n",
pTab2->zQuoted, iRoot, iPgno, nField,
iMin<0 ? "" : "NULL, ", zVal, pTab2->azlCol[nField]
);
}else{
- raw_printf(p->out, "INSERT INTO %s(%s) VALUES( %s );\n",
+ raw_printf(out, "INSERT INTO %s(%s) VALUES( %s );\n",
pTab2->zQuoted, pTab2->azlCol[nField], zVal
);
}
/* The rest of the schema */
if( rc==SQLITE_OK ){
sqlite3_stmt *pStmt = 0;
- shellPrepare(p->db, &rc,
+ shellPrepare(db, &rc,
"SELECT sql, name FROM recovery.schema "
"WHERE sql NOT LIKE 'create table%'", &pStmt
);
"INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)",
zName, zName, zSql
);
- raw_printf(p->out, "%s;\n", zPrint);
+ raw_printf(out, "%s;\n", zPrint);
sqlite3_free(zPrint);
}else{
- raw_printf(p->out, "%s;\n", zSql);
+ raw_printf(out, "%s;\n", zSql);
}
}
shellFinalize(&rc, pStmt);
}
if( rc==SQLITE_OK ){
- raw_printf(p->out, "PRAGMA writable_schema = off;\n");
- raw_printf(p->out, "COMMIT;\n");
+ raw_printf(out, "PRAGMA writable_schema = off;\n");
+ raw_printf(out, "COMMIT;\n");
}
- sqlite3_exec(p->db, "DETACH recovery", 0, 0, 0);
+ sqlite3_exec(db, "DETACH recovery", 0, 0, 0);
return rc;
}
sqlite3_backup *pBackup;
int nTimeout = 0;
- if( p->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
if( nArg==2 ){
zSrcFile = azArg[1];
zDb = "main";
return 1;
}
open_db(p, 0);
- pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
+ pBackup = sqlite3_backup_init(DBX(p), zDb, pSrc, "main");
if( pBackup==0 ){
- *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(p->db));
+ *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(DBX(p)));
close_db(pSrc);
return 1;
}
*pzErr = shellMPrintf(0,"Error: source database is busy\n");
rc = 1;
}else{
- *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(p->db));
+ *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(DBX(p)));
rc = 1;
}
close_db(pSrc);
" --nosys Omit objects whose names start with \"sqlite_\"",
];
DISPATCHABLE_COMMAND( scanstats ? 2 2 ){
- p->scanstatsOn = (u8)booleanValue(azArg[1]);
+ ISS(p)->scanstatsOn = (u8)booleanValue(azArg[1]);
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
- raw_printf(STD_ERR, "Warning: .scanstats not available in this build.\n");
+ raw_printf(STD_ERR, "Warning: .scanstats not available in this build.\n");
#endif
return 0;
}
DISPATCHABLE_COMMAND( schema ? 1 2 ){
int rc;
ShellText sSelect;
- ShellState data;
+ ShellInState data;
+ ShellExState datax;
char *zErrMsg = 0;
const char *zDiv = "(";
const char *zName = 0;
int ii;
open_db(p, 0);
- memcpy(&data, p, sizeof(data));
+ /* Consider some refactoring to avoid duplicative wholesale copying. */
+ memcpy(&data, ISS(p), sizeof(data));
+ memcpy(&datax, p, sizeof(datax));
+ data.pSXS = &datax;
+ datax.pSIS = &data;
+
data.showHeader = 0;
data.cMode = data.mode = MODE_Semi;
initText(&sSelect);
new_argv[1] = 0;
new_colv[0] = "sql";
new_colv[1] = 0;
- callback(&data, 1, new_argv, new_colv);
+ callback(&datax, 1, new_argv, new_colv);
sqlite3_free(new_argv[0]);
}
}
if( zDiv ){
sqlite3_stmt *pStmt = 0;
- rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
+ rc = sqlite3_prepare_v2(datax.dbUser,
+ "SELECT name FROM pragma_database_list",
-1, &pStmt, 0);
if( rc ){
- *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(p->db));
+ *pzErr = shellMPrintf(0,"Error: %s\n", sqlite3_errmsg(datax.dbUser));
sqlite3_finalize(pStmt);
return 1;
}
appendText(&sSelect, "sql IS NOT NULL"
" ORDER BY snum, rowid", 0);
if( bDebug ){
- utf8_printf(p->out, "SQL: %s;\n", sSelect.z);
+ utf8_printf(data.out, "SQL: %s;\n", sSelect.z);
}else{
- rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
+ rc = sqlite3_exec(datax.dbUser, sSelect.z, callback, &datax, &zErrMsg);
}
freeText(&sSelect);
}
if( zErrMsg ){
*pzErr = zErrMsg;
- rc = 1;
+ return 1;
}else if( rc != SQLITE_OK ){
*pzErr = shellMPrintf(0,"Error: querying schema information\n");
- rc = 1;
+ return 1;
}else{
- rc = 0;
+ return 0;
}
- return rc;
}
/*****************
}
DISPATCHABLE_COMMAND( separator ? 2 3 ){
if( nArg>=2 ){
- sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
- "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
+ sqlite3_snprintf(sizeof(ISS(p)->colSeparator), ISS(p)->colSeparator,
+ "%.*s", (int)ArraySize(ISS(p)->colSeparator)-1, azArg[1]);
}
if( nArg>=3 ){
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
- "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
+ sqlite3_snprintf(sizeof(ISS(p)->rowSeparator), ISS(p)->rowSeparator,
+ "%.*s", (int)ArraySize(ISS(p)->rowSeparator)-1, azArg[2]);
}
return 0;
}
DISPATCHABLE_COMMAND( session 3 2 0 ){
int rc = 0;
- struct AuxDb *pAuxDb = p->pAuxDb;
+ struct AuxDb *pAuxDb = ISS(p)->pAuxDb;
OpenSession *pSession = &pAuxDb->aSession[0];
+ FILE *out = ISS(p)->out;
char **azCmd = &azArg[1];
int iSes = 0;
int nCmd = nArg - 1;
** Write a changeset or patchset into a file. The file is overwritten.
*/
if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){
- FILE *out = 0;
+ FILE *cs_out = 0;
if( failIfSafeMode
(p, "cannot run \".session %s\" in safe mode", azCmd[0]) ){
rc = SHELL_FORBIDDEN_OP;
}else{
if( nCmd!=2 ) goto session_syntax_error;
if( pSession->p==0 ) goto session_not_open;
- out = fopen(azCmd[1], "wb");
- if( out==0 ){
+ cs_out = fopen(azCmd[1], "wb");
+ if( cs_out==0 ){
*pzErr = sqlite3_mprintf
("ERROR: cannot open \"%s\" for writing\n", azCmd[1]);
rc = 1;
rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
}
if( rc ){
- fprintf(STD_OUT, "Error: error code %d\n", rc);
+ fprintf(out, "Error: error code %d\n", rc);
rc = 0;
}
- if( pChng && fwrite(pChng, szChng, 1, out)!=1 ){
+ if( pChng && fwrite(pChng, szChng, 1, cs_out)!=1 ){
raw_printf(STD_ERR, "ERROR: Failed to write entire %d-byte output\n",
szChng);
}
sqlite3_free(pChng);
- fclose(out);
+ fclose(cs_out);
}
}
}else
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
if( pAuxDb->nSession ){
ii = sqlite3session_enable(pSession->p, ii);
- utf8_printf(p->out, "session %s enable flag = %d\n",
+ utf8_printf(out, "session %s enable flag = %d\n",
pSession->zName, ii);
}
}else
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
if( pAuxDb->nSession ){
ii = sqlite3session_indirect(pSession->p, ii);
- utf8_printf(p->out, "session %s indirect flag = %d\n",
+ utf8_printf(out, "session %s indirect flag = %d\n",
pSession->zName, ii);
}
}else
if( nCmd!=1 ) goto session_syntax_error;
if( pAuxDb->nSession ){
ii = sqlite3session_isempty(pSession->p);
- utf8_printf(p->out, "session %s isempty flag = %d\n",
+ utf8_printf(out, "session %s isempty flag = %d\n",
pSession->zName, ii);
}
}else
*/
if( strcmp(azCmd[0],"list")==0 ){
for(i=0; i<pAuxDb->nSession; i++){
- utf8_printf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName);
+ utf8_printf(out, "%d %s\n", i, pAuxDb->aSession[i].zName);
}
}else
return rc;
}
pSession = &pAuxDb->aSession[pAuxDb->nSession];
- rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
+ rc = sqlite3session_create(DBX(p), azCmd[1], &pSession->p);
if( rc ){
*pzErr = sqlite3_mprintf
("Cannot open session: error code=%d\n", rc);
/* If no command name matches, show a syntax error */
session_syntax_error:
- showHelp(p->out, "session");
+ showHelp(out, "session");
return 1;
}
return rc;
" AND name NOT LIKE 'sqlite_%'"
" ORDER BY 1 collate nocase";
}
- sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_prepare_v2(DBX(p), zSql, -1, &pStmt, 0);
initText(&sQuery);
initText(&sSql);
appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
freeText(&sQuery);
freeText(&sSql);
if( bDebug ){
- utf8_printf(p->out, "%s\n", zSql);
+ utf8_printf(ISS(p)->out, "%s\n", zSql);
}else{
shell_exec(p, zSql, 0);
}
];
DISPATCHABLE_COMMAND( selftest 4 0 0 ){
int rc;
+ ShellInState *psi = ISS(p);
int bIsInit = 0; /* True to initialize the SELFTEST table */
int bVerbose = 0; /* Verbose output */
int bSelftestExists; /* True if SELFTEST already exists */
ShellText str; /* Answer for a query */
sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
- open_db(p,0);
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( z[0]=='-' && z[1]=='-' ) z++;
return 1;
}
}
- if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
+ open_db(p,0);
+ if( sqlite3_table_column_metadata(DBX(p),"main","selftest",0,0,0,0,0,0)
!= SQLITE_OK ){
bSelftestExists = 0;
}else{
bSelftestExists = 1;
}
if( bIsInit ){
- createSelftestTable(p);
+ createSelftestTable(ISS(p));
bSelftestExists = 1;
}
initText(&str);
appendText(&str, "x", 0);
for(k=bSelftestExists; k>=0; k--){
if( k==1 ){
- rc = sqlite3_prepare_v2(p->db,
+ rc = sqlite3_prepare_v2(DBX(p),
"SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
-1, &pStmt, 0);
}else{
- rc = sqlite3_prepare_v2(p->db,
- "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
- " (1,'run','PRAGMA integrity_check','ok')",
- -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(DBX(p),
+ "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
+ " (1,'run','PRAGMA integrity_check','ok')",
+ -1, &pStmt, 0);
}
if( rc ){
*pzErr = shellMPrintf(0,"Error querying the selftest table\n");
if( zOp==0 || zSql==0 || zAns==0 ) continue;
k = 0;
if( bVerbose>0 ){
+ /* This unusually directed output is for test purposes. */
fprintf(STD_OUT, "%d: %s %s\n", tno, zOp, zSql);
}
if( strcmp(zOp,"memo")==0 ){
- utf8_printf(p->out, "%s\n", zSql);
+ utf8_printf(psi->out, "%s\n", zSql);
}else if( strcmp(zOp,"run")==0 ){
char *zErrMsg = 0;
str.n = 0;
str.z[0] = 0;
- rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
+ rc = sqlite3_exec(DBX(p), zSql, captureOutputCallback, &str, &zErrMsg);
nTest++;
if( bVerbose ){
- utf8_printf(p->out, "Result: %s\n", str.z);
+ utf8_printf(psi->out, "Result: %s\n", str.z);
}
if( rc || zErrMsg ){
nErr++;
rc = 1;
- utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
+ utf8_printf(psi->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
sqlite3_free(zErrMsg);
}else if( strcmp(zAns,str.z)!=0 ){
nErr++;
rc = 1;
- utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
- utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
+ utf8_printf(psi->out, "%d: Expected: [%s]\n", tno, zAns);
+ utf8_printf(psi->out, "%d: Got: [%s]\n", tno, str.z);
}
}else{
*pzErr = sqlite3_mprintf
sqlite3_finalize(pStmt);
} /* End loop over k */
freeText(&str);
- utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
+ utf8_printf(psi->out, "%d errors out of %d tests\n", nErr, nTest);
return rc > 0;
}
-#ifndef SQLITE_NOHAVE_SYSTEM
-static int shellOut(char *azArg[], int nArg, ShellState *p, char **pzErr){
+DISPATCHABLE_COMMAND( shell ? 2 0 ){
char *zCmd;
int i, x;
- if( p->bSafeMode ) return SHELL_FORBIDDEN_OP;
+ if( ISS(p)->bSafeMode ) return SHELL_FORBIDDEN_OP;
zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
shell_check_oom(zCmd);
for(i=2; i<nArg; i++){
if( x ) raw_printf(STD_ERR, "%s command returns %d\n", azArg[0], x);
return 0;
}
-#endif
-DISPATCHABLE_COMMAND( shell ? 2 0 ){
- return shellOut(azArg, nArg, p, pzErr);
-}
DISPATCHABLE_COMMAND( shxopts 3 0 0 ){
static struct { const char *name; u8 mask; } shopts[] = {
#if SHELL_DYNAMIC_COMMANDS
{"all_opts", SHELL_ALL_EXTENSIONS}
};
const char *zMoan = 0, *zAbout = 0;
+ ShellInState *psi = ISS(p);
int ia, io;
if( nArg>1 ){
for( ia=1; ia<nArg; ++ia ){
}
for( io=0; io<ArraySize(shopts); ++io ){
if( strcmp(azArg[ia]+1, shopts[io].name)==0 ){
- if( cs=='+' ) p->bExtendedDotCmds |= shopts[io].mask;
- else p->bExtendedDotCmds &= ~shopts[io].mask;
+ if( cs=='+' ) psi->bExtendedDotCmds |= shopts[io].mask;
+ else psi->bExtendedDotCmds &= ~shopts[io].mask;
break;
}
}
}
}
}else{
- raw_printf(p->out,
+ raw_printf(psi->out,
" name value \"-shxopts set\"\n"
" -------- ----- ---------------\n");
for( io=0; io<ArraySize(shopts); ++io ){
unsigned m = shopts[io].mask;
- unsigned v = ((p->bExtendedDotCmds & m) == m)? 1 : 0;
- raw_printf(p->out,
+ unsigned v = ((psi->bExtendedDotCmds & m) == m)? 1 : 0;
+ raw_printf(psi->out,
" %9s %2d \"-shxopts 0x%02X\"\n",
shopts[io].name, v, m);
}
return 1;
}
DISPATCHABLE_COMMAND( system ? 2 0 ){
- return shellOut(azArg, nArg, p, pzErr);
+ return shellCommand(azArg, nArg, p, pzErr);
}
DISPATCHABLE_COMMAND( show ? 1 1 ){
static const char *azBool[] = { "off", "on", "trigger", "full"};
const char *zOut;
+ ShellInState *psi = ISS(p);
+ FILE *out = psi->out;
int i;
- utf8_printf(p->out, "%12.12s: %s\n","echo",
+ utf8_printf(out, "%12.12s: %s\n","echo",
azBool[ShellHasFlag(p, SHFLG_Echo)]);
- utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
- utf8_printf(p->out, "%12.12s: %s\n","explain",
- p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
- utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
- zOut = modeDescr[p->mode].zModeName;
- i = strlen30(zOut) - modeDescr[p->mode].bDepluralize;
- if( MODE_IS_COLUMNAR(p->mode) ){
+ utf8_printf(out, "%12.12s: %s\n","eqp", azBool[psi->autoEQP&3]);
+ utf8_printf(out, "%12.12s: %s\n","explain",
+ psi->mode==MODE_Explain
+ ? "on" : psi->autoExplain ? "auto" : "off");
+ utf8_printf(out,"%12.12s: %s\n","headers", azBool[psi->showHeader!=0]);
+ zOut = modeDescr[psi->mode].zModeName;
+ i = strlen30(zOut) - modeDescr[psi->mode].bDepluralize;
+ if( MODE_IS_COLUMNAR(psi->mode) ){
utf8_printf
- (p->out, "%12.12s: %.*s --wrap %d --wordwrap %s --%squote\n", "mode",
- i, zOut, p->cmOpts.iWrap,
- p->cmOpts.bWordWrap ? "on" : "off",
- p->cmOpts.bQuote ? "" : "no");
+ (out, "%12.12s: %.*s --wrap %d --wordwrap %s --%squote\n", "mode",
+ i, zOut, psi->cmOpts.iWrap,
+ psi->cmOpts.bWordWrap ? "on" : "off",
+ psi->cmOpts.bQuote ? "" : "no");
}else{
- utf8_printf(p->out, "%12.12s: %.*s\n","mode", i, zOut);
- }
- utf8_printf(p->out, "%12.12s: ", "nullvalue");
- output_c_string(p->out, p->nullValue);
- raw_printf(p->out, "\n");
- utf8_printf(p->out,"%12.12s: %s\n","output",
- strlen30(p->outfile) ? p->outfile : "stdout");
- utf8_printf(p->out,"%12.12s: ", "colseparator");
- output_c_string(p->out, p->colSeparator);
- raw_printf(p->out, "\n");
- utf8_printf(p->out,"%12.12s: ", "rowseparator");
- output_c_string(p->out, p->rowSeparator);
- raw_printf(p->out, "\n");
- switch( p->statsOn ){
+ utf8_printf(out, "%12.12s: %.*s\n","mode", i, zOut);
+ }
+ utf8_printf(out, "%12.12s: ", "nullvalue");
+ output_c_string(out, psi->nullValue);
+ raw_printf(out, "\n");
+ utf8_printf(out,"%12.12s: %s\n","output",
+ strlen30(psi->outfile) ? psi->outfile : "stdout");
+ utf8_printf(out,"%12.12s: ", "colseparator");
+ output_c_string(out, psi->colSeparator);
+ raw_printf(out, "\n");
+ utf8_printf(out,"%12.12s: ", "rowseparator");
+ output_c_string(out, psi->rowSeparator);
+ raw_printf(out, "\n");
+ switch( psi->statsOn ){
case 0: zOut = "off"; break;
default: zOut = "on"; break;
case 2: zOut = "stmt"; break;
case 3: zOut = "vmstep"; break;
}
- utf8_printf(p->out, "%12.12s: %s\n","stats", zOut);
- utf8_printf(p->out, "%12.12s: ", "width");
- for (i=0;i<p->nWidth;i++) {
- raw_printf(p->out, "%d ", p->colWidth[i]);
+ utf8_printf(out, "%12.12s: %s\n","stats", zOut);
+ utf8_printf(out, "%12.12s: ", "width");
+ for (i=0;i<p->numWidths;i++) {
+ raw_printf(out, "%d ", p->pSpecWidths[i]);
}
- raw_printf(p->out, "\n");
- utf8_printf(p->out, "%12.12s: %s\n", "filename",
- p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : "");
+ raw_printf(out, "\n");
+ utf8_printf(out, "%12.12s: %s\n", "filename",
+ psi->pAuxDb->zDbFilename ? psi->pAuxDb->zDbFilename : "");
return 0;
}
DISPATCHABLE_COMMAND( stats ? 0 0 ){
+ ShellInState *psi = ISS(p);
if( nArg==2 ){
if( strcmp(azArg[1],"stmt")==0 ){
- p->statsOn = 2;
+ psi->statsOn = 2;
}else if( strcmp(azArg[1],"vmstep")==0 ){
- p->statsOn = 3;
+ psi->statsOn = 3;
}else{
- p->statsOn = (u8)booleanValue(azArg[1]);
+ psi->statsOn = (u8)booleanValue(azArg[1]);
}
}else if( nArg==1 ){
- display_stats(p->db, p, 0);
+ display_stats(DBX(p), psi, 0);
}else{
*pzErr = shellMPrintf(0,"Usage: .stats ?on|off|stmt|vmstep?\n");
return 1;
" If TABLE is specified, only show indexes for",
" tables matching TABLE using the LIKE operator.",
];
-static int showTableLike(char *azArg[], int nArg, ShellState *p,
+static int showTableLike(char *azArg[], int nArg, ShellExState *p,
char **pzErr, char ot){
int rc;
sqlite3_stmt *pStmt;
ShellText s;
initText(&s);
open_db(p, 0);
- rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(DBX(p), "PRAGMA database_list", -1, &pStmt, 0);
if( rc ){
sqlite3_finalize(pStmt);
- return shellDatabaseError(p->db);
+ return shellDatabaseError(DBX(p));
}
if( nArg>2 && ot=='i' ){
rc = sqlite3_finalize(pStmt);
if( rc==SQLITE_OK ){
appendText(&s, " ORDER BY 1", 0);
- rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(DBX(p), s.z, -1, &pStmt, 0);
}
freeText(&s);
- if( rc ) return shellDatabaseError(p->db);
+ if( rc ) return shellDatabaseError(DBX(p));
/* Run the SQL statement prepared by the above block. Store the results
** as an array of nul-terminated strings in azResult[]. */
nRow++;
}
if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
- rc = shellDatabaseError(p->db);
+ rc = shellDatabaseError(DBX(p));
}
/* Pretty-print the contents of array azResult[] to the output */
for(i=0; i<nPrintRow; i++){
for(j=i; j<nRow; j+=nPrintRow){
char *zSp = j<nPrintRow ? "" : " ";
- utf8_printf(p->out, "%s%-*s", zSp, maxlen,
+ utf8_printf(ISS(p)->out, "%s%-*s", zSp, maxlen,
azResult[j] ? azResult[j]:"");
}
- raw_printf(p->out, "\n");
+ raw_printf(ISS(p)->out, "\n");
}
}
return showTableLike(azArg, nArg, p, pzErr, 'i');
}
-/*****************
- * The .unmodule command
- */
-CONDITION_COMMAND( unmodule defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE) );
-COLLECT_HELP_TEXT[
- ".unmodule NAME ... Unregister virtual table modules",
- " --allexcept Unregister everything except those named",
-];
-DISPATCHABLE_COMMAND( unmodule ? 2 0 ){
- int ii;
- int lenOpt;
- char *zOpt;
- open_db(p, 0);
- zOpt = azArg[1];
- if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++;
- lenOpt = (int)strlen(zOpt);
- if( lenOpt>=3 && strncmp(zOpt, "-allexcept",lenOpt)==0 ){
- assert( azArg[nArg]==0 );
- sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0);
- }else{
- for(ii=1; ii<nArg; ii++){
- sqlite3_create_module(p->db, azArg[ii], 0, 0);
- }
- }
- return 0;
-}
-
/*****************
* The .testcase, .testctrl, .timeout, .timer and .trace commands
*/
/* Begin redirecting output to the file "testcase-out.txt" */
DISPATCHABLE_COMMAND( testcase ? 0 0 ){
- output_reset(p);
- p->out = output_file_open("testcase-out.txt", 0);
- if( p->out==0 ){
+ ShellInState *psi = ISS(p);
+ output_reset(psi);
+ psi->out = output_file_open("testcase-out.txt", 0);
+ if( psi->out==0 ){
raw_printf(STD_ERR, "Error: cannot open 'testcase-out.txt'\n");
}
if( nArg>=2 ){
- sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
+ sqlite3_snprintf(sizeof(psi->zTestcase), psi->zTestcase, "%s", azArg[1]);
}else{
- sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
+ sqlite3_snprintf(sizeof(psi->zTestcase), psi->zTestcase, "?");
}
+ return 0;
}
DISPATCHABLE_COMMAND( testctrl ? 0 0 ){
+ FILE *out = ISS(p)->out;
static const struct {
const char *zCtrlName; /* Name of a test-control option */
int ctrlCode; /* Integer code for that option */
/* --help lists all test-controls */
if( strcmp(zCmd,"help")==0 ){
- utf8_printf(p->out, "Available test-controls:\n");
+ utf8_printf(out, "Available test-controls:\n");
for(i=0; i<ArraySize(aCtrl); i++){
- utf8_printf(p->out, " .testctrl %s %s\n",
+ utf8_printf(out, " .testctrl %s %s\n",
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
}
return 1;
if( testctrl<0 ){
utf8_printf(STD_ERR,"Error: unknown test-control: %s\n"
"Use \".testctrl --help\" for help\n", zCmd);
- }else if( aCtrl[iCtrl].unSafe && p->bSafeMode ){
+ }else if( aCtrl[iCtrl].unSafe && ISS(p)->bSafeMode ){
utf8_printf(STD_ERR,
- "line %d: \".testctrl %s\" may not be used in safe mode\n",
- p->pInSource->lineno, aCtrl[iCtrl].zCtrlName);
+ "line %d: \".testctrl %s\" may not be used in safe mode\n",
+ ISS(p)->pInSource->lineno, aCtrl[iCtrl].zCtrlName);
exit(1);
}else{
switch(testctrl){
case SQLITE_TESTCTRL_OPTIMIZATIONS:
if( nArg==3 ){
unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0);
- rc2 = sqlite3_test_control(testctrl, p->db, opt);
+ rc2 = sqlite3_test_control(testctrl, DBX(p), opt);
isOk = 3;
}
break;
if( nArg==3 ){
db = 0;
}else{
- db = p->db;
+ db = DBX(p);
/* Make sure the schema has been loaded */
sqlite3_table_column_metadata(db, 0, "x", 0, 0, 0, 0, 0, 0);
}
/* sqlite3_test_control(sqlite3*) */
case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
- rc2 = sqlite3_test_control(testctrl, p->db);
+ rc2 = sqlite3_test_control(testctrl, DBX(p));
isOk = 3;
break;
case SQLITE_TESTCTRL_IMPOSTER:
if( nArg==5 ){
- rc2 = sqlite3_test_control(testctrl, p->db,
+ rc2 = sqlite3_test_control(testctrl, DBX(p),
azArg[2],
integerValue(azArg[3]),
integerValue(azArg[4]));
case SQLITE_TESTCTRL_SEEK_COUNT: {
u64 x = 0;
- rc2 = sqlite3_test_control(testctrl, p->db, &x);
- utf8_printf(p->out, "%llu\n", x);
+ rc2 = sqlite3_test_control(testctrl, DBX(p), &x);
+ utf8_printf(out, "%llu\n", x);
isOk = 3;
break;
}
#ifdef YYCOVERAGE
case SQLITE_TESTCTRL_PARSER_COVERAGE: {
if( nArg==2 ){
- sqlite3_test_control(testctrl, p->out);
+ sqlite3_test_control(testctrl, out);
isOk = 3;
}
break;
int val = 0;
rc2 = sqlite3_test_control(testctrl, -id, &val);
if( rc2!=SQLITE_OK ) break;
- if( id>1 ) utf8_printf(p->out, " ");
- utf8_printf(p->out, "%d: %d", id, val);
+ if( id>1 ) utf8_printf(out, " ");
+ utf8_printf(out, "%d: %d", id, val);
id++;
}
- if( id>1 ) utf8_printf(p->out, "\n");
+ if( id>1 ) utf8_printf(out, "\n");
isOk = 3;
}
break;
}
}
if( isOk==0 && iCtrl>=0 ){
- utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
+ utf8_printf(out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
return 1;
}else if( isOk==1 ){
- raw_printf(p->out, "%d\n", rc2);
+ raw_printf(out, "%d\n", rc2);
}else if( isOk==2 ){
- raw_printf(p->out, "0x%08x\n", rc2);
+ raw_printf(out, "0x%08x\n", rc2);
}
return 0;
}
DISPATCHABLE_COMMAND( timeout 4 1 2 ){
open_db(p, 0);
- sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
+ sqlite3_busy_timeout(DBX(p), nArg>=2 ? (int)integerValue(azArg[1]) : 0);
return 0;
}
DISPATCHABLE_COMMAND( timer ? 2 2 ){
return 0;
}
DISPATCHABLE_COMMAND( trace ? 0 0 ){
+ ShellInState *psi = ISS(p);
int mType = 0;
int jj;
open_db(p, 0);
const char *z = azArg[jj];
if( z[0]=='-' ){
if( optionMatch(z, "expanded") ){
- p->eTraceType = SHELL_TRACE_EXPANDED;
+ psi->eTraceType = SHELL_TRACE_EXPANDED;
}
#ifdef SQLITE_ENABLE_NORMALIZE
else if( optionMatch(z, "normalized") ){
- p->eTraceType = SHELL_TRACE_NORMALIZED;
+ psi->eTraceType = SHELL_TRACE_NORMALIZED;
}
#endif
else if( optionMatch(z, "plain") ){
- p->eTraceType = SHELL_TRACE_PLAIN;
+ psi->eTraceType = SHELL_TRACE_PLAIN;
}
else if( optionMatch(z, "profile") ){
mType |= SQLITE_TRACE_PROFILE;
return 1;
}
}else{
- output_file_close(p->traceOut);
- p->traceOut = output_file_open(azArg[1], 0);
+ output_file_close(psi->traceOut);
+ psi->traceOut = output_file_open(azArg[1], 0);
}
}
- if( p->traceOut==0 ){
- sqlite3_trace_v2(p->db, 0, 0, 0);
+ if( psi->traceOut==0 ){
+ sqlite3_trace_v2(DBX(p), 0, 0, 0);
}else{
if( mType==0 ) mType = SQLITE_TRACE_STMT;
- sqlite3_trace_v2(p->db, mType, sql_trace_callback, p);
+ sqlite3_trace_v2(DBX(p), mType, sql_trace_callback, psi);
+ }
+ return 0;
+}
+
+/*****************
+ * The .unmodule command
+ */
+CONDITION_COMMAND( unmodule defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE) );
+COLLECT_HELP_TEXT[
+ ".unmodule NAME ... Unregister virtual table modules",
+ " --allexcept Unregister everything except those named",
+];
+DISPATCHABLE_COMMAND( unmodule ? 2 0 ){
+ int ii;
+ int lenOpt;
+ char *zOpt;
+ open_db(p, 0);
+ zOpt = azArg[1];
+ if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++;
+ lenOpt = (int)strlen(zOpt);
+ if( lenOpt>=3 && strncmp(zOpt, "-allexcept",lenOpt)==0 ){
+ assert( azArg[nArg]==0 );
+ sqlite3_drop_modules(DBX(p), nArg>2 ? (const char**)(azArg+2) : 0);
+ }else{
+ for(ii=1; ii<nArg; ii++){
+ sqlite3_create_module(DBX(p), azArg[ii], 0, 0);
+ }
}
return 0;
}
if( nArg!=4 ){
goto teach_fail;
}
- rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
+ rc = sqlite3_user_authenticate(DBX(p), azArg[2], azArg[3],
strlen30(azArg[3]));
if( rc ){
*pzErr = shellMPrintf(0,"Authentication failed for user %s\n", azArg[2]);
if( nArg!=5 ){
goto teach_fail;
}
- rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
+ rc = sqlite3_user_add(DBX(p), azArg[2], azArg[3], strlen30(azArg[3]),
booleanValue(azArg[4]));
if( rc ){
*pzErr = shellMPrintf(0,"User-Add failed: %d\n", rc);
if( nArg!=5 ){
goto teach_fail;
}
- rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
+ rc = sqlite3_user_change(DBX(p), azArg[2], azArg[3], strlen30(azArg[3]),
booleanValue(azArg[4]));
if( rc ){
*pzErr = shellMPrintf(0,"User-Edit failed: %d\n", rc);
if( nArg!=3 ){
goto teach_fail;
}
- rc = sqlite3_user_delete(p->db, azArg[2]);
+ rc = sqlite3_user_delete(DBX(p), azArg[2]);
if( rc ){
*pzErr = shellMPrintf(0,"User-Delete failed: %d\n", rc);
return 1;
".vfsname ?AUX? Print the name of the VFS stack",
];
DISPATCHABLE_COMMAND( version ? 1 1 ){
- utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
+ FILE *out = ISS(p)->out;
+ utf8_printf(out, "SQLite %s %s\n" /*extra-version-info*/,
sqlite3_libversion(), sqlite3_sourceid());
#if SQLITE_HAVE_ZLIB
- utf8_printf(p->out, "zlib version %s\n", zlibVersion());
+ utf8_printf(out, "zlib version %s\n", zlibVersion());
#endif
#define CTIMEOPT_VAL_(opt) #opt
#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
#if defined(__clang__) && defined(__clang_major__)
- utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
+ utf8_printf(out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
CTIMEOPT_VAL(__clang_minor__) "."
CTIMEOPT_VAL(__clang_patchlevel__) "\n");
#elif defined(_MSC_VER)
- utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n");
+ utf8_printf(out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n");
#elif defined(__GNUC__) && defined(__VERSION__)
- utf8_printf(p->out, "gcc-" __VERSION__ "\n");
+ utf8_printf(out, "gcc-" __VERSION__ "\n");
#endif
return 0;
}
DISPATCHABLE_COMMAND( vfsinfo ? 1 2 ){
const char *zDbName = nArg==2 ? azArg[1] : "main";
sqlite3_vfs *pVfs = 0;
- if( p->db ){
- sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
+ if( DBX(p) ){
+ sqlite3_file_control(DBX(p), zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
if( pVfs ){
- utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
- raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
- raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
- raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
+ FILE *out = ISS(p)->out;
+ utf8_printf(out, "vfs.zName = \"%s\"\n", pVfs->zName);
+ raw_printf(out, "vfs.iVersion = %d\n", pVfs->iVersion);
+ raw_printf(out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
+ raw_printf(out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
}
}
return 0;
DISPATCHABLE_COMMAND( vfslist ? 1 1 ){
sqlite3_vfs *pVfs;
sqlite3_vfs *pCurrent = 0;
- if( p->db ){
- sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
+ FILE *out = ISS(p)->out;
+ if( DBX(p) ){
+ sqlite3_file_control(DBX(p), "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
}
for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
- utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
+ utf8_printf(out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
pVfs==pCurrent ? " <--- CURRENT" : "");
- raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
- raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
- raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
+ raw_printf(out, "vfs.iVersion = %d\n", pVfs->iVersion);
+ raw_printf(out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
+ raw_printf(out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
if( pVfs->pNext ){
- raw_printf(p->out, "-----------------------------------\n");
+ raw_printf(out, "-----------------------------------\n");
}
}
return 0;
DISPATCHABLE_COMMAND( vfsname ? 0 0 ){
const char *zDbName = nArg==2 ? azArg[1] : "main";
char *zVfsName = 0;
- if( p->db ){
- sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
+ if( DBX(p) ){
+ sqlite3_file_control(DBX(p), zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
if( zVfsName ){
- utf8_printf(p->out, "%s\n", zVfsName);
+ utf8_printf(ISS(p)->out, "%s\n", zVfsName);
sqlite3_free(zVfsName);
}
}
* The .width and .wheretrace commands
* The .wheretrace command has no help.
*/
+static void setColumnWidths(ShellExState *p, char *azWidths[], int nWidths){
+ int j;
+ p->numWidths = nWidths;
+ p->pSpecWidths = realloc(p->pSpecWidths, (nWidths+1)*sizeof(int)*2);
+ if( nWidths>0 ){
+ shell_check_oom(p->pSpecWidths);
+ p->pHaveWidths = &p->pSpecWidths[nWidths];
+ for(j=0; j<nWidths; j++){
+ p->pSpecWidths[j] = (int)integerValue(azWidths[j]);
+ p->pHaveWidths[j] = 0;
+ }
+ }else p->pHaveWidths = p->pSpecWidths;
+}
COLLECT_HELP_TEXT[
".width NUM1 NUM2 ... Set minimum column widths for columnar output",
" Negative values right-justify",
];
DISPATCHABLE_COMMAND( width ? 1 0 ){
- int j;
- p->nWidth = nArg-1;
- p->colWidth = realloc(p->colWidth, (p->nWidth+1)*sizeof(int)*2);
- if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory();
- if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth];
- for(j=1; j<nArg; j++){
- p->colWidth[j-1] = (int)integerValue(azArg[j]);
- }
+ setColumnWidths(p, azArg+1, nArg-1);
return 0;
}
DISPATCHABLE_COMMAND( wheretrace ? 1 2 ){
DISPATCHABLE_COMMAND( x ? 1 0 ){
int ia, rc, nErrors = 0;
sqlite3_stmt *pStmt = 0;
+ sqlite3 *db;
+
open_db(p, 0);
- if( p->db==0 ){
+ db = DBX(p);
+ if( db==0 ){
utf8_printf(STD_ERR, ".x can only be done with a database open.\n");
return 1;
}
- if( sqlite3_table_column_metadata(p->db, PARAM_TABLE_SCHEMA,
+ if( sqlite3_table_column_metadata(db, PARAM_TABLE_SCHEMA,
PARAM_TABLE_NAME,
"key", 0, 0, 0, 0, 0)!=SQLITE_OK ){
utf8_printf(STD_ERR, "No "PARAM_TABLE_SNAME" table exists.\n");
return 1;
}
- rc = sqlite3_prepare_v2
- (p->db, "SELECT value FROM "PARAM_TABLE_SNAME
- " WHERE key=$1 AND uses=1",
- -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(db, "SELECT value FROM "PARAM_TABLE_SNAME
+ " WHERE key=$1 AND uses=1", -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
utf8_printf(STD_ERR, PARAM_TABLE_SNAME" is wrongly created.\n");
return 1;
*/
int nle = zValue[nb-1]=='\n';
char *zSubmit = sqlite3_mprintf( "%.*s%s", nb, zValue, "\n"+nle );
+ ShellInState *psi = ISS(p);
InSource inRedir
- = INSOURCE_STR_REDIR(zSubmit, azArg[ia], p->pInSource);
+ = INSOURCE_STR_REDIR(zSubmit, azArg[ia], psi->pInSource);
shell_check_oom(zSubmit);
- p->pInSource = &inRedir;
- rc = process_input(p);
+ psi->pInSource = &inRedir;
+ rc = process_input(psi);
sqlite3_free(zSubmit);
- p->pInSource = inRedir.pFrom;
+ psi->pInSource = inRedir.pFrom;
}else{
continue; /* All white, ignore. */
}
/* End of published, standard meta-command implementation functions
COMMENT Build-time overrides of above meta-commands or new meta-commands may be
COMMENT incorporated into shell.c via: -it COMMAND_CUSTOMIZE=<customize source>
-COMMENT where <customize source> names a file using the methodology of the above
-COMMENT section to define new or altered meta-commands and their help text.
+COMMENT where <customize source> names a file using the above methodology to
+COMMENT define new or altered meta-commands and their help text.
*/
INCLUDE( COMMAND_CUSTOMIZE );
-typedef struct MetaCommand MetaCommand;
+COMMENT This help text is set seperately from meta-command definition section
+COMMENT for the always-built-in, non-customizable commands with visible help.
+COLLECT_HELP_TEXT[
+ ".exit ?CODE? Exit this program with return-code CODE or 0",
+ ".quit Exit this program",
+];
+
+static void MetaCommand_dtor(MetaCommand *);
+static const char * MetaCommand_name(MetaCommand *);
+static const char * MetaCommand_help(MetaCommand *, int);
+static int MetaCommand_argsCheck(MetaCommand *, char **, int, char *azArgs[]);
+static int MetaCommand_execute(MetaCommand *, ShellExState *,
+ char **, int, char *azArgs[]);
+
+static VTABLE_NAME(MetaCommand) meta_cmd_VtabBuiltIn = {
+ MetaCommand_dtor,
+ MetaCommand_name,
+ MetaCommand_help,
+ MetaCommand_argsCheck,
+ MetaCommand_execute
+};
/* Define and populate command dispatch table. */
static struct CommandInfo {
+#if OBJECTIFY_COMMANDS
+ VTABLE_NAME(MetaCommand) *mcVtabBuiltIn;
+#endif
const char * cmdName;
- int (*cmdDoer)(char *azArg[], int nArg, ShellState *, char **pzErr);
+ int (*cmdDoer)(char *azArg[], int nArg, ShellExState *, char **pzErr);
unsigned char minLen, minArgs, maxArgs;
#if OBJECTIFY_COMMANDS
const char *azHelp[2]; /* primary and secondary help text */
#endif
} command_table[] = {
COMMENT Emit the dispatch table entries generated and collected above.
+#if OBJECTIFY_COMMANDS
+# define META_CMD_INFO(cmd, nlenMin, minArgs, maxArgs, ht0, ht1 ) \
+ { &meta_cmd_VtabBuiltIn, #cmd, cmd ## Command, \
+ nlenMin, minArgs, maxArgs, { ht0, ht1 }, 0 \
+ }
+ EMIT_METACMD_INIT(2);
+ { 0, 0, 0, 0, ~0, ~0, {0,0}, 0 }
+#else
EMIT_DISPATCH(2);
- { 0, 0, 0, -1, -1 }
+ { 0, 0, 0, ~0, ~0 }
+#endif
};
static unsigned numCommands
= sizeof(command_table)/sizeof(struct CommandInfo) - 1;
-COMMENT This help text is set seperately from meta-command definition section
-COMMENT for the always-built-in, non-customizable commands with visible help.
-COLLECT_HELP_TEXT[
- ".exit ?CODE? Exit this program with return-code CODE or 0",
- ".quit Exit this program",
-];
+static void MetaCommand_dtor(MetaCommand *pMe){
+ UNUSED_PARAMETER(pMe);
+}
+
+static const char * MetaCommand_name(MetaCommand *pMe){
+ return ((struct CommandInfo *)pMe)->cmdName;
+}
+
+static const char * MetaCommand_help(MetaCommand *pMe, int more){
+ if( more>=0 && more<2 ) return ((struct CommandInfo *)pMe)->azHelp[more];
+ else return 0;
+}
+
+static int MetaCommand_argsCheck(MetaCommand *pMe,
+ char **pzErrMsg, int nArgs, char *azArgs[]){
+ struct CommandInfo *pci = (struct CommandInfo *)pMe;
+ UNUSED_PARAMETER(pzErrMsg); /* Future: Make this more informative. */
+ UNUSED_PARAMETER(nArgs);
+ UNUSED_PARAMETER(azArgs);
+ if( pci->minArgs > nArgs||(pci->maxArgs > 0 && pci->maxArgs < nArgs) ){
+ return SHELL_INVALID_ARGS;
+ }else return 0;
+}
+
+static int MetaCommand_execute(MetaCommand *pMe, ShellExState *pssx,
+ char **pzErrMsg, int nArgs, char *azArgs[]){
+ return (((struct CommandInfo *)pMe)->cmdDoer)(azArgs, nArgs, pssx, pzErrMsg);
+}
/*
** Text of help messages.
** The return is either a dispatch error or whatever the dispatched
** meta-command returns.
*/
-int dispatchCommand(char *azArg[], int nArg, ShellState *pSS, char **pzErr){
+int dispatchCommand(char *azArg[], int nArg, ShellExState *psx, char **pzErr){
const char *cmdName = azArg[0];
int cmdLen = strlen30(cmdName);
struct CommandInfo *pci = 0;
}
/* Replace any user-shortened command name with its whole name. */
azArg[0] = (char *)pci->cmdName;
- return (pci->cmdDoer)(azArg, nArg, pSS, pzErr);
+ return (pci->cmdDoer)(azArg, nArg, psx, pzErr);
}
/*
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
-static int do_meta_command(char *zLine, ShellState *p){
+static int do_meta_command(char *zLine, ShellExState *psx){
int h = 1;
int nArg = 0;
int n, c;
char *azArg[52];
#if SHELL_VARIABLE_EXPANSION
int ncLineIn = strlen30(zLine);
- u8 bExpVars = SHEXT_VAREXP(p);
+ u8 bExpVars = SHEXT_VAREXP(ISS(psx));
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( p->expert.pExpert ){
- expertFinish(p, 1, 0);
+ if( ISS(psx)->expert.pExpert ){
+ expertFinish(ISS(psx), 1, 0);
}
#endif
if( nArg==0 ) return 0; /* no tokens, no error */
n = strlen30(azArg[0]);
c = azArg[0][0];
- clearTempFile(p);
+ clearTempFile(ISS(psx));
/* Check for the special, non-dispatched meta-commands.
*/
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 )
- p->abruptExit = rc;
+ psx->shellAbruptExit = rc;
rc = 2;
}else
int i, v;
for(i=1; i<nArg; i++){
v = booleanValue(azArg[i]);
- utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
+ utf8_printf(ISS(psx)->out, "%s: %d 0x%x\n", azArg[i], v, v);
}
}
if( strncmp(azArg[0]+9, "integer", n-9)==0 ){
char zBuf[200];
v = integerValue(azArg[i]);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
- utf8_printf(p->out, "%s", zBuf);
+ utf8_printf(ISS(psx)->out, "%s", zBuf);
}
}
}else
/* The meta-command is not among the specially handled ones. Dispatch it. */
{
char *zErr = 0;
- int dispatchResult = dispatchCommand(azArg, nArg, p, &zErr);
- if( p->abruptExit!=0 ){
+ int dispatchResult = dispatchCommand(azArg, nArg, psx, &zErr);
+ if( psx->shellAbruptExit!=0 ){
dispatchResult = SHELL_FORBIDDEN_OP;
}
switch( dispatchResult ){
utf8_printf(STD_ERR,
"Error: \".%s\" forbidden in --safe mode\n", azArg[0]);
}
- p->abruptExit = 3;
+ psx->shellAbruptExit = 3;
rc = 2;
default:
if( 0!=dispatchResult ) rc = 1;
}
meta_command_exit:
- if( p->outCount ){
- p->outCount--;
- if( p->outCount==0 ) output_reset(p);
+ if( ISS(psx)->outCount ){
+ ISS(psx)->outCount--;
+ if( ISS(psx)->outCount==0 ) output_reset(ISS(psx));
}
- updateSafeMode(p);
+ updateSafeMode(ISS(psx));
#if SHELL_VARIABLE_EXPANSION
if( bExpVars ){
/* Free any arguments that are allocated rather than tokenized in place. */
** Run a single line of SQL. Return the number of errors.
** bAltIn indicates that input has been redirected in some way.
*/
-static int runOneSqlLine(ShellState *p, char *zSql, int bAltIn, int startline){
+static int runOneSqlLine(ShellExState *psx, char *zSql,
+ int bAltIn, int startline){
int rc;
char *zErrMsg = 0;
- open_db(p, 0);
- if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
- if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
+ open_db(psx, 0);
+ if( ShellHasFlag(psx,SHFLG_Backslash) ) resolve_backslashes(zSql);
+ if( ISS(psx)->flgProgress & SHELL_PROGRESS_RESET ) ISS(psx)->nProgress = 0;
BEGIN_TIMER;
- rc = shell_exec(p, zSql, &zErrMsg);
+ /* This shell_exec call will also echo the submitted SQL when echo is on. */
+ rc = shell_exec(psx, zSql, &zErrMsg);
END_TIMER;
if( rc || zErrMsg ){
char zPrefix[100];
const char *zErrorType;
if( zErrMsg==0 ){
zErrorType = "Error";
- zErrorTail = sqlite3_errmsg(p->db);
+ zErrorTail = sqlite3_errmsg(DBX(psx));
}else if( strncmp(zErrMsg, "in prepare, ",12)==0 ){
zErrorType = "Parse error";
zErrorTail = &zErrMsg[12];
utf8_printf(STD_ERR, "%s %s\n", zPrefix, zErrorTail);
sqlite3_free(zErrMsg);
return 1;
- }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
+ }else if( ShellHasFlag(psx, SHFLG_CountChanges) ){
char zLineBuf[2000];
sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
"changes: %lld total_changes: %lld",
- sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
- raw_printf(p->out, "%s\n", zLineBuf);
+ sqlite3_changes64(DBX(psx)), sqlite3_total_changes64(DBX(psx)));
+ raw_printf(ISS(psx)->out, "%s\n", zLineBuf);
}
return 0;
}
** 2 => exit demanded, no errors.
** 3 => exit demanded, errors>0
*/
-static int process_input(ShellState *p){
+static int process_input(ShellInState *psi){
char *zLineInput = 0; /* a line-at-a-time input buffer or usable result */
char *zLineAccum = 0; /* accumulation buffer, used for multi-line input */
/* Above two pointers could be local to the group handling loop, but are
/* Some flags for ending the overall group processing loop, always 1 or 0 */
u8 bErrorBail=0, bInputEnd=0, bExitDemand=0, bInterrupted=0;
/* Flag to affect prompting and interrupt action */
- u8 bInteractive = (p->pInSource==&stdInSource && stdin_is_interactive);
+ u8 bInteractive = INSOURCE_IS_INTERACTIVE(psi->pInSource);
int nErrors = 0; /* count of errors during execution or its prep */
/* Block overly-recursive or absurdly nested input redirects. */
- if( p->inputNesting==MAX_INPUT_NESTING ){
- InSource *pInSrc = p->pInSource->pFrom;
+ if( psi->inputNesting>=MAX_INPUT_NESTING ){
+ InSource *pInSrc = psi->pInSource->pFrom;
const char *zLead = "Input nesting limit ("
SHELL_STRINGIFY(MAX_INPUT_NESTING)") reached,";
int i = 3;
utf8_printf(STD_ERR, " ...\nERROR: Check recursion.\n");
return 1;
}
- ++p->inputNesting;
+ ++psi->inputNesting;
/* line-group processing loop (per SQL block, dot-command or comment) */
while( !bErrorBail && !bInputEnd && !bExitDemand && !bInterrupted ){
int *pncLineUse = &ncLineIn; /* ref that line's char count */
int iStartline = 0; /* starting line number of group */
- fflush(p->out);
- zLineInput = one_input_line(p->pInSource, zLineInput, nGroupLines>0);
+ fflush(psi->out);
+ zLineInput = one_input_line(psi->pInSource, zLineInput, nGroupLines>0);
if( zLineInput==0 ){
bInputEnd = 1;
inKind = Eof;
if( bInteractive ) printf("\n");
}else{
++nGroupLines;
- iStartline = p->pInSource->lineno;
+ iStartline = psi->pInSource->lineno;
ncLineIn = strlen30(zLineInput);
if( seenInterrupt ){
- if( p->pInSource!=0 ) break;
+ if( psi->pInSource!=0 ) break;
bInterrupted = 1; /* This will be honored, or not, later. */
seenInterrupt = 0;
disposition = Dumpable;
}
/* Classify and check for single-line dispositions, prep for more. */
#if SHELL_EXTENDED_PARSING
- ndcLeadWhite = (SHEXT_PARSING(p))
+ ndcLeadWhite = (SHEXT_PARSING(psi))
? skipWhite(zLineInput)-zLineInput
: 0; /* Disallow leading whitespace for . or # in legacy mode. */
#endif
disposition = Dumpable;
case Cmd:
#if SHELL_EXTENDED_PARSING
- if( SHEXT_PARSING(p) ){
+ if( SHEXT_PARSING(psi) ){
if( line_join_ends(dcScanState, *pzLineUse, pncLineUse, &cLineEnd) ){
disposition = Runnable;
}
pncLineUse = &ncLineAcc;
}
/* Read in next line of group, (if available.) */
- zLineInput = one_input_line(p->pInSource, zLineInput, nGroupLines>0);
+ zLineInput = one_input_line(psi->pInSource, zLineInput, nGroupLines>0);
if( zLineInput==0 ){
bInputEnd = 1;
inKind = Eof;
/* Here, the group is fully collected or known to be incomplete forever. */
switch( disposition ){
case Dumpable:
- echo_group_input(p, *pzLineUse);
+ echo_group_input(psi, *pzLineUse);
break;
case Runnable:
switch( inKind ){
case Sql:
/* runOneSqlLine() does its own echo when requested. */
- nErrors += runOneSqlLine(p, *pzLineUse,
- INSOURCE_IS_INTERACTIVE(p->pInSource),
+ nErrors += runOneSqlLine(XSS(psi), *pzLineUse,
+ INSOURCE_IS_INTERACTIVE(psi->pInSource),
iStartline);
if( bail_on_error && nErrors>0 ) bErrorBail = 1;
break;
case Cmd:
- echo_group_input(p, *pzLineUse);
- switch( do_meta_command(*pzLineUse+ndcLeadWhite, p) ){
+ echo_group_input(psi, *pzLineUse);
+ switch( do_meta_command(*pzLineUse+ndcLeadWhite, XSS(psi)) ){
default: ++nErrors; /* fall thru */
case 0: break;
case 2: bExitDemand = 1; break;
assert(inKind!=Tbd);
break;
}
- if( p->abruptExit!=0 ) bExitDemand = 1;
+ if( XSS(psi)->shellAbruptExit!=0 ) bExitDemand = 1;
break;
case Erroneous:
utf8_printf(STD_ERR, "Error: Input incomplete at line %d of \"%s\"\n",
- p->pInSource->lineno, p->pInSource->zSourceSay);
+ psi->pInSource->lineno, psi->pInSource->zSourceSay);
++nErrors;
break;
case Ignore:
** This is a convenience function, used in several places, all of
** demand a shell exit upon failure, which leads to return 2.
*/
-static int run_single_query(ShellState *p, char *zSql){
+static int run_single_query(ShellExState *psx, char *zSql){
char *zErrMsg = 0;
int rc;
- open_db(p, 0);
- rc = shell_exec(p, zSql, &zErrMsg);
+ open_db(psx, 0);
+ rc = shell_exec(psx, zSql, &zErrMsg);
if( zErrMsg!=0 || rc>0 ){
/* Some kind of error, to result in exit before REPL. */
if( zErrMsg!=0 ){
}else{
utf8_printf(STD_ERR,"Error: unable to process SQL \"%s\"\n", zSql);
}
- p->abruptExit = (rc==0)? 1 : rc;
+ psx->shellAbruptExit = (rc==0)? 1 : rc;
rc = 2;
}
return rc;
** The return is similar to process_input() (0 success, 1 error, x abort)
*/
static void process_sqliterc(
- ShellState *p, /* Configuration data */
+ ShellInState *psi, /* shell state (internal) */
const char *sqliterc_override /* Name of config file. NULL to use default */
){
char *home_dir = NULL;
inUse = fopen(sqliterc,"rb");
if( inUse!=0 ){
InSource inSourceRedir
- = INSOURCE_FILE_REDIR(inUse, sqliterc, p->pInSource);
+ = INSOURCE_FILE_REDIR(inUse, sqliterc, psi->pInSource);
int rc;
- p->pInSource = &inSourceRedir;
+ psi->pInSource = &inSourceRedir;
if( stdin_is_interactive ){
utf8_printf(STD_ERR,"-- Loading resources from %s\n",sqliterc);
}
- rc = process_input(p);
+ rc = process_input(psi);
fclose(inUse);
- p->pInSource = inSourceRedir.pFrom;
- if( rc!=0 && bail_on_error ) p->abruptExit = rc;
+ psi->pInSource = inSourceRedir.pFrom;
+ if( rc!=0 && bail_on_error ) XSS(psi)->shellAbruptExit = rc;
}else if( sqliterc_override!=0 ){
utf8_printf(STD_ERR,"cannot open: \"%s\"\n", sqliterc);
- if( bail_on_error ) exit(1);
+ if( bail_on_error ) exit(1); /* Future: Exit shell rather than process. */
}
sqlite3_free(zBuf);
}
}
/*
-** Initialize the state information in data
-*/
-static void main_init(ShellState *data) {
- memset(data, 0, sizeof(*data));
- data->out = STD_OUT;
- data->normalMode = data->cMode = data->mode = MODE_List;
- data->autoExplain = 1;
- data->pAuxDb = &data->aAuxDb[0];
- memcpy(data->colSeparator,SEP_Column, 2);
- memcpy(data->rowSeparator,SEP_Row, 2);
- data->showHeader = 0;
- data->shellFlgs = SHFLG_Lookaside;
+** Initialize the state information in data and datax
+*/
+ static void main_init(ShellInState *pData, ShellExState *pDatax) {
+ memset(pData, 0, sizeof(*pData));
+ memset(pDatax, 0, sizeof(*pDatax));
+ pDatax->sizeofThis = sizeof(*pDatax);
+ pDatax->pSIS = pData;
+ pData->pSXS = pDatax;
+ pDatax->pShowHeader = &pData->showHeader;
+ pDatax->zFieldSeparator = &pData->colSeparator[0];
+ pDatax->zRecordSeparator = &pData->rowSeparator[0];
+ pDatax->zNullValue = &pData->nullValue[0];
+ pData->out = STD_OUT;
+ pDatax->ppCurrentOutput = &pData->out;
+ pData->normalMode = pData->cMode = pData->mode = MODE_List;
+ pData->autoExplain = 1;
+ pData->pAuxDb = &pData->aAuxDb[0];
+ memcpy(pData->colSeparator,SEP_Column, 2);
+ memcpy(pData->rowSeparator,SEP_Row, 2);
+ pData->showHeader = 0;
+ pData->shellFlgs = SHFLG_Lookaside;
verify_uninitialized();
sqlite3_config(SQLITE_CONFIG_URI, 1);
- sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
+ sqlite3_config(SQLITE_CONFIG_LOG, shellLog, pData);
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
int SQLITE_CDECL SHELL_MAIN(int argc, wchar_t **wargv){
char **argv;
#endif
- ShellState data;
+ ShellInState data;
+ ShellExState datax;
const char *zInitFile = 0;
int bQuiet = 0; /* for testing, to suppress banner and history actions */
- int i;
+ int i, aec;
int rc = 0;
int warnInmemoryDb = 0;
int readStdin = 1;
exit(1);
}
#endif
- main_init(&data);
+ main_init(&data,&datax);
/* On Windows, we must translate command-line arguments into UTF-8.
** The SQLite memory allocator subsystem has to be enabled in order to
** to the sqlite command-line tool.
*/
if( access(data.pAuxDb->zDbFilename, 0)==0 ){
- open_db(&data, 0);
+ open_db(&datax, 0);
}
/* Process the initialization file if there is one. If no -init option
"%s",cmdline_option_value(argc,argv,++i));
}else if( strcmp(z,"-header")==0 ){
data.showHeader = 1;
- ShellSetFlag(&data, SHFLG_HeaderSet);
+ ShellSetFlag(&datax, SHFLG_HeaderSet);
}else if( strcmp(z,"-noheader")==0 ){
data.showHeader = 0;
- ShellSetFlag(&data, SHFLG_HeaderSet);
+ ShellSetFlag(&datax, SHFLG_HeaderSet);
}else if( strcmp(z,"-echo")==0 ){
- ShellSetFlag(&data, SHFLG_Echo);
+ ShellSetFlag(&datax, SHFLG_Echo);
}else if( strcmp(z,"-eqp")==0 ){
data.autoEQP = AUTOEQP_on;
}else if( strcmp(z,"-eqpfull")==0 ){
** prior to sending the SQL into SQLite. Useful for injecting
** crazy bytes in the middle of SQL statements for testing and debugging.
*/
- ShellSetFlag(&data, SHFLG_Backslash);
+ ShellSetFlag(&datax, SHFLG_Backslash);
}else if( strcmp(z,"-bail")==0 ){
/* No-op. The bail_on_error flag should already be set. */
#if SHELL_EXTENSIONS
if( i==argc-1 ) break;
z = cmdline_option_value(argc,argv,++i);
if( z[0]=='.' ){
- rc = do_meta_command(z, &data);
+ rc = do_meta_command(z, &datax);
}else{
- rc = run_single_query(&data, z);
+ rc = run_single_query(&datax, z);
}
if( rc && bail_on_error ){
if( rc==2 ) rc = 0;
rc = 1;
goto shell_bail;
}
- open_db(&data, OPEN_DB_ZIPFILE);
+ open_db(&datax, OPEN_DB_ZIPFILE);
if( z[2] ){
argv[i] = &z[2];
- rc = arDotCommand(&data, 1, argv+(i-1), argc-(i-1));
+ rc = arDotCommand(&datax, 1, argv+(i-1), argc-(i-1));
}else{
- rc = arDotCommand(&data, 1, argv+i, argc-i);
+ rc = arDotCommand(&datax, 1, argv+i, argc-i);
}
readStdin = 0;
break;
}
if( zModeSet!=0 ){
char *azModeCmd[] = { ".mode", zModeSet+1 };
- modeCommand(azModeCmd, 2, &data, 0);
+ modeCommand(azModeCmd, 2, &datax, 0);
data.cMode = data.mode;
}
}
*/
for(i=0; i<nCmd && rc<2; i++){
if( azCmd[i][0]=='.' ){
- rc = do_meta_command(azCmd[i], &data);
+ rc = do_meta_command(azCmd[i], &datax);
}else{
- rc = run_single_query(&data, azCmd[i]);
+ rc = run_single_query(&datax, azCmd[i]);
}
if( rc && bail_on_error ){
goto shell_bail;
}
}
shell_bail:
- set_table_name(&data, 0);
- if( data.db ){
+ set_table_name(&datax, 0);
+ if( datax.dbUser ){
session_close_all(&data, -1);
- close_db(data.db);
+ close_db(datax.dbUser);
}
sqlite3_mutex_free(pGlobalDbLock);
pGlobalDbLock = 0;
data.doXdgOpen = 0;
clearTempFile(&data);
sqlite3_free(data.zEditor);
+#if SHELL_DYNAMIC_EXTENSION
+ sqlite3_close(datax.dbShell);
+#endif
#if !SQLITE_SHELL_IS_UTF8
for(i=0; i<argcToFree; i++) free(argvToFree[i]);
free(argvToFree);
#endif
- free(data.colWidth);
+ free(datax.pSpecWidths);
free(data.zNonce);
for(i=0; i<data.nSavedModes; ++i) sqlite3_free(data.pModeStack[i]);
free(azCmd);
- /* Clear ShellState objects so that valgrind detects real memory leaks. */
+ aec = datax.shellAbruptExit;
+ /* Clear shell state objects so that valgrind detects real memory leaks. */
memset(&data, 0, sizeof(data));
- /* Process exit codes to yield single shell exit code.
+ memset(&datax, 0, sizeof(datax));
+ /* Process exit codes to yield single shell exit code.
* rc == 2 is a quit signal, resulting in no error by itself.
- * data.bAbruptExit conveys either an normal (success or error) exit
- * code or an abnormal exit code. Its abnormal values take priority.
+ * datax.shellAbruptExit conveyed either an normal (success or error)
+ * exit code or an abnormal exit code. Its abnormal values take priority.
*/
/* Check for an abnormal exit, and issue error if so. */
- if( rc>2 || data.abruptExit>1 ){
- rc = (rc<data.abruptExit)? data.abruptExit : rc;
- raw_printf(STD_ERR, "Abnormal exit (%d)\n", data.abruptExit);
+ if( rc>2 || aec>1 ){
+ rc = (rc<aec)? aec : rc;
+ if( rc>255 ) rc = 255; /* Clamp to valid error exit range. */
+ raw_printf(STD_ERR, "Abnormal exit (%d)\n", rc);
}else{
/* rc is one of 0,1,2, mapping to 0,1,0 shellexit codes. */
rc &= ~2;