}
}
#else
-# define shell_check_ooms(p) shell_check_oom(p)
-# define shell_check_oomm(p) shell_check_oom(p)
-static void shell_check_oom(const void *p){
- if( p==0 ) shell_out_of_memory();
-}
+# define shell_check_ooms(p) do{ if((p)==0) shell_out_of_memory(); }while 0
+# define shell_check_oomm(p) do{ if((p)==0) shell_out_of_memory(); }while 0
#endif
/* Check a SQLite result code for out-of-memory indication.
}
/*
-** Release memory previously allocated by tableColumnList().
+** Release memory previously allocated by tableColumnList() and others.
+** The *azCol object is a zero-terminated sequence of char pointers,
+** all but first of which is to be sqlite3_free()'ed, after which the
+** azCol object is to be sqlite3_free()'ed.
*/
-static void freeColumnList(char **azCol){
+static void freeNameList(char **azCol){
int i;
if( azCol!=0 ){
+ /* azCol[0] is a static string, not to be freed. */
for(i=1; azCol[i]; i++){
sqlite3_free(azCol[i]);
}
- /* azCol[0] is a static string */
sqlite3_free(azCol);
}
}
** 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
** allocated and must be released by the caller using a subsequent call
-** to freeColumnList().
+** to freeNameList().
**
** The azCol[0] entry is usually NULL. However, if zTab contains a rowid
** value that needs to be preserved, then azCol[0] is filled in with the
**
** The first regular column in the table is azCol[1]. The list is terminated
** by an entry with azCol[i]==0 for i>0. This is an invariant, maintained
-** as the list is grown so that freeColumnList() can always deal with it.
+** as the list is grown so that freeNameList() can always deal with it.
**
** This function can exit abruptly under OOM conditions.
*/
int nPK = 0; /* Number of PRIMARY KEY columns seen */
int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */
ResourceMark mark = holder_mark();
- AnyResourceHolder arh = { 0, (GenericFreer)freeColumnList };
+ AnyResourceHolder arh = { 0, (GenericFreer)freeNameList };
int rc;
zSql = smprintf("PRAGMA table_info=%Q", zTab);
}
if( cli_strcmp(zType, "table")==0 ){
- AnyResourceHolder arh = { 0, (GenericFreer)freeColumnList };
+ AnyResourceHolder arh = { 0, (GenericFreer)freeNameList };
ShellText sSelect;
ShellText sTable;
char **azCol;
FILE *cs_out = 0;
if( failIfSafeMode
(p, "cannot run \".session %s\" in safe mode", azCmd[0]) ){
- rc = DCR_AbortError;
+ return DCR_AbortError;
}else{
if( nCmd!=2 ) goto session_syntax_error;
if( pSession->p==0 ) goto session_not_open;
rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
}
if( rc ){
- fprintf(out, "Error: error code %d\n", rc);
+ fprintf(out, "Error: error code %d (swallowed)\n", rc);
rc = 0;
}
if( pChng && fwrite(pChng, szChng, 1, cs_out)!=1 ){
raw_printf(STD_ERR, "ERROR: Failed to write entire %d-byte output\n",
szChng);
+ rc = 1;
}
sqlite3_free(pChng);
fclose(cs_out);
for(i=0; i<pAuxDb->nSession; i++){
if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
utf8_printf(STD_ERR, "Session \"%s\" already exists\n", zName);
- return rc;
+ return DCR_Error;
}
}
if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){
showHelp(out, "session", p);
return DCR_CmdErred;
}
- return DCR_Ok;
+ return DCR_Ok|(rc!=0);
}
DISPATCHABLE_COMMAND( sha3sum 4 1 1 ){
char *zSep; /* Separator */
ShellText sSql; /* Complete SQL for the query to run the hash */
ShellText sQuery; /* Set of queries used to read all content */
+ RESOURCE_MARK(mark);
+
open_db(p, 0);
for(i=1; i<nArg; i++){
const char *z = azArg[i];
" AND name NOT LIKE 'sqlite_%'"
" ORDER BY 1 collate nocase";
}
- sqlite3_prepare_v2(DBX(p), zSql, -1, &pStmt, 0);
+ shell_check_nomem(sqlite3_prepare_v2(DBX(p), zSql, -1, &pStmt, 0));
+ stmt_ptr_holder(&pStmt); /* +1 */
initText(&sQuery);
+ text_ref_holder(&sQuery); /* +2 */
initText(&sSql);
+ text_ref_holder(&sSql); /* +3 */
appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
zSep = "VALUES(";
while( SQLITE_ROW==sqlite3_step(pStmt) ){
appendText(&sSql, zTab, '\'');
zSep = "),(";
}
- sqlite3_finalize(pStmt);
if( bSeparate ){
zSql = smprintf(
"%s))"
" FROM [sha3sum$query]",
sSql.z, iSize);
}
+ release_holders(mark);
shell_check_ooms(zSql);
- freeText(&sQuery);
- freeText(&sSql);
+ sstr_holder(zSql); /* +1 */
if( bDebug ){
utf8_printf(ISS(p)->out, "%s\n", zSql);
}else{
shell_exec(p, zSql, 0);
}
+ release_holder(); /* 0 */
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && !defined(SQLITE_OMIT_VIRTUALTABLE)
{
int lrc;
"WHERE type='table' AND coalesce(rootpage,0)>1\n"
"AND name NOT LIKE 'sqlite_%%'%s\n"
"ORDER BY 1 collate nocase";
- zRevText = sqlite3_mprintf(zRevText, zLike? " AND name LIKE $tspec" : "");
- zRevText = sqlite3_mprintf(
+ zRevText = smprintf(zRevText, zLike? " AND name LIKE $tspec" : "");
+ zRevText = smprintf(
/* lower-case query is first run, producing upper-case query. */
"with tabcols as materialized(\n"
"select tname, cname\n"
"' OR ') as query, tname from tabcols group by tname)"
, zRevText);
shell_check_ooms(zRevText);
+ sstr_holder(zRevText); /* +1 */
if( bDebug ) utf8_printf(ISS(p)->out, "%s\n", zRevText);
- lrc = sqlite3_prepare_v2(DBX(p), zRevText, -1, &pStmt, 0);
+ lrc = shell_check_nomem(sqlite3_prepare_v2(DBX(p), zRevText,-1,&pStmt,0));
if( lrc!=SQLITE_OK ){
- sqlite3_free(zRevText);
+ release_holders_mark(mark);
return DCR_Error;
}
+ stmt_holder(pStmt); /* +2 */
if( zLike ) sqlite3_bind_text(pStmt,1,zLike,-1,SQLITE_STATIC);
- lrc = SQLITE_ROW==sqlite3_step(pStmt);
+ lrc = SQLITE_ROW==shell_check_nomem(sqlite3_step(pStmt));
if( lrc ){
const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0);
sqlite3_stmt *pCheckStmt;
lrc = sqlite3_prepare_v2(DBX(p), zGenQuery, -1, &pCheckStmt, 0);
+ shell_check_nomem(lrc);
if( bDebug ) utf8_printf(ISS(p)->out, "%s\n", zGenQuery);
+ stmt_holder(pCheckStmt); /* +3 */
if( SQLITE_OK!=lrc ){
- sqlite3_finalize(pStmt);
- sqlite3_free(zRevText);
+ release_holders_mark(mark);
return DCR_Error;
}else{
if( SQLITE_ROW==sqlite3_step(pCheckStmt) ){
sz, (sz>1)? "s": "");
}
}
- sqlite3_finalize(pCheckStmt);
}
- sqlite3_finalize(pStmt);
}
- sqlite3_free(zRevText);
}
#endif /* !defined(*_OMIT_SCHEMA_PRAGMAS) && !defined(*_OMIT_VIRTUALTABLE) */
- sqlite3_free(zSql);
+ release_holders_mark(mark);
return DCR_Ok;
}
int i, k; /* Loop counters */
int nTest = 0; /* Number of tests runs */
int nErr = 0; /* Number of errors seen */
- ShellText str; /* Answer for a query */
+ RESOURCE_MARK(mark);
+ ShellText str = {0}; /* Answer for a query */
sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
for(i=1; i<nArg; i++){
bSelftestExists = 1;
}
initText(&str);
+ text_ref_holder(&str);
appendText(&str, "x", 0);
+ stmt_ptr_holder(&pStmt);
for(k=bSelftestExists; k>=0; k--){
if( k==1 ){
rc = sqlite3_prepare_v2(DBX(p),
}
if( rc ){
*pzErr = smprintf("Error querying the selftest table\n");
- sqlite3_finalize(pStmt);
+ release_holders_mark(mark);
return DCR_Error;
}
- for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
+ for(i=1; shell_check_nomem(sqlite3_step(pStmt))==SQLITE_ROW; i++){
int tno = sqlite3_column_int(pStmt, 0);
const char *zOp = (const char*)sqlite3_column_text(pStmt, 1);
const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
utf8_printf(psi->out, "%s\n", zSql);
}else if( cli_strcmp(zOp,"run")==0 ){
char *zErrMsg = 0;
+ sstr_ptr_holder(&zErrMsg);
str.n = 0;
str.z[0] = 0;
rc = sqlite3_exec(DBX(p), zSql, captureOutputCallback, &str, &zErrMsg);
if( rc || zErrMsg ){
nErr++;
rc = 1;
- utf8_printf(psi->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
- sqlite3_free(zErrMsg);
+ utf8_printf(psi->out, "%d: error-code-%d: %s\n", tno, rc,
+ (zErrMsg)? zErrMsg : "");
}else if( cli_strcmp(zAns,str.z)!=0 ){
nErr++;
rc = 1;
utf8_printf(psi->out, "%d: Expected: [%s]\n", tno, zAns);
utf8_printf(psi->out, "%d: Got: [%s]\n", tno, str.z);
}
+ release_holder();
}else{
*pzErr = smprintf
("Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
break;
}
} /* End loop over rows of content from SELFTEST */
- sqlite3_finalize(pStmt);
} /* End loop over k */
- freeText(&str);
+ release_holders_mark(mark);
utf8_printf(psi->out, "%d errors out of %d tests\n", nErr, nTest);
return rc > 0;
}
#if SHELLOUT_ENABLE
static DotCmdRC shellOut(char *azArg[], int nArg,
ShellExState *psx, char **pzErr){
- char *zCmd;
+ char *zCmd = 0;
int i, x;
if( ISS(psx)->bSafeMode ) return DCR_AbortError;
zCmd = smprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
zCmd, azArg[i]);
}
shell_check_ooms(zCmd);
+ sstr_holder(zCmd);
x = system(zCmd);
- sqlite3_free(zCmd);
+ release_holder();
if( x ) raw_printf(STD_ERR, "%s command returns %d\n", azArg[0], x);
return DCR_Ok;
}
}
return DCR_Ok;
moan_error:
- raw_printf(STD_ERR, "Error: %s %s\n", zAbout, zMoan);
+ *pzErr = smprintf("Error: %s %s\n", zAbout, zMoan);
return DCR_CmdErred;
}
static int showTableLike(char *azArg[], int nArg, ShellExState *p,
char **pzErr, char ot){
int rc;
- sqlite3_stmt *pStmt;
+ sqlite3_stmt *pStmt = 0;
+ ShellText s = {0};
+ AnyResourceHolder arh = { 0, (GenericFreer)freeNameList };
char **azResult;
int nRow, nAlloc;
int ii;
- ShellText s;
+ RESOURCE_MARK(mark);
+
initText(&s);
+ text_ref_holder(&s);
open_db(p, 0);
rc = sqlite3_prepare_v2(DBX(p), "PRAGMA database_list", -1, &pStmt, 0);
- if( rc ){
- sqlite3_finalize(pStmt);
+ stmt_ptr_holder(&pStmt);
+ if( shell_check_nomem(rc) ){
+ db_err_bail:
+ release_holders_mark(mark);
return shellDatabaseError(DBX(p));
}
** when called with the wrong number of arguments whereas the .tables
** command does not. */
*pzErr = smprintf("Usage: .indexes ?LIKE-PATTERN?\n");
- sqlite3_finalize(pStmt);
+ release_holders_mark(mark);
return DCR_SayUsage;
}
for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
appendText(&s, zSystem, 0);
}
rc = sqlite3_finalize(pStmt);
+ pStmt = 0;
if( rc==SQLITE_OK ){
appendText(&s, " ORDER BY 1", 0);
- rc = sqlite3_prepare_v2(DBX(p), s.z, -1, &pStmt, 0);
+ rc = shell_check_nomem(sqlite3_prepare_v2(DBX(p), s.z, -1, &pStmt, 0));
}
- freeText(&s);
- if( rc ) return shellDatabaseError(DBX(p));
+ if( rc ) goto db_err_bail;
/* Run the SQL statement prepared by the above block. Store the results
- ** as an array of nul-terminated strings in azResult[]. */
+ ** as an array of nul-terminated strings in azResult[]. The 0th element
+ ** of azResult[] is not used so that freeNameList() can free it. */
nRow = nAlloc = 0;
azResult = 0;
if( nArg>1 ){
}else{
sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
}
- while( sqlite3_step(pStmt)==SQLITE_ROW ){
- if( nRow>=nAlloc ){
+ while( shell_check_nomem(sqlite3_step(pStmt))==SQLITE_ROW ){
+ if( nRow+2 > nAlloc ){
char **azNew;
int n2 = nAlloc*2 + 10;
azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
shell_check_ooms(azNew);
+ /* Keep the object usable by freeNameList at all times. */
+ memset(azNew+nAlloc, 0, (n2-nAlloc)*sizeof(azResult[0]));
nAlloc = n2;
+ arh.pAny = azNew;
azResult = azNew;
}
+ ++nRow;
azResult[nRow] = smprintf("%s", sqlite3_column_text(pStmt, 0));
shell_check_ooms(azResult[nRow]);
- nRow++;
}
if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
- rc = shellDatabaseError(DBX(p));
+ pStmt = 0;
+ goto db_err_bail;
}
-
+ pStmt = 0;
/* Pretty-print the contents of array azResult[] to the output */
if( rc==0 && nRow>0 ){
int len, maxlen = 0;
int i, j;
int nPrintCol, nPrintRow;
- for(i=0; i<nRow; i++){
+ for(i=1; i<=nRow; i++){
len = strlen30(azResult[i]);
if( len>maxlen ) maxlen = len;
}
nPrintCol = 80/(maxlen+2);
if( nPrintCol<1 ) nPrintCol = 1;
nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
- for(i=0; i<nPrintRow; i++){
- for(j=i; j<nRow; j+=nPrintRow){
- char *zSp = j<nPrintRow ? "" : " ";
+ for(i=1; i<=nPrintRow; i++){
+ for(j=i; j<=nRow; j+=nPrintRow){
+ char *zSp = j<=nPrintRow ? "" : " ";
utf8_printf(ISS(p)->out, "%s%-*s", zSp, maxlen,
azResult[j] ? azResult[j]:"");
}
raw_printf(ISS(p)->out, "\n");
}
}
-
- for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
- sqlite3_free(azResult);
+ release_holders_mark(mark);
return DCR_Ok;
}
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 && ISS(p)->bSafeMode ){
- utf8_printf(STD_ERR,
- "line %d: \".testctrl %s\" may not be used in safe mode\n",
- ISS(p)->pInSource->lineno, aCtrl[iCtrl].zCtrlName);
- exit(1);
+ }else if( aCtrl[iCtrl].unSafe
+ && failIfSafeMode(p,"line %d: \".testctrl %s\" "
+ "may not be used in safe mode\n",
+ ISS(p)->pInSource->lineno,
+ aCtrl[iCtrl].zCtrlName) ){
+ return DCR_Abort;
}else{
switch(testctrl){
if( (nArg>2 || zCmd[0]=='c') ){
sqlite3_str *sbZap = sqlite3_str_new(dbs);
char *zSql;
+ sqst_ptr_holder(&sbZap);
sqlite3_str_appendf
(sbZap, "DELETE FROM "SHVAR_TABLE_SNAME" WHERE key ");
append_in_clause(sbZap,
(const char **)&azArg[2], (const char **)&azArg[nArg]);
zSql = sqlite3_str_finish(sbZap);
+ drop_holder();
shell_check_ooms(zSql);
+ sstr_holder(zSql);
rc = sqlite3_exec(dbs, zSql, 0, 0, 0);
- sqlite3_free(zSql);
+ release_holder();
}
#ifndef SQLITE_NOHAVE_SYSTEM
}else if( SUBCMD("edit") ){
*/
static void setColumnWidths(ShellExState *p, char *azWidths[], int nWidths){
int j;
+ int *pSW = p->pSpecWidths;
p->numWidths = nWidths;
- p->pSpecWidths = realloc(p->pSpecWidths, (nWidths+1)*sizeof(int)*2);
+ pSW = realloc(pSW, (nWidths+1)*sizeof(int)*2);;
+ shell_check_oomm(pSW);
+ p->pSpecWidths = pSW;
if( nWidths>0 ){
- shell_check_oomm(p->pSpecWidths);
p->pHaveWidths = &p->pSpecWidths[nWidths];
for(j=0; j<nWidths; j++){
p->pSpecWidths[j] = (int)integerValue(azWidths[j]);
DISPATCHABLE_COMMAND( read 3 2 2 ){
DotCmdRC rc = DCR_Ok;
ShellInState *psi = ISS(p);
- FILE *inUse = 0;
- int (*fCloser)(FILE *) = 0;
+ InSource inSourceRedir
+ = INSOURCE_FILE_REDIR(0, azArg[1], psi->pInSource);
+
if( psi->bSafeMode ) return DCR_AbortError;
if( azArg[1][0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
*pzErr = smprintf("pipes are not supported in this OS\n");
rc = DCR_Error;
- /* p->out = STD_OUT; This was likely not needed. To be investigated. */
#else
- inUse = popen(azArg[1]+1, "r");
- if( inUse==0 ){
+ if( (inSourceRedir.inFile = popen(azArg[1]+1, "r"))==0 ){
*pzErr = smprintf("cannot open \"%s\"\n", azArg[1]);
rc = DCR_Error;
}else{
- fCloser = pclose;
+ inSourceRedir.closer.stream = pclose;
}
#endif
- }else if( (inUse = openChrSource(azArg[1]))==0 ){
+ }else if( (inSourceRedir.inFile = openChrSource(azArg[1]))==0 ){
*pzErr = smprintf("cannot open \"%s\"\n", azArg[1]);
rc = DCR_Error;
}else{
- fCloser = fclose;
+ inSourceRedir.closer.stream = fclose;
}
- if( inUse!=0 ){
- InSource inSourceRedir
- = INSOURCE_FILE_REDIR(inUse, azArg[1], psi->pInSource);
+ if( inSourceRedir.inFile!=0 ){
AnyResourceHolder arh = { &(psi->pInSource),(GenericFreer)finish_InSource };
psi->pInSource = &inSourceRedir;
- inSourceRedir.closer.stream = fCloser;
any_ref_holder(&arh);
rc = process_input(psi);
/* If error(s) occured during process, leave complaining to them. */