summaryrefslogtreecommitdiff
path: root/contrib/sqlite3/shell.c
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2020-06-12 13:02:44 +0000
committerCy Schubert <cy@FreeBSD.org>2020-06-12 13:02:44 +0000
commitb622dc25cf3c9940df3e4f7ac9fc961093db6ea8 (patch)
treea6ae9bea740b1d1de6c718964f9d55389586cfbf /contrib/sqlite3/shell.c
parent400c0119a7bd89812281c06f4a0beac163ea8f8a (diff)
parent6ee6343f020017596072c6feb3f62a79a2b5b4cb (diff)
downloadsrc-test2-b622dc25cf3c9940df3e4f7ac9fc961093db6ea8.tar.gz
src-test2-b622dc25cf3c9940df3e4f7ac9fc961093db6ea8.zip
Notes
Diffstat (limited to 'contrib/sqlite3/shell.c')
-rw-r--r--contrib/sqlite3/shell.c670
1 files changed, 519 insertions, 151 deletions
diff --git a/contrib/sqlite3/shell.c b/contrib/sqlite3/shell.c
index 4e3d3979b644..525aca5c2ee2 100644
--- a/contrib/sqlite3/shell.c
+++ b/contrib/sqlite3/shell.c
@@ -36,6 +36,14 @@
#endif
/*
+** Determine if we are dealing with WinRT, which provides only a subset of
+** the full Win32 API.
+*/
+#if !defined(SQLITE_OS_WINRT)
+# define SQLITE_OS_WINRT 0
+#endif
+
+/*
** Warning pragmas copied from msvc.h in the core.
*/
#if defined(_MSC_VER)
@@ -147,22 +155,26 @@ typedef unsigned char u8;
#if defined(_WIN32) || defined(WIN32)
-# include <io.h>
-# include <fcntl.h>
-# define isatty(h) _isatty(h)
-# ifndef access
-# define access(f,m) _access((f),(m))
-# endif
-# ifndef unlink
-# define unlink _unlink
-# endif
-# ifndef strdup
-# define strdup _strdup
+# if SQLITE_OS_WINRT
+# define SQLITE_OMIT_POPEN 1
+# else
+# include <io.h>
+# include <fcntl.h>
+# define isatty(h) _isatty(h)
+# ifndef access
+# define access(f,m) _access((f),(m))
+# endif
+# ifndef unlink
+# define unlink _unlink
+# endif
+# ifndef strdup
+# define strdup _strdup
+# endif
+# undef popen
+# define popen _popen
+# undef pclose
+# define pclose _pclose
# endif
-# undef popen
-# define popen _popen
-# undef pclose
-# define pclose _pclose
#else
/* Make sure isatty() has a prototype. */
extern int isatty(int);
@@ -191,6 +203,9 @@ typedef unsigned char u8;
#define ToLower(X) (char)tolower((unsigned char)X)
#if defined(_WIN32) || defined(WIN32)
+#if SQLITE_OS_WINRT
+#include <intrin.h>
+#endif
#include <windows.h>
/* string conversion routines only needed on Win32 */
@@ -206,7 +221,7 @@ extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
** rendering quoted strings that contain \n characters). The following
** routines take care of that.
*/
-#if defined(_WIN32) || defined(WIN32)
+#if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
static void setBinaryMode(FILE *file, int isOutput){
if( isOutput ) fflush(file);
_setmode(_fileno(file), _O_BINARY);
@@ -310,6 +325,7 @@ static int hasTimer(void){
if( getProcessTimesAddr ){
return 1;
} else {
+#if !SQLITE_OS_WINRT
/* GetProcessTimes() isn't supported in WIN95 and some other Windows
** versions. See if the version we are running on has it, and if it
** does, save off a pointer to it and the current process handle.
@@ -326,6 +342,7 @@ static int hasTimer(void){
FreeLibrary(hinstLib);
}
}
+#endif
}
return 0;
}
@@ -415,6 +432,15 @@ static sqlite3 *globalDb = 0;
*/
static volatile int seenInterrupt = 0;
+#ifdef SQLITE_DEBUG
+/*
+** Out-of-memory simulator variables
+*/
+static unsigned int oomCounter = 0; /* Simulate OOM when equals 1 */
+static unsigned int oomRepeat = 0; /* Number of OOMs in a row */
+static void*(*defaultMalloc)(int) = 0; /* The low-level malloc routine */
+#endif /* SQLITE_DEBUG */
+
/*
** This is the name of our program. It is set in main(), used
** in a number of other places, mostly for error messages.
@@ -466,6 +492,49 @@ static void shell_out_of_memory(void){
exit(1);
}
+#ifdef SQLITE_DEBUG
+/* This routine is called when a simulated OOM occurs. It is broken
+** out as a separate routine to make it easy to set a breakpoint on
+** the OOM
+*/
+void shellOomFault(void){
+ if( oomRepeat>0 ){
+ oomRepeat--;
+ }else{
+ oomCounter--;
+ }
+}
+#endif /* SQLITE_DEBUG */
+
+#ifdef SQLITE_DEBUG
+/* This routine is a replacement malloc() that is used to simulate
+** Out-Of-Memory (OOM) errors for testing purposes.
+*/
+static void *oomMalloc(int nByte){
+ if( oomCounter ){
+ if( oomCounter==1 ){
+ shellOomFault();
+ return 0;
+ }else{
+ oomCounter--;
+ }
+ }
+ return defaultMalloc(nByte);
+}
+#endif /* SQLITE_DEBUG */
+
+#ifdef SQLITE_DEBUG
+/* Register the OOM simulator. This must occur before any memory
+** allocations */
+static void registerOomSimulator(void){
+ sqlite3_mem_methods mem;
+ sqlite3_config(SQLITE_CONFIG_GETMALLOC, &mem);
+ defaultMalloc = mem.xMalloc;
+ mem.xMalloc = oomMalloc;
+ sqlite3_config(SQLITE_CONFIG_MALLOC, &mem);
+}
+#endif
+
/*
** Write I/O traces to the following stream.
*/
@@ -2426,6 +2495,7 @@ static int writeFile(
if( mtime>=0 ){
#if defined(_WIN32)
+#if !SQLITE_OS_WINRT
/* Windows */
FILETIME lastAccess;
FILETIME lastWrite;
@@ -2456,6 +2526,7 @@ static int writeFile(
}else{
return 1;
}
+#endif
#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
/* Recent unix */
struct timespec times[2];
@@ -4213,6 +4284,101 @@ int sqlite3MemTraceDeactivate(void){
}
/************************* End ../ext/misc/memtrace.c ********************/
+/************************* Begin ../ext/misc/uint.c ******************/
+/*
+** 2020-04-14
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This SQLite extension implements the UINT collating sequence.
+**
+** UINT works like BINARY for text, except that embedded strings
+** of digits compare in numeric order.
+**
+** * Leading zeros are handled properly, in the sense that
+** they do not mess of the maginitude comparison of embedded
+** strings of digits. "x00123y" is equal to "x123y".
+**
+** * Only unsigned integers are recognized. Plus and minus
+** signs are ignored. Decimal points and exponential notation
+** are ignored.
+**
+** * Embedded integers can be of arbitrary length. Comparison
+** is *not* limited integers that can be expressed as a
+** 64-bit machine integer.
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+/*
+** Compare text in lexicographic order, except strings of digits
+** compare in numeric order.
+*/
+static int uintCollFunc(
+ void *notUsed,
+ int nKey1, const void *pKey1,
+ int nKey2, const void *pKey2
+){
+ const unsigned char *zA = (const unsigned char*)pKey1;
+ const unsigned char *zB = (const unsigned char*)pKey2;
+ int i=0, j=0, x;
+ (void)notUsed;
+ while( i<nKey1 && j<nKey2 ){
+ x = zA[i] - zB[j];
+ if( isdigit(zA[i]) ){
+ int k;
+ if( !isdigit(zB[j]) ) return x;
+ while( i<nKey1 && zA[i]=='0' ){ i++; }
+ while( j<nKey2 && zB[j]=='0' ){ j++; }
+ k = 0;
+ while( i+k<nKey1 && isdigit(zA[i+k])
+ && j+k<nKey2 && isdigit(zB[j+k]) ){
+ k++;
+ }
+ if( i+k<nKey1 && isdigit(zA[i+k]) ){
+ return +1;
+ }else if( j+k<nKey2 && isdigit(zB[j+k]) ){
+ return -1;
+ }else{
+ x = memcmp(zA+i, zB+j, k);
+ if( x ) return x;
+ i += k;
+ j += k;
+ }
+ }else if( x ){
+ return x;
+ }else{
+ i++;
+ j++;
+ }
+ }
+ return (nKey1 - i) - (nKey2 - j);
+}
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_uint_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ return sqlite3_create_collation(db, "uint", SQLITE_UTF8, 0, uintCollFunc);
+}
+
+/************************* End ../ext/misc/uint.c ********************/
#ifdef SQLITE_HAVE_ZLIB
/************************* Begin ../ext/misc/zipfile.c ******************/
/*
@@ -7834,14 +8000,19 @@ int idxFindIndexes(
/* int iParent = sqlite3_column_int(pExplain, 1); */
/* int iNotUsed = sqlite3_column_int(pExplain, 2); */
const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3);
- int nDetail = STRLEN(zDetail);
+ int nDetail;
int i;
+ if( !zDetail ) continue;
+ nDetail = STRLEN(zDetail);
+
for(i=0; i<nDetail; i++){
const char *zIdx = 0;
- if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
+ if( i+13<nDetail && memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
zIdx = &zDetail[i+13];
- }else if( memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0 ){
+ }else if( i+22<nDetail
+ && memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0
+ ){
zIdx = &zDetail[i+22];
}
if( zIdx ){
@@ -8656,7 +8827,7 @@ void sqlite3_expert_destroy(sqlite3expert *p){
}
}
-#endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
/************************* End ../ext/expert/sqlite3expert.c ********************/
@@ -9602,6 +9773,7 @@ struct ShellState {
unsigned mxProgress; /* Maximum progress callbacks before failing */
unsigned flgProgress; /* Flags for the progress callback */
unsigned shellFlgs; /* Various flags */
+ unsigned priorShFlgs; /* Saved copy of flags */
sqlite3_int64 szMax; /* --maxsize argument to .open */
char *zDestTable; /* Name of destination table when MODE_Insert */
char *zTempFile; /* Temporary file that might need deleting */
@@ -9902,11 +10074,13 @@ edit_func_end:
*/
static void outputModePush(ShellState *p){
p->modePrior = p->mode;
+ p->priorShFlgs = p->shellFlgs;
memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
}
static void outputModePop(ShellState *p){
p->mode = p->modePrior;
+ p->shellFlgs = p->priorShFlgs;
memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
}
@@ -10871,8 +11045,7 @@ static void set_table_name(ShellState *p, const char *zName){
*/
static int run_table_dump_query(
ShellState *p, /* Query context */
- const char *zSelect, /* SELECT statement to extract content */
- const char *zFirstRow /* Print before first row, if not NULL */
+ const char *zSelect /* SELECT statement to extract content */
){
sqlite3_stmt *pSelect;
int rc;
@@ -10889,10 +11062,6 @@ static int run_table_dump_query(
rc = sqlite3_step(pSelect);
nResult = sqlite3_column_count(pSelect);
while( rc==SQLITE_ROW ){
- if( zFirstRow ){
- utf8_printf(p->out, "%s", zFirstRow);
- zFirstRow = 0;
- }
z = (const char*)sqlite3_column_text(pSelect, 0);
utf8_printf(p->out, "%s", z);
for(i=1; i<nResult; i++){
@@ -11349,9 +11518,9 @@ static void bind_table_init(ShellState *p){
** CREATE TEMP TABLE sqlite_parameters(key TEXT PRIMARY KEY, value)
** WITHOUT ROWID;
**
-** No bindings occur if this table does not exist. The special character '$'
-** is included in the table name to help prevent collisions with actual tables.
-** The table must be in the TEMP schema.
+** No bindings occur if this table does not exist. The name of the table
+** begins with "sqlite_" so that it will not collide with ordinary application
+** tables. The table must be in the TEMP schema.
*/
static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
int nVar;
@@ -11655,6 +11824,7 @@ static int shell_exec(
const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3);
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);
}
@@ -12065,11 +12235,12 @@ static const char *(azHelp[]) = {
".databases List names and files of attached databases",
".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
".dbinfo ?DB? Show status information about the database",
- ".dump ?TABLE? ... Render all database content as SQL",
+ ".dump ?TABLE? Render database content as SQL",
" Options:",
" --preserve-rowids Include ROWID values in the output",
" --newlines Allow unescaped newline characters in output",
" TABLE is a LIKE pattern for the tables to dump",
+ " Additional LIKE patterns can be given in subsequent arguments",
".echo on|off Turn command echo on or off",
".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN",
" Other Modes:",
@@ -12079,15 +12250,29 @@ static const char *(azHelp[]) = {
#endif
" trigger Like \"full\" but also show trigger bytecode",
".excel Display the output of next command in spreadsheet",
+ " --bom Put a UTF8 byte-order mark on intermediate file",
".exit ?CODE? Exit this program with return-code CODE",
".expert EXPERIMENTAL. Suggest indexes for queries",
".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto",
".filectrl CMD ... Run various sqlite3_file_control() operations",
- " Run \".filectrl\" with no arguments for details",
+ " --schema SCHEMA Use SCHEMA instead of \"main\"",
+ " --help Show CMD details",
".fullschema ?--indent? Show schema and the content of sqlite_stat tables",
".headers on|off Turn display of headers on or off",
".help ?-all? ?PATTERN? Show help text for PATTERN",
".import FILE TABLE Import data from FILE into TABLE",
+ " Options:",
+ " --ascii Use \\037 and \\036 as column and row separators",
+ " --csv Use , and \\n as column and row separators",
+ " --skip N Skip the first N rows of input",
+ " -v \"Verbose\" - increase auxiliary output",
+ " Notes:",
+ " * If TABLE does not exist, it is created. The first row of input",
+ " determines the column names.",
+ " * If neither --csv or --ascii are used, the input mode is derived",
+ " from the \".mode\" output mode",
+ " * If FILE begins with \"|\" then it is a command that generates the",
+ " input text.",
#ifndef SQLITE_OMIT_TEST_CONTROL
".imposter INDEX TABLE Create imposter table TABLE on index INDEX",
#endif
@@ -12118,11 +12303,14 @@ static const char *(azHelp[]) = {
" tabs Tab-separated values",
" tcl TCL list elements",
".nullvalue STRING Use STRING in place of NULL values",
- ".once (-e|-x|FILE) Output for the next SQL command only to FILE",
+ ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
" If FILE begins with '|' then open as a pipe",
- " Other options:",
- " -e Invoke system text editor",
- " -x Open in a spreadsheet",
+ " --bom Put a UTF8 byte-order mark at the beginning",
+ " -e Send output to the system text editor",
+ " -x Send output as CSV to a spreadsheet (same as \".excel\")",
+#ifdef SQLITE_DEBUG
+ ".oom [--repeat M] [N] Simulate an OOM error on the N-th allocation",
+#endif
".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
" Options:",
" --append Use appendvfs to append database to the end of FILE",
@@ -12136,7 +12324,11 @@ static const char *(azHelp[]) = {
" --readonly Open FILE readonly",
" --zip FILE is a ZIP archive",
".output ?FILE? Send output to FILE or stdout if FILE is omitted",
- " If FILE begins with '|' then open it as a pipe.",
+ " If FILE begins with '|' then open it as a pipe.",
+ " Options:",
+ " --bom Prefix output with a UTF8 byte-order mark",
+ " -e Send output to the system text editor",
+ " -x Send output as CSV to a spreadsheet",
".parameter CMD ... Manage SQL parameter bindings",
" clear Erase all bindings",
" init Initialize the TEMP table that holds bindings",
@@ -12256,6 +12448,7 @@ static int showHelp(FILE *out, const char *zPattern){
|| zPattern[0]=='0'
|| strcmp(zPattern,"-a")==0
|| strcmp(zPattern,"-all")==0
+ || strcmp(zPattern,"--all")==0
){
/* Show all commands, but only one line per command */
if( zPattern==0 ) zPattern = "";
@@ -12737,6 +12930,7 @@ static void open_db(ShellState *p, int openFlags){
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);
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
sqlite3_dbdata_init(p->db, 0, 0);
#endif
@@ -13073,6 +13267,8 @@ struct ImportCtx {
int n; /* Number of bytes in z */
int nAlloc; /* Space allocated for z[] */
int nLine; /* Current line number */
+ int nRow; /* Number of rows imported */
+ int nErr; /* Number of errors encountered */
int bNotFirst; /* True if one or more bytes already read */
int cTerm; /* Character that terminated the most recent field */
int cColSep; /* The column separator character. (Usually ",") */
@@ -13454,11 +13650,15 @@ static void output_reset(ShellState *p){
zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
if( system(zCmd) ){
utf8_printf(stderr, "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 */
+ sqlite3_sleep(2000);
}
sqlite3_free(zCmd);
outputModePop(p);
p->doXdgOpen = 0;
- sqlite3_sleep(100);
}
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
}
@@ -13534,12 +13734,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
-1, &pStmt, 0);
if( rc ){
- if( !sqlite3_compileoption_used("ENABLE_DBPAGE_VTAB") ){
- utf8_printf(stderr, "the \".dbinfo\" command requires the "
- "-DSQLITE_ENABLE_DBPAGE_VTAB compile-time options\n");
- }else{
- utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db));
- }
+ utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db));
sqlite3_finalize(pStmt);
return 1;
}
@@ -13748,9 +13943,21 @@ static void newTempFile(ShellState *p, const char *zSuffix){
sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
}
if( p->zTempFile==0 ){
+ /* If p->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;
sqlite3_randomness(sizeof(r), &r);
- p->zTempFile = sqlite3_mprintf("temp%llx.%s", r, zSuffix);
+ zTemp = getenv("TEMP");
+ if( zTemp==0 ) zTemp = getenv("TMP");
+ if( zTemp==0 ){
+#ifdef _WIN32
+ zTemp = "\\tmp";
+#else
+ zTemp = "/tmp";
+#endif
+ }
+ p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
}else{
p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
}
@@ -15774,7 +15981,8 @@ static int do_meta_command(char *zLine, ShellState *p){
#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
- const char *zLike = 0;
+ char *zLike = 0;
+ char *zSql;
int i;
int savedShowHeader = p->showHeader;
int savedShellFlags = p->shellFlgs;
@@ -15802,12 +16010,10 @@ static int do_meta_command(char *zLine, ShellState *p){
goto meta_command_exit;
}
}else if( zLike ){
- raw_printf(stderr, "Usage: .dump ?--preserve-rowids? "
- "?--newlines? ?LIKE-PATTERN?\n");
- rc = 1;
- goto meta_command_exit;
+ zLike = sqlite3_mprintf("%z OR name LIKE %Q ESCAPE '\\'",
+ zLike, azArg[i]);
}else{
- zLike = azArg[i];
+ zLike = sqlite3_mprintf("name LIKE %Q ESCAPE '\\'", azArg[i]);
}
}
@@ -15825,35 +16031,25 @@ static int do_meta_command(char *zLine, ShellState *p){
** corrupt. */
sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
p->nErr = 0;
- if( zLike==0 ){
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
- );
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE name=='sqlite_sequence'"
- );
- run_table_dump_query(p,
- "SELECT sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
- );
- }else{
- char *zSql;
- zSql = sqlite3_mprintf(
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE tbl_name LIKE %Q AND type=='table'"
- " AND sql NOT NULL", zLike);
- run_schema_dump_query(p,zSql);
- sqlite3_free(zSql);
- zSql = sqlite3_mprintf(
- "SELECT sql FROM sqlite_master "
- "WHERE sql NOT NULL"
- " AND type IN ('index','trigger','view')"
- " AND tbl_name LIKE %Q", zLike);
- run_table_dump_query(p, zSql, 0);
- sqlite3_free(zSql);
- }
+ if( zLike==0 ) zLike = sqlite3_mprintf("true");
+ zSql = sqlite3_mprintf(
+ "SELECT name, type, sql FROM sqlite_master "
+ "WHERE (%s) AND type=='table'"
+ " AND sql NOT NULL"
+ " ORDER BY tbl_name='sqlite_sequence', rowid",
+ zLike
+ );
+ run_schema_dump_query(p,zSql);
+ sqlite3_free(zSql);
+ zSql = sqlite3_mprintf(
+ "SELECT sql FROM sqlite_master "
+ "WHERE (%s) AND sql NOT NULL"
+ " AND type IN ('index','trigger','view')",
+ zLike
+ );
+ run_table_dump_query(p, zSql);
+ sqlite3_free(zSql);
+ sqlite3_free(zLike);
if( p->writableSchema ){
raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
p->writableSchema = 0;
@@ -15956,6 +16152,7 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" },
{ "has_moved", SQLITE_FCNTL_HAS_MOVED, "" },
{ "lock_timeout", SQLITE_FCNTL_LOCK_TIMEOUT, "MILLISEC" },
+ { "reserve_bytes", SQLITE_FCNTL_RESERVE_BYTES, "[N]" },
};
int filectrl = -1;
int iCtrl = -1;
@@ -15963,10 +16160,21 @@ static int do_meta_command(char *zLine, ShellState *p){
int isOk = 0; /* 0: usage 1: %lld 2: no-result */
int n2, i;
const char *zCmd = 0;
+ const char *zSchema = 0;
open_db(p, 0);
zCmd = nArg>=2 ? azArg[1] : "help";
+ if( zCmd[0]=='-'
+ && (strcmp(zCmd,"--schema")==0 || strcmp(zCmd,"-schema")==0)
+ && nArg>=4
+ ){
+ zSchema = azArg[2];
+ for(i=3; i<nArg; i++) azArg[i-2] = azArg[i];
+ nArg -= 2;
+ zCmd = azArg[1];
+ }
+
/* The argument can optionally begin with "-" or "--" */
if( zCmd[0]=='-' && zCmd[1] ){
zCmd++;
@@ -16008,7 +16216,7 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_FCNTL_SIZE_LIMIT: {
if( nArg!=2 && nArg!=3 ) break;
iRes = nArg==3 ? integerValue(azArg[2]) : -1;
- sqlite3_file_control(p->db, 0, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
+ sqlite3_file_control(p->db, zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
isOk = 1;
break;
}
@@ -16017,7 +16225,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int x;
if( nArg!=3 ) break;
x = (int)integerValue(azArg[2]);
- sqlite3_file_control(p->db, 0, filectrl, &x);
+ sqlite3_file_control(p->db, zSchema, filectrl, &x);
isOk = 2;
break;
}
@@ -16026,7 +16234,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int x;
if( nArg!=2 && nArg!=3 ) break;
x = nArg==3 ? booleanValue(azArg[2]) : -1;
- sqlite3_file_control(p->db, 0, filectrl, &x);
+ sqlite3_file_control(p->db, zSchema, filectrl, &x);
iRes = x;
isOk = 1;
break;
@@ -16034,7 +16242,7 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_FCNTL_HAS_MOVED: {
int x;
if( nArg!=2 ) break;
- sqlite3_file_control(p->db, 0, filectrl, &x);
+ sqlite3_file_control(p->db, zSchema, filectrl, &x);
iRes = x;
isOk = 1;
break;
@@ -16042,7 +16250,7 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_FCNTL_TEMPFILENAME: {
char *z = 0;
if( nArg!=2 ) break;
- sqlite3_file_control(p->db, 0, filectrl, &z);
+ sqlite3_file_control(p->db, zSchema, filectrl, &z);
if( z ){
utf8_printf(p->out, "%s\n", z);
sqlite3_free(z);
@@ -16050,6 +16258,18 @@ static int do_meta_command(char *zLine, ShellState *p){
isOk = 2;
break;
}
+ case SQLITE_FCNTL_RESERVE_BYTES: {
+ int x;
+ if( nArg>=3 ){
+ x = atoi(azArg[2]);
+ sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ }
+ x = -1;
+ sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ utf8_printf(p->out,"%d\n", x);
+ isOk = 2;
+ break;
+ }
}
}
if( isOk==0 && iCtrl>=0 ){
@@ -16133,8 +16353,8 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
- char *zTable; /* Insert data into this table */
- char *zFile; /* Name of file to extra content from */
+ char *zTable = 0; /* Insert data into this table */
+ char *zFile = 0; /* Name of file to extra content from */
sqlite3_stmt *pStmt = NULL; /* A statement */
int nCol; /* Number of columns in the table */
int nByte; /* Number of bytes in an SQL string */
@@ -16145,51 +16365,108 @@ static int do_meta_command(char *zLine, ShellState *p){
ImportCtx sCtx; /* Reader context */
char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */
+ int eVerbose = 0; /* Larger for more console output */
+ int nSkip = 0; /* Initial lines to skip */
+ int useOutputMode = 1; /* Use output mode to determine separators */
- if( nArg!=3 ){
- raw_printf(stderr, "Usage: .import FILE TABLE\n");
- goto meta_command_exit;
- }
- zFile = azArg[1];
- zTable = azArg[2];
- seenInterrupt = 0;
memset(&sCtx, 0, sizeof(sCtx));
- open_db(p, 0);
- nSep = strlen30(p->colSeparator);
- if( nSep==0 ){
- raw_printf(stderr,
- "Error: non-null column separator required for import\n");
- return 1;
+ if( p->mode==MODE_Ascii ){
+ xRead = ascii_read_one_field;
+ }else{
+ xRead = csv_read_one_field;
}
- if( nSep>1 ){
- raw_printf(stderr, "Error: multi-character column separators not allowed"
- " for import\n");
- return 1;
+ for(i=1; i<nArg; i++){
+ char *z = azArg[i];
+ if( z[0]=='-' && z[1]=='-' ) z++;
+ if( z[0]!='-' ){
+ if( zFile==0 ){
+ zFile = z;
+ }else if( zTable==0 ){
+ zTable = z;
+ }else{
+ utf8_printf(p->out, "ERROR: extra argument: \"%s\". Usage:\n", z);
+ showHelp(p->out, "import");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }else if( strcmp(z,"-v")==0 ){
+ eVerbose++;
+ }else if( strcmp(z,"-skip")==0 && i<nArg-1 ){
+ nSkip = integerValue(azArg[++i]);
+ }else if( strcmp(z,"-ascii")==0 ){
+ sCtx.cColSep = SEP_Unit[0];
+ sCtx.cRowSep = SEP_Record[0];
+ xRead = ascii_read_one_field;
+ useOutputMode = 0;
+ }else if( strcmp(z,"-csv")==0 ){
+ sCtx.cColSep = ',';
+ sCtx.cRowSep = '\n';
+ xRead = csv_read_one_field;
+ useOutputMode = 0;
+ }else{
+ utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z);
+ showHelp(p->out, "import");
+ rc = 1;
+ goto meta_command_exit;
+ }
}
- nSep = strlen30(p->rowSeparator);
- if( nSep==0 ){
- raw_printf(stderr, "Error: non-null row separator required for import\n");
- return 1;
+ if( zTable==0 ){
+ utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n",
+ zFile==0 ? "FILE" : "TABLE");
+ showHelp(p->out, "import");
+ rc = 1;
+ goto meta_command_exit;
}
- if( nSep==2 && p->mode==MODE_Csv && strcmp(p->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);
+ seenInterrupt = 0;
+ open_db(p, 0);
+ if( useOutputMode ){
+ /* 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);
+ if( nSep==0 ){
+ raw_printf(stderr,
+ "Error: non-null column separator required for import\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( nSep>1 ){
+ raw_printf(stderr,
+ "Error: multi-character column separators not allowed"
+ " for import\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
nSep = strlen30(p->rowSeparator);
- }
- if( nSep>1 ){
- raw_printf(stderr, "Error: multi-character row separators not allowed"
- " for import\n");
- return 1;
+ if( nSep==0 ){
+ raw_printf(stderr,
+ "Error: non-null row separator required for import\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( nSep==2 && p->mode==MODE_Csv && strcmp(p->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);
+ }
+ if( nSep>1 ){
+ raw_printf(stderr, "Error: multi-character row separators not allowed"
+ " for import\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ sCtx.cColSep = p->colSeparator[0];
+ sCtx.cRowSep = p->rowSeparator[0];
}
sCtx.zFile = zFile;
sCtx.nLine = 1;
if( sCtx.zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
raw_printf(stderr, "Error: pipes are not supported in this OS\n");
- return 1;
+ rc = 1;
+ goto meta_command_exit;
#else
sCtx.in = popen(sCtx.zFile+1, "r");
sCtx.zFile = "<pipe>";
@@ -16199,17 +16476,26 @@ static int do_meta_command(char *zLine, ShellState *p){
sCtx.in = fopen(sCtx.zFile, "rb");
xCloser = fclose;
}
- if( p->mode==MODE_Ascii ){
- xRead = ascii_read_one_field;
- }else{
- xRead = csv_read_one_field;
- }
if( sCtx.in==0 ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
- return 1;
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
+ 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 ");
+ zSep[0] = sCtx.cRowSep;
+ output_c_string(p->out, zSep);
+ utf8_printf(p->out, "\n");
+ }
+ while( (nSkip--)>0 ){
+ while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
+ sCtx.nLine++;
}
- sCtx.cColSep = p->colSeparator[0];
- sCtx.cRowSep = p->rowSeparator[0];
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
if( zSql==0 ){
xCloser(sCtx.in);
@@ -16231,9 +16517,13 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(sCtx.z);
xCloser(sCtx.in);
utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
- return 1;
+ rc = 1;
+ goto meta_command_exit;
}
zCreate = sqlite3_mprintf("%z\n)", zCreate);
+ if( eVerbose>=1 ){
+ utf8_printf(p->out, "%s\n", zCreate);
+ }
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
sqlite3_free(zCreate);
if( rc ){
@@ -16241,7 +16531,8 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_errmsg(p->db));
sqlite3_free(sCtx.z);
xCloser(sCtx.in);
- return 1;
+ rc = 1;
+ goto meta_command_exit;
}
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
}
@@ -16250,7 +16541,8 @@ static int do_meta_command(char *zLine, ShellState *p){
if (pStmt) sqlite3_finalize(pStmt);
utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
xCloser(sCtx.in);
- return 1;
+ rc = 1;
+ goto meta_command_exit;
}
nCol = sqlite3_column_count(pStmt);
sqlite3_finalize(pStmt);
@@ -16269,13 +16561,17 @@ static int do_meta_command(char *zLine, ShellState *p){
}
zSql[j++] = ')';
zSql[j] = 0;
+ if( eVerbose>=2 ){
+ utf8_printf(p->out, "Insert using: %s\n", zSql);
+ }
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
if (pStmt) sqlite3_finalize(pStmt);
xCloser(sCtx.in);
- return 1;
+ rc = 1;
+ goto meta_command_exit;
}
needCommit = sqlite3_get_autocommit(p->db);
if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
@@ -16318,6 +16614,9 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc!=SQLITE_OK ){
utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
startLine, sqlite3_errmsg(p->db));
+ sCtx.nErr++;
+ }else{
+ sCtx.nRow++;
}
}
}while( sCtx.cTerm!=EOF );
@@ -16326,6 +16625,11 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(sCtx.z);
sqlite3_finalize(pStmt);
if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
+ if( eVerbose>0 ){
+ utf8_printf(p->out,
+ "Added %d rows with %d errors using %d lines of input\n",
+ sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
+ }
}else
#ifndef SQLITE_UNTESTABLE
@@ -16604,6 +16908,34 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+#ifdef SQLITE_DEBUG
+ if( c=='o' && strcmp(azArg[0],"oom")==0 ){
+ int i;
+ for(i=1; i<nArg; i++){
+ const char *z = azArg[i];
+ if( z[0]=='-' && z[1]=='-' ) z++;
+ if( strcmp(z,"-repeat")==0 ){
+ if( i==nArg-1 ){
+ raw_printf(p->out, "missing argument on \"%s\"\n", azArg[i]);
+ rc = 1;
+ }else{
+ oomRepeat = (int)integerValue(azArg[++i]);
+ }
+ }else if( IsDigit(z[0]) ){
+ oomCounter = (int)integerValue(azArg[i]);
+ }else{
+ raw_printf(p->out, "unknown argument: \"%s\"\n", azArg[i]);
+ raw_printf(p->out, "Usage: .oom [--repeat N] [M]\n");
+ rc = 1;
+ }
+ }
+ if( rc==0 ){
+ raw_printf(p->out, "oomCounter = %d\n", oomCounter);
+ raw_printf(p->out, "oomRepeat = %d\n", oomRepeat);
+ }
+ }else
+#endif /* SQLITE_DEBUG */
+
if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
char *zNewFilename; /* Name of the database file to open */
int iName = 1; /* Index in azArg[] of the filename */
@@ -16671,42 +17003,66 @@ static int do_meta_command(char *zLine, ShellState *p){
&& (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
|| (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
){
- const char *zFile = nArg>=2 ? azArg[1] : "stdout";
+ const char *zFile = 0;
int bTxtMode = 0;
- if( azArg[0][0]=='e' ){
- /* Transform the ".excel" command into ".once -x" */
- nArg = 2;
- azArg[0] = "once";
- zFile = azArg[1] = "-x";
- n = 4;
- }
- if( nArg>2 ){
- utf8_printf(stderr, "Usage: .%s [-e|-x|FILE]\n", azArg[0]);
- rc = 1;
- goto meta_command_exit;
+ int i;
+ int eMode = 0;
+ int bBOM = 0;
+ int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
+
+ if( c=='e' ){
+ eMode = 'x';
+ bOnce = 2;
+ }else if( strncmp(azArg[0],"once",n)==0 ){
+ bOnce = 1;
}
- if( n>1 && strncmp(azArg[0], "once", n)==0 ){
- if( nArg<2 ){
- raw_printf(stderr, "Usage: .once (-e|-x|FILE)\n");
+ for(i=1; i<nArg; i++){
+ char *z = azArg[i];
+ if( z[0]=='-' ){
+ if( z[1]=='-' ) z++;
+ if( strcmp(z,"-bom")==0 ){
+ bBOM = 1;
+ }else if( c!='e' && strcmp(z,"-x")==0 ){
+ eMode = 'x'; /* spreadsheet */
+ }else if( c!='e' && strcmp(z,"-e")==0 ){
+ eMode = 'e'; /* text editor */
+ }else{
+ utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n",
+ azArg[i]);
+ showHelp(p->out, azArg[0]);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }else if( zFile==0 ){
+ zFile = z;
+ }else{
+ utf8_printf(p->out,"ERROR: extra parameter: \"%s\". Usage:\n",
+ azArg[i]);
+ showHelp(p->out, azArg[0]);
rc = 1;
goto meta_command_exit;
}
+ }
+ if( zFile==0 ) zFile = "stdout";
+ if( bOnce ){
p->outCount = 2;
}else{
p->outCount = 0;
}
output_reset(p);
- if( zFile[0]=='-' && zFile[1]=='-' ) zFile++;
#ifndef SQLITE_NOHAVE_SYSTEM
- if( strcmp(zFile, "-e")==0 || strcmp(zFile, "-x")==0 ){
+ if( eMode=='e' || eMode=='x' ){
p->doXdgOpen = 1;
outputModePush(p);
- if( zFile[1]=='x' ){
+ 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);
}else{
+ /* text editor mode */
newTempFile(p, "txt");
bTxtMode = 1;
}
@@ -16725,6 +17081,7 @@ static int do_meta_command(char *zLine, ShellState *p){
p->out = stdout;
rc = 1;
}else{
+ if( bBOM ) fprintf(p->out,"\357\273\277");
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
#endif
@@ -16737,6 +17094,7 @@ static int do_meta_command(char *zLine, ShellState *p){
p->out = stdout;
rc = 1;
} else {
+ if( bBOM ) fprintf(p->out,"\357\273\277");
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
}
@@ -17800,7 +18158,6 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" },
{ "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, "" },
{ "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, "SEED ?db?" },
- { "reserve", SQLITE_TESTCTRL_RESERVE, "BYTES-OF-RESERVE"},
};
int testctrl = -1;
int iCtrl = -1;
@@ -17853,7 +18210,6 @@ static int do_meta_command(char *zLine, ShellState *p){
/* sqlite3_test_control(int, db, int) */
case SQLITE_TESTCTRL_OPTIMIZATIONS:
- case SQLITE_TESTCTRL_RESERVE:
if( nArg==3 ){
int opt = (int)strtol(azArg[2], 0, 0);
rc2 = sqlite3_test_control(testctrl, p->db, opt);
@@ -18625,14 +18981,18 @@ static void main_init(ShellState *data) {
*/
#ifdef _WIN32
static void printBold(const char *zText){
+#if !SQLITE_OS_WINRT
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
SetConsoleTextAttribute(out,
FOREGROUND_RED|FOREGROUND_INTENSITY
);
+#endif
printf("%s", zText);
+#if !SQLITE_OS_WINRT
SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
+#endif
}
#else
static void printBold(const char *zText){
@@ -18687,6 +19047,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
stdin_is_interactive = isatty(0);
stdout_is_console = isatty(1);
+#ifdef SQLITE_DEBUG
+ registerOomSimulator();
+#endif
+
#if !defined(_WIN32_WCE)
if( getenv("SQLITE_DEBUG_BREAK") ){
if( isatty(0) && isatty(2) ){
@@ -18696,7 +19060,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
fgetc(stdin);
}else{
#if defined(_WIN32) || defined(WIN32)
+#if SQLITE_OS_WINRT
+ __debugbreak();
+#else
DebugBreak();
+#endif
#elif defined(SIGTRAP)
raise(SIGTRAP);
#endif