From: drh <> Date: Fri, 27 Mar 2026 13:13:32 +0000 (+0000) Subject: Merge the latest trunk enhancments into the reuse-schema branch. X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=59b13ce421d8a87deadcaf6ba11bfa203caa9035;p=thirdparty%2Fsqlite.git Merge the latest trunk enhancments into the reuse-schema branch. FossilOrigin-Name: 337a9f3f4724f5f46ca5cd000a3742f5f3c9682f23f9f9fcdd6aa42f1501b3d3 --- 59b13ce421d8a87deadcaf6ba11bfa203caa9035 diff --cc manifest index 8f778ae44a,0a15ae3ac3..c17e532796 --- a/manifest +++ b/manifest @@@ -1,5 -1,5 +1,5 @@@ - C Merge\sall\sthe\slatest\strunk\senhancements\sinto\sthe\sreuse-schema\sbranch - D 2026-03-21T18:42:16.487 -C Add\sa\scomment\sshowing\sreserved\sfile-control\snumbers\sto\ssqlite3.h -D 2026-03-27T11:46:11.333 ++C Merge\sthe\slatest\strunk\senhancments\sinto\sthe\sreuse-schema\sbranch. ++D 2026-03-27T13:13:32.943 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@@ -697,10 -694,10 +697,10 @@@ F src/hash.h 46b92795a95bfefb210f52f0c3 F src/hwtime.h 21c2cf1f736e7b97502c3674d0c386db3f06870d6f10d0cf8174e2a4b8cb726e F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd - F src/json.c 7401618493219bb605408be48d2ea5ed5c9055f1c3b733268331eb0174048746 + F src/json.c 5027b856cd9b621dc9ba66b211e21a440ccdc63cefdefb44c51e7d3ac550d1a4 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 56a542244fbefc739a2ef57fac007c16b2aefdb4377f584e9547db2ce3e071f9 - F src/main.c b66ee684a0cf1e0f3f1e8735f6f4de525ad624c1981fbfc4bee2aeca920e07eb -F src/main.c 387bb9d0216d6d35b221481ba8e661d94ad043060cd89581b6422c269ce680a0 ++F src/main.c 2b8335837a1c778f4976a3b3242f74205bdda0b5100c43b6a882fd3b147dd85e F src/malloc.c 422f7e0498e1c9ef967f06283b6f2c0b16db6b905d8e06f6dbc8baaa3e4e6c5a F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2 @@@ -730,22 -727,22 +730,22 @@@ F src/parse.y 3b784d6083380a950e3b1b32c F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484 F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd -F src/pragma.c 789ef67117b74b5be0a2db6681f7f0c55e6913791b9da309aefd280de2c8a74d -F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d +F src/pragma.c 16bfe475bb6bcc14eb9dbb2847fec6383fb7361fc4cd23b390e3e10daf089bd7 +F src/prepare.c 40312476d751aa775fc7de9620c3b6fe42b268f3f49f832eb8c27588a7dd9cbe - F src/printf.c 9cff219dba73b1aa9a8113e83e962f03f7bea8b6eb51cefb25bc468d5a69fb2d + F src/printf.c a440c004a3892cc3d334fa90e0ae59720918fe26c16942d4d45e2534640ce786 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576 - F src/shell.c.in 6702a4092c573e69b1496a380b1fb50be0b37409d66c8a10d616c0ef92cbd97f - F src/sqlite.h.in 924eeda59f2ae7693fa761471844787fe7330f922c1e1b63f3b9c83199884e87 -F src/shell.c.in 91ee40ec3f75192362cbaa0ad85316140b8dde00a184113d73a837fb6173dbcc -F src/sqlite.h.in e7acbb01518f05c5a342149ec1eeb1afcdccf9b90a6e9770a4893ae9a3c756ae ++F src/shell.c.in 5df627411c239325de5a08410859c90eb18a3cf21516a169a6652f8a8ad8241e ++F src/sqlite.h.in caaacf199e9e7df2e1ff4eba893d7f23a76e9487e9d6e9805c3ca125deff8416 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h 9716721fb57e32938a1d30a84560ce7633c63860a2209e188c87afad15d4b464 +F src/sqliteInt.h 0836d90234eb4e3131ea2d3b54184620a6bfcc44e7600362505a58e944ed5cad - F src/sqliteLimit.h 904a3f520362c7065c18165aaabd504fb13cc1b76cb411f38bd41ac219e4af1e + F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092 -F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 +F src/status.c 426bbfac49c3501675d3c2db63834a29d78e14587695e81327f86689d7eb1593 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 - F src/tclsqlite.c 3d9855481d3169acc9030975ef5aed233effcef6043d68963820c18cc40900f2 -F src/tclsqlite.c 7401c73c917a4d1b380c896a324c8d8eb533a999559d9e339d479596553bebfd ++F src/tclsqlite.c 2a8c7f54fc667a4d4aa71c93bf547b7ca05d33bd3f96394ec80462c25a7bb1ed F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a F src/test1.c 3e3b013f59ffcb57dce00c90d55907072d71d4e970cb0a590cb261efe11bae9c F src/test2.c 2b9ab96bba63a1c369d5769390475259ad210f144a877805f2e32e563f9e93c1 @@@ -802,15 -798,15 +802,15 @@@ F src/trigger.c 5497958d682b6269924b19c F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 - F src/util.c 51662502243422f3238a7220fe00de32d9a7d0d3149dd33c6d721d7039cb2e74 + F src/util.c c24ed5647e81eea3abe3d9878b709425a3e843cbf4580ac442ed46b93824138c -F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 -F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3 -F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71 +F src/vacuum.c 13b7c418199d6344e341eb6ae3759b7886f925c0f5920d30925dbe45fc933fbd - F src/vdbe.c 2f981ecab2985a3427966395cc8628256015ec2ef2f9b994edec17eff4afd13e ++F src/vdbe.c 3c797690341d92a6330088fa2212f8dd3c2329ceadc46ad0b36e6fcca4c853bf +F src/vdbe.h e085d965c37e722b60303ec9345f42bd14a89e0c5ae9760ce648f24d6848fd86 F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1 F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1 -F src/vdbeaux.c 81687c55682b9f4d942186695f4f7fa4743c564a985e0889def52eded9076d61 -F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692 +F src/vdbeaux.c fa683c4bdfa13c7b8f03b76698cce403589000d81114f1a0e77d6f7946f6bb48 +F src/vdbeblob.c ad7e1db18b53074702ce267f48106c12fb1ac76b54b6eb3aefa4188411eb7c46 - F src/vdbemem.c 05610ea8423c4c852a9039e47fb6a2706d4d848758602ebf30da6c3212344695 + F src/vdbemem.c 5af6cf1253ac2aed0612b85138a1faf43f30ad38777d554db6c85b7281fa79fb F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70 F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41 F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 @@@ -2209,8 -2195,8 +2209,8 @@@ F tool/warnings-clang.sh bbf6a1e685e534 F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c - P c35597d4db59385e973c8f555f2b5016147a9f767829583e1d3c08ccd740a035 8e1d0c4eac303cd0834449f4792605c0ed983db1f360af42300f0048dadbbef8 - R 5d4905f7dd58ea224aeb6b3b1ab8915b -P c5af6a10245b6b847d30002806c1577b020c36ab27f7b1cf202ade136aa4779c -R 51ff65a6bd1b538cf25dd22d8d1484ee ++P f54462c4b1838d613785adf63073347ff8019de8b6438806f3dfa79eb9847593 cd472d7c85f3fda54bba5166eae72b5f9b86861c4a1160583e8ee902ba992255 ++R 569fb353a340a32b263662c23b972d63 U drh - Z 4a3579fa736f68fb57d702cfcd2c09d7 -Z d9594447f664fc3f5df800bf2243aaf0 ++Z 586663d6d2f0e2701d4ccd34adf4afd8 # Remove this line to create a well-formed Fossil manifest. diff --cc manifest.uuid index b69da68a6c,0f229184a6..3ac159f1eb --- a/manifest.uuid +++ b/manifest.uuid @@@ -1,1 -1,1 +1,1 @@@ - f54462c4b1838d613785adf63073347ff8019de8b6438806f3dfa79eb9847593 -cd472d7c85f3fda54bba5166eae72b5f9b86861c4a1160583e8ee902ba992255 ++337a9f3f4724f5f46ca5cd000a3742f5f3c9682f23f9f9fcdd6aa42f1501b3d3 diff --cc src/shell.c.in index e183ab0322,c931055ca2..f71e062747 --- a/src/shell.c.in +++ b/src/shell.c.in @@@ -246,1147 -262,1131 +262,1133 @@@ INCLUDE ../ext/qrf/qrf. #endif /* - ** Output routines that are able to redirect to memory rather than - ** doing actually I/O. - ** Works like. - ** -------------- - ** cli_printf(FILE*, const char*, ...); fprintf() - ** cli_puts(const char*, FILE*); fputs() - ** cli_vprintf(FILE*, const char*, va_list); vfprintf() - ** - ** These are just thin wrappers with the following added semantics: - ** If the file-scope variable cli_output_capture is not NULL, and - ** if the FILE* argument is stdout or stderr, then rather than - ** writing to stdout/stdout, append the text to the cli_output_capture - ** variable. - ** - ** The cli_exit(int) routine works like exit() except that it - ** first dumps any capture output to stdout. + ** The source code for several run-time loadable extensions is inserted + ** below by the ../tool/mkshellc.tcl script. Before processing that included + ** code, we need to override some macros to make the included program code + ** work here in the middle of this regular program. */ - static sqlite3_str *cli_output_capture = 0; - static int cli_printf(FILE *out, const char *zFormat, ...){ - va_list ap; - int rc; - va_start(ap,zFormat); - if( cli_output_capture && (out==stdout || out==stderr) ){ - sqlite3_str_vappendf(cli_output_capture, zFormat, ap); - rc = 1; - }else{ - rc = sqlite3_vfprintf(out, zFormat, ap); - } - va_end(ap); - return rc; - } - static int cli_puts(const char *zText, FILE *out){ - if( cli_output_capture && (out==stdout || out==stderr) ){ - sqlite3_str_appendall(cli_output_capture, zText); - return 1; - } - return sqlite3_fputs(zText, out); - } - #if 0 /* Not currently used - available if we need it later */ - static int cli_vprintf(FILE *out, const char *zFormat, va_list ap){ - if( cli_output_capture && (out==stdout || out==stderr) ){ - sqlite3_str_vappendf(cli_output_capture, zFormat, ap); - return 1; - }else{ - return sqlite3_vfprintf(out, zFormat, ap); - } - } - #endif - static void cli_exit(int rc){ - if( cli_output_capture ){ - char *z = sqlite3_str_finish(cli_output_capture); - sqlite3_fputs(z, stdout); - fflush(stdout); - } - exit(rc); - } - - - #define eputz(z) cli_puts(z,stderr) - #define sputz(fp,z) cli_puts(z,fp) + #define SQLITE_EXTENSION_INIT1 + #define SQLITE_EXTENSION_INIT2(X) (void)(X) - /* A version of strcmp() that works with NULL values */ - static int cli_strcmp(const char *a, const char *b){ - if( a==0 ) a = ""; - if( b==0 ) b = ""; - return strcmp(a,b); - } - static int cli_strncmp(const char *a, const char *b, size_t n){ - if( a==0 ) a = ""; - if( b==0 ) b = ""; - return strncmp(a,b,n); - } + INCLUDE ../ext/misc/windirent.h + INCLUDE ../ext/misc/memtrace.c + INCLUDE ../ext/misc/pcachetrace.c + INCLUDE ../ext/misc/shathree.c + INCLUDE ../ext/misc/sha1.c + INCLUDE ../ext/misc/uint.c + INCLUDE ../ext/misc/decimal.c + INCLUDE ../ext/misc/base64.c + INCLUDE ../ext/misc/base85.c + INCLUDE ../ext/misc/ieee754.c + INCLUDE ../ext/misc/series.c + INCLUDE ../ext/misc/regexp.c + #ifndef SQLITE_SHELL_FIDDLE + INCLUDE ../ext/misc/fileio.c + INCLUDE ../ext/misc/completion.c + INCLUDE ../ext/misc/appendvfs.c + #endif + #ifdef SQLITE_HAVE_ZLIB + INCLUDE ../ext/misc/zipfile.c + INCLUDE ../ext/misc/sqlar.c + #endif + #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION) + INCLUDE ../ext/expert/sqlite3expert.h + INCLUDE ../ext/expert/sqlite3expert.c + #endif + INCLUDE ../ext/intck/sqlite3intck.h + INCLUDE ../ext/intck/sqlite3intck.c + INCLUDE ../ext/misc/stmtrand.c + INCLUDE ../ext/misc/vfstrace.c - /* Return the current wall-clock time in microseconds since the - ** Unix epoch (1970-01-01T00:00:00Z) - */ - static sqlite3_int64 timeOfDay(void){ - #if defined(_WIN64) && _WIN32_WINNT >= _WIN32_WINNT_WIN8 - sqlite3_uint64 t; - FILETIME tm; - GetSystemTimePreciseAsFileTime(&tm); - t = ((u64)tm.dwHighDateTime<<32) | (u64)tm.dwLowDateTime; - t += 116444736000000000LL; - t /= 10; - return t; - #elif defined(_WIN32) - static sqlite3_vfs *clockVfs = 0; - sqlite3_int64 t; - if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); - if( clockVfs==0 ) return 0; /* Never actually happens */ - if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ - clockVfs->xCurrentTimeInt64(clockVfs, &t); - }else{ - double r; - clockVfs->xCurrentTime(clockVfs, &r); - t = (sqlite3_int64)(r*86400000.0); - } - return t*1000; + #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) + #define SQLITE_SHELL_HAVE_RECOVER 1 #else - struct timeval sNow; - (void)gettimeofday(&sNow,0); - return ((i64)sNow.tv_sec)*1000000 + sNow.tv_usec; + #define SQLITE_SHELL_HAVE_RECOVER 0 + #endif + #if SQLITE_SHELL_HAVE_RECOVER + INCLUDE ../ext/recover/sqlite3recover.h + # ifndef SQLITE_HAVE_SQLITE3R + INCLUDE ../ext/recover/dbdata.c + INCLUDE ../ext/recover/sqlite3recover.c + # endif /* SQLITE_HAVE_SQLITE3R */ + #endif + #ifdef SQLITE_SHELL_EXTSRC + # include SHELL_STRINGIFY(SQLITE_SHELL_EXTSRC) #endif - } - - - /* - ** Used to prevent warnings about unused parameters - */ - #define UNUSED_PARAMETER(x) (void)(x) - - /* - ** Number of elements in an array - */ - #define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) - - /* - ** If the following flag is set, then command execution stops - ** at an error if we are not interactive. - */ - static int bail_on_error = 0; - - /* - ** Treat stdin as an interactive input if the following variable - ** is true. Otherwise, assume stdin is connected to a file or pipe. - */ - static int stdin_is_interactive = 1; - - /* - ** Treat stdout like a TTY if true. - */ - static int stdout_is_console = 1; + #if defined(SQLITE_ENABLE_SESSION) /* - ** Use this value as the width of the output device. Or, figure it - ** out at runtime if the value is negative. Or use a default width - ** if this value is zero. + ** State information for a single open session */ - static int stdout_tty_width = -1; + typedef struct OpenSession OpenSession; + struct OpenSession { + char *zName; /* Symbolic name for this session */ + int nFilter; /* Number of xFilter rejection GLOB patterns */ + char **azFilter; /* Array of xFilter rejection GLOB patterns */ + sqlite3_session *p; /* The open session */ + }; + #endif - /* - ** The following is the open SQLite database. We make a pointer - ** to this database a static variable so that it can be accessed - ** by the SIGINT handler to interrupt database processing. - */ - static sqlite3 *globalDb = 0; + #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION) + typedef struct ExpertInfo ExpertInfo; + struct ExpertInfo { + sqlite3expert *pExpert; + int bVerbose; + }; + #endif - /* - ** True if an interrupt (Control-C) has been received. + /* All the parameters that determine how to render query results. */ - static volatile int seenInterrupt = 0; + typedef struct Mode { + u8 autoExplain; /* Automatically turn on .explain mode */ + u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to each SQL stmt */ + u8 autoEQPtrace; /* autoEQP is in trace mode */ + u8 scanstatsOn; /* True to display scan stats before each finalize */ + u8 bAutoScreenWidth; /* Using the TTY to determine screen width */ + u8 mFlags; /* MFLG_ECHO, MFLG_CRLF, etc. */ + u8 eMode; /* One of the MODE_ values */ + sqlite3_qrf_spec spec; /* Spec to be passed into QRF */ + } Mode; - /* - ** This is the name of our program. It is set in main(), used - ** in a number of other places, mostly for error messages. - */ - static char *Argv0; + /* Flags for Mode.mFlags */ + #define MFLG_ECHO 0x01 /* Echo inputs to output */ + #define MFLG_CRLF 0x02 /* Use CR/LF output line endings */ + #define MFLG_HDR 0x04 /* .header used to change headers on/off */ - /* - ** Prompt strings. Initialized in main. Settable with - ** .prompt main continue - */ - #define PROMPT_LEN_MAX 128 - /* First line prompt. default: "sqlite> " */ - static char mainPrompt[PROMPT_LEN_MAX]; - /* Continuation prompt. default: " ...> " */ - static char continuePrompt[PROMPT_LEN_MAX]; /* - ** Write I/O traces to the following stream. + ** State information about the database connection is contained in an + ** instance of the following structure. */ - #ifdef SQLITE_ENABLE_IOTRACE - static FILE *iotrace = 0; - #endif + typedef struct ShellState ShellState; + struct ShellState { + sqlite3 *db; /* The database */ + u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */ + u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ + u8 nEqpLevel; /* Depth of the EQP output graph */ + u8 eTraceType; /* SHELL_TRACE_* value for type of trace */ + u8 bSafeMode; /* True to prohibit unsafe operations */ + u8 bSafeModePersist; /* The long-term value of bSafeMode */ + u8 eRestoreState; /* See comments above doAutoDetectRestore() */ + unsigned statsOn; /* True to display memory stats before each finalize */ + unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */ + u8 nPopOutput; /* Revert .output settings when reaching zero */ + u8 nPopMode; /* Revert .mode settings when reaching zero */ + u8 enableTimer; /* Enable the timer. 2: permanently 1: only once */ + int inputNesting; /* Track nesting level of .read and other redirects */ + double prevTimer; /* Last reported timer value */ + double tmProgress; /* --timeout option for .progress */ + i64 lineno; /* Line number of last line read from in */ + const char *zInFile; /* Name of the input file */ + int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */ + FILE *in; /* Read commands from this stream */ + FILE *out; /* Write results here */ + FILE *traceOut; /* Output for sqlite3_trace() */ + int nErr; /* Number of errors seen */ + int writableSchema; /* True if PRAGMA writable_schema=ON */ + int nCheck; /* Number of ".check" commands run */ + unsigned nProgress; /* Number of progress callbacks encountered */ + unsigned mxProgress; /* Maximum progress callbacks before failing */ + unsigned flgProgress; /* Flags for the progress callback */ + unsigned shellFlgs; /* Various flags */ + unsigned nTestRun; /* Number of test cases run */ + unsigned nTestErr; /* Number of test cases that failed */ + 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 *zErrPrefix; /* Alternative error message prefix */ + char zTestcase[30]; /* Name of current test case */ + char outfile[FILENAME_MAX]; /* Filename for *out */ + sqlite3_stmt *pStmt; /* Current statement if any. */ + FILE *pLog; /* Write log output here */ + Mode mode; /* Current display mode */ + Mode modePrior; /* Backup */ + struct SavedMode { /* Ability to define custom mode configurations */ + char *zTag; /* Name of this saved mode */ + Mode mode; /* The saved mode */ + } *aSavedModes; /* Array of saved .mode settings. system malloc() */ + int nSavedModes; /* Number of saved .mode settings */ + struct AuxDb { /* Storage space for auxiliary database connections */ + sqlite3 *db; /* Connection pointer */ + const char *zDbFilename; /* Filename used to open the connection */ + char *zFreeOnClose; /* Free this memory allocation on close */ + #if defined(SQLITE_ENABLE_SESSION) + int nSession; /* Number of active sessions */ + OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */ + #endif + } aAuxDb[5], /* Array of all database connections */ + *pAuxDb; /* Currently active database connection */ + char *zNonce; /* Nonce for temporary safe-mode escapes */ + #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION) + ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */ + #endif + struct DotCmdLine { /* Info about arguments to a dot-command */ + const char *zOrig; /* Original text of the dot-command */ + char *zCopy; /* Copy of zOrig, from malloc() */ + int nAlloc; /* Size of allocates for arrays below */ + int nArg; /* Number of argument slots actually used */ + char **azArg; /* Pointer to each argument, dequoted */ + int *aiOfst; /* Offset into zOrig[] for start of each arg */ + char *abQuot; /* True if the argment was originally quoted */ + } dot; + #ifdef SQLITE_SHELL_FIDDLE + struct { + const char * zInput; /* Input string from wasm/JS proxy */ + const char * zPos; /* Cursor pos into zInput */ + const char * zDefaultDbName; /* Default name for db file */ + } wasm; + #endif + }; + #ifdef SQLITE_SHELL_FIDDLE + static ShellState shellState; + #endif - /* This is variant of the standard-library strncpy() routine with the - ** one change that the destination string is always zero-terminated, even - ** if there is no zero-terminator in the first n-1 characters of the source - ** string. - */ - static char *shell_strncpy(char *dest, const char *src, size_t n){ - size_t i; - for(i=0; iinParenLevel += ni; - if( ni==0 ) p->inParenLevel = 0; - p->zScannerAwaits = 0; - } - - /* Record that a lexeme is opened, or closed with args==0. */ - static void setLexemeOpen(struct DynaPrompt *p, char *s, char c){ - if( s!=0 || c==0 ){ - p->zScannerAwaits = s; - p->acAwait[0] = 0; - }else{ - p->acAwait[0] = c; - p->zScannerAwaits = p->acAwait; - } - } -#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ -#define SHELL_OPEN_NORMAL 1 /* Normal database file */ -#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ -#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ -#define SHELL_OPEN_DESERIALIZE 4 /* Open using sqlite3_deserialize() */ -#define SHELL_OPEN_HEXDB 5 /* Use "dbtotxt" output as data source */ ++#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ ++#define SHELL_OPEN_NORMAL 1 /* Normal database file */ ++#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ ++#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ ++#define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */ ++#define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */ ++#define SHELL_OPEN_HEXDB 6 /* Use "dbtotxt" output as data source */ ++#define SHELL_OPEN_SHAREDSCHEMA 7 /* Open for schema reuse */ - /* Upon demand, derive the continuation prompt to display. */ - static char *dynamicContinuePrompt(void){ - if( continuePrompt[0]==0 - || (dynPrompt.zScannerAwaits==0 && dynPrompt.inParenLevel == 0) ){ - return continuePrompt; - }else{ - if( dynPrompt.zScannerAwaits ){ - size_t ncp = strlen(continuePrompt); - size_t ndp = strlen(dynPrompt.zScannerAwaits); - if( ndp > ncp-3 ) return continuePrompt; - shell_strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits); - while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' '; - shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, - PROMPT_LEN_MAX-4); - }else{ - if( dynPrompt.inParenLevel>9 ){ - shell_strncpy(dynPrompt.dynamicPrompt, "(..", 4); - }else if( dynPrompt.inParenLevel<0 ){ - shell_strncpy(dynPrompt.dynamicPrompt, ")x!", 4); - }else{ - shell_strncpy(dynPrompt.dynamicPrompt, "(x.", 4); - dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel); - } - shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, - PROMPT_LEN_MAX-4); - } - } - return dynPrompt.dynamicPrompt; - } - #endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */ + /* Allowed values for ShellState.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 */ - /* Indicate out-of-memory and exit. */ - static void shell_out_of_memory(void){ - eputz("Error: out of memory\n"); - cli_exit(1); - } + /* Bits in the ShellState.flgProgress variable */ + #define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */ + #define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progress + ** callback limit is reached, and for each + ** top-level SQL statement */ + #define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */ + #define SHELL_PROGRESS_TMOUT 0x08 /* Stop after tmProgress seconds */ - /* Check a pointer to see if it is NULL. If it is NULL, exit with an - ** out-of-memory error. + /* Names of values for Mode.spec.eEsc and Mode.spec.eText */ - static void shell_check_oom(const void *p){ - if( p==0 ) shell_out_of_memory(); - } + static const char *qrfEscNames[] = { "auto", "off", "ascii", "symbol" }; + static const char *qrfQuoteNames[] = + { "off","off","sql","hex","csv","tcl","json","relaxed"}; /* - ** This routine works like printf in that its first argument is a - ** format string and subsequent arguments are values to be substituted - ** in place of % fields. The result of formatting this string - ** is written to iotrace. + ** These are the allowed shellFlgs values */ - #ifdef SQLITE_ENABLE_IOTRACE - static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ - va_list ap; - char *z; - if( iotrace==0 ) return; - va_start(ap, zFormat); - z = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - cli_printf(iotrace, "%s", z); - sqlite3_free(z); - } - #endif + #define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */ + #define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */ + #define SHFLG_Backslash 0x00000004 /* The --backslash option is used */ + #define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */ + #define SHFLG_NoErrLineno 0x00000010 /* Omit line numbers from error msgs */ + #define SHFLG_CountChanges 0x00000020 /* .changes setting */ + #define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */ + #define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */ + #define SHFLG_TestingMode 0x00000400 /* allow unsafe testing features */ /* - ** Compute a string length that is limited to what can be stored in - ** lower 30 bits of a 32-bit signed integer. + ** Macros for testing and setting shellFlgs */ - static int strlen30(const char *z){ - size_t n; - if( z==0 ) return 0; - n = strlen(z); - return n>0x3fffffff ? 0x3fffffff : (int)n; - } + #define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0) + #define ShellSetFlag(P,X) ((P)->shellFlgs|=(X)) + #define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X))) /* - ** Return open FILE * if zFile exists, can be opened for read - ** and is an ordinary file or a character stream source. - ** Otherwise return 0. + ** These are the allowed values for Mode.eMode. There is a lot of overlap + ** between these values and the Mode.spec.eStyle values, but they are not + ** one-to-one, and thus need to be tracked separately. */ - static FILE * openChrSource(const char *zFile){ - #if defined(_WIN32) || defined(WIN32) - struct __stat64 x = {0}; - # define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0) - /* On Windows, open first, then check the stream nature. This order - ** is necessary because _stat() and sibs, when checking a named pipe, - ** effectively break the pipe as its supplier sees it. */ - FILE *rv = sqlite3_fopen(zFile, "rb"); - if( rv==0 ) return 0; - if( _fstat64(_fileno(rv), &x) != 0 - || !STAT_CHR_SRC(x.st_mode)){ - fclose(rv); - rv = 0; - } - return rv; - #else - struct stat x = {0}; - int rc = stat(zFile, &x); - # define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode)) - if( rc!=0 ) return 0; - if( STAT_CHR_SRC(x.st_mode) ){ - return sqlite3_fopen(zFile, "rb"); - }else{ - return 0; - } - #endif - #undef STAT_CHR_SRC - } + #define MODE_Ascii 0 /* Use ASCII unit and record separators (0x1F/0x1E) */ + #define MODE_Box 1 /* Unicode box-drawing characters */ + #define MODE_C 2 /* Comma-separated list of C-strings */ + #define MODE_Column 3 /* One record per line in neat columns */ + #define MODE_Count 4 /* Output only a count of the rows of output */ + #define MODE_Csv 5 /* Quote strings, numbers are plain */ + #define MODE_Html 6 /* Generate an XHTML table */ + #define MODE_Insert 7 /* Generate SQL "insert" statements */ + #define MODE_JAtom 8 /* Comma-separated list of JSON atoms */ + #define MODE_JObject 9 /* One JSON object per row */ + #define MODE_Json 10 /* Output JSON */ + #define MODE_Line 11 /* One column per line. Blank line between records */ + #define MODE_List 12 /* One record per line with a separator */ + #define MODE_Markdown 13 /* Markdown formatting */ + #define MODE_Off 14 /* No query output shown */ + #define MODE_Psql 15 /* Similar to psql */ + #define MODE_QBox 16 /* BOX with SQL-quoted content */ + #define MODE_Quote 17 /* Quote values as for SQL */ + #define MODE_Split 18 /* Split-column mode */ + #define MODE_Table 19 /* MySQL-style table formatting */ + #define MODE_Tabs 20 /* Tab-separated values */ + #define MODE_Tcl 21 /* Space-separated list of TCL strings */ + #define MODE_Www 22 /* Full web-page output */ + + #define MODE_BUILTIN 22 /* Maximum built-in mode */ + #define MODE_BATCH 50 /* Default mode for batch processing */ + #define MODE_TTY 51 /* Default mode for interactive processing */ + #define MODE_USER 75 /* First user-defined mode */ + #define MODE_N_USER 25 /* Maximum number of user-defined modes */ /* - ** This routine reads a line of text from FILE in, stores - ** the text in memory obtained from malloc() and returns a pointer - ** to the text. NULL is returned at end of file, or if malloc() - ** fails, or if the length of the line is longer than about a gigabyte. - ** - ** If zLine is not NULL then it is a malloced buffer returned from - ** a previous call to this routine that may be reused. + ** Information about built-in display modes */ - static char *local_getline(char *zLine, FILE *in){ - int nLine = zLine==0 ? 0 : 100; - int n = 0; + typedef struct ModeInfo ModeInfo; + struct ModeInfo { + char zName[9]; /* Symbolic name of the mode */ + unsigned char eCSep; /* Column separator */ + unsigned char eRSep; /* Row separator */ + unsigned char eNull; /* Null representation */ + unsigned char eText; /* Default text encoding */ + unsigned char eHdr; /* Default header encoding. */ + unsigned char eBlob; /* Default blob encoding. */ + unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */ + unsigned char eStyle; /* Underlying QRF style */ + unsigned char eCx; /* 0: other, 1: line, 2: columnar */ + unsigned char mFlg; /* Flags. 1=border-off 2=split-column */ + }; - while( 1 ){ - if( n+100>nLine ){ - if( nLine>=1073741773 ){ - free(zLine); - return 0; - } - nLine = nLine*2 + 100; - zLine = realloc(zLine, nLine); - shell_check_oom(zLine); - } - if( sqlite3_fgets(&zLine[n], nLine - n, in)==0 ){ - if( n==0 ){ - free(zLine); - return 0; - } - zLine[n] = 0; - break; - } - while( zLine[n] ) n++; - if( n>0 && zLine[n-1]=='\n' ){ - n--; - if( n>0 && zLine[n-1]=='\r' ) n--; - zLine[n] = 0; - break; - } - } - return zLine; - } + /* String constants used by built-in modes */ + static const char *aModeStr[] = + /* 0 1 2 3 4 5 6 7 8 */ + { 0, "\n", "|", " ", ",", "\r\n", "\036", "\037", "\t", + "", "NULL", "null", "\"\"", ": ", }; + /* 9 10 11 12 13 */ + + static const ModeInfo aModeInfo[] = { + /* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */ + { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 }, + { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2, 0 }, + { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 }, + { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2, 0 }, + { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, + { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 }, + { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 }, + { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 }, + { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 }, + { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 }, + { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 }, + { "line", 13, 1, 9, 1, 1, 0, 0, 11, 1, 0 }, + { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 }, + { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2, 0 }, + { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 }, + { "psql", 0, 0, 9, 1, 1, 0, 2, 19, 2, 1 }, + { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2, 0 }, + { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 }, + { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 }, + { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2, 0 }, + { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 }, + { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 }, + { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 } + }; /* | / / | / / | | \ + ** | / / | / / | | \_ 2: columnar + ** Index into aModeStr[] | / / | | 1: line + ** | / / | | 0: other + ** | / / | \ + ** text encoding |/ | show | \ + ** v-------------------' | hdrs? | The QRF style + ** 0: n/a blob | v-----' + ** 1: plain v_---------' 0: n/a + ** 2: sql 0: auto 1: no + ** 3: csv 1: as-text 2: yes + ** 4: html 2: sql + ** 5: c 3: hex + ** 6: json 4: c + ** 5: json + ** 6: size + ******************************************************************/ + /* + ** These are the column/row/line separators used by the various + ** import/export modes. + */ + #define SEP_Column "|" + #define SEP_Row "\n" + #define SEP_Tab "\t" + #define SEP_Space " " + #define SEP_Comma "," + #define SEP_CrLf "\r\n" + #define SEP_Unit "\x1F" + #define SEP_Record "\x1E" /* - ** Retrieve a single line of input text. - ** - ** If in==0 then read from standard input and prompt before each line. - ** If isContinuation is true, then a continuation prompt is appropriate. - ** If isContinuation is zero, then the main prompt should be used. - ** - ** If zPrior is not NULL then it is a buffer from a prior call to this - ** routine that can be reused. - ** - ** The result is stored in space obtained from malloc() and must either - ** be freed by the caller or else passed back into this routine via the - ** zPrior argument for reuse. + ** Default values for the various QRF limits */ - #ifndef SQLITE_SHELL_FIDDLE - static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ - char *zPrompt; - char *zResult; - if( in!=0 ){ - zResult = local_getline(zPrior, in); - }else{ - zPrompt = isContinuation ? CONTINUATION_PROMPT : mainPrompt; - #if SHELL_USE_LOCAL_GETLINE - sputz(stdout, zPrompt); - fflush(stdout); - do{ - zResult = local_getline(zPrior, stdin); - zPrior = 0; - /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ - if( zResult==0 ) sqlite3_sleep(50); - }while( zResult==0 && seenInterrupt>0 ); - #else - free(zPrior); - zResult = shell_readline(zPrompt); - while( zResult==0 ){ - /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ - sqlite3_sleep(50); - if( seenInterrupt==0 ) break; - zResult = shell_readline(""); - } - if( zResult && *zResult ) shell_add_history(zResult); + #ifndef DFLT_CHAR_LIMIT + # define DFLT_CHAR_LIMIT 300 + #endif + #ifndef DFLT_LINE_LIMIT + # define DFLT_LINE_LIMIT 5 + #endif + #ifndef DFLT_TITLE_LIMIT + # define DFLT_TITLE_LIMIT 20 + #endif + #ifndef DFLT_MULTI_INSERT + # define DFLT_MULTI_INSERT 3000 #endif - } - return zResult; - } - #endif /* !SQLITE_SHELL_FIDDLE */ /* - ** Return the value of a hexadecimal digit. Return -1 if the input - ** is not a hex digit. + ** If the following flag is set, then command execution stops + ** at an error if we are not interactive. */ - static int hexDigitValue(char c){ - if( c>='0' && c<='9' ) return c - '0'; - if( c>='a' && c<='f' ) return c - 'a' + 10; - if( c>='A' && c<='F' ) return c - 'A' + 10; - return -1; - } + static int bail_on_error = 0; /* - ** Interpret zArg as an integer value, possibly with suffixes. - ** - ** If the value specified by zArg is outside the range of values that - ** can be represented using a 64-bit twos-complement integer, then return - ** the nearest representable value. + ** Treat stdin as an interactive input if the following variable + ** is true. Otherwise, assume stdin is connected to a file or pipe. */ - static sqlite3_int64 integerValue(const char *zArg){ - sqlite3_uint64 v = 0; - static const struct { char *zSuffix; unsigned int iMult; } aMult[] = { - { "KiB", 1024 }, - { "MiB", 1024*1024 }, - { "GiB", 1024*1024*1024 }, - { "KB", 1000 }, - { "MB", 1000000 }, - { "GB", 1000000000 }, - { "K", 1000 }, - { "M", 1000000 }, - { "G", 1000000000 }, - }; - int i; - int isNeg = 0; - if( zArg[0]=='-' ){ - isNeg = 1; - zArg++; - }else if( zArg[0]=='+' ){ - zArg++; - } - if( zArg[0]=='0' && zArg[1]=='x' ){ - int x; - zArg += 2; - while( (x = hexDigitValue(zArg[0]))>=0 ){ - if( v > 0x0fffffffffffffffULL ) goto integer_overflow; - v = (v<<4) + x; - zArg++; - } - }else{ - while( IsDigit(zArg[0]) ){ - if( v>=922337203685477580LL ){ - if( v>922337203685477580LL || zArg[0]>='8' ) goto integer_overflow; - } - v = v*10 + (zArg[0] - '0'); - zArg++; - } - } - for(i=0; i0x7fffffffffffffffULL ) goto integer_overflow; - return isNeg? -(sqlite3_int64)v : (sqlite3_int64)v; - integer_overflow: - return isNeg ? (i64)0x8000000000000000LL : 0x7fffffffffffffffLL; - } + static int stdin_is_interactive = 1; /* - ** A variable length string to which one can append text. + ** Treat stdout like a TTY if true. */ - typedef struct ShellText ShellText; - struct ShellText { - char *zTxt; /* The text */ - i64 n; /* Number of bytes of zTxt[] actually used */ - i64 nAlloc; /* Number of bytes allocated for zTxt[] */ - }; + static int stdout_is_console = 1; /* - ** Initialize and destroy a ShellText object + ** Use this value as the width of the output device. Or, figure it + ** out at runtime if the value is negative. Or use a default width + ** if this value is zero. */ - static void initText(ShellText *p){ - memset(p, 0, sizeof(*p)); - } - static void freeText(ShellText *p){ - sqlite3_free(p->zTxt); - initText(p); - } + static int stdout_tty_width = -1; - /* zIn is either a pointer to a NULL-terminated string in memory obtained - ** from malloc(), or a NULL pointer. The string pointed to by zAppend is - ** added to zIn, and the result returned in memory obtained from malloc(). - ** zIn, if it was not NULL, is freed. - ** - ** If the third argument, quote, is not '\0', then it is used as a - ** quote character for zAppend. + /* + ** The following is the open SQLite database. We make a pointer + ** to this database a static variable so that it can be accessed + ** by the SIGINT handler to interrupt database processing. */ - static void appendText(ShellText *p, const char *zAppend, char quote){ - i64 len; - i64 i; - i64 nAppend = strlen30(zAppend); - - len = nAppend+p->n+1; - if( quote ){ - len += 2; - for(i=0; izTxt==0 || p->n+len>=p->nAlloc ){ - p->nAlloc = p->nAlloc*2 + len + 20; - p->zTxt = sqlite3_realloc64(p->zTxt, p->nAlloc); - shell_check_oom(p->zTxt); - } - - if( quote ){ - char *zCsr = p->zTxt+p->n; - *zCsr++ = quote; - for(i=0; in = (i64)(zCsr - p->zTxt); - *zCsr = '\0'; - }else{ - memcpy(p->zTxt+p->n, zAppend, nAppend); - p->n += nAppend; - p->zTxt[p->n] = '\0'; - } - } + static sqlite3 *globalDb = 0; /* - ** Attempt to determine if identifier zName needs to be quoted, either - ** because it contains non-alphanumeric characters, or because it is an - ** SQLite keyword. Be conservative in this estimate: When in doubt assume - ** that quoting is required. - ** - ** Return '"' if quoting is required. Return 0 if no quoting is required. + ** True if an interrupt (Control-C) has been received. */ - static char quoteChar(const char *zName){ - int i; - if( zName==0 ) return '"'; - if( !IsAlpha(zName[0]) && zName[0]!='_' ) return '"'; - for(i=0; zName[i]; i++){ - if( !IsAlnum(zName[i]) && zName[i]!='_' ) return '"'; - } - return sqlite3_keyword_check(zName, i) ? '"' : 0; - } + static volatile int seenInterrupt = 0; /* - ** Construct a fake object name and column list to describe the structure - ** of the view, virtual table, or table valued function zSchema.zName. - ** - ** The returned string comes from sqlite3_mprintf() and should be freed - ** by the caller using sqlite3_free(). + ** This is the name of our program. It is set in main(), used + ** in a number of other places, mostly for error messages. */ - static char *shellFakeSchema( - sqlite3 *db, /* The database connection containing the vtab */ - const char *zSchema, /* Schema of the database holding the vtab */ - const char *zName /* The name of the virtual table */ - ){ - sqlite3_stmt *pStmt = 0; - char *zSql; - ShellText s; - char cQuote; - char *zDiv = "("; - int nRow = 0; - - zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;", - zSchema ? zSchema : "main", zName); - shell_check_oom(zSql); - sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - initText(&s); - if( zSchema ){ - cQuote = quoteChar(zSchema); - if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0; - appendText(&s, zSchema, cQuote); - appendText(&s, ".", 0); - } - cQuote = quoteChar(zName); - appendText(&s, zName, cQuote); - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - const char *zCol = (const char*)sqlite3_column_text(pStmt, 1); - nRow++; - appendText(&s, zDiv, 0); - zDiv = ","; - if( zCol==0 ) zCol = ""; - cQuote = quoteChar(zCol); - appendText(&s, zCol, cQuote); - } - appendText(&s, ")", 0); - sqlite3_finalize(pStmt); - if( nRow==0 ){ - freeText(&s); - s.zTxt = 0; - } - return s.zTxt; - } + static char *Argv0; /* - ** SQL function: strtod(X) - ** - ** Use the C-library strtod() function to convert string X into a double. - ** Used for comparing the accuracy of SQLite's internal text-to-float conversion - ** routines against the C-library. + ** Prompt strings. Initialized in main. Settable with + ** .prompt main continue */ - static void shellStrtod( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal - ){ - char *z = (char*)sqlite3_value_text(apVal[0]); - UNUSED_PARAMETER(nVal); - if( z==0 ) return; - sqlite3_result_double(pCtx, strtod(z,0)); - } + #define PROMPT_LEN_MAX 128 + /* First line prompt. default: "sqlite> " */ + static char mainPrompt[PROMPT_LEN_MAX]; + /* Continuation prompt. default: " ...> " */ + static char continuePrompt[PROMPT_LEN_MAX]; /* - ** SQL function: dtostr(X) - ** - ** Use the C-library printf() function to convert real value X into a string. - ** Used for comparing the accuracy of SQLite's internal float-to-text conversion - ** routines against the C-library. + ** Write I/O traces to the following stream. */ - static void shellDtostr( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal - ){ - double r = sqlite3_value_double(apVal[0]); - int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26; - char z[400]; - if( n<1 ) n = 1; - if( n>350 ) n = 350; - sprintf(z, "%#+.*e", n, r); - sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); - } + #ifdef SQLITE_ENABLE_IOTRACE + static FILE *iotrace = 0; + #endif /* - ** SQL function: shell_add_schema(S,X) - ** - ** Add the schema name X to the CREATE statement in S and return the result. - ** Examples: - ** - ** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x); - ** - ** Also works on + ** Output routines that are able to redirect to memory rather than + ** doing actually I/O. + ** Works like. + ** -------------- + ** cli_printf(FILE*, const char*, ...); fprintf() + ** cli_puts(const char*, FILE*); fputs() + ** cli_vprintf(FILE*, const char*, va_list); vfprintf() ** - ** CREATE INDEX - ** CREATE UNIQUE INDEX - ** CREATE VIEW - ** CREATE TRIGGER - ** CREATE VIRTUAL TABLE + ** These are just thin wrappers with the following added semantics: + ** If the file-scope variable cli_output_capture is not NULL, and + ** if the FILE* argument is stdout or stderr, then rather than + ** writing to stdout/stdout, append the text to the cli_output_capture + ** variable. ** - ** This UDF is used by the .schema command to insert the schema name of - ** attached databases into the middle of the sqlite_schema.sql field. - */ - static void shellAddSchemaName( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal - ){ - static const char *aPrefix[] = { - "TABLE", - "INDEX", - "UNIQUE INDEX", - "VIEW", - "TRIGGER", - "VIRTUAL TABLE" - }; - int i = 0; - const char *zIn = (const char*)sqlite3_value_text(apVal[0]); - const char *zSchema = (const char*)sqlite3_value_text(apVal[1]); - const char *zName = (const char*)sqlite3_value_text(apVal[2]); - sqlite3 *db = sqlite3_context_db_handle(pCtx); - UNUSED_PARAMETER(nVal); - if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){ - for(i=0; i= _WIN32_WINNT_WIN8 + sqlite3_uint64 t; + FILETIME tm; + GetSystemTimePreciseAsFileTime(&tm); + t = ((u64)tm.dwHighDateTime<<32) | (u64)tm.dwLowDateTime; + t += 116444736000000000LL; + t /= 10; + return t; + #elif defined(_WIN32) + static sqlite3_vfs *clockVfs = 0; + sqlite3_int64 t; + if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); + if( clockVfs==0 ) return 0; /* Never actually happens */ + if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ + clockVfs->xCurrentTimeInt64(clockVfs, &t); + }else{ + double r; + clockVfs->xCurrentTime(clockVfs, &r); + t = (sqlite3_int64)(r*86400000.0); + } + return t*1000; + #else + struct timeval sNow; + (void)gettimeofday(&sNow,0); + return ((i64)sNow.tv_sec)*1000000 + sNow.tv_usec; #endif + } - #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION) - typedef struct ExpertInfo ExpertInfo; - struct ExpertInfo { - sqlite3expert *pExpert; - int bVerbose; - }; - #endif - /* All the parameters that determine how to render query results. - */ - typedef struct Mode { - u8 autoExplain; /* Automatically turn on .explain mode */ - u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to each SQL stmt */ - u8 autoEQPtrace; /* autoEQP is in trace mode */ - u8 scanstatsOn; /* True to display scan stats before each finalize */ - u8 bAutoScreenWidth; /* Using the TTY to determine screen width */ - u8 mFlags; /* MFLG_ECHO, MFLG_CRLF, etc. */ - u8 eMode; /* One of the MODE_ values */ - sqlite3_qrf_spec spec; /* Spec to be passed into QRF */ - } Mode; - /* Flags for Mode.mFlags */ - #define MFLG_ECHO 0x01 /* Echo inputs to output */ - #define MFLG_CRLF 0x02 /* Use CR/LF output line endings */ - #define MFLG_HDR 0x04 /* .header used to change headers on/off */ + /* This is variant of the standard-library strncpy() routine with the + ** one change that the destination string is always zero-terminated, even + ** if there is no zero-terminator in the first n-1 characters of the source + ** string. + */ + static char *shell_strncpy(char *dest, const char *src, size_t n){ + size_t i; + for(i=0; iinParenLevel += ni; + if( ni==0 ) p->inParenLevel = 0; + p->zScannerAwaits = 0; + } - /* Allowed values for ShellState.openMode - */ - #define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ - #define SHELL_OPEN_NORMAL 1 /* Normal database file */ - #define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ - #define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ - #define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */ - #define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */ - #define SHELL_OPEN_HEXDB 6 /* Use "dbtotxt" output as data source */ - #define SHELL_OPEN_SHAREDSCHEMA 7 /* Open for schema reuse */ + /* Record that a lexeme is opened, or closed with args==0. */ + static void setLexemeOpen(struct DynaPrompt *p, char *s, char c){ + if( s!=0 || c==0 ){ + p->zScannerAwaits = s; + p->acAwait[0] = 0; + }else{ + p->acAwait[0] = c; + p->zScannerAwaits = p->acAwait; + } + } - /* Allowed values for ShellState.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 */ + /* Upon demand, derive the continuation prompt to display. */ + static char *dynamicContinuePrompt(void){ + if( continuePrompt[0]==0 + || (dynPrompt.zScannerAwaits==0 && dynPrompt.inParenLevel == 0) ){ + return continuePrompt; + }else{ + if( dynPrompt.zScannerAwaits ){ + size_t ncp = strlen(continuePrompt); + size_t ndp = strlen(dynPrompt.zScannerAwaits); + if( ndp > ncp-3 ) return continuePrompt; + shell_strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits); + while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' '; + shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, + PROMPT_LEN_MAX-4); + }else{ + if( dynPrompt.inParenLevel>9 ){ + shell_strncpy(dynPrompt.dynamicPrompt, "(..", 4); + }else if( dynPrompt.inParenLevel<0 ){ + shell_strncpy(dynPrompt.dynamicPrompt, ")x!", 4); + }else{ + shell_strncpy(dynPrompt.dynamicPrompt, "(x.", 4); + dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel); + } + shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, + PROMPT_LEN_MAX-4); + } + } + return dynPrompt.dynamicPrompt; + } + #endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */ - /* Bits in the ShellState.flgProgress variable */ - #define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */ - #define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progress - ** callback limit is reached, and for each - ** top-level SQL statement */ - #define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */ - #define SHELL_PROGRESS_TMOUT 0x08 /* Stop after tmProgress seconds */ + /* Indicate out-of-memory and exit. */ + static void shell_out_of_memory(void){ + eputz("Error: out of memory\n"); + cli_exit(1); + } - /* Names of values for Mode.spec.eEsc and Mode.spec.eText + /* Check a pointer to see if it is NULL. If it is NULL, exit with an + ** out-of-memory error. */ - static const char *qrfEscNames[] = { "auto", "off", "ascii", "symbol" }; - static const char *qrfQuoteNames[] = - { "off","off","sql","hex","csv","tcl","json","relaxed"}; + static void shell_check_oom(const void *p){ + if( p==0 ) shell_out_of_memory(); + } /* - ** These are the allowed shellFlgs values + ** This routine works like printf in that its first argument is a + ** format string and subsequent arguments are values to be substituted + ** in place of % fields. The result of formatting this string + ** is written to iotrace. */ - #define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */ - #define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */ - #define SHFLG_Backslash 0x00000004 /* The --backslash option is used */ - #define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */ - #define SHFLG_NoErrLineno 0x00000010 /* Omit line numbers from error msgs */ - #define SHFLG_CountChanges 0x00000020 /* .changes setting */ - #define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */ - #define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */ - #define SHFLG_TestingMode 0x00000400 /* allow unsafe testing features */ + #ifdef SQLITE_ENABLE_IOTRACE + static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ + va_list ap; + char *z; + if( iotrace==0 ) return; + va_start(ap, zFormat); + z = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + cli_printf(iotrace, "%s", z); + sqlite3_free(z); + } + #endif /* - ** Macros for testing and setting shellFlgs + ** Compute a string length that is limited to what can be stored in + ** lower 30 bits of a 32-bit signed integer. */ - #define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0) - #define ShellSetFlag(P,X) ((P)->shellFlgs|=(X)) - #define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X))) + static int strlen30(const char *z){ + size_t n; + if( z==0 ) return 0; + n = strlen(z); + return n>0x3fffffff ? 0x3fffffff : (int)n; + } /* - ** These are the allowed values for Mode.eMode. There is a lot of overlap - ** between these values and the Mode.spec.eStyle values, but they are not - ** one-to-one, and thus need to be tracked separately. + ** Return open FILE * if zFile exists, can be opened for read + ** and is an ordinary file or a character stream source. + ** Otherwise return 0. */ - #define MODE_Ascii 0 /* Use ASCII unit and record separators (0x1F/0x1E) */ - #define MODE_Box 1 /* Unicode box-drawing characters */ - #define MODE_C 2 /* Comma-separated list of C-strings */ - #define MODE_Column 3 /* One record per line in neat columns */ - #define MODE_Count 4 /* Output only a count of the rows of output */ - #define MODE_Csv 5 /* Quote strings, numbers are plain */ - #define MODE_Html 6 /* Generate an XHTML table */ - #define MODE_Insert 7 /* Generate SQL "insert" statements */ - #define MODE_JAtom 8 /* Comma-separated list of JSON atoms */ - #define MODE_JObject 9 /* One JSON object per row */ - #define MODE_Json 10 /* Output JSON */ - #define MODE_Line 11 /* One column per line. Blank line between records */ - #define MODE_List 12 /* One record per line with a separator */ - #define MODE_Markdown 13 /* Markdown formatting */ - #define MODE_Off 14 /* No query output shown */ - #define MODE_Psql 15 /* Similar to psql */ - #define MODE_QBox 16 /* BOX with SQL-quoted content */ - #define MODE_Quote 17 /* Quote values as for SQL */ - #define MODE_Split 18 /* Split-column mode */ - #define MODE_Table 19 /* MySQL-style table formatting */ - #define MODE_Tabs 20 /* Tab-separated values */ - #define MODE_Tcl 21 /* Space-separated list of TCL strings */ - #define MODE_Www 22 /* Full web-page output */ - - #define MODE_BUILTIN 22 /* Maximum built-in mode */ - #define MODE_BATCH 50 /* Default mode for batch processing */ - #define MODE_TTY 51 /* Default mode for interactive processing */ - #define MODE_USER 75 /* First user-defined mode */ - #define MODE_N_USER 25 /* Maximum number of user-defined modes */ + static FILE * openChrSource(const char *zFile){ + #if defined(_WIN32) || defined(WIN32) + struct __stat64 x = {0}; + # define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0) + /* On Windows, open first, then check the stream nature. This order + ** is necessary because _stat() and sibs, when checking a named pipe, + ** effectively break the pipe as its supplier sees it. */ + FILE *rv = sqlite3_fopen(zFile, "rb"); + if( rv==0 ) return 0; + if( _fstat64(_fileno(rv), &x) != 0 + || !STAT_CHR_SRC(x.st_mode)){ + fclose(rv); + rv = 0; + } + return rv; + #else + struct stat x = {0}; + int rc = stat(zFile, &x); + # define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode)) + if( rc!=0 ) return 0; + if( STAT_CHR_SRC(x.st_mode) ){ + return sqlite3_fopen(zFile, "rb"); + }else{ + return 0; + } + #endif + #undef STAT_CHR_SRC + } /* - ** Information about built-in display modes + ** This routine reads a line of text from FILE in, stores + ** the text in memory obtained from malloc() and returns a pointer + ** to the text. NULL is returned at end of file, or if malloc() + ** fails, or if the length of the line is longer than about a gigabyte. + ** + ** If zLine is not NULL then it is a malloced buffer returned from + ** a previous call to this routine that may be reused. */ - typedef struct ModeInfo ModeInfo; - struct ModeInfo { - char zName[9]; /* Symbolic name of the mode */ - unsigned char eCSep; /* Column separator */ - unsigned char eRSep; /* Row separator */ - unsigned char eNull; /* Null representation */ - unsigned char eText; /* Default text encoding */ - unsigned char eHdr; /* Default header encoding. */ - unsigned char eBlob; /* Default blob encoding. */ - unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */ - unsigned char eStyle; /* Underlying QRF style */ - unsigned char eCx; /* 0: other, 1: line, 2: columnar */ - unsigned char mFlg; /* Flags. 1=border-off 2=split-column */ + static char *local_getline(char *zLine, FILE *in){ + int nLine = zLine==0 ? 0 : 100; + int n = 0; + + while( 1 ){ + if( n+100>nLine ){ + if( nLine>=1073741773 ){ + free(zLine); + return 0; + } + nLine = nLine*2 + 100; + zLine = realloc(zLine, nLine); + shell_check_oom(zLine); + } + if( sqlite3_fgets(&zLine[n], nLine - n, in)==0 ){ + if( n==0 ){ + free(zLine); + return 0; + } + zLine[n] = 0; + break; + } + while( zLine[n] ) n++; + if( n>0 && zLine[n-1]=='\n' ){ + n--; + if( n>0 && zLine[n-1]=='\r' ) n--; + zLine[n] = 0; + break; + } + } + return zLine; + } + + /* + ** Retrieve a single line of input text. + ** + ** If in==0 then read from standard input and prompt before each line. + ** If isContinuation is true, then a continuation prompt is appropriate. + ** If isContinuation is zero, then the main prompt should be used. + ** + ** If zPrior is not NULL then it is a buffer from a prior call to this + ** routine that can be reused. + ** + ** The result is stored in space obtained from malloc() and must either + ** be freed by the caller or else passed back into this routine via the + ** zPrior argument for reuse. + */ + #ifndef SQLITE_SHELL_FIDDLE + static char *one_input_line(ShellState *p, char *zPrior, int isContinuation){ + char *zPrompt; + char *zResult; + FILE *in = p->in; + if( in!=0 ){ + zResult = local_getline(zPrior, in); + }else{ + zPrompt = isContinuation ? CONTINUATION_PROMPT : mainPrompt; + #if SHELL_USE_LOCAL_GETLINE + sputz(stdout, zPrompt); + fflush(stdout); + do{ + zResult = local_getline(zPrior, stdin); + zPrior = 0; + /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ + if( zResult==0 ) sqlite3_sleep(50); + }while( zResult==0 && seenInterrupt>0 ); + #else + free(zPrior); + zResult = shell_readline(zPrompt); + while( zResult==0 ){ + /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ + sqlite3_sleep(50); + if( seenInterrupt==0 ) break; + zResult = shell_readline(""); + } + if( zResult && *zResult ) shell_add_history(zResult); + #endif + } + return zResult; + } + #endif /* !SQLITE_SHELL_FIDDLE */ + + /* + ** Return the value of a hexadecimal digit. Return -1 if the input + ** is not a hex digit. + */ + static int hexDigitValue(char c){ + if( c>='0' && c<='9' ) return c - '0'; + if( c>='a' && c<='f' ) return c - 'a' + 10; + if( c>='A' && c<='F' ) return c - 'A' + 10; + return -1; + } + + /* + ** Interpret zArg as an integer value, possibly with suffixes. + ** + ** If the value specified by zArg is outside the range of values that + ** can be represented using a 64-bit twos-complement integer, then return + ** the nearest representable value. + */ + static sqlite3_int64 integerValue(const char *zArg){ + sqlite3_uint64 v = 0; + static const struct { char *zSuffix; unsigned int iMult; } aMult[] = { + { "KiB", 1024 }, + { "MiB", 1024*1024 }, + { "GiB", 1024*1024*1024 }, + { "KB", 1000 }, + { "MB", 1000000 }, + { "GB", 1000000000 }, + { "K", 1000 }, + { "M", 1000000 }, + { "G", 1000000000 }, + }; + int i; + int isNeg = 0; + if( zArg[0]=='-' ){ + isNeg = 1; + zArg++; + }else if( zArg[0]=='+' ){ + zArg++; + } + if( zArg[0]=='0' && zArg[1]=='x' ){ + int x; + zArg += 2; + while( (x = hexDigitValue(zArg[0]))>=0 ){ + if( v > 0x0fffffffffffffffULL ) goto integer_overflow; + v = (v<<4) + x; + zArg++; + } + }else{ + while( IsDigit(zArg[0]) ){ + if( v>=922337203685477580LL ){ + if( v>922337203685477580LL || zArg[0]>='8' ) goto integer_overflow; + } + v = v*10 + (zArg[0] - '0'); + zArg++; + } + } + for(i=0; i0x7fffffffffffffffULL ) goto integer_overflow; + return isNeg? -(sqlite3_int64)v : (sqlite3_int64)v; + integer_overflow: + return isNeg ? (i64)0x8000000000000000LL : 0x7fffffffffffffffLL; + } + + /* + ** A variable length string to which one can append text. + */ + typedef struct ShellText ShellText; + struct ShellText { + char *zTxt; /* The text */ + i64 n; /* Number of bytes of zTxt[] actually used */ + i64 nAlloc; /* Number of bytes allocated for zTxt[] */ }; - /* String constants used by built-in modes */ - static const char *aModeStr[] = - /* 0 1 2 3 4 5 6 7 8 */ - { 0, "\n", "|", " ", ",", "\r\n", "\036", "\037", "\t", - "", "NULL", "null", "\"\"", ": ", }; - /* 9 10 11 12 13 */ + /* + ** Initialize and destroy a ShellText object + */ + static void initText(ShellText *p){ + memset(p, 0, sizeof(*p)); + } + static void freeText(ShellText *p){ + sqlite3_free(p->zTxt); + initText(p); + } + + /* zIn is either a pointer to a NULL-terminated string in memory obtained + ** from malloc(), or a NULL pointer. The string pointed to by zAppend is + ** added to zIn, and the result returned in memory obtained from malloc(). + ** zIn, if it was not NULL, is freed. + ** + ** If the third argument, quote, is not '\0', then it is used as a + ** quote character for zAppend. + */ + static void appendText(ShellText *p, const char *zAppend, char quote){ + i64 len; + i64 i; + i64 nAppend = strlen30(zAppend); + + len = nAppend+p->n+1; + if( quote ){ + len += 2; + for(i=0; izTxt==0 || p->n+len>=p->nAlloc ){ + p->nAlloc = p->nAlloc*2 + len + 20; + p->zTxt = sqlite3_realloc64(p->zTxt, p->nAlloc); + shell_check_oom(p->zTxt); + } + + if( quote ){ + char *zCsr = p->zTxt+p->n; + *zCsr++ = quote; + for(i=0; in = (i64)(zCsr - p->zTxt); + *zCsr = '\0'; + }else{ + memcpy(p->zTxt+p->n, zAppend, nAppend); + p->n += nAppend; + p->zTxt[p->n] = '\0'; + } + } - static const ModeInfo aModeInfo[] = { - /* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */ - { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 }, - { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2, 0 }, - { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 }, - { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2, 0 }, - { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, - { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 }, - { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 }, - { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 }, - { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 }, - { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 }, - { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 }, - { "line", 13, 1, 9, 1, 1, 0, 0, 11, 1, 0 }, - { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 }, - { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2, 0 }, - { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 }, - { "psql", 0, 0, 9, 1, 1, 0, 2, 19, 2, 1 }, - { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2, 0 }, - { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 }, - { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 }, - { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2, 0 }, - { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 }, - { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 }, - { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 } - }; /* | / / | / / | | \ - ** | / / | / / | | \_ 2: columnar - ** Index into aModeStr[] | / / | | 1: line - ** | / / | | 0: other - ** | / / | \ - ** text encoding |/ | show | \ - ** v-------------------' | hdrs? | The QRF style - ** 0: n/a blob | v-----' - ** 1: plain v_---------' 0: n/a - ** 2: sql 0: auto 1: no - ** 3: csv 1: as-text 2: yes - ** 4: html 2: sql - ** 5: c 3: hex - ** 6: json 4: c - ** 5: json - ** 6: size - ******************************************************************/ /* - ** These are the column/row/line separators used by the various - ** import/export modes. + ** Attempt to determine if identifier zName needs to be quoted, either + ** because it contains non-alphanumeric characters, or because it is an + ** SQLite keyword. Be conservative in this estimate: When in doubt assume + ** that quoting is required. + ** + ** Return '"' if quoting is required. Return 0 if no quoting is required. */ - #define SEP_Column "|" - #define SEP_Row "\n" - #define SEP_Tab "\t" - #define SEP_Space " " - #define SEP_Comma "," - #define SEP_CrLf "\r\n" - #define SEP_Unit "\x1F" - #define SEP_Record "\x1E" + static char quoteChar(const char *zName){ + int i; + if( zName==0 ) return '"'; + if( !IsAlpha(zName[0]) && zName[0]!='_' ) return '"'; + for(i=0; zName[i]; i++){ + if( !IsAlnum(zName[i]) && zName[i]!='_' ) return '"'; + } + return sqlite3_keyword_check(zName, i) ? '"' : 0; + } /* - ** Default values for the various QRF limits + ** Construct a fake object name and column list to describe the structure + ** of the view, virtual table, or table valued function zSchema.zName. + ** + ** The returned string comes from sqlite3_mprintf() and should be freed + ** by the caller using sqlite3_free(). */ - #ifndef DFLT_CHAR_LIMIT - # define DFLT_CHAR_LIMIT 300 - #endif - #ifndef DFLT_LINE_LIMIT - # define DFLT_LINE_LIMIT 5 - #endif - #ifndef DFLT_TITLE_LIMIT - # define DFLT_TITLE_LIMIT 20 - #endif - #ifndef DFLT_MULTI_INSERT - # define DFLT_MULTI_INSERT 3000 - #endif + static char *shellFakeSchema( + sqlite3 *db, /* The database connection containing the vtab */ + const char *zSchema, /* Schema of the database holding the vtab */ + const char *zName /* The name of the virtual table */ + ){ + sqlite3_stmt *pStmt = 0; + char *zSql; + ShellText s; + char cQuote; + char *zDiv = "("; + int nRow = 0; + + zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;", + zSchema ? zSchema : "main", zName); + shell_check_oom(zSql); + sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + initText(&s); + if( zSchema ){ + cQuote = quoteChar(zSchema); + if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0; + appendText(&s, zSchema, cQuote); + appendText(&s, ".", 0); + } + cQuote = quoteChar(zName); + appendText(&s, zName, cQuote); + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zCol = (const char*)sqlite3_column_text(pStmt, 1); + nRow++; + appendText(&s, zDiv, 0); + zDiv = ","; + if( zCol==0 ) zCol = ""; + cQuote = quoteChar(zCol); + appendText(&s, zCol, cQuote); + } + appendText(&s, ")", 0); + sqlite3_finalize(pStmt); + if( nRow==0 ){ + freeText(&s); + s.zTxt = 0; + } + return s.zTxt; + } /* - ** Limit input nesting via .read or any other input redirect. - ** It's not too expensive, so a generous allowance can be made. + ** SQL function: strtod(X) + ** + ** Use the C-library strtod() function to convert string X into a double. + ** Used for comparing the accuracy of SQLite's internal text-to-float conversion + ** routines against the C-library. */ - #define MAX_INPUT_NESTING 25 + static void shellStrtod( + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal + ){ + char *z = (char*)sqlite3_value_text(apVal[0]); + UNUSED_PARAMETER(nVal); + if( z==0 ) return; + sqlite3_result_double(pCtx, strtod(z,0)); + } + + /* + ** SQL function: dtostr(X) + ** + ** Use the C-library printf() function to convert real value X into a string. + ** Used for comparing the accuracy of SQLite's internal float-to-text conversion + ** routines against the C-library. + */ + static void shellDtostr( + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal + ){ + double r = sqlite3_value_double(apVal[0]); + int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26; + char z[400]; + if( n<1 ) n = 1; + if( n>350 ) n = 350; + sprintf(z, "%#+.*e", n, r); + sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); + } + + /* + ** SQL function: shell_add_schema(S,X) + ** + ** Add the schema name X to the CREATE statement in S and return the result. + ** Examples: + ** + ** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x); + ** + ** Also works on + ** + ** CREATE INDEX + ** CREATE UNIQUE INDEX + ** CREATE VIEW + ** CREATE TRIGGER + ** CREATE VIRTUAL TABLE + ** + ** This UDF is used by the .schema command to insert the schema name of + ** attached databases into the middle of the sqlite_schema.sql field. + */ + static void shellAddSchemaName( + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal + ){ + static const char *aPrefix[] = { + "TABLE", + "INDEX", + "UNIQUE INDEX", + "VIEW", + "TRIGGER", + "VIRTUAL TABLE" + }; + int i = 0; + const char *zIn = (const char*)sqlite3_value_text(apVal[0]); + const char *zSchema = (const char*)sqlite3_value_text(apVal[1]); + const char *zName = (const char*)sqlite3_value_text(apVal[2]); + sqlite3 *db = sqlite3_context_db_handle(pCtx); + UNUSED_PARAMETER(nVal); + if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){ + for(i=0; i