Fossil SCM
Merge from trunk.
Commit
e63e0803b7c80670b3c39fcc6f85bcbcfe61661334478425433f955432e30286
Parent
f02094e3f329fe4…
99 files changed
+1
-1
+23
-3
+1298
-472
+4085
-1741
+108
-17
+17
-41
+43
-73
+30
-37
+72
-10
+1
-1
+1199
-181
+2
-4
+66
-38
+4
-1
+32
-1
+1
-1
+2
+10
-6
+3
-2
+8
-3
+2
+2
+37
-8
+3
-2
+178
-2
+26
-14
+12
-11
+1
-1
+88
-14
+82
-20
+2
-2
+14
-7
+2
-2
+1
-1
+1307
-216
+663
+8
-5
+4
+28
-8
+1386
-35
+1
+5
-6
+10
-10
+62
-7
+3
-2
+2
-2
+95
-2
+64
-12
+257
-141
+10
-1
+10
-14
+6
-1
+98
-53
+44
-5
+61
-21
+129
-2
+251
-58
+19
+4
-2
+33
-3
+2
-2
+34
-28
+13
-10
+4
+4
+21
-5
+34
+271
-62
+32
-4
+109
+108
-28
+4
-1
+2
-2
+112
-43
+12
-7
+2
-2
+14
-44
+16
-15
+171
-51
+2
-1
+1
-1
+4
-1
+2
+4
+19
-6
+45
-36
+39
+2
-2
+46
-11
+204
-1
+2
-1
+142
-119
+1093
+6
-6
+1
+1
-1
+3
-1
+3
-3
+1
-1
~
auto.def
~
extsrc/qrf.h
~
extsrc/shell.c
~
extsrc/sqlite3.c
~
extsrc/sqlite3.h
~
skins/ardoise/css.txt
~
skins/blitz/css.txt
~
skins/darkmode/css.txt
~
src/ajax.c
~
src/alerts.c
~
src/attach.c
~
src/backlink.c
~
src/blob.c
~
src/branch.c
~
src/builtin.c
~
src/bundle.c
~
src/capabilities.c
~
src/captcha.c
~
src/cgi.c
~
src/checkin.c
~
src/comformat.c
~
src/configure.c
~
src/content.c
~
src/db.c
~
src/default.css
~
src/delta.c
~
src/deltafunc.c
~
src/descendants.c
~
src/diff.tcl
~
src/diffcmd.c
~
src/doc.c
~
src/event.c
~
src/fileedit.c
~
src/finfo.c
~
src/forum.c
~
src/fossil.attach.js
~
src/fossil.bootstrap.js
~
src/fossil.dom.js
~
src/fossil.page.chat.js
~
src/fossil.page.forumpost.js
~
src/fossil.page.ticket.js
~
src/fossil.page.wikiedit.js
~
src/fossil.popupwidget.js
~
src/fossil.storage.js
~
src/fossil.tabs.js
~
src/graph.c
~
src/http.c
~
src/http_transport.c
~
src/info.c
~
src/login.c
~
src/main.c
~
src/main.mk
~
src/manifest.c
~
src/markdown.md
~
src/merge.c
~
src/moderate.c
~
src/name.c
~
src/path.c
~
src/repolist.c
~
src/robot.c
~
src/schema.c
~
src/security_audit.c
~
src/setup.c
~
src/setupuser.c
~
src/sqlcmd.c
~
src/stash.c
~
src/stat.c
~
src/statrep.c
~
src/style.c
~
src/style.forum.css
~
src/tag.c
~
src/tar.c
~
src/th_main.c
~
src/timeline.c
~
src/tkt.c
~
src/util.c
~
src/wiki.c
~
src/wiki.wiki
~
src/wikiformat.c
~
src/xfer.c
~
src/xsystem.c
~
tools/makemake.tcl
~
win/Makefile.mingw
~
win/Makefile.msc
~
www/antibot.wiki
~
www/caps/ref.html
~
www/changes.wiki
~
www/customskin.md
~
www/fileformat.wiki
~
www/forum.wiki
~
www/fossil-is-not-relational.md
~
www/fossil-v-git.wiki
~
www/hundredandone.md
~
www/javascript.md
~
www/mkindex.tcl
~
www/permutedindex.html
~
www/server/any/cgi.md
~
www/sync.wiki
~
www/wikitheory.wiki
M
auto.def
+1
-1
| --- auto.def | ||
| +++ auto.def | ||
| @@ -36,11 +36,11 @@ | ||
| 36 | 36 | } |
| 37 | 37 | |
| 38 | 38 | # Update the minimum required SQLite version number here, and also |
| 39 | 39 | # in src/main.c near the sqlite3_libversion_number() call. Take care |
| 40 | 40 | # that both places agree! |
| 41 | -define MINIMUM_SQLITE_VERSION "3.49.0" | |
| 41 | +define MINIMUM_SQLITE_VERSION "3.54.0" | |
| 42 | 42 | |
| 43 | 43 | # This is useful for people wanting Fossil to use an external SQLite library |
| 44 | 44 | # to compare the one they have against the minimum required |
| 45 | 45 | if {[opt-bool print-minimum-sqlite-version]} { |
| 46 | 46 | puts [get-define MINIMUM_SQLITE_VERSION] |
| 47 | 47 |
| --- auto.def | |
| +++ auto.def | |
| @@ -36,11 +36,11 @@ | |
| 36 | } |
| 37 | |
| 38 | # Update the minimum required SQLite version number here, and also |
| 39 | # in src/main.c near the sqlite3_libversion_number() call. Take care |
| 40 | # that both places agree! |
| 41 | define MINIMUM_SQLITE_VERSION "3.49.0" |
| 42 | |
| 43 | # This is useful for people wanting Fossil to use an external SQLite library |
| 44 | # to compare the one they have against the minimum required |
| 45 | if {[opt-bool print-minimum-sqlite-version]} { |
| 46 | puts [get-define MINIMUM_SQLITE_VERSION] |
| 47 |
| --- auto.def | |
| +++ auto.def | |
| @@ -36,11 +36,11 @@ | |
| 36 | } |
| 37 | |
| 38 | # Update the minimum required SQLite version number here, and also |
| 39 | # in src/main.c near the sqlite3_libversion_number() call. Take care |
| 40 | # that both places agree! |
| 41 | define MINIMUM_SQLITE_VERSION "3.54.0" |
| 42 | |
| 43 | # This is useful for people wanting Fossil to use an external SQLite library |
| 44 | # to compare the one they have against the minimum required |
| 45 | if {[opt-bool print-minimum-sqlite-version]} { |
| 46 | puts [get-define MINIMUM_SQLITE_VERSION] |
| 47 |
+23
-3
| --- extsrc/qrf.h | ||
| +++ extsrc/qrf.h | ||
| @@ -55,10 +55,14 @@ | ||
| 55 | 55 | char *(*xRender)(void*,sqlite3_value*); /* Render a value */ |
| 56 | 56 | int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */ |
| 57 | 57 | void *pRenderArg; /* First argument to the xRender callback */ |
| 58 | 58 | void *pWriteArg; /* First argument to the xWrite callback */ |
| 59 | 59 | char **pzOutput; /* Storage location for output string */ |
| 60 | + /* The following are available in iVersion 2 and later */ | |
| 61 | + unsigned char bRowCount; /* Show the number of rows at end of each query */ | |
| 62 | + char *zIFmt; /* Format string for integers */ | |
| 63 | + char *zFpFmt; /* Format string for floating point */ | |
| 60 | 64 | /* Additional fields may be added in the future */ |
| 61 | 65 | }; |
| 62 | 66 | |
| 63 | 67 | /* |
| 64 | 68 | ** Interfaces |
| @@ -68,12 +72,11 @@ | ||
| 68 | 72 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 69 | 73 | char **pzErr /* OUT: Write error message here */ |
| 70 | 74 | ); |
| 71 | 75 | |
| 72 | 76 | /* |
| 73 | -** Range of values for sqlite3_qrf_spec.aWidth[] entries and for | |
| 74 | -** sqlite3_qrf_spec.mxColWidth and .nScreenWidth | |
| 77 | +** Range of values for sqlite3_qrf_spec.aWidth[] entries. | |
| 75 | 78 | */ |
| 76 | 79 | #define QRF_MAX_WIDTH 10000 |
| 77 | 80 | #define QRF_MIN_WIDTH 0 |
| 78 | 81 | |
| 79 | 82 | /* |
| @@ -84,11 +87,11 @@ | ||
| 84 | 87 | #define QRF_STYLE_Column 2 /* One record per line in neat columns */ |
| 85 | 88 | #define QRF_STYLE_Count 3 /* Output only a count of the rows of output */ |
| 86 | 89 | #define QRF_STYLE_Csv 4 /* Comma-separated-value */ |
| 87 | 90 | #define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */ |
| 88 | 91 | #define QRF_STYLE_Explain 6 /* EXPLAIN output */ |
| 89 | -#define QRF_STYLE_Html 7 /* Generate an XHTML table */ | |
| 92 | +#define QRF_STYLE_Html 7 /* Generate HTML-style <tr><td> output */ | |
| 90 | 93 | #define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */ |
| 91 | 94 | #define QRF_STYLE_Json 9 /* Output is a list of JSON objects */ |
| 92 | 95 | #define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */ |
| 93 | 96 | #define QRF_STYLE_Line 11 /* One column per line. */ |
| 94 | 97 | #define QRF_STYLE_List 12 /* One record per line with a separator */ |
| @@ -144,10 +147,15 @@ | ||
| 144 | 147 | #define QRF_SW_On 2 /* This setting is forced on */ |
| 145 | 148 | #define QRF_Auto 0 /* Alternate spelling for QRF_*_Auto */ |
| 146 | 149 | #define QRF_No 1 /* Alternate spelling for QRF_SW_Off */ |
| 147 | 150 | #define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */ |
| 148 | 151 | |
| 152 | +/* | |
| 153 | +** Additional value allowed for bTitles | |
| 154 | +*/ | |
| 155 | +#define QRF_Always 3 /* Always show titles, even if no rows */ | |
| 156 | + | |
| 149 | 157 | /* |
| 150 | 158 | ** Possible alignment values alignment settings |
| 151 | 159 | ** |
| 152 | 160 | ** Horizontal Vertial |
| 153 | 161 | ** ---------- -------- */ |
| @@ -192,10 +200,22 @@ | ||
| 192 | 200 | ** determined as for sqlite3_qrf_wcwidth(). VT100 escape code sequences |
| 193 | 201 | ** are assigned a width of zero. |
| 194 | 202 | */ |
| 195 | 203 | size_t sqlite3_qrf_wcswidth(const char*); |
| 196 | 204 | |
| 205 | +/* | |
| 206 | +** The argument is a proposed format string for the zIFmt or zFpFmt | |
| 207 | +** parameters. Return value indicates: | |
| 208 | +** | |
| 209 | +** 0 The input is not a valid format string. If this string | |
| 210 | +** appears in either zIFmt or zFpFmt, it will be ignored. | |
| 211 | +** | |
| 212 | +** 1 The input is a valid format string for integers. | |
| 213 | +** | |
| 214 | +** 2 The input is a valid format string for floating point. | |
| 215 | +*/ | |
| 216 | +int sqlite3_qrf_ckformat(const char*); | |
| 197 | 217 | |
| 198 | 218 | #ifdef __cplusplus |
| 199 | 219 | } |
| 200 | 220 | #endif |
| 201 | 221 | #endif /* !defined(SQLITE_QRF_H) */ |
| 202 | 222 |
| --- extsrc/qrf.h | |
| +++ extsrc/qrf.h | |
| @@ -55,10 +55,14 @@ | |
| 55 | char *(*xRender)(void*,sqlite3_value*); /* Render a value */ |
| 56 | int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */ |
| 57 | void *pRenderArg; /* First argument to the xRender callback */ |
| 58 | void *pWriteArg; /* First argument to the xWrite callback */ |
| 59 | char **pzOutput; /* Storage location for output string */ |
| 60 | /* Additional fields may be added in the future */ |
| 61 | }; |
| 62 | |
| 63 | /* |
| 64 | ** Interfaces |
| @@ -68,12 +72,11 @@ | |
| 68 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 69 | char **pzErr /* OUT: Write error message here */ |
| 70 | ); |
| 71 | |
| 72 | /* |
| 73 | ** Range of values for sqlite3_qrf_spec.aWidth[] entries and for |
| 74 | ** sqlite3_qrf_spec.mxColWidth and .nScreenWidth |
| 75 | */ |
| 76 | #define QRF_MAX_WIDTH 10000 |
| 77 | #define QRF_MIN_WIDTH 0 |
| 78 | |
| 79 | /* |
| @@ -84,11 +87,11 @@ | |
| 84 | #define QRF_STYLE_Column 2 /* One record per line in neat columns */ |
| 85 | #define QRF_STYLE_Count 3 /* Output only a count of the rows of output */ |
| 86 | #define QRF_STYLE_Csv 4 /* Comma-separated-value */ |
| 87 | #define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */ |
| 88 | #define QRF_STYLE_Explain 6 /* EXPLAIN output */ |
| 89 | #define QRF_STYLE_Html 7 /* Generate an XHTML table */ |
| 90 | #define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */ |
| 91 | #define QRF_STYLE_Json 9 /* Output is a list of JSON objects */ |
| 92 | #define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */ |
| 93 | #define QRF_STYLE_Line 11 /* One column per line. */ |
| 94 | #define QRF_STYLE_List 12 /* One record per line with a separator */ |
| @@ -144,10 +147,15 @@ | |
| 144 | #define QRF_SW_On 2 /* This setting is forced on */ |
| 145 | #define QRF_Auto 0 /* Alternate spelling for QRF_*_Auto */ |
| 146 | #define QRF_No 1 /* Alternate spelling for QRF_SW_Off */ |
| 147 | #define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */ |
| 148 | |
| 149 | /* |
| 150 | ** Possible alignment values alignment settings |
| 151 | ** |
| 152 | ** Horizontal Vertial |
| 153 | ** ---------- -------- */ |
| @@ -192,10 +200,22 @@ | |
| 192 | ** determined as for sqlite3_qrf_wcwidth(). VT100 escape code sequences |
| 193 | ** are assigned a width of zero. |
| 194 | */ |
| 195 | size_t sqlite3_qrf_wcswidth(const char*); |
| 196 | |
| 197 | |
| 198 | #ifdef __cplusplus |
| 199 | } |
| 200 | #endif |
| 201 | #endif /* !defined(SQLITE_QRF_H) */ |
| 202 |
| --- extsrc/qrf.h | |
| +++ extsrc/qrf.h | |
| @@ -55,10 +55,14 @@ | |
| 55 | char *(*xRender)(void*,sqlite3_value*); /* Render a value */ |
| 56 | int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */ |
| 57 | void *pRenderArg; /* First argument to the xRender callback */ |
| 58 | void *pWriteArg; /* First argument to the xWrite callback */ |
| 59 | char **pzOutput; /* Storage location for output string */ |
| 60 | /* The following are available in iVersion 2 and later */ |
| 61 | unsigned char bRowCount; /* Show the number of rows at end of each query */ |
| 62 | char *zIFmt; /* Format string for integers */ |
| 63 | char *zFpFmt; /* Format string for floating point */ |
| 64 | /* Additional fields may be added in the future */ |
| 65 | }; |
| 66 | |
| 67 | /* |
| 68 | ** Interfaces |
| @@ -68,12 +72,11 @@ | |
| 72 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 73 | char **pzErr /* OUT: Write error message here */ |
| 74 | ); |
| 75 | |
| 76 | /* |
| 77 | ** Range of values for sqlite3_qrf_spec.aWidth[] entries. |
| 78 | */ |
| 79 | #define QRF_MAX_WIDTH 10000 |
| 80 | #define QRF_MIN_WIDTH 0 |
| 81 | |
| 82 | /* |
| @@ -84,11 +87,11 @@ | |
| 87 | #define QRF_STYLE_Column 2 /* One record per line in neat columns */ |
| 88 | #define QRF_STYLE_Count 3 /* Output only a count of the rows of output */ |
| 89 | #define QRF_STYLE_Csv 4 /* Comma-separated-value */ |
| 90 | #define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */ |
| 91 | #define QRF_STYLE_Explain 6 /* EXPLAIN output */ |
| 92 | #define QRF_STYLE_Html 7 /* Generate HTML-style <tr><td> output */ |
| 93 | #define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */ |
| 94 | #define QRF_STYLE_Json 9 /* Output is a list of JSON objects */ |
| 95 | #define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */ |
| 96 | #define QRF_STYLE_Line 11 /* One column per line. */ |
| 97 | #define QRF_STYLE_List 12 /* One record per line with a separator */ |
| @@ -144,10 +147,15 @@ | |
| 147 | #define QRF_SW_On 2 /* This setting is forced on */ |
| 148 | #define QRF_Auto 0 /* Alternate spelling for QRF_*_Auto */ |
| 149 | #define QRF_No 1 /* Alternate spelling for QRF_SW_Off */ |
| 150 | #define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */ |
| 151 | |
| 152 | /* |
| 153 | ** Additional value allowed for bTitles |
| 154 | */ |
| 155 | #define QRF_Always 3 /* Always show titles, even if no rows */ |
| 156 | |
| 157 | /* |
| 158 | ** Possible alignment values alignment settings |
| 159 | ** |
| 160 | ** Horizontal Vertial |
| 161 | ** ---------- -------- */ |
| @@ -192,10 +200,22 @@ | |
| 200 | ** determined as for sqlite3_qrf_wcwidth(). VT100 escape code sequences |
| 201 | ** are assigned a width of zero. |
| 202 | */ |
| 203 | size_t sqlite3_qrf_wcswidth(const char*); |
| 204 | |
| 205 | /* |
| 206 | ** The argument is a proposed format string for the zIFmt or zFpFmt |
| 207 | ** parameters. Return value indicates: |
| 208 | ** |
| 209 | ** 0 The input is not a valid format string. If this string |
| 210 | ** appears in either zIFmt or zFpFmt, it will be ignored. |
| 211 | ** |
| 212 | ** 1 The input is a valid format string for integers. |
| 213 | ** |
| 214 | ** 2 The input is a valid format string for floating point. |
| 215 | */ |
| 216 | int sqlite3_qrf_ckformat(const char*); |
| 217 | |
| 218 | #ifdef __cplusplus |
| 219 | } |
| 220 | #endif |
| 221 | #endif /* !defined(SQLITE_QRF_H) */ |
| 222 |
+1298
-472
| --- extsrc/shell.c | ||
| +++ extsrc/shell.c | ||
| @@ -5,16 +5,16 @@ | ||
| 5 | 5 | ** |
| 6 | 6 | ** ext/expert/sqlite3expert.c |
| 7 | 7 | ** ext/expert/sqlite3expert.h |
| 8 | 8 | ** ext/intck/sqlite3intck.c |
| 9 | 9 | ** ext/intck/sqlite3intck.h |
| 10 | -** ext/misc/analyze.c | |
| 11 | 10 | ** ext/misc/appendvfs.c |
| 12 | 11 | ** ext/misc/base64.c |
| 13 | 12 | ** ext/misc/base85.c |
| 14 | 13 | ** ext/misc/completion.c |
| 15 | 14 | ** ext/misc/decimal.c |
| 15 | +** ext/misc/diskused.c | |
| 16 | 16 | ** ext/misc/fileio.c |
| 17 | 17 | ** ext/misc/ieee754.c |
| 18 | 18 | ** ext/misc/memtrace.c |
| 19 | 19 | ** ext/misc/pcachetrace.c |
| 20 | 20 | ** ext/misc/regexp.c |
| @@ -23,10 +23,11 @@ | ||
| 23 | 23 | ** ext/misc/shathree.c |
| 24 | 24 | ** ext/misc/sqlar.c |
| 25 | 25 | ** ext/misc/sqlite3_stdio.c |
| 26 | 26 | ** ext/misc/sqlite3_stdio.h |
| 27 | 27 | ** ext/misc/stmtrand.c |
| 28 | +** ext/misc/strdup.c | |
| 28 | 29 | ** ext/misc/uint.c |
| 29 | 30 | ** ext/misc/vfstrace.c |
| 30 | 31 | ** ext/misc/windirent.h |
| 31 | 32 | ** ext/misc/zipfile.c |
| 32 | 33 | ** ext/qrf/qrf.c |
| @@ -154,10 +155,11 @@ | ||
| 154 | 155 | #include <string.h> |
| 155 | 156 | #include <stdio.h> |
| 156 | 157 | #include <assert.h> |
| 157 | 158 | #include <math.h> |
| 158 | 159 | #include <stdint.h> |
| 160 | +#include <time.h> | |
| 159 | 161 | #include "sqlite3.h" |
| 160 | 162 | typedef sqlite3_int64 i64; |
| 161 | 163 | typedef sqlite3_uint64 u64; |
| 162 | 164 | typedef unsigned char u8; |
| 163 | 165 | #include <ctype.h> |
| @@ -190,13 +192,14 @@ | ||
| 190 | 192 | #include <sys/stat.h> |
| 191 | 193 | |
| 192 | 194 | #if HAVE_READLINE |
| 193 | 195 | # include <readline/readline.h> |
| 194 | 196 | # include <readline/history.h> |
| 195 | -#endif | |
| 196 | - | |
| 197 | -#if HAVE_EDITLINE | |
| 197 | +#elif HAVE_EDITLINE | |
| 198 | +/* If both HAVE_READLINE and HAVE_EDITLINE are true, assume that this | |
| 199 | +** libedit installation does not have its own headers, instead using | |
| 200 | +** those from libreadline. */ | |
| 198 | 201 | # include <editline/readline.h> |
| 199 | 202 | #endif |
| 200 | 203 | |
| 201 | 204 | #if HAVE_EDITLINE || HAVE_READLINE |
| 202 | 205 | |
| @@ -203,28 +206,38 @@ | ||
| 203 | 206 | # define shell_add_history(X) add_history(X) |
| 204 | 207 | # define shell_read_history(X) read_history(X) |
| 205 | 208 | # define shell_write_history(X) write_history(X) |
| 206 | 209 | # define shell_stifle_history(X) stifle_history(X) |
| 207 | 210 | # define shell_readline(X) readline(X) |
| 211 | +# define SHELL_CMDLINE_EDIT_AVAILABLE 1 /* command-line editing available */ | |
| 208 | 212 | |
| 209 | 213 | #elif HAVE_LINENOISE |
| 210 | 214 | |
| 211 | 215 | # include "linenoise.h" |
| 212 | 216 | # define shell_add_history(X) linenoiseHistoryAdd(X) |
| 213 | 217 | # define shell_read_history(X) linenoiseHistoryLoad(X) |
| 214 | 218 | # define shell_write_history(X) linenoiseHistorySave(X) |
| 215 | 219 | # define shell_stifle_history(X) linenoiseHistorySetMaxLen(X) |
| 216 | 220 | # define shell_readline(X) linenoise(X) |
| 221 | +# define SHELL_CMDLINE_EDIT_AVAILABLE 1 /* command-line editing available */ | |
| 217 | 222 | |
| 218 | 223 | #else |
| 219 | 224 | |
| 220 | 225 | # define shell_read_history(X) |
| 221 | 226 | # define shell_write_history(X) |
| 222 | 227 | # define shell_stifle_history(X) |
| 228 | +# define SHELL_CMDLINE_EDIT_AVAILABLE 0 /* command-line editing not available */ | |
| 229 | +#endif | |
| 223 | 230 | |
| 224 | -# define SHELL_USE_LOCAL_GETLINE 1 | |
| 225 | -#endif | |
| 231 | +/* | |
| 232 | +** Global variable shellCmdLineEdit determines whether or not command-line | |
| 233 | +** editing is enabled. It defaults to 1 if the CLI is linked against a | |
| 234 | +** command-line editing library (linenoise, readline, or editline) and | |
| 235 | +** to 0 if no command-line editing library is available. The | |
| 236 | +** "--cmdline-edit off" command-line option will change this value to 0. | |
| 237 | +*/ | |
| 238 | +static int shellCmdLineEdit = SHELL_CMDLINE_EDIT_AVAILABLE; | |
| 226 | 239 | |
| 227 | 240 | #ifndef deliberate_fall_through |
| 228 | 241 | /* Quiet some compilers about some of our intentional code. */ |
| 229 | 242 | # if defined(GCC_VERSION) && GCC_VERSION>=7000000 |
| 230 | 243 | # define deliberate_fall_through __attribute__((fallthrough)); |
| @@ -731,10 +744,14 @@ | ||
| 731 | 744 | char *(*xRender)(void*,sqlite3_value*); /* Render a value */ |
| 732 | 745 | int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */ |
| 733 | 746 | void *pRenderArg; /* First argument to the xRender callback */ |
| 734 | 747 | void *pWriteArg; /* First argument to the xWrite callback */ |
| 735 | 748 | char **pzOutput; /* Storage location for output string */ |
| 749 | + /* The following are available in iVersion 2 and later */ | |
| 750 | + unsigned char bRowCount; /* Show the number of rows at end of each query */ | |
| 751 | + char *zIFmt; /* Format string for integers */ | |
| 752 | + char *zFpFmt; /* Format string for floating point */ | |
| 736 | 753 | /* Additional fields may be added in the future */ |
| 737 | 754 | }; |
| 738 | 755 | |
| 739 | 756 | /* |
| 740 | 757 | ** Interfaces |
| @@ -744,12 +761,11 @@ | ||
| 744 | 761 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 745 | 762 | char **pzErr /* OUT: Write error message here */ |
| 746 | 763 | ); |
| 747 | 764 | |
| 748 | 765 | /* |
| 749 | -** Range of values for sqlite3_qrf_spec.aWidth[] entries and for | |
| 750 | -** sqlite3_qrf_spec.mxColWidth and .nScreenWidth | |
| 766 | +** Range of values for sqlite3_qrf_spec.aWidth[] entries. | |
| 751 | 767 | */ |
| 752 | 768 | #define QRF_MAX_WIDTH 10000 |
| 753 | 769 | #define QRF_MIN_WIDTH 0 |
| 754 | 770 | |
| 755 | 771 | /* |
| @@ -760,11 +776,11 @@ | ||
| 760 | 776 | #define QRF_STYLE_Column 2 /* One record per line in neat columns */ |
| 761 | 777 | #define QRF_STYLE_Count 3 /* Output only a count of the rows of output */ |
| 762 | 778 | #define QRF_STYLE_Csv 4 /* Comma-separated-value */ |
| 763 | 779 | #define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */ |
| 764 | 780 | #define QRF_STYLE_Explain 6 /* EXPLAIN output */ |
| 765 | -#define QRF_STYLE_Html 7 /* Generate an XHTML table */ | |
| 781 | +#define QRF_STYLE_Html 7 /* Generate HTML-style <tr><td> output */ | |
| 766 | 782 | #define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */ |
| 767 | 783 | #define QRF_STYLE_Json 9 /* Output is a list of JSON objects */ |
| 768 | 784 | #define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */ |
| 769 | 785 | #define QRF_STYLE_Line 11 /* One column per line. */ |
| 770 | 786 | #define QRF_STYLE_List 12 /* One record per line with a separator */ |
| @@ -820,10 +836,15 @@ | ||
| 820 | 836 | #define QRF_SW_On 2 /* This setting is forced on */ |
| 821 | 837 | #define QRF_Auto 0 /* Alternate spelling for QRF_*_Auto */ |
| 822 | 838 | #define QRF_No 1 /* Alternate spelling for QRF_SW_Off */ |
| 823 | 839 | #define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */ |
| 824 | 840 | |
| 841 | +/* | |
| 842 | +** Additional value allowed for bTitles | |
| 843 | +*/ | |
| 844 | +#define QRF_Always 3 /* Always show titles, even if no rows */ | |
| 845 | + | |
| 825 | 846 | /* |
| 826 | 847 | ** Possible alignment values alignment settings |
| 827 | 848 | ** |
| 828 | 849 | ** Horizontal Vertial |
| 829 | 850 | ** ---------- -------- */ |
| @@ -868,10 +889,22 @@ | ||
| 868 | 889 | ** determined as for sqlite3_qrf_wcwidth(). VT100 escape code sequences |
| 869 | 890 | ** are assigned a width of zero. |
| 870 | 891 | */ |
| 871 | 892 | size_t sqlite3_qrf_wcswidth(const char*); |
| 872 | 893 | |
| 894 | +/* | |
| 895 | +** The argument is a proposed format string for the zIFmt or zFpFmt | |
| 896 | +** parameters. Return value indicates: | |
| 897 | +** | |
| 898 | +** 0 The input is not a valid format string. If this string | |
| 899 | +** appears in either zIFmt or zFpFmt, it will be ignored. | |
| 900 | +** | |
| 901 | +** 1 The input is a valid format string for integers. | |
| 902 | +** | |
| 903 | +** 2 The input is a valid format string for floating point. | |
| 904 | +*/ | |
| 905 | +int sqlite3_qrf_ckformat(const char*); | |
| 873 | 906 | |
| 874 | 907 | #ifdef __cplusplus |
| 875 | 908 | } |
| 876 | 909 | #endif |
| 877 | 910 | #endif /* !defined(SQLITE_QRF_H) */ |
| @@ -950,10 +983,11 @@ | ||
| 950 | 983 | } sExpln; |
| 951 | 984 | unsigned int nIns; /* Bytes used for current INSERT stmt */ |
| 952 | 985 | } u; |
| 953 | 986 | sqlite3_int64 nRow; /* Number of rows handled so far */ |
| 954 | 987 | int *actualWidth; /* Actual width of each column */ |
| 988 | + char zFmt[24]; /* Space to hold the true integer rendering fmt */ | |
| 955 | 989 | sqlite3_qrf_spec spec; /* Copy of the original spec */ |
| 956 | 990 | }; |
| 957 | 991 | |
| 958 | 992 | /* |
| 959 | 993 | ** Data for substitute ctype.h functions. Used for x-platform |
| @@ -993,10 +1027,48 @@ | ||
| 993 | 1027 | # define deliberate_fall_through __attribute__((fallthrough)); |
| 994 | 1028 | # else |
| 995 | 1029 | # define deliberate_fall_through |
| 996 | 1030 | # endif |
| 997 | 1031 | #endif |
| 1032 | + | |
| 1033 | +/* | |
| 1034 | +** The argument is a proposed format string for the zIFmt or zFpFmt | |
| 1035 | +** parameters. Return value indicates: | |
| 1036 | +** | |
| 1037 | +** 0 The input is not a valid format string. If this string | |
| 1038 | +** appears in either zIFmt or zFpFmt, it will be ignored. | |
| 1039 | +** | |
| 1040 | +** 1 The input is a valid format string for integers. | |
| 1041 | +** | |
| 1042 | +** 2 The input is a valid format string for floating point. | |
| 1043 | +*/ | |
| 1044 | +int sqlite3_qrf_ckformat(const char *z){ | |
| 1045 | + size_t n; | |
| 1046 | + if( z==0 ) return 0; | |
| 1047 | + if( z[0]!='%' ) return 0; | |
| 1048 | + z++; | |
| 1049 | + n = strspn(z,"+-,#0"); | |
| 1050 | + if( n>5 ) return 0; | |
| 1051 | + z += n; | |
| 1052 | + if( z[0]>='1' && z[0]<='9' ){ | |
| 1053 | + n = strspn(z,"0123456789"); | |
| 1054 | + if( n>3 ) return 0; | |
| 1055 | + z += n; | |
| 1056 | + } | |
| 1057 | + if( z[0]=='.' ){ | |
| 1058 | + z++; | |
| 1059 | + n = strspn(z,"0123456789"); | |
| 1060 | + if( n>3 ) return 0; | |
| 1061 | + z += n; | |
| 1062 | + } | |
| 1063 | + n = strspn(z,"eEgGf"); | |
| 1064 | + if( n==1 && z[1]==0 ) return 2; | |
| 1065 | + n = strspn(z,"dxXo"); | |
| 1066 | + if( n==1 && z[1]==0 ) return 1; | |
| 1067 | + return 0; | |
| 1068 | +} | |
| 1069 | + | |
| 998 | 1070 | |
| 999 | 1071 | /* |
| 1000 | 1072 | ** Set an error code and error message. |
| 1001 | 1073 | */ |
| 1002 | 1074 | static void qrfError( |
| @@ -1129,10 +1201,14 @@ | ||
| 1129 | 1201 | sqlite3_str_append(pOut, "-", 1); |
| 1130 | 1202 | } |
| 1131 | 1203 | if( N<10000 ){ |
| 1132 | 1204 | sqlite3_str_appendf(pOut, "%4lld ", N); |
| 1133 | 1205 | return; |
| 1206 | + } | |
| 1207 | + if( N>=9223372036854775800LL ){ | |
| 1208 | + sqlite3_str_appendf(pOut, "%.2fE", 1e-18*(double)N); | |
| 1209 | + return; | |
| 1134 | 1210 | } |
| 1135 | 1211 | for(i=1; i<=18; i++){ |
| 1136 | 1212 | N = (N+5)/10; |
| 1137 | 1213 | if( N<10000 ){ |
| 1138 | 1214 | int n = (int)N; |
| @@ -1289,12 +1365,12 @@ | ||
| 1289 | 1365 | if( nCycle>=0 || nLoop>=0 || nRow>=0 ){ |
| 1290 | 1366 | int nSp = 0; |
| 1291 | 1367 | sqlite3_str_reset(pStats); |
| 1292 | 1368 | if( nCycle>=0 && nTotal>0 ){ |
| 1293 | 1369 | qrfApproxInt64(pStats, nCycle); |
| 1294 | - sqlite3_str_appendf(pStats, " %3d%%", | |
| 1295 | - ((nCycle*100)+nTotal/2) / nTotal | |
| 1370 | + sqlite3_str_appendf(pStats, " %3.0f%%", | |
| 1371 | + ((100.0*(double)nCycle)+nTotal/2.0) / (double)nTotal | |
| 1296 | 1372 | ); |
| 1297 | 1373 | nSp = 2; |
| 1298 | 1374 | } |
| 1299 | 1375 | if( nLoop>=0 ){ |
| 1300 | 1376 | if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' '); |
| @@ -1787,11 +1863,11 @@ | ||
| 1787 | 1863 | } |
| 1788 | 1864 | if( i>0 ){ |
| 1789 | 1865 | sqlite3_str_append(pOut, (const char*)z, i); |
| 1790 | 1866 | } |
| 1791 | 1867 | switch( z[i] ){ |
| 1792 | - case '>': sqlite3_str_append(pOut, "<", 4); break; | |
| 1868 | + case '>': sqlite3_str_append(pOut, ">", 4); break; | |
| 1793 | 1869 | case '&': sqlite3_str_append(pOut, "&", 5); break; |
| 1794 | 1870 | case '<': sqlite3_str_append(pOut, "<", 4); break; |
| 1795 | 1871 | case '"': sqlite3_str_append(pOut, """, 6); break; |
| 1796 | 1872 | case '\'': sqlite3_str_append(pOut, "'", 5); break; |
| 1797 | 1873 | default: i--; |
| @@ -1977,16 +2053,22 @@ | ||
| 1977 | 2053 | return; |
| 1978 | 2054 | } |
| 1979 | 2055 | } |
| 1980 | 2056 | switch( sqlite3_column_type(p->pStmt,iCol) ){ |
| 1981 | 2057 | case SQLITE_INTEGER: { |
| 1982 | - sqlite3_str_appendf(pOut, "%lld", sqlite3_column_int64(p->pStmt,iCol)); | |
| 2058 | + sqlite3_str_appendf(pOut, p->spec.zIFmt, | |
| 2059 | + sqlite3_column_int64(p->pStmt,iCol)); | |
| 1983 | 2060 | break; |
| 1984 | 2061 | } |
| 1985 | 2062 | case SQLITE_FLOAT: { |
| 1986 | - const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol); | |
| 1987 | - sqlite3_str_appendall(pOut, zTxt); | |
| 2063 | + if( p->spec.zFpFmt ){ | |
| 2064 | + double r = sqlite3_column_double(p->pStmt,iCol); | |
| 2065 | + sqlite3_str_appendf(pOut,p->spec.zFpFmt,r); | |
| 2066 | + }else{ | |
| 2067 | + const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol); | |
| 2068 | + sqlite3_str_appendall(pOut, zTxt); | |
| 2069 | + } | |
| 1988 | 2070 | break; |
| 1989 | 2071 | } |
| 1990 | 2072 | case SQLITE_BLOB: { |
| 1991 | 2073 | if( p->spec.bTextJsonb==QRF_Yes ){ |
| 1992 | 2074 | const char *zJson = qrfJsonbToJson(p, iCol); |
| @@ -2281,11 +2363,11 @@ | ||
| 2281 | 2363 | if( bWrap && z[i]!=0 && !qrfSpace(z[i]) && qrfAlnum(c)==qrfAlnum(z[i]) ){ |
| 2282 | 2364 | /* Perhaps try to back up to a better place to break the line */ |
| 2283 | 2365 | for(k=i-1; k>=i/2; k--){ |
| 2284 | 2366 | if( qrfSpace(z[k]) ) break; |
| 2285 | 2367 | } |
| 2286 | - if( k<i/2 ){ | |
| 2368 | + if( k<i/2 && i/2>0 ){ | |
| 2287 | 2369 | for(k=i; k>=i/2; k--){ |
| 2288 | 2370 | if( qrfAlnum(z[k-1])!=qrfAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break; |
| 2289 | 2371 | } |
| 2290 | 2372 | } |
| 2291 | 2373 | if( k>=i/2 ){ |
| @@ -2522,10 +2604,14 @@ | ||
| 2522 | 2604 | /* Doubled horizontal lines: */ |
| 2523 | 2605 | #define DBL_24 "\342\225\220" /* U+2550 === */ |
| 2524 | 2606 | #define DBL_123 "\342\225\236" /* U+255e |= */ |
| 2525 | 2607 | #define DBL_134 "\342\225\241" /* U+2561 =| */ |
| 2526 | 2608 | #define DBL_1234 "\342\225\252" /* U+256a =|= */ |
| 2609 | +#define DBL_12 "\342\225\230" /* U+2558 `= */ | |
| 2610 | +#define DBL_14 "\342\225\233" /* U+255b =' */ | |
| 2611 | +#define DBL_124 "\342\225\247" /* U+2567 ='= */ | |
| 2612 | + | |
| 2527 | 2613 | |
| 2528 | 2614 | /* Draw horizontal line N characters long using unicode box |
| 2529 | 2615 | ** characters |
| 2530 | 2616 | */ |
| 2531 | 2617 | static void qrfBoxLine(sqlite3_str *pOut, int N, int bDbl){ |
| @@ -2532,28 +2618,28 @@ | ||
| 2532 | 2618 | const char *azDash[2] = { |
| 2533 | 2619 | BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24, |
| 2534 | 2620 | DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 |
| 2535 | 2621 | };/* 0 1 2 3 4 5 6 7 8 9 */ |
| 2536 | 2622 | const int nDash = 30; |
| 2537 | - N *= 3; | |
| 2538 | - while( N>nDash ){ | |
| 2623 | + i64 nn = 3*(i64)N; | |
| 2624 | + while( nn>nDash ){ | |
| 2539 | 2625 | sqlite3_str_append(pOut, azDash[bDbl], nDash); |
| 2540 | - N -= nDash; | |
| 2626 | + nn -= nDash; | |
| 2541 | 2627 | } |
| 2542 | - sqlite3_str_append(pOut, azDash[bDbl], N); | |
| 2628 | + sqlite3_str_append(pOut, azDash[bDbl], (int)nn); | |
| 2543 | 2629 | } |
| 2544 | 2630 | |
| 2545 | 2631 | /* |
| 2546 | 2632 | ** Draw a horizontal separator for a QRF_STYLE_Box table. |
| 2547 | 2633 | */ |
| 2548 | 2634 | static void qrfBoxSeparator( |
| 2549 | - sqlite3_str *pOut, | |
| 2550 | - qrfColData *p, | |
| 2551 | - const char *zSep1, | |
| 2552 | - const char *zSep2, | |
| 2553 | - const char *zSep3, | |
| 2554 | - int bDbl | |
| 2635 | + sqlite3_str *pOut, /* Output to this sqlite3_str */ | |
| 2636 | + qrfColData *p, /* Columnar data */ | |
| 2637 | + const char *zSep1, /* Left margin */ | |
| 2638 | + const char *zSep2, /* Column separator */ | |
| 2639 | + const char *zSep3, /* Right margin */ | |
| 2640 | + int bDbl /* True for double-lines */ | |
| 2555 | 2641 | ){ |
| 2556 | 2642 | int i; |
| 2557 | 2643 | if( p->nCol>0 ){ |
| 2558 | 2644 | int useBorder = p->p->spec.bBorder!=QRF_No; |
| 2559 | 2645 | if( useBorder ){ |
| @@ -2568,10 +2654,36 @@ | ||
| 2568 | 2654 | sqlite3_str_appendall(pOut, zSep3); |
| 2569 | 2655 | } |
| 2570 | 2656 | } |
| 2571 | 2657 | sqlite3_str_append(pOut, "\n", 1); |
| 2572 | 2658 | } |
| 2659 | + | |
| 2660 | +/* | |
| 2661 | +** Draw a horizontal separator for a QRF_STYLE_Column table. | |
| 2662 | +** This style of separator is only used for separating the title | |
| 2663 | +** from the content. | |
| 2664 | +*/ | |
| 2665 | +static void qrfColumnSeparator( | |
| 2666 | + sqlite3_str *pOut, /* Output to this sqlite3_str */ | |
| 2667 | + qrfColData *p, /* Columnar data */ | |
| 2668 | + const char *colSep, /* Column separator text */ | |
| 2669 | + int szColSep, /* Size of zColSep in bytes */ | |
| 2670 | + const char *rowSep, /* Row separator text */ | |
| 2671 | + int szRowSep /* Size of zRowSep in bytes */ | |
| 2672 | +){ | |
| 2673 | + int j; | |
| 2674 | + int nColumn = p->nCol; | |
| 2675 | + for(j=0; j<nColumn; j++){ | |
| 2676 | + sqlite3_str_appendchar(pOut, p->a[j].w, '-'); | |
| 2677 | + if( j<nColumn-1 ){ | |
| 2678 | + sqlite3_str_append(pOut, colSep, szColSep); | |
| 2679 | + }else{ | |
| 2680 | + qrfRTrim(pOut); | |
| 2681 | + sqlite3_str_append(pOut, rowSep, szRowSep); | |
| 2682 | + } | |
| 2683 | + } | |
| 2684 | +} | |
| 2573 | 2685 | |
| 2574 | 2686 | /* |
| 2575 | 2687 | ** Load into pData the default alignment for the body of a table. |
| 2576 | 2688 | */ |
| 2577 | 2689 | static void qrfLoadAlignment(qrfColData *pData, Qrf *p){ |
| @@ -2610,11 +2722,11 @@ | ||
| 2610 | 2722 | int nSW /* Screen width */ |
| 2611 | 2723 | ){ |
| 2612 | 2724 | int i; /* Loop counter */ |
| 2613 | 2725 | int nr; /* Number of rows */ |
| 2614 | 2726 | int w = 0; /* Width of the current column */ |
| 2615 | - int t; /* Total width of all columns */ | |
| 2727 | + i64 t; /* Total width of all columns */ | |
| 2616 | 2728 | int *aw; /* Array of individual column widths */ |
| 2617 | 2729 | |
| 2618 | 2730 | aw = sqlite3_malloc64( sizeof(int)*nCol ); |
| 2619 | 2731 | if( aw==0 ){ |
| 2620 | 2732 | qrfOom(p); |
| @@ -2748,12 +2860,15 @@ | ||
| 2748 | 2860 | }else{ |
| 2749 | 2861 | sepW = pData->nCol*3 + 1; |
| 2750 | 2862 | if( p->spec.bBorder==QRF_No ) sepW -= 2; |
| 2751 | 2863 | } |
| 2752 | 2864 | nCol = pData->nCol; |
| 2753 | - for(i=sumW=0; i<nCol; i++) sumW += pData->a[i].w; | |
| 2754 | - if( p->spec.nScreenWidth >= sumW+sepW ) return; | |
| 2865 | + for(i=0, sumW=0; i<nCol; i++){ | |
| 2866 | + if( sumW > 2147483647 - pData->a[i].w ) return; | |
| 2867 | + sumW += pData->a[i].w; | |
| 2868 | + } | |
| 2869 | + if( p->spec.nScreenWidth >= (i64)sumW + sepW ) return; | |
| 2755 | 2870 | |
| 2756 | 2871 | /* First thing to do is reduce the separation between columns */ |
| 2757 | 2872 | pData->nMargin = 0; |
| 2758 | 2873 | if( p->spec.eStyle==QRF_STYLE_Column ){ |
| 2759 | 2874 | sepW = pData->nCol - 1; |
| @@ -2823,11 +2938,25 @@ | ||
| 2823 | 2938 | sqlite3_str *pStr; /* Temporary rendering */ |
| 2824 | 2939 | qrfColData data; /* Columnar layout data */ |
| 2825 | 2940 | int bRTrim; /* Trim trailing space */ |
| 2826 | 2941 | |
| 2827 | 2942 | rc = sqlite3_step(p->pStmt); |
| 2828 | - if( rc!=SQLITE_ROW || nColumn==0 ){ | |
| 2943 | + if( nColumn==0 ){ | |
| 2944 | + return; /* Not a query. No results every shown. */ | |
| 2945 | + } | |
| 2946 | + if( rc==SQLITE_DONE && nColumn>0 ){ | |
| 2947 | + /* Empty query */ | |
| 2948 | + if( p->spec.bTitles==QRF_Always ){ | |
| 2949 | + /* fall through into the columnar logic below */ | |
| 2950 | + }else{ | |
| 2951 | + if( p->spec.bRowCount==QRF_Yes ){ | |
| 2952 | + sqlite3_str_appendf(p->pOut, "(0 rows)\n"); | |
| 2953 | + qrfWrite(p); | |
| 2954 | + } | |
| 2955 | + return; /* No output, other than the row count */ | |
| 2956 | + } | |
| 2957 | + }else if( rc!=SQLITE_ROW ){ | |
| 2829 | 2958 | return; /* No output */ |
| 2830 | 2959 | } |
| 2831 | 2960 | |
| 2832 | 2961 | /* Initialize the data container */ |
| 2833 | 2962 | memset(&data, 0, sizeof(data)); |
| @@ -2840,12 +2969,12 @@ | ||
| 2840 | 2969 | } |
| 2841 | 2970 | memset(data.a, 0, nColumn*sizeof(struct qrfPerCol) ); |
| 2842 | 2971 | if( qrfColDataEnlarge(&data) ) return; |
| 2843 | 2972 | assert( data.az!=0 ); |
| 2844 | 2973 | |
| 2845 | - /* Load the column header names and all cell content into data */ | |
| 2846 | - if( p->spec.bTitles==QRF_Yes ){ | |
| 2974 | + /* Load the column header names into data */ | |
| 2975 | + if( p->spec.bTitles>=QRF_Yes ){ | |
| 2847 | 2976 | unsigned char saved_eText = p->spec.eText; |
| 2848 | 2977 | p->spec.eText = p->spec.eTitle; |
| 2849 | 2978 | memset(data.abNum, 0, nColumn); |
| 2850 | 2979 | for(i=0; i<nColumn; i++){ |
| 2851 | 2980 | const char *z = (const char*)sqlite3_column_name(p->pStmt,i); |
| @@ -2866,13 +2995,14 @@ | ||
| 2866 | 2995 | data.n++; |
| 2867 | 2996 | if( w>data.a[i].mxW ) data.a[i].mxW = w; |
| 2868 | 2997 | if( nNL ) data.bMultiRow = 1; |
| 2869 | 2998 | } |
| 2870 | 2999 | p->spec.eText = saved_eText; |
| 2871 | - p->nRow++; | |
| 2872 | 3000 | } |
| 2873 | - do{ | |
| 3001 | + | |
| 3002 | + /* Load query results into data */ | |
| 3003 | + while( rc==SQLITE_ROW && p->iErr==SQLITE_OK ){ | |
| 2874 | 3004 | if( data.n+nColumn > data.nAlloc ){ |
| 2875 | 3005 | if( qrfColDataEnlarge(&data) ) return; |
| 2876 | 3006 | } |
| 2877 | 3007 | for(i=0; i<nColumn; i++){ |
| 2878 | 3008 | char *z; |
| @@ -2889,11 +3019,12 @@ | ||
| 2889 | 3019 | data.n++; |
| 2890 | 3020 | if( w>data.a[i].mxW ) data.a[i].mxW = w; |
| 2891 | 3021 | if( nNL ) data.bMultiRow = 1; |
| 2892 | 3022 | } |
| 2893 | 3023 | p->nRow++; |
| 2894 | - }while( sqlite3_step(p->pStmt)==SQLITE_ROW && p->iErr==SQLITE_OK ); | |
| 3024 | + rc = sqlite3_step(p->pStmt); | |
| 3025 | + } | |
| 2895 | 3026 | if( p->iErr ){ |
| 2896 | 3027 | qrfColDataFree(&data); |
| 2897 | 3028 | return; |
| 2898 | 3029 | } |
| 2899 | 3030 | |
| @@ -3097,11 +3228,11 @@ | ||
| 3097 | 3228 | /* Draw either (1) the separator between the title line and the body |
| 3098 | 3229 | ** of the table, or (2) separators between individual rows of the table |
| 3099 | 3230 | ** body. isTitleDataSeparator will be true if we are doing (1). |
| 3100 | 3231 | */ |
| 3101 | 3232 | if( (i==0 || data.bMultiRow) && i+nColumn<data.n ){ |
| 3102 | - int isTitleDataSeparator = (i==0 && p->spec.bTitles==QRF_Yes); | |
| 3233 | + int isTitleDataSeparator = (i==0 && p->spec.bTitles>=QRF_Yes); | |
| 3103 | 3234 | if( isTitleDataSeparator ){ |
| 3104 | 3235 | qrfLoadAlignment(&data, p); |
| 3105 | 3236 | } |
| 3106 | 3237 | switch( p->spec.eStyle ){ |
| 3107 | 3238 | case QRF_STYLE_Table: { |
| @@ -3124,19 +3255,12 @@ | ||
| 3124 | 3255 | } |
| 3125 | 3256 | break; |
| 3126 | 3257 | } |
| 3127 | 3258 | case QRF_STYLE_Column: { |
| 3128 | 3259 | if( isTitleDataSeparator ){ |
| 3129 | - for(j=0; j<nColumn; j++){ | |
| 3130 | - sqlite3_str_appendchar(p->pOut, data.a[j].w, '-'); | |
| 3131 | - if( j<nColumn-1 ){ | |
| 3132 | - sqlite3_str_append(p->pOut, colSep, szColSep); | |
| 3133 | - }else{ | |
| 3134 | - qrfRTrim(p->pOut); | |
| 3135 | - sqlite3_str_append(p->pOut, rowSep, szRowSep); | |
| 3136 | - } | |
| 3137 | - } | |
| 3260 | + qrfColumnSeparator(p->pOut, &data, colSep, szColSep, | |
| 3261 | + rowSep, szRowSep); | |
| 3138 | 3262 | }else if( data.bMultiRow ){ |
| 3139 | 3263 | qrfRTrim(p->pOut); |
| 3140 | 3264 | sqlite3_str_append(p->pOut, "\n", 1); |
| 3141 | 3265 | } |
| 3142 | 3266 | break; |
| @@ -3144,20 +3268,39 @@ | ||
| 3144 | 3268 | } |
| 3145 | 3269 | } |
| 3146 | 3270 | } |
| 3147 | 3271 | |
| 3148 | 3272 | /* Draw the line across the bottom of the table */ |
| 3149 | - if( p->spec.bBorder!=QRF_No ){ | |
| 3273 | + if( p->spec.bBorder!=QRF_No || p->nRow==0 ){ | |
| 3150 | 3274 | switch( p->spec.eStyle ){ |
| 3151 | 3275 | case QRF_STYLE_Box: |
| 3152 | - qrfBoxSeparator(p->pOut, &data, BOX_R12, BOX_124, BOX_R14, 0); | |
| 3276 | + if( p->nRow>0 ){ | |
| 3277 | + qrfBoxSeparator(p->pOut, &data, BOX_R12, BOX_124, BOX_R14, 0); | |
| 3278 | + }else{ | |
| 3279 | + qrfBoxSeparator(p->pOut, &data, DBL_12, DBL_124, DBL_14, 1); | |
| 3280 | + } | |
| 3153 | 3281 | break; |
| 3154 | 3282 | case QRF_STYLE_Table: |
| 3155 | 3283 | qrfRowSeparator(p->pOut, &data, '+'); |
| 3156 | 3284 | break; |
| 3285 | + case QRF_STYLE_Markdown: | |
| 3286 | + if( p->nRow==0 ){ | |
| 3287 | + qrfRowSeparator(p->pOut, &data, '|'); | |
| 3288 | + } | |
| 3289 | + break; | |
| 3290 | + case QRF_STYLE_Column: | |
| 3291 | + if( p->nRow==0 ){ | |
| 3292 | + qrfColumnSeparator(p->pOut, &data, colSep, szColSep, | |
| 3293 | + rowSep, szRowSep); | |
| 3294 | + } | |
| 3295 | + break; | |
| 3157 | 3296 | } |
| 3158 | 3297 | } |
| 3298 | + if( p->spec.bRowCount==QRF_Yes ){ | |
| 3299 | + sqlite3_int64 n = p->nRow; | |
| 3300 | + sqlite3_str_appendf(p->pOut, "(%lld row%s)\n", n, n==1 ? "" : "s"); | |
| 3301 | + } | |
| 3159 | 3302 | qrfWrite(p); |
| 3160 | 3303 | |
| 3161 | 3304 | qrfColDataFree(&data); |
| 3162 | 3305 | return; |
| 3163 | 3306 | } |
| @@ -3404,10 +3547,49 @@ | ||
| 3404 | 3547 | sqlite3_str_append(p->pOut, ":", 1); |
| 3405 | 3548 | qrfRenderValue(p, p->pOut, i); |
| 3406 | 3549 | } |
| 3407 | 3550 | qrfWrite(p); |
| 3408 | 3551 | } |
| 3552 | + | |
| 3553 | +/* | |
| 3554 | +** Render a title row (a row containing column names) if the spec | |
| 3555 | +** calls for one and if it makes sense for the eStyle. Title rows | |
| 3556 | +** do not make sense for some eStyles, such as QRF_STYLE_Off, | |
| 3557 | +** QRF_STYLE_Count, QRF_STYLE_Json, and similar. | |
| 3558 | +*/ | |
| 3559 | +static void qrfSimpleTitle(Qrf *p){ | |
| 3560 | + assert( p->nRow==0 ); | |
| 3561 | + assert( p->spec.bTitles>=QRF_Yes ); | |
| 3562 | + switch( p->spec.eStyle ){ | |
| 3563 | + case QRF_STYLE_Html: { | |
| 3564 | + int i; | |
| 3565 | + sqlite3_str_append(p->pOut, "<tr>", 4); | |
| 3566 | + for(i=0; i<p->nCol; i++){ | |
| 3567 | + const char *zCName = sqlite3_column_name(p->pStmt, i); | |
| 3568 | + sqlite3_str_append(p->pOut, "\n<th>", 5); | |
| 3569 | + qrfEncodeText(p, p->pOut, zCName); | |
| 3570 | + } | |
| 3571 | + sqlite3_str_append(p->pOut, "\n</tr>\n", 7); | |
| 3572 | + break; | |
| 3573 | + } | |
| 3574 | + case QRF_STYLE_Quote: | |
| 3575 | + case QRF_STYLE_List: { | |
| 3576 | + int i; | |
| 3577 | + int saved_eText = p->spec.eText; | |
| 3578 | + p->spec.eText = p->spec.eTitle; | |
| 3579 | + for(i=0; i<p->nCol; i++){ | |
| 3580 | + const char *zCName = sqlite3_column_name(p->pStmt, i); | |
| 3581 | + if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep); | |
| 3582 | + qrfEncodeText(p, p->pOut, zCName); | |
| 3583 | + } | |
| 3584 | + sqlite3_str_appendall(p->pOut, p->spec.zRowSep); | |
| 3585 | + qrfWrite(p); | |
| 3586 | + p->spec.eText = saved_eText; | |
| 3587 | + break; | |
| 3588 | + } | |
| 3589 | + } | |
| 3590 | +} | |
| 3409 | 3591 | |
| 3410 | 3592 | /* |
| 3411 | 3593 | ** Render a single row of output for non-columnar styles - any |
| 3412 | 3594 | ** style that lets us render row by row as the content is received |
| 3413 | 3595 | ** from the query. |
| @@ -3437,25 +3619,19 @@ | ||
| 3437 | 3619 | } |
| 3438 | 3620 | qrfOneJsonRow(p); |
| 3439 | 3621 | break; |
| 3440 | 3622 | } |
| 3441 | 3623 | case QRF_STYLE_Html: { |
| 3442 | - if( p->nRow==0 && p->spec.bTitles==QRF_Yes ){ | |
| 3443 | - sqlite3_str_append(p->pOut, "<TR>", 4); | |
| 3444 | - for(i=0; i<p->nCol; i++){ | |
| 3445 | - const char *zCName = sqlite3_column_name(p->pStmt, i); | |
| 3446 | - sqlite3_str_append(p->pOut, "\n<TH>", 5); | |
| 3447 | - qrfEncodeText(p, p->pOut, zCName); | |
| 3448 | - } | |
| 3449 | - sqlite3_str_append(p->pOut, "\n</TR>\n", 7); | |
| 3450 | - } | |
| 3451 | - sqlite3_str_append(p->pOut, "<TR>", 4); | |
| 3452 | - for(i=0; i<p->nCol; i++){ | |
| 3453 | - sqlite3_str_append(p->pOut, "\n<TD>", 5); | |
| 3624 | + if( p->nRow==0 && p->spec.bTitles>=QRF_Yes ){ | |
| 3625 | + qrfSimpleTitle(p); | |
| 3626 | + } | |
| 3627 | + sqlite3_str_append(p->pOut, "<tr>", 4); | |
| 3628 | + for(i=0; i<p->nCol; i++){ | |
| 3629 | + sqlite3_str_append(p->pOut, "\n<td>", 5); | |
| 3454 | 3630 | qrfRenderValue(p, p->pOut, i); |
| 3455 | 3631 | } |
| 3456 | - sqlite3_str_append(p->pOut, "\n</TR>\n", 7); | |
| 3632 | + sqlite3_str_append(p->pOut, "\n</tr>\n", 7); | |
| 3457 | 3633 | qrfWrite(p); |
| 3458 | 3634 | break; |
| 3459 | 3635 | } |
| 3460 | 3636 | case QRF_STYLE_Insert: { |
| 3461 | 3637 | unsigned int mxIns = p->spec.nMultiInsert; |
| @@ -3468,11 +3644,11 @@ | ||
| 3468 | 3644 | if( qrf_need_quote(p->spec.zTableName) ){ |
| 3469 | 3645 | sqlite3_str_appendf(p->pOut,"INSERT INTO \"%w\"",p->spec.zTableName); |
| 3470 | 3646 | }else{ |
| 3471 | 3647 | sqlite3_str_appendf(p->pOut,"INSERT INTO %s",p->spec.zTableName); |
| 3472 | 3648 | } |
| 3473 | - if( p->spec.bTitles==QRF_Yes ){ | |
| 3649 | + if( p->spec.bTitles>=QRF_Yes ){ | |
| 3474 | 3650 | for(i=0; i<p->nCol; i++){ |
| 3475 | 3651 | const char *zCName = sqlite3_column_name(p->pStmt, i); |
| 3476 | 3652 | if( qrf_need_quote(zCName) ){ |
| 3477 | 3653 | sqlite3_str_appendf(p->pOut, "%c\"%w\"", |
| 3478 | 3654 | i==0 ? '(' : ',', zCName); |
| @@ -3568,21 +3744,12 @@ | ||
| 3568 | 3744 | if( zEqpLine[0]=='-' ) qrfEqpRender(p, 0); |
| 3569 | 3745 | qrfEqpAppend(p, iEqpId, iParentId, zEqpLine); |
| 3570 | 3746 | break; |
| 3571 | 3747 | } |
| 3572 | 3748 | default: { /* QRF_STYLE_List */ |
| 3573 | - if( p->nRow==0 && p->spec.bTitles==QRF_Yes ){ | |
| 3574 | - int saved_eText = p->spec.eText; | |
| 3575 | - p->spec.eText = p->spec.eTitle; | |
| 3576 | - for(i=0; i<p->nCol; i++){ | |
| 3577 | - const char *zCName = sqlite3_column_name(p->pStmt, i); | |
| 3578 | - if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep); | |
| 3579 | - qrfEncodeText(p, p->pOut, zCName); | |
| 3580 | - } | |
| 3581 | - sqlite3_str_appendall(p->pOut, p->spec.zRowSep); | |
| 3582 | - qrfWrite(p); | |
| 3583 | - p->spec.eText = saved_eText; | |
| 3749 | + if( p->nRow==0 && p->spec.bTitles>=QRF_Yes ){ | |
| 3750 | + qrfSimpleTitle(p); | |
| 3584 | 3751 | } |
| 3585 | 3752 | for(i=0; i<p->nCol; i++){ |
| 3586 | 3753 | if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep); |
| 3587 | 3754 | qrfRenderValue(p, p->pOut, i); |
| 3588 | 3755 | } |
| @@ -3604,11 +3771,11 @@ | ||
| 3604 | 3771 | char **pzErr /* Write errors here */ |
| 3605 | 3772 | ){ |
| 3606 | 3773 | size_t sz; /* Size of pSpec[], based on pSpec->iVersion */ |
| 3607 | 3774 | memset(p, 0, sizeof(*p)); |
| 3608 | 3775 | p->pzErr = pzErr; |
| 3609 | - if( pSpec->iVersion>1 ){ | |
| 3776 | + if( pSpec->iVersion>2 ){ | |
| 3610 | 3777 | qrfError(p, SQLITE_ERROR, |
| 3611 | 3778 | "unusable sqlite3_qrf_spec.iVersion (%d)", |
| 3612 | 3779 | pSpec->iVersion); |
| 3613 | 3780 | return; |
| 3614 | 3781 | } |
| @@ -3620,15 +3787,19 @@ | ||
| 3620 | 3787 | return; |
| 3621 | 3788 | } |
| 3622 | 3789 | p->iErr = SQLITE_OK; |
| 3623 | 3790 | p->nCol = sqlite3_column_count(p->pStmt); |
| 3624 | 3791 | p->nRow = 0; |
| 3625 | - sz = sizeof(sqlite3_qrf_spec); | |
| 3792 | + switch( pSpec->iVersion ){ | |
| 3793 | + case 0: sz = offsetof(sqlite3_qrf_spec, bRowCount); break; | |
| 3794 | + case 1: sz = offsetof(sqlite3_qrf_spec, bRowCount); break; | |
| 3795 | + default: sz = sizeof(sqlite3_qrf_spec); break; | |
| 3796 | + } | |
| 3626 | 3797 | memcpy(&p->spec, pSpec, sz); |
| 3627 | 3798 | if( p->spec.zNull==0 ) p->spec.zNull = ""; |
| 3628 | 3799 | p->mxWidth = p->spec.nScreenWidth; |
| 3629 | - if( p->mxWidth<=0 ) p->mxWidth = QRF_MAX_WIDTH; | |
| 3800 | + if( p->mxWidth<=0 ) p->mxWidth = 2147483647; | |
| 3630 | 3801 | p->mxHeight = p->spec.nLineLimit; |
| 3631 | 3802 | if( p->mxHeight<=0 ) p->mxHeight = 2147483647; |
| 3632 | 3803 | if( p->spec.eStyle>QRF_STYLE_Table ) p->spec.eStyle = QRF_Auto; |
| 3633 | 3804 | if( p->spec.eEsc>QRF_ESC_Symbol ) p->spec.eEsc = QRF_Auto; |
| 3634 | 3805 | if( p->spec.eText>QRF_TEXT_Relaxed ) p->spec.eText = QRF_Auto; |
| @@ -3756,10 +3927,24 @@ | ||
| 3756 | 3927 | if( p->spec.bTextJsonb==QRF_Auto ){ |
| 3757 | 3928 | p->spec.bTextJsonb = QRF_No; |
| 3758 | 3929 | } |
| 3759 | 3930 | if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = ","; |
| 3760 | 3931 | if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n"; |
| 3932 | + if( p->spec.zIFmt==0 || sqlite3_qrf_ckformat(p->spec.zIFmt)!=1 ){ | |
| 3933 | + p->spec.zIFmt = "%lld"; | |
| 3934 | + }else{ | |
| 3935 | + size_t n = strlen(p->spec.zIFmt); | |
| 3936 | + memcpy(p->zFmt, p->spec.zIFmt, n-1); | |
| 3937 | + p->zFmt[n-1] = 'l'; | |
| 3938 | + p->zFmt[n] = 'l'; | |
| 3939 | + p->zFmt[n+1] = p->spec.zIFmt[n-1]; | |
| 3940 | + p->zFmt[n+2] = 0; | |
| 3941 | + p->spec.zIFmt = p->zFmt; | |
| 3942 | + } | |
| 3943 | + if( p->spec.zFpFmt && sqlite3_qrf_ckformat(p->spec.zFpFmt)!=2 ){ | |
| 3944 | + p->spec.zFpFmt = 0; | |
| 3945 | + } | |
| 3761 | 3946 | } |
| 3762 | 3947 | |
| 3763 | 3948 | /* |
| 3764 | 3949 | ** Finish rendering the results |
| 3765 | 3950 | */ |
| @@ -3890,10 +4075,34 @@ | ||
| 3890 | 4075 | default: { |
| 3891 | 4076 | /* Non-columnar modes where the output can occur after each row |
| 3892 | 4077 | ** of result is received */ |
| 3893 | 4078 | while( qrf.iErr==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ |
| 3894 | 4079 | qrfOneSimpleRow(&qrf); |
| 4080 | + } | |
| 4081 | + if( qrf.nCol>0 && qrf.nRow==0 && qrf.spec.bTitles==QRF_Always ){ | |
| 4082 | + qrfSimpleTitle(&qrf); | |
| 4083 | + } | |
| 4084 | + if( qrf.nCol>0 && qrf.spec.bRowCount==QRF_Yes ){ | |
| 4085 | + const char *zPlural = qrf.nRow==1 ? "" : "s"; | |
| 4086 | + switch( qrf.spec.eStyle ){ | |
| 4087 | + case QRF_STYLE_Line: | |
| 4088 | + if( qrf.nRow>0 ) sqlite3_str_append(qrf.pOut, "\n", 1); | |
| 4089 | + /* Fall through */ | |
| 4090 | + case QRF_STYLE_Csv: | |
| 4091 | + case QRF_STYLE_List: | |
| 4092 | + case QRF_STYLE_Quote: | |
| 4093 | + sqlite3_str_appendf(qrf.pOut,"(%lld row%s)\n",qrf.nRow,zPlural); | |
| 4094 | + break; | |
| 4095 | + case QRF_STYLE_Html: | |
| 4096 | + sqlite3_str_appendf(qrf.pOut,"<!-- %lld row%s -->\n", | |
| 4097 | + qrf.nRow, zPlural); | |
| 4098 | + break; | |
| 4099 | + case QRF_STYLE_Insert: | |
| 4100 | + sqlite3_str_appendf(qrf.pOut,"/* %lld row%s inserted */\n", | |
| 4101 | + qrf.nRow, zPlural); | |
| 4102 | + break; | |
| 4103 | + } | |
| 3895 | 4104 | } |
| 3896 | 4105 | break; |
| 3897 | 4106 | } |
| 3898 | 4107 | } |
| 3899 | 4108 | qrfResetStmt(&qrf); |
| @@ -5106,10 +5315,12 @@ | ||
| 5106 | 5315 | int rc; |
| 5107 | 5316 | int n; |
| 5108 | 5317 | const char *z; |
| 5109 | 5318 | SHA3Context cx; |
| 5110 | 5319 | int iSize; |
| 5320 | + int isRecursive = 0; | |
| 5321 | + int *pIsRecursive; | |
| 5111 | 5322 | |
| 5112 | 5323 | if( argc==1 ){ |
| 5113 | 5324 | iSize = 256; |
| 5114 | 5325 | }else{ |
| 5115 | 5326 | iSize = sqlite3_value_int(argv[1]); |
| @@ -5119,10 +5330,15 @@ | ||
| 5119 | 5330 | return; |
| 5120 | 5331 | } |
| 5121 | 5332 | } |
| 5122 | 5333 | if( zSql==0 ) return; |
| 5123 | 5334 | SHA3Init(&cx, iSize); |
| 5335 | + pIsRecursive = (int*)sqlite3_get_clientdata(db,"sha3_query()"); | |
| 5336 | + if( pIsRecursive ){ | |
| 5337 | + *pIsRecursive = 1; | |
| 5338 | + return; | |
| 5339 | + } | |
| 5124 | 5340 | while( zSql[0] ){ |
| 5125 | 5341 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); |
| 5126 | 5342 | if( rc ){ |
| 5127 | 5343 | char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", |
| 5128 | 5344 | zSql, sqlite3_errmsg(db)); |
| @@ -5145,19 +5361,25 @@ | ||
| 5145 | 5361 | sha3_step_vformat(&cx,"S%d:",n); |
| 5146 | 5362 | SHA3Update(&cx,(unsigned char*)z,n); |
| 5147 | 5363 | } |
| 5148 | 5364 | |
| 5149 | 5365 | /* Compute a hash over the result of the query */ |
| 5366 | + sqlite3_set_clientdata(db, "sha3_query()", &isRecursive, 0); | |
| 5150 | 5367 | while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 5151 | 5368 | SHA3Update(&cx,(const unsigned char*)"R",1); |
| 5152 | 5369 | for(i=0; i<nCol; i++){ |
| 5153 | 5370 | sha3UpdateFromValue(&cx, sqlite3_column_value(pStmt,i)); |
| 5154 | 5371 | } |
| 5155 | 5372 | } |
| 5156 | 5373 | sqlite3_finalize(pStmt); |
| 5374 | + sqlite3_set_clientdata(db, "sha3_query()", 0, 0); | |
| 5157 | 5375 | } |
| 5158 | - sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); | |
| 5376 | + if( isRecursive ){ | |
| 5377 | + sqlite3_result_error(context, "recursive use of sha3_query()", -1); | |
| 5378 | + }else{ | |
| 5379 | + sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); | |
| 5380 | + } | |
| 5159 | 5381 | } |
| 5160 | 5382 | |
| 5161 | 5383 | /* |
| 5162 | 5384 | ** xStep function for sha3_agg(). |
| 5163 | 5385 | */ |
| @@ -5272,10 +5494,14 @@ | ||
| 5272 | 5494 | #include <stdarg.h> |
| 5273 | 5495 | |
| 5274 | 5496 | /****************************************************************************** |
| 5275 | 5497 | ** The Hash Engine |
| 5276 | 5498 | */ |
| 5499 | +#if defined(__GNUC__) && __GNUC__>=11 | |
| 5500 | +# pragma GCC diagnostic push | |
| 5501 | +# pragma GCC diagnostic ignored "-Wstringop-overread" | |
| 5502 | +#endif | |
| 5277 | 5503 | /* Context for the SHA1 hash */ |
| 5278 | 5504 | typedef struct SHA1Context SHA1Context; |
| 5279 | 5505 | struct SHA1Context { |
| 5280 | 5506 | unsigned int state[5]; |
| 5281 | 5507 | unsigned int count[2]; |
| @@ -5412,11 +5638,11 @@ | ||
| 5412 | 5638 | } |
| 5413 | 5639 | j = 0; |
| 5414 | 5640 | }else{ |
| 5415 | 5641 | i = 0; |
| 5416 | 5642 | } |
| 5417 | - (void)memcpy(&p->buffer[j], &data[i], len - i); | |
| 5643 | + if( len-i>0 ) (void)memcpy(&p->buffer[j], &data[i], len - i); | |
| 5418 | 5644 | } |
| 5419 | 5645 | |
| 5420 | 5646 | /* Compute a string using sqlite3_vsnprintf() and hash it */ |
| 5421 | 5647 | static void hash_step_vformat( |
| 5422 | 5648 | SHA1Context *p, /* Add content to this context */ |
| @@ -5467,10 +5693,13 @@ | ||
| 5467 | 5693 | zOut[i*2+1] = zEncode[digest[i] & 0xf]; |
| 5468 | 5694 | } |
| 5469 | 5695 | zOut[i*2]= 0; |
| 5470 | 5696 | } |
| 5471 | 5697 | } |
| 5698 | +#if defined(__GNUC__) && __GNUC__>=11 | |
| 5699 | +# pragma GCC diagnostic pop | |
| 5700 | +#endif | |
| 5472 | 5701 | /* End of the hashing logic |
| 5473 | 5702 | *****************************************************************************/ |
| 5474 | 5703 | |
| 5475 | 5704 | /* |
| 5476 | 5705 | ** Two SQL functions: sha1(X) and sha1b(X). |
| @@ -5501,11 +5730,14 @@ | ||
| 5501 | 5730 | if( eType==SQLITE_BLOB ){ |
| 5502 | 5731 | pData = (const unsigned char*)sqlite3_value_blob(argv[0]); |
| 5503 | 5732 | }else{ |
| 5504 | 5733 | pData = (const unsigned char*)sqlite3_value_text(argv[0]); |
| 5505 | 5734 | } |
| 5506 | - if( pData==0 ) return; | |
| 5735 | + if( pData==0 ){ | |
| 5736 | + if( nByte ) return; | |
| 5737 | + pData = (const unsigned char*)""; | |
| 5738 | + } | |
| 5507 | 5739 | hash_step(&cx, pData, nByte); |
| 5508 | 5740 | if( sqlite3_user_data(context)!=0 ){ |
| 5509 | 5741 | /* sha1b() - binary result */ |
| 5510 | 5742 | hash_finish(&cx, zOut, 1); |
| 5511 | 5743 | sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT); |
| @@ -5541,13 +5773,20 @@ | ||
| 5541 | 5773 | int rc; |
| 5542 | 5774 | int n; |
| 5543 | 5775 | const char *z; |
| 5544 | 5776 | SHA1Context cx; |
| 5545 | 5777 | char zOut[44]; |
| 5778 | + int isRecursive = 0; | |
| 5779 | + int *pIsRecursive; | |
| 5546 | 5780 | |
| 5547 | 5781 | assert( argc==1 ); |
| 5548 | 5782 | if( zSql==0 ) return; |
| 5783 | + pIsRecursive = sqlite3_get_clientdata(db, "sha1_query()"); | |
| 5784 | + if( pIsRecursive ){ | |
| 5785 | + *pIsRecursive = 1; | |
| 5786 | + return; | |
| 5787 | + } | |
| 5549 | 5788 | hash_init(&cx); |
| 5550 | 5789 | while( zSql[0] ){ |
| 5551 | 5790 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); |
| 5552 | 5791 | if( rc ){ |
| 5553 | 5792 | char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", |
| @@ -5570,10 +5809,11 @@ | ||
| 5570 | 5809 | n = (int)strlen(z); |
| 5571 | 5810 | hash_step_vformat(&cx,"S%d:",n); |
| 5572 | 5811 | hash_step(&cx,(unsigned char*)z,n); |
| 5573 | 5812 | |
| 5574 | 5813 | /* Compute a hash over the result of the query */ |
| 5814 | + sqlite3_set_clientdata(db, "sha1_query()", &isRecursive, 0); | |
| 5575 | 5815 | while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 5576 | 5816 | hash_step(&cx,(const unsigned char*)"R",1); |
| 5577 | 5817 | for(i=0; i<nCol; i++){ |
| 5578 | 5818 | switch( sqlite3_column_type(pStmt,i) ){ |
| 5579 | 5819 | case SQLITE_NULL: { |
| @@ -5624,13 +5864,18 @@ | ||
| 5624 | 5864 | } |
| 5625 | 5865 | } |
| 5626 | 5866 | } |
| 5627 | 5867 | } |
| 5628 | 5868 | sqlite3_finalize(pStmt); |
| 5869 | + sqlite3_set_clientdata(db, "sha1_query()", 0, 0); | |
| 5629 | 5870 | } |
| 5630 | 5871 | hash_finish(&cx, zOut, 0); |
| 5631 | - sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT); | |
| 5872 | + if( isRecursive ){ | |
| 5873 | + sqlite3_result_error(context, "recursive use of sha1_query()", -1); | |
| 5874 | + }else{ | |
| 5875 | + sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT); | |
| 5876 | + } | |
| 5632 | 5877 | } |
| 5633 | 5878 | |
| 5634 | 5879 | |
| 5635 | 5880 | #ifdef _WIN32 |
| 5636 | 5881 | |
| @@ -5824,10 +6069,13 @@ | ||
| 5824 | 6069 | } |
| 5825 | 6070 | |
| 5826 | 6071 | /* |
| 5827 | 6072 | ** Allocate a new Decimal object initialized to the text in zIn[]. |
| 5828 | 6073 | ** Return NULL if any kind of error occurs. |
| 6074 | +** | |
| 6075 | +** Note that zIn[] is not necessarily zero-terminated. Always | |
| 6076 | +** respect the boundary imposed by the n argument. | |
| 5829 | 6077 | */ |
| 5830 | 6078 | static Decimal *decimalNewFromText(const char *zIn, int n){ |
| 5831 | 6079 | Decimal *p = 0; |
| 5832 | 6080 | int i; |
| 5833 | 6081 | int iExp = 0; |
| @@ -5841,15 +6089,15 @@ | ||
| 5841 | 6089 | p->isNull = 0; |
| 5842 | 6090 | p->nDigit = 0; |
| 5843 | 6091 | p->nFrac = 0; |
| 5844 | 6092 | p->a = sqlite3_malloc64( n+1 ); |
| 5845 | 6093 | if( p->a==0 ) goto new_from_text_failed; |
| 5846 | - for(i=0; IsSpace(zIn[i]); i++){} | |
| 5847 | - if( zIn[i]=='-' ){ | |
| 6094 | + for(i=0; i<n && IsSpace(zIn[i]); i++){} | |
| 6095 | + if( i<n && zIn[i]=='-' ){ | |
| 5848 | 6096 | p->sign = 1; |
| 5849 | 6097 | i++; |
| 5850 | - }else if( zIn[i]=='+' ){ | |
| 6098 | + }else if( i<n && zIn[i]=='+' ){ | |
| 5851 | 6099 | i++; |
| 5852 | 6100 | } |
| 5853 | 6101 | while( i<n && zIn[i]=='0' ) i++; |
| 5854 | 6102 | while( i<n ){ |
| 5855 | 6103 | char c = zIn[i]; |
| @@ -6056,32 +6304,41 @@ | ||
| 6056 | 6304 | } |
| 6057 | 6305 | z[i] = 0; |
| 6058 | 6306 | sqlite3_result_text(pCtx, z, i, sqlite3_free); |
| 6059 | 6307 | } |
| 6060 | 6308 | |
| 6309 | +/* Forward declaration */ | |
| 6310 | +static void decimal_expand(Decimal *p, int nDigit, int nFrac); | |
| 6311 | + | |
| 6061 | 6312 | /* |
| 6062 | 6313 | ** Round a decimal value to N significant digits. N must be positive. |
| 6063 | 6314 | */ |
| 6064 | 6315 | static void decimal_round(Decimal *p, int N){ |
| 6065 | 6316 | int i; |
| 6066 | - int nZero; | |
| 6317 | + int nZero; /* Number of leading zeros */ | |
| 6067 | 6318 | if( N<1 ) return; |
| 6068 | 6319 | if( p==0 ) return; |
| 6069 | 6320 | if( p->nDigit<=N ) return; |
| 6070 | 6321 | for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){} |
| 6071 | 6322 | N += nZero; |
| 6072 | 6323 | if( p->nDigit<=N ) return; |
| 6073 | - if( p->a[N]>4 ){ | |
| 6324 | + if( p->a[N]>=5 ){ | |
| 6325 | + /* If all leading digits are 9, increase the number of digits | |
| 6326 | + ** by adding a new 0 to the front */ | |
| 6327 | + for(i=0; i<N && p->a[i]==9; i++){} | |
| 6328 | + if( i==N ){ | |
| 6329 | + decimal_expand(p, p->nDigit+1, p->nFrac); | |
| 6330 | + if( p->oom ) return; | |
| 6331 | + } | |
| 6332 | + | |
| 6333 | + /* Do the rounding */ | |
| 6074 | 6334 | p->a[N-1]++; |
| 6075 | 6335 | for(i=N-1; i>0 && p->a[i]>9; i--){ |
| 6076 | 6336 | p->a[i] = 0; |
| 6077 | 6337 | p->a[i-1]++; |
| 6078 | 6338 | } |
| 6079 | - if( p->a[0]>9 ){ | |
| 6080 | - p->a[0] = 1; | |
| 6081 | - p->nFrac--; | |
| 6082 | - } | |
| 6339 | + assert( p->a[0]<=9 ); | |
| 6083 | 6340 | } |
| 6084 | 6341 | memset(&p->a[N], 0, p->nDigit - N); |
| 6085 | 6342 | } |
| 6086 | 6343 | |
| 6087 | 6344 | /* |
| @@ -6225,10 +6482,11 @@ | ||
| 6225 | 6482 | int nAddSig; |
| 6226 | 6483 | int nAddFrac; |
| 6227 | 6484 | signed char *a; |
| 6228 | 6485 | if( p==0 ) return; |
| 6229 | 6486 | nAddFrac = nFrac - p->nFrac; |
| 6487 | + assert( nAddFrac>=0 ); | |
| 6230 | 6488 | nAddSig = (nDigit - p->nDigit) - nAddFrac; |
| 6231 | 6489 | if( nAddFrac==0 && nAddSig==0 ) return; |
| 6232 | 6490 | if( nDigit+1>SQLITE_DECIMAL_MAX_DIGIT ){ p->oom = 1; return; } |
| 6233 | 6491 | a = sqlite3_realloc64(p->a, nDigit+1); |
| 6234 | 6492 | if( a==0 ){ |
| @@ -8232,10 +8490,20 @@ | ||
| 8232 | 8490 | if( r==(double)x ) return r; |
| 8233 | 8491 | if( r<(double)x ) x--; |
| 8234 | 8492 | return (double)x; |
| 8235 | 8493 | } |
| 8236 | 8494 | #endif |
| 8495 | + | |
| 8496 | +/* Convert a floating point value to its closest integer. Do so in | |
| 8497 | +** a way that avoids 'outside the range of representable values' warnings | |
| 8498 | +** from UBSAN. | |
| 8499 | +*/ | |
| 8500 | +static sqlite3_int64 seriesRealToI64(double r){ | |
| 8501 | + if( r<-9223372036854774784.0 ) return SMALLEST_INT64; | |
| 8502 | + if( r>+9223372036854774784.0 ) return LARGEST_INT64; | |
| 8503 | + return (sqlite3_int64)r; | |
| 8504 | +} | |
| 8237 | 8505 | |
| 8238 | 8506 | /* |
| 8239 | 8507 | ** This method is called to "rewind" the series_cursor object back |
| 8240 | 8508 | ** to the first row of output. This method is always called at least |
| 8241 | 8509 | ** once prior to any call to seriesColumn() or seriesRowid() or |
| @@ -8355,27 +8623,31 @@ | ||
| 8355 | 8623 | double r = sqlite3_value_double(argv[iArg++]); |
| 8356 | 8624 | if( r==seriesCeil(r) |
| 8357 | 8625 | && r>=(double)SMALLEST_INT64 |
| 8358 | 8626 | && r<=(double)LARGEST_INT64 |
| 8359 | 8627 | ){ |
| 8360 | - iMin = iMax = (sqlite3_int64)r; | |
| 8628 | + iMin = iMax = seriesRealToI64(r); | |
| 8361 | 8629 | }else{ |
| 8362 | 8630 | goto series_no_rows; |
| 8363 | 8631 | } |
| 8364 | 8632 | }else{ |
| 8365 | 8633 | iMin = iMax = sqlite3_value_int64(argv[iArg++]); |
| 8366 | 8634 | } |
| 8367 | 8635 | }else{ |
| 8368 | - if( idxNum & 0x0300 ){ /* value>X or value>=X */ | |
| 8636 | + if( idxNum & 0x0300 ){ /* value>X (0x200) or value>=X (0x100) */ | |
| 8369 | 8637 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8370 | 8638 | double r = sqlite3_value_double(argv[iArg++]); |
| 8371 | - if( r<(double)SMALLEST_INT64 ){ | |
| 8639 | + if( r<=(double)SMALLEST_INT64 ){ | |
| 8372 | 8640 | iMin = SMALLEST_INT64; |
| 8373 | - }else if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){ | |
| 8374 | - iMin = (sqlite3_int64)seriesCeil(r+1.0); | |
| 8641 | + }else if( r>(double)LARGEST_INT64 ){ | |
| 8642 | + goto series_no_rows; | |
| 8375 | 8643 | }else{ |
| 8376 | - iMin = (sqlite3_int64)seriesCeil(r); | |
| 8644 | + iMin = seriesRealToI64(seriesCeil(r)); | |
| 8645 | + if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){ | |
| 8646 | + if( iMin==LARGEST_INT64 ) goto series_no_rows; | |
| 8647 | + iMin++; | |
| 8648 | + } | |
| 8377 | 8649 | } |
| 8378 | 8650 | }else{ |
| 8379 | 8651 | iMin = sqlite3_value_int64(argv[iArg++]); |
| 8380 | 8652 | if( (idxNum & 0x0200)!=0 ){ |
| 8381 | 8653 | if( iMin==LARGEST_INT64 ){ |
| @@ -8384,19 +8656,23 @@ | ||
| 8384 | 8656 | iMin++; |
| 8385 | 8657 | } |
| 8386 | 8658 | } |
| 8387 | 8659 | } |
| 8388 | 8660 | } |
| 8389 | - if( idxNum & 0x3000 ){ /* value<X or value<=X */ | |
| 8661 | + if( idxNum & 0x3000 ){ /* value<X (0x2000) or value<=X (0x1000) */ | |
| 8390 | 8662 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8391 | 8663 | double r = sqlite3_value_double(argv[iArg++]); |
| 8392 | - if( r>(double)LARGEST_INT64 ){ | |
| 8664 | + if( r>=(double)LARGEST_INT64 ){ | |
| 8393 | 8665 | iMax = LARGEST_INT64; |
| 8394 | - }else if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){ | |
| 8395 | - iMax = (sqlite3_int64)(r-1.0); | |
| 8666 | + }else if( r<=(double)SMALLEST_INT64 ){ | |
| 8667 | + goto series_no_rows; | |
| 8396 | 8668 | }else{ |
| 8397 | - iMax = (sqlite3_int64)seriesFloor(r); | |
| 8669 | + iMax = seriesRealToI64(seriesFloor(r)); | |
| 8670 | + if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){ | |
| 8671 | + if( iMax==SMALLEST_INT64 ) goto series_no_rows; | |
| 8672 | + iMax--; | |
| 8673 | + } | |
| 8398 | 8674 | } |
| 8399 | 8675 | }else{ |
| 8400 | 8676 | iMax = sqlite3_value_int64(argv[iArg++]); |
| 8401 | 8677 | if( idxNum & 0x2000 ){ |
| 8402 | 8678 | if( iMax==SMALLEST_INT64 ){ |
| @@ -9638,11 +9914,10 @@ | ||
| 9638 | 9914 | if( pRe==0 ){ |
| 9639 | 9915 | sqlite3_result_error_nomem(context); |
| 9640 | 9916 | return; |
| 9641 | 9917 | } |
| 9642 | 9918 | pStr = sqlite3_str_new(0); |
| 9643 | - if( pStr==0 ) goto re_bytecode_func_err; | |
| 9644 | 9919 | if( pRe->nInit>0 ){ |
| 9645 | 9920 | sqlite3_str_appendf(pStr, "INIT "); |
| 9646 | 9921 | for(i=0; i<pRe->nInit; i++){ |
| 9647 | 9922 | sqlite3_str_appendf(pStr, "%02x", pRe->zInit[i]); |
| 9648 | 9923 | } |
| @@ -9649,20 +9924,20 @@ | ||
| 9649 | 9924 | sqlite3_str_appendf(pStr, "\n"); |
| 9650 | 9925 | } |
| 9651 | 9926 | for(i=0; (unsigned)i<pRe->nState; i++){ |
| 9652 | 9927 | sqlite3_str_appendf(pStr, "%-8s %4d\n", |
| 9653 | 9928 | ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]); |
| 9929 | + } | |
| 9930 | + if( sqlite3_str_errcode(pStr)==SQLITE_NOMEM ){ | |
| 9931 | + sqlite3_str_finish(pStr); | |
| 9932 | + re_free(pRe); | |
| 9933 | + sqlite3_result_error_nomem(context); | |
| 9934 | + return; | |
| 9654 | 9935 | } |
| 9655 | 9936 | n = sqlite3_str_length(pStr); |
| 9656 | 9937 | z = sqlite3_str_finish(pStr); |
| 9657 | - if( n==0 ){ | |
| 9658 | - sqlite3_free(z); | |
| 9659 | - }else{ | |
| 9660 | - sqlite3_result_text(context, z, n-1, sqlite3_free); | |
| 9661 | - } | |
| 9662 | - | |
| 9663 | -re_bytecode_func_err: | |
| 9938 | + sqlite3_result_text(context, z, n-1, sqlite3_free); | |
| 9664 | 9939 | re_free(pRe); |
| 9665 | 9940 | } |
| 9666 | 9941 | |
| 9667 | 9942 | #endif /* SQLITE_DEBUG */ |
| 9668 | 9943 | |
| @@ -10557,11 +10832,15 @@ | ||
| 10557 | 10832 | sqlite3_result_error_nomem(ctx); |
| 10558 | 10833 | return SQLITE_NOMEM; |
| 10559 | 10834 | } |
| 10560 | 10835 | } |
| 10561 | 10836 | |
| 10562 | - sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT); | |
| 10837 | + if( n>0 ){ | |
| 10838 | + sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT); | |
| 10839 | + }else{ | |
| 10840 | + sqlite3_result_null(ctx); | |
| 10841 | + } | |
| 10563 | 10842 | if( aBuf!=aStatic ) sqlite3_free(aBuf); |
| 10564 | 10843 | #endif |
| 10565 | 10844 | }else{ |
| 10566 | 10845 | readFileContents(ctx, pCur->zPath); |
| 10567 | 10846 | } |
| @@ -10870,10 +11149,13 @@ | ||
| 10870 | 11149 | ** Return NULL if unable. |
| 10871 | 11150 | ** |
| 10872 | 11151 | ** The file or directory X is not required to exist. The answer is formed |
| 10873 | 11152 | ** by calling system realpath() on the prefix of X that does exist and |
| 10874 | 11153 | ** appending the tail of X that does not (yet) exist. |
| 11154 | +** | |
| 11155 | +** FIXME: This routine sometimes returns NULL rather than raising | |
| 11156 | +** an SQLITE_NOMEM error if an OOM is encountered. | |
| 10875 | 11157 | */ |
| 10876 | 11158 | static void realpathFunc( |
| 10877 | 11159 | sqlite3_context *context, |
| 10878 | 11160 | int argc, |
| 10879 | 11161 | sqlite3_value **argv |
| @@ -10892,10 +11174,11 @@ | ||
| 10892 | 11174 | (void)argc; |
| 10893 | 11175 | zPath = (const char*)sqlite3_value_text(argv[0]); |
| 10894 | 11176 | if( zPath==0 ) return; |
| 10895 | 11177 | if( zPath[0]==0 ) zPath = "."; |
| 10896 | 11178 | zCopy = sqlite3_mprintf("%s",zPath); |
| 11179 | + if( zCopy==0 ) return; | |
| 10897 | 11180 | len = strlen(zCopy); |
| 10898 | 11181 | while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){ |
| 10899 | 11182 | len--; |
| 10900 | 11183 | } |
| 10901 | 11184 | zCopy[len] = 0; |
| @@ -11802,11 +12085,13 @@ | ||
| 11802 | 12085 | int iAmt, |
| 11803 | 12086 | sqlite_int64 iOfst |
| 11804 | 12087 | ){ |
| 11805 | 12088 | ApndFile *paf = (ApndFile *)pFile; |
| 11806 | 12089 | sqlite_int64 iWriteEnd = iOfst + iAmt; |
| 11807 | - if( iWriteEnd>=APND_MAX_SIZE ) return SQLITE_FULL; | |
| 12090 | + if( iWriteEnd + paf->iPgOne >= APND_MAX_SIZE-APND_MARK_SIZE ){ | |
| 12091 | + return SQLITE_FULL; | |
| 12092 | + } | |
| 11808 | 12093 | pFile = ORIGFILE(pFile); |
| 11809 | 12094 | /* If append-mark is absent or will be overwritten, write it. */ |
| 11810 | 12095 | if( paf->iMark < 0 || paf->iPgOne + iWriteEnd > paf->iMark ){ |
| 11811 | 12096 | int rc = apndWriteMark(paf, pFile, iWriteEnd); |
| 11812 | 12097 | if( SQLITE_OK!=rc ) return rc; |
| @@ -12220,10 +12505,12 @@ | ||
| 12220 | 12505 | ** |
| 12221 | 12506 | ** * No support for encryption |
| 12222 | 12507 | ** * No support for ZIP archives spanning multiple files |
| 12223 | 12508 | ** * No support for zip64 extensions |
| 12224 | 12509 | ** * Only the "inflate/deflate" (zlib) compression method is supported |
| 12510 | +** * No support for transactions. ROLLBACK is the same as COMMIT. | |
| 12511 | +** A crash mid-transaction can leave the ZIP archive in a corrupt state. | |
| 12225 | 12512 | */ |
| 12226 | 12513 | /* #include "sqlite3ext.h" */ |
| 12227 | 12514 | SQLITE_EXTENSION_INIT1 |
| 12228 | 12515 | #include <stdio.h> |
| 12229 | 12516 | #include <string.h> |
| @@ -12685,10 +12972,11 @@ | ||
| 12685 | 12972 | |
| 12686 | 12973 | for(p=pCsr->pFreeEntry; p; p=pNext){ |
| 12687 | 12974 | pNext = p->pNext; |
| 12688 | 12975 | zipfileEntryFree(p); |
| 12689 | 12976 | } |
| 12977 | + pCsr->pFreeEntry = 0; | |
| 12690 | 12978 | } |
| 12691 | 12979 | |
| 12692 | 12980 | /* |
| 12693 | 12981 | ** Destructor for an ZipfileCsr. |
| 12694 | 12982 | */ |
| @@ -13087,11 +13375,17 @@ | ||
| 13087 | 13375 | } |
| 13088 | 13376 | } |
| 13089 | 13377 | |
| 13090 | 13378 | if( rc==SQLITE_OK ){ |
| 13091 | 13379 | u32 *pt = &pNew->mUnixTime; |
| 13092 | - pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead); | |
| 13380 | + /* aRead[0..nFile-1] might contain embedded \000 characters | |
| 13381 | + ** See Bug 2026-05-31T11:43:05Z */ | |
| 13382 | + pNew->cds.zFile = sqlite3_malloc64(nFile+1); | |
| 13383 | + if( pNew->cds.zFile!=0 ){ | |
| 13384 | + memcpy(pNew->cds.zFile, aRead, nFile); | |
| 13385 | + pNew->cds.zFile[nFile] = 0; | |
| 13386 | + } | |
| 13093 | 13387 | pNew->aExtra = (u8*)&pNew[1]; |
| 13094 | 13388 | memcpy(pNew->aExtra, &aRead[nFile], nExtra); |
| 13095 | 13389 | if( pNew->cds.zFile==0 ){ |
| 13096 | 13390 | rc = SQLITE_NOMEM; |
| 13097 | 13391 | }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){ |
| @@ -13844,14 +14138,14 @@ | ||
| 13844 | 14138 | if( zUpdate && zipfileComparePath(zUpdate, zDelete, nDelete)!=0 ){ |
| 13845 | 14139 | bUpdate = 1; |
| 13846 | 14140 | } |
| 13847 | 14141 | } |
| 13848 | 14142 | for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){ |
| 14143 | + if( pOld==0 ) return SQLITE_OK; | |
| 13849 | 14144 | if( zipfileComparePath(pOld->cds.zFile, zDelete, nDelete)==0 ){ |
| 13850 | 14145 | break; |
| 13851 | 14146 | } |
| 13852 | - assert( pOld->pNext ); | |
| 13853 | 14147 | } |
| 13854 | 14148 | } |
| 13855 | 14149 | |
| 13856 | 14150 | if( nVal>1 ){ |
| 13857 | 14151 | /* Check that "sz" and "rawdata" are both NULL: */ |
| @@ -14191,14 +14485,14 @@ | ||
| 14191 | 14485 | ZipfileBuffer body; |
| 14192 | 14486 | ZipfileBuffer cds; |
| 14193 | 14487 | }; |
| 14194 | 14488 | |
| 14195 | 14489 | static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){ |
| 14196 | - if( pBuf->n+nByte>pBuf->nAlloc ){ | |
| 14490 | + if( (pBuf->nAlloc-pBuf->n)<nByte ){ | |
| 14197 | 14491 | u8 *aNew; |
| 14198 | - sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512; | |
| 14199 | - int nReq = pBuf->n + nByte; | |
| 14492 | + i64 nNew = pBuf->n ? (i64)pBuf->n*2 : 512; | |
| 14493 | + i64 nReq = pBuf->n + nByte; | |
| 14200 | 14494 | |
| 14201 | 14495 | while( nNew<nReq ) nNew = nNew*2; |
| 14202 | 14496 | aNew = sqlite3_realloc64(pBuf->a, nNew); |
| 14203 | 14497 | if( aNew==0 ) return SQLITE_NOMEM; |
| 14204 | 14498 | pBuf->a = aNew; |
| @@ -14410,11 +14704,11 @@ | ||
| 14410 | 14704 | eocd.nEntry = (u16)p->nEntry; |
| 14411 | 14705 | eocd.nEntryTotal = (u16)p->nEntry; |
| 14412 | 14706 | eocd.nSize = p->cds.n; |
| 14413 | 14707 | eocd.iOffset = p->body.n; |
| 14414 | 14708 | |
| 14415 | - nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ; | |
| 14709 | + nZip = (i64)p->body.n + (i64)p->cds.n + ZIPFILE_EOCD_FIXED_SZ; | |
| 14416 | 14710 | aZip = (u8*)sqlite3_malloc64(nZip); |
| 14417 | 14711 | if( aZip==0 ){ |
| 14418 | 14712 | sqlite3_result_error_nomem(pCtx); |
| 14419 | 14713 | }else{ |
| 14420 | 14714 | memcpy(aZip, p->body.a, p->body.n); |
| @@ -16296,11 +16590,11 @@ | ||
| 16296 | 16590 | p->pTable = pTab; |
| 16297 | 16591 | |
| 16298 | 16592 | /* The statement the vtab will pass to sqlite3_declare_vtab() */ |
| 16299 | 16593 | zInner = idxAppendText(&rc, 0, "CREATE TABLE x("); |
| 16300 | 16594 | for(i=0; i<pTab->nCol; i++){ |
| 16301 | - zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s", | |
| 16595 | + zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %Q", | |
| 16302 | 16596 | (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl |
| 16303 | 16597 | ); |
| 16304 | 16598 | } |
| 16305 | 16599 | zInner = idxAppendText(&rc, zInner, ")"); |
| 16306 | 16600 | |
| @@ -16496,11 +16790,11 @@ | ||
| 16496 | 16790 | sqlite3_free(zCols); |
| 16497 | 16791 | sqlite3_free(zOrder); |
| 16498 | 16792 | return sqlite3_reset(pIndexXInfo); |
| 16499 | 16793 | } |
| 16500 | 16794 | zCols = idxAppendText(&rc, zCols, |
| 16501 | - "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s", | |
| 16795 | + "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %Q", | |
| 16502 | 16796 | zComma, zName, nCol, zName, zColl |
| 16503 | 16797 | ); |
| 16504 | 16798 | zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol); |
| 16505 | 16799 | } |
| 16506 | 16800 | sqlite3_reset(pIndexXInfo); |
| @@ -17537,16 +17831,19 @@ | ||
| 17537 | 17831 | } |
| 17538 | 17832 | iRet++; |
| 17539 | 17833 | } |
| 17540 | 17834 | } |
| 17541 | 17835 | else if( c=='[' ){ |
| 17542 | - while( z[iRet++]!=']' && z[iRet] ); | |
| 17836 | + while( z[iRet] && z[iRet++]!=']' ){} | |
| 17543 | 17837 | } |
| 17544 | 17838 | else if( (c>='A' && c<='Z') || (c>='a' && c<='z') ){ |
| 17545 | 17839 | while( (z[iRet]>='A' && z[iRet]<='Z') || (z[iRet]>='a' && z[iRet]<='z') ){ |
| 17546 | 17840 | iRet++; |
| 17547 | 17841 | } |
| 17842 | + } | |
| 17843 | + else if( c==0 ){ | |
| 17844 | + iRet = 0; | |
| 17548 | 17845 | } |
| 17549 | 17846 | |
| 17550 | 17847 | return iRet; |
| 17551 | 17848 | } |
| 17552 | 17849 | |
| @@ -17983,10 +18280,27 @@ | ||
| 17983 | 18280 | intckFinalize(p, pStmt); |
| 17984 | 18281 | |
| 17985 | 18282 | if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 1"); |
| 17986 | 18283 | return zRet; |
| 17987 | 18284 | } |
| 18285 | + | |
| 18286 | +/* | |
| 18287 | +** Register or unregister special SQL functions implemented by intck. | |
| 18288 | +** | |
| 18289 | +** Normally the custom SQL functions used by intck are only available | |
| 18290 | +** in between sqlite3_intck_open() and sqlite3_intck_close(). However, | |
| 18291 | +** for testing and debugging, it is sometimes useful to make those | |
| 18292 | +** functions available generally. This routine provides as a separate | |
| 18293 | +** interface in order to provide that capability. | |
| 18294 | +*/ | |
| 18295 | +int sqlite3_intck_register(sqlite3 *db, int bCreate){ | |
| 18296 | + int rc; | |
| 18297 | + rc = sqlite3_create_function(db, "parse_create_index", | |
| 18298 | + 2, SQLITE_UTF8, 0, bCreate ? intckParseCreateIndexFunc : 0, 0, 0 | |
| 18299 | + ); | |
| 18300 | + return rc; | |
| 18301 | +} | |
| 17988 | 18302 | |
| 17989 | 18303 | /* |
| 17990 | 18304 | ** Open a new integrity-check object. |
| 17991 | 18305 | */ |
| 17992 | 18306 | int sqlite3_intck_open( |
| @@ -18005,13 +18319,11 @@ | ||
| 18005 | 18319 | }else{ |
| 18006 | 18320 | memset(pNew, 0, sizeof(*pNew)); |
| 18007 | 18321 | pNew->db = db; |
| 18008 | 18322 | pNew->zDb = (const char*)&pNew[1]; |
| 18009 | 18323 | memcpy(&pNew[1], zDb, nDb+1); |
| 18010 | - rc = sqlite3_create_function(db, "parse_create_index", | |
| 18011 | - 2, SQLITE_UTF8, 0, intckParseCreateIndexFunc, 0, 0 | |
| 18012 | - ); | |
| 18324 | + rc = sqlite3_intck_register(db, 1); | |
| 18013 | 18325 | if( rc!=SQLITE_OK ){ |
| 18014 | 18326 | sqlite3_intck_close(pNew); |
| 18015 | 18327 | pNew = 0; |
| 18016 | 18328 | } |
| 18017 | 18329 | } |
| @@ -18024,13 +18336,11 @@ | ||
| 18024 | 18336 | ** Free the integrity-check object. |
| 18025 | 18337 | */ |
| 18026 | 18338 | void sqlite3_intck_close(sqlite3_intck *p){ |
| 18027 | 18339 | if( p ){ |
| 18028 | 18340 | sqlite3_finalize(p->pCheck); |
| 18029 | - sqlite3_create_function( | |
| 18030 | - p->db, "parse_create_index", 1, SQLITE_UTF8, 0, 0, 0, 0 | |
| 18031 | - ); | |
| 18341 | + sqlite3_intck_register(p->db, 0); | |
| 18032 | 18342 | sqlite3_free(p->zObj); |
| 18033 | 18343 | sqlite3_free(p->zKey); |
| 18034 | 18344 | sqlite3_free(p->zTestSql); |
| 18035 | 18345 | sqlite3_free(p->zErr); |
| 18036 | 18346 | sqlite3_free(p->zMessage); |
| @@ -19464,11 +19774,11 @@ | ||
| 19464 | 19774 | sqlite3_vfs_unregister(pVfs); |
| 19465 | 19775 | sqlite3_free(pVfs); |
| 19466 | 19776 | } |
| 19467 | 19777 | |
| 19468 | 19778 | /************************* End ext/misc/vfstrace.c ********************/ |
| 19469 | -/************************* Begin ext/misc/analyze.c ******************/ | |
| 19779 | +/************************* Begin ext/misc/diskused.c ******************/ | |
| 19470 | 19780 | /* |
| 19471 | 19781 | ** 2026-04-13 |
| 19472 | 19782 | ** |
| 19473 | 19783 | ** The author disclaims copyright to this source code. In place of |
| 19474 | 19784 | ** a legal notice, here is a blessing: |
| @@ -19477,12 +19787,21 @@ | ||
| 19477 | 19787 | ** May you find forgiveness for yourself and forgive others. |
| 19478 | 19788 | ** May you share freely, never taking more than you give. |
| 19479 | 19789 | ** |
| 19480 | 19790 | ****************************************************************************** |
| 19481 | 19791 | ** |
| 19482 | -** Partial reimplement of the sqlite3_analyzer utility program as | |
| 19483 | -** loadable SQL function. | |
| 19792 | +** This extension implements an SQL function: | |
| 19793 | +** | |
| 19794 | +** diskused(X) | |
| 19795 | +** | |
| 19796 | +** Where X is the schema name (typically 'main'). The output is text | |
| 19797 | +** that describes how much filesystem space the various tables and indexes | |
| 19798 | +** of the database consume. | |
| 19799 | +** | |
| 19800 | +** This function is a replacement for the (now deprecated) | |
| 19801 | +** "sqlite3_analyzer" utility program. This function is built | |
| 19802 | +** into the CLI and is used to implement the ".diskused" command there. | |
| 19484 | 19803 | */ |
| 19485 | 19804 | /* #include "sqlite3ext.h" */ |
| 19486 | 19805 | SQLITE_EXTENSION_INIT1 |
| 19487 | 19806 | #include <assert.h> |
| 19488 | 19807 | #include <string.h> |
| @@ -19490,28 +19809,28 @@ | ||
| 19490 | 19809 | #include <math.h> |
| 19491 | 19810 | |
| 19492 | 19811 | /* |
| 19493 | 19812 | ** State information for the analysis |
| 19494 | 19813 | */ |
| 19495 | -typedef struct Analysis Analysis; | |
| 19496 | -struct Analysis { | |
| 19814 | +typedef struct DiskUsed DiskUsed; | |
| 19815 | +struct DiskUsed { | |
| 19497 | 19816 | sqlite3 *db; /* Database connection */ |
| 19498 | 19817 | sqlite3_context *context; /* SQL function context */ |
| 19499 | 19818 | sqlite3_str *pOut; /* Write output here */ |
| 19500 | 19819 | char *zSU; /* Name of the temp.space_used table */ |
| 19501 | 19820 | const char *zSchema; /* Schema to be analyzed */ |
| 19502 | 19821 | }; |
| 19503 | 19822 | |
| 19504 | 19823 | /* |
| 19505 | -** Free all resources that the Analysis object references and | |
| 19506 | -** reset the Analysis object. | |
| 19824 | +** Free all resources that the DiskUsed object references and | |
| 19825 | +** reset the DiskUsed object. | |
| 19507 | 19826 | ** |
| 19508 | -** Call this routine multiple times on the same Analysis object | |
| 19827 | +** Call this routine multiple times on the same DiskUsed object | |
| 19509 | 19828 | ** is a harmless no-op, as long as the memory for the object itself |
| 19510 | 19829 | ** has not been freed. |
| 19511 | 19830 | */ |
| 19512 | -static void analysisReset(Analysis *p){ | |
| 19831 | +static void diskusedReset(DiskUsed *p){ | |
| 19513 | 19832 | if( p->zSU ){ |
| 19514 | 19833 | char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU); |
| 19515 | 19834 | if( zSql ){ |
| 19516 | 19835 | sqlite3_exec(p->db, zSql, 0, 0, 0); |
| 19517 | 19836 | sqlite3_free(zSql); |
| @@ -19524,11 +19843,11 @@ | ||
| 19524 | 19843 | |
| 19525 | 19844 | /* |
| 19526 | 19845 | ** Report an error using formatted text. If zFormat==NULL then report |
| 19527 | 19846 | ** an OOM error. |
| 19528 | 19847 | */ |
| 19529 | -static void analysisError(Analysis *p, const char *zFormat, ...){ | |
| 19848 | +static void diskusedError(DiskUsed *p, const char *zFormat, ...){ | |
| 19530 | 19849 | char *zErr; |
| 19531 | 19850 | if( zFormat ){ |
| 19532 | 19851 | va_list ap; |
| 19533 | 19852 | va_start(ap, zFormat); |
| 19534 | 19853 | zErr = sqlite3_vmprintf(zFormat, ap); |
| @@ -19540,38 +19859,38 @@ | ||
| 19540 | 19859 | sqlite3_result_error_nomem(p->context); |
| 19541 | 19860 | }else{ |
| 19542 | 19861 | sqlite3_result_error(p->context, zErr, -1); |
| 19543 | 19862 | sqlite3_free(zErr); |
| 19544 | 19863 | } |
| 19545 | - analysisReset(p); | |
| 19864 | + diskusedReset(p); | |
| 19546 | 19865 | } |
| 19547 | 19866 | |
| 19548 | 19867 | /* |
| 19549 | 19868 | ** Prepare and return an SQL statement. |
| 19550 | 19869 | */ |
| 19551 | -static sqlite3_stmt *analysisVPrep(Analysis *p, const char *zFmt, va_list ap){ | |
| 19870 | +static sqlite3_stmt *diskusedVPrep(DiskUsed *p, const char *zFmt, va_list ap){ | |
| 19552 | 19871 | char *zSql; |
| 19553 | 19872 | int rc; |
| 19554 | 19873 | sqlite3_stmt *pStmt = 0; |
| 19555 | 19874 | zSql = sqlite3_vmprintf(zFmt, ap); |
| 19556 | - if( zSql==0 ){ analysisError(p,0); return 0; } | |
| 19875 | + if( zSql==0 ){ diskusedError(p,0); return 0; } | |
| 19557 | 19876 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 19558 | 19877 | if( rc ){ |
| 19559 | - analysisError(p, "SQL parse error: %s\nOriginal SQL: %s", | |
| 19878 | + diskusedError(p, "SQL parse error: %s\nOriginal SQL: %s", | |
| 19560 | 19879 | sqlite3_errmsg(p->db), zSql); |
| 19561 | 19880 | sqlite3_finalize(pStmt); |
| 19562 | - analysisReset(p); | |
| 19881 | + diskusedReset(p); | |
| 19563 | 19882 | pStmt = 0; |
| 19564 | 19883 | } |
| 19565 | 19884 | sqlite3_free(zSql); |
| 19566 | 19885 | return pStmt; |
| 19567 | 19886 | } |
| 19568 | -static sqlite3_stmt *analysisPrepare(Analysis *p, const char *zFormat, ...){ | |
| 19887 | +static sqlite3_stmt *diskusedPrepare(DiskUsed *p, const char *zFormat, ...){ | |
| 19569 | 19888 | va_list ap; |
| 19570 | 19889 | sqlite3_stmt *pStmt = 0; |
| 19571 | 19890 | va_start(ap, zFormat); |
| 19572 | - pStmt = analysisVPrep(p,zFormat,ap); | |
| 19891 | + pStmt = diskusedVPrep(p,zFormat,ap); | |
| 19573 | 19892 | va_end(ap); |
| 19574 | 19893 | return pStmt; |
| 19575 | 19894 | } |
| 19576 | 19895 | |
| 19577 | 19896 | /* |
| @@ -19580,60 +19899,60 @@ | ||
| 19580 | 19899 | ** |
| 19581 | 19900 | ** If rc is SQLITE_DONE or SQLITE_OK, then return false. |
| 19582 | 19901 | ** |
| 19583 | 19902 | ** The prepared statement is closed in either case. |
| 19584 | 19903 | */ |
| 19585 | -static int analysisStmtFinish(Analysis *p, int rc, sqlite3_stmt *pStmt){ | |
| 19904 | +static int diskusedStmtFinish(DiskUsed *p, int rc, sqlite3_stmt *pStmt){ | |
| 19586 | 19905 | if( rc==SQLITE_DONE ){ |
| 19587 | 19906 | rc = SQLITE_OK; |
| 19588 | 19907 | } |
| 19589 | 19908 | if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){ |
| 19590 | - analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19909 | + diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19591 | 19910 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19592 | - analysisReset(p); | |
| 19911 | + diskusedReset(p); | |
| 19593 | 19912 | } |
| 19594 | 19913 | sqlite3_finalize(pStmt); |
| 19595 | 19914 | return rc; |
| 19596 | 19915 | } |
| 19597 | 19916 | |
| 19598 | 19917 | /* |
| 19599 | 19918 | ** Run SQL. Return the number of errors. |
| 19600 | 19919 | */ |
| 19601 | -static int analysisSql(Analysis *p, const char *zFormat, ...){ | |
| 19920 | +static int diskusedSql(DiskUsed *p, const char *zFormat, ...){ | |
| 19602 | 19921 | va_list ap; |
| 19603 | 19922 | int rc; |
| 19604 | 19923 | sqlite3_stmt *pStmt = 0; |
| 19605 | 19924 | va_start(ap, zFormat); |
| 19606 | - pStmt = analysisVPrep(p,zFormat,ap); | |
| 19925 | + pStmt = diskusedVPrep(p,zFormat,ap); | |
| 19607 | 19926 | va_end(ap); |
| 19608 | 19927 | if( pStmt==0 ) return 1; |
| 19609 | 19928 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){} |
| 19610 | 19929 | if( rc==SQLITE_DONE ){ |
| 19611 | 19930 | rc = SQLITE_OK; |
| 19612 | 19931 | }else{ |
| 19613 | - analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19932 | + diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19614 | 19933 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19615 | - analysisReset(p); | |
| 19934 | + diskusedReset(p); | |
| 19616 | 19935 | } |
| 19617 | 19936 | sqlite3_finalize(pStmt); |
| 19618 | 19937 | return rc; |
| 19619 | 19938 | } |
| 19620 | 19939 | |
| 19621 | 19940 | /* |
| 19622 | 19941 | ** Run an SQL query that returns an integer. Write that integer |
| 19623 | 19942 | ** into *piRes. Return the number of errors. |
| 19624 | 19943 | */ |
| 19625 | -static int analysisSqlInt( | |
| 19626 | - Analysis *p, | |
| 19944 | +static int diskusedSqlInt( | |
| 19945 | + DiskUsed *p, | |
| 19627 | 19946 | sqlite3_int64 *piRes, |
| 19628 | 19947 | const char *zFormat, ... |
| 19629 | 19948 | ){ |
| 19630 | 19949 | va_list ap; |
| 19631 | 19950 | int rc; |
| 19632 | 19951 | sqlite3_stmt *pStmt = 0; |
| 19633 | 19952 | va_start(ap, zFormat); |
| 19634 | - pStmt = analysisVPrep(p,zFormat,ap); | |
| 19953 | + pStmt = diskusedVPrep(p,zFormat,ap); | |
| 19635 | 19954 | va_end(ap); |
| 19636 | 19955 | if( pStmt==0 ) return 1; |
| 19637 | 19956 | rc = sqlite3_step(pStmt); |
| 19638 | 19957 | if( rc==SQLITE_ROW ){ |
| 19639 | 19958 | *piRes = sqlite3_column_int64(pStmt, 0); |
| @@ -19641,14 +19960,14 @@ | ||
| 19641 | 19960 | }else if( rc==SQLITE_DONE ){ |
| 19642 | 19961 | rc = SQLITE_OK; |
| 19643 | 19962 | }else{ |
| 19644 | 19963 | if( p->db ){ |
| 19645 | 19964 | /* p->db is NULL if there was some prior error */ |
| 19646 | - analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19965 | + diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", | |
| 19647 | 19966 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19648 | 19967 | } |
| 19649 | - analysisReset(p); | |
| 19968 | + diskusedReset(p); | |
| 19650 | 19969 | } |
| 19651 | 19970 | sqlite3_finalize(pStmt); |
| 19652 | 19971 | return rc; |
| 19653 | 19972 | } |
| 19654 | 19973 | |
| @@ -19657,20 +19976,20 @@ | ||
| 19657 | 19976 | ** by the format string. If the output is initially empty, begin |
| 19658 | 19977 | ** the title line with "/" so that it forms the beginning of a C-style |
| 19659 | 19978 | ** comment. Otherwise begin with a new-line. Always finish with a |
| 19660 | 19979 | ** newline. |
| 19661 | 19980 | */ |
| 19662 | -static void analysisTitle(Analysis *p, const char *zFormat, ...){ | |
| 19981 | +static void diskusedTitle(DiskUsed *p, const char *zFormat, ...){ | |
| 19663 | 19982 | char *zFirst; |
| 19664 | 19983 | char *zTitle; |
| 19665 | 19984 | size_t nTitle; |
| 19666 | 19985 | va_list ap; |
| 19667 | 19986 | va_start(ap, zFormat); |
| 19668 | 19987 | zTitle = sqlite3_vmprintf(zFormat, ap); |
| 19669 | 19988 | va_end(ap); |
| 19670 | 19989 | if( zTitle==0 ){ |
| 19671 | - analysisError(p, 0); | |
| 19990 | + diskusedError(p, 0); | |
| 19672 | 19991 | return; |
| 19673 | 19992 | } |
| 19674 | 19993 | zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*"; |
| 19675 | 19994 | nTitle = strlen(zTitle); |
| 19676 | 19995 | if( nTitle>=75 ){ |
| @@ -19685,12 +20004,12 @@ | ||
| 19685 | 20004 | /* |
| 19686 | 20005 | ** Add an output line that begins with the zDesc text extended out to |
| 19687 | 20006 | ** 50 columns with "." characters, and followed by whatever text is |
| 19688 | 20007 | ** described by zFormat. |
| 19689 | 20008 | */ |
| 19690 | -static void analysisLine( | |
| 19691 | - Analysis *p, /* Analysis context */ | |
| 20009 | +static void diskusedLine( | |
| 20010 | + DiskUsed *p, /* DiskUsed context */ | |
| 19692 | 20011 | const char *zDesc, /* Description */ |
| 19693 | 20012 | const char *zFormat, /* Argument to the description */ |
| 19694 | 20013 | ... |
| 19695 | 20014 | ){ |
| 19696 | 20015 | char *zTxt; |
| @@ -19698,14 +20017,14 @@ | ||
| 19698 | 20017 | va_list ap; |
| 19699 | 20018 | va_start(ap, zFormat); |
| 19700 | 20019 | zTxt = sqlite3_vmprintf(zFormat, ap); |
| 19701 | 20020 | va_end(ap); |
| 19702 | 20021 | if( zTxt==0 ){ |
| 19703 | - analysisError(p, 0); | |
| 20022 | + diskusedError(p, 0); | |
| 19704 | 20023 | return; |
| 19705 | 20024 | } |
| 19706 | - nDesc = strlen(zDesc); | |
| 20025 | + nDesc = zDesc ? strlen(zDesc) : 0; | |
| 19707 | 20026 | if( nDesc>=50 ){ |
| 19708 | 20027 | sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt); |
| 19709 | 20028 | }else{ |
| 19710 | 20029 | int nExtra = 50 - (int)nDesc; |
| 19711 | 20030 | sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt); |
| @@ -19715,15 +20034,28 @@ | ||
| 19715 | 20034 | /* |
| 19716 | 20035 | ** Write a percentage into the output. The number written should show |
| 19717 | 20036 | ** two or three significant digits, with the decimal point being the fourth |
| 19718 | 20037 | ** character. |
| 19719 | 20038 | */ |
| 19720 | -static void analysisPercent(Analysis *p, double r){ | |
| 20039 | +static void diskusedPercent( | |
| 20040 | + DiskUsed *p, /* Context of the disk-usage analysis */ | |
| 20041 | + sqlite3_int64 num, /* Numerator of the fraction */ | |
| 20042 | + sqlite3_int64 denom /* Denominator of the fraction. Might be zero! */ | |
| 20043 | +){ | |
| 19721 | 20044 | char zNum[100]; |
| 19722 | 20045 | char *zDP; |
| 19723 | 20046 | int nLeadingDigit; |
| 19724 | 20047 | int sz; |
| 20048 | + double r; | |
| 20049 | + if( num==0 ){ | |
| 20050 | + r = 0.0; | |
| 20051 | + }else if( denom==0 ){ | |
| 20052 | + sqlite3_str_appendchar(p->pOut, 1, '\n'); | |
| 20053 | + return; | |
| 20054 | + }else{ | |
| 20055 | + r = num*100.0/(double)denom; | |
| 20056 | + } | |
| 19725 | 20057 | sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r); |
| 19726 | 20058 | sz = (int)strlen(zNum); |
| 19727 | 20059 | zDP = strchr(zNum, '.'); |
| 19728 | 20060 | if( zDP==0 ){ |
| 19729 | 20061 | memcpy(zNum+sz,".0",3); |
| @@ -19744,12 +20076,12 @@ | ||
| 19744 | 20076 | ** |
| 19745 | 20077 | ** The title if the subreport is given by zTitle. zWhere is |
| 19746 | 20078 | ** a boolean expression that can go in the WHERE clause to select |
| 19747 | 20079 | ** the relevant rows of the s.zSU table. |
| 19748 | 20080 | */ |
| 19749 | -static int analysisSubreport( | |
| 19750 | - Analysis *p, /* Analysis context */ | |
| 20081 | +static int diskusedSubreport( | |
| 20082 | + DiskUsed *p, /* DiskUsed context */ | |
| 19751 | 20083 | char *zTitle, /* Title for this subreport */ |
| 19752 | 20084 | char *zWhere, /* WHERE clause for this subreport */ |
| 19753 | 20085 | sqlite3_int64 pgsz, /* Database page size */ |
| 19754 | 20086 | sqlite3_int64 nPage /* Number of pages in entire database */ |
| 19755 | 20087 | ){ |
| @@ -19773,14 +20105,14 @@ | ||
| 19773 | 20105 | sqlite3_int64 total_unused; /* Total unused bytes */ |
| 19774 | 20106 | sqlite3_int64 total_meta; /* Total metadata */ |
| 19775 | 20107 | int rc; |
| 19776 | 20108 | |
| 19777 | 20109 | if( zTitle==0 || zWhere==0 ){ |
| 19778 | - analysisError(p, 0); | |
| 20110 | + diskusedError(p, 0); | |
| 19779 | 20111 | return SQLITE_NOMEM; |
| 19780 | 20112 | } |
| 19781 | - pStmt = analysisPrepare(p, | |
| 20113 | + pStmt = diskusedPrepare(p, | |
| 19782 | 20114 | "SELECT\n" |
| 19783 | 20115 | " sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */ |
| 19784 | 20116 | " sum(payload),\n" /* 1 */ |
| 19785 | 20117 | " sum(ovfl_payload),\n" /* 2 */ |
| 19786 | 20118 | " max(mx_payload),\n" /* 3 */ |
| @@ -19797,11 +20129,11 @@ | ||
| 19797 | 20129 | " FROM temp.%s WHERE %s", |
| 19798 | 20130 | p->zSU, zWhere); |
| 19799 | 20131 | if( pStmt==0 ) return 1; |
| 19800 | 20132 | rc = sqlite3_step(pStmt); |
| 19801 | 20133 | if( rc==SQLITE_ROW ){ |
| 19802 | - analysisTitle(p, zTitle); | |
| 20134 | + diskusedTitle(p, "%s", zTitle); | |
| 19803 | 20135 | |
| 19804 | 20136 | nentry = sqlite3_column_int64(pStmt, 0); |
| 19805 | 20137 | payload = sqlite3_column_int64(pStmt, 1); |
| 19806 | 20138 | ovfl_payload = sqlite3_column_int64(pStmt, 2); |
| 19807 | 20139 | mx_payload = sqlite3_column_int64(pStmt, 3); |
| @@ -19816,73 +20148,73 @@ | ||
| 19816 | 20148 | cnt = sqlite3_column_int64(pStmt, 12); |
| 19817 | 20149 | int_cell = sqlite3_column_int64(pStmt, 13); |
| 19818 | 20150 | rc = SQLITE_DONE; |
| 19819 | 20151 | |
| 19820 | 20152 | total_pages = leaf_pages + int_pages + ovfl_pages; |
| 19821 | - analysisLine(p, "Percentage of total database", "%.3g%%\n", | |
| 20153 | + diskusedLine(p, "Percentage of total database", "%.3g%%\n", | |
| 19822 | 20154 | (total_pages*100.0)/(double)nPage); |
| 19823 | - analysisLine(p, "Number of entries", "%lld\n", nentry); | |
| 20155 | + diskusedLine(p, "Number of entries", "%lld\n", nentry); | |
| 19824 | 20156 | storage = total_pages*pgsz; |
| 19825 | - analysisLine(p, "Bytes of storage consumed", "%lld\n", storage); | |
| 19826 | - analysisLine(p, "Bytes of payload", "%-11lld ", payload); | |
| 19827 | - analysisPercent(p, payload*100.0/(double)storage); | |
| 20157 | + diskusedLine(p, "Bytes of storage consumed", "%lld\n", storage); | |
| 20158 | + diskusedLine(p, "Bytes of payload", "%-11lld ", payload); | |
| 20159 | + diskusedPercent(p, payload, storage); | |
| 19828 | 20160 | if( ovfl_cnt>0 ){ |
| 19829 | - analysisLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload); | |
| 19830 | - analysisPercent(p, ovfl_payload*100.0/(double)payload); | |
| 20161 | + diskusedLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload); | |
| 20162 | + diskusedPercent(p, ovfl_payload, payload); | |
| 19831 | 20163 | } |
| 19832 | 20164 | total_unused = leaf_unused + int_unused + ovfl_unused; |
| 19833 | 20165 | total_meta = storage - payload - total_unused; |
| 19834 | - analysisLine(p, "Bytes of metadata","%-11lld ", total_meta); | |
| 19835 | - analysisPercent(p, total_meta*100.0/(double)storage); | |
| 20166 | + diskusedLine(p, "Bytes of metadata","%-11lld ", total_meta); | |
| 20167 | + diskusedPercent(p, total_meta, storage); | |
| 19836 | 20168 | if( cnt==1 ){ |
| 19837 | - analysisLine(p, "B-tree depth", "%lld\n", depth); | |
| 20169 | + diskusedLine(p, "B-tree depth", "%lld\n", depth); | |
| 19838 | 20170 | if( int_cell>1 ){ |
| 19839 | - analysisLine(p, "Average fanout", "%.1f\n", | |
| 20171 | + diskusedLine(p, "Average fanout", "%.1f\n", | |
| 19840 | 20172 | (double)(int_cell+int_pages)/(double)int_pages); |
| 19841 | 20173 | } |
| 19842 | 20174 | } |
| 19843 | 20175 | if( nentry>0 ){ |
| 19844 | - analysisLine(p, "Average payload per entry", "%.1f\n", | |
| 20176 | + diskusedLine(p, "Average payload per entry", "%.1f\n", | |
| 19845 | 20177 | (double)payload/(double)nentry); |
| 19846 | - analysisLine(p, "Average unused bytes per entry", "%.1f\n", | |
| 20178 | + diskusedLine(p, "Average unused bytes per entry", "%.1f\n", | |
| 19847 | 20179 | (double)total_unused/(double)nentry); |
| 19848 | - analysisLine(p, "Average metadata per entry", "%.1f\n", | |
| 20180 | + diskusedLine(p, "Average metadata per entry", "%.1f\n", | |
| 19849 | 20181 | (double)total_meta/(double)nentry); |
| 19850 | 20182 | } |
| 19851 | - analysisLine(p, "Maximum single-entry payload", "%lld\n", mx_payload); | |
| 19852 | - if( nentry>0 ){ | |
| 19853 | - analysisLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt); | |
| 19854 | - analysisPercent(p, ovfl_cnt*100.0/(double)nentry); | |
| 19855 | - } | |
| 19856 | - if( int_pages>0 ){ | |
| 19857 | - analysisLine(p, "Index pages used", "%lld\n", int_pages); | |
| 19858 | - } | |
| 19859 | - analysisLine(p, "Primary pages used", "%lld\n", leaf_pages); | |
| 19860 | - if( ovfl_cnt ){ | |
| 19861 | - analysisLine(p, "Overflow pages used", "%lld\n", ovfl_pages); | |
| 19862 | - } | |
| 19863 | - analysisLine(p, "Total pages used", "%lld\n", total_pages); | |
| 19864 | - if( int_pages>0 ){ | |
| 19865 | - analysisLine(p, "Unused bytes on index pages", "%lld\n", int_unused); | |
| 19866 | - } | |
| 19867 | - analysisLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused); | |
| 19868 | - if( ovfl_cnt ){ | |
| 19869 | - analysisLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused); | |
| 19870 | - } | |
| 19871 | - analysisLine(p, "Unused bytes on all pages", "%-11lld ", total_unused); | |
| 19872 | - analysisPercent(p, total_unused*100.0/(double)storage); | |
| 19873 | - } | |
| 19874 | - return analysisStmtFinish(p, rc, pStmt); | |
| 19875 | -} | |
| 19876 | - | |
| 19877 | -/* | |
| 19878 | -** SQL Function: analyze(SCHEMA) | |
| 20183 | + diskusedLine(p, "Maximum single-entry payload", "%lld\n", mx_payload); | |
| 20184 | + if( nentry>0 ){ | |
| 20185 | + diskusedLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt); | |
| 20186 | + diskusedPercent(p, ovfl_cnt, nentry); | |
| 20187 | + } | |
| 20188 | + if( int_pages>0 ){ | |
| 20189 | + diskusedLine(p, "Index pages used", "%lld\n", int_pages); | |
| 20190 | + } | |
| 20191 | + diskusedLine(p, "Primary pages used", "%lld\n", leaf_pages); | |
| 20192 | + if( ovfl_cnt ){ | |
| 20193 | + diskusedLine(p, "Overflow pages used", "%lld\n", ovfl_pages); | |
| 20194 | + } | |
| 20195 | + diskusedLine(p, "Total pages used", "%lld\n", total_pages); | |
| 20196 | + if( int_pages>0 ){ | |
| 20197 | + diskusedLine(p, "Unused bytes on index pages", "%lld\n", int_unused); | |
| 20198 | + } | |
| 20199 | + diskusedLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused); | |
| 20200 | + if( ovfl_cnt ){ | |
| 20201 | + diskusedLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused); | |
| 20202 | + } | |
| 20203 | + diskusedLine(p, "Unused bytes on all pages", "%-11lld ", total_unused); | |
| 20204 | + diskusedPercent(p, total_unused, storage); | |
| 20205 | + } | |
| 20206 | + return diskusedStmtFinish(p, rc, pStmt); | |
| 20207 | +} | |
| 20208 | + | |
| 20209 | +/* | |
| 20210 | +** SQL Function: diskused(SCHEMA) | |
| 19879 | 20211 | ** |
| 19880 | 20212 | ** Analyze the database schema named in the argument. Return text |
| 19881 | -** containing the analysis. | |
| 20213 | +** containing the space utilization stats. | |
| 19882 | 20214 | */ |
| 19883 | -static void analyzeFunc( | |
| 20215 | +static void diskusedFunc( | |
| 19884 | 20216 | sqlite3_context *context, |
| 19885 | 20217 | int argc, |
| 19886 | 20218 | sqlite3_value **argv |
| 19887 | 20219 | ){ |
| 19888 | 20220 | int rc; |
| @@ -19893,47 +20225,47 @@ | ||
| 19893 | 20225 | sqlite3_int64 nPage; |
| 19894 | 20226 | sqlite3_int64 nPageInUse; |
| 19895 | 20227 | sqlite3_int64 nFreeList; |
| 19896 | 20228 | sqlite3_int64 nIndex; |
| 19897 | 20229 | sqlite3_int64 nWORowid; |
| 19898 | - Analysis s; | |
| 20230 | + DiskUsed s; | |
| 19899 | 20231 | sqlite3_uint64 r[2]; |
| 19900 | 20232 | |
| 19901 | 20233 | (void)argc; |
| 19902 | 20234 | memset(&s, 0, sizeof(s)); |
| 19903 | 20235 | s.db = sqlite3_context_db_handle(context); |
| 19904 | 20236 | s.context = context; |
| 19905 | 20237 | s.pOut = sqlite3_str_new(0); |
| 19906 | 20238 | if( sqlite3_str_errcode(s.pOut) ){ |
| 19907 | - analysisError(&s, 0); | |
| 20239 | + diskusedError(&s, 0); | |
| 19908 | 20240 | return; |
| 19909 | 20241 | } |
| 19910 | 20242 | s.zSchema = (const char*)sqlite3_value_text(argv[0]); |
| 19911 | 20243 | if( s.zSchema==0 ){ |
| 19912 | 20244 | s.zSchema = "main"; |
| 19913 | 20245 | }else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){ |
| 19914 | - analysisReset(&s); | |
| 20246 | + diskusedReset(&s); | |
| 19915 | 20247 | sqlite3_result_text(context, "cannot analyze \"temp\"",-1,SQLITE_STATIC); |
| 19916 | 20248 | return; |
| 19917 | 20249 | } |
| 19918 | 20250 | ii = 0; |
| 19919 | - rc = analysisSqlInt(&s,&ii,"SELECT 1 FROM pragma_database_list" | |
| 20251 | + rc = diskusedSqlInt(&s,&ii,"SELECT 1 FROM pragma_database_list" | |
| 19920 | 20252 | " WHERE name=%Q COLLATE nocase",s.zSchema); |
| 19921 | 20253 | if( rc || ii==0 ){ |
| 19922 | - analysisReset(&s); | |
| 20254 | + diskusedReset(&s); | |
| 19923 | 20255 | sqlite3_result_text(context,"no such database",-1,SQLITE_STATIC); |
| 19924 | 20256 | return; |
| 19925 | 20257 | } |
| 19926 | 20258 | sqlite3_randomness(sizeof(r), &r); |
| 19927 | - s.zSU = sqlite3_mprintf("analysis%016llx%016llx", r[0], r[1]); | |
| 19928 | - if( s.zSU==0 ){ analysisError(&s, 0); return; } | |
| 20259 | + s.zSU = sqlite3_mprintf("diskused%016llx%016llx", r[0], r[1]); | |
| 20260 | + if( s.zSU==0 ){ diskusedError(&s, 0); return; } | |
| 19929 | 20261 | |
| 19930 | 20262 | /* The s.zSU table contains the data used for the analysis. |
| 19931 | 20263 | ** The table name contains 128-bits of randomness to avoid |
| 19932 | 20264 | ** collisions with preexisting tables in temp. |
| 19933 | 20265 | */ |
| 19934 | - rc = analysisSql(&s, | |
| 20266 | + rc = diskusedSql(&s, | |
| 19935 | 20267 | "CREATE TABLE temp.%s(\n" |
| 19936 | 20268 | " name text, -- A table or index\n" |
| 19937 | 20269 | " tblname text, -- Table that owns name\n" |
| 19938 | 20270 | " is_index boolean, -- TRUE if it is an index\n" |
| 19939 | 20271 | " is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" |
| @@ -19956,11 +20288,11 @@ | ||
| 19956 | 20288 | ); |
| 19957 | 20289 | if( rc ) return; |
| 19958 | 20290 | |
| 19959 | 20291 | /* Populate the s.zSU table |
| 19960 | 20292 | */ |
| 19961 | - rc = analysisSql(&s, | |
| 20293 | + rc = diskusedSql(&s, | |
| 19962 | 20294 | "WITH\n" |
| 19963 | 20295 | " allidx(idxname) AS (\n" |
| 19964 | 20296 | " SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n" |
| 19965 | 20297 | " ),\n" |
| 19966 | 20298 | " allobj(allname,tblname,isidx,isworowid) AS (\n" |
| @@ -20008,141 +20340,143 @@ | ||
| 20008 | 20340 | s.zSchema /* JOIN dbstat(%Q) */ |
| 20009 | 20341 | ); |
| 20010 | 20342 | if( rc ) return; |
| 20011 | 20343 | |
| 20012 | 20344 | nPage = 0; |
| 20013 | - rc = analysisSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema); | |
| 20345 | + rc = diskusedSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema); | |
| 20014 | 20346 | if( rc ) return; |
| 20015 | 20347 | if( nPage<=0 ){ |
| 20016 | 20348 | /* Very brief reply for an empty database */ |
| 20017 | - analysisReset(&s); | |
| 20349 | + diskusedReset(&s); | |
| 20018 | 20350 | sqlite3_result_text(context, "empty database", -1, SQLITE_STATIC); |
| 20019 | 20351 | return; |
| 20020 | 20352 | } |
| 20021 | 20353 | |
| 20022 | 20354 | /* Begin generating the report */ |
| 20023 | - analysisTitle(&s, "Database storage utilization report"); | |
| 20355 | + diskusedTitle(&s, "Database storage utilization report"); | |
| 20024 | 20356 | pgsz = 0; |
| 20025 | - rc = analysisSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema); | |
| 20357 | + rc = diskusedSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema); | |
| 20026 | 20358 | if( rc ) return; |
| 20027 | - analysisLine(&s, "Page size in bytes","%lld\n",pgsz); | |
| 20028 | - analysisLine(&s, "Pages in the database", "%lld\n", nPage); | |
| 20359 | + diskusedLine(&s, "Page size in bytes","%lld\n",pgsz); | |
| 20360 | + diskusedLine(&s, "Pages in the database", "%lld\n", nPage); | |
| 20029 | 20361 | |
| 20030 | 20362 | nPageInUse = 0; |
| 20031 | - rc = analysisSqlInt(&s, &nPageInUse, | |
| 20363 | + rc = diskusedSqlInt(&s, &nPageInUse, | |
| 20032 | 20364 | "SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU); |
| 20033 | 20365 | if( rc ) return; |
| 20034 | - analysisLine(&s, "Pages that store data", "%-11lld ", nPageInUse); | |
| 20035 | - analysisPercent(&s, (nPageInUse*100.0)/(double)nPage); | |
| 20366 | + diskusedLine(&s, "Pages that store data", "%-11lld ", nPageInUse); | |
| 20367 | + diskusedPercent(&s, nPageInUse, nPage); | |
| 20036 | 20368 | |
| 20037 | 20369 | nFreeList = 0; |
| 20038 | - rc = analysisSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema); | |
| 20370 | + rc = diskusedSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema); | |
| 20039 | 20371 | if( rc ) return; |
| 20040 | - analysisLine(&s, "Pages on the freelist", "%-11lld ", nFreeList); | |
| 20041 | - analysisPercent(&s, (nFreeList*100.0)/(double)nPage); | |
| 20372 | + diskusedLine(&s, "Pages on the freelist", "%-11lld ", nFreeList); | |
| 20373 | + diskusedPercent(&s, nFreeList, nPage); | |
| 20042 | 20374 | |
| 20043 | 20375 | ii = 0; |
| 20044 | - rc = analysisSqlInt(&s, &ii, "PRAGMA \"%w\".auto_vacuum", s.zSchema); | |
| 20376 | + rc = diskusedSqlInt(&s, &ii, "PRAGMA \"%w\".auto_vacuum", s.zSchema); | |
| 20045 | 20377 | if( rc ) return; |
| 20046 | 20378 | if( ii==0 || nPage<=1 ){ |
| 20047 | 20379 | ii = 0; |
| 20048 | 20380 | }else{ |
| 20049 | 20381 | double rPtrsPerPage = pgsz/5; |
| 20050 | 20382 | double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0); |
| 20051 | 20383 | ii = (sqlite3_int64)ceil(rAvPage); |
| 20052 | 20384 | } |
| 20053 | - analysisLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", ii); | |
| 20054 | - analysisPercent(&s, (ii*100.0)/(double)nPage); | |
| 20385 | + diskusedLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", ii); | |
| 20386 | + diskusedPercent(&s, ii, nPage); | |
| 20055 | 20387 | |
| 20056 | 20388 | ii = 0; |
| 20057 | - rc = analysisSqlInt(&s, &ii, | |
| 20389 | + rc = diskusedSqlInt(&s, &ii, | |
| 20058 | 20390 | "SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'", |
| 20059 | 20391 | s.zSchema); |
| 20060 | 20392 | if( rc ) return; |
| 20061 | - analysisLine(&s, "Number of tables", "%lld\n", ii); | |
| 20393 | + diskusedLine(&s, "Number of tables", "%lld\n", ii); | |
| 20062 | 20394 | nWORowid = 0; |
| 20063 | - rc = analysisSqlInt(&s, &nWORowid, | |
| 20395 | + rc = diskusedSqlInt(&s, &nWORowid, | |
| 20064 | 20396 | "SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr", |
| 20065 | 20397 | s.zSchema); |
| 20066 | 20398 | if( rc ) return; |
| 20067 | 20399 | if( nWORowid>0 ){ |
| 20068 | - analysisLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid); | |
| 20069 | - analysisLine(&s, "Number of rowid tables", "%lld\n", ii - nWORowid); | |
| 20400 | + diskusedLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid); | |
| 20401 | + diskusedLine(&s, "Number of rowid tables", "%lld\n", ii - nWORowid); | |
| 20070 | 20402 | } |
| 20071 | 20403 | nIndex = 0; |
| 20072 | - rc = analysisSqlInt(&s, &nIndex, | |
| 20404 | + rc = diskusedSqlInt(&s, &nIndex, | |
| 20073 | 20405 | "SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'", |
| 20074 | 20406 | s.zSchema); |
| 20075 | 20407 | if( rc ) return; |
| 20076 | - analysisLine(&s, "Number of indexes", "%lld\n", nIndex); | |
| 20408 | + diskusedLine(&s, "Number of indexes", "%lld\n", nIndex); | |
| 20077 | 20409 | ii = 0; |
| 20078 | - rc = analysisSqlInt(&s, &ii, | |
| 20410 | + rc = diskusedSqlInt(&s, &ii, | |
| 20079 | 20411 | "SELECT count(*) FROM \"%w\".sqlite_schema" |
| 20080 | 20412 | " WHERE name GLOB 'sqlite_autoindex_*' AND type='index'", |
| 20081 | 20413 | s.zSchema); |
| 20082 | 20414 | if( rc ) return; |
| 20083 | - analysisLine(&s, "Number of defined indexes", "%lld\n", nIndex - ii); | |
| 20084 | - analysisLine(&s, "Number of implied indexes", "%lld\n", ii); | |
| 20085 | - analysisLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage); | |
| 20415 | + diskusedLine(&s, "Number of defined indexes", "%lld\n", nIndex - ii); | |
| 20416 | + diskusedLine(&s, "Number of implied indexes", "%lld\n", ii); | |
| 20417 | + diskusedLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage); | |
| 20086 | 20418 | ii = 0; |
| 20087 | - rc = analysisSqlInt(&s, &ii, | |
| 20419 | + rc = diskusedSqlInt(&s, &ii, | |
| 20088 | 20420 | "SELECT sum(payload) FROM temp.%s" |
| 20089 | 20421 | " WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'", |
| 20090 | 20422 | s.zSU); |
| 20091 | 20423 | if( rc ) return; |
| 20092 | - analysisLine(&s, "Bytes of payload", "%-11lld ", ii); | |
| 20093 | - analysisPercent(&s, ii*100.0/(double)(pgsz*nPage)); | |
| 20424 | + diskusedLine(&s, "Bytes of payload", "%-11lld ", ii); | |
| 20425 | + diskusedPercent(&s, ii, pgsz*nPage); | |
| 20094 | 20426 | |
| 20095 | - analysisTitle(&s, "Page counts for all tables with their indexes"); | |
| 20096 | - pStmt = analysisPrepare(&s, | |
| 20427 | + diskusedTitle(&s, "Page counts for all tables with their indexes"); | |
| 20428 | + pStmt = diskusedPrepare(&s, | |
| 20097 | 20429 | "SELECT upper(tblname),\n" |
| 20098 | 20430 | " sum(int_pages+leaf_pages+ovfl_pages)\n" |
| 20099 | 20431 | " FROM temp.%s\n" |
| 20432 | + " WHERE tblname IS NOT NULL\n" | |
| 20433 | + " GROUP BY 1\n" | |
| 20434 | + " ORDER BY 2 DESC, 1;", | |
| 20435 | + s.zSU); | |
| 20436 | + if( pStmt==0 ) return; | |
| 20437 | + while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ | |
| 20438 | + sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); | |
| 20439 | + diskusedLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); | |
| 20440 | + diskusedPercent(&s, nn, nPage); | |
| 20441 | + } | |
| 20442 | + if( diskusedStmtFinish(&s, rc, pStmt) ) return; | |
| 20443 | + | |
| 20444 | + diskusedTitle(&s, "Page counts for all tables and indexes separately"); | |
| 20445 | + pStmt = diskusedPrepare(&s, | |
| 20446 | + "SELECT upper(name),\n" | |
| 20447 | + " sum(int_pages+leaf_pages+ovfl_pages)\n" | |
| 20448 | + " FROM temp.%s\n" | |
| 20449 | + " WHERE name IS NOT NULL\n" | |
| 20100 | 20450 | " GROUP BY 1\n" |
| 20101 | 20451 | " ORDER BY 2 DESC, 1;", |
| 20102 | 20452 | s.zSU); |
| 20103 | 20453 | if( pStmt==0 ) return; |
| 20104 | 20454 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| 20105 | 20455 | sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); |
| 20106 | - analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); | |
| 20107 | - analysisPercent(&s, (nn*100.0)/(double)nPage); | |
| 20108 | - } | |
| 20109 | - if( analysisStmtFinish(&s, rc, pStmt) ) return; | |
| 20110 | - | |
| 20111 | - analysisTitle(&s, "Page counts for all tables and indexes separately"); | |
| 20112 | - pStmt = analysisPrepare(&s, | |
| 20113 | - "SELECT upper(name),\n" | |
| 20114 | - " sum(int_pages+leaf_pages+ovfl_pages)\n" | |
| 20115 | - " FROM temp.%s\n" | |
| 20116 | - " GROUP BY 1\n" | |
| 20117 | - " ORDER BY 2 DESC, 1;", | |
| 20118 | - s.zSU); | |
| 20119 | - if( pStmt==0 ) return; | |
| 20120 | - while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ | |
| 20121 | - sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); | |
| 20122 | - analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); | |
| 20123 | - analysisPercent(&s, (nn*100.0)/(double)nPage); | |
| 20124 | - } | |
| 20125 | - if( analysisStmtFinish(&s, rc, pStmt) ) return; | |
| 20126 | - | |
| 20127 | - rc = analysisSubreport(&s, "All tables and indexes", "1", pgsz, nPage); | |
| 20456 | + diskusedLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); | |
| 20457 | + diskusedPercent(&s, nn, nPage); | |
| 20458 | + } | |
| 20459 | + if( diskusedStmtFinish(&s, rc, pStmt) ) return; | |
| 20460 | + | |
| 20461 | + rc = diskusedSubreport(&s, "All tables and indexes", "1", pgsz, nPage); | |
| 20128 | 20462 | if( rc ) return; |
| 20129 | - rc = analysisSubreport(&s, "All tables", "NOT is_index", pgsz, nPage); | |
| 20463 | + rc = diskusedSubreport(&s, "All tables", "NOT is_index", pgsz, nPage); | |
| 20130 | 20464 | if( rc ) return; |
| 20131 | 20465 | if( nWORowid>0 ){ |
| 20132 | - rc = analysisSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid", | |
| 20466 | + rc = diskusedSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid", | |
| 20133 | 20467 | pgsz, nPage); |
| 20134 | 20468 | if( rc ) return; |
| 20135 | - rc = analysisSubreport(&s, "All rowid tables", | |
| 20469 | + rc = diskusedSubreport(&s, "All rowid tables", | |
| 20136 | 20470 | "NOT is_without_rowid AND NOT is_index", |
| 20137 | 20471 | pgsz, nPage); |
| 20138 | 20472 | if( rc ) return; |
| 20139 | 20473 | } |
| 20140 | - rc = analysisSubreport(&s, "All indexes", "is_index", pgsz, nPage); | |
| 20474 | + rc = diskusedSubreport(&s, "All indexes", "is_index", pgsz, nPage); | |
| 20141 | 20475 | if( rc ) return; |
| 20142 | 20476 | |
| 20143 | - pStmt = analysisPrepare(&s, | |
| 20477 | + pStmt = diskusedPrepare(&s, | |
| 20144 | 20478 | "SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s" |
| 20145 | 20479 | " GROUP BY 1 ORDER BY 1", |
| 20146 | 20480 | s.zSU); |
| 20147 | 20481 | if( pStmt==0 ) return; |
| 20148 | 20482 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| @@ -20150,37 +20484,37 @@ | ||
| 20150 | 20484 | const char *zName = (const char*)sqlite3_column_text(pStmt, 1); |
| 20151 | 20485 | int nSubIndex = sqlite3_column_int(pStmt, 2); |
| 20152 | 20486 | if( nSubIndex==0 ){ |
| 20153 | 20487 | char *zTitle = sqlite3_mprintf("Table %s", zUpper); |
| 20154 | 20488 | char *zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20155 | - rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20489 | + rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20156 | 20490 | sqlite3_free(zTitle); |
| 20157 | 20491 | sqlite3_free(zWhere); |
| 20158 | 20492 | if( rc ) break; |
| 20159 | 20493 | }else{ |
| 20160 | 20494 | sqlite3_stmt *pS2; |
| 20161 | 20495 | char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper); |
| 20162 | 20496 | char *zWhere = sqlite3_mprintf("tblname=%Q", zName); |
| 20163 | - rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20497 | + rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20164 | 20498 | sqlite3_free(zTitle); |
| 20165 | 20499 | sqlite3_free(zWhere); |
| 20166 | 20500 | if( rc ) break; |
| 20167 | 20501 | zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper); |
| 20168 | 20502 | zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20169 | - rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20503 | + rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20170 | 20504 | sqlite3_free(zTitle); |
| 20171 | 20505 | sqlite3_free(zWhere); |
| 20172 | 20506 | if( rc ) break; |
| 20173 | 20507 | if( nSubIndex>1 ){ |
| 20174 | 20508 | zTitle = sqlite3_mprintf("All indexes of table %s", zUpper); |
| 20175 | 20509 | zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName); |
| 20176 | - rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20510 | + rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20177 | 20511 | sqlite3_free(zTitle); |
| 20178 | 20512 | sqlite3_free(zWhere); |
| 20179 | 20513 | if( rc ) break; |
| 20180 | 20514 | } |
| 20181 | - pS2 = analysisPrepare(&s, | |
| 20515 | + pS2 = diskusedPrepare(&s, | |
| 20182 | 20516 | "SELECT name, upper(name) FROM temp.%s" |
| 20183 | 20517 | " WHERE is_index AND tblname=%Q", |
| 20184 | 20518 | s.zSU, zName); |
| 20185 | 20519 | if( pS2==0 ){ |
| 20186 | 20520 | rc = SQLITE_NOMEM; |
| @@ -20189,25 +20523,25 @@ | ||
| 20189 | 20523 | while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){ |
| 20190 | 20524 | const char *zU = (const char*)sqlite3_column_text(pS2, 1); |
| 20191 | 20525 | const char *zN = (const char*)sqlite3_column_text(pS2, 0); |
| 20192 | 20526 | zTitle = sqlite3_mprintf("Index %s", zU); |
| 20193 | 20527 | zWhere = sqlite3_mprintf("name=%Q", zN); |
| 20194 | - rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20528 | + rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); | |
| 20195 | 20529 | sqlite3_free(zTitle); |
| 20196 | 20530 | sqlite3_free(zWhere); |
| 20197 | 20531 | if( rc ) break; |
| 20198 | 20532 | } |
| 20199 | - rc = analysisStmtFinish(&s, rc, pS2); | |
| 20533 | + rc = diskusedStmtFinish(&s, rc, pS2); | |
| 20200 | 20534 | if( rc ) break; |
| 20201 | 20535 | } |
| 20202 | 20536 | } |
| 20203 | - if( analysisStmtFinish(&s, rc, pStmt) ) return; | |
| 20537 | + if( diskusedStmtFinish(&s, rc, pStmt) ) return; | |
| 20204 | 20538 | |
| 20205 | 20539 | /* Append SQL statements that will recreate the raw data used for |
| 20206 | 20540 | ** the analysis. |
| 20207 | 20541 | */ |
| 20208 | - analysisTitle(&s, "Raw data used to generate this report"); | |
| 20542 | + diskusedTitle(&s, "Raw data used to generate this report"); | |
| 20209 | 20543 | sqlite3_str_appendf(s.pOut, |
| 20210 | 20544 | "The following SQL will create a table named \"space_used\" which\n" |
| 20211 | 20545 | "contains most of the information used to generate the report above.\n" |
| 20212 | 20546 | "*/\n" |
| 20213 | 20547 | ); |
| @@ -20233,11 +20567,11 @@ | ||
| 20233 | 20567 | " ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */ |
| 20234 | 20568 | " int_entries int -- B-tree entries on internal pages\n"/* 17 */ |
| 20235 | 20569 | ");\n" |
| 20236 | 20570 | "INSERT INTO space_used VALUES\n" |
| 20237 | 20571 | ); |
| 20238 | - pStmt = analysisPrepare(&s, | |
| 20572 | + pStmt = diskusedPrepare(&s, | |
| 20239 | 20573 | "SELECT quote(name), quote(tblname),\n" /* 0..1 */ |
| 20240 | 20574 | " is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */ |
| 20241 | 20575 | " depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */ |
| 20242 | 20576 | " int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */ |
| 20243 | 20577 | " leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */ |
| @@ -20268,11 +20602,11 @@ | ||
| 20268 | 20602 | sqlite3_column_int64(pStmt, 15), |
| 20269 | 20603 | sqlite3_column_int64(pStmt, 16), |
| 20270 | 20604 | sqlite3_column_int64(pStmt, 17)); |
| 20271 | 20605 | } |
| 20272 | 20606 | if( rc!=SQLITE_DONE ){ |
| 20273 | - analysisError(&s, "SQL run-time error: %s\nSQL: %s", | |
| 20607 | + diskusedError(&s, "SQL run-time error: %s\nSQL: %s", | |
| 20274 | 20608 | sqlite3_errmsg(s.db), sqlite3_sql(pStmt)); |
| 20275 | 20609 | sqlite3_finalize(pStmt); |
| 20276 | 20610 | return; |
| 20277 | 20611 | } |
| 20278 | 20612 | sqlite3_str_appendf(s.pOut,";\nCOMMIT;"); |
| @@ -20281,32 +20615,144 @@ | ||
| 20281 | 20615 | if( sqlite3_str_length(s.pOut) ){ |
| 20282 | 20616 | sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1, |
| 20283 | 20617 | sqlite3_free); |
| 20284 | 20618 | s.pOut = 0; |
| 20285 | 20619 | } |
| 20286 | - analysisReset(&s); | |
| 20620 | + diskusedReset(&s); | |
| 20287 | 20621 | } |
| 20288 | 20622 | |
| 20623 | + | |
| 20624 | +#ifdef _WIN32 | |
| 20625 | + | |
| 20626 | +#endif | |
| 20627 | +int sqlite3_diskused_init( | |
| 20628 | + sqlite3 *db, | |
| 20629 | + char **pzErrMsg, | |
| 20630 | + const sqlite3_api_routines *pApi | |
| 20631 | +){ | |
| 20632 | + int rc = SQLITE_OK; | |
| 20633 | + SQLITE_EXTENSION_INIT2(pApi); | |
| 20634 | + (void)pzErrMsg; /* Unused parameter */ | |
| 20635 | + rc = sqlite3_create_function(db, "diskused", 1, | |
| 20636 | + SQLITE_UTF8|SQLITE_DIRECTONLY, | |
| 20637 | + 0, diskusedFunc, 0, 0); | |
| 20638 | + return rc; | |
| 20639 | +} | |
| 20640 | + | |
| 20641 | +/************************* End ext/misc/diskused.c ********************/ | |
| 20642 | +/************************* Begin ext/misc/strdup.c ******************/ | |
| 20643 | +/* | |
| 20644 | +** 2026-07-04 | |
| 20645 | +** | |
| 20646 | +** The author disclaims copyright to this source code. In place of | |
| 20647 | +** a legal notice, here is a blessing: | |
| 20648 | +** | |
| 20649 | +** May you do good and not evil. | |
| 20650 | +** May you find forgiveness for yourself and forgive others. | |
| 20651 | +** May you share freely, never taking more than you give. | |
| 20652 | +** | |
| 20653 | +****************************************************************************** | |
| 20654 | +** | |
| 20655 | +** Since this module was written (coincidentally) on the 250th anniversary | |
| 20656 | +** of the signing of the Declaration of Independence of The United States, | |
| 20657 | +** it seems fitting to quote from that document: | |
| 20658 | +** | |
| 20659 | +** We hold these truths to be self-evident, that all men are created | |
| 20660 | +** equal, that they are endowed by their Creator with certain unalienable | |
| 20661 | +** Rights, that among these are Life, Liberty and the pursuit of Happiness | |
| 20662 | +** - That to secure these rights, Governments are instituted among Men, | |
| 20663 | +** deriving their just powers from the consent of the governed,.... | |
| 20664 | +** | |
| 20665 | +** Two core ideas that (1) rights come from God and not from government, | |
| 20666 | +** and that (2) there should not be special privileged classes of people | |
| 20667 | +** were radical thoughts then, and are indeed disputed even today. Many | |
| 20668 | +** people still hold that human rights derive from the beneficence of | |
| 20669 | +** government and that certain classes of people have special rights and | |
| 20670 | +** privileges not available to all. Yet, were it not for the crazy ideas | |
| 20671 | +** espoused in the original Declaration of Independence, this software | |
| 20672 | +** project, and indeed most of modern technology, would not exist. | |
| 20673 | +** | |
| 20674 | +** Therefore let us give thanks for the bold leadership and vision | |
| 20675 | +** demonstrated by the authors of the American Revolution, 250 years ago | |
| 20676 | +** this day. | |
| 20677 | +** | |
| 20678 | +****************************************************************************** | |
| 20679 | +** | |
| 20680 | +** Implementation of the strdup() SQL function. strdup() makes a copy | |
| 20681 | +** of its argument (a string or a BLOB) into memory obtained directly | |
| 20682 | +** from system malloc() (not from sqlite3_malloc()) and sized exactly | |
| 20683 | +** to hold the string or BLOB. This is intended for testing purposes, | |
| 20684 | +** particularly testing with ASAN. This function serves no practical | |
| 20685 | +** purpose beyond testing and not not intended for production use. | |
| 20686 | +** | |
| 20687 | +** NULL, BLOB, and TEXT values come through as NULL, BLOB, and TEXT, | |
| 20688 | +** respectively. Numeric values are rendered as strings and come out | |
| 20689 | +** as text. | |
| 20690 | +*/ | |
| 20691 | +/* #include "sqlite3ext.h" */ | |
| 20692 | +SQLITE_EXTENSION_INIT1 | |
| 20693 | +#include <assert.h> | |
| 20694 | +#include <string.h> | |
| 20695 | +#include <stdlib.h> | |
| 20696 | + | |
| 20697 | +/* | |
| 20698 | +** Make a copy of a string or BLOB in memory obtained from malloc(). | |
| 20699 | +*/ | |
| 20700 | +static void strdupfunc( | |
| 20701 | + sqlite3_context *context, | |
| 20702 | + int argc, | |
| 20703 | + sqlite3_value **argv | |
| 20704 | +){ | |
| 20705 | + const unsigned char *zIn; | |
| 20706 | + int nIn; | |
| 20707 | + unsigned char *zOut; | |
| 20708 | + | |
| 20709 | + assert( argc==1 ); | |
| 20710 | + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; | |
| 20711 | + if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){ | |
| 20712 | + zIn = (const unsigned char*)sqlite3_value_blob(argv[0]); | |
| 20713 | + nIn = sqlite3_value_bytes(argv[0]); | |
| 20714 | + zOut = malloc( nIn==0 ? 1 : nIn ); | |
| 20715 | + if( zOut==0 ){ | |
| 20716 | + sqlite3_result_error_nomem(context); | |
| 20717 | + return; | |
| 20718 | + } | |
| 20719 | + if( nIn>0 ) memcpy(zOut, zIn, nIn); | |
| 20720 | + sqlite3_result_blob(context, zOut, nIn, free); | |
| 20721 | + }else{ | |
| 20722 | + zIn = (const unsigned char*)sqlite3_value_text(argv[0]); | |
| 20723 | + if( zIn==0 ) return; | |
| 20724 | + nIn = (int)strlen((char*)zIn); | |
| 20725 | + zOut = malloc( nIn+1 ); | |
| 20726 | + if( zOut==0 ){ | |
| 20727 | + sqlite3_result_error_nomem(context); | |
| 20728 | + return; | |
| 20729 | + } | |
| 20730 | + memcpy(zOut, zIn, nIn); | |
| 20731 | + zOut[nIn] = 0; | |
| 20732 | + sqlite3_result_text64(context, (char*)zOut, nIn, free, | |
| 20733 | + SQLITE_UTF8_ZT); | |
| 20734 | + } | |
| 20735 | +} | |
| 20289 | 20736 | |
| 20290 | 20737 | #ifdef _WIN32 |
| 20291 | 20738 | |
| 20292 | 20739 | #endif |
| 20293 | -int sqlite3_analyze_init( | |
| 20740 | +int sqlite3_strdup_init( | |
| 20294 | 20741 | sqlite3 *db, |
| 20295 | 20742 | char **pzErrMsg, |
| 20296 | 20743 | const sqlite3_api_routines *pApi |
| 20297 | 20744 | ){ |
| 20298 | 20745 | int rc = SQLITE_OK; |
| 20299 | 20746 | SQLITE_EXTENSION_INIT2(pApi); |
| 20300 | 20747 | (void)pzErrMsg; /* Unused parameter */ |
| 20301 | - rc = sqlite3_create_function(db, "analyze", 1, | |
| 20302 | - SQLITE_UTF8|SQLITE_INNOCUOUS, | |
| 20303 | - 0, analyzeFunc, 0, 0); | |
| 20748 | + rc = sqlite3_create_function(db, "strdup", 1, SQLITE_UTF8, | |
| 20749 | + 0, strdupfunc, 0, 0); | |
| 20304 | 20750 | return rc; |
| 20305 | 20751 | } |
| 20306 | 20752 | |
| 20307 | -/************************* End ext/misc/analyze.c ********************/ | |
| 20753 | +/************************* End ext/misc/strdup.c ********************/ | |
| 20308 | 20754 | |
| 20309 | 20755 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 20310 | 20756 | #define SQLITE_SHELL_HAVE_RECOVER 1 |
| 20311 | 20757 | #else |
| 20312 | 20758 | #define SQLITE_SHELL_HAVE_RECOVER 0 |
| @@ -22123,23 +22569,44 @@ | ||
| 22123 | 22569 | int rc = sqlite3_finalize(pStmt); |
| 22124 | 22570 | if( rc!=SQLITE_OK && p->errCode==SQLITE_OK ){ |
| 22125 | 22571 | recoverDbError(p, db); |
| 22126 | 22572 | } |
| 22127 | 22573 | } |
| 22574 | + | |
| 22575 | +/* | |
| 22576 | +** Run a single SQL statement in zSql. If zSql contains two or more | |
| 22577 | +** SQL statements separated by ';', only the first is run. | |
| 22578 | +** | |
| 22579 | +** Return the sqlite3_finalizer() or sqlite3_prepare() result code | |
| 22580 | +** from running the zSql statement. | |
| 22581 | +*/ | |
| 22582 | +static int recoverOneStmt(sqlite3 *db, const char *zSql){ | |
| 22583 | + sqlite3_stmt *pStmt = 0; | |
| 22584 | + int rc; | |
| 22585 | + if( zSql==0 ) return SQLITE_OK; | |
| 22586 | + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); | |
| 22587 | + if( rc ){ | |
| 22588 | + sqlite3_finalize(pStmt); | |
| 22589 | + return rc; | |
| 22590 | + } | |
| 22591 | + while( SQLITE_ROW==sqlite3_step(pStmt) ){} | |
| 22592 | + return sqlite3_finalize(pStmt); | |
| 22593 | +} | |
| 22128 | 22594 | |
| 22129 | 22595 | /* |
| 22130 | 22596 | ** This function is a no-op if recover handle p already contains an error |
| 22131 | 22597 | ** (if p->errCode!=SQLITE_OK). A copy of p->errCode is returned in this |
| 22132 | 22598 | ** case. |
| 22133 | 22599 | ** |
| 22134 | -** Otherwise, execute SQL script zSql. If successful, return SQLITE_OK. | |
| 22135 | -** Or, if an error occurs, leave an error code and message in the recover | |
| 22136 | -** handle and return a copy of the error code. | |
| 22600 | +** Otherwise, execute a single SQL statment in zSql. Even if zSql contains | |
| 22601 | +** two or more SQL statements separated by ';', only execute the first one. | |
| 22602 | +** If successful, return SQLITE_OK. Or, if an error occurs, leave an error | |
| 22603 | +** code and message in the recover handle and return a copy of the error code. | |
| 22137 | 22604 | */ |
| 22138 | 22605 | static int recoverExec(sqlite3_recover *p, sqlite3 *db, const char *zSql){ |
| 22139 | 22606 | if( p->errCode==SQLITE_OK ){ |
| 22140 | - int rc = sqlite3_exec(db, zSql, 0, 0, 0); | |
| 22607 | + int rc = recoverOneStmt(db, zSql); | |
| 22141 | 22608 | if( rc ){ |
| 22142 | 22609 | recoverDbError(p, db); |
| 22143 | 22610 | } |
| 22144 | 22611 | } |
| 22145 | 22612 | return p->errCode; |
| @@ -22535,11 +23002,12 @@ | ||
| 22535 | 23002 | recoverError(p, SQLITE_NOMEM, 0); |
| 22536 | 23003 | } |
| 22537 | 23004 | } |
| 22538 | 23005 | recoverFinalize(p, p1); |
| 22539 | 23006 | } |
| 22540 | - recoverExec(p, db2, "CREATE TABLE t1(a); DROP TABLE t1;"); | |
| 23007 | + recoverExec(p, db2, "CREATE TABLE t1(a)"); | |
| 23008 | + recoverExec(p, db2, "DROP TABLE t1"); | |
| 22541 | 23009 | |
| 22542 | 23010 | if( p->errCode==SQLITE_OK ){ |
| 22543 | 23011 | sqlite3 *db = p->dbOut; |
| 22544 | 23012 | sqlite3_backup *pBackup = sqlite3_backup_init(db, "main", db2, "main"); |
| 22545 | 23013 | if( pBackup ){ |
| @@ -22617,16 +23085,16 @@ | ||
| 22617 | 23085 | ** discarded. |
| 22618 | 23086 | */ |
| 22619 | 23087 | static void recoverOpenRecovery(sqlite3_recover *p){ |
| 22620 | 23088 | char *zSql = recoverMPrintf(p, "ATTACH %Q AS recovery;", p->zStateDb); |
| 22621 | 23089 | recoverExec(p, p->dbOut, zSql); |
| 23090 | + sqlite3_free(zSql); | |
| 23091 | + recoverExec(p, p->dbOut, "PRAGMA writable_schema = 1"); | |
| 23092 | + recoverExec(p, p->dbOut, | |
| 23093 | + "CREATE TABLE recovery.map(pgno INTEGER PRIMARY KEY, parent INT)"); | |
| 22622 | 23094 | recoverExec(p, p->dbOut, |
| 22623 | - "PRAGMA writable_schema = 1;" | |
| 22624 | - "CREATE TABLE recovery.map(pgno INTEGER PRIMARY KEY, parent INT);" | |
| 22625 | - "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);" | |
| 22626 | - ); | |
| 22627 | - sqlite3_free(zSql); | |
| 23095 | + "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql)"); | |
| 22628 | 23096 | } |
| 22629 | 23097 | |
| 22630 | 23098 | |
| 22631 | 23099 | /* |
| 22632 | 23100 | ** This function is a no-op if recover handle p already contains an error |
| @@ -22762,11 +23230,11 @@ | ||
| 22762 | 23230 | " (type='index' AND (sql LIKE '%unique%' OR ?1))" |
| 22763 | 23231 | " FROM recovery.schema" |
| 22764 | 23232 | ")" |
| 22765 | 23233 | "SELECT rootpage, tbl, isVirtual, name, sql" |
| 22766 | 23234 | " FROM dbschema " |
| 22767 | - " WHERE tbl OR isIndex" | |
| 23235 | + " WHERE (tbl OR isIndex) AND sql GLOB 'CREATE *'" | |
| 22768 | 23236 | " ORDER BY tbl DESC, name=='sqlite_sequence' DESC" |
| 22769 | 23237 | ); |
| 22770 | 23238 | |
| 22771 | 23239 | pTblname = recoverPrepare(p, p->dbOut, |
| 22772 | 23240 | "SELECT name FROM sqlite_schema " |
| @@ -22788,11 +23256,11 @@ | ||
| 22788 | 23256 | zSql = (const char*)(zFree = recoverMPrintf(p, |
| 22789 | 23257 | "INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)", |
| 22790 | 23258 | zName, zName, zSql |
| 22791 | 23259 | )); |
| 22792 | 23260 | } |
| 22793 | - rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0); | |
| 23261 | + rc = recoverOneStmt(p->dbOut, zSql); | |
| 22794 | 23262 | if( rc==SQLITE_OK ){ |
| 22795 | 23263 | recoverSqlCallback(p, zSql); |
| 22796 | 23264 | if( bTable && !bVirtual ){ |
| 22797 | 23265 | if( SQLITE_ROW==sqlite3_step(pTblname) ){ |
| 22798 | 23266 | const char *zTbl = (const char*)sqlite3_column_text(pTblname, 0); |
| @@ -22830,19 +23298,21 @@ | ||
| 22830 | 23298 | |
| 22831 | 23299 | pSelect = recoverPrepare(p, p->dbOut, |
| 22832 | 23300 | p->bSlowIndexes ? |
| 22833 | 23301 | "SELECT rootpage, sql FROM recovery.schema " |
| 22834 | 23302 | " WHERE type!='table' AND type!='index'" |
| 23303 | + " AND sql GLOB 'CREATE *'" | |
| 22835 | 23304 | : |
| 22836 | 23305 | "SELECT rootpage, sql FROM recovery.schema " |
| 22837 | 23306 | " WHERE type!='table' AND (type!='index' OR sql NOT LIKE '%unique%')" |
| 23307 | + " AND sql GLOB 'CREATE *'" | |
| 22838 | 23308 | ); |
| 22839 | 23309 | |
| 22840 | 23310 | if( pSelect ){ |
| 22841 | 23311 | while( sqlite3_step(pSelect)==SQLITE_ROW ){ |
| 22842 | 23312 | const char *zSql = (const char*)sqlite3_column_text(pSelect, 1); |
| 22843 | - int rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0); | |
| 23313 | + int rc = recoverOneStmt(p->dbOut, zSql); | |
| 22844 | 23314 | if( rc==SQLITE_OK ){ |
| 22845 | 23315 | recoverSqlCallback(p, zSql); |
| 22846 | 23316 | }else if( rc!=SQLITE_ERROR ){ |
| 22847 | 23317 | recoverDbError(p, p->dbOut); |
| 22848 | 23318 | } |
| @@ -24216,11 +24686,11 @@ | ||
| 24216 | 24686 | recoverCacheSchema(p); |
| 24217 | 24687 | |
| 24218 | 24688 | if( bUseWrapper ) recoverUninstallWrapper(p); |
| 24219 | 24689 | }while( p->errCode==SQLITE_NOTADB |
| 24220 | 24690 | && (bUseWrapper--) |
| 24221 | - && SQLITE_OK==sqlite3_exec(p->dbIn, "ROLLBACK", 0, 0, 0) | |
| 24691 | + && SQLITE_OK==recoverOneStmt(p->dbIn, "ROLLBACK") | |
| 24222 | 24692 | ); |
| 24223 | 24693 | } |
| 24224 | 24694 | |
| 24225 | 24695 | recoverLeaveMutex(); |
| 24226 | 24696 | recoverExec(p, p->dbOut, "BEGIN"); |
| @@ -24281,11 +24751,11 @@ | ||
| 24281 | 24751 | |
| 24282 | 24752 | /* If no error has occurred, commit the write transaction on the output |
| 24283 | 24753 | ** database. Regardless of whether or not an error has occurred, make |
| 24284 | 24754 | ** an attempt to end the read transaction on the input database. */ |
| 24285 | 24755 | recoverExec(p, p->dbOut, "COMMIT"); |
| 24286 | - rc = sqlite3_exec(p->dbIn, "END", 0, 0, 0); | |
| 24756 | + rc = recoverOneStmt(p->dbIn, "END"); | |
| 24287 | 24757 | if( p->errCode==SQLITE_OK ) p->errCode = rc; |
| 24288 | 24758 | |
| 24289 | 24759 | recoverSqlCallback(p, "PRAGMA writable_schema = off"); |
| 24290 | 24760 | recoverSqlCallback(p, "COMMIT"); |
| 24291 | 24761 | p->eState = RECOVER_STATE_DONE; |
| @@ -24477,11 +24947,11 @@ | ||
| 24477 | 24947 | if( p==0 ){ |
| 24478 | 24948 | rc = SQLITE_NOMEM; |
| 24479 | 24949 | }else{ |
| 24480 | 24950 | recoverFinalCleanup(p); |
| 24481 | 24951 | if( p->bCloseTransaction && sqlite3_get_autocommit(p->dbIn)==0 ){ |
| 24482 | - rc = sqlite3_exec(p->dbIn, "END", 0, 0, 0); | |
| 24952 | + rc = recoverOneStmt(p->dbIn, "END"); | |
| 24483 | 24953 | if( p->errCode==SQLITE_OK ) p->errCode = rc; |
| 24484 | 24954 | } |
| 24485 | 24955 | rc = p->errCode; |
| 24486 | 24956 | sqlite3_free(p->zErrMsg); |
| 24487 | 24957 | sqlite3_free(p->zStateDb); |
| @@ -24499,10 +24969,20 @@ | ||
| 24499 | 24969 | #endif |
| 24500 | 24970 | #ifdef SQLITE_SHELL_EXTSRC |
| 24501 | 24971 | # include SHELL_STRINGIFY(SQLITE_SHELL_EXTSRC) |
| 24502 | 24972 | #endif |
| 24503 | 24973 | |
| 24974 | +/* | |
| 24975 | +** Set the SQLITE_SHELL_EDITION to a YYYYMMDD date string and the | |
| 24976 | +** code will attempt to use defaults for the prompt and for the | |
| 24977 | +** initial output mode (and maybe other feature) that were for | |
| 24978 | +** the most recent version not newer than the specified date. | |
| 24979 | +*/ | |
| 24980 | +#ifndef SQLITE_SHELL_EDITION | |
| 24981 | +# define SQLITE_SHELL_EDITION 99991231 /* Use the latest if unspecified */ | |
| 24982 | +#endif | |
| 24983 | + | |
| 24504 | 24984 | #if defined(SQLITE_ENABLE_SESSION) |
| 24505 | 24985 | /* |
| 24506 | 24986 | ** State information for a single open session |
| 24507 | 24987 | */ |
| 24508 | 24988 | typedef struct OpenSession OpenSession; |
| @@ -24530,10 +25010,12 @@ | ||
| 24530 | 25010 | u8 autoEQPtrace; /* autoEQP is in trace mode */ |
| 24531 | 25011 | u8 scanstatsOn; /* True to display scan stats before each finalize */ |
| 24532 | 25012 | u8 bAutoScreenWidth; /* Using the TTY to determine screen width */ |
| 24533 | 25013 | u8 mFlags; /* MFLG_ECHO, MFLG_CRLF, etc. */ |
| 24534 | 25014 | u8 eMode; /* One of the MODE_ values */ |
| 25015 | + char zIFmt[24]; /* Space to hold the --ifmt value */ | |
| 25016 | + char zFpFmt[24]; /* Space to hold the --fpfmt value */ | |
| 24535 | 25017 | sqlite3_qrf_spec spec; /* Spec to be passed into QRF */ |
| 24536 | 25018 | } Mode; |
| 24537 | 25019 | |
| 24538 | 25020 | /* Flags for Mode.mFlags */ |
| 24539 | 25021 | #define MFLG_ECHO 0x01 /* Echo inputs to output */ |
| @@ -24564,10 +25046,11 @@ | ||
| 24564 | 25046 | unsigned statsOn; /* True to display memory stats before each finalize */ |
| 24565 | 25047 | unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */ |
| 24566 | 25048 | u8 nPopOutput; /* Revert .output settings when reaching zero */ |
| 24567 | 25049 | u8 nPopMode; /* Revert .mode settings when reaching zero */ |
| 24568 | 25050 | u8 enableTimer; /* Enable the timer. 2: permanently 1: only once */ |
| 25051 | + u8 bDelimitNonprint; /* Add \001...\002 around non-printing in prompts */ | |
| 24569 | 25052 | int inputNesting; /* Track nesting level of .read and other redirects */ |
| 24570 | 25053 | double prevTimer; /* Last reported timer value */ |
| 24571 | 25054 | double tmProgress; /* --timeout option for .progress */ |
| 24572 | 25055 | i64 lineno; /* Line number of last line read from in */ |
| 24573 | 25056 | const char *zInFile; /* Name of the input file */ |
| @@ -24745,11 +25228,11 @@ | ||
| 24745 | 25228 | unsigned char eHdr; /* Default header encoding. */ |
| 24746 | 25229 | unsigned char eBlob; /* Default blob encoding. */ |
| 24747 | 25230 | unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */ |
| 24748 | 25231 | unsigned char eStyle; /* Underlying QRF style */ |
| 24749 | 25232 | unsigned char eCx; /* 0: other, 1: line, 2: columnar */ |
| 24750 | - unsigned char mFlg; /* Flags. 1=border-off 2=split-column */ | |
| 25233 | + unsigned char mFlg; /* Flags. 1=border-off 2=split-column 4=rowcount */ | |
| 24751 | 25234 | }; |
| 24752 | 25235 | |
| 24753 | 25236 | /* String constants used by built-in modes */ |
| 24754 | 25237 | static const char *aModeStr[] = |
| 24755 | 25238 | /* 0 1 2 3 4 5 6 7 8 */ |
| @@ -24758,45 +25241,45 @@ | ||
| 24758 | 25241 | /* 9 10 11 12 13 */ |
| 24759 | 25242 | |
| 24760 | 25243 | static const ModeInfo aModeInfo[] = { |
| 24761 | 25244 | /* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */ |
| 24762 | 25245 | { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 }, |
| 24763 | - { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2, 0 }, | |
| 25246 | + { "box", 0, 0, 9, 1, 1, 0, 3, 1, 2, 0 }, | |
| 24764 | 25247 | { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 }, |
| 24765 | - { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2, 0 }, | |
| 25248 | + { "column", 0, 0, 9, 1, 1, 0, 3, 2, 2, 0 }, | |
| 24766 | 25249 | { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, |
| 24767 | 25250 | { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 }, |
| 24768 | - { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 }, | |
| 25251 | + { "html", 0, 0, 9, 4, 4, 0, 3, 7, 0, 0 }, | |
| 24769 | 25252 | { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 }, |
| 24770 | 25253 | { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 }, |
| 24771 | 25254 | { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 }, |
| 24772 | 25255 | { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 }, |
| 24773 | 25256 | { "line", 13, 1, 9, 1, 1, 0, 0, 11, 1, 0 }, |
| 24774 | 25257 | { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 }, |
| 24775 | - { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2, 0 }, | |
| 25258 | + { "markdown", 0, 0, 9, 1, 1, 0, 3, 13, 2, 0 }, | |
| 24776 | 25259 | { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 }, |
| 24777 | - { "psql", 0, 0, 9, 1, 1, 0, 2, 19, 2, 1 }, | |
| 24778 | - { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2, 0 }, | |
| 25260 | + { "psql", 0, 0, 9, 1, 1, 0, 3, 19, 2, 5 }, | |
| 25261 | + { "qbox", 0, 0, 10, 2, 1, 0, 3, 1, 2, 0 }, | |
| 24779 | 25262 | { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 }, |
| 24780 | 25263 | { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 }, |
| 24781 | - { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2, 0 }, | |
| 25264 | + { "table", 0, 0, 9, 1, 1, 0, 3, 19, 2, 0 }, | |
| 24782 | 25265 | { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 }, |
| 24783 | 25266 | { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 }, |
| 24784 | - { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 } | |
| 24785 | -}; /* | / / | / / | | \ | |
| 24786 | - ** | / / | / / | | \_ 2: columnar | |
| 24787 | - ** Index into aModeStr[] | / / | | 1: line | |
| 24788 | - ** | / / | | 0: other | |
| 24789 | - ** | / / | \ | |
| 24790 | - ** text encoding |/ | show | \ | |
| 24791 | - ** v-------------------' | hdrs? | The QRF style | |
| 24792 | - ** 0: n/a blob | v-----' | |
| 24793 | - ** 1: plain v----------' 0: n/a | |
| 24794 | - ** 2: sql 0: auto 1: no | |
| 24795 | - ** 3: csv 1: as-text 2: yes | |
| 24796 | - ** 4: html 2: sql | |
| 24797 | - ** 5: c 3: hex | |
| 25267 | + { "www", 0, 0, 9, 4, 4, 0, 3, 7, 0, 0 } | |
| 25268 | +}; /* | / / | / / | | / \____ | |
| 25269 | + ** | / / | / / | | / | | |
| 25270 | + ** Index into aModeStr[] | / / | | 2: columnar | | |
| 25271 | + ** | / / | | 1: line | | |
| 25272 | + ** | / / | | 0: other | | |
| 25273 | + ** text encoding |/ | show | | | | |
| 25274 | + ** v-------------------' | hdrs? | The QRF style | | |
| 25275 | + ** 0: n/a blob | v-----' / | |
| 25276 | + ** 1: plain v----------' 0: n/a _________/ | |
| 25277 | + ** 2: sql 0: auto 1: no | | |
| 25278 | + ** 3: csv 1: as-text 2: yes 1: border-off | |
| 25279 | + ** 4: html 2: sql 3: always 2: split-column | |
| 25280 | + ** 5: c 3: hex 4: rowcount | |
| 24798 | 25281 | ** 6: json 4: c |
| 24799 | 25282 | ** 5: json |
| 24800 | 25283 | ** 6: size |
| 24801 | 25284 | ******************************************************************/ |
| 24802 | 25285 | |
| @@ -25079,11 +25562,11 @@ | ||
| 25079 | 25562 | */ |
| 25080 | 25563 | static char *local_getline(char *zLine, FILE *in){ |
| 25081 | 25564 | int nLine = zLine==0 ? 0 : 100; |
| 25082 | 25565 | int n = 0; |
| 25083 | 25566 | |
| 25084 | - while( 1 ){ | |
| 25567 | + while( seenInterrupt<2 ){ | |
| 25085 | 25568 | if( n+100>nLine ){ |
| 25086 | 25569 | if( nLine>=1073741773 ){ |
| 25087 | 25570 | free(zLine); |
| 25088 | 25571 | return 0; |
| 25089 | 25572 | } |
| @@ -25107,10 +25590,22 @@ | ||
| 25107 | 25590 | break; |
| 25108 | 25591 | } |
| 25109 | 25592 | } |
| 25110 | 25593 | return zLine; |
| 25111 | 25594 | } |
| 25595 | + | |
| 25596 | +/* | |
| 25597 | +** Return true if either the SQLITE_NO_COLOR compile-time option is used | |
| 25598 | +** or if the NO_COLOR environment variable exists | |
| 25599 | +*/ | |
| 25600 | +static int shellNoColor(void){ | |
| 25601 | +#if defined(SQLITE_NO_COLOR) || defined(SQLITE_SHELL_FIDDLE) | |
| 25602 | + return 1; | |
| 25603 | +#else | |
| 25604 | + return getenv("NO_COLOR")!=0; | |
| 25605 | +#endif | |
| 25606 | +} | |
| 25112 | 25607 | |
| 25113 | 25608 | /* |
| 25114 | 25609 | ** The SQLITE_PS_APPDEF macro should be set to the name of a function |
| 25115 | 25610 | ** that accepts a single "int" argument and returns a "const char *" |
| 25116 | 25611 | ** that is guaranteed to be non-NULL. The value returned depends on the |
| @@ -25131,35 +25626,47 @@ | ||
| 25131 | 25626 | # define SQLITE_PS_APPDEF shellPromptAppDef |
| 25132 | 25627 | static const char *shellPromptAppDef(int c){ |
| 25133 | 25628 | switch( c ){ |
| 25134 | 25629 | /* The default main prompt string */ |
| 25135 | 25630 | case 1: |
| 25136 | -#if defined(SQLITE_PS1) | |
| 25631 | +#if SQLITE_SHELL_EDITION<20260423 | |
| 25632 | + return "sqlite> "; /* Legacy prompt for backwards compatibility */ | |
| 25633 | +#elif defined(SQLITE_PS1) | |
| 25137 | 25634 | return SQLITE_PS1; |
| 25138 | -#elif defined(SQLITE_PS_NOANSI) | |
| 25139 | - return "/A-/v /~> "; | |
| 25140 | 25635 | #else |
| 25141 | - return "/e[1;32m/A-/v /e[1;/x33/:36/;m/m/e[3m/;/f/;/e[0m-> "; | |
| 25636 | + if( shellNoColor() ){ | |
| 25637 | + return "/A-/v /f-> "; | |
| 25638 | + }else{ | |
| 25639 | + return "/e[1;32m/A-/v /e[1;/x33/:36/;m/m/e[3m/;/f/;/e[0m-> "; | |
| 25640 | + } | |
| 25142 | 25641 | #endif |
| 25143 | 25642 | |
| 25144 | 25643 | /* The default continuation prompt string */ |
| 25145 | 25644 | case 2: |
| 25146 | -#if defined(SQLITE_PS2) | |
| 25645 | +#if SQLITE_SHELL_EDITION<20260423 | |
| 25646 | + return " ...> "; /* Legacy continuation prompt */ | |
| 25647 | +#elif defined(SQLITE_PS2) | |
| 25147 | 25648 | return SQLITE_PS2; |
| 25148 | -#elif defined(SQLITE_PS_NOANSI) | |
| 25149 | - return "/B/C> "; | |
| 25150 | 25649 | #else |
| 25151 | - return "/B/e[1;/x33/:36/;m/C/e[0m-> "; | |
| 25650 | + if( shellNoColor() ){ | |
| 25651 | + return "/B/C-> "; | |
| 25652 | + }else{ | |
| 25653 | + return "/B/e[1;/x33/:36/;m/C/e[0m-> "; | |
| 25654 | + } | |
| 25152 | 25655 | #endif |
| 25153 | 25656 | |
| 25154 | 25657 | /* Name of environment variables that override the prompt strings |
| 25155 | 25658 | ** of cases 1 and 2 */ |
| 25156 | 25659 | case 3: return "SQLITE_PS1"; |
| 25157 | 25660 | case 4: return "SQLITE_PS2"; |
| 25158 | 25661 | |
| 25159 | 25662 | /* Name of the application */ |
| 25663 | +#ifndef SQLITE_CLI_APPNAME | |
| 25160 | 25664 | case 'A': return "SQLite"; |
| 25665 | +#else | |
| 25666 | + case 'A': return SHELL_STRINGIFY(SQLITE_CLI_APPNAME); | |
| 25667 | +#endif | |
| 25161 | 25668 | |
| 25162 | 25669 | /* Full version number of the application, including patch level */ |
| 25163 | 25670 | case 'V': return sqlite3_libversion(); |
| 25164 | 25671 | |
| 25165 | 25672 | /* Version number without the patch level */ |
| @@ -25218,13 +25725,13 @@ | ||
| 25218 | 25725 | }else if( p->db && (pFN = sqlite3_db_filename(p->db,0))!=0 ){ |
| 25219 | 25726 | zFN = sqlite3_filename_database(pFN); |
| 25220 | 25727 | } |
| 25221 | 25728 | if( zFN==0 || zFN[0]==0 ){ |
| 25222 | 25729 | zFN = p->pAuxDb->zDbFilename; |
| 25223 | - if( zFN==0 || zFN[0]==0 || cli_strcmp(zFN,":memory:")==0 ){ | |
| 25224 | - zFN = zMemoryName; | |
| 25225 | - } | |
| 25730 | + } | |
| 25731 | + if( zFN==0 || zFN[0]==0 || cli_strcmp(zFN,":memory:")==0 ){ | |
| 25732 | + zFN = zMemoryName; | |
| 25226 | 25733 | } |
| 25227 | 25734 | return zFN; |
| 25228 | 25735 | } |
| 25229 | 25736 | |
| 25230 | 25737 | /* |
| @@ -25263,10 +25770,26 @@ | ||
| 25263 | 25770 | if( z==0 || z[0]==0 ) z = getenv("LOGNAME"); |
| 25264 | 25771 | if( z==0 || z[0]==0 ) z = "?"; |
| 25265 | 25772 | #endif |
| 25266 | 25773 | return z; |
| 25267 | 25774 | } |
| 25775 | + | |
| 25776 | +/* If z[] begins with one or more ANSI X3.64 (VT100) escape sequences | |
| 25777 | +** return the number of bytes in all such escape sequences. Return | |
| 25778 | +** zero if there are no valid escape sequences. | |
| 25779 | +*/ | |
| 25780 | +static int nAnsiEscape(const char *z){ | |
| 25781 | + int i = 0; | |
| 25782 | + while( z[i]=='\033' && z[i+1]=='[' ){ | |
| 25783 | + int k = i+2; | |
| 25784 | + while( z[k]>=0x30 && z[k]<=0x3f ){ k++; } | |
| 25785 | + while( z[k]>=0x20 && z[k]<=0x2f ){ k++; } | |
| 25786 | + if( z[k]<0x40 || z[k]>0x7e ) break; | |
| 25787 | + i = k+1; | |
| 25788 | + } | |
| 25789 | + return i; | |
| 25790 | +} | |
| 25268 | 25791 | |
| 25269 | 25792 | /* |
| 25270 | 25793 | ** Expand escapes in the given input prompt string. Return the |
| 25271 | 25794 | ** expanded prompt in memory obtained from sqlite3_malloc(). The |
| 25272 | 25795 | ** caller is responsible for freeing the memory. |
| @@ -25311,10 +25834,11 @@ | ||
| 25311 | 25834 | continue; |
| 25312 | 25835 | } |
| 25313 | 25836 | if( c>='0' && c<='7' ){ |
| 25314 | 25837 | /* /nnn becomes a single byte given by octal nnn */ |
| 25315 | 25838 | int v = c - '0'; |
| 25839 | + i++; | |
| 25316 | 25840 | while( i<=2 && zPrompt[i+1]>='0' && zPrompt[i+1]<='7' ){ |
| 25317 | 25841 | v = v*8 + zPrompt[++i] - '0'; |
| 25318 | 25842 | } |
| 25319 | 25843 | if( !mOff ) sqlite3_str_appendchar(pOut, 1, v); |
| 25320 | 25844 | zPrompt += i+1; |
| @@ -25533,15 +26057,36 @@ | ||
| 25533 | 26057 | memmove(z+idxSpace+nNew, z+idxSpace, len-nNew-idxSpace); |
| 25534 | 26058 | memset(z+idxSpace, ' ', nNew); |
| 25535 | 26059 | } |
| 25536 | 26060 | } |
| 25537 | 26061 | } |
| 25538 | - | |
| 25539 | 26062 | if( 0==sqlite3_str_length(pOut) ){ |
| 25540 | 26063 | /* Avoid a bogus OOM */ |
| 25541 | 26064 | sqlite3_str_appendchar(pOut, 1, '\0'); |
| 25542 | 26065 | } |
| 26066 | + | |
| 26067 | + /* Editline does not recognize ANSI X3.64 escape sequences. So we have | |
| 26068 | + ** to find them all and enclose them inside '\001'...'\002' delimiters. | |
| 26069 | + ** Some versions of readline also require this, but others do not. | |
| 26070 | + */ | |
| 26071 | + if( p->bDelimitNonprint && strstr(sqlite3_str_value(pOut),"\033[")!=0 ){ | |
| 26072 | + char *zOrig = sqlite3_str_finish(pOut); | |
| 26073 | + int n; | |
| 26074 | + pOut = sqlite3_str_new(0); | |
| 26075 | + for(i=0; zOrig[i]; i++){ | |
| 26076 | + if( zOrig[i]=='\033' && (n = nAnsiEscape(zOrig+i))>0 ){ | |
| 26077 | + sqlite3_str_appendchar(pOut, 1, 1); | |
| 26078 | + sqlite3_str_append(pOut, &zOrig[i], n); | |
| 26079 | + sqlite3_str_appendchar(pOut, 1, 2); | |
| 26080 | + i += n-1; | |
| 26081 | + }else{ | |
| 26082 | + sqlite3_str_appendchar(pOut, 1, zOrig[i]); | |
| 26083 | + } | |
| 26084 | + } | |
| 26085 | + sqlite3_free(zOrig); | |
| 26086 | + } | |
| 26087 | + | |
| 25543 | 26088 | return sqlite3_str_finish(pOut); |
| 25544 | 26089 | } |
| 25545 | 26090 | |
| 25546 | 26091 | /* |
| 25547 | 26092 | ** Retrieve a single line of input text. |
| @@ -25570,30 +26115,33 @@ | ||
| 25570 | 26115 | zResult = local_getline(zPrior, in); |
| 25571 | 26116 | }else{ |
| 25572 | 26117 | const char *zBase = prompt_string(p, bContinue!=0); |
| 25573 | 26118 | char *zPrompt = expand_prompt(p, zAll, zBase); |
| 25574 | 26119 | shell_check_oom(zPrompt); |
| 25575 | -#if SHELL_USE_LOCAL_GETLINE | |
| 25576 | - sputz(stdout, zPrompt); | |
| 25577 | - fflush(stdout); | |
| 25578 | - do{ | |
| 25579 | - zResult = local_getline(zPrior, stdin); | |
| 25580 | - zPrior = 0; | |
| 25581 | - /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ | |
| 25582 | - if( zResult==0 ) sqlite3_sleep(50); | |
| 25583 | - }while( zResult==0 && seenInterrupt>0 ); | |
| 25584 | -#else | |
| 25585 | - free(zPrior); | |
| 25586 | - zResult = shell_readline(zPrompt); | |
| 25587 | - while( zResult==0 ){ | |
| 25588 | - /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ | |
| 25589 | - sqlite3_sleep(50); | |
| 25590 | - if( seenInterrupt==0 ) break; | |
| 25591 | - zResult = shell_readline(""); | |
| 25592 | - } | |
| 25593 | - if( zResult && *zResult ) shell_add_history(zResult); | |
| 25594 | -#endif | |
| 26120 | +#if SHELL_CMDLINE_EDIT_AVAILABLE | |
| 26121 | + if( shellCmdLineEdit ){ | |
| 26122 | + free(zPrior); | |
| 26123 | + zResult = shell_readline(zPrompt); | |
| 26124 | + while( zResult==0 ){ | |
| 26125 | + /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ | |
| 26126 | + sqlite3_sleep(50); | |
| 26127 | + if( seenInterrupt==0 ) break; | |
| 26128 | + zResult = shell_readline(""); | |
| 26129 | + } | |
| 26130 | + if( zResult && *zResult ) shell_add_history(zResult); | |
| 26131 | + }else | |
| 26132 | +#endif | |
| 26133 | + { | |
| 26134 | + sputz(stdout, zPrompt); | |
| 26135 | + fflush(stdout); | |
| 26136 | + do{ | |
| 26137 | + zResult = local_getline(zPrior, stdin); | |
| 26138 | + zPrior = 0; | |
| 26139 | + /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ | |
| 26140 | + if( zResult==0 ) sqlite3_sleep(50); | |
| 26141 | + }while( zResult==0 && seenInterrupt>0 ); | |
| 26142 | + } | |
| 25595 | 26143 | sqlite3_free(zPrompt); |
| 25596 | 26144 | } |
| 25597 | 26145 | return zResult; |
| 25598 | 26146 | } |
| 25599 | 26147 | #endif /* !SQLITE_SHELL_FIDDLE */ |
| @@ -25834,11 +26382,12 @@ | ||
| 25834 | 26382 | double r = sqlite3_value_double(apVal[0]); |
| 25835 | 26383 | int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26; |
| 25836 | 26384 | char z[400]; |
| 25837 | 26385 | if( n<1 ) n = 1; |
| 25838 | 26386 | if( n>350 ) n = 350; |
| 25839 | - sprintf(z, "%#+.*e", n, r); | |
| 26387 | + z[sizeof(z)-1] = 0; | |
| 26388 | + snprintf(z, sizeof(z)-1, "%#+.*e", n, r); | |
| 25840 | 26389 | sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); |
| 25841 | 26390 | } |
| 25842 | 26391 | |
| 25843 | 26392 | /* |
| 25844 | 26393 | ** SQL function: shell_add_schema(S,X) |
| @@ -25912,21 +26461,27 @@ | ||
| 25912 | 26461 | } |
| 25913 | 26462 | sqlite3_result_value(pCtx, apVal[0]); |
| 25914 | 26463 | } |
| 25915 | 26464 | |
| 25916 | 26465 | /* |
| 25917 | -** SQL function: shell_prompt_test(PROMPT) | |
| 25918 | -** shell_prompt_test(PROMPT,PRIOR) | |
| 25919 | -** shell_prompt_test(PROMPT,PRIOR,FILENAME) | |
| 26466 | +** SQL function: shell_prompt_test(PROMPT,PRIOR,FILENAME,FLAGS) | |
| 25920 | 26467 | ** |
| 25921 | 26468 | ** Return the shell prompt, with escapes expanded, for testing purposes. |
| 25922 | 26469 | ** The first argument is the raw (unexpanded) prompt string. Or if the |
| 25923 | 26470 | ** first argument is NULL, then use whatever prompt string is currently |
| 25924 | 26471 | ** configured. If the second argument exists and is not NULL, then the |
| 25925 | 26472 | ** second argument is understood to be prior incomplete text and a |
| 25926 | 26473 | ** continuation prompt is generated. If a third argument is provided, |
| 25927 | -** it is assumed to be the full pathname of the database file. | |
| 26474 | +** it is assumed to be the full pathname of the database file. The | |
| 26475 | +** fourth argument, if provided, is an integer of flags: | |
| 26476 | +** | |
| 26477 | +** 0x0001 Always insert \001..\002 delimiters around ANSI escapes | |
| 26478 | +** 0x0002 Never insert \001..\002 delimiters | |
| 26479 | +** | |
| 26480 | +** This function is for testing purposes only. The interface may change. | |
| 26481 | +** The function itself might be renamed or removed in future releases. Do | |
| 26482 | +** not use this function in applications. | |
| 25928 | 26483 | */ |
| 25929 | 26484 | static void shellExpandPrompt( |
| 25930 | 26485 | sqlite3_context *pCtx, |
| 25931 | 26486 | int nVal, |
| 25932 | 26487 | sqlite3_value **apVal |
| @@ -25936,11 +26491,14 @@ | ||
| 25936 | 26491 | const char *zPrior; |
| 25937 | 26492 | const char *zSavedDbFile; |
| 25938 | 26493 | int mSavedFlgs; |
| 25939 | 26494 | const char *zFName; |
| 25940 | 26495 | char *zRes; |
| 26496 | + int mFlags; | |
| 26497 | + char bSavedDelimit = p->bDelimitNonprint; | |
| 25941 | 26498 | |
| 26499 | + if( nVal<1 ) return; | |
| 25942 | 26500 | if( nVal<2 |
| 25943 | 26501 | || (zPrior = (const char*)sqlite3_value_text(apVal[1]))==0 |
| 25944 | 26502 | || zPrior[0]==0 |
| 25945 | 26503 | ){ |
| 25946 | 26504 | zPrior = 0; |
| @@ -25952,12 +26510,19 @@ | ||
| 25952 | 26510 | zSavedDbFile = p->pAuxDb->zDbFilename; |
| 25953 | 26511 | mSavedFlgs = p->pAuxDb->mFlgs; |
| 25954 | 26512 | if( nVal>=3 && (zFName = (const char*)sqlite3_value_text(apVal[2]))!=0 ){ |
| 25955 | 26513 | p->pAuxDb->zDbFilename = zFName; |
| 25956 | 26514 | p->pAuxDb->mFlgs |= 0x001; |
| 26515 | + } | |
| 26516 | + mFlags = nVal>=4 ? sqlite3_value_int(apVal[3]) : 0; | |
| 26517 | + if( mFlags & 0x0001 ){ | |
| 26518 | + p->bDelimitNonprint = 1; | |
| 26519 | + }else if( mFlags & 0x0002 ){ | |
| 26520 | + p->bDelimitNonprint = 0; | |
| 25957 | 26521 | } |
| 25958 | 26522 | zRes = expand_prompt(p, zPrior, zPrompt); |
| 26523 | + p->bDelimitNonprint = bSavedDelimit; | |
| 25959 | 26524 | p->pAuxDb->zDbFilename = zSavedDbFile; |
| 25960 | 26525 | p->pAuxDb->mFlgs = mSavedFlgs; |
| 25961 | 26526 | sqlite3_result_text(pCtx, zRes, -1, SQLITE_TRANSIENT); |
| 25962 | 26527 | sqlite3_free(zRes); |
| 25963 | 26528 | } |
| @@ -26150,11 +26715,11 @@ | ||
| 26150 | 26715 | free(p->spec.zColumnSep); |
| 26151 | 26716 | free(p->spec.zRowSep); |
| 26152 | 26717 | free(p->spec.zTableName); |
| 26153 | 26718 | free(p->spec.zNull); |
| 26154 | 26719 | memset(p, 0, sizeof(*p)); |
| 26155 | - p->spec.iVersion = 1; | |
| 26720 | + p->spec.iVersion = 2; | |
| 26156 | 26721 | p->autoExplain = autoExplain; |
| 26157 | 26722 | } |
| 26158 | 26723 | |
| 26159 | 26724 | /* |
| 26160 | 26725 | ** Duplicate Mode pSrc into pDest. pDest is assumed to be |
| @@ -26190,10 +26755,18 @@ | ||
| 26190 | 26755 | pDest->spec.zTableName = strdup(pSrc->spec.zTableName); |
| 26191 | 26756 | } |
| 26192 | 26757 | if( pDest->spec.zNull ){ |
| 26193 | 26758 | pDest->spec.zNull = strdup(pSrc->spec.zNull); |
| 26194 | 26759 | } |
| 26760 | + if( pDest->spec.zFpFmt ){ | |
| 26761 | + assert( pDest->spec.zFpFmt==pSrc->zFpFmt ); | |
| 26762 | + pDest->spec.zFpFmt = pDest->zFpFmt; | |
| 26763 | + } | |
| 26764 | + if( pDest->spec.zIFmt ){ | |
| 26765 | + assert( pDest->spec.zIFmt==pSrc->zIFmt ); | |
| 26766 | + pDest->spec.zIFmt = pDest->zIFmt; | |
| 26767 | + } | |
| 26195 | 26768 | } |
| 26196 | 26769 | |
| 26197 | 26770 | /* |
| 26198 | 26771 | ** Set a string value to a copy of the zNew string in memory |
| 26199 | 26772 | ** obtained from system malloc(). |
| @@ -26208,10 +26781,47 @@ | ||
| 26208 | 26781 | if( *az ){ |
| 26209 | 26782 | memcpy(*az, zNew, n+1 ); |
| 26210 | 26783 | } |
| 26211 | 26784 | } |
| 26212 | 26785 | } |
| 26786 | + | |
| 26787 | +/* Forward reference */ | |
| 26788 | +static int pickStr(const char *zArg, char **pzErr, ...); | |
| 26789 | + | |
| 26790 | +/* | |
| 26791 | +** Change the limits on the display mode. Return 0 on | |
| 26792 | +** success. Return non-zero if zArg is mis-formatted. | |
| 26793 | +** | |
| 26794 | +** Valid arguments: | |
| 26795 | +** | |
| 26796 | +** "on" Default limits | |
| 26797 | +** "off" All limits turned off | |
| 26798 | +** L,C Line and Characters limits set | |
| 26799 | +** L,C,T Line, Character, and Title limits set | |
| 26800 | +** | |
| 26801 | +** Anything else returns non-zero | |
| 26802 | +*/ | |
| 26803 | +static int modeSetLimit(ShellState *p, const char *zArg){ | |
| 26804 | + int k = zArg==0 ? 1 : pickStr(zArg,0,"on","off",""); | |
| 26805 | + if( k==0 ){ | |
| 26806 | + p->mode.spec.nLineLimit = DFLT_LINE_LIMIT; | |
| 26807 | + p->mode.spec.nCharLimit = DFLT_CHAR_LIMIT; | |
| 26808 | + p->mode.spec.nTitleLimit = DFLT_TITLE_LIMIT; | |
| 26809 | + }else if( k==1 ){ | |
| 26810 | + p->mode.spec.nLineLimit = 0; | |
| 26811 | + p->mode.spec.nCharLimit = 0; | |
| 26812 | + p->mode.spec.nTitleLimit = 0; | |
| 26813 | + }else{ | |
| 26814 | + int L, C, T = 0; | |
| 26815 | + int nNum = sscanf(zArg, "%d,%d,%d", &L, &C, &T); | |
| 26816 | + if( nNum<2 || L<0 || C<0 || T<0) return 1; | |
| 26817 | + p->mode.spec.nLineLimit = L; | |
| 26818 | + p->mode.spec.nCharLimit = C; | |
| 26819 | + if( nNum==3 ) p->mode.spec.nTitleLimit = T; | |
| 26820 | + } | |
| 26821 | + return 0; | |
| 26822 | +} | |
| 26213 | 26823 | |
| 26214 | 26824 | /* |
| 26215 | 26825 | ** Change the mode to eMode |
| 26216 | 26826 | */ |
| 26217 | 26827 | static void modeChange(ShellState *p, unsigned char eMode){ |
| @@ -26238,17 +26848,23 @@ | ||
| 26238 | 26848 | pM->spec.bSplitColumn = QRF_Yes; |
| 26239 | 26849 | pM->bAutoScreenWidth = 1; |
| 26240 | 26850 | }else{ |
| 26241 | 26851 | pM->spec.bSplitColumn = QRF_No; |
| 26242 | 26852 | } |
| 26853 | + if( pI->mFlg & 0x04 ){ | |
| 26854 | + pM->spec.bRowCount = QRF_Yes; | |
| 26855 | + }else{ | |
| 26856 | + pM->spec.bRowCount = QRF_No; | |
| 26857 | + } | |
| 26243 | 26858 | }else if( eMode>=MODE_USER && eMode-MODE_USER<p->nSavedModes ){ |
| 26244 | 26859 | modeFree(&p->mode); |
| 26245 | 26860 | modeDup(&p->mode, &p->aSavedModes[eMode-MODE_USER].mode); |
| 26246 | 26861 | }else if( eMode==MODE_BATCH ){ |
| 26247 | 26862 | u8 mFlags = p->mode.mFlags; |
| 26248 | 26863 | modeFree(&p->mode); |
| 26249 | 26864 | modeChange(p, MODE_List); |
| 26865 | + modeSetLimit(p, "off"); | |
| 26250 | 26866 | p->mode.mFlags = mFlags; |
| 26251 | 26867 | }else if( eMode==MODE_TTY ){ |
| 26252 | 26868 | u8 mFlags = p->mode.mFlags; |
| 26253 | 26869 | modeFree(&p->mode); |
| 26254 | 26870 | modeChange(p, MODE_QBox); |
| @@ -26266,13 +26882,15 @@ | ||
| 26266 | 26882 | /* |
| 26267 | 26883 | ** Set the mode to the default. It assumed that the mode has |
| 26268 | 26884 | ** already been freed and zeroed prior to calling this routine. |
| 26269 | 26885 | */ |
| 26270 | 26886 | static void modeDefault(ShellState *p){ |
| 26271 | - p->mode.spec.iVersion = 1; | |
| 26887 | + p->mode.spec.iVersion = 2; | |
| 26272 | 26888 | p->mode.autoExplain = 1; |
| 26273 | - if( stdin_is_interactive || stdout_is_console ){ | |
| 26889 | + if( (stdin_is_interactive || stdout_is_console) | |
| 26890 | + && SQLITE_SHELL_EDITION>=20260409 | |
| 26891 | + ){ | |
| 26274 | 26892 | modeChange(p, MODE_TTY); |
| 26275 | 26893 | }else{ |
| 26276 | 26894 | modeChange(p, MODE_BATCH); |
| 26277 | 26895 | } |
| 26278 | 26896 | } |
| @@ -26881,11 +27499,11 @@ | ||
| 26881 | 27499 | return SQLITE_OK; |
| 26882 | 27500 | } |
| 26883 | 27501 | #endif |
| 26884 | 27502 | |
| 26885 | 27503 | /* |
| 26886 | -** Print a schema statement. This is helper routine to dump_callbac(). | |
| 27504 | +** Print a schema statement. This is a helper routine to dump_callback(). | |
| 26887 | 27505 | ** |
| 26888 | 27506 | ** This routine converts some CREATE TABLE statements for shadow tables |
| 26889 | 27507 | ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements. |
| 26890 | 27508 | ** |
| 26891 | 27509 | ** If the schema statement in z[] contains a start-of-comment and if |
| @@ -28333,12 +28951,12 @@ | ||
| 28333 | 28951 | ".databases List names and files of attached databases", |
| 28334 | 28952 | ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", |
| 28335 | 28953 | #if SQLITE_SHELL_HAVE_RECOVER |
| 28336 | 28954 | ".dbinfo ?DB? Show status information about the database", |
| 28337 | 28955 | #endif |
| 28338 | - ".dbstat ?SCHEMA? Report database space and size stats", | |
| 28339 | 28956 | ".dbtotxt Hex dump of the database file", |
| 28957 | + ".diskused ?SCHEMA? Report database space and size stats", | |
| 28340 | 28958 | ".dump ?OBJECTS? Render database content as SQL", |
| 28341 | 28959 | " Options:", |
| 28342 | 28960 | " --data-only Output only INSERT statements", |
| 28343 | 28961 | " --newlines Allow unescaped newline characters in output", |
| 28344 | 28962 | " --nosys Omit system tables (ex: \"sqlite_stat1\")", |
| @@ -28445,10 +29063,13 @@ | ||
| 28445 | 29063 | " --reset Reset the count for each input and interrupt", |
| 28446 | 29064 | " --timeout S Halt after running for S seconds", |
| 28447 | 29065 | #endif |
| 28448 | 29066 | ".prompt MAIN CONTINUE Replace the standard prompts", |
| 28449 | 29067 | " --hard-reset Unset SQLITE_PS1/2 and then --reset", |
| 29068 | +#ifndef SQLITE_NO_COLOR | |
| 29069 | + " --no-color Disable color prompts. Use --color to re-enable", | |
| 29070 | +#endif | |
| 28450 | 29071 | " --reset Revert to default prompts", |
| 28451 | 29072 | " --show Show the current prompt strings", |
| 28452 | 29073 | " -- No more options. Subsequent args are prompts", |
| 28453 | 29074 | #ifndef SQLITE_SHELL_FIDDLE |
| 28454 | 29075 | ".quit Stop interpreting input stream, exit if primary.", |
| @@ -28609,10 +29230,14 @@ | ||
| 28609 | 29230 | " truncated. Zero means \"no limit\".\n" |
| 28610 | 29231 | " --colsep STRING Use STRING as the column separator\n" |
| 28611 | 29232 | " --escape ESC Enable/disable escaping of control characters\n" |
| 28612 | 29233 | " found in the output. ESC can be \"off\", \"ascii\",\n" |
| 28613 | 29234 | " or \"symbol\".\n" |
| 29235 | +" --fpfmt STRING String is a printf-style format string used to\n" | |
| 29236 | +" render floating-point values.\n" | |
| 29237 | +" --ifmt STRING String is a printf-style format string used to\n" | |
| 29238 | +" render integer values.\n" | |
| 28614 | 29239 | " --linelimit N Set the maximum number of output lines to show for\n" |
| 28615 | 29240 | " any single SQL value to N. Longer values are\n" |
| 28616 | 29241 | " truncated. Zero means \"no limit\". Only works\n" |
| 28617 | 29242 | " in \"line\" mode and in columnar modes.\n" |
| 28618 | 29243 | " --limits L,C,T Shorthand for \"--linelimit L --charlimit C\n" |
| @@ -28629,10 +29254,11 @@ | ||
| 28629 | 29254 | " --quote ARG Enable/disable quoting of text. ARG can be\n" |
| 28630 | 29255 | " \"off\", \"on\", \"sql\", \"relaxed\", \"csv\", \"html\",\n" |
| 28631 | 29256 | " \"tcl\", or \"json\". \"off\" means show the text as-is.\n" |
| 28632 | 29257 | " \"on\" is an alias for \"sql\".\n" |
| 28633 | 29258 | " --reset Changes all mode settings back to their default.\n" |
| 29259 | +" --rowcount BOOLEAN Show \"(N rows)\" at the end of query results.\n" | |
| 28634 | 29260 | " --rowsep STRING Use STRING as the row separator\n" |
| 28635 | 29261 | " --sw|--screenwidth N Declare the screen width of the output device\n" |
| 28636 | 29262 | " to be N characters. An attempt may be made to\n" |
| 28637 | 29263 | " wrap output text to fit within this limit. Zero\n" |
| 28638 | 29264 | " means \"no limit\". Or N can be \"auto\" to set the\n" |
| @@ -28640,11 +29266,11 @@ | ||
| 28640 | 29266 | " --tablename NAME Set the name of the table for \"insert\" mode.\n" |
| 28641 | 29267 | " --tag NAME Save mode to the left as NAME.\n" |
| 28642 | 29268 | " --textjsonb BOOLEAN If enabled, JSONB text is displayed as text JSON.\n" |
| 28643 | 29269 | " --title ARG Whether or not to show column headers, and if so\n" |
| 28644 | 29270 | " how to encode them. ARG can be \"off\", \"on\",\n" |
| 28645 | -" \"sql\", \"csv\", \"html\", \"tcl\", or \"json\".\n" | |
| 29271 | +" \"always\", \"sql\", \"csv\", \"html\", \"tcl\", or \"json\".\n" | |
| 28646 | 29272 | " --titlelimit N Limit the length of column titles to N characters.\n" |
| 28647 | 29273 | " -v|--verbose Verbose output\n" |
| 28648 | 29274 | " --widths LIST Set the columns widths for columnar modes. The\n" |
| 28649 | 29275 | " argument is a list of integers, one for each\n" |
| 28650 | 29276 | " column. A \"0\" width means use a dynamic width\n" |
| @@ -29345,11 +29971,12 @@ | ||
| 29345 | 29971 | sqlite3_base64_init(p->db, 0, 0); |
| 29346 | 29972 | sqlite3_base85_init(p->db, 0, 0); |
| 29347 | 29973 | sqlite3_regexp_init(p->db, 0, 0); |
| 29348 | 29974 | sqlite3_ieee_init(p->db, 0, 0); |
| 29349 | 29975 | sqlite3_series_init(p->db, 0, 0); |
| 29350 | - sqlite3_analyze_init(p->db, 0, 0); | |
| 29976 | + sqlite3_diskused_init(p->db, 0, 0); | |
| 29977 | + sqlite3_strdup_init(p->db, 0, 0); | |
| 29351 | 29978 | #ifndef SQLITE_SHELL_FIDDLE |
| 29352 | 29979 | sqlite3_fileio_init(p->db, 0, 0); |
| 29353 | 29980 | sqlite3_completion_init(p->db, 0, 0); |
| 29354 | 29981 | #endif |
| 29355 | 29982 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -29406,15 +30033,11 @@ | ||
| 29406 | 30033 | sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0, |
| 29407 | 30034 | editFunc, 0, 0); |
| 29408 | 30035 | sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0, |
| 29409 | 30036 | editFunc, 0, 0); |
| 29410 | 30037 | #endif |
| 29411 | - sqlite3_create_function(p->db, "shell_prompt_test", 1, SQLITE_UTF8, | |
| 29412 | - p, shellExpandPrompt, 0, 0); | |
| 29413 | - sqlite3_create_function(p->db, "shell_prompt_test", 2, SQLITE_UTF8, | |
| 29414 | - p, shellExpandPrompt, 0, 0); | |
| 29415 | - sqlite3_create_function(p->db, "shell_prompt_test", 3, SQLITE_UTF8, | |
| 30038 | + sqlite3_create_function(p->db, "shell_prompt_test", -1, SQLITE_UTF8, | |
| 29416 | 30039 | p, shellExpandPrompt, 0, 0); |
| 29417 | 30040 | sqlite3_create_function(p->db, "shell_temp_filename", 1, SQLITE_UTF8, |
| 29418 | 30041 | p, shellTempFilenameFunc, 0, 0); |
| 29419 | 30042 | |
| 29420 | 30043 | |
| @@ -31155,11 +31778,11 @@ | ||
| 31155 | 31778 | typedef struct ArCommand ArCommand; |
| 31156 | 31779 | struct ArCommand { |
| 31157 | 31780 | u8 eCmd; /* An AR_CMD_* value */ |
| 31158 | 31781 | u8 bVerbose; /* True if --verbose */ |
| 31159 | 31782 | u8 bZip; /* True if the archive is a ZIP */ |
| 31160 | - u8 bDryRun; /* True if --dry-run */ | |
| 31783 | + u8 bDryRun; /* 1 for --dry-run, 2 for --debug */ | |
| 31161 | 31784 | u8 bAppend; /* True if --append */ |
| 31162 | 31785 | u8 bGlob; /* True if --glob */ |
| 31163 | 31786 | u8 fromCmdLine; /* Run from -A instead of .archive */ |
| 31164 | 31787 | int nArg; /* Number of command arguments */ |
| 31165 | 31788 | char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ |
| @@ -31217,10 +31840,11 @@ | ||
| 31217 | 31840 | #define AR_SWITCH_FILE 9 |
| 31218 | 31841 | #define AR_SWITCH_DIRECTORY 10 |
| 31219 | 31842 | #define AR_SWITCH_APPEND 11 |
| 31220 | 31843 | #define AR_SWITCH_DRYRUN 12 |
| 31221 | 31844 | #define AR_SWITCH_GLOB 13 |
| 31845 | +#define AR_SWITCH_DEBUG 14 | |
| 31222 | 31846 | |
| 31223 | 31847 | static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ |
| 31224 | 31848 | switch( eSwitch ){ |
| 31225 | 31849 | case AR_CMD_CREATE: |
| 31226 | 31850 | case AR_CMD_EXTRACT: |
| @@ -31234,11 +31858,14 @@ | ||
| 31234 | 31858 | } |
| 31235 | 31859 | pAr->eCmd = eSwitch; |
| 31236 | 31860 | break; |
| 31237 | 31861 | |
| 31238 | 31862 | case AR_SWITCH_DRYRUN: |
| 31239 | - pAr->bDryRun = 1; | |
| 31863 | + if( pAr->bDryRun<2 ) pAr->bDryRun = 1; | |
| 31864 | + break; | |
| 31865 | + case AR_SWITCH_DEBUG: | |
| 31866 | + pAr->bDryRun = 2; | |
| 31240 | 31867 | break; |
| 31241 | 31868 | case AR_SWITCH_GLOB: |
| 31242 | 31869 | pAr->bGlob = 1; |
| 31243 | 31870 | break; |
| 31244 | 31871 | case AR_SWITCH_VERBOSE: |
| @@ -31285,10 +31912,11 @@ | ||
| 31285 | 31912 | { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, |
| 31286 | 31913 | { "file", 'f', AR_SWITCH_FILE, 1 }, |
| 31287 | 31914 | { "append", 'a', AR_SWITCH_APPEND, 1 }, |
| 31288 | 31915 | { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, |
| 31289 | 31916 | { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, |
| 31917 | + { "debug", 0, AR_SWITCH_DEBUG, 0 }, | |
| 31290 | 31918 | { "glob", 'g', AR_SWITCH_GLOB, 0 }, |
| 31291 | 31919 | }; |
| 31292 | 31920 | int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); |
| 31293 | 31921 | struct ArSwitch *pEnd = &aSwitch[nSwitch]; |
| 31294 | 31922 | |
| @@ -31585,18 +32213,41 @@ | ||
| 31585 | 32213 | |
| 31586 | 32214 | /* |
| 31587 | 32215 | ** Implementation of .ar "eXtract" command. |
| 31588 | 32216 | */ |
| 31589 | 32217 | static int arExtractCommand(ArCommand *pAr){ |
| 32218 | + /* The zSql1[] string is a template for the query that does the | |
| 32219 | + ** extraction. Notes: | |
| 32220 | + ** | |
| 32221 | + ** * $dir is the directory into which the archive is to be extracted | |
| 32222 | + ** * $pass is the integer pass number: 0, 1, or 2 | |
| 32223 | + ** * The dest CTE is created so that realpath($dir) only needs | |
| 32224 | + ** to be called once. | |
| 32225 | + */ | |
| 31590 | 32226 | const char *zSql1 = |
| 31591 | - "WITH dest(dpath,dlen) AS (SELECT realpath($dir),length(realpath($dir)))\n" | |
| 31592 | - "SELECT ($dir || name),\n" | |
| 31593 | - " CASE WHEN $dryrun THEN 0\n" | |
| 31594 | - " ELSE writefile($dir||name, %s, mode, mtime) END\n" | |
| 32227 | + "WITH dest(dpath,dlen) AS (\n" | |
| 32228 | +#ifdef _WIN32 | |
| 32229 | + " SELECT realpath($dir) || '\\',\n" | |
| 32230 | +#else | |
| 32231 | + " SELECT realpath($dir) || '/',\n" | |
| 32232 | +#endif | |
| 32233 | + " 1+length(realpath($dir))\n" | |
| 32234 | + ")\n" | |
| 32235 | + "SELECT\n" | |
| 32236 | + " ($dir || name),\n" | |
| 32237 | + " CASE $dryrun\n" /* vv--- azExtraArg */ | |
| 32238 | + " WHEN 0 THEN writefile($dir||name, %s, mode, mtime)\n" | |
| 32239 | + " WHEN 1 THEN 0\n" | |
| 32240 | + " ELSE shell_putsnl(format('writefile(%%Q,%%s,%%0o,%%d)'," | |
| 32241 | + "$dir||name,quote(%s),mode,mtime)) IS NULL\n" | |
| 32242 | + " END\n" /* ^^--- azExtraArg */ | |
| 31595 | 32243 | " FROM dest CROSS JOIN %s\n" |
| 31596 | - " WHERE (%s)\n" | |
| 31597 | - " AND (data IS NULL OR $pass==0)\n" /* Dirs both passes */ | |
| 32244 | + " WHERE (%s)\n" /* ^^-- pAr->zSrcTable */ | |
| 32245 | + /* ^^--- zWhere */ | |
| 32246 | + " AND (CASE $pass WHEN 0 THEN (mode&0xf000)<>0xa000\n" | |
| 32247 | + " WHEN 1 THEN (mode&0xf000)=0xa000\n" | |
| 32248 | + " ELSE data IS NULL END)\n" | |
| 31598 | 32249 | " AND dpath=substr(realpath($dir||name),1,dlen)\n" /* No escapes */ |
| 31599 | 32250 | " AND name NOT GLOB '*..[/\\]*'\n"; /* No /../ in paths */ |
| 31600 | 32251 | |
| 31601 | 32252 | const char *azExtraArg[] = { |
| 31602 | 32253 | "sqlar_uncompress(data, sz)", |
| @@ -31623,39 +32274,48 @@ | ||
| 31623 | 32274 | } |
| 31624 | 32275 | if( zDir==0 ) rc = SQLITE_NOMEM; |
| 31625 | 32276 | } |
| 31626 | 32277 | |
| 31627 | 32278 | shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, |
| 31628 | - azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere | |
| 32279 | + azExtraArg[pAr->bZip], | |
| 32280 | + azExtraArg[pAr->bZip], | |
| 32281 | + pAr->zSrcTable, | |
| 32282 | + zWhere | |
| 31629 | 32283 | ); |
| 31630 | 32284 | |
| 31631 | 32285 | if( rc==SQLITE_OK ){ |
| 31632 | 32286 | j = sqlite3_bind_parameter_index(pSql, "$dir"); |
| 31633 | 32287 | sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); |
| 31634 | 32288 | j = sqlite3_bind_parameter_index(pSql, "$dryrun"); |
| 31635 | 32289 | sqlite3_bind_int(pSql, j, pAr->bDryRun); |
| 31636 | 32290 | |
| 31637 | 32291 | /* Run the SELECT statement twice |
| 31638 | - ** (0) writefile() all files and directories | |
| 31639 | - ** (1) writefile() for directory again | |
| 31640 | - ** The second pass is so that the timestamps for extracted directories | |
| 32292 | + ** (0) writefile() files and directories | |
| 32293 | + ** (1) writefile() symlinks | |
| 32294 | + ** (2) writefile() for directory again | |
| 32295 | + ** The third pass is so that the timestamps for extracted directories | |
| 31641 | 32296 | ** will be reset to the value in the archive, since populating them |
| 31642 | 32297 | ** in the first pass will have changed the timestamp. */ |
| 31643 | - for(i=0; i<2; i++){ | |
| 32298 | + for(i=0; i<3; i++){ | |
| 32299 | + if( pAr->bDryRun>=2 ){ | |
| 32300 | + cli_printf(pAr->out, "*** BEGIN PASS %d ***\n", i+1); | |
| 32301 | + } | |
| 31644 | 32302 | j = sqlite3_bind_parameter_index(pSql, "$pass"); |
| 31645 | 32303 | sqlite3_bind_int(pSql, j, i); |
| 31646 | - if( pAr->bDryRun ){ | |
| 32304 | + if( pAr->bDryRun && i==0 ){ | |
| 31647 | 32305 | cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql)); |
| 31648 | - if( pAr->bVerbose==0 ) break; | |
| 31649 | 32306 | } |
| 31650 | 32307 | while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 31651 | 32308 | if( i==0 && pAr->bVerbose ){ |
| 31652 | 32309 | cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 31653 | 32310 | } |
| 31654 | 32311 | } |
| 31655 | - if( pAr->bDryRun ) break; | |
| 32312 | + if( pAr->bDryRun==1 ) break; | |
| 31656 | 32313 | shellReset(&rc, pSql); |
| 32314 | + if( pAr->bDryRun>=2 ){ | |
| 32315 | + cli_printf(pAr->out, "*** END PASS %d ***\n", i+1); | |
| 32316 | + } | |
| 31657 | 32317 | } |
| 31658 | 32318 | shellFinalize(&rc, pSql); |
| 31659 | 32319 | } |
| 31660 | 32320 | |
| 31661 | 32321 | sqlite3_free(zDir); |
| @@ -32166,11 +32826,11 @@ | ||
| 32166 | 32826 | ; |
| 32167 | 32827 | static const char * const zCollectVar = "\ |
| 32168 | 32828 | SELECT\ |
| 32169 | 32829 | '('||x'0a'\ |
| 32170 | 32830 | || group_concat(\ |
| 32171 | - cname||' ANY',\ | |
| 32831 | + cname,\ | |
| 32172 | 32832 | ','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\ |
| 32173 | 32833 | ||')' AS ColsSpec \ |
| 32174 | 32834 | FROM (\ |
| 32175 | 32835 | SELECT cpos, printf('\"%w\"',printf('%!.*s%s', nlen-chop,name,suff)) AS cname \ |
| 32176 | 32836 | FROM ColNames ORDER BY cpos\ |
| @@ -32767,14 +33427,16 @@ | ||
| 32767 | 33427 | /* |
| 32768 | 33428 | ** This function computes what to show the user about the configured |
| 32769 | 33429 | ** titles (or column-names). Output is an integer between 0 and 3: |
| 32770 | 33430 | ** |
| 32771 | 33431 | ** 0: The titles do not matter. Never show anything. |
| 32772 | -** 1: Show "--titles off" | |
| 32773 | -** 2: Show "--titles on" | |
| 32774 | -** 3: Show "--title VALUE" where VALUE is an encoding method | |
| 33432 | +** 1: Show "--title off" | |
| 33433 | +** 2: Show "--title on" | |
| 33434 | +** 3: Show "--title always" | |
| 33435 | +** 4: Show "--title VALUE" where VALUE is an encoding method | |
| 32775 | 33436 | ** to use, one of: plain sql csv html tcl json |
| 33437 | +** 5: Show "--title VALUE" as in 3, followed by "--title always" | |
| 32776 | 33438 | ** |
| 32777 | 33439 | ** Inputs are: |
| 32778 | 33440 | ** |
| 32779 | 33441 | ** spec.bTitles (bT) Whether or not to show the titles |
| 32780 | 33442 | ** spec.eTitle (eT) The actual encoding to be used for titles |
| @@ -32807,11 +33469,27 @@ | ||
| 32807 | 33469 | if( eT!=eH ) v >>= 32; /* Encoding disagree in upper 4-bytes */ |
| 32808 | 33470 | if( bT!=bH ) v >>= 16; /* ON/OFF disagree in upper 2-byte pairs */ |
| 32809 | 33471 | if( bT<2 ) v >>= 8; /* ON in even bytes, OFF in odd bytes (1st byte 0) */ |
| 32810 | 33472 | if( !bAll ) v >>= 4; /* bAll values are in the lower half-byte */ |
| 32811 | 33473 | |
| 32812 | - return v & 3; /* Return the selected truth-table entry */ | |
| 33474 | + v &= 3; | |
| 33475 | + /* At this point v means: | |
| 33476 | + ** 0: The titles do not matter. Never show anything. | |
| 33477 | + ** 1: Show "--title off" | |
| 33478 | + ** 2: Show "--title on" | |
| 33479 | + ** 3: Show "--title VALUE" where VALUE is an encoding method | |
| 33480 | + ** to use, one of: plain sql csv html tcl json | |
| 33481 | + ** If bTitles is QRF_Always, convert 2->3, 3->5. If bTitles is not | |
| 33482 | + ** QRF_Always, convert 3->4. | |
| 33483 | + */ | |
| 33484 | + if( p->mode.spec.bTitles==QRF_Always ){ | |
| 33485 | + if( v==3 ) v = 5; | |
| 33486 | + if( v==2 ) v = 3; | |
| 33487 | + }else{ | |
| 33488 | + if( v==3 ) v = 4; | |
| 33489 | + } | |
| 33490 | + return v; | |
| 32813 | 33491 | } |
| 32814 | 33492 | |
| 32815 | 33493 | /* |
| 32816 | 33494 | ** DOT-COMMAND: .mode |
| 32817 | 33495 | ** |
| @@ -32835,10 +33513,14 @@ | ||
| 32835 | 33513 | ** truncated. Zero means "no limit". |
| 32836 | 33514 | ** --colsep STRING Use STRING as the column separator |
| 32837 | 33515 | ** --escape ESC Enable/disable escaping of control characters |
| 32838 | 33516 | ** found in the output. ESC can be "off", "ascii", |
| 32839 | 33517 | ** or "symbol". |
| 33518 | +** --fpfmt STRING String is a printf-style format string used to | |
| 33519 | +** render floating-point values. | |
| 33520 | +** --ifmt STRING String is a printf-style format string used to | |
| 33521 | +** render integer values. | |
| 32840 | 33522 | ** --linelimit N Set the maximum number of output lines to show for |
| 32841 | 33523 | ** any single SQL value to N. Longer values are |
| 32842 | 33524 | ** truncated. Zero means "no limit". Only works |
| 32843 | 33525 | ** in "line" mode and in columnar modes. |
| 32844 | 33526 | ** --limits L,C,T Shorthand for "--linelimit L --charlimit C |
| @@ -32855,10 +33537,11 @@ | ||
| 32855 | 33537 | ** --quote ARG Enable/disable quoting of text. ARG can be |
| 32856 | 33538 | ** "off", "on", "sql", "relaxed", "csv", "html", |
| 32857 | 33539 | ** "tcl", or "json". "off" means show the text as-is. |
| 32858 | 33540 | ** "on" is an alias for "sql". |
| 32859 | 33541 | ** --reset Changes all mode settings back to their default. |
| 33542 | +** --rowcount BOOLEAN Show "(N rows)" at the end of query results. | |
| 32860 | 33543 | ** --rowsep STRING Use STRING as the row separator |
| 32861 | 33544 | ** --sw|--screenwidth N Declare the screen width of the output device |
| 32862 | 33545 | ** to be N characters. An attempt may be made to |
| 32863 | 33546 | ** wrap output text to fit within this limit. Zero |
| 32864 | 33547 | ** means "no limit". Or N can be "auto" to set the |
| @@ -32866,11 +33549,11 @@ | ||
| 32866 | 33549 | ** --tablename NAME Set the name of the table for "insert" mode. |
| 32867 | 33550 | ** --tag NAME Save mode to the left as NAME. |
| 32868 | 33551 | ** --textjsonb BOOLEAN If enabled, JSONB text is displayed as text JSON. |
| 32869 | 33552 | ** --title ARG Whether or not to show column headers, and if so |
| 32870 | 33553 | ** how to encode them. ARG can be "off", "on", |
| 32871 | -** "sql", "csv", "html", "tcl", or "json". | |
| 33554 | +** "always", "sql", "csv", "html", "tcl", or "json". | |
| 32872 | 33555 | ** --titlelimit N Limit the length of column titles to N characters. |
| 32873 | 33556 | ** -v|--verbose Verbose output |
| 32874 | 33557 | ** --widths LIST Set the columns widths for columnar modes. The |
| 32875 | 33558 | ** argument is a list of integers, one for each |
| 32876 | 33559 | ** column. A "0" width means use a dynamic width |
| @@ -33011,30 +33694,14 @@ | ||
| 33011 | 33694 | }else if( optionMatch(z,"limits") ){ |
| 33012 | 33695 | if( (++i)>=nArg ){ |
| 33013 | 33696 | dotCmdError(p, i-1, "missing argument", 0); |
| 33014 | 33697 | return 1; |
| 33015 | 33698 | } |
| 33016 | - k = pickStr(azArg[i],0,"on","off",""); | |
| 33017 | - if( k==0 ){ | |
| 33018 | - p->mode.spec.nLineLimit = DFLT_LINE_LIMIT; | |
| 33019 | - p->mode.spec.nCharLimit = DFLT_CHAR_LIMIT; | |
| 33020 | - p->mode.spec.nTitleLimit = DFLT_TITLE_LIMIT; | |
| 33021 | - }else if( k==1 ){ | |
| 33022 | - p->mode.spec.nLineLimit = 0; | |
| 33023 | - p->mode.spec.nCharLimit = 0; | |
| 33024 | - p->mode.spec.nTitleLimit = 0; | |
| 33025 | - }else{ | |
| 33026 | - int L, C, T = 0; | |
| 33027 | - int nNum = sscanf(azArg[i], "%d,%d,%d", &L, &C, &T); | |
| 33028 | - if( nNum<2 || L<0 || C<0 || T<0){ | |
| 33029 | - dotCmdError(p, i, "bad argument", "Should be \"L,C,T\" where L, C" | |
| 33030 | - " and T are unsigned integers"); | |
| 33031 | - return 1; | |
| 33032 | - } | |
| 33033 | - p->mode.spec.nLineLimit = L; | |
| 33034 | - p->mode.spec.nCharLimit = C; | |
| 33035 | - if( nNum==3 ) p->mode.spec.nTitleLimit = T; | |
| 33699 | + if( modeSetLimit(p, azArg[i]) ){ | |
| 33700 | + dotCmdError(p, i, "bad argument", "Should be \"on\" or \"off\" or " | |
| 33701 | + "\"L,C,T\" where L, C, and T are unsigned integers"); | |
| 33702 | + return 1; | |
| 33036 | 33703 | } |
| 33037 | 33704 | chng = 1; |
| 33038 | 33705 | }else if( optionMatch(z,"list") ){ |
| 33039 | 33706 | int ii; |
| 33040 | 33707 | cli_puts("available modes:", p->out); |
| @@ -33105,15 +33772,56 @@ | ||
| 33105 | 33772 | break; |
| 33106 | 33773 | default: /* off */ |
| 33107 | 33774 | p->mode.spec.eText = QRF_TEXT_Plain; |
| 33108 | 33775 | break; |
| 33109 | 33776 | } |
| 33777 | + chng = 1; | |
| 33778 | + }else if( optionMatch(z,"ifmt") ){ | |
| 33779 | + if( i+1>=nArg ){ | |
| 33780 | + dotCmdError(p, i, "missing argument", 0); | |
| 33781 | + return 1; | |
| 33782 | + } | |
| 33783 | + i++; | |
| 33784 | + if( azArg[i][0]==0 || cli_strcmp(azArg[i],"auto")==0 ){ | |
| 33785 | + p->mode.spec.zIFmt = 0; | |
| 33786 | + }else if( sqlite3_qrf_ckformat(azArg[i])!=1 ){ | |
| 33787 | + dotCmdError(p, i, "not a valid integer format", 0); | |
| 33788 | + return 1; | |
| 33789 | + }else{ | |
| 33790 | + assert( strlen(azArg[i])<sizeof(p->mode.zIFmt)-1 ); | |
| 33791 | + memcpy(p->mode.zIFmt, azArg[i], strlen(azArg[i])+1); | |
| 33792 | + p->mode.spec.zIFmt = p->mode.zIFmt; | |
| 33793 | + } | |
| 33794 | + chng = 1; | |
| 33795 | + }else if( optionMatch(z,"fpfmt") ){ | |
| 33796 | + if( i+1>=nArg ){ | |
| 33797 | + dotCmdError(p, i, "missing argument", 0); | |
| 33798 | + return 1; | |
| 33799 | + } | |
| 33800 | + i++; | |
| 33801 | + if( azArg[i][0]==0 || cli_strcmp(azArg[i],"auto")==0 ){ | |
| 33802 | + p->mode.spec.zFpFmt = 0; | |
| 33803 | + }else if( sqlite3_qrf_ckformat(azArg[i])!=2 ){ | |
| 33804 | + dotCmdError(p, i, "not a valid floating-point format", 0); | |
| 33805 | + return 1; | |
| 33806 | + }else{ | |
| 33807 | + assert( strlen(azArg[i])<sizeof(p->mode.zFpFmt)-1 ); | |
| 33808 | + memcpy(p->mode.zFpFmt, azArg[i], strlen(azArg[i])+1); | |
| 33809 | + p->mode.spec.zFpFmt = p->mode.zFpFmt; | |
| 33810 | + } | |
| 33110 | 33811 | chng = 1; |
| 33111 | 33812 | }else if( optionMatch(z,"reset") ){ |
| 33112 | 33813 | int saved_eMode = p->mode.eMode; |
| 33113 | 33814 | modeFree(&p->mode); |
| 33114 | 33815 | modeChange(p, saved_eMode); |
| 33816 | + }else if( optionMatch(z,"rowcount") ){ | |
| 33817 | + if( i+1>=nArg ){ | |
| 33818 | + dotCmdError(p, i, "missing argument", 0); | |
| 33819 | + return 1; | |
| 33820 | + } | |
| 33821 | + p->mode.spec.bRowCount = booleanValue(azArg[++i]) ? QRF_Yes : QRF_No; | |
| 33822 | + chng = 1; | |
| 33115 | 33823 | }else if( optionMatch(z,"screenwidth") || optionMatch(z,"sw") ){ |
| 33116 | 33824 | if( (++i)>=nArg ){ |
| 33117 | 33825 | dotCmdError(p, i-1, "missing argument", 0); |
| 33118 | 33826 | return 1; |
| 33119 | 33827 | } |
| @@ -33163,25 +33871,63 @@ | ||
| 33163 | 33871 | return 1; |
| 33164 | 33872 | } |
| 33165 | 33873 | p->mode.spec.bTextJsonb = booleanValue(azArg[++i]) ? QRF_Yes : QRF_No; |
| 33166 | 33874 | chng = 1; |
| 33167 | 33875 | }else if( optionMatch(z,"titles") || optionMatch(z,"title") ){ |
| 33876 | + /* The --titles option controls two fields of the | |
| 33877 | + ** sqlite3_qrf_spec object: eTitle and bTitles. | |
| 33878 | + ** | |
| 33879 | + ** --titles eTitle bTitles | |
| 33880 | + ** -------- --------------- --------------------- | |
| 33881 | + ** "off" (unchanged) QRF_Off | |
| 33882 | + ** "on" (unchanged) QRF_On | |
| 33883 | + ** "always" (unchanged) QRF_Always | |
| 33884 | + ** "auto", (default) (default) | |
| 33885 | + ** "plain" QRF_TEXT_Plain QRF_Always or QRF_On | |
| 33886 | + ** "sql" QRF_TEXT_Sql QRF_Always or QRF_On | |
| 33887 | + ** "csv" QRF_TEXT_Csv QRF_Always or QRF_On | |
| 33888 | + ** "html" QRF_TEXT_Html QRF_Always or QRF_On | |
| 33889 | + ** "tcl" QRF_TEXT_Tcl QRF_Always or QRF_On | |
| 33890 | + ** "json" QRF_TEXT_Json QRF_Always or QRF_On | |
| 33891 | + ** | |
| 33892 | + ** This mapping is different from the -title option to the "format" | |
| 33893 | + ** method of the TCL interface. In this mapping: | |
| 33894 | + ** | |
| 33895 | + ** * "off", "on", and "always" affect only bTitles and leave | |
| 33896 | + ** eTitle unchanged | |
| 33897 | + ** | |
| 33898 | + ** * "auto" sets both bTitles and eTitle to the default value | |
| 33899 | + ** in aModeInfo[] according to the current --style. | |
| 33900 | + ** | |
| 33901 | + ** * "plain" through "json" set eTitle but leave bTitles | |
| 33902 | + ** unchanged if it is not QRF_Off. If bTitles is QRF_Off, | |
| 33903 | + ** then it is changed QRF_Always. | |
| 33904 | + */ | |
| 33168 | 33905 | char *zErr = 0; |
| 33169 | 33906 | if( i+1>=nArg ){ |
| 33170 | 33907 | dotCmdError(p, i, "missing argument", 0); |
| 33171 | 33908 | return 1; |
| 33172 | 33909 | } |
| 33173 | 33910 | k = pickStr(azArg[++i],&zErr, |
| 33174 | - "off","on","plain","sql","csv","html","tcl","json",""); | |
| 33175 | - /* 0 1 2 3 4 5 6 7 */ | |
| 33911 | + "off","on","always","auto","plain","sql","csv","html","tcl","json",""); | |
| 33912 | + /* 0 1 2 3 4 5 6 7 8 9 */ | |
| 33176 | 33913 | if( k<0 ){ |
| 33177 | 33914 | dotCmdError(p, i, "bad --titles value","%z", zErr); |
| 33178 | 33915 | return 1; |
| 33179 | 33916 | } |
| 33180 | - p->mode.spec.bTitles = k>=1 ? QRF_Yes : QRF_No; | |
| 33181 | 33917 | p->mode.mFlags &= ~MFLG_HDR; |
| 33182 | - p->mode.spec.eTitle = k>1 ? k-1 : aModeInfo[p->mode.eMode].eHdr; | |
| 33918 | + if( k<=2 ){ | |
| 33919 | + p->mode.spec.bTitles = QRF_No+k; | |
| 33920 | + }else if( k==3 ){ | |
| 33921 | + p->mode.spec.eTitle = aModeInfo[p->mode.eMode].eHdr; | |
| 33922 | + p->mode.spec.bTitles = aModeInfo[p->mode.eMode].bHdr; | |
| 33923 | + }else{ | |
| 33924 | + p->mode.spec.eTitle = (k-4)+QRF_TEXT_Plain; | |
| 33925 | + if( p->mode.spec.bTitles==QRF_No ){ | |
| 33926 | + p->mode.spec.bTitles = QRF_Always; | |
| 33927 | + } | |
| 33928 | + } | |
| 33183 | 33929 | chng = 1; |
| 33184 | 33930 | }else if( optionMatch(z,"widths") || optionMatch(z,"width") ){ |
| 33185 | 33931 | int nWidth = 0; |
| 33186 | 33932 | short int *aWidth; |
| 33187 | 33933 | const char *zW; |
| @@ -33295,10 +34041,18 @@ | ||
| 33295 | 34041 | append_c_string(pDesc, p->mode.spec.zColumnSep); |
| 33296 | 34042 | } |
| 33297 | 34043 | if( bAll || p->mode.spec.eEsc!=QRF_Auto ){ |
| 33298 | 34044 | sqlite3_str_appendf(pDesc, " --escape %s",qrfEscNames[p->mode.spec.eEsc]); |
| 33299 | 34045 | } |
| 34046 | + if( bAll || p->mode.spec.zFpFmt!=0 ){ | |
| 34047 | + const char *z = p->mode.spec.zFpFmt; | |
| 34048 | + sqlite3_str_appendf(pDesc, " --fpfmt %s", z ? z : "auto"); | |
| 34049 | + } | |
| 34050 | + if( bAll || p->mode.spec.zIFmt!=0 ){ | |
| 34051 | + const char *z = p->mode.spec.zIFmt; | |
| 34052 | + sqlite3_str_appendf(pDesc, " --ifmt %s", z ? z : "auto"); | |
| 34053 | + } | |
| 33300 | 34054 | if( bAll |
| 33301 | 34055 | || (p->mode.spec.nLineLimit>0 && pI->eCx>0) |
| 33302 | 34056 | || p->mode.spec.nCharLimit>0 |
| 33303 | 34057 | || (p->mode.spec.nTitleLimit>0 && pI->eCx>0) |
| 33304 | 34058 | ){ |
| @@ -33332,10 +34086,16 @@ | ||
| 33332 | 34086 | if( bAll |
| 33333 | 34087 | || (pI->eText!=p->mode.spec.eText && (pI->eText>1 || p->mode.spec.eText>1)) |
| 33334 | 34088 | ){ |
| 33335 | 34089 | sqlite3_str_appendf(pDesc," --quote %s",qrfQuoteNames[p->mode.spec.eText]); |
| 33336 | 34090 | } |
| 34091 | + if( bAll | |
| 34092 | + || ((p->mode.spec.bRowCount==QRF_Yes) != ((pI->mFlg&4)!=0)) | |
| 34093 | + ){ | |
| 34094 | + sqlite3_str_appendf(pDesc," --rowcount %s", | |
| 34095 | + p->mode.spec.bRowCount==QRF_Yes ? "on" : "off"); | |
| 34096 | + } | |
| 33337 | 34097 | zSetting = aModeStr[pI->eRSep]; |
| 33338 | 34098 | if( bAll || (zSetting && cli_strcmp(zSetting,p->mode.spec.zRowSep)!=0) ){ |
| 33339 | 34099 | sqlite3_str_appendf(pDesc, " --rowsep "); |
| 33340 | 34100 | append_c_string(pDesc, p->mode.spec.zRowSep); |
| 33341 | 34101 | } |
| @@ -33361,14 +34121,19 @@ | ||
| 33361 | 34121 | if( k==1 ){ |
| 33362 | 34122 | sqlite3_str_appendall(pDesc, " --titles off"); |
| 33363 | 34123 | }else if( k==2 ){ |
| 33364 | 34124 | sqlite3_str_appendall(pDesc, " --titles on"); |
| 33365 | 34125 | }else if( k==3 ){ |
| 34126 | + sqlite3_str_appendall(pDesc, " --titles always"); | |
| 34127 | + }else if( k>=4 ){ | |
| 33366 | 34128 | static const char *azTitle[] = |
| 33367 | 34129 | { "plain", "sql", "csv", "html", "tcl", "json"}; |
| 33368 | 34130 | sqlite3_str_appendf(pDesc, " --titles %s", |
| 33369 | 34131 | azTitle[p->mode.spec.eTitle-1]); |
| 34132 | + if( k==5 ){ | |
| 34133 | + sqlite3_str_appendf(pDesc, " --titles always"); | |
| 34134 | + } | |
| 33370 | 34135 | } |
| 33371 | 34136 | if( p->mode.spec.nWidth>0 && (bAll || pI->eCx==2) ){ |
| 33372 | 34137 | int ii; |
| 33373 | 34138 | const char *zSep = " --widths "; |
| 33374 | 34139 | for(ii=0; ii<p->mode.spec.nWidth; ii++){ |
| @@ -34248,11 +35013,16 @@ | ||
| 34248 | 35013 | if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){ |
| 34249 | 35014 | rc = shell_dbinfo_command(p, nArg, azArg); |
| 34250 | 35015 | }else |
| 34251 | 35016 | #endif /* SQLITE_SHELL_HAVE_RECOVER */ |
| 34252 | 35017 | |
| 34253 | - if( c=='d' && n==6 && cli_strncmp(azArg[0], "dbstat", n)==0 ){ | |
| 35018 | + if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){ | |
| 35019 | + open_db(p, 0); | |
| 35020 | + rc = shell_dbtotxt_command(p, nArg, azArg); | |
| 35021 | + }else | |
| 35022 | + | |
| 35023 | + if( c=='d' && n==8 && cli_strncmp(azArg[0], "diskused", n)==0 ){ | |
| 34254 | 35024 | const char *zSchema = 0; |
| 34255 | 35025 | int ii; |
| 34256 | 35026 | char *zSql; |
| 34257 | 35027 | open_db(p, 0); |
| 34258 | 35028 | for(ii=1; ii<nArg; ii++){ |
| @@ -34267,27 +35037,19 @@ | ||
| 34267 | 35037 | rc = 1; |
| 34268 | 35038 | goto meta_command_exit; |
| 34269 | 35039 | } |
| 34270 | 35040 | zSchema = z; |
| 34271 | 35041 | } |
| 34272 | - zSql = sqlite3_mprintf("SELECT analyze(%Q)", zSchema); | |
| 35042 | + zSql = sqlite3_mprintf("SELECT diskused(%Q)", zSchema); | |
| 34273 | 35043 | shell_check_oom(zSql); |
| 34274 | 35044 | modePush(p); |
| 34275 | 35045 | modeChange(p, MODE_BATCH); |
| 34276 | - p->mode.spec.nLineLimit = 0; | |
| 34277 | - p->mode.spec.nCharLimit = 0; | |
| 34278 | - p->mode.spec.nTitleLimit = 0; | |
| 34279 | 35046 | shell_exec(p, zSql, 0); |
| 34280 | 35047 | modePop(p); |
| 34281 | 35048 | sqlite3_free(zSql); |
| 34282 | 35049 | }else |
| 34283 | 35050 | |
| 34284 | - if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){ | |
| 34285 | - open_db(p, 0); | |
| 34286 | - rc = shell_dbtotxt_command(p, nArg, azArg); | |
| 34287 | - }else | |
| 34288 | - | |
| 34289 | 35051 | if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){ |
| 34290 | 35052 | char *zLike = 0; |
| 34291 | 35053 | char *zSql; |
| 34292 | 35054 | int i; |
| 34293 | 35055 | int savedShellFlags = p->shellFlgs; |
| @@ -34689,15 +35451,19 @@ | ||
| 34689 | 35451 | } |
| 34690 | 35452 | }else |
| 34691 | 35453 | |
| 34692 | 35454 | if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){ |
| 34693 | 35455 | if( nArg==2 ){ |
| 34694 | - p->mode.spec.bTitles = booleanValue(azArg[1]) ? QRF_Yes : QRF_No; | |
| 35456 | + if( cli_strcmp(azArg[1],"always")==0 ){ | |
| 35457 | + p->mode.spec.bTitles = QRF_Always; | |
| 35458 | + }else{ | |
| 35459 | + p->mode.spec.bTitles = booleanValue(azArg[1]) ? QRF_Yes : QRF_No; | |
| 35460 | + } | |
| 34695 | 35461 | p->mode.mFlags |= MFLG_HDR; |
| 34696 | 35462 | p->mode.spec.eTitle = aModeInfo[p->mode.eMode].eHdr; |
| 34697 | 35463 | }else{ |
| 34698 | - eputz("Usage: .headers on|off\n"); | |
| 35464 | + eputz("Usage: .headers off|on|always\n"); | |
| 34699 | 35465 | rc = 1; |
| 34700 | 35466 | } |
| 34701 | 35467 | }else |
| 34702 | 35468 | |
| 34703 | 35469 | if( c=='h' && cli_strncmp(azArg[0], "help", n)==0 ){ |
| @@ -34901,13 +35667,21 @@ | ||
| 34901 | 35667 | sqlite3_str_free(pSql); |
| 34902 | 35668 | }else |
| 34903 | 35669 | |
| 34904 | 35670 | if( c=='i' && cli_strncmp(azArg[0], "intck", n)==0 ){ |
| 34905 | 35671 | i64 iArg = 0; |
| 35672 | + open_db(p, 0); | |
| 34906 | 35673 | if( nArg==2 ){ |
| 34907 | 35674 | iArg = integerValue(azArg[1]); |
| 34908 | - if( iArg==0 ) iArg = -1; | |
| 35675 | + if( iArg==0 ){ | |
| 35676 | + if( cli_strcmp(azArg[1],"register")==0 ){ | |
| 35677 | + sqlite3_intck_register(p->db, 1); | |
| 35678 | + rc = 0; | |
| 35679 | + goto meta_command_exit; | |
| 35680 | + } | |
| 35681 | + iArg = -1; | |
| 35682 | + } | |
| 34909 | 35683 | } |
| 34910 | 35684 | if( (nArg!=1 && nArg!=2) || iArg<0 ){ |
| 34911 | 35685 | cli_printf(stderr,"%s","Usage: .intck STEPS_PER_UNLOCK\n"); |
| 34912 | 35686 | rc = 1; |
| 34913 | 35687 | goto meta_command_exit; |
| @@ -34955,10 +35729,12 @@ | ||
| 34955 | 35729 | { "attached", SQLITE_LIMIT_ATTACHED }, |
| 34956 | 35730 | { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, |
| 34957 | 35731 | { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER }, |
| 34958 | 35732 | { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH }, |
| 34959 | 35733 | { "worker_threads", SQLITE_LIMIT_WORKER_THREADS }, |
| 35734 | + { "schema", SQLITE_LIMIT_SCHEMA }, | |
| 35735 | + { "trigger_steps", SQLITE_LIMIT_TRIGGER_STEPS }, | |
| 34960 | 35736 | }; |
| 34961 | 35737 | int i, n2; |
| 34962 | 35738 | open_db(p, 0); |
| 34963 | 35739 | if( nArg==1 ){ |
| 34964 | 35740 | for(i=0; i<ArraySize(aLimit); i++){ |
| @@ -35400,10 +36176,26 @@ | ||
| 35400 | 36176 | }else |
| 35401 | 36177 | if( strcmp(z,"-show")==0 ){ |
| 35402 | 36178 | cli_printf(stdout,"Main prompt: '%s'\n", prompt_string(p, 0)); |
| 35403 | 36179 | cli_printf(stdout,"Continuation: '%s'\n", prompt_string(p, 1)); |
| 35404 | 36180 | }else |
| 36181 | +#ifndef SQLITE_NO_COLOR | |
| 36182 | + if( strcmp(z,"-color")==0 ){ | |
| 36183 | +#ifdef _WIN32 | |
| 36184 | + _putenv("NO_COLOR="); | |
| 36185 | +#else | |
| 36186 | + unsetenv("NO_COLOR"); | |
| 36187 | +#endif | |
| 36188 | + }else | |
| 36189 | + if( strcmp(z,"-no-color")==0 ){ | |
| 36190 | +#ifdef _WIN32 | |
| 36191 | + _putenv("NO_COLOR=1"); | |
| 36192 | +#else | |
| 36193 | + setenv("NO_COLOR","1",1); | |
| 36194 | +#endif | |
| 36195 | + }else | |
| 36196 | +#endif | |
| 35405 | 36197 | if( strcmp(z,"-")==0 ){ |
| 35406 | 36198 | noOpt = 1; |
| 35407 | 36199 | }else |
| 35408 | 36200 | { |
| 35409 | 36201 | dotCmdError(p, i, "unknown option", 0); |
| @@ -35414,10 +36206,11 @@ | ||
| 35414 | 36206 | dotCmdError(p, i, "extra argument", 0); |
| 35415 | 36207 | rc = 1; |
| 35416 | 36208 | goto meta_command_exit; |
| 35417 | 36209 | }else if( !p->dot.abQuot[i] && sqlite3_strglob("*[^a-z]*",z)!=0 ){ |
| 35418 | 36210 | dotCmdError(p, i, "use quotes around the prompt string", 0); |
| 36211 | + rc = 1; | |
| 35419 | 36212 | }else{ |
| 35420 | 36213 | free(p->azPrompt[cnt]); |
| 35421 | 36214 | p->azPrompt[cnt] = strdup(z); |
| 35422 | 36215 | cnt++; |
| 35423 | 36216 | } |
| @@ -36264,11 +37057,12 @@ | ||
| 36264 | 37057 | azBool[(p->mode.mFlags & MFLG_ECHO)!=0]); |
| 36265 | 37058 | cli_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->mode.autoEQP&3]); |
| 36266 | 37059 | cli_printf(p->out, "%12.12s: %s\n","explain", |
| 36267 | 37060 | p->mode.autoExplain ? "auto" : "off"); |
| 36268 | 37061 | cli_printf(p->out, "%12.12s: %s\n","headers", |
| 36269 | - azBool[p->mode.spec.bTitles==QRF_Yes]); | |
| 37062 | + p->mode.spec.bTitles==QRF_Always ? "always" : | |
| 37063 | + azBool[p->mode.spec.bTitles==QRF_Yes]); | |
| 36270 | 37064 | if( p->mode.spec.eStyle==QRF_STYLE_Column |
| 36271 | 37065 | || p->mode.spec.eStyle==QRF_STYLE_Box |
| 36272 | 37066 | || p->mode.spec.eStyle==QRF_STYLE_Table |
| 36273 | 37067 | || p->mode.spec.eStyle==QRF_STYLE_Markdown |
| 36274 | 37068 | ){ |
| @@ -37626,17 +38420,18 @@ | ||
| 37626 | 38420 | " -- treat no subsequent arguments as options\n" |
| 37627 | 38421 | #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) |
| 37628 | 38422 | " -A ARGS... run \".archive ARGS\" and exit\n" |
| 37629 | 38423 | #endif |
| 37630 | 38424 | " -append append the database to the end of the file\n" |
| 37631 | - " -ascii set output mode to 'ascii'\n" | |
| 38425 | + " -ascii set '.mode ascii'\n" | |
| 37632 | 38426 | " -bail stop after hitting an error\n" |
| 37633 | 38427 | " -batch force batch I/O\n" |
| 37634 | - " -box set output mode to 'box'\n" | |
| 38428 | + " -box set '.mode box'\n" | |
| 37635 | 38429 | " -cmd COMMAND run \"COMMAND\" before reading stdin\n" |
| 37636 | - " -column set output mode to 'column'\n" | |
| 37637 | - " -csv set output mode to 'csv'\n" | |
| 38430 | + " -cmdline-edit BOOL enable or disable command-line editing\n" | |
| 38431 | + " -column set '.mode column'\n" | |
| 38432 | + " -csv set '.mode csv -limits off'\n" | |
| 37638 | 38433 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 37639 | 38434 | " -deserialize open the database using sqlite3_deserialize()\n" |
| 37640 | 38435 | #endif |
| 37641 | 38436 | " -echo print inputs before execution\n" |
| 37642 | 38437 | " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n" |
| @@ -37644,18 +38439,18 @@ | ||
| 37644 | 38439 | " -[no]header turn headers on or off\n" |
| 37645 | 38440 | #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) |
| 37646 | 38441 | " -heap SIZE Size of heap for memsys3 or memsys5\n" |
| 37647 | 38442 | #endif |
| 37648 | 38443 | " -help show this message\n" |
| 37649 | - " -html set output mode to HTML\n" | |
| 38444 | + " -html set '.mode html'\n" | |
| 37650 | 38445 | " -ifexists only open if database already exists\n" |
| 37651 | 38446 | " -interactive force interactive I/O\n" |
| 37652 | - " -json set output mode to 'json'\n" | |
| 37653 | - " -line set output mode to 'line'\n" | |
| 37654 | - " -list set output mode to 'list'\n" | |
| 38447 | + " -json set '.mode json'\n" | |
| 38448 | + " -line set '.mode line'\n" | |
| 38449 | + " -list set '.mode list'\n" | |
| 37655 | 38450 | " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" |
| 37656 | - " -markdown set output mode to 'markdown'\n" | |
| 38451 | + " -markdown set '.mode markdown'\n" | |
| 37657 | 38452 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 37658 | 38453 | " -maxsize N maximum size for a --deserialize database\n" |
| 37659 | 38454 | #endif |
| 37660 | 38455 | " -memtrace trace all memory allocations and deallocations\n" |
| 37661 | 38456 | " -mmap N default mmap size set to N\n" |
| @@ -37668,21 +38463,21 @@ | ||
| 37668 | 38463 | " -nonce STRING set the safe-mode escape nonce\n" |
| 37669 | 38464 | " -no-rowid-in-view Disable rowid-in-view using sqlite3_config()\n" |
| 37670 | 38465 | " -nullvalue TEXT set text string for NULL values. Default ''\n" |
| 37671 | 38466 | " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" |
| 37672 | 38467 | " -pcachetrace trace all page cache operations\n" |
| 37673 | - " -quote set output mode to 'quote'\n" | |
| 38468 | + " -quote set '.mode quote'\n" | |
| 37674 | 38469 | " -readonly open the database read-only\n" |
| 37675 | 38470 | " -safe enable safe-mode\n" |
| 37676 | 38471 | " -screenwidth N use N as the default screenwidth \n" |
| 37677 | 38472 | " -separator SEP set output column separator. Default: '|'\n" |
| 37678 | 38473 | #ifdef SQLITE_ENABLE_SORTER_REFERENCES |
| 37679 | 38474 | " -sorterref SIZE sorter references threshold size\n" |
| 37680 | 38475 | #endif |
| 37681 | 38476 | " -stats print memory stats before each finalize\n" |
| 37682 | - " -table set output mode to 'table'\n" | |
| 37683 | - " -tabs set output mode to 'tabs'\n" | |
| 38477 | + " -table set '.mode table'\n" | |
| 38478 | + " -tabs set '.mode tabs'\n" | |
| 37684 | 38479 | " -unsafe-testing allow unsafe commands and modes for testing\n" |
| 37685 | 38480 | " -version show SQLite version\n" |
| 37686 | 38481 | " -vfs NAME use NAME as the default VFS\n" |
| 37687 | 38482 | " -vfstrace enable tracing of all VFS calls\n" |
| 37688 | 38483 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -37710,10 +38505,23 @@ | ||
| 37710 | 38505 | sputz(stdout, "WARNING: attempt to configure SQLite after" |
| 37711 | 38506 | " initialization.\n"); |
| 37712 | 38507 | } |
| 37713 | 38508 | } |
| 37714 | 38509 | |
| 38510 | +#if HAVE_EDITLINE | |
| 38511 | +/* | |
| 38512 | +** https://sqlite.org/forum/forumpost/aad7a634916ff050: | |
| 38513 | +** | |
| 38514 | +** Calling setlocale(LC_...,"") is required to get libedit to accept | |
| 38515 | +** non-ASCII input. | |
| 38516 | +*/ | |
| 38517 | +#define DO_SET_LOCALE 1 | |
| 38518 | +#include <locale.h> | |
| 38519 | +#else | |
| 38520 | +#define DO_SET_LOCALE 0 | |
| 38521 | +#endif | |
| 38522 | + | |
| 37715 | 38523 | /* |
| 37716 | 38524 | ** Initialize the state information in data |
| 37717 | 38525 | */ |
| 37718 | 38526 | static void main_init(ShellState *p) { |
| 37719 | 38527 | memset(p, 0, sizeof(*p)); |
| @@ -37724,31 +38532,36 @@ | ||
| 37724 | 38532 | verify_uninitialized(); |
| 37725 | 38533 | #endif |
| 37726 | 38534 | sqlite3_config(SQLITE_CONFIG_URI, 1); |
| 37727 | 38535 | sqlite3_config(SQLITE_CONFIG_MULTITHREAD); |
| 37728 | 38536 | globalShellState = p; |
| 38537 | +#if HAVE_EDITLINE || HAVE_READLINE | |
| 38538 | + /* Editline requires \001...\002 delimiters around ANSI x3.64 escapes in | |
| 38539 | + ** prompt strings. Readline does sometimes, depending on how it is | |
| 38540 | + ** compiled and installed. */ | |
| 38541 | + p->bDelimitNonprint = 1; | |
| 38542 | +#else | |
| 38543 | + /* No \001...\002 escapes required for linenoise or when not using a | |
| 38544 | + ** command-line editing library */ | |
| 38545 | + p->bDelimitNonprint = 0; | |
| 38546 | +#endif | |
| 38547 | +#if DO_SET_LOCALE | |
| 38548 | + setlocale(LC_CTYPE,""); | |
| 38549 | +#endif | |
| 38550 | +#undef DO_SET_LOCALE | |
| 37729 | 38551 | } |
| 37730 | 38552 | |
| 37731 | 38553 | /* |
| 37732 | 38554 | ** Output text to the console in a font that attracts extra attention. |
| 37733 | 38555 | */ |
| 37734 | -#if 0 /* Windows now handles ANSI escape codes */ | |
| 37735 | -static void printBold(const char *zText){ | |
| 37736 | - HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); | |
| 37737 | - CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo; | |
| 37738 | - GetConsoleScreenBufferInfo(out, &defaultScreenInfo); | |
| 37739 | - SetConsoleTextAttribute(out, | |
| 37740 | - FOREGROUND_RED|FOREGROUND_INTENSITY | |
| 37741 | - ); | |
| 37742 | - sputz(stdout, zText); | |
| 37743 | - SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes); | |
| 37744 | -} | |
| 37745 | -#else | |
| 37746 | -static void printBold(const char *zText){ | |
| 37747 | - cli_printf(stdout, "\033[1;36m\033[3m%s\033[0m", zText); | |
| 37748 | -} | |
| 37749 | -#endif | |
| 38556 | +static void printBold(const char *zText){ | |
| 38557 | + if( shellNoColor() ){ | |
| 38558 | + cli_printf(stdout, "%s", zText); | |
| 38559 | + }else{ | |
| 38560 | + cli_printf(stdout, "\033[1;36m\033[3m%s\033[0m", zText); | |
| 38561 | + } | |
| 38562 | +} | |
| 37750 | 38563 | |
| 37751 | 38564 | /* |
| 37752 | 38565 | ** Get the argument to an --option. Throw an error and die if no argument |
| 37753 | 38566 | ** is available. |
| 37754 | 38567 | */ |
| @@ -37762,11 +38575,11 @@ | ||
| 37762 | 38575 | } |
| 37763 | 38576 | |
| 37764 | 38577 | /* |
| 37765 | 38578 | ** The callback from atexit(). |
| 37766 | 38579 | */ |
| 37767 | -static void abnormalExit(void){ | |
| 38580 | +static void SQLITE_CDECL abnormalExit(void){ | |
| 37768 | 38581 | if( seenInterrupt ) eputz("Program interrupted.\n"); |
| 37769 | 38582 | if( globalShellState ){ |
| 37770 | 38583 | clearTempFile(globalShellState, 1, 1); |
| 37771 | 38584 | } |
| 37772 | 38585 | } |
| @@ -37837,10 +38650,11 @@ | ||
| 37837 | 38650 | } |
| 37838 | 38651 | argv[argc] = 0; |
| 37839 | 38652 | hOut = GetStdHandle(STD_OUTPUT_HANDLE); |
| 37840 | 38653 | GetConsoleMode(hOut, &mode); |
| 37841 | 38654 | SetConsoleMode(hOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); |
| 38655 | + _setmode(_fileno(stdout),_O_BINARY); /* Bug 2026-08-03T08:52:42Z */ | |
| 37842 | 38656 | rc = utf8_main(argc, argv); |
| 37843 | 38657 | for(i=0; i<argc; i++) free(orig[i]); |
| 37844 | 38658 | free(argv); |
| 37845 | 38659 | return rc; |
| 37846 | 38660 | } |
| @@ -37883,10 +38697,13 @@ | ||
| 37883 | 38697 | stdout_is_console = 1; |
| 37884 | 38698 | data.wasm.zDefaultDbName = "/fiddle.sqlite3"; |
| 37885 | 38699 | #else |
| 37886 | 38700 | stdin_is_interactive = isatty(0); |
| 37887 | 38701 | stdout_is_console = isatty(1); |
| 38702 | + if( !stdin_is_interactive || !stdout_is_console ){ | |
| 38703 | + shellCmdLineEdit = 0; | |
| 38704 | + } | |
| 37888 | 38705 | #endif |
| 37889 | 38706 | atexit(abnormalExit); |
| 37890 | 38707 | #ifdef SQLITE_DEBUG |
| 37891 | 38708 | mem_main_enter = sqlite3_memory_used(); |
| 37892 | 38709 | #endif |
| @@ -37973,11 +38790,11 @@ | ||
| 37973 | 38790 | stdin_is_interactive = 0; |
| 37974 | 38791 | nCmd++; |
| 37975 | 38792 | azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); |
| 37976 | 38793 | shell_check_oom(azCmd); |
| 37977 | 38794 | aiCmd = realloc(aiCmd, sizeof(aiCmd[0])*nCmd); |
| 37978 | - shell_check_oom(azCmd); | |
| 38795 | + shell_check_oom(aiCmd); | |
| 37979 | 38796 | azCmd[nCmd-1] = z; |
| 37980 | 38797 | aiCmd[nCmd-1] = i; |
| 37981 | 38798 | } |
| 37982 | 38799 | continue; |
| 37983 | 38800 | } |
| @@ -38130,10 +38947,12 @@ | ||
| 38130 | 38947 | }else if( cli_strcmp(z,"-safe")==0 ){ |
| 38131 | 38948 | /* no-op - catch this on the second pass */ |
| 38132 | 38949 | }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ |
| 38133 | 38950 | /* skip over the argument */ |
| 38134 | 38951 | i++; |
| 38952 | + }else if( cli_strcmp(z,"-cmdline-edit")==0 ){ | |
| 38953 | + shellCmdLineEdit = booleanValue(cmdline_option_value(argc,argv,++i)); | |
| 38135 | 38954 | }else if( cli_strcmp(z,"-test-argv")==0 ){ |
| 38136 | 38955 | /* Undocumented test option. Print the values in argv[] and exit. |
| 38137 | 38956 | ** Use this to verify that any translation of the argv[], for example |
| 38138 | 38957 | ** on Windows that receives wargv[] from the OS and must convert |
| 38139 | 38958 | ** to UTF8 prior to calling this routine. */ |
| @@ -38262,10 +39081,11 @@ | ||
| 38262 | 39081 | modeChange(&data, MODE_Psql); |
| 38263 | 39082 | }else if( cli_strcmp(z,"-box")==0 ){ |
| 38264 | 39083 | modeChange(&data, MODE_Box); |
| 38265 | 39084 | }else if( cli_strcmp(z,"-csv")==0 ){ |
| 38266 | 39085 | modeChange(&data, MODE_Csv); |
| 39086 | + modeSetLimit(&data, "off"); | |
| 38267 | 39087 | }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ |
| 38268 | 39088 | /* See similar code at tag-20250224-1 */ |
| 38269 | 39089 | const char *zEsc = argv[++i]; |
| 38270 | 39090 | int k; |
| 38271 | 39091 | for(k=0; k<ArraySize(qrfEscNames); k++){ |
| @@ -38319,13 +39139,15 @@ | ||
| 38319 | 39139 | cmdline_option_value(argc,argv,++i)); |
| 38320 | 39140 | }else if( cli_strcmp(z,"-nullvalue")==0 ){ |
| 38321 | 39141 | modeSetStr(&data.mode.spec.zNull, |
| 38322 | 39142 | cmdline_option_value(argc,argv,++i)); |
| 38323 | 39143 | }else if( cli_strcmp(z,"-header")==0 ){ |
| 38324 | - data.mode.spec.bTitles = QRF_Yes; | |
| 39144 | + data.mode.spec.bTitles = QRF_Always; | |
| 39145 | + data.mode.mFlags |= MFLG_HDR; | |
| 38325 | 39146 | }else if( cli_strcmp(z,"-noheader")==0 ){ |
| 38326 | 39147 | data.mode.spec.bTitles = QRF_No; |
| 39148 | + data.mode.mFlags |= MFLG_HDR; | |
| 38327 | 39149 | }else if( cli_strcmp(z,"-echo")==0 ){ |
| 38328 | 39150 | data.mode.mFlags |= MFLG_ECHO; |
| 38329 | 39151 | }else if( cli_strcmp(z,"-eqp")==0 ){ |
| 38330 | 39152 | data.mode.autoEQP = AUTOEQP_on; |
| 38331 | 39153 | }else if( cli_strcmp(z,"-eqpfull")==0 ){ |
| @@ -38389,10 +39211,12 @@ | ||
| 38389 | 39211 | i++; |
| 38390 | 39212 | #ifdef SQLITE_ENABLE_MULTIPLEX |
| 38391 | 39213 | }else if( cli_strcmp(z,"-multiplex")==0 ){ |
| 38392 | 39214 | i++; |
| 38393 | 39215 | #endif |
| 39216 | + }else if( cli_strcmp(z,"-cmdline-edit")==0 ){ | |
| 39217 | + i+=2; | |
| 38394 | 39218 | }else if( cli_strcmp(z,"-help")==0 ){ |
| 38395 | 39219 | usage(1); |
| 38396 | 39220 | }else if( cli_strcmp(z,"-cmd")==0 ){ |
| 38397 | 39221 | /* Run commands that follow -cmd first and separately from commands |
| 38398 | 39222 | ** that simply appear on the command-line. This seems goofy. It would |
| @@ -38418,12 +39242,14 @@ | ||
| 38418 | 39242 | rc = 1; |
| 38419 | 39243 | goto shell_main_exit; |
| 38420 | 39244 | } |
| 38421 | 39245 | open_db(&data, OPEN_DB_ZIPFILE); |
| 38422 | 39246 | if( z[2] ){ |
| 39247 | + char *zSaved = argv[i]; | |
| 38423 | 39248 | argv[i] = &z[2]; |
| 38424 | 39249 | arDotCommand(&data, 1, argv+(i-1), argc-(i-1)); |
| 39250 | + argv[i] = zSaved; | |
| 38425 | 39251 | }else{ |
| 38426 | 39252 | arDotCommand(&data, 1, argv+i, argc-i); |
| 38427 | 39253 | } |
| 38428 | 39254 | readStdin = 0; |
| 38429 | 39255 | stdin_is_interactive = 0; |
| 38430 | 39256 |
| --- extsrc/shell.c | |
| +++ extsrc/shell.c | |
| @@ -5,16 +5,16 @@ | |
| 5 | ** |
| 6 | ** ext/expert/sqlite3expert.c |
| 7 | ** ext/expert/sqlite3expert.h |
| 8 | ** ext/intck/sqlite3intck.c |
| 9 | ** ext/intck/sqlite3intck.h |
| 10 | ** ext/misc/analyze.c |
| 11 | ** ext/misc/appendvfs.c |
| 12 | ** ext/misc/base64.c |
| 13 | ** ext/misc/base85.c |
| 14 | ** ext/misc/completion.c |
| 15 | ** ext/misc/decimal.c |
| 16 | ** ext/misc/fileio.c |
| 17 | ** ext/misc/ieee754.c |
| 18 | ** ext/misc/memtrace.c |
| 19 | ** ext/misc/pcachetrace.c |
| 20 | ** ext/misc/regexp.c |
| @@ -23,10 +23,11 @@ | |
| 23 | ** ext/misc/shathree.c |
| 24 | ** ext/misc/sqlar.c |
| 25 | ** ext/misc/sqlite3_stdio.c |
| 26 | ** ext/misc/sqlite3_stdio.h |
| 27 | ** ext/misc/stmtrand.c |
| 28 | ** ext/misc/uint.c |
| 29 | ** ext/misc/vfstrace.c |
| 30 | ** ext/misc/windirent.h |
| 31 | ** ext/misc/zipfile.c |
| 32 | ** ext/qrf/qrf.c |
| @@ -154,10 +155,11 @@ | |
| 154 | #include <string.h> |
| 155 | #include <stdio.h> |
| 156 | #include <assert.h> |
| 157 | #include <math.h> |
| 158 | #include <stdint.h> |
| 159 | #include "sqlite3.h" |
| 160 | typedef sqlite3_int64 i64; |
| 161 | typedef sqlite3_uint64 u64; |
| 162 | typedef unsigned char u8; |
| 163 | #include <ctype.h> |
| @@ -190,13 +192,14 @@ | |
| 190 | #include <sys/stat.h> |
| 191 | |
| 192 | #if HAVE_READLINE |
| 193 | # include <readline/readline.h> |
| 194 | # include <readline/history.h> |
| 195 | #endif |
| 196 | |
| 197 | #if HAVE_EDITLINE |
| 198 | # include <editline/readline.h> |
| 199 | #endif |
| 200 | |
| 201 | #if HAVE_EDITLINE || HAVE_READLINE |
| 202 | |
| @@ -203,28 +206,38 @@ | |
| 203 | # define shell_add_history(X) add_history(X) |
| 204 | # define shell_read_history(X) read_history(X) |
| 205 | # define shell_write_history(X) write_history(X) |
| 206 | # define shell_stifle_history(X) stifle_history(X) |
| 207 | # define shell_readline(X) readline(X) |
| 208 | |
| 209 | #elif HAVE_LINENOISE |
| 210 | |
| 211 | # include "linenoise.h" |
| 212 | # define shell_add_history(X) linenoiseHistoryAdd(X) |
| 213 | # define shell_read_history(X) linenoiseHistoryLoad(X) |
| 214 | # define shell_write_history(X) linenoiseHistorySave(X) |
| 215 | # define shell_stifle_history(X) linenoiseHistorySetMaxLen(X) |
| 216 | # define shell_readline(X) linenoise(X) |
| 217 | |
| 218 | #else |
| 219 | |
| 220 | # define shell_read_history(X) |
| 221 | # define shell_write_history(X) |
| 222 | # define shell_stifle_history(X) |
| 223 | |
| 224 | # define SHELL_USE_LOCAL_GETLINE 1 |
| 225 | #endif |
| 226 | |
| 227 | #ifndef deliberate_fall_through |
| 228 | /* Quiet some compilers about some of our intentional code. */ |
| 229 | # if defined(GCC_VERSION) && GCC_VERSION>=7000000 |
| 230 | # define deliberate_fall_through __attribute__((fallthrough)); |
| @@ -731,10 +744,14 @@ | |
| 731 | char *(*xRender)(void*,sqlite3_value*); /* Render a value */ |
| 732 | int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */ |
| 733 | void *pRenderArg; /* First argument to the xRender callback */ |
| 734 | void *pWriteArg; /* First argument to the xWrite callback */ |
| 735 | char **pzOutput; /* Storage location for output string */ |
| 736 | /* Additional fields may be added in the future */ |
| 737 | }; |
| 738 | |
| 739 | /* |
| 740 | ** Interfaces |
| @@ -744,12 +761,11 @@ | |
| 744 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 745 | char **pzErr /* OUT: Write error message here */ |
| 746 | ); |
| 747 | |
| 748 | /* |
| 749 | ** Range of values for sqlite3_qrf_spec.aWidth[] entries and for |
| 750 | ** sqlite3_qrf_spec.mxColWidth and .nScreenWidth |
| 751 | */ |
| 752 | #define QRF_MAX_WIDTH 10000 |
| 753 | #define QRF_MIN_WIDTH 0 |
| 754 | |
| 755 | /* |
| @@ -760,11 +776,11 @@ | |
| 760 | #define QRF_STYLE_Column 2 /* One record per line in neat columns */ |
| 761 | #define QRF_STYLE_Count 3 /* Output only a count of the rows of output */ |
| 762 | #define QRF_STYLE_Csv 4 /* Comma-separated-value */ |
| 763 | #define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */ |
| 764 | #define QRF_STYLE_Explain 6 /* EXPLAIN output */ |
| 765 | #define QRF_STYLE_Html 7 /* Generate an XHTML table */ |
| 766 | #define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */ |
| 767 | #define QRF_STYLE_Json 9 /* Output is a list of JSON objects */ |
| 768 | #define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */ |
| 769 | #define QRF_STYLE_Line 11 /* One column per line. */ |
| 770 | #define QRF_STYLE_List 12 /* One record per line with a separator */ |
| @@ -820,10 +836,15 @@ | |
| 820 | #define QRF_SW_On 2 /* This setting is forced on */ |
| 821 | #define QRF_Auto 0 /* Alternate spelling for QRF_*_Auto */ |
| 822 | #define QRF_No 1 /* Alternate spelling for QRF_SW_Off */ |
| 823 | #define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */ |
| 824 | |
| 825 | /* |
| 826 | ** Possible alignment values alignment settings |
| 827 | ** |
| 828 | ** Horizontal Vertial |
| 829 | ** ---------- -------- */ |
| @@ -868,10 +889,22 @@ | |
| 868 | ** determined as for sqlite3_qrf_wcwidth(). VT100 escape code sequences |
| 869 | ** are assigned a width of zero. |
| 870 | */ |
| 871 | size_t sqlite3_qrf_wcswidth(const char*); |
| 872 | |
| 873 | |
| 874 | #ifdef __cplusplus |
| 875 | } |
| 876 | #endif |
| 877 | #endif /* !defined(SQLITE_QRF_H) */ |
| @@ -950,10 +983,11 @@ | |
| 950 | } sExpln; |
| 951 | unsigned int nIns; /* Bytes used for current INSERT stmt */ |
| 952 | } u; |
| 953 | sqlite3_int64 nRow; /* Number of rows handled so far */ |
| 954 | int *actualWidth; /* Actual width of each column */ |
| 955 | sqlite3_qrf_spec spec; /* Copy of the original spec */ |
| 956 | }; |
| 957 | |
| 958 | /* |
| 959 | ** Data for substitute ctype.h functions. Used for x-platform |
| @@ -993,10 +1027,48 @@ | |
| 993 | # define deliberate_fall_through __attribute__((fallthrough)); |
| 994 | # else |
| 995 | # define deliberate_fall_through |
| 996 | # endif |
| 997 | #endif |
| 998 | |
| 999 | /* |
| 1000 | ** Set an error code and error message. |
| 1001 | */ |
| 1002 | static void qrfError( |
| @@ -1129,10 +1201,14 @@ | |
| 1129 | sqlite3_str_append(pOut, "-", 1); |
| 1130 | } |
| 1131 | if( N<10000 ){ |
| 1132 | sqlite3_str_appendf(pOut, "%4lld ", N); |
| 1133 | return; |
| 1134 | } |
| 1135 | for(i=1; i<=18; i++){ |
| 1136 | N = (N+5)/10; |
| 1137 | if( N<10000 ){ |
| 1138 | int n = (int)N; |
| @@ -1289,12 +1365,12 @@ | |
| 1289 | if( nCycle>=0 || nLoop>=0 || nRow>=0 ){ |
| 1290 | int nSp = 0; |
| 1291 | sqlite3_str_reset(pStats); |
| 1292 | if( nCycle>=0 && nTotal>0 ){ |
| 1293 | qrfApproxInt64(pStats, nCycle); |
| 1294 | sqlite3_str_appendf(pStats, " %3d%%", |
| 1295 | ((nCycle*100)+nTotal/2) / nTotal |
| 1296 | ); |
| 1297 | nSp = 2; |
| 1298 | } |
| 1299 | if( nLoop>=0 ){ |
| 1300 | if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' '); |
| @@ -1787,11 +1863,11 @@ | |
| 1787 | } |
| 1788 | if( i>0 ){ |
| 1789 | sqlite3_str_append(pOut, (const char*)z, i); |
| 1790 | } |
| 1791 | switch( z[i] ){ |
| 1792 | case '>': sqlite3_str_append(pOut, "<", 4); break; |
| 1793 | case '&': sqlite3_str_append(pOut, "&", 5); break; |
| 1794 | case '<': sqlite3_str_append(pOut, "<", 4); break; |
| 1795 | case '"': sqlite3_str_append(pOut, """, 6); break; |
| 1796 | case '\'': sqlite3_str_append(pOut, "'", 5); break; |
| 1797 | default: i--; |
| @@ -1977,16 +2053,22 @@ | |
| 1977 | return; |
| 1978 | } |
| 1979 | } |
| 1980 | switch( sqlite3_column_type(p->pStmt,iCol) ){ |
| 1981 | case SQLITE_INTEGER: { |
| 1982 | sqlite3_str_appendf(pOut, "%lld", sqlite3_column_int64(p->pStmt,iCol)); |
| 1983 | break; |
| 1984 | } |
| 1985 | case SQLITE_FLOAT: { |
| 1986 | const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol); |
| 1987 | sqlite3_str_appendall(pOut, zTxt); |
| 1988 | break; |
| 1989 | } |
| 1990 | case SQLITE_BLOB: { |
| 1991 | if( p->spec.bTextJsonb==QRF_Yes ){ |
| 1992 | const char *zJson = qrfJsonbToJson(p, iCol); |
| @@ -2281,11 +2363,11 @@ | |
| 2281 | if( bWrap && z[i]!=0 && !qrfSpace(z[i]) && qrfAlnum(c)==qrfAlnum(z[i]) ){ |
| 2282 | /* Perhaps try to back up to a better place to break the line */ |
| 2283 | for(k=i-1; k>=i/2; k--){ |
| 2284 | if( qrfSpace(z[k]) ) break; |
| 2285 | } |
| 2286 | if( k<i/2 ){ |
| 2287 | for(k=i; k>=i/2; k--){ |
| 2288 | if( qrfAlnum(z[k-1])!=qrfAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break; |
| 2289 | } |
| 2290 | } |
| 2291 | if( k>=i/2 ){ |
| @@ -2522,10 +2604,14 @@ | |
| 2522 | /* Doubled horizontal lines: */ |
| 2523 | #define DBL_24 "\342\225\220" /* U+2550 === */ |
| 2524 | #define DBL_123 "\342\225\236" /* U+255e |= */ |
| 2525 | #define DBL_134 "\342\225\241" /* U+2561 =| */ |
| 2526 | #define DBL_1234 "\342\225\252" /* U+256a =|= */ |
| 2527 | |
| 2528 | /* Draw horizontal line N characters long using unicode box |
| 2529 | ** characters |
| 2530 | */ |
| 2531 | static void qrfBoxLine(sqlite3_str *pOut, int N, int bDbl){ |
| @@ -2532,28 +2618,28 @@ | |
| 2532 | const char *azDash[2] = { |
| 2533 | BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24, |
| 2534 | DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 |
| 2535 | };/* 0 1 2 3 4 5 6 7 8 9 */ |
| 2536 | const int nDash = 30; |
| 2537 | N *= 3; |
| 2538 | while( N>nDash ){ |
| 2539 | sqlite3_str_append(pOut, azDash[bDbl], nDash); |
| 2540 | N -= nDash; |
| 2541 | } |
| 2542 | sqlite3_str_append(pOut, azDash[bDbl], N); |
| 2543 | } |
| 2544 | |
| 2545 | /* |
| 2546 | ** Draw a horizontal separator for a QRF_STYLE_Box table. |
| 2547 | */ |
| 2548 | static void qrfBoxSeparator( |
| 2549 | sqlite3_str *pOut, |
| 2550 | qrfColData *p, |
| 2551 | const char *zSep1, |
| 2552 | const char *zSep2, |
| 2553 | const char *zSep3, |
| 2554 | int bDbl |
| 2555 | ){ |
| 2556 | int i; |
| 2557 | if( p->nCol>0 ){ |
| 2558 | int useBorder = p->p->spec.bBorder!=QRF_No; |
| 2559 | if( useBorder ){ |
| @@ -2568,10 +2654,36 @@ | |
| 2568 | sqlite3_str_appendall(pOut, zSep3); |
| 2569 | } |
| 2570 | } |
| 2571 | sqlite3_str_append(pOut, "\n", 1); |
| 2572 | } |
| 2573 | |
| 2574 | /* |
| 2575 | ** Load into pData the default alignment for the body of a table. |
| 2576 | */ |
| 2577 | static void qrfLoadAlignment(qrfColData *pData, Qrf *p){ |
| @@ -2610,11 +2722,11 @@ | |
| 2610 | int nSW /* Screen width */ |
| 2611 | ){ |
| 2612 | int i; /* Loop counter */ |
| 2613 | int nr; /* Number of rows */ |
| 2614 | int w = 0; /* Width of the current column */ |
| 2615 | int t; /* Total width of all columns */ |
| 2616 | int *aw; /* Array of individual column widths */ |
| 2617 | |
| 2618 | aw = sqlite3_malloc64( sizeof(int)*nCol ); |
| 2619 | if( aw==0 ){ |
| 2620 | qrfOom(p); |
| @@ -2748,12 +2860,15 @@ | |
| 2748 | }else{ |
| 2749 | sepW = pData->nCol*3 + 1; |
| 2750 | if( p->spec.bBorder==QRF_No ) sepW -= 2; |
| 2751 | } |
| 2752 | nCol = pData->nCol; |
| 2753 | for(i=sumW=0; i<nCol; i++) sumW += pData->a[i].w; |
| 2754 | if( p->spec.nScreenWidth >= sumW+sepW ) return; |
| 2755 | |
| 2756 | /* First thing to do is reduce the separation between columns */ |
| 2757 | pData->nMargin = 0; |
| 2758 | if( p->spec.eStyle==QRF_STYLE_Column ){ |
| 2759 | sepW = pData->nCol - 1; |
| @@ -2823,11 +2938,25 @@ | |
| 2823 | sqlite3_str *pStr; /* Temporary rendering */ |
| 2824 | qrfColData data; /* Columnar layout data */ |
| 2825 | int bRTrim; /* Trim trailing space */ |
| 2826 | |
| 2827 | rc = sqlite3_step(p->pStmt); |
| 2828 | if( rc!=SQLITE_ROW || nColumn==0 ){ |
| 2829 | return; /* No output */ |
| 2830 | } |
| 2831 | |
| 2832 | /* Initialize the data container */ |
| 2833 | memset(&data, 0, sizeof(data)); |
| @@ -2840,12 +2969,12 @@ | |
| 2840 | } |
| 2841 | memset(data.a, 0, nColumn*sizeof(struct qrfPerCol) ); |
| 2842 | if( qrfColDataEnlarge(&data) ) return; |
| 2843 | assert( data.az!=0 ); |
| 2844 | |
| 2845 | /* Load the column header names and all cell content into data */ |
| 2846 | if( p->spec.bTitles==QRF_Yes ){ |
| 2847 | unsigned char saved_eText = p->spec.eText; |
| 2848 | p->spec.eText = p->spec.eTitle; |
| 2849 | memset(data.abNum, 0, nColumn); |
| 2850 | for(i=0; i<nColumn; i++){ |
| 2851 | const char *z = (const char*)sqlite3_column_name(p->pStmt,i); |
| @@ -2866,13 +2995,14 @@ | |
| 2866 | data.n++; |
| 2867 | if( w>data.a[i].mxW ) data.a[i].mxW = w; |
| 2868 | if( nNL ) data.bMultiRow = 1; |
| 2869 | } |
| 2870 | p->spec.eText = saved_eText; |
| 2871 | p->nRow++; |
| 2872 | } |
| 2873 | do{ |
| 2874 | if( data.n+nColumn > data.nAlloc ){ |
| 2875 | if( qrfColDataEnlarge(&data) ) return; |
| 2876 | } |
| 2877 | for(i=0; i<nColumn; i++){ |
| 2878 | char *z; |
| @@ -2889,11 +3019,12 @@ | |
| 2889 | data.n++; |
| 2890 | if( w>data.a[i].mxW ) data.a[i].mxW = w; |
| 2891 | if( nNL ) data.bMultiRow = 1; |
| 2892 | } |
| 2893 | p->nRow++; |
| 2894 | }while( sqlite3_step(p->pStmt)==SQLITE_ROW && p->iErr==SQLITE_OK ); |
| 2895 | if( p->iErr ){ |
| 2896 | qrfColDataFree(&data); |
| 2897 | return; |
| 2898 | } |
| 2899 | |
| @@ -3097,11 +3228,11 @@ | |
| 3097 | /* Draw either (1) the separator between the title line and the body |
| 3098 | ** of the table, or (2) separators between individual rows of the table |
| 3099 | ** body. isTitleDataSeparator will be true if we are doing (1). |
| 3100 | */ |
| 3101 | if( (i==0 || data.bMultiRow) && i+nColumn<data.n ){ |
| 3102 | int isTitleDataSeparator = (i==0 && p->spec.bTitles==QRF_Yes); |
| 3103 | if( isTitleDataSeparator ){ |
| 3104 | qrfLoadAlignment(&data, p); |
| 3105 | } |
| 3106 | switch( p->spec.eStyle ){ |
| 3107 | case QRF_STYLE_Table: { |
| @@ -3124,19 +3255,12 @@ | |
| 3124 | } |
| 3125 | break; |
| 3126 | } |
| 3127 | case QRF_STYLE_Column: { |
| 3128 | if( isTitleDataSeparator ){ |
| 3129 | for(j=0; j<nColumn; j++){ |
| 3130 | sqlite3_str_appendchar(p->pOut, data.a[j].w, '-'); |
| 3131 | if( j<nColumn-1 ){ |
| 3132 | sqlite3_str_append(p->pOut, colSep, szColSep); |
| 3133 | }else{ |
| 3134 | qrfRTrim(p->pOut); |
| 3135 | sqlite3_str_append(p->pOut, rowSep, szRowSep); |
| 3136 | } |
| 3137 | } |
| 3138 | }else if( data.bMultiRow ){ |
| 3139 | qrfRTrim(p->pOut); |
| 3140 | sqlite3_str_append(p->pOut, "\n", 1); |
| 3141 | } |
| 3142 | break; |
| @@ -3144,20 +3268,39 @@ | |
| 3144 | } |
| 3145 | } |
| 3146 | } |
| 3147 | |
| 3148 | /* Draw the line across the bottom of the table */ |
| 3149 | if( p->spec.bBorder!=QRF_No ){ |
| 3150 | switch( p->spec.eStyle ){ |
| 3151 | case QRF_STYLE_Box: |
| 3152 | qrfBoxSeparator(p->pOut, &data, BOX_R12, BOX_124, BOX_R14, 0); |
| 3153 | break; |
| 3154 | case QRF_STYLE_Table: |
| 3155 | qrfRowSeparator(p->pOut, &data, '+'); |
| 3156 | break; |
| 3157 | } |
| 3158 | } |
| 3159 | qrfWrite(p); |
| 3160 | |
| 3161 | qrfColDataFree(&data); |
| 3162 | return; |
| 3163 | } |
| @@ -3404,10 +3547,49 @@ | |
| 3404 | sqlite3_str_append(p->pOut, ":", 1); |
| 3405 | qrfRenderValue(p, p->pOut, i); |
| 3406 | } |
| 3407 | qrfWrite(p); |
| 3408 | } |
| 3409 | |
| 3410 | /* |
| 3411 | ** Render a single row of output for non-columnar styles - any |
| 3412 | ** style that lets us render row by row as the content is received |
| 3413 | ** from the query. |
| @@ -3437,25 +3619,19 @@ | |
| 3437 | } |
| 3438 | qrfOneJsonRow(p); |
| 3439 | break; |
| 3440 | } |
| 3441 | case QRF_STYLE_Html: { |
| 3442 | if( p->nRow==0 && p->spec.bTitles==QRF_Yes ){ |
| 3443 | sqlite3_str_append(p->pOut, "<TR>", 4); |
| 3444 | for(i=0; i<p->nCol; i++){ |
| 3445 | const char *zCName = sqlite3_column_name(p->pStmt, i); |
| 3446 | sqlite3_str_append(p->pOut, "\n<TH>", 5); |
| 3447 | qrfEncodeText(p, p->pOut, zCName); |
| 3448 | } |
| 3449 | sqlite3_str_append(p->pOut, "\n</TR>\n", 7); |
| 3450 | } |
| 3451 | sqlite3_str_append(p->pOut, "<TR>", 4); |
| 3452 | for(i=0; i<p->nCol; i++){ |
| 3453 | sqlite3_str_append(p->pOut, "\n<TD>", 5); |
| 3454 | qrfRenderValue(p, p->pOut, i); |
| 3455 | } |
| 3456 | sqlite3_str_append(p->pOut, "\n</TR>\n", 7); |
| 3457 | qrfWrite(p); |
| 3458 | break; |
| 3459 | } |
| 3460 | case QRF_STYLE_Insert: { |
| 3461 | unsigned int mxIns = p->spec.nMultiInsert; |
| @@ -3468,11 +3644,11 @@ | |
| 3468 | if( qrf_need_quote(p->spec.zTableName) ){ |
| 3469 | sqlite3_str_appendf(p->pOut,"INSERT INTO \"%w\"",p->spec.zTableName); |
| 3470 | }else{ |
| 3471 | sqlite3_str_appendf(p->pOut,"INSERT INTO %s",p->spec.zTableName); |
| 3472 | } |
| 3473 | if( p->spec.bTitles==QRF_Yes ){ |
| 3474 | for(i=0; i<p->nCol; i++){ |
| 3475 | const char *zCName = sqlite3_column_name(p->pStmt, i); |
| 3476 | if( qrf_need_quote(zCName) ){ |
| 3477 | sqlite3_str_appendf(p->pOut, "%c\"%w\"", |
| 3478 | i==0 ? '(' : ',', zCName); |
| @@ -3568,21 +3744,12 @@ | |
| 3568 | if( zEqpLine[0]=='-' ) qrfEqpRender(p, 0); |
| 3569 | qrfEqpAppend(p, iEqpId, iParentId, zEqpLine); |
| 3570 | break; |
| 3571 | } |
| 3572 | default: { /* QRF_STYLE_List */ |
| 3573 | if( p->nRow==0 && p->spec.bTitles==QRF_Yes ){ |
| 3574 | int saved_eText = p->spec.eText; |
| 3575 | p->spec.eText = p->spec.eTitle; |
| 3576 | for(i=0; i<p->nCol; i++){ |
| 3577 | const char *zCName = sqlite3_column_name(p->pStmt, i); |
| 3578 | if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep); |
| 3579 | qrfEncodeText(p, p->pOut, zCName); |
| 3580 | } |
| 3581 | sqlite3_str_appendall(p->pOut, p->spec.zRowSep); |
| 3582 | qrfWrite(p); |
| 3583 | p->spec.eText = saved_eText; |
| 3584 | } |
| 3585 | for(i=0; i<p->nCol; i++){ |
| 3586 | if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep); |
| 3587 | qrfRenderValue(p, p->pOut, i); |
| 3588 | } |
| @@ -3604,11 +3771,11 @@ | |
| 3604 | char **pzErr /* Write errors here */ |
| 3605 | ){ |
| 3606 | size_t sz; /* Size of pSpec[], based on pSpec->iVersion */ |
| 3607 | memset(p, 0, sizeof(*p)); |
| 3608 | p->pzErr = pzErr; |
| 3609 | if( pSpec->iVersion>1 ){ |
| 3610 | qrfError(p, SQLITE_ERROR, |
| 3611 | "unusable sqlite3_qrf_spec.iVersion (%d)", |
| 3612 | pSpec->iVersion); |
| 3613 | return; |
| 3614 | } |
| @@ -3620,15 +3787,19 @@ | |
| 3620 | return; |
| 3621 | } |
| 3622 | p->iErr = SQLITE_OK; |
| 3623 | p->nCol = sqlite3_column_count(p->pStmt); |
| 3624 | p->nRow = 0; |
| 3625 | sz = sizeof(sqlite3_qrf_spec); |
| 3626 | memcpy(&p->spec, pSpec, sz); |
| 3627 | if( p->spec.zNull==0 ) p->spec.zNull = ""; |
| 3628 | p->mxWidth = p->spec.nScreenWidth; |
| 3629 | if( p->mxWidth<=0 ) p->mxWidth = QRF_MAX_WIDTH; |
| 3630 | p->mxHeight = p->spec.nLineLimit; |
| 3631 | if( p->mxHeight<=0 ) p->mxHeight = 2147483647; |
| 3632 | if( p->spec.eStyle>QRF_STYLE_Table ) p->spec.eStyle = QRF_Auto; |
| 3633 | if( p->spec.eEsc>QRF_ESC_Symbol ) p->spec.eEsc = QRF_Auto; |
| 3634 | if( p->spec.eText>QRF_TEXT_Relaxed ) p->spec.eText = QRF_Auto; |
| @@ -3756,10 +3927,24 @@ | |
| 3756 | if( p->spec.bTextJsonb==QRF_Auto ){ |
| 3757 | p->spec.bTextJsonb = QRF_No; |
| 3758 | } |
| 3759 | if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = ","; |
| 3760 | if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n"; |
| 3761 | } |
| 3762 | |
| 3763 | /* |
| 3764 | ** Finish rendering the results |
| 3765 | */ |
| @@ -3890,10 +4075,34 @@ | |
| 3890 | default: { |
| 3891 | /* Non-columnar modes where the output can occur after each row |
| 3892 | ** of result is received */ |
| 3893 | while( qrf.iErr==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ |
| 3894 | qrfOneSimpleRow(&qrf); |
| 3895 | } |
| 3896 | break; |
| 3897 | } |
| 3898 | } |
| 3899 | qrfResetStmt(&qrf); |
| @@ -5106,10 +5315,12 @@ | |
| 5106 | int rc; |
| 5107 | int n; |
| 5108 | const char *z; |
| 5109 | SHA3Context cx; |
| 5110 | int iSize; |
| 5111 | |
| 5112 | if( argc==1 ){ |
| 5113 | iSize = 256; |
| 5114 | }else{ |
| 5115 | iSize = sqlite3_value_int(argv[1]); |
| @@ -5119,10 +5330,15 @@ | |
| 5119 | return; |
| 5120 | } |
| 5121 | } |
| 5122 | if( zSql==0 ) return; |
| 5123 | SHA3Init(&cx, iSize); |
| 5124 | while( zSql[0] ){ |
| 5125 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); |
| 5126 | if( rc ){ |
| 5127 | char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", |
| 5128 | zSql, sqlite3_errmsg(db)); |
| @@ -5145,19 +5361,25 @@ | |
| 5145 | sha3_step_vformat(&cx,"S%d:",n); |
| 5146 | SHA3Update(&cx,(unsigned char*)z,n); |
| 5147 | } |
| 5148 | |
| 5149 | /* Compute a hash over the result of the query */ |
| 5150 | while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 5151 | SHA3Update(&cx,(const unsigned char*)"R",1); |
| 5152 | for(i=0; i<nCol; i++){ |
| 5153 | sha3UpdateFromValue(&cx, sqlite3_column_value(pStmt,i)); |
| 5154 | } |
| 5155 | } |
| 5156 | sqlite3_finalize(pStmt); |
| 5157 | } |
| 5158 | sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); |
| 5159 | } |
| 5160 | |
| 5161 | /* |
| 5162 | ** xStep function for sha3_agg(). |
| 5163 | */ |
| @@ -5272,10 +5494,14 @@ | |
| 5272 | #include <stdarg.h> |
| 5273 | |
| 5274 | /****************************************************************************** |
| 5275 | ** The Hash Engine |
| 5276 | */ |
| 5277 | /* Context for the SHA1 hash */ |
| 5278 | typedef struct SHA1Context SHA1Context; |
| 5279 | struct SHA1Context { |
| 5280 | unsigned int state[5]; |
| 5281 | unsigned int count[2]; |
| @@ -5412,11 +5638,11 @@ | |
| 5412 | } |
| 5413 | j = 0; |
| 5414 | }else{ |
| 5415 | i = 0; |
| 5416 | } |
| 5417 | (void)memcpy(&p->buffer[j], &data[i], len - i); |
| 5418 | } |
| 5419 | |
| 5420 | /* Compute a string using sqlite3_vsnprintf() and hash it */ |
| 5421 | static void hash_step_vformat( |
| 5422 | SHA1Context *p, /* Add content to this context */ |
| @@ -5467,10 +5693,13 @@ | |
| 5467 | zOut[i*2+1] = zEncode[digest[i] & 0xf]; |
| 5468 | } |
| 5469 | zOut[i*2]= 0; |
| 5470 | } |
| 5471 | } |
| 5472 | /* End of the hashing logic |
| 5473 | *****************************************************************************/ |
| 5474 | |
| 5475 | /* |
| 5476 | ** Two SQL functions: sha1(X) and sha1b(X). |
| @@ -5501,11 +5730,14 @@ | |
| 5501 | if( eType==SQLITE_BLOB ){ |
| 5502 | pData = (const unsigned char*)sqlite3_value_blob(argv[0]); |
| 5503 | }else{ |
| 5504 | pData = (const unsigned char*)sqlite3_value_text(argv[0]); |
| 5505 | } |
| 5506 | if( pData==0 ) return; |
| 5507 | hash_step(&cx, pData, nByte); |
| 5508 | if( sqlite3_user_data(context)!=0 ){ |
| 5509 | /* sha1b() - binary result */ |
| 5510 | hash_finish(&cx, zOut, 1); |
| 5511 | sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT); |
| @@ -5541,13 +5773,20 @@ | |
| 5541 | int rc; |
| 5542 | int n; |
| 5543 | const char *z; |
| 5544 | SHA1Context cx; |
| 5545 | char zOut[44]; |
| 5546 | |
| 5547 | assert( argc==1 ); |
| 5548 | if( zSql==0 ) return; |
| 5549 | hash_init(&cx); |
| 5550 | while( zSql[0] ){ |
| 5551 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); |
| 5552 | if( rc ){ |
| 5553 | char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", |
| @@ -5570,10 +5809,11 @@ | |
| 5570 | n = (int)strlen(z); |
| 5571 | hash_step_vformat(&cx,"S%d:",n); |
| 5572 | hash_step(&cx,(unsigned char*)z,n); |
| 5573 | |
| 5574 | /* Compute a hash over the result of the query */ |
| 5575 | while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 5576 | hash_step(&cx,(const unsigned char*)"R",1); |
| 5577 | for(i=0; i<nCol; i++){ |
| 5578 | switch( sqlite3_column_type(pStmt,i) ){ |
| 5579 | case SQLITE_NULL: { |
| @@ -5624,13 +5864,18 @@ | |
| 5624 | } |
| 5625 | } |
| 5626 | } |
| 5627 | } |
| 5628 | sqlite3_finalize(pStmt); |
| 5629 | } |
| 5630 | hash_finish(&cx, zOut, 0); |
| 5631 | sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT); |
| 5632 | } |
| 5633 | |
| 5634 | |
| 5635 | #ifdef _WIN32 |
| 5636 | |
| @@ -5824,10 +6069,13 @@ | |
| 5824 | } |
| 5825 | |
| 5826 | /* |
| 5827 | ** Allocate a new Decimal object initialized to the text in zIn[]. |
| 5828 | ** Return NULL if any kind of error occurs. |
| 5829 | */ |
| 5830 | static Decimal *decimalNewFromText(const char *zIn, int n){ |
| 5831 | Decimal *p = 0; |
| 5832 | int i; |
| 5833 | int iExp = 0; |
| @@ -5841,15 +6089,15 @@ | |
| 5841 | p->isNull = 0; |
| 5842 | p->nDigit = 0; |
| 5843 | p->nFrac = 0; |
| 5844 | p->a = sqlite3_malloc64( n+1 ); |
| 5845 | if( p->a==0 ) goto new_from_text_failed; |
| 5846 | for(i=0; IsSpace(zIn[i]); i++){} |
| 5847 | if( zIn[i]=='-' ){ |
| 5848 | p->sign = 1; |
| 5849 | i++; |
| 5850 | }else if( zIn[i]=='+' ){ |
| 5851 | i++; |
| 5852 | } |
| 5853 | while( i<n && zIn[i]=='0' ) i++; |
| 5854 | while( i<n ){ |
| 5855 | char c = zIn[i]; |
| @@ -6056,32 +6304,41 @@ | |
| 6056 | } |
| 6057 | z[i] = 0; |
| 6058 | sqlite3_result_text(pCtx, z, i, sqlite3_free); |
| 6059 | } |
| 6060 | |
| 6061 | /* |
| 6062 | ** Round a decimal value to N significant digits. N must be positive. |
| 6063 | */ |
| 6064 | static void decimal_round(Decimal *p, int N){ |
| 6065 | int i; |
| 6066 | int nZero; |
| 6067 | if( N<1 ) return; |
| 6068 | if( p==0 ) return; |
| 6069 | if( p->nDigit<=N ) return; |
| 6070 | for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){} |
| 6071 | N += nZero; |
| 6072 | if( p->nDigit<=N ) return; |
| 6073 | if( p->a[N]>4 ){ |
| 6074 | p->a[N-1]++; |
| 6075 | for(i=N-1; i>0 && p->a[i]>9; i--){ |
| 6076 | p->a[i] = 0; |
| 6077 | p->a[i-1]++; |
| 6078 | } |
| 6079 | if( p->a[0]>9 ){ |
| 6080 | p->a[0] = 1; |
| 6081 | p->nFrac--; |
| 6082 | } |
| 6083 | } |
| 6084 | memset(&p->a[N], 0, p->nDigit - N); |
| 6085 | } |
| 6086 | |
| 6087 | /* |
| @@ -6225,10 +6482,11 @@ | |
| 6225 | int nAddSig; |
| 6226 | int nAddFrac; |
| 6227 | signed char *a; |
| 6228 | if( p==0 ) return; |
| 6229 | nAddFrac = nFrac - p->nFrac; |
| 6230 | nAddSig = (nDigit - p->nDigit) - nAddFrac; |
| 6231 | if( nAddFrac==0 && nAddSig==0 ) return; |
| 6232 | if( nDigit+1>SQLITE_DECIMAL_MAX_DIGIT ){ p->oom = 1; return; } |
| 6233 | a = sqlite3_realloc64(p->a, nDigit+1); |
| 6234 | if( a==0 ){ |
| @@ -8232,10 +8490,20 @@ | |
| 8232 | if( r==(double)x ) return r; |
| 8233 | if( r<(double)x ) x--; |
| 8234 | return (double)x; |
| 8235 | } |
| 8236 | #endif |
| 8237 | |
| 8238 | /* |
| 8239 | ** This method is called to "rewind" the series_cursor object back |
| 8240 | ** to the first row of output. This method is always called at least |
| 8241 | ** once prior to any call to seriesColumn() or seriesRowid() or |
| @@ -8355,27 +8623,31 @@ | |
| 8355 | double r = sqlite3_value_double(argv[iArg++]); |
| 8356 | if( r==seriesCeil(r) |
| 8357 | && r>=(double)SMALLEST_INT64 |
| 8358 | && r<=(double)LARGEST_INT64 |
| 8359 | ){ |
| 8360 | iMin = iMax = (sqlite3_int64)r; |
| 8361 | }else{ |
| 8362 | goto series_no_rows; |
| 8363 | } |
| 8364 | }else{ |
| 8365 | iMin = iMax = sqlite3_value_int64(argv[iArg++]); |
| 8366 | } |
| 8367 | }else{ |
| 8368 | if( idxNum & 0x0300 ){ /* value>X or value>=X */ |
| 8369 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8370 | double r = sqlite3_value_double(argv[iArg++]); |
| 8371 | if( r<(double)SMALLEST_INT64 ){ |
| 8372 | iMin = SMALLEST_INT64; |
| 8373 | }else if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){ |
| 8374 | iMin = (sqlite3_int64)seriesCeil(r+1.0); |
| 8375 | }else{ |
| 8376 | iMin = (sqlite3_int64)seriesCeil(r); |
| 8377 | } |
| 8378 | }else{ |
| 8379 | iMin = sqlite3_value_int64(argv[iArg++]); |
| 8380 | if( (idxNum & 0x0200)!=0 ){ |
| 8381 | if( iMin==LARGEST_INT64 ){ |
| @@ -8384,19 +8656,23 @@ | |
| 8384 | iMin++; |
| 8385 | } |
| 8386 | } |
| 8387 | } |
| 8388 | } |
| 8389 | if( idxNum & 0x3000 ){ /* value<X or value<=X */ |
| 8390 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8391 | double r = sqlite3_value_double(argv[iArg++]); |
| 8392 | if( r>(double)LARGEST_INT64 ){ |
| 8393 | iMax = LARGEST_INT64; |
| 8394 | }else if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){ |
| 8395 | iMax = (sqlite3_int64)(r-1.0); |
| 8396 | }else{ |
| 8397 | iMax = (sqlite3_int64)seriesFloor(r); |
| 8398 | } |
| 8399 | }else{ |
| 8400 | iMax = sqlite3_value_int64(argv[iArg++]); |
| 8401 | if( idxNum & 0x2000 ){ |
| 8402 | if( iMax==SMALLEST_INT64 ){ |
| @@ -9638,11 +9914,10 @@ | |
| 9638 | if( pRe==0 ){ |
| 9639 | sqlite3_result_error_nomem(context); |
| 9640 | return; |
| 9641 | } |
| 9642 | pStr = sqlite3_str_new(0); |
| 9643 | if( pStr==0 ) goto re_bytecode_func_err; |
| 9644 | if( pRe->nInit>0 ){ |
| 9645 | sqlite3_str_appendf(pStr, "INIT "); |
| 9646 | for(i=0; i<pRe->nInit; i++){ |
| 9647 | sqlite3_str_appendf(pStr, "%02x", pRe->zInit[i]); |
| 9648 | } |
| @@ -9649,20 +9924,20 @@ | |
| 9649 | sqlite3_str_appendf(pStr, "\n"); |
| 9650 | } |
| 9651 | for(i=0; (unsigned)i<pRe->nState; i++){ |
| 9652 | sqlite3_str_appendf(pStr, "%-8s %4d\n", |
| 9653 | ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]); |
| 9654 | } |
| 9655 | n = sqlite3_str_length(pStr); |
| 9656 | z = sqlite3_str_finish(pStr); |
| 9657 | if( n==0 ){ |
| 9658 | sqlite3_free(z); |
| 9659 | }else{ |
| 9660 | sqlite3_result_text(context, z, n-1, sqlite3_free); |
| 9661 | } |
| 9662 | |
| 9663 | re_bytecode_func_err: |
| 9664 | re_free(pRe); |
| 9665 | } |
| 9666 | |
| 9667 | #endif /* SQLITE_DEBUG */ |
| 9668 | |
| @@ -10557,11 +10832,15 @@ | |
| 10557 | sqlite3_result_error_nomem(ctx); |
| 10558 | return SQLITE_NOMEM; |
| 10559 | } |
| 10560 | } |
| 10561 | |
| 10562 | sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT); |
| 10563 | if( aBuf!=aStatic ) sqlite3_free(aBuf); |
| 10564 | #endif |
| 10565 | }else{ |
| 10566 | readFileContents(ctx, pCur->zPath); |
| 10567 | } |
| @@ -10870,10 +11149,13 @@ | |
| 10870 | ** Return NULL if unable. |
| 10871 | ** |
| 10872 | ** The file or directory X is not required to exist. The answer is formed |
| 10873 | ** by calling system realpath() on the prefix of X that does exist and |
| 10874 | ** appending the tail of X that does not (yet) exist. |
| 10875 | */ |
| 10876 | static void realpathFunc( |
| 10877 | sqlite3_context *context, |
| 10878 | int argc, |
| 10879 | sqlite3_value **argv |
| @@ -10892,10 +11174,11 @@ | |
| 10892 | (void)argc; |
| 10893 | zPath = (const char*)sqlite3_value_text(argv[0]); |
| 10894 | if( zPath==0 ) return; |
| 10895 | if( zPath[0]==0 ) zPath = "."; |
| 10896 | zCopy = sqlite3_mprintf("%s",zPath); |
| 10897 | len = strlen(zCopy); |
| 10898 | while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){ |
| 10899 | len--; |
| 10900 | } |
| 10901 | zCopy[len] = 0; |
| @@ -11802,11 +12085,13 @@ | |
| 11802 | int iAmt, |
| 11803 | sqlite_int64 iOfst |
| 11804 | ){ |
| 11805 | ApndFile *paf = (ApndFile *)pFile; |
| 11806 | sqlite_int64 iWriteEnd = iOfst + iAmt; |
| 11807 | if( iWriteEnd>=APND_MAX_SIZE ) return SQLITE_FULL; |
| 11808 | pFile = ORIGFILE(pFile); |
| 11809 | /* If append-mark is absent or will be overwritten, write it. */ |
| 11810 | if( paf->iMark < 0 || paf->iPgOne + iWriteEnd > paf->iMark ){ |
| 11811 | int rc = apndWriteMark(paf, pFile, iWriteEnd); |
| 11812 | if( SQLITE_OK!=rc ) return rc; |
| @@ -12220,10 +12505,12 @@ | |
| 12220 | ** |
| 12221 | ** * No support for encryption |
| 12222 | ** * No support for ZIP archives spanning multiple files |
| 12223 | ** * No support for zip64 extensions |
| 12224 | ** * Only the "inflate/deflate" (zlib) compression method is supported |
| 12225 | */ |
| 12226 | /* #include "sqlite3ext.h" */ |
| 12227 | SQLITE_EXTENSION_INIT1 |
| 12228 | #include <stdio.h> |
| 12229 | #include <string.h> |
| @@ -12685,10 +12972,11 @@ | |
| 12685 | |
| 12686 | for(p=pCsr->pFreeEntry; p; p=pNext){ |
| 12687 | pNext = p->pNext; |
| 12688 | zipfileEntryFree(p); |
| 12689 | } |
| 12690 | } |
| 12691 | |
| 12692 | /* |
| 12693 | ** Destructor for an ZipfileCsr. |
| 12694 | */ |
| @@ -13087,11 +13375,17 @@ | |
| 13087 | } |
| 13088 | } |
| 13089 | |
| 13090 | if( rc==SQLITE_OK ){ |
| 13091 | u32 *pt = &pNew->mUnixTime; |
| 13092 | pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead); |
| 13093 | pNew->aExtra = (u8*)&pNew[1]; |
| 13094 | memcpy(pNew->aExtra, &aRead[nFile], nExtra); |
| 13095 | if( pNew->cds.zFile==0 ){ |
| 13096 | rc = SQLITE_NOMEM; |
| 13097 | }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){ |
| @@ -13844,14 +14138,14 @@ | |
| 13844 | if( zUpdate && zipfileComparePath(zUpdate, zDelete, nDelete)!=0 ){ |
| 13845 | bUpdate = 1; |
| 13846 | } |
| 13847 | } |
| 13848 | for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){ |
| 13849 | if( zipfileComparePath(pOld->cds.zFile, zDelete, nDelete)==0 ){ |
| 13850 | break; |
| 13851 | } |
| 13852 | assert( pOld->pNext ); |
| 13853 | } |
| 13854 | } |
| 13855 | |
| 13856 | if( nVal>1 ){ |
| 13857 | /* Check that "sz" and "rawdata" are both NULL: */ |
| @@ -14191,14 +14485,14 @@ | |
| 14191 | ZipfileBuffer body; |
| 14192 | ZipfileBuffer cds; |
| 14193 | }; |
| 14194 | |
| 14195 | static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){ |
| 14196 | if( pBuf->n+nByte>pBuf->nAlloc ){ |
| 14197 | u8 *aNew; |
| 14198 | sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512; |
| 14199 | int nReq = pBuf->n + nByte; |
| 14200 | |
| 14201 | while( nNew<nReq ) nNew = nNew*2; |
| 14202 | aNew = sqlite3_realloc64(pBuf->a, nNew); |
| 14203 | if( aNew==0 ) return SQLITE_NOMEM; |
| 14204 | pBuf->a = aNew; |
| @@ -14410,11 +14704,11 @@ | |
| 14410 | eocd.nEntry = (u16)p->nEntry; |
| 14411 | eocd.nEntryTotal = (u16)p->nEntry; |
| 14412 | eocd.nSize = p->cds.n; |
| 14413 | eocd.iOffset = p->body.n; |
| 14414 | |
| 14415 | nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ; |
| 14416 | aZip = (u8*)sqlite3_malloc64(nZip); |
| 14417 | if( aZip==0 ){ |
| 14418 | sqlite3_result_error_nomem(pCtx); |
| 14419 | }else{ |
| 14420 | memcpy(aZip, p->body.a, p->body.n); |
| @@ -16296,11 +16590,11 @@ | |
| 16296 | p->pTable = pTab; |
| 16297 | |
| 16298 | /* The statement the vtab will pass to sqlite3_declare_vtab() */ |
| 16299 | zInner = idxAppendText(&rc, 0, "CREATE TABLE x("); |
| 16300 | for(i=0; i<pTab->nCol; i++){ |
| 16301 | zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s", |
| 16302 | (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl |
| 16303 | ); |
| 16304 | } |
| 16305 | zInner = idxAppendText(&rc, zInner, ")"); |
| 16306 | |
| @@ -16496,11 +16790,11 @@ | |
| 16496 | sqlite3_free(zCols); |
| 16497 | sqlite3_free(zOrder); |
| 16498 | return sqlite3_reset(pIndexXInfo); |
| 16499 | } |
| 16500 | zCols = idxAppendText(&rc, zCols, |
| 16501 | "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s", |
| 16502 | zComma, zName, nCol, zName, zColl |
| 16503 | ); |
| 16504 | zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol); |
| 16505 | } |
| 16506 | sqlite3_reset(pIndexXInfo); |
| @@ -17537,16 +17831,19 @@ | |
| 17537 | } |
| 17538 | iRet++; |
| 17539 | } |
| 17540 | } |
| 17541 | else if( c=='[' ){ |
| 17542 | while( z[iRet++]!=']' && z[iRet] ); |
| 17543 | } |
| 17544 | else if( (c>='A' && c<='Z') || (c>='a' && c<='z') ){ |
| 17545 | while( (z[iRet]>='A' && z[iRet]<='Z') || (z[iRet]>='a' && z[iRet]<='z') ){ |
| 17546 | iRet++; |
| 17547 | } |
| 17548 | } |
| 17549 | |
| 17550 | return iRet; |
| 17551 | } |
| 17552 | |
| @@ -17983,10 +18280,27 @@ | |
| 17983 | intckFinalize(p, pStmt); |
| 17984 | |
| 17985 | if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 1"); |
| 17986 | return zRet; |
| 17987 | } |
| 17988 | |
| 17989 | /* |
| 17990 | ** Open a new integrity-check object. |
| 17991 | */ |
| 17992 | int sqlite3_intck_open( |
| @@ -18005,13 +18319,11 @@ | |
| 18005 | }else{ |
| 18006 | memset(pNew, 0, sizeof(*pNew)); |
| 18007 | pNew->db = db; |
| 18008 | pNew->zDb = (const char*)&pNew[1]; |
| 18009 | memcpy(&pNew[1], zDb, nDb+1); |
| 18010 | rc = sqlite3_create_function(db, "parse_create_index", |
| 18011 | 2, SQLITE_UTF8, 0, intckParseCreateIndexFunc, 0, 0 |
| 18012 | ); |
| 18013 | if( rc!=SQLITE_OK ){ |
| 18014 | sqlite3_intck_close(pNew); |
| 18015 | pNew = 0; |
| 18016 | } |
| 18017 | } |
| @@ -18024,13 +18336,11 @@ | |
| 18024 | ** Free the integrity-check object. |
| 18025 | */ |
| 18026 | void sqlite3_intck_close(sqlite3_intck *p){ |
| 18027 | if( p ){ |
| 18028 | sqlite3_finalize(p->pCheck); |
| 18029 | sqlite3_create_function( |
| 18030 | p->db, "parse_create_index", 1, SQLITE_UTF8, 0, 0, 0, 0 |
| 18031 | ); |
| 18032 | sqlite3_free(p->zObj); |
| 18033 | sqlite3_free(p->zKey); |
| 18034 | sqlite3_free(p->zTestSql); |
| 18035 | sqlite3_free(p->zErr); |
| 18036 | sqlite3_free(p->zMessage); |
| @@ -19464,11 +19774,11 @@ | |
| 19464 | sqlite3_vfs_unregister(pVfs); |
| 19465 | sqlite3_free(pVfs); |
| 19466 | } |
| 19467 | |
| 19468 | /************************* End ext/misc/vfstrace.c ********************/ |
| 19469 | /************************* Begin ext/misc/analyze.c ******************/ |
| 19470 | /* |
| 19471 | ** 2026-04-13 |
| 19472 | ** |
| 19473 | ** The author disclaims copyright to this source code. In place of |
| 19474 | ** a legal notice, here is a blessing: |
| @@ -19477,12 +19787,21 @@ | |
| 19477 | ** May you find forgiveness for yourself and forgive others. |
| 19478 | ** May you share freely, never taking more than you give. |
| 19479 | ** |
| 19480 | ****************************************************************************** |
| 19481 | ** |
| 19482 | ** Partial reimplement of the sqlite3_analyzer utility program as |
| 19483 | ** loadable SQL function. |
| 19484 | */ |
| 19485 | /* #include "sqlite3ext.h" */ |
| 19486 | SQLITE_EXTENSION_INIT1 |
| 19487 | #include <assert.h> |
| 19488 | #include <string.h> |
| @@ -19490,28 +19809,28 @@ | |
| 19490 | #include <math.h> |
| 19491 | |
| 19492 | /* |
| 19493 | ** State information for the analysis |
| 19494 | */ |
| 19495 | typedef struct Analysis Analysis; |
| 19496 | struct Analysis { |
| 19497 | sqlite3 *db; /* Database connection */ |
| 19498 | sqlite3_context *context; /* SQL function context */ |
| 19499 | sqlite3_str *pOut; /* Write output here */ |
| 19500 | char *zSU; /* Name of the temp.space_used table */ |
| 19501 | const char *zSchema; /* Schema to be analyzed */ |
| 19502 | }; |
| 19503 | |
| 19504 | /* |
| 19505 | ** Free all resources that the Analysis object references and |
| 19506 | ** reset the Analysis object. |
| 19507 | ** |
| 19508 | ** Call this routine multiple times on the same Analysis object |
| 19509 | ** is a harmless no-op, as long as the memory for the object itself |
| 19510 | ** has not been freed. |
| 19511 | */ |
| 19512 | static void analysisReset(Analysis *p){ |
| 19513 | if( p->zSU ){ |
| 19514 | char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU); |
| 19515 | if( zSql ){ |
| 19516 | sqlite3_exec(p->db, zSql, 0, 0, 0); |
| 19517 | sqlite3_free(zSql); |
| @@ -19524,11 +19843,11 @@ | |
| 19524 | |
| 19525 | /* |
| 19526 | ** Report an error using formatted text. If zFormat==NULL then report |
| 19527 | ** an OOM error. |
| 19528 | */ |
| 19529 | static void analysisError(Analysis *p, const char *zFormat, ...){ |
| 19530 | char *zErr; |
| 19531 | if( zFormat ){ |
| 19532 | va_list ap; |
| 19533 | va_start(ap, zFormat); |
| 19534 | zErr = sqlite3_vmprintf(zFormat, ap); |
| @@ -19540,38 +19859,38 @@ | |
| 19540 | sqlite3_result_error_nomem(p->context); |
| 19541 | }else{ |
| 19542 | sqlite3_result_error(p->context, zErr, -1); |
| 19543 | sqlite3_free(zErr); |
| 19544 | } |
| 19545 | analysisReset(p); |
| 19546 | } |
| 19547 | |
| 19548 | /* |
| 19549 | ** Prepare and return an SQL statement. |
| 19550 | */ |
| 19551 | static sqlite3_stmt *analysisVPrep(Analysis *p, const char *zFmt, va_list ap){ |
| 19552 | char *zSql; |
| 19553 | int rc; |
| 19554 | sqlite3_stmt *pStmt = 0; |
| 19555 | zSql = sqlite3_vmprintf(zFmt, ap); |
| 19556 | if( zSql==0 ){ analysisError(p,0); return 0; } |
| 19557 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 19558 | if( rc ){ |
| 19559 | analysisError(p, "SQL parse error: %s\nOriginal SQL: %s", |
| 19560 | sqlite3_errmsg(p->db), zSql); |
| 19561 | sqlite3_finalize(pStmt); |
| 19562 | analysisReset(p); |
| 19563 | pStmt = 0; |
| 19564 | } |
| 19565 | sqlite3_free(zSql); |
| 19566 | return pStmt; |
| 19567 | } |
| 19568 | static sqlite3_stmt *analysisPrepare(Analysis *p, const char *zFormat, ...){ |
| 19569 | va_list ap; |
| 19570 | sqlite3_stmt *pStmt = 0; |
| 19571 | va_start(ap, zFormat); |
| 19572 | pStmt = analysisVPrep(p,zFormat,ap); |
| 19573 | va_end(ap); |
| 19574 | return pStmt; |
| 19575 | } |
| 19576 | |
| 19577 | /* |
| @@ -19580,60 +19899,60 @@ | |
| 19580 | ** |
| 19581 | ** If rc is SQLITE_DONE or SQLITE_OK, then return false. |
| 19582 | ** |
| 19583 | ** The prepared statement is closed in either case. |
| 19584 | */ |
| 19585 | static int analysisStmtFinish(Analysis *p, int rc, sqlite3_stmt *pStmt){ |
| 19586 | if( rc==SQLITE_DONE ){ |
| 19587 | rc = SQLITE_OK; |
| 19588 | } |
| 19589 | if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){ |
| 19590 | analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19591 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19592 | analysisReset(p); |
| 19593 | } |
| 19594 | sqlite3_finalize(pStmt); |
| 19595 | return rc; |
| 19596 | } |
| 19597 | |
| 19598 | /* |
| 19599 | ** Run SQL. Return the number of errors. |
| 19600 | */ |
| 19601 | static int analysisSql(Analysis *p, const char *zFormat, ...){ |
| 19602 | va_list ap; |
| 19603 | int rc; |
| 19604 | sqlite3_stmt *pStmt = 0; |
| 19605 | va_start(ap, zFormat); |
| 19606 | pStmt = analysisVPrep(p,zFormat,ap); |
| 19607 | va_end(ap); |
| 19608 | if( pStmt==0 ) return 1; |
| 19609 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){} |
| 19610 | if( rc==SQLITE_DONE ){ |
| 19611 | rc = SQLITE_OK; |
| 19612 | }else{ |
| 19613 | analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19614 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19615 | analysisReset(p); |
| 19616 | } |
| 19617 | sqlite3_finalize(pStmt); |
| 19618 | return rc; |
| 19619 | } |
| 19620 | |
| 19621 | /* |
| 19622 | ** Run an SQL query that returns an integer. Write that integer |
| 19623 | ** into *piRes. Return the number of errors. |
| 19624 | */ |
| 19625 | static int analysisSqlInt( |
| 19626 | Analysis *p, |
| 19627 | sqlite3_int64 *piRes, |
| 19628 | const char *zFormat, ... |
| 19629 | ){ |
| 19630 | va_list ap; |
| 19631 | int rc; |
| 19632 | sqlite3_stmt *pStmt = 0; |
| 19633 | va_start(ap, zFormat); |
| 19634 | pStmt = analysisVPrep(p,zFormat,ap); |
| 19635 | va_end(ap); |
| 19636 | if( pStmt==0 ) return 1; |
| 19637 | rc = sqlite3_step(pStmt); |
| 19638 | if( rc==SQLITE_ROW ){ |
| 19639 | *piRes = sqlite3_column_int64(pStmt, 0); |
| @@ -19641,14 +19960,14 @@ | |
| 19641 | }else if( rc==SQLITE_DONE ){ |
| 19642 | rc = SQLITE_OK; |
| 19643 | }else{ |
| 19644 | if( p->db ){ |
| 19645 | /* p->db is NULL if there was some prior error */ |
| 19646 | analysisError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19647 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19648 | } |
| 19649 | analysisReset(p); |
| 19650 | } |
| 19651 | sqlite3_finalize(pStmt); |
| 19652 | return rc; |
| 19653 | } |
| 19654 | |
| @@ -19657,20 +19976,20 @@ | |
| 19657 | ** by the format string. If the output is initially empty, begin |
| 19658 | ** the title line with "/" so that it forms the beginning of a C-style |
| 19659 | ** comment. Otherwise begin with a new-line. Always finish with a |
| 19660 | ** newline. |
| 19661 | */ |
| 19662 | static void analysisTitle(Analysis *p, const char *zFormat, ...){ |
| 19663 | char *zFirst; |
| 19664 | char *zTitle; |
| 19665 | size_t nTitle; |
| 19666 | va_list ap; |
| 19667 | va_start(ap, zFormat); |
| 19668 | zTitle = sqlite3_vmprintf(zFormat, ap); |
| 19669 | va_end(ap); |
| 19670 | if( zTitle==0 ){ |
| 19671 | analysisError(p, 0); |
| 19672 | return; |
| 19673 | } |
| 19674 | zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*"; |
| 19675 | nTitle = strlen(zTitle); |
| 19676 | if( nTitle>=75 ){ |
| @@ -19685,12 +20004,12 @@ | |
| 19685 | /* |
| 19686 | ** Add an output line that begins with the zDesc text extended out to |
| 19687 | ** 50 columns with "." characters, and followed by whatever text is |
| 19688 | ** described by zFormat. |
| 19689 | */ |
| 19690 | static void analysisLine( |
| 19691 | Analysis *p, /* Analysis context */ |
| 19692 | const char *zDesc, /* Description */ |
| 19693 | const char *zFormat, /* Argument to the description */ |
| 19694 | ... |
| 19695 | ){ |
| 19696 | char *zTxt; |
| @@ -19698,14 +20017,14 @@ | |
| 19698 | va_list ap; |
| 19699 | va_start(ap, zFormat); |
| 19700 | zTxt = sqlite3_vmprintf(zFormat, ap); |
| 19701 | va_end(ap); |
| 19702 | if( zTxt==0 ){ |
| 19703 | analysisError(p, 0); |
| 19704 | return; |
| 19705 | } |
| 19706 | nDesc = strlen(zDesc); |
| 19707 | if( nDesc>=50 ){ |
| 19708 | sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt); |
| 19709 | }else{ |
| 19710 | int nExtra = 50 - (int)nDesc; |
| 19711 | sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt); |
| @@ -19715,15 +20034,28 @@ | |
| 19715 | /* |
| 19716 | ** Write a percentage into the output. The number written should show |
| 19717 | ** two or three significant digits, with the decimal point being the fourth |
| 19718 | ** character. |
| 19719 | */ |
| 19720 | static void analysisPercent(Analysis *p, double r){ |
| 19721 | char zNum[100]; |
| 19722 | char *zDP; |
| 19723 | int nLeadingDigit; |
| 19724 | int sz; |
| 19725 | sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r); |
| 19726 | sz = (int)strlen(zNum); |
| 19727 | zDP = strchr(zNum, '.'); |
| 19728 | if( zDP==0 ){ |
| 19729 | memcpy(zNum+sz,".0",3); |
| @@ -19744,12 +20076,12 @@ | |
| 19744 | ** |
| 19745 | ** The title if the subreport is given by zTitle. zWhere is |
| 19746 | ** a boolean expression that can go in the WHERE clause to select |
| 19747 | ** the relevant rows of the s.zSU table. |
| 19748 | */ |
| 19749 | static int analysisSubreport( |
| 19750 | Analysis *p, /* Analysis context */ |
| 19751 | char *zTitle, /* Title for this subreport */ |
| 19752 | char *zWhere, /* WHERE clause for this subreport */ |
| 19753 | sqlite3_int64 pgsz, /* Database page size */ |
| 19754 | sqlite3_int64 nPage /* Number of pages in entire database */ |
| 19755 | ){ |
| @@ -19773,14 +20105,14 @@ | |
| 19773 | sqlite3_int64 total_unused; /* Total unused bytes */ |
| 19774 | sqlite3_int64 total_meta; /* Total metadata */ |
| 19775 | int rc; |
| 19776 | |
| 19777 | if( zTitle==0 || zWhere==0 ){ |
| 19778 | analysisError(p, 0); |
| 19779 | return SQLITE_NOMEM; |
| 19780 | } |
| 19781 | pStmt = analysisPrepare(p, |
| 19782 | "SELECT\n" |
| 19783 | " sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */ |
| 19784 | " sum(payload),\n" /* 1 */ |
| 19785 | " sum(ovfl_payload),\n" /* 2 */ |
| 19786 | " max(mx_payload),\n" /* 3 */ |
| @@ -19797,11 +20129,11 @@ | |
| 19797 | " FROM temp.%s WHERE %s", |
| 19798 | p->zSU, zWhere); |
| 19799 | if( pStmt==0 ) return 1; |
| 19800 | rc = sqlite3_step(pStmt); |
| 19801 | if( rc==SQLITE_ROW ){ |
| 19802 | analysisTitle(p, zTitle); |
| 19803 | |
| 19804 | nentry = sqlite3_column_int64(pStmt, 0); |
| 19805 | payload = sqlite3_column_int64(pStmt, 1); |
| 19806 | ovfl_payload = sqlite3_column_int64(pStmt, 2); |
| 19807 | mx_payload = sqlite3_column_int64(pStmt, 3); |
| @@ -19816,73 +20148,73 @@ | |
| 19816 | cnt = sqlite3_column_int64(pStmt, 12); |
| 19817 | int_cell = sqlite3_column_int64(pStmt, 13); |
| 19818 | rc = SQLITE_DONE; |
| 19819 | |
| 19820 | total_pages = leaf_pages + int_pages + ovfl_pages; |
| 19821 | analysisLine(p, "Percentage of total database", "%.3g%%\n", |
| 19822 | (total_pages*100.0)/(double)nPage); |
| 19823 | analysisLine(p, "Number of entries", "%lld\n", nentry); |
| 19824 | storage = total_pages*pgsz; |
| 19825 | analysisLine(p, "Bytes of storage consumed", "%lld\n", storage); |
| 19826 | analysisLine(p, "Bytes of payload", "%-11lld ", payload); |
| 19827 | analysisPercent(p, payload*100.0/(double)storage); |
| 19828 | if( ovfl_cnt>0 ){ |
| 19829 | analysisLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload); |
| 19830 | analysisPercent(p, ovfl_payload*100.0/(double)payload); |
| 19831 | } |
| 19832 | total_unused = leaf_unused + int_unused + ovfl_unused; |
| 19833 | total_meta = storage - payload - total_unused; |
| 19834 | analysisLine(p, "Bytes of metadata","%-11lld ", total_meta); |
| 19835 | analysisPercent(p, total_meta*100.0/(double)storage); |
| 19836 | if( cnt==1 ){ |
| 19837 | analysisLine(p, "B-tree depth", "%lld\n", depth); |
| 19838 | if( int_cell>1 ){ |
| 19839 | analysisLine(p, "Average fanout", "%.1f\n", |
| 19840 | (double)(int_cell+int_pages)/(double)int_pages); |
| 19841 | } |
| 19842 | } |
| 19843 | if( nentry>0 ){ |
| 19844 | analysisLine(p, "Average payload per entry", "%.1f\n", |
| 19845 | (double)payload/(double)nentry); |
| 19846 | analysisLine(p, "Average unused bytes per entry", "%.1f\n", |
| 19847 | (double)total_unused/(double)nentry); |
| 19848 | analysisLine(p, "Average metadata per entry", "%.1f\n", |
| 19849 | (double)total_meta/(double)nentry); |
| 19850 | } |
| 19851 | analysisLine(p, "Maximum single-entry payload", "%lld\n", mx_payload); |
| 19852 | if( nentry>0 ){ |
| 19853 | analysisLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt); |
| 19854 | analysisPercent(p, ovfl_cnt*100.0/(double)nentry); |
| 19855 | } |
| 19856 | if( int_pages>0 ){ |
| 19857 | analysisLine(p, "Index pages used", "%lld\n", int_pages); |
| 19858 | } |
| 19859 | analysisLine(p, "Primary pages used", "%lld\n", leaf_pages); |
| 19860 | if( ovfl_cnt ){ |
| 19861 | analysisLine(p, "Overflow pages used", "%lld\n", ovfl_pages); |
| 19862 | } |
| 19863 | analysisLine(p, "Total pages used", "%lld\n", total_pages); |
| 19864 | if( int_pages>0 ){ |
| 19865 | analysisLine(p, "Unused bytes on index pages", "%lld\n", int_unused); |
| 19866 | } |
| 19867 | analysisLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused); |
| 19868 | if( ovfl_cnt ){ |
| 19869 | analysisLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused); |
| 19870 | } |
| 19871 | analysisLine(p, "Unused bytes on all pages", "%-11lld ", total_unused); |
| 19872 | analysisPercent(p, total_unused*100.0/(double)storage); |
| 19873 | } |
| 19874 | return analysisStmtFinish(p, rc, pStmt); |
| 19875 | } |
| 19876 | |
| 19877 | /* |
| 19878 | ** SQL Function: analyze(SCHEMA) |
| 19879 | ** |
| 19880 | ** Analyze the database schema named in the argument. Return text |
| 19881 | ** containing the analysis. |
| 19882 | */ |
| 19883 | static void analyzeFunc( |
| 19884 | sqlite3_context *context, |
| 19885 | int argc, |
| 19886 | sqlite3_value **argv |
| 19887 | ){ |
| 19888 | int rc; |
| @@ -19893,47 +20225,47 @@ | |
| 19893 | sqlite3_int64 nPage; |
| 19894 | sqlite3_int64 nPageInUse; |
| 19895 | sqlite3_int64 nFreeList; |
| 19896 | sqlite3_int64 nIndex; |
| 19897 | sqlite3_int64 nWORowid; |
| 19898 | Analysis s; |
| 19899 | sqlite3_uint64 r[2]; |
| 19900 | |
| 19901 | (void)argc; |
| 19902 | memset(&s, 0, sizeof(s)); |
| 19903 | s.db = sqlite3_context_db_handle(context); |
| 19904 | s.context = context; |
| 19905 | s.pOut = sqlite3_str_new(0); |
| 19906 | if( sqlite3_str_errcode(s.pOut) ){ |
| 19907 | analysisError(&s, 0); |
| 19908 | return; |
| 19909 | } |
| 19910 | s.zSchema = (const char*)sqlite3_value_text(argv[0]); |
| 19911 | if( s.zSchema==0 ){ |
| 19912 | s.zSchema = "main"; |
| 19913 | }else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){ |
| 19914 | analysisReset(&s); |
| 19915 | sqlite3_result_text(context, "cannot analyze \"temp\"",-1,SQLITE_STATIC); |
| 19916 | return; |
| 19917 | } |
| 19918 | ii = 0; |
| 19919 | rc = analysisSqlInt(&s,&ii,"SELECT 1 FROM pragma_database_list" |
| 19920 | " WHERE name=%Q COLLATE nocase",s.zSchema); |
| 19921 | if( rc || ii==0 ){ |
| 19922 | analysisReset(&s); |
| 19923 | sqlite3_result_text(context,"no such database",-1,SQLITE_STATIC); |
| 19924 | return; |
| 19925 | } |
| 19926 | sqlite3_randomness(sizeof(r), &r); |
| 19927 | s.zSU = sqlite3_mprintf("analysis%016llx%016llx", r[0], r[1]); |
| 19928 | if( s.zSU==0 ){ analysisError(&s, 0); return; } |
| 19929 | |
| 19930 | /* The s.zSU table contains the data used for the analysis. |
| 19931 | ** The table name contains 128-bits of randomness to avoid |
| 19932 | ** collisions with preexisting tables in temp. |
| 19933 | */ |
| 19934 | rc = analysisSql(&s, |
| 19935 | "CREATE TABLE temp.%s(\n" |
| 19936 | " name text, -- A table or index\n" |
| 19937 | " tblname text, -- Table that owns name\n" |
| 19938 | " is_index boolean, -- TRUE if it is an index\n" |
| 19939 | " is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" |
| @@ -19956,11 +20288,11 @@ | |
| 19956 | ); |
| 19957 | if( rc ) return; |
| 19958 | |
| 19959 | /* Populate the s.zSU table |
| 19960 | */ |
| 19961 | rc = analysisSql(&s, |
| 19962 | "WITH\n" |
| 19963 | " allidx(idxname) AS (\n" |
| 19964 | " SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n" |
| 19965 | " ),\n" |
| 19966 | " allobj(allname,tblname,isidx,isworowid) AS (\n" |
| @@ -20008,141 +20340,143 @@ | |
| 20008 | s.zSchema /* JOIN dbstat(%Q) */ |
| 20009 | ); |
| 20010 | if( rc ) return; |
| 20011 | |
| 20012 | nPage = 0; |
| 20013 | rc = analysisSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema); |
| 20014 | if( rc ) return; |
| 20015 | if( nPage<=0 ){ |
| 20016 | /* Very brief reply for an empty database */ |
| 20017 | analysisReset(&s); |
| 20018 | sqlite3_result_text(context, "empty database", -1, SQLITE_STATIC); |
| 20019 | return; |
| 20020 | } |
| 20021 | |
| 20022 | /* Begin generating the report */ |
| 20023 | analysisTitle(&s, "Database storage utilization report"); |
| 20024 | pgsz = 0; |
| 20025 | rc = analysisSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema); |
| 20026 | if( rc ) return; |
| 20027 | analysisLine(&s, "Page size in bytes","%lld\n",pgsz); |
| 20028 | analysisLine(&s, "Pages in the database", "%lld\n", nPage); |
| 20029 | |
| 20030 | nPageInUse = 0; |
| 20031 | rc = analysisSqlInt(&s, &nPageInUse, |
| 20032 | "SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU); |
| 20033 | if( rc ) return; |
| 20034 | analysisLine(&s, "Pages that store data", "%-11lld ", nPageInUse); |
| 20035 | analysisPercent(&s, (nPageInUse*100.0)/(double)nPage); |
| 20036 | |
| 20037 | nFreeList = 0; |
| 20038 | rc = analysisSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema); |
| 20039 | if( rc ) return; |
| 20040 | analysisLine(&s, "Pages on the freelist", "%-11lld ", nFreeList); |
| 20041 | analysisPercent(&s, (nFreeList*100.0)/(double)nPage); |
| 20042 | |
| 20043 | ii = 0; |
| 20044 | rc = analysisSqlInt(&s, &ii, "PRAGMA \"%w\".auto_vacuum", s.zSchema); |
| 20045 | if( rc ) return; |
| 20046 | if( ii==0 || nPage<=1 ){ |
| 20047 | ii = 0; |
| 20048 | }else{ |
| 20049 | double rPtrsPerPage = pgsz/5; |
| 20050 | double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0); |
| 20051 | ii = (sqlite3_int64)ceil(rAvPage); |
| 20052 | } |
| 20053 | analysisLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", ii); |
| 20054 | analysisPercent(&s, (ii*100.0)/(double)nPage); |
| 20055 | |
| 20056 | ii = 0; |
| 20057 | rc = analysisSqlInt(&s, &ii, |
| 20058 | "SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'", |
| 20059 | s.zSchema); |
| 20060 | if( rc ) return; |
| 20061 | analysisLine(&s, "Number of tables", "%lld\n", ii); |
| 20062 | nWORowid = 0; |
| 20063 | rc = analysisSqlInt(&s, &nWORowid, |
| 20064 | "SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr", |
| 20065 | s.zSchema); |
| 20066 | if( rc ) return; |
| 20067 | if( nWORowid>0 ){ |
| 20068 | analysisLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid); |
| 20069 | analysisLine(&s, "Number of rowid tables", "%lld\n", ii - nWORowid); |
| 20070 | } |
| 20071 | nIndex = 0; |
| 20072 | rc = analysisSqlInt(&s, &nIndex, |
| 20073 | "SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'", |
| 20074 | s.zSchema); |
| 20075 | if( rc ) return; |
| 20076 | analysisLine(&s, "Number of indexes", "%lld\n", nIndex); |
| 20077 | ii = 0; |
| 20078 | rc = analysisSqlInt(&s, &ii, |
| 20079 | "SELECT count(*) FROM \"%w\".sqlite_schema" |
| 20080 | " WHERE name GLOB 'sqlite_autoindex_*' AND type='index'", |
| 20081 | s.zSchema); |
| 20082 | if( rc ) return; |
| 20083 | analysisLine(&s, "Number of defined indexes", "%lld\n", nIndex - ii); |
| 20084 | analysisLine(&s, "Number of implied indexes", "%lld\n", ii); |
| 20085 | analysisLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage); |
| 20086 | ii = 0; |
| 20087 | rc = analysisSqlInt(&s, &ii, |
| 20088 | "SELECT sum(payload) FROM temp.%s" |
| 20089 | " WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'", |
| 20090 | s.zSU); |
| 20091 | if( rc ) return; |
| 20092 | analysisLine(&s, "Bytes of payload", "%-11lld ", ii); |
| 20093 | analysisPercent(&s, ii*100.0/(double)(pgsz*nPage)); |
| 20094 | |
| 20095 | analysisTitle(&s, "Page counts for all tables with their indexes"); |
| 20096 | pStmt = analysisPrepare(&s, |
| 20097 | "SELECT upper(tblname),\n" |
| 20098 | " sum(int_pages+leaf_pages+ovfl_pages)\n" |
| 20099 | " FROM temp.%s\n" |
| 20100 | " GROUP BY 1\n" |
| 20101 | " ORDER BY 2 DESC, 1;", |
| 20102 | s.zSU); |
| 20103 | if( pStmt==0 ) return; |
| 20104 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| 20105 | sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); |
| 20106 | analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); |
| 20107 | analysisPercent(&s, (nn*100.0)/(double)nPage); |
| 20108 | } |
| 20109 | if( analysisStmtFinish(&s, rc, pStmt) ) return; |
| 20110 | |
| 20111 | analysisTitle(&s, "Page counts for all tables and indexes separately"); |
| 20112 | pStmt = analysisPrepare(&s, |
| 20113 | "SELECT upper(name),\n" |
| 20114 | " sum(int_pages+leaf_pages+ovfl_pages)\n" |
| 20115 | " FROM temp.%s\n" |
| 20116 | " GROUP BY 1\n" |
| 20117 | " ORDER BY 2 DESC, 1;", |
| 20118 | s.zSU); |
| 20119 | if( pStmt==0 ) return; |
| 20120 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| 20121 | sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); |
| 20122 | analysisLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); |
| 20123 | analysisPercent(&s, (nn*100.0)/(double)nPage); |
| 20124 | } |
| 20125 | if( analysisStmtFinish(&s, rc, pStmt) ) return; |
| 20126 | |
| 20127 | rc = analysisSubreport(&s, "All tables and indexes", "1", pgsz, nPage); |
| 20128 | if( rc ) return; |
| 20129 | rc = analysisSubreport(&s, "All tables", "NOT is_index", pgsz, nPage); |
| 20130 | if( rc ) return; |
| 20131 | if( nWORowid>0 ){ |
| 20132 | rc = analysisSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid", |
| 20133 | pgsz, nPage); |
| 20134 | if( rc ) return; |
| 20135 | rc = analysisSubreport(&s, "All rowid tables", |
| 20136 | "NOT is_without_rowid AND NOT is_index", |
| 20137 | pgsz, nPage); |
| 20138 | if( rc ) return; |
| 20139 | } |
| 20140 | rc = analysisSubreport(&s, "All indexes", "is_index", pgsz, nPage); |
| 20141 | if( rc ) return; |
| 20142 | |
| 20143 | pStmt = analysisPrepare(&s, |
| 20144 | "SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s" |
| 20145 | " GROUP BY 1 ORDER BY 1", |
| 20146 | s.zSU); |
| 20147 | if( pStmt==0 ) return; |
| 20148 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| @@ -20150,37 +20484,37 @@ | |
| 20150 | const char *zName = (const char*)sqlite3_column_text(pStmt, 1); |
| 20151 | int nSubIndex = sqlite3_column_int(pStmt, 2); |
| 20152 | if( nSubIndex==0 ){ |
| 20153 | char *zTitle = sqlite3_mprintf("Table %s", zUpper); |
| 20154 | char *zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20155 | rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20156 | sqlite3_free(zTitle); |
| 20157 | sqlite3_free(zWhere); |
| 20158 | if( rc ) break; |
| 20159 | }else{ |
| 20160 | sqlite3_stmt *pS2; |
| 20161 | char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper); |
| 20162 | char *zWhere = sqlite3_mprintf("tblname=%Q", zName); |
| 20163 | rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20164 | sqlite3_free(zTitle); |
| 20165 | sqlite3_free(zWhere); |
| 20166 | if( rc ) break; |
| 20167 | zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper); |
| 20168 | zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20169 | rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20170 | sqlite3_free(zTitle); |
| 20171 | sqlite3_free(zWhere); |
| 20172 | if( rc ) break; |
| 20173 | if( nSubIndex>1 ){ |
| 20174 | zTitle = sqlite3_mprintf("All indexes of table %s", zUpper); |
| 20175 | zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName); |
| 20176 | rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20177 | sqlite3_free(zTitle); |
| 20178 | sqlite3_free(zWhere); |
| 20179 | if( rc ) break; |
| 20180 | } |
| 20181 | pS2 = analysisPrepare(&s, |
| 20182 | "SELECT name, upper(name) FROM temp.%s" |
| 20183 | " WHERE is_index AND tblname=%Q", |
| 20184 | s.zSU, zName); |
| 20185 | if( pS2==0 ){ |
| 20186 | rc = SQLITE_NOMEM; |
| @@ -20189,25 +20523,25 @@ | |
| 20189 | while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){ |
| 20190 | const char *zU = (const char*)sqlite3_column_text(pS2, 1); |
| 20191 | const char *zN = (const char*)sqlite3_column_text(pS2, 0); |
| 20192 | zTitle = sqlite3_mprintf("Index %s", zU); |
| 20193 | zWhere = sqlite3_mprintf("name=%Q", zN); |
| 20194 | rc = analysisSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20195 | sqlite3_free(zTitle); |
| 20196 | sqlite3_free(zWhere); |
| 20197 | if( rc ) break; |
| 20198 | } |
| 20199 | rc = analysisStmtFinish(&s, rc, pS2); |
| 20200 | if( rc ) break; |
| 20201 | } |
| 20202 | } |
| 20203 | if( analysisStmtFinish(&s, rc, pStmt) ) return; |
| 20204 | |
| 20205 | /* Append SQL statements that will recreate the raw data used for |
| 20206 | ** the analysis. |
| 20207 | */ |
| 20208 | analysisTitle(&s, "Raw data used to generate this report"); |
| 20209 | sqlite3_str_appendf(s.pOut, |
| 20210 | "The following SQL will create a table named \"space_used\" which\n" |
| 20211 | "contains most of the information used to generate the report above.\n" |
| 20212 | "*/\n" |
| 20213 | ); |
| @@ -20233,11 +20567,11 @@ | |
| 20233 | " ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */ |
| 20234 | " int_entries int -- B-tree entries on internal pages\n"/* 17 */ |
| 20235 | ");\n" |
| 20236 | "INSERT INTO space_used VALUES\n" |
| 20237 | ); |
| 20238 | pStmt = analysisPrepare(&s, |
| 20239 | "SELECT quote(name), quote(tblname),\n" /* 0..1 */ |
| 20240 | " is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */ |
| 20241 | " depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */ |
| 20242 | " int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */ |
| 20243 | " leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */ |
| @@ -20268,11 +20602,11 @@ | |
| 20268 | sqlite3_column_int64(pStmt, 15), |
| 20269 | sqlite3_column_int64(pStmt, 16), |
| 20270 | sqlite3_column_int64(pStmt, 17)); |
| 20271 | } |
| 20272 | if( rc!=SQLITE_DONE ){ |
| 20273 | analysisError(&s, "SQL run-time error: %s\nSQL: %s", |
| 20274 | sqlite3_errmsg(s.db), sqlite3_sql(pStmt)); |
| 20275 | sqlite3_finalize(pStmt); |
| 20276 | return; |
| 20277 | } |
| 20278 | sqlite3_str_appendf(s.pOut,";\nCOMMIT;"); |
| @@ -20281,32 +20615,144 @@ | |
| 20281 | if( sqlite3_str_length(s.pOut) ){ |
| 20282 | sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1, |
| 20283 | sqlite3_free); |
| 20284 | s.pOut = 0; |
| 20285 | } |
| 20286 | analysisReset(&s); |
| 20287 | } |
| 20288 | |
| 20289 | |
| 20290 | #ifdef _WIN32 |
| 20291 | |
| 20292 | #endif |
| 20293 | int sqlite3_analyze_init( |
| 20294 | sqlite3 *db, |
| 20295 | char **pzErrMsg, |
| 20296 | const sqlite3_api_routines *pApi |
| 20297 | ){ |
| 20298 | int rc = SQLITE_OK; |
| 20299 | SQLITE_EXTENSION_INIT2(pApi); |
| 20300 | (void)pzErrMsg; /* Unused parameter */ |
| 20301 | rc = sqlite3_create_function(db, "analyze", 1, |
| 20302 | SQLITE_UTF8|SQLITE_INNOCUOUS, |
| 20303 | 0, analyzeFunc, 0, 0); |
| 20304 | return rc; |
| 20305 | } |
| 20306 | |
| 20307 | /************************* End ext/misc/analyze.c ********************/ |
| 20308 | |
| 20309 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 20310 | #define SQLITE_SHELL_HAVE_RECOVER 1 |
| 20311 | #else |
| 20312 | #define SQLITE_SHELL_HAVE_RECOVER 0 |
| @@ -22123,23 +22569,44 @@ | |
| 22123 | int rc = sqlite3_finalize(pStmt); |
| 22124 | if( rc!=SQLITE_OK && p->errCode==SQLITE_OK ){ |
| 22125 | recoverDbError(p, db); |
| 22126 | } |
| 22127 | } |
| 22128 | |
| 22129 | /* |
| 22130 | ** This function is a no-op if recover handle p already contains an error |
| 22131 | ** (if p->errCode!=SQLITE_OK). A copy of p->errCode is returned in this |
| 22132 | ** case. |
| 22133 | ** |
| 22134 | ** Otherwise, execute SQL script zSql. If successful, return SQLITE_OK. |
| 22135 | ** Or, if an error occurs, leave an error code and message in the recover |
| 22136 | ** handle and return a copy of the error code. |
| 22137 | */ |
| 22138 | static int recoverExec(sqlite3_recover *p, sqlite3 *db, const char *zSql){ |
| 22139 | if( p->errCode==SQLITE_OK ){ |
| 22140 | int rc = sqlite3_exec(db, zSql, 0, 0, 0); |
| 22141 | if( rc ){ |
| 22142 | recoverDbError(p, db); |
| 22143 | } |
| 22144 | } |
| 22145 | return p->errCode; |
| @@ -22535,11 +23002,12 @@ | |
| 22535 | recoverError(p, SQLITE_NOMEM, 0); |
| 22536 | } |
| 22537 | } |
| 22538 | recoverFinalize(p, p1); |
| 22539 | } |
| 22540 | recoverExec(p, db2, "CREATE TABLE t1(a); DROP TABLE t1;"); |
| 22541 | |
| 22542 | if( p->errCode==SQLITE_OK ){ |
| 22543 | sqlite3 *db = p->dbOut; |
| 22544 | sqlite3_backup *pBackup = sqlite3_backup_init(db, "main", db2, "main"); |
| 22545 | if( pBackup ){ |
| @@ -22617,16 +23085,16 @@ | |
| 22617 | ** discarded. |
| 22618 | */ |
| 22619 | static void recoverOpenRecovery(sqlite3_recover *p){ |
| 22620 | char *zSql = recoverMPrintf(p, "ATTACH %Q AS recovery;", p->zStateDb); |
| 22621 | recoverExec(p, p->dbOut, zSql); |
| 22622 | recoverExec(p, p->dbOut, |
| 22623 | "PRAGMA writable_schema = 1;" |
| 22624 | "CREATE TABLE recovery.map(pgno INTEGER PRIMARY KEY, parent INT);" |
| 22625 | "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);" |
| 22626 | ); |
| 22627 | sqlite3_free(zSql); |
| 22628 | } |
| 22629 | |
| 22630 | |
| 22631 | /* |
| 22632 | ** This function is a no-op if recover handle p already contains an error |
| @@ -22762,11 +23230,11 @@ | |
| 22762 | " (type='index' AND (sql LIKE '%unique%' OR ?1))" |
| 22763 | " FROM recovery.schema" |
| 22764 | ")" |
| 22765 | "SELECT rootpage, tbl, isVirtual, name, sql" |
| 22766 | " FROM dbschema " |
| 22767 | " WHERE tbl OR isIndex" |
| 22768 | " ORDER BY tbl DESC, name=='sqlite_sequence' DESC" |
| 22769 | ); |
| 22770 | |
| 22771 | pTblname = recoverPrepare(p, p->dbOut, |
| 22772 | "SELECT name FROM sqlite_schema " |
| @@ -22788,11 +23256,11 @@ | |
| 22788 | zSql = (const char*)(zFree = recoverMPrintf(p, |
| 22789 | "INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)", |
| 22790 | zName, zName, zSql |
| 22791 | )); |
| 22792 | } |
| 22793 | rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0); |
| 22794 | if( rc==SQLITE_OK ){ |
| 22795 | recoverSqlCallback(p, zSql); |
| 22796 | if( bTable && !bVirtual ){ |
| 22797 | if( SQLITE_ROW==sqlite3_step(pTblname) ){ |
| 22798 | const char *zTbl = (const char*)sqlite3_column_text(pTblname, 0); |
| @@ -22830,19 +23298,21 @@ | |
| 22830 | |
| 22831 | pSelect = recoverPrepare(p, p->dbOut, |
| 22832 | p->bSlowIndexes ? |
| 22833 | "SELECT rootpage, sql FROM recovery.schema " |
| 22834 | " WHERE type!='table' AND type!='index'" |
| 22835 | : |
| 22836 | "SELECT rootpage, sql FROM recovery.schema " |
| 22837 | " WHERE type!='table' AND (type!='index' OR sql NOT LIKE '%unique%')" |
| 22838 | ); |
| 22839 | |
| 22840 | if( pSelect ){ |
| 22841 | while( sqlite3_step(pSelect)==SQLITE_ROW ){ |
| 22842 | const char *zSql = (const char*)sqlite3_column_text(pSelect, 1); |
| 22843 | int rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0); |
| 22844 | if( rc==SQLITE_OK ){ |
| 22845 | recoverSqlCallback(p, zSql); |
| 22846 | }else if( rc!=SQLITE_ERROR ){ |
| 22847 | recoverDbError(p, p->dbOut); |
| 22848 | } |
| @@ -24216,11 +24686,11 @@ | |
| 24216 | recoverCacheSchema(p); |
| 24217 | |
| 24218 | if( bUseWrapper ) recoverUninstallWrapper(p); |
| 24219 | }while( p->errCode==SQLITE_NOTADB |
| 24220 | && (bUseWrapper--) |
| 24221 | && SQLITE_OK==sqlite3_exec(p->dbIn, "ROLLBACK", 0, 0, 0) |
| 24222 | ); |
| 24223 | } |
| 24224 | |
| 24225 | recoverLeaveMutex(); |
| 24226 | recoverExec(p, p->dbOut, "BEGIN"); |
| @@ -24281,11 +24751,11 @@ | |
| 24281 | |
| 24282 | /* If no error has occurred, commit the write transaction on the output |
| 24283 | ** database. Regardless of whether or not an error has occurred, make |
| 24284 | ** an attempt to end the read transaction on the input database. */ |
| 24285 | recoverExec(p, p->dbOut, "COMMIT"); |
| 24286 | rc = sqlite3_exec(p->dbIn, "END", 0, 0, 0); |
| 24287 | if( p->errCode==SQLITE_OK ) p->errCode = rc; |
| 24288 | |
| 24289 | recoverSqlCallback(p, "PRAGMA writable_schema = off"); |
| 24290 | recoverSqlCallback(p, "COMMIT"); |
| 24291 | p->eState = RECOVER_STATE_DONE; |
| @@ -24477,11 +24947,11 @@ | |
| 24477 | if( p==0 ){ |
| 24478 | rc = SQLITE_NOMEM; |
| 24479 | }else{ |
| 24480 | recoverFinalCleanup(p); |
| 24481 | if( p->bCloseTransaction && sqlite3_get_autocommit(p->dbIn)==0 ){ |
| 24482 | rc = sqlite3_exec(p->dbIn, "END", 0, 0, 0); |
| 24483 | if( p->errCode==SQLITE_OK ) p->errCode = rc; |
| 24484 | } |
| 24485 | rc = p->errCode; |
| 24486 | sqlite3_free(p->zErrMsg); |
| 24487 | sqlite3_free(p->zStateDb); |
| @@ -24499,10 +24969,20 @@ | |
| 24499 | #endif |
| 24500 | #ifdef SQLITE_SHELL_EXTSRC |
| 24501 | # include SHELL_STRINGIFY(SQLITE_SHELL_EXTSRC) |
| 24502 | #endif |
| 24503 | |
| 24504 | #if defined(SQLITE_ENABLE_SESSION) |
| 24505 | /* |
| 24506 | ** State information for a single open session |
| 24507 | */ |
| 24508 | typedef struct OpenSession OpenSession; |
| @@ -24530,10 +25010,12 @@ | |
| 24530 | u8 autoEQPtrace; /* autoEQP is in trace mode */ |
| 24531 | u8 scanstatsOn; /* True to display scan stats before each finalize */ |
| 24532 | u8 bAutoScreenWidth; /* Using the TTY to determine screen width */ |
| 24533 | u8 mFlags; /* MFLG_ECHO, MFLG_CRLF, etc. */ |
| 24534 | u8 eMode; /* One of the MODE_ values */ |
| 24535 | sqlite3_qrf_spec spec; /* Spec to be passed into QRF */ |
| 24536 | } Mode; |
| 24537 | |
| 24538 | /* Flags for Mode.mFlags */ |
| 24539 | #define MFLG_ECHO 0x01 /* Echo inputs to output */ |
| @@ -24564,10 +25046,11 @@ | |
| 24564 | unsigned statsOn; /* True to display memory stats before each finalize */ |
| 24565 | unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */ |
| 24566 | u8 nPopOutput; /* Revert .output settings when reaching zero */ |
| 24567 | u8 nPopMode; /* Revert .mode settings when reaching zero */ |
| 24568 | u8 enableTimer; /* Enable the timer. 2: permanently 1: only once */ |
| 24569 | int inputNesting; /* Track nesting level of .read and other redirects */ |
| 24570 | double prevTimer; /* Last reported timer value */ |
| 24571 | double tmProgress; /* --timeout option for .progress */ |
| 24572 | i64 lineno; /* Line number of last line read from in */ |
| 24573 | const char *zInFile; /* Name of the input file */ |
| @@ -24745,11 +25228,11 @@ | |
| 24745 | unsigned char eHdr; /* Default header encoding. */ |
| 24746 | unsigned char eBlob; /* Default blob encoding. */ |
| 24747 | unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */ |
| 24748 | unsigned char eStyle; /* Underlying QRF style */ |
| 24749 | unsigned char eCx; /* 0: other, 1: line, 2: columnar */ |
| 24750 | unsigned char mFlg; /* Flags. 1=border-off 2=split-column */ |
| 24751 | }; |
| 24752 | |
| 24753 | /* String constants used by built-in modes */ |
| 24754 | static const char *aModeStr[] = |
| 24755 | /* 0 1 2 3 4 5 6 7 8 */ |
| @@ -24758,45 +25241,45 @@ | |
| 24758 | /* 9 10 11 12 13 */ |
| 24759 | |
| 24760 | static const ModeInfo aModeInfo[] = { |
| 24761 | /* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */ |
| 24762 | { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 }, |
| 24763 | { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2, 0 }, |
| 24764 | { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 }, |
| 24765 | { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2, 0 }, |
| 24766 | { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, |
| 24767 | { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 }, |
| 24768 | { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 }, |
| 24769 | { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 }, |
| 24770 | { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 }, |
| 24771 | { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 }, |
| 24772 | { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 }, |
| 24773 | { "line", 13, 1, 9, 1, 1, 0, 0, 11, 1, 0 }, |
| 24774 | { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 }, |
| 24775 | { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2, 0 }, |
| 24776 | { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 }, |
| 24777 | { "psql", 0, 0, 9, 1, 1, 0, 2, 19, 2, 1 }, |
| 24778 | { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2, 0 }, |
| 24779 | { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 }, |
| 24780 | { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 }, |
| 24781 | { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2, 0 }, |
| 24782 | { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 }, |
| 24783 | { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 }, |
| 24784 | { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 } |
| 24785 | }; /* | / / | / / | | \ |
| 24786 | ** | / / | / / | | \_ 2: columnar |
| 24787 | ** Index into aModeStr[] | / / | | 1: line |
| 24788 | ** | / / | | 0: other |
| 24789 | ** | / / | \ |
| 24790 | ** text encoding |/ | show | \ |
| 24791 | ** v-------------------' | hdrs? | The QRF style |
| 24792 | ** 0: n/a blob | v-----' |
| 24793 | ** 1: plain v----------' 0: n/a |
| 24794 | ** 2: sql 0: auto 1: no |
| 24795 | ** 3: csv 1: as-text 2: yes |
| 24796 | ** 4: html 2: sql |
| 24797 | ** 5: c 3: hex |
| 24798 | ** 6: json 4: c |
| 24799 | ** 5: json |
| 24800 | ** 6: size |
| 24801 | ******************************************************************/ |
| 24802 | |
| @@ -25079,11 +25562,11 @@ | |
| 25079 | */ |
| 25080 | static char *local_getline(char *zLine, FILE *in){ |
| 25081 | int nLine = zLine==0 ? 0 : 100; |
| 25082 | int n = 0; |
| 25083 | |
| 25084 | while( 1 ){ |
| 25085 | if( n+100>nLine ){ |
| 25086 | if( nLine>=1073741773 ){ |
| 25087 | free(zLine); |
| 25088 | return 0; |
| 25089 | } |
| @@ -25107,10 +25590,22 @@ | |
| 25107 | break; |
| 25108 | } |
| 25109 | } |
| 25110 | return zLine; |
| 25111 | } |
| 25112 | |
| 25113 | /* |
| 25114 | ** The SQLITE_PS_APPDEF macro should be set to the name of a function |
| 25115 | ** that accepts a single "int" argument and returns a "const char *" |
| 25116 | ** that is guaranteed to be non-NULL. The value returned depends on the |
| @@ -25131,35 +25626,47 @@ | |
| 25131 | # define SQLITE_PS_APPDEF shellPromptAppDef |
| 25132 | static const char *shellPromptAppDef(int c){ |
| 25133 | switch( c ){ |
| 25134 | /* The default main prompt string */ |
| 25135 | case 1: |
| 25136 | #if defined(SQLITE_PS1) |
| 25137 | return SQLITE_PS1; |
| 25138 | #elif defined(SQLITE_PS_NOANSI) |
| 25139 | return "/A-/v /~> "; |
| 25140 | #else |
| 25141 | return "/e[1;32m/A-/v /e[1;/x33/:36/;m/m/e[3m/;/f/;/e[0m-> "; |
| 25142 | #endif |
| 25143 | |
| 25144 | /* The default continuation prompt string */ |
| 25145 | case 2: |
| 25146 | #if defined(SQLITE_PS2) |
| 25147 | return SQLITE_PS2; |
| 25148 | #elif defined(SQLITE_PS_NOANSI) |
| 25149 | return "/B/C> "; |
| 25150 | #else |
| 25151 | return "/B/e[1;/x33/:36/;m/C/e[0m-> "; |
| 25152 | #endif |
| 25153 | |
| 25154 | /* Name of environment variables that override the prompt strings |
| 25155 | ** of cases 1 and 2 */ |
| 25156 | case 3: return "SQLITE_PS1"; |
| 25157 | case 4: return "SQLITE_PS2"; |
| 25158 | |
| 25159 | /* Name of the application */ |
| 25160 | case 'A': return "SQLite"; |
| 25161 | |
| 25162 | /* Full version number of the application, including patch level */ |
| 25163 | case 'V': return sqlite3_libversion(); |
| 25164 | |
| 25165 | /* Version number without the patch level */ |
| @@ -25218,13 +25725,13 @@ | |
| 25218 | }else if( p->db && (pFN = sqlite3_db_filename(p->db,0))!=0 ){ |
| 25219 | zFN = sqlite3_filename_database(pFN); |
| 25220 | } |
| 25221 | if( zFN==0 || zFN[0]==0 ){ |
| 25222 | zFN = p->pAuxDb->zDbFilename; |
| 25223 | if( zFN==0 || zFN[0]==0 || cli_strcmp(zFN,":memory:")==0 ){ |
| 25224 | zFN = zMemoryName; |
| 25225 | } |
| 25226 | } |
| 25227 | return zFN; |
| 25228 | } |
| 25229 | |
| 25230 | /* |
| @@ -25263,10 +25770,26 @@ | |
| 25263 | if( z==0 || z[0]==0 ) z = getenv("LOGNAME"); |
| 25264 | if( z==0 || z[0]==0 ) z = "?"; |
| 25265 | #endif |
| 25266 | return z; |
| 25267 | } |
| 25268 | |
| 25269 | /* |
| 25270 | ** Expand escapes in the given input prompt string. Return the |
| 25271 | ** expanded prompt in memory obtained from sqlite3_malloc(). The |
| 25272 | ** caller is responsible for freeing the memory. |
| @@ -25311,10 +25834,11 @@ | |
| 25311 | continue; |
| 25312 | } |
| 25313 | if( c>='0' && c<='7' ){ |
| 25314 | /* /nnn becomes a single byte given by octal nnn */ |
| 25315 | int v = c - '0'; |
| 25316 | while( i<=2 && zPrompt[i+1]>='0' && zPrompt[i+1]<='7' ){ |
| 25317 | v = v*8 + zPrompt[++i] - '0'; |
| 25318 | } |
| 25319 | if( !mOff ) sqlite3_str_appendchar(pOut, 1, v); |
| 25320 | zPrompt += i+1; |
| @@ -25533,15 +26057,36 @@ | |
| 25533 | memmove(z+idxSpace+nNew, z+idxSpace, len-nNew-idxSpace); |
| 25534 | memset(z+idxSpace, ' ', nNew); |
| 25535 | } |
| 25536 | } |
| 25537 | } |
| 25538 | |
| 25539 | if( 0==sqlite3_str_length(pOut) ){ |
| 25540 | /* Avoid a bogus OOM */ |
| 25541 | sqlite3_str_appendchar(pOut, 1, '\0'); |
| 25542 | } |
| 25543 | return sqlite3_str_finish(pOut); |
| 25544 | } |
| 25545 | |
| 25546 | /* |
| 25547 | ** Retrieve a single line of input text. |
| @@ -25570,30 +26115,33 @@ | |
| 25570 | zResult = local_getline(zPrior, in); |
| 25571 | }else{ |
| 25572 | const char *zBase = prompt_string(p, bContinue!=0); |
| 25573 | char *zPrompt = expand_prompt(p, zAll, zBase); |
| 25574 | shell_check_oom(zPrompt); |
| 25575 | #if SHELL_USE_LOCAL_GETLINE |
| 25576 | sputz(stdout, zPrompt); |
| 25577 | fflush(stdout); |
| 25578 | do{ |
| 25579 | zResult = local_getline(zPrior, stdin); |
| 25580 | zPrior = 0; |
| 25581 | /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ |
| 25582 | if( zResult==0 ) sqlite3_sleep(50); |
| 25583 | }while( zResult==0 && seenInterrupt>0 ); |
| 25584 | #else |
| 25585 | free(zPrior); |
| 25586 | zResult = shell_readline(zPrompt); |
| 25587 | while( zResult==0 ){ |
| 25588 | /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ |
| 25589 | sqlite3_sleep(50); |
| 25590 | if( seenInterrupt==0 ) break; |
| 25591 | zResult = shell_readline(""); |
| 25592 | } |
| 25593 | if( zResult && *zResult ) shell_add_history(zResult); |
| 25594 | #endif |
| 25595 | sqlite3_free(zPrompt); |
| 25596 | } |
| 25597 | return zResult; |
| 25598 | } |
| 25599 | #endif /* !SQLITE_SHELL_FIDDLE */ |
| @@ -25834,11 +26382,12 @@ | |
| 25834 | double r = sqlite3_value_double(apVal[0]); |
| 25835 | int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26; |
| 25836 | char z[400]; |
| 25837 | if( n<1 ) n = 1; |
| 25838 | if( n>350 ) n = 350; |
| 25839 | sprintf(z, "%#+.*e", n, r); |
| 25840 | sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); |
| 25841 | } |
| 25842 | |
| 25843 | /* |
| 25844 | ** SQL function: shell_add_schema(S,X) |
| @@ -25912,21 +26461,27 @@ | |
| 25912 | } |
| 25913 | sqlite3_result_value(pCtx, apVal[0]); |
| 25914 | } |
| 25915 | |
| 25916 | /* |
| 25917 | ** SQL function: shell_prompt_test(PROMPT) |
| 25918 | ** shell_prompt_test(PROMPT,PRIOR) |
| 25919 | ** shell_prompt_test(PROMPT,PRIOR,FILENAME) |
| 25920 | ** |
| 25921 | ** Return the shell prompt, with escapes expanded, for testing purposes. |
| 25922 | ** The first argument is the raw (unexpanded) prompt string. Or if the |
| 25923 | ** first argument is NULL, then use whatever prompt string is currently |
| 25924 | ** configured. If the second argument exists and is not NULL, then the |
| 25925 | ** second argument is understood to be prior incomplete text and a |
| 25926 | ** continuation prompt is generated. If a third argument is provided, |
| 25927 | ** it is assumed to be the full pathname of the database file. |
| 25928 | */ |
| 25929 | static void shellExpandPrompt( |
| 25930 | sqlite3_context *pCtx, |
| 25931 | int nVal, |
| 25932 | sqlite3_value **apVal |
| @@ -25936,11 +26491,14 @@ | |
| 25936 | const char *zPrior; |
| 25937 | const char *zSavedDbFile; |
| 25938 | int mSavedFlgs; |
| 25939 | const char *zFName; |
| 25940 | char *zRes; |
| 25941 | |
| 25942 | if( nVal<2 |
| 25943 | || (zPrior = (const char*)sqlite3_value_text(apVal[1]))==0 |
| 25944 | || zPrior[0]==0 |
| 25945 | ){ |
| 25946 | zPrior = 0; |
| @@ -25952,12 +26510,19 @@ | |
| 25952 | zSavedDbFile = p->pAuxDb->zDbFilename; |
| 25953 | mSavedFlgs = p->pAuxDb->mFlgs; |
| 25954 | if( nVal>=3 && (zFName = (const char*)sqlite3_value_text(apVal[2]))!=0 ){ |
| 25955 | p->pAuxDb->zDbFilename = zFName; |
| 25956 | p->pAuxDb->mFlgs |= 0x001; |
| 25957 | } |
| 25958 | zRes = expand_prompt(p, zPrior, zPrompt); |
| 25959 | p->pAuxDb->zDbFilename = zSavedDbFile; |
| 25960 | p->pAuxDb->mFlgs = mSavedFlgs; |
| 25961 | sqlite3_result_text(pCtx, zRes, -1, SQLITE_TRANSIENT); |
| 25962 | sqlite3_free(zRes); |
| 25963 | } |
| @@ -26150,11 +26715,11 @@ | |
| 26150 | free(p->spec.zColumnSep); |
| 26151 | free(p->spec.zRowSep); |
| 26152 | free(p->spec.zTableName); |
| 26153 | free(p->spec.zNull); |
| 26154 | memset(p, 0, sizeof(*p)); |
| 26155 | p->spec.iVersion = 1; |
| 26156 | p->autoExplain = autoExplain; |
| 26157 | } |
| 26158 | |
| 26159 | /* |
| 26160 | ** Duplicate Mode pSrc into pDest. pDest is assumed to be |
| @@ -26190,10 +26755,18 @@ | |
| 26190 | pDest->spec.zTableName = strdup(pSrc->spec.zTableName); |
| 26191 | } |
| 26192 | if( pDest->spec.zNull ){ |
| 26193 | pDest->spec.zNull = strdup(pSrc->spec.zNull); |
| 26194 | } |
| 26195 | } |
| 26196 | |
| 26197 | /* |
| 26198 | ** Set a string value to a copy of the zNew string in memory |
| 26199 | ** obtained from system malloc(). |
| @@ -26208,10 +26781,47 @@ | |
| 26208 | if( *az ){ |
| 26209 | memcpy(*az, zNew, n+1 ); |
| 26210 | } |
| 26211 | } |
| 26212 | } |
| 26213 | |
| 26214 | /* |
| 26215 | ** Change the mode to eMode |
| 26216 | */ |
| 26217 | static void modeChange(ShellState *p, unsigned char eMode){ |
| @@ -26238,17 +26848,23 @@ | |
| 26238 | pM->spec.bSplitColumn = QRF_Yes; |
| 26239 | pM->bAutoScreenWidth = 1; |
| 26240 | }else{ |
| 26241 | pM->spec.bSplitColumn = QRF_No; |
| 26242 | } |
| 26243 | }else if( eMode>=MODE_USER && eMode-MODE_USER<p->nSavedModes ){ |
| 26244 | modeFree(&p->mode); |
| 26245 | modeDup(&p->mode, &p->aSavedModes[eMode-MODE_USER].mode); |
| 26246 | }else if( eMode==MODE_BATCH ){ |
| 26247 | u8 mFlags = p->mode.mFlags; |
| 26248 | modeFree(&p->mode); |
| 26249 | modeChange(p, MODE_List); |
| 26250 | p->mode.mFlags = mFlags; |
| 26251 | }else if( eMode==MODE_TTY ){ |
| 26252 | u8 mFlags = p->mode.mFlags; |
| 26253 | modeFree(&p->mode); |
| 26254 | modeChange(p, MODE_QBox); |
| @@ -26266,13 +26882,15 @@ | |
| 26266 | /* |
| 26267 | ** Set the mode to the default. It assumed that the mode has |
| 26268 | ** already been freed and zeroed prior to calling this routine. |
| 26269 | */ |
| 26270 | static void modeDefault(ShellState *p){ |
| 26271 | p->mode.spec.iVersion = 1; |
| 26272 | p->mode.autoExplain = 1; |
| 26273 | if( stdin_is_interactive || stdout_is_console ){ |
| 26274 | modeChange(p, MODE_TTY); |
| 26275 | }else{ |
| 26276 | modeChange(p, MODE_BATCH); |
| 26277 | } |
| 26278 | } |
| @@ -26881,11 +27499,11 @@ | |
| 26881 | return SQLITE_OK; |
| 26882 | } |
| 26883 | #endif |
| 26884 | |
| 26885 | /* |
| 26886 | ** Print a schema statement. This is helper routine to dump_callbac(). |
| 26887 | ** |
| 26888 | ** This routine converts some CREATE TABLE statements for shadow tables |
| 26889 | ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements. |
| 26890 | ** |
| 26891 | ** If the schema statement in z[] contains a start-of-comment and if |
| @@ -28333,12 +28951,12 @@ | |
| 28333 | ".databases List names and files of attached databases", |
| 28334 | ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", |
| 28335 | #if SQLITE_SHELL_HAVE_RECOVER |
| 28336 | ".dbinfo ?DB? Show status information about the database", |
| 28337 | #endif |
| 28338 | ".dbstat ?SCHEMA? Report database space and size stats", |
| 28339 | ".dbtotxt Hex dump of the database file", |
| 28340 | ".dump ?OBJECTS? Render database content as SQL", |
| 28341 | " Options:", |
| 28342 | " --data-only Output only INSERT statements", |
| 28343 | " --newlines Allow unescaped newline characters in output", |
| 28344 | " --nosys Omit system tables (ex: \"sqlite_stat1\")", |
| @@ -28445,10 +29063,13 @@ | |
| 28445 | " --reset Reset the count for each input and interrupt", |
| 28446 | " --timeout S Halt after running for S seconds", |
| 28447 | #endif |
| 28448 | ".prompt MAIN CONTINUE Replace the standard prompts", |
| 28449 | " --hard-reset Unset SQLITE_PS1/2 and then --reset", |
| 28450 | " --reset Revert to default prompts", |
| 28451 | " --show Show the current prompt strings", |
| 28452 | " -- No more options. Subsequent args are prompts", |
| 28453 | #ifndef SQLITE_SHELL_FIDDLE |
| 28454 | ".quit Stop interpreting input stream, exit if primary.", |
| @@ -28609,10 +29230,14 @@ | |
| 28609 | " truncated. Zero means \"no limit\".\n" |
| 28610 | " --colsep STRING Use STRING as the column separator\n" |
| 28611 | " --escape ESC Enable/disable escaping of control characters\n" |
| 28612 | " found in the output. ESC can be \"off\", \"ascii\",\n" |
| 28613 | " or \"symbol\".\n" |
| 28614 | " --linelimit N Set the maximum number of output lines to show for\n" |
| 28615 | " any single SQL value to N. Longer values are\n" |
| 28616 | " truncated. Zero means \"no limit\". Only works\n" |
| 28617 | " in \"line\" mode and in columnar modes.\n" |
| 28618 | " --limits L,C,T Shorthand for \"--linelimit L --charlimit C\n" |
| @@ -28629,10 +29254,11 @@ | |
| 28629 | " --quote ARG Enable/disable quoting of text. ARG can be\n" |
| 28630 | " \"off\", \"on\", \"sql\", \"relaxed\", \"csv\", \"html\",\n" |
| 28631 | " \"tcl\", or \"json\". \"off\" means show the text as-is.\n" |
| 28632 | " \"on\" is an alias for \"sql\".\n" |
| 28633 | " --reset Changes all mode settings back to their default.\n" |
| 28634 | " --rowsep STRING Use STRING as the row separator\n" |
| 28635 | " --sw|--screenwidth N Declare the screen width of the output device\n" |
| 28636 | " to be N characters. An attempt may be made to\n" |
| 28637 | " wrap output text to fit within this limit. Zero\n" |
| 28638 | " means \"no limit\". Or N can be \"auto\" to set the\n" |
| @@ -28640,11 +29266,11 @@ | |
| 28640 | " --tablename NAME Set the name of the table for \"insert\" mode.\n" |
| 28641 | " --tag NAME Save mode to the left as NAME.\n" |
| 28642 | " --textjsonb BOOLEAN If enabled, JSONB text is displayed as text JSON.\n" |
| 28643 | " --title ARG Whether or not to show column headers, and if so\n" |
| 28644 | " how to encode them. ARG can be \"off\", \"on\",\n" |
| 28645 | " \"sql\", \"csv\", \"html\", \"tcl\", or \"json\".\n" |
| 28646 | " --titlelimit N Limit the length of column titles to N characters.\n" |
| 28647 | " -v|--verbose Verbose output\n" |
| 28648 | " --widths LIST Set the columns widths for columnar modes. The\n" |
| 28649 | " argument is a list of integers, one for each\n" |
| 28650 | " column. A \"0\" width means use a dynamic width\n" |
| @@ -29345,11 +29971,12 @@ | |
| 29345 | sqlite3_base64_init(p->db, 0, 0); |
| 29346 | sqlite3_base85_init(p->db, 0, 0); |
| 29347 | sqlite3_regexp_init(p->db, 0, 0); |
| 29348 | sqlite3_ieee_init(p->db, 0, 0); |
| 29349 | sqlite3_series_init(p->db, 0, 0); |
| 29350 | sqlite3_analyze_init(p->db, 0, 0); |
| 29351 | #ifndef SQLITE_SHELL_FIDDLE |
| 29352 | sqlite3_fileio_init(p->db, 0, 0); |
| 29353 | sqlite3_completion_init(p->db, 0, 0); |
| 29354 | #endif |
| 29355 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -29406,15 +30033,11 @@ | |
| 29406 | sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0, |
| 29407 | editFunc, 0, 0); |
| 29408 | sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0, |
| 29409 | editFunc, 0, 0); |
| 29410 | #endif |
| 29411 | sqlite3_create_function(p->db, "shell_prompt_test", 1, SQLITE_UTF8, |
| 29412 | p, shellExpandPrompt, 0, 0); |
| 29413 | sqlite3_create_function(p->db, "shell_prompt_test", 2, SQLITE_UTF8, |
| 29414 | p, shellExpandPrompt, 0, 0); |
| 29415 | sqlite3_create_function(p->db, "shell_prompt_test", 3, SQLITE_UTF8, |
| 29416 | p, shellExpandPrompt, 0, 0); |
| 29417 | sqlite3_create_function(p->db, "shell_temp_filename", 1, SQLITE_UTF8, |
| 29418 | p, shellTempFilenameFunc, 0, 0); |
| 29419 | |
| 29420 | |
| @@ -31155,11 +31778,11 @@ | |
| 31155 | typedef struct ArCommand ArCommand; |
| 31156 | struct ArCommand { |
| 31157 | u8 eCmd; /* An AR_CMD_* value */ |
| 31158 | u8 bVerbose; /* True if --verbose */ |
| 31159 | u8 bZip; /* True if the archive is a ZIP */ |
| 31160 | u8 bDryRun; /* True if --dry-run */ |
| 31161 | u8 bAppend; /* True if --append */ |
| 31162 | u8 bGlob; /* True if --glob */ |
| 31163 | u8 fromCmdLine; /* Run from -A instead of .archive */ |
| 31164 | int nArg; /* Number of command arguments */ |
| 31165 | char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ |
| @@ -31217,10 +31840,11 @@ | |
| 31217 | #define AR_SWITCH_FILE 9 |
| 31218 | #define AR_SWITCH_DIRECTORY 10 |
| 31219 | #define AR_SWITCH_APPEND 11 |
| 31220 | #define AR_SWITCH_DRYRUN 12 |
| 31221 | #define AR_SWITCH_GLOB 13 |
| 31222 | |
| 31223 | static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ |
| 31224 | switch( eSwitch ){ |
| 31225 | case AR_CMD_CREATE: |
| 31226 | case AR_CMD_EXTRACT: |
| @@ -31234,11 +31858,14 @@ | |
| 31234 | } |
| 31235 | pAr->eCmd = eSwitch; |
| 31236 | break; |
| 31237 | |
| 31238 | case AR_SWITCH_DRYRUN: |
| 31239 | pAr->bDryRun = 1; |
| 31240 | break; |
| 31241 | case AR_SWITCH_GLOB: |
| 31242 | pAr->bGlob = 1; |
| 31243 | break; |
| 31244 | case AR_SWITCH_VERBOSE: |
| @@ -31285,10 +31912,11 @@ | |
| 31285 | { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, |
| 31286 | { "file", 'f', AR_SWITCH_FILE, 1 }, |
| 31287 | { "append", 'a', AR_SWITCH_APPEND, 1 }, |
| 31288 | { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, |
| 31289 | { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, |
| 31290 | { "glob", 'g', AR_SWITCH_GLOB, 0 }, |
| 31291 | }; |
| 31292 | int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); |
| 31293 | struct ArSwitch *pEnd = &aSwitch[nSwitch]; |
| 31294 | |
| @@ -31585,18 +32213,41 @@ | |
| 31585 | |
| 31586 | /* |
| 31587 | ** Implementation of .ar "eXtract" command. |
| 31588 | */ |
| 31589 | static int arExtractCommand(ArCommand *pAr){ |
| 31590 | const char *zSql1 = |
| 31591 | "WITH dest(dpath,dlen) AS (SELECT realpath($dir),length(realpath($dir)))\n" |
| 31592 | "SELECT ($dir || name),\n" |
| 31593 | " CASE WHEN $dryrun THEN 0\n" |
| 31594 | " ELSE writefile($dir||name, %s, mode, mtime) END\n" |
| 31595 | " FROM dest CROSS JOIN %s\n" |
| 31596 | " WHERE (%s)\n" |
| 31597 | " AND (data IS NULL OR $pass==0)\n" /* Dirs both passes */ |
| 31598 | " AND dpath=substr(realpath($dir||name),1,dlen)\n" /* No escapes */ |
| 31599 | " AND name NOT GLOB '*..[/\\]*'\n"; /* No /../ in paths */ |
| 31600 | |
| 31601 | const char *azExtraArg[] = { |
| 31602 | "sqlar_uncompress(data, sz)", |
| @@ -31623,39 +32274,48 @@ | |
| 31623 | } |
| 31624 | if( zDir==0 ) rc = SQLITE_NOMEM; |
| 31625 | } |
| 31626 | |
| 31627 | shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, |
| 31628 | azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere |
| 31629 | ); |
| 31630 | |
| 31631 | if( rc==SQLITE_OK ){ |
| 31632 | j = sqlite3_bind_parameter_index(pSql, "$dir"); |
| 31633 | sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); |
| 31634 | j = sqlite3_bind_parameter_index(pSql, "$dryrun"); |
| 31635 | sqlite3_bind_int(pSql, j, pAr->bDryRun); |
| 31636 | |
| 31637 | /* Run the SELECT statement twice |
| 31638 | ** (0) writefile() all files and directories |
| 31639 | ** (1) writefile() for directory again |
| 31640 | ** The second pass is so that the timestamps for extracted directories |
| 31641 | ** will be reset to the value in the archive, since populating them |
| 31642 | ** in the first pass will have changed the timestamp. */ |
| 31643 | for(i=0; i<2; i++){ |
| 31644 | j = sqlite3_bind_parameter_index(pSql, "$pass"); |
| 31645 | sqlite3_bind_int(pSql, j, i); |
| 31646 | if( pAr->bDryRun ){ |
| 31647 | cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql)); |
| 31648 | if( pAr->bVerbose==0 ) break; |
| 31649 | } |
| 31650 | while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 31651 | if( i==0 && pAr->bVerbose ){ |
| 31652 | cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 31653 | } |
| 31654 | } |
| 31655 | if( pAr->bDryRun ) break; |
| 31656 | shellReset(&rc, pSql); |
| 31657 | } |
| 31658 | shellFinalize(&rc, pSql); |
| 31659 | } |
| 31660 | |
| 31661 | sqlite3_free(zDir); |
| @@ -32166,11 +32826,11 @@ | |
| 32166 | ; |
| 32167 | static const char * const zCollectVar = "\ |
| 32168 | SELECT\ |
| 32169 | '('||x'0a'\ |
| 32170 | || group_concat(\ |
| 32171 | cname||' ANY',\ |
| 32172 | ','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\ |
| 32173 | ||')' AS ColsSpec \ |
| 32174 | FROM (\ |
| 32175 | SELECT cpos, printf('\"%w\"',printf('%!.*s%s', nlen-chop,name,suff)) AS cname \ |
| 32176 | FROM ColNames ORDER BY cpos\ |
| @@ -32767,14 +33427,16 @@ | |
| 32767 | /* |
| 32768 | ** This function computes what to show the user about the configured |
| 32769 | ** titles (or column-names). Output is an integer between 0 and 3: |
| 32770 | ** |
| 32771 | ** 0: The titles do not matter. Never show anything. |
| 32772 | ** 1: Show "--titles off" |
| 32773 | ** 2: Show "--titles on" |
| 32774 | ** 3: Show "--title VALUE" where VALUE is an encoding method |
| 32775 | ** to use, one of: plain sql csv html tcl json |
| 32776 | ** |
| 32777 | ** Inputs are: |
| 32778 | ** |
| 32779 | ** spec.bTitles (bT) Whether or not to show the titles |
| 32780 | ** spec.eTitle (eT) The actual encoding to be used for titles |
| @@ -32807,11 +33469,27 @@ | |
| 32807 | if( eT!=eH ) v >>= 32; /* Encoding disagree in upper 4-bytes */ |
| 32808 | if( bT!=bH ) v >>= 16; /* ON/OFF disagree in upper 2-byte pairs */ |
| 32809 | if( bT<2 ) v >>= 8; /* ON in even bytes, OFF in odd bytes (1st byte 0) */ |
| 32810 | if( !bAll ) v >>= 4; /* bAll values are in the lower half-byte */ |
| 32811 | |
| 32812 | return v & 3; /* Return the selected truth-table entry */ |
| 32813 | } |
| 32814 | |
| 32815 | /* |
| 32816 | ** DOT-COMMAND: .mode |
| 32817 | ** |
| @@ -32835,10 +33513,14 @@ | |
| 32835 | ** truncated. Zero means "no limit". |
| 32836 | ** --colsep STRING Use STRING as the column separator |
| 32837 | ** --escape ESC Enable/disable escaping of control characters |
| 32838 | ** found in the output. ESC can be "off", "ascii", |
| 32839 | ** or "symbol". |
| 32840 | ** --linelimit N Set the maximum number of output lines to show for |
| 32841 | ** any single SQL value to N. Longer values are |
| 32842 | ** truncated. Zero means "no limit". Only works |
| 32843 | ** in "line" mode and in columnar modes. |
| 32844 | ** --limits L,C,T Shorthand for "--linelimit L --charlimit C |
| @@ -32855,10 +33537,11 @@ | |
| 32855 | ** --quote ARG Enable/disable quoting of text. ARG can be |
| 32856 | ** "off", "on", "sql", "relaxed", "csv", "html", |
| 32857 | ** "tcl", or "json". "off" means show the text as-is. |
| 32858 | ** "on" is an alias for "sql". |
| 32859 | ** --reset Changes all mode settings back to their default. |
| 32860 | ** --rowsep STRING Use STRING as the row separator |
| 32861 | ** --sw|--screenwidth N Declare the screen width of the output device |
| 32862 | ** to be N characters. An attempt may be made to |
| 32863 | ** wrap output text to fit within this limit. Zero |
| 32864 | ** means "no limit". Or N can be "auto" to set the |
| @@ -32866,11 +33549,11 @@ | |
| 32866 | ** --tablename NAME Set the name of the table for "insert" mode. |
| 32867 | ** --tag NAME Save mode to the left as NAME. |
| 32868 | ** --textjsonb BOOLEAN If enabled, JSONB text is displayed as text JSON. |
| 32869 | ** --title ARG Whether or not to show column headers, and if so |
| 32870 | ** how to encode them. ARG can be "off", "on", |
| 32871 | ** "sql", "csv", "html", "tcl", or "json". |
| 32872 | ** --titlelimit N Limit the length of column titles to N characters. |
| 32873 | ** -v|--verbose Verbose output |
| 32874 | ** --widths LIST Set the columns widths for columnar modes. The |
| 32875 | ** argument is a list of integers, one for each |
| 32876 | ** column. A "0" width means use a dynamic width |
| @@ -33011,30 +33694,14 @@ | |
| 33011 | }else if( optionMatch(z,"limits") ){ |
| 33012 | if( (++i)>=nArg ){ |
| 33013 | dotCmdError(p, i-1, "missing argument", 0); |
| 33014 | return 1; |
| 33015 | } |
| 33016 | k = pickStr(azArg[i],0,"on","off",""); |
| 33017 | if( k==0 ){ |
| 33018 | p->mode.spec.nLineLimit = DFLT_LINE_LIMIT; |
| 33019 | p->mode.spec.nCharLimit = DFLT_CHAR_LIMIT; |
| 33020 | p->mode.spec.nTitleLimit = DFLT_TITLE_LIMIT; |
| 33021 | }else if( k==1 ){ |
| 33022 | p->mode.spec.nLineLimit = 0; |
| 33023 | p->mode.spec.nCharLimit = 0; |
| 33024 | p->mode.spec.nTitleLimit = 0; |
| 33025 | }else{ |
| 33026 | int L, C, T = 0; |
| 33027 | int nNum = sscanf(azArg[i], "%d,%d,%d", &L, &C, &T); |
| 33028 | if( nNum<2 || L<0 || C<0 || T<0){ |
| 33029 | dotCmdError(p, i, "bad argument", "Should be \"L,C,T\" where L, C" |
| 33030 | " and T are unsigned integers"); |
| 33031 | return 1; |
| 33032 | } |
| 33033 | p->mode.spec.nLineLimit = L; |
| 33034 | p->mode.spec.nCharLimit = C; |
| 33035 | if( nNum==3 ) p->mode.spec.nTitleLimit = T; |
| 33036 | } |
| 33037 | chng = 1; |
| 33038 | }else if( optionMatch(z,"list") ){ |
| 33039 | int ii; |
| 33040 | cli_puts("available modes:", p->out); |
| @@ -33105,15 +33772,56 @@ | |
| 33105 | break; |
| 33106 | default: /* off */ |
| 33107 | p->mode.spec.eText = QRF_TEXT_Plain; |
| 33108 | break; |
| 33109 | } |
| 33110 | chng = 1; |
| 33111 | }else if( optionMatch(z,"reset") ){ |
| 33112 | int saved_eMode = p->mode.eMode; |
| 33113 | modeFree(&p->mode); |
| 33114 | modeChange(p, saved_eMode); |
| 33115 | }else if( optionMatch(z,"screenwidth") || optionMatch(z,"sw") ){ |
| 33116 | if( (++i)>=nArg ){ |
| 33117 | dotCmdError(p, i-1, "missing argument", 0); |
| 33118 | return 1; |
| 33119 | } |
| @@ -33163,25 +33871,63 @@ | |
| 33163 | return 1; |
| 33164 | } |
| 33165 | p->mode.spec.bTextJsonb = booleanValue(azArg[++i]) ? QRF_Yes : QRF_No; |
| 33166 | chng = 1; |
| 33167 | }else if( optionMatch(z,"titles") || optionMatch(z,"title") ){ |
| 33168 | char *zErr = 0; |
| 33169 | if( i+1>=nArg ){ |
| 33170 | dotCmdError(p, i, "missing argument", 0); |
| 33171 | return 1; |
| 33172 | } |
| 33173 | k = pickStr(azArg[++i],&zErr, |
| 33174 | "off","on","plain","sql","csv","html","tcl","json",""); |
| 33175 | /* 0 1 2 3 4 5 6 7 */ |
| 33176 | if( k<0 ){ |
| 33177 | dotCmdError(p, i, "bad --titles value","%z", zErr); |
| 33178 | return 1; |
| 33179 | } |
| 33180 | p->mode.spec.bTitles = k>=1 ? QRF_Yes : QRF_No; |
| 33181 | p->mode.mFlags &= ~MFLG_HDR; |
| 33182 | p->mode.spec.eTitle = k>1 ? k-1 : aModeInfo[p->mode.eMode].eHdr; |
| 33183 | chng = 1; |
| 33184 | }else if( optionMatch(z,"widths") || optionMatch(z,"width") ){ |
| 33185 | int nWidth = 0; |
| 33186 | short int *aWidth; |
| 33187 | const char *zW; |
| @@ -33295,10 +34041,18 @@ | |
| 33295 | append_c_string(pDesc, p->mode.spec.zColumnSep); |
| 33296 | } |
| 33297 | if( bAll || p->mode.spec.eEsc!=QRF_Auto ){ |
| 33298 | sqlite3_str_appendf(pDesc, " --escape %s",qrfEscNames[p->mode.spec.eEsc]); |
| 33299 | } |
| 33300 | if( bAll |
| 33301 | || (p->mode.spec.nLineLimit>0 && pI->eCx>0) |
| 33302 | || p->mode.spec.nCharLimit>0 |
| 33303 | || (p->mode.spec.nTitleLimit>0 && pI->eCx>0) |
| 33304 | ){ |
| @@ -33332,10 +34086,16 @@ | |
| 33332 | if( bAll |
| 33333 | || (pI->eText!=p->mode.spec.eText && (pI->eText>1 || p->mode.spec.eText>1)) |
| 33334 | ){ |
| 33335 | sqlite3_str_appendf(pDesc," --quote %s",qrfQuoteNames[p->mode.spec.eText]); |
| 33336 | } |
| 33337 | zSetting = aModeStr[pI->eRSep]; |
| 33338 | if( bAll || (zSetting && cli_strcmp(zSetting,p->mode.spec.zRowSep)!=0) ){ |
| 33339 | sqlite3_str_appendf(pDesc, " --rowsep "); |
| 33340 | append_c_string(pDesc, p->mode.spec.zRowSep); |
| 33341 | } |
| @@ -33361,14 +34121,19 @@ | |
| 33361 | if( k==1 ){ |
| 33362 | sqlite3_str_appendall(pDesc, " --titles off"); |
| 33363 | }else if( k==2 ){ |
| 33364 | sqlite3_str_appendall(pDesc, " --titles on"); |
| 33365 | }else if( k==3 ){ |
| 33366 | static const char *azTitle[] = |
| 33367 | { "plain", "sql", "csv", "html", "tcl", "json"}; |
| 33368 | sqlite3_str_appendf(pDesc, " --titles %s", |
| 33369 | azTitle[p->mode.spec.eTitle-1]); |
| 33370 | } |
| 33371 | if( p->mode.spec.nWidth>0 && (bAll || pI->eCx==2) ){ |
| 33372 | int ii; |
| 33373 | const char *zSep = " --widths "; |
| 33374 | for(ii=0; ii<p->mode.spec.nWidth; ii++){ |
| @@ -34248,11 +35013,16 @@ | |
| 34248 | if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){ |
| 34249 | rc = shell_dbinfo_command(p, nArg, azArg); |
| 34250 | }else |
| 34251 | #endif /* SQLITE_SHELL_HAVE_RECOVER */ |
| 34252 | |
| 34253 | if( c=='d' && n==6 && cli_strncmp(azArg[0], "dbstat", n)==0 ){ |
| 34254 | const char *zSchema = 0; |
| 34255 | int ii; |
| 34256 | char *zSql; |
| 34257 | open_db(p, 0); |
| 34258 | for(ii=1; ii<nArg; ii++){ |
| @@ -34267,27 +35037,19 @@ | |
| 34267 | rc = 1; |
| 34268 | goto meta_command_exit; |
| 34269 | } |
| 34270 | zSchema = z; |
| 34271 | } |
| 34272 | zSql = sqlite3_mprintf("SELECT analyze(%Q)", zSchema); |
| 34273 | shell_check_oom(zSql); |
| 34274 | modePush(p); |
| 34275 | modeChange(p, MODE_BATCH); |
| 34276 | p->mode.spec.nLineLimit = 0; |
| 34277 | p->mode.spec.nCharLimit = 0; |
| 34278 | p->mode.spec.nTitleLimit = 0; |
| 34279 | shell_exec(p, zSql, 0); |
| 34280 | modePop(p); |
| 34281 | sqlite3_free(zSql); |
| 34282 | }else |
| 34283 | |
| 34284 | if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){ |
| 34285 | open_db(p, 0); |
| 34286 | rc = shell_dbtotxt_command(p, nArg, azArg); |
| 34287 | }else |
| 34288 | |
| 34289 | if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){ |
| 34290 | char *zLike = 0; |
| 34291 | char *zSql; |
| 34292 | int i; |
| 34293 | int savedShellFlags = p->shellFlgs; |
| @@ -34689,15 +35451,19 @@ | |
| 34689 | } |
| 34690 | }else |
| 34691 | |
| 34692 | if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){ |
| 34693 | if( nArg==2 ){ |
| 34694 | p->mode.spec.bTitles = booleanValue(azArg[1]) ? QRF_Yes : QRF_No; |
| 34695 | p->mode.mFlags |= MFLG_HDR; |
| 34696 | p->mode.spec.eTitle = aModeInfo[p->mode.eMode].eHdr; |
| 34697 | }else{ |
| 34698 | eputz("Usage: .headers on|off\n"); |
| 34699 | rc = 1; |
| 34700 | } |
| 34701 | }else |
| 34702 | |
| 34703 | if( c=='h' && cli_strncmp(azArg[0], "help", n)==0 ){ |
| @@ -34901,13 +35667,21 @@ | |
| 34901 | sqlite3_str_free(pSql); |
| 34902 | }else |
| 34903 | |
| 34904 | if( c=='i' && cli_strncmp(azArg[0], "intck", n)==0 ){ |
| 34905 | i64 iArg = 0; |
| 34906 | if( nArg==2 ){ |
| 34907 | iArg = integerValue(azArg[1]); |
| 34908 | if( iArg==0 ) iArg = -1; |
| 34909 | } |
| 34910 | if( (nArg!=1 && nArg!=2) || iArg<0 ){ |
| 34911 | cli_printf(stderr,"%s","Usage: .intck STEPS_PER_UNLOCK\n"); |
| 34912 | rc = 1; |
| 34913 | goto meta_command_exit; |
| @@ -34955,10 +35729,12 @@ | |
| 34955 | { "attached", SQLITE_LIMIT_ATTACHED }, |
| 34956 | { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, |
| 34957 | { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER }, |
| 34958 | { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH }, |
| 34959 | { "worker_threads", SQLITE_LIMIT_WORKER_THREADS }, |
| 34960 | }; |
| 34961 | int i, n2; |
| 34962 | open_db(p, 0); |
| 34963 | if( nArg==1 ){ |
| 34964 | for(i=0; i<ArraySize(aLimit); i++){ |
| @@ -35400,10 +36176,26 @@ | |
| 35400 | }else |
| 35401 | if( strcmp(z,"-show")==0 ){ |
| 35402 | cli_printf(stdout,"Main prompt: '%s'\n", prompt_string(p, 0)); |
| 35403 | cli_printf(stdout,"Continuation: '%s'\n", prompt_string(p, 1)); |
| 35404 | }else |
| 35405 | if( strcmp(z,"-")==0 ){ |
| 35406 | noOpt = 1; |
| 35407 | }else |
| 35408 | { |
| 35409 | dotCmdError(p, i, "unknown option", 0); |
| @@ -35414,10 +36206,11 @@ | |
| 35414 | dotCmdError(p, i, "extra argument", 0); |
| 35415 | rc = 1; |
| 35416 | goto meta_command_exit; |
| 35417 | }else if( !p->dot.abQuot[i] && sqlite3_strglob("*[^a-z]*",z)!=0 ){ |
| 35418 | dotCmdError(p, i, "use quotes around the prompt string", 0); |
| 35419 | }else{ |
| 35420 | free(p->azPrompt[cnt]); |
| 35421 | p->azPrompt[cnt] = strdup(z); |
| 35422 | cnt++; |
| 35423 | } |
| @@ -36264,11 +37057,12 @@ | |
| 36264 | azBool[(p->mode.mFlags & MFLG_ECHO)!=0]); |
| 36265 | cli_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->mode.autoEQP&3]); |
| 36266 | cli_printf(p->out, "%12.12s: %s\n","explain", |
| 36267 | p->mode.autoExplain ? "auto" : "off"); |
| 36268 | cli_printf(p->out, "%12.12s: %s\n","headers", |
| 36269 | azBool[p->mode.spec.bTitles==QRF_Yes]); |
| 36270 | if( p->mode.spec.eStyle==QRF_STYLE_Column |
| 36271 | || p->mode.spec.eStyle==QRF_STYLE_Box |
| 36272 | || p->mode.spec.eStyle==QRF_STYLE_Table |
| 36273 | || p->mode.spec.eStyle==QRF_STYLE_Markdown |
| 36274 | ){ |
| @@ -37626,17 +38420,18 @@ | |
| 37626 | " -- treat no subsequent arguments as options\n" |
| 37627 | #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) |
| 37628 | " -A ARGS... run \".archive ARGS\" and exit\n" |
| 37629 | #endif |
| 37630 | " -append append the database to the end of the file\n" |
| 37631 | " -ascii set output mode to 'ascii'\n" |
| 37632 | " -bail stop after hitting an error\n" |
| 37633 | " -batch force batch I/O\n" |
| 37634 | " -box set output mode to 'box'\n" |
| 37635 | " -cmd COMMAND run \"COMMAND\" before reading stdin\n" |
| 37636 | " -column set output mode to 'column'\n" |
| 37637 | " -csv set output mode to 'csv'\n" |
| 37638 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 37639 | " -deserialize open the database using sqlite3_deserialize()\n" |
| 37640 | #endif |
| 37641 | " -echo print inputs before execution\n" |
| 37642 | " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n" |
| @@ -37644,18 +38439,18 @@ | |
| 37644 | " -[no]header turn headers on or off\n" |
| 37645 | #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) |
| 37646 | " -heap SIZE Size of heap for memsys3 or memsys5\n" |
| 37647 | #endif |
| 37648 | " -help show this message\n" |
| 37649 | " -html set output mode to HTML\n" |
| 37650 | " -ifexists only open if database already exists\n" |
| 37651 | " -interactive force interactive I/O\n" |
| 37652 | " -json set output mode to 'json'\n" |
| 37653 | " -line set output mode to 'line'\n" |
| 37654 | " -list set output mode to 'list'\n" |
| 37655 | " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" |
| 37656 | " -markdown set output mode to 'markdown'\n" |
| 37657 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 37658 | " -maxsize N maximum size for a --deserialize database\n" |
| 37659 | #endif |
| 37660 | " -memtrace trace all memory allocations and deallocations\n" |
| 37661 | " -mmap N default mmap size set to N\n" |
| @@ -37668,21 +38463,21 @@ | |
| 37668 | " -nonce STRING set the safe-mode escape nonce\n" |
| 37669 | " -no-rowid-in-view Disable rowid-in-view using sqlite3_config()\n" |
| 37670 | " -nullvalue TEXT set text string for NULL values. Default ''\n" |
| 37671 | " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" |
| 37672 | " -pcachetrace trace all page cache operations\n" |
| 37673 | " -quote set output mode to 'quote'\n" |
| 37674 | " -readonly open the database read-only\n" |
| 37675 | " -safe enable safe-mode\n" |
| 37676 | " -screenwidth N use N as the default screenwidth \n" |
| 37677 | " -separator SEP set output column separator. Default: '|'\n" |
| 37678 | #ifdef SQLITE_ENABLE_SORTER_REFERENCES |
| 37679 | " -sorterref SIZE sorter references threshold size\n" |
| 37680 | #endif |
| 37681 | " -stats print memory stats before each finalize\n" |
| 37682 | " -table set output mode to 'table'\n" |
| 37683 | " -tabs set output mode to 'tabs'\n" |
| 37684 | " -unsafe-testing allow unsafe commands and modes for testing\n" |
| 37685 | " -version show SQLite version\n" |
| 37686 | " -vfs NAME use NAME as the default VFS\n" |
| 37687 | " -vfstrace enable tracing of all VFS calls\n" |
| 37688 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -37710,10 +38505,23 @@ | |
| 37710 | sputz(stdout, "WARNING: attempt to configure SQLite after" |
| 37711 | " initialization.\n"); |
| 37712 | } |
| 37713 | } |
| 37714 | |
| 37715 | /* |
| 37716 | ** Initialize the state information in data |
| 37717 | */ |
| 37718 | static void main_init(ShellState *p) { |
| 37719 | memset(p, 0, sizeof(*p)); |
| @@ -37724,31 +38532,36 @@ | |
| 37724 | verify_uninitialized(); |
| 37725 | #endif |
| 37726 | sqlite3_config(SQLITE_CONFIG_URI, 1); |
| 37727 | sqlite3_config(SQLITE_CONFIG_MULTITHREAD); |
| 37728 | globalShellState = p; |
| 37729 | } |
| 37730 | |
| 37731 | /* |
| 37732 | ** Output text to the console in a font that attracts extra attention. |
| 37733 | */ |
| 37734 | #if 0 /* Windows now handles ANSI escape codes */ |
| 37735 | static void printBold(const char *zText){ |
| 37736 | HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); |
| 37737 | CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo; |
| 37738 | GetConsoleScreenBufferInfo(out, &defaultScreenInfo); |
| 37739 | SetConsoleTextAttribute(out, |
| 37740 | FOREGROUND_RED|FOREGROUND_INTENSITY |
| 37741 | ); |
| 37742 | sputz(stdout, zText); |
| 37743 | SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes); |
| 37744 | } |
| 37745 | #else |
| 37746 | static void printBold(const char *zText){ |
| 37747 | cli_printf(stdout, "\033[1;36m\033[3m%s\033[0m", zText); |
| 37748 | } |
| 37749 | #endif |
| 37750 | |
| 37751 | /* |
| 37752 | ** Get the argument to an --option. Throw an error and die if no argument |
| 37753 | ** is available. |
| 37754 | */ |
| @@ -37762,11 +38575,11 @@ | |
| 37762 | } |
| 37763 | |
| 37764 | /* |
| 37765 | ** The callback from atexit(). |
| 37766 | */ |
| 37767 | static void abnormalExit(void){ |
| 37768 | if( seenInterrupt ) eputz("Program interrupted.\n"); |
| 37769 | if( globalShellState ){ |
| 37770 | clearTempFile(globalShellState, 1, 1); |
| 37771 | } |
| 37772 | } |
| @@ -37837,10 +38650,11 @@ | |
| 37837 | } |
| 37838 | argv[argc] = 0; |
| 37839 | hOut = GetStdHandle(STD_OUTPUT_HANDLE); |
| 37840 | GetConsoleMode(hOut, &mode); |
| 37841 | SetConsoleMode(hOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); |
| 37842 | rc = utf8_main(argc, argv); |
| 37843 | for(i=0; i<argc; i++) free(orig[i]); |
| 37844 | free(argv); |
| 37845 | return rc; |
| 37846 | } |
| @@ -37883,10 +38697,13 @@ | |
| 37883 | stdout_is_console = 1; |
| 37884 | data.wasm.zDefaultDbName = "/fiddle.sqlite3"; |
| 37885 | #else |
| 37886 | stdin_is_interactive = isatty(0); |
| 37887 | stdout_is_console = isatty(1); |
| 37888 | #endif |
| 37889 | atexit(abnormalExit); |
| 37890 | #ifdef SQLITE_DEBUG |
| 37891 | mem_main_enter = sqlite3_memory_used(); |
| 37892 | #endif |
| @@ -37973,11 +38790,11 @@ | |
| 37973 | stdin_is_interactive = 0; |
| 37974 | nCmd++; |
| 37975 | azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); |
| 37976 | shell_check_oom(azCmd); |
| 37977 | aiCmd = realloc(aiCmd, sizeof(aiCmd[0])*nCmd); |
| 37978 | shell_check_oom(azCmd); |
| 37979 | azCmd[nCmd-1] = z; |
| 37980 | aiCmd[nCmd-1] = i; |
| 37981 | } |
| 37982 | continue; |
| 37983 | } |
| @@ -38130,10 +38947,12 @@ | |
| 38130 | }else if( cli_strcmp(z,"-safe")==0 ){ |
| 38131 | /* no-op - catch this on the second pass */ |
| 38132 | }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ |
| 38133 | /* skip over the argument */ |
| 38134 | i++; |
| 38135 | }else if( cli_strcmp(z,"-test-argv")==0 ){ |
| 38136 | /* Undocumented test option. Print the values in argv[] and exit. |
| 38137 | ** Use this to verify that any translation of the argv[], for example |
| 38138 | ** on Windows that receives wargv[] from the OS and must convert |
| 38139 | ** to UTF8 prior to calling this routine. */ |
| @@ -38262,10 +39081,11 @@ | |
| 38262 | modeChange(&data, MODE_Psql); |
| 38263 | }else if( cli_strcmp(z,"-box")==0 ){ |
| 38264 | modeChange(&data, MODE_Box); |
| 38265 | }else if( cli_strcmp(z,"-csv")==0 ){ |
| 38266 | modeChange(&data, MODE_Csv); |
| 38267 | }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ |
| 38268 | /* See similar code at tag-20250224-1 */ |
| 38269 | const char *zEsc = argv[++i]; |
| 38270 | int k; |
| 38271 | for(k=0; k<ArraySize(qrfEscNames); k++){ |
| @@ -38319,13 +39139,15 @@ | |
| 38319 | cmdline_option_value(argc,argv,++i)); |
| 38320 | }else if( cli_strcmp(z,"-nullvalue")==0 ){ |
| 38321 | modeSetStr(&data.mode.spec.zNull, |
| 38322 | cmdline_option_value(argc,argv,++i)); |
| 38323 | }else if( cli_strcmp(z,"-header")==0 ){ |
| 38324 | data.mode.spec.bTitles = QRF_Yes; |
| 38325 | }else if( cli_strcmp(z,"-noheader")==0 ){ |
| 38326 | data.mode.spec.bTitles = QRF_No; |
| 38327 | }else if( cli_strcmp(z,"-echo")==0 ){ |
| 38328 | data.mode.mFlags |= MFLG_ECHO; |
| 38329 | }else if( cli_strcmp(z,"-eqp")==0 ){ |
| 38330 | data.mode.autoEQP = AUTOEQP_on; |
| 38331 | }else if( cli_strcmp(z,"-eqpfull")==0 ){ |
| @@ -38389,10 +39211,12 @@ | |
| 38389 | i++; |
| 38390 | #ifdef SQLITE_ENABLE_MULTIPLEX |
| 38391 | }else if( cli_strcmp(z,"-multiplex")==0 ){ |
| 38392 | i++; |
| 38393 | #endif |
| 38394 | }else if( cli_strcmp(z,"-help")==0 ){ |
| 38395 | usage(1); |
| 38396 | }else if( cli_strcmp(z,"-cmd")==0 ){ |
| 38397 | /* Run commands that follow -cmd first and separately from commands |
| 38398 | ** that simply appear on the command-line. This seems goofy. It would |
| @@ -38418,12 +39242,14 @@ | |
| 38418 | rc = 1; |
| 38419 | goto shell_main_exit; |
| 38420 | } |
| 38421 | open_db(&data, OPEN_DB_ZIPFILE); |
| 38422 | if( z[2] ){ |
| 38423 | argv[i] = &z[2]; |
| 38424 | arDotCommand(&data, 1, argv+(i-1), argc-(i-1)); |
| 38425 | }else{ |
| 38426 | arDotCommand(&data, 1, argv+i, argc-i); |
| 38427 | } |
| 38428 | readStdin = 0; |
| 38429 | stdin_is_interactive = 0; |
| 38430 |
| --- extsrc/shell.c | |
| +++ extsrc/shell.c | |
| @@ -5,16 +5,16 @@ | |
| 5 | ** |
| 6 | ** ext/expert/sqlite3expert.c |
| 7 | ** ext/expert/sqlite3expert.h |
| 8 | ** ext/intck/sqlite3intck.c |
| 9 | ** ext/intck/sqlite3intck.h |
| 10 | ** ext/misc/appendvfs.c |
| 11 | ** ext/misc/base64.c |
| 12 | ** ext/misc/base85.c |
| 13 | ** ext/misc/completion.c |
| 14 | ** ext/misc/decimal.c |
| 15 | ** ext/misc/diskused.c |
| 16 | ** ext/misc/fileio.c |
| 17 | ** ext/misc/ieee754.c |
| 18 | ** ext/misc/memtrace.c |
| 19 | ** ext/misc/pcachetrace.c |
| 20 | ** ext/misc/regexp.c |
| @@ -23,10 +23,11 @@ | |
| 23 | ** ext/misc/shathree.c |
| 24 | ** ext/misc/sqlar.c |
| 25 | ** ext/misc/sqlite3_stdio.c |
| 26 | ** ext/misc/sqlite3_stdio.h |
| 27 | ** ext/misc/stmtrand.c |
| 28 | ** ext/misc/strdup.c |
| 29 | ** ext/misc/uint.c |
| 30 | ** ext/misc/vfstrace.c |
| 31 | ** ext/misc/windirent.h |
| 32 | ** ext/misc/zipfile.c |
| 33 | ** ext/qrf/qrf.c |
| @@ -154,10 +155,11 @@ | |
| 155 | #include <string.h> |
| 156 | #include <stdio.h> |
| 157 | #include <assert.h> |
| 158 | #include <math.h> |
| 159 | #include <stdint.h> |
| 160 | #include <time.h> |
| 161 | #include "sqlite3.h" |
| 162 | typedef sqlite3_int64 i64; |
| 163 | typedef sqlite3_uint64 u64; |
| 164 | typedef unsigned char u8; |
| 165 | #include <ctype.h> |
| @@ -190,13 +192,14 @@ | |
| 192 | #include <sys/stat.h> |
| 193 | |
| 194 | #if HAVE_READLINE |
| 195 | # include <readline/readline.h> |
| 196 | # include <readline/history.h> |
| 197 | #elif HAVE_EDITLINE |
| 198 | /* If both HAVE_READLINE and HAVE_EDITLINE are true, assume that this |
| 199 | ** libedit installation does not have its own headers, instead using |
| 200 | ** those from libreadline. */ |
| 201 | # include <editline/readline.h> |
| 202 | #endif |
| 203 | |
| 204 | #if HAVE_EDITLINE || HAVE_READLINE |
| 205 | |
| @@ -203,28 +206,38 @@ | |
| 206 | # define shell_add_history(X) add_history(X) |
| 207 | # define shell_read_history(X) read_history(X) |
| 208 | # define shell_write_history(X) write_history(X) |
| 209 | # define shell_stifle_history(X) stifle_history(X) |
| 210 | # define shell_readline(X) readline(X) |
| 211 | # define SHELL_CMDLINE_EDIT_AVAILABLE 1 /* command-line editing available */ |
| 212 | |
| 213 | #elif HAVE_LINENOISE |
| 214 | |
| 215 | # include "linenoise.h" |
| 216 | # define shell_add_history(X) linenoiseHistoryAdd(X) |
| 217 | # define shell_read_history(X) linenoiseHistoryLoad(X) |
| 218 | # define shell_write_history(X) linenoiseHistorySave(X) |
| 219 | # define shell_stifle_history(X) linenoiseHistorySetMaxLen(X) |
| 220 | # define shell_readline(X) linenoise(X) |
| 221 | # define SHELL_CMDLINE_EDIT_AVAILABLE 1 /* command-line editing available */ |
| 222 | |
| 223 | #else |
| 224 | |
| 225 | # define shell_read_history(X) |
| 226 | # define shell_write_history(X) |
| 227 | # define shell_stifle_history(X) |
| 228 | # define SHELL_CMDLINE_EDIT_AVAILABLE 0 /* command-line editing not available */ |
| 229 | #endif |
| 230 | |
| 231 | /* |
| 232 | ** Global variable shellCmdLineEdit determines whether or not command-line |
| 233 | ** editing is enabled. It defaults to 1 if the CLI is linked against a |
| 234 | ** command-line editing library (linenoise, readline, or editline) and |
| 235 | ** to 0 if no command-line editing library is available. The |
| 236 | ** "--cmdline-edit off" command-line option will change this value to 0. |
| 237 | */ |
| 238 | static int shellCmdLineEdit = SHELL_CMDLINE_EDIT_AVAILABLE; |
| 239 | |
| 240 | #ifndef deliberate_fall_through |
| 241 | /* Quiet some compilers about some of our intentional code. */ |
| 242 | # if defined(GCC_VERSION) && GCC_VERSION>=7000000 |
| 243 | # define deliberate_fall_through __attribute__((fallthrough)); |
| @@ -731,10 +744,14 @@ | |
| 744 | char *(*xRender)(void*,sqlite3_value*); /* Render a value */ |
| 745 | int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */ |
| 746 | void *pRenderArg; /* First argument to the xRender callback */ |
| 747 | void *pWriteArg; /* First argument to the xWrite callback */ |
| 748 | char **pzOutput; /* Storage location for output string */ |
| 749 | /* The following are available in iVersion 2 and later */ |
| 750 | unsigned char bRowCount; /* Show the number of rows at end of each query */ |
| 751 | char *zIFmt; /* Format string for integers */ |
| 752 | char *zFpFmt; /* Format string for floating point */ |
| 753 | /* Additional fields may be added in the future */ |
| 754 | }; |
| 755 | |
| 756 | /* |
| 757 | ** Interfaces |
| @@ -744,12 +761,11 @@ | |
| 761 | const sqlite3_qrf_spec *pSpec, /* Result format specification */ |
| 762 | char **pzErr /* OUT: Write error message here */ |
| 763 | ); |
| 764 | |
| 765 | /* |
| 766 | ** Range of values for sqlite3_qrf_spec.aWidth[] entries. |
| 767 | */ |
| 768 | #define QRF_MAX_WIDTH 10000 |
| 769 | #define QRF_MIN_WIDTH 0 |
| 770 | |
| 771 | /* |
| @@ -760,11 +776,11 @@ | |
| 776 | #define QRF_STYLE_Column 2 /* One record per line in neat columns */ |
| 777 | #define QRF_STYLE_Count 3 /* Output only a count of the rows of output */ |
| 778 | #define QRF_STYLE_Csv 4 /* Comma-separated-value */ |
| 779 | #define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */ |
| 780 | #define QRF_STYLE_Explain 6 /* EXPLAIN output */ |
| 781 | #define QRF_STYLE_Html 7 /* Generate HTML-style <tr><td> output */ |
| 782 | #define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */ |
| 783 | #define QRF_STYLE_Json 9 /* Output is a list of JSON objects */ |
| 784 | #define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */ |
| 785 | #define QRF_STYLE_Line 11 /* One column per line. */ |
| 786 | #define QRF_STYLE_List 12 /* One record per line with a separator */ |
| @@ -820,10 +836,15 @@ | |
| 836 | #define QRF_SW_On 2 /* This setting is forced on */ |
| 837 | #define QRF_Auto 0 /* Alternate spelling for QRF_*_Auto */ |
| 838 | #define QRF_No 1 /* Alternate spelling for QRF_SW_Off */ |
| 839 | #define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */ |
| 840 | |
| 841 | /* |
| 842 | ** Additional value allowed for bTitles |
| 843 | */ |
| 844 | #define QRF_Always 3 /* Always show titles, even if no rows */ |
| 845 | |
| 846 | /* |
| 847 | ** Possible alignment values alignment settings |
| 848 | ** |
| 849 | ** Horizontal Vertial |
| 850 | ** ---------- -------- */ |
| @@ -868,10 +889,22 @@ | |
| 889 | ** determined as for sqlite3_qrf_wcwidth(). VT100 escape code sequences |
| 890 | ** are assigned a width of zero. |
| 891 | */ |
| 892 | size_t sqlite3_qrf_wcswidth(const char*); |
| 893 | |
| 894 | /* |
| 895 | ** The argument is a proposed format string for the zIFmt or zFpFmt |
| 896 | ** parameters. Return value indicates: |
| 897 | ** |
| 898 | ** 0 The input is not a valid format string. If this string |
| 899 | ** appears in either zIFmt or zFpFmt, it will be ignored. |
| 900 | ** |
| 901 | ** 1 The input is a valid format string for integers. |
| 902 | ** |
| 903 | ** 2 The input is a valid format string for floating point. |
| 904 | */ |
| 905 | int sqlite3_qrf_ckformat(const char*); |
| 906 | |
| 907 | #ifdef __cplusplus |
| 908 | } |
| 909 | #endif |
| 910 | #endif /* !defined(SQLITE_QRF_H) */ |
| @@ -950,10 +983,11 @@ | |
| 983 | } sExpln; |
| 984 | unsigned int nIns; /* Bytes used for current INSERT stmt */ |
| 985 | } u; |
| 986 | sqlite3_int64 nRow; /* Number of rows handled so far */ |
| 987 | int *actualWidth; /* Actual width of each column */ |
| 988 | char zFmt[24]; /* Space to hold the true integer rendering fmt */ |
| 989 | sqlite3_qrf_spec spec; /* Copy of the original spec */ |
| 990 | }; |
| 991 | |
| 992 | /* |
| 993 | ** Data for substitute ctype.h functions. Used for x-platform |
| @@ -993,10 +1027,48 @@ | |
| 1027 | # define deliberate_fall_through __attribute__((fallthrough)); |
| 1028 | # else |
| 1029 | # define deliberate_fall_through |
| 1030 | # endif |
| 1031 | #endif |
| 1032 | |
| 1033 | /* |
| 1034 | ** The argument is a proposed format string for the zIFmt or zFpFmt |
| 1035 | ** parameters. Return value indicates: |
| 1036 | ** |
| 1037 | ** 0 The input is not a valid format string. If this string |
| 1038 | ** appears in either zIFmt or zFpFmt, it will be ignored. |
| 1039 | ** |
| 1040 | ** 1 The input is a valid format string for integers. |
| 1041 | ** |
| 1042 | ** 2 The input is a valid format string for floating point. |
| 1043 | */ |
| 1044 | int sqlite3_qrf_ckformat(const char *z){ |
| 1045 | size_t n; |
| 1046 | if( z==0 ) return 0; |
| 1047 | if( z[0]!='%' ) return 0; |
| 1048 | z++; |
| 1049 | n = strspn(z,"+-,#0"); |
| 1050 | if( n>5 ) return 0; |
| 1051 | z += n; |
| 1052 | if( z[0]>='1' && z[0]<='9' ){ |
| 1053 | n = strspn(z,"0123456789"); |
| 1054 | if( n>3 ) return 0; |
| 1055 | z += n; |
| 1056 | } |
| 1057 | if( z[0]=='.' ){ |
| 1058 | z++; |
| 1059 | n = strspn(z,"0123456789"); |
| 1060 | if( n>3 ) return 0; |
| 1061 | z += n; |
| 1062 | } |
| 1063 | n = strspn(z,"eEgGf"); |
| 1064 | if( n==1 && z[1]==0 ) return 2; |
| 1065 | n = strspn(z,"dxXo"); |
| 1066 | if( n==1 && z[1]==0 ) return 1; |
| 1067 | return 0; |
| 1068 | } |
| 1069 | |
| 1070 | |
| 1071 | /* |
| 1072 | ** Set an error code and error message. |
| 1073 | */ |
| 1074 | static void qrfError( |
| @@ -1129,10 +1201,14 @@ | |
| 1201 | sqlite3_str_append(pOut, "-", 1); |
| 1202 | } |
| 1203 | if( N<10000 ){ |
| 1204 | sqlite3_str_appendf(pOut, "%4lld ", N); |
| 1205 | return; |
| 1206 | } |
| 1207 | if( N>=9223372036854775800LL ){ |
| 1208 | sqlite3_str_appendf(pOut, "%.2fE", 1e-18*(double)N); |
| 1209 | return; |
| 1210 | } |
| 1211 | for(i=1; i<=18; i++){ |
| 1212 | N = (N+5)/10; |
| 1213 | if( N<10000 ){ |
| 1214 | int n = (int)N; |
| @@ -1289,12 +1365,12 @@ | |
| 1365 | if( nCycle>=0 || nLoop>=0 || nRow>=0 ){ |
| 1366 | int nSp = 0; |
| 1367 | sqlite3_str_reset(pStats); |
| 1368 | if( nCycle>=0 && nTotal>0 ){ |
| 1369 | qrfApproxInt64(pStats, nCycle); |
| 1370 | sqlite3_str_appendf(pStats, " %3.0f%%", |
| 1371 | ((100.0*(double)nCycle)+nTotal/2.0) / (double)nTotal |
| 1372 | ); |
| 1373 | nSp = 2; |
| 1374 | } |
| 1375 | if( nLoop>=0 ){ |
| 1376 | if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' '); |
| @@ -1787,11 +1863,11 @@ | |
| 1863 | } |
| 1864 | if( i>0 ){ |
| 1865 | sqlite3_str_append(pOut, (const char*)z, i); |
| 1866 | } |
| 1867 | switch( z[i] ){ |
| 1868 | case '>': sqlite3_str_append(pOut, ">", 4); break; |
| 1869 | case '&': sqlite3_str_append(pOut, "&", 5); break; |
| 1870 | case '<': sqlite3_str_append(pOut, "<", 4); break; |
| 1871 | case '"': sqlite3_str_append(pOut, """, 6); break; |
| 1872 | case '\'': sqlite3_str_append(pOut, "'", 5); break; |
| 1873 | default: i--; |
| @@ -1977,16 +2053,22 @@ | |
| 2053 | return; |
| 2054 | } |
| 2055 | } |
| 2056 | switch( sqlite3_column_type(p->pStmt,iCol) ){ |
| 2057 | case SQLITE_INTEGER: { |
| 2058 | sqlite3_str_appendf(pOut, p->spec.zIFmt, |
| 2059 | sqlite3_column_int64(p->pStmt,iCol)); |
| 2060 | break; |
| 2061 | } |
| 2062 | case SQLITE_FLOAT: { |
| 2063 | if( p->spec.zFpFmt ){ |
| 2064 | double r = sqlite3_column_double(p->pStmt,iCol); |
| 2065 | sqlite3_str_appendf(pOut,p->spec.zFpFmt,r); |
| 2066 | }else{ |
| 2067 | const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol); |
| 2068 | sqlite3_str_appendall(pOut, zTxt); |
| 2069 | } |
| 2070 | break; |
| 2071 | } |
| 2072 | case SQLITE_BLOB: { |
| 2073 | if( p->spec.bTextJsonb==QRF_Yes ){ |
| 2074 | const char *zJson = qrfJsonbToJson(p, iCol); |
| @@ -2281,11 +2363,11 @@ | |
| 2363 | if( bWrap && z[i]!=0 && !qrfSpace(z[i]) && qrfAlnum(c)==qrfAlnum(z[i]) ){ |
| 2364 | /* Perhaps try to back up to a better place to break the line */ |
| 2365 | for(k=i-1; k>=i/2; k--){ |
| 2366 | if( qrfSpace(z[k]) ) break; |
| 2367 | } |
| 2368 | if( k<i/2 && i/2>0 ){ |
| 2369 | for(k=i; k>=i/2; k--){ |
| 2370 | if( qrfAlnum(z[k-1])!=qrfAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break; |
| 2371 | } |
| 2372 | } |
| 2373 | if( k>=i/2 ){ |
| @@ -2522,10 +2604,14 @@ | |
| 2604 | /* Doubled horizontal lines: */ |
| 2605 | #define DBL_24 "\342\225\220" /* U+2550 === */ |
| 2606 | #define DBL_123 "\342\225\236" /* U+255e |= */ |
| 2607 | #define DBL_134 "\342\225\241" /* U+2561 =| */ |
| 2608 | #define DBL_1234 "\342\225\252" /* U+256a =|= */ |
| 2609 | #define DBL_12 "\342\225\230" /* U+2558 `= */ |
| 2610 | #define DBL_14 "\342\225\233" /* U+255b =' */ |
| 2611 | #define DBL_124 "\342\225\247" /* U+2567 ='= */ |
| 2612 | |
| 2613 | |
| 2614 | /* Draw horizontal line N characters long using unicode box |
| 2615 | ** characters |
| 2616 | */ |
| 2617 | static void qrfBoxLine(sqlite3_str *pOut, int N, int bDbl){ |
| @@ -2532,28 +2618,28 @@ | |
| 2618 | const char *azDash[2] = { |
| 2619 | BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24, |
| 2620 | DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 |
| 2621 | };/* 0 1 2 3 4 5 6 7 8 9 */ |
| 2622 | const int nDash = 30; |
| 2623 | i64 nn = 3*(i64)N; |
| 2624 | while( nn>nDash ){ |
| 2625 | sqlite3_str_append(pOut, azDash[bDbl], nDash); |
| 2626 | nn -= nDash; |
| 2627 | } |
| 2628 | sqlite3_str_append(pOut, azDash[bDbl], (int)nn); |
| 2629 | } |
| 2630 | |
| 2631 | /* |
| 2632 | ** Draw a horizontal separator for a QRF_STYLE_Box table. |
| 2633 | */ |
| 2634 | static void qrfBoxSeparator( |
| 2635 | sqlite3_str *pOut, /* Output to this sqlite3_str */ |
| 2636 | qrfColData *p, /* Columnar data */ |
| 2637 | const char *zSep1, /* Left margin */ |
| 2638 | const char *zSep2, /* Column separator */ |
| 2639 | const char *zSep3, /* Right margin */ |
| 2640 | int bDbl /* True for double-lines */ |
| 2641 | ){ |
| 2642 | int i; |
| 2643 | if( p->nCol>0 ){ |
| 2644 | int useBorder = p->p->spec.bBorder!=QRF_No; |
| 2645 | if( useBorder ){ |
| @@ -2568,10 +2654,36 @@ | |
| 2654 | sqlite3_str_appendall(pOut, zSep3); |
| 2655 | } |
| 2656 | } |
| 2657 | sqlite3_str_append(pOut, "\n", 1); |
| 2658 | } |
| 2659 | |
| 2660 | /* |
| 2661 | ** Draw a horizontal separator for a QRF_STYLE_Column table. |
| 2662 | ** This style of separator is only used for separating the title |
| 2663 | ** from the content. |
| 2664 | */ |
| 2665 | static void qrfColumnSeparator( |
| 2666 | sqlite3_str *pOut, /* Output to this sqlite3_str */ |
| 2667 | qrfColData *p, /* Columnar data */ |
| 2668 | const char *colSep, /* Column separator text */ |
| 2669 | int szColSep, /* Size of zColSep in bytes */ |
| 2670 | const char *rowSep, /* Row separator text */ |
| 2671 | int szRowSep /* Size of zRowSep in bytes */ |
| 2672 | ){ |
| 2673 | int j; |
| 2674 | int nColumn = p->nCol; |
| 2675 | for(j=0; j<nColumn; j++){ |
| 2676 | sqlite3_str_appendchar(pOut, p->a[j].w, '-'); |
| 2677 | if( j<nColumn-1 ){ |
| 2678 | sqlite3_str_append(pOut, colSep, szColSep); |
| 2679 | }else{ |
| 2680 | qrfRTrim(pOut); |
| 2681 | sqlite3_str_append(pOut, rowSep, szRowSep); |
| 2682 | } |
| 2683 | } |
| 2684 | } |
| 2685 | |
| 2686 | /* |
| 2687 | ** Load into pData the default alignment for the body of a table. |
| 2688 | */ |
| 2689 | static void qrfLoadAlignment(qrfColData *pData, Qrf *p){ |
| @@ -2610,11 +2722,11 @@ | |
| 2722 | int nSW /* Screen width */ |
| 2723 | ){ |
| 2724 | int i; /* Loop counter */ |
| 2725 | int nr; /* Number of rows */ |
| 2726 | int w = 0; /* Width of the current column */ |
| 2727 | i64 t; /* Total width of all columns */ |
| 2728 | int *aw; /* Array of individual column widths */ |
| 2729 | |
| 2730 | aw = sqlite3_malloc64( sizeof(int)*nCol ); |
| 2731 | if( aw==0 ){ |
| 2732 | qrfOom(p); |
| @@ -2748,12 +2860,15 @@ | |
| 2860 | }else{ |
| 2861 | sepW = pData->nCol*3 + 1; |
| 2862 | if( p->spec.bBorder==QRF_No ) sepW -= 2; |
| 2863 | } |
| 2864 | nCol = pData->nCol; |
| 2865 | for(i=0, sumW=0; i<nCol; i++){ |
| 2866 | if( sumW > 2147483647 - pData->a[i].w ) return; |
| 2867 | sumW += pData->a[i].w; |
| 2868 | } |
| 2869 | if( p->spec.nScreenWidth >= (i64)sumW + sepW ) return; |
| 2870 | |
| 2871 | /* First thing to do is reduce the separation between columns */ |
| 2872 | pData->nMargin = 0; |
| 2873 | if( p->spec.eStyle==QRF_STYLE_Column ){ |
| 2874 | sepW = pData->nCol - 1; |
| @@ -2823,11 +2938,25 @@ | |
| 2938 | sqlite3_str *pStr; /* Temporary rendering */ |
| 2939 | qrfColData data; /* Columnar layout data */ |
| 2940 | int bRTrim; /* Trim trailing space */ |
| 2941 | |
| 2942 | rc = sqlite3_step(p->pStmt); |
| 2943 | if( nColumn==0 ){ |
| 2944 | return; /* Not a query. No results every shown. */ |
| 2945 | } |
| 2946 | if( rc==SQLITE_DONE && nColumn>0 ){ |
| 2947 | /* Empty query */ |
| 2948 | if( p->spec.bTitles==QRF_Always ){ |
| 2949 | /* fall through into the columnar logic below */ |
| 2950 | }else{ |
| 2951 | if( p->spec.bRowCount==QRF_Yes ){ |
| 2952 | sqlite3_str_appendf(p->pOut, "(0 rows)\n"); |
| 2953 | qrfWrite(p); |
| 2954 | } |
| 2955 | return; /* No output, other than the row count */ |
| 2956 | } |
| 2957 | }else if( rc!=SQLITE_ROW ){ |
| 2958 | return; /* No output */ |
| 2959 | } |
| 2960 | |
| 2961 | /* Initialize the data container */ |
| 2962 | memset(&data, 0, sizeof(data)); |
| @@ -2840,12 +2969,12 @@ | |
| 2969 | } |
| 2970 | memset(data.a, 0, nColumn*sizeof(struct qrfPerCol) ); |
| 2971 | if( qrfColDataEnlarge(&data) ) return; |
| 2972 | assert( data.az!=0 ); |
| 2973 | |
| 2974 | /* Load the column header names into data */ |
| 2975 | if( p->spec.bTitles>=QRF_Yes ){ |
| 2976 | unsigned char saved_eText = p->spec.eText; |
| 2977 | p->spec.eText = p->spec.eTitle; |
| 2978 | memset(data.abNum, 0, nColumn); |
| 2979 | for(i=0; i<nColumn; i++){ |
| 2980 | const char *z = (const char*)sqlite3_column_name(p->pStmt,i); |
| @@ -2866,13 +2995,14 @@ | |
| 2995 | data.n++; |
| 2996 | if( w>data.a[i].mxW ) data.a[i].mxW = w; |
| 2997 | if( nNL ) data.bMultiRow = 1; |
| 2998 | } |
| 2999 | p->spec.eText = saved_eText; |
| 3000 | } |
| 3001 | |
| 3002 | /* Load query results into data */ |
| 3003 | while( rc==SQLITE_ROW && p->iErr==SQLITE_OK ){ |
| 3004 | if( data.n+nColumn > data.nAlloc ){ |
| 3005 | if( qrfColDataEnlarge(&data) ) return; |
| 3006 | } |
| 3007 | for(i=0; i<nColumn; i++){ |
| 3008 | char *z; |
| @@ -2889,11 +3019,12 @@ | |
| 3019 | data.n++; |
| 3020 | if( w>data.a[i].mxW ) data.a[i].mxW = w; |
| 3021 | if( nNL ) data.bMultiRow = 1; |
| 3022 | } |
| 3023 | p->nRow++; |
| 3024 | rc = sqlite3_step(p->pStmt); |
| 3025 | } |
| 3026 | if( p->iErr ){ |
| 3027 | qrfColDataFree(&data); |
| 3028 | return; |
| 3029 | } |
| 3030 | |
| @@ -3097,11 +3228,11 @@ | |
| 3228 | /* Draw either (1) the separator between the title line and the body |
| 3229 | ** of the table, or (2) separators between individual rows of the table |
| 3230 | ** body. isTitleDataSeparator will be true if we are doing (1). |
| 3231 | */ |
| 3232 | if( (i==0 || data.bMultiRow) && i+nColumn<data.n ){ |
| 3233 | int isTitleDataSeparator = (i==0 && p->spec.bTitles>=QRF_Yes); |
| 3234 | if( isTitleDataSeparator ){ |
| 3235 | qrfLoadAlignment(&data, p); |
| 3236 | } |
| 3237 | switch( p->spec.eStyle ){ |
| 3238 | case QRF_STYLE_Table: { |
| @@ -3124,19 +3255,12 @@ | |
| 3255 | } |
| 3256 | break; |
| 3257 | } |
| 3258 | case QRF_STYLE_Column: { |
| 3259 | if( isTitleDataSeparator ){ |
| 3260 | qrfColumnSeparator(p->pOut, &data, colSep, szColSep, |
| 3261 | rowSep, szRowSep); |
| 3262 | }else if( data.bMultiRow ){ |
| 3263 | qrfRTrim(p->pOut); |
| 3264 | sqlite3_str_append(p->pOut, "\n", 1); |
| 3265 | } |
| 3266 | break; |
| @@ -3144,20 +3268,39 @@ | |
| 3268 | } |
| 3269 | } |
| 3270 | } |
| 3271 | |
| 3272 | /* Draw the line across the bottom of the table */ |
| 3273 | if( p->spec.bBorder!=QRF_No || p->nRow==0 ){ |
| 3274 | switch( p->spec.eStyle ){ |
| 3275 | case QRF_STYLE_Box: |
| 3276 | if( p->nRow>0 ){ |
| 3277 | qrfBoxSeparator(p->pOut, &data, BOX_R12, BOX_124, BOX_R14, 0); |
| 3278 | }else{ |
| 3279 | qrfBoxSeparator(p->pOut, &data, DBL_12, DBL_124, DBL_14, 1); |
| 3280 | } |
| 3281 | break; |
| 3282 | case QRF_STYLE_Table: |
| 3283 | qrfRowSeparator(p->pOut, &data, '+'); |
| 3284 | break; |
| 3285 | case QRF_STYLE_Markdown: |
| 3286 | if( p->nRow==0 ){ |
| 3287 | qrfRowSeparator(p->pOut, &data, '|'); |
| 3288 | } |
| 3289 | break; |
| 3290 | case QRF_STYLE_Column: |
| 3291 | if( p->nRow==0 ){ |
| 3292 | qrfColumnSeparator(p->pOut, &data, colSep, szColSep, |
| 3293 | rowSep, szRowSep); |
| 3294 | } |
| 3295 | break; |
| 3296 | } |
| 3297 | } |
| 3298 | if( p->spec.bRowCount==QRF_Yes ){ |
| 3299 | sqlite3_int64 n = p->nRow; |
| 3300 | sqlite3_str_appendf(p->pOut, "(%lld row%s)\n", n, n==1 ? "" : "s"); |
| 3301 | } |
| 3302 | qrfWrite(p); |
| 3303 | |
| 3304 | qrfColDataFree(&data); |
| 3305 | return; |
| 3306 | } |
| @@ -3404,10 +3547,49 @@ | |
| 3547 | sqlite3_str_append(p->pOut, ":", 1); |
| 3548 | qrfRenderValue(p, p->pOut, i); |
| 3549 | } |
| 3550 | qrfWrite(p); |
| 3551 | } |
| 3552 | |
| 3553 | /* |
| 3554 | ** Render a title row (a row containing column names) if the spec |
| 3555 | ** calls for one and if it makes sense for the eStyle. Title rows |
| 3556 | ** do not make sense for some eStyles, such as QRF_STYLE_Off, |
| 3557 | ** QRF_STYLE_Count, QRF_STYLE_Json, and similar. |
| 3558 | */ |
| 3559 | static void qrfSimpleTitle(Qrf *p){ |
| 3560 | assert( p->nRow==0 ); |
| 3561 | assert( p->spec.bTitles>=QRF_Yes ); |
| 3562 | switch( p->spec.eStyle ){ |
| 3563 | case QRF_STYLE_Html: { |
| 3564 | int i; |
| 3565 | sqlite3_str_append(p->pOut, "<tr>", 4); |
| 3566 | for(i=0; i<p->nCol; i++){ |
| 3567 | const char *zCName = sqlite3_column_name(p->pStmt, i); |
| 3568 | sqlite3_str_append(p->pOut, "\n<th>", 5); |
| 3569 | qrfEncodeText(p, p->pOut, zCName); |
| 3570 | } |
| 3571 | sqlite3_str_append(p->pOut, "\n</tr>\n", 7); |
| 3572 | break; |
| 3573 | } |
| 3574 | case QRF_STYLE_Quote: |
| 3575 | case QRF_STYLE_List: { |
| 3576 | int i; |
| 3577 | int saved_eText = p->spec.eText; |
| 3578 | p->spec.eText = p->spec.eTitle; |
| 3579 | for(i=0; i<p->nCol; i++){ |
| 3580 | const char *zCName = sqlite3_column_name(p->pStmt, i); |
| 3581 | if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep); |
| 3582 | qrfEncodeText(p, p->pOut, zCName); |
| 3583 | } |
| 3584 | sqlite3_str_appendall(p->pOut, p->spec.zRowSep); |
| 3585 | qrfWrite(p); |
| 3586 | p->spec.eText = saved_eText; |
| 3587 | break; |
| 3588 | } |
| 3589 | } |
| 3590 | } |
| 3591 | |
| 3592 | /* |
| 3593 | ** Render a single row of output for non-columnar styles - any |
| 3594 | ** style that lets us render row by row as the content is received |
| 3595 | ** from the query. |
| @@ -3437,25 +3619,19 @@ | |
| 3619 | } |
| 3620 | qrfOneJsonRow(p); |
| 3621 | break; |
| 3622 | } |
| 3623 | case QRF_STYLE_Html: { |
| 3624 | if( p->nRow==0 && p->spec.bTitles>=QRF_Yes ){ |
| 3625 | qrfSimpleTitle(p); |
| 3626 | } |
| 3627 | sqlite3_str_append(p->pOut, "<tr>", 4); |
| 3628 | for(i=0; i<p->nCol; i++){ |
| 3629 | sqlite3_str_append(p->pOut, "\n<td>", 5); |
| 3630 | qrfRenderValue(p, p->pOut, i); |
| 3631 | } |
| 3632 | sqlite3_str_append(p->pOut, "\n</tr>\n", 7); |
| 3633 | qrfWrite(p); |
| 3634 | break; |
| 3635 | } |
| 3636 | case QRF_STYLE_Insert: { |
| 3637 | unsigned int mxIns = p->spec.nMultiInsert; |
| @@ -3468,11 +3644,11 @@ | |
| 3644 | if( qrf_need_quote(p->spec.zTableName) ){ |
| 3645 | sqlite3_str_appendf(p->pOut,"INSERT INTO \"%w\"",p->spec.zTableName); |
| 3646 | }else{ |
| 3647 | sqlite3_str_appendf(p->pOut,"INSERT INTO %s",p->spec.zTableName); |
| 3648 | } |
| 3649 | if( p->spec.bTitles>=QRF_Yes ){ |
| 3650 | for(i=0; i<p->nCol; i++){ |
| 3651 | const char *zCName = sqlite3_column_name(p->pStmt, i); |
| 3652 | if( qrf_need_quote(zCName) ){ |
| 3653 | sqlite3_str_appendf(p->pOut, "%c\"%w\"", |
| 3654 | i==0 ? '(' : ',', zCName); |
| @@ -3568,21 +3744,12 @@ | |
| 3744 | if( zEqpLine[0]=='-' ) qrfEqpRender(p, 0); |
| 3745 | qrfEqpAppend(p, iEqpId, iParentId, zEqpLine); |
| 3746 | break; |
| 3747 | } |
| 3748 | default: { /* QRF_STYLE_List */ |
| 3749 | if( p->nRow==0 && p->spec.bTitles>=QRF_Yes ){ |
| 3750 | qrfSimpleTitle(p); |
| 3751 | } |
| 3752 | for(i=0; i<p->nCol; i++){ |
| 3753 | if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep); |
| 3754 | qrfRenderValue(p, p->pOut, i); |
| 3755 | } |
| @@ -3604,11 +3771,11 @@ | |
| 3771 | char **pzErr /* Write errors here */ |
| 3772 | ){ |
| 3773 | size_t sz; /* Size of pSpec[], based on pSpec->iVersion */ |
| 3774 | memset(p, 0, sizeof(*p)); |
| 3775 | p->pzErr = pzErr; |
| 3776 | if( pSpec->iVersion>2 ){ |
| 3777 | qrfError(p, SQLITE_ERROR, |
| 3778 | "unusable sqlite3_qrf_spec.iVersion (%d)", |
| 3779 | pSpec->iVersion); |
| 3780 | return; |
| 3781 | } |
| @@ -3620,15 +3787,19 @@ | |
| 3787 | return; |
| 3788 | } |
| 3789 | p->iErr = SQLITE_OK; |
| 3790 | p->nCol = sqlite3_column_count(p->pStmt); |
| 3791 | p->nRow = 0; |
| 3792 | switch( pSpec->iVersion ){ |
| 3793 | case 0: sz = offsetof(sqlite3_qrf_spec, bRowCount); break; |
| 3794 | case 1: sz = offsetof(sqlite3_qrf_spec, bRowCount); break; |
| 3795 | default: sz = sizeof(sqlite3_qrf_spec); break; |
| 3796 | } |
| 3797 | memcpy(&p->spec, pSpec, sz); |
| 3798 | if( p->spec.zNull==0 ) p->spec.zNull = ""; |
| 3799 | p->mxWidth = p->spec.nScreenWidth; |
| 3800 | if( p->mxWidth<=0 ) p->mxWidth = 2147483647; |
| 3801 | p->mxHeight = p->spec.nLineLimit; |
| 3802 | if( p->mxHeight<=0 ) p->mxHeight = 2147483647; |
| 3803 | if( p->spec.eStyle>QRF_STYLE_Table ) p->spec.eStyle = QRF_Auto; |
| 3804 | if( p->spec.eEsc>QRF_ESC_Symbol ) p->spec.eEsc = QRF_Auto; |
| 3805 | if( p->spec.eText>QRF_TEXT_Relaxed ) p->spec.eText = QRF_Auto; |
| @@ -3756,10 +3927,24 @@ | |
| 3927 | if( p->spec.bTextJsonb==QRF_Auto ){ |
| 3928 | p->spec.bTextJsonb = QRF_No; |
| 3929 | } |
| 3930 | if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = ","; |
| 3931 | if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n"; |
| 3932 | if( p->spec.zIFmt==0 || sqlite3_qrf_ckformat(p->spec.zIFmt)!=1 ){ |
| 3933 | p->spec.zIFmt = "%lld"; |
| 3934 | }else{ |
| 3935 | size_t n = strlen(p->spec.zIFmt); |
| 3936 | memcpy(p->zFmt, p->spec.zIFmt, n-1); |
| 3937 | p->zFmt[n-1] = 'l'; |
| 3938 | p->zFmt[n] = 'l'; |
| 3939 | p->zFmt[n+1] = p->spec.zIFmt[n-1]; |
| 3940 | p->zFmt[n+2] = 0; |
| 3941 | p->spec.zIFmt = p->zFmt; |
| 3942 | } |
| 3943 | if( p->spec.zFpFmt && sqlite3_qrf_ckformat(p->spec.zFpFmt)!=2 ){ |
| 3944 | p->spec.zFpFmt = 0; |
| 3945 | } |
| 3946 | } |
| 3947 | |
| 3948 | /* |
| 3949 | ** Finish rendering the results |
| 3950 | */ |
| @@ -3890,10 +4075,34 @@ | |
| 4075 | default: { |
| 4076 | /* Non-columnar modes where the output can occur after each row |
| 4077 | ** of result is received */ |
| 4078 | while( qrf.iErr==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ |
| 4079 | qrfOneSimpleRow(&qrf); |
| 4080 | } |
| 4081 | if( qrf.nCol>0 && qrf.nRow==0 && qrf.spec.bTitles==QRF_Always ){ |
| 4082 | qrfSimpleTitle(&qrf); |
| 4083 | } |
| 4084 | if( qrf.nCol>0 && qrf.spec.bRowCount==QRF_Yes ){ |
| 4085 | const char *zPlural = qrf.nRow==1 ? "" : "s"; |
| 4086 | switch( qrf.spec.eStyle ){ |
| 4087 | case QRF_STYLE_Line: |
| 4088 | if( qrf.nRow>0 ) sqlite3_str_append(qrf.pOut, "\n", 1); |
| 4089 | /* Fall through */ |
| 4090 | case QRF_STYLE_Csv: |
| 4091 | case QRF_STYLE_List: |
| 4092 | case QRF_STYLE_Quote: |
| 4093 | sqlite3_str_appendf(qrf.pOut,"(%lld row%s)\n",qrf.nRow,zPlural); |
| 4094 | break; |
| 4095 | case QRF_STYLE_Html: |
| 4096 | sqlite3_str_appendf(qrf.pOut,"<!-- %lld row%s -->\n", |
| 4097 | qrf.nRow, zPlural); |
| 4098 | break; |
| 4099 | case QRF_STYLE_Insert: |
| 4100 | sqlite3_str_appendf(qrf.pOut,"/* %lld row%s inserted */\n", |
| 4101 | qrf.nRow, zPlural); |
| 4102 | break; |
| 4103 | } |
| 4104 | } |
| 4105 | break; |
| 4106 | } |
| 4107 | } |
| 4108 | qrfResetStmt(&qrf); |
| @@ -5106,10 +5315,12 @@ | |
| 5315 | int rc; |
| 5316 | int n; |
| 5317 | const char *z; |
| 5318 | SHA3Context cx; |
| 5319 | int iSize; |
| 5320 | int isRecursive = 0; |
| 5321 | int *pIsRecursive; |
| 5322 | |
| 5323 | if( argc==1 ){ |
| 5324 | iSize = 256; |
| 5325 | }else{ |
| 5326 | iSize = sqlite3_value_int(argv[1]); |
| @@ -5119,10 +5330,15 @@ | |
| 5330 | return; |
| 5331 | } |
| 5332 | } |
| 5333 | if( zSql==0 ) return; |
| 5334 | SHA3Init(&cx, iSize); |
| 5335 | pIsRecursive = (int*)sqlite3_get_clientdata(db,"sha3_query()"); |
| 5336 | if( pIsRecursive ){ |
| 5337 | *pIsRecursive = 1; |
| 5338 | return; |
| 5339 | } |
| 5340 | while( zSql[0] ){ |
| 5341 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); |
| 5342 | if( rc ){ |
| 5343 | char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", |
| 5344 | zSql, sqlite3_errmsg(db)); |
| @@ -5145,19 +5361,25 @@ | |
| 5361 | sha3_step_vformat(&cx,"S%d:",n); |
| 5362 | SHA3Update(&cx,(unsigned char*)z,n); |
| 5363 | } |
| 5364 | |
| 5365 | /* Compute a hash over the result of the query */ |
| 5366 | sqlite3_set_clientdata(db, "sha3_query()", &isRecursive, 0); |
| 5367 | while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 5368 | SHA3Update(&cx,(const unsigned char*)"R",1); |
| 5369 | for(i=0; i<nCol; i++){ |
| 5370 | sha3UpdateFromValue(&cx, sqlite3_column_value(pStmt,i)); |
| 5371 | } |
| 5372 | } |
| 5373 | sqlite3_finalize(pStmt); |
| 5374 | sqlite3_set_clientdata(db, "sha3_query()", 0, 0); |
| 5375 | } |
| 5376 | if( isRecursive ){ |
| 5377 | sqlite3_result_error(context, "recursive use of sha3_query()", -1); |
| 5378 | }else{ |
| 5379 | sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); |
| 5380 | } |
| 5381 | } |
| 5382 | |
| 5383 | /* |
| 5384 | ** xStep function for sha3_agg(). |
| 5385 | */ |
| @@ -5272,10 +5494,14 @@ | |
| 5494 | #include <stdarg.h> |
| 5495 | |
| 5496 | /****************************************************************************** |
| 5497 | ** The Hash Engine |
| 5498 | */ |
| 5499 | #if defined(__GNUC__) && __GNUC__>=11 |
| 5500 | # pragma GCC diagnostic push |
| 5501 | # pragma GCC diagnostic ignored "-Wstringop-overread" |
| 5502 | #endif |
| 5503 | /* Context for the SHA1 hash */ |
| 5504 | typedef struct SHA1Context SHA1Context; |
| 5505 | struct SHA1Context { |
| 5506 | unsigned int state[5]; |
| 5507 | unsigned int count[2]; |
| @@ -5412,11 +5638,11 @@ | |
| 5638 | } |
| 5639 | j = 0; |
| 5640 | }else{ |
| 5641 | i = 0; |
| 5642 | } |
| 5643 | if( len-i>0 ) (void)memcpy(&p->buffer[j], &data[i], len - i); |
| 5644 | } |
| 5645 | |
| 5646 | /* Compute a string using sqlite3_vsnprintf() and hash it */ |
| 5647 | static void hash_step_vformat( |
| 5648 | SHA1Context *p, /* Add content to this context */ |
| @@ -5467,10 +5693,13 @@ | |
| 5693 | zOut[i*2+1] = zEncode[digest[i] & 0xf]; |
| 5694 | } |
| 5695 | zOut[i*2]= 0; |
| 5696 | } |
| 5697 | } |
| 5698 | #if defined(__GNUC__) && __GNUC__>=11 |
| 5699 | # pragma GCC diagnostic pop |
| 5700 | #endif |
| 5701 | /* End of the hashing logic |
| 5702 | *****************************************************************************/ |
| 5703 | |
| 5704 | /* |
| 5705 | ** Two SQL functions: sha1(X) and sha1b(X). |
| @@ -5501,11 +5730,14 @@ | |
| 5730 | if( eType==SQLITE_BLOB ){ |
| 5731 | pData = (const unsigned char*)sqlite3_value_blob(argv[0]); |
| 5732 | }else{ |
| 5733 | pData = (const unsigned char*)sqlite3_value_text(argv[0]); |
| 5734 | } |
| 5735 | if( pData==0 ){ |
| 5736 | if( nByte ) return; |
| 5737 | pData = (const unsigned char*)""; |
| 5738 | } |
| 5739 | hash_step(&cx, pData, nByte); |
| 5740 | if( sqlite3_user_data(context)!=0 ){ |
| 5741 | /* sha1b() - binary result */ |
| 5742 | hash_finish(&cx, zOut, 1); |
| 5743 | sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT); |
| @@ -5541,13 +5773,20 @@ | |
| 5773 | int rc; |
| 5774 | int n; |
| 5775 | const char *z; |
| 5776 | SHA1Context cx; |
| 5777 | char zOut[44]; |
| 5778 | int isRecursive = 0; |
| 5779 | int *pIsRecursive; |
| 5780 | |
| 5781 | assert( argc==1 ); |
| 5782 | if( zSql==0 ) return; |
| 5783 | pIsRecursive = sqlite3_get_clientdata(db, "sha1_query()"); |
| 5784 | if( pIsRecursive ){ |
| 5785 | *pIsRecursive = 1; |
| 5786 | return; |
| 5787 | } |
| 5788 | hash_init(&cx); |
| 5789 | while( zSql[0] ){ |
| 5790 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); |
| 5791 | if( rc ){ |
| 5792 | char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", |
| @@ -5570,10 +5809,11 @@ | |
| 5809 | n = (int)strlen(z); |
| 5810 | hash_step_vformat(&cx,"S%d:",n); |
| 5811 | hash_step(&cx,(unsigned char*)z,n); |
| 5812 | |
| 5813 | /* Compute a hash over the result of the query */ |
| 5814 | sqlite3_set_clientdata(db, "sha1_query()", &isRecursive, 0); |
| 5815 | while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 5816 | hash_step(&cx,(const unsigned char*)"R",1); |
| 5817 | for(i=0; i<nCol; i++){ |
| 5818 | switch( sqlite3_column_type(pStmt,i) ){ |
| 5819 | case SQLITE_NULL: { |
| @@ -5624,13 +5864,18 @@ | |
| 5864 | } |
| 5865 | } |
| 5866 | } |
| 5867 | } |
| 5868 | sqlite3_finalize(pStmt); |
| 5869 | sqlite3_set_clientdata(db, "sha1_query()", 0, 0); |
| 5870 | } |
| 5871 | hash_finish(&cx, zOut, 0); |
| 5872 | if( isRecursive ){ |
| 5873 | sqlite3_result_error(context, "recursive use of sha1_query()", -1); |
| 5874 | }else{ |
| 5875 | sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT); |
| 5876 | } |
| 5877 | } |
| 5878 | |
| 5879 | |
| 5880 | #ifdef _WIN32 |
| 5881 | |
| @@ -5824,10 +6069,13 @@ | |
| 6069 | } |
| 6070 | |
| 6071 | /* |
| 6072 | ** Allocate a new Decimal object initialized to the text in zIn[]. |
| 6073 | ** Return NULL if any kind of error occurs. |
| 6074 | ** |
| 6075 | ** Note that zIn[] is not necessarily zero-terminated. Always |
| 6076 | ** respect the boundary imposed by the n argument. |
| 6077 | */ |
| 6078 | static Decimal *decimalNewFromText(const char *zIn, int n){ |
| 6079 | Decimal *p = 0; |
| 6080 | int i; |
| 6081 | int iExp = 0; |
| @@ -5841,15 +6089,15 @@ | |
| 6089 | p->isNull = 0; |
| 6090 | p->nDigit = 0; |
| 6091 | p->nFrac = 0; |
| 6092 | p->a = sqlite3_malloc64( n+1 ); |
| 6093 | if( p->a==0 ) goto new_from_text_failed; |
| 6094 | for(i=0; i<n && IsSpace(zIn[i]); i++){} |
| 6095 | if( i<n && zIn[i]=='-' ){ |
| 6096 | p->sign = 1; |
| 6097 | i++; |
| 6098 | }else if( i<n && zIn[i]=='+' ){ |
| 6099 | i++; |
| 6100 | } |
| 6101 | while( i<n && zIn[i]=='0' ) i++; |
| 6102 | while( i<n ){ |
| 6103 | char c = zIn[i]; |
| @@ -6056,32 +6304,41 @@ | |
| 6304 | } |
| 6305 | z[i] = 0; |
| 6306 | sqlite3_result_text(pCtx, z, i, sqlite3_free); |
| 6307 | } |
| 6308 | |
| 6309 | /* Forward declaration */ |
| 6310 | static void decimal_expand(Decimal *p, int nDigit, int nFrac); |
| 6311 | |
| 6312 | /* |
| 6313 | ** Round a decimal value to N significant digits. N must be positive. |
| 6314 | */ |
| 6315 | static void decimal_round(Decimal *p, int N){ |
| 6316 | int i; |
| 6317 | int nZero; /* Number of leading zeros */ |
| 6318 | if( N<1 ) return; |
| 6319 | if( p==0 ) return; |
| 6320 | if( p->nDigit<=N ) return; |
| 6321 | for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){} |
| 6322 | N += nZero; |
| 6323 | if( p->nDigit<=N ) return; |
| 6324 | if( p->a[N]>=5 ){ |
| 6325 | /* If all leading digits are 9, increase the number of digits |
| 6326 | ** by adding a new 0 to the front */ |
| 6327 | for(i=0; i<N && p->a[i]==9; i++){} |
| 6328 | if( i==N ){ |
| 6329 | decimal_expand(p, p->nDigit+1, p->nFrac); |
| 6330 | if( p->oom ) return; |
| 6331 | } |
| 6332 | |
| 6333 | /* Do the rounding */ |
| 6334 | p->a[N-1]++; |
| 6335 | for(i=N-1; i>0 && p->a[i]>9; i--){ |
| 6336 | p->a[i] = 0; |
| 6337 | p->a[i-1]++; |
| 6338 | } |
| 6339 | assert( p->a[0]<=9 ); |
| 6340 | } |
| 6341 | memset(&p->a[N], 0, p->nDigit - N); |
| 6342 | } |
| 6343 | |
| 6344 | /* |
| @@ -6225,10 +6482,11 @@ | |
| 6482 | int nAddSig; |
| 6483 | int nAddFrac; |
| 6484 | signed char *a; |
| 6485 | if( p==0 ) return; |
| 6486 | nAddFrac = nFrac - p->nFrac; |
| 6487 | assert( nAddFrac>=0 ); |
| 6488 | nAddSig = (nDigit - p->nDigit) - nAddFrac; |
| 6489 | if( nAddFrac==0 && nAddSig==0 ) return; |
| 6490 | if( nDigit+1>SQLITE_DECIMAL_MAX_DIGIT ){ p->oom = 1; return; } |
| 6491 | a = sqlite3_realloc64(p->a, nDigit+1); |
| 6492 | if( a==0 ){ |
| @@ -8232,10 +8490,20 @@ | |
| 8490 | if( r==(double)x ) return r; |
| 8491 | if( r<(double)x ) x--; |
| 8492 | return (double)x; |
| 8493 | } |
| 8494 | #endif |
| 8495 | |
| 8496 | /* Convert a floating point value to its closest integer. Do so in |
| 8497 | ** a way that avoids 'outside the range of representable values' warnings |
| 8498 | ** from UBSAN. |
| 8499 | */ |
| 8500 | static sqlite3_int64 seriesRealToI64(double r){ |
| 8501 | if( r<-9223372036854774784.0 ) return SMALLEST_INT64; |
| 8502 | if( r>+9223372036854774784.0 ) return LARGEST_INT64; |
| 8503 | return (sqlite3_int64)r; |
| 8504 | } |
| 8505 | |
| 8506 | /* |
| 8507 | ** This method is called to "rewind" the series_cursor object back |
| 8508 | ** to the first row of output. This method is always called at least |
| 8509 | ** once prior to any call to seriesColumn() or seriesRowid() or |
| @@ -8355,27 +8623,31 @@ | |
| 8623 | double r = sqlite3_value_double(argv[iArg++]); |
| 8624 | if( r==seriesCeil(r) |
| 8625 | && r>=(double)SMALLEST_INT64 |
| 8626 | && r<=(double)LARGEST_INT64 |
| 8627 | ){ |
| 8628 | iMin = iMax = seriesRealToI64(r); |
| 8629 | }else{ |
| 8630 | goto series_no_rows; |
| 8631 | } |
| 8632 | }else{ |
| 8633 | iMin = iMax = sqlite3_value_int64(argv[iArg++]); |
| 8634 | } |
| 8635 | }else{ |
| 8636 | if( idxNum & 0x0300 ){ /* value>X (0x200) or value>=X (0x100) */ |
| 8637 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8638 | double r = sqlite3_value_double(argv[iArg++]); |
| 8639 | if( r<=(double)SMALLEST_INT64 ){ |
| 8640 | iMin = SMALLEST_INT64; |
| 8641 | }else if( r>(double)LARGEST_INT64 ){ |
| 8642 | goto series_no_rows; |
| 8643 | }else{ |
| 8644 | iMin = seriesRealToI64(seriesCeil(r)); |
| 8645 | if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){ |
| 8646 | if( iMin==LARGEST_INT64 ) goto series_no_rows; |
| 8647 | iMin++; |
| 8648 | } |
| 8649 | } |
| 8650 | }else{ |
| 8651 | iMin = sqlite3_value_int64(argv[iArg++]); |
| 8652 | if( (idxNum & 0x0200)!=0 ){ |
| 8653 | if( iMin==LARGEST_INT64 ){ |
| @@ -8384,19 +8656,23 @@ | |
| 8656 | iMin++; |
| 8657 | } |
| 8658 | } |
| 8659 | } |
| 8660 | } |
| 8661 | if( idxNum & 0x3000 ){ /* value<X (0x2000) or value<=X (0x1000) */ |
| 8662 | if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){ |
| 8663 | double r = sqlite3_value_double(argv[iArg++]); |
| 8664 | if( r>=(double)LARGEST_INT64 ){ |
| 8665 | iMax = LARGEST_INT64; |
| 8666 | }else if( r<=(double)SMALLEST_INT64 ){ |
| 8667 | goto series_no_rows; |
| 8668 | }else{ |
| 8669 | iMax = seriesRealToI64(seriesFloor(r)); |
| 8670 | if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){ |
| 8671 | if( iMax==SMALLEST_INT64 ) goto series_no_rows; |
| 8672 | iMax--; |
| 8673 | } |
| 8674 | } |
| 8675 | }else{ |
| 8676 | iMax = sqlite3_value_int64(argv[iArg++]); |
| 8677 | if( idxNum & 0x2000 ){ |
| 8678 | if( iMax==SMALLEST_INT64 ){ |
| @@ -9638,11 +9914,10 @@ | |
| 9914 | if( pRe==0 ){ |
| 9915 | sqlite3_result_error_nomem(context); |
| 9916 | return; |
| 9917 | } |
| 9918 | pStr = sqlite3_str_new(0); |
| 9919 | if( pRe->nInit>0 ){ |
| 9920 | sqlite3_str_appendf(pStr, "INIT "); |
| 9921 | for(i=0; i<pRe->nInit; i++){ |
| 9922 | sqlite3_str_appendf(pStr, "%02x", pRe->zInit[i]); |
| 9923 | } |
| @@ -9649,20 +9924,20 @@ | |
| 9924 | sqlite3_str_appendf(pStr, "\n"); |
| 9925 | } |
| 9926 | for(i=0; (unsigned)i<pRe->nState; i++){ |
| 9927 | sqlite3_str_appendf(pStr, "%-8s %4d\n", |
| 9928 | ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]); |
| 9929 | } |
| 9930 | if( sqlite3_str_errcode(pStr)==SQLITE_NOMEM ){ |
| 9931 | sqlite3_str_finish(pStr); |
| 9932 | re_free(pRe); |
| 9933 | sqlite3_result_error_nomem(context); |
| 9934 | return; |
| 9935 | } |
| 9936 | n = sqlite3_str_length(pStr); |
| 9937 | z = sqlite3_str_finish(pStr); |
| 9938 | sqlite3_result_text(context, z, n-1, sqlite3_free); |
| 9939 | re_free(pRe); |
| 9940 | } |
| 9941 | |
| 9942 | #endif /* SQLITE_DEBUG */ |
| 9943 | |
| @@ -10557,11 +10832,15 @@ | |
| 10832 | sqlite3_result_error_nomem(ctx); |
| 10833 | return SQLITE_NOMEM; |
| 10834 | } |
| 10835 | } |
| 10836 | |
| 10837 | if( n>0 ){ |
| 10838 | sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT); |
| 10839 | }else{ |
| 10840 | sqlite3_result_null(ctx); |
| 10841 | } |
| 10842 | if( aBuf!=aStatic ) sqlite3_free(aBuf); |
| 10843 | #endif |
| 10844 | }else{ |
| 10845 | readFileContents(ctx, pCur->zPath); |
| 10846 | } |
| @@ -10870,10 +11149,13 @@ | |
| 11149 | ** Return NULL if unable. |
| 11150 | ** |
| 11151 | ** The file or directory X is not required to exist. The answer is formed |
| 11152 | ** by calling system realpath() on the prefix of X that does exist and |
| 11153 | ** appending the tail of X that does not (yet) exist. |
| 11154 | ** |
| 11155 | ** FIXME: This routine sometimes returns NULL rather than raising |
| 11156 | ** an SQLITE_NOMEM error if an OOM is encountered. |
| 11157 | */ |
| 11158 | static void realpathFunc( |
| 11159 | sqlite3_context *context, |
| 11160 | int argc, |
| 11161 | sqlite3_value **argv |
| @@ -10892,10 +11174,11 @@ | |
| 11174 | (void)argc; |
| 11175 | zPath = (const char*)sqlite3_value_text(argv[0]); |
| 11176 | if( zPath==0 ) return; |
| 11177 | if( zPath[0]==0 ) zPath = "."; |
| 11178 | zCopy = sqlite3_mprintf("%s",zPath); |
| 11179 | if( zCopy==0 ) return; |
| 11180 | len = strlen(zCopy); |
| 11181 | while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){ |
| 11182 | len--; |
| 11183 | } |
| 11184 | zCopy[len] = 0; |
| @@ -11802,11 +12085,13 @@ | |
| 12085 | int iAmt, |
| 12086 | sqlite_int64 iOfst |
| 12087 | ){ |
| 12088 | ApndFile *paf = (ApndFile *)pFile; |
| 12089 | sqlite_int64 iWriteEnd = iOfst + iAmt; |
| 12090 | if( iWriteEnd + paf->iPgOne >= APND_MAX_SIZE-APND_MARK_SIZE ){ |
| 12091 | return SQLITE_FULL; |
| 12092 | } |
| 12093 | pFile = ORIGFILE(pFile); |
| 12094 | /* If append-mark is absent or will be overwritten, write it. */ |
| 12095 | if( paf->iMark < 0 || paf->iPgOne + iWriteEnd > paf->iMark ){ |
| 12096 | int rc = apndWriteMark(paf, pFile, iWriteEnd); |
| 12097 | if( SQLITE_OK!=rc ) return rc; |
| @@ -12220,10 +12505,12 @@ | |
| 12505 | ** |
| 12506 | ** * No support for encryption |
| 12507 | ** * No support for ZIP archives spanning multiple files |
| 12508 | ** * No support for zip64 extensions |
| 12509 | ** * Only the "inflate/deflate" (zlib) compression method is supported |
| 12510 | ** * No support for transactions. ROLLBACK is the same as COMMIT. |
| 12511 | ** A crash mid-transaction can leave the ZIP archive in a corrupt state. |
| 12512 | */ |
| 12513 | /* #include "sqlite3ext.h" */ |
| 12514 | SQLITE_EXTENSION_INIT1 |
| 12515 | #include <stdio.h> |
| 12516 | #include <string.h> |
| @@ -12685,10 +12972,11 @@ | |
| 12972 | |
| 12973 | for(p=pCsr->pFreeEntry; p; p=pNext){ |
| 12974 | pNext = p->pNext; |
| 12975 | zipfileEntryFree(p); |
| 12976 | } |
| 12977 | pCsr->pFreeEntry = 0; |
| 12978 | } |
| 12979 | |
| 12980 | /* |
| 12981 | ** Destructor for an ZipfileCsr. |
| 12982 | */ |
| @@ -13087,11 +13375,17 @@ | |
| 13375 | } |
| 13376 | } |
| 13377 | |
| 13378 | if( rc==SQLITE_OK ){ |
| 13379 | u32 *pt = &pNew->mUnixTime; |
| 13380 | /* aRead[0..nFile-1] might contain embedded \000 characters |
| 13381 | ** See Bug 2026-05-31T11:43:05Z */ |
| 13382 | pNew->cds.zFile = sqlite3_malloc64(nFile+1); |
| 13383 | if( pNew->cds.zFile!=0 ){ |
| 13384 | memcpy(pNew->cds.zFile, aRead, nFile); |
| 13385 | pNew->cds.zFile[nFile] = 0; |
| 13386 | } |
| 13387 | pNew->aExtra = (u8*)&pNew[1]; |
| 13388 | memcpy(pNew->aExtra, &aRead[nFile], nExtra); |
| 13389 | if( pNew->cds.zFile==0 ){ |
| 13390 | rc = SQLITE_NOMEM; |
| 13391 | }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){ |
| @@ -13844,14 +14138,14 @@ | |
| 14138 | if( zUpdate && zipfileComparePath(zUpdate, zDelete, nDelete)!=0 ){ |
| 14139 | bUpdate = 1; |
| 14140 | } |
| 14141 | } |
| 14142 | for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){ |
| 14143 | if( pOld==0 ) return SQLITE_OK; |
| 14144 | if( zipfileComparePath(pOld->cds.zFile, zDelete, nDelete)==0 ){ |
| 14145 | break; |
| 14146 | } |
| 14147 | } |
| 14148 | } |
| 14149 | |
| 14150 | if( nVal>1 ){ |
| 14151 | /* Check that "sz" and "rawdata" are both NULL: */ |
| @@ -14191,14 +14485,14 @@ | |
| 14485 | ZipfileBuffer body; |
| 14486 | ZipfileBuffer cds; |
| 14487 | }; |
| 14488 | |
| 14489 | static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){ |
| 14490 | if( (pBuf->nAlloc-pBuf->n)<nByte ){ |
| 14491 | u8 *aNew; |
| 14492 | i64 nNew = pBuf->n ? (i64)pBuf->n*2 : 512; |
| 14493 | i64 nReq = pBuf->n + nByte; |
| 14494 | |
| 14495 | while( nNew<nReq ) nNew = nNew*2; |
| 14496 | aNew = sqlite3_realloc64(pBuf->a, nNew); |
| 14497 | if( aNew==0 ) return SQLITE_NOMEM; |
| 14498 | pBuf->a = aNew; |
| @@ -14410,11 +14704,11 @@ | |
| 14704 | eocd.nEntry = (u16)p->nEntry; |
| 14705 | eocd.nEntryTotal = (u16)p->nEntry; |
| 14706 | eocd.nSize = p->cds.n; |
| 14707 | eocd.iOffset = p->body.n; |
| 14708 | |
| 14709 | nZip = (i64)p->body.n + (i64)p->cds.n + ZIPFILE_EOCD_FIXED_SZ; |
| 14710 | aZip = (u8*)sqlite3_malloc64(nZip); |
| 14711 | if( aZip==0 ){ |
| 14712 | sqlite3_result_error_nomem(pCtx); |
| 14713 | }else{ |
| 14714 | memcpy(aZip, p->body.a, p->body.n); |
| @@ -16296,11 +16590,11 @@ | |
| 16590 | p->pTable = pTab; |
| 16591 | |
| 16592 | /* The statement the vtab will pass to sqlite3_declare_vtab() */ |
| 16593 | zInner = idxAppendText(&rc, 0, "CREATE TABLE x("); |
| 16594 | for(i=0; i<pTab->nCol; i++){ |
| 16595 | zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %Q", |
| 16596 | (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl |
| 16597 | ); |
| 16598 | } |
| 16599 | zInner = idxAppendText(&rc, zInner, ")"); |
| 16600 | |
| @@ -16496,11 +16790,11 @@ | |
| 16790 | sqlite3_free(zCols); |
| 16791 | sqlite3_free(zOrder); |
| 16792 | return sqlite3_reset(pIndexXInfo); |
| 16793 | } |
| 16794 | zCols = idxAppendText(&rc, zCols, |
| 16795 | "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %Q", |
| 16796 | zComma, zName, nCol, zName, zColl |
| 16797 | ); |
| 16798 | zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol); |
| 16799 | } |
| 16800 | sqlite3_reset(pIndexXInfo); |
| @@ -17537,16 +17831,19 @@ | |
| 17831 | } |
| 17832 | iRet++; |
| 17833 | } |
| 17834 | } |
| 17835 | else if( c=='[' ){ |
| 17836 | while( z[iRet] && z[iRet++]!=']' ){} |
| 17837 | } |
| 17838 | else if( (c>='A' && c<='Z') || (c>='a' && c<='z') ){ |
| 17839 | while( (z[iRet]>='A' && z[iRet]<='Z') || (z[iRet]>='a' && z[iRet]<='z') ){ |
| 17840 | iRet++; |
| 17841 | } |
| 17842 | } |
| 17843 | else if( c==0 ){ |
| 17844 | iRet = 0; |
| 17845 | } |
| 17846 | |
| 17847 | return iRet; |
| 17848 | } |
| 17849 | |
| @@ -17983,10 +18280,27 @@ | |
| 18280 | intckFinalize(p, pStmt); |
| 18281 | |
| 18282 | if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 1"); |
| 18283 | return zRet; |
| 18284 | } |
| 18285 | |
| 18286 | /* |
| 18287 | ** Register or unregister special SQL functions implemented by intck. |
| 18288 | ** |
| 18289 | ** Normally the custom SQL functions used by intck are only available |
| 18290 | ** in between sqlite3_intck_open() and sqlite3_intck_close(). However, |
| 18291 | ** for testing and debugging, it is sometimes useful to make those |
| 18292 | ** functions available generally. This routine provides as a separate |
| 18293 | ** interface in order to provide that capability. |
| 18294 | */ |
| 18295 | int sqlite3_intck_register(sqlite3 *db, int bCreate){ |
| 18296 | int rc; |
| 18297 | rc = sqlite3_create_function(db, "parse_create_index", |
| 18298 | 2, SQLITE_UTF8, 0, bCreate ? intckParseCreateIndexFunc : 0, 0, 0 |
| 18299 | ); |
| 18300 | return rc; |
| 18301 | } |
| 18302 | |
| 18303 | /* |
| 18304 | ** Open a new integrity-check object. |
| 18305 | */ |
| 18306 | int sqlite3_intck_open( |
| @@ -18005,13 +18319,11 @@ | |
| 18319 | }else{ |
| 18320 | memset(pNew, 0, sizeof(*pNew)); |
| 18321 | pNew->db = db; |
| 18322 | pNew->zDb = (const char*)&pNew[1]; |
| 18323 | memcpy(&pNew[1], zDb, nDb+1); |
| 18324 | rc = sqlite3_intck_register(db, 1); |
| 18325 | if( rc!=SQLITE_OK ){ |
| 18326 | sqlite3_intck_close(pNew); |
| 18327 | pNew = 0; |
| 18328 | } |
| 18329 | } |
| @@ -18024,13 +18336,11 @@ | |
| 18336 | ** Free the integrity-check object. |
| 18337 | */ |
| 18338 | void sqlite3_intck_close(sqlite3_intck *p){ |
| 18339 | if( p ){ |
| 18340 | sqlite3_finalize(p->pCheck); |
| 18341 | sqlite3_intck_register(p->db, 0); |
| 18342 | sqlite3_free(p->zObj); |
| 18343 | sqlite3_free(p->zKey); |
| 18344 | sqlite3_free(p->zTestSql); |
| 18345 | sqlite3_free(p->zErr); |
| 18346 | sqlite3_free(p->zMessage); |
| @@ -19464,11 +19774,11 @@ | |
| 19774 | sqlite3_vfs_unregister(pVfs); |
| 19775 | sqlite3_free(pVfs); |
| 19776 | } |
| 19777 | |
| 19778 | /************************* End ext/misc/vfstrace.c ********************/ |
| 19779 | /************************* Begin ext/misc/diskused.c ******************/ |
| 19780 | /* |
| 19781 | ** 2026-04-13 |
| 19782 | ** |
| 19783 | ** The author disclaims copyright to this source code. In place of |
| 19784 | ** a legal notice, here is a blessing: |
| @@ -19477,12 +19787,21 @@ | |
| 19787 | ** May you find forgiveness for yourself and forgive others. |
| 19788 | ** May you share freely, never taking more than you give. |
| 19789 | ** |
| 19790 | ****************************************************************************** |
| 19791 | ** |
| 19792 | ** This extension implements an SQL function: |
| 19793 | ** |
| 19794 | ** diskused(X) |
| 19795 | ** |
| 19796 | ** Where X is the schema name (typically 'main'). The output is text |
| 19797 | ** that describes how much filesystem space the various tables and indexes |
| 19798 | ** of the database consume. |
| 19799 | ** |
| 19800 | ** This function is a replacement for the (now deprecated) |
| 19801 | ** "sqlite3_analyzer" utility program. This function is built |
| 19802 | ** into the CLI and is used to implement the ".diskused" command there. |
| 19803 | */ |
| 19804 | /* #include "sqlite3ext.h" */ |
| 19805 | SQLITE_EXTENSION_INIT1 |
| 19806 | #include <assert.h> |
| 19807 | #include <string.h> |
| @@ -19490,28 +19809,28 @@ | |
| 19809 | #include <math.h> |
| 19810 | |
| 19811 | /* |
| 19812 | ** State information for the analysis |
| 19813 | */ |
| 19814 | typedef struct DiskUsed DiskUsed; |
| 19815 | struct DiskUsed { |
| 19816 | sqlite3 *db; /* Database connection */ |
| 19817 | sqlite3_context *context; /* SQL function context */ |
| 19818 | sqlite3_str *pOut; /* Write output here */ |
| 19819 | char *zSU; /* Name of the temp.space_used table */ |
| 19820 | const char *zSchema; /* Schema to be analyzed */ |
| 19821 | }; |
| 19822 | |
| 19823 | /* |
| 19824 | ** Free all resources that the DiskUsed object references and |
| 19825 | ** reset the DiskUsed object. |
| 19826 | ** |
| 19827 | ** Call this routine multiple times on the same DiskUsed object |
| 19828 | ** is a harmless no-op, as long as the memory for the object itself |
| 19829 | ** has not been freed. |
| 19830 | */ |
| 19831 | static void diskusedReset(DiskUsed *p){ |
| 19832 | if( p->zSU ){ |
| 19833 | char *zSql = sqlite3_mprintf("DROP TABLE temp.%s;", p->zSU); |
| 19834 | if( zSql ){ |
| 19835 | sqlite3_exec(p->db, zSql, 0, 0, 0); |
| 19836 | sqlite3_free(zSql); |
| @@ -19524,11 +19843,11 @@ | |
| 19843 | |
| 19844 | /* |
| 19845 | ** Report an error using formatted text. If zFormat==NULL then report |
| 19846 | ** an OOM error. |
| 19847 | */ |
| 19848 | static void diskusedError(DiskUsed *p, const char *zFormat, ...){ |
| 19849 | char *zErr; |
| 19850 | if( zFormat ){ |
| 19851 | va_list ap; |
| 19852 | va_start(ap, zFormat); |
| 19853 | zErr = sqlite3_vmprintf(zFormat, ap); |
| @@ -19540,38 +19859,38 @@ | |
| 19859 | sqlite3_result_error_nomem(p->context); |
| 19860 | }else{ |
| 19861 | sqlite3_result_error(p->context, zErr, -1); |
| 19862 | sqlite3_free(zErr); |
| 19863 | } |
| 19864 | diskusedReset(p); |
| 19865 | } |
| 19866 | |
| 19867 | /* |
| 19868 | ** Prepare and return an SQL statement. |
| 19869 | */ |
| 19870 | static sqlite3_stmt *diskusedVPrep(DiskUsed *p, const char *zFmt, va_list ap){ |
| 19871 | char *zSql; |
| 19872 | int rc; |
| 19873 | sqlite3_stmt *pStmt = 0; |
| 19874 | zSql = sqlite3_vmprintf(zFmt, ap); |
| 19875 | if( zSql==0 ){ diskusedError(p,0); return 0; } |
| 19876 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 19877 | if( rc ){ |
| 19878 | diskusedError(p, "SQL parse error: %s\nOriginal SQL: %s", |
| 19879 | sqlite3_errmsg(p->db), zSql); |
| 19880 | sqlite3_finalize(pStmt); |
| 19881 | diskusedReset(p); |
| 19882 | pStmt = 0; |
| 19883 | } |
| 19884 | sqlite3_free(zSql); |
| 19885 | return pStmt; |
| 19886 | } |
| 19887 | static sqlite3_stmt *diskusedPrepare(DiskUsed *p, const char *zFormat, ...){ |
| 19888 | va_list ap; |
| 19889 | sqlite3_stmt *pStmt = 0; |
| 19890 | va_start(ap, zFormat); |
| 19891 | pStmt = diskusedVPrep(p,zFormat,ap); |
| 19892 | va_end(ap); |
| 19893 | return pStmt; |
| 19894 | } |
| 19895 | |
| 19896 | /* |
| @@ -19580,60 +19899,60 @@ | |
| 19899 | ** |
| 19900 | ** If rc is SQLITE_DONE or SQLITE_OK, then return false. |
| 19901 | ** |
| 19902 | ** The prepared statement is closed in either case. |
| 19903 | */ |
| 19904 | static int diskusedStmtFinish(DiskUsed *p, int rc, sqlite3_stmt *pStmt){ |
| 19905 | if( rc==SQLITE_DONE ){ |
| 19906 | rc = SQLITE_OK; |
| 19907 | } |
| 19908 | if( rc!=SQLITE_OK || (rc = sqlite3_reset(pStmt))!=SQLITE_OK ){ |
| 19909 | diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19910 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19911 | diskusedReset(p); |
| 19912 | } |
| 19913 | sqlite3_finalize(pStmt); |
| 19914 | return rc; |
| 19915 | } |
| 19916 | |
| 19917 | /* |
| 19918 | ** Run SQL. Return the number of errors. |
| 19919 | */ |
| 19920 | static int diskusedSql(DiskUsed *p, const char *zFormat, ...){ |
| 19921 | va_list ap; |
| 19922 | int rc; |
| 19923 | sqlite3_stmt *pStmt = 0; |
| 19924 | va_start(ap, zFormat); |
| 19925 | pStmt = diskusedVPrep(p,zFormat,ap); |
| 19926 | va_end(ap); |
| 19927 | if( pStmt==0 ) return 1; |
| 19928 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){} |
| 19929 | if( rc==SQLITE_DONE ){ |
| 19930 | rc = SQLITE_OK; |
| 19931 | }else{ |
| 19932 | diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19933 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19934 | diskusedReset(p); |
| 19935 | } |
| 19936 | sqlite3_finalize(pStmt); |
| 19937 | return rc; |
| 19938 | } |
| 19939 | |
| 19940 | /* |
| 19941 | ** Run an SQL query that returns an integer. Write that integer |
| 19942 | ** into *piRes. Return the number of errors. |
| 19943 | */ |
| 19944 | static int diskusedSqlInt( |
| 19945 | DiskUsed *p, |
| 19946 | sqlite3_int64 *piRes, |
| 19947 | const char *zFormat, ... |
| 19948 | ){ |
| 19949 | va_list ap; |
| 19950 | int rc; |
| 19951 | sqlite3_stmt *pStmt = 0; |
| 19952 | va_start(ap, zFormat); |
| 19953 | pStmt = diskusedVPrep(p,zFormat,ap); |
| 19954 | va_end(ap); |
| 19955 | if( pStmt==0 ) return 1; |
| 19956 | rc = sqlite3_step(pStmt); |
| 19957 | if( rc==SQLITE_ROW ){ |
| 19958 | *piRes = sqlite3_column_int64(pStmt, 0); |
| @@ -19641,14 +19960,14 @@ | |
| 19960 | }else if( rc==SQLITE_DONE ){ |
| 19961 | rc = SQLITE_OK; |
| 19962 | }else{ |
| 19963 | if( p->db ){ |
| 19964 | /* p->db is NULL if there was some prior error */ |
| 19965 | diskusedError(p, "SQL run-time error: %s\nOriginal SQL: %s", |
| 19966 | sqlite3_errmsg(p->db), sqlite3_sql(pStmt)); |
| 19967 | } |
| 19968 | diskusedReset(p); |
| 19969 | } |
| 19970 | sqlite3_finalize(pStmt); |
| 19971 | return rc; |
| 19972 | } |
| 19973 | |
| @@ -19657,20 +19976,20 @@ | |
| 19976 | ** by the format string. If the output is initially empty, begin |
| 19977 | ** the title line with "/" so that it forms the beginning of a C-style |
| 19978 | ** comment. Otherwise begin with a new-line. Always finish with a |
| 19979 | ** newline. |
| 19980 | */ |
| 19981 | static void diskusedTitle(DiskUsed *p, const char *zFormat, ...){ |
| 19982 | char *zFirst; |
| 19983 | char *zTitle; |
| 19984 | size_t nTitle; |
| 19985 | va_list ap; |
| 19986 | va_start(ap, zFormat); |
| 19987 | zTitle = sqlite3_vmprintf(zFormat, ap); |
| 19988 | va_end(ap); |
| 19989 | if( zTitle==0 ){ |
| 19990 | diskusedError(p, 0); |
| 19991 | return; |
| 19992 | } |
| 19993 | zFirst = sqlite3_str_length(p->pOut)==0 ? "/" : "\n*"; |
| 19994 | nTitle = strlen(zTitle); |
| 19995 | if( nTitle>=75 ){ |
| @@ -19685,12 +20004,12 @@ | |
| 20004 | /* |
| 20005 | ** Add an output line that begins with the zDesc text extended out to |
| 20006 | ** 50 columns with "." characters, and followed by whatever text is |
| 20007 | ** described by zFormat. |
| 20008 | */ |
| 20009 | static void diskusedLine( |
| 20010 | DiskUsed *p, /* DiskUsed context */ |
| 20011 | const char *zDesc, /* Description */ |
| 20012 | const char *zFormat, /* Argument to the description */ |
| 20013 | ... |
| 20014 | ){ |
| 20015 | char *zTxt; |
| @@ -19698,14 +20017,14 @@ | |
| 20017 | va_list ap; |
| 20018 | va_start(ap, zFormat); |
| 20019 | zTxt = sqlite3_vmprintf(zFormat, ap); |
| 20020 | va_end(ap); |
| 20021 | if( zTxt==0 ){ |
| 20022 | diskusedError(p, 0); |
| 20023 | return; |
| 20024 | } |
| 20025 | nDesc = zDesc ? strlen(zDesc) : 0; |
| 20026 | if( nDesc>=50 ){ |
| 20027 | sqlite3_str_appendf(p->pOut, "%s %z", zDesc, zTxt); |
| 20028 | }else{ |
| 20029 | int nExtra = 50 - (int)nDesc; |
| 20030 | sqlite3_str_appendf(p->pOut, "%s%.*c %z", zDesc, nExtra, '.', zTxt); |
| @@ -19715,15 +20034,28 @@ | |
| 20034 | /* |
| 20035 | ** Write a percentage into the output. The number written should show |
| 20036 | ** two or three significant digits, with the decimal point being the fourth |
| 20037 | ** character. |
| 20038 | */ |
| 20039 | static void diskusedPercent( |
| 20040 | DiskUsed *p, /* Context of the disk-usage analysis */ |
| 20041 | sqlite3_int64 num, /* Numerator of the fraction */ |
| 20042 | sqlite3_int64 denom /* Denominator of the fraction. Might be zero! */ |
| 20043 | ){ |
| 20044 | char zNum[100]; |
| 20045 | char *zDP; |
| 20046 | int nLeadingDigit; |
| 20047 | int sz; |
| 20048 | double r; |
| 20049 | if( num==0 ){ |
| 20050 | r = 0.0; |
| 20051 | }else if( denom==0 ){ |
| 20052 | sqlite3_str_appendchar(p->pOut, 1, '\n'); |
| 20053 | return; |
| 20054 | }else{ |
| 20055 | r = num*100.0/(double)denom; |
| 20056 | } |
| 20057 | sqlite3_snprintf(sizeof(zNum)-5, zNum, r>=10.0 ? "%.3g" :"%.2g", r); |
| 20058 | sz = (int)strlen(zNum); |
| 20059 | zDP = strchr(zNum, '.'); |
| 20060 | if( zDP==0 ){ |
| 20061 | memcpy(zNum+sz,".0",3); |
| @@ -19744,12 +20076,12 @@ | |
| 20076 | ** |
| 20077 | ** The title if the subreport is given by zTitle. zWhere is |
| 20078 | ** a boolean expression that can go in the WHERE clause to select |
| 20079 | ** the relevant rows of the s.zSU table. |
| 20080 | */ |
| 20081 | static int diskusedSubreport( |
| 20082 | DiskUsed *p, /* DiskUsed context */ |
| 20083 | char *zTitle, /* Title for this subreport */ |
| 20084 | char *zWhere, /* WHERE clause for this subreport */ |
| 20085 | sqlite3_int64 pgsz, /* Database page size */ |
| 20086 | sqlite3_int64 nPage /* Number of pages in entire database */ |
| 20087 | ){ |
| @@ -19773,14 +20105,14 @@ | |
| 20105 | sqlite3_int64 total_unused; /* Total unused bytes */ |
| 20106 | sqlite3_int64 total_meta; /* Total metadata */ |
| 20107 | int rc; |
| 20108 | |
| 20109 | if( zTitle==0 || zWhere==0 ){ |
| 20110 | diskusedError(p, 0); |
| 20111 | return SQLITE_NOMEM; |
| 20112 | } |
| 20113 | pStmt = diskusedPrepare(p, |
| 20114 | "SELECT\n" |
| 20115 | " sum(if(is_without_rowid OR is_index,nentry,leaf_entries)),\n" /* 0 */ |
| 20116 | " sum(payload),\n" /* 1 */ |
| 20117 | " sum(ovfl_payload),\n" /* 2 */ |
| 20118 | " max(mx_payload),\n" /* 3 */ |
| @@ -19797,11 +20129,11 @@ | |
| 20129 | " FROM temp.%s WHERE %s", |
| 20130 | p->zSU, zWhere); |
| 20131 | if( pStmt==0 ) return 1; |
| 20132 | rc = sqlite3_step(pStmt); |
| 20133 | if( rc==SQLITE_ROW ){ |
| 20134 | diskusedTitle(p, "%s", zTitle); |
| 20135 | |
| 20136 | nentry = sqlite3_column_int64(pStmt, 0); |
| 20137 | payload = sqlite3_column_int64(pStmt, 1); |
| 20138 | ovfl_payload = sqlite3_column_int64(pStmt, 2); |
| 20139 | mx_payload = sqlite3_column_int64(pStmt, 3); |
| @@ -19816,73 +20148,73 @@ | |
| 20148 | cnt = sqlite3_column_int64(pStmt, 12); |
| 20149 | int_cell = sqlite3_column_int64(pStmt, 13); |
| 20150 | rc = SQLITE_DONE; |
| 20151 | |
| 20152 | total_pages = leaf_pages + int_pages + ovfl_pages; |
| 20153 | diskusedLine(p, "Percentage of total database", "%.3g%%\n", |
| 20154 | (total_pages*100.0)/(double)nPage); |
| 20155 | diskusedLine(p, "Number of entries", "%lld\n", nentry); |
| 20156 | storage = total_pages*pgsz; |
| 20157 | diskusedLine(p, "Bytes of storage consumed", "%lld\n", storage); |
| 20158 | diskusedLine(p, "Bytes of payload", "%-11lld ", payload); |
| 20159 | diskusedPercent(p, payload, storage); |
| 20160 | if( ovfl_cnt>0 ){ |
| 20161 | diskusedLine(p, "Bytes of payload in overflow","%-11lld ",ovfl_payload); |
| 20162 | diskusedPercent(p, ovfl_payload, payload); |
| 20163 | } |
| 20164 | total_unused = leaf_unused + int_unused + ovfl_unused; |
| 20165 | total_meta = storage - payload - total_unused; |
| 20166 | diskusedLine(p, "Bytes of metadata","%-11lld ", total_meta); |
| 20167 | diskusedPercent(p, total_meta, storage); |
| 20168 | if( cnt==1 ){ |
| 20169 | diskusedLine(p, "B-tree depth", "%lld\n", depth); |
| 20170 | if( int_cell>1 ){ |
| 20171 | diskusedLine(p, "Average fanout", "%.1f\n", |
| 20172 | (double)(int_cell+int_pages)/(double)int_pages); |
| 20173 | } |
| 20174 | } |
| 20175 | if( nentry>0 ){ |
| 20176 | diskusedLine(p, "Average payload per entry", "%.1f\n", |
| 20177 | (double)payload/(double)nentry); |
| 20178 | diskusedLine(p, "Average unused bytes per entry", "%.1f\n", |
| 20179 | (double)total_unused/(double)nentry); |
| 20180 | diskusedLine(p, "Average metadata per entry", "%.1f\n", |
| 20181 | (double)total_meta/(double)nentry); |
| 20182 | } |
| 20183 | diskusedLine(p, "Maximum single-entry payload", "%lld\n", mx_payload); |
| 20184 | if( nentry>0 ){ |
| 20185 | diskusedLine(p, "Entries that use overflow", "%-11lld ", ovfl_cnt); |
| 20186 | diskusedPercent(p, ovfl_cnt, nentry); |
| 20187 | } |
| 20188 | if( int_pages>0 ){ |
| 20189 | diskusedLine(p, "Index pages used", "%lld\n", int_pages); |
| 20190 | } |
| 20191 | diskusedLine(p, "Primary pages used", "%lld\n", leaf_pages); |
| 20192 | if( ovfl_cnt ){ |
| 20193 | diskusedLine(p, "Overflow pages used", "%lld\n", ovfl_pages); |
| 20194 | } |
| 20195 | diskusedLine(p, "Total pages used", "%lld\n", total_pages); |
| 20196 | if( int_pages>0 ){ |
| 20197 | diskusedLine(p, "Unused bytes on index pages", "%lld\n", int_unused); |
| 20198 | } |
| 20199 | diskusedLine(p, "Unused bytes on primary pages", "%lld\n", leaf_unused); |
| 20200 | if( ovfl_cnt ){ |
| 20201 | diskusedLine(p, "Unused bytes on overflow pages", "%lld\n", ovfl_unused); |
| 20202 | } |
| 20203 | diskusedLine(p, "Unused bytes on all pages", "%-11lld ", total_unused); |
| 20204 | diskusedPercent(p, total_unused, storage); |
| 20205 | } |
| 20206 | return diskusedStmtFinish(p, rc, pStmt); |
| 20207 | } |
| 20208 | |
| 20209 | /* |
| 20210 | ** SQL Function: diskused(SCHEMA) |
| 20211 | ** |
| 20212 | ** Analyze the database schema named in the argument. Return text |
| 20213 | ** containing the space utilization stats. |
| 20214 | */ |
| 20215 | static void diskusedFunc( |
| 20216 | sqlite3_context *context, |
| 20217 | int argc, |
| 20218 | sqlite3_value **argv |
| 20219 | ){ |
| 20220 | int rc; |
| @@ -19893,47 +20225,47 @@ | |
| 20225 | sqlite3_int64 nPage; |
| 20226 | sqlite3_int64 nPageInUse; |
| 20227 | sqlite3_int64 nFreeList; |
| 20228 | sqlite3_int64 nIndex; |
| 20229 | sqlite3_int64 nWORowid; |
| 20230 | DiskUsed s; |
| 20231 | sqlite3_uint64 r[2]; |
| 20232 | |
| 20233 | (void)argc; |
| 20234 | memset(&s, 0, sizeof(s)); |
| 20235 | s.db = sqlite3_context_db_handle(context); |
| 20236 | s.context = context; |
| 20237 | s.pOut = sqlite3_str_new(0); |
| 20238 | if( sqlite3_str_errcode(s.pOut) ){ |
| 20239 | diskusedError(&s, 0); |
| 20240 | return; |
| 20241 | } |
| 20242 | s.zSchema = (const char*)sqlite3_value_text(argv[0]); |
| 20243 | if( s.zSchema==0 ){ |
| 20244 | s.zSchema = "main"; |
| 20245 | }else if( sqlite3_strlike("temp",s.zSchema,0)==0 ){ |
| 20246 | diskusedReset(&s); |
| 20247 | sqlite3_result_text(context, "cannot analyze \"temp\"",-1,SQLITE_STATIC); |
| 20248 | return; |
| 20249 | } |
| 20250 | ii = 0; |
| 20251 | rc = diskusedSqlInt(&s,&ii,"SELECT 1 FROM pragma_database_list" |
| 20252 | " WHERE name=%Q COLLATE nocase",s.zSchema); |
| 20253 | if( rc || ii==0 ){ |
| 20254 | diskusedReset(&s); |
| 20255 | sqlite3_result_text(context,"no such database",-1,SQLITE_STATIC); |
| 20256 | return; |
| 20257 | } |
| 20258 | sqlite3_randomness(sizeof(r), &r); |
| 20259 | s.zSU = sqlite3_mprintf("diskused%016llx%016llx", r[0], r[1]); |
| 20260 | if( s.zSU==0 ){ diskusedError(&s, 0); return; } |
| 20261 | |
| 20262 | /* The s.zSU table contains the data used for the analysis. |
| 20263 | ** The table name contains 128-bits of randomness to avoid |
| 20264 | ** collisions with preexisting tables in temp. |
| 20265 | */ |
| 20266 | rc = diskusedSql(&s, |
| 20267 | "CREATE TABLE temp.%s(\n" |
| 20268 | " name text, -- A table or index\n" |
| 20269 | " tblname text, -- Table that owns name\n" |
| 20270 | " is_index boolean, -- TRUE if it is an index\n" |
| 20271 | " is_without_rowid boolean, -- TRUE if WITHOUT ROWID table\n" |
| @@ -19956,11 +20288,11 @@ | |
| 20288 | ); |
| 20289 | if( rc ) return; |
| 20290 | |
| 20291 | /* Populate the s.zSU table |
| 20292 | */ |
| 20293 | rc = diskusedSql(&s, |
| 20294 | "WITH\n" |
| 20295 | " allidx(idxname) AS (\n" |
| 20296 | " SELECT name FROM \"%w\".sqlite_schema WHERE type='index'\n" |
| 20297 | " ),\n" |
| 20298 | " allobj(allname,tblname,isidx,isworowid) AS (\n" |
| @@ -20008,141 +20340,143 @@ | |
| 20340 | s.zSchema /* JOIN dbstat(%Q) */ |
| 20341 | ); |
| 20342 | if( rc ) return; |
| 20343 | |
| 20344 | nPage = 0; |
| 20345 | rc = diskusedSqlInt(&s, &nPage, "PRAGMA \"%w\".page_count", s.zSchema); |
| 20346 | if( rc ) return; |
| 20347 | if( nPage<=0 ){ |
| 20348 | /* Very brief reply for an empty database */ |
| 20349 | diskusedReset(&s); |
| 20350 | sqlite3_result_text(context, "empty database", -1, SQLITE_STATIC); |
| 20351 | return; |
| 20352 | } |
| 20353 | |
| 20354 | /* Begin generating the report */ |
| 20355 | diskusedTitle(&s, "Database storage utilization report"); |
| 20356 | pgsz = 0; |
| 20357 | rc = diskusedSqlInt(&s, &pgsz, "PRAGMA \"%w\".page_size", s.zSchema); |
| 20358 | if( rc ) return; |
| 20359 | diskusedLine(&s, "Page size in bytes","%lld\n",pgsz); |
| 20360 | diskusedLine(&s, "Pages in the database", "%lld\n", nPage); |
| 20361 | |
| 20362 | nPageInUse = 0; |
| 20363 | rc = diskusedSqlInt(&s, &nPageInUse, |
| 20364 | "SELECT sum(leaf_pages+int_pages+ovfl_pages) FROM temp.%s", s.zSU); |
| 20365 | if( rc ) return; |
| 20366 | diskusedLine(&s, "Pages that store data", "%-11lld ", nPageInUse); |
| 20367 | diskusedPercent(&s, nPageInUse, nPage); |
| 20368 | |
| 20369 | nFreeList = 0; |
| 20370 | rc = diskusedSqlInt(&s, &nFreeList, "PRAGMA \"%w\".freelist_count",s.zSchema); |
| 20371 | if( rc ) return; |
| 20372 | diskusedLine(&s, "Pages on the freelist", "%-11lld ", nFreeList); |
| 20373 | diskusedPercent(&s, nFreeList, nPage); |
| 20374 | |
| 20375 | ii = 0; |
| 20376 | rc = diskusedSqlInt(&s, &ii, "PRAGMA \"%w\".auto_vacuum", s.zSchema); |
| 20377 | if( rc ) return; |
| 20378 | if( ii==0 || nPage<=1 ){ |
| 20379 | ii = 0; |
| 20380 | }else{ |
| 20381 | double rPtrsPerPage = pgsz/5; |
| 20382 | double rAvPage = (nPage-1.0)/(rPtrsPerPage+1.0); |
| 20383 | ii = (sqlite3_int64)ceil(rAvPage); |
| 20384 | } |
| 20385 | diskusedLine(&s, "Pages of auto-vacuum overhead", "%-11lld ", ii); |
| 20386 | diskusedPercent(&s, ii, nPage); |
| 20387 | |
| 20388 | ii = 0; |
| 20389 | rc = diskusedSqlInt(&s, &ii, |
| 20390 | "SELECT count(*)+1 FROM \"%w\".sqlite_schema WHERE type='table'", |
| 20391 | s.zSchema); |
| 20392 | if( rc ) return; |
| 20393 | diskusedLine(&s, "Number of tables", "%lld\n", ii); |
| 20394 | nWORowid = 0; |
| 20395 | rc = diskusedSqlInt(&s, &nWORowid, |
| 20396 | "SELECT count(*) FROM \"%w\".pragma_table_list WHERE wr", |
| 20397 | s.zSchema); |
| 20398 | if( rc ) return; |
| 20399 | if( nWORowid>0 ){ |
| 20400 | diskusedLine(&s, "Number of WITHOUT ROWID tables", "%lld\n", nWORowid); |
| 20401 | diskusedLine(&s, "Number of rowid tables", "%lld\n", ii - nWORowid); |
| 20402 | } |
| 20403 | nIndex = 0; |
| 20404 | rc = diskusedSqlInt(&s, &nIndex, |
| 20405 | "SELECT count(*) FROM \"%w\".sqlite_schema WHERE type='index'", |
| 20406 | s.zSchema); |
| 20407 | if( rc ) return; |
| 20408 | diskusedLine(&s, "Number of indexes", "%lld\n", nIndex); |
| 20409 | ii = 0; |
| 20410 | rc = diskusedSqlInt(&s, &ii, |
| 20411 | "SELECT count(*) FROM \"%w\".sqlite_schema" |
| 20412 | " WHERE name GLOB 'sqlite_autoindex_*' AND type='index'", |
| 20413 | s.zSchema); |
| 20414 | if( rc ) return; |
| 20415 | diskusedLine(&s, "Number of defined indexes", "%lld\n", nIndex - ii); |
| 20416 | diskusedLine(&s, "Number of implied indexes", "%lld\n", ii); |
| 20417 | diskusedLine(&s, "Size of the database in bytes", "%lld\n", pgsz*nPage); |
| 20418 | ii = 0; |
| 20419 | rc = diskusedSqlInt(&s, &ii, |
| 20420 | "SELECT sum(payload) FROM temp.%s" |
| 20421 | " WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'", |
| 20422 | s.zSU); |
| 20423 | if( rc ) return; |
| 20424 | diskusedLine(&s, "Bytes of payload", "%-11lld ", ii); |
| 20425 | diskusedPercent(&s, ii, pgsz*nPage); |
| 20426 | |
| 20427 | diskusedTitle(&s, "Page counts for all tables with their indexes"); |
| 20428 | pStmt = diskusedPrepare(&s, |
| 20429 | "SELECT upper(tblname),\n" |
| 20430 | " sum(int_pages+leaf_pages+ovfl_pages)\n" |
| 20431 | " FROM temp.%s\n" |
| 20432 | " WHERE tblname IS NOT NULL\n" |
| 20433 | " GROUP BY 1\n" |
| 20434 | " ORDER BY 2 DESC, 1;", |
| 20435 | s.zSU); |
| 20436 | if( pStmt==0 ) return; |
| 20437 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| 20438 | sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); |
| 20439 | diskusedLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); |
| 20440 | diskusedPercent(&s, nn, nPage); |
| 20441 | } |
| 20442 | if( diskusedStmtFinish(&s, rc, pStmt) ) return; |
| 20443 | |
| 20444 | diskusedTitle(&s, "Page counts for all tables and indexes separately"); |
| 20445 | pStmt = diskusedPrepare(&s, |
| 20446 | "SELECT upper(name),\n" |
| 20447 | " sum(int_pages+leaf_pages+ovfl_pages)\n" |
| 20448 | " FROM temp.%s\n" |
| 20449 | " WHERE name IS NOT NULL\n" |
| 20450 | " GROUP BY 1\n" |
| 20451 | " ORDER BY 2 DESC, 1;", |
| 20452 | s.zSU); |
| 20453 | if( pStmt==0 ) return; |
| 20454 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| 20455 | sqlite3_int64 nn = sqlite3_column_int64(pStmt,1); |
| 20456 | diskusedLine(&s, (const char*)sqlite3_column_text(pStmt,0), "%-11lld ", nn); |
| 20457 | diskusedPercent(&s, nn, nPage); |
| 20458 | } |
| 20459 | if( diskusedStmtFinish(&s, rc, pStmt) ) return; |
| 20460 | |
| 20461 | rc = diskusedSubreport(&s, "All tables and indexes", "1", pgsz, nPage); |
| 20462 | if( rc ) return; |
| 20463 | rc = diskusedSubreport(&s, "All tables", "NOT is_index", pgsz, nPage); |
| 20464 | if( rc ) return; |
| 20465 | if( nWORowid>0 ){ |
| 20466 | rc = diskusedSubreport(&s, "All WITHOUT ROWID tables", "is_without_rowid", |
| 20467 | pgsz, nPage); |
| 20468 | if( rc ) return; |
| 20469 | rc = diskusedSubreport(&s, "All rowid tables", |
| 20470 | "NOT is_without_rowid AND NOT is_index", |
| 20471 | pgsz, nPage); |
| 20472 | if( rc ) return; |
| 20473 | } |
| 20474 | rc = diskusedSubreport(&s, "All indexes", "is_index", pgsz, nPage); |
| 20475 | if( rc ) return; |
| 20476 | |
| 20477 | pStmt = diskusedPrepare(&s, |
| 20478 | "SELECT upper(tblname), tblname, sum(is_index) FROM temp.%s" |
| 20479 | " GROUP BY 1 ORDER BY 1", |
| 20480 | s.zSU); |
| 20481 | if( pStmt==0 ) return; |
| 20482 | while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ |
| @@ -20150,37 +20484,37 @@ | |
| 20484 | const char *zName = (const char*)sqlite3_column_text(pStmt, 1); |
| 20485 | int nSubIndex = sqlite3_column_int(pStmt, 2); |
| 20486 | if( nSubIndex==0 ){ |
| 20487 | char *zTitle = sqlite3_mprintf("Table %s", zUpper); |
| 20488 | char *zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20489 | rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20490 | sqlite3_free(zTitle); |
| 20491 | sqlite3_free(zWhere); |
| 20492 | if( rc ) break; |
| 20493 | }else{ |
| 20494 | sqlite3_stmt *pS2; |
| 20495 | char *zTitle = sqlite3_mprintf("Table %s and all its indexes", zUpper); |
| 20496 | char *zWhere = sqlite3_mprintf("tblname=%Q", zName); |
| 20497 | rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20498 | sqlite3_free(zTitle); |
| 20499 | sqlite3_free(zWhere); |
| 20500 | if( rc ) break; |
| 20501 | zTitle = sqlite3_mprintf("Table %s w/o any indexes", zUpper); |
| 20502 | zWhere = sqlite3_mprintf("name=%Q", zName); |
| 20503 | rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20504 | sqlite3_free(zTitle); |
| 20505 | sqlite3_free(zWhere); |
| 20506 | if( rc ) break; |
| 20507 | if( nSubIndex>1 ){ |
| 20508 | zTitle = sqlite3_mprintf("All indexes of table %s", zUpper); |
| 20509 | zWhere = sqlite3_mprintf("tblname=%Q AND is_index", zName); |
| 20510 | rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20511 | sqlite3_free(zTitle); |
| 20512 | sqlite3_free(zWhere); |
| 20513 | if( rc ) break; |
| 20514 | } |
| 20515 | pS2 = diskusedPrepare(&s, |
| 20516 | "SELECT name, upper(name) FROM temp.%s" |
| 20517 | " WHERE is_index AND tblname=%Q", |
| 20518 | s.zSU, zName); |
| 20519 | if( pS2==0 ){ |
| 20520 | rc = SQLITE_NOMEM; |
| @@ -20189,25 +20523,25 @@ | |
| 20523 | while( (rc = sqlite3_step(pS2))==SQLITE_ROW ){ |
| 20524 | const char *zU = (const char*)sqlite3_column_text(pS2, 1); |
| 20525 | const char *zN = (const char*)sqlite3_column_text(pS2, 0); |
| 20526 | zTitle = sqlite3_mprintf("Index %s", zU); |
| 20527 | zWhere = sqlite3_mprintf("name=%Q", zN); |
| 20528 | rc = diskusedSubreport(&s, zTitle, zWhere, pgsz, nPage); |
| 20529 | sqlite3_free(zTitle); |
| 20530 | sqlite3_free(zWhere); |
| 20531 | if( rc ) break; |
| 20532 | } |
| 20533 | rc = diskusedStmtFinish(&s, rc, pS2); |
| 20534 | if( rc ) break; |
| 20535 | } |
| 20536 | } |
| 20537 | if( diskusedStmtFinish(&s, rc, pStmt) ) return; |
| 20538 | |
| 20539 | /* Append SQL statements that will recreate the raw data used for |
| 20540 | ** the analysis. |
| 20541 | */ |
| 20542 | diskusedTitle(&s, "Raw data used to generate this report"); |
| 20543 | sqlite3_str_appendf(s.pOut, |
| 20544 | "The following SQL will create a table named \"space_used\" which\n" |
| 20545 | "contains most of the information used to generate the report above.\n" |
| 20546 | "*/\n" |
| 20547 | ); |
| @@ -20233,11 +20567,11 @@ | |
| 20567 | " ovfl_unused int, -- Unused bytes on overflow pages\n" /* 16 */ |
| 20568 | " int_entries int -- B-tree entries on internal pages\n"/* 17 */ |
| 20569 | ");\n" |
| 20570 | "INSERT INTO space_used VALUES\n" |
| 20571 | ); |
| 20572 | pStmt = diskusedPrepare(&s, |
| 20573 | "SELECT quote(name), quote(tblname),\n" /* 0..1 */ |
| 20574 | " is_index, is_without_rowid, nentry, leaf_entries,\n" /* 2..5 */ |
| 20575 | " depth, payload, ovfl_payload, ovfl_cnt, mx_payload,\n" /* 6..10 */ |
| 20576 | " int_pages, leaf_pages, ovfl_pages, int_unused,\n" /* 11..14 */ |
| 20577 | " leaf_unused, ovfl_unused, int_entries\n" /* 15..17 */ |
| @@ -20268,11 +20602,11 @@ | |
| 20602 | sqlite3_column_int64(pStmt, 15), |
| 20603 | sqlite3_column_int64(pStmt, 16), |
| 20604 | sqlite3_column_int64(pStmt, 17)); |
| 20605 | } |
| 20606 | if( rc!=SQLITE_DONE ){ |
| 20607 | diskusedError(&s, "SQL run-time error: %s\nSQL: %s", |
| 20608 | sqlite3_errmsg(s.db), sqlite3_sql(pStmt)); |
| 20609 | sqlite3_finalize(pStmt); |
| 20610 | return; |
| 20611 | } |
| 20612 | sqlite3_str_appendf(s.pOut,";\nCOMMIT;"); |
| @@ -20281,32 +20615,144 @@ | |
| 20615 | if( sqlite3_str_length(s.pOut) ){ |
| 20616 | sqlite3_result_text(context, sqlite3_str_finish(s.pOut), -1, |
| 20617 | sqlite3_free); |
| 20618 | s.pOut = 0; |
| 20619 | } |
| 20620 | diskusedReset(&s); |
| 20621 | } |
| 20622 | |
| 20623 | |
| 20624 | #ifdef _WIN32 |
| 20625 | |
| 20626 | #endif |
| 20627 | int sqlite3_diskused_init( |
| 20628 | sqlite3 *db, |
| 20629 | char **pzErrMsg, |
| 20630 | const sqlite3_api_routines *pApi |
| 20631 | ){ |
| 20632 | int rc = SQLITE_OK; |
| 20633 | SQLITE_EXTENSION_INIT2(pApi); |
| 20634 | (void)pzErrMsg; /* Unused parameter */ |
| 20635 | rc = sqlite3_create_function(db, "diskused", 1, |
| 20636 | SQLITE_UTF8|SQLITE_DIRECTONLY, |
| 20637 | 0, diskusedFunc, 0, 0); |
| 20638 | return rc; |
| 20639 | } |
| 20640 | |
| 20641 | /************************* End ext/misc/diskused.c ********************/ |
| 20642 | /************************* Begin ext/misc/strdup.c ******************/ |
| 20643 | /* |
| 20644 | ** 2026-07-04 |
| 20645 | ** |
| 20646 | ** The author disclaims copyright to this source code. In place of |
| 20647 | ** a legal notice, here is a blessing: |
| 20648 | ** |
| 20649 | ** May you do good and not evil. |
| 20650 | ** May you find forgiveness for yourself and forgive others. |
| 20651 | ** May you share freely, never taking more than you give. |
| 20652 | ** |
| 20653 | ****************************************************************************** |
| 20654 | ** |
| 20655 | ** Since this module was written (coincidentally) on the 250th anniversary |
| 20656 | ** of the signing of the Declaration of Independence of The United States, |
| 20657 | ** it seems fitting to quote from that document: |
| 20658 | ** |
| 20659 | ** We hold these truths to be self-evident, that all men are created |
| 20660 | ** equal, that they are endowed by their Creator with certain unalienable |
| 20661 | ** Rights, that among these are Life, Liberty and the pursuit of Happiness |
| 20662 | ** - That to secure these rights, Governments are instituted among Men, |
| 20663 | ** deriving their just powers from the consent of the governed,.... |
| 20664 | ** |
| 20665 | ** Two core ideas that (1) rights come from God and not from government, |
| 20666 | ** and that (2) there should not be special privileged classes of people |
| 20667 | ** were radical thoughts then, and are indeed disputed even today. Many |
| 20668 | ** people still hold that human rights derive from the beneficence of |
| 20669 | ** government and that certain classes of people have special rights and |
| 20670 | ** privileges not available to all. Yet, were it not for the crazy ideas |
| 20671 | ** espoused in the original Declaration of Independence, this software |
| 20672 | ** project, and indeed most of modern technology, would not exist. |
| 20673 | ** |
| 20674 | ** Therefore let us give thanks for the bold leadership and vision |
| 20675 | ** demonstrated by the authors of the American Revolution, 250 years ago |
| 20676 | ** this day. |
| 20677 | ** |
| 20678 | ****************************************************************************** |
| 20679 | ** |
| 20680 | ** Implementation of the strdup() SQL function. strdup() makes a copy |
| 20681 | ** of its argument (a string or a BLOB) into memory obtained directly |
| 20682 | ** from system malloc() (not from sqlite3_malloc()) and sized exactly |
| 20683 | ** to hold the string or BLOB. This is intended for testing purposes, |
| 20684 | ** particularly testing with ASAN. This function serves no practical |
| 20685 | ** purpose beyond testing and not not intended for production use. |
| 20686 | ** |
| 20687 | ** NULL, BLOB, and TEXT values come through as NULL, BLOB, and TEXT, |
| 20688 | ** respectively. Numeric values are rendered as strings and come out |
| 20689 | ** as text. |
| 20690 | */ |
| 20691 | /* #include "sqlite3ext.h" */ |
| 20692 | SQLITE_EXTENSION_INIT1 |
| 20693 | #include <assert.h> |
| 20694 | #include <string.h> |
| 20695 | #include <stdlib.h> |
| 20696 | |
| 20697 | /* |
| 20698 | ** Make a copy of a string or BLOB in memory obtained from malloc(). |
| 20699 | */ |
| 20700 | static void strdupfunc( |
| 20701 | sqlite3_context *context, |
| 20702 | int argc, |
| 20703 | sqlite3_value **argv |
| 20704 | ){ |
| 20705 | const unsigned char *zIn; |
| 20706 | int nIn; |
| 20707 | unsigned char *zOut; |
| 20708 | |
| 20709 | assert( argc==1 ); |
| 20710 | if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; |
| 20711 | if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){ |
| 20712 | zIn = (const unsigned char*)sqlite3_value_blob(argv[0]); |
| 20713 | nIn = sqlite3_value_bytes(argv[0]); |
| 20714 | zOut = malloc( nIn==0 ? 1 : nIn ); |
| 20715 | if( zOut==0 ){ |
| 20716 | sqlite3_result_error_nomem(context); |
| 20717 | return; |
| 20718 | } |
| 20719 | if( nIn>0 ) memcpy(zOut, zIn, nIn); |
| 20720 | sqlite3_result_blob(context, zOut, nIn, free); |
| 20721 | }else{ |
| 20722 | zIn = (const unsigned char*)sqlite3_value_text(argv[0]); |
| 20723 | if( zIn==0 ) return; |
| 20724 | nIn = (int)strlen((char*)zIn); |
| 20725 | zOut = malloc( nIn+1 ); |
| 20726 | if( zOut==0 ){ |
| 20727 | sqlite3_result_error_nomem(context); |
| 20728 | return; |
| 20729 | } |
| 20730 | memcpy(zOut, zIn, nIn); |
| 20731 | zOut[nIn] = 0; |
| 20732 | sqlite3_result_text64(context, (char*)zOut, nIn, free, |
| 20733 | SQLITE_UTF8_ZT); |
| 20734 | } |
| 20735 | } |
| 20736 | |
| 20737 | #ifdef _WIN32 |
| 20738 | |
| 20739 | #endif |
| 20740 | int sqlite3_strdup_init( |
| 20741 | sqlite3 *db, |
| 20742 | char **pzErrMsg, |
| 20743 | const sqlite3_api_routines *pApi |
| 20744 | ){ |
| 20745 | int rc = SQLITE_OK; |
| 20746 | SQLITE_EXTENSION_INIT2(pApi); |
| 20747 | (void)pzErrMsg; /* Unused parameter */ |
| 20748 | rc = sqlite3_create_function(db, "strdup", 1, SQLITE_UTF8, |
| 20749 | 0, strdupfunc, 0, 0); |
| 20750 | return rc; |
| 20751 | } |
| 20752 | |
| 20753 | /************************* End ext/misc/strdup.c ********************/ |
| 20754 | |
| 20755 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| 20756 | #define SQLITE_SHELL_HAVE_RECOVER 1 |
| 20757 | #else |
| 20758 | #define SQLITE_SHELL_HAVE_RECOVER 0 |
| @@ -22123,23 +22569,44 @@ | |
| 22569 | int rc = sqlite3_finalize(pStmt); |
| 22570 | if( rc!=SQLITE_OK && p->errCode==SQLITE_OK ){ |
| 22571 | recoverDbError(p, db); |
| 22572 | } |
| 22573 | } |
| 22574 | |
| 22575 | /* |
| 22576 | ** Run a single SQL statement in zSql. If zSql contains two or more |
| 22577 | ** SQL statements separated by ';', only the first is run. |
| 22578 | ** |
| 22579 | ** Return the sqlite3_finalizer() or sqlite3_prepare() result code |
| 22580 | ** from running the zSql statement. |
| 22581 | */ |
| 22582 | static int recoverOneStmt(sqlite3 *db, const char *zSql){ |
| 22583 | sqlite3_stmt *pStmt = 0; |
| 22584 | int rc; |
| 22585 | if( zSql==0 ) return SQLITE_OK; |
| 22586 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); |
| 22587 | if( rc ){ |
| 22588 | sqlite3_finalize(pStmt); |
| 22589 | return rc; |
| 22590 | } |
| 22591 | while( SQLITE_ROW==sqlite3_step(pStmt) ){} |
| 22592 | return sqlite3_finalize(pStmt); |
| 22593 | } |
| 22594 | |
| 22595 | /* |
| 22596 | ** This function is a no-op if recover handle p already contains an error |
| 22597 | ** (if p->errCode!=SQLITE_OK). A copy of p->errCode is returned in this |
| 22598 | ** case. |
| 22599 | ** |
| 22600 | ** Otherwise, execute a single SQL statment in zSql. Even if zSql contains |
| 22601 | ** two or more SQL statements separated by ';', only execute the first one. |
| 22602 | ** If successful, return SQLITE_OK. Or, if an error occurs, leave an error |
| 22603 | ** code and message in the recover handle and return a copy of the error code. |
| 22604 | */ |
| 22605 | static int recoverExec(sqlite3_recover *p, sqlite3 *db, const char *zSql){ |
| 22606 | if( p->errCode==SQLITE_OK ){ |
| 22607 | int rc = recoverOneStmt(db, zSql); |
| 22608 | if( rc ){ |
| 22609 | recoverDbError(p, db); |
| 22610 | } |
| 22611 | } |
| 22612 | return p->errCode; |
| @@ -22535,11 +23002,12 @@ | |
| 23002 | recoverError(p, SQLITE_NOMEM, 0); |
| 23003 | } |
| 23004 | } |
| 23005 | recoverFinalize(p, p1); |
| 23006 | } |
| 23007 | recoverExec(p, db2, "CREATE TABLE t1(a)"); |
| 23008 | recoverExec(p, db2, "DROP TABLE t1"); |
| 23009 | |
| 23010 | if( p->errCode==SQLITE_OK ){ |
| 23011 | sqlite3 *db = p->dbOut; |
| 23012 | sqlite3_backup *pBackup = sqlite3_backup_init(db, "main", db2, "main"); |
| 23013 | if( pBackup ){ |
| @@ -22617,16 +23085,16 @@ | |
| 23085 | ** discarded. |
| 23086 | */ |
| 23087 | static void recoverOpenRecovery(sqlite3_recover *p){ |
| 23088 | char *zSql = recoverMPrintf(p, "ATTACH %Q AS recovery;", p->zStateDb); |
| 23089 | recoverExec(p, p->dbOut, zSql); |
| 23090 | sqlite3_free(zSql); |
| 23091 | recoverExec(p, p->dbOut, "PRAGMA writable_schema = 1"); |
| 23092 | recoverExec(p, p->dbOut, |
| 23093 | "CREATE TABLE recovery.map(pgno INTEGER PRIMARY KEY, parent INT)"); |
| 23094 | recoverExec(p, p->dbOut, |
| 23095 | "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql)"); |
| 23096 | } |
| 23097 | |
| 23098 | |
| 23099 | /* |
| 23100 | ** This function is a no-op if recover handle p already contains an error |
| @@ -22762,11 +23230,11 @@ | |
| 23230 | " (type='index' AND (sql LIKE '%unique%' OR ?1))" |
| 23231 | " FROM recovery.schema" |
| 23232 | ")" |
| 23233 | "SELECT rootpage, tbl, isVirtual, name, sql" |
| 23234 | " FROM dbschema " |
| 23235 | " WHERE (tbl OR isIndex) AND sql GLOB 'CREATE *'" |
| 23236 | " ORDER BY tbl DESC, name=='sqlite_sequence' DESC" |
| 23237 | ); |
| 23238 | |
| 23239 | pTblname = recoverPrepare(p, p->dbOut, |
| 23240 | "SELECT name FROM sqlite_schema " |
| @@ -22788,11 +23256,11 @@ | |
| 23256 | zSql = (const char*)(zFree = recoverMPrintf(p, |
| 23257 | "INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)", |
| 23258 | zName, zName, zSql |
| 23259 | )); |
| 23260 | } |
| 23261 | rc = recoverOneStmt(p->dbOut, zSql); |
| 23262 | if( rc==SQLITE_OK ){ |
| 23263 | recoverSqlCallback(p, zSql); |
| 23264 | if( bTable && !bVirtual ){ |
| 23265 | if( SQLITE_ROW==sqlite3_step(pTblname) ){ |
| 23266 | const char *zTbl = (const char*)sqlite3_column_text(pTblname, 0); |
| @@ -22830,19 +23298,21 @@ | |
| 23298 | |
| 23299 | pSelect = recoverPrepare(p, p->dbOut, |
| 23300 | p->bSlowIndexes ? |
| 23301 | "SELECT rootpage, sql FROM recovery.schema " |
| 23302 | " WHERE type!='table' AND type!='index'" |
| 23303 | " AND sql GLOB 'CREATE *'" |
| 23304 | : |
| 23305 | "SELECT rootpage, sql FROM recovery.schema " |
| 23306 | " WHERE type!='table' AND (type!='index' OR sql NOT LIKE '%unique%')" |
| 23307 | " AND sql GLOB 'CREATE *'" |
| 23308 | ); |
| 23309 | |
| 23310 | if( pSelect ){ |
| 23311 | while( sqlite3_step(pSelect)==SQLITE_ROW ){ |
| 23312 | const char *zSql = (const char*)sqlite3_column_text(pSelect, 1); |
| 23313 | int rc = recoverOneStmt(p->dbOut, zSql); |
| 23314 | if( rc==SQLITE_OK ){ |
| 23315 | recoverSqlCallback(p, zSql); |
| 23316 | }else if( rc!=SQLITE_ERROR ){ |
| 23317 | recoverDbError(p, p->dbOut); |
| 23318 | } |
| @@ -24216,11 +24686,11 @@ | |
| 24686 | recoverCacheSchema(p); |
| 24687 | |
| 24688 | if( bUseWrapper ) recoverUninstallWrapper(p); |
| 24689 | }while( p->errCode==SQLITE_NOTADB |
| 24690 | && (bUseWrapper--) |
| 24691 | && SQLITE_OK==recoverOneStmt(p->dbIn, "ROLLBACK") |
| 24692 | ); |
| 24693 | } |
| 24694 | |
| 24695 | recoverLeaveMutex(); |
| 24696 | recoverExec(p, p->dbOut, "BEGIN"); |
| @@ -24281,11 +24751,11 @@ | |
| 24751 | |
| 24752 | /* If no error has occurred, commit the write transaction on the output |
| 24753 | ** database. Regardless of whether or not an error has occurred, make |
| 24754 | ** an attempt to end the read transaction on the input database. */ |
| 24755 | recoverExec(p, p->dbOut, "COMMIT"); |
| 24756 | rc = recoverOneStmt(p->dbIn, "END"); |
| 24757 | if( p->errCode==SQLITE_OK ) p->errCode = rc; |
| 24758 | |
| 24759 | recoverSqlCallback(p, "PRAGMA writable_schema = off"); |
| 24760 | recoverSqlCallback(p, "COMMIT"); |
| 24761 | p->eState = RECOVER_STATE_DONE; |
| @@ -24477,11 +24947,11 @@ | |
| 24947 | if( p==0 ){ |
| 24948 | rc = SQLITE_NOMEM; |
| 24949 | }else{ |
| 24950 | recoverFinalCleanup(p); |
| 24951 | if( p->bCloseTransaction && sqlite3_get_autocommit(p->dbIn)==0 ){ |
| 24952 | rc = recoverOneStmt(p->dbIn, "END"); |
| 24953 | if( p->errCode==SQLITE_OK ) p->errCode = rc; |
| 24954 | } |
| 24955 | rc = p->errCode; |
| 24956 | sqlite3_free(p->zErrMsg); |
| 24957 | sqlite3_free(p->zStateDb); |
| @@ -24499,10 +24969,20 @@ | |
| 24969 | #endif |
| 24970 | #ifdef SQLITE_SHELL_EXTSRC |
| 24971 | # include SHELL_STRINGIFY(SQLITE_SHELL_EXTSRC) |
| 24972 | #endif |
| 24973 | |
| 24974 | /* |
| 24975 | ** Set the SQLITE_SHELL_EDITION to a YYYYMMDD date string and the |
| 24976 | ** code will attempt to use defaults for the prompt and for the |
| 24977 | ** initial output mode (and maybe other feature) that were for |
| 24978 | ** the most recent version not newer than the specified date. |
| 24979 | */ |
| 24980 | #ifndef SQLITE_SHELL_EDITION |
| 24981 | # define SQLITE_SHELL_EDITION 99991231 /* Use the latest if unspecified */ |
| 24982 | #endif |
| 24983 | |
| 24984 | #if defined(SQLITE_ENABLE_SESSION) |
| 24985 | /* |
| 24986 | ** State information for a single open session |
| 24987 | */ |
| 24988 | typedef struct OpenSession OpenSession; |
| @@ -24530,10 +25010,12 @@ | |
| 25010 | u8 autoEQPtrace; /* autoEQP is in trace mode */ |
| 25011 | u8 scanstatsOn; /* True to display scan stats before each finalize */ |
| 25012 | u8 bAutoScreenWidth; /* Using the TTY to determine screen width */ |
| 25013 | u8 mFlags; /* MFLG_ECHO, MFLG_CRLF, etc. */ |
| 25014 | u8 eMode; /* One of the MODE_ values */ |
| 25015 | char zIFmt[24]; /* Space to hold the --ifmt value */ |
| 25016 | char zFpFmt[24]; /* Space to hold the --fpfmt value */ |
| 25017 | sqlite3_qrf_spec spec; /* Spec to be passed into QRF */ |
| 25018 | } Mode; |
| 25019 | |
| 25020 | /* Flags for Mode.mFlags */ |
| 25021 | #define MFLG_ECHO 0x01 /* Echo inputs to output */ |
| @@ -24564,10 +25046,11 @@ | |
| 25046 | unsigned statsOn; /* True to display memory stats before each finalize */ |
| 25047 | unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */ |
| 25048 | u8 nPopOutput; /* Revert .output settings when reaching zero */ |
| 25049 | u8 nPopMode; /* Revert .mode settings when reaching zero */ |
| 25050 | u8 enableTimer; /* Enable the timer. 2: permanently 1: only once */ |
| 25051 | u8 bDelimitNonprint; /* Add \001...\002 around non-printing in prompts */ |
| 25052 | int inputNesting; /* Track nesting level of .read and other redirects */ |
| 25053 | double prevTimer; /* Last reported timer value */ |
| 25054 | double tmProgress; /* --timeout option for .progress */ |
| 25055 | i64 lineno; /* Line number of last line read from in */ |
| 25056 | const char *zInFile; /* Name of the input file */ |
| @@ -24745,11 +25228,11 @@ | |
| 25228 | unsigned char eHdr; /* Default header encoding. */ |
| 25229 | unsigned char eBlob; /* Default blob encoding. */ |
| 25230 | unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */ |
| 25231 | unsigned char eStyle; /* Underlying QRF style */ |
| 25232 | unsigned char eCx; /* 0: other, 1: line, 2: columnar */ |
| 25233 | unsigned char mFlg; /* Flags. 1=border-off 2=split-column 4=rowcount */ |
| 25234 | }; |
| 25235 | |
| 25236 | /* String constants used by built-in modes */ |
| 25237 | static const char *aModeStr[] = |
| 25238 | /* 0 1 2 3 4 5 6 7 8 */ |
| @@ -24758,45 +25241,45 @@ | |
| 25241 | /* 9 10 11 12 13 */ |
| 25242 | |
| 25243 | static const ModeInfo aModeInfo[] = { |
| 25244 | /* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */ |
| 25245 | { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 }, |
| 25246 | { "box", 0, 0, 9, 1, 1, 0, 3, 1, 2, 0 }, |
| 25247 | { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 }, |
| 25248 | { "column", 0, 0, 9, 1, 1, 0, 3, 2, 2, 0 }, |
| 25249 | { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, |
| 25250 | { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 }, |
| 25251 | { "html", 0, 0, 9, 4, 4, 0, 3, 7, 0, 0 }, |
| 25252 | { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 }, |
| 25253 | { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 }, |
| 25254 | { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 }, |
| 25255 | { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 }, |
| 25256 | { "line", 13, 1, 9, 1, 1, 0, 0, 11, 1, 0 }, |
| 25257 | { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 }, |
| 25258 | { "markdown", 0, 0, 9, 1, 1, 0, 3, 13, 2, 0 }, |
| 25259 | { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 }, |
| 25260 | { "psql", 0, 0, 9, 1, 1, 0, 3, 19, 2, 5 }, |
| 25261 | { "qbox", 0, 0, 10, 2, 1, 0, 3, 1, 2, 0 }, |
| 25262 | { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 }, |
| 25263 | { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 }, |
| 25264 | { "table", 0, 0, 9, 1, 1, 0, 3, 19, 2, 0 }, |
| 25265 | { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 }, |
| 25266 | { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 }, |
| 25267 | { "www", 0, 0, 9, 4, 4, 0, 3, 7, 0, 0 } |
| 25268 | }; /* | / / | / / | | / \____ |
| 25269 | ** | / / | / / | | / | |
| 25270 | ** Index into aModeStr[] | / / | | 2: columnar | |
| 25271 | ** | / / | | 1: line | |
| 25272 | ** | / / | | 0: other | |
| 25273 | ** text encoding |/ | show | | | |
| 25274 | ** v-------------------' | hdrs? | The QRF style | |
| 25275 | ** 0: n/a blob | v-----' / |
| 25276 | ** 1: plain v----------' 0: n/a _________/ |
| 25277 | ** 2: sql 0: auto 1: no | |
| 25278 | ** 3: csv 1: as-text 2: yes 1: border-off |
| 25279 | ** 4: html 2: sql 3: always 2: split-column |
| 25280 | ** 5: c 3: hex 4: rowcount |
| 25281 | ** 6: json 4: c |
| 25282 | ** 5: json |
| 25283 | ** 6: size |
| 25284 | ******************************************************************/ |
| 25285 | |
| @@ -25079,11 +25562,11 @@ | |
| 25562 | */ |
| 25563 | static char *local_getline(char *zLine, FILE *in){ |
| 25564 | int nLine = zLine==0 ? 0 : 100; |
| 25565 | int n = 0; |
| 25566 | |
| 25567 | while( seenInterrupt<2 ){ |
| 25568 | if( n+100>nLine ){ |
| 25569 | if( nLine>=1073741773 ){ |
| 25570 | free(zLine); |
| 25571 | return 0; |
| 25572 | } |
| @@ -25107,10 +25590,22 @@ | |
| 25590 | break; |
| 25591 | } |
| 25592 | } |
| 25593 | return zLine; |
| 25594 | } |
| 25595 | |
| 25596 | /* |
| 25597 | ** Return true if either the SQLITE_NO_COLOR compile-time option is used |
| 25598 | ** or if the NO_COLOR environment variable exists |
| 25599 | */ |
| 25600 | static int shellNoColor(void){ |
| 25601 | #if defined(SQLITE_NO_COLOR) || defined(SQLITE_SHELL_FIDDLE) |
| 25602 | return 1; |
| 25603 | #else |
| 25604 | return getenv("NO_COLOR")!=0; |
| 25605 | #endif |
| 25606 | } |
| 25607 | |
| 25608 | /* |
| 25609 | ** The SQLITE_PS_APPDEF macro should be set to the name of a function |
| 25610 | ** that accepts a single "int" argument and returns a "const char *" |
| 25611 | ** that is guaranteed to be non-NULL. The value returned depends on the |
| @@ -25131,35 +25626,47 @@ | |
| 25626 | # define SQLITE_PS_APPDEF shellPromptAppDef |
| 25627 | static const char *shellPromptAppDef(int c){ |
| 25628 | switch( c ){ |
| 25629 | /* The default main prompt string */ |
| 25630 | case 1: |
| 25631 | #if SQLITE_SHELL_EDITION<20260423 |
| 25632 | return "sqlite> "; /* Legacy prompt for backwards compatibility */ |
| 25633 | #elif defined(SQLITE_PS1) |
| 25634 | return SQLITE_PS1; |
| 25635 | #else |
| 25636 | if( shellNoColor() ){ |
| 25637 | return "/A-/v /f-> "; |
| 25638 | }else{ |
| 25639 | return "/e[1;32m/A-/v /e[1;/x33/:36/;m/m/e[3m/;/f/;/e[0m-> "; |
| 25640 | } |
| 25641 | #endif |
| 25642 | |
| 25643 | /* The default continuation prompt string */ |
| 25644 | case 2: |
| 25645 | #if SQLITE_SHELL_EDITION<20260423 |
| 25646 | return " ...> "; /* Legacy continuation prompt */ |
| 25647 | #elif defined(SQLITE_PS2) |
| 25648 | return SQLITE_PS2; |
| 25649 | #else |
| 25650 | if( shellNoColor() ){ |
| 25651 | return "/B/C-> "; |
| 25652 | }else{ |
| 25653 | return "/B/e[1;/x33/:36/;m/C/e[0m-> "; |
| 25654 | } |
| 25655 | #endif |
| 25656 | |
| 25657 | /* Name of environment variables that override the prompt strings |
| 25658 | ** of cases 1 and 2 */ |
| 25659 | case 3: return "SQLITE_PS1"; |
| 25660 | case 4: return "SQLITE_PS2"; |
| 25661 | |
| 25662 | /* Name of the application */ |
| 25663 | #ifndef SQLITE_CLI_APPNAME |
| 25664 | case 'A': return "SQLite"; |
| 25665 | #else |
| 25666 | case 'A': return SHELL_STRINGIFY(SQLITE_CLI_APPNAME); |
| 25667 | #endif |
| 25668 | |
| 25669 | /* Full version number of the application, including patch level */ |
| 25670 | case 'V': return sqlite3_libversion(); |
| 25671 | |
| 25672 | /* Version number without the patch level */ |
| @@ -25218,13 +25725,13 @@ | |
| 25725 | }else if( p->db && (pFN = sqlite3_db_filename(p->db,0))!=0 ){ |
| 25726 | zFN = sqlite3_filename_database(pFN); |
| 25727 | } |
| 25728 | if( zFN==0 || zFN[0]==0 ){ |
| 25729 | zFN = p->pAuxDb->zDbFilename; |
| 25730 | } |
| 25731 | if( zFN==0 || zFN[0]==0 || cli_strcmp(zFN,":memory:")==0 ){ |
| 25732 | zFN = zMemoryName; |
| 25733 | } |
| 25734 | return zFN; |
| 25735 | } |
| 25736 | |
| 25737 | /* |
| @@ -25263,10 +25770,26 @@ | |
| 25770 | if( z==0 || z[0]==0 ) z = getenv("LOGNAME"); |
| 25771 | if( z==0 || z[0]==0 ) z = "?"; |
| 25772 | #endif |
| 25773 | return z; |
| 25774 | } |
| 25775 | |
| 25776 | /* If z[] begins with one or more ANSI X3.64 (VT100) escape sequences |
| 25777 | ** return the number of bytes in all such escape sequences. Return |
| 25778 | ** zero if there are no valid escape sequences. |
| 25779 | */ |
| 25780 | static int nAnsiEscape(const char *z){ |
| 25781 | int i = 0; |
| 25782 | while( z[i]=='\033' && z[i+1]=='[' ){ |
| 25783 | int k = i+2; |
| 25784 | while( z[k]>=0x30 && z[k]<=0x3f ){ k++; } |
| 25785 | while( z[k]>=0x20 && z[k]<=0x2f ){ k++; } |
| 25786 | if( z[k]<0x40 || z[k]>0x7e ) break; |
| 25787 | i = k+1; |
| 25788 | } |
| 25789 | return i; |
| 25790 | } |
| 25791 | |
| 25792 | /* |
| 25793 | ** Expand escapes in the given input prompt string. Return the |
| 25794 | ** expanded prompt in memory obtained from sqlite3_malloc(). The |
| 25795 | ** caller is responsible for freeing the memory. |
| @@ -25311,10 +25834,11 @@ | |
| 25834 | continue; |
| 25835 | } |
| 25836 | if( c>='0' && c<='7' ){ |
| 25837 | /* /nnn becomes a single byte given by octal nnn */ |
| 25838 | int v = c - '0'; |
| 25839 | i++; |
| 25840 | while( i<=2 && zPrompt[i+1]>='0' && zPrompt[i+1]<='7' ){ |
| 25841 | v = v*8 + zPrompt[++i] - '0'; |
| 25842 | } |
| 25843 | if( !mOff ) sqlite3_str_appendchar(pOut, 1, v); |
| 25844 | zPrompt += i+1; |
| @@ -25533,15 +26057,36 @@ | |
| 26057 | memmove(z+idxSpace+nNew, z+idxSpace, len-nNew-idxSpace); |
| 26058 | memset(z+idxSpace, ' ', nNew); |
| 26059 | } |
| 26060 | } |
| 26061 | } |
| 26062 | if( 0==sqlite3_str_length(pOut) ){ |
| 26063 | /* Avoid a bogus OOM */ |
| 26064 | sqlite3_str_appendchar(pOut, 1, '\0'); |
| 26065 | } |
| 26066 | |
| 26067 | /* Editline does not recognize ANSI X3.64 escape sequences. So we have |
| 26068 | ** to find them all and enclose them inside '\001'...'\002' delimiters. |
| 26069 | ** Some versions of readline also require this, but others do not. |
| 26070 | */ |
| 26071 | if( p->bDelimitNonprint && strstr(sqlite3_str_value(pOut),"\033[")!=0 ){ |
| 26072 | char *zOrig = sqlite3_str_finish(pOut); |
| 26073 | int n; |
| 26074 | pOut = sqlite3_str_new(0); |
| 26075 | for(i=0; zOrig[i]; i++){ |
| 26076 | if( zOrig[i]=='\033' && (n = nAnsiEscape(zOrig+i))>0 ){ |
| 26077 | sqlite3_str_appendchar(pOut, 1, 1); |
| 26078 | sqlite3_str_append(pOut, &zOrig[i], n); |
| 26079 | sqlite3_str_appendchar(pOut, 1, 2); |
| 26080 | i += n-1; |
| 26081 | }else{ |
| 26082 | sqlite3_str_appendchar(pOut, 1, zOrig[i]); |
| 26083 | } |
| 26084 | } |
| 26085 | sqlite3_free(zOrig); |
| 26086 | } |
| 26087 | |
| 26088 | return sqlite3_str_finish(pOut); |
| 26089 | } |
| 26090 | |
| 26091 | /* |
| 26092 | ** Retrieve a single line of input text. |
| @@ -25570,30 +26115,33 @@ | |
| 26115 | zResult = local_getline(zPrior, in); |
| 26116 | }else{ |
| 26117 | const char *zBase = prompt_string(p, bContinue!=0); |
| 26118 | char *zPrompt = expand_prompt(p, zAll, zBase); |
| 26119 | shell_check_oom(zPrompt); |
| 26120 | #if SHELL_CMDLINE_EDIT_AVAILABLE |
| 26121 | if( shellCmdLineEdit ){ |
| 26122 | free(zPrior); |
| 26123 | zResult = shell_readline(zPrompt); |
| 26124 | while( zResult==0 ){ |
| 26125 | /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ |
| 26126 | sqlite3_sleep(50); |
| 26127 | if( seenInterrupt==0 ) break; |
| 26128 | zResult = shell_readline(""); |
| 26129 | } |
| 26130 | if( zResult && *zResult ) shell_add_history(zResult); |
| 26131 | }else |
| 26132 | #endif |
| 26133 | { |
| 26134 | sputz(stdout, zPrompt); |
| 26135 | fflush(stdout); |
| 26136 | do{ |
| 26137 | zResult = local_getline(zPrior, stdin); |
| 26138 | zPrior = 0; |
| 26139 | /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ |
| 26140 | if( zResult==0 ) sqlite3_sleep(50); |
| 26141 | }while( zResult==0 && seenInterrupt>0 ); |
| 26142 | } |
| 26143 | sqlite3_free(zPrompt); |
| 26144 | } |
| 26145 | return zResult; |
| 26146 | } |
| 26147 | #endif /* !SQLITE_SHELL_FIDDLE */ |
| @@ -25834,11 +26382,12 @@ | |
| 26382 | double r = sqlite3_value_double(apVal[0]); |
| 26383 | int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26; |
| 26384 | char z[400]; |
| 26385 | if( n<1 ) n = 1; |
| 26386 | if( n>350 ) n = 350; |
| 26387 | z[sizeof(z)-1] = 0; |
| 26388 | snprintf(z, sizeof(z)-1, "%#+.*e", n, r); |
| 26389 | sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); |
| 26390 | } |
| 26391 | |
| 26392 | /* |
| 26393 | ** SQL function: shell_add_schema(S,X) |
| @@ -25912,21 +26461,27 @@ | |
| 26461 | } |
| 26462 | sqlite3_result_value(pCtx, apVal[0]); |
| 26463 | } |
| 26464 | |
| 26465 | /* |
| 26466 | ** SQL function: shell_prompt_test(PROMPT,PRIOR,FILENAME,FLAGS) |
| 26467 | ** |
| 26468 | ** Return the shell prompt, with escapes expanded, for testing purposes. |
| 26469 | ** The first argument is the raw (unexpanded) prompt string. Or if the |
| 26470 | ** first argument is NULL, then use whatever prompt string is currently |
| 26471 | ** configured. If the second argument exists and is not NULL, then the |
| 26472 | ** second argument is understood to be prior incomplete text and a |
| 26473 | ** continuation prompt is generated. If a third argument is provided, |
| 26474 | ** it is assumed to be the full pathname of the database file. The |
| 26475 | ** fourth argument, if provided, is an integer of flags: |
| 26476 | ** |
| 26477 | ** 0x0001 Always insert \001..\002 delimiters around ANSI escapes |
| 26478 | ** 0x0002 Never insert \001..\002 delimiters |
| 26479 | ** |
| 26480 | ** This function is for testing purposes only. The interface may change. |
| 26481 | ** The function itself might be renamed or removed in future releases. Do |
| 26482 | ** not use this function in applications. |
| 26483 | */ |
| 26484 | static void shellExpandPrompt( |
| 26485 | sqlite3_context *pCtx, |
| 26486 | int nVal, |
| 26487 | sqlite3_value **apVal |
| @@ -25936,11 +26491,14 @@ | |
| 26491 | const char *zPrior; |
| 26492 | const char *zSavedDbFile; |
| 26493 | int mSavedFlgs; |
| 26494 | const char *zFName; |
| 26495 | char *zRes; |
| 26496 | int mFlags; |
| 26497 | char bSavedDelimit = p->bDelimitNonprint; |
| 26498 | |
| 26499 | if( nVal<1 ) return; |
| 26500 | if( nVal<2 |
| 26501 | || (zPrior = (const char*)sqlite3_value_text(apVal[1]))==0 |
| 26502 | || zPrior[0]==0 |
| 26503 | ){ |
| 26504 | zPrior = 0; |
| @@ -25952,12 +26510,19 @@ | |
| 26510 | zSavedDbFile = p->pAuxDb->zDbFilename; |
| 26511 | mSavedFlgs = p->pAuxDb->mFlgs; |
| 26512 | if( nVal>=3 && (zFName = (const char*)sqlite3_value_text(apVal[2]))!=0 ){ |
| 26513 | p->pAuxDb->zDbFilename = zFName; |
| 26514 | p->pAuxDb->mFlgs |= 0x001; |
| 26515 | } |
| 26516 | mFlags = nVal>=4 ? sqlite3_value_int(apVal[3]) : 0; |
| 26517 | if( mFlags & 0x0001 ){ |
| 26518 | p->bDelimitNonprint = 1; |
| 26519 | }else if( mFlags & 0x0002 ){ |
| 26520 | p->bDelimitNonprint = 0; |
| 26521 | } |
| 26522 | zRes = expand_prompt(p, zPrior, zPrompt); |
| 26523 | p->bDelimitNonprint = bSavedDelimit; |
| 26524 | p->pAuxDb->zDbFilename = zSavedDbFile; |
| 26525 | p->pAuxDb->mFlgs = mSavedFlgs; |
| 26526 | sqlite3_result_text(pCtx, zRes, -1, SQLITE_TRANSIENT); |
| 26527 | sqlite3_free(zRes); |
| 26528 | } |
| @@ -26150,11 +26715,11 @@ | |
| 26715 | free(p->spec.zColumnSep); |
| 26716 | free(p->spec.zRowSep); |
| 26717 | free(p->spec.zTableName); |
| 26718 | free(p->spec.zNull); |
| 26719 | memset(p, 0, sizeof(*p)); |
| 26720 | p->spec.iVersion = 2; |
| 26721 | p->autoExplain = autoExplain; |
| 26722 | } |
| 26723 | |
| 26724 | /* |
| 26725 | ** Duplicate Mode pSrc into pDest. pDest is assumed to be |
| @@ -26190,10 +26755,18 @@ | |
| 26755 | pDest->spec.zTableName = strdup(pSrc->spec.zTableName); |
| 26756 | } |
| 26757 | if( pDest->spec.zNull ){ |
| 26758 | pDest->spec.zNull = strdup(pSrc->spec.zNull); |
| 26759 | } |
| 26760 | if( pDest->spec.zFpFmt ){ |
| 26761 | assert( pDest->spec.zFpFmt==pSrc->zFpFmt ); |
| 26762 | pDest->spec.zFpFmt = pDest->zFpFmt; |
| 26763 | } |
| 26764 | if( pDest->spec.zIFmt ){ |
| 26765 | assert( pDest->spec.zIFmt==pSrc->zIFmt ); |
| 26766 | pDest->spec.zIFmt = pDest->zIFmt; |
| 26767 | } |
| 26768 | } |
| 26769 | |
| 26770 | /* |
| 26771 | ** Set a string value to a copy of the zNew string in memory |
| 26772 | ** obtained from system malloc(). |
| @@ -26208,10 +26781,47 @@ | |
| 26781 | if( *az ){ |
| 26782 | memcpy(*az, zNew, n+1 ); |
| 26783 | } |
| 26784 | } |
| 26785 | } |
| 26786 | |
| 26787 | /* Forward reference */ |
| 26788 | static int pickStr(const char *zArg, char **pzErr, ...); |
| 26789 | |
| 26790 | /* |
| 26791 | ** Change the limits on the display mode. Return 0 on |
| 26792 | ** success. Return non-zero if zArg is mis-formatted. |
| 26793 | ** |
| 26794 | ** Valid arguments: |
| 26795 | ** |
| 26796 | ** "on" Default limits |
| 26797 | ** "off" All limits turned off |
| 26798 | ** L,C Line and Characters limits set |
| 26799 | ** L,C,T Line, Character, and Title limits set |
| 26800 | ** |
| 26801 | ** Anything else returns non-zero |
| 26802 | */ |
| 26803 | static int modeSetLimit(ShellState *p, const char *zArg){ |
| 26804 | int k = zArg==0 ? 1 : pickStr(zArg,0,"on","off",""); |
| 26805 | if( k==0 ){ |
| 26806 | p->mode.spec.nLineLimit = DFLT_LINE_LIMIT; |
| 26807 | p->mode.spec.nCharLimit = DFLT_CHAR_LIMIT; |
| 26808 | p->mode.spec.nTitleLimit = DFLT_TITLE_LIMIT; |
| 26809 | }else if( k==1 ){ |
| 26810 | p->mode.spec.nLineLimit = 0; |
| 26811 | p->mode.spec.nCharLimit = 0; |
| 26812 | p->mode.spec.nTitleLimit = 0; |
| 26813 | }else{ |
| 26814 | int L, C, T = 0; |
| 26815 | int nNum = sscanf(zArg, "%d,%d,%d", &L, &C, &T); |
| 26816 | if( nNum<2 || L<0 || C<0 || T<0) return 1; |
| 26817 | p->mode.spec.nLineLimit = L; |
| 26818 | p->mode.spec.nCharLimit = C; |
| 26819 | if( nNum==3 ) p->mode.spec.nTitleLimit = T; |
| 26820 | } |
| 26821 | return 0; |
| 26822 | } |
| 26823 | |
| 26824 | /* |
| 26825 | ** Change the mode to eMode |
| 26826 | */ |
| 26827 | static void modeChange(ShellState *p, unsigned char eMode){ |
| @@ -26238,17 +26848,23 @@ | |
| 26848 | pM->spec.bSplitColumn = QRF_Yes; |
| 26849 | pM->bAutoScreenWidth = 1; |
| 26850 | }else{ |
| 26851 | pM->spec.bSplitColumn = QRF_No; |
| 26852 | } |
| 26853 | if( pI->mFlg & 0x04 ){ |
| 26854 | pM->spec.bRowCount = QRF_Yes; |
| 26855 | }else{ |
| 26856 | pM->spec.bRowCount = QRF_No; |
| 26857 | } |
| 26858 | }else if( eMode>=MODE_USER && eMode-MODE_USER<p->nSavedModes ){ |
| 26859 | modeFree(&p->mode); |
| 26860 | modeDup(&p->mode, &p->aSavedModes[eMode-MODE_USER].mode); |
| 26861 | }else if( eMode==MODE_BATCH ){ |
| 26862 | u8 mFlags = p->mode.mFlags; |
| 26863 | modeFree(&p->mode); |
| 26864 | modeChange(p, MODE_List); |
| 26865 | modeSetLimit(p, "off"); |
| 26866 | p->mode.mFlags = mFlags; |
| 26867 | }else if( eMode==MODE_TTY ){ |
| 26868 | u8 mFlags = p->mode.mFlags; |
| 26869 | modeFree(&p->mode); |
| 26870 | modeChange(p, MODE_QBox); |
| @@ -26266,13 +26882,15 @@ | |
| 26882 | /* |
| 26883 | ** Set the mode to the default. It assumed that the mode has |
| 26884 | ** already been freed and zeroed prior to calling this routine. |
| 26885 | */ |
| 26886 | static void modeDefault(ShellState *p){ |
| 26887 | p->mode.spec.iVersion = 2; |
| 26888 | p->mode.autoExplain = 1; |
| 26889 | if( (stdin_is_interactive || stdout_is_console) |
| 26890 | && SQLITE_SHELL_EDITION>=20260409 |
| 26891 | ){ |
| 26892 | modeChange(p, MODE_TTY); |
| 26893 | }else{ |
| 26894 | modeChange(p, MODE_BATCH); |
| 26895 | } |
| 26896 | } |
| @@ -26881,11 +27499,11 @@ | |
| 27499 | return SQLITE_OK; |
| 27500 | } |
| 27501 | #endif |
| 27502 | |
| 27503 | /* |
| 27504 | ** Print a schema statement. This is a helper routine to dump_callback(). |
| 27505 | ** |
| 27506 | ** This routine converts some CREATE TABLE statements for shadow tables |
| 27507 | ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements. |
| 27508 | ** |
| 27509 | ** If the schema statement in z[] contains a start-of-comment and if |
| @@ -28333,12 +28951,12 @@ | |
| 28951 | ".databases List names and files of attached databases", |
| 28952 | ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", |
| 28953 | #if SQLITE_SHELL_HAVE_RECOVER |
| 28954 | ".dbinfo ?DB? Show status information about the database", |
| 28955 | #endif |
| 28956 | ".dbtotxt Hex dump of the database file", |
| 28957 | ".diskused ?SCHEMA? Report database space and size stats", |
| 28958 | ".dump ?OBJECTS? Render database content as SQL", |
| 28959 | " Options:", |
| 28960 | " --data-only Output only INSERT statements", |
| 28961 | " --newlines Allow unescaped newline characters in output", |
| 28962 | " --nosys Omit system tables (ex: \"sqlite_stat1\")", |
| @@ -28445,10 +29063,13 @@ | |
| 29063 | " --reset Reset the count for each input and interrupt", |
| 29064 | " --timeout S Halt after running for S seconds", |
| 29065 | #endif |
| 29066 | ".prompt MAIN CONTINUE Replace the standard prompts", |
| 29067 | " --hard-reset Unset SQLITE_PS1/2 and then --reset", |
| 29068 | #ifndef SQLITE_NO_COLOR |
| 29069 | " --no-color Disable color prompts. Use --color to re-enable", |
| 29070 | #endif |
| 29071 | " --reset Revert to default prompts", |
| 29072 | " --show Show the current prompt strings", |
| 29073 | " -- No more options. Subsequent args are prompts", |
| 29074 | #ifndef SQLITE_SHELL_FIDDLE |
| 29075 | ".quit Stop interpreting input stream, exit if primary.", |
| @@ -28609,10 +29230,14 @@ | |
| 29230 | " truncated. Zero means \"no limit\".\n" |
| 29231 | " --colsep STRING Use STRING as the column separator\n" |
| 29232 | " --escape ESC Enable/disable escaping of control characters\n" |
| 29233 | " found in the output. ESC can be \"off\", \"ascii\",\n" |
| 29234 | " or \"symbol\".\n" |
| 29235 | " --fpfmt STRING String is a printf-style format string used to\n" |
| 29236 | " render floating-point values.\n" |
| 29237 | " --ifmt STRING String is a printf-style format string used to\n" |
| 29238 | " render integer values.\n" |
| 29239 | " --linelimit N Set the maximum number of output lines to show for\n" |
| 29240 | " any single SQL value to N. Longer values are\n" |
| 29241 | " truncated. Zero means \"no limit\". Only works\n" |
| 29242 | " in \"line\" mode and in columnar modes.\n" |
| 29243 | " --limits L,C,T Shorthand for \"--linelimit L --charlimit C\n" |
| @@ -28629,10 +29254,11 @@ | |
| 29254 | " --quote ARG Enable/disable quoting of text. ARG can be\n" |
| 29255 | " \"off\", \"on\", \"sql\", \"relaxed\", \"csv\", \"html\",\n" |
| 29256 | " \"tcl\", or \"json\". \"off\" means show the text as-is.\n" |
| 29257 | " \"on\" is an alias for \"sql\".\n" |
| 29258 | " --reset Changes all mode settings back to their default.\n" |
| 29259 | " --rowcount BOOLEAN Show \"(N rows)\" at the end of query results.\n" |
| 29260 | " --rowsep STRING Use STRING as the row separator\n" |
| 29261 | " --sw|--screenwidth N Declare the screen width of the output device\n" |
| 29262 | " to be N characters. An attempt may be made to\n" |
| 29263 | " wrap output text to fit within this limit. Zero\n" |
| 29264 | " means \"no limit\". Or N can be \"auto\" to set the\n" |
| @@ -28640,11 +29266,11 @@ | |
| 29266 | " --tablename NAME Set the name of the table for \"insert\" mode.\n" |
| 29267 | " --tag NAME Save mode to the left as NAME.\n" |
| 29268 | " --textjsonb BOOLEAN If enabled, JSONB text is displayed as text JSON.\n" |
| 29269 | " --title ARG Whether or not to show column headers, and if so\n" |
| 29270 | " how to encode them. ARG can be \"off\", \"on\",\n" |
| 29271 | " \"always\", \"sql\", \"csv\", \"html\", \"tcl\", or \"json\".\n" |
| 29272 | " --titlelimit N Limit the length of column titles to N characters.\n" |
| 29273 | " -v|--verbose Verbose output\n" |
| 29274 | " --widths LIST Set the columns widths for columnar modes. The\n" |
| 29275 | " argument is a list of integers, one for each\n" |
| 29276 | " column. A \"0\" width means use a dynamic width\n" |
| @@ -29345,11 +29971,12 @@ | |
| 29971 | sqlite3_base64_init(p->db, 0, 0); |
| 29972 | sqlite3_base85_init(p->db, 0, 0); |
| 29973 | sqlite3_regexp_init(p->db, 0, 0); |
| 29974 | sqlite3_ieee_init(p->db, 0, 0); |
| 29975 | sqlite3_series_init(p->db, 0, 0); |
| 29976 | sqlite3_diskused_init(p->db, 0, 0); |
| 29977 | sqlite3_strdup_init(p->db, 0, 0); |
| 29978 | #ifndef SQLITE_SHELL_FIDDLE |
| 29979 | sqlite3_fileio_init(p->db, 0, 0); |
| 29980 | sqlite3_completion_init(p->db, 0, 0); |
| 29981 | #endif |
| 29982 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -29406,15 +30033,11 @@ | |
| 30033 | sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0, |
| 30034 | editFunc, 0, 0); |
| 30035 | sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0, |
| 30036 | editFunc, 0, 0); |
| 30037 | #endif |
| 30038 | sqlite3_create_function(p->db, "shell_prompt_test", -1, SQLITE_UTF8, |
| 30039 | p, shellExpandPrompt, 0, 0); |
| 30040 | sqlite3_create_function(p->db, "shell_temp_filename", 1, SQLITE_UTF8, |
| 30041 | p, shellTempFilenameFunc, 0, 0); |
| 30042 | |
| 30043 | |
| @@ -31155,11 +31778,11 @@ | |
| 31778 | typedef struct ArCommand ArCommand; |
| 31779 | struct ArCommand { |
| 31780 | u8 eCmd; /* An AR_CMD_* value */ |
| 31781 | u8 bVerbose; /* True if --verbose */ |
| 31782 | u8 bZip; /* True if the archive is a ZIP */ |
| 31783 | u8 bDryRun; /* 1 for --dry-run, 2 for --debug */ |
| 31784 | u8 bAppend; /* True if --append */ |
| 31785 | u8 bGlob; /* True if --glob */ |
| 31786 | u8 fromCmdLine; /* Run from -A instead of .archive */ |
| 31787 | int nArg; /* Number of command arguments */ |
| 31788 | char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ |
| @@ -31217,10 +31840,11 @@ | |
| 31840 | #define AR_SWITCH_FILE 9 |
| 31841 | #define AR_SWITCH_DIRECTORY 10 |
| 31842 | #define AR_SWITCH_APPEND 11 |
| 31843 | #define AR_SWITCH_DRYRUN 12 |
| 31844 | #define AR_SWITCH_GLOB 13 |
| 31845 | #define AR_SWITCH_DEBUG 14 |
| 31846 | |
| 31847 | static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ |
| 31848 | switch( eSwitch ){ |
| 31849 | case AR_CMD_CREATE: |
| 31850 | case AR_CMD_EXTRACT: |
| @@ -31234,11 +31858,14 @@ | |
| 31858 | } |
| 31859 | pAr->eCmd = eSwitch; |
| 31860 | break; |
| 31861 | |
| 31862 | case AR_SWITCH_DRYRUN: |
| 31863 | if( pAr->bDryRun<2 ) pAr->bDryRun = 1; |
| 31864 | break; |
| 31865 | case AR_SWITCH_DEBUG: |
| 31866 | pAr->bDryRun = 2; |
| 31867 | break; |
| 31868 | case AR_SWITCH_GLOB: |
| 31869 | pAr->bGlob = 1; |
| 31870 | break; |
| 31871 | case AR_SWITCH_VERBOSE: |
| @@ -31285,10 +31912,11 @@ | |
| 31912 | { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, |
| 31913 | { "file", 'f', AR_SWITCH_FILE, 1 }, |
| 31914 | { "append", 'a', AR_SWITCH_APPEND, 1 }, |
| 31915 | { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, |
| 31916 | { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, |
| 31917 | { "debug", 0, AR_SWITCH_DEBUG, 0 }, |
| 31918 | { "glob", 'g', AR_SWITCH_GLOB, 0 }, |
| 31919 | }; |
| 31920 | int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); |
| 31921 | struct ArSwitch *pEnd = &aSwitch[nSwitch]; |
| 31922 | |
| @@ -31585,18 +32213,41 @@ | |
| 32213 | |
| 32214 | /* |
| 32215 | ** Implementation of .ar "eXtract" command. |
| 32216 | */ |
| 32217 | static int arExtractCommand(ArCommand *pAr){ |
| 32218 | /* The zSql1[] string is a template for the query that does the |
| 32219 | ** extraction. Notes: |
| 32220 | ** |
| 32221 | ** * $dir is the directory into which the archive is to be extracted |
| 32222 | ** * $pass is the integer pass number: 0, 1, or 2 |
| 32223 | ** * The dest CTE is created so that realpath($dir) only needs |
| 32224 | ** to be called once. |
| 32225 | */ |
| 32226 | const char *zSql1 = |
| 32227 | "WITH dest(dpath,dlen) AS (\n" |
| 32228 | #ifdef _WIN32 |
| 32229 | " SELECT realpath($dir) || '\\',\n" |
| 32230 | #else |
| 32231 | " SELECT realpath($dir) || '/',\n" |
| 32232 | #endif |
| 32233 | " 1+length(realpath($dir))\n" |
| 32234 | ")\n" |
| 32235 | "SELECT\n" |
| 32236 | " ($dir || name),\n" |
| 32237 | " CASE $dryrun\n" /* vv--- azExtraArg */ |
| 32238 | " WHEN 0 THEN writefile($dir||name, %s, mode, mtime)\n" |
| 32239 | " WHEN 1 THEN 0\n" |
| 32240 | " ELSE shell_putsnl(format('writefile(%%Q,%%s,%%0o,%%d)'," |
| 32241 | "$dir||name,quote(%s),mode,mtime)) IS NULL\n" |
| 32242 | " END\n" /* ^^--- azExtraArg */ |
| 32243 | " FROM dest CROSS JOIN %s\n" |
| 32244 | " WHERE (%s)\n" /* ^^-- pAr->zSrcTable */ |
| 32245 | /* ^^--- zWhere */ |
| 32246 | " AND (CASE $pass WHEN 0 THEN (mode&0xf000)<>0xa000\n" |
| 32247 | " WHEN 1 THEN (mode&0xf000)=0xa000\n" |
| 32248 | " ELSE data IS NULL END)\n" |
| 32249 | " AND dpath=substr(realpath($dir||name),1,dlen)\n" /* No escapes */ |
| 32250 | " AND name NOT GLOB '*..[/\\]*'\n"; /* No /../ in paths */ |
| 32251 | |
| 32252 | const char *azExtraArg[] = { |
| 32253 | "sqlar_uncompress(data, sz)", |
| @@ -31623,39 +32274,48 @@ | |
| 32274 | } |
| 32275 | if( zDir==0 ) rc = SQLITE_NOMEM; |
| 32276 | } |
| 32277 | |
| 32278 | shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, |
| 32279 | azExtraArg[pAr->bZip], |
| 32280 | azExtraArg[pAr->bZip], |
| 32281 | pAr->zSrcTable, |
| 32282 | zWhere |
| 32283 | ); |
| 32284 | |
| 32285 | if( rc==SQLITE_OK ){ |
| 32286 | j = sqlite3_bind_parameter_index(pSql, "$dir"); |
| 32287 | sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); |
| 32288 | j = sqlite3_bind_parameter_index(pSql, "$dryrun"); |
| 32289 | sqlite3_bind_int(pSql, j, pAr->bDryRun); |
| 32290 | |
| 32291 | /* Run the SELECT statement twice |
| 32292 | ** (0) writefile() files and directories |
| 32293 | ** (1) writefile() symlinks |
| 32294 | ** (2) writefile() for directory again |
| 32295 | ** The third pass is so that the timestamps for extracted directories |
| 32296 | ** will be reset to the value in the archive, since populating them |
| 32297 | ** in the first pass will have changed the timestamp. */ |
| 32298 | for(i=0; i<3; i++){ |
| 32299 | if( pAr->bDryRun>=2 ){ |
| 32300 | cli_printf(pAr->out, "*** BEGIN PASS %d ***\n", i+1); |
| 32301 | } |
| 32302 | j = sqlite3_bind_parameter_index(pSql, "$pass"); |
| 32303 | sqlite3_bind_int(pSql, j, i); |
| 32304 | if( pAr->bDryRun && i==0 ){ |
| 32305 | cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql)); |
| 32306 | } |
| 32307 | while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 32308 | if( i==0 && pAr->bVerbose ){ |
| 32309 | cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 32310 | } |
| 32311 | } |
| 32312 | if( pAr->bDryRun==1 ) break; |
| 32313 | shellReset(&rc, pSql); |
| 32314 | if( pAr->bDryRun>=2 ){ |
| 32315 | cli_printf(pAr->out, "*** END PASS %d ***\n", i+1); |
| 32316 | } |
| 32317 | } |
| 32318 | shellFinalize(&rc, pSql); |
| 32319 | } |
| 32320 | |
| 32321 | sqlite3_free(zDir); |
| @@ -32166,11 +32826,11 @@ | |
| 32826 | ; |
| 32827 | static const char * const zCollectVar = "\ |
| 32828 | SELECT\ |
| 32829 | '('||x'0a'\ |
| 32830 | || group_concat(\ |
| 32831 | cname,\ |
| 32832 | ','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\ |
| 32833 | ||')' AS ColsSpec \ |
| 32834 | FROM (\ |
| 32835 | SELECT cpos, printf('\"%w\"',printf('%!.*s%s', nlen-chop,name,suff)) AS cname \ |
| 32836 | FROM ColNames ORDER BY cpos\ |
| @@ -32767,14 +33427,16 @@ | |
| 33427 | /* |
| 33428 | ** This function computes what to show the user about the configured |
| 33429 | ** titles (or column-names). Output is an integer between 0 and 3: |
| 33430 | ** |
| 33431 | ** 0: The titles do not matter. Never show anything. |
| 33432 | ** 1: Show "--title off" |
| 33433 | ** 2: Show "--title on" |
| 33434 | ** 3: Show "--title always" |
| 33435 | ** 4: Show "--title VALUE" where VALUE is an encoding method |
| 33436 | ** to use, one of: plain sql csv html tcl json |
| 33437 | ** 5: Show "--title VALUE" as in 3, followed by "--title always" |
| 33438 | ** |
| 33439 | ** Inputs are: |
| 33440 | ** |
| 33441 | ** spec.bTitles (bT) Whether or not to show the titles |
| 33442 | ** spec.eTitle (eT) The actual encoding to be used for titles |
| @@ -32807,11 +33469,27 @@ | |
| 33469 | if( eT!=eH ) v >>= 32; /* Encoding disagree in upper 4-bytes */ |
| 33470 | if( bT!=bH ) v >>= 16; /* ON/OFF disagree in upper 2-byte pairs */ |
| 33471 | if( bT<2 ) v >>= 8; /* ON in even bytes, OFF in odd bytes (1st byte 0) */ |
| 33472 | if( !bAll ) v >>= 4; /* bAll values are in the lower half-byte */ |
| 33473 | |
| 33474 | v &= 3; |
| 33475 | /* At this point v means: |
| 33476 | ** 0: The titles do not matter. Never show anything. |
| 33477 | ** 1: Show "--title off" |
| 33478 | ** 2: Show "--title on" |
| 33479 | ** 3: Show "--title VALUE" where VALUE is an encoding method |
| 33480 | ** to use, one of: plain sql csv html tcl json |
| 33481 | ** If bTitles is QRF_Always, convert 2->3, 3->5. If bTitles is not |
| 33482 | ** QRF_Always, convert 3->4. |
| 33483 | */ |
| 33484 | if( p->mode.spec.bTitles==QRF_Always ){ |
| 33485 | if( v==3 ) v = 5; |
| 33486 | if( v==2 ) v = 3; |
| 33487 | }else{ |
| 33488 | if( v==3 ) v = 4; |
| 33489 | } |
| 33490 | return v; |
| 33491 | } |
| 33492 | |
| 33493 | /* |
| 33494 | ** DOT-COMMAND: .mode |
| 33495 | ** |
| @@ -32835,10 +33513,14 @@ | |
| 33513 | ** truncated. Zero means "no limit". |
| 33514 | ** --colsep STRING Use STRING as the column separator |
| 33515 | ** --escape ESC Enable/disable escaping of control characters |
| 33516 | ** found in the output. ESC can be "off", "ascii", |
| 33517 | ** or "symbol". |
| 33518 | ** --fpfmt STRING String is a printf-style format string used to |
| 33519 | ** render floating-point values. |
| 33520 | ** --ifmt STRING String is a printf-style format string used to |
| 33521 | ** render integer values. |
| 33522 | ** --linelimit N Set the maximum number of output lines to show for |
| 33523 | ** any single SQL value to N. Longer values are |
| 33524 | ** truncated. Zero means "no limit". Only works |
| 33525 | ** in "line" mode and in columnar modes. |
| 33526 | ** --limits L,C,T Shorthand for "--linelimit L --charlimit C |
| @@ -32855,10 +33537,11 @@ | |
| 33537 | ** --quote ARG Enable/disable quoting of text. ARG can be |
| 33538 | ** "off", "on", "sql", "relaxed", "csv", "html", |
| 33539 | ** "tcl", or "json". "off" means show the text as-is. |
| 33540 | ** "on" is an alias for "sql". |
| 33541 | ** --reset Changes all mode settings back to their default. |
| 33542 | ** --rowcount BOOLEAN Show "(N rows)" at the end of query results. |
| 33543 | ** --rowsep STRING Use STRING as the row separator |
| 33544 | ** --sw|--screenwidth N Declare the screen width of the output device |
| 33545 | ** to be N characters. An attempt may be made to |
| 33546 | ** wrap output text to fit within this limit. Zero |
| 33547 | ** means "no limit". Or N can be "auto" to set the |
| @@ -32866,11 +33549,11 @@ | |
| 33549 | ** --tablename NAME Set the name of the table for "insert" mode. |
| 33550 | ** --tag NAME Save mode to the left as NAME. |
| 33551 | ** --textjsonb BOOLEAN If enabled, JSONB text is displayed as text JSON. |
| 33552 | ** --title ARG Whether or not to show column headers, and if so |
| 33553 | ** how to encode them. ARG can be "off", "on", |
| 33554 | ** "always", "sql", "csv", "html", "tcl", or "json". |
| 33555 | ** --titlelimit N Limit the length of column titles to N characters. |
| 33556 | ** -v|--verbose Verbose output |
| 33557 | ** --widths LIST Set the columns widths for columnar modes. The |
| 33558 | ** argument is a list of integers, one for each |
| 33559 | ** column. A "0" width means use a dynamic width |
| @@ -33011,30 +33694,14 @@ | |
| 33694 | }else if( optionMatch(z,"limits") ){ |
| 33695 | if( (++i)>=nArg ){ |
| 33696 | dotCmdError(p, i-1, "missing argument", 0); |
| 33697 | return 1; |
| 33698 | } |
| 33699 | if( modeSetLimit(p, azArg[i]) ){ |
| 33700 | dotCmdError(p, i, "bad argument", "Should be \"on\" or \"off\" or " |
| 33701 | "\"L,C,T\" where L, C, and T are unsigned integers"); |
| 33702 | return 1; |
| 33703 | } |
| 33704 | chng = 1; |
| 33705 | }else if( optionMatch(z,"list") ){ |
| 33706 | int ii; |
| 33707 | cli_puts("available modes:", p->out); |
| @@ -33105,15 +33772,56 @@ | |
| 33772 | break; |
| 33773 | default: /* off */ |
| 33774 | p->mode.spec.eText = QRF_TEXT_Plain; |
| 33775 | break; |
| 33776 | } |
| 33777 | chng = 1; |
| 33778 | }else if( optionMatch(z,"ifmt") ){ |
| 33779 | if( i+1>=nArg ){ |
| 33780 | dotCmdError(p, i, "missing argument", 0); |
| 33781 | return 1; |
| 33782 | } |
| 33783 | i++; |
| 33784 | if( azArg[i][0]==0 || cli_strcmp(azArg[i],"auto")==0 ){ |
| 33785 | p->mode.spec.zIFmt = 0; |
| 33786 | }else if( sqlite3_qrf_ckformat(azArg[i])!=1 ){ |
| 33787 | dotCmdError(p, i, "not a valid integer format", 0); |
| 33788 | return 1; |
| 33789 | }else{ |
| 33790 | assert( strlen(azArg[i])<sizeof(p->mode.zIFmt)-1 ); |
| 33791 | memcpy(p->mode.zIFmt, azArg[i], strlen(azArg[i])+1); |
| 33792 | p->mode.spec.zIFmt = p->mode.zIFmt; |
| 33793 | } |
| 33794 | chng = 1; |
| 33795 | }else if( optionMatch(z,"fpfmt") ){ |
| 33796 | if( i+1>=nArg ){ |
| 33797 | dotCmdError(p, i, "missing argument", 0); |
| 33798 | return 1; |
| 33799 | } |
| 33800 | i++; |
| 33801 | if( azArg[i][0]==0 || cli_strcmp(azArg[i],"auto")==0 ){ |
| 33802 | p->mode.spec.zFpFmt = 0; |
| 33803 | }else if( sqlite3_qrf_ckformat(azArg[i])!=2 ){ |
| 33804 | dotCmdError(p, i, "not a valid floating-point format", 0); |
| 33805 | return 1; |
| 33806 | }else{ |
| 33807 | assert( strlen(azArg[i])<sizeof(p->mode.zFpFmt)-1 ); |
| 33808 | memcpy(p->mode.zFpFmt, azArg[i], strlen(azArg[i])+1); |
| 33809 | p->mode.spec.zFpFmt = p->mode.zFpFmt; |
| 33810 | } |
| 33811 | chng = 1; |
| 33812 | }else if( optionMatch(z,"reset") ){ |
| 33813 | int saved_eMode = p->mode.eMode; |
| 33814 | modeFree(&p->mode); |
| 33815 | modeChange(p, saved_eMode); |
| 33816 | }else if( optionMatch(z,"rowcount") ){ |
| 33817 | if( i+1>=nArg ){ |
| 33818 | dotCmdError(p, i, "missing argument", 0); |
| 33819 | return 1; |
| 33820 | } |
| 33821 | p->mode.spec.bRowCount = booleanValue(azArg[++i]) ? QRF_Yes : QRF_No; |
| 33822 | chng = 1; |
| 33823 | }else if( optionMatch(z,"screenwidth") || optionMatch(z,"sw") ){ |
| 33824 | if( (++i)>=nArg ){ |
| 33825 | dotCmdError(p, i-1, "missing argument", 0); |
| 33826 | return 1; |
| 33827 | } |
| @@ -33163,25 +33871,63 @@ | |
| 33871 | return 1; |
| 33872 | } |
| 33873 | p->mode.spec.bTextJsonb = booleanValue(azArg[++i]) ? QRF_Yes : QRF_No; |
| 33874 | chng = 1; |
| 33875 | }else if( optionMatch(z,"titles") || optionMatch(z,"title") ){ |
| 33876 | /* The --titles option controls two fields of the |
| 33877 | ** sqlite3_qrf_spec object: eTitle and bTitles. |
| 33878 | ** |
| 33879 | ** --titles eTitle bTitles |
| 33880 | ** -------- --------------- --------------------- |
| 33881 | ** "off" (unchanged) QRF_Off |
| 33882 | ** "on" (unchanged) QRF_On |
| 33883 | ** "always" (unchanged) QRF_Always |
| 33884 | ** "auto", (default) (default) |
| 33885 | ** "plain" QRF_TEXT_Plain QRF_Always or QRF_On |
| 33886 | ** "sql" QRF_TEXT_Sql QRF_Always or QRF_On |
| 33887 | ** "csv" QRF_TEXT_Csv QRF_Always or QRF_On |
| 33888 | ** "html" QRF_TEXT_Html QRF_Always or QRF_On |
| 33889 | ** "tcl" QRF_TEXT_Tcl QRF_Always or QRF_On |
| 33890 | ** "json" QRF_TEXT_Json QRF_Always or QRF_On |
| 33891 | ** |
| 33892 | ** This mapping is different from the -title option to the "format" |
| 33893 | ** method of the TCL interface. In this mapping: |
| 33894 | ** |
| 33895 | ** * "off", "on", and "always" affect only bTitles and leave |
| 33896 | ** eTitle unchanged |
| 33897 | ** |
| 33898 | ** * "auto" sets both bTitles and eTitle to the default value |
| 33899 | ** in aModeInfo[] according to the current --style. |
| 33900 | ** |
| 33901 | ** * "plain" through "json" set eTitle but leave bTitles |
| 33902 | ** unchanged if it is not QRF_Off. If bTitles is QRF_Off, |
| 33903 | ** then it is changed QRF_Always. |
| 33904 | */ |
| 33905 | char *zErr = 0; |
| 33906 | if( i+1>=nArg ){ |
| 33907 | dotCmdError(p, i, "missing argument", 0); |
| 33908 | return 1; |
| 33909 | } |
| 33910 | k = pickStr(azArg[++i],&zErr, |
| 33911 | "off","on","always","auto","plain","sql","csv","html","tcl","json",""); |
| 33912 | /* 0 1 2 3 4 5 6 7 8 9 */ |
| 33913 | if( k<0 ){ |
| 33914 | dotCmdError(p, i, "bad --titles value","%z", zErr); |
| 33915 | return 1; |
| 33916 | } |
| 33917 | p->mode.mFlags &= ~MFLG_HDR; |
| 33918 | if( k<=2 ){ |
| 33919 | p->mode.spec.bTitles = QRF_No+k; |
| 33920 | }else if( k==3 ){ |
| 33921 | p->mode.spec.eTitle = aModeInfo[p->mode.eMode].eHdr; |
| 33922 | p->mode.spec.bTitles = aModeInfo[p->mode.eMode].bHdr; |
| 33923 | }else{ |
| 33924 | p->mode.spec.eTitle = (k-4)+QRF_TEXT_Plain; |
| 33925 | if( p->mode.spec.bTitles==QRF_No ){ |
| 33926 | p->mode.spec.bTitles = QRF_Always; |
| 33927 | } |
| 33928 | } |
| 33929 | chng = 1; |
| 33930 | }else if( optionMatch(z,"widths") || optionMatch(z,"width") ){ |
| 33931 | int nWidth = 0; |
| 33932 | short int *aWidth; |
| 33933 | const char *zW; |
| @@ -33295,10 +34041,18 @@ | |
| 34041 | append_c_string(pDesc, p->mode.spec.zColumnSep); |
| 34042 | } |
| 34043 | if( bAll || p->mode.spec.eEsc!=QRF_Auto ){ |
| 34044 | sqlite3_str_appendf(pDesc, " --escape %s",qrfEscNames[p->mode.spec.eEsc]); |
| 34045 | } |
| 34046 | if( bAll || p->mode.spec.zFpFmt!=0 ){ |
| 34047 | const char *z = p->mode.spec.zFpFmt; |
| 34048 | sqlite3_str_appendf(pDesc, " --fpfmt %s", z ? z : "auto"); |
| 34049 | } |
| 34050 | if( bAll || p->mode.spec.zIFmt!=0 ){ |
| 34051 | const char *z = p->mode.spec.zIFmt; |
| 34052 | sqlite3_str_appendf(pDesc, " --ifmt %s", z ? z : "auto"); |
| 34053 | } |
| 34054 | if( bAll |
| 34055 | || (p->mode.spec.nLineLimit>0 && pI->eCx>0) |
| 34056 | || p->mode.spec.nCharLimit>0 |
| 34057 | || (p->mode.spec.nTitleLimit>0 && pI->eCx>0) |
| 34058 | ){ |
| @@ -33332,10 +34086,16 @@ | |
| 34086 | if( bAll |
| 34087 | || (pI->eText!=p->mode.spec.eText && (pI->eText>1 || p->mode.spec.eText>1)) |
| 34088 | ){ |
| 34089 | sqlite3_str_appendf(pDesc," --quote %s",qrfQuoteNames[p->mode.spec.eText]); |
| 34090 | } |
| 34091 | if( bAll |
| 34092 | || ((p->mode.spec.bRowCount==QRF_Yes) != ((pI->mFlg&4)!=0)) |
| 34093 | ){ |
| 34094 | sqlite3_str_appendf(pDesc," --rowcount %s", |
| 34095 | p->mode.spec.bRowCount==QRF_Yes ? "on" : "off"); |
| 34096 | } |
| 34097 | zSetting = aModeStr[pI->eRSep]; |
| 34098 | if( bAll || (zSetting && cli_strcmp(zSetting,p->mode.spec.zRowSep)!=0) ){ |
| 34099 | sqlite3_str_appendf(pDesc, " --rowsep "); |
| 34100 | append_c_string(pDesc, p->mode.spec.zRowSep); |
| 34101 | } |
| @@ -33361,14 +34121,19 @@ | |
| 34121 | if( k==1 ){ |
| 34122 | sqlite3_str_appendall(pDesc, " --titles off"); |
| 34123 | }else if( k==2 ){ |
| 34124 | sqlite3_str_appendall(pDesc, " --titles on"); |
| 34125 | }else if( k==3 ){ |
| 34126 | sqlite3_str_appendall(pDesc, " --titles always"); |
| 34127 | }else if( k>=4 ){ |
| 34128 | static const char *azTitle[] = |
| 34129 | { "plain", "sql", "csv", "html", "tcl", "json"}; |
| 34130 | sqlite3_str_appendf(pDesc, " --titles %s", |
| 34131 | azTitle[p->mode.spec.eTitle-1]); |
| 34132 | if( k==5 ){ |
| 34133 | sqlite3_str_appendf(pDesc, " --titles always"); |
| 34134 | } |
| 34135 | } |
| 34136 | if( p->mode.spec.nWidth>0 && (bAll || pI->eCx==2) ){ |
| 34137 | int ii; |
| 34138 | const char *zSep = " --widths "; |
| 34139 | for(ii=0; ii<p->mode.spec.nWidth; ii++){ |
| @@ -34248,11 +35013,16 @@ | |
| 35013 | if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){ |
| 35014 | rc = shell_dbinfo_command(p, nArg, azArg); |
| 35015 | }else |
| 35016 | #endif /* SQLITE_SHELL_HAVE_RECOVER */ |
| 35017 | |
| 35018 | if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){ |
| 35019 | open_db(p, 0); |
| 35020 | rc = shell_dbtotxt_command(p, nArg, azArg); |
| 35021 | }else |
| 35022 | |
| 35023 | if( c=='d' && n==8 && cli_strncmp(azArg[0], "diskused", n)==0 ){ |
| 35024 | const char *zSchema = 0; |
| 35025 | int ii; |
| 35026 | char *zSql; |
| 35027 | open_db(p, 0); |
| 35028 | for(ii=1; ii<nArg; ii++){ |
| @@ -34267,27 +35037,19 @@ | |
| 35037 | rc = 1; |
| 35038 | goto meta_command_exit; |
| 35039 | } |
| 35040 | zSchema = z; |
| 35041 | } |
| 35042 | zSql = sqlite3_mprintf("SELECT diskused(%Q)", zSchema); |
| 35043 | shell_check_oom(zSql); |
| 35044 | modePush(p); |
| 35045 | modeChange(p, MODE_BATCH); |
| 35046 | shell_exec(p, zSql, 0); |
| 35047 | modePop(p); |
| 35048 | sqlite3_free(zSql); |
| 35049 | }else |
| 35050 | |
| 35051 | if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){ |
| 35052 | char *zLike = 0; |
| 35053 | char *zSql; |
| 35054 | int i; |
| 35055 | int savedShellFlags = p->shellFlgs; |
| @@ -34689,15 +35451,19 @@ | |
| 35451 | } |
| 35452 | }else |
| 35453 | |
| 35454 | if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){ |
| 35455 | if( nArg==2 ){ |
| 35456 | if( cli_strcmp(azArg[1],"always")==0 ){ |
| 35457 | p->mode.spec.bTitles = QRF_Always; |
| 35458 | }else{ |
| 35459 | p->mode.spec.bTitles = booleanValue(azArg[1]) ? QRF_Yes : QRF_No; |
| 35460 | } |
| 35461 | p->mode.mFlags |= MFLG_HDR; |
| 35462 | p->mode.spec.eTitle = aModeInfo[p->mode.eMode].eHdr; |
| 35463 | }else{ |
| 35464 | eputz("Usage: .headers off|on|always\n"); |
| 35465 | rc = 1; |
| 35466 | } |
| 35467 | }else |
| 35468 | |
| 35469 | if( c=='h' && cli_strncmp(azArg[0], "help", n)==0 ){ |
| @@ -34901,13 +35667,21 @@ | |
| 35667 | sqlite3_str_free(pSql); |
| 35668 | }else |
| 35669 | |
| 35670 | if( c=='i' && cli_strncmp(azArg[0], "intck", n)==0 ){ |
| 35671 | i64 iArg = 0; |
| 35672 | open_db(p, 0); |
| 35673 | if( nArg==2 ){ |
| 35674 | iArg = integerValue(azArg[1]); |
| 35675 | if( iArg==0 ){ |
| 35676 | if( cli_strcmp(azArg[1],"register")==0 ){ |
| 35677 | sqlite3_intck_register(p->db, 1); |
| 35678 | rc = 0; |
| 35679 | goto meta_command_exit; |
| 35680 | } |
| 35681 | iArg = -1; |
| 35682 | } |
| 35683 | } |
| 35684 | if( (nArg!=1 && nArg!=2) || iArg<0 ){ |
| 35685 | cli_printf(stderr,"%s","Usage: .intck STEPS_PER_UNLOCK\n"); |
| 35686 | rc = 1; |
| 35687 | goto meta_command_exit; |
| @@ -34955,10 +35729,12 @@ | |
| 35729 | { "attached", SQLITE_LIMIT_ATTACHED }, |
| 35730 | { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, |
| 35731 | { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER }, |
| 35732 | { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH }, |
| 35733 | { "worker_threads", SQLITE_LIMIT_WORKER_THREADS }, |
| 35734 | { "schema", SQLITE_LIMIT_SCHEMA }, |
| 35735 | { "trigger_steps", SQLITE_LIMIT_TRIGGER_STEPS }, |
| 35736 | }; |
| 35737 | int i, n2; |
| 35738 | open_db(p, 0); |
| 35739 | if( nArg==1 ){ |
| 35740 | for(i=0; i<ArraySize(aLimit); i++){ |
| @@ -35400,10 +36176,26 @@ | |
| 36176 | }else |
| 36177 | if( strcmp(z,"-show")==0 ){ |
| 36178 | cli_printf(stdout,"Main prompt: '%s'\n", prompt_string(p, 0)); |
| 36179 | cli_printf(stdout,"Continuation: '%s'\n", prompt_string(p, 1)); |
| 36180 | }else |
| 36181 | #ifndef SQLITE_NO_COLOR |
| 36182 | if( strcmp(z,"-color")==0 ){ |
| 36183 | #ifdef _WIN32 |
| 36184 | _putenv("NO_COLOR="); |
| 36185 | #else |
| 36186 | unsetenv("NO_COLOR"); |
| 36187 | #endif |
| 36188 | }else |
| 36189 | if( strcmp(z,"-no-color")==0 ){ |
| 36190 | #ifdef _WIN32 |
| 36191 | _putenv("NO_COLOR=1"); |
| 36192 | #else |
| 36193 | setenv("NO_COLOR","1",1); |
| 36194 | #endif |
| 36195 | }else |
| 36196 | #endif |
| 36197 | if( strcmp(z,"-")==0 ){ |
| 36198 | noOpt = 1; |
| 36199 | }else |
| 36200 | { |
| 36201 | dotCmdError(p, i, "unknown option", 0); |
| @@ -35414,10 +36206,11 @@ | |
| 36206 | dotCmdError(p, i, "extra argument", 0); |
| 36207 | rc = 1; |
| 36208 | goto meta_command_exit; |
| 36209 | }else if( !p->dot.abQuot[i] && sqlite3_strglob("*[^a-z]*",z)!=0 ){ |
| 36210 | dotCmdError(p, i, "use quotes around the prompt string", 0); |
| 36211 | rc = 1; |
| 36212 | }else{ |
| 36213 | free(p->azPrompt[cnt]); |
| 36214 | p->azPrompt[cnt] = strdup(z); |
| 36215 | cnt++; |
| 36216 | } |
| @@ -36264,11 +37057,12 @@ | |
| 37057 | azBool[(p->mode.mFlags & MFLG_ECHO)!=0]); |
| 37058 | cli_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->mode.autoEQP&3]); |
| 37059 | cli_printf(p->out, "%12.12s: %s\n","explain", |
| 37060 | p->mode.autoExplain ? "auto" : "off"); |
| 37061 | cli_printf(p->out, "%12.12s: %s\n","headers", |
| 37062 | p->mode.spec.bTitles==QRF_Always ? "always" : |
| 37063 | azBool[p->mode.spec.bTitles==QRF_Yes]); |
| 37064 | if( p->mode.spec.eStyle==QRF_STYLE_Column |
| 37065 | || p->mode.spec.eStyle==QRF_STYLE_Box |
| 37066 | || p->mode.spec.eStyle==QRF_STYLE_Table |
| 37067 | || p->mode.spec.eStyle==QRF_STYLE_Markdown |
| 37068 | ){ |
| @@ -37626,17 +38420,18 @@ | |
| 38420 | " -- treat no subsequent arguments as options\n" |
| 38421 | #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) |
| 38422 | " -A ARGS... run \".archive ARGS\" and exit\n" |
| 38423 | #endif |
| 38424 | " -append append the database to the end of the file\n" |
| 38425 | " -ascii set '.mode ascii'\n" |
| 38426 | " -bail stop after hitting an error\n" |
| 38427 | " -batch force batch I/O\n" |
| 38428 | " -box set '.mode box'\n" |
| 38429 | " -cmd COMMAND run \"COMMAND\" before reading stdin\n" |
| 38430 | " -cmdline-edit BOOL enable or disable command-line editing\n" |
| 38431 | " -column set '.mode column'\n" |
| 38432 | " -csv set '.mode csv -limits off'\n" |
| 38433 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 38434 | " -deserialize open the database using sqlite3_deserialize()\n" |
| 38435 | #endif |
| 38436 | " -echo print inputs before execution\n" |
| 38437 | " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n" |
| @@ -37644,18 +38439,18 @@ | |
| 38439 | " -[no]header turn headers on or off\n" |
| 38440 | #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) |
| 38441 | " -heap SIZE Size of heap for memsys3 or memsys5\n" |
| 38442 | #endif |
| 38443 | " -help show this message\n" |
| 38444 | " -html set '.mode html'\n" |
| 38445 | " -ifexists only open if database already exists\n" |
| 38446 | " -interactive force interactive I/O\n" |
| 38447 | " -json set '.mode json'\n" |
| 38448 | " -line set '.mode line'\n" |
| 38449 | " -list set '.mode list'\n" |
| 38450 | " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" |
| 38451 | " -markdown set '.mode markdown'\n" |
| 38452 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 38453 | " -maxsize N maximum size for a --deserialize database\n" |
| 38454 | #endif |
| 38455 | " -memtrace trace all memory allocations and deallocations\n" |
| 38456 | " -mmap N default mmap size set to N\n" |
| @@ -37668,21 +38463,21 @@ | |
| 38463 | " -nonce STRING set the safe-mode escape nonce\n" |
| 38464 | " -no-rowid-in-view Disable rowid-in-view using sqlite3_config()\n" |
| 38465 | " -nullvalue TEXT set text string for NULL values. Default ''\n" |
| 38466 | " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" |
| 38467 | " -pcachetrace trace all page cache operations\n" |
| 38468 | " -quote set '.mode quote'\n" |
| 38469 | " -readonly open the database read-only\n" |
| 38470 | " -safe enable safe-mode\n" |
| 38471 | " -screenwidth N use N as the default screenwidth \n" |
| 38472 | " -separator SEP set output column separator. Default: '|'\n" |
| 38473 | #ifdef SQLITE_ENABLE_SORTER_REFERENCES |
| 38474 | " -sorterref SIZE sorter references threshold size\n" |
| 38475 | #endif |
| 38476 | " -stats print memory stats before each finalize\n" |
| 38477 | " -table set '.mode table'\n" |
| 38478 | " -tabs set '.mode tabs'\n" |
| 38479 | " -unsafe-testing allow unsafe commands and modes for testing\n" |
| 38480 | " -version show SQLite version\n" |
| 38481 | " -vfs NAME use NAME as the default VFS\n" |
| 38482 | " -vfstrace enable tracing of all VFS calls\n" |
| 38483 | #ifdef SQLITE_HAVE_ZLIB |
| @@ -37710,10 +38505,23 @@ | |
| 38505 | sputz(stdout, "WARNING: attempt to configure SQLite after" |
| 38506 | " initialization.\n"); |
| 38507 | } |
| 38508 | } |
| 38509 | |
| 38510 | #if HAVE_EDITLINE |
| 38511 | /* |
| 38512 | ** https://sqlite.org/forum/forumpost/aad7a634916ff050: |
| 38513 | ** |
| 38514 | ** Calling setlocale(LC_...,"") is required to get libedit to accept |
| 38515 | ** non-ASCII input. |
| 38516 | */ |
| 38517 | #define DO_SET_LOCALE 1 |
| 38518 | #include <locale.h> |
| 38519 | #else |
| 38520 | #define DO_SET_LOCALE 0 |
| 38521 | #endif |
| 38522 | |
| 38523 | /* |
| 38524 | ** Initialize the state information in data |
| 38525 | */ |
| 38526 | static void main_init(ShellState *p) { |
| 38527 | memset(p, 0, sizeof(*p)); |
| @@ -37724,31 +38532,36 @@ | |
| 38532 | verify_uninitialized(); |
| 38533 | #endif |
| 38534 | sqlite3_config(SQLITE_CONFIG_URI, 1); |
| 38535 | sqlite3_config(SQLITE_CONFIG_MULTITHREAD); |
| 38536 | globalShellState = p; |
| 38537 | #if HAVE_EDITLINE || HAVE_READLINE |
| 38538 | /* Editline requires \001...\002 delimiters around ANSI x3.64 escapes in |
| 38539 | ** prompt strings. Readline does sometimes, depending on how it is |
| 38540 | ** compiled and installed. */ |
| 38541 | p->bDelimitNonprint = 1; |
| 38542 | #else |
| 38543 | /* No \001...\002 escapes required for linenoise or when not using a |
| 38544 | ** command-line editing library */ |
| 38545 | p->bDelimitNonprint = 0; |
| 38546 | #endif |
| 38547 | #if DO_SET_LOCALE |
| 38548 | setlocale(LC_CTYPE,""); |
| 38549 | #endif |
| 38550 | #undef DO_SET_LOCALE |
| 38551 | } |
| 38552 | |
| 38553 | /* |
| 38554 | ** Output text to the console in a font that attracts extra attention. |
| 38555 | */ |
| 38556 | static void printBold(const char *zText){ |
| 38557 | if( shellNoColor() ){ |
| 38558 | cli_printf(stdout, "%s", zText); |
| 38559 | }else{ |
| 38560 | cli_printf(stdout, "\033[1;36m\033[3m%s\033[0m", zText); |
| 38561 | } |
| 38562 | } |
| 38563 | |
| 38564 | /* |
| 38565 | ** Get the argument to an --option. Throw an error and die if no argument |
| 38566 | ** is available. |
| 38567 | */ |
| @@ -37762,11 +38575,11 @@ | |
| 38575 | } |
| 38576 | |
| 38577 | /* |
| 38578 | ** The callback from atexit(). |
| 38579 | */ |
| 38580 | static void SQLITE_CDECL abnormalExit(void){ |
| 38581 | if( seenInterrupt ) eputz("Program interrupted.\n"); |
| 38582 | if( globalShellState ){ |
| 38583 | clearTempFile(globalShellState, 1, 1); |
| 38584 | } |
| 38585 | } |
| @@ -37837,10 +38650,11 @@ | |
| 38650 | } |
| 38651 | argv[argc] = 0; |
| 38652 | hOut = GetStdHandle(STD_OUTPUT_HANDLE); |
| 38653 | GetConsoleMode(hOut, &mode); |
| 38654 | SetConsoleMode(hOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); |
| 38655 | _setmode(_fileno(stdout),_O_BINARY); /* Bug 2026-08-03T08:52:42Z */ |
| 38656 | rc = utf8_main(argc, argv); |
| 38657 | for(i=0; i<argc; i++) free(orig[i]); |
| 38658 | free(argv); |
| 38659 | return rc; |
| 38660 | } |
| @@ -37883,10 +38697,13 @@ | |
| 38697 | stdout_is_console = 1; |
| 38698 | data.wasm.zDefaultDbName = "/fiddle.sqlite3"; |
| 38699 | #else |
| 38700 | stdin_is_interactive = isatty(0); |
| 38701 | stdout_is_console = isatty(1); |
| 38702 | if( !stdin_is_interactive || !stdout_is_console ){ |
| 38703 | shellCmdLineEdit = 0; |
| 38704 | } |
| 38705 | #endif |
| 38706 | atexit(abnormalExit); |
| 38707 | #ifdef SQLITE_DEBUG |
| 38708 | mem_main_enter = sqlite3_memory_used(); |
| 38709 | #endif |
| @@ -37973,11 +38790,11 @@ | |
| 38790 | stdin_is_interactive = 0; |
| 38791 | nCmd++; |
| 38792 | azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); |
| 38793 | shell_check_oom(azCmd); |
| 38794 | aiCmd = realloc(aiCmd, sizeof(aiCmd[0])*nCmd); |
| 38795 | shell_check_oom(aiCmd); |
| 38796 | azCmd[nCmd-1] = z; |
| 38797 | aiCmd[nCmd-1] = i; |
| 38798 | } |
| 38799 | continue; |
| 38800 | } |
| @@ -38130,10 +38947,12 @@ | |
| 38947 | }else if( cli_strcmp(z,"-safe")==0 ){ |
| 38948 | /* no-op - catch this on the second pass */ |
| 38949 | }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ |
| 38950 | /* skip over the argument */ |
| 38951 | i++; |
| 38952 | }else if( cli_strcmp(z,"-cmdline-edit")==0 ){ |
| 38953 | shellCmdLineEdit = booleanValue(cmdline_option_value(argc,argv,++i)); |
| 38954 | }else if( cli_strcmp(z,"-test-argv")==0 ){ |
| 38955 | /* Undocumented test option. Print the values in argv[] and exit. |
| 38956 | ** Use this to verify that any translation of the argv[], for example |
| 38957 | ** on Windows that receives wargv[] from the OS and must convert |
| 38958 | ** to UTF8 prior to calling this routine. */ |
| @@ -38262,10 +39081,11 @@ | |
| 39081 | modeChange(&data, MODE_Psql); |
| 39082 | }else if( cli_strcmp(z,"-box")==0 ){ |
| 39083 | modeChange(&data, MODE_Box); |
| 39084 | }else if( cli_strcmp(z,"-csv")==0 ){ |
| 39085 | modeChange(&data, MODE_Csv); |
| 39086 | modeSetLimit(&data, "off"); |
| 39087 | }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){ |
| 39088 | /* See similar code at tag-20250224-1 */ |
| 39089 | const char *zEsc = argv[++i]; |
| 39090 | int k; |
| 39091 | for(k=0; k<ArraySize(qrfEscNames); k++){ |
| @@ -38319,13 +39139,15 @@ | |
| 39139 | cmdline_option_value(argc,argv,++i)); |
| 39140 | }else if( cli_strcmp(z,"-nullvalue")==0 ){ |
| 39141 | modeSetStr(&data.mode.spec.zNull, |
| 39142 | cmdline_option_value(argc,argv,++i)); |
| 39143 | }else if( cli_strcmp(z,"-header")==0 ){ |
| 39144 | data.mode.spec.bTitles = QRF_Always; |
| 39145 | data.mode.mFlags |= MFLG_HDR; |
| 39146 | }else if( cli_strcmp(z,"-noheader")==0 ){ |
| 39147 | data.mode.spec.bTitles = QRF_No; |
| 39148 | data.mode.mFlags |= MFLG_HDR; |
| 39149 | }else if( cli_strcmp(z,"-echo")==0 ){ |
| 39150 | data.mode.mFlags |= MFLG_ECHO; |
| 39151 | }else if( cli_strcmp(z,"-eqp")==0 ){ |
| 39152 | data.mode.autoEQP = AUTOEQP_on; |
| 39153 | }else if( cli_strcmp(z,"-eqpfull")==0 ){ |
| @@ -38389,10 +39211,12 @@ | |
| 39211 | i++; |
| 39212 | #ifdef SQLITE_ENABLE_MULTIPLEX |
| 39213 | }else if( cli_strcmp(z,"-multiplex")==0 ){ |
| 39214 | i++; |
| 39215 | #endif |
| 39216 | }else if( cli_strcmp(z,"-cmdline-edit")==0 ){ |
| 39217 | i+=2; |
| 39218 | }else if( cli_strcmp(z,"-help")==0 ){ |
| 39219 | usage(1); |
| 39220 | }else if( cli_strcmp(z,"-cmd")==0 ){ |
| 39221 | /* Run commands that follow -cmd first and separately from commands |
| 39222 | ** that simply appear on the command-line. This seems goofy. It would |
| @@ -38418,12 +39242,14 @@ | |
| 39242 | rc = 1; |
| 39243 | goto shell_main_exit; |
| 39244 | } |
| 39245 | open_db(&data, OPEN_DB_ZIPFILE); |
| 39246 | if( z[2] ){ |
| 39247 | char *zSaved = argv[i]; |
| 39248 | argv[i] = &z[2]; |
| 39249 | arDotCommand(&data, 1, argv+(i-1), argc-(i-1)); |
| 39250 | argv[i] = zSaved; |
| 39251 | }else{ |
| 39252 | arDotCommand(&data, 1, argv+i, argc-i); |
| 39253 | } |
| 39254 | readStdin = 0; |
| 39255 | stdin_is_interactive = 0; |
| 39256 |
+4085
-1741
| --- extsrc/sqlite3.c | ||
| +++ extsrc/sqlite3.c | ||
| @@ -16,11 +16,11 @@ | ||
| 16 | 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | 19 | ** |
| 20 | 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | -** 4aac1057eeaf6c29a4893e9c080497c780b0 with changes in files: | |
| 21 | +** 3bd5456e50ef321f2cafcf67261d556a7606 with changes in files: | |
| 22 | 22 | ** |
| 23 | 23 | ** |
| 24 | 24 | */ |
| 25 | 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | 26 | #define SQLITE_CORE 1 |
| @@ -467,14 +467,14 @@ | ||
| 467 | 467 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 468 | 468 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 469 | 469 | */ |
| 470 | 470 | #define SQLITE_VERSION "3.54.0" |
| 471 | 471 | #define SQLITE_VERSION_NUMBER 3054000 |
| 472 | -#define SQLITE_SOURCE_ID "2026-04-30 18:23:58 4aac1057eeaf6c29a4893e9c080497c780b0963e810c501532d79eba1b457f27" | |
| 472 | +#define SQLITE_SOURCE_ID "2026-08-20 13:25:12 3bd5456e50ef321f2cafcf67261d556a760624ce0caab430ed9454cebec233e7" | |
| 473 | 473 | #define SQLITE_SCM_BRANCH "trunk" |
| 474 | 474 | #define SQLITE_SCM_TAGS "" |
| 475 | -#define SQLITE_SCM_DATETIME "2026-04-30T18:23:58.352Z" | |
| 475 | +#define SQLITE_SCM_DATETIME "2026-08-20T13:25:12.207Z" | |
| 476 | 476 | |
| 477 | 477 | /* |
| 478 | 478 | ** CAPI3REF: Run-Time Library Version Numbers |
| 479 | 479 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 480 | 480 | ** |
| @@ -3732,11 +3732,11 @@ | ||
| 3732 | 3732 | ** authorizer will fail with an error message explaining that |
| 3733 | 3733 | ** access is denied. |
| 3734 | 3734 | ** |
| 3735 | 3735 | ** ^The first parameter to the authorizer callback is a copy of the third |
| 3736 | 3736 | ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter |
| 3737 | -** to the callback is an integer [SQLITE_COPY | action code] that specifies | |
| 3737 | +** to the callback is an integer [SQLITE_READ | action code] that specifies | |
| 3738 | 3738 | ** the particular action to be authorized. ^The third through sixth parameters |
| 3739 | 3739 | ** to the callback are either NULL pointers or zero-terminated strings |
| 3740 | 3740 | ** that contain additional details about the action to be authorized. |
| 3741 | 3741 | ** Applications must always be prepared to encounter a NULL pointer in any |
| 3742 | 3742 | ** of the third through the sixth parameters of the authorization callback. |
| @@ -3775,25 +3775,37 @@ | ||
| 3775 | 3775 | ** ^(Only a single authorizer can be in place on a database connection |
| 3776 | 3776 | ** at a time. Each call to sqlite3_set_authorizer overrides the |
| 3777 | 3777 | ** previous call.)^ ^Disable the authorizer by installing a NULL callback. |
| 3778 | 3778 | ** The authorizer is disabled by default. |
| 3779 | 3779 | ** |
| 3780 | -** The authorizer callback must not do anything that will modify | |
| 3780 | +** <h3>Limitations And Caveats</h3><ul> | |
| 3781 | +** | |
| 3782 | +** <li>The authorizer callback must not do anything that will modify | |
| 3781 | 3783 | ** the database connection that invoked the authorizer callback. |
| 3782 | 3784 | ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their |
| 3783 | 3785 | ** database connections for the meaning of "modify" in this paragraph. |
| 3784 | 3786 | ** |
| 3785 | -** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the | |
| 3787 | +** <li>^When [sqlite3_prepare_v2()] is used to prepare a statement, the | |
| 3786 | 3788 | ** statement might be re-prepared during [sqlite3_step()] due to a |
| 3787 | 3789 | ** schema change. Hence, the application should ensure that the |
| 3788 | 3790 | ** correct authorizer callback remains in place during the [sqlite3_step()]. |
| 3789 | 3791 | ** |
| 3790 | -** ^Note that the authorizer callback is invoked only during | |
| 3792 | +** <li>^The authorizer callback is invoked only during | |
| 3791 | 3793 | ** [sqlite3_prepare()] or its variants. Authorization is not |
| 3792 | 3794 | ** performed during statement evaluation in [sqlite3_step()], unless |
| 3793 | 3795 | ** as stated in the previous paragraph, sqlite3_step() invokes |
| 3794 | 3796 | ** sqlite3_prepare_v2() to reprepare a statement after a schema change. |
| 3797 | +** | |
| 3798 | +** <li>Authorizer callbacks for the expressions of a | |
| 3799 | +** [generated column] are invoked when the schema is parsed (and specifically | |
| 3800 | +** when the [CREATE TABLE] statement that contains the generated column is | |
| 3801 | +** parsed) not when the generated column is used in a DML statement. | |
| 3802 | +** This is deliberate, as one of the purposes of generated columns | |
| 3803 | +** is to give schema designers the ability to provide gated access | |
| 3804 | +** to privileged columns and/or functions. | |
| 3805 | +** | |
| 3806 | +** </ul> | |
| 3795 | 3807 | */ |
| 3796 | 3808 | SQLITE_API int sqlite3_set_authorizer( |
| 3797 | 3809 | sqlite3*, |
| 3798 | 3810 | int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), |
| 3799 | 3811 | void *pUserData |
| @@ -3864,12 +3876,17 @@ | ||
| 3864 | 3876 | #define SQLITE_ANALYZE 28 /* Table Name NULL */ |
| 3865 | 3877 | #define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ |
| 3866 | 3878 | #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ |
| 3867 | 3879 | #define SQLITE_FUNCTION 31 /* NULL Function Name */ |
| 3868 | 3880 | #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ |
| 3869 | -#define SQLITE_COPY 0 /* No longer used */ | |
| 3870 | 3881 | #define SQLITE_RECURSIVE 33 /* NULL NULL */ |
| 3882 | + | |
| 3883 | +/* | |
| 3884 | +** Note: The SQLITE_COPY macro (with value 0) used to be one of the | |
| 3885 | +** action codes above. That macro has now been repurposed as a possible | |
| 3886 | +** value to the 3rd argument to sqlite3_result_str(). | |
| 3887 | +*/ | |
| 3871 | 3888 | |
| 3872 | 3889 | /* |
| 3873 | 3890 | ** CAPI3REF: Deprecated Tracing And Profiling Functions |
| 3874 | 3891 | ** DEPRECATED |
| 3875 | 3892 | ** |
| @@ -4373,12 +4390,11 @@ | ||
| 4373 | 4390 | ** parameter on F or if the value of P does not match any of the |
| 4374 | 4391 | ** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). |
| 4375 | 4392 | ** |
| 4376 | 4393 | ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a |
| 4377 | 4394 | ** 64-bit signed integer and returns that integer, or D if P does not |
| 4378 | -** exist. If the value of P is something other than an integer, then | |
| 4379 | -** zero is returned. | |
| 4395 | +** exist or ff the value of P is something other than an integer. | |
| 4380 | 4396 | ** |
| 4381 | 4397 | ** The sqlite3_uri_key(F,N) returns a pointer to the name (not |
| 4382 | 4398 | ** the value) of the N-th query parameter for filename F, or a NULL |
| 4383 | 4399 | ** pointer if N is less than zero or greater than the number of query |
| 4384 | 4400 | ** parameters minus 1. The N value is zero-based so N should be 0 to obtain |
| @@ -4697,11 +4713,12 @@ | ||
| 4697 | 4713 | ** <dd>The maximum number of columns in a table definition or in the |
| 4698 | 4714 | ** result set of a [SELECT] or the maximum number of columns in an index |
| 4699 | 4715 | ** or in an ORDER BY or GROUP BY clause.</dd>)^ |
| 4700 | 4716 | ** |
| 4701 | 4717 | ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> |
| 4702 | -** <dd>The maximum depth of the parse tree on any expression.</dd>)^ | |
| 4718 | +** <dd>The maximum depth of the parse tree on any expression and | |
| 4719 | +** the maximum nesting depth for subqueries and VIEWs</dd>)^ | |
| 4703 | 4720 | ** |
| 4704 | 4721 | ** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(<dt>SQLITE_LIMIT_PARSER_DEPTH</dt> |
| 4705 | 4722 | ** <dd>The maximum depth of the LALR(1) parser stack used to analyze |
| 4706 | 4723 | ** input SQL statements.</dd>)^ |
| 4707 | 4724 | ** |
| @@ -4728,15 +4745,24 @@ | ||
| 4728 | 4745 | ** [[SQLITE_LIMIT_VARIABLE_NUMBER]] |
| 4729 | 4746 | ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> |
| 4730 | 4747 | ** <dd>The maximum index number of any [parameter] in an SQL statement.)^ |
| 4731 | 4748 | ** |
| 4732 | 4749 | ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> |
| 4733 | -** <dd>The maximum depth of recursion for triggers.</dd>)^ | |
| 4750 | +** <dd>The maximum depth of recursion for triggers, and the maximum | |
| 4751 | +** nesting depth for separate triggers.</dd>)^ | |
| 4734 | 4752 | ** |
| 4735 | 4753 | ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(<dt>SQLITE_LIMIT_WORKER_THREADS</dt> |
| 4736 | 4754 | ** <dd>The maximum number of auxiliary worker threads that a single |
| 4737 | 4755 | ** [prepared statement] may start.</dd>)^ |
| 4756 | +** | |
| 4757 | +** [[SQLITE_LIMIT_SCHEMA]] ^(<dt>SQLITE_LIMIT_SCHEMA</dt> | |
| 4758 | +** <dd>The maximum number of objects (tables, indexes, triggers, and views) | |
| 4759 | +** defined by the database schema.</dd>)^ | |
| 4760 | +** | |
| 4761 | +** [[SQLITE_LIMIT_TRIGGER_STEPS]] ^(<dt>SQLITE_LIMIT_TRIGGER_STEPS</dt> | |
| 4762 | +** <dd>The maximum number of SQL statements that can be contained within | |
| 4763 | +** a single trigger.</dd>)^ | |
| 4738 | 4764 | ** </dl> |
| 4739 | 4765 | */ |
| 4740 | 4766 | #define SQLITE_LIMIT_LENGTH 0 |
| 4741 | 4767 | #define SQLITE_LIMIT_SQL_LENGTH 1 |
| 4742 | 4768 | #define SQLITE_LIMIT_COLUMN 2 |
| @@ -4748,10 +4774,12 @@ | ||
| 4748 | 4774 | #define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 |
| 4749 | 4775 | #define SQLITE_LIMIT_VARIABLE_NUMBER 9 |
| 4750 | 4776 | #define SQLITE_LIMIT_TRIGGER_DEPTH 10 |
| 4751 | 4777 | #define SQLITE_LIMIT_WORKER_THREADS 11 |
| 4752 | 4778 | #define SQLITE_LIMIT_PARSER_DEPTH 12 |
| 4779 | +#define SQLITE_LIMIT_SCHEMA 13 | |
| 4780 | +#define SQLITE_LIMIT_TRIGGER_STEPS 14 | |
| 4753 | 4781 | |
| 4754 | 4782 | /* |
| 4755 | 4783 | ** CAPI3REF: Prepare Flags |
| 4756 | 4784 | ** |
| 4757 | 4785 | ** These constants define various flags that can be passed into the |
| @@ -4859,10 +4887,12 @@ | ||
| 4859 | 4887 | ** there is a small performance advantage to passing an nByte parameter that |
| 4860 | 4888 | ** is the number of bytes in the input string <i>including</i> |
| 4861 | 4889 | ** the nul-terminator. |
| 4862 | 4890 | ** Note that nByte measures the length of the input in bytes, not |
| 4863 | 4891 | ** characters, even for the UTF-16 interfaces. |
| 4892 | +** For the sqlite3_prepare16() and sqlite3_prepare16_v2() interfaces, | |
| 4893 | +** the nByte value must be even or undefined behavior can result. | |
| 4864 | 4894 | ** |
| 4865 | 4895 | ** ^If pzTail is not NULL then *pzTail is made to point to the first byte |
| 4866 | 4896 | ** past the end of the first SQL statement in zSql. These routines only |
| 4867 | 4897 | ** compile the first statement in zSql, so *pzTail is left pointing to |
| 4868 | 4898 | ** what remains uncompiled. |
| @@ -5605,11 +5635,11 @@ | ||
| 5605 | 5635 | ** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) |
| 5606 | 5636 | ** can be obtained by calling [sqlite3_reset()] on the |
| 5607 | 5637 | ** [prepared statement]. ^In the "v2" interface, |
| 5608 | 5638 | ** the more specific error code is returned directly by sqlite3_step(). |
| 5609 | 5639 | ** |
| 5610 | -** [SQLITE_MISUSE] means that the this routine was called inappropriately. | |
| 5640 | +** [SQLITE_MISUSE] means that this routine was called inappropriately. | |
| 5611 | 5641 | ** Perhaps it was called on a [prepared statement] that has |
| 5612 | 5642 | ** already been [sqlite3_finalize | finalized] or on one that had |
| 5613 | 5643 | ** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could |
| 5614 | 5644 | ** be the case that the same database connection is being used by two or |
| 5615 | 5645 | ** more threads at the same moment in time. |
| @@ -6778,11 +6808,15 @@ | ||
| 6778 | 6808 | ** to by the second parameter and which is N bytes long where N is the |
| 6779 | 6809 | ** third parameter. |
| 6780 | 6810 | ** |
| 6781 | 6811 | ** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N) |
| 6782 | 6812 | ** interfaces set the result of the application-defined function to be |
| 6783 | -** a BLOB containing all zero bytes and N bytes in size. | |
| 6813 | +** a BLOB containing all zero bytes and N bytes in size. The | |
| 6814 | +** zeroblob64(C,N) interface returns a [result code], which is normally | |
| 6815 | +** [SQLITE_OK] but might be some other value if the requested operation | |
| 6816 | +** could not be complete, for example if insufficient memory is available | |
| 6817 | +** or if the value of N is out of range. | |
| 6784 | 6818 | ** |
| 6785 | 6819 | ** ^The sqlite3_result_double() interface sets the result from |
| 6786 | 6820 | ** an application-defined function to be a floating point value specified |
| 6787 | 6821 | ** by its 2nd argument. |
| 6788 | 6822 | ** |
| @@ -9116,12 +9150,12 @@ | ||
| 9116 | 9150 | ** The lifecycle of an sqlite3_str object is as follows: |
| 9117 | 9151 | ** <ol> |
| 9118 | 9152 | ** <li> ^The sqlite3_str object is created using [sqlite3_str_new()]. |
| 9119 | 9153 | ** <li> ^Text is appended to the sqlite3_str object using various |
| 9120 | 9154 | ** methods, such as [sqlite3_str_appendf()]. |
| 9121 | -** <li> ^The sqlite3_str object is destroyed and the string it created | |
| 9122 | -** is returned using the [sqlite3_str_finish()] interface. | |
| 9155 | +** <li> The sqlite3_str object is destroyed and the string it created | |
| 9156 | +** is returned using [sqlite3_str_finish()] or [sqlite3_result_str()]. | |
| 9123 | 9157 | ** </ol> |
| 9124 | 9158 | */ |
| 9125 | 9159 | typedef struct sqlite3_str sqlite3_str; |
| 9126 | 9160 | |
| 9127 | 9161 | /* |
| @@ -9169,10 +9203,44 @@ | ||
| 9169 | 9203 | ** the equivalent of calling [sqlite3_free](sqlite3_str_finish(X)). |
| 9170 | 9204 | */ |
| 9171 | 9205 | SQLITE_API char *sqlite3_str_finish(sqlite3_str*); |
| 9172 | 9206 | SQLITE_API void sqlite3_str_free(sqlite3_str*); |
| 9173 | 9207 | |
| 9208 | +/* | |
| 9209 | +** CAPI3REF: Return A Dynamic String From an SQL Function | |
| 9210 | +** | |
| 9211 | +** The [sqlite3_result_str(C,S,F)] interface causes the | |
| 9212 | +** [sqlite3_str|dynamic string] S to become the return value for the | |
| 9213 | +** application-defined function or virtual table that uses | |
| 9214 | +** [sqlite3_context] C. The F flag can be one of [SQLITE_COPY] | |
| 9215 | +** or [SQLITE_XFER] or [SQLITE_FINISH]. | |
| 9216 | +** | |
| 9217 | +** If the dynamic string is invalid or incomplete due to an out-of-memory | |
| 9218 | +** or string-too-large error, then this routine transfers that error | |
| 9219 | +** over to the SQL function. | |
| 9220 | +** | |
| 9221 | +** If the F argument is SQLITE_COPY, then a copy of the dynamic string | |
| 9222 | +** content is made and the dynamic string object is unchanged. | |
| 9223 | +** If the F argument is SQLITE_XFER, then ownership of the content | |
| 9224 | +** in the dynamic is transferred to the SQL function (via a pointer copy | |
| 9225 | +** rather than a string copy) and the dynamic string is reset to an | |
| 9226 | +** empty string. The SQLITE_FINISH value for F works like SQLITE_RESET | |
| 9227 | +** except that it also invokes the [sqlite3_str_free(S)] destructor | |
| 9228 | +** on the dynamic string object. | |
| 9229 | +*/ | |
| 9230 | +SQLITE_API void sqlite3_result_str(sqlite3_context*, sqlite3_str*, int); | |
| 9231 | + | |
| 9232 | +/* | |
| 9233 | +** CAPI3REF: Control Flags For sqlite3_result_str() | |
| 9234 | +** | |
| 9235 | +** The following integers can be used as the third "F" argument | |
| 9236 | +** to [sqlite3_result_str(C,S,F)]. | |
| 9237 | +*/ | |
| 9238 | +#define SQLITE_COPY 0 /* Results copied. Dynamic string unchanged */ | |
| 9239 | +#define SQLITE_XFER 1 /* Results transfered. Dynamic string reset */ | |
| 9240 | +#define SQLITE_FINISH 2 /* Like SQLITE_XFER, plus dynamic string freed */ | |
| 9241 | + | |
| 9174 | 9242 | /* |
| 9175 | 9243 | ** CAPI3REF: Add Content To A Dynamic String |
| 9176 | 9244 | ** METHOD: sqlite3_str |
| 9177 | 9245 | ** |
| 9178 | 9246 | ** These interfaces add or remove content to an sqlite3_str object |
| @@ -11534,12 +11602,23 @@ | ||
| 11534 | 11602 | ** reopen S as an in-memory database based on the serialization |
| 11535 | 11603 | ** contained in P. If S is a NULL pointer, the main database is |
| 11536 | 11604 | ** used. The serialized database P is N bytes in size. M is the size |
| 11537 | 11605 | ** of the buffer P, which might be larger than N. If M is larger than |
| 11538 | 11606 | ** N, and the SQLITE_DESERIALIZE_READONLY bit is not set in F, then |
| 11539 | -** SQLite is permitted to add content to the in-memory database as | |
| 11540 | -** long as the total size does not exceed M bytes. | |
| 11607 | +** SQLite is permitted to add content to the in-memory database, in | |
| 11608 | +** page-sized chunks, as long as the total size does not exceed M bytes. | |
| 11609 | +** | |
| 11610 | +** The parameter M must be greater than or equal to N. Ideally, M | |
| 11611 | +** should have a value which is N+(512×K)+20 where K determines how | |
| 11612 | +** must extra space is available to hold new content as the database | |
| 11613 | +** grows. K can be 0 if the database is read-only. | |
| 11614 | +** | |
| 11615 | +** If the database content in P is malformed in a malicious way then | |
| 11616 | +** it is possible that SQLite might try to read a few more than N bytes | |
| 11617 | +** from P. If the veracity of the database content P is uncertain, | |
| 11618 | +** then applications are advised to allocate about 20 extra bytes on | |
| 11619 | +** the end of the P buffer to avoid a memory error. | |
| 11541 | 11620 | ** |
| 11542 | 11621 | ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will |
| 11543 | 11622 | ** invoke sqlite3_free() on the serialization buffer when the database |
| 11544 | 11623 | ** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then |
| 11545 | 11624 | ** SQLite will try to increase the buffer size using sqlite3_realloc64() |
| @@ -13184,15 +13263,27 @@ | ||
| 13184 | 13263 | ** <dt>SQLITE_CHANGESETAPPLY_FKNOACTION <dd> |
| 13185 | 13264 | ** If this flag it set, then all foreign key constraints in the target |
| 13186 | 13265 | ** database behave as if they were declared with "ON UPDATE NO ACTION ON |
| 13187 | 13266 | ** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL |
| 13188 | 13267 | ** or SET DEFAULT. |
| 13268 | +** | |
| 13269 | +** <dt>SQLITE_CHANGESETAPPLY_NOUPDATELOOP <dd> | |
| 13270 | +** Sometimes, a changeset contains two or more update statements such that | |
| 13271 | +** although after applying all updates the database will contain no | |
| 13272 | +** constraint violations, no single update can be applied before the others. | |
| 13273 | +** The simplest example of this is a pair of UPDATEs that have "swapped" | |
| 13274 | +** two column values with a UNIQUE constraint. | |
| 13275 | +** <p> | |
| 13276 | +** Usually, sqlite3changeset_apply() and similar functions work hard to try | |
| 13277 | +** to find a way to apply such a changeset. However, if this flag is set, | |
| 13278 | +** then all such updates are considered CONSTRAINT conflicts. | |
| 13189 | 13279 | */ |
| 13190 | 13280 | #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 |
| 13191 | 13281 | #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 |
| 13192 | 13282 | #define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 |
| 13193 | 13283 | #define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008 |
| 13284 | +#define SQLITE_CHANGESETAPPLY_NOUPDATELOOP 0x0010 | |
| 13194 | 13285 | |
| 13195 | 13286 | /* |
| 13196 | 13287 | ** CAPI3REF: Constants Passed To The Conflict Handler |
| 13197 | 13288 | ** |
| 13198 | 13289 | ** Values that may be passed as the second argument to a conflict-handler. |
| @@ -14954,10 +15045,45 @@ | ||
| 14954 | 15045 | */ |
| 14955 | 15046 | #ifndef SQLITE_MAX_TRIGGER_DEPTH |
| 14956 | 15047 | # define SQLITE_MAX_TRIGGER_DEPTH 1000 |
| 14957 | 15048 | #endif |
| 14958 | 15049 | |
| 15050 | +/* | |
| 15051 | +** Maximum number of objects defined by a single database schema. | |
| 15052 | +** Objects include: | |
| 15053 | +** | |
| 15054 | +** * tables (including the sqlite_schema table) | |
| 15055 | +** * virtual tables | |
| 15056 | +** * named indexes | |
| 15057 | +** * indexes created automatically by UNIQUE and PRIMARY KEY constraints | |
| 15058 | +** * triggers | |
| 15059 | +** * views | |
| 15060 | +** | |
| 15061 | +** The total of all of the above is the number of objects in the schema, | |
| 15062 | +** and that number may not exceed this value. | |
| 15063 | +** | |
| 15064 | +** The maximum number of objects is restricted to forestall theoretical | |
| 15065 | +** signed integer overflow attacks using databases with billions of | |
| 15066 | +** schema objects. Such attacks are "theoretical" because memory and | |
| 15067 | +** disk space constraints would be reached long before billions of schema | |
| 15068 | +** objects could be created. Even so, it seems good to have a well defined | |
| 15069 | +** upper limit on the complexity of the schema, for defense in depth. | |
| 15070 | +** No real-world application should ever get anywhere close to hitting | |
| 15071 | +** this limit. | |
| 15072 | +*/ | |
| 15073 | +#ifndef SQLITE_MAX_SCHEMA | |
| 15074 | +# define SQLITE_MAX_SCHEMA 10000000 | |
| 15075 | +#endif | |
| 15076 | + | |
| 15077 | +/* | |
| 15078 | +** Maximum number of SQL statements allowed in the body of a single | |
| 15079 | +** trigger. | |
| 15080 | +*/ | |
| 15081 | +#ifndef SQLITE_MAX_TRIGGER_STEPS | |
| 15082 | +# define SQLITE_MAX_TRIGGER_STEPS 65000 | |
| 15083 | +#endif | |
| 15084 | + | |
| 14959 | 15085 | /************** End of sqliteLimit.h *****************************************/ |
| 14960 | 15086 | /************** Continuing where we left off in sqliteInt.h ******************/ |
| 14961 | 15087 | |
| 14962 | 15088 | /* Disable nuisance warnings on Borland compilers */ |
| 14963 | 15089 | #if defined(__BORLANDC__) |
| @@ -15022,26 +15148,54 @@ | ||
| 15022 | 15148 | # define SQLITE_INT_TO_PTR(X) ((void*)(X)) |
| 15023 | 15149 | # define SQLITE_PTR_TO_INT(X) ((int)(X)) |
| 15024 | 15150 | #endif |
| 15025 | 15151 | |
| 15026 | 15152 | /* |
| 15027 | -** Macros to hint to the compiler that a function should or should not be | |
| 15028 | -** inlined. | |
| 15153 | +** Hint to the compiler that a function should or should not be inlined: | |
| 15154 | +** | |
| 15155 | +** SQLITE_NOINLINE Never in-line this function | |
| 15156 | +** | |
| 15157 | +** SQLITE_INLINE Strive to in-line this function | |
| 15158 | +** | |
| 15159 | +** SQLITE_OPT_INLINE In-line this function if building the | |
| 15160 | +** amalgamation. | |
| 15161 | +** | |
| 15162 | +** SQLITE_USES_INLINE Set to 1 or 0 according to whether or not | |
| 15163 | +** inline functions are supported. | |
| 15029 | 15164 | */ |
| 15030 | -#if defined(__GNUC__) | |
| 15031 | -# define SQLITE_NOINLINE __attribute__((noinline)) | |
| 15032 | -# define SQLITE_INLINE __attribute__((always_inline)) inline | |
| 15165 | +#if defined(SQLITE_DISABLE_INLINE) | |
| 15166 | +# define SQLITE_NOINLINE | |
| 15167 | +# define SQLITE_INLINE | |
| 15168 | +# define SQLITE_OPT_INLINE | |
| 15169 | +# define SQLITE_USES_INLINE 0 | |
| 15170 | +#elif defined(__GNUC__) | |
| 15171 | +# define SQLITE_NOINLINE __attribute__((noinline)) | |
| 15172 | +# define SQLITE_INLINE __attribute__((always_inline)) inline | |
| 15173 | +# define SQLITE_OPT_INLINE __attribute__((always_inline)) inline | |
| 15174 | +# define SQLITE_USES_INLINE 1 | |
| 15033 | 15175 | #elif defined(_MSC_VER) && _MSC_VER>=1310 |
| 15034 | -# define SQLITE_NOINLINE __declspec(noinline) | |
| 15035 | -# define SQLITE_INLINE __forceinline | |
| 15176 | +# define SQLITE_NOINLINE __declspec(noinline) | |
| 15177 | +# define SQLITE_INLINE __forceinline | |
| 15178 | +# define SQLITE_OPT_INLINE __forceinline | |
| 15179 | +# define SQLITE_USES_INLINE 1 | |
| 15036 | 15180 | #else |
| 15037 | 15181 | # define SQLITE_NOINLINE |
| 15038 | 15182 | # define SQLITE_INLINE |
| 15183 | +# define SQLITE_OPT_INLINE | |
| 15184 | +# define SQLITE_USES_INLINE 0 | |
| 15039 | 15185 | #endif |
| 15040 | 15186 | #if defined(SQLITE_COVERAGE_TEST) || defined(__STRICT_ANSI__) |
| 15041 | 15187 | # undef SQLITE_INLINE |
| 15042 | 15188 | # define SQLITE_INLINE |
| 15189 | +# undef SQLITE_OPT_INLINE | |
| 15190 | +# define SQLITE_OPT_INLINE | |
| 15191 | +# undef SQLITE_USES_INLINE | |
| 15192 | +# define SQLITE_USES_INLINE 0 | |
| 15193 | +#endif | |
| 15194 | +#if !defined(SQLITE_AMALGAMATION) | |
| 15195 | +# undef SQLITE_OPT_INLINE | |
| 15196 | +# define SQLITE_OPT_INLINE | |
| 15043 | 15197 | #endif |
| 15044 | 15198 | |
| 15045 | 15199 | /* |
| 15046 | 15200 | ** Make sure that the compiler intrinsics we desire are enabled when |
| 15047 | 15201 | ** compiling with an appropriate version of MSVC unless prevented by |
| @@ -15212,11 +15366,13 @@ | ||
| 15212 | 15366 | ** bitmask tests, testcase() can be used to make sure each bit |
| 15213 | 15367 | ** is significant and used at least once. On switch statements |
| 15214 | 15368 | ** where multiple cases go to the same block of code, testcase() |
| 15215 | 15369 | ** can insure that all cases are evaluated. |
| 15216 | 15370 | */ |
| 15217 | -#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) | |
| 15371 | +#if defined(SQLITE_MUTATION_TEST) | |
| 15372 | +# define testcase(X) | |
| 15373 | +#elif defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) | |
| 15218 | 15374 | # ifndef SQLITE_AMALGAMATION |
| 15219 | 15375 | extern unsigned int sqlite3CoverageCounter; |
| 15220 | 15376 | # endif |
| 15221 | 15377 | # define testcase(X) if( X ){ sqlite3CoverageCounter += (unsigned)__LINE__; } |
| 15222 | 15378 | #else |
| @@ -15798,10 +15954,17 @@ | ||
| 15798 | 15954 | */ |
| 15799 | 15955 | #ifndef offsetof |
| 15800 | 15956 | # define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0)) |
| 15801 | 15957 | #endif |
| 15802 | 15958 | |
| 15959 | +/* | |
| 15960 | +** sizeof64() is like sizeof(), but always returns a 64-bit value, even | |
| 15961 | +** on 32-bit builds. This can help to avoid overflow by ensuring 64-bit | |
| 15962 | +** arithmetic is used consistently in both 32-bit and 64-bit builds. | |
| 15963 | +*/ | |
| 15964 | +#define sizeof64(X) ((sqlite3_int64)sizeof(X)) | |
| 15965 | + | |
| 15803 | 15966 | /* |
| 15804 | 15967 | ** Work around C99 "flex-array" syntax for pre-C99 compilers, so as |
| 15805 | 15968 | ** to avoid complaints from -fsanitize=strict-bounds. |
| 15806 | 15969 | */ |
| 15807 | 15970 | #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) |
| @@ -17159,11 +17322,11 @@ | ||
| 17159 | 17322 | SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); |
| 17160 | 17323 | #endif |
| 17161 | 17324 | |
| 17162 | 17325 | SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *); |
| 17163 | 17326 | SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *); |
| 17164 | -SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *); | |
| 17327 | +SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree*, Btree*); | |
| 17165 | 17328 | |
| 17166 | 17329 | SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *); |
| 17167 | 17330 | |
| 17168 | 17331 | /* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR |
| 17169 | 17332 | ** of the flags shown below. |
| @@ -17236,16 +17399,23 @@ | ||
| 17236 | 17399 | ** The design of the _RANGE hint is aid b-tree implementations that try |
| 17237 | 17400 | ** to prefetch content from remote machines - to provide those |
| 17238 | 17401 | ** implementations with limits on what needs to be prefetched and thereby |
| 17239 | 17402 | ** reduce network bandwidth. |
| 17240 | 17403 | ** |
| 17404 | +** BTREE_HINT_TABLECURSOR (arguments: BtCursor*) | |
| 17405 | +** | |
| 17406 | +** This hint is invoked on a non-covering index cursor soon after it | |
| 17407 | +** is opened. The only argument is a pointer to the table cursor used to | |
| 17408 | +** obtain non-covered fields from the database. | |
| 17409 | +** | |
| 17241 | 17410 | ** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by |
| 17242 | 17411 | ** standard SQLite. The other hints are provided for extensions that use |
| 17243 | 17412 | ** the SQLite parser and code generator but substitute their own storage |
| 17244 | 17413 | ** engine. |
| 17245 | 17414 | */ |
| 17246 | 17415 | #define BTREE_HINT_RANGE 0 /* Range constraints on queries */ |
| 17416 | +#define BTREE_HINT_TABLECURSOR 1 /* Table csr associated with this index csr */ | |
| 17247 | 17417 | |
| 17248 | 17418 | /* |
| 17249 | 17419 | ** Values that may be OR'd together to form the argument to the |
| 17250 | 17420 | ** BTREE_HINT_FLAGS hint for sqlite3BtreeCursorHint(): |
| 17251 | 17421 | ** |
| @@ -17301,10 +17471,13 @@ | ||
| 17301 | 17471 | #endif |
| 17302 | 17472 | SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*); |
| 17303 | 17473 | SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); |
| 17304 | 17474 | #ifdef SQLITE_ENABLE_CURSOR_HINTS |
| 17305 | 17475 | SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...); |
| 17476 | + #ifdef SQLITE_DEBUG | |
| 17477 | +SQLITE_PRIVATE BtCursor *sqlite3BtreeCursorHintTblCsr(BtCursor*); | |
| 17478 | + #endif | |
| 17306 | 17479 | #endif |
| 17307 | 17480 | |
| 17308 | 17481 | SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*); |
| 17309 | 17482 | SQLITE_PRIVATE int sqlite3BtreeTableMoveto( |
| 17310 | 17483 | BtCursor*, |
| @@ -17547,12 +17720,10 @@ | ||
| 17547 | 17720 | int p3; /* The third parameter */ |
| 17548 | 17721 | union p4union { /* fourth parameter */ |
| 17549 | 17722 | int i; /* Integer value if p4type==P4_INT32 */ |
| 17550 | 17723 | void *p; /* Generic pointer */ |
| 17551 | 17724 | char *z; /* Pointer to data for string (char array) types */ |
| 17552 | - i64 *pI64; /* Used when p4type is P4_INT64 */ | |
| 17553 | - double *pReal; /* Used when p4type is P4_REAL */ | |
| 17554 | 17725 | FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ |
| 17555 | 17726 | sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */ |
| 17556 | 17727 | CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ |
| 17557 | 17728 | Mem *pMem; /* Used when p4type is P4_MEM */ |
| 17558 | 17729 | VTable *pVtab; /* Used when p4type is P4_VTAB */ |
| @@ -17603,10 +17774,23 @@ | ||
| 17603 | 17774 | signed char p1; /* First operand */ |
| 17604 | 17775 | signed char p2; /* Second parameter (often the jump destination) */ |
| 17605 | 17776 | signed char p3; /* Third parameter */ |
| 17606 | 17777 | }; |
| 17607 | 17778 | typedef struct VdbeOpList VdbeOpList; |
| 17779 | + | |
| 17780 | +/* | |
| 17781 | +** Combine two int32 values into a single int64. The least significant | |
| 17782 | +** term comes first. | |
| 17783 | +*/ | |
| 17784 | +#define INT32_TO_64(a,b) (i64)(((u64)(u32)(b)<<32)|(u32)(a)) | |
| 17785 | + | |
| 17786 | +/* | |
| 17787 | +** Return an int32 that is the lower or upper 32-bits of an int64. | |
| 17788 | +*/ | |
| 17789 | +#define LOWER32(x) (int)(((u64)(x))&0xffffffff) | |
| 17790 | +#define UPPER32(x) (int)(((u64)(x))>>32) | |
| 17791 | + | |
| 17608 | 17792 | |
| 17609 | 17793 | /* |
| 17610 | 17794 | ** Allowed values of VdbeOp.p4type |
| 17611 | 17795 | */ |
| 17612 | 17796 | #define P4_NOTUSED 0 /* The P4 parameter is not used */ |
| @@ -17623,16 +17807,14 @@ | ||
| 17623 | 17807 | #define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */ |
| 17624 | 17808 | #define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */ |
| 17625 | 17809 | #define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */ |
| 17626 | 17810 | #define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */ |
| 17627 | 17811 | #define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */ |
| 17628 | -#define P4_REAL (-13) /* P4 is a 64-bit floating point value */ | |
| 17629 | -#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */ | |
| 17630 | -#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ | |
| 17631 | -#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ | |
| 17632 | -#define P4_TABLEREF (-17) /* Like P4_TABLE, but reference counted */ | |
| 17633 | -#define P4_SUBRTNSIG (-18) /* P4 is a SubrtnSig pointer */ | |
| 17812 | +#define P4_INTARRAY (-13) /* P4 is a vector of 32-bit integers */ | |
| 17813 | +#define P4_FUNCCTX (-14) /* P4 is a pointer to an sqlite3_context object */ | |
| 17814 | +#define P4_TABLEREF (-15) /* Like P4_TABLE, but reference counted */ | |
| 17815 | +#define P4_SUBRTNSIG (-16) /* P4 is a SubrtnSig pointer */ | |
| 17634 | 17816 | |
| 17635 | 17817 | /* Error message codes for OP_Halt */ |
| 17636 |