Index: src/shell.c.in ================================================================== --- src/shell.c.in +++ src/shell.c.in @@ -3545,12 +3545,15 @@ FILE *f = fopen(zName, "rb"); size_t n; int rc = SHELL_OPEN_UNSPEC; char zBuf[100]; if( f==0 ){ - if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ) return SHELL_OPEN_ZIPFILE; - return SHELL_OPEN_NORMAL; + if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ + return SHELL_OPEN_ZIPFILE; + }else{ + return SHELL_OPEN_NORMAL; + } } fseek(f, -25, SEEK_END); n = fread(zBuf, 25, 1, f); if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){ rc = SHELL_OPEN_APPENDVFS; @@ -3566,21 +3569,35 @@ } fclose(f); return rc; } +/* Flags for open_db(). +** +** The default behavior of open_db() is to exit(1) if the database fails to +** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error +** but still returns without calling exit. +** +** The OPEN_DB_ZIPFILE flag causes open_db() to prefer to open files as a +** ZIP archive if the file does not exist or is empty and its name matches +** the *.zip pattern. +*/ +#define OPEN_DB_KEEPALIVE 0x001 /* Return after error if true */ +#define OPEN_DB_ZIPFILE 0x002 /* Open as ZIP if name matches *.zip */ + /* ** 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 keepAlive){ +static void open_db(ShellState *p, int openFlags){ if( p->db==0 ){ if( p->openMode==SHELL_OPEN_UNSPEC ){ if( p->zDbFilename==0 || p->zDbFilename[0]==0 ){ p->openMode = SHELL_OPEN_NORMAL; - }else if( access(p->zDbFilename,0)==0 ){ - p->openMode = (u8)deduceDatabaseType(p->zDbFilename, 0); + }else{ + p->openMode = (u8)deduceDatabaseType(p->zDbFilename, + (openFlags & OPEN_DB_ZIPFILE)!=0); } } switch( p->openMode ){ case SHELL_OPEN_APPENDVFS: { sqlite3_open_v2(p->zDbFilename, &p->db, @@ -3603,11 +3620,11 @@ } globalDb = p->db; if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n", p->zDbFilename, sqlite3_errmsg(p->db)); - if( keepAlive ) return; + if( openFlags & OPEN_DB_KEEPALIVE ) return; exit(1); } #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif @@ -3636,10 +3653,21 @@ sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } } } + +/* +** Attempt to close the databaes connection. Report errors. +*/ +void close_db(sqlite3 *db){ + int rc = sqlite3_close(db); + if( rc ){ + utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n", + rc, sqlite3_errmsg(db)); + } +} #if HAVE_READLINE || HAVE_EDITLINE /* ** Readline completion callbacks */ @@ -4217,11 +4245,11 @@ tryToCloneSchema(p, newDb, "type='table'", tryToCloneData); tryToCloneSchema(p, newDb, "type!='table'", 0); sqlite3_exec(newDb, "COMMIT;", 0, 0, 0); sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); } - sqlite3_close(newDb); + close_db(newDb); } /* ** Change the output file back to stdout. ** @@ -4872,10 +4900,11 @@ u8 eCmd; /* An AR_CMD_* value */ u8 bVerbose; /* True if --verbose */ u8 bZip; /* True if the archive is a ZIP */ u8 bDryRun; /* True if --dry-run */ u8 bAppend; /* True if --append */ + u8 fromCmdLine; /* Run from -A instead of .archive */ int nArg; /* Number of command arguments */ char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ const char *zFile; /* --file argument, or NULL */ const char *zDir; /* --directory argument, or NULL */ char **azArg; /* Array of command arguments */ @@ -4918,17 +4947,22 @@ /* ** Print an error message for the .ar command to stderr and return ** SQLITE_ERROR. */ -static int arErrorMsg(const char *zFmt, ...){ +static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){ va_list ap; char *z; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); va_end(ap); - raw_printf(stderr, "Error: %s (try \".ar --help\")\n", z); + utf8_printf(stderr, "Error: %s\n", z); + if( pAr->fromCmdLine ){ + utf8_printf(stderr, "Use \"-A\" for more help\n"); + }else{ + utf8_printf(stderr, "Use \".archive --help\" for more help\n"); + } sqlite3_free(z); return SQLITE_ERROR; } /* @@ -4955,11 +4989,11 @@ case AR_CMD_EXTRACT: case AR_CMD_LIST: case AR_CMD_UPDATE: case AR_CMD_HELP: if( pAr->eCmd ){ - return arErrorMsg("multiple command options"); + return arErrorMsg(pAr, "multiple command options"); } pAr->eCmd = eSwitch; break; case AR_SWITCH_DRYRUN: @@ -5015,12 +5049,10 @@ if( nArg<=1 ){ return arUsage(stderr); }else{ char *z = azArg[1]; - memset(pAr, 0, sizeof(ArCommand)); - if( z[0]!='-' ){ /* Traditional style [tar] invocation */ int i; int iArg = 2; for(i=0; z[i]; i++){ @@ -5028,15 +5060,15 @@ struct ArSwitch *pOpt; for(pOpt=&aSwitch[0]; pOptcShort ) break; } if( pOpt==pEnd ){ - return arErrorMsg("unrecognized option: %c", z[i]); + return arErrorMsg(pAr, "unrecognized option: %c", z[i]); } if( pOpt->bArg ){ if( iArg>=nArg ){ - return arErrorMsg("option requires an argument: %c",z[i]); + return arErrorMsg(pAr, "option requires an argument: %c",z[i]); } zArg = azArg[iArg++]; } if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR; } @@ -5066,19 +5098,19 @@ struct ArSwitch *pOpt; for(pOpt=&aSwitch[0]; pOptcShort ) break; } if( pOpt==pEnd ){ - return arErrorMsg("unrecognized option: %c\n", z[i]); + return arErrorMsg(pAr, "unrecognized option: %c", z[i]); } if( pOpt->bArg ){ if( i<(n-1) ){ zArg = &z[i+1]; i = n; }else{ if( iArg>=(nArg-1) ){ - return arErrorMsg("option requires an argument: %c\n",z[i]); + return arErrorMsg(pAr, "option requires an argument: %c",z[i]); } zArg = azArg[++iArg]; } } if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR; @@ -5096,23 +5128,23 @@ struct ArSwitch *pOpt; /* Iterator */ for(pOpt=&aSwitch[0]; pOptzLong; if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){ if( pMatch ){ - return arErrorMsg("ambiguous option: %s",z); + return arErrorMsg(pAr, "ambiguous option: %s",z); }else{ pMatch = pOpt; } } } if( pMatch==0 ){ - return arErrorMsg("unrecognized option: %s", z); + return arErrorMsg(pAr, "unrecognized option: %s", z); } if( pMatch->bArg ){ if( iArg>=(nArg-1) ){ - return arErrorMsg("option requires an argument: %s", z); + return arErrorMsg(pAr, "option requires an argument: %s", z); } zArg = azArg[++iArg]; } if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR; } @@ -5237,10 +5269,11 @@ utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); } } } shellFinalize(&rc, pSql); + sqlite3_free(zWhere); return rc; } /* @@ -5439,16 +5472,18 @@ /* ** Implementation of ".ar" dot command. */ static int arDotCommand( ShellState *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[] */ ){ ArCommand cmd; int rc; memset(&cmd, 0, sizeof(cmd)); + cmd.fromCmdLine = fromCmdLine; rc = arParseCommand(azArg, nArg, &cmd); if( rc==SQLITE_OK ){ int eDbType = SHELL_OPEN_UNSPEC; cmd.p = pState; cmd.db = pState->db; @@ -5491,11 +5526,11 @@ 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 ){ + if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){ if( cmd.eCmd!=AR_CMD_CREATE && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0) ){ utf8_printf(stderr, "database does not contain an 'sqlar' table\n"); rc = SQLITE_ERROR; @@ -5527,11 +5562,11 @@ break; } } end_ar_command: if( cmd.db!=pState->db ){ - sqlite3_close(cmd.db); + close_db(cmd.db); } sqlite3_free(cmd.zSrcTable); return rc; } @@ -5607,11 +5642,11 @@ #endif #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){ open_db(p, 0); - rc = arDotCommand(p, azArg, nArg); + rc = arDotCommand(p, 0, azArg, nArg); }else #endif if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0) || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0) @@ -5650,18 +5685,18 @@ if( zDb==0 ) zDb = "main"; rc = sqlite3_open_v2(zDestFile, &pDest, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile); - sqlite3_close(pDest); + close_db(pDest); return 1; } open_db(p, 0); pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); if( pBackup==0 ){ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); - sqlite3_close(pDest); + close_db(pDest); return 1; } while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} sqlite3_backup_finish(pBackup); if( rc==SQLITE_DONE ){ @@ -5668,11 +5703,11 @@ rc = 0; }else{ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); rc = 1; } - sqlite3_close(pDest); + close_db(pDest); }else if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){ if( nArg==2 ){ bail_on_error = booleanValue(azArg[1]); @@ -6484,11 +6519,11 @@ char *zNewFilename; /* 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 */ /* Close the existing database */ session_close_all(p); - sqlite3_close(p->db); + close_db(p->db); p->db = 0; p->zDbFilename = 0; sqlite3_free(p->zFreeOnClose); p->zFreeOnClose = 0; p->openMode = SHELL_OPEN_UNSPEC; @@ -6514,11 +6549,11 @@ /* If a filename is specified, try to open it first */ zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0; if( zNewFilename ){ if( newFlag ) shellDeleteFile(zNewFilename); p->zDbFilename = zNewFilename; - open_db(p, 1); + open_db(p, OPEN_DB_KEEPALIVE); if( p->db==0 ){ utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename); sqlite3_free(zNewFilename); }else{ p->zFreeOnClose = zNewFilename; @@ -6664,18 +6699,18 @@ goto meta_command_exit; } rc = sqlite3_open(zSrcFile, &pSrc); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); - sqlite3_close(pSrc); + close_db(pSrc); return 1; } open_db(p, 0); pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); if( pBackup==0 ){ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); - sqlite3_close(pSrc); + close_db(pSrc); return 1; } while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK || rc==SQLITE_BUSY ){ if( rc==SQLITE_BUSY ){ @@ -6691,11 +6726,11 @@ rc = 1; }else{ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; } - sqlite3_close(pSrc); + close_db(pSrc); }else if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ if( nArg==2 ){ p->scanstatsOn = (u8)booleanValue(azArg[1]); @@ -7375,18 +7410,22 @@ int ii; ShellText s; initText(&s); open_db(p, 0); rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); - if( rc ) return shellDatabaseError(p->db); + if( rc ){ + sqlite3_finalize(pStmt); + return shellDatabaseError(p->db); + } if( nArg>2 && c=='i' ){ /* It is an historical accident that the .indexes command shows an error ** when called with the wrong number of arguments whereas the .tables ** command does not. */ raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n"); rc = 1; + sqlite3_finalize(pStmt); goto meta_command_exit; } for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){ const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); if( zDbName==0 ) continue; @@ -8283,10 +8322,14 @@ int warnInmemoryDb = 0; int readStdin = 1; int nCmd = 0; char **azCmd = 0; const char *zVfs = 0; /* Value of -vfs command-line option */ +#if !SQLITE_SHELL_IS_UTF8 + char **argvToFree = 0; + int argcToFree = 0; +#endif setBinaryMode(stdin, 0); setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ stdin_is_interactive = isatty(0); stdout_is_console = isatty(1); @@ -8306,20 +8349,23 @@ ** subsequent sqlite3_config() calls will work. So copy all results into ** memory that does not come from the SQLite memory allocator. */ #if !SQLITE_SHELL_IS_UTF8 sqlite3_initialize(); - argv = malloc(sizeof(argv[0])*argc); + argvToFree = malloc(sizeof(argv[0])*argc*2); + argcToFree = argc; + argv = argvToFree + argc; if( argv==0 ) shell_out_of_memory(); for(i=0; i0 ){ utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands" " with \"%s\"\n", z); return 1; } - open_db(&data, 0); + open_db(&data, OPEN_DB_ZIPFILE); if( z[2] ){ argv[i] = &z[2]; - arDotCommand(&data, argv+(i-1), argc-(i-1)); + arDotCommand(&data, 1, argv+(i-1), argc-(i-1)); }else{ - arDotCommand(&data, argv+i, argc-i); + arDotCommand(&data, 1, argv+i, argc-i); } readStdin = 0; break; #endif }else{ @@ -8721,18 +8767,21 @@ } } set_table_name(&data, 0); if( data.db ){ session_close_all(&data); - sqlite3_close(data.db); + close_db(data.db); } sqlite3_free(data.zFreeOnClose); find_home_dir(1); output_reset(&data); data.doXdgOpen = 0; clearTempFile(&data); #if !SQLITE_SHELL_IS_UTF8 - for(i=0; i9223372036854775807.0 ) return -1; + if( r>=9223372036854775808.0 ) return -1; y = (i64)r; if( iy ){ - if( y==SMALLEST_INT64 && r>0.0 ) return -1; - return +1; - } + if( i>y ) return +1; s = (double)i; if( sr ) return +1; return 0; }