1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-03 16:53:36 +03:00

Merge updates from trunk.

FossilOrigin-Name: acf7684323da4dc3aaf9746bd13b0f56054a17dd
This commit is contained in:
mistachkin
2015-02-27 19:40:08 +00:00
73 changed files with 2322 additions and 1087 deletions

View File

@@ -59,18 +59,38 @@
# include <readline/readline.h>
# include <readline/history.h>
#endif
#if HAVE_EDITLINE
# undef HAVE_READLINE
# define HAVE_READLINE 1
# include <editline/readline.h>
#endif
#if !HAVE_READLINE
# define add_history(X)
# define read_history(X)
# define write_history(X)
# define stifle_history(X)
#if HAVE_EDITLINE || HAVE_READLINE
# define shell_add_history(X) add_history(X)
# define shell_read_history(X) read_history(X)
# define shell_write_history(X) write_history(X)
# define shell_stifle_history(X) stifle_history(X)
# define shell_readline(X) readline(X)
#elif HAVE_LINENOISE
# include "linenoise.h"
# define shell_add_history(X) linenoiseHistoryAdd(X)
# define shell_read_history(X) linenoiseHistoryLoad(X)
# define shell_write_history(X) linenoiseHistorySave(X)
# define shell_stifle_history(X) linenoiseHistorySetMaxLen(X)
# define shell_readline(X) linenoise(X)
#else
# define shell_read_history(X)
# define shell_write_history(X)
# define shell_stifle_history(X)
# define SHELL_USE_LOCAL_GETLINE 1
#endif
#if defined(_WIN32) || defined(WIN32)
# include <io.h>
# include <fcntl.h>
@@ -113,11 +133,11 @@ extern int pclose(FILE*);
** routines take care of that.
*/
#if defined(_WIN32) || defined(WIN32)
static setBinaryMode(FILE *out){
static void setBinaryMode(FILE *out){
fflush(out);
_setmode(_fileno(out), _O_BINARY);
}
static setTextMode(FILE *out){
static void setTextMode(FILE *out){
fflush(out);
_setmode(_fileno(out), _O_TEXT);
}
@@ -451,14 +471,14 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
zResult = local_getline(zPrior, in);
}else{
zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if HAVE_READLINE
free(zPrior);
zResult = readline(zPrompt);
if( zResult && *zResult ) add_history(zResult);
#else
#if SHELL_USE_LOCAL_GETLINE
printf("%s", zPrompt);
fflush(stdout);
zResult = local_getline(zPrior, stdin);
#else
free(zPrior);
zResult = shell_readline(zPrompt);
if( zResult && *zResult ) shell_add_history(zResult);
#endif
}
return zResult;
@@ -1734,6 +1754,7 @@ static char zHelp[] =
".binary on|off Turn binary output on or off. Default OFF\n"
".clone NEWDB Clone data into NEWDB from the existing database\n"
".databases List names and files of attached databases\n"
".dbinfo ?DB? Show status information about the database\n"
".dump ?TABLE? ... Dump the database in an SQL text format\n"
" If TABLE specified, only dump tables matching\n"
" LIKE pattern TABLE.\n"
@@ -1746,8 +1767,8 @@ static char zHelp[] =
".headers on|off Turn display of headers on or off\n"
".help Show this message\n"
".import FILE TABLE Import data from FILE into TABLE\n"
".indices ?TABLE? Show names of all indices\n"
" If TABLE specified, only show indices for tables\n"
".indexes ?TABLE? Show names of all indexes\n"
" If TABLE specified, only show indexes for tables\n"
" matching LIKE pattern TABLE.\n"
#ifdef SQLITE_ENABLE_IOTRACE
".iotrace FILE Enable I/O diagnostic logging to FILE\n"
@@ -2445,6 +2466,115 @@ static void output_reset(ShellState *p){
p->out = stdout;
}
/*
** Run an SQL command and return the single integer result.
*/
static int db_int(ShellState *p, const char *zSql){
sqlite3_stmt *pStmt;
int res = 0;
sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
res = sqlite3_column_int(pStmt,0);
}
sqlite3_finalize(pStmt);
return res;
}
/*
** Convert a 2-byte or 4-byte big-endian integer into a native integer
*/
unsigned int get2byteInt(unsigned char *a){
return (a[0]<<8) + a[1];
}
unsigned int get4byteInt(unsigned char *a){
return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
}
/*
** Implementation of the ".info" command.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
static const struct { const char *zName; int ofst; } aField[] = {
{ "file change counter:", 24 },
{ "database page count:", 28 },
{ "freelist page count:", 36 },
{ "schema cookie:", 40 },
{ "schema format:", 44 },
{ "default cache size:", 48 },
{ "autovacuum top root:", 52 },
{ "incremental vacuum:", 64 },
{ "text encoding:", 56 },
{ "user version:", 60 },
{ "application id:", 68 },
{ "software version:", 96 },
};
static const struct { const char *zName; const char *zSql; } aQuery[] = {
{ "number of tables:",
"SELECT count(*) FROM %s WHERE type='table'" },
{ "number of indexes:",
"SELECT count(*) FROM %s WHERE type='index'" },
{ "number of triggers:",
"SELECT count(*) FROM %s WHERE type='trigger'" },
{ "number of views:",
"SELECT count(*) FROM %s WHERE type='view'" },
{ "schema size:",
"SELECT total(length(sql)) FROM %s" },
};
sqlite3_file *pFile;
int i;
char *zSchemaTab;
char *zDb = nArg>=2 ? azArg[1] : "main";
unsigned char aHdr[100];
open_db(p, 0);
if( p->db==0 ) return 1;
sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
return 1;
}
i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
if( i!=SQLITE_OK ){
fprintf(stderr, "unable to read database header\n");
return 1;
}
i = get2byteInt(aHdr+16);
if( i==1 ) i = 65536;
fprintf(p->out, "%-20s %d\n", "database page size:", i);
fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
for(i=0; i<sizeof(aField)/sizeof(aField[0]); i++){
int ofst = aField[i].ofst;
unsigned int val = get4byteInt(aHdr + ofst);
fprintf(p->out, "%-20s %u", aField[i].zName, val);
switch( ofst ){
case 56: {
if( val==1 ) fprintf(p->out, " (utf8)");
if( val==2 ) fprintf(p->out, " (utf16le)");
if( val==3 ) fprintf(p->out, " (utf16be)");
}
}
fprintf(p->out, "\n");
}
if( zDb==0 ){
zSchemaTab = sqlite3_mprintf("main.sqlite_master");
}else if( strcmp(zDb,"temp")==0 ){
zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
}else{
zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
}
for(i=0; i<sizeof(aQuery)/sizeof(aQuery[0]); i++){
char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
int val = db_int(p, zSql);
sqlite3_free(zSql);
fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
}
sqlite3_free(zSchemaTab);
return 0;
}
/*
** If an input line begins with "." then invoke this routine to
** process that line.
@@ -2600,6 +2730,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
rc = shell_dbinfo_command(p, nArg, azArg);
}else
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
open_db(p, 0);
/* When playing back a "dump", the content might appear in an order
@@ -2939,7 +3073,7 @@ static int do_meta_command(char *zLine, ShellState *p){
fprintf(stderr, "%s:%d: expected %d columns but found %d - "
"filling the rest with NULL\n",
sCtx.zFile, startLine, nCol, i+1);
i++;
i += 2;
while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
}
}
@@ -2968,7 +3102,8 @@ static int do_meta_command(char *zLine, ShellState *p){
if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
}else
if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
if( c=='i' && (strncmp(azArg[0], "indices", n)==0
|| strncmp(azArg[0], "indexes", n)==0) ){
ShellState data;
char *zErrMsg = 0;
open_db(p, 0);
@@ -2998,7 +3133,7 @@ static int do_meta_command(char *zLine, ShellState *p){
);
zShellStatic = 0;
}else{
fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n");
fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
rc = 1;
goto meta_command_exit;
}
@@ -3361,7 +3496,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
extern int sqlite3SelectTrace;
sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
sqlite3SelectTrace = integerValue(azArg[1]);
}else
#endif
@@ -3568,6 +3703,7 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
{ "imposter", SQLITE_TESTCTRL_IMPOSTER },
};
int testctrl = -1;
int rc = 0;
@@ -3660,6 +3796,18 @@ static int do_meta_command(char *zLine, ShellState *p){
break;
#endif
case SQLITE_TESTCTRL_IMPOSTER:
if( nArg==5 ){
rc = sqlite3_test_control(testctrl, p->db,
azArg[2],
integerValue(azArg[3]),
integerValue(azArg[4]));
}else{
fprintf(stderr,"Usage: .testctrl initmode dbName onoff tnum\n");
rc = 1;
}
break;
case SQLITE_TESTCTRL_BITVEC_TEST:
case SQLITE_TESTCTRL_FAULT_INSTALL:
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
@@ -4227,6 +4375,7 @@ int main(int argc, char **argv){
}
#endif
setBinaryMode(stdin);
setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
Argv0 = argv[0];
main_init(&data);
stdin_is_interactive = isatty(0);
@@ -4539,13 +4688,11 @@ int main(int argc, char **argv){
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
}
}
#if HAVE_READLINE
if( zHistory ) read_history(zHistory);
#endif
if( zHistory ) shell_read_history(zHistory);
rc = process_input(&data, 0);
if( zHistory ){
stifle_history(100);
write_history(zHistory);
shell_stifle_history(100);
shell_write_history(zHistory);
free(zHistory);
}
}else{