Fossil SCM

fossil-scm / extsrc / shell.c
Source Blame History 8485 lines
4f76459… drh 1 /*
4f76459… drh 2 ** This is the amalgamated source code to the "sqlite3" or "sqlite3.exe"
4f76459… drh 3 ** command-line shell (CLI) for SQLite. This file is automatically
4f76459… drh 4 ** generated by the tool/mkshellc.tcl script from the following sources:
4f76459… drh 5 **
4f76459… drh 6 ** ext/expert/sqlite3expert.c
4f76459… drh 7 ** ext/expert/sqlite3expert.h
4f76459… drh 8 ** ext/intck/sqlite3intck.c
4f76459… drh 9 ** ext/intck/sqlite3intck.h
4f76459… drh 10 ** ext/misc/appendvfs.c
4f76459… drh 11 ** ext/misc/base64.c
4f76459… drh 12 ** ext/misc/base85.c
4f76459… drh 13 ** ext/misc/completion.c
4f76459… drh 14 ** ext/misc/decimal.c
4f76459… drh 15 ** ext/misc/fileio.c
4f76459… drh 16 ** ext/misc/ieee754.c
4f76459… drh 17 ** ext/misc/memtrace.c
4f76459… drh 18 ** ext/misc/pcachetrace.c
4f76459… drh 19 ** ext/misc/regexp.c
4f76459… drh 20 ** ext/misc/series.c
4f76459… drh 21 ** ext/misc/sha1.c
4f76459… drh 22 ** ext/misc/shathree.c
4f76459… drh 23 ** ext/misc/sqlar.c
4f76459… drh 24 ** ext/misc/sqlite3_stdio.c
4f76459… drh 25 ** ext/misc/sqlite3_stdio.h
4f76459… drh 26 ** ext/misc/stmtrand.c
4f76459… drh 27 ** ext/misc/uint.c
4f76459… drh 28 ** ext/misc/vfstrace.c
4f76459… drh 29 ** ext/misc/windirent.h
4f76459… drh 30 ** ext/misc/zipfile.c
4f76459… drh 31 ** ext/qrf/qrf.c
4f76459… drh 32 ** ext/qrf/qrf.h
4f76459… drh 33 ** ext/recover/dbdata.c
4f76459… drh 34 ** ext/recover/sqlite3recover.c
4f76459… drh 35 ** ext/recover/sqlite3recover.h
4f76459… drh 36 ** src/shell.c.in
4f76459… drh 37 ** edit the src/shell.c.in file and/or some of the other files that are
b9ecacf… drh 38 ** listed above, then rerun the command "make shell.c".
4f76459… drh 39 /************************* Begin src/shell.c.in ******************/
b9ecacf… drh 40 ** This file contains code to implement the "sqlite3" command line
b9ecacf… drh 41
b9ecacf… drh 42 /*
a10f931… drh 43 ** Limit input nesting via .read or any other input redirect.
a10f931… drh 44 ** It's not too expensive, so a generous allowance can be made.
a10f931… drh 45 */
a10f931… drh 46 #define MAX_INPUT_NESTING 25
a10f931… drh 47
a10f931… drh 48 /*
a10f931… drh 49 ** Used to prevent warnings about unused parameters
a10f931… drh 50 */
a10f931… drh 51 #define UNUSED_PARAMETER(x) (void)(x)
a10f931… drh 52
a10f931… drh 53 /*
a10f931… drh 54 ** Number of elements in an array
a10f931… drh 55 */
a10f931… drh 56 #define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
a10f931… drh 57
a10f931… drh 58 /*
2b2530d… drh 59 #if defined(SQLITE_SHELL_FIDDLE)
2b2530d… drh 60 # undef SQLITE_OMIT_LOAD_EXTENSION
2b2530d… drh 61 # define SQLITE_OMIT_LOAD_EXTENSION 1
2b2530d… drh 62 #endif
cb89386… drh 63 #include <stdint.h>
4f76459… drh 64 # include <sys/ioctl.h>
4f76459… drh 65 /************************* Begin ext/misc/sqlite3_stdio.h ******************/
4f76459… drh 66 #include <stdarg.h>
4f76459… drh 67 int sqlite3_vfprintf(FILE *stream, const char *format, va_list);
4f76459… drh 68 #define sqlite3_vfprintf vfprintf
4f76459… drh 69 /************************* End ext/misc/sqlite3_stdio.h ********************/
4f76459… drh 70 /************************* Begin ext/misc/sqlite3_stdio.c ******************/
0201a1e… drh 71 b1 = sqlite3_malloc64( (sz1+1)*sizeof(b1[0]) );
0201a1e… drh 72 b2 = sqlite3_malloc64( (sz2+1)*sizeof(b1[0]) );
0201a1e… drh 73 b1 = sqlite3_malloc64( (sz1+1)*sizeof(b1[0]) );
0201a1e… drh 74 b2 = sqlite3_malloc64( (sz2+1)*sizeof(b1[0]) );
0201a1e… drh 75 wchar_t *b1 = sqlite3_malloc64( sz*sizeof(wchar_t) );
0201a1e… drh 76 wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(wchar_t) );
4f76459… drh 77 ** Work-alikes for fprintf() and vfprintf() from the standard C library.
4f76459… drh 78 int sqlite3_vfprintf(FILE *out, const char *zFormat, va_list ap){
4f76459… drh 79 int rc;
4f76459… drh 80 if( UseWtextForOutput(out) ){
4f76459… drh 81 /* When writing to the command-prompt in Windows, it is necessary
4f76459… drh 82 ** to use _O_WTEXT input mode and write UTF-16 characters.
4f76459… drh 83 */
4f76459… drh 84 char *z;
4f76459… drh 85 z = sqlite3_vmprintf(zFormat, ap);
4f76459… drh 86 sqlite3_fputs(z, out);
4f76459… drh 87 rc = (int)strlen(z);
4f76459… drh 88 sqlite3_free(z);
4f76459… drh 89 }else{
4f76459… drh 90 /* Writing to a file or other destination, just write bytes without
4f76459… drh 91 ** any translation. */
4f76459… drh 92 rc = vfprintf(out, zFormat, ap);
4f76459… drh 93 }
4f76459… drh 94 return rc;
4f76459… drh 95 }
4f76459… drh 96 /************************* End ext/misc/sqlite3_stdio.c ********************/
4f76459… drh 97 /************************* Begin ext/qrf/qrf.h ******************/
4f76459… drh 98 /*
4f76459… drh 99 ** 2025-10-20
4f76459… drh 100 **
4f76459… drh 101 ** The author disclaims copyright to this source code. In place of
4f76459… drh 102 ** a legal notice, here is a blessing:
4f76459… drh 103 **
4f76459… drh 104 ** May you do good and not evil.
4f76459… drh 105 ** May you find forgiveness for yourself and forgive others.
4f76459… drh 106 ** May you share freely, never taking more than you give.
4f76459… drh 107 **
4f76459… drh 108 *************************************************************************
4f76459… drh 109 ** Header file for the Result-Format or "resfmt" utility library for SQLite.
0201a1e… drh 110 ** See the README.md documentation for additional information.
4f76459… drh 111 */
4f76459… drh 112 #ifndef SQLITE_QRF_H
4f76459… drh 113 #define SQLITE_QRF_H
9aee493… drh 114 #ifdef __cplusplus
9aee493… drh 115 extern "C" {
9aee493… drh 116 #endif
4f76459… drh 117 #include <stdlib.h>
4f76459… drh 118 /* #include "sqlite3.h" */
4f76459… drh 119
4f76459… drh 120 /*
4f76459… drh 121 ** Specification used by clients to define the output format they want
4f76459… drh 122 */
4f76459… drh 123 typedef struct sqlite3_qrf_spec sqlite3_qrf_spec;
4f76459… drh 124 struct sqlite3_qrf_spec {
4f76459… drh 125 unsigned char iVersion; /* Version number of this structure */
4f76459… drh 126 unsigned char eStyle; /* Formatting style. "box", "csv", etc... */
4f76459… drh 127 unsigned char eEsc; /* How to escape control characters in text */
4f76459… drh 128 unsigned char eText; /* Quoting style for text */
4f76459… drh 129 unsigned char eTitle; /* Quating style for the text of column names */
4f76459… drh 130 unsigned char eBlob; /* Quoting style for BLOBs */
4f76459… drh 131 unsigned char bTitles; /* True to show column names */
4f76459… drh 132 unsigned char bWordWrap; /* Try to wrap on word boundaries */
4f76459… drh 133 unsigned char bTextJsonb; /* Render JSONB blobs as JSON text */
4f76459… drh 134 unsigned char eDfltAlign; /* Default alignment, no covered by aAlignment */
4f76459… drh 135 unsigned char eTitleAlign; /* Alignment for column headers */
9aee493… drh 136 unsigned char bSplitColumn; /* Wrap single-column output into many columns */
f4b3b59… drh 137 unsigned char bBorder; /* Show outer border in Box and Table styles */
4f76459… drh 138 short int nWrap; /* Wrap columns wider than this */
4f76459… drh 139 short int nScreenWidth; /* Maximum overall table width */
4f76459… drh 140 short int nLineLimit; /* Maximum number of lines for any row */
ae7e3f0… drh 141 short int nTitleLimit; /* Maximum number of characters in a title */
cb89386… drh 142 unsigned int nMultiInsert; /* Add rows to one INSERT until size exceeds */
4f76459… drh 143 int nCharLimit; /* Maximum number of characters in a cell */
4f76459… drh 144 int nWidth; /* Number of entries in aWidth[] */
4f76459… drh 145 int nAlign; /* Number of entries in aAlignment[] */
4f76459… drh 146 short int *aWidth; /* Column widths */
4f76459… drh 147 unsigned char *aAlign; /* Column alignments */
4f76459… drh 148 char *zColumnSep; /* Alternative column separator */
4f76459… drh 149 char *zRowSep; /* Alternative row separator */
4f76459… drh 150 char *zTableName; /* Output table name */
4f76459… drh 151 char *zNull; /* Rendering of NULL */
4f76459… drh 152 char *(*xRender)(void*,sqlite3_value*); /* Render a value */
4f76459… drh 153 int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */
4f76459… drh 154 void *pRenderArg; /* First argument to the xRender callback */
4f76459… drh 155 void *pWriteArg; /* First argument to the xWrite callback */
4f76459… drh 156 char **pzOutput; /* Storage location for output string */
4f76459… drh 157 /* Additional fields may be added in the future */
4f76459… drh 158 };
4f76459… drh 159
4f76459… drh 160 /*
4f76459… drh 161 ** Interfaces
4f76459… drh 162 */
4f76459… drh 163 int sqlite3_format_query_result(
4f76459… drh 164 sqlite3_stmt *pStmt, /* SQL statement to run */
4f76459… drh 165 const sqlite3_qrf_spec *pSpec, /* Result format specification */
4f76459… drh 166 char **pzErr /* OUT: Write error message here */
4f76459… drh 167 );
4f76459… drh 168
4f76459… drh 169 /*
4f76459… drh 170 ** Range of values for sqlite3_qrf_spec.aWidth[] entries and for
4f76459… drh 171 ** sqlite3_qrf_spec.mxColWidth and .nScreenWidth
4f76459… drh 172 */
4f76459… drh 173 #define QRF_MAX_WIDTH 10000
4f76459… drh 174 #define QRF_MIN_WIDTH 0
4f76459… drh 175
4f76459… drh 176 /*
4f76459… drh 177 ** Output styles:
4f76459… drh 178 */
4f76459… drh 179 #define QRF_STYLE_Auto 0 /* Choose a style automatically */
4f76459… drh 180 #define QRF_STYLE_Box 1 /* Unicode box-drawing characters */
4f76459… drh 181 #define QRF_STYLE_Column 2 /* One record per line in neat columns */
4f76459… drh 182 #define QRF_STYLE_Count 3 /* Output only a count of the rows of output */
4f76459… drh 183 #define QRF_STYLE_Csv 4 /* Comma-separated-value */
4f76459… drh 184 #define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */
4f76459… drh 185 #define QRF_STYLE_Explain 6 /* EXPLAIN output */
4f76459… drh 186 #define QRF_STYLE_Html 7 /* Generate an XHTML table */
4f76459… drh 187 #define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */
4f76459… drh 188 #define QRF_STYLE_Json 9 /* Output is a list of JSON objects */
4f76459… drh 189 #define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */
4f76459… drh 190 #define QRF_STYLE_Line 11 /* One column per line. */
4f76459… drh 191 #define QRF_STYLE_List 12 /* One record per line with a separator */
4f76459… drh 192 #define QRF_STYLE_Markdown 13 /* Markdown formatting */
4f76459… drh 193 #define QRF_STYLE_Off 14 /* No query output shown */
4f76459… drh 194 #define QRF_STYLE_Quote 15 /* SQL-quoted, comma-separated */
4f76459… drh 195 #define QRF_STYLE_Stats 16 /* EQP-like output but with performance stats */
4f76459… drh 196 #define QRF_STYLE_StatsEst 17 /* EQP-like output with planner estimates */
4f76459… drh 197 #define QRF_STYLE_StatsVm 18 /* EXPLAIN-like output with performance stats */
4f76459… drh 198 #define QRF_STYLE_Table 19 /* MySQL-style table formatting */
4f76459… drh 199
4f76459… drh 200 /*
4f76459… drh 201 ** Quoting styles for text.
4f76459… drh 202 ** Allowed values for sqlite3_qrf_spec.eText
4f76459… drh 203 */
4f76459… drh 204 #define QRF_TEXT_Auto 0 /* Choose text encoding automatically */
4f76459… drh 205 #define QRF_TEXT_Plain 1 /* Literal text */
4f76459… drh 206 #define QRF_TEXT_Sql 2 /* Quote as an SQL literal */
4f76459… drh 207 #define QRF_TEXT_Csv 3 /* CSV-style quoting */
4f76459… drh 208 #define QRF_TEXT_Html 4 /* HTML-style quoting */
4f76459… drh 209 #define QRF_TEXT_Tcl 5 /* C/Tcl quoting */
4f76459… drh 210 #define QRF_TEXT_Json 6 /* JSON quoting */
709b566… drh 211 #define QRF_TEXT_Relaxed 7 /* Relaxed SQL quoting */
4f76459… drh 212
4f76459… drh 213 /*
4f76459… drh 214 ** Quoting styles for BLOBs
4f76459… drh 215 ** Allowed values for sqlite3_qrf_spec.eBlob
4f76459… drh 216 */
4f76459… drh 217 #define QRF_BLOB_Auto 0 /* Determine BLOB quoting using eText */
4f76459… drh 218 #define QRF_BLOB_Text 1 /* Display content exactly as it is */
4f76459… drh 219 #define QRF_BLOB_Sql 2 /* Quote as an SQL literal */
4f76459… drh 220 #define QRF_BLOB_Hex 3 /* Hexadecimal representation */
4f76459… drh 221 #define QRF_BLOB_Tcl 4 /* "\000" notation */
4f76459… drh 222 #define QRF_BLOB_Json 5 /* A JSON string */
45de97f… drh 223 #define QRF_BLOB_Size 6 /* Display the blob size only */
4f76459… drh 224
4f76459… drh 225 /*
4f76459… drh 226 ** Control-character escape modes.
4f76459… drh 227 ** Allowed values for sqlite3_qrf_spec.eEsc
4f76459… drh 228 */
4f76459… drh 229 #define QRF_ESC_Auto 0 /* Choose the ctrl-char escape automatically */
4f76459… drh 230 #define QRF_ESC_Off 1 /* Do not escape control characters */
4f76459… drh 231 #define QRF_ESC_Ascii 2 /* Unix-style escapes. Ex: U+0007 shows ^G */
4f76459… drh 232 #define QRF_ESC_Symbol 3 /* Unicode escapes. Ex: U+0007 shows U+2407 */
4f76459… drh 233
4f76459… drh 234 /*
4f76459… drh 235 ** Allowed values for "boolean" fields, such as "bColumnNames", "bWordWrap",
4f76459… drh 236 ** and "bTextJsonb". There is an extra "auto" variants so these are actually
4f76459… drh 237 ** tri-state settings, not booleans.
4f76459… drh 238 */
4f76459… drh 239 #define QRF_SW_Auto 0 /* Let QRF choose the best value */
4f76459… drh 240 #define QRF_SW_Off 1 /* This setting is forced off */
4f76459… drh 241 #define QRF_SW_On 2 /* This setting is forced on */
4f76459… drh 242 #define QRF_Auto 0 /* Alternate spelling for QRF_*_Auto */
4f76459… drh 243 #define QRF_No 1 /* Alternate spelling for QRF_SW_Off */
4f76459… drh 244 #define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */
4f76459… drh 245
4f76459… drh 246 /*
4f76459… drh 247 ** Possible alignment values alignment settings
4f76459… drh 248 **
4f76459… drh 249 ** Horizontal Vertial
4f76459… drh 250 ** ---------- -------- */
4f76459… drh 251 #define QRF_ALIGN_Auto 0 /* auto auto */
4f76459… drh 252 #define QRF_ALIGN_Left 1 /* left auto */
4f76459… drh 253 #define QRF_ALIGN_Center 2 /* center auto */
4f76459… drh 254 #define QRF_ALIGN_Right 3 /* right auto */
4f76459… drh 255 #define QRF_ALIGN_Top 4 /* auto top */
4f76459… drh 256 #define QRF_ALIGN_NW 5 /* left top */
4f76459… drh 257 #define QRF_ALIGN_N 6 /* center top */
4f76459… drh 258 #define QRF_ALIGN_NE 7 /* right top */
4f76459… drh 259 #define QRF_ALIGN_Middle 8 /* auto middle */
4f76459… drh 260 #define QRF_ALIGN_W 9 /* left middle */
4f76459… drh 261 #define QRF_ALIGN_C 10 /* center middle */
4f76459… drh 262 #define QRF_ALIGN_E 11 /* right middle */
4f76459… drh 263 #define QRF_ALIGN_Bottom 12 /* auto bottom */
4f76459… drh 264 #define QRF_ALIGN_SW 13 /* left bottom */
4f76459… drh 265 #define QRF_ALIGN_S 14 /* center bottom */
4f76459… drh 266 #define QRF_ALIGN_SE 15 /* right bottom */
4f76459… drh 267 #define QRF_ALIGN_HMASK 3 /* Horizontal alignment mask */
4f76459… drh 268 #define QRF_ALIGN_VMASK 12 /* Vertical alignment mask */
4f76459… drh 269
4f76459… drh 270 /*
4f76459… drh 271 ** Auxiliary routines contined within this module that might be useful
4f76459… drh 272 ** in other contexts, and which are therefore exported.
4f76459… drh 273 */
4f76459… drh 274 /*
4f76459… drh 275 ** Return an estimate of the width, in columns, for the single Unicode
4f76459… drh 276 ** character c. For normal characters, the answer is always 1. But the
4f76459… drh 277 ** estimate might be 0 or 2 for zero-width and double-width characters.
4f76459… drh 278 **
d326547… drh 279 ** Different devices display unicode using different widths. So
4f76459… drh 280 ** it is impossible to know that true display width with 100% accuracy.
4f76459… drh 281 ** Inaccuracies in the width estimates might cause columns to be misaligned.
4f76459… drh 282 ** Unfortunately, there is nothing we can do about that.
4f76459… drh 283 */
4f76459… drh 284 int sqlite3_qrf_wcwidth(int c);
d326547… drh 285
d326547… drh 286 /*
d326547… drh 287 ** Return an estimate of the number of display columns used by the
d326547… drh 288 ** string in the argument. The width of individual characters is
d326547… drh 289 ** determined as for sqlite3_qrf_wcwidth(). VT100 escape code sequences
d326547… drh 290 ** are assigned a width of zero.
d326547… drh 291 */
d326547… drh 292 size_t sqlite3_qrf_wcswidth(const char*);
4f76459… drh 293
4f76459… drh 294
9aee493… drh 295 #ifdef __cplusplus
9aee493… drh 296 }
9aee493… drh 297 #endif
4f76459… drh 298 #endif /* !defined(SQLITE_QRF_H) */
4f76459… drh 299
4f76459… drh 300 /************************* End ext/qrf/qrf.h ********************/
4f76459… drh 301 /************************* Begin ext/qrf/qrf.c ******************/
4f76459… drh 302 /*
4f76459… drh 303 ** 2025-10-20
4f76459… drh 304 **
4f76459… drh 305 ** The author disclaims copyright to this source code. In place of
4f76459… drh 306 ** a legal notice, here is a blessing:
4f76459… drh 307 **
4f76459… drh 308 ** May you do good and not evil.
4f76459… drh 309 ** May you find forgiveness for yourself and forgive others.
4f76459… drh 310 ** May you share freely, never taking more than you give.
4f76459… drh 311 **
4f76459… drh 312 *************************************************************************
4f76459… drh 313 ** Implementation of the Result-Format or "qrf" utility library for SQLite.
4f76459… drh 314 ** See the qrf.md documentation for additional information.
4f76459… drh 315 */
4f76459… drh 316 #ifndef SQLITE_QRF_H
4f76459… drh 317 #include "qrf.h"
4f76459… drh 318 #endif
4f76459… drh 319 #include <string.h>
4f76459… drh 320 #include <assert.h>
7b0960d… drh 321 #include <stdint.h>
4f76459… drh 322
4f76459… drh 323 /* typedef sqlite3_int64 i64; */
4f76459… drh 324
4f76459… drh 325 /* A single line in the EQP output */
4f76459… drh 326 typedef struct qrfEQPGraphRow qrfEQPGraphRow;
4f76459… drh 327 struct qrfEQPGraphRow {
4f76459… drh 328 int iEqpId; /* ID for this row */
4f76459… drh 329 int iParentId; /* ID of the parent row */
4f76459… drh 330 qrfEQPGraphRow *pNext; /* Next row in sequence */
4f76459… drh 331 char zText[1]; /* Text to display for this row */
4f76459… drh 332 };
4f76459… drh 333
4f76459… drh 334 /* All EQP output is collected into an instance of the following */
4f76459… drh 335 typedef struct qrfEQPGraph qrfEQPGraph;
4f76459… drh 336 struct qrfEQPGraph {
4f76459… drh 337 qrfEQPGraphRow *pRow; /* Linked list of all rows of the EQP output */
4f76459… drh 338 qrfEQPGraphRow *pLast; /* Last element of the pRow list */
7b0960d… drh 339 int nWidth; /* Width of the graph */
7b0960d… drh 340 char zPrefix[400]; /* Graph prefix */
4f76459… drh 341 };
4f76459… drh 342
4f76459… drh 343 /*
4f76459… drh 344 ** Private state information. Subject to change from one release to the
4f76459… drh 345 ** next.
4f76459… drh 346 */
4f76459… drh 347 typedef struct Qrf Qrf;
4f76459… drh 348 struct Qrf {
4f76459… drh 349 sqlite3_stmt *pStmt; /* The statement whose output is to be rendered */
4f76459… drh 350 sqlite3 *db; /* The corresponding database connection */
4f76459… drh 351 sqlite3_stmt *pJTrans; /* JSONB to JSON translator statement */
4f76459… drh 352 char **pzErr; /* Write error message here, if not NULL */
4f76459… drh 353 sqlite3_str *pOut; /* Accumulated output */
4f76459… drh 354 int iErr; /* Error code */
4f76459… drh 355 int nCol; /* Number of output columns */
4f76459… drh 356 int expMode; /* Original sqlite3_stmt_isexplain() plus 1 */
4f76459… drh 357 int mxWidth; /* Screen width */
4f76459… drh 358 int mxHeight; /* nLineLimit */
4f76459… drh 359 union {
4f76459… drh 360 struct { /* Content for QRF_STYLE_Line */
4f76459… drh 361 int mxColWth; /* Maximum display width of any column */
ae7e3f0… drh 362 char **azCol; /* Names of output columns (MODE_Line) */
4f76459… drh 363 } sLine;
4f76459… drh 364 qrfEQPGraph *pGraph; /* EQP graph (Eqp, Stats, and StatsEst) */
4f76459… drh 365 struct { /* Content for QRF_STYLE_Explain */
4f76459… drh 366 int nIndent; /* Slots allocated for aiIndent */
4f76459… drh 367 int iIndent; /* Current slot */
4f76459… drh 368 int *aiIndent; /* Indentation for each opcode */
4f76459… drh 369 } sExpln;
17f9878… drh 370 unsigned int nIns; /* Bytes used for current INSERT stmt */
4f76459… drh 371 } u;
4f76459… drh 372 sqlite3_int64 nRow; /* Number of rows handled so far */
4f76459… drh 373 int *actualWidth; /* Actual width of each column */
4f76459… drh 374 sqlite3_qrf_spec spec; /* Copy of the original spec */
4f76459… drh 375 };
4f76459… drh 376
4f76459… drh 377 /*
4f76459… drh 378 ** Data for substitute ctype.h functions. Used for x-platform
4f76459… drh 379 ** consistency and so that '_' is counted as an alphabetic
4f76459… drh 380 ** character.
4f76459… drh 381 **
4f76459… drh 382 ** 0x01 - space
4f76459… drh 383 ** 0x02 - digit
4f76459… drh 384 ** 0x04 - alphabetic, including '_'
4f76459… drh 385 */
4f76459… drh 386 static const char qrfCType[] = {
4f76459… drh 387 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
4f76459… drh 388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 389 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 390 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
4f76459… drh 391 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4f76459… drh 392 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4,
4f76459… drh 393 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4f76459… drh 394 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0,
4f76459… drh 395 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 397 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 398 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 399 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 400 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 401 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 402 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
4f76459… drh 403 };
4f76459… drh 404 #define qrfSpace(x) ((qrfCType[(unsigned char)x]&1)!=0)
4f76459… drh 405 #define qrfDigit(x) ((qrfCType[(unsigned char)x]&2)!=0)
4f76459… drh 406 #define qrfAlpha(x) ((qrfCType[(unsigned char)x]&4)!=0)
4f76459… drh 407 #define qrfAlnum(x) ((qrfCType[(unsigned char)x]&6)!=0)
4f76459… drh 408
709b566… drh 409 #ifndef deliberate_fall_through
709b566… drh 410 /* Quiet some compilers about some of our intentional code. */
709b566… drh 411 # if defined(GCC_VERSION) && GCC_VERSION>=7000000
709b566… drh 412 # define deliberate_fall_through __attribute__((fallthrough));
709b566… drh 413 # else
709b566… drh 414 # define deliberate_fall_through
709b566… drh 415 # endif
709b566… drh 416 #endif
709b566… drh 417
4f76459… drh 418 /*
4f76459… drh 419 ** Set an error code and error message.
4f76459… drh 420 */
4f76459… drh 421 static void qrfError(
4f76459… drh 422 Qrf *p, /* Query result state */
4f76459… drh 423 int iCode, /* Error code */
4f76459… drh 424 const char *zFormat, /* Message format (or NULL) */
4f76459… drh 425 ...
4f76459… drh 426 ){
4f76459… drh 427 p->iErr = iCode;
4f76459… drh 428 if( p->pzErr!=0 ){
4f76459… drh 429 sqlite3_free(*p->pzErr);
4f76459… drh 430 *p->pzErr = 0;
4f76459… drh 431 if( zFormat ){
4f76459… drh 432 va_list ap;
4f76459… drh 433 va_start(ap, zFormat);
4f76459… drh 434 *p->pzErr = sqlite3_vmprintf(zFormat, ap);
4f76459… drh 435 va_end(ap);
4f76459… drh 436 }
4f76459… drh 437 }
4f76459… drh 438 }
4f76459… drh 439
4f76459… drh 440 /*
4f76459… drh 441 ** Out-of-memory error.
4f76459… drh 442 */
4f76459… drh 443 static void qrfOom(Qrf *p){
4f76459… drh 444 qrfError(p, SQLITE_NOMEM, "out of memory");
4f76459… drh 445 }
4f76459… drh 446
2b2530d… drh 447 /*
2b2530d… drh 448 ** Transfer any error in pStr over into p.
2b2530d… drh 449 */
2b2530d… drh 450 static void qrfStrErr(Qrf *p, sqlite3_str *pStr){
2b2530d… drh 451 int rc = pStr ? sqlite3_str_errcode(pStr) : 0;
2b2530d… drh 452 if( rc ){
2b2530d… drh 453 qrfError(p, rc, sqlite3_errstr(rc));
2b2530d… drh 454 }
2b2530d… drh 455 }
4f76459… drh 456
4f76459… drh 457
4f76459… drh 458 /*
4f76459… drh 459 ** Add a new entry to the EXPLAIN QUERY PLAN data
4f76459… drh 460 */
4f76459… drh 461 static void qrfEqpAppend(Qrf *p, int iEqpId, int p2, const char *zText){
4f76459… drh 462 qrfEQPGraphRow *pNew;
4f76459… drh 463 sqlite3_int64 nText;
4f76459… drh 464 if( zText==0 ) return;
4f76459… drh 465 if( p->u.pGraph==0 ){
4f76459… drh 466 p->u.pGraph = sqlite3_malloc64( sizeof(qrfEQPGraph) );
4f76459… drh 467 if( p->u.pGraph==0 ){
4f76459… drh 468 qrfOom(p);
4f76459… drh 469 return;
4f76459… drh 470 }
4f76459… drh 471 memset(p->u.pGraph, 0, sizeof(qrfEQPGraph) );
4f76459… drh 472 }
4f76459… drh 473 nText = strlen(zText);
4f76459… drh 474 pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
4f76459… drh 475 if( pNew==0 ){
4f76459… drh 476 qrfOom(p);
4f76459… drh 477 return;
4f76459… drh 478 }
4f76459… drh 479 pNew->iEqpId = iEqpId;
4f76459… drh 480 pNew->iParentId = p2;
4f76459… drh 481 memcpy(pNew->zText, zText, nText+1);
4f76459… drh 482 pNew->pNext = 0;
4f76459… drh 483 if( p->u.pGraph->pLast ){
4f76459… drh 484 p->u.pGraph->pLast->pNext = pNew;
4f76459… drh 485 }else{
4f76459… drh 486 p->u.pGraph->pRow = pNew;
4f76459… drh 487 }
4f76459… drh 488 p->u.pGraph->pLast = pNew;
4f76459… drh 489 }
4f76459… drh 490
4f76459… drh 491 /*
4f76459… drh 492 ** Free and reset the EXPLAIN QUERY PLAN data that has been collected
4f76459… drh 493 ** in p->u.pGraph.
4f76459… drh 494 */
4f76459… drh 495 static void qrfEqpReset(Qrf *p){
4f76459… drh 496 qrfEQPGraphRow *pRow, *pNext;
4f76459… drh 497 if( p->u.pGraph ){
4f76459… drh 498 for(pRow = p->u.pGraph->pRow; pRow; pRow = pNext){
4f76459… drh 499 pNext = pRow->pNext;
4f76459… drh 500 sqlite3_free(pRow);
4f76459… drh 501 }
4f76459… drh 502 sqlite3_free(p->u.pGraph);
4f76459… drh 503 p->u.pGraph = 0;
4f76459… drh 504 }
4f76459… drh 505 }
4f76459… drh 506
4f76459… drh 507 /* Return the next EXPLAIN QUERY PLAN line with iEqpId that occurs after
4f76459… drh 508 ** pOld, or return the first such line if pOld is NULL
4f76459… drh 509 */
4f76459… drh 510 static qrfEQPGraphRow *qrfEqpNextRow(Qrf *p, int iEqpId, qrfEQPGraphRow *pOld){
4f76459… drh 511 qrfEQPGraphRow *pRow = pOld ? pOld->pNext : p->u.pGraph->pRow;
4f76459… drh 512 while( pRow && pRow->iParentId!=iEqpId ) pRow = pRow->pNext;
4f76459… drh 513 return pRow;
4f76459… drh 514 }
4f76459… drh 515
4f76459… drh 516 /* Render a single level of the graph that has iEqpId as its parent. Called
4f76459… drh 517 ** recursively to render sublevels.
4f76459… drh 518 */
4f76459… drh 519 static void qrfEqpRenderLevel(Qrf *p, int iEqpId){
4f76459… drh 520 qrfEQPGraphRow *pRow, *pNext;
4f76459… drh 521 i64 n = strlen(p->u.pGraph->zPrefix);
4f76459… drh 522 for(pRow = qrfEqpNextRow(p, iEqpId, 0); pRow; pRow = pNext){
4f76459… drh 523 pNext = qrfEqpNextRow(p, iEqpId, pRow);
4f76459… drh 524 z = pRow->zText;
4f76459… drh 525 sqlite3_str_appendf(p->pOut, "%s%s%s\n", p->u.pGraph->zPrefix,
4f76459… drh 526 pNext ? "|--" : "`--", z);
4f76459… drh 527 if( n<(i64)sizeof(p->u.pGraph->zPrefix)-7 ){
4f76459… drh 528 memcpy(&p->u.pGraph->zPrefix[n], pNext ? "| " : " ", 4);
4f76459… drh 529 qrfEqpRenderLevel(p, pRow->iEqpId);
4f76459… drh 530 p->u.pGraph->zPrefix[n] = 0;
4f76459… drh 531 }
4f76459… drh 532 }
4f76459… drh 533 }
4f76459… drh 534
4f76459… drh 535 /*
7b0960d… drh 536 ** Render the 64-bit value N in a more human-readable format into
7b0960d… drh 537 ** pOut.
7b0960d… drh 538 **
7b0960d… drh 539 ** + Only show the first three significant digits.
7b0960d… drh 540 ** + Append suffixes K, M, G, T, P, and E for 1e3, 1e6, ... 1e18
7b0960d… drh 541 */
7b0960d… drh 542 static void qrfApproxInt64(sqlite3_str *pOut, i64 N){
7b0960d… drh 543 static const char aSuffix[] = { 'K', 'M', 'G', 'T', 'P', 'E' };
7b0960d… drh 544 int i;
7b0960d… drh 545 if( N<0 ){
7b0960d… drh 546 N = N==INT64_MIN ? INT64_MAX : -N;
7b0960d… drh 547 sqlite3_str_append(pOut, "-", 1);
7b0960d… drh 548 }
7b0960d… drh 549 if( N<10000 ){
7b0960d… drh 550 sqlite3_str_appendf(pOut, "%4lld ", N);
7b0960d… drh 551 return;
7b0960d… drh 552 }
7b0960d… drh 553 for(i=1; i<=18; i++){
7b0960d… drh 554 N = (N+5)/10;
7b0960d… drh 555 if( N<10000 ){
7b0960d… drh 556 int n = (int)N;
7b0960d… drh 557 switch( i%3 ){
7b0960d… drh 558 case 0:
7b0960d… drh 559 sqlite3_str_appendf(pOut, "%d.%02d", n/1000, (n%1000)/10);
7b0960d… drh 560 break;
7b0960d… drh 561 case 1:
7b0960d… drh 562 sqlite3_str_appendf(pOut, "%2d.%d", n/100, (n%100)/10);
7b0960d… drh 563 break;
7b0960d… drh 564 case 2:
7b0960d… drh 565 sqlite3_str_appendf(pOut, "%4d", n/10);
7b0960d… drh 566 break;
7b0960d… drh 567 }
7b0960d… drh 568 sqlite3_str_append(pOut, &aSuffix[i/3], 1);
7b0960d… drh 569 break;
7b0960d… drh 570 }
7b0960d… drh 571 }
7b0960d… drh 572 }
7b0960d… drh 573
7b0960d… drh 574 /*
4f76459… drh 575 ** Display and reset the EXPLAIN QUERY PLAN data
4f76459… drh 576 */
4f76459… drh 577 static void qrfEqpRender(Qrf *p, i64 nCycle){
4f76459… drh 578 qrfEQPGraphRow *pRow;
4f76459… drh 579 if( p->u.pGraph!=0 && (pRow = p->u.pGraph->pRow)!=0 ){
4f76459… drh 580 if( pRow->zText[0]=='-' ){
4f76459… drh 581 if( pRow->pNext==0 ){
4f76459… drh 582 qrfEqpReset(p);
4f76459… drh 583 return;
4f76459… drh 584 }
4f76459… drh 585 sqlite3_str_appendf(p->pOut, "%s\n", pRow->zText+3);
4f76459… drh 586 p->u.pGraph->pRow = pRow->pNext;
4f76459… drh 587 sqlite3_free(pRow);
4f76459… drh 588 }else if( nCycle>0 ){
7b0960d… drh 589 int nSp = p->u.pGraph->nWidth - 2;
7b0960d… drh 590 if( p->spec.eStyle==QRF_STYLE_StatsEst ){
7b0960d… drh 591 sqlite3_str_appendchar(p->pOut, nSp, ' ');
7b0960d… drh 592 sqlite3_str_appendall(p->pOut,
7b0960d… drh 593 "Cycles Loops (est) Rows (est)\n");
7b0960d… drh 594 sqlite3_str_appendchar(p->pOut, nSp, ' ');
7b0960d… drh 595 sqlite3_str_appendall(p->pOut,
7b0960d… drh 596 "---------- ------------ ------------\n");
7b0960d… drh 597 }else{
7b0960d… drh 598 sqlite3_str_appendchar(p->pOut, nSp, ' ');
7b0960d… drh 599 sqlite3_str_appendall(p->pOut,
7b0960d… drh 600 "Cycles Loops Rows \n");
7b0960d… drh 601 sqlite3_str_appendchar(p->pOut, nSp, ' ');
7b0960d… drh 602 sqlite3_str_appendall(p->pOut,
7b0960d… drh 603 "---------- ----- -----\n");
7b0960d… drh 604 }
7b0960d… drh 605 sqlite3_str_appendall(p->pOut, "QUERY PLAN");
7b0960d… drh 606 sqlite3_str_appendchar(p->pOut, nSp - 10, ' ');
7b0960d… drh 607 qrfApproxInt64(p->pOut, nCycle);
7b0960d… drh 608 sqlite3_str_appendall(p->pOut, " 100%\n");
4f76459… drh 609 }else{
4f76459… drh 610 sqlite3_str_appendall(p->pOut, "QUERY PLAN\n");
4f76459… drh 611 }
4f76459… drh 612 p->u.pGraph->zPrefix[0] = 0;
4f76459… drh 613 qrfEqpRenderLevel(p, 0);
4f76459… drh 614 qrfEqpReset(p);
4f76459… drh 615 }
4f76459… drh 616 }
4f76459… drh 617
4f76459… drh 618 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
4f76459… drh 619 /*
4f76459… drh 620 ** Helper function for qrfExpStats().
4f76459… drh 621 **
4f76459… drh 622 */
4f76459… drh 623 static int qrfStatsHeight(sqlite3_stmt *p, int iEntry){
4f76459… drh 624 int iPid = 0;
4f76459… drh 625 int ret = 1;
4f76459… drh 626 sqlite3_stmt_scanstatus_v2(p, iEntry,
4f76459… drh 627 SQLITE_SCANSTAT_SELECTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iPid
4f76459… drh 628 );
4f76459… drh 629 while( iPid!=0 ){
4f76459… drh 630 int ii;
4f76459… drh 631 for(ii=0; 1; ii++){
4f76459… drh 632 int iId;
4f76459… drh 633 int res;
4f76459… drh 634 res = sqlite3_stmt_scanstatus_v2(p, ii,
4f76459… drh 635 SQLITE_SCANSTAT_SELECTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iId
4f76459… drh 636 );
4f76459… drh 637 if( res ) break;
4f76459… drh 638 if( iId==iPid ){
4f76459… drh 639 sqlite3_stmt_scanstatus_v2(p, ii,
4f76459… drh 640 SQLITE_SCANSTAT_PARENTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iPid
4f76459… drh 641 );
4f76459… drh 642 }
4f76459… drh 643 }
4f76459… drh 644 ret++;
4f76459… drh 645 }
4f76459… drh 646 return ret;
4f76459… drh 647 }
4f76459… drh 648 #endif /* SQLITE_ENABLE_STMT_SCANSTATUS */
4f76459… drh 649
4f76459… drh 650
4f76459… drh 651 /*
4f76459… drh 652 ** Generate ".scanstatus est" style of EQP output.
4f76459… drh 653 */
4f76459… drh 654 static void qrfEqpStats(Qrf *p){
4f76459… drh 655 #ifndef SQLITE_ENABLE_STMT_SCANSTATUS
4f76459… drh 656 qrfError(p, SQLITE_ERROR, "not available in this build");
4f76459… drh 657 #else
4f76459… drh 658 static const int f = SQLITE_SCANSTAT_COMPLEX;
4f76459… drh 659 sqlite3_stmt *pS = p->pStmt;
4f76459… drh 660 int i = 0;
4f76459… drh 661 i64 nTotal = 0;
4f76459… drh 662 int nWidth = 0;
7b0960d… drh 663 int prevPid = -1; /* Previous iPid */
7b0960d… drh 664 double rEstCum = 1.0; /* Cumulative row estimate */
4f76459… drh 665 sqlite3_str *pLine = sqlite3_str_new(p->db);
4f76459… drh 666 sqlite3_str *pStats = sqlite3_str_new(p->db);
4f76459… drh 667 qrfEqpReset(p);
4f76459… drh 668
4f76459… drh 669 for(i=0; 1; i++){
4f76459… drh 670 const char *z = 0;
4f76459… drh 671 int n = 0;
4f76459… drh 672 if( sqlite3_stmt_scanstatus_v2(pS,i,SQLITE_SCANSTAT_EXPLAIN,f,(void*)&z) ){
4f76459… drh 673 break;
4f76459… drh 674 }
4f76459… drh 675 n = (int)strlen(z) + qrfStatsHeight(pS,i)*3;
4f76459… drh 676 if( n>nWidth ) nWidth = n;
4f76459… drh 677 }
7b0960d… drh 678 nWidth += 2;
4f76459… drh 679
4f76459… drh 680 sqlite3_stmt_scanstatus_v2(pS,-1, SQLITE_SCANSTAT_NCYCLE, f, (void*)&nTotal);
4f76459… drh 681 for(i=0; 1; i++){
4f76459… drh 682 i64 nLoop = 0;
4f76459… drh 683 i64 nRow = 0;
4f76459… drh 684 i64 nCycle = 0;
4f76459… drh 685 int iId = 0;
4f76459… drh 686 int iPid = 0;
4f76459… drh 687 const char *zo = 0;
4f76459… drh 688 const char *zName = 0;
4f76459… drh 689 double rEst = 0.0;
4f76459… drh 690
4f76459… drh 691 if( sqlite3_stmt_scanstatus_v2(pS,i,SQLITE_SCANSTAT_EXPLAIN,f,(void*)&zo) ){
4f76459… drh 692 break;
4f76459… drh 693 }
7b0960d… drh 694 sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_PARENTID,f,(void*)&iPid);
7b0960d… drh 695 if( iPid!=prevPid ){
7b0960d… drh 696 prevPid = iPid;
7b0960d… drh 697 rEstCum = 1.0;
7b0960d… drh 698 }
4f76459… drh 699 sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_EST,f,(void*)&rEst);
7b0960d… drh 700 rEstCum *= rEst;
4f76459… drh 701 sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_NLOOP,f,(void*)&nLoop);
4f76459… drh 702 sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_NVISIT,f,(void*)&nRow);
4f76459… drh 703 sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_NCYCLE,f,(void*)&nCycle);
4f76459… drh 704 sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_SELECTID,f,(void*)&iId);
4f76459… drh 705 sqlite3_stmt_scanstatus_v2(pS,i, SQLITE_SCANSTAT_NAME,f,(void*)&zName);
4f76459… drh 706
4f76459… drh 707 if( nCycle>=0 || nLoop>=0 || nRow>=0 ){
7b0960d… drh 708 int nSp = 0;
4f76459… drh 709 sqlite3_str_reset(pStats);
4f76459… drh 710 if( nCycle>=0 && nTotal>0 ){
7b0960d… drh 711 qrfApproxInt64(pStats, nCycle);
7b0960d… drh 712 sqlite3_str_appendf(pStats, " %3d%%",
7b0960d… drh 713 ((nCycle*100)+nTotal/2) / nTotal
4f76459… drh 714 );
7b0960d… drh 715 nSp = 2;
4f76459… drh 716 }
4f76459… drh 717 if( nLoop>=0 ){
7b0960d… drh 718 if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' ');
7b0960d… drh 719 qrfApproxInt64(pStats, nLoop);
7b0960d… drh 720 nSp = 2;
7b0960d… drh 721 if( p->spec.eStyle==QRF_STYLE_StatsEst ){
7b0960d… drh 722 sqlite3_str_appendf(pStats, " ");
7b0960d… drh 723 qrfApproxInt64(pStats, (i64)(rEstCum/rEst));
7b0960d… drh 724 }
4f76459… drh 725 }
4f76459… drh 726 if( nRow>=0 ){
7b0960d… drh 727 if( nSp ) sqlite3_str_appendchar(pStats, nSp, ' ');
7b0960d… drh 728 qrfApproxInt64(pStats, nRow);
7b0960d… drh 729 nSp = 2;
7b0960d… drh 730 if( p->spec.eStyle==QRF_STYLE_StatsEst ){
7b0960d… drh 731 sqlite3_str_appendf(pStats, " ");
7b0960d… drh 732 qrfApproxInt64(pStats, (i64)rEstCum);
7b0960d… drh 733 }
7b0960d… drh 734 }
4f76459… drh 735 sqlite3_str_appendf(pLine,
7b0960d… drh 736 "% *s %s", -1*(nWidth-qrfStatsHeight(pS,i)*3), zo,
4f76459… drh 737 sqlite3_str_value(pStats)
4f76459… drh 738 );
4f76459… drh 739 sqlite3_str_reset(pStats);
4f76459… drh 740 qrfEqpAppend(p, iId, iPid, sqlite3_str_value(pLine));
4f76459… drh 741 sqlite3_str_reset(pLine);
4f76459… drh 742 }else{
4f76459… drh 743 qrfEqpAppend(p, iId, iPid, zo);
4f76459… drh 744 }
4f76459… drh 745 }
7b0960d… drh 746 if( p->u.pGraph ) p->u.pGraph->nWidth = nWidth;
2b2530d… drh 747 qrfStrErr(p, pLine);
4f76459… drh 748 sqlite3_free(sqlite3_str_finish(pLine));
2b2530d… drh 749 qrfStrErr(p, pStats);
4f76459… drh 750 sqlite3_free(sqlite3_str_finish(pStats));
4f76459… drh 751 #endif
4f76459… drh 752 }
4f76459… drh 753
4f76459… drh 754
4f76459… drh 755 /*
4f76459… drh 756 ** Reset the prepared statement.
4f76459… drh 757 */
4f76459… drh 758 static void qrfResetStmt(Qrf *p){
4f76459… drh 759 int rc = sqlite3_reset(p->pStmt);
4f76459… drh 760 if( rc!=SQLITE_OK && p->iErr==SQLITE_OK ){
4f76459… drh 761 qrfError(p, rc, "%s", sqlite3_errmsg(p->db));
4f76459… drh 762 }
4f76459… drh 763 }
4f76459… drh 764
4f76459… drh 765 /*
4f76459… drh 766 ** If xWrite is defined, send all content of pOut to xWrite and
4f76459… drh 767 ** reset pOut.
4f76459… drh 768 */
4f76459… drh 769 static void qrfWrite(Qrf *p){
4f76459… drh 770 int n;
4f76459… drh 771 if( p->spec.xWrite && (n = sqlite3_str_length(p->pOut))>0 ){
4f76459… drh 772 int rc = p->spec.xWrite(p->spec.pWriteArg,
4f76459… drh 773 sqlite3_str_value(p->pOut),
4f76459… drh 774 (sqlite3_int64)n);
4f76459… drh 775 sqlite3_str_reset(p->pOut);
4f76459… drh 776 if( rc ){
4f76459… drh 777 qrfError(p, rc, "Failed to write %d bytes of output", n);
4f76459… drh 778 }
4f76459… drh 779 }
4f76459… drh 780 }
4f76459… drh 781 } aQrfUWidth[] = {
d326547… drh 782 {0, 0x01036}, {1, 0x0103b}, {0, 0x01058},
4f76459… drh 783 int sqlite3_qrf_wcwidth(int c){
d326547… drh 784 if( c<0x300 ) return 1;
4f76459… drh 785 iLast = sizeof(aQrfUWidth)/sizeof(aQrfUWidth[0]) - 1;
4f76459… drh 786 int cMid = aQrfUWidth[iMid].iFirst;
4f76459… drh 787 return aQrfUWidth[iMid].w;
4f76459… drh 788 if( aQrfUWidth[iLast].iFirst > c ) return aQrfUWidth[iFirst].w;
4f76459… drh 789 return aQrfUWidth[iLast].w;
4f76459… drh 790 ** begins at z[0]. Return the length. Write the Unicode value into *pU.
4f76459… drh 791 ** This routine only works for *multi-byte* UTF-8 characters. It does
4f76459… drh 792 ** not attempt to detect illegal characters.
4f76459… drh 793 int sqlite3_qrf_decode_utf8(const unsigned char *z, int *pU){
4f76459… drh 794 static int qrfIsVt100(const unsigned char *z){
4f76459… drh 795 ** Return the length of a string in display characters.
d326547… drh 796 **
d326547… drh 797 ** Most characters of the input string count as 1, including
d326547… drh 798 ** multi-byte UTF8 characters. However, zero-width unicode
d326547… drh 799 ** characters and VT100 escape sequences count as zero, and
d326547… drh 800 ** double-width characters count as two.
d326547… drh 801 **
d326547… drh 802 ** The definition of "zero-width" and "double-width" characters
d326547… drh 803 ** is not precise. It depends on the output device, to some extent,
d326547… drh 804 ** and it varies according to the Unicode version. This routine
d326547… drh 805 ** makes the best guess that it can.
4f76459… drh 806 */
d326547… drh 807 size_t sqlite3_qrf_wcswidth(const char *zIn){
4f76459… drh 808 const unsigned char *z = (const unsigned char*)zIn;
d326547… drh 809 size_t n = 0;
4f76459… drh 810 while( *z ){
4f76459… drh 811 if( z[0]<' ' ){
4f76459… drh 812 int k;
4f76459… drh 813 if( z[0]=='\033' && (k = qrfIsVt100(z))>0 ){
4f76459… drh 814 z += k;
4f76459… drh 815 }else{
4f76459… drh 816 z++;
4f76459… drh 817 }
4f76459… drh 818 }else if( (0x80&z[0])==0 ){
4f76459… drh 819 n++;
4f76459… drh 820 z++;
4f76459… drh 821 }else{
4f76459… drh 822 int u = 0;
4f76459… drh 823 int len = sqlite3_qrf_decode_utf8(z, &u);
4f76459… drh 824 z += len;
4f76459… drh 825 n += sqlite3_qrf_wcwidth(u);
4f76459… drh 826 }
4f76459… drh 827 }
4f76459… drh 828 return n;
4f76459… drh 829 }
4f76459… drh 830
4f76459… drh 831 /*
4f76459… drh 832 ** Return the display width of the longest line of text
4f76459… drh 833 ** in the (possibly) multi-line input string zIn[0..nByte].
4f76459… drh 834 ** zIn[] is not necessarily zero-terminated. Take
4f76459… drh 835 ** into account tab characters, zero- and double-width
4f76459… drh 836 ** characters, CR and NL, and VT100 escape codes.
4f76459… drh 837 **
4f76459… drh 838 ** Write the number of newlines into *pnNL. So, *pnNL will
4f76459… drh 839 ** return 0 if everything fits on one line, or positive it
4f76459… drh 840 ** it will need to be split.
4f76459… drh 841 */
4f76459… drh 842 static int qrfDisplayWidth(const char *zIn, sqlite3_int64 nByte, int *pnNL){
d326547… drh 843 const unsigned char *z;
d326547… drh 844 const unsigned char *zEnd;
4f76459… drh 845 int mx = 0;
4f76459… drh 846 int n = 0;
4f76459… drh 847 int nNL = 0;
d326547… drh 848 if( zIn==0 ) zIn = "";
d326547… drh 849 z = (const unsigned char*)zIn;
d326547… drh 850 zEnd = &z[nByte];
4f76459… drh 851 while( z<zEnd ){
4f76459… drh 852 if( z[0]<' ' ){
4f76459… drh 853 int k;
4f76459… drh 854 if( z[0]=='\033' && (k = qrfIsVt100(z))>0 ){
4f76459… drh 855 z += k;
4f76459… drh 856 }else{
4f76459… drh 857 if( z[0]=='\t' ){
4f76459… drh 858 n = (n+8)&~7;
4f76459… drh 859 }else if( z[0]=='\n' || z[0]=='\r' ){
4f76459… drh 860 nNL++;
4f76459… drh 861 if( n>mx ) mx = n;
4f76459… drh 862 n = 0;
4f76459… drh 863 }
4f76459… drh 864 z++;
4f76459… drh 865 }
4f76459… drh 866 }else if( (0x80&z[0])==0 ){
4f76459… drh 867 n++;
4f76459… drh 868 z++;
4f76459… drh 869 }else{
4f76459… drh 870 int u = 0;
4f76459… drh 871 int len = sqlite3_qrf_decode_utf8(z, &u);
4f76459… drh 872 z += len;
4f76459… drh 873 n += sqlite3_qrf_wcwidth(u);
4f76459… drh 874 }
4f76459… drh 875 }
4f76459… drh 876 if( mx>n ) n = mx;
4f76459… drh 877 if( pnNL ) *pnNL = nNL;
4f76459… drh 878 return n;
4f76459… drh 879 }
4f76459… drh 880
4f76459… drh 881 /*
4f76459… drh 882 ** Escape the input string if it is needed and in accordance with
4f76459… drh 883 ** eEsc, which is either QRF_ESC_Ascii or QRF_ESC_Symbol.
4f76459… drh 884 **
4f76459… drh 885 ** Escaping is needed if the string contains any control characters
4f76459… drh 886 ** other than \t, \n, and \r\n
4f76459… drh 887 **
4f76459… drh 888 ** If no escaping is needed (the common case) then set *ppOut to NULL
4f76459… drh 889 ** and return 0. If escaping is needed, write the escaped string into
4f76459… drh 890 ** memory obtained from sqlite3_malloc64() and make *ppOut point to that
4f76459… drh 891 ** memory and return 0. If an error occurs, return non-zero.
4f76459… drh 892 **
4f76459… drh 893 ** The caller is responsible for freeing *ppFree if it is non-NULL in order
4f76459… drh 894 ** to reclaim memory.
4f76459… drh 895 */
4f76459… drh 896 static void qrfEscape(
4f76459… drh 897 int eEsc, /* QRF_ESC_Ascii or QRF_ESC_Symbol */
4f76459… drh 898 sqlite3_str *pStr, /* String to be escaped */
4f76459… drh 899 int iStart /* Begin escapding on this byte of pStr */
4f76459… drh 900 ){
4f76459… drh 901 sqlite3_int64 i, j; /* Loop counters */
4f76459… drh 902 sqlite3_int64 sz; /* Size of the string prior to escaping */
4f76459… drh 903 sqlite3_int64 nCtrl = 0;/* Number of control characters to escape */
4f76459… drh 904 unsigned char *zIn; /* Text to be escaped */
4f76459… drh 905 unsigned char c; /* A single character of the text */
4f76459… drh 906 unsigned char *zOut; /* Where to write the results */
4f76459… drh 907
4f76459… drh 908 /* Find the text to be escaped */
4f76459… drh 909 zIn = (unsigned char*)sqlite3_str_value(pStr);
4f76459… drh 910 if( zIn==0 ) return;
4f76459… drh 911 zIn += iStart;
4f76459… drh 912
4f76459… drh 913 /* Count the control characters */
4f76459… drh 914 for(i=0; (c = zIn[i])!=0; i++){
4f76459… drh 915 if( c<=0x1f
4f76459… drh 916 && c!='\t'
4f76459… drh 917 && c!='\n'
4f76459… drh 918 && (c!='\r' || zIn[i+1]!='\n')
4f76459… drh 919 ){
4f76459… drh 920 nCtrl++;
4f76459… drh 921 }
4f76459… drh 922 }
4f76459… drh 923 if( nCtrl==0 ) return; /* Early out if no control characters */
4f76459… drh 924
4f76459… drh 925 /* Make space to hold the escapes. Copy the original text to the end
4f76459… drh 926 ** of the available space. */
4f76459… drh 927 sz = sqlite3_str_length(pStr) - iStart;
4f76459… drh 928 if( eEsc==QRF_ESC_Symbol ) nCtrl *= 2;
4f76459… drh 929 sqlite3_str_appendchar(pStr, nCtrl, ' ');
4f76459… drh 930 zOut = (unsigned char*)sqlite3_str_value(pStr);
4f76459… drh 931 if( zOut==0 ) return;
4f76459… drh 932 zOut += iStart;
4f76459… drh 933 zIn = zOut + nCtrl;
4f76459… drh 934 memmove(zIn,zOut,sz);
4f76459… drh 935
4f76459… drh 936 /* Convert the control characters */
4f76459… drh 937 for(i=j=0; (c = zIn[i])!=0; i++){
4f76459… drh 938 if( c>0x1f
4f76459… drh 939 || c=='\t'
4f76459… drh 940 || c=='\n'
4f76459… drh 941 || (c=='\r' && zIn[i+1]=='\n')
4f76459… drh 942 ){
4f76459… drh 943 continue;
4f76459… drh 944 }
4f76459… drh 945 if( i>0 ){
4f76459… drh 946 memmove(&zOut[j], zIn, i);
4f76459… drh 947 j += i;
4f76459… drh 948 }
4f76459… drh 949 zIn += i+1;
4f76459… drh 950 i = -1;
4f76459… drh 951 if( eEsc==QRF_ESC_Symbol ){
4f76459… drh 952 zOut[j++] = 0xe2;
4f76459… drh 953 zOut[j++] = 0x90;
4f76459… drh 954 zOut[j++] = 0x80+c;
4f76459… drh 955 }else{
4f76459… drh 956 zOut[j++] = '^';
4f76459… drh 957 zOut[j++] = 0x40+c;
4f76459… drh 958 }
4f76459… drh 959 }
4f76459… drh 960 }
4f76459… drh 961
4f76459… drh 962 /*
709b566… drh 963 ** Determine if the string z[] can be shown as plain text. Return true
709b566… drh 964 ** if z[] is unambiguously text. Return false if z[] needs to be
709b566… drh 965 ** quoted.
709b566… drh 966 **
709b566… drh 967 ** All of the following must be true in order for z[] to be relaxable:
709b566… drh 968 **
709b566… drh 969 ** (1) z[] does not begin or end with ' or whitespace
709b566… drh 970 ** (2) z[] is not the same as the NULL rendering
709b566… drh 971 ** (3) z[] does not looks like a numeric literal
709b566… drh 972 */
709b566… drh 973 static int qrfRelaxable(Qrf *p, const char *z){
709b566… drh 974 size_t i, n;
709b566… drh 975 if( z[0]=='\'' || qrfSpace(z[0]) ) return 0;
5f65ed5… drh 976 if( z[0]==0 ){
5f65ed5… drh 977 return (p->spec.zNull!=0 && p->spec.zNull[0]!=0);
5f65ed5… drh 978 }
709b566… drh 979 n = strlen(z);
5f65ed5… drh 980 if( n==0 || z[n-1]=='\'' || qrfSpace(z[n-1]) ) return 0;
709b566… drh 981 if( p->spec.zNull && strcmp(p->spec.zNull,z)==0 ) return 0;
709b566… drh 982 i = (z[0]=='-' || z[0]=='+');
709b566… drh 983 if( strcmp(z+i,"Inf")==0 ) return 0;
709b566… drh 984 if( !qrfDigit(z[i]) ) return 1;
709b566… drh 985 i++;
709b566… drh 986 while( qrfDigit(z[i]) ){ i++; }
709b566… drh 987 if( z[i]==0 ) return 0;
709b566… drh 988 if( z[i]=='.' ){
709b566… drh 989 i++;
709b566… drh 990 while( qrfDigit(z[i]) ){ i++; }
709b566… drh 991 if( z[i]==0 ) return 0;
709b566… drh 992 }
709b566… drh 993 if( z[i]=='e' || z[i]=='E' ){
709b566… drh 994 i++;
709b566… drh 995 if( z[i]=='+' || z[i]=='-' ){ i++; }
709b566… drh 996 if( !qrfDigit(z[i]) ) return 1;
709b566… drh 997 i++;
709b566… drh 998 while( qrfDigit(z[i]) ){ i++; }
709b566… drh 999 }
709b566… drh 1000 return z[i]!=0;
709b566… drh 1001 }
709b566… drh 1002
709b566… drh 1003 /*
4f76459… drh 1004 ** If a field contains any character identified by a 1 in the following
4f76459… drh 1005 ** array, then the string must be quoted for CSV.
4f76459… drh 1006 */
4f76459… drh 1007 static const char qrfCsvQuote[] = {
4f76459… drh 1008 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4f76459… drh 1009 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4f76459… drh 1010 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 1011 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 1012 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 1013 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 1014 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4f76459… drh 1015 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
4f76459… drh 1016 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4f76459… drh 1017 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4f76459… drh 1018 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4f76459… drh 1019 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4f76459… drh 1020 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4f76459… drh 1021 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4f76459… drh 1022 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4f76459… drh 1023 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4f76459… drh 1024 };
4f76459… drh 1025
4f76459… drh 1026 /*
4f76459… drh 1027 ** Encode text appropriately and append it to pOut.
4f76459… drh 1028 */
4f76459… drh 1029 static void qrfEncodeText(Qrf *p, sqlite3_str *pOut, const char *zTxt){
4f76459… drh 1030 int iStart = sqlite3_str_length(pOut);
4f76459… drh 1031 switch( p->spec.eText ){
709b566… drh 1032 case QRF_TEXT_Relaxed:
709b566… drh 1033 if( qrfRelaxable(p, zTxt) ){
709b566… drh 1034 sqlite3_str_appendall(pOut, zTxt);
709b566… drh 1035 break;
709b566… drh 1036 }
709b566… drh 1037 deliberate_fall_through; /* FALLTHRU */
4f76459… drh 1038 case QRF_TEXT_Sql: {
4f76459… drh 1039 if( p->spec.eEsc==QRF_ESC_Off ){
4f76459… drh 1040 sqlite3_str_appendf(pOut, "%Q", zTxt);
4f76459… drh 1041 }else{
4f76459… drh 1042 sqlite3_str_appendf(pOut, "%#Q", zTxt);
4f76459… drh 1043 }
4f76459… drh 1044 break;
4f76459… drh 1045 }
4f76459… drh 1046 case QRF_TEXT_Csv: {
4f76459… drh 1047 unsigned int i;
4f76459… drh 1048 for(i=0; zTxt[i]; i++){
4f76459… drh 1049 if( qrfCsvQuote[((const unsigned char*)zTxt)[i]] ){
4f76459… drh 1050 i = 0;
4f76459… drh 1051 break;
4f76459… drh 1052 }
4f76459… drh 1053 }
4f76459… drh 1054 if( i==0 || strstr(zTxt, p->spec.zColumnSep)!=0 ){
4f76459… drh 1055 sqlite3_str_appendf(pOut, "\"%w\"", zTxt);
4f76459… drh 1056 }else{
4f76459… drh 1057 sqlite3_str_appendall(pOut, zTxt);
4f76459… drh 1058 }
4f76459… drh 1059 break;
4f76459… drh 1060 }
4f76459… drh 1061 case QRF_TEXT_Html: {
4f76459… drh 1062 const unsigned char *z = (const unsigned char*)zTxt;
4f76459… drh 1063 while( *z ){
4f76459… drh 1064 unsigned int i = 0;
4f76459… drh 1065 unsigned char c;
4f76459… drh 1066 while( (c=z[i])>'>'
4f76459… drh 1067 || (c && c!='<' && c!='>' && c!='&' && c!='\"' && c!='\'')
4f76459… drh 1068 ){
4f76459… drh 1069 i++;
4f76459… drh 1070 }
4f76459… drh 1071 if( i>0 ){
4f76459… drh 1072 sqlite3_str_append(pOut, (const char*)z, i);
4f76459… drh 1073 }
4f76459… drh 1074 switch( z[i] ){
4f76459… drh 1075 case '>': sqlite3_str_append(pOut, "&lt;", 4); break;
4f76459… drh 1076 case '&': sqlite3_str_append(pOut, "&amp;", 5); break;
4f76459… drh 1077 case '<': sqlite3_str_append(pOut, "&lt;", 4); break;
4f76459… drh 1078 case '"': sqlite3_str_append(pOut, "&quot;", 6); break;
4f76459… drh 1079 case '\'': sqlite3_str_append(pOut, "&#39;", 5); break;
4f76459… drh 1080 default: i--;
4f76459… drh 1081 }
4f76459… drh 1082 z += i + 1;
4f76459… drh 1083 }
4f76459… drh 1084 break;
4f76459… drh 1085 }
4f76459… drh 1086 case QRF_TEXT_Tcl:
4f76459… drh 1087 case QRF_TEXT_Json: {
4f76459… drh 1088 const unsigned char *z = (const unsigned char*)zTxt;
4f76459… drh 1089 sqlite3_str_append(pOut, "\"", 1);
4f76459… drh 1090 while( *z ){
4f76459… drh 1091 unsigned int i;
4f76459… drh 1092 for(i=0; z[i]>=0x20 && z[i]!='\\' && z[i]!='"'; i++){}
4f76459… drh 1093 if( i>0 ){
4f76459… drh 1094 sqlite3_str_append(pOut, (const char*)z, i);
4f76459… drh 1095 }
4f76459… drh 1096 if( z[i]==0 ) break;
4f76459… drh 1097 switch( z[i] ){
4f76459… drh 1098 case '"': sqlite3_str_append(pOut, "\\\"", 2); break;
4f76459… drh 1099 case '\\': sqlite3_str_append(pOut, "\\\\", 2); break;
4f76459… drh 1100 case '\b': sqlite3_str_append(pOut, "\\b", 2); break;
4f76459… drh 1101 case '\f': sqlite3_str_append(pOut, "\\f", 2); break;
4f76459… drh 1102 case '\n': sqlite3_str_append(pOut, "\\n", 2); break;
4f76459… drh 1103 case '\r': sqlite3_str_append(pOut, "\\r", 2); break;
4f76459… drh 1104 case '\t': sqlite3_str_append(pOut, "\\t", 2); break;
4f76459… drh 1105 default: {
4f76459… drh 1106 if( p->spec.eText==QRF_TEXT_Json ){
4f76459… drh 1107 sqlite3_str_appendf(pOut, "\\u%04x", z[i]);
4f76459… drh 1108 }else{
4f76459… drh 1109 sqlite3_str_appendf(pOut, "\\%03o", z[i]);
4f76459… drh 1110 }
4f76459… drh 1111 break;
4f76459… drh 1112 }
4f76459… drh 1113 }
4f76459… drh 1114 z += i + 1;
4f76459… drh 1115 }
4f76459… drh 1116 sqlite3_str_append(pOut, "\"", 1);
4f76459… drh 1117 break;
4f76459… drh 1118 }
4f76459… drh 1119 default: {
4f76459… drh 1120 sqlite3_str_appendall(pOut, zTxt);
4f76459… drh 1121 break;
4f76459… drh 1122 }
4f76459… drh 1123 }
4f76459… drh 1124 if( p->spec.eEsc!=QRF_ESC_Off ){
4f76459… drh 1125 qrfEscape(p->spec.eEsc, pOut, iStart);
4f76459… drh 1126 }
4f76459… drh 1127 }
4f76459… drh 1128
4f76459… drh 1129 /*
4f76459… drh 1130 ** Do a quick sanity check to see aBlob[0..nBlob-1] is valid JSONB
4f76459… drh 1131 ** return true if it is and false if it is not.
4f76459… drh 1132 **
4f76459… drh 1133 ** False positives are possible, but not false negatives.
4f76459… drh 1134 */
4f76459… drh 1135 static int qrfJsonbQuickCheck(unsigned char *aBlob, int nBlob){
4f76459… drh 1136 unsigned char x; /* Payload size half-byte */
4f76459… drh 1137 int i; /* Loop counter */
4f76459… drh 1138 int n; /* Bytes in the payload size integer */
4f76459… drh 1139 sqlite3_uint64 sz; /* value of the payload size integer */
4f76459… drh 1140
4f76459… drh 1141 if( nBlob==0 ) return 0;
4f76459… drh 1142 x = aBlob[0]>>4;
4f76459… drh 1143 if( x<=11 ) return nBlob==(1+x);
4f76459… drh 1144 n = x<14 ? x-11 : 4*(x-13);
4f76459… drh 1145 if( nBlob<1+n ) return 0;
4f76459… drh 1146 sz = aBlob[1];
4f76459… drh 1147 for(i=1; i<n; i++) sz = (sz<<8) + aBlob[i+1];
4f76459… drh 1148 return sz+n+1==(sqlite3_uint64)nBlob;
4f76459… drh 1149 }
4f76459… drh 1150
4f76459… drh 1151 /*
4f76459… drh 1152 ** The current iCol-th column of p->pStmt is known to be a BLOB. Check
4f76459… drh 1153 ** to see if that BLOB is really a JSONB blob. If it is, then translate
4f76459… drh 1154 ** it into a text JSON representation and return a pointer to that text JSON.
4f76459… drh 1155 ** If the BLOB is not JSONB, then return a NULL pointer.
4f76459… drh 1156 **
4f76459… drh 1157 ** The memory used to hold the JSON text is managed internally by the
4f76459… drh 1158 ** "p" object and is overwritten and/or deallocated upon the next call
4f76459… drh 1159 ** to this routine (with the same p argument) or when the p object is
4f76459… drh 1160 ** finailized.
4f76459… drh 1161 */
4f76459… drh 1162 static const char *qrfJsonbToJson(Qrf *p, int iCol){
4f76459… drh 1163 int nByte;
4f76459… drh 1164 const void *pBlob;
4f76459… drh 1165 int rc;
4f76459… drh 1166 nByte = sqlite3_column_bytes(p->pStmt, iCol);
4f76459… drh 1167 pBlob = sqlite3_column_blob(p->pStmt, iCol);
4f76459… drh 1168 if( qrfJsonbQuickCheck((unsigned char*)pBlob, nByte)==0 ){
4f76459… drh 1169 return 0;
4f76459… drh 1170 }
4f76459… drh 1171 if( p->pJTrans==0 ){
4f76459… drh 1172 sqlite3 *db;
4f76459… drh 1173 rc = sqlite3_open(":memory:",&db);
4f76459… drh 1174 if( rc ){
4f76459… drh 1175 sqlite3_close(db);
4f76459… drh 1176 return 0;
4f76459… drh 1177 }
4f76459… drh 1178 rc = sqlite3_prepare_v2(db, "SELECT json(?1)", -1, &p->pJTrans, 0);
4f76459… drh 1179 if( rc ){
4f76459… drh 1180 sqlite3_finalize(p->pJTrans);
4f76459… drh 1181 p->pJTrans = 0;
4f76459… drh 1182 sqlite3_close(db);
4f76459… drh 1183 return 0;
4f76459… drh 1184 }
4f76459… drh 1185 }else{
4f76459… drh 1186 sqlite3_reset(p->pJTrans);
4f76459… drh 1187 }
4f76459… drh 1188 sqlite3_bind_blob(p->pJTrans, 1, (void*)pBlob, nByte, SQLITE_STATIC);
4f76459… drh 1189 rc = sqlite3_step(p->pJTrans);
4f76459… drh 1190 if( rc==SQLITE_ROW ){
4f76459… drh 1191 return (const char*)sqlite3_column_text(p->pJTrans, 0);
4f76459… drh 1192 }else{
4f76459… drh 1193 return 0;
4f76459… drh 1194 }
4f76459… drh 1195 }
ae7e3f0… drh 1196
ae7e3f0… drh 1197 /*
ae7e3f0… drh 1198 ** Adjust the input string zIn[] such that it is no more than N display
ae7e3f0… drh 1199 ** characters wide. If it is wider than that, then truncate and add
ae7e3f0… drh 1200 ** ellipsis. Or if zIn[] contains a \r or \n, truncate at that point,
ae7e3f0… drh 1201 ** adding ellipsis. Embedded tabs in zIn[] are converted into ordinary
ae7e3f0… drh 1202 ** spaces.
ae7e3f0… drh 1203 **
ae7e3f0… drh 1204 ** Return this display width of the modified title string.
ae7e3f0… drh 1205 */
ae7e3f0… drh 1206 static int qrfTitleLimit(char *zIn, int N){
ae7e3f0… drh 1207 unsigned char *z = (unsigned char*)zIn;
ae7e3f0… drh 1208 int n = 0;
ae7e3f0… drh 1209 unsigned char *zEllipsis = 0;
ae7e3f0… drh 1210 while( 1 /*exit-by-break*/ ){
ae7e3f0… drh 1211 if( z[0]<' ' ){
ae7e3f0… drh 1212 int k;
ae7e3f0… drh 1213 if( z[0]==0 ){
ae7e3f0… drh 1214 zEllipsis = 0;
ae7e3f0… drh 1215 break;
ae7e3f0… drh 1216 }else if( z[0]=='\033' && (k = qrfIsVt100(z))>0 ){
ae7e3f0… drh 1217 z += k;
ae7e3f0… drh 1218 }else if( z[0]=='\t' ){
ae7e3f0… drh 1219 z[0] = ' ';
ae7e3f0… drh 1220 }else if( z[0]=='\n' || z[0]=='\r' ){
ae7e3f0… drh 1221 z[0] = ' ';
ae7e3f0… drh 1222 }else{
ae7e3f0… drh 1223 z++;
ae7e3f0… drh 1224 }
ae7e3f0… drh 1225 }else if( (0x80&z[0])==0 ){
ae7e3f0… drh 1226 if( n>=(N-3) && zEllipsis==0 ) zEllipsis = z;
ae7e3f0… drh 1227 if( n==N ){ z[0] = 0; break; }
ae7e3f0… drh 1228 n++;
ae7e3f0… drh 1229 z++;
ae7e3f0… drh 1230 }else{
ae7e3f0… drh 1231 int u = 0;
ae7e3f0… drh 1232 int len = sqlite3_qrf_decode_utf8(z, &u);
ae7e3f0… drh 1233 if( n+len>(N-3) && zEllipsis==0 ) zEllipsis = z;
ae7e3f0… drh 1234 if( n+len>N ){ z[0] = 0; break; }
ae7e3f0… drh 1235 z += len;
ae7e3f0… drh 1236 n += sqlite3_qrf_wcwidth(u);
ae7e3f0… drh 1237 }
ae7e3f0… drh 1238 }
ae7e3f0… drh 1239 if( zEllipsis && N>=3 ) memcpy(zEllipsis,"...",4);
ae7e3f0… drh 1240 return n;
ae7e3f0… drh 1241 }
ae7e3f0… drh 1242
45de97f… drh 1243
45de97f… drh 1244 /*
4f76459… drh 1245 ** Render value pVal into pOut
4f76459… drh 1246 */
4f76459… drh 1247 static void qrfRenderValue(Qrf *p, sqlite3_str *pOut, int iCol){
4f76459… drh 1248 #if SQLITE_VERSION_NUMBER>=3052000
4f76459… drh 1249 int iStartLen = sqlite3_str_length(pOut);
4f76459… drh 1250 #endif
4f76459… drh 1251 if( p->spec.xRender ){
4f76459… drh 1252 sqlite3_value *pVal;
4f76459… drh 1253 char *z;
4f76459… drh 1254 pVal = sqlite3_value_dup(sqlite3_column_value(p->pStmt,iCol));
4f76459… drh 1255 z = p->spec.xRender(p->spec.pRenderArg, pVal);
4f76459… drh 1256 sqlite3_value_free(pVal);
4f76459… drh 1257 if( z ){
4f76459… drh 1258 sqlite3_str_appendall(pOut, z);
4f76459… drh 1259 sqlite3_free(z);
4f76459… drh 1260 return;
4f76459… drh 1261 }
4f76459… drh 1262 }
4f76459… drh 1263 switch( sqlite3_column_type(p->pStmt,iCol) ){
4f76459… drh 1264 case SQLITE_INTEGER: {
4f76459… drh 1265 sqlite3_str_appendf(pOut, "%lld", sqlite3_column_int64(p->pStmt,iCol));
4f76459… drh 1266 break;
4f76459… drh 1267 }
4f76459… drh 1268 case SQLITE_FLOAT: {
4f76459… drh 1269 const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
4f76459… drh 1270 sqlite3_str_appendall(pOut, zTxt);
4f76459… drh 1271 break;
4f76459… drh 1272 }
4f76459… drh 1273 case SQLITE_BLOB: {
4f76459… drh 1274 if( p->spec.bTextJsonb==QRF_Yes ){
4f76459… drh 1275 const char *zJson = qrfJsonbToJson(p, iCol);
4f76459… drh 1276 if( zJson ){
4f76459… drh 1277 if( p->spec.eText==QRF_TEXT_Sql ){
4f76459… drh 1278 sqlite3_str_append(pOut,"jsonb(",6);
4f76459… drh 1279 qrfEncodeText(p, pOut, zJson);
4f76459… drh 1280 sqlite3_str_append(pOut,")",1);
4f76459… drh 1281 }else{
4f76459… drh 1282 qrfEncodeText(p, pOut, zJson);
4f76459… drh 1283 }
4f76459… drh 1284 break;
4f76459… drh 1285 }
4f76459… drh 1286 }
4f76459… drh 1287 switch( p->spec.eBlob ){
4f76459… drh 1288 case QRF_BLOB_Hex:
4f76459… drh 1289 case QRF_BLOB_Sql: {
4f76459… drh 1290 int iStart;
4f76459… drh 1291 int nBlob = sqlite3_column_bytes(p->pStmt,iCol);
4f76459… drh 1292 int i, j;
4f76459… drh 1293 char *zVal;
4f76459… drh 1294 const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol);
4f76459… drh 1295 if( p->spec.eBlob==QRF_BLOB_Sql ){
4f76459… drh 1296 sqlite3_str_append(pOut, "x'", 2);
4f76459… drh 1297 }
4f76459… drh 1298 iStart = sqlite3_str_length(pOut);
4f76459… drh 1299 sqlite3_str_appendchar(pOut, nBlob, ' ');
4f76459… drh 1300 sqlite3_str_appendchar(pOut, nBlob, ' ');
4f76459… drh 1301 if( p->spec.eBlob==QRF_BLOB_Sql ){
4f76459… drh 1302 sqlite3_str_appendchar(pOut, 1, '\'');
4f76459… drh 1303 }
4f76459… drh 1304 if( sqlite3_str_errcode(pOut) ) return;
4f76459… drh 1305 zVal = sqlite3_str_value(pOut);
4f76459… drh 1306 for(i=0, j=iStart; i<nBlob; i++, j+=2){
4f76459… drh 1307 unsigned char c = a[i];
4f76459… drh 1308 zVal[j] = "0123456789abcdef"[(c>>4)&0xf];
4f76459… drh 1309 zVal[j+1] = "0123456789abcdef"[(c)&0xf];
4f76459… drh 1310 }
4f76459… drh 1311 break;
4f76459… drh 1312 }
4f76459… drh 1313 case QRF_BLOB_Tcl:
4f76459… drh 1314 case QRF_BLOB_Json: {
4f76459… drh 1315 int iStart;
4f76459… drh 1316 int nBlob = sqlite3_column_bytes(p->pStmt,iCol);
4f76459… drh 1317 int i, j;
4f76459… drh 1318 char *zVal;
4f76459… drh 1319 const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol);
4f76459… drh 1320 int szC = p->spec.eBlob==QRF_BLOB_Json ? 6 : 4;
4f76459… drh 1321 sqlite3_str_append(pOut, "\"", 1);
4f76459… drh 1322 iStart = sqlite3_str_length(pOut);
4f76459… drh 1323 for(i=szC; i>0; i--){
4f76459… drh 1324 sqlite3_str_appendchar(pOut, nBlob, ' ');
4f76459… drh 1325 }
4f76459… drh 1326 sqlite3_str_appendchar(pOut, 1, '"');
4f76459… drh 1327 if( sqlite3_str_errcode(pOut) ) return;
4f76459… drh 1328 zVal = sqlite3_str_value(pOut);
4f76459… drh 1329 for(i=0, j=iStart; i<nBlob; i++, j+=szC){
4f76459… drh 1330 unsigned char c = a[i];
4f76459… drh 1331 zVal[j] = '\\';
4f76459… drh 1332 if( szC==4 ){
4f76459… drh 1333 zVal[j+1] = '0' + ((c>>6)&3);
4f76459… drh 1334 zVal[j+2] = '0' + ((c>>3)&7);
4f76459… drh 1335 zVal[j+3] = '0' + (c&7);
4f76459… drh 1336 }else{
4f76459… drh 1337 zVal[j+1] = 'u';
4f76459… drh 1338 zVal[j+2] = '0';
4f76459… drh 1339 zVal[j+3] = '0';
4f76459… drh 1340 zVal[j+4] = "0123456789abcdef"[(c>>4)&0xf];
4f76459… drh 1341 zVal[j+5] = "0123456789abcdef"[(c)&0xf];
4f76459… drh 1342 }
4f76459… drh 1343 }
4f76459… drh 1344 break;
4f76459… drh 1345 }
45de97f… drh 1346 case QRF_BLOB_Size: {
45de97f… drh 1347 int nBlob = sqlite3_column_bytes(p->pStmt,iCol);
45de97f… drh 1348 sqlite3_str_appendf(pOut, "(%d-byte blob)", nBlob);
45de97f… drh 1349 break;
45de97f… drh 1350 }
4f76459… drh 1351 default: {
4f76459… drh 1352 const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
4f76459… drh 1353 qrfEncodeText(p, pOut, zTxt);
4f76459… drh 1354 }
4f76459… drh 1355 }
4f76459… drh 1356 break;
4f76459… drh 1357 }
4f76459… drh 1358 case SQLITE_NULL: {
45de97f… drh 1359 sqlite3_str_appendall(pOut, p->spec.zNull);
4f76459… drh 1360 break;
4f76459… drh 1361 }
4f76459… drh 1362 case SQLITE_TEXT: {
4f76459… drh 1363 const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
4f76459… drh 1364 qrfEncodeText(p, pOut, zTxt);
4f76459… drh 1365 break;
4f76459… drh 1366 }
4f76459… drh 1367 }
4f76459… drh 1368 #if SQLITE_VERSION_NUMBER>=3052000
4f76459… drh 1369 if( p->spec.nCharLimit>0
4f76459… drh 1370 && (sqlite3_str_length(pOut) - iStartLen) > p->spec.nCharLimit
4f76459… drh 1371 ){
4f76459… drh 1372 const unsigned char *z;
4f76459… drh 1373 int ii = 0, w = 0, limit = p->spec.nCharLimit;
4f76459… drh 1374 z = (const unsigned char*)sqlite3_str_value(pOut) + iStartLen;
4f76459… drh 1375 if( limit<4 ) limit = 4;
4f76459… drh 1376 while( 1 ){
4f76459… drh 1377 if( z[ii]<' ' ){
4f76459… drh 1378 int k;
4f76459… drh 1379 if( z[ii]=='\033' && (k = qrfIsVt100(z+ii))>0 ){
4f76459… drh 1380 ii += k;
4f76459… drh 1381 }else if( z[ii]==0 ){
4f76459… drh 1382 break;
4f76459… drh 1383 }else{
4f76459… drh 1384 ii++;
4f76459… drh 1385 }
4f76459… drh 1386 }else if( (0x80&z[ii])==0 ){
4f76459… drh 1387 w++;
4f76459… drh 1388 if( w>limit ) break;
4f76459… drh 1389 ii++;
4f76459… drh 1390 }else{
4f76459… drh 1391 int u = 0;
4f76459… drh 1392 int len = sqlite3_qrf_decode_utf8(&z[ii], &u);
4f76459… drh 1393 w += sqlite3_qrf_wcwidth(u);
4f76459… drh 1394 if( w>limit ) break;
4f76459… drh 1395 ii += len;
4f76459… drh 1396 }
4f76459… drh 1397 }
4f76459… drh 1398 if( w>limit ){
4f76459… drh 1399 sqlite3_str_truncate(pOut, iStartLen+ii);
4f76459… drh 1400 sqlite3_str_append(pOut, "...", 3);
4f76459… drh 1401 }
4f76459… drh 1402 }
9aee493… drh 1403 #endif
9aee493… drh 1404 }
9aee493… drh 1405
9aee493… drh 1406 /* Trim spaces of the end if pOut
9aee493… drh 1407 */
9aee493… drh 1408 static void qrfRTrim(sqlite3_str *pOut){
9aee493… drh 1409 #if SQLITE_VERSION_NUMBER>=3052000
9aee493… drh 1410 int nByte = sqlite3_str_length(pOut);
9aee493… drh 1411 const char *zOut = sqlite3_str_value(pOut);
9aee493… drh 1412 while( nByte>0 && zOut[nByte-1]==' ' ){ nByte--; }
9aee493… drh 1413 sqlite3_str_truncate(pOut, nByte);
4f76459… drh 1414 #endif
4f76459… drh 1415 }
4f76459… drh 1416
4f76459… drh 1417 /*
4f76459… drh 1418 ** Store string zUtf to pOut as w characters. If w is negative,
4f76459… drh 1419 ** then right-justify the text. W is the width in display characters, not
4f76459… drh 1420 ** in bytes. Double-width unicode characters count as two characters.
4f76459… drh 1421 ** VT100 escape sequences count as zero. And so forth.
4f76459… drh 1422 */
4f76459… drh 1423 static void qrfWidthPrint(Qrf *p, sqlite3_str *pOut, int w, const char *zUtf){
4f76459… drh 1424 (void)p;
4f76459… drh 1425 if( a==0 ) a = (const unsigned char*)"";
4f76459… drh 1426 int len = sqlite3_qrf_decode_utf8(a+i, &u);
4f76459… drh 1427 int x = sqlite3_qrf_wcwidth(u);
4f76459… drh 1428 }else if( c==0x1b && (k = qrfIsVt100(&a[i]))>0 ){
4f76459… drh 1429 sqlite3_str_append(pOut, zUtf, i);
4f76459… drh 1430 if( aw>n ) sqlite3_str_appendchar(pOut, aw-n, ' ');
4f76459… drh 1431 sqlite3_str_append(pOut, zUtf, i);
4f76459… drh 1432 }else{
4f76459… drh 1433 sqlite3_str_append(pOut, zUtf, i);
4f76459… drh 1434 if( aw>n ) sqlite3_str_appendchar(pOut, aw-n, ' ');
4f76459… drh 1435 }
4f76459… drh 1436 }
4f76459… drh 1437
4f76459… drh 1438 /*
4f76459… drh 1439 ** (*pz)[] is a line of text that is to be displayed the box or table or
4f76459… drh 1440 ** similar tabular formats. z[] contain newlines or might be too wide
4f76459… drh 1441 ** to fit in the columns so will need to be split into multiple line.
4f76459… drh 1442 **
4f76459… drh 1443 ** This routine determines:
4f76459… drh 1444 **
4f76459… drh 1445 ** * How many bytes of z[] should be shown on the current line.
4f76459… drh 1446 ** * How many character positions those bytes will cover.
4f76459… drh 1447 ** * The byte offset to the start of the next line.
4f76459… drh 1448 */
4f76459… drh 1449 static void qrfWrapLine(
4f76459… drh 1450 const char *zIn, /* Input text to be displayed */
4f76459… drh 1451 int w, /* Column width in characters (not bytes) */
4f76459… drh 1452 int bWrap, /* True if we should do word-wrapping */
4f76459… drh 1453 int *pnThis, /* OUT: How many bytes of z[] for the current line */
4f76459… drh 1454 int *pnWide, /* OUT: How wide is the text of this line */
4f76459… drh 1455 int *piNext /* OUT: Offset into z[] to start of the next line */
4f76459… drh 1456 ){
4f76459… drh 1457 int i; /* Input bytes consumed */
4f76459… drh 1458 int k; /* Bytes in a VT100 code */
4f76459… drh 1459 int n; /* Output column number */
4f76459… drh 1460 const unsigned char *z = (const unsigned char*)zIn;
4f76459… drh 1461 unsigned char c = 0;
4f76459… drh 1462
6ae9c9a… drh 1463 if( z[0]==0 ){
4f76459… drh 1464 *pnThis = 0;
4f76459… drh 1465 *pnWide = 0;
4f76459… drh 1466 *piNext = 0;
4f76459… drh 1467 return;
4f76459… drh 1468 }
4f76459… drh 1469 n = 0;
6ae9c9a… drh 1470 for(i=0; n<=w; i++){
6ae9c9a… drh 1471 c = z[i];
4f76459… drh 1472 if( c>=0xc0 ){
4f76459… drh 1473 int u;
4f76459… drh 1474 int len = sqlite3_qrf_decode_utf8(&z[i], &u);
4f76459… drh 1475 int wcw = sqlite3_qrf_wcwidth(u);
4f76459… drh 1476 if( wcw+n>w ) break;
4f76459… drh 1477 i += len-1;
4f76459… drh 1478 n += wcw;
4f76459… drh 1479 continue;
4f76459… drh 1480 }
4f76459… drh 1481 if( c>=' ' ){
6ae9c9a… drh 1482 if( n==w ) break;
4f76459… drh 1483 n++;
4f76459… drh 1484 continue;
4f76459… drh 1485 }
4f76459… drh 1486 if( c==0 || c=='\n' ) break;
6ae9c9a… drh 1487 if( c=='\r' && z[i+1]=='\n' ){ c = z[++i]; break; }
4f76459… drh 1488 if( c=='\t' ){
4f76459… drh 1489 int wcw = 8 - (n&7);
4f76459… drh 1490 if( n+wcw>w ) break;
4f76459… drh 1491 n += wcw;
4f76459… drh 1492 continue;
4f76459… drh 1493 }
4f76459… drh 1494 if( c==0x1b && (k = qrfIsVt100(&z[i]))>0 ){
4f76459… drh 1495 i += k-1;
6ae9c9a… drh 1496 }else if( n==w ){
6ae9c9a… drh 1497 break;
4f76459… drh 1498 }else{
4f76459… drh 1499 }
4f76459… drh 1500 }
4f76459… drh 1501 if( c==0 ){
4f76459… drh 1502 *pnThis = i;
4f76459… drh 1503 *pnWide = n;
4f76459… drh 1504 *piNext = i;
4f76459… drh 1505 return;
4f76459… drh 1506 }
4f76459… drh 1507 if( c=='\n' ){
4f76459… drh 1508 *pnThis = i;
4f76459… drh 1509 *pnWide = n;
4f76459… drh 1510 *piNext = i+1;
4f76459… drh 1511 return;
4f76459… drh 1512 }
4f76459… drh 1513
4f76459… drh 1514 /* If we get this far, that means the current line will end at some
4f76459… drh 1515 ** point that is neither a "\n" or a 0x00. Figure out where that
4f76459… drh 1516 ** split should occur
4f76459… drh 1517 */
4f76459… drh 1518 if( bWrap && z[i]!=0 && !qrfSpace(z[i]) && qrfAlnum(c)==qrfAlnum(z[i]) ){
4f76459… drh 1519 /* Perhaps try to back up to a better place to break the line */
4f76459… drh 1520 for(k=i-1; k>=i/2; k--){
4f76459… drh 1521 if( qrfSpace(z[k]) ) break;
4f76459… drh 1522 }
4f76459… drh 1523 if( k<i/2 ){
4f76459… drh 1524 for(k=i; k>=i/2; k--){
4f76459… drh 1525 if( qrfAlnum(z[k-1])!=qrfAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break;
4f76459… drh 1526 }
4f76459… drh 1527 }
4f76459… drh 1528 if( k>=i/2 ){
4f76459… drh 1529 i = k;
4f76459… drh 1530 n = qrfDisplayWidth((const char*)z, k, 0);
4f76459… drh 1531 }
4f76459… drh 1532 }
4f76459… drh 1533 *pnThis = i;
4f76459… drh 1534 *pnWide = n;
4f76459… drh 1535 while( zIn[i]==' ' || zIn[i]=='\t' || zIn[i]=='\r' ){ i++; }
4f76459… drh 1536 *piNext = i;
4f76459… drh 1537 }
4f76459… drh 1538
4f76459… drh 1539 /*
4f76459… drh 1540 ** Append nVal bytes of text from zVal onto the end of pOut.
4f76459… drh 1541 ** Convert tab characters in zVal to the appropriate number of
4f76459… drh 1542 ** spaces.
4f76459… drh 1543 */
4f76459… drh 1544 static void qrfAppendWithTabs(
4f76459… drh 1545 sqlite3_str *pOut, /* Append text here */
4f76459… drh 1546 const char *zVal, /* Text to append */
4f76459… drh 1547 int nVal /* Use only the first nVal bytes of zVal[] */
4f76459… drh 1548 ){
4f76459… drh 1549 int i = 0;
4f76459… drh 1550 unsigned int col = 0;
4f76459… drh 1551 unsigned char *z = (unsigned char *)zVal;
4f76459… drh 1552 while( i<nVal ){
4f76459… drh 1553 unsigned char c = z[i];
4f76459… drh 1554 if( c<' ' ){
4f76459… drh 1555 int k;
4f76459… drh 1556 sqlite3_str_append(pOut, (const char*)z, i);
4f76459… drh 1557 nVal -= i;
4f76459… drh 1558 z += i;
4f76459… drh 1559 i = 0;
4f76459… drh 1560 if( c=='\033' && (k = qrfIsVt100(z))>0 ){
4f76459… drh 1561 sqlite3_str_append(pOut, (const char*)z, k);
4f76459… drh 1562 z += k;
4f76459… drh 1563 nVal -= k;
4f76459… drh 1564 }else if( c=='\t' ){
4f76459… drh 1565 k = 8 - (col&7);
4f76459… drh 1566 sqlite3_str_appendchar(pOut, k, ' ');
4f76459… drh 1567 col += k;
4f76459… drh 1568 z++;
4f76459… drh 1569 nVal--;
4f76459… drh 1570 }else if( c=='\r' && nVal==1 ){
4f76459… drh 1571 z++;
4f76459… drh 1572 nVal--;
4f76459… drh 1573 }else{
4f76459… drh 1574 char zCtrlPik[4];
4f76459… drh 1575 col++;
4f76459… drh 1576 zCtrlPik[0] = 0xe2;
4f76459… drh 1577 zCtrlPik[1] = 0x90;
4f76459… drh 1578 zCtrlPik[2] = 0x80+c;
4f76459… drh 1579 sqlite3_str_append(pOut, zCtrlPik, 3);
4f76459… drh 1580 z++;
4f76459… drh 1581 nVal--;
4f76459… drh 1582 }
4f76459… drh 1583 }else if( (0x80&c)==0 ){
4f76459… drh 1584 i++;
4f76459… drh 1585 col++;
4f76459… drh 1586 int len = sqlite3_qrf_decode_utf8(&z[i], &u);
4f76459… drh 1587 i += len;
4f76459… drh 1588 col += sqlite3_qrf_wcwidth(u);
4f76459… drh 1589 }
4f76459… drh 1590 }
4f76459… drh 1591 sqlite3_str_append(pOut, (const char*)z, i);
4f76459… drh 1592 }
4f76459… drh 1593
4f76459… drh 1594 /*
4f76459… drh 1595 ** GCC does not define the offsetof() macro so we'll have to do it
4f76459… drh 1596 ** ourselves.
4f76459… drh 1597 */
4f76459… drh 1598 #ifndef offsetof
4f76459… drh 1599 # define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0))
4f76459… drh 1600 #endif
4f76459… drh 1601
4f76459… drh 1602 /*
4f76459… drh 1603 ** Data for columnar layout, collected into a single object so
4f76459… drh 1604 ** that it can be more easily passed into subroutines.
4f76459… drh 1605 */
4f76459… drh 1606 typedef struct qrfColData qrfColData;
4f76459… drh 1607 struct qrfColData {
4f76459… drh 1608 Qrf *p; /* The QRF instance */
4f76459… drh 1609 int nCol; /* Number of columns in the table */
4f76459… drh 1610 unsigned char bMultiRow; /* One or more cells will span multiple lines */
4f76459… drh 1611 unsigned char nMargin; /* Width of column margins */
4f76459… drh 1612 sqlite3_int64 nRow; /* Number of rows */
4f76459… drh 1613 sqlite3_int64 nAlloc; /* Number of cells allocated */
4f76459… drh 1614 sqlite3_int64 n; /* Number of cells. nCol*nRow */
4f76459… drh 1615 char **az; /* Content of all cells */
4f76459… drh 1616 int *aiWth; /* Width of each cell */
f4b3b59… drh 1617 unsigned char *abNum; /* True for each numeric cell */
4f76459… drh 1618 struct qrfPerCol { /* Per-column data */
4f76459… drh 1619 char *z; /* Cache of text for current row */
4f76459… drh 1620 int w; /* Computed width of this column */
4f76459… drh 1621 int mxW; /* Maximum natural (unwrapped) width */
4f76459… drh 1622 unsigned char e; /* Alignment */
4f76459… drh 1623 unsigned char fx; /* Width is fixed */
f4b3b59… drh 1624 unsigned char bNum; /* True if is numeric */
4f76459… drh 1625 } *a; /* One per column */
4f76459… drh 1626 };
f4b3b59… drh 1627
f4b3b59… drh 1628 /*
f4b3b59… drh 1629 ** Output horizontally justified text into pOut. The text is the
f4b3b59… drh 1630 ** first nVal bytes of zVal. Include nWS bytes of whitespace, either
f4b3b59… drh 1631 ** split between both sides, or on the left, or on the right, depending
f4b3b59… drh 1632 ** on eAlign.
f4b3b59… drh 1633 */
f4b3b59… drh 1634 static void qrfPrintAligned(
f4b3b59… drh 1635 sqlite3_str *pOut, /* Append text here */
f4b3b59… drh 1636 struct qrfPerCol *pCol, /* Information about the text to print */
f4b3b59… drh 1637 int nVal, /* Use only the first nVal bytes of zVal[] */
f4b3b59… drh 1638 int nWS /* Whitespace for horizonal alignment */
f4b3b59… drh 1639 ){
f4b3b59… drh 1640 unsigned char eAlign = pCol->e & QRF_ALIGN_HMASK;
f4b3b59… drh 1641 if( eAlign==QRF_Auto && pCol->bNum ) eAlign = QRF_ALIGN_Right;
f4b3b59… drh 1642 if( eAlign==QRF_ALIGN_Center ){
f4b3b59… drh 1643 /* Center the text */
f4b3b59… drh 1644 sqlite3_str_appendchar(pOut, nWS/2, ' ');
f4b3b59… drh 1645 qrfAppendWithTabs(pOut, pCol->z, nVal);
f4b3b59… drh 1646 sqlite3_str_appendchar(pOut, nWS - nWS/2, ' ');
f4b3b59… drh 1647 }else if( eAlign==QRF_ALIGN_Right ){
f4b3b59… drh 1648 /* Right justify the text */
f4b3b59… drh 1649 sqlite3_str_appendchar(pOut, nWS, ' ');
f4b3b59… drh 1650 qrfAppendWithTabs(pOut, pCol->z, nVal);
f4b3b59… drh 1651 }else{
f4b3b59… drh 1652 /* Left justify the text */
f4b3b59… drh 1653 qrfAppendWithTabs(pOut, pCol->z, nVal);
f4b3b59… drh 1654 sqlite3_str_appendchar(pOut, nWS, ' ');
f4b3b59… drh 1655 }
f4b3b59… drh 1656 }
4f76459… drh 1657
4f76459… drh 1658 /*
4f76459… drh 1659 ** Free all the memory allocates in the qrfColData object
4f76459… drh 1660 */
4f76459… drh 1661 static void qrfColDataFree(qrfColData *p){
4f76459… drh 1662 sqlite3_int64 i;
4f76459… drh 1663 for(i=0; i<p->n; i++) sqlite3_free(p->az[i]);
4f76459… drh 1664 sqlite3_free(p->az);
4f76459… drh 1665 sqlite3_free(p->aiWth);
f4b3b59… drh 1666 sqlite3_free(p->abNum);
4f76459… drh 1667 sqlite3_free(p->a);
4f76459… drh 1668
4f76459… drh 1669 /*
4f76459… drh 1670 ** Allocate space for more cells in the qrfColData object.
4f76459… drh 1671 ** Return non-zero if a memory allocation fails.
4f76459… drh 1672 */
4f76459… drh 1673 static int qrfColDataEnlarge(qrfColData *p){
4f76459… drh 1674 char **azData;
4f76459… drh 1675 int *aiWth;
f4b3b59… drh 1676 unsigned char *abNum;
4f76459… drh 1677 p->nAlloc = 2*p->nAlloc + 10*p->nCol;
4f76459… drh 1678 azData = sqlite3_realloc64(p->az, p->nAlloc*sizeof(char*));
4f76459… drh 1679 if( azData==0 ){
4f76459… drh 1680 qrfOom(p->p);
4f76459… drh 1681 qrfColDataFree(p);
4f76459… drh 1682 return 1;
4f76459… drh 1683 }
4f76459… drh 1684 p->az = azData;
4f76459… drh 1685 aiWth = sqlite3_realloc64(p->aiWth, p->nAlloc*sizeof(int));
4f76459… drh 1686 if( aiWth==0 ){
4f76459… drh 1687 qrfOom(p->p);
4f76459… drh 1688 qrfColDataFree(p);
4f76459… drh 1689 return 1;
4f76459… drh 1690 }
4f76459… drh 1691 p->aiWth = aiWth;
f4b3b59… drh 1692 abNum = sqlite3_realloc64(p->abNum, p->nAlloc);
f4b3b59… drh 1693 if( abNum==0 ){
f4b3b59… drh 1694 qrfOom(p->p);
f4b3b59… drh 1695 qrfColDataFree(p);
f4b3b59… drh 1696 return 1;
f4b3b59… drh 1697 }
f4b3b59… drh 1698 p->abNum = abNum;
4f76459… drh 1699 return 0;
4f76459… drh 1700 }
4f76459… drh 1701
4f76459… drh 1702 /*
4f76459… drh 1703 ** Print a markdown or table-style row separator using ascii-art
4f76459… drh 1704 */
4f76459… drh 1705 static void qrfRowSeparator(sqlite3_str *pOut, qrfColData *p, char cSep){
4f76459… drh 1706 int i;
4f76459… drh 1707 if( p->nCol>0 ){
f4b3b59… drh 1708 int useBorder = p->p->spec.bBorder!=QRF_No;
f4b3b59… drh 1709 if( useBorder ){
f4b3b59… drh 1710 sqlite3_str_append(pOut, &cSep, 1);
f4b3b59… drh 1711 }
4f76459… drh 1712 sqlite3_str_appendchar(pOut, p->a[0].w+p->nMargin, '-');
4f76459… drh 1713 for(i=1; i<p->nCol; i++){
4f76459… drh 1714 sqlite3_str_append(pOut, &cSep, 1);
4f76459… drh 1715 sqlite3_str_appendchar(pOut, p->a[i].w+p->nMargin, '-');
4f76459… drh 1716 }
f4b3b59… drh 1717 if( useBorder ){
f4b3b59… drh 1718 sqlite3_str_append(pOut, &cSep, 1);
f4b3b59… drh 1719 }
4f76459… drh 1720 }
4f76459… drh 1721 sqlite3_str_append(pOut, "\n", 1);
4f76459… drh 1722 }
4f76459… drh 1723
4f76459… drh 1724 /*
4f76459… drh 1725 ** UTF8 box-drawing characters. Imagine box lines like this:
4f76459… drh 1726 **
4f76459… drh 1727 ** 1
4f76459… drh 1728 ** |
4f76459… drh 1729 ** 4 --+-- 2
4f76459… drh 1730 ** |
4f76459… drh 1731 ** 3
4f76459… drh 1732 **
4f76459… drh 1733 ** Each box characters has between 2 and 4 of the lines leading from
4f76459… drh 1734 ** the center. The characters are here identified by the numbers of
4f76459… drh 1735 ** their corresponding lines.
4f76459… drh 1736 */
4f76459… drh 1737 #define BOX_24 "\342\224\200" /* U+2500 --- */
4f76459… drh 1738 #define BOX_13 "\342\224\202" /* U+2502 | */
4f76459… drh 1739 #define BOX_23 "\342\224\214" /* U+250c ,- */
4f76459… drh 1740 #define BOX_34 "\342\224\220" /* U+2510 -, */
4f76459… drh 1741 #define BOX_12 "\342\224\224" /* U+2514 '- */
4f76459… drh 1742 #define BOX_14 "\342\224\230" /* U+2518 -' */
4f76459… drh 1743 #define BOX_123 "\342\224\234" /* U+251c |- */
4f76459… drh 1744 #define BOX_134 "\342\224\244" /* U+2524 -| */
4f76459… drh 1745 #define BOX_234 "\342\224\254" /* U+252c -,- */
4f76459… drh 1746 #define BOX_124 "\342\224\264" /* U+2534 -'- */
4f76459… drh 1747 #define BOX_1234 "\342\224\274" /* U+253c -|- */
4f76459… drh 1748
709b566… drh 1749 /* Rounded corners: */
709b566… drh 1750 #define BOX_R12 "\342\225\260" /* U+2570 '- */
709b566… drh 1751 #define BOX_R23 "\342\225\255" /* U+256d ,- */
709b566… drh 1752 #define BOX_R34 "\342\225\256" /* U+256e -, */
709b566… drh 1753 #define BOX_R14 "\342\225\257" /* U+256f -' */
709b566… drh 1754
709b566… drh 1755 /* Doubled horizontal lines: */
709b566… drh 1756 #define DBL_24 "\342\225\220" /* U+2550 === */
709b566… drh 1757 #define DBL_123 "\342\225\236" /* U+255e |= */
709b566… drh 1758 #define DBL_134 "\342\225\241" /* U+2561 =| */
709b566… drh 1759 #define DBL_1234 "\342\225\252" /* U+256a =|= */
709b566… drh 1760
4f76459… drh 1761 /* Draw horizontal line N characters long using unicode box
4f76459… drh 1762 ** characters
4f76459… drh 1763 */
709b566… drh 1764 static void qrfBoxLine(sqlite3_str *pOut, int N, int bDbl){
709b566… drh 1765 const char *azDash[2] = {
709b566… drh 1766 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24,
709b566… drh 1767 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24 DBL_24
709b566… drh 1768 };/* 0 1 2 3 4 5 6 7 8 9 */
709b566… drh 1769 const int nDash = 30;
4f76459… drh 1770 N *= 3;
4f76459… drh 1771 while( N>nDash ){
709b566… drh 1772 sqlite3_str_append(pOut, azDash[bDbl], nDash);
4f76459… drh 1773 N -= nDash;
4f76459… drh 1774 }
709b566… drh 1775 sqlite3_str_append(pOut, azDash[bDbl], N);
4f76459… drh 1776 }
4f76459… drh 1777
4f76459… drh 1778 /*
4f76459… drh 1779 ** Draw a horizontal separator for a QRF_STYLE_Box table.
4f76459… drh 1780 */
4f76459… drh 1781 static void qrfBoxSeparator(
4f76459… drh 1782 sqlite3_str *pOut,
4f76459… drh 1783 qrfColData *p,
4f76459… drh 1784 const char *zSep1,
4f76459… drh 1785 const char *zSep2,
709b566… drh 1786 const char *zSep3,
709b566… drh 1787 int bDbl
4f76459… drh 1788 ){
4f76459… drh 1789 int i;
4f76459… drh 1790 if( p->nCol>0 ){
f4b3b59… drh 1791 int useBorder = p->p->spec.bBorder!=QRF_No;
f4b3b59… drh 1792 if( useBorder ){
f4b3b59… drh 1793 sqlite3_str_appendall(pOut, zSep1);
f4b3b59… drh 1794 }
709b566… drh 1795 qrfBoxLine(pOut, p->a[0].w+p->nMargin, bDbl);
4f76459… drh 1796 for(i=1; i<p->nCol; i++){
4f76459… drh 1797 sqlite3_str_appendall(pOut, zSep2);
709b566… drh 1798 qrfBoxLine(pOut, p->a[i].w+p->nMargin, bDbl);
4f76459… drh 1799 }
f4b3b59… drh 1800 if( useBorder ){
f4b3b59… drh 1801 sqlite3_str_appendall(pOut, zSep3);
f4b3b59… drh 1802 }
4f76459… drh 1803 }
4f76459… drh 1804 sqlite3_str_append(pOut, "\n", 1);
4f76459… drh 1805 }
4f76459… drh 1806
4f76459… drh 1807 /*
4f76459… drh 1808 ** Load into pData the default alignment for the body of a table.
4f76459… drh 1809 */
4f76459… drh 1810 static void qrfLoadAlignment(qrfColData *pData, Qrf *p){
4f76459… drh 1811 sqlite3_int64 i;
4f76459… drh 1812 for(i=0; i<pData->nCol; i++){
4f76459… drh 1813 pData->a[i].e = p->spec.eDfltAlign;
4f76459… drh 1814 if( i<p->spec.nAlign ){
4f76459… drh 1815 unsigned char ax = p->spec.aAlign[i];
4f76459… drh 1816 if( (ax & QRF_ALIGN_HMASK)!=0 ){
4f76459… drh 1817 pData->a[i].e = (ax & QRF_ALIGN_HMASK) |
4f76459… drh 1818 (pData->a[i].e & QRF_ALIGN_VMASK);
4f76459… drh 1819 }
4f76459… drh 1820 }else if( i<p->spec.nWidth ){
4f76459… drh 1821 if( p->spec.aWidth[i]<0 ){
4f76459… drh 1822 pData->a[i].e = QRF_ALIGN_Right |
4f76459… drh 1823 (pData->a[i].e & QRF_ALIGN_VMASK);
4f76459… drh 1824 }
4f76459… drh 1825 }
4f76459… drh 1826 }
4f76459… drh 1827 }
4f76459… drh 1828
4f76459… drh 1829 /*
9aee493… drh 1830 ** If the single column in pData->a[] with pData->n entries can be
9aee493… drh 1831 ** laid out as nCol columns with a 2-space gap between each such
9aee493… drh 1832 ** that all columns fit within nSW, then return a pointer to an array
9aee493… drh 1833 ** of integers which is the width of each column from left to right.
9aee493… drh 1834 **
9aee493… drh 1835 ** If the layout is not possible, return a NULL pointer.
9aee493… drh 1836 **
9aee493… drh 1837 ** Space to hold the returned array is from sqlite_malloc64().
9aee493… drh 1838 */
9aee493… drh 1839 static int *qrfValidLayout(
9aee493… drh 1840 qrfColData *pData, /* Collected query results */
9aee493… drh 1841 Qrf *p, /* On which to report an OOM */
9aee493… drh 1842 int nCol, /* Attempt this many columns */
9aee493… drh 1843 int nSW /* Screen width */
9aee493… drh 1844 ){
9aee493… drh 1845 int i; /* Loop counter */
9aee493… drh 1846 int nr; /* Number of rows */
9aee493… drh 1847 int w = 0; /* Width of the current column */
9aee493… drh 1848 int t; /* Total width of all columns */
9aee493… drh 1849 int *aw; /* Array of individual column widths */
9aee493… drh 1850
9aee493… drh 1851 aw = sqlite3_malloc64( sizeof(int)*nCol );
9aee493… drh 1852 if( aw==0 ){
9aee493… drh 1853 qrfOom(p);
9aee493… drh 1854 return 0;
9aee493… drh 1855 }
9aee493… drh 1856 nr = (pData->n + nCol - 1)/nCol;
9aee493… drh 1857 for(i=0; i<pData->n; i++){
9aee493… drh 1858 if( (i%nr)==0 ){
9aee493… drh 1859 if( i>0 ) aw[i/nr-1] = w;
9aee493… drh 1860 w = pData->aiWth[i];
9aee493… drh 1861 }else if( pData->aiWth[i]>w ){
9aee493… drh 1862 w = pData->aiWth[i];
9aee493… drh 1863 }
9aee493… drh 1864 }
9aee493… drh 1865 aw[nCol-1] = w;
9aee493… drh 1866 for(t=i=0; i<nCol; i++) t += aw[i];
9aee493… drh 1867 t += 2*(nCol-1);
9aee493… drh 1868 if( t>nSW ){
9aee493… drh 1869 sqlite3_free(aw);
9aee493… drh 1870 return 0;
9aee493… drh 1871 }
9aee493… drh 1872 return aw;
9aee493… drh 1873 }
9aee493… drh 1874
9aee493… drh 1875 /*
9aee493… drh 1876 ** The output is single-column and the bSplitColumn flag is set.
9aee493… drh 1877 ** Check to see if the single-column output can be split into multiple
9aee493… drh 1878 ** columns that appear side-by-side. Adjust pData appropriately.
9aee493… drh 1879 */
9aee493… drh 1880 static void qrfSplitColumn(qrfColData *pData, Qrf *p){
9aee493… drh 1881 int nCol = 1;
9aee493… drh 1882 int *aw = 0;
9aee493… drh 1883 char **az = 0;
9aee493… drh 1884 int *aiWth = 0;
f4b3b59… drh 1885 unsigned char *abNum = 0;
9aee493… drh 1886 int nColNext = 2;
9aee493… drh 1887 int w;
9aee493… drh 1888 struct qrfPerCol *a = 0;
9aee493… drh 1889 sqlite3_int64 nRow = 1;
9aee493… drh 1890 sqlite3_int64 i;
9aee493… drh 1891 while( 1/*exit-by-break*/ ){
9aee493… drh 1892 int *awNew = qrfValidLayout(pData, p, nColNext, p->spec.nScreenWidth);
9aee493… drh 1893 if( awNew==0 ) break;
9aee493… drh 1894 sqlite3_free(aw);
9aee493… drh 1895 aw = awNew;
9aee493… drh 1896 nCol = nColNext;
9aee493… drh 1897 nRow = (pData->n + nCol - 1)/nCol;
9aee493… drh 1898 if( nRow==1 ) break;
9aee493… drh 1899 nColNext++;
9aee493… drh 1900 while( (pData->n + nColNext - 1)/nColNext == nRow ) nColNext++;
9aee493… drh 1901 }
9aee493… drh 1902 if( nCol==1 ){
9aee493… drh 1903 sqlite3_free(aw);
9aee493… drh 1904 return; /* Cannot do better than 1 column */
9aee493… drh 1905 }
9aee493… drh 1906 az = sqlite3_malloc64( nRow*nCol*sizeof(char*) );
9aee493… drh 1907 if( az==0 ){
9aee493… drh 1908 qrfOom(p);
9aee493… drh 1909 return;
9aee493… drh 1910 }
9aee493… drh 1911 aiWth = sqlite3_malloc64( nRow*nCol*sizeof(int) );
9aee493… drh 1912 if( aiWth==0 ){
9aee493… drh 1913 sqlite3_free(az);
9aee493… drh 1914 qrfOom(p);
9aee493… drh 1915 return;
9aee493… drh 1916 }
9aee493… drh 1917 a = sqlite3_malloc64( nCol*sizeof(struct qrfPerCol) );
9aee493… drh 1918 if( a==0 ){
9aee493… drh 1919 sqlite3_free(az);
9aee493… drh 1920 sqlite3_free(aiWth);
9aee493… drh 1921 qrfOom(p);
9aee493… drh 1922 return;
9aee493… drh 1923 }
f4b3b59… drh 1924 abNum = sqlite3_malloc64( nRow*nCol );
f4b3b59… drh 1925 if( abNum==0 ){
f4b3b59… drh 1926 sqlite3_free(az);
f4b3b59… drh 1927 sqlite3_free(aiWth);
f4b3b59… drh 1928 sqlite3_free(a);
f4b3b59… drh 1929 qrfOom(p);
f4b3b59… drh 1930 return;
f4b3b59… drh 1931 }
9aee493… drh 1932 for(i=0; i<pData->n; i++){
9aee493… drh 1933 sqlite3_int64 j = (i%nRow)*nCol + (i/nRow);
9aee493… drh 1934 az[j] = pData->az[i];
f4b3b59… drh 1935 abNum[j]= pData->abNum[i];
9aee493… drh 1936 pData->az[i] = 0;
9aee493… drh 1937 aiWth[j] = pData->aiWth[i];
9aee493… drh 1938 }
9aee493… drh 1939 while( i<nRow*nCol ){
9aee493… drh 1940 sqlite3_int64 j = (i%nRow)*nCol + (i/nRow);
9aee493… drh 1941 az[j] = sqlite3_mprintf("");
9aee493… drh 1942 if( az[j]==0 ) qrfOom(p);
9aee493… drh 1943 aiWth[j] = 0;
f4b3b59… drh 1944 abNum[j] = 0;
9aee493… drh 1945 i++;
9aee493… drh 1946 }
9aee493… drh 1947 for(i=0; i<nCol; i++){
9aee493… drh 1948 a[i].fx = a[i].mxW = a[i].w = aw[i];
9aee493… drh 1949 a[i].e = pData->a[0].e;
9aee493… drh 1950 }
9aee493… drh 1951 sqlite3_free(pData->az);
9aee493… drh 1952 sqlite3_free(pData->aiWth);
9aee493… drh 1953 sqlite3_free(pData->a);
f4b3b59… drh 1954 sqlite3_free(pData->abNum);
9aee493… drh 1955 sqlite3_free(aw);
9aee493… drh 1956 pData->az = az;
9aee493… drh 1957 pData->aiWth = aiWth;
9aee493… drh 1958 pData->a = a;
f4b3b59… drh 1959 pData->abNum = abNum;
9aee493… drh 1960 pData->nCol = nCol;
9aee493… drh 1961 pData->n = pData->nAlloc = nRow*nCol;
9aee493… drh 1962 for(i=w=0; i<nCol; i++) w += a[i].w;
9aee493… drh 1963 pData->nMargin = (p->spec.nScreenWidth - w)/(nCol - 1);
9aee493… drh 1964 if( pData->nMargin>5 ) pData->nMargin = 5;
9aee493… drh 1965 }
9aee493… drh 1966
9aee493… drh 1967 /*
4f76459… drh 1968 ** Adjust the layout for the screen width restriction
4f76459… drh 1969 */
4f76459… drh 1970 static void qrfRestrictScreenWidth(qrfColData *pData, Qrf *p){
4f76459… drh 1971 int sepW; /* Width of all box separators and margins */
4f76459… drh 1972 int sumW; /* Total width of data area over all columns */
4f76459… drh 1973 int targetW; /* Desired total data area */
4f76459… drh 1974 int i; /* Loop counters */
4f76459… drh 1975 int nCol; /* Number of columns */
4f76459… drh 1976
4f76459… drh 1977 pData->nMargin = 2; /* Default to normal margins */
4f76459… drh 1978 if( p->spec.nScreenWidth==0 ) return;
4f76459… drh 1979 if( p->spec.eStyle==QRF_STYLE_Column ){
4f76459… drh 1980 sepW = pData->nCol*2 - 2;
4f76459… drh 1981 }else{
4f76459… drh 1982 sepW = pData->nCol*3 + 1;
f4b3b59… drh 1983 if( p->spec.bBorder==QRF_No ) sepW -= 2;
4f76459… drh 1984 }
4f76459… drh 1985 nCol = pData->nCol;
4f76459… drh 1986 for(i=sumW=0; i<nCol; i++) sumW += pData->a[i].w;
4f76459… drh 1987 if( p->spec.nScreenWidth >= sumW+sepW ) return;
4f76459… drh 1988
4f76459… drh 1989 /* First thing to do is reduce the separation between columns */
4f76459… drh 1990 pData->nMargin = 0;
4f76459… drh 1991 if( p->spec.eStyle==QRF_STYLE_Column ){
4f76459… drh 1992 sepW = pData->nCol - 1;
4f76459… drh 1993 }else{
4f76459… drh 1994 sepW = pData->nCol + 1;
f4b3b59… drh 1995 if( p->spec.bBorder==QRF_No ) sepW -= 2;
4f76459… drh 1996 }
4f76459… drh 1997 targetW = p->spec.nScreenWidth - sepW;
4f76459… drh 1998
4f76459… drh 1999 #define MIN_SQUOZE 8
4f76459… drh 2000 #define MIN_EX_SQUOZE 16
4f76459… drh 2001 /* Reduce the width of the widest eligible column. A column is
4f76459… drh 2002 ** eligible for narrowing if:
4f76459… drh 2003 **
4f76459… drh 2004 ** * It is not a fixed-width column (a[0].fx is false)
4f76459… drh 2005 ** * The current width is more than MIN_SQUOZE
4f76459… drh 2006 ** * Either:
4f76459… drh 2007 ** + The current width is more then MIN_EX_SQUOZE, or
4f76459… drh 2008 ** + The current width is more than half the max width (a[].mxW)
4f76459… drh 2009 **
4f76459… drh 2010 ** Keep making reductions until either no more reductions are
4f76459… drh 2011 ** possible or until the size target is reached.
4f76459… drh 2012 */
4f76459… drh 2013 while( sumW > targetW ){
4f76459… drh 2014 int gain, w;
4f76459… drh 2015 int ix = -1;
4f76459… drh 2016 int mx = 0;
4f76459… drh 2017 for(i=0; i<nCol; i++){
4f76459… drh 2018 if( pData->a[i].fx==0
4f76459… drh 2019 && (w = pData->a[i].w)>mx
4f76459… drh 2020 && w>MIN_SQUOZE
4f76459… drh 2021 && (w>MIN_EX_SQUOZE || w*2>pData->a[i].mxW)
4f76459… drh 2022 ){
4f76459… drh 2023 ix = i;
4f76459… drh 2024 mx = w;
4f76459… drh 2025 }
4f76459… drh 2026 }
4f76459… drh 2027 if( ix<0 ) break;
4f76459… drh 2028 if( mx>=MIN_SQUOZE*2 ){
4f76459… drh 2029 gain = mx/2;
4f76459… drh 2030 }else{
4f76459… drh 2031 gain = mx - MIN_SQUOZE;
4f76459… drh 2032 }
4f76459… drh 2033 if( sumW - gain < targetW ){
4f76459… drh 2034 gain = sumW - targetW;
4f76459… drh 2035 }
4f76459… drh 2036 sumW -= gain;
4f76459… drh 2037 pData->a[ix].w -= gain;
4f76459… drh 2038 pData->bMultiRow = 1;
4f76459… drh 2039 }
4f76459… drh 2040 }
4f76459… drh 2041
4f76459… drh 2042 /*
4f76459… drh 2043 ** Columnar modes require that the entire query be evaluated first, with
4f76459… drh 2044 ** results written into memory, so that we can compute appropriate column
4f76459… drh 2045 ** widths.
4f76459… drh 2046 */
4f76459… drh 2047 static void qrfColumnar(Qrf *p){
4f76459… drh 2048 sqlite3_int64 i, j; /* Loop counters */
4f76459… drh 2049 const char *colSep = 0; /* Column separator text */
4f76459… drh 2050 const char *rowSep = 0; /* Row terminator text */
4f76459… drh 2051 const char *rowStart = 0; /* Row start text */
4f76459… drh 2052 int szColSep, szRowSep, szRowStart; /* Size in bytes of previous 3 */
4f76459… drh 2053 int rc; /* Result code */
4f76459… drh 2054 int nColumn = p->nCol; /* Number of columns */
4f76459… drh 2055 int bWW; /* True to do word-wrap */
4f76459… drh 2056 sqlite3_str *pStr; /* Temporary rendering */
4f76459… drh 2057 qrfColData data; /* Columnar layout data */
9aee493… drh 2058 int bRTrim; /* Trim trailing space */
4f76459… drh 2059
4f76459… drh 2060 rc = sqlite3_step(p->pStmt);
4f76459… drh 2061 if( rc!=SQLITE_ROW || nColumn==0 ){
4f76459… drh 2062 return; /* No output */
4f76459… drh 2063 }
4f76459… drh 2064
4f76459… drh 2065 /* Initialize the data container */
4f76459… drh 2066 memset(&data, 0, sizeof(data));
4f76459… drh 2067 data.nCol = p->nCol;
f4b3b59… drh 2068 data.p = p;
4f76459… drh 2069 data.a = sqlite3_malloc64( nColumn*sizeof(struct qrfPerCol) );
4f76459… drh 2070 if( data.a==0 ){
4f76459… drh 2071 qrfOom(p);
4f76459… drh 2072 return;
4f76459… drh 2073 }
4f76459… drh 2074 memset(data.a, 0, nColumn*sizeof(struct qrfPerCol) );
4f76459… drh 2075 if( qrfColDataEnlarge(&data) ) return;
4f76459… drh 2076 assert( data.az!=0 );
4f76459… drh 2077
4f76459… drh 2078 /* Load the column header names and all cell content into data */
4f76459… drh 2079 if( p->spec.bTitles==QRF_Yes ){
4f76459… drh 2080 unsigned char saved_eText = p->spec.eText;
4f76459… drh 2081 p->spec.eText = p->spec.eTitle;
f4b3b59… drh 2082 memset(data.abNum, 0, nColumn);
4f76459… drh 2083 for(i=0; i<nColumn; i++){
4f76459… drh 2084 const char *z = (const char*)sqlite3_column_name(p->pStmt,i);
4f76459… drh 2085 int nNL = 0;
4f76459… drh 2086 int n, w;
4f76459… drh 2087 pStr = sqlite3_str_new(p->db);
4f76459… drh 2088 qrfEncodeText(p, pStr, z ? z : "");
4f76459… drh 2089 n = sqlite3_str_length(pStr);
2b2530d… drh 2090 qrfStrErr(p, pStr);
4f76459… drh 2091 z = data.az[data.n] = sqlite3_str_finish(pStr);
ae7e3f0… drh 2092 if( p->spec.nTitleLimit ){
ae7e3f0… drh 2093 nNL = 0;
ae7e3f0… drh 2094 data.aiWth[data.n] = w = qrfTitleLimit(data.az[data.n],
ae7e3f0… drh 2095 p->spec.nTitleLimit );
ae7e3f0… drh 2096 }else{
ae7e3f0… drh 2097 data.aiWth[data.n] = w = qrfDisplayWidth(z, n, &nNL);
ae7e3f0… drh 2098 }
4f76459… drh 2099 data.n++;
4f76459… drh 2100 if( w>data.a[i].mxW ) data.a[i].mxW = w;
4f76459… drh 2101 if( nNL ) data.bMultiRow = 1;
4f76459… drh 2102 }
4f76459… drh 2103 p->spec.eText = saved_eText;
4f76459… drh 2104 p->nRow++;
4f76459… drh 2105 }
4f76459… drh 2106 do{
4f76459… drh 2107 if( data.n+nColumn > data.nAlloc ){
4f76459… drh 2108 if( qrfColDataEnlarge(&data) ) return;
4f76459… drh 2109 }
4f76459… drh 2110 for(i=0; i<nColumn; i++){
4f76459… drh 2111 char *z;
4f76459… drh 2112 int nNL = 0;
4f76459… drh 2113 int n, w;
f4b3b59… drh 2114 int eType = sqlite3_column_type(p->pStmt,i);
4f76459… drh 2115 pStr = sqlite3_str_new(p->db);
4f76459… drh 2116 qrfRenderValue(p, pStr, i);
4f76459… drh 2117 n = sqlite3_str_length(pStr);
2b2530d… drh 2118 qrfStrErr(p, pStr);
4f76459… drh 2119 z = data.az[data.n] = sqlite3_str_finish(pStr);
f4b3b59… drh 2120 data.abNum[data.n] = eType==SQLITE_INTEGER || eType==SQLITE_FLOAT;
4f76459… drh 2121 data.aiWth[data.n] = w = qrfDisplayWidth(z, n, &nNL);
4f76459… drh 2122 data.n++;
4f76459… drh 2123 if( w>data.a[i].mxW ) data.a[i].mxW = w;
4f76459… drh 2124 if( nNL ) data.bMultiRow = 1;
4f76459… drh 2125 }
4f76459… drh 2126 p->nRow++;
4f76459… drh 2127 }while( sqlite3_step(p->pStmt)==SQLITE_ROW && p->iErr==SQLITE_OK );
4f76459… drh 2128 if( p->iErr ){
4f76459… drh 2129 qrfColDataFree(&data);
4f76459… drh 2130 return;
4f76459… drh 2131 }
4f76459… drh 2132
4f76459… drh 2133 /* Compute the width and alignment of every column */
4f76459… drh 2134 if( p->spec.bTitles==QRF_No ){
4f76459… drh 2135 qrfLoadAlignment(&data, p);
4f76459… drh 2136 }else{
4f76459… drh 2137 unsigned char e;
4f76459… drh 2138 if( p->spec.eTitleAlign==QRF_Auto ){
4f76459… drh 2139 e = QRF_ALIGN_Center;
4f76459… drh 2140 }else{
4f76459… drh 2141 e = p->spec.eTitleAlign;
4f76459… drh 2142 }
4f76459… drh 2143 for(i=0; i<nColumn; i++) data.a[i].e = e;
4f76459… drh 2144 }
4f76459… drh 2145
4f76459… drh 2146 for(i=0; i<nColumn; i++){
4f76459… drh 2147 int w = 0;
4f76459… drh 2148 if( i<p->spec.nWidth ){
4f76459… drh 2149 w = p->spec.aWidth[i];
4f76459… drh 2150 if( w==(-32768) ){
4f76459… drh 2151 w = 0;
4f76459… drh 2152 if( p->spec.nAlign>i && (p->spec.aAlign[i] & QRF_ALIGN_HMASK)==0 ){
4f76459… drh 2153 data.a[i].e |= QRF_ALIGN_Right;
4f76459… drh 2154 }
4f76459… drh 2155 }else if( w<0 ){
4f76459… drh 2156 w = -w;
4f76459… drh 2157 if( p->spec.nAlign>i && (p->spec.aAlign[i] & QRF_ALIGN_HMASK)==0 ){
4f76459… drh 2158 data.a[i].e |= QRF_ALIGN_Right;
4f76459… drh 2159 }
4f76459… drh 2160 }
4f76459… drh 2161 if( w ) data.a[i].fx = 1;
4f76459… drh 2162 }
4f76459… drh 2163 if( w==0 ){
4f76459… drh 2164 w = data.a[i].mxW;
4f76459… drh 2165 if( p->spec.nWrap>0 && w>p->spec.nWrap ){
4f76459… drh 2166 w = p->spec.nWrap;
4f76459… drh 2167 data.bMultiRow = 1;
4f76459… drh 2168 }
4f76459… drh 2169 }else if( (data.bMultiRow==0 || w==1) && data.a[i].mxW>w ){
4f76459… drh 2170 data.bMultiRow = 1;
4f76459… drh 2171 if( w==1 ){
4f76459… drh 2172 /* If aiWth[j] is 2 or more, then there might be a double-wide
4f76459… drh 2173 ** character somewhere. So make the column width at least 2. */
4f76459… drh 2174 w = 2;
4f76459… drh 2175 }
4f76459… drh 2176 }
4f76459… drh 2177 data.a[i].w = w;
4f76459… drh 2178 }
4f76459… drh 2179
9aee493… drh 2180 if( nColumn==1
9aee493… drh 2181 && data.n>1
9aee493… drh 2182 && p->spec.bSplitColumn==QRF_Yes
9aee493… drh 2183 && p->spec.eStyle==QRF_STYLE_Column
9aee493… drh 2184 && p->spec.bTitles==QRF_No
9aee493… drh 2185 && p->spec.nScreenWidth>data.a[0].w+3
9aee493… drh 2186 ){
9aee493… drh 2187 /* Attempt to convert single-column tables into multi-column by
9aee493… drh 2188 ** verticle wrapping, if the screen is wide enough and if the
9aee493… drh 2189 ** bSplitColumn flag is set. */
9aee493… drh 2190 qrfSplitColumn(&data, p);
9aee493… drh 2191 nColumn = data.nCol;
9aee493… drh 2192 }else{
9aee493… drh 2193 /* Adjust the column widths due to screen width restrictions */
9aee493… drh 2194 qrfRestrictScreenWidth(&data, p);
9aee493… drh 2195 }
4f76459… drh 2196
4f76459… drh 2197 /* Draw the line across the top of the table. Also initialize
4f76459… drh 2198 ** the row boundary and column separator texts. */
4f76459… drh 2199 switch( p->spec.eStyle ){
4f76459… drh 2200 case QRF_STYLE_Box:
4f76459… drh 2201 if( data.nMargin ){
4f76459… drh 2202 rowStart = BOX_13 " ";
4f76459… drh 2203 colSep = " " BOX_13 " ";
4f76459… drh 2204 rowSep = " " BOX_13 "\n";
4f76459… drh 2205 }else{
4f76459… drh 2206 rowStart = BOX_13;
4f76459… drh 2207 colSep = BOX_13;
4f76459… drh 2208 rowSep = BOX_13 "\n";
4f76459… drh 2209 }
f4b3b59… drh 2210 if( p->spec.bBorder==QRF_No){
f4b3b59… drh 2211 rowStart += 3;
f4b3b59… drh 2212 rowSep = "\n";
f4b3b59… drh 2213 }else{
709b566… drh 2214 qrfBoxSeparator(p->pOut, &data, BOX_R23, BOX_234, BOX_R34, 0);
f4b3b59… drh 2215 }
4f76459… drh 2216 break;
4f76459… drh 2217 case QRF_STYLE_Table:
4f76459… drh 2218 if( data.nMargin ){
4f76459… drh 2219 rowStart = "| ";
4f76459… drh 2220 colSep = " | ";
4f76459… drh 2221 rowSep = " |\n";
4f76459… drh 2222 }else{
4f76459… drh 2223 rowStart = "|";
4f76459… drh 2224 colSep = "|";
4f76459… drh 2225 rowSep = "|\n";
4f76459… drh 2226 }
f4b3b59… drh 2227 if( p->spec.bBorder==QRF_No ){
f4b3b59… drh 2228 rowStart += 1;
f4b3b59… drh 2229 rowSep = "\n";
f4b3b59… drh 2230 }else{
f4b3b59… drh 2231 qrfRowSeparator(p->pOut, &data, '+');
f4b3b59… drh 2232 }
4f76459… drh 2233 break;
45de97f… drh 2234 case QRF_STYLE_Column: {
45de97f… drh 2235 static const char zSpace[] = " ";
4f76459… drh 2236 rowStart = "";
9aee493… drh 2237 if( data.nMargin<2 ){
9aee493… drh 2238 colSep = " ";
9aee493… drh 2239 }else if( data.nMargin<=5 ){
45de97f… drh 2240 colSep = &zSpace[5-data.nMargin];
9aee493… drh 2241 }else{
45de97f… drh 2242 colSep = zSpace;
9aee493… drh 2243 }
4f76459… drh 2244 rowSep = "\n";
4f76459… drh 2245 break;
45de97f… drh 2246 }
4f76459… drh 2247 default: /*case QRF_STYLE_Markdown:*/
4f76459… drh 2248 if( data.nMargin ){
4f76459… drh 2249 rowStart = "| ";
4f76459… drh 2250 colSep = " | ";
4f76459… drh 2251 rowSep = " |\n";
4f76459… drh 2252 }else{
4f76459… drh 2253 rowStart = "|";
4f76459… drh 2254 colSep = "|";
4f76459… drh 2255 rowSep = "|\n";
4f76459… drh 2256 }
4f76459… drh 2257 break;
4f76459… drh 2258 }
4f76459… drh 2259 szRowStart = (int)strlen(rowStart);
4f76459… drh 2260 szRowSep = (int)strlen(rowSep);
4f76459… drh 2261 szColSep = (int)strlen(colSep);
4f76459… drh 2262
4f76459… drh 2263 bWW = (p->spec.bWordWrap==QRF_Yes && data.bMultiRow);
f4b3b59… drh 2264 if( p->spec.eStyle==QRF_STYLE_Column
f4b3b59… drh 2265 || (p->spec.bBorder==QRF_No
f4b3b59… drh 2266 && (p->spec.eStyle==QRF_STYLE_Box || p->spec.eStyle==QRF_STYLE_Table)
f4b3b59… drh 2267 )
f4b3b59… drh 2268 ){
f4b3b59… drh 2269 bRTrim = 1;
f4b3b59… drh 2270 }else{
f4b3b59… drh 2271 bRTrim = 0;
f4b3b59… drh 2272 }
2b2530d… drh 2273 for(i=0; i<data.n && sqlite3_str_errcode(p->pOut)==SQLITE_OK; i+=nColumn){
4f76459… drh 2274 int bMore;
4f76459… drh 2275 int nRow = 0;
4f76459… drh 2276
4f76459… drh 2277 /* Draw a single row of the table. This might be the title line
4f76459… drh 2278 ** (if there is a title line) or a row in the body of the table.
4f76459… drh 2279 ** The column number will be j. The row number is i/nColumn.
4f76459… drh 2280 */
f4b3b59… drh 2281 for(j=0; j<nColumn; j++){
f4b3b59… drh 2282 data.a[j].z = data.az[i+j];
d326547… drh 2283 if( data.a[j].z==0 ) data.a[j].z = "";
f4b3b59… drh 2284 data.a[j].bNum = data.abNum[i+j];
f4b3b59… drh 2285 }
4f76459… drh 2286 do{
4f76459… drh 2287 sqlite3_str_append(p->pOut, rowStart, szRowStart);
4f76459… drh 2288 bMore = 0;
4f76459… drh 2289 for(j=0; j<nColumn; j++){
4f76459… drh 2290 int nThis = 0;
4f76459… drh 2291 int nWide = 0;
4f76459… drh 2292 int iNext = 0;
4f76459… drh 2293 int nWS;
4f76459… drh 2294 qrfWrapLine(data.a[j].z, data.a[j].w, bWW, &nThis, &nWide, &iNext);
4f76459… drh 2295 nWS = data.a[j].w - nWide;
f4b3b59… drh 2296 qrfPrintAligned(p->pOut, &data.a[j], nThis, nWS);
4f76459… drh 2297 data.a[j].z += iNext;
9aee493… drh 2298 if( data.a[j].z[0]!=0 ){
9aee493… drh 2299 bMore = 1;
9aee493… drh 2300 }
4f76459… drh 2301 if( j<nColumn-1 ){
4f76459… drh 2302 sqlite3_str_append(p->pOut, colSep, szColSep);
4f76459… drh 2303 }else{
9aee493… drh 2304 if( bRTrim ) qrfRTrim(p->pOut);
4f76459… drh 2305 sqlite3_str_append(p->pOut, rowSep, szRowSep);
4f76459… drh 2306 }
4f76459… drh 2307 }
4f76459… drh 2308 }while( bMore && ++nRow < p->mxHeight );
4f76459… drh 2309 if( bMore ){
4f76459… drh 2310 /* This row was terminated by nLineLimit. Show ellipsis. */
4f76459… drh 2311 sqlite3_str_append(p->pOut, rowStart, szRowStart);
4f76459… drh 2312 for(j=0; j<nColumn; j++){
4f76459… drh 2313 if( data.a[j].z[0]==0 ){
4f76459… drh 2314 sqlite3_str_appendchar(p->pOut, data.a[j].w, ' ');
4f76459… drh 2315 }else{
4f76459… drh 2316 int nE = 3;
4f76459… drh 2317 if( nE>data.a[j].w ) nE = data.a[j].w;
f4b3b59… drh 2318 data.a[j].z = "...";
f4b3b59… drh 2319 qrfPrintAligned(p->pOut, &data.a[j], nE, data.a[j].w-nE);
4f76459… drh 2320 }
4f76459… drh 2321 if( j<nColumn-1 ){
4f76459… drh 2322 sqlite3_str_append(p->pOut, colSep, szColSep);
4f76459… drh 2323 }else{
9aee493… drh 2324 if( bRTrim ) qrfRTrim(p->pOut);
4f76459… drh 2325 sqlite3_str_append(p->pOut, rowSep, szRowSep);
4f76459… drh 2326 }
4f76459… drh 2327 }
4f76459… drh 2328 }
4f76459… drh 2329
4f76459… drh 2330 /* Draw either (1) the separator between the title line and the body
4f76459… drh 2331 ** of the table, or (2) separators between individual rows of the table
4f76459… drh 2332 ** body. isTitleDataSeparator will be true if we are doing (1).
4f76459… drh 2333 */
4f76459… drh 2334 if( (i==0 || data.bMultiRow) && i+nColumn<data.n ){
4f76459… drh 2335 int isTitleDataSeparator = (i==0 && p->spec.bTitles==QRF_Yes);
4f76459… drh 2336 if( isTitleDataSeparator ){
4f76459… drh 2337 qrfLoadAlignment(&data, p);
4f76459… drh 2338 }
4f76459… drh 2339 switch( p->spec.eStyle ){
4f76459… drh 2340 case QRF_STYLE_Table: {
4f76459… drh 2341 if( isTitleDataSeparator || data.bMultiRow ){
4f76459… drh 2342 qrfRowSeparator(p->pOut, &data, '+');
4f76459… drh 2343 }
4f76459… drh 2344 break;
4f76459… drh 2345 }
4f76459… drh 2346 case QRF_STYLE_Box: {
709b566… drh 2347 if( isTitleDataSeparator ){
709b566… drh 2348 qrfBoxSeparator(p->pOut, &data, DBL_123, DBL_1234, DBL_134, 1);
709b566… drh 2349 }else if( data.bMultiRow ){
709b566… drh 2350 qrfBoxSeparator(p->pOut, &data, BOX_123, BOX_1234, BOX_134, 0);
4f76459… drh 2351 }
4f76459… drh 2352 break;
4f76459… drh 2353 }
4f76459… drh 2354 case QRF_STYLE_Markdown: {
4f76459… drh 2355 if( isTitleDataSeparator ){
4f76459… drh 2356 qrfRowSeparator(p->pOut, &data, '|');
4f76459… drh 2357 }
4f76459… drh 2358 break;
4f76459… drh 2359 }
4f76459… drh 2360 case QRF_STYLE_Column: {
4f76459… drh 2361 if( isTitleDataSeparator ){
4f76459… drh 2362 for(j=0; j<nColumn; j++){
4f76459… drh 2363 sqlite3_str_appendchar(p->pOut, data.a[j].w, '-');
4f76459… drh 2364 if( j<nColumn-1 ){
4f76459… drh 2365 sqlite3_str_append(p->pOut, colSep, szColSep);
4f76459… drh 2366 }else{
9aee493… drh 2367 qrfRTrim(p->pOut);
4f76459… drh 2368 sqlite3_str_append(p->pOut, rowSep, szRowSep);
4f76459… drh 2369 }
4f76459… drh 2370 }
4f76459… drh 2371 }else if( data.bMultiRow ){
9aee493… drh 2372 qrfRTrim(p->pOut);
4f76459… drh 2373 sqlite3_str_append(p->pOut, "\n", 1);
4f76459… drh 2374 }
4f76459… drh 2375 break;
4f76459… drh 2376 }
4f76459… drh 2377 }
4f76459… drh 2378 }
4f76459… drh 2379 }
4f76459… drh 2380
4f76459… drh 2381 /* Draw the line across the bottom of the table */
f4b3b59… drh 2382 if( p->spec.bBorder!=QRF_No ){
f4b3b59… drh 2383 switch( p->spec.eStyle ){
f4b3b59… drh 2384 case QRF_STYLE_Box:
709b566… drh 2385 qrfBoxSeparator(p->pOut, &data, BOX_R12, BOX_124, BOX_R14, 0);
f4b3b59… drh 2386 break;
f4b3b59… drh 2387 case QRF_STYLE_Table:
f4b3b59… drh 2388 qrfRowSeparator(p->pOut, &data, '+');
f4b3b59… drh 2389 break;
f4b3b59… drh 2390 }
4f76459… drh 2391 }
4f76459… drh 2392 qrfWrite(p);
4f76459… drh 2393
4f76459… drh 2394 qrfColDataFree(&data);
4f76459… drh 2395 return;
4f76459… drh 2396 }
4f76459… drh 2397
4f76459… drh 2398 /*
4f76459… drh 2399 ** Parameter azArray points to a zero-terminated array of strings. zStr
4f76459… drh 2400 ** points to a single nul-terminated string. Return non-zero if zStr
4f76459… drh 2401 ** is equal, according to strcmp(), to any of the strings in the array.
4f76459… drh 2402 ** Otherwise, return zero.
4f76459… drh 2403 */
4f76459… drh 2404 static int qrfStringInArray(const char *zStr, const char **azArray){
4f76459… drh 2405 int i;
4f76459… drh 2406 if( zStr==0 ) return 0;
4f76459… drh 2407 for(i=0; azArray[i]; i++){
4f76459… drh 2408 if( 0==strcmp(zStr, azArray[i]) ) return 1;
4f76459… drh 2409 }
4f76459… drh 2410 return 0;
4f76459… drh 2411 }
4f76459… drh 2412
4f76459… drh 2413 /*
4f76459… drh 2414 ** Print out an EXPLAIN with indentation. This is a two-pass algorithm.
4f76459… drh 2415 **
4f76459… drh 2416 ** On the first pass, we compute aiIndent[iOp] which is the amount of
4f76459… drh 2417 ** indentation to apply to the iOp-th opcode. The output actually occurs
4f76459… drh 2418 ** on the second pass.
4f76459… drh 2419 **
4f76459… drh 2420 ** The indenting rules are:
4f76459… drh 2421 **
4f76459… drh 2422 ** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
4f76459… drh 2423 ** all opcodes that occur between the p2 jump destination and the opcode
4f76459… drh 2424 ** itself by 2 spaces.
4f76459… drh 2425 **
4f76459… drh 2426 ** * Do the previous for "Return" instructions for when P2 is positive.
4f76459… drh 2427 ** See tag-20220407a in wherecode.c and vdbe.c.
4f76459… drh 2428 **
4f76459… drh 2429 ** * For each "Goto", if the jump destination is earlier in the program
4f76459… drh 2430 ** and ends on one of:
4f76459… drh 2431 ** Yield SeekGt SeekLt RowSetRead Rewind
4f76459… drh 2432 ** or if the P1 parameter is one instead of zero,
4f76459… drh 2433 ** then indent all opcodes between the earlier instruction
4f76459… drh 2434 ** and "Goto" by 2 spaces.
4f76459… drh 2435 */
4f76459… drh 2436 static void qrfExplain(Qrf *p){
4f76459… drh 2437 int *abYield = 0; /* abYield[iOp] is rue if opcode iOp is an OP_Yield */
4f76459… drh 2438 int *aiIndent = 0; /* Indent the iOp-th opcode by aiIndent[iOp] */
4f76459… drh 2439 i64 nAlloc = 0; /* Allocated size of aiIndent[], abYield */
4f76459… drh 2440 int nIndent = 0; /* Number of entries in aiIndent[] */
4f76459… drh 2441 int iOp; /* Opcode number */
4f76459… drh 2442 int i; /* Column loop counter */
4f76459… drh 2443
4f76459… drh 2444 const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
4f76459… drh 2445 "Return", 0 };
4f76459… drh 2446 const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
4f76459… drh 2447 "Rewind", 0 };
4f76459… drh 2448 const char *azGoto[] = { "Goto", 0 };
4f76459… drh 2449
4f76459… drh 2450 /* The caller guarantees that the leftmost 4 columns of the statement
4f76459… drh 2451 ** passed to this function are equivalent to the leftmost 4 columns
4f76459… drh 2452 ** of EXPLAIN statement output. In practice the statement may be
4f76459… drh 2453 ** an EXPLAIN, or it may be a query on the bytecode() virtual table. */
4f76459… drh 2454 assert( sqlite3_column_count(p->pStmt)>=4 );
4f76459… drh 2455 assert( 0==sqlite3_stricmp( sqlite3_column_name(p->pStmt, 0), "addr" ) );
4f76459… drh 2456 assert( 0==sqlite3_stricmp( sqlite3_column_name(p->pStmt, 1), "opcode" ) );
4f76459… drh 2457 assert( 0==sqlite3_stricmp( sqlite3_column_name(p->pStmt, 2), "p1" ) );
4f76459… drh 2458 assert( 0==sqlite3_stricmp( sqlite3_column_name(p->pStmt, 3), "p2" ) );
4f76459… drh 2459
2b2530d… drh 2460 for(iOp=0; SQLITE_ROW==sqlite3_step(p->pStmt) && !p->iErr; iOp++){
4f76459… drh 2461 int iAddr = sqlite3_column_int(p->pStmt, 0);
4f76459… drh 2462 const char *zOp = (const char*)sqlite3_column_text(p->pStmt, 1);
4f76459… drh 2463 int p1 = sqlite3_column_int(p->pStmt, 2);
4f76459… drh 2464 int p2 = sqlite3_column_int(p->pStmt, 3);
4f76459… drh 2465
4f76459… drh 2466 /* Assuming that p2 is an instruction address, set variable p2op to the
4f76459… drh 2467 ** index of that instruction in the aiIndent[] array. p2 and p2op may be
4f76459… drh 2468 ** different if the current instruction is part of a sub-program generated
4f76459… drh 2469 ** by an SQL trigger or foreign key. */
4f76459… drh 2470 int p2op = (p2 + (iOp-iAddr));
4f76459… drh 2471
4f76459… drh 2472 /* Grow the aiIndent array as required */
4f76459… drh 2473 if( iOp>=nAlloc ){
4f76459… drh 2474 nAlloc += 100;
4f76459… drh 2475 aiIndent = (int*)sqlite3_realloc64(aiIndent, nAlloc*sizeof(int));
4f76459… drh 2476 abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
4f76459… drh 2477 if( aiIndent==0 || abYield==0 ){
4f76459… drh 2478 qrfOom(p);
4f76459… drh 2479 sqlite3_free(aiIndent);
4f76459… drh 2480 sqlite3_free(abYield);
4f76459… drh 2481 return;
4f76459… drh 2482 }
4f76459… drh 2483 }
4f76459… drh 2484
4f76459… drh 2485 abYield[iOp] = qrfStringInArray(zOp, azYield);
4f76459… drh 2486 aiIndent[iOp] = 0;
4f76459… drh 2487 nIndent = iOp+1;
4f76459… drh 2488 if( qrfStringInArray(zOp, azNext) && p2op>0 ){
4f76459… drh 2489 for(i=p2op; i<iOp; i++) aiIndent[i] += 2;
4f76459… drh 2490 }
4f76459… drh 2491 if( qrfStringInArray(zOp, azGoto) && p2op<iOp && (abYield[p2op] || p1) ){
4f76459… drh 2492 for(i=p2op; i<iOp; i++) aiIndent[i] += 2;
4f76459… drh 2493 }
4f76459… drh 2494 }
4f76459… drh 2495 sqlite3_free(abYield);
4f76459… drh 2496
4f76459… drh 2497 /* Second pass. Actually generate output */
4f76459… drh 2498 sqlite3_reset(p->pStmt);
4f76459… drh 2499 if( p->iErr==SQLITE_OK ){
4f76459… drh 2500 static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
4f76459… drh 2501 static const int aExplainMap[] = {0, 1, 2, 3, 4, 5, 6, 7 };
4f76459… drh 2502 static const int aScanExpWidth[] = {4,15, 6, 13, 4, 4, 4, 13, 2, 13};
4f76459… drh 2503 static const int aScanExpMap[] = {0, 9, 8, 1, 2, 3, 4, 5, 6, 7 };
4f76459… drh 2504 const int *aWidth = aExplainWidth;
4f76459… drh 2505 const int *aMap = aExplainMap;
4f76459… drh 2506 int nWidth = sizeof(aExplainWidth)/sizeof(int);
4f76459… drh 2507 int iIndent = 1;
4f76459… drh 2508 int nArg = p->nCol;
4f76459… drh 2509 if( p->spec.eStyle==QRF_STYLE_StatsVm ){
4f76459… drh 2510 aWidth = aScanExpWidth;
4f76459… drh 2511 aMap = aScanExpMap;
4f76459… drh 2512 nWidth = sizeof(aScanExpWidth)/sizeof(int);
4f76459… drh 2513 iIndent = 3;
4f76459… drh 2514 }
4f76459… drh 2515 if( nArg>nWidth ) nArg = nWidth;
4f76459… drh 2516
2b2530d… drh 2517 for(iOp=0; sqlite3_step(p->pStmt)==SQLITE_ROW && !p->iErr; iOp++){
4f76459… drh 2518 /* If this is the first row seen, print out the headers */
4f76459… drh 2519 if( iOp==0 ){
4f76459… drh 2520 for(i=0; i<nArg; i++){
4f76459… drh 2521 const char *zCol = sqlite3_column_name(p->pStmt, aMap[i]);
4f76459… drh 2522 qrfWidthPrint(p,p->pOut, aWidth[i], zCol);
4f76459… drh 2523 if( i==nArg-1 ){
4f76459… drh 2524 sqlite3_str_append(p->pOut, "\n", 1);
4f76459… drh 2525 }else{
4f76459… drh 2526 sqlite3_str_append(p->pOut, " ", 2);
4f76459… drh 2527 }
4f76459… drh 2528 }
4f76459… drh 2529 for(i=0; i<nArg; i++){
4f76459… drh 2530 sqlite3_str_appendf(p->pOut, "%.*c", aWidth[i], '-');
4f76459… drh 2531 if( i==nArg-1 ){
4f76459… drh 2532 sqlite3_str_append(p->pOut, "\n", 1);
4f76459… drh 2533 }else{
4f76459… drh 2534 sqlite3_str_append(p->pOut, " ", 2);
4f76459… drh 2535 }
4f76459… drh 2536 }
4f76459… drh 2537 }
4f76459… drh 2538
4f76459… drh 2539 for(i=0; i<nArg; i++){
4f76459… drh 2540 const char *zSep = " ";
4f76459… drh 2541 int w = aWidth[i];
4f76459… drh 2542 const char *zVal = (const char*)sqlite3_column_text(p->pStmt, aMap[i]);
4f76459… drh 2543 int len;
4f76459… drh 2544 if( i==nArg-1 ) w = 0;
4f76459… drh 2545 if( zVal==0 ) zVal = "";
d326547… drh 2546 len = (int)sqlite3_qrf_wcswidth(zVal);
4f76459… drh 2547 if( len>w ){
4f76459… drh 2548 w = len;
4f76459… drh 2549 zSep = " ";
4f76459… drh 2550 }
4f76459… drh 2551 if( i==iIndent && aiIndent && iOp<nIndent ){
4f76459… drh 2552 sqlite3_str_appendchar(p->pOut, aiIndent[iOp], ' ');
4f76459… drh 2553 }
4f76459… drh 2554 qrfWidthPrint(p, p->pOut, w, zVal);
4f76459… drh 2555 if( i==nArg-1 ){
4f76459… drh 2556 sqlite3_str_append(p->pOut, "\n", 1);
4f76459… drh 2557 }else{
4f76459… drh 2558 sqlite3_str_appendall(p->pOut, zSep);
4f76459… drh 2559 }
4f76459… drh 2560 }
4f76459… drh 2561 p->nRow++;
4f76459… drh 2562 }
4f76459… drh 2563 qrfWrite(p);
4f76459… drh 2564 }
4f76459… drh 2565 sqlite3_free(aiIndent);
4f76459… drh 2566 }
4f76459… drh 2567
4f76459… drh 2568 /*
4f76459… drh 2569 ** Do a "scanstatus vm" style EXPLAIN listing on p->pStmt.
4f76459… drh 2570 **
4f76459… drh 2571 ** p->pStmt is probably not an EXPLAIN query. Instead, construct a
4f76459… drh 2572 ** new query that is a bytecode() rendering of p->pStmt with extra
4f76459… drh 2573 ** columns for the "scanstatus vm" outputs, and run the results of
4f76459… drh 2574 ** that new query through the normal EXPLAIN formatting.
4f76459… drh 2575 */
4f76459… drh 2576 static void qrfScanStatusVm(Qrf *p){
4f76459… drh 2577 sqlite3_stmt *pOrigStmt = p->pStmt;
4f76459… drh 2578 sqlite3_stmt *pExplain;
4f76459… drh 2579 int rc;
4f76459… drh 2580 static const char *zSql =
4f76459… drh 2581 " SELECT addr, opcode, p1, p2, p3, p4, p5, comment, nexec,"
4f76459… drh 2582 " format('% 6s (%.2f%%)',"
4f76459… drh 2583 " CASE WHEN ncycle<100_000 THEN ncycle || ' '"
4f76459… drh 2584 " WHEN ncycle<100_000_000 THEN (ncycle/1_000) || 'K'"
4f76459… drh 2585 " WHEN ncycle<100_000_000_000 THEN (ncycle/1_000_000) || 'M'"
4f76459… drh 2586 " ELSE (ncycle/1000_000_000) || 'G' END,"
4f76459… drh 2587 " ncycle*100.0/(sum(ncycle) OVER ())"
4f76459… drh 2588 " ) AS cycles"
4f76459… drh 2589 " FROM bytecode(?1)";
4f76459… drh 2590 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pExplain, 0);
4f76459… drh 2591 if( rc ){
4f76459… drh 2592 qrfError(p, rc, "%s", sqlite3_errmsg(p->db));
4f76459… drh 2593 sqlite3_finalize(pExplain);
4f76459… drh 2594 return;
4f76459… drh 2595 }
4f76459… drh 2596 sqlite3_bind_pointer(pExplain, 1, pOrigStmt, "stmt-pointer", 0);
4f76459… drh 2597 p->pStmt = pExplain;
4f76459… drh 2598 p->nCol = 10;
4f76459… drh 2599 qrfExplain(p);
4f76459… drh 2600 sqlite3_finalize(pExplain);
4f76459… drh 2601 p->pStmt = pOrigStmt;
4f76459… drh 2602 ** Return 1 if quoting is required. Return 0 if no quoting is required.
4f76459… drh 2603
4f76459… drh 2604 static int qrf_need_quote(const char *zName){
4f76459… drh 2605 int i;
4f76459… drh 2606 const unsigned char *z = (const unsigned char*)zName;
4f76459… drh 2607 if( z==0 ) return 1;
4f76459… drh 2608 if( !qrfAlpha(z[0]) ) return 1;
4f76459… drh 2609 for(i=0; z[i]; i++){
4f76459… drh 2610 if( !qrfAlnum(z[i]) ) return 1;
4f76459… drh 2611 }
4f76459… drh 2612 return sqlite3_keyword_check(zName, i)!=0;
4f76459… drh 2613 }
4f76459… drh 2614
4f76459… drh 2615 /*
4f76459… drh 2616 ** Helper function for QRF_STYLE_Json and QRF_STYLE_JObject.
4f76459… drh 2617 ** The initial "{" for a JSON object that will contain row content
4f76459… drh 2618 ** has been output. Now output all the content.
4f76459… drh 2619 */
4f76459… drh 2620 static void qrfOneJsonRow(Qrf *p){
4f76459… drh 2621 int i, nItem;
4f76459… drh 2622 for(nItem=i=0; i<p->nCol; i++){
4f76459… drh 2623 const char *zCName;
4f76459… drh 2624 zCName = sqlite3_column_name(p->pStmt, i);
4f76459… drh 2625 if( nItem>0 ) sqlite3_str_append(p->pOut, ",", 1);
4f76459… drh 2626 nItem++;
4f76459… drh 2627 qrfEncodeText(p, p->pOut, zCName);
4f76459… drh 2628 sqlite3_str_append(p->pOut, ":", 1);
4f76459… drh 2629 qrfRenderValue(p, p->pOut, i);
4f76459… drh 2630 }
4f76459… drh 2631 qrfWrite(p);
4f76459… drh 2632 }
4f76459… drh 2633
4f76459… drh 2634 /*
4f76459… drh 2635 ** Render a single row of output for non-columnar styles - any
4f76459… drh 2636 ** style that lets us render row by row as the content is received
4f76459… drh 2637 ** from the query.
4f76459… drh 2638 */
4f76459… drh 2639 static void qrfOneSimpleRow(Qrf *p){
4f76459… drh 2640 switch( p->spec.eStyle ){
4f76459… drh 2641 case QRF_STYLE_Off:
4f76459… drh 2642 case QRF_STYLE_Count: {
4f76459… drh 2643 /* No-op */
4f76459… drh 2644 break;
4f76459… drh 2645 }
4f76459… drh 2646 case QRF_STYLE_Json: {
4f76459… drh 2647 if( p->nRow==0 ){
4f76459… drh 2648 sqlite3_str_append(p->pOut, "[{", 2);
4f76459… drh 2649 }else{
4f76459… drh 2650 sqlite3_str_append(p->pOut, "},\n{", 4);
4f76459… drh 2651 }
4f76459… drh 2652 qrfOneJsonRow(p);
4f76459… drh 2653 break;
4f76459… drh 2654 }
4f76459… drh 2655 case QRF_STYLE_JObject: {
4f76459… drh 2656 if( p->nRow==0 ){
4f76459… drh 2657 sqlite3_str_append(p->pOut, "{", 1);
4f76459… drh 2658 }else{
4f76459… drh 2659 sqlite3_str_append(p->pOut, "}\n{", 3);
4f76459… drh 2660 }
4f76459… drh 2661 qrfOneJsonRow(p);
4f76459… drh 2662 break;
4f76459… drh 2663 }
4f76459… drh 2664 case QRF_STYLE_Html: {
4f76459… drh 2665 if( p->nRow==0 && p->spec.bTitles==QRF_Yes ){
4f76459… drh 2666 sqlite3_str_append(p->pOut, "<TR>", 4);
4f76459… drh 2667 for(i=0; i<p->nCol; i++){
4f76459… drh 2668 const char *zCName = sqlite3_column_name(p->pStmt, i);
4f76459… drh 2669 sqlite3_str_append(p->pOut, "\n<TH>", 5);
4f76459… drh 2670 qrfEncodeText(p, p->pOut, zCName);
4f76459… drh 2671 }
4f76459… drh 2672 sqlite3_str_append(p->pOut, "\n</TR>\n", 7);
4f76459… drh 2673 }
4f76459… drh 2674 sqlite3_str_append(p->pOut, "<TR>", 4);
4f76459… drh 2675 for(i=0; i<p->nCol; i++){
4f76459… drh 2676 sqlite3_str_append(p->pOut, "\n<TD>", 5);
4f76459… drh 2677 qrfRenderValue(p, p->pOut, i);
4f76459… drh 2678 }
4f76459… drh 2679 sqlite3_str_append(p->pOut, "\n</TR>\n", 7);
4f76459… drh 2680 qrfWrite(p);
4f76459… drh 2681 break;
4f76459… drh 2682 }
4f76459… drh 2683 case QRF_STYLE_Insert: {
cb89386… drh 2684 unsigned int mxIns = p->spec.nMultiInsert;
17f9878… drh 2685 int szStart = sqlite3_str_length(p->pOut);
17f9878… drh 2686 if( p->u.nIns==0 || p->u.nIns>=mxIns ){
17f9878… drh 2687 if( p->u.nIns ){
17f9878… drh 2688 sqlite3_str_append(p->pOut, ";\n", 2);
17f9878… drh 2689 p->u.nIns = 0;
17f9878… drh 2690 }
17f9878… drh 2691 if( qrf_need_quote(p->spec.zTableName) ){
17f9878… drh 2692 sqlite3_str_appendf(p->pOut,"INSERT INTO \"%w\"",p->spec.zTableName);
17f9878… drh 2693 }else{
17f9878… drh 2694 sqlite3_str_appendf(p->pOut,"INSERT INTO %s",p->spec.zTableName);
17f9878… drh 2695 }
17f9878… drh 2696 if( p->spec.bTitles==QRF_Yes ){
17f9878… drh 2697 for(i=0; i<p->nCol; i++){
17f9878… drh 2698 const char *zCName = sqlite3_column_name(p->pStmt, i);
17f9878… drh 2699 if( qrf_need_quote(zCName) ){
17f9878… drh 2700 sqlite3_str_appendf(p->pOut, "%c\"%w\"",
17f9878… drh 2701 i==0 ? '(' : ',', zCName);
17f9878… drh 2702 }else{
17f9878… drh 2703 sqlite3_str_appendf(p->pOut, "%c%s",
17f9878… drh 2704 i==0 ? '(' : ',', zCName);
17f9878… drh 2705 }
17f9878… drh 2706 }
17f9878… drh 2707 sqlite3_str_append(p->pOut, ")", 1);
17f9878… drh 2708 }
17f9878… drh 2709 sqlite3_str_append(p->pOut," VALUES(", 8);
17f9878… drh 2710 }else{
17f9878… drh 2711 sqlite3_str_append(p->pOut,",\n (", 5);
17f9878… drh 2712 }
4f76459… drh 2713 for(i=0; i<p->nCol; i++){
4f76459… drh 2714 if( i>0 ) sqlite3_str_append(p->pOut, ",", 1);
4f76459… drh 2715 qrfRenderValue(p, p->pOut, i);
4f76459… drh 2716 }
17f9878… drh 2717 p->u.nIns += sqlite3_str_length(p->pOut) + 2 - szStart;
17f9878… drh 2718 if( p->u.nIns>=mxIns ){
17f9878… drh 2719 sqlite3_str_append(p->pOut, ");\n", 3);
17f9878… drh 2720 p->u.nIns = 0;
17f9878… drh 2721 }else{
17f9878… drh 2722 sqlite3_str_append(p->pOut, ")", 1);
17f9878… drh 2723 }
4f76459… drh 2724 qrfWrite(p);
4f76459… drh 2725 break;
4f76459… drh 2726 }
4f76459… drh 2727 case QRF_STYLE_Line: {
4f76459… drh 2728 sqlite3_str *pVal;
4f76459… drh 2729 int mxW;
4f76459… drh 2730 int bWW;
ae7e3f0… drh 2731 int nSep;
4f76459… drh 2732 if( p->u.sLine.azCol==0 ){
4f76459… drh 2733 p->u.sLine.azCol = sqlite3_malloc64( p->nCol*sizeof(char*) );
4f76459… drh 2734 if( p->u.sLine.azCol==0 ){
4f76459… drh 2735 qrfOom(p);
4f76459… drh 2736 break;
4f76459… drh 2737 }
4f76459… drh 2738 p->u.sLine.mxColWth = 0;
4f76459… drh 2739 for(i=0; i<p->nCol; i++){
4f76459… drh 2740 int sz;
ae7e3f0… drh 2741 const char *zCName = sqlite3_column_name(p->pStmt, i);
ae7e3f0… drh 2742 if( zCName==0 ) zCName = "unknown";
ae7e3f0… drh 2743 p->u.sLine.azCol[i] = sqlite3_mprintf("%s", zCName);
ae7e3f0… drh 2744 if( p->spec.nTitleLimit>0 ){
ae7e3f0… drh 2745 (void)qrfTitleLimit(p->u.sLine.azCol[i], p->spec.nTitleLimit);
ae7e3f0… drh 2746 }
d326547… drh 2747 sz = (int)sqlite3_qrf_wcswidth(p->u.sLine.azCol[i]);
4f76459… drh 2748 if( sz > p->u.sLine.mxColWth ) p->u.sLine.mxColWth = sz;
4f76459… drh 2749 }
4f76459… drh 2750 }
4f76459… drh 2751 if( p->nRow ) sqlite3_str_append(p->pOut, "\n", 1);
4f76459… drh 2752 pVal = sqlite3_str_new(p->db);
ae7e3f0… drh 2753 nSep = (int)strlen(p->spec.zColumnSep);
ae7e3f0… drh 2754 mxW = p->mxWidth - (nSep + p->u.sLine.mxColWth);
4f76459… drh 2755 bWW = p->spec.bWordWrap==QRF_Yes;
4f76459… drh 2756 for(i=0; i<p->nCol; i++){
4f76459… drh 2757 const char *zVal;
4f76459… drh 2758 int cnt = 0;
4f76459… drh 2759 qrfWidthPrint(p, p->pOut, -p->u.sLine.mxColWth, p->u.sLine.azCol[i]);
ae7e3f0… drh 2760 sqlite3_str_append(p->pOut, p->spec.zColumnSep, nSep);
4f76459… drh 2761 qrfRenderValue(p, pVal, i);
4f76459… drh 2762 zVal = sqlite3_str_value(pVal);
4f76459… drh 2763 if( zVal==0 ) zVal = "";
4f76459… drh 2764 do{
4f76459… drh 2765 int nThis, nWide, iNext;
4f76459… drh 2766 qrfWrapLine(zVal, mxW, bWW, &nThis, &nWide, &iNext);
17f9878… drh 2767 if( cnt ){
17f9878… drh 2768 sqlite3_str_appendchar(p->pOut,p->u.sLine.mxColWth+nSep,' ');
17f9878… drh 2769 }
4f76459… drh 2770 cnt++;
4f76459… drh 2771 if( cnt>p->mxHeight ){
4f76459… drh 2772 zVal = "...";
4f76459… drh 2773 nThis = iNext = 3;
4f76459… drh 2774 }
4f76459… drh 2775 sqlite3_str_append(p->pOut, zVal, nThis);
4f76459… drh 2776 sqlite3_str_append(p->pOut, "\n", 1);
4f76459… drh 2777 zVal += iNext;
4f76459… drh 2778 }while( zVal[0] );
4f76459… drh 2779 sqlite3_str_reset(pVal);
4f76459… drh 2780 }
2b2530d… drh 2781 qrfStrErr(p, pVal);
4f76459… drh 2782 sqlite3_free(sqlite3_str_finish(pVal));
4f76459… drh 2783 qrfWrite(p);
4f76459… drh 2784 break;
4f76459… drh 2785 }
4f76459… drh 2786 case QRF_STYLE_Eqp: {
4f76459… drh 2787 const char *zEqpLine = (const char*)sqlite3_column_text(p->pStmt,3);
4f76459… drh 2788 int iEqpId = sqlite3_column_int(p->pStmt, 0);
4f76459… drh 2789 int iParentId = sqlite3_column_int(p->pStmt, 1);
4f76459… drh 2790 if( zEqpLine==0 ) zEqpLine = "";
4f76459… drh 2791 if( zEqpLine[0]=='-' ) qrfEqpRender(p, 0);
4f76459… drh 2792 qrfEqpAppend(p, iEqpId, iParentId, zEqpLine);
4f76459… drh 2793 break;
4f76459… drh 2794 }
4f76459… drh 2795 default: { /* QRF_STYLE_List */
4f76459… drh 2796 if( p->nRow==0 && p->spec.bTitles==QRF_Yes ){
4f76459… drh 2797 int saved_eText = p->spec.eText;
4f76459… drh 2798 p->spec.eText = p->spec.eTitle;
4f76459… drh 2799 for(i=0; i<p->nCol; i++){
4f76459… drh 2800 const char *zCName = sqlite3_column_name(p->pStmt, i);
4f76459… drh 2801 if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
4f76459… drh 2802 qrfEncodeText(p, p->pOut, zCName);
4f76459… drh 2803 }
4f76459… drh 2804 sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
4f76459… drh 2805 qrfWrite(p);
4f76459… drh 2806 p->spec.eText = saved_eText;
4f76459… drh 2807 }
4f76459… drh 2808 for(i=0; i<p->nCol; i++){
4f76459… drh 2809 if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
4f76459… drh 2810 qrfRenderValue(p, p->pOut, i);
4f76459… drh 2811 }
4f76459… drh 2812 sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
4f76459… drh 2813 qrfWrite(p);
4f76459… drh 2814 break;
4f76459… drh 2815 }
4f76459… drh 2816 }
4f76459… drh 2817 p->nRow++;
4f76459… drh 2818 }
4f76459… drh 2819
4f76459… drh 2820 /*
4f76459… drh 2821 ** Initialize the internal Qrf object.
4f76459… drh 2822 */
4f76459… drh 2823 static void qrfInitialize(
4f76459… drh 2824 Qrf *p, /* State object to be initialized */
4f76459… drh 2825 sqlite3_stmt *pStmt, /* Query whose output to be formatted */
4f76459… drh 2826 const sqlite3_qrf_spec *pSpec, /* Format specification */
4f76459… drh 2827 char **pzErr /* Write errors here */
4f76459… drh 2828 ){
4f76459… drh 2829 size_t sz; /* Size of pSpec[], based on pSpec->iVersion */
4f76459… drh 2830 memset(p, 0, sizeof(*p));
4f76459… drh 2831 p->pzErr = pzErr;
cb89386… drh 2832 if( pSpec->iVersion>1 ){
4f76459… drh 2833 qrfError(p, SQLITE_ERROR,
4f76459… drh 2834 "unusable sqlite3_qrf_spec.iVersion (%d)",
4f76459… drh 2835 pSpec->iVersion);
4f76459… drh 2836 return;
4f76459… drh 2837 }
4f76459… drh 2838 p->pStmt = pStmt;
4f76459… drh 2839 p->db = sqlite3_db_handle(pStmt);
4f76459… drh 2840 p->pOut = sqlite3_str_new(p->db);
4f76459… drh 2841 if( p->pOut==0 ){
4f76459… drh 2842 qrfOom(p);
4f76459… drh 2843 return;
4f76459… drh 2844 }
2b2530d… drh 2845 p->iErr = SQLITE_OK;
4f76459… drh 2846 p->nCol = sqlite3_column_count(p->pStmt);
4f76459… drh 2847 p->nRow = 0;
4f76459… drh 2848 sz = sizeof(sqlite3_qrf_spec);
4f76459… drh 2849 memcpy(&p->spec, pSpec, sz);
4f76459… drh 2850 if( p->spec.zNull==0 ) p->spec.zNull = "";
4f76459… drh 2851 p->mxWidth = p->spec.nScreenWidth;
4f76459… drh 2852 if( p->mxWidth<=0 ) p->mxWidth = QRF_MAX_WIDTH;
4f76459… drh 2853 p->mxHeight = p->spec.nLineLimit;
4f76459… drh 2854 if( p->mxHeight<=0 ) p->mxHeight = 2147483647;
45de97f… drh 2855 if( p->spec.eStyle>QRF_STYLE_Table ) p->spec.eStyle = QRF_Auto;
45de97f… drh 2856 if( p->spec.eEsc>QRF_ESC_Symbol ) p->spec.eEsc = QRF_Auto;
709b566… drh 2857 if( p->spec.eText>QRF_TEXT_Relaxed ) p->spec.eText = QRF_Auto;
709b566… drh 2858 if( p->spec.eTitle>QRF_TEXT_Relaxed ) p->spec.eTitle = QRF_Auto;
45de97f… drh 2859 if( p->spec.eBlob>QRF_BLOB_Size ) p->spec.eBlob = QRF_Auto;
4f76459… drh 2860 qrf_reinit:
4f76459… drh 2861 switch( p->spec.eStyle ){
4f76459… drh 2862 case QRF_Auto: {
4f76459… drh 2863 switch( sqlite3_stmt_isexplain(pStmt) ){
4f76459… drh 2864 case 0: p->spec.eStyle = QRF_STYLE_Box; break;
4f76459… drh 2865 case 1: p->spec.eStyle = QRF_STYLE_Explain; break;
4f76459… drh 2866 default: p->spec.eStyle = QRF_STYLE_Eqp; break;
4f76459… drh 2867 }
4f76459… drh 2868 goto qrf_reinit;
4f76459… drh 2869 }
4f76459… drh 2870 case QRF_STYLE_List: {
4f76459… drh 2871 if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = "|";
4f76459… drh 2872 if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n";
4f76459… drh 2873 break;
4f76459… drh 2874 }
4f76459… drh 2875 case QRF_STYLE_JObject:
4f76459… drh 2876 case QRF_STYLE_Json: {
4f76459… drh 2877 p->spec.eText = QRF_TEXT_Json;
4f76459… drh 2878 p->spec.zNull = "null";
4f76459… drh 2879 break;
4f76459… drh 2880 }
4f76459… drh 2881 case QRF_STYLE_Html: {
4f76459… drh 2882 p->spec.eText = QRF_TEXT_Html;
4f76459… drh 2883 p->spec.zNull = "null";
4f76459… drh 2884 break;
4f76459… drh 2885 }
4f76459… drh 2886 case QRF_STYLE_Insert: {
4f76459… drh 2887 p->spec.eText = QRF_TEXT_Sql;
4f76459… drh 2888 p->spec.zNull = "NULL";
4f76459… drh 2889 if( p->spec.zTableName==0 || p->spec.zTableName[0]==0 ){
4f76459… drh 2890 p->spec.zTableName = "tab";
ae7e3f0… drh 2891 }
17f9878… drh 2892 p->u.nIns = 0;
ae7e3f0… drh 2893 break;
ae7e3f0… drh 2894 }
ae7e3f0… drh 2895 case QRF_STYLE_Line: {
ae7e3f0… drh 2896 if( p->spec.zColumnSep==0 ){
ae7e3f0… drh 2897 p->spec.zColumnSep = ": ";
4f76459… drh 2898 }
4f76459… drh 2899 break;
4f76459… drh 2900 }
4f76459… drh 2901 case QRF_STYLE_Csv: {
4f76459… drh 2902 p->spec.eStyle = QRF_STYLE_List;
4f76459… drh 2903 p->spec.eText = QRF_TEXT_Csv;
4f76459… drh 2904 p->spec.zColumnSep = ",";
4f76459… drh 2905 p->spec.zRowSep = "\r\n";
4f76459… drh 2906 p->spec.zNull = "";
4f76459… drh 2907 break;
4f76459… drh 2908 }
4f76459… drh 2909 case QRF_STYLE_Quote: {
4f76459… drh 2910 p->spec.eText = QRF_TEXT_Sql;
4f76459… drh 2911 p->spec.zNull = "NULL";
4f76459… drh 2912 p->spec.zColumnSep = ",";
4f76459… drh 2913 p->spec.zRowSep = "\n";
4f76459… drh 2914 break;
4f76459… drh 2915 }
4f76459… drh 2916 case QRF_STYLE_Eqp: {
4f76459… drh 2917 int expMode = sqlite3_stmt_isexplain(p->pStmt);
4f76459… drh 2918 if( expMode!=2 ){
4f76459… drh 2919 sqlite3_stmt_explain(p->pStmt, 2);
4f76459… drh 2920 p->expMode = expMode+1;
4f76459… drh 2921 }
4f76459… drh 2922 break;
4f76459… drh 2923 }
4f76459… drh 2924 case QRF_STYLE_Explain: {
4f76459… drh 2925 int expMode = sqlite3_stmt_isexplain(p->pStmt);
4f76459… drh 2926 if( expMode!=1 ){
4f76459… drh 2927 sqlite3_stmt_explain(p->pStmt, 1);
4f76459… drh 2928 p->expMode = expMode+1;
4f76459… drh 2929 }
4f76459… drh 2930 break;
4f76459… drh 2931 }
4f76459… drh 2932 }
4f76459… drh 2933 if( p->spec.eEsc==QRF_Auto ){
4f76459… drh 2934 p->spec.eEsc = QRF_ESC_Ascii;
4f76459… drh 2935 }
4f76459… drh 2936 if( p->spec.eText==QRF_Auto ){
4f76459… drh 2937 p->spec.eText = QRF_TEXT_Plain;
4f76459… drh 2938 }
4f76459… drh 2939 if( p->spec.eTitle==QRF_Auto ){
4f76459… drh 2940 switch( p->spec.eStyle ){
4f76459… drh 2941 case QRF_STYLE_Box:
4f76459… drh 2942 case QRF_STYLE_Column:
4f76459… drh 2943 case QRF_STYLE_Table:
4f76459… drh 2944 p->spec.eTitle = QRF_TEXT_Plain;
4f76459… drh 2945 break;
4f76459… drh 2946 default:
4f76459… drh 2947 p->spec.eTitle = p->spec.eText;
4f76459… drh 2948 break;
4f76459… drh 2949 }
4f76459… drh 2950 }
4f76459… drh 2951 if( p->spec.eBlob==QRF_Auto ){
4f76459… drh 2952 switch( p->spec.eText ){
4f76459… drh 2953 case QRF_TEXT_Sql: p->spec.eBlob = QRF_BLOB_Sql; break;
4f76459… drh 2954 case QRF_TEXT_Csv: p->spec.eBlob = QRF_BLOB_Tcl; break;
4f76459… drh 2955 case QRF_TEXT_Tcl: p->spec.eBlob = QRF_BLOB_Tcl; break;
4f76459… drh 2956 case QRF_TEXT_Json: p->spec.eBlob = QRF_BLOB_Json; break;
4f76459… drh 2957 default: p->spec.eBlob = QRF_BLOB_Text; break;
4f76459… drh 2958 }
4f76459… drh 2959 }
4f76459… drh 2960 if( p->spec.bTitles==QRF_Auto ){
4f76459… drh 2961 switch( p->spec.eStyle ){
4f76459… drh 2962 case QRF_STYLE_Box:
4f76459… drh 2963 case QRF_STYLE_Csv:
4f76459… drh 2964 case QRF_STYLE_Column:
4f76459… drh 2965 case QRF_STYLE_Table:
4f76459… drh 2966 case QRF_STYLE_Markdown:
4f76459… drh 2967 p->spec.bTitles = QRF_Yes;
4f76459… drh 2968 break;
4f76459… drh 2969 default:
4f76459… drh 2970 p->spec.bTitles = QRF_No;
4f76459… drh 2971 break;
4f76459… drh 2972 }
4f76459… drh 2973 }
4f76459… drh 2974 if( p->spec.bWordWrap==QRF_Auto ){
4f76459… drh 2975 p->spec.bWordWrap = QRF_Yes;
4f76459… drh 2976 }
4f76459… drh 2977 if( p->spec.bTextJsonb==QRF_Auto ){
4f76459… drh 2978 p->spec.bTextJsonb = QRF_No;
4f76459… drh 2979 }
4f76459… drh 2980 if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = ",";
4f76459… drh 2981 if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n";
4f76459… drh 2982 }
4f76459… drh 2983
4f76459… drh 2984 /*
4f76459… drh 2985 ** Finish rendering the results
4f76459… drh 2986 */
4f76459… drh 2987 static void qrfFinalize(Qrf *p){
4f76459… drh 2988 switch( p->spec.eStyle ){
4f76459… drh 2989 case QRF_STYLE_Count: {
4f76459… drh 2990 sqlite3_str_appendf(p->pOut, "%lld\n", p->nRow);
4f76459… drh 2991 break;
4f76459… drh 2992 }
4f76459… drh 2993 case QRF_STYLE_Json: {
f07aa62… drh 2994 if( p->nRow>0 ){
f07aa62… drh 2995 sqlite3_str_append(p->pOut, "}]\n", 3);
f07aa62… drh 2996 }
4f76459… drh 2997 break;
4f76459… drh 2998 }
4f76459… drh 2999 case QRF_STYLE_JObject: {
f07aa62… drh 3000 if( p->nRow>0 ){
f07aa62… drh 3001 sqlite3_str_append(p->pOut, "}\n", 2);
17f9878… drh 3002 }
17f9878… drh 3003 break;
17f9878… drh 3004 }
17f9878… drh 3005 case QRF_STYLE_Insert: {
17f9878… drh 3006 if( p->u.nIns ){
17f9878… drh 3007 sqlite3_str_append(p->pOut, ";\n", 2);
f07aa62… drh 3008 }
4f76459… drh 3009 break;
4f76459… drh 3010 }
4f76459… drh 3011 case QRF_STYLE_Line: {
ae7e3f0… drh 3012 if( p->u.sLine.azCol ){
ae7e3f0… drh 3013 int i;
ae7e3f0… drh 3014 for(i=0; i<p->nCol; i++) sqlite3_free(p->u.sLine.azCol[i]);
ae7e3f0… drh 3015 sqlite3_free(p->u.sLine.azCol);
ae7e3f0… drh 3016 }
4f76459… drh 3017 break;
4f76459… drh 3018 }
4f76459… drh 3019 case QRF_STYLE_Stats:
7b0960d… drh 3020 case QRF_STYLE_StatsEst: {
7b0960d… drh 3021 i64 nCycle = 0;
7b0960d… drh 3022 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
7b0960d… drh 3023 sqlite3_stmt_scanstatus_v2(p->pStmt, -1, SQLITE_SCANSTAT_NCYCLE,
7b0960d… drh 3024 SQLITE_SCANSTAT_COMPLEX, (void*)&nCycle);
7b0960d… drh 3025 #endif
7b0960d… drh 3026 qrfEqpRender(p, nCycle);
7b0960d… drh 3027 break;
7b0960d… drh 3028 }
4f76459… drh 3029 case QRF_STYLE_Eqp: {
4f76459… drh 3030 qrfEqpRender(p, 0);
4f76459… drh 3031 break;
4f76459… drh 3032 }
4f76459… drh 3033 }
17f9878… drh 3034 qrfWrite(p);
2b2530d… drh 3035 qrfStrErr(p, p->pOut);
4f76459… drh 3036 if( p->spec.pzOutput ){
4f76459… drh 3037 if( p->spec.pzOutput[0] ){
4f76459… drh 3038 sqlite3_int64 n, sz;
4f76459… drh 3039 char *zCombined;
4f76459… drh 3040 sz = strlen(p->spec.pzOutput[0]);
4f76459… drh 3041 n = sqlite3_str_length(p->pOut);
ba8756a… drh 3042 zCombined = sqlite3_realloc64(p->spec.pzOutput[0], sz+n+1);
4f76459… drh 3043 if( zCombined==0 ){
4f76459… drh 3044 sqlite3_free(p->spec.pzOutput[0]);
4f76459… drh 3045 p->spec.pzOutput[0] = 0;
4f76459… drh 3046 qrfOom(p);
4f76459… drh 3047 }else{
4f76459… drh 3048 p->spec.pzOutput[0] = zCombined;
4f76459… drh 3049 memcpy(zCombined+sz, sqlite3_str_value(p->pOut), n+1);
4f76459… drh 3050 }
4f76459… drh 3051 sqlite3_free(sqlite3_str_finish(p->pOut));
4f76459… drh 3052 }else{
4f76459… drh 3053 p->spec.pzOutput[0] = sqlite3_str_finish(p->pOut);
4f76459… drh 3054 }
4f76459… drh 3055 }else if( p->pOut ){
4f76459… drh 3056 sqlite3_free(sqlite3_str_finish(p->pOut));
4f76459… drh 3057 }
4f76459… drh 3058 if( p->expMode>0 ){
4f76459… drh 3059 sqlite3_stmt_explain(p->pStmt, p->expMode-1);
4f76459… drh 3060 }
4f76459… drh 3061 if( p->actualWidth ){
4f76459… drh 3062 sqlite3_free(p->actualWidth);
4f76459… drh 3063 }
4f76459… drh 3064 if( p->pJTrans ){
4f76459… drh 3065 sqlite3 *db = sqlite3_db_handle(p->pJTrans);
4f76459… drh 3066 sqlite3_finalize(p->pJTrans);
4f76459… drh 3067 sqlite3_close(db);
4f76459… drh 3068 }
4f76459… drh 3069 }
4f76459… drh 3070
4f76459… drh 3071 /*
4f76459… drh 3072 ** Run the prepared statement pStmt and format the results according
4f76459… drh 3073 ** to the specification provided in pSpec. Return an error code.
4f76459… drh 3074 ** If pzErr is not NULL and if an error occurs, write an error message
4f76459… drh 3075 ** into *pzErr.
4f76459… drh 3076 */
4f76459… drh 3077 int sqlite3_format_query_result(
4f76459… drh 3078 sqlite3_stmt *pStmt, /* Statement to evaluate */
4f76459… drh 3079 const sqlite3_qrf_spec *pSpec, /* Format specification */
4f76459… drh 3080 char **pzErr /* Write error message here */
4f76459… drh 3081 ){
4f76459… drh 3082 Qrf qrf; /* The new Qrf being created */
4f76459… drh 3083
4f76459… drh 3084 if( pStmt==0 ) return SQLITE_OK; /* No-op */
4f76459… drh 3085 if( pSpec==0 ) return SQLITE_MISUSE;
4f76459… drh 3086 qrfInitialize(&qrf, pStmt, pSpec, pzErr);
4f76459… drh 3087 switch( qrf.spec.eStyle ){
4f76459… drh 3088 case QRF_STYLE_Box:
4f76459… drh 3089 case QRF_STYLE_Column:
4f76459… drh 3090 case QRF_STYLE_Markdown:
4f76459… drh 3091 case QRF_STYLE_Table: {
4f76459… drh 3092 /* Columnar modes require that the entire query be evaluated and the
4f76459… drh 3093 ** results stored in memory, so that we can compute column widths */
4f76459… drh 3094 qrfColumnar(&qrf);
4f76459… drh 3095 break;
4f76459… drh 3096 }
4f76459… drh 3097 case QRF_STYLE_Explain: {
4f76459… drh 3098 qrfExplain(&qrf);
4f76459… drh 3099 break;
4f76459… drh 3100 }
4f76459… drh 3101 case QRF_STYLE_StatsVm: {
4f76459… drh 3102 qrfScanStatusVm(&qrf);
4f76459… drh 3103 break;
4f76459… drh 3104 }
4f76459… drh 3105 case QRF_STYLE_Stats:
4f76459… drh 3106 case QRF_STYLE_StatsEst: {
4f76459… drh 3107 qrfEqpStats(&qrf);
4f76459… drh 3108 break;
4f76459… drh 3109 }
4f76459… drh 3110 default: {
4f76459… drh 3111 /* Non-columnar modes where the output can occur after each row
4f76459… drh 3112 ** of result is received */
4f76459… drh 3113 while( qrf.iErr==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
4f76459… drh 3114 qrfOneSimpleRow(&qrf);
4f76459… drh 3115 }
4f76459… drh 3116 break;
4f76459… drh 3117 }
4f76459… drh 3118 }
4f76459… drh 3119 qrfResetStmt(&qrf);
4f76459… drh 3120 qrfFinalize(&qrf);
4f76459… drh 3121 return qrf.iErr;
4f76459… drh 3122 }
4f76459… drh 3123
4f76459… drh 3124 /************************* End ext/qrf/qrf.c ********************/
4f76459… drh 3125
4f76459… drh 3126 /* Use console I/O package as a direct INCLUDE. */
4f76459… drh 3127 #define SQLITE_INTERNAL_LINKAGE static
4f76459… drh 3128
4f76459… drh 3129 #ifdef SQLITE_SHELL_FIDDLE
4f76459… drh 3130 /* Deselect most features from the console I/O package for Fiddle. */
4f76459… drh 3131 # define SQLITE_CIO_NO_REDIRECT
4f76459… drh 3132 # define SQLITE_CIO_NO_CLASSIFY
4f76459… drh 3133 # define SQLITE_CIO_NO_TRANSLATE
4f76459… drh 3134 # define SQLITE_CIO_NO_SETMODE
4f76459… drh 3135 # define SQLITE_CIO_NO_FLUSH
4f76459… drh 3136 #endif
4f76459… drh 3137 /************************* Begin ext/misc/windirent.h ******************/
4f76459… drh 3138 /************************* End ext/misc/windirent.h ********************/
4f76459… drh 3139 /************************* Begin ext/misc/memtrace.c ******************/
4f76459… drh 3140 /************************* End ext/misc/memtrace.c ********************/
4f76459… drh 3141 /************************* Begin ext/misc/pcachetrace.c ******************/
4f76459… drh 3142 /************************* End ext/misc/pcachetrace.c ********************/
4f76459… drh 3143 /************************* Begin ext/misc/shathree.c ******************/
4f76459… drh 3144 /************************* End ext/misc/shathree.c ********************/
4f76459… drh 3145 /************************* Begin ext/misc/sha1.c ******************/
f4b3b59… drh 3146 ** Two SQL functions: sha1(X) and sha1b(X).
f4b3b59… drh 3147 ** sha1(X) returns a lower-case hexadecimal rendering of the SHA1 hash
f4b3b59… drh 3148 ** of the argument X. If X is a BLOB, it is hashed as is. For all other
f4b3b59… drh 3149 ** is hashed without the trailing 0x00 terminator. The hash of a NULL
f4b3b59… drh 3150 **
f4b3b59… drh 3151 ** sha1b(X) is the same except that it returns a 20-byte BLOB containing
f4b3b59… drh 3152 ** the binary hash instead of a hexadecimal string.
17f9878… drh 3153 const unsigned char *pData;
17f9878… drh 3154 pData = (const unsigned char*)sqlite3_value_blob(argv[0]);
17f9878… drh 3155 pData = (const unsigned char*)sqlite3_value_text(argv[0]);
17f9878… drh 3156 if( pData==0 ) return;
17f9878… drh 3157 hash_step(&cx, pData, nByte);
f4b3b59… drh 3158 /* sha1b() - binary result */
f4b3b59… drh 3159 /* sha1() - hexadecimal text result */
f4b3b59… drh 3160 sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
17f9878… drh 3161 if( z==0 ) z = "";
4f76459… drh 3162 /************************* End ext/misc/sha1.c ********************/
4f76459… drh 3163 /************************* Begin ext/misc/uint.c ******************/
4f76459… drh 3164 /************************* End ext/misc/uint.c ********************/
4f76459… drh 3165 /************************* Begin ext/misc/decimal.c ******************/
4f76459… drh 3166 #endif
4f76459… drh 3167
17f9878… drh 3168 #ifndef SQLITE_DECIMAL_MAX_DIGIT
17f9878… drh 3169 # define SQLITE_DECIMAL_MAX_DIGIT 10000000
17f9878… drh 3170 #endif
17f9878… drh 3171
17f9878… drh 3172 if( zIn==0 ) goto new_from_text_failed;
0201a1e… drh 3173 p = sqlite3_malloc64( sizeof(*p) );
17f9878… drh 3174 signed char *a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit
3c639f7… drh 3175 + (sqlite3_int64)iExp + 1 );
17f9878… drh 3176 if( a==0 ) goto new_from_text_failed;
17f9878… drh 3177 p->a = a;
17f9878… drh 3178 signed char *a = sqlite3_realloc64(p->a, (sqlite3_int64)p->nDigit
3c639f7… drh 3179 + (sqlite3_int64)iExp + 1 );
17f9878… drh 3180 if( a==0 ) goto new_from_text_failed;
17f9878… drh 3181 p->a = a;
17f9878… drh 3182 if( p->nDigit>SQLITE_DECIMAL_MAX_DIGIT ) goto new_from_text_failed;
3c639f7… drh 3183 z = sqlite3_malloc64( (sqlite3_int64)p->nDigit+4 );
b8ab8b3… drh 3184 ** Round a decimal value to N significant digits. N must be positive.
b8ab8b3… drh 3185 */
b8ab8b3… drh 3186 static void decimal_round(Decimal *p, int N){
b8ab8b3… drh 3187 int i;
b8ab8b3… drh 3188 int nZero;
b8ab8b3… drh 3189 if( N<1 ) return;
17f9878… drh 3190 if( p==0 ) return;
17f9878… drh 3191 if( p->nDigit<=N ) return;
b8ab8b3… drh 3192 for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){}
b8ab8b3… drh 3193 N += nZero;
b8ab8b3… drh 3194 if( p->nDigit<=N ) return;
b8ab8b3… drh 3195 if( p->a[N]>4 ){
b8ab8b3… drh 3196 p->a[N-1]++;
b8ab8b3… drh 3197 for(i=N-1; i>0 && p->a[i]>9; i--){
b8ab8b3… drh 3198 p->a[i] = 0;
b8ab8b3… drh 3199 p->a[i-1]++;
b8ab8b3… drh 3200 }
b8ab8b3… drh 3201 if( p->a[0]>9 ){
b8ab8b3… drh 3202 p->a[0] = 1;
b8ab8b3… drh 3203 p->nFrac--;
b8ab8b3… drh 3204 }
b8ab8b3… drh 3205 }
b8ab8b3… drh 3206 memset(&p->a[N], 0, p->nDigit - N);
b8ab8b3… drh 3207 }
b8ab8b3… drh 3208
b8ab8b3… drh 3209 /*
b8ab8b3… drh 3210 static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p, int N){
b8ab8b3… drh 3211 if( N<1 ) N = 0;
b8ab8b3… drh 3212 for(nDigit=p->nDigit; nDigit>N && p->a[nDigit-1]==0; nDigit--){}
3c639f7… drh 3213 z = sqlite3_malloc64( (sqlite3_int64)nDigit+20 );
17f9878… drh 3214 signed char *a;
17f9878… drh 3215 if( nDigit+1>SQLITE_DECIMAL_MAX_DIGIT ){ p->oom = 1; return; }
17f9878… drh 3216 a = sqlite3_realloc64(p->a, nDigit+1);
17f9878… drh 3217 if( a==0 ){
17f9878… drh 3218 p->a = a;
17f9878… drh 3219 sqlite3_int64 sumDigit;
17f9878… drh 3220 sumDigit = pA->nDigit;
17f9878… drh 3221 sumDigit += pB->nDigit;
17f9878… drh 3222 sumDigit += 2;
17f9878… drh 3223 if( sumDigit>SQLITE_DECIMAL_MAX_DIGIT ){ pA->oom = 1; return; }
17f9878… drh 3224 acc = sqlite3_malloc64( sumDigit );
b8ab8b3… drh 3225 int N;
b8ab8b3… drh 3226 if( argc==2 ){
b8ab8b3… drh 3227 N = sqlite3_value_int(argv[1]);
b8ab8b3… drh 3228 if( N>0 ) decimal_round(p, N);
b8ab8b3… drh 3229 }else{
b8ab8b3… drh 3230 N = 0;
b8ab8b3… drh 3231 }
b8ab8b3… drh 3232 decimal_result_sci(context, p, N);
0201a1e… drh 3233 p->a = sqlite3_malloc64(2);
b8ab8b3… drh 3234 decimal_result_sci(context, pA, 0);
b8ab8b3… drh 3235 { "decimal", 2, 0, decimalFunc },
b8ab8b3… drh 3236 { "decimal_exp", 2, 1, decimalFunc },
4f76459… drh 3237 /************************* End ext/misc/decimal.c ********************/
4f76459… drh 3238 /************************* Begin ext/misc/base64.c ******************/
70539ee… drh 3239 sqlite3_int64 nb;
70539ee… drh 3240 sqlite3_int64 nv = sqlite3_value_bytes(av[0]);
0201a1e… drh 3241 cBuf = sqlite3_malloc64(nc);
0201a1e… drh 3242 bBuf = sqlite3_malloc64(nb);
17f9878… drh 3243 int sqlite3_base64_init
4f76459… drh 3244 /************************* End ext/misc/base64.c ********************/
4f76459… drh 3245 /************************* Begin ext/misc/base85.c ******************/
17f9878… drh 3246 #ifndef OMIT_BASE85_CHECKER
17f9878… drh 3247 #endif
70539ee… drh 3248 sqlite3_int64 nb, nc, nv = sqlite3_value_bytes(av[0]);
0201a1e… drh 3249 cBuf = sqlite3_malloc64(nc);
0201a1e… drh 3250 bBuf = sqlite3_malloc64(nb);
17f9878… drh 3251 int sqlite3_base85_init
17f9878… drh 3252 #ifndef OMIT_BASE85_CHECKER
17f9878… drh 3253 #endif
17f9878… drh 3254 #ifndef OMIT_BASE85_CHECKER
17f9878… drh 3255 #endif
4f76459… drh 3256 /************************* End ext/misc/base85.c ********************/
4f76459… drh 3257 /************************* Begin ext/misc/ieee754.c ******************/
b9ecacf… drh 3258 if( m<(-9223372036854775807LL) ) return;
b8ab8b3… drh 3259 ** Functions to convert between 64-bit integers and floats.
b8ab8b3… drh 3260 **
b8ab8b3… drh 3261 ** The bit patterns are copied. The numeric values are different.
b8ab8b3… drh 3262 */
b8ab8b3… drh 3263 static void ieee754func_from_int(
b8ab8b3… drh 3264 sqlite3_context *context,
b8ab8b3… drh 3265 int argc,
b8ab8b3… drh 3266 sqlite3_value **argv
b8ab8b3… drh 3267 ){
b8ab8b3… drh 3268 UNUSED_PARAMETER(argc);
b8ab8b3… drh 3269 if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){
b8ab8b3… drh 3270 double r;
b8ab8b3… drh 3271 sqlite3_int64 v = sqlite3_value_int64(argv[0]);
b8ab8b3… drh 3272 memcpy(&r, &v, sizeof(r));
b8ab8b3… drh 3273 sqlite3_result_double(context, r);
b8ab8b3… drh 3274 }
b8ab8b3… drh 3275 }
b8ab8b3… drh 3276 static void ieee754func_to_int(
b8ab8b3… drh 3277 sqlite3_context *context,
b8ab8b3… drh 3278 int argc,
b8ab8b3… drh 3279 sqlite3_value **argv
b8ab8b3… drh 3280 ){
b8ab8b3… drh 3281 UNUSED_PARAMETER(argc);
b8ab8b3… drh 3282 if( sqlite3_value_type(argv[0])==SQLITE_FLOAT ){
b8ab8b3… drh 3283 double r = sqlite3_value_double(argv[0]);
b8ab8b3… drh 3284 sqlite3_uint64 v;
b8ab8b3… drh 3285 memcpy(&v, &r, sizeof(v));
b8ab8b3… drh 3286 sqlite3_result_int64(context, v);
b8ab8b3… drh 3287 }
b8ab8b3… drh 3288 }
b8ab8b3… drh 3289
b8ab8b3… drh 3290 /*
b8ab8b3… drh 3291 { "ieee754_to_int", 1, 0, ieee754func_to_int },
b8ab8b3… drh 3292 { "ieee754_from_int", 1, 0, ieee754func_from_int },
4f76459… drh 3293 /************************* End ext/misc/ieee754.c ********************/
4f76459… drh 3294 /************************* Begin ext/misc/series.c ******************/
0201a1e… drh 3295 pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) );
0201a1e… drh 3296 pCur = sqlite3_malloc64( sizeof(*pCur) );
3c639f7… drh 3297
3c639f7… drh 3298 #if defined(SQLITE_ENABLE_MATH_FUNCTIONS) || defined(_WIN32)
3c639f7… drh 3299 /*
3c639f7… drh 3300 ** Case 1 (the most common case):
3c639f7… drh 3301 ** The standard math library is available so use ceil() and floor() from there.
3c639f7… drh 3302 */
3c639f7… drh 3303 static double seriesCeil(double r){ return ceil(r); }
3c639f7… drh 3304 static double seriesFloor(double r){ return floor(r); }
3c639f7… drh 3305 #elif defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
3c639f7… drh 3306 /*
3c639f7… drh 3307 ** Case 2 (2nd most common): Use GCC/Clang builtins
3c639f7… drh 3308 */
3c639f7… drh 3309 static double seriesCeil(double r){ return __builtin_ceil(r); }
3c639f7… drh 3310 static double seriesFloor(double r){ return __builtin_floor(r); }
3c639f7… drh 3311 #else
3c639f7… drh 3312 /*
3c639f7… drh 3313 ** Case 3 (rarely happens): Use home-grown ceil() and floor() routines.
3c639f7… drh 3314 */
3c639f7… drh 3315 static double seriesCeil(double r){
3c639f7… drh 3316 sqlite3_int64 x;
3c639f7… drh 3317 if( r!=r ) return r;
3c639f7… drh 3318 if( r<=(-4503599627370496.0) ) return r;
3c639f7… drh 3319 if( r>=(+4503599627370496.0) ) return r;
3c639f7… drh 3320 x = (sqlite3_int64)r;
3c639f7… drh 3321 if( r==(double)x ) return r;
3c639f7… drh 3322 if( r>(double)x ) x++;
3c639f7… drh 3323 return (double)x;
3c639f7… drh 3324 }
3c639f7… drh 3325 static double seriesFloor(double r){
3c639f7… drh 3326 sqlite3_int64 x;
3c639f7… drh 3327 if( r!=r ) return r;
3c639f7… drh 3328 if( r<=(-4503599627370496.0) ) return r;
3c639f7… drh 3329 if( r>=(+4503599627370496.0) ) return r;
3c639f7… drh 3330 x = (sqlite3_int64)r;
3c639f7… drh 3331 if( r==(double)x ) return r;
3c639f7… drh 3332 if( r<(double)x ) x--;
3c639f7… drh 3333 return (double)x;
3c639f7… drh 3334 }
3c639f7… drh 3335 #endif
3c639f7… drh 3336 if( r==seriesCeil(r)
3c639f7… drh 3337 }else if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){
3c639f7… drh 3338 iMin = (sqlite3_int64)seriesCeil(r+1.0);
3c639f7… drh 3339 iMin = (sqlite3_int64)seriesCeil(r);
3c639f7… drh 3340 }else if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){
3c639f7… drh 3341 iMax = (sqlite3_int64)seriesFloor(r);
3c639f7… drh 3342 if( iLimit>=0 && seriesSteps(pCur) > (sqlite3_uint64)iLimit ){
4f76459… drh 3343 /************************* End ext/misc/series.c ********************/
4f76459… drh 3344 /************************* Begin ext/misc/regexp.c ******************/
2b2530d… drh 3345 ** \c Character c where c is one of \{}()[]|*+?-.
2b2530d… drh 3346 static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]-";
92871e0… drh 3347 ** Version of re_free() that accepts a pointer of type (void*). Required
92871e0… drh 3348 ** to satisfy sanitizers when the re_free() function is called via a
92871e0… drh 3349 ** function pointer.
92871e0… drh 3350 */
92871e0… drh 3351 static void re_free_voidptr(void *p){
92871e0… drh 3352 re_free((ReCompiled*)p);
92871e0… drh 3353 }
92871e0… drh 3354
92871e0… drh 3355 /*
0201a1e… drh 3356 pRe = sqlite3_malloc64( sizeof(*pRe) );
5f65ed5… drh 3357 ** The value of LIMIT_MAX_PATTERN_LENGTH.
5f65ed5… drh 3358 return sqlite3_limit(db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH,-1);
5f65ed5… drh 3359 }
5f65ed5… drh 3360
5f65ed5… drh 3361 /*
5f65ed5… drh 3362 ** Maximum NFA size given a maximum pattern length.
5f65ed5… drh 3363 */
5f65ed5… drh 3364 static int re_maxnfa(int mxlen){
5f65ed5… drh 3365 return 75+mxlen/2;
5f65ed5… drh 3366 int mxLen = re_maxlen(context);
5f65ed5… drh 3367 int nPattern;
5f65ed5… drh 3368 nPattern = sqlite3_value_bytes(argv[0]);
5f65ed5… drh 3369 if( nPattern>mxLen ){
5f65ed5… drh 3370 zErr = "REGEXP pattern too big";
5f65ed5… drh 3371 }else{
5f65ed5… drh 3372 zErr = re_compile(&pRe, zPattern, re_maxnfa(mxLen),
5f65ed5… drh 3373 sqlite3_user_data(context)!=0);
5f65ed5… drh 3374 }
92871e0… drh 3375 sqlite3_set_auxdata(context, 0, pRe, re_free_voidptr);
17f9878… drh 3376 (void)argc;
5f65ed5… drh 3377 zErr = re_compile(&pRe, zPattern, re_maxnfa(re_maxlen(context)),
4f76459… drh 3378 /************************* End ext/misc/regexp.c ********************/
4f76459… drh 3379 /************************* Begin ext/misc/fileio.c ******************/
b8ab8b3… drh 3380 # include <limits.h>
b8ab8b3… drh 3381 # include <stdlib.h>
b8ab8b3… drh 3382 extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
b8ab8b3… drh 3383 extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
b8ab8b3… drh 3384 wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath);
b8ab8b3… drh 3385 wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath);
b8ab8b3… drh 3386 #endif /* _WIN32 */
b8ab8b3… drh 3387 wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath);
b8ab8b3… drh 3388 if( rc==0 ){
b8ab8b3… drh 3389 HANDLE hFindFile;
b8ab8b3… drh 3390 WIN32_FIND_DATAW fd;
b8ab8b3… drh 3391 memset(&fd, 0, sizeof(WIN32_FIND_DATAW));
b8ab8b3… drh 3392 hFindFile = FindFirstFileW(b1, &fd);
b8ab8b3… drh 3393 if( hFindFile!=NULL ){
b8ab8b3… drh 3394 pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime);
b8ab8b3… drh 3395 pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime);
b8ab8b3… drh 3396 pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime);
b8ab8b3… drh 3397 FindClose(hFindFile);
b8ab8b3… drh 3398 }
b8ab8b3… drh 3399 }
709b566… drh 3400 sqlite3_free(b1);
0201a1e… drh 3401 pNew = (fsdir_tab*)sqlite3_malloc64( sizeof(*pNew) );
0201a1e… drh 3402 pCur = sqlite3_malloc64( sizeof(*pCur) );
92871e0… drh 3403 fsdirSetErrmsg(pCur, "cannot read directory: %s", pLvl->zDir);
b8ab8b3… drh 3404 /*
b8ab8b3… drh 3405 ** This version of realpath() works on any system. The string
b8ab8b3… drh 3406 ** returned is held in memory allocated using sqlite3_malloc64().
b8ab8b3… drh 3407 ** The caller is responsible for calling sqlite3_free().
b8ab8b3… drh 3408 */
b8ab8b3… drh 3409 static char *portable_realpath(const char *zPath){
b8ab8b3… drh 3410 #if !defined(_WIN32) /* BEGIN unix */
b8ab8b3… drh 3411
b8ab8b3… drh 3412 char *zOut = 0; /* Result */
b8ab8b3… drh 3413 char *z; /* Temporary buffer */
b8ab8b3… drh 3414 #if defined(PATH_MAX)
b8ab8b3… drh 3415 char zBuf[PATH_MAX+1]; /* Space for the temporary buffer */
b8ab8b3… drh 3416 #endif
b8ab8b3… drh 3417
b8ab8b3… drh 3418 if( zPath==0 ) return 0;
b8ab8b3… drh 3419 #if defined(PATH_MAX)
b8ab8b3… drh 3420 z = realpath(zPath, zBuf);
b8ab8b3… drh 3421 if( z ){
b8ab8b3… drh 3422 zOut = sqlite3_mprintf("%s", zBuf);
b8ab8b3… drh 3423 }
b8ab8b3… drh 3424 #endif /* defined(PATH_MAX) */
b8ab8b3… drh 3425 if( zOut==0 ){
b8ab8b3… drh 3426 /* Try POSIX.1-2008 malloc behavior */
b8ab8b3… drh 3427 z = realpath(zPath, NULL);
b8ab8b3… drh 3428 if( z ){
b8ab8b3… drh 3429 zOut = sqlite3_mprintf("%s", z);
b8ab8b3… drh 3430 free(z);
b8ab8b3… drh 3431 }
b8ab8b3… drh 3432 }
b8ab8b3… drh 3433 return zOut;
b8ab8b3… drh 3434
b8ab8b3… drh 3435 #else /* End UNIX, Begin WINDOWS */
b8ab8b3… drh 3436
b8ab8b3… drh 3437 wchar_t *zPath16; /* UTF16 translation of zPath */
b8ab8b3… drh 3438 char *zOut = 0; /* Result */
b8ab8b3… drh 3439 wchar_t *z = 0; /* Temporary buffer */
b8ab8b3… drh 3440
b8ab8b3… drh 3441 if( zPath==0 ) return 0;
b8ab8b3… drh 3442
b8ab8b3… drh 3443 zPath16 = sqlite3_win32_utf8_to_unicode(zPath);
b8ab8b3… drh 3444 if( zPath16==0 ) return 0;
b8ab8b3… drh 3445 z = _wfullpath(NULL, zPath16, 0);
b8ab8b3… drh 3446 sqlite3_free(zPath16);
b8ab8b3… drh 3447 if( z ){
b8ab8b3… drh 3448 zOut = sqlite3_win32_unicode_to_utf8(z);
b8ab8b3… drh 3449 free(z);
b8ab8b3… drh 3450 }
b8ab8b3… drh 3451 return zOut;
b8ab8b3… drh 3452
b8ab8b3… drh 3453 #endif /* End WINDOWS, Begin common code */
b8ab8b3… drh 3454 }
b8ab8b3… drh 3455
b8ab8b3… drh 3456 /*
b8ab8b3… drh 3457 ** SQL function: realpath(X)
b8ab8b3… drh 3458 **
b8ab8b3… drh 3459 ** Try to convert file or pathname X into its real, absolute pathname.
b8ab8b3… drh 3460 ** Return NULL if unable.
b8ab8b3… drh 3461 **
b8ab8b3… drh 3462 ** The file or directory X is not required to exist. The answer is formed
b8ab8b3… drh 3463 ** by calling system realpath() on the prefix of X that does exist and
b8ab8b3… drh 3464 ** appending the tail of X that does not (yet) exist.
b8ab8b3… drh 3465 */
b8ab8b3… drh 3466 static void realpathFunc(
b8ab8b3… drh 3467 sqlite3_context *context,
b8ab8b3… drh 3468 int argc,
b8ab8b3… drh 3469 sqlite3_value **argv
b8ab8b3… drh 3470 ){
b8ab8b3… drh 3471 const char *zPath; /* Original input path */
b8ab8b3… drh 3472 char *zCopy; /* An editable copy of zPath */
b8ab8b3… drh 3473 char *zOut; /* The result */
b8ab8b3… drh 3474 char cSep = 0; /* Separator turned into \000 */
b8ab8b3… drh 3475 size_t len; /* Prefix length before cSep */
b8ab8b3… drh 3476 #ifdef _WIN32
b8ab8b3… drh 3477 const int isWin = 1;
b8ab8b3… drh 3478 #else
b8ab8b3… drh 3479 const int isWin = 0;
b8ab8b3… drh 3480 #endif
b8ab8b3… drh 3481
b8ab8b3… drh 3482 (void)argc;
b8ab8b3… drh 3483 zPath = (const char*)sqlite3_value_text(argv[0]);
b8ab8b3… drh 3484 if( zPath==0 ) return;
b8ab8b3… drh 3485 if( zPath[0]==0 ) zPath = ".";
b8ab8b3… drh 3486 zCopy = sqlite3_mprintf("%s",zPath);
b8ab8b3… drh 3487 len = strlen(zCopy);
b8ab8b3… drh 3488 while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){
b8ab8b3… drh 3489 len--;
b8ab8b3… drh 3490 }
b8ab8b3… drh 3491 zCopy[len] = 0;
b8ab8b3… drh 3492 while( 1 /*exit-by-break*/ ){
b8ab8b3… drh 3493 zOut = portable_realpath(zCopy);
b8ab8b3… drh 3494 zCopy[len] = cSep;
b8ab8b3… drh 3495 if( zOut ){
b8ab8b3… drh 3496 if( cSep ){
b8ab8b3… drh 3497 zOut = sqlite3_mprintf("%z%s",zOut,&zCopy[len]);
b8ab8b3… drh 3498 }
b8ab8b3… drh 3499 break;
b8ab8b3… drh 3500 }else{
b8ab8b3… drh 3501 size_t i = len-1;
b8ab8b3… drh 3502 while( i>0 ){
b8ab8b3… drh 3503 if( zCopy[i]=='/' || (isWin && zCopy[i]=='\\') ) break;
b8ab8b3… drh 3504 i--;
b8ab8b3… drh 3505 }
b8ab8b3… drh 3506 if( i<=0 ){
b8ab8b3… drh 3507 if( zCopy[0]=='/' ){
b8ab8b3… drh 3508 zOut = zCopy;
b8ab8b3… drh 3509 zCopy = 0;
b8ab8b3… drh 3510 }else if( (zOut = portable_realpath("."))!=0 ){
b8ab8b3… drh 3511 zOut = sqlite3_mprintf("%z/%s", zOut, zCopy);
b8ab8b3… drh 3512 }
b8ab8b3… drh 3513 break;
b8ab8b3… drh 3514 }
b8ab8b3… drh 3515 cSep = zCopy[i];
b8ab8b3… drh 3516 zCopy[i] = 0;
b8ab8b3… drh 3517 len = i;
b8ab8b3… drh 3518 }
b8ab8b3… drh 3519 }
b8ab8b3… drh 3520 sqlite3_free(zCopy);
b8ab8b3… drh 3521 if( zOut ){
b8ab8b3… drh 3522 /* Simplify any "/./" or "/../" that might have snuck into the
b8ab8b3… drh 3523 ** pathname due to appending of zCopy. We only have to consider
b8ab8b3… drh 3524 ** unix "/" separators, because the _wfilepath() system call on
b8ab8b3… drh 3525 ** Windows will have already done this simplification for us. */
b8ab8b3… drh 3526 size_t i, j, n;
b8ab8b3… drh 3527 n = strlen(zOut);
b8ab8b3… drh 3528 for(i=j=0; i<n; i++){
b8ab8b3… drh 3529 if( zOut[i]=='/' ){
b8ab8b3… drh 3530 if( zOut[i+1]=='/' ) continue;
b8ab8b3… drh 3531 if( zOut[i+1]=='.' && i+2<n && zOut[i+2]=='/' ){
b8ab8b3… drh 3532 i += 1;
b8ab8b3… drh 3533 continue;
b8ab8b3… drh 3534 }
b8ab8b3… drh 3535 if( zOut[i+1]=='.' && i+3<n && zOut[i+2]=='.' && zOut[i+3]=='/' ){
b8ab8b3… drh 3536 while( j>0 && zOut[j-1]!='/' ){ j--; }
b8ab8b3… drh 3537 if( j>0 ){ j--; }
b8ab8b3… drh 3538 i += 2;
b8ab8b3… drh 3539 continue;
b8ab8b3… drh 3540 }
b8ab8b3… drh 3541 }
b8ab8b3… drh 3542 zOut[j++] = zOut[i];
b8ab8b3… drh 3543 }
b8ab8b3… drh 3544 zOut[j] = 0;
b8ab8b3… drh 3545
b8ab8b3… drh 3546 /* Return the result */
b8ab8b3… drh 3547 sqlite3_result_text(context, zOut, -1, sqlite3_free);
b8ab8b3… drh 3548 }
b8ab8b3… drh 3549 }
b8ab8b3… drh 3550
b8ab8b3… drh 3551
b8ab8b3… drh 3552 }
b8ab8b3… drh 3553 if( rc==SQLITE_OK ){
b8ab8b3… drh 3554 rc = sqlite3_create_function(db, "realpath", 1,
b8ab8b3… drh 3555 SQLITE_UTF8, 0,
b8ab8b3… drh 3556 realpathFunc, 0, 0);
4f76459… drh 3557 }
4f76459… drh 3558 /************************* End ext/misc/fileio.c ********************/
4f76459… drh 3559 /************************* Begin ext/misc/completion.c ******************/
0201a1e… drh 3560 pNew = sqlite3_malloc64( sizeof(*pNew) );
0201a1e… drh 3561 pCur = sqlite3_malloc64( sizeof(*pCur) );
17f9878… drh 3562 int rc;
17f9878… drh 3563 sqlite3_str* pStr = sqlite3_str_new(pCur->db);
17f9878… drh 3564 sqlite3_str_appendf(pStr,
17f9878… drh 3565 "%s"
17f9878… drh 3566 zSep, zDb
17f9878… drh 3567 rc = sqlite3_finalize(pS2);
17f9878… drh 3568 zSql = sqlite3_str_finish(pStr);
17f9878… drh 3569 if( zSql==0 ) return SQLITE_NOMEM;
17f9878… drh 3570 if( rc==SQLITE_OK ){
17f9878… drh 3571 sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
17f9878… drh 3572 }
17f9878… drh 3573 if( rc ) return rc;
17f9878… drh 3574 sqlite3_str *pStr = sqlite3_str_new(pCur->db);
17f9878… drh 3575 sqlite3_str_appendf(pStr,
17f9878… drh 3576 "%s"
17f9878… drh 3577 zSep, zDb, zDb
17f9878… drh 3578 rc = sqlite3_finalize(pS2);
17f9878… drh 3579 zSql = sqlite3_str_finish(pStr);
17f9878… drh 3580 if( zSql==0 ) return SQLITE_NOMEM;
17f9878… drh 3581 if( rc==SQLITE_OK ){
17f9878… drh 3582 sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
17f9878… drh 3583 }
17f9878… drh 3584 if( rc ) return rc;
17f9878… drh 3585 rc = sqlite3_finalize(pCur->pStmt);
17f9878… drh 3586 if( rc ) return rc;
4f76459… drh 3587 /************************* End ext/misc/completion.c ********************/
4f76459… drh 3588 /************************* Begin ext/misc/appendvfs.c ******************/
4f76459… drh 3589 /************************* End ext/misc/appendvfs.c ********************/
4f76459… drh 3590 /************************* Begin ext/misc/zipfile.c ******************/
13c221a… drh 3591 pNew = (ZipfileTab*)sqlite3_malloc64((i64)nByte+nFile);
0201a1e… drh 3592 pCsr = sqlite3_malloc64(sizeof(*pCsr));
13c221a… drh 3593 i64 nRead, /* Number of bytes to read */
13c221a… drh 3594 n = fread(aRead, 1, (long)nRead, pFile);
13c221a… drh 3595 if( n!=(size_t)nRead ){
13c221a… drh 3596 sqlite3_free(*pzErrmsg);
13c221a… drh 3597 zipfileTableErr(pTab,"error in fwrite()");
ba8756a… drh 3598 /* Stop when there are less than 9 bytes left to scan in the buffer. This
ba8756a… drh 3599 ** is because the timestamp field requires exactly 9 bytes - 4 bytes of
ba8756a… drh 3600 ** header fields and 5 bytes of data. If there are less than 9 bytes
ba8756a… drh 3601 ** remaining, either it is some other field or else the extra data
ba8756a… drh 3602 ** is corrupt. Either way, do not process it. */
ba8756a… drh 3603 while( p+(2*sizeof(u16) + 1 + sizeof(u32))<=pEnd ){
13c221a… drh 3604 sqlite3_free(*pzErr);
13c221a… drh 3605 i64 nBlob, /* Size of aBlob[] in bytes */
13c221a… drh 3606 zipfileTableErr(pTab, "failed to read CDS at offset %lld", iOff);
12e4a0f… drh 3607 if( (iOff + ZIPFILE_CDS_FIXED_SZ + nFile + nExtra)>nBlob ){
13c221a… drh 3608 if( ((i64)pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ)>nBlob ){
d326547… drh 3609 memset(&lfh, 0, sizeof(lfh));
13c221a… drh 3610 pNew->iDataOff = (i64)pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
13c221a… drh 3611 zipfileTableErr(pTab, "failed to read LFH at offset %d",
13c221a… drh 3612 i64 iEof = (i64)pCsr->eocd.iOffset + (i64)pCsr->eocd.nSize;
0201a1e… drh 3613 u8 *aRes = sqlite3_malloc64(nOut);
ae7e3f0… drh 3614 sqlite3_result_blob(pCtx, aRes, (int)str.total_out, zipfileFree);
13c221a… drh 3615 i64 nBlob, /* Size of aBlob[] in bytes */
13c221a… drh 3616 i64 nRead; /* Bytes to read from file */
13c221a… drh 3617 i64 i;
13c221a… drh 3618 zipfileTableErr(pTab, "cannot find end of central directory record");
13c221a… drh 3619 static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, i64 nBlob){
13c221a… drh 3620 i64 nBlob = sqlite3_value_bytes(argv[0]);
0201a1e… drh 3621 pNew = sqlite3_malloc64(sizeof(ZipfileEntry));
13c221a… drh 3622 zipfileTableErr(pTab, "zipfile: missing filename");
13c221a… drh 3623 zipfileTableErr(pTab,
13c221a… drh 3624 "zipfile: failed to open file %s for writing", pTab->zFile
13c221a… drh 3625 );
13c221a… drh 3626 static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){
13c221a… drh 3627 i64 nByte;
4f76459… drh 3628 /************************* End ext/misc/zipfile.c ********************/
4f76459… drh 3629 /************************* Begin ext/misc/sqlar.c ******************/
0201a1e… drh 3630 pOut = (Bytef*)sqlite3_malloc64(nOut);
17f9878… drh 3631 sz = sqlite3_value_int64(argv[1]);
0201a1e… drh 3632 Bytef *pOut = sqlite3_malloc64(sz);
4f76459… drh 3633 /************************* End ext/misc/sqlar.c ********************/
4f76459… drh 3634 /************************* Begin ext/expert/sqlite3expert.h ******************/
4f76459… drh 3635 /************************* End ext/expert/sqlite3expert.h ********************/
4f76459… drh 3636 /************************* Begin ext/expert/sqlite3expert.c ******************/
92871e0… drh 3637 static void *idxMalloc(int *pRc, i64 nByte){
92871e0… drh 3638 pRet = sqlite3_malloc64(nByte);
92871e0… drh 3639 pEntry = idxMalloc(pRc, sizeof(IdxHashEntry) + (i64)nKey+1 + (i64)nVal+1);
92871e0… drh 3640 i64 n = STRLEN(zIn);
92871e0… drh 3641 char *zRet = sqlite3_malloc64(n);
92871e0… drh 3642 i64 iOut = 0;
92871e0… drh 3643 i64 iIn = 0;
92871e0… drh 3644 i64 nByte;
92871e0… drh 3645 i64 nIn = zIn ? STRLEN(zIn) : 0;
92871e0… drh 3646 i64 nAppend = 0;
92871e0… drh 3647 zRet = (char*)sqlite3_malloc64(nIn + nAppend + 1);
92871e0… drh 3648 i64 nByte; /* Bytes of space allocated at z */
92871e0… drh 3649 i64 n; /* Size of buffer z */
92871e0… drh 3650 assert( pSlot->n <= 0x7fffffff );
92871e0… drh 3651 sqlite3_result_blob(pCtx, pSlot->z, (int)pSlot->n, SQLITE_TRANSIENT);
92871e0… drh 3652 assert( pSlot->n <= 0x7fffffff );
92871e0… drh 3653 sqlite3_result_text(pCtx, pSlot->z, (int)pSlot->n, SQLITE_TRANSIENT);
92871e0… drh 3654 i64 nByte = sqlite3_value_bytes(argv[1]);
92871e0… drh 3655 char *zNew = (char*)sqlite3_realloc64(pSlot->z, nByte*2);
92871e0… drh 3656 i64 *aStat = 0;
92871e0… drh 3657 aStat = (i64*)idxMalloc(&rc, sizeof(i64)*(nCol+1));
92871e0… drh 3658 i64 s0 = aStat[0];
92871e0… drh 3659 zStat = sqlite3_mprintf("%lld", s0);
92871e0… drh 3660 zStat = idxAppendText(&rc, zStat, " %lld", (s0+aStat[i]/2) / aStat[i]);
92871e0… drh 3661 i64 nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax);
92871e0… drh 3662 pCtx->nSlot = (i64)nMax+1;
92871e0… drh 3663 i64 n = STRLEN(z);
4f76459… drh 3664 /************************* End ext/expert/sqlite3expert.c ********************/
4f76459… drh 3665 /************************* Begin ext/intck/sqlite3intck.h ******************/
4f76459… drh 3666 /************************* End ext/intck/sqlite3intck.h ********************/
4f76459… drh 3667 /************************* Begin ext/intck/sqlite3intck.c ******************/
4f76459… drh 3668 va_end(ap);
ba8756a… drh 3669 while( z[iRet] ){
4f76459… drh 3670 /************************* End ext/intck/sqlite3intck.c ********************/
4f76459… drh 3671 /************************* Begin ext/misc/stmtrand.c ******************/
0201a1e… drh 3672 p = sqlite3_malloc64( sizeof(*p) );
4f76459… drh 3673 /************************* End ext/misc/stmtrand.c ********************/
4f76459… drh 3674 /************************* Begin ext/misc/vfstrace.c ******************/
0201a1e… drh 3675 sqlite3_io_methods *pNew = sqlite3_malloc64( sizeof(*pNew) );
4f76459… drh 3676 /************************* End ext/misc/vfstrace.c ********************/
4f76459… drh 3677 /************************* Begin ext/recover/sqlite3recover.h ******************/
4f76459… drh 3678 /************************* End ext/recover/sqlite3recover.h ********************/
4f76459… drh 3679 /************************* Begin ext/recover/dbdata.c ******************/
4f76459… drh 3680 /************************* End ext/recover/dbdata.c ********************/
4f76459… drh 3681 /************************* Begin ext/recover/sqlite3recover.c ******************/
4f76459… drh 3682 /************************* End ext/recover/sqlite3recover.c ********************/
4f76459… drh 3683 /* All the parameters that determine how to render query results.
4f76459… drh 3684 */
4f76459… drh 3685 typedef struct Mode {
4f76459… drh 3686 u8 autoExplain; /* Automatically turn on .explain mode */
4f76459… drh 3687 u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to each SQL stmt */
4f76459… drh 3688 u8 autoEQPtrace; /* autoEQP is in trace mode */
4f76459… drh 3689 u8 scanstatsOn; /* True to display scan stats before each finalize */
4f76459… drh 3690 u8 bAutoScreenWidth; /* Using the TTY to determine screen width */
12e4a0f… drh 3691 u8 mFlags; /* MFLG_ECHO, MFLG_CRLF, etc. */
4f76459… drh 3692 u8 eMode; /* One of the MODE_ values */
4f76459… drh 3693 sqlite3_qrf_spec spec; /* Spec to be passed into QRF */
4f76459… drh 3694 } Mode;
4f76459… drh 3695
4f76459… drh 3696 /* Flags for Mode.mFlags */
4f76459… drh 3697 #define MFLG_ECHO 0x01 /* Echo inputs to output */
4f76459… drh 3698 #define MFLG_CRLF 0x02 /* Use CR/LF output line endings */
12e4a0f… drh 3699 #define MFLG_HDR 0x04 /* .header used to change headers on/off */
4f76459… drh 3700
4f76459… drh 3701 u8 nPopOutput; /* Revert .output settings when reaching zero */
4f76459… drh 3702 u8 nPopMode; /* Revert .mode settings when reaching zero */
7b0960d… drh 3703 u8 enableTimer; /* Enable the timer. 2: permanently 1: only once */
7b0960d… drh 3704 double prevTimer; /* Last reported timer value */
7b0960d… drh 3705 double tmProgress; /* --timeout option for .progress */
92871e0… drh 3706 i64 lineno; /* Line number of last line read from in */
4f76459… drh 3707 const char *zInFile; /* Name of the input file */
4f76459… drh 3708 unsigned nTestRun; /* Number of test cases run */
4f76459… drh 3709 unsigned nTestErr; /* Number of test cases that failed */
4f76459… drh 3710 char *zErrPrefix; /* Alternative error message prefix */
4f76459… drh 3711 Mode mode; /* Current display mode */
4f76459… drh 3712 Mode modePrior; /* Backup */
4f76459… drh 3713 struct SavedMode { /* Ability to define custom mode configurations */
4f76459… drh 3714 char *zTag; /* Name of this saved mode */
4f76459… drh 3715 Mode mode; /* The saved mode */
4f76459… drh 3716 } *aSavedModes; /* Array of saved .mode settings. system malloc() */
4f76459… drh 3717 int nSavedModes; /* Number of saved .mode settings */
4f76459… drh 3718 struct DotCmdLine { /* Info about arguments to a dot-command */
4f76459… drh 3719 const char *zOrig; /* Original text of the dot-command */
4f76459… drh 3720 char *zCopy; /* Copy of zOrig, from malloc() */
4f76459… drh 3721 int nAlloc; /* Size of allocates for arrays below */
4f76459… drh 3722 int nArg; /* Number of argument slots actually used */
4f76459… drh 3723 char **azArg; /* Pointer to each argument, dequoted */
4f76459… drh 3724 int *aiOfst; /* Offset into zOrig[] for start of each arg */
4f76459… drh 3725 char *abQuot; /* True if the argment was originally quoted */
4f76459… drh 3726 } dot;
4f76459… drh 3727 /* Allowed values for ShellState.mode.autoEQP
7b0960d… drh 3728 #define SHELL_PROGRESS_TMOUT 0x08 /* Stop after tmProgress seconds */
4f76459… drh 3729
4f76459… drh 3730 /* Names of values for Mode.spec.eEsc and Mode.spec.eText
4f76459… drh 3731 */
4f76459… drh 3732 static const char *qrfEscNames[] = { "auto", "off", "ascii", "symbol" };
4f76459… drh 3733 static const char *qrfQuoteNames[] =
709b566… drh 3734 { "off","off","sql","hex","csv","tcl","json","relaxed"};
4f76459… drh 3735 #define SHFLG_NoErrLineno 0x00000010 /* Omit line numbers from error msgs */
4f76459… drh 3736 ** These are the allowed values for Mode.eMode. There is a lot of overlap
4f76459… drh 3737 ** between these values and the Mode.spec.eStyle values, but they are not
4f76459… drh 3738 ** one-to-one, and thus need to be tracked separately.
4f76459… drh 3739 #define MODE_Ascii 0 /* Use ASCII unit and record separators (0x1F/0x1E) */
4f76459… drh 3740 #define MODE_Box 1 /* Unicode box-drawing characters */
4f76459… drh 3741 #define MODE_C 2 /* Comma-separated list of C-strings */
4f76459… drh 3742 #define MODE_Column 3 /* One record per line in neat columns */
4f76459… drh 3743 #define MODE_Count 4 /* Output only a count of the rows of output */
4f76459… drh 3744 #define MODE_Csv 5 /* Quote strings, numbers are plain */
4f76459… drh 3745 #define MODE_Html 6 /* Generate an XHTML table */
4f76459… drh 3746 #define MODE_Insert 7 /* Generate SQL "insert" statements */
4f76459… drh 3747 #define MODE_JAtom 8 /* Comma-separated list of JSON atoms */
4f76459… drh 3748 #define MODE_JObject 9 /* One JSON object per row */
4f76459… drh 3749 #define MODE_Json 10 /* Output JSON */
4f76459… drh 3750 #define MODE_Line 11 /* One column per line. Blank line between records */
4f76459… drh 3751 #define MODE_List 12 /* One record per line with a separator */
4f76459… drh 3752 #define MODE_Markdown 13 /* Markdown formatting */
4f76459… drh 3753 #define MODE_Off 14 /* No query output shown */
f4b3b59… drh 3754 #define MODE_Psql 15 /* Similar to psql */
f4b3b59… drh 3755 #define MODE_QBox 16 /* BOX with SQL-quoted content */
f4b3b59… drh 3756 #define MODE_Quote 17 /* Quote values as for SQL */
f4b3b59… drh 3757 #define MODE_Split 18 /* Split-column mode */
f4b3b59… drh 3758 #define MODE_Table 19 /* MySQL-style table formatting */
f4b3b59… drh 3759 #define MODE_Tabs 20 /* Tab-separated values */
f4b3b59… drh 3760 #define MODE_Tcl 21 /* Space-separated list of TCL strings */
f4b3b59… drh 3761 #define MODE_Www 22 /* Full web-page output */
f4b3b59… drh 3762
f4b3b59… drh 3763 #define MODE_BUILTIN 22 /* Maximum built-in mode */
4f76459… drh 3764 #define MODE_BATCH 50 /* Default mode for batch processing */
4f76459… drh 3765 #define MODE_TTY 51 /* Default mode for interactive processing */
4f76459… drh 3766 #define MODE_USER 75 /* First user-defined mode */
4f76459… drh 3767 #define MODE_N_USER 25 /* Maximum number of user-defined modes */
4f76459… drh 3768
4f76459… drh 3769 /*
4f76459… drh 3770 ** Information about built-in display modes
4f76459… drh 3771 */
4f76459… drh 3772 typedef struct ModeInfo ModeInfo;
4f76459… drh 3773 struct ModeInfo {
4f76459… drh 3774 char zName[9]; /* Symbolic name of the mode */
4f76459… drh 3775 unsigned char eCSep; /* Column separator */
4f76459… drh 3776 unsigned char eRSep; /* Row separator */
4f76459… drh 3777 unsigned char eNull; /* Null representation */
4f76459… drh 3778 unsigned char eText; /* Default text encoding */
4f76459… drh 3779 unsigned char eHdr; /* Default header encoding. */
4f76459… drh 3780 unsigned char eBlob; /* Default blob encoding. */
4f76459… drh 3781 unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */
4f76459… drh 3782 unsigned char eStyle; /* Underlying QRF style */
4f76459… drh 3783 unsigned char eCx; /* 0: other, 1: line, 2: columnar */
f4b3b59… drh 3784 unsigned char mFlg; /* Flags. 1=border-off 2=split-column */
4f76459… drh 3785 /* String constants used by built-in modes */
4f76459… drh 3786 static const char *aModeStr[] =
4f76459… drh 3787 /* 0 1 2 3 4 5 6 7 8 */
4f76459… drh 3788 { 0, "\n", "|", " ", ",", "\r\n", "\036", "\037", "\t",
ae7e3f0… drh 3789 "", "NULL", "null", "\"\"", ": ", };
ae7e3f0… drh 3790 /* 9 10 11 12 13 */
4f76459… drh 3791
4f76459… drh 3792 static const ModeInfo aModeInfo[] = {
f4b3b59… drh 3793 /* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */
f4b3b59… drh 3794 { "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 },
f4b3b59… drh 3795 { "box", 0, 0, 9, 1, 1, 0, 2, 1, 2, 0 },
f4b3b59… drh 3796 { "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 },
f4b3b59… drh 3797 { "column", 0, 0, 9, 1, 1, 0, 2, 2, 2, 0 },
f4b3b59… drh 3798 { "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
f4b3b59… drh 3799 { "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 },
f4b3b59… drh 3800 { "html", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 },
f4b3b59… drh 3801 { "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 },
f4b3b59… drh 3802 { "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 },
f4b3b59… drh 3803 { "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 },
f4b3b59… drh 3804 { "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 },
ae7e3f0… drh 3805 { "line", 13, 1, 9, 1, 1, 0, 0, 11, 1, 0 },
f4b3b59… drh 3806 { "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 },
f4b3b59… drh 3807 { "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2, 0 },
f4b3b59… drh 3808 { "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 },
f4b3b59… drh 3809 { "psql", 0, 0, 9, 1, 1, 0, 2, 19, 2, 1 },
f4b3b59… drh 3810 { "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2, 0 },
f4b3b59… drh 3811 { "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 },
f4b3b59… drh 3812 { "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 },
f4b3b59… drh 3813 { "table", 0, 0, 9, 1, 1, 0, 2, 19, 2, 0 },
f4b3b59… drh 3814 { "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 },
f4b3b59… drh 3815 { "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 },
f4b3b59… drh 3816 { "www", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 }
4f76459… drh 3817 }; /* | / / | / / | | \
4f76459… drh 3818 ** | / / | / / | | \_ 2: columnar
4f76459… drh 3819 ** Index into aModeStr[] | / / | | 1: line
4f76459… drh 3820 ** | / / | | 0: other
4f76459… drh 3821 ** | / / | \
4f76459… drh 3822 ** text encoding |/ | show | \
4f76459… drh 3823 ** v-------------------' | hdrs? | The QRF style
4f76459… drh 3824 ** 0: n/a blob | v-----'
4f76459… drh 3825 ** 1: plain v_---------' 0: n/a
45de97f… drh 3826 ** 2: sql 0: auto 1: no
4f76459… drh 3827 ** 3: csv 1: as-text 2: yes
4f76459… drh 3828 ** 4: html 2: sql
4f76459… drh 3829 ** 5: c 3: hex
4f76459… drh 3830 ** 6: json 4: c
4f76459… drh 3831 ** 5: json
45de97f… drh 3832 ** 6: size
4f76459… drh 3833 ******************************************************************/
ae7e3f0… drh 3834 ** Default values for the various QRF limits
ae7e3f0… drh 3835 */
ae7e3f0… drh 3836 #ifndef DFLT_CHAR_LIMIT
ae7e3f0… drh 3837 # define DFLT_CHAR_LIMIT 300
ae7e3f0… drh 3838 #endif
ae7e3f0… drh 3839 #ifndef DFLT_LINE_LIMIT
ae7e3f0… drh 3840 # define DFLT_LINE_LIMIT 5
ae7e3f0… drh 3841 #endif
ae7e3f0… drh 3842 #ifndef DFLT_TITLE_LIMIT
ae7e3f0… drh 3843 # define DFLT_TITLE_LIMIT 20
ae7e3f0… drh 3844 #endif
17f9878… drh 3845 #ifndef DFLT_MULTI_INSERT
17f9878… drh 3846 # define DFLT_MULTI_INSERT 3000
17f9878… drh 3847 #endif
17f9878… drh 3848
17f9878… drh 3849 /*
a10f931… drh 3850 ** If the following flag is set, then command execution stops
a10f931… drh 3851 ** at an error if we are not interactive.
a10f931… drh 3852 */
a10f931… drh 3853 static int bail_on_error = 0;
a10f931… drh 3854
a10f931… drh 3855 /*
a10f931… drh 3856 ** Treat stdin as an interactive input if the following variable
a10f931… drh 3857 ** is true. Otherwise, assume stdin is connected to a file or pipe.
a10f931… drh 3858 */
a10f931… drh 3859 static int stdin_is_interactive = 1;
a10f931… drh 3860
a10f931… drh 3861 /*
a10f931… drh 3862 ** Treat stdout like a TTY if true.
a10f931… drh 3863 */
a10f931… drh 3864 static int stdout_is_console = 1;
a10f931… drh 3865
a10f931… drh 3866 /*
a10f931… drh 3867 ** Use this value as the width of the output device. Or, figure it
a10f931… drh 3868 ** out at runtime if the value is negative. Or use a default width
a10f931… drh 3869 ** if this value is zero.
a10f931… drh 3870 */
a10f931… drh 3871 static int stdout_tty_width = -1;
a10f931… drh 3872
a10f931… drh 3873 /*
a10f931… drh 3874 ** The following is the open SQLite database. We make a pointer
a10f931… drh 3875 ** to this database a static variable so that it can be accessed
a10f931… drh 3876 ** by the SIGINT handler to interrupt database processing.
a10f931… drh 3877 */
a10f931… drh 3878 static sqlite3 *globalDb = 0;
a10f931… drh 3879
a10f931… drh 3880 /*
a10f931… drh 3881 ** True if an interrupt (Control-C) has been received.
a10f931… drh 3882 */
a10f931… drh 3883 static volatile int seenInterrupt = 0;
a10f931… drh 3884
a10f931… drh 3885 /*
a10f931… drh 3886 ** This is the name of our program. It is set in main(), used
a10f931… drh 3887 ** in a number of other places, mostly for error messages.
a10f931… drh 3888 */
a10f931… drh 3889 static char *Argv0;
a10f931… drh 3890
a10f931… drh 3891 /*
a10f931… drh 3892 ** Prompt strings. Initialized in main. Settable with
a10f931… drh 3893 ** .prompt main continue
a10f931… drh 3894 */
a10f931… drh 3895 #define PROMPT_LEN_MAX 128
a10f931… drh 3896 /* First line prompt. default: "sqlite> " */
a10f931… drh 3897 static char mainPrompt[PROMPT_LEN_MAX];
a10f931… drh 3898 /* Continuation prompt. default: " ...> " */
a10f931… drh 3899 static char continuePrompt[PROMPT_LEN_MAX];
a10f931… drh 3900
a10f931… drh 3901 /*
a10f931… drh 3902 ** Write I/O traces to the following stream.
a10f931… drh 3903 */
a10f931… drh 3904 #ifdef SQLITE_ENABLE_IOTRACE
a10f931… drh 3905 static FILE *iotrace = 0;
a10f931… drh 3906 #endif
a10f931… drh 3907
a10f931… drh 3908 /*
a10f931… drh 3909 ** Output routines that are able to redirect to memory rather than
a10f931… drh 3910 ** doing actually I/O.
a10f931… drh 3911 ** Works like.
a10f931… drh 3912 ** --------------
a10f931… drh 3913 ** cli_printf(FILE*, const char*, ...); fprintf()
a10f931… drh 3914 ** cli_puts(const char*, FILE*); fputs()
a10f931… drh 3915 ** cli_vprintf(FILE*, const char*, va_list); vfprintf()
a10f931… drh 3916 **
a10f931… drh 3917 ** These are just thin wrappers with the following added semantics:
a10f931… drh 3918 ** If the file-scope variable cli_output_capture is not NULL, and
a10f931… drh 3919 ** if the FILE* argument is stdout or stderr, then rather than
a10f931… drh 3920 ** writing to stdout/stdout, append the text to the cli_output_capture
a10f931… drh 3921 ** variable.
a10f931… drh 3922 **
a10f931… drh 3923 ** The cli_exit(int) routine works like exit() except that it
a10f931… drh 3924 ** first dumps any capture output to stdout.
a10f931… drh 3925 */
a10f931… drh 3926 static sqlite3_str *cli_output_capture = 0;
a10f931… drh 3927 static int cli_printf(FILE *out, const char *zFormat, ...){
a10f931… drh 3928 va_list ap;
a10f931… drh 3929 int rc;
a10f931… drh 3930 va_start(ap,zFormat);
a10f931… drh 3931 if( cli_output_capture && (out==stdout || out==stderr) ){
a10f931… drh 3932 sqlite3_str_vappendf(cli_output_capture, zFormat, ap);
a10f931… drh 3933 rc = 1;
a10f931… drh 3934 }else{
a10f931… drh 3935 rc = sqlite3_vfprintf(out, zFormat, ap);
a10f931… drh 3936 }
a10f931… drh 3937 va_end(ap);
a10f931… drh 3938 return rc;
a10f931… drh 3939 }
a10f931… drh 3940 static int cli_puts(const char *zText, FILE *out){
a10f931… drh 3941 if( cli_output_capture && (out==stdout || out==stderr) ){
a10f931… drh 3942 sqlite3_str_appendall(cli_output_capture, zText);
a10f931… drh 3943 return 1;
a10f931… drh 3944 }
a10f931… drh 3945 return sqlite3_fputs(zText, out);
a10f931… drh 3946 }
a10f931… drh 3947 #if 0 /* Not currently used - available if we need it later */
a10f931… drh 3948 static int cli_vprintf(FILE *out, const char *zFormat, va_list ap){
a10f931… drh 3949 if( cli_output_capture && (out==stdout || out==stderr) ){
a10f931… drh 3950 sqlite3_str_vappendf(cli_output_capture, zFormat, ap);
a10f931… drh 3951 return 1;
a10f931… drh 3952 }else{
a10f931… drh 3953 return sqlite3_vfprintf(out, zFormat, ap);
a10f931… drh 3954 }
a10f931… drh 3955 }
a10f931… drh 3956 #endif
a10f931… drh 3957 static void cli_exit(int rc){
a10f931… drh 3958 if( cli_output_capture ){
a10f931… drh 3959 char *z = sqlite3_str_finish(cli_output_capture);
a10f931… drh 3960 sqlite3_fputs(z, stdout);
a10f931… drh 3961 fflush(stdout);
a10f931… drh 3962 }
a10f931… drh 3963 exit(rc);
a10f931… drh 3964 }
a10f931… drh 3965
a10f931… drh 3966
a10f931… drh 3967 #define eputz(z) cli_puts(z,stderr)
a10f931… drh 3968 #define sputz(fp,z) cli_puts(z,fp)
a10f931… drh 3969
a10f931… drh 3970 /* A version of strcmp() that works with NULL values */
a10f931… drh 3971 static int cli_strcmp(const char *a, const char *b){
a10f931… drh 3972 if( a==0 ) a = "";
a10f931… drh 3973 if( b==0 ) b = "";
a10f931… drh 3974 return strcmp(a,b);
a10f931… drh 3975 }
a10f931… drh 3976 static int cli_strncmp(const char *a, const char *b, size_t n){
a10f931… drh 3977 if( a==0 ) a = "";
a10f931… drh 3978 if( b==0 ) b = "";
a10f931… drh 3979 return strncmp(a,b,n);
a10f931… drh 3980 }
a10f931… drh 3981
a10f931… drh 3982 /* Return the current wall-clock time in microseconds since the
a10f931… drh 3983 ** Unix epoch (1970-01-01T00:00:00Z)
a10f931… drh 3984 */
a10f931… drh 3985 static sqlite3_int64 timeOfDay(void){
a10f931… drh 3986 #if defined(_WIN64) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
a10f931… drh 3987 sqlite3_uint64 t;
a10f931… drh 3988 FILETIME tm;
a10f931… drh 3989 GetSystemTimePreciseAsFileTime(&tm);
a10f931… drh 3990 t = ((u64)tm.dwHighDateTime<<32) | (u64)tm.dwLowDateTime;
a10f931… drh 3991 t += 116444736000000000LL;
a10f931… drh 3992 t /= 10;
a10f931… drh 3993 return t;
a10f931… drh 3994 #elif defined(_WIN32)
a10f931… drh 3995 static sqlite3_vfs *clockVfs = 0;
a10f931… drh 3996 sqlite3_int64 t;
a10f931… drh 3997 if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
a10f931… drh 3998 if( clockVfs==0 ) return 0; /* Never actually happens */
a10f931… drh 3999 if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
a10f931… drh 4000 clockVfs->xCurrentTimeInt64(clockVfs, &t);
a10f931… drh 4001 }else{
a10f931… drh 4002 double r;
a10f931… drh 4003 clockVfs->xCurrentTime(clockVfs, &r);
a10f931… drh 4004 t = (sqlite3_int64)(r*86400000.0);
a10f931… drh 4005 }
a10f931… drh 4006 return t*1000;
a10f931… drh 4007 #else
a10f931… drh 4008 struct timeval sNow;
a10f931… drh 4009 (void)gettimeofday(&sNow,0);
a10f931… drh 4010 return ((i64)sNow.tv_sec)*1000000 + sNow.tv_usec;
a10f931… drh 4011 #endif
a10f931… drh 4012 }
a10f931… drh 4013
a10f931… drh 4014
a10f931… drh 4015
a10f931… drh 4016 /* This is variant of the standard-library strncpy() routine with the
a10f931… drh 4017 ** one change that the destination string is always zero-terminated, even
a10f931… drh 4018 ** if there is no zero-terminator in the first n-1 characters of the source
a10f931… drh 4019 ** string.
a10f931… drh 4020 */
a10f931… drh 4021 static char *shell_strncpy(char *dest, const char *src, size_t n){
a10f931… drh 4022 size_t i;
a10f931… drh 4023 for(i=0; i<n-1 && src[i]!=0; i++) dest[i] = src[i];
a10f931… drh 4024 dest[i] = 0;
a10f931… drh 4025 return dest;
a10f931… drh 4026 }
a10f931… drh 4027
a10f931… drh 4028 /*
a10f931… drh 4029 ** strcpy() workalike to squelch an unwarranted link-time warning
a10f931… drh 4030 ** from OpenBSD.
a10f931… drh 4031 */
a10f931… drh 4032 static void shell_strcpy(char *dest, const char *src){
a10f931… drh 4033 while( (*(dest++) = *(src++))!=0 ){}
a10f931… drh 4034 }
a10f931… drh 4035
a10f931… drh 4036 /*
a10f931… drh 4037 ** Optionally disable dynamic continuation prompt.
a10f931… drh 4038 ** Unless disabled, the continuation prompt shows open SQL lexemes if any,
a10f931… drh 4039 ** or open parentheses level if non-zero, or continuation prompt as set.
a10f931… drh 4040 ** This facility interacts with the scanner and process_input() where the
a10f931… drh 4041 ** below 5 macros are used.
a10f931… drh 4042 */
a10f931… drh 4043 #ifdef SQLITE_OMIT_DYNAPROMPT
a10f931… drh 4044 # define CONTINUATION_PROMPT continuePrompt
a10f931… drh 4045 # define CONTINUE_PROMPT_RESET
a10f931… drh 4046 # define CONTINUE_PROMPT_AWAITS(p,s)
a10f931… drh 4047 # define CONTINUE_PROMPT_AWAITC(p,c)
a10f931… drh 4048 # define CONTINUE_PAREN_INCR(p,n)
a10f931… drh 4049 # define CONTINUE_PROMPT_PSTATE 0
a10f931… drh 4050 typedef void *t_NoDynaPrompt;
a10f931… drh 4051 # define SCAN_TRACKER_REFTYPE t_NoDynaPrompt
a10f931… drh 4052 #else
a10f931… drh 4053 # define CONTINUATION_PROMPT dynamicContinuePrompt()
a10f931… drh 4054 # define CONTINUE_PROMPT_RESET \
a10f931… drh 4055 do {setLexemeOpen(&dynPrompt,0,0); trackParenLevel(&dynPrompt,0);} while(0)
a10f931… drh 4056 # define CONTINUE_PROMPT_AWAITS(p,s) \
a10f931… drh 4057 if(p && stdin_is_interactive) setLexemeOpen(p, s, 0)
a10f931… drh 4058 # define CONTINUE_PROMPT_AWAITC(p,c) \
a10f931… drh 4059 if(p && stdin_is_interactive) setLexemeOpen(p, 0, c)
a10f931… drh 4060 # define CONTINUE_PAREN_INCR(p,n) \
a10f931… drh 4061 if(p && stdin_is_interactive) (trackParenLevel(p,n))
a10f931… drh 4062 # define CONTINUE_PROMPT_PSTATE (&dynPrompt)
a10f931… drh 4063 typedef struct DynaPrompt *t_DynaPromptRef;
a10f931… drh 4064 # define SCAN_TRACKER_REFTYPE t_DynaPromptRef
a10f931… drh 4065
a10f931… drh 4066 static struct DynaPrompt {
a10f931… drh 4067 char dynamicPrompt[PROMPT_LEN_MAX];
a10f931… drh 4068 char acAwait[2];
a10f931… drh 4069 int inParenLevel;
a10f931… drh 4070 char *zScannerAwaits;
a10f931… drh 4071 } dynPrompt = { {0}, {0}, 0, 0 };
a10f931… drh 4072
a10f931… drh 4073 /* Record parenthesis nesting level change, or force level to 0. */
a10f931… drh 4074 static void trackParenLevel(struct DynaPrompt *p, int ni){
a10f931… drh 4075 p->inParenLevel += ni;
a10f931… drh 4076 if( ni==0 ) p->inParenLevel = 0;
a10f931… drh 4077 p->zScannerAwaits = 0;
a10f931… drh 4078 }
a10f931… drh 4079
a10f931… drh 4080 /* Record that a lexeme is opened, or closed with args==0. */
a10f931… drh 4081 static void setLexemeOpen(struct DynaPrompt *p, char *s, char c){
a10f931… drh 4082 if( s!=0 || c==0 ){
a10f931… drh 4083 p->zScannerAwaits = s;
a10f931… drh 4084 p->acAwait[0] = 0;
a10f931… drh 4085 }else{
a10f931… drh 4086 p->acAwait[0] = c;
a10f931… drh 4087 p->zScannerAwaits = p->acAwait;
a10f931… drh 4088 }
a10f931… drh 4089 }
a10f931… drh 4090
a10f931… drh 4091 /* Upon demand, derive the continuation prompt to display. */
a10f931… drh 4092 static char *dynamicContinuePrompt(void){
a10f931… drh 4093 if( continuePrompt[0]==0
a10f931… drh 4094 || (dynPrompt.zScannerAwaits==0 && dynPrompt.inParenLevel == 0) ){
a10f931… drh 4095 return continuePrompt;
a10f931… drh 4096 }else{
a10f931… drh 4097 if( dynPrompt.zScannerAwaits ){
a10f931… drh 4098 size_t ncp = strlen(continuePrompt);
a10f931… drh 4099 size_t ndp = strlen(dynPrompt.zScannerAwaits);
a10f931… drh 4100 if( ndp > ncp-3 ) return continuePrompt;
a10f931… drh 4101 shell_strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
a10f931… drh 4102 while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' ';
a10f931… drh 4103 shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
a10f931… drh 4104 PROMPT_LEN_MAX-4);
a10f931… drh 4105 }else{
a10f931… drh 4106 if( dynPrompt.inParenLevel>9 ){
a10f931… drh 4107 shell_strncpy(dynPrompt.dynamicPrompt, "(..", 4);
a10f931… drh 4108 }else if( dynPrompt.inParenLevel<0 ){
a10f931… drh 4109 shell_strncpy(dynPrompt.dynamicPrompt, ")x!", 4);
a10f931… drh 4110 }else{
a10f931… drh 4111 shell_strncpy(dynPrompt.dynamicPrompt, "(x.", 4);
a10f931… drh 4112 dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel);
a10f931… drh 4113 }
a10f931… drh 4114 shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
a10f931… drh 4115 PROMPT_LEN_MAX-4);
a10f931… drh 4116 }
a10f931… drh 4117 }
a10f931… drh 4118 return dynPrompt.dynamicPrompt;
a10f931… drh 4119 }
a10f931… drh 4120 #endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */
a10f931… drh 4121
a10f931… drh 4122 /* Indicate out-of-memory and exit. */
a10f931… drh 4123 static void shell_out_of_memory(void){
a10f931… drh 4124 eputz("Error: out of memory\n");
a10f931… drh 4125 cli_exit(1);
a10f931… drh 4126 }
a10f931… drh 4127
a10f931… drh 4128 /* Check a pointer to see if it is NULL. If it is NULL, exit with an
a10f931… drh 4129 ** out-of-memory error.
a10f931… drh 4130 */
a10f931… drh 4131 static void shell_check_oom(const void *p){
a10f931… drh 4132 if( p==0 ) shell_out_of_memory();
a10f931… drh 4133 }
a10f931… drh 4134
a10f931… drh 4135 /*
a10f931… drh 4136 ** This routine works like printf in that its first argument is a
a10f931… drh 4137 ** format string and subsequent arguments are values to be substituted
a10f931… drh 4138 ** in place of % fields. The result of formatting this string
a10f931… drh 4139 ** is written to iotrace.
a10f931… drh 4140 */
a10f931… drh 4141 #ifdef SQLITE_ENABLE_IOTRACE
a10f931… drh 4142 static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
a10f931… drh 4143 va_list ap;
a10f931… drh 4144 char *z;
a10f931… drh 4145 if( iotrace==0 ) return;
a10f931… drh 4146 va_start(ap, zFormat);
a10f931… drh 4147 z = sqlite3_vmprintf(zFormat, ap);
a10f931… drh 4148 va_end(ap);
a10f931… drh 4149 cli_printf(iotrace, "%s", z);
a10f931… drh 4150 sqlite3_free(z);
a10f931… drh 4151 }
a10f931… drh 4152 #endif
a10f931… drh 4153
a10f931… drh 4154 /*
a10f931… drh 4155 ** Compute a string length that is limited to what can be stored in
a10f931… drh 4156 ** lower 30 bits of a 32-bit signed integer.
a10f931… drh 4157 */
a10f931… drh 4158 static int strlen30(const char *z){
a10f931… drh 4159 size_t n;
a10f931… drh 4160 if( z==0 ) return 0;
a10f931… drh 4161 n = strlen(z);
a10f931… drh 4162 return n>0x3fffffff ? 0x3fffffff : (int)n;
a10f931… drh 4163 }
a10f931… drh 4164
a10f931… drh 4165 /*
a10f931… drh 4166 ** Return open FILE * if zFile exists, can be opened for read
a10f931… drh 4167 ** and is an ordinary file or a character stream source.
a10f931… drh 4168 ** Otherwise return 0.
a10f931… drh 4169 */
a10f931… drh 4170 static FILE * openChrSource(const char *zFile){
a10f931… drh 4171 #if defined(_WIN32) || defined(WIN32)
a10f931… drh 4172 struct __stat64 x = {0};
a10f931… drh 4173 # define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
a10f931… drh 4174 /* On Windows, open first, then check the stream nature. This order
a10f931… drh 4175 ** is necessary because _stat() and sibs, when checking a named pipe,
a10f931… drh 4176 ** effectively break the pipe as its supplier sees it. */
a10f931… drh 4177 FILE *rv = sqlite3_fopen(zFile, "rb");
a10f931… drh 4178 if( rv==0 ) return 0;
a10f931… drh 4179 if( _fstat64(_fileno(rv), &x) != 0
a10f931… drh 4180 || !STAT_CHR_SRC(x.st_mode)){
a10f931… drh 4181 fclose(rv);
a10f931… drh 4182 rv = 0;
a10f931… drh 4183 }
a10f931… drh 4184 return rv;
a10f931… drh 4185 #else
a10f931… drh 4186 struct stat x = {0};
a10f931… drh 4187 int rc = stat(zFile, &x);
a10f931… drh 4188 # define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
a10f931… drh 4189 if( rc!=0 ) return 0;
a10f931… drh 4190 if( STAT_CHR_SRC(x.st_mode) ){
a10f931… drh 4191 return sqlite3_fopen(zFile, "rb");
a10f931… drh 4192 }else{
a10f931… drh 4193 return 0;
a10f931… drh 4194 }
a10f931… drh 4195 #endif
a10f931… drh 4196 #undef STAT_CHR_SRC
a10f931… drh 4197 }
a10f931… drh 4198
a10f931… drh 4199 /*
a10f931… drh 4200 ** This routine reads a line of text from FILE in, stores
a10f931… drh 4201 ** the text in memory obtained from malloc() and returns a pointer
a10f931… drh 4202 ** to the text. NULL is returned at end of file, or if malloc()
a10f931… drh 4203 ** fails, or if the length of the line is longer than about a gigabyte.
a10f931… drh 4204 **
a10f931… drh 4205 ** If zLine is not NULL then it is a malloced buffer returned from
a10f931… drh 4206 ** a previous call to this routine that may be reused.
a10f931… drh 4207 */
a10f931… drh 4208 static char *local_getline(char *zLine, FILE *in){
a10f931… drh 4209 int nLine = zLine==0 ? 0 : 100;
a10f931… drh 4210 int n = 0;
a10f931… drh 4211
a10f931… drh 4212 while( 1 ){
a10f931… drh 4213 if( n+100>nLine ){
a10f931… drh 4214 if( nLine>=1073741773 ){
a10f931… drh 4215 free(zLine);
a10f931… drh 4216 return 0;
a10f931… drh 4217 }
a10f931… drh 4218 nLine = nLine*2 + 100;
a10f931… drh 4219 zLine = realloc(zLine, nLine);
a10f931… drh 4220 shell_check_oom(zLine);
a10f931… drh 4221 }
a10f931… drh 4222 if( sqlite3_fgets(&zLine[n], nLine - n, in)==0 ){
a10f931… drh 4223 if( n==0 ){
a10f931… drh 4224 free(zLine);
a10f931… drh 4225 return 0;
a10f931… drh 4226 }
a10f931… drh 4227 zLine[n] = 0;
a10f931… drh 4228 break;
a10f931… drh 4229 }
a10f931… drh 4230 while( zLine[n] ) n++;
a10f931… drh 4231 if( n>0 && zLine[n-1]=='\n' ){
a10f931… drh 4232 n--;
a10f931… drh 4233 if( n>0 && zLine[n-1]=='\r' ) n--;
a10f931… drh 4234 zLine[n] = 0;
a10f931… drh 4235 break;
a10f931… drh 4236 }
a10f931… drh 4237 }
a10f931… drh 4238 return zLine;
a10f931… drh 4239 }
a10f931… drh 4240
a10f931… drh 4241 /*
a10f931… drh 4242 ** Retrieve a single line of input text.
a10f931… drh 4243 **
a10f931… drh 4244 ** If in==0 then read from standard input and prompt before each line.
a10f931… drh 4245 ** If isContinuation is true, then a continuation prompt is appropriate.
a10f931… drh 4246 ** If isContinuation is zero, then the main prompt should be used.
a10f931… drh 4247 **
a10f931… drh 4248 ** If zPrior is not NULL then it is a buffer from a prior call to this
a10f931… drh 4249 ** routine that can be reused.
a10f931… drh 4250 **
a10f931… drh 4251 ** The result is stored in space obtained from malloc() and must either
a10f931… drh 4252 ** be freed by the caller or else passed back into this routine via the
a10f931… drh 4253 ** zPrior argument for reuse.
a10f931… drh 4254 */
a10f931… drh 4255 #ifndef SQLITE_SHELL_FIDDLE
a10f931… drh 4256 static char *one_input_line(ShellState *p, char *zPrior, int isContinuation){
a10f931… drh 4257 char *zPrompt;
a10f931… drh 4258 char *zResult;
a10f931… drh 4259 FILE *in = p->in;
a10f931… drh 4260 if( in!=0 ){
a10f931… drh 4261 zResult = local_getline(zPrior, in);
a10f931… drh 4262 }else{
a10f931… drh 4263 zPrompt = isContinuation ? CONTINUATION_PROMPT : mainPrompt;
a10f931… drh 4264 #if SHELL_USE_LOCAL_GETLINE
a10f931… drh 4265 sputz(stdout, zPrompt);
a10f931… drh 4266 fflush(stdout);
a10f931… drh 4267 do{
a10f931… drh 4268 zResult = local_getline(zPrior, stdin);
a10f931… drh 4269 zPrior = 0;
a10f931… drh 4270 /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
a10f931… drh 4271 if( zResult==0 ) sqlite3_sleep(50);
a10f931… drh 4272 }while( zResult==0 && seenInterrupt>0 );
a10f931… drh 4273 #else
a10f931… drh 4274 free(zPrior);
a10f931… drh 4275 zResult = shell_readline(zPrompt);
a10f931… drh 4276 while( zResult==0 ){
a10f931… drh 4277 /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
a10f931… drh 4278 sqlite3_sleep(50);
a10f931… drh 4279 if( seenInterrupt==0 ) break;
a10f931… drh 4280 zResult = shell_readline("");
a10f931… drh 4281 }
a10f931… drh 4282 if( zResult && *zResult ) shell_add_history(zResult);
a10f931… drh 4283 #endif
a10f931… drh 4284 }
a10f931… drh 4285 return zResult;
a10f931… drh 4286 }
a10f931… drh 4287 #endif /* !SQLITE_SHELL_FIDDLE */
a10f931… drh 4288
a10f931… drh 4289 /*
a10f931… drh 4290 ** Return the value of a hexadecimal digit. Return -1 if the input
a10f931… drh 4291 ** is not a hex digit.
a10f931… drh 4292 */
a10f931… drh 4293 static int hexDigitValue(char c){
a10f931… drh 4294 if( c>='0' && c<='9' ) return c - '0';
a10f931… drh 4295 if( c>='a' && c<='f' ) return c - 'a' + 10;
a10f931… drh 4296 if( c>='A' && c<='F' ) return c - 'A' + 10;
a10f931… drh 4297 return -1;
a10f931… drh 4298 }
a10f931… drh 4299
a10f931… drh 4300 /*
a10f931… drh 4301 ** Interpret zArg as an integer value, possibly with suffixes.
a10f931… drh 4302 **
a10f931… drh 4303 ** If the value specified by zArg is outside the range of values that
a10f931… drh 4304 ** can be represented using a 64-bit twos-complement integer, then return
a10f931… drh 4305 ** the nearest representable value.
a10f931… drh 4306 */
a10f931… drh 4307 static sqlite3_int64 integerValue(const char *zArg){
a10f931… drh 4308 sqlite3_uint64 v = 0;
a10f931… drh 4309 static const struct { char *zSuffix; unsigned int iMult; } aMult[] = {
a10f931… drh 4310 { "KiB", 1024 },
a10f931… drh 4311 { "MiB", 1024*1024 },
a10f931… drh 4312 { "GiB", 1024*1024*1024 },
a10f931… drh 4313 { "KB", 1000 },
a10f931… drh 4314 { "MB", 1000000 },
a10f931… drh 4315 { "GB", 1000000000 },
a10f931… drh 4316 { "K", 1000 },
a10f931… drh 4317 { "M", 1000000 },
a10f931… drh 4318 { "G", 1000000000 },
a10f931… drh 4319 };
a10f931… drh 4320 int i;
a10f931… drh 4321 int isNeg = 0;
a10f931… drh 4322 if( zArg[0]=='-' ){
a10f931… drh 4323 isNeg = 1;
a10f931… drh 4324 zArg++;
a10f931… drh 4325 }else if( zArg[0]=='+' ){
a10f931… drh 4326 zArg++;
a10f931… drh 4327 }
a10f931… drh 4328 if( zArg[0]=='0' && zArg[1]=='x' ){
a10f931… drh 4329 int x;
a10f931… drh 4330 zArg += 2;
a10f931… drh 4331 while( (x = hexDigitValue(zArg[0]))>=0 ){
a10f931… drh 4332 if( v > 0x0fffffffffffffffULL ) goto integer_overflow;
a10f931… drh 4333 v = (v<<4) + x;
a10f931… drh 4334 zArg++;
a10f931… drh 4335 }
a10f931… drh 4336 }else{
a10f931… drh 4337 while( IsDigit(zArg[0]) ){
a10f931… drh 4338 if( v>=922337203685477580LL ){
a10f931… drh 4339 if( v>922337203685477580LL || zArg[0]>='8' ) goto integer_overflow;
a10f931… drh 4340 }
a10f931… drh 4341 v = v*10 + (zArg[0] - '0');
a10f931… drh 4342 zArg++;
a10f931… drh 4343 }
a10f931… drh 4344 }
a10f931… drh 4345 for(i=0; i<ArraySize(aMult); i++){
a10f931… drh 4346 if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
a10f931… drh 4347 if( 0x7fffffffffffffffULL/aMult[i].iMult < v ) goto integer_overflow;
a10f931… drh 4348 v *= aMult[i].iMult;
a10f931… drh 4349 break;
a10f931… drh 4350 }
a10f931… drh 4351 }
a10f931… drh 4352 if( isNeg && v>0x7fffffffffffffffULL ) goto integer_overflow;
a10f931… drh 4353 return isNeg? -(sqlite3_int64)v : (sqlite3_int64)v;
a10f931… drh 4354 integer_overflow:
a10f931… drh 4355 return isNeg ? (i64)0x8000000000000000LL : 0x7fffffffffffffffLL;
a10f931… drh 4356 }
a10f931… drh 4357
a10f931… drh 4358 /*
a10f931… drh 4359 ** A variable length string to which one can append text.
a10f931… drh 4360 */
a10f931… drh 4361 typedef struct ShellText ShellText;
a10f931… drh 4362 struct ShellText {
a10f931… drh 4363 char *zTxt; /* The text */
a10f931… drh 4364 i64 n; /* Number of bytes of zTxt[] actually used */
a10f931… drh 4365 i64 nAlloc; /* Number of bytes allocated for zTxt[] */
a10f931… drh 4366 };
a10f931… drh 4367
a10f931… drh 4368 /*
a10f931… drh 4369 ** Initialize and destroy a ShellText object
a10f931… drh 4370 */
a10f931… drh 4371 static void initText(ShellText *p){
a10f931… drh 4372 memset(p, 0, sizeof(*p));
a10f931… drh 4373 }
a10f931… drh 4374 static void freeText(ShellText *p){
a10f931… drh 4375 sqlite3_free(p->zTxt);
a10f931… drh 4376 initText(p);
a10f931… drh 4377 }
a10f931… drh 4378
a10f931… drh 4379 /* zIn is either a pointer to a NULL-terminated string in memory obtained
a10f931… drh 4380 ** from malloc(), or a NULL pointer. The string pointed to by zAppend is
a10f931… drh 4381 ** added to zIn, and the result returned in memory obtained from malloc().
a10f931… drh 4382 ** zIn, if it was not NULL, is freed.
a10f931… drh 4383 **
a10f931… drh 4384 ** If the third argument, quote, is not '\0', then it is used as a
a10f931… drh 4385 ** quote character for zAppend.
a10f931… drh 4386 */
a10f931… drh 4387 static void appendText(ShellText *p, const char *zAppend, char quote){
a10f931… drh 4388 i64 len;
a10f931… drh 4389 i64 i;
a10f931… drh 4390 i64 nAppend = strlen30(zAppend);
a10f931… drh 4391
a10f931… drh 4392 len = nAppend+p->n+1;
a10f931… drh 4393 if( quote ){
a10f931… drh 4394 len += 2;
a10f931… drh 4395 for(i=0; i<nAppend; i++){
a10f931… drh 4396 if( zAppend[i]==quote ) len++;
a10f931… drh 4397 }
a10f931… drh 4398 }
a10f931… drh 4399
a10f931… drh 4400 if( p->zTxt==0 || p->n+len>=p->nAlloc ){
a10f931… drh 4401 p->nAlloc = p->nAlloc*2 + len + 20;
a10f931… drh 4402 p->zTxt = sqlite3_realloc64(p->zTxt, p->nAlloc);
a10f931… drh 4403 shell_check_oom(p->zTxt);
a10f931… drh 4404 }
a10f931… drh 4405
a10f931… drh 4406 if( quote ){
a10f931… drh 4407 char *zCsr = p->zTxt+p->n;
a10f931… drh 4408 *zCsr++ = quote;
a10f931… drh 4409 for(i=0; i<nAppend; i++){
a10f931… drh 4410 *zCsr++ = zAppend[i];
a10f931… drh 4411 if( zAppend[i]==quote ) *zCsr++ = quote;
a10f931… drh 4412 }
a10f931… drh 4413 *zCsr++ = quote;
a10f931… drh 4414 p->n = (i64)(zCsr - p->zTxt);
a10f931… drh 4415 *zCsr = '\0';
a10f931… drh 4416 }else{
a10f931… drh 4417 memcpy(p->zTxt+p->n, zAppend, nAppend);
a10f931… drh 4418 p->n += nAppend;
a10f931… drh 4419 p->zTxt[p->n] = '\0';
a10f931… drh 4420 }
a10f931… drh 4421 }
a10f931… drh 4422
a10f931… drh 4423 /*
a10f931… drh 4424 ** Attempt to determine if identifier zName needs to be quoted, either
a10f931… drh 4425 ** because it contains non-alphanumeric characters, or because it is an
a10f931… drh 4426 ** SQLite keyword. Be conservative in this estimate: When in doubt assume
a10f931… drh 4427 ** that quoting is required.
a10f931… drh 4428 **
a10f931… drh 4429 ** Return '"' if quoting is required. Return 0 if no quoting is required.
a10f931… drh 4430 */
a10f931… drh 4431 static char quoteChar(const char *zName){
a10f931… drh 4432 int i;
a10f931… drh 4433 if( zName==0 ) return '"';
a10f931… drh 4434 if( !IsAlpha(zName[0]) && zName[0]!='_' ) return '"';
a10f931… drh 4435 for(i=0; zName[i]; i++){
a10f931… drh 4436 if( !IsAlnum(zName[i]) && zName[i]!='_' ) return '"';
a10f931… drh 4437 }
a10f931… drh 4438 return sqlite3_keyword_check(zName, i) ? '"' : 0;
a10f931… drh 4439 }
a10f931… drh 4440
a10f931… drh 4441 /*
a10f931… drh 4442 ** Construct a fake object name and column list to describe the structure
a10f931… drh 4443 ** of the view, virtual table, or table valued function zSchema.zName.
a10f931… drh 4444 **
a10f931… drh 4445 ** The returned string comes from sqlite3_mprintf() and should be freed
a10f931… drh 4446 ** by the caller using sqlite3_free().
a10f931… drh 4447 */
a10f931… drh 4448 static char *shellFakeSchema(
a10f931… drh 4449 sqlite3 *db, /* The database connection containing the vtab */
a10f931… drh 4450 const char *zSchema, /* Schema of the database holding the vtab */
a10f931… drh 4451 const char *zName /* The name of the virtual table */
a10f931… drh 4452 ){
a10f931… drh 4453 sqlite3_stmt *pStmt = 0;
a10f931… drh 4454 char *zSql;
a10f931… drh 4455 ShellText s;
a10f931… drh 4456 char cQuote;
a10f931… drh 4457 char *zDiv = "(";
a10f931… drh 4458 int nRow = 0;
a10f931… drh 4459
a10f931… drh 4460 zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
a10f931… drh 4461 zSchema ? zSchema : "main", zName);
a10f931… drh 4462 shell_check_oom(zSql);
a10f931… drh 4463 sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
a10f931… drh 4464 sqlite3_free(zSql);
a10f931… drh 4465 initText(&s);
a10f931… drh 4466 if( zSchema ){
a10f931… drh 4467 cQuote = quoteChar(zSchema);
a10f931… drh 4468 if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0;
a10f931… drh 4469 appendText(&s, zSchema, cQuote);
a10f931… drh 4470 appendText(&s, ".", 0);
a10f931… drh 4471 }
a10f931… drh 4472 cQuote = quoteChar(zName);
a10f931… drh 4473 appendText(&s, zName, cQuote);
a10f931… drh 4474 while( sqlite3_step(pStmt)==SQLITE_ROW ){
a10f931… drh 4475 const char *zCol = (const char*)sqlite3_column_text(pStmt, 1);
a10f931… drh 4476 nRow++;
a10f931… drh 4477 appendText(&s, zDiv, 0);
a10f931… drh 4478 zDiv = ",";
a10f931… drh 4479 if( zCol==0 ) zCol = "";
a10f931… drh 4480 cQuote = quoteChar(zCol);
a10f931… drh 4481 appendText(&s, zCol, cQuote);
a10f931… drh 4482 }
a10f931… drh 4483 appendText(&s, ")", 0);
a10f931… drh 4484 sqlite3_finalize(pStmt);
a10f931… drh 4485 if( nRow==0 ){
a10f931… drh 4486 freeText(&s);
a10f931… drh 4487 s.zTxt = 0;
a10f931… drh 4488 }
a10f931… drh 4489 return s.zTxt;
a10f931… drh 4490 }
a10f931… drh 4491
a10f931… drh 4492 /*
a10f931… drh 4493 ** SQL function: strtod(X)
a10f931… drh 4494 **
a10f931… drh 4495 ** Use the C-library strtod() function to convert string X into a double.
a10f931… drh 4496 ** Used for comparing the accuracy of SQLite's internal text-to-float conversion
a10f931… drh 4497 ** routines against the C-library.
a10f931… drh 4498 */
a10f931… drh 4499 static void shellStrtod(
a10f931… drh 4500 sqlite3_context *pCtx,
a10f931… drh 4501 int nVal,
a10f931… drh 4502 sqlite3_value **apVal
a10f931… drh 4503 ){
a10f931… drh 4504 char *z = (char*)sqlite3_value_text(apVal[0]);
a10f931… drh 4505 UNUSED_PARAMETER(nVal);
a10f931… drh 4506 if( z==0 ) return;
a10f931… drh 4507 sqlite3_result_double(pCtx, strtod(z,0));
a10f931… drh 4508 }
a10f931… drh 4509
a10f931… drh 4510 /*
a10f931… drh 4511 ** SQL function: dtostr(X)
a10f931… drh 4512 **
a10f931… drh 4513 ** Use the C-library printf() function to convert real value X into a string.
a10f931… drh 4514 ** Used for comparing the accuracy of SQLite's internal float-to-text conversion
a10f931… drh 4515 ** routines against the C-library.
a10f931… drh 4516 */
a10f931… drh 4517 static void shellDtostr(
a10f931… drh 4518 sqlite3_context *pCtx,
a10f931… drh 4519 int nVal,
a10f931… drh 4520 sqlite3_value **apVal
a10f931… drh 4521 ){
a10f931… drh 4522 double r = sqlite3_value_double(apVal[0]);
a10f931… drh 4523 int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26;
a10f931… drh 4524 char z[400];
a10f931… drh 4525 if( n<1 ) n = 1;
a10f931… drh 4526 if( n>350 ) n = 350;
a10f931… drh 4527 sprintf(z, "%#+.*e", n, r);
a10f931… drh 4528 sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
a10f931… drh 4529 }
a10f931… drh 4530
a10f931… drh 4531 /*
a10f931… drh 4532 ** SQL function: shell_add_schema(S,X)
a10f931… drh 4533 **
a10f931… drh 4534 ** Add the schema name X to the CREATE statement in S and return the result.
a10f931… drh 4535 ** Examples:
a10f931… drh 4536 **
a10f931… drh 4537 ** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x);
a10f931… drh 4538 **
a10f931… drh 4539 ** Also works on
a10f931… drh 4540 **
a10f931… drh 4541 ** CREATE INDEX
a10f931… drh 4542 ** CREATE UNIQUE INDEX
a10f931… drh 4543 ** CREATE VIEW
a10f931… drh 4544 ** CREATE TRIGGER
a10f931… drh 4545 ** CREATE VIRTUAL TABLE
a10f931… drh 4546 **
a10f931… drh 4547 ** This UDF is used by the .schema command to insert the schema name of
a10f931… drh 4548 ** attached databases into the middle of the sqlite_schema.sql field.
a10f931… drh 4549 */
a10f931… drh 4550 static void shellAddSchemaName(
a10f931… drh 4551 sqlite3_context *pCtx,
a10f931… drh 4552 int nVal,
a10f931… drh 4553 sqlite3_value **apVal
a10f931… drh 4554 ){
a10f931… drh 4555 static const char *aPrefix[] = {
a10f931… drh 4556 "TABLE",
a10f931… drh 4557 "INDEX",
a10f931… drh 4558 "UNIQUE INDEX",
a10f931… drh 4559 "VIEW",
a10f931… drh 4560 "TRIGGER",
a10f931… drh 4561 "VIRTUAL TABLE"
a10f931… drh 4562 };
a10f931… drh 4563 int i = 0;
a10f931… drh 4564 const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
a10f931… drh 4565 const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
a10f931… drh 4566 const char *zName = (const char*)sqlite3_value_text(apVal[2]);
a10f931… drh 4567 sqlite3 *db = sqlite3_context_db_handle(pCtx);
a10f931… drh 4568 UNUSED_PARAMETER(nVal);
a10f931… drh 4569 if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){
a10f931… drh 4570 for(i=0; i<ArraySize(aPrefix); i++){
a10f931… drh 4571 int n = strlen30(aPrefix[i]);
a10f931… drh 4572 if( cli_strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
a10f931… drh 4573 char *z = 0;
a10f931… drh 4574 char *zFake = 0;
a10f931… drh 4575 if( zSchema ){
a10f931… drh 4576 char cQuote = quoteChar(zSchema);
a10f931… drh 4577 if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
a10f931… drh 4578 z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
a10f931… drh 4579 }else{
a10f931… drh 4580 z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
a10f931… drh 4581 }
a10f931… drh 4582 }
a10f931… drh 4583 if( zName
a10f931… drh 4584 && aPrefix[i][0]=='V'
a10f931… drh 4585 && (zFake = shellFakeSchema(db, zSchema, zName))!=0
a10f931… drh 4586 ){
a10f931… drh 4587 if( z==0 ){
a10f931… drh 4588 z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake);
a10f931… drh 4589 }else{
a10f931… drh 4590 z = sqlite3_mprintf("%z\n/* %s */", z, zFake);
a10f931… drh 4591 }
a10f931… drh 4592 sqlite3_free(zFake);
a10f931… drh 4593 }
a10f931… drh 4594 if( z ){
a10f931… drh 4595 sqlite3_result_text(pCtx, z, -1, sqlite3_free);
a10f931… drh 4596 return;
a10f931… drh 4597 }
a10f931… drh 4598 }
a10f931… drh 4599 }
a10f931… drh 4600 }
a10f931… drh 4601 sqlite3_result_value(pCtx, apVal[0]);
a10f931… drh 4602 }
a10f931… drh 4603
7b0960d… drh 4604
7b0960d… drh 4605 /************************* BEGIN PERFORMANCE TIMER *****************************/
7b0960d… drh 4606 #if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
7b0960d… drh 4607 #include <sys/time.h>
7b0960d… drh 4608 #include <sys/resource.h>
7b0960d… drh 4609 /* VxWorks does not support getrusage() as far as we can determine */
7b0960d… drh 4610 #if defined(_WRS_KERNEL) || defined(__RTP__)
7b0960d… drh 4611 struct rusage {
7b0960d… drh 4612 struct timeval ru_utime; /* user CPU time used */
7b0960d… drh 4613 struct timeval ru_stime; /* system CPU time used */
7b0960d… drh 4614 };
7b0960d… drh 4615 #define getrusage(A,B) memset(B,0,sizeof(*B))
7b0960d… drh 4616 #endif
7b0960d… drh 4617
7b0960d… drh 4618 /* Saved resource information for the beginning of an operation */
7b0960d… drh 4619 static struct rusage sBegin; /* CPU time at start */
7b0960d… drh 4620 static sqlite3_int64 iBegin; /* Wall-clock time at start */
7b0960d… drh 4621
7b0960d… drh 4622 /*
7b0960d… drh 4623 ** Begin timing an operation
7b0960d… drh 4624 */
7b0960d… drh 4625 static void beginTimer(ShellState *p){
7b0960d… drh 4626 if( p->enableTimer || (p->flgProgress & SHELL_PROGRESS_TMOUT)!=0 ){
7b0960d… drh 4627 getrusage(RUSAGE_SELF, &sBegin);
7b0960d… drh 4628 iBegin = timeOfDay();
7b0960d… drh 4629 }
7b0960d… drh 4630 }
7b0960d… drh 4631
7b0960d… drh 4632 /* Return the difference of two time_structs in seconds */
7b0960d… drh 4633 static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
7b0960d… drh 4634 return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
7b0960d… drh 4635 (double)(pEnd->tv_sec - pStart->tv_sec);
7b0960d… drh 4636 }
7b0960d… drh 4637
6c6c1fe… drh 4638 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
7b0960d… drh 4639 /* Return the time since the start of the timer in
7b0960d… drh 4640 ** seconds. */
7b0960d… drh 4641 static double elapseTime(ShellState *NotUsed){
7b0960d… drh 4642 (void)NotUsed;
7b0960d… drh 4643 if( iBegin==0 ) return 0.0;
7b0960d… drh 4644 return (timeOfDay() - iBegin)*0.000001;
7b0960d… drh 4645 }
6c6c1fe… drh 4646 #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
7b0960d… drh 4647
7b0960d… drh 4648 /*
7b0960d… drh 4649 ** Print the timing results.
7b0960d… drh 4650 */
7b0960d… drh 4651 static void endTimer(ShellState *p){
7b0960d… drh 4652 if( p->enableTimer ){
7b0960d… drh 4653 sqlite3_int64 iEnd = timeOfDay();
7b0960d… drh 4654 struct rusage sEnd;
7b0960d… drh 4655 getrusage(RUSAGE_SELF, &sEnd);
7b0960d… drh 4656 p->prevTimer = (iEnd - iBegin)*0.000001;
7b0960d… drh 4657 cli_printf(p->out, "Run Time: real %.6f user %.6f sys %.6f\n",
7b0960d… drh 4658 p->prevTimer,
7b0960d… drh 4659 timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
7b0960d… drh 4660 timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
7b0960d… drh 4661 if( p->enableTimer==1 ) p->enableTimer = 0;
7b0960d… drh 4662 iBegin = 0;
7b0960d… drh 4663 }
7b0960d… drh 4664 }
7b0960d… drh 4665
7b0960d… drh 4666 #define BEGIN_TIMER(X) beginTimer(X)
7b0960d… drh 4667 #define END_TIMER(X) endTimer(X)
7b0960d… drh 4668 #define ELAPSE_TIME(X) elapseTime(X)
7b0960d… drh 4669 #define HAS_TIMER 1
7b0960d… drh 4670
7b0960d… drh 4671 #elif (defined(_WIN32) || defined(WIN32))
7b0960d… drh 4672
7b0960d… drh 4673 /* Saved resource information for the beginning of an operation */
7b0960d… drh 4674 static HANDLE hProcess;
7b0960d… drh 4675 static FILETIME ftKernelBegin;
7b0960d… drh 4676 static FILETIME ftUserBegin;
7b0960d… drh 4677 static sqlite3_int64 ftWallBegin;
7b0960d… drh 4678 typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME,
7b0960d… drh 4679 LPFILETIME, LPFILETIME);
7b0960d… drh 4680 static GETPROCTIMES getProcessTimesAddr = NULL;
7b0960d… drh 4681
7b0960d… drh 4682 /*
7b0960d… drh 4683 ** Check to see if we have timer support. Return 1 if necessary
7b0960d… drh 4684 ** support found (or found previously).
7b0960d… drh 4685 */
7b0960d… drh 4686 static int hasTimer(void){
7b0960d… drh 4687 if( getProcessTimesAddr ){
7b0960d… drh 4688 return 1;
7b0960d… drh 4689 } else {
7b0960d… drh 4690 /* GetProcessTimes() isn't supported in WIN95 and some other Windows
7b0960d… drh 4691 ** versions. See if the version we are running on has it, and if it
7b0960d… drh 4692 ** does, save off a pointer to it and the current process handle.
7b0960d… drh 4693 */
7b0960d… drh 4694 hProcess = GetCurrentProcess();
7b0960d… drh 4695 if( hProcess ){
7b0960d… drh 4696 HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
7b0960d… drh 4697 if( NULL != hinstLib ){
7b0960d… drh 4698 getProcessTimesAddr =
7b0960d… drh 4699 (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
7b0960d… drh 4700 if( NULL != getProcessTimesAddr ){
7b0960d… drh 4701 return 1;
7b0960d… drh 4702 }
7b0960d… drh 4703 FreeLibrary(hinstLib);
7b0960d… drh 4704 }
7b0960d… drh 4705 }
7b0960d… drh 4706 }
7b0960d… drh 4707 return 0;
7b0960d… drh 4708 }
7b0960d… drh 4709
7b0960d… drh 4710 /*
7b0960d… drh 4711 ** Begin timing an operation
7b0960d… drh 4712 */
7b0960d… drh 4713 static void beginTimer(ShellState *p){
7b0960d… drh 4714 if( (p->enableTimer || (p->flgProgress & SHELL_PROGRESS_TMOUT)!=0)
7b0960d… drh 4715 && getProcessTimesAddr
7b0960d… drh 4716 ){
7b0960d… drh 4717 FILETIME ftCreation, ftExit;
7b0960d… drh 4718 getProcessTimesAddr(hProcess,&ftCreation,&ftExit,
7b0960d… drh 4719 &ftKernelBegin,&ftUserBegin);
7b0960d… drh 4720 ftWallBegin = timeOfDay();
7b0960d… drh 4721 }
7b0960d… drh 4722 }
7b0960d… drh 4723
7b0960d… drh 4724 /* Return the difference of two FILETIME structs in seconds */
7b0960d… drh 4725 static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
7b0960d… drh 4726 sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
7b0960d… drh 4727 sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
7b0960d… drh 4728 return (double) ((i64End - i64Start) / 10000000.0);
7b0960d… drh 4729 }
7b0960d… drh 4730
6c6c1fe… drh 4731 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
7b0960d… drh 4732 /* Return the time since the start of the timer in
7b0960d… drh 4733 ** seconds. */
7b0960d… drh 4734 static double elapseTime(ShellState *NotUsed){
7b0960d… drh 4735 (void)NotUsed;
7b0960d… drh 4736 if( ftWallBegin==0 ) return 0.0;
7b0960d… drh 4737 return (timeOfDay() - ftWallBegin)*0.000001;
7b0960d… drh 4738 }
6c6c1fe… drh 4739 #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
7b0960d… drh 4740
7b0960d… drh 4741 /*
7b0960d… drh 4742 ** Print the timing results.
7b0960d… drh 4743 */
7b0960d… drh 4744 static void endTimer(ShellState *p){
7b0960d… drh 4745 if( p->enableTimer && getProcessTimesAddr){
7b0960d… drh 4746 FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
7b0960d… drh 4747 sqlite3_int64 ftWallEnd = timeOfDay();
7b0960d… drh 4748 getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
7b0960d… drh 4749 p->prevTimer = (ftWallEnd - ftWallBegin)*0.000001;
7b0960d… drh 4750 #ifdef _WIN64
7b0960d… drh 4751 /* microsecond precision on 64-bit windows */
7b0960d… drh 4752 cli_printf(p->out, "Run Time: real %.6f user %f sys %f\n",
7b0960d… drh 4753 p->prevTimer,
7b0960d… drh 4754 timeDiff(&ftUserBegin, &ftUserEnd),
7b0960d… drh 4755 timeDiff(&ftKernelBegin, &ftKernelEnd));
7b0960d… drh 4756 #else
7b0960d… drh 4757 /* millisecond precisino on 32-bit windows */
7b0960d… drh 4758 cli_printf(p->out, "Run Time: real %.3f user %.3f sys %.3f\n",
7b0960d… drh 4759 p->prevTimer,
7b0960d… drh 4760 timeDiff(&ftUserBegin, &ftUserEnd),
7b0960d… drh 4761 timeDiff(&ftKernelBegin, &ftKernelEnd));
7b0960d… drh 4762 #endif
7b0960d… drh 4763 if( p->enableTimer==1 ) p->enableTimer = 0;
7b0960d… drh 4764 ftWallBegin = 0;
7b0960d… drh 4765 }
7b0960d… drh 4766 }
7b0960d… drh 4767
7b0960d… drh 4768 #define BEGIN_TIMER(X) beginTimer(X)
7b0960d… drh 4769 #define ELAPSE_TIME(X) elapseTime(X)
7b0960d… drh 4770 #define END_TIMER(X) endTimer(X)
7b0960d… drh 4771 #define HAS_TIMER hasTimer()
7b0960d… drh 4772
7b0960d… drh 4773 #else
7b0960d… drh 4774 #define BEGIN_TIMER(X) /* no-op */
7b0960d… drh 4775 #define ELAPSE_TIME(X) 0.0
7b0960d… drh 4776 #define END_TIMER(X) /*no-op*/
7b0960d… drh 4777 #define HAS_TIMER 0
7b0960d… drh 4778 #endif
7b0960d… drh 4779 /************************* END PERFORMANCE TIMER ******************************/
4f76459… drh 4780
4f76459… drh 4781 /*
4f76459… drh 4782 ** Clear a display mode, freeing any allocated memory that it
4f76459… drh 4783 ** contains.
4f76459… drh 4784 */
4f76459… drh 4785 static void modeFree(Mode *p){
f07aa62… drh 4786 u8 autoExplain = p->autoExplain;
4f76459… drh 4787 free(p->spec.aWidth);
4f76459… drh 4788 free(p->spec.aAlign);
4f76459… drh 4789 free(p->spec.zColumnSep);
4f76459… drh 4790 free(p->spec.zRowSep);
4f76459… drh 4791 free(p->spec.zTableName);
4f76459… drh 4792 free(p->spec.zNull);
4f76459… drh 4793 memset(p, 0, sizeof(*p));
cb89386… drh 4794 p->spec.iVersion = 1;
f07aa62… drh 4795 p->autoExplain = autoExplain;
4f76459… drh 4796 }
4f76459… drh 4797
4f76459… drh 4798 /*
4f76459… drh 4799 ** Duplicate Mode pSrc into pDest. pDest is assumed to be
4f76459… drh 4800 ** uninitialized prior to invoking this routine.
4f76459… drh 4801 */
4f76459… drh 4802 static void modeDup(Mode *pDest, Mode *pSrc){
4f76459… drh 4803 memcpy(pDest, pSrc, sizeof(*pDest));
4f76459… drh 4804 if( pDest->spec.aWidth ){
4f76459… drh 4805 size_t sz = sizeof(pSrc->spec.aWidth[0]) * pSrc->spec.nWidth;
4f76459… drh 4806 pDest->spec.aWidth = malloc( sz );
4f76459… drh 4807 if( pDest->spec.aWidth ){
4f76459… drh 4808 memcpy(pDest->spec.aWidth, pSrc->spec.aWidth, sz);
4f76459… drh 4809 }else{
4f76459… drh 4810 pDest->spec.nWidth = 0;
4f76459… drh 4811 }
4f76459… drh 4812 }
4f76459… drh 4813 if( pDest->spec.aAlign ){
4f76459… drh 4814 size_t sz = sizeof(pSrc->spec.aAlign[0]) * pSrc->spec.nAlign;
4f76459… drh 4815 pDest->spec.aAlign = malloc( sz );
4f76459… drh 4816 if( pDest->spec.aAlign ){
4f76459… drh 4817 memcpy(pDest->spec.aAlign, pSrc->spec.aAlign, sz);
4f76459… drh 4818 }else{
4f76459… drh 4819 pDest->spec.nAlign = 0;
4f76459… drh 4820 }
4f76459… drh 4821 }
4f76459… drh 4822 if( pDest->spec.zColumnSep ){
4f76459… drh 4823 pDest->spec.zColumnSep = strdup(pSrc->spec.zColumnSep);
4f76459… drh 4824 }
4f76459… drh 4825 if( pDest->spec.zRowSep ){
4f76459… drh 4826 pDest->spec.zRowSep = strdup(pSrc->spec.zRowSep);
4f76459… drh 4827 }
4f76459… drh 4828 if( pDest->spec.zTableName ){
4f76459… drh 4829 pDest->spec.zTableName = strdup(pSrc->spec.zTableName);
4f76459… drh 4830 }
4f76459… drh 4831 if( pDest->spec.zNull ){
4f76459… drh 4832 pDest->spec.zNull = strdup(pSrc->spec.zNull);
4f76459… drh 4833 }
4f76459… drh 4834 }
4f76459… drh 4835
4f76459… drh 4836 /*
4f76459… drh 4837 ** Set a string value to a copy of the zNew string in memory
4f76459… drh 4838 ** obtained from system malloc().
4f76459… drh 4839 */
4f76459… drh 4840 static void modeSetStr(char **az, const char *zNew){
4f76459… drh 4841 free(*az);
4f76459… drh 4842 if( zNew==0 ){
4f76459… drh 4843 *az = 0;
4f76459… drh 4844 }else{
4f76459… drh 4845 size_t n = strlen(zNew);
4f76459… drh 4846 *az = malloc( n+1 );
4f76459… drh 4847 if( *az ){
4f76459… drh 4848 memcpy(*az, zNew, n+1 );
4f76459… drh 4849 }
4f76459… drh 4850 }
4f76459… drh 4851 }
4f76459… drh 4852
4f76459… drh 4853 /*
4f76459… drh 4854 ** Change the mode to eMode
4f76459… drh 4855 */
4f76459… drh 4856 static void modeChange(ShellState *p, unsigned char eMode){
4f76459… drh 4857 const ModeInfo *pI;
4f76459… drh 4858 if( eMode<ArraySize(aModeInfo) ){
4f76459… drh 4859 Mode *pM = &p->mode;
0276100… drh 4860 pI = &aModeInfo[eMode];
4f76459… drh 4861 pM->eMode = eMode;
4f76459… drh 4862 if( pI->eCSep ) modeSetStr(&pM->spec.zColumnSep, aModeStr[pI->eCSep]);
4f76459… drh 4863 if( pI->eRSep ) modeSetStr(&pM->spec.zRowSep, aModeStr[pI->eRSep]);
4f76459… drh 4864 if( pI->eNull ) modeSetStr(&pM->spec.zNull, aModeStr[pI->eNull]);
4f76459… drh 4865 pM->spec.eText = pI->eText;
4f76459… drh 4866 pM->spec.eBlob = pI->eBlob;
12e4a0f… drh 4867 if( (pM->mFlags & MFLG_HDR)==0 ){
12e4a0f… drh 4868 pM->spec.bTitles = pI->bHdr;
12e4a0f… drh 4869 }
4f76459… drh 4870 pM->spec.eTitle = pI->eHdr;
f4b3b59… drh 4871 if( pI->mFlg & 0x01 ){
f4b3b59… drh 4872 pM->spec.bBorder = QRF_No;
f4b3b59… drh 4873 }else{
f4b3b59… drh 4874 pM->spec.bBorder = QRF_Auto;
f4b3b59… drh 4875 }
f4b3b59… drh 4876 if( pI->mFlg & 0x02 ){
9aee493… drh 4877 pM->spec.bSplitColumn = QRF_Yes;
9aee493… drh 4878 pM->bAutoScreenWidth = 1;
9aee493… drh 4879 }else{
9aee493… drh 4880 pM->spec.bSplitColumn = QRF_No;
9aee493… drh 4881 }
4f76459… drh 4882 }else if( eMode>=MODE_USER && eMode-MODE_USER<p->nSavedModes ){
4f76459… drh 4883 modeFree(&p->mode);
4f76459… drh 4884 modeDup(&p->mode, &p->aSavedModes[eMode-MODE_USER].mode);
4f76459… drh 4885 }else if( eMode==MODE_BATCH ){
4f76459… drh 4886 u8 mFlags = p->mode.mFlags;
4f76459… drh 4887 modeFree(&p->mode);
4f76459… drh 4888 modeChange(p, MODE_List);
4f76459… drh 4889 p->mode.mFlags = mFlags;
4f76459… drh 4890 }else if( eMode==MODE_TTY ){
4f76459… drh 4891 u8 mFlags = p->mode.mFlags;
4f76459… drh 4892 modeFree(&p->mode);
4f76459… drh 4893 modeChange(p, MODE_QBox);
4f76459… drh 4894 p->mode.bAutoScreenWidth = 1;
709b566… drh 4895 p->mode.spec.eText = QRF_TEXT_Relaxed;
ae7e3f0… drh 4896 p->mode.spec.nCharLimit = DFLT_CHAR_LIMIT;
ae7e3f0… drh 4897 p->mode.spec.nLineLimit = DFLT_LINE_LIMIT;
4f76459… drh 4898 p->mode.spec.bTextJsonb = QRF_Yes;
ae7e3f0… drh 4899 p->mode.spec.nTitleLimit = DFLT_TITLE_LIMIT;
17f9878… drh 4900 p->mode.spec.nMultiInsert = DFLT_MULTI_INSERT;
4f76459… drh 4901 p->mode.mFlags = mFlags;
4f76459… drh 4902 }
4f76459… drh 4903 }
4f76459… drh 4904
4f76459… drh 4905 /*
5f65ed5… drh 4906 ** Set the mode to the default. It assumed that the mode has
5f65ed5… drh 4907 ** already been freed and zeroed prior to calling this routine.
4f76459… drh 4908 */
4f76459… drh 4909 static void modeDefault(ShellState *p){
cb89386… drh 4910 p->mode.spec.iVersion = 1;
4f76459… drh 4911 p->mode.autoExplain = 1;
5f65ed5… drh 4912 if( stdin_is_interactive || stdout_is_console ){
4f76459… drh 4913 modeChange(p, MODE_TTY);
4f76459… drh 4914 }else{
4f76459… drh 4915 modeChange(p, MODE_BATCH);
4f76459… drh 4916 }
4f76459… drh 4917 }
4f76459… drh 4918
4f76459… drh 4919 /*
4f76459… drh 4920 ** Find the number of a display mode given its name. Return -1 if
4f76459… drh 4921 ** the name does not match any mode.
4f76459… drh 4922 **
4f76459… drh 4923 ** Saved modes are also searched if p!=NULL. The number returned
4f76459… drh 4924 ** for a saved mode is the index into the p->aSavedModes[] array
4f76459… drh 4925 ** plus MODE_USER.
4f76459… drh 4926 **
4f76459… drh 4927 ** Two special mode names are also available: "batch" and "tty".
4f76459… drh 4928 ** evaluate to the default mode for batch operation and interactive
4f76459… drh 4929 ** operation on a TTY, respectively.
4f76459… drh 4930 */
4f76459… drh 4931 static int modeFind(ShellState *p, const char *zName){
4f76459… drh 4932 int i;
4f76459… drh 4933 for(i=0; i<ArraySize(aModeInfo); i++){
4f76459… drh 4934 if( cli_strcmp(aModeInfo[i].zName,zName)==0 ) return i;
4f76459… drh 4935 }
4f76459… drh 4936 for(i=0; i<p->nSavedModes; i++){
4f76459… drh 4937 if( cli_strcmp(p->aSavedModes[i].zTag,zName)==0 ) return i+MODE_USER;
4f76459… drh 4938 }
4f76459… drh 4939 if( strcmp(zName,"batch")==0 ) return MODE_BATCH;
4f76459… drh 4940 if( strcmp(zName,"tty")==0 ) return MODE_TTY;
4f76459… drh 4941 return -1;
4f76459… drh 4942 }
4f76459… drh 4943
4f76459… drh 4944 /*
4f76459… drh 4945 ** Save or restore the current output mode
4f76459… drh 4946 */
4f76459… drh 4947 static void modePush(ShellState *p){
4f76459… drh 4948 if( p->nPopMode==0 ){
4f76459… drh 4949 modeFree(&p->modePrior);
4f76459… drh 4950 modeDup(&p->modePrior,&p->mode);
4f76459… drh 4951 }
4f76459… drh 4952 }
4f76459… drh 4953 static void modePop(ShellState *p){
4f76459… drh 4954 if( p->modePrior.spec.iVersion>0 ){
4f76459… drh 4955 modeFree(&p->mode);
4f76459… drh 4956 p->mode = p->modePrior;
4f76459… drh 4957 memset(&p->modePrior, 0, sizeof(p->modePrior));
4f76459… drh 4958 }
4f76459… drh 4959 }
4f76459… drh 4960
4f76459… drh 4961 cli_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
4f76459… drh 4962 cli_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
4f76459… drh 4963 }
4f76459… drh 4964
4f76459… drh 4965 /*
4f76459… drh 4966 ** Compute the name of the location of an input error in memory
4f76459… drh 4967 ** obtained from sqlite3_malloc().
4f76459… drh 4968 */
4f76459… drh 4969 static char *shellErrorLocation(ShellState *p){
4f76459… drh 4970 char *zLoc;
4f76459… drh 4971 if( p->zErrPrefix ){
4f76459… drh 4972 zLoc = sqlite3_mprintf("%s", p->zErrPrefix);
4f76459… drh 4973 }else if( p->zInFile==0 || strcmp(p->zInFile,"<stdin>")==0){
4f76459… drh 4974 zLoc = sqlite3_mprintf("line %lld:", p->lineno);
4f76459… drh 4975 }else{
4f76459… drh 4976 zLoc = sqlite3_mprintf("%s:%lld:", p->zInFile, p->lineno);
4f76459… drh 4977 }
4f76459… drh 4978 return zLoc;
4f76459… drh 4979 char *zLoc = shellErrorLocation(p);
4f76459… drh 4980 cli_printf(stderr, "%s %s\n", zLoc, zMsg);
4f76459… drh 4981 cli_exit(1);
4f76459… drh 4982
4f76459… drh 4983 /*
4f76459… drh 4984 ** Issue an error message from a dot-command.
4f76459… drh 4985 */
4f76459… drh 4986 static void dotCmdError(
4f76459… drh 4987 ShellState *p, /* Shell state */
4f76459… drh 4988 int iArg, /* Index of argument on which error occurred */
4f76459… drh 4989 const char *zBrief, /* Brief (<20 character) error description */
4f76459… drh 4990 const char *zDetail, /* Error details */
4f76459… drh 4991 ...
4f76459… drh 4992 ){
4f76459… drh 4993 FILE *out = stderr;
4f76459… drh 4994 char *zLoc = shellErrorLocation(p);
4f76459… drh 4995 if( zBrief!=0 && iArg>=0 && iArg<p->dot.nArg ){
4f76459… drh 4996 int i = p->dot.aiOfst[iArg];
4f76459… drh 4997 int nPrompt = strlen30(zBrief) + 5;
4f76459… drh 4998 cli_printf(out, "%s %s\n", zLoc, p->dot.zOrig);
4f76459… drh 4999 if( i > nPrompt ){
4f76459… drh 5000 cli_printf(out, "%s %*s%s ---^\n", zLoc, 1+i-nPrompt, "", zBrief);
4f76459… drh 5001 }else{
4f76459… drh 5002 cli_printf(out, "%s %*s^--- %s\n", zLoc, i, "", zBrief);
4f76459… drh 5003 }
4f76459… drh 5004 }
4f76459… drh 5005 if( zDetail ){
4f76459… drh 5006 char *zMsg;
4f76459… drh 5007 va_list ap;
4f76459… drh 5008 va_start(ap, zDetail);
4f76459… drh 5009 zMsg = sqlite3_vmprintf(zDetail,ap);
4f76459… drh 5010 va_end(ap);
4f76459… drh 5011 cli_printf(out,"%s %s\n", zLoc, zMsg);
4f76459… drh 5012 sqlite3_free(zMsg);
4f76459… drh 5013 }
4f76459… drh 5014 sqlite3_free(zLoc);
4f76459… drh 5015 }
4f76459… drh 5016
4f76459… drh 5017 if( p->mode.mFlags & MFLG_CRLF ){
4f76459… drh 5018 cli_puts(zq, out);
4f76459… drh 5019 if( z==0 ) z = "";
4f76459… drh 5020 while( *z!=0 ){
4f76459… drh 5021 const char *pcDQBSRO = anyOfInStr(z, zDQBSRO, ~(size_t)0);
4f76459… drh 5022 const char *pcPast = zSkipValidUtf8(z, INT_MAX, ctrlMask);
4f76459… drh 5023 const char *pcEnd = (pcDQBSRO && pcDQBSRO < pcPast)? pcDQBSRO : pcPast;
4f76459… drh 5024 if( pcEnd > z ){
4f76459… drh 5025 cli_printf(out, "%.*s", (int)(pcEnd-z), z);
4f76459… drh 5026 }
4f76459… drh 5027 if( (c = *pcEnd)==0 ) break;
4f76459… drh 5028 ++pcEnd;
4f76459… drh 5029 switch( c ){
4f76459… drh 5030 case '\\': case '"':
4f76459… drh 5031 cbsSay = (char)c;
4f76459… drh 5032 break;
4f76459… drh 5033 case '\t': cbsSay = 't'; break;
4f76459… drh 5034 case '\n': cbsSay = 'n'; break;
4f76459… drh 5035 case '\r': cbsSay = 'r'; break;
4f76459… drh 5036 case '\f': cbsSay = 'f'; break;
4f76459… drh 5037 default: cbsSay = 0; break;
4f76459… drh 5038 }
4f76459… drh 5039 if( cbsSay ){
4f76459… drh 5040 ace[1] = cbsSay;
4f76459… drh 5041 cli_puts(ace, out);
4f76459… drh 5042 }else if( !isprint(c&0xff) ){
4f76459… drh 5043 cli_printf(out, "\\%03o", c&0xff);
4f76459… drh 5044 }else{
4f76459… drh 5045 ace[1] = (char)c;
4f76459… drh 5046 cli_puts(ace+1, out);
4f76459… drh 5047 }
4f76459… drh 5048 z = pcEnd;
4f76459… drh 5049 }
4f76459… drh 5050 cli_puts(zq, out);
4f76459… drh 5051 }
4f76459… drh 5052
4f76459… drh 5053 /* Encode input string z[] as a C-language string literal and
4f76459… drh 5054 ** append it to the sqlite3_str. If z is NULL render and empty string.
4f76459… drh 5055 */
4f76459… drh 5056 static void append_c_string(sqlite3_str *out, const char *z){
4f76459… drh 5057 char c;
4f76459… drh 5058 static const char *zq = "\"";
4f76459… drh 5059 static long ctrlMask = ~0L;
4f76459… drh 5060 static const char *zDQBSRO = "\"\\\x7f"; /* double-quote, backslash, rubout */
4f76459… drh 5061 char ace[3] = "\\?";
4f76459… drh 5062 char cbsSay;
4f76459… drh 5063 if( z==0 ) z = "";
4f76459… drh 5064 sqlite3_str_appendall(out,zq);
4f76459… drh 5065 sqlite3_str_appendf(out, "%.*s", (int)(pcEnd-z), z);
4f76459… drh 5066 sqlite3_str_appendall(out,ace);
4f76459… drh 5067 }else if( !isprint(c&0xff) ){
4f76459… drh 5068 sqlite3_str_appendf(out, "\\%03o", c&0xff);
4f76459… drh 5069 }else{
4f76459… drh 5070 ace[1] = (char)c;
4f76459… drh 5071 sqlite3_str_appendall(out, ace+1);
4f76459… drh 5072 }
4f76459… drh 5073 z = pcEnd;
4f76459… drh 5074 }
4f76459… drh 5075 sqlite3_str_appendall(out, zq);
4f76459… drh 5076 if( ++seenInterrupt>1 ) cli_exit(1);
4f76459… drh 5077 }
4f76459… drh 5078
4f76459… drh 5079 /* Try to determine the screen width. Use the default if unable.
4f76459… drh 5080 */
4f76459… drh 5081 int shellScreenWidth(void){
0276100… drh 5082 if( stdout_tty_width>0 ){
0276100… drh 5083 return stdout_tty_width;
0276100… drh 5084 }else{
4f76459… drh 5085 #if defined(TIOCGSIZE)
0276100… drh 5086 struct ttysize ts;
0276100… drh 5087 if( ioctl(STDIN_FILENO, TIOCGSIZE, &ts)>=0
0276100… drh 5088 || ioctl(STDOUT_FILENO, TIOCGSIZE, &ts)>=0
0276100… drh 5089 || ioctl(STDERR_FILENO, TIOCGSIZE, &ts)>=0
0276100… drh 5090 ){
0276100… drh 5091 return ts.ts_cols;
0276100… drh 5092 }
4f76459… drh 5093 #elif defined(TIOCGWINSZ)
0276100… drh 5094 struct winsize ws;
0276100… drh 5095 if( ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)>=0
0276100… drh 5096 || ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)>=0
0276100… drh 5097 || ioctl(STDERR_FILENO, TIOCGWINSZ, &ws)>=0
0276100… drh 5098 ){
0276100… drh 5099 return ws.ws_col;
0276100… drh 5100 }
4f76459… drh 5101 #elif defined(_WIN32)
0276100… drh 5102 CONSOLE_SCREEN_BUFFER_INFO csbi;
0276100… drh 5103 if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)
0276100… drh 5104 || GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)
0276100… drh 5105 || GetConsoleScreenBufferInfo(GetStdHandle(STD_INPUT_HANDLE), &csbi)
0276100… drh 5106 ){
0276100… drh 5107 return csbi.srWindow.Right - csbi.srWindow.Left + 1;
0276100… drh 5108 }
4f76459… drh 5109 #endif
4f76459… drh 5110 #define DEFAULT_SCREEN_WIDTH 80
0276100… drh 5111 return DEFAULT_SCREEN_WIDTH;
0276100… drh 5112 }
81eeb1c… drh 5113 "realpath",
4f76459… drh 5114 cli_printf(p->out, "authorizer: %s", azAction[op]);
4f76459… drh 5115 cli_puts(" ", p->out);
4f76459… drh 5116 cli_puts("NULL", p->out);
4f76459… drh 5117 cli_puts("\n", p->out);
4f76459… drh 5118 ** Print a schema statement. This is helper routine to dump_callbac().
4f76459… drh 5119 cli_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
4f76459… drh 5120 cli_printf(out, "%s%s", z, zTail);
4f76459… drh 5121 ** SQL Function: shell_format_schema(SQL,FLAGS)
4f76459… drh 5122 **
4f76459… drh 5123 ** This function is internally by the CLI to assist with the
4f76459… drh 5124 ** ".schema", ".fullschema", and ".dump" commands. The first
4f76459… drh 5125 ** argument is the value from sqlite_schema.sql. The value returned
4f76459… drh 5126 ** is a modification of the input that can actually be run as SQL
4f76459… drh 5127 ** to recreate the schema object.
4f76459… drh 5128 **
4f76459… drh 5129 ** When FLAGS is zero, the only changes is to append ";". If the
4f76459… drh 5130 ** 0x01 bit of FLAGS is set, then transformations are made to implement
4f76459… drh 5131 ** ".schema --indent".
4f76459… drh 5132 */
4f76459… drh 5133 static void shellFormatSchema(
4f76459… drh 5134 sqlite3_context *pCtx,
4f76459… drh 5135 int nVal,
4f76459… drh 5136 sqlite3_value **apVal
4f76459… drh 5137 ){
4f76459… drh 5138 int flags; /* Value of 2nd parameter */
4f76459… drh 5139 const char *zSql; /* Value of 1st parameter */
4f76459… drh 5140 int nSql; /* Bytes of text in zSql[] */
4f76459… drh 5141 sqlite3_str *pOut; /* Output buffer */
4f76459… drh 5142 char *z; /* Writable copy of zSql */
4f76459… drh 5143 int i, j; /* Loop counters */
4f76459… drh 5144 int nParen = 0;
4f76459… drh 5145 char cEnd = 0;
4f76459… drh 5146 char c;
4f76459… drh 5147 int nLine = 0;
4f76459… drh 5148 int isIndex;
4f76459… drh 5149 int isWhere = 0;
4f76459… drh 5150
4f76459… drh 5151 assert( nVal==2 );
4f76459… drh 5152 pOut = sqlite3_str_new(sqlite3_context_db_handle(pCtx));
4f76459… drh 5153 nSql = sqlite3_value_bytes(apVal[0]);
4f76459… drh 5154 zSql = (const char*)sqlite3_value_text(apVal[0]);
4f76459… drh 5155 if( zSql==0 || zSql[0]==0 ) goto shellFormatSchema_finish;
4f76459… drh 5156 flags = sqlite3_value_int(apVal[1]);
4f76459… drh 5157 if( (flags & 0x01)==0 ){
4f76459… drh 5158 sqlite3_str_append(pOut, zSql, nSql);
4f76459… drh 5159 sqlite3_str_append(pOut, ";", 1);
4f76459… drh 5160 goto shellFormatSchema_finish;
4f76459… drh 5161 }
4f76459… drh 5162 if( sqlite3_strlike("CREATE VIEW%", zSql, 0)==0
4f76459… drh 5163 || sqlite3_strlike("CREATE TRIG%", zSql, 0)==0
4f76459… drh 5164 ){
4f76459… drh 5165 sqlite3_str_append(pOut, zSql, nSql);
4f76459… drh 5166 sqlite3_str_append(pOut, ";", 1);
4f76459… drh 5167 goto shellFormatSchema_finish;
4f76459… drh 5168 }
4f76459… drh 5169 isIndex = sqlite3_strlike("CREATE INDEX%", zSql, 0)==0
4f76459… drh 5170 || sqlite3_strlike("CREATE UNIQUE INDEX%", zSql, 0)==0;
4f76459… drh 5171 z = sqlite3_mprintf("%s", zSql);
4f76459… drh 5172 if( z==0 ){
4f76459… drh 5173 sqlite3_str_free(pOut);
4f76459… drh 5174 sqlite3_result_error_nomem(pCtx);
4f76459… drh 5175 return;
4f76459… drh 5176 }
4f76459… drh 5177 j = 0;
4f76459… drh 5178 for(i=0; IsSpace(z[i]); i++){}
4f76459… drh 5179 for(; (c = z[i])!=0; i++){
4f76459… drh 5180 if( IsSpace(c) ){
4f76459… drh 5181 if( z[j-1]=='\r' ) z[j-1] = '\n';
4f76459… drh 5182 if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
4f76459… drh 5183 }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
4f76459… drh 5184 j--;
4f76459… drh 5185 }
4f76459… drh 5186 z[j++] = c;
4f76459… drh 5187 }
4f76459… drh 5188 while( j>0 && IsSpace(z[j-1]) ){ j--; }
4f76459… drh 5189 z[j] = 0;
4f76459… drh 5190 if( strlen30(z)>=79 ){
4f76459… drh 5191 for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */
4f76459… drh 5192 if( c==cEnd ){
4f76459… drh 5193 cEnd = 0;
d326547… drh 5194 }else if( cEnd!=0){
d326547… drh 5195 /* No-op */
4f76459… drh 5196 }else if( c=='"' || c=='\'' || c=='`' ){
4f76459… drh 5197 cEnd = c;
4f76459… drh 5198 }else if( c=='[' ){
4f76459… drh 5199 cEnd = ']';
4f76459… drh 5200 }else if( c=='-' && z[i+1]=='-' ){
4f76459… drh 5201 cEnd = '\n';
4f76459… drh 5202 }else if( c=='(' ){
4f76459… drh 5203 nParen++;
4f76459… drh 5204 }else if( c==')' ){
4f76459… drh 5205 nParen--;
4f76459… drh 5206 if( nLine>0 && nParen==0 && j>0 && !isWhere ){
4f76459… drh 5207 sqlite3_str_append(pOut, z, j);
4f76459… drh 5208 sqlite3_str_append(pOut, "\n", 1);
4f76459… drh 5209 j = 0;
4f76459… drh 5210 }
4f76459… drh 5211 }else if( (c=='w' || c=='W')
4f76459… drh 5212 && nParen==0 && isIndex
4f76459… drh 5213 && sqlite3_strnicmp("WHERE",&z[i],5)==0
4f76459… drh 5214 && !IsAlnum(z[i+5]) && z[i+5]!='_' ){
4f76459… drh 5215 isWhere = 1;
4f76459… drh 5216 }else if( isWhere && (c=='A' || c=='a')
4f76459… drh 5217 && nParen==0
4f76459… drh 5218 && sqlite3_strnicmp("AND",&z[i],3)==0
4f76459… drh 5219 && !IsAlnum(z[i+3]) && z[i+3]!='_' ){
4f76459… drh 5220 sqlite3_str_append(pOut, z, j);
4f76459… drh 5221 sqlite3_str_append(pOut, "\n ", 5);
4f76459… drh 5222 j = 0;
4f76459… drh 5223 }
4f76459… drh 5224 z[j++] = c;
4f76459… drh 5225 if( nParen==1 && cEnd==0
4f76459… drh 5226 && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
4f76459… drh 5227 && !isWhere
4f76459… drh 5228 ){
4f76459… drh 5229 if( c=='\n' ) j--;
4f76459… drh 5230 sqlite3_str_append(pOut, z, j);
4f76459… drh 5231 sqlite3_str_append(pOut, "\n ", 3);
4f76459… drh 5232 j = 0;
4f76459… drh 5233 nLine++;
4f76459… drh 5234 while( IsSpace(z[i+1]) ){ i++; }
4f76459… drh 5235 }
4f76459… drh 5236 }
4f76459… drh 5237 z[j] = 0;
4f76459… drh 5238 }
4f76459… drh 5239 sqlite3_str_appendall(pOut, z);
4f76459… drh 5240 sqlite3_str_append(pOut, ";", 1);
4f76459… drh 5241 sqlite3_free(z);
4f76459… drh 5242
4f76459… drh 5243 shellFormatSchema_finish:
4f76459… drh 5244 sqlite3_result_text(pCtx, sqlite3_str_finish(pOut), -1, sqlite3_free);
7b0960d… drh 5245 if( (p->flgProgress & SHELL_PROGRESS_TMOUT)!=0
7b0960d… drh 5246 && ELAPSE_TIME(p)>=p->tmProgress
7b0960d… drh 5247 ){
7b0960d… drh 5248 cli_printf(p->out, "Progress timeout after %.6f seconds\n",
7b0960d… drh 5249 ELAPSE_TIME(p));
7b0960d… drh 5250 return 1;
7b0960d… drh 5251 }
4f76459… drh 5252 cli_printf(p->out, "Progress limit reached (%u)\n", p->nProgress);
4f76459… drh 5253 cli_printf(p->out, "Progress %u\n", p->nProgress);
4f76459… drh 5254 cli_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
4f76459… drh 5255 p->zDestTable = sqlite3_mprintf("%s", zName);
4f76459… drh 5256 cli_printf(p->out, "/**** ERROR: (%d) %s *****/\n%s",
4f76459… drh 5257 cli_printf(p->out, "%s", z);
4f76459… drh 5258 cli_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
4f76459… drh 5259 cli_puts("\n;\n", p->out);
4f76459… drh 5260 cli_puts(";\n", p->out);
4f76459… drh 5261 cli_printf(p->out, "/**** ERROR: (%d) %s *****/\n",
4f76459… drh 5262 cli_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
4f76459… drh 5263 cli_printf(out, "%-36s %s\n", zLabel, zLine);
3c639f7… drh 5264 int iCur, iHiwtr;
3c639f7… drh 5265 sqlite3_int64 iCur64, iHiwtr64;
4f76459… drh 5266 cli_printf(out, "%-36s %d\n", "Number of output columns:", nCol);
4f76459… drh 5267 cli_printf(out, "%-36s %s\n", z, sqlite3_column_name(pStmt,i));
4f76459… drh 5268 cli_printf(out, "%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
4f76459… drh 5269 cli_printf(out, "%-36s %s\n", z,
4f76459… drh 5270 cli_printf(out, "%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
4f76459… drh 5271 cli_printf(out, "%-36s %s\n", z,sqlite3_column_origin_name(pStmt,i));
4f76459… drh 5272 cli_printf(out, "VM-steps: %d\n", iCur);
4f76459… drh 5273 cli_printf(out,
4f76459… drh 5274 cli_printf(out,
4f76459… drh 5275 cli_printf(out,
4f76459… drh 5276 cli_printf(out,
4f76459… drh 5277 cli_printf(out,
4f76459… drh 5278 cli_printf(out,
4f76459… drh 5279 cli_printf(out,
3c639f7… drh 5280 iHiwtr64 = iCur64 = -1;
3c639f7… drh 5281 sqlite3_db_status64(db, SQLITE_DBSTATUS_TEMPBUF_SPILL, &iCur64, &iHiwtr64,
3c639f7… drh 5282 0);
4f76459… drh 5283 cli_printf(out,
4f76459… drh 5284 cli_printf(out,
4f76459… drh 5285 cli_printf(out,
3c639f7… drh 5286 "Temporary data spilled to disk: %lld\n", iCur64);
3c639f7… drh 5287 sqlite3_db_status64(db, SQLITE_DBSTATUS_TEMPBUF_SPILL, &iCur64, &iHiwtr64,
3c639f7… drh 5288 1);
4f76459… drh 5289 cli_printf(out,
4f76459… drh 5290 cli_printf(out,
4f76459… drh 5291 cli_printf(out,
4f76459… drh 5292 cli_printf(out,
4f76459… drh 5293 cli_printf(out,
4f76459… drh 5294 cli_printf(out,
4f76459… drh 5295 cli_printf(out,
4f76459… drh 5296 cli_printf(out,
4f76459… drh 5297 cli_printf(out,
4f76459… drh 5298 cli_printf(out,
7b0960d… drh 5299 }else if( strcmp(zVar, "$TIMER")==0 ){
7b0960d… drh 5300 sqlite3_bind_double(pStmt, i, pArg->prevTimer);
70539ee… drh 5301 #ifdef SQLITE_ENABLE_CARRAY
70539ee… drh 5302 }else if( strncmp(zVar, "$carray_", 8)==0 ){
70539ee… drh 5303 static char *azColorNames[] = {
70539ee… drh 5304 "azure", "black", "blue", "brown", "cyan", "fuchsia", "gold",
70539ee… drh 5305 "gray", "green", "indigo", "khaki", "lime", "magenta", "maroon",
70539ee… drh 5306 "navy", "olive", "orange", "pink", "purple", "red", "silver",
70539ee… drh 5307 "tan", "teal", "violet", "white", "yellow"
70539ee… drh 5308 };
70539ee… drh 5309 static int aPrimes[] = {
70539ee… drh 5310 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
70539ee… drh 5311 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
70539ee… drh 5312 };
70539ee… drh 5313 /* Special bindings: carray($carray_clr), carray($carray_primes)
70539ee… drh 5314 ** with --unsafe-testing: carray($carray_clr_p,26,'char*'),
70539ee… drh 5315 ** carray($carray_primes_p,26,'int32')
70539ee… drh 5316 */
70539ee… drh 5317 if( strcmp(zVar+8,"clr")==0 ){
70539ee… drh 5318 sqlite3_carray_bind(pStmt,i,azColorNames,26,SQLITE_CARRAY_TEXT,0);
70539ee… drh 5319 }else if( strcmp(zVar+8,"primes")==0 ){
70539ee… drh 5320 sqlite3_carray_bind(pStmt,i,aPrimes,26,SQLITE_CARRAY_INT32,0);
70539ee… drh 5321 }else if( strcmp(zVar+8,"clr_p")==0
70539ee… drh 5322 && ShellHasFlag(pArg,SHFLG_TestingMode) ){
70539ee… drh 5323 sqlite3_bind_pointer(pStmt,i,azColorNames,"carray",0);
70539ee… drh 5324 }else if( strcmp(zVar+8,"primes_p")==0
70539ee… drh 5325 && ShellHasFlag(pArg,SHFLG_TestingMode) ){
70539ee… drh 5326 sqlite3_bind_pointer(pStmt,i,aPrimes,"carray",0);
70539ee… drh 5327 }else{
70539ee… drh 5328 sqlite3_bind_null(pStmt, i);
70539ee… drh 5329 }
70539ee… drh 5330 #endif
4f76459… drh 5331 cli_puts("-- Candidates -----------------------------\n", out);
4f76459… drh 5332 cli_printf(out, "%s\n", zCand);
4f76459… drh 5333 cli_printf(out,
4f76459… drh 5334 cli_printf(out, "%s\n%s\n", zIdx, zEQP);
4f76459… drh 5335 cli_printf(stderr, "option requires an argument: %s\n", z);
4f76459… drh 5336 cli_printf(stderr,"value out of range: %s\n", azArg[i]);
4f76459… drh 5337 cli_printf(stderr,"unknown option: %s\n", z);
4f76459… drh 5338 cli_printf(stderr,
4f76459… drh 5339
4f76459… drh 5340 /*
4f76459… drh 5341 ** QRF write callback
4f76459… drh 5342 */
4f76459… drh 5343 static int shellWriteQR(void *pX, const char *z, sqlite3_int64 n){
4f76459… drh 5344 ShellState *pArg = (ShellState*)pX;
4f76459… drh 5345 cli_printf(pArg->out, "%.*s", (int)n, z);
4f76459… drh 5346 return SQLITE_OK;
4f76459… drh 5347 }
4f76459… drh 5348 unsigned char eStyle;
4f76459… drh 5349 sqlite3_qrf_spec spec;
4f76459… drh 5350 }
4f76459… drh 5351 memcpy(&spec, &pArg->mode.spec, sizeof(spec));
4f76459… drh 5352 spec.xWrite = shellWriteQR;
4f76459… drh 5353 spec.pWriteArg = (void*)pArg;
cb89386… drh 5354 if( pArg->mode.eMode==MODE_Insert && ShellHasFlag(pArg,SHFLG_PreserveRowid) ){
4f76459… drh 5355 spec.bTitles = QRF_SW_On;
4f76459… drh 5356 }
cb89386… drh 5357 /* ,- This is true, but it is omitted
cb89386… drh 5358 ** vvvvvvvvvvvvvvvvvvv ----- to avoid compiler warnings. */
cb89386… drh 5359 assert( /*pArg->mode.eMode>=0 &&*/ pArg->mode.eMode<ArraySize(aModeInfo) );
4f76459… drh 5360 eStyle = aModeInfo[pArg->mode.eMode].eStyle;
4f76459… drh 5361 if( pArg->mode.bAutoScreenWidth ){
4f76459… drh 5362 spec.nScreenWidth = shellScreenWidth();
45de97f… drh 5363 }
45de97f… drh 5364 if( spec.eBlob==QRF_BLOB_Auto ){
45de97f… drh 5365 switch( spec.eText ){
709b566… drh 5366 case QRF_TEXT_Relaxed: /* fall through */
45de97f… drh 5367 case QRF_TEXT_Sql: spec.eBlob = QRF_BLOB_Sql; break;
45de97f… drh 5368 case QRF_TEXT_Json: spec.eBlob = QRF_BLOB_Json; break;
45de97f… drh 5369 default: spec.eBlob = QRF_BLOB_Text; break;
45de97f… drh 5370 }
d326547… drh 5371 while( zSql && zSql[0] && (SQLITE_OK == rc) ){
4f76459… drh 5372 int isExplain;
4f76459… drh 5373 /* save off the prepared statement handle */
4f76459… drh 5374
4f76459… drh 5375 isExplain = sqlite3_stmt_isexplain(pStmt);
7b0960d… drh 5376 if( pArg && pArg->mode.autoEQP && isExplain==0 && pArg->dot.nArg==0 ){
7b0960d… drh 5377 u8 savedEnableTimer = pArg->enableTimer;
7b0960d… drh 5378 pArg->enableTimer = 0;
4f76459… drh 5379 if( pArg->mode.autoEQP>=AUTOEQP_trigger ){
4f76459… drh 5380 sqlite3_reset(pStmt);
4f76459… drh 5381 spec.eStyle = QRF_STYLE_Auto;
13c221a… drh 5382 sqlite3_stmt_explain(pStmt, 2);
4f76459… drh 5383 sqlite3_format_query_result(pStmt, &spec, 0);
13c221a… drh 5384 if( pArg->mode.autoEQP>=AUTOEQP_full ){
13c221a… drh 5385 sqlite3_reset(pStmt);
13c221a… drh 5386 sqlite3_stmt_explain(pStmt, 1);
13c221a… drh 5387 sqlite3_format_query_result(pStmt, &spec, 0);
13c221a… drh 5388 }
13c221a… drh 5389
4f76459… drh 5390 if( pArg->mode.autoEQP>=AUTOEQP_trigger && triggerEQP==0 ){
7b0960d… drh 5391 pArg->enableTimer = savedEnableTimer;
4f76459… drh 5392 if( isExplain && pArg->mode.autoExplain ){
4f76459… drh 5393 spec.eStyle = isExplain==1 ? QRF_STYLE_Explain : QRF_STYLE_Eqp;
4f76459… drh 5394 sqlite3_format_query_result(pStmt, &spec, pzErrMsg);
4f76459… drh 5395 }else if( pArg->mode.eMode==MODE_Www ){
4f76459… drh 5396 cli_printf(pArg->out,
4f76459… drh 5397 "</PRE>\n"
4f76459… drh 5398 "<TABLE border='1' cellspacing='0' cellpadding='2'>\n");
4f76459… drh 5399 spec.eStyle = QRF_STYLE_Html;
4f76459… drh 5400 sqlite3_format_query_result(pStmt, &spec, pzErrMsg);
4f76459… drh 5401 cli_printf(pArg->out,
4f76459… drh 5402 "</TABLE>\n"
4f76459… drh 5403 "<PRE>");
4f76459… drh 5404 }else{
4f76459… drh 5405 spec.eStyle = eStyle;
4f76459… drh 5406 sqlite3_format_query_result(pStmt, &spec, pzErrMsg);
4f76459… drh 5407 }
4f76459… drh 5408 if( pArg && pArg->mode.scanstatsOn ){
4f76459… drh 5409 char *zErr = 0;
4f76459… drh 5410 switch( pArg->mode.scanstatsOn ){
4f76459… drh 5411 case 1: spec.eStyle = QRF_STYLE_Stats; break;
4f76459… drh 5412 case 2: spec.eStyle = QRF_STYLE_StatsEst; break;
4f76459… drh 5413 default: spec.eStyle = QRF_STYLE_StatsVm; break;
4f76459… drh 5414 }
4f76459… drh 5415 sqlite3_reset(pStmt);
4f76459… drh 5416 rc = sqlite3_format_query_result(pStmt, &spec, &zErr);
4f76459… drh 5417 if( rc ){
4f76459… drh 5418 cli_printf(stderr, "Stats query failed: %s\n", zErr);
4f76459… drh 5419 sqlite3_free(zErr);
4f76459… drh 5420 }
8690598… drh 5421 /* Forward reference */
8690598… drh 5422 static int db_int(sqlite3 *db, const char *zSql, ...);
8690598… drh 5423
8690598… drh 5424 /* The sqlite_sequence table is repopulated last. Delete content
8690598… drh 5425 ** in the sqlite_sequence table added by prior repopulations prior to
8690598… drh 5426 ** repopulating sqlite_sequence itself. But only do this if the
8690598… drh 5427 ** table is non-empty, because if it is empty the table might not
8690598… drh 5428 ** have been recreated by prior repopulations. See forum posts:
8690598… drh 5429 ** 2024-10-13T17:10:01z and 2025-10-29T19:38:43z
8690598… drh 5430 */
8690598… drh 5431 if( db_int(p->db, "SELECT count(*) FROM sqlite_sequence")>0 ){
8690598… drh 5432 if( !p->writableSchema ){
4f76459… drh 5433 cli_puts("PRAGMA writable_schema=ON;\n", p->out);
8690598… drh 5434 p->writableSchema = 1;
8690598… drh 5435 }
4f76459… drh 5436 cli_puts("CREATE TABLE IF NOT EXISTS sqlite_sequence(name,seq);\n"
8690598… drh 5437 "DELETE FROM sqlite_sequence;\n", p->out);
8690598… drh 5438 }
4f76459… drh 5439 if( !dataOnly ) cli_puts("ANALYZE sqlite_schema;\n", p->out);
4f76459… drh 5440 cli_puts("PRAGMA writable_schema=ON;\n", p->out);
4f76459… drh 5441 cli_printf(p->out, "%s\n", zIns);
4f76459… drh 5442 Mode savedMode;
4f76459… drh 5443
4f76459… drh 5444 p->mode.spec.zTableName = (char*)zTable;
4f76459… drh 5445 p->mode.eMode = MODE_Insert;
45de97f… drh 5446 p->mode.spec.eText = QRF_TEXT_Sql;
45de97f… drh 5447 p->mode.spec.eBlob = QRF_BLOB_Sql;
4f76459… drh 5448 p->mode.spec.bTitles = QRF_No;
17f9878… drh 5449 p->mode.spec.nCharLimit = 0;
4f76459… drh 5450 cli_puts("/****** CORRUPTION ERROR *******/\n", p->out);
4f76459… drh 5451 cli_puts("/****** CORRUPTION ERROR *******/\n", p->out);
4f76459… drh 5452 cli_printf(p->out, "/****** %s ******/\n", zErr);
4f76459… drh 5453 cli_printf(p->out, "/****** ERROR: %s ******/\n", zErr);
5f65ed5… drh 5454 ".check OPTIONS ... Verify the results of a .testcase",
4f76459… drh 5455 ",headers on|off Turn display of headers on or off",
3c639f7… drh 5456 ".imposter INDEX TABLE Create imposter table TABLE on index INDEX",
17f9878… drh 5457 ".indexes ?PATTERN? Show names of indexes matching PATTERN",
17f9878… drh 5458 " -a|--all Also show system-generated indexes",
17f9878… drh 5459 " --expr Show only expression indexes",
17f9878… drh 5460 " --sys Show only system-generated indexes",
92871e0… drh 5461 " --normal FILE is an ordinary SQLite database",
7b0960d… drh 5462 " --timeout S Halt after running for S seconds",
4f76459… drh 5463 ",separator COL ?ROW? Change the column and row separators",
4f76459… drh 5464 ",show Show the current values for various settings",
5f65ed5… drh 5465 ".testcase NAME Begin a test case.",
7b0960d… drh 5466 ".timer on|off|once Turn SQL timer on or off.",
4f76459… drh 5467 ",width NUM1 NUM2 ... Set minimum column widths for columnar output",
4f76459… drh 5468
4f76459… drh 5469 /**************************************************************
4f76459… drh 5470 ** "Usage" help text automatically generated from comments */
4f76459… drh 5471 static const struct {
4f76459… drh 5472 const char *zCmd; /* Name of the dot-command */
4f76459… drh 5473 const char *zUsage; /* Documentation */
4f76459… drh 5474 } aUsage[] = {
4f76459… drh 5475 { ".import",
4f76459… drh 5476 "USAGE: .import [OPTIONS] FILE TABLE\n"
4f76459… drh 5477 "\n"
4f76459… drh 5478 "Import CSV or similar text from FILE into TABLE. If TABLE does\n"
4f76459… drh 5479 "not exist, it is created using the first row of FILE as the column\n"
4f76459… drh 5480 "names. If FILE begins with \"|\" then it is a command that is run\n"
b9ecacf… drh 5481 "and the output from the command is used as the input data. If\n"
b9ecacf… drh 5482 "FILE begins with \"<<\" followed by a label, then content is read from\n"
b9ecacf… drh 5483 "the script until the first line that matches the label.\n"
b9ecacf… drh 5484 "\n"
b9ecacf… drh 5485 "The content of FILE is interpreted using RFC-4180 (\"CSV\") quoting\n"
b9ecacf… drh 5486 "rules unless the current mode is \"ascii\" or \"tabs\" or unless one\n"
b9ecacf… drh 5487 "the --ascii option is used.\n"
4f76459… drh 5488 "\n"
b9ecacf… drh 5489 "The column and row separators must be single ASCII characters. If\n"
b9ecacf… drh 5490 "multiple characters or a Unicode character are specified for the\n"
b9ecacf… drh 5491 "separators, then only the first byte of the separator is used. Except,\n"
b9ecacf… drh 5492 "if the row separator is \\n and the mode is not --ascii, then \\r\\n is\n"
b9ecacf… drh 5493 "understood as a row separator too.\n"
4f76459… drh 5494 "\n"
4f76459… drh 5495 "Options:\n"
b9ecacf… drh 5496 " --ascii Do not use RFC-4180 quoting. Use \\037 and \\036\n"
b9ecacf… drh 5497 " as column and row separators on input, unless other\n"
b9ecacf… drh 5498 " delimiters are specified using --colsep and/or --rowsep\n"
b9ecacf… drh 5499 " --colsep CHAR Use CHAR as the column separator.\n"
4f76459… drh 5500 " --csv Input is standard RFC-4180 CSV.\n"
7b0960d… drh 5501 " --esc CHAR Use CHAR as an escape character in unquoted CSV inputs.\n"
7b0960d… drh 5502 " --qesc CHAR Use CHAR as an escape character in quoted CSV inputs.\n"
b9ecacf… drh 5503 " --rowsep CHAR Use CHAR as the row separator.\n"
4f76459… drh 5504 " --schema S When creating TABLE, put it in schema S\n"
4f76459… drh 5505 " --skip N Ignore the first N rows of input\n"
4f76459… drh 5506 " -v Verbose mode\n"
4f76459… drh 5507 },
4f76459… drh 5508 { ".mode",
4f76459… drh 5509 "USAGE: .mode [MODE] [OPTIONS]\n"
4f76459… drh 5510 "\n"
45de97f… drh 5511 "Change the output mode to MODE and/or apply OPTIONS to the output mode.\n"
45de97f… drh 5512 "Arguments are processed from left to right. If no arguments, show the\n"
45de97f… drh 5513 "current output mode and relevant options.\n"
4f76459… drh 5514 "\n"
4f76459… drh 5515 "Options:\n"
4f76459… drh 5516 " --align STRING Set the alignment of text in columnar modes\n"
4f76459… drh 5517 " String consists of characters 'L', 'C', 'R'\n"
4f76459… drh 5518 " meaning \"left\", \"centered\", and \"right\", with\n"
4f76459… drh 5519 " one letter per column starting from the left.\n"
4f76459… drh 5520 " Unspecified alignment defaults to 'L'.\n"
45de97f… drh 5521 " --blob-quote ARG ARG can be \"auto\", \"text\", \"sql\", \"hex\", \"tcl\",\n"
45de97f… drh 5522 " \"json\", or \"size\". Default is \"auto\".\n"
f4b3b59… drh 5523 " --border on|off Show outer border on \"box\" and \"table\" modes.\n"
4f76459… drh 5524 " --charlimit N Set the maximum number of output characters to\n"
4f76459… drh 5525 " show for any single SQL value to N. Longer values\n"
4f76459… drh 5526 " truncated. Zero means \"no limit\".\n"
4f76459… drh 5527 " --colsep STRING Use STRING as the column separator\n"
4f76459… drh 5528 " --escape ESC Enable/disable escaping of control characters\n"
45de97f… drh 5529 " found in the output. ESC can be \"off\", \"ascii\",\n"
45de97f… drh 5530 " or \"symbol\".\n"
4f76459… drh 5531 " --linelimit N Set the maximum number of output lines to show for\n"
4f76459… drh 5532 " any single SQL value to N. Longer values are\n"
4f76459… drh 5533 " truncated. Zero means \"no limit\". Only works\n"
4f76459… drh 5534 " in \"line\" mode and in columnar modes.\n"
ae7e3f0… drh 5535 " --limits L,C,T Shorthand for \"--linelimit L --charlimit C\n"
ae7e3f0… drh 5536 " --titlelimit T\". The \",T\" can be omitted in which\n"
ae7e3f0… drh 5537 " case the --titlelimit is unchanged. The argument\n"
ae7e3f0… drh 5538 " can also be \"off\" to mean \"0,0,0\" or \"on\" to\n"
ae7e3f0… drh 5539 " mean \"5,300,20\".\n"
4f76459… drh 5540 " --list List available modes\n"
17f9878… drh 5541 " --multiinsert N In \"insert\" mode, put multiple rows on a single\n"
17f9878… drh 5542 " INSERT statement until the size exceeds N bytes.\n"
4f76459… drh 5543 " --null STRING Render SQL NULL values as the given string\n"
4f76459… drh 5544 " --once Setting changes to the right are reverted after\n"
4f76459… drh 5545 " the next SQL command.\n"
4f76459… drh 5546 " --quote ARG Enable/disable quoting of text. ARG can be\n"
709b566… drh 5547 " \"off\", \"on\", \"sql\", \"relaxed\", \"csv\", \"html\",\n"
709b566… drh 5548 " \"tcl\", or \"json\". \"off\" means show the text as-is.\n"
45de97f… drh 5549 " \"on\" is an alias for \"sql\".\n"
4f76459… drh 5550 " --reset Changes all mode settings back to their default.\n"
4f76459… drh 5551 " --rowsep STRING Use STRING as the row separator\n"
45de97f… drh 5552 " --sw|--screenwidth N Declare the screen width of the output device\n"
4f76459… drh 5553 " to be N characters. An attempt may be made to\n"
4f76459… drh 5554 " wrap output text to fit within this limit. Zero\n"
4f76459… drh 5555 " means \"no limit\". Or N can be \"auto\" to set the\n"
4f76459… drh 5556 " width automatically.\n"
4f76459… drh 5557 " --tablename NAME Set the name of the table for \"insert\" mode.\n"
4f76459… drh 5558 " --tag NAME Save mode to the left as NAME.\n"
4f76459… drh 5559 " --textjsonb BOOLEAN If enabled, JSONB text is displayed as text JSON.\n"
45de97f… drh 5560 " --title ARG Whether or not to show column headers, and if so\n"
4f76459… drh 5561 " how to encode them. ARG can be \"off\", \"on\",\n"
4f76459… drh 5562 " \"sql\", \"csv\", \"html\", \"tcl\", or \"json\".\n"
ae7e3f0… drh 5563 " --titlelimit N Limit the length of column titles to N characters.\n"
4f76459… drh 5564 " -v|--verbose Verbose output\n"
4f76459… drh 5565 " --widths LIST Set the columns widths for columnar modes. The\n"
4f76459… drh 5566 " argument is a list of integers, one for each\n"
4f76459… drh 5567 " column. A \"0\" width means use a dynamic width\n"
4f76459… drh 5568 " based on the actual width of data. If there are\n"
4f76459… drh 5569 " fewer entries in LIST than columns, \"0\" is used\n"
4f76459… drh 5570 " for the unspecified widths.\n"
4f76459… drh 5571 " --wordwrap BOOLEAN Enable/disable word wrapping\n"
4f76459… drh 5572 " --wrap N Wrap columns wider than N characters\n"
4f76459… drh 5573 " --ww Shorthand for \"--wordwrap on\"\n"
4f76459… drh 5574 },
4f76459… drh 5575 { ".output",
4f76459… drh 5576 "USAGE: .output [OPTIONS] [FILE]\n"
4f76459… drh 5577 "\n"
4f76459… drh 5578 "Begin redirecting output to FILE. Or if FILE is omitted, revert\n"
4f76459… drh 5579 "to sending output to the console. If FILE begins with \"|\" then\n"
4f76459… drh 5580 "the remainder of file is taken as a pipe and output is directed\n"
4f76459… drh 5581 "into that pipe. If FILE is \"memory\" then output is captured in an\n"
4f76459… drh 5582 "internal memory buffer. If FILE is \"off\" then output is redirected\n"
4f76459… drh 5583 "into /dev/null or the equivalent.\n"
4f76459… drh 5584 "\n"
4f76459… drh 5585 "Options:\n"
4f76459… drh 5586 " --bom Prepend a byte-order mark to the output\n"
4f76459… drh 5587 " -e Accumulate output in a temporary text file then\n"
4f76459… drh 5588 " launch a text editor when the redirection ends.\n"
4f76459… drh 5589 " --error-prefix X Use X as the left-margin prefix for error messages.\n"
4f76459… drh 5590 " Set to an empty string to restore the default.\n"
5f65ed5… drh 5591 " --keep Keep redirecting output to its current destination.\n"
5f65ed5… drh 5592 " Use this option in combination with --show or\n"
5f65ed5… drh 5593 " with --error-prefix when you do not want to stop\n"
5f65ed5… drh 5594 " a current redirection.\n"
4f76459… drh 5595 " --plain Use plain text rather than HTML tables with -w\n"
5f65ed5… drh 5596 " --show Show output text captured by .testcase or by\n"
5f65ed5… drh 5597 " redirecting to \"memory\".\n"
4f76459… drh 5598 " -w Show the output in a web browser. Output is\n"
4f76459… drh 5599 " written into a temporary HTML file until the\n"
4f76459… drh 5600 " redirect ends, then the web browser is launched.\n"
4f76459… drh 5601 " Query results are shown as HTML tables, unless\n"
4f76459… drh 5602 " the --plain is used too.\n"
4f76459… drh 5603 " -x Show the output in a spreadsheet. Output is\n"
4f76459… drh 5604 " written to a temp file as CSV then the spreadsheet\n"
4f76459… drh 5605 " is launched when\n"
4f76459… drh 5606 },
4f76459… drh 5607 { ".once",
4f76459… drh 5608 "USAGE: .once [OPTIONS] FILE ...\n"
4f76459… drh 5609 "\n"
4f76459… drh 5610 "Write the output for the next line of SQL or the next dot-command into\n"
4f76459… drh 5611 "FILE. If FILE begins with \"|\" then it is a program into which output\n"
4f76459… drh 5612 "is written. The FILE argument should be omitted if one of the -e, -w,\n"
4f76459… drh 5613 "or -x options is used.\n"
4f76459… drh 5614 "\n"
4f76459… drh 5615 "Options:\n"
4f76459… drh 5616 " -e Capture output into a temporary file then bring up\n"
4f76459… drh 5617 " a text editor on that temporary file.\n"
4f76459… drh 5618 " --plain Use plain text rather than HTML tables with -w\n"
4f76459… drh 5619 " -w Capture output into an HTML file then bring up that\n"
4f76459… drh 5620 " file in a web browser\n"
4f76459… drh 5621 " -x Show the output in a spreadsheet. Output is\n"
4f76459… drh 5622 " written to a temp file as CSV then the spreadsheet\n"
4f76459… drh 5623 " is launched when\n"
5f65ed5… drh 5624 },
5f65ed5… drh 5625 { ".check",
5f65ed5… drh 5626 "USAGE: .check [OPTIONS] PATTERN\n"
5f65ed5… drh 5627 "\n"
5f65ed5… drh 5628 "Verify results of commands since the most recent .testcase command.\n"
5f65ed5… drh 5629 "Restore output to the console, unless --keep is used.\n"
5f65ed5… drh 5630 "\n"
5f65ed5… drh 5631 "If PATTERN starts with \"<<ENDMARK\" then the actual pattern is taken from\n"
5f65ed5… drh 5632 "subsequent lines of text up to the first line that begins with ENDMARK.\n"
5f65ed5… drh 5633 "All pattern lines and the ENDMARK are discarded.\n"
5f65ed5… drh 5634 "\n"
5f65ed5… drh 5635 "Options:\n"
5f65ed5… drh 5636 " --exact Do an exact comparison including leading and\n"
5f65ed5… drh 5637 " trailing whitespace.\n"
5f65ed5… drh 5638 " --glob Treat PATTERN as a GLOB\n"
5f65ed5… drh 5639 " --keep Do not reset the testcase. More .check commands\n"
5f65ed5… drh 5640 " will follow.\n"
5f65ed5… drh 5641 " --notglob Output should not match PATTERN\n"
5f65ed5… drh 5642 " --show Write testcase output to the screen, for debugging.\n"
5f65ed5… drh 5643 },
5f65ed5… drh 5644 { ".testcase",
5f65ed5… drh 5645 "USAGE: .testcase [OPTIONS] NAME\n"
5f65ed5… drh 5646 "\n"
5f65ed5… drh 5647 "Start a new test case identified by NAME. All output\n"
5f65ed5… drh 5648 "through the next \".check\" command is captured for comparison. See the\n"
5f65ed5… drh 5649 "\".check\" commandn for additional informatioon.\n"
5f65ed5… drh 5650 "\n"
5f65ed5… drh 5651 "Options:\n"
5f65ed5… drh 5652 " --error-prefix TEXT Change error message prefix text to TEXT\n"
4f76459… drh 5653 },
4f76459… drh 5654 };
4f76459… drh 5655
4f76459… drh 5656 /*
4f76459… drh 5657 ** Return a pointer to usage text for zCmd, or NULL if none exists.
4f76459… drh 5658 */
4f76459… drh 5659 static const char *findUsage(const char *zCmd){
4f76459… drh 5660 int i;
4f76459… drh 5661 for(i=0; i<ArraySize(aUsage); i++){
4f76459… drh 5662 if( sqlite3_strglob(zCmd, aUsage[i].zCmd)==0 ) return aUsage[i].zUsage;
4f76459… drh 5663 }
4f76459… drh 5664 return 0;
4f76459… drh 5665 }
4f76459… drh 5666 const char *zHit = 0;
4f76459… drh 5667 cli_printf(out, ".%s\n", &azHelp[i][1]);
4f76459… drh 5668 cli_printf(out, "%s\n", azHelp[i]);
4f76459… drh 5669 zPat = sqlite3_mprintf(".%s*", zPattern[0]=='.' ? &zPattern[1] : zPattern);
4f76459… drh 5670 if( zHit ) cli_printf(out, "%s\n", zHit);
4f76459… drh 5671 zHit = azHelp[i];
4f76459… drh 5672 const char *zUsage = findUsage(zPat);
4f76459… drh 5673 if( zUsage ){
4f76459… drh 5674 cli_puts(zUsage, out);
4f76459… drh 5675 }else{
4f76459… drh 5676 /* when zPattern is a prefix of exactly one command, then include
4f76459… drh 5677 ** the details of that command, which should begin at offset j */
4f76459… drh 5678 cli_printf(out, "%s\n", zHit);
4f76459… drh 5679 while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){
4f76459… drh 5680 cli_printf(out, "%s\n", azHelp[j]);
4f76459… drh 5681 j++;
4f76459… drh 5682 }
4f76459… drh 5683 }
4f76459… drh 5684 }else{
4f76459… drh 5685 cli_printf(out, "%s\n", zHit);
4f76459… drh 5686 }
4f76459… drh 5687 }
4f76459… drh 5688 sqlite3_free(zPat);
4f76459… drh 5689 if( n ) return n;
4f76459… drh 5690 cli_printf(out, "%s\n", azHelp[j]);
4f76459… drh 5691 cli_printf(out, "%s\n", azHelp[j]);
92871e0… drh 5692 static int process_input(ShellState *p, const char*);
4f76459… drh 5693 cli_printf(stderr,"Error: '%s' not seekable\n", zName);
4f76459… drh 5694 cli_puts("Error: out of memory\n", stderr);
4f76459… drh 5695 cli_printf(stderr,"Error: cannot read '%s'\n", zName);
5f65ed5… drh 5696 ** Return the size of the named file in bytes. Or return a negative
5f65ed5… drh 5697 ** number if the file does not exist.
5f65ed5… drh 5698 */
5f65ed5… drh 5699 static sqlite3_int64 fileSize(const char *zFile){
5f65ed5… drh 5700 #if defined(_WIN32) || defined(WIN32)
5f65ed5… drh 5701 struct _stat64 x;
5f65ed5… drh 5702 if( _stat64(zFile, &x)!=0 ) return -1;
5f65ed5… drh 5703 return (sqlite3_int64)x.st_size;
5f65ed5… drh 5704 #else
5f65ed5… drh 5705 struct stat x;
5f65ed5… drh 5706 if( stat(zFile, &x)!=0 ) return -1;
5f65ed5… drh 5707 return (sqlite3_int64)x.st_size;
5f65ed5… drh 5708 #endif
5f65ed5… drh 5709 }
5f65ed5… drh 5710
5f65ed5… drh 5711 /*
5f65ed5… drh 5712 ** Return true if zFile is an SQLite database.
5f65ed5… drh 5713 **
5f65ed5… drh 5714 ** Algorithm:
5f65ed5… drh 5715 ** * If the file does not exist -> return false
5f65ed5… drh 5716 ** * If the size of the file is not a multiple of 512 -> return false
5f65ed5… drh 5717 ** * If sqlite3_open() fails -> return false
5f65ed5… drh 5718 ** * if sqlite3_prepare() or sqlite3_step() fails -> return false
5f65ed5… drh 5719 ** * Otherwise -> return true
5f65ed5… drh 5720 */
5f65ed5… drh 5721 static int isDatabaseFile(const char *zFile, int openFlags){
5f65ed5… drh 5722 sqlite3 *db = 0;
5f65ed5… drh 5723 sqlite3_stmt *pStmt = 0;
5f65ed5… drh 5724 int rc;
5f65ed5… drh 5725 sqlite3_int64 sz = fileSize(zFile);
5f65ed5… drh 5726 if( sz<512 || (sz%512)!=0 ) return 0;
5f65ed5… drh 5727 if( sqlite3_open_v2(zFile, &db, openFlags, 0)==SQLITE_OK
5f65ed5… drh 5728 && sqlite3_prepare_v2(db,"SELECT count(*) FROM sqlite_schema",-1,&pStmt,0)
5f65ed5… drh 5729 ==SQLITE_OK
5f65ed5… drh 5730 && sqlite3_step(pStmt)==SQLITE_ROW
5f65ed5… drh 5731 ){
5f65ed5… drh 5732 rc = 1;
5f65ed5… drh 5733 }else{
5f65ed5… drh 5734 rc = 0;
5f65ed5… drh 5735 }
5f65ed5… drh 5736 sqlite3_finalize(pStmt);
5f65ed5… drh 5737 sqlite3_close(db);
5f65ed5… drh 5738 return rc;
5f65ed5… drh 5739 }
5f65ed5… drh 5740
5f65ed5… drh 5741 /*
92871e0… drh 5742 int deduceDatabaseType(const char *zName, int dfltZip, int openFlags){
92871e0… drh 5743 FILE *f;
92871e0… drh 5744 if( access(zName,0)!=0 ) goto database_type_by_name;
5f65ed5… drh 5745 if( isDatabaseFile(zName, openFlags) ){
92871e0… drh 5746 rc = SHELL_OPEN_NORMAL;
92871e0… drh 5747 if( rc==SHELL_OPEN_NORMAL ) return SHELL_OPEN_NORMAL;
92871e0… drh 5748 f = sqlite3_fopen(zName, "rb");
92871e0… drh 5749 if( f==0 ) goto database_type_by_name;
92871e0… drh 5750
92871e0… drh 5751 database_type_by_name:
92871e0… drh 5752 if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
92871e0… drh 5753 rc = SHELL_OPEN_ZIPFILE;
92871e0… drh 5754 }else{
92871e0… drh 5755 rc = SHELL_OPEN_NORMAL;
92871e0… drh 5756 }
92871e0… drh 5757 return rc;
5f65ed5… drh 5758 }
5f65ed5… drh 5759
5f65ed5… drh 5760 /*
5f65ed5… drh 5761 ** If the text in z[] is the name of a readable file and that file appears
5f65ed5… drh 5762 ** to contain SQL text and/or dot-commands, then return true. If z[] is
5f65ed5… drh 5763 ** not a file, or if the file is unreadable, or if the file is a database
5f65ed5… drh 5764 ** or anything else that is not SQL text and dot-commands, then return false.
5f65ed5… drh 5765 **
5f65ed5… drh 5766 ** If the bLeaveUninit flag is set, then be sure to leave SQLite in an
5f65ed5… drh 5767 ** uninitialized state. This means invoking sqlite3_shutdown() after any
5f65ed5… drh 5768 ** SQLite API is used.
5f65ed5… drh 5769 **
5f65ed5… drh 5770 ** Some amount of guesswork is involved in this decision.
5f65ed5… drh 5771 */
5f65ed5… drh 5772 static int isScriptFile(const char *z, int bLeaveUninit){
5f65ed5… drh 5773 sqlite3_int64 sz = fileSize(z);
5f65ed5… drh 5774 if( sz<=0 ) return 0;
5f65ed5… drh 5775 if( (sz%512)==0 ){
13c221a… drh 5776 int rc;
13c221a… drh 5777 sqlite3_initialize();
13c221a… drh 5778 rc = isDatabaseFile(z, SQLITE_OPEN_READONLY);
5f65ed5… drh 5779 if( bLeaveUninit ){
5f65ed5… drh 5780 sqlite3_shutdown();
5f65ed5… drh 5781 }
5f65ed5… drh 5782 if( rc ) return 0; /* Is a database */
5f65ed5… drh 5783 }
5f65ed5… drh 5784 if( sqlite3_strlike("%.sql",z,0)==0 ) return 1;
5f65ed5… drh 5785 if( sqlite3_strlike("%.txt",z,0)==0 ) return 1;
5f65ed5… drh 5786 return 0;
4f76459… drh 5787 }
4f76459… drh 5788
92871e0… drh 5789 i64 nLine;
4f76459… drh 5790 cli_printf(stderr,"cannot open \"%s\" for reading\n", zDbFilename);
4f76459… drh 5791 cli_puts("invalid pagesize\n", stderr);
92871e0… drh 5792 if( nLine>=2000000000 ){
4f76459… drh 5793 cli_printf(stderr, "input too big\n");
92871e0… drh 5794 goto readHexDb_error;
92871e0… drh 5795 }
4f76459… drh 5796 cli_printf(stderr,"Error on line %lld of --hexdb input\n", nLine);
92871e0… drh 5797 (openFlags & OPEN_DB_ZIPFILE)!=0, p->openFlags);
4f76459… drh 5798 cli_printf(stderr,"Error: unable to open database \"%s\": %s\n",
4f76459… drh 5799 cli_exit(1);
4f76459… drh 5800 cli_puts("Also: unable to open substitute in-memory database.\n",
4f76459… drh 5801 cli_exit(1);
4f76459… drh 5802 cli_printf(stderr,
4f76459… drh 5803 sqlite3_create_function(p->db, "shell_format_schema", 2, SQLITE_UTF8, p,
4f76459… drh 5804 shellFormatSchema, 0, 0);
4f76459… drh 5805 cli_printf(stderr,"Error: sqlite3_deserialize() returns %d\n", rc);
4f76459… drh 5806 p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, p->mode.scanstatsOn, (int*)0
4f76459… drh 5807 cli_printf(stderr,
4f76459… drh 5808 cli_printf(stderr,
4f76459… drh 5809 static FILE *output_file_open(ShellState *p, const char *zFile){
4f76459… drh 5810 }else if( cli_strcmp(zFile, "off")==0 || p->bSafeMode ){
4f76459… drh 5811 cli_printf(stderr,"Error: cannot open \"%s\"\n", zFile);
4f76459… drh 5812 cli_printf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
4f76459… drh 5813 cli_printf(p->traceOut,
b9ecacf… drh 5814 char *zIn; /* Input text */
b9ecacf… drh 5815 i64 nUsed; /* Bytes of zIn[] used so far */
7b0960d… drh 5816 int cQEscape; /* Escape character with "...". 0 for none */
7b0960d… drh 5817 int cUQEscape; /* Escape character not with "...". 0 for none */
b9ecacf… drh 5818 if( p->zIn ){
b9ecacf… drh 5819 sqlite3_free(p->zIn);
b9ecacf… drh 5820 p->zIn = 0;
b9ecacf… drh 5821 }
b9ecacf… drh 5822 /* Read a single character of the .import input text. Return EOF
b9ecacf… drh 5823 ** at end-of-file.
b9ecacf… drh 5824 */
b9ecacf… drh 5825 static int import_getc(ImportCtx *p){
b9ecacf… drh 5826 if( p->in ){
b9ecacf… drh 5827 return fgetc(p->in);
b9ecacf… drh 5828 }else if( p->zIn && p->zIn[p->nUsed]!=0 ){
b9ecacf… drh 5829 return p->zIn[p->nUsed++];
b9ecacf… drh 5830 }else{
b9ecacf… drh 5831 return EOF;
b9ecacf… drh 5832 }
b9ecacf… drh 5833 }
b9ecacf… drh 5834
b9ecacf… drh 5835 /* Append a single byte to the field value begin constructed
b9ecacf… drh 5836 ** in the p->z[] buffer
b9ecacf… drh 5837 */
b9ecacf… drh 5838 ** + Use p->cColSep as the column separator. The default is ",".
b9ecacf… drh 5839 ** + Use p->cRowSep as the row separator. The default is "\n".
b9ecacf… drh 5840 c = import_getc(p);
7b0960d… drh 5841 int cEsc = (u8)p->cQEscape;
b9ecacf… drh 5842 c = import_getc(p);
7b0960d… drh 5843 if( c==cEsc && cEsc!=0 ){
7b0960d… drh 5844 c = import_getc(p);
7b0960d… drh 5845 import_append_char(p, c);
7b0960d… drh 5846 ppc = pc = 0;
7b0960d… drh 5847 continue;
7b0960d… drh 5848 }
4f76459… drh 5849 cli_printf(stderr,"%s:%d: unescaped %c character\n",
7b0960d… drh 5850 p->zFile, p->nLine, cQuote);
4f76459… drh 5851 cli_printf(stderr,"%s:%d: unterminated %c-quoted field\n",
7b0960d… drh 5852 int cEsc = p->cUQEscape;
b9ecacf… drh 5853 c = import_getc(p);
b9ecacf… drh 5854 c = import_getc(p);
7b0960d… drh 5855 if( c==cEsc && cEsc!=0 ) c = import_getc(p);
b9ecacf… drh 5856 c = import_getc(p);
b9ecacf… drh 5857 ** + Use p->cColSep as the column separator. The default is "\x1F".
b9ecacf… drh 5858 ** + Use p->cRowSep as the row separator. The default is "\x1E".
b9ecacf… drh 5859 c = import_getc(p);
b9ecacf… drh 5860 c = import_getc(p);
4f76459… drh 5861 cli_printf(stderr,"Error %d: %s on [%s]\n",
4f76459… drh 5862 cli_printf(stderr,"Error %d: %s on [%s]\n",
4f76459… drh 5863 cli_printf(stderr,"Error %d: %s\n",
4f76459… drh 5864 cli_printf(stderr,"Warning: cannot step \"%s\" backwards", zTable);
4f76459… drh 5865 cli_printf(stderr,
4f76459… drh 5866 cli_printf(stdout, "%s... ", zName); fflush(stdout);
4f76459… drh 5867 cli_printf(stderr,"Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
4f76459… drh 5868 cli_printf(stderr,"Error: (%d) %s on [%s]\n",
4f76459… drh 5869 cli_printf(stdout, "%s... ", zName); fflush(stdout);
4f76459… drh 5870 cli_printf(stderr,"Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
4f76459… drh 5871 cli_printf(stderr,"File \"%s\" already exists.\n", zNewDb);
4f76459… drh 5872 cli_printf(stderr,
4f76459… drh 5873 cli_puts("Output already redirected.\n", stderr);
4f76459… drh 5874 if( p->mode.eMode==MODE_Www ){
4f76459… drh 5875 cli_puts(
4f76459… drh 5876 if( p->mode.eMode==MODE_Www ){
4f76459… drh 5877 cli_puts("</PRE></BODY></HTML>\n", p->out);
4f76459… drh 5878 cli_printf(stderr,"Failed: [%s]\n", zCmd);
4f76459… drh 5879 modePop(p);
4f76459… drh 5880 if( cli_output_capture ){
4f76459… drh 5881 sqlite3_str_free(cli_output_capture);
4f76459… drh 5882 cli_output_capture = 0;
4f76459… drh 5883 }
4f76459… drh 5884 cli_printf(stderr,"error: %s\n", sqlite3_errmsg(p->db));
4f76459… drh 5885 cli_puts("unable to read database header\n", stderr);
4f76459… drh 5886 cli_printf(p->out, "%-20s %d\n", "database page size:", i);
4f76459… drh 5887 cli_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
4f76459… drh 5888 cli_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
4f76459… drh 5889 cli_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
4f76459… drh 5890 cli_printf(p->out, "%-20s %u", aField[i].zName, val);
4f76459… drh 5891 if( val==1 ) cli_puts(" (utf8)", p->out);
4f76459… drh 5892 if( val==2 ) cli_puts(" (utf16le)", p->out);
4f76459… drh 5893 if( val==3 ) cli_puts(" (utf16be)", p->out);
4f76459… drh 5894 cli_puts("\n", p->out);
4f76459… drh 5895 cli_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
4f76459… drh 5896 cli_printf(p->out, "%-20s %u\n", "data version", iDataVersion);
4f76459… drh 5897 cli_printf(p->out, "| size %lld pagesize %d filename %s\n",
4f76459… drh 5898 cli_printf(p->out, "| page %lld offset %lld\n",pgno,(pgno-1)*pgSz);
4f76459… drh 5899 cli_printf(p->out, "| %5d:", i);
4f76459… drh 5900 for(j=0; j<16; j++) cli_printf(p->out, " %02x", aLine[j]);
4f76459… drh 5901 cli_printf(p->out, " ");
4f76459… drh 5902 cli_printf(p->out, "%c", bShow[c]);
4f76459… drh 5903 cli_printf(p->out, "\n");
4f76459… drh 5904 cli_printf(p->out, "| end %s\n", zName);
4f76459… drh 5905 cli_printf(stderr, "ERROR: %s\n", sqlite3_errmsg(p->db));
4f76459… drh 5906 cli_printf(stderr,"Error: %s\n", zErr);
70539ee… drh 5907 ** The input zFN is guaranteed to start with "file:" and is thus a URI
70539ee… drh 5908 ** filename. Extract the actual filename and return a pointer to that
70539ee… drh 5909 ** filename in spaced obtained from sqlite3_malloc().
70539ee… drh 5910 **
70539ee… drh 5911 ** The caller is responsible for freeing space using sqlite3_free() when
70539ee… drh 5912 ** it has finished with the filename.
70539ee… drh 5913 */
70539ee… drh 5914 static char *shellFilenameFromUri(const char *zFN){
70539ee… drh 5915 char *zOut;
70539ee… drh 5916 int i, j, d1, d2;
70539ee… drh 5917
70539ee… drh 5918 assert( cli_strncmp(zFN,"file:",5)==0 );
70539ee… drh 5919 zOut = sqlite3_mprintf("%s", zFN+5);
70539ee… drh 5920 shell_check_oom(zOut);
70539ee… drh 5921 for(i=j=0; zOut[i]!=0 && zOut[i]!='?'; i++){
70539ee… drh 5922 if( zOut[i]!='%' ){
70539ee… drh 5923 zOut[j++] = zOut[i];
70539ee… drh 5924 continue;
70539ee… drh 5925 }
70539ee… drh 5926 d1 = hexDigitValue(zOut[i+1]);
70539ee… drh 5927 if( d1<0 ){
70539ee… drh 5928 zOut[j] = 0;
70539ee… drh 5929 break;
70539ee… drh 5930 }
70539ee… drh 5931 d2 = hexDigitValue(zOut[i+2]);
70539ee… drh 5932 if( d2<0 ){
70539ee… drh 5933 zOut[j] = 0;
70539ee… drh 5934 break;
70539ee… drh 5935 }
70539ee… drh 5936 zOut[j++] = d1*16 + d2;
70539ee… drh 5937 i += 2;
70539ee… drh 5938 }
70539ee… drh 5939 zOut[j] = 0;
70539ee… drh 5940 return zOut;
70539ee… drh 5941 }
70539ee… drh 5942
70539ee… drh 5943 /*
4f76459… drh 5944 /* Forward reference */
4f76459… drh 5945 static char *find_home_dir(int clearFlag);
4f76459… drh 5946
4f76459… drh 5947 **
4f76459… drh 5948 ** Because the classic temp folders like /tmp are no longer
4f76459… drh 5949 ** accessible to web browsers, for security reasons, create the
4f76459… drh 5950 ** temp file in the user's home directory.
4f76459… drh 5951 char *zHome; /* Home directory */
4f76459… drh 5952 int i; /* Loop counter */
4f76459… drh 5953 sqlite3_uint64 r = 0; /* Integer with 64 bits of randomness */
4f76459… drh 5954 char zRand[32]; /* Text string with 160 bits of randomness */
4f76459… drh 5955 #ifdef _WIN32
4f76459… drh 5956 const char cDirSep = '\\';
4f76459… drh 5957 #else
4f76459… drh 5958 const char cDirSep = '/';
4f76459… drh 5959 #endif
4f76459… drh 5960
4f76459… drh 5961 for(i=0; i<31; i++){
4f76459… drh 5962 if( (i%12)==0 ) sqlite3_randomness(sizeof(r),&r);
4f76459… drh 5963 zRand[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[r%36];
4f76459… drh 5964 r /= 36;
4f76459… drh 5965 }
4f76459… drh 5966 zRand[i] = 0;
4f76459… drh 5967 zHome = find_home_dir(0);
4f76459… drh 5968 p->zTempFile = sqlite3_mprintf("%s%ctemp-%s.%s",
4f76459… drh 5969 zHome,cDirSep,zRand,zSuffix);
4f76459… drh 5970 cli_printf(stderr,
4f76459… drh 5971 cli_puts("Error: internal error", stderr);
4f76459… drh 5972 cli_printf(out, "-- Parent table %s\n", zParent);
4f76459… drh 5973 cli_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
4f76459… drh 5974 cli_printf(out,
4f76459… drh 5975 cli_printf(stderr,"%s\n", sqlite3_errmsg(db));
4f76459… drh 5976 cli_printf(stderr,"%s\n", sqlite3_errmsg(db));
4f76459… drh 5977 cli_printf(stderr,"%s\n", sqlite3_errmsg(db));
4f76459… drh 5978 cli_printf(stderr,"Usage %s sub-command ?switches...?\n", azArg[0]);
4f76459… drh 5979 cli_printf(stderr, "Where sub-commands are:\n");
4f76459… drh 5980 cli_printf(stderr, " fkey-indexes\n");
4f76459… drh 5981 cli_printf(stderr,
4f76459… drh 5982 cli_printf(stderr,"SQL error: %s\n", sqlite3_errmsg(db));
4f76459… drh 5983 cli_printf(stderr,"SQL error: %s\n", sqlite3_errmsg(db));
4f76459… drh 5984 cli_puts("Use \"-A\" for more help\n", stderr);
4f76459… drh 5985 cli_puts("Use \".archive --help\" for more help\n", stderr);
4f76459… drh 5986 cli_printf(stderr, "Wrong number of arguments. Usage:\n");
4f76459… drh 5987 cli_printf(stderr, "Required argument missing. Usage:\n");
4f76459… drh 5988 cli_printf(stderr,"not found in archive: %s\n", z);
92871e0… drh 5989 char *z1 = sqlite3_mprintf(pAr->bGlob ? "" : "name IN(");
92871e0… drh 5990 char *z2 = sqlite3_mprintf("");
92871e0… drh 5991 const char *zSep1 = "";
92871e0… drh 5992 const char *zSep2 = "";
92871e0… drh 5993
92871e0… drh 5994 for(i=0; i<pAr->nArg && z1 && z2; i++){
92871e0… drh 5995 int n = strlen30(z);
92871e0… drh 5996
92871e0… drh 5997 if( pAr->bGlob ){
92871e0… drh 5998 z1 = sqlite3_mprintf("%z%sname GLOB '%q'", z1, zSep2, z);
92871e0… drh 5999 z2 = sqlite3_mprintf(
92871e0… drh 6000 "%z%ssubstr(name,1,%d) GLOB '%q/'", z2, zSep2, n+1,z
92871e0… drh 6001 );
92871e0… drh 6002 }else{
92871e0… drh 6003 z1 = sqlite3_mprintf("%z%s'%q'", z1, zSep1, z);
92871e0… drh 6004 z2 = sqlite3_mprintf("%z%ssubstr(name,1,%d) = '%q/'",z2,zSep2,n+1,z);
92871e0… drh 6005 }
92871e0… drh 6006 zSep1 = ", ";
92871e0… drh 6007 zSep2 = " OR ";
92871e0… drh 6008 }
92871e0… drh 6009 if( z1==0 || z2==0 ){
92871e0… drh 6010 *pRc = SQLITE_NOMEM;
92871e0… drh 6011 }else{
92871e0… drh 6012 zWhere = sqlite3_mprintf("(%s%s OR (name GLOB '*/*' AND (%s))) ",
92871e0… drh 6013 z1, pAr->bGlob==0 ? ")" : "", z2
92871e0… drh 6014 sqlite3_free(z1);
92871e0… drh 6015 sqlite3_free(z2);
4f76459… drh 6016 cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql));
4f76459… drh 6017 cli_printf(pAr->out, "%s % 10d %s %s\n",
4f76459… drh 6018 cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
4f76459… drh 6019 cli_printf(pAr->out, "%s\n", zSql);
4f76459… drh 6020 cli_printf(stdout, "ERROR: %s\n", zErr); /* stdout? */
b8ab8b3… drh 6021 "WITH dest(dpath,dlen) AS (SELECT realpath($dir),length(realpath($dir)))\n"
b8ab8b3… drh 6022 "SELECT ($dir || name),\n"
b8ab8b3… drh 6023 " CASE WHEN $dryrun THEN 0\n"
b8ab8b3… drh 6024 " ELSE writefile($dir||name, %s, mode, mtime) END\n"
b8ab8b3… drh 6025 " FROM dest CROSS JOIN %s\n"
b8ab8b3… drh 6026 " WHERE (%s)\n"
b8ab8b3… drh 6027 " AND (data IS NULL OR $pass==0)\n" /* Dirs both passes */
b8ab8b3… drh 6028 " AND dpath=substr(realpath($dir||name),1,dlen)\n" /* No escapes */
b8ab8b3… drh 6029 " AND name NOT GLOB '*..[/\\]*'\n"; /* No /../ in paths */
b8ab8b3… drh 6030 j = sqlite3_bind_parameter_index(pSql, "$dryrun");
b8ab8b3… drh 6031 sqlite3_bind_int(pSql, j, pAr->bDryRun);
b8ab8b3… drh 6032 /* Run the SELECT statement twice
b8ab8b3… drh 6033 ** (0) writefile() all files and directories
b8ab8b3… drh 6034 ** (1) writefile() for directory again
b8ab8b3… drh 6035 ** The second pass is so that the timestamps for extracted directories
b8ab8b3… drh 6036 ** will be reset to the value in the archive, since populating them
b8ab8b3… drh 6037 ** in the first pass will have changed the timestamp. */
b8ab8b3… drh 6038 j = sqlite3_bind_parameter_index(pSql, "$pass");
4f76459… drh 6039 cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql));
b8ab8b3… drh 6040 if( pAr->bVerbose==0 ) break;
b8ab8b3… drh 6041 }
b8ab8b3… drh 6042 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
b8ab8b3… drh 6043 if( i==0 && pAr->bVerbose ){
b8ab8b3… drh 6044 cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
b8ab8b3… drh 6045 if( pAr->bDryRun ) break;
4f76459… drh 6046 cli_printf(pAr->out, "%s\n", zSql);
4f76459… drh 6047 cli_printf(stdout, "ERROR: %s\n", zErr);
92871e0… drh 6048 eDbType = deduceDatabaseType(cmd.zFile, 1, 0);
4f76459… drh 6049 cli_printf(cmd.out, "-- open database '%s'%s\n", cmd.zFile,
4f76459… drh 6050 cli_printf(stderr, "cannot open file: %s (%s)\n",
4f76459… drh 6051 cli_printf(stderr, "database does not contain an 'sqlar' table\n");
4f76459… drh 6052 cli_printf(pState->out, "%s;\n", zSql);
4f76459… drh 6053 cli_printf(stderr,"unexpected option: %s\n", azArg[i]);
d326547… drh 6054 if( !pState->bSafeMode ){
d326547… drh 6055 sqlite3_recover_config(p, 789, (void*)zRecoveryDb); /* Debug use only */
d326547… drh 6056 }
4f76459… drh 6057 cli_printf(pState->out, ".dbconfig defensive off\n");
4f76459… drh 6058 cli_printf(stderr,"sql error: %s (%d)\n", zErr, errCode);
4f76459… drh 6059 cli_printf(pState->out, "%s\n", zMsg);
4f76459… drh 6060 cli_printf(stderr,"%s\n", zErr);
4f76459… drh 6061 cli_printf(pState->out, "%lld steps, %lld errors\n", nStep, nError);
4f76459… drh 6062 cli_printf(stderr,"E:%d\n",rc), assert(0)
7b0960d… drh 6063 cname||' ANY',\
17f9878… drh 6064 "sql LIKE 'CREATE VIRTUAL TABLE%%' AND (%s)", zLike ? zLike : "true"
4f76459… drh 6065 cli_puts("/* WARNING: "
4f76459… drh 6066 cli_printf(stdout,
4f76459… drh 6067 cli_printf(stdout,
4f76459… drh 6068 ** pickStr(zArg, &zErr, zS1, zS2, ..., "");
4f76459… drh 6069 **
4f76459… drh 6070 ** Try to match zArg against zS1, zS2, and so forth until the first
4f76459… drh 6071 ** emptry string. Return the index of the match or -1 if none is found.
4f76459… drh 6072 ** If no match is found, and &zErr is not NULL, then write into
4f76459… drh 6073 ** zErr a message describing the valid choices.
4f76459… drh 6074 */
4f76459… drh 6075 static int pickStr(const char *zArg, char **pzErr, ...){
4f76459… drh 6076 int i, n;
4f76459… drh 6077 const char *z;
4f76459… drh 6078 sqlite3_str *pMsg;
4f76459… drh 6079 va_list ap;
4f76459… drh 6080 va_start(ap, pzErr);
4f76459… drh 6081 i = 0;
4f76459… drh 6082 while( (z = va_arg(ap,const char*))!=0 && z[0]!=0 ){
4f76459… drh 6083 if( cli_strcmp(zArg, z)==0 ) return i;
4f76459… drh 6084 i++;
4f76459… drh 6085 }
4f76459… drh 6086 va_end(ap);
4f76459… drh 6087 if( pzErr==0 ) return -1;
4f76459… drh 6088 n = i;
4f76459… drh 6089 pMsg = sqlite3_str_new(0);
4f76459… drh 6090 va_start(ap, pzErr);
4f76459… drh 6091 sqlite3_str_appendall(pMsg, "should be");
4f76459… drh 6092 i = 0;
4f76459… drh 6093 while( (z = va_arg(ap, const char*))!=0 && z[0]!=0 ){
4f76459… drh 6094 if( i==n-1 ){
4f76459… drh 6095 sqlite3_str_append(pMsg,", or",4);
4f76459… drh 6096 }else if( i>0 ){
4f76459… drh 6097 sqlite3_str_append(pMsg, ",", 1);
4f76459… drh 6098 }
4f76459… drh 6099 sqlite3_str_appendf(pMsg, " %s", z);
4f76459… drh 6100 i++;
4f76459… drh 6101 }
4f76459… drh 6102 va_end(ap);
4f76459… drh 6103 *pzErr = sqlite3_str_finish(pMsg);
4f76459… drh 6104 return -1;
4f76459… drh 6105 }
4f76459… drh 6106
4f76459… drh 6107 /*
4f76459… drh 6108 ** DOT-COMMAND: .import
4f76459… drh 6109 **
4f76459… drh 6110 ** USAGE: .import [OPTIONS] FILE TABLE
4f76459… drh 6111 **
4f76459… drh 6112 ** Import CSV or similar text from FILE into TABLE. If TABLE does
4f76459… drh 6113 ** not exist, it is created using the first row of FILE as the column
4f76459… drh 6114 ** names. If FILE begins with "|" then it is a command that is run
b9ecacf… drh 6115 ** and the output from the command is used as the input data. If
b9ecacf… drh 6116 ** FILE begins with "<<" followed by a label, then content is read from
b9ecacf… drh 6117 ** the script until the first line that matches the label.
b9ecacf… drh 6118 **
b9ecacf… drh 6119 ** The content of FILE is interpreted using RFC-4180 ("CSV") quoting
b9ecacf… drh 6120 ** rules unless the current mode is "ascii" or "tabs" or unless one
b9ecacf… drh 6121 ** the --ascii option is used.
4f76459… drh 6122 **
b9ecacf… drh 6123 ** The column and row separators must be single ASCII characters. If
b9ecacf… drh 6124 ** multiple characters or a Unicode character are specified for the
b9ecacf… drh 6125 ** separators, then only the first byte of the separator is used. Except,
b9ecacf… drh 6126 ** if the row separator is \n and the mode is not --ascii, then \r\n is
b9ecacf… drh 6127 ** understood as a row separator too.
4f76459… drh 6128 **
4f76459… drh 6129 ** Options:
b9ecacf… drh 6130 ** --ascii Do not use RFC-4180 quoting. Use \037 and \036
b9ecacf… drh 6131 ** as column and row separators on input, unless other
b9ecacf… drh 6132 ** delimiters are specified using --colsep and/or --rowsep
b9ecacf… drh 6133 ** --colsep CHAR Use CHAR as the column separator.
4f76459… drh 6134 ** --csv Input is standard RFC-4180 CSV.
7b0960d… drh 6135 ** --esc CHAR Use CHAR as an escape character in unquoted CSV inputs.
7b0960d… drh 6136 ** --qesc CHAR Use CHAR as an escape character in quoted CSV inputs.
b9ecacf… drh 6137 ** --rowsep CHAR Use CHAR as the row separator.
4f76459… drh 6138 ** --schema S When creating TABLE, put it in schema S
4f76459… drh 6139 ** --skip N Ignore the first N rows of input
4f76459… drh 6140 ** -v Verbose mode
4f76459… drh 6141 */
4f76459… drh 6142 static int dotCmdImport(ShellState *p){
4f76459… drh 6143 int nArg = p->dot.nArg; /* Number of arguments */
4f76459… drh 6144 char **azArg = p->dot.azArg;/* Argument list */
4f76459… drh 6145 char *zTable = 0; /* Insert data into this table */
4f76459… drh 6146 char *zSchema = 0; /* Schema of zTable */
4f76459… drh 6147 char *zFile = 0; /* Name of file to extra content from */
4f76459… drh 6148 sqlite3_stmt *pStmt = NULL; /* A statement */
4f76459… drh 6149 int nCol; /* Number of columns in the table */
4f76459… drh 6150 i64 nByte; /* Number of bytes in an SQL string */
4f76459… drh 6151 int i, j; /* Loop counters */
4f76459… drh 6152 int needCommit; /* True to COMMIT or ROLLBACK at end */
4f76459… drh 6153 char *zSql = 0; /* An SQL statement */
4f76459… drh 6154 ImportCtx sCtx; /* Reader context */
4f76459… drh 6155 char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
4f76459… drh 6156 int eVerbose = 0; /* Larger for more console output */
4f76459… drh 6157 i64 nSkip = 0; /* Initial lines to skip */
b9ecacf… drh 6158 i64 iLineOffset = 0; /* Offset to the first line of input */
4f76459… drh 6159 char *zCreate = 0; /* CREATE TABLE statement text */
4f76459… drh 6160 int rc; /* Result code */
4f76459… drh 6161
4f76459… drh 6162 failIfSafeMode(p, "cannot run .import in safe mode");
4f76459… drh 6163 memset(&sCtx, 0, sizeof(sCtx));
4f76459… drh 6164 if( p->mode.eMode==MODE_Ascii ){
4f76459… drh 6165 xRead = ascii_read_one_field;
4f76459… drh 6166 }else{
4f76459… drh 6167 xRead = csv_read_one_field;
4f76459… drh 6168 }
4f76459… drh 6169 for(i=1; i<nArg; i++){
4f76459… drh 6170 char *z = azArg[i];
4f76459… drh 6171 if( z[0]=='-' && z[1]=='-' ) z++;
4f76459… drh 6172 if( z[0]!='-' ){
4f76459… drh 6173 if( zFile==0 ){
4f76459… drh 6174 zFile = z;
4f76459… drh 6175 }else if( zTable==0 ){
4f76459… drh 6176 zTable = z;
4f76459… drh 6177 }else{
4f76459… drh 6178 dotCmdError(p, i, "unknown argument", 0);
4f76459… drh 6179 return 1;
4f76459… drh 6180 }
4f76459… drh 6181 }else if( cli_strcmp(z,"-v")==0 ){
4f76459… drh 6182 eVerbose++;
4f76459… drh 6183 }else if( cli_strcmp(z,"-schema")==0 && i<nArg-1 ){
4f76459… drh 6184 zSchema = azArg[++i];
4f76459… drh 6185 }else if( cli_strcmp(z,"-skip")==0 && i<nArg-1 ){
4f76459… drh 6186 nSkip = integerValue(azArg[++i]);
4f76459… drh 6187 }else if( cli_strcmp(z,"-ascii")==0 ){
b9ecacf… drh 6188 if( sCtx.cColSep==0 ) sCtx.cColSep = SEP_Unit[0];
b9ecacf… drh 6189 if( sCtx.cRowSep==0 ) sCtx.cRowSep = SEP_Record[0];
4f76459… drh 6190 xRead = ascii_read_one_field;
4f76459… drh 6191 }else if( cli_strcmp(z,"-csv")==0 ){
b9ecacf… drh 6192 if( sCtx.cColSep==0 ) sCtx.cColSep = ',';
b9ecacf… drh 6193 if( sCtx.cRowSep==0 ) sCtx.cRowSep = '\n';
4f76459… drh 6194 xRead = csv_read_one_field;
7b0960d… drh 6195 }else if( cli_strcmp(z,"-esc")==0 ){
7b0960d… drh 6196 sCtx.cUQEscape = azArg[++i][0];
7b0960d… drh 6197 }else if( cli_strcmp(z,"-qesc")==0 ){
7b0960d… drh 6198 sCtx.cQEscape = azArg[++i][0];
b9ecacf… drh 6199 }else if( cli_strcmp(z,"-colsep")==0 ){
b9ecacf… drh 6200 if( i==nArg-1 ){
b9ecacf… drh 6201 dotCmdError(p, i, "missing argument", 0);
b9ecacf… drh 6202 return 1;
b9ecacf… drh 6203 }
b9ecacf… drh 6204 i++;
b9ecacf… drh 6205 sCtx.cColSep = azArg[i][0];
b9ecacf… drh 6206 }else if( cli_strcmp(z,"-rowsep")==0 ){
b9ecacf… drh 6207 if( i==nArg-1 ){
b9ecacf… drh 6208 dotCmdError(p, i, "missing argument", 0);
b9ecacf… drh 6209 return 1;
b9ecacf… drh 6210 }
b9ecacf… drh 6211 i++;
b9ecacf… drh 6212 sCtx.cRowSep = azArg[i][0];
4f76459… drh 6213 }else{
4f76459… drh 6214 dotCmdError(p, i, "unknown option", 0);
4f76459… drh 6215 return 1;
4f76459… drh 6216 }
4f76459… drh 6217 }
4f76459… drh 6218 if( zTable==0 ){
b9ecacf… drh 6219 dotCmdError(p, nArg, 0, "Missing %s argument\n",
4f76459… drh 6220 zFile==0 ? "FILE" : "TABLE");
4f76459… drh 6221 return 1;
4f76459… drh 6222 }
4f76459… drh 6223 seenInterrupt = 0;
4f76459… drh 6224 open_db(p, 0);
b9ecacf… drh 6225 if( sCtx.cColSep==0 ){
b9ecacf… drh 6226 if( p->mode.spec.zColumnSep && p->mode.spec.zColumnSep[0]!=0 ){
b9ecacf… drh 6227 sCtx.cColSep = p->mode.spec.zColumnSep[0];
b9ecacf… drh 6228 }else{
b9ecacf… drh 6229 sCtx.cColSep = ',';
b9ecacf… drh 6230 }
b9ecacf… drh 6231 }
b9ecacf… drh 6232 if( (sCtx.cColSep & 0x80)!=0 ){
b9ecacf… drh 6233 eputz("Error: .import column separator must be ASCII\n");
b9ecacf… drh 6234 return 1;
b9ecacf… drh 6235 }
b9ecacf… drh 6236 if( sCtx.cRowSep==0 ){
b9ecacf… drh 6237 if( p->mode.spec.zRowSep && p->mode.spec.zRowSep[0]!=0 ){
b9ecacf… drh 6238 sCtx.cRowSep = p->mode.spec.zRowSep[0];
b9ecacf… drh 6239 }else{
b9ecacf… drh 6240 sCtx.cRowSep = '\n';
b9ecacf… drh 6241 }
b9ecacf… drh 6242 }
b9ecacf… drh 6243 if( sCtx.cRowSep=='\r' && xRead!=ascii_read_one_field ){
b9ecacf… drh 6244 sCtx.cRowSep = '\n';
b9ecacf… drh 6245 }
b9ecacf… drh 6246 if( (sCtx.cRowSep & 0x80)!=0 ){
b9ecacf… drh 6247 eputz("Error: .import row separator must be ASCII\n");
b9ecacf… drh 6248 return 1;
4f76459… drh 6249 }
4f76459… drh 6250 sCtx.zFile = zFile;
4f76459… drh 6251 sCtx.nLine = 1;
4f76459… drh 6252 if( sCtx.zFile[0]=='|' ){
4f76459… drh 6253 #ifdef SQLITE_OMIT_POPEN
4f76459… drh 6254 eputz("Error: pipes are not supported in this OS\n");
4f76459… drh 6255 return 1;
4f76459… drh 6256 #else
4f76459… drh 6257 sCtx.in = sqlite3_popen(sCtx.zFile+1, "r");
4f76459… drh 6258 sCtx.zFile = "<pipe>";
4f76459… drh 6259 sCtx.xCloser = pclose;
4f76459… drh 6260 #endif
b9ecacf… drh 6261 }else if( sCtx.zFile[0]=='<' && sCtx.zFile[1]=='<' && sCtx.zFile[2]!=0 ){
b9ecacf… drh 6262 /* Input text comes from subsequent lines of script until the zFile
b9ecacf… drh 6263 ** delimiter */
b9ecacf… drh 6264 int nEndMark = strlen30(zFile)-2;
b9ecacf… drh 6265 char *zEndMark = &zFile[2];
b9ecacf… drh 6266 sqlite3_str *pContent = sqlite3_str_new(p->db);
b9ecacf… drh 6267 int ckEnd = 1;
b9ecacf… drh 6268 i64 iStart = p->lineno;
b9ecacf… drh 6269 char zLine[2000];
b9ecacf… drh 6270 sCtx.zFile = p->zInFile;
b9ecacf… drh 6271 sCtx.nLine = p->lineno+1;
b9ecacf… drh 6272 iLineOffset = p->lineno;
b9ecacf… drh 6273 while( sqlite3_fgets(zLine,sizeof(zLine),p->in) ){
b9ecacf… drh 6274 if( ckEnd && cli_strncmp(zLine,zEndMark,nEndMark)==0 ){
b9ecacf… drh 6275 ckEnd = 2;
b9ecacf… drh 6276 if( strchr(zLine,'\n') ) p->lineno++;
b9ecacf… drh 6277 break;
b9ecacf… drh 6278 }
b9ecacf… drh 6279 if( strchr(zLine,'\n') ){
b9ecacf… drh 6280 p->lineno++;
b9ecacf… drh 6281 ckEnd = 1;
b9ecacf… drh 6282 }else{
b9ecacf… drh 6283 ckEnd = 0;
b9ecacf… drh 6284 }
b9ecacf… drh 6285 sqlite3_str_appendall(pContent, zLine);
b9ecacf… drh 6286 }
b9ecacf… drh 6287 sCtx.zIn = sqlite3_str_finish(pContent);
b9ecacf… drh 6288 if( sCtx.zIn==0 ){
b9ecacf… drh 6289 sCtx.zIn = sqlite3_mprintf("");
b9ecacf… drh 6290 }
b9ecacf… drh 6291 if( ckEnd<2 ){
b9ecacf… drh 6292 i64 savedLn = p->lineno;
b9ecacf… drh 6293 p->lineno = iStart;
b9ecacf… drh 6294 dotCmdError(p, 0, 0,"Content terminator \"%s\" not found.",zEndMark);
b9ecacf… drh 6295 p->lineno = savedLn;
b9ecacf… drh 6296 import_cleanup(&sCtx);
b9ecacf… drh 6297 return 1;
b9ecacf… drh 6298 }
4f76459… drh 6299 }else{
4f76459… drh 6300 sCtx.in = sqlite3_fopen(sCtx.zFile, "rb");
4f76459… drh 6301 sCtx.xCloser = fclose;
4f76459… drh 6302 }
b9ecacf… drh 6303 if( sCtx.in==0 && sCtx.zIn==0 ){
b9ecacf… drh 6304 dotCmdError(p, 0, 0, "cannot open \"%s\"", zFile);
b9ecacf… drh 6305 import_cleanup(&sCtx);
4f76459… drh 6306 return 1;
4f76459… drh 6307 }
b9ecacf… drh 6308 if( eVerbose>=1 ){
4f76459… drh 6309 char zSep[2];
4f76459… drh 6310 zSep[1] = 0;
4f76459… drh 6311 zSep[0] = sCtx.cColSep;
4f76459… drh 6312 cli_puts("Column separator ", p->out);
4f76459… drh 6313 output_c_string(p->out, zSep);
4f76459… drh 6314 cli_puts(", row separator ", p->out);
4f76459… drh 6315 zSep[0] = sCtx.cRowSep;
4f76459… drh 6316 output_c_string(p->out, zSep);
4f76459… drh 6317 cli_puts("\n", p->out);
4f76459… drh 6318 }
4f76459… drh 6319 sCtx.z = sqlite3_malloc64(120);
4f76459… drh 6320 if( sCtx.z==0 ){
4f76459… drh 6321 import_cleanup(&sCtx);
4f76459… drh 6322 shell_out_of_memory();
4f76459… drh 6323 }
4f76459… drh 6324 /* Below, resources must be freed before exit. */
4f76459… drh 6325 while( nSkip>0 ){
4f76459… drh 6326 nSkip--;
4f76459… drh 6327 while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
4f76459… drh 6328 }
4f76459… drh 6329 import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
4f76459… drh 6330 if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0)
4f76459… drh 6331 && 0==db_int(p->db, "SELECT count(*) FROM \"%w\".sqlite_schema"
4f76459… drh 6332 " WHERE name=%Q AND type='view'",
4f76459… drh 6333 zSchema ? zSchema : "main", zTable)
4f76459… drh 6334 ){
4f76459… drh 6335 /* Table does not exist. Create it. */
4f76459… drh 6336 sqlite3 *dbCols = 0;
4f76459… drh 6337 char *zRenames = 0;
4f76459… drh 6338 char *zColDefs;
4f76459… drh 6339 zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"",
4f76459… drh 6340 zSchema ? zSchema : "main", zTable);
4f76459… drh 6341 while( xRead(&sCtx) ){
4f76459… drh 6342 zAutoColumn(sCtx.z, &dbCols, 0);
4f76459… drh 6343 if( sCtx.cTerm!=sCtx.cColSep ) break;
4f76459… drh 6344 }
4f76459… drh 6345 zColDefs = zAutoColumn(0, &dbCols, &zRenames);
4f76459… drh 6346 if( zRenames!=0 ){
4f76459… drh 6347 cli_printf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
4f76459… drh 6348 "Columns renamed during .import %s due to duplicates:\n"
4f76459… drh 6349 "%s\n", sCtx.zFile, zRenames);
4f76459… drh 6350 sqlite3_free(zRenames);
4f76459… drh 6351 }
4f76459… drh 6352 assert(dbCols==0);
4f76459… drh 6353 if( zColDefs==0 ){
4f76459… drh 6354 cli_printf(stderr,"%s: empty file\n", sCtx.zFile);
4f76459… drh 6355 import_cleanup(&sCtx);
4f76459… drh 6356 sqlite3_free(zCreate);
4f76459… drh 6357 return 1;
4f76459… drh 6358 }
4f76459… drh 6359 zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs);
4f76459… drh 6360 if( zCreate==0 ){
4f76459… drh 6361 import_cleanup(&sCtx);
4f76459… drh 6362 shell_out_of_memory();
4f76459… drh 6363 }
4f76459… drh 6364 if( eVerbose>=1 ){
4f76459… drh 6365 cli_printf(p->out, "%s\n", zCreate);
4f76459… drh 6366 }
4f76459… drh 6367 rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
4f76459… drh 6368 if( rc ){
4f76459… drh 6369 cli_printf(stderr,
4f76459… drh 6370 "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
4f76459… drh 6371 }
4f76459… drh 6372 sqlite3_free(zCreate);
4f76459… drh 6373 zCreate = 0;
4f76459… drh 6374 if( rc ){
4f76459… drh 6375 import_cleanup(&sCtx);
4f76459… drh 6376 return 1;
4f76459… drh 6377 }
4f76459… drh 6378 }
4f76459… drh 6379 zSql = sqlite3_mprintf("SELECT count(*) FROM pragma_table_info(%Q,%Q);",
4f76459… drh 6380 zTable, zSchema);
4f76459… drh 6381 if( zSql==0 ){
4f76459… drh 6382 import_cleanup(&sCtx);
4f76459… drh 6383 shell_out_of_memory();
4f76459… drh 6384 }
4f76459… drh 6385 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
4f76459… drh 6386 sqlite3_free(zSql);
4f76459… drh 6387 zSql = 0;
4f76459… drh 6388 if( rc ){
4f76459… drh 6389 if (pStmt) sqlite3_finalize(pStmt);
4f76459… drh 6390 shellDatabaseError(p->db);
4f76459… drh 6391 import_cleanup(&sCtx);
4f76459… drh 6392 return 1;
4f76459… drh 6393 }
4f76459… drh 6394 if( sqlite3_step(pStmt)==SQLITE_ROW ){
4f76459… drh 6395 nCol = sqlite3_column_int(pStmt, 0);
4f76459… drh 6396 }else{
4f76459… drh 6397 nCol = 0;
4f76459… drh 6398 }
4f76459… drh 6399 sqlite3_finalize(pStmt);
4f76459… drh 6400 pStmt = 0;
4f76459… drh 6401 if( nCol==0 ) return 0; /* no columns, no error */
4f76459… drh 6402
4f76459… drh 6403 nByte = 64 /* space for "INSERT INTO", "VALUES(", ")\0" */
4f76459… drh 6404 + (zSchema ? strlen(zSchema)*2 + 2: 0) /* Quoted schema name */
4f76459… drh 6405 + strlen(zTable)*2 + 2 /* Quoted table name */
4f76459… drh 6406 + nCol*2; /* Space for ",?" for each column */
4f76459… drh 6407 zSql = sqlite3_malloc64( nByte );
4f76459… drh 6408 if( zSql==0 ){
4f76459… drh 6409 import_cleanup(&sCtx);
4f76459… drh 6410 shell_out_of_memory();
4f76459… drh 6411 }
4f76459… drh 6412 if( zSchema ){
4f76459… drh 6413 sqlite3_snprintf(nByte, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?",
4f76459… drh 6414 zSchema, zTable);
4f76459… drh 6415 }else{
4f76459… drh 6416 sqlite3_snprintf(nByte, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
4f76459… drh 6417 }
4f76459… drh 6418 j = strlen30(zSql);
4f76459… drh 6419 for(i=1; i<nCol; i++){
4f76459… drh 6420 zSql[j++] = ',';
4f76459… drh 6421 zSql[j++] = '?';
4f76459… drh 6422 }
4f76459… drh 6423 zSql[j++] = ')';
4f76459… drh 6424 zSql[j] = 0;
4f76459… drh 6425 assert( j<nByte );
4f76459… drh 6426 if( eVerbose>=2 ){
4f76459… drh 6427 cli_printf(p->out, "Insert using: %s\n", zSql);
4f76459… drh 6428 }
4f76459… drh 6429 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
4f76459… drh 6430 sqlite3_free(zSql);
4f76459… drh 6431 zSql = 0;
4f76459… drh 6432 if( rc ){
4f76459… drh 6433 shellDatabaseError(p->db);
4f76459… drh 6434 if (pStmt) sqlite3_finalize(pStmt);
4f76459… drh 6435 import_cleanup(&sCtx);
4f76459… drh 6436 return 1;
4f76459… drh 6437 }
4f76459… drh 6438 needCommit = sqlite3_get_autocommit(p->db);
4f76459… drh 6439 if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
4f76459… drh 6440 do{
4f76459… drh 6441 int startLine = sCtx.nLine;
4f76459… drh 6442 for(i=0; i<nCol; i++){
4f76459… drh 6443 char *z = xRead(&sCtx);
4f76459… drh 6444 /*
4f76459… drh 6445 ** Did we reach end-of-file before finding any columns?
4f76459… drh 6446 ** If so, stop instead of NULL filling the remaining columns.
4f76459… drh 6447 */
4f76459… drh 6448 if( z==0 && i==0 ) break;
4f76459… drh 6449 /*
4f76459… drh 6450 ** Did we reach end-of-file OR end-of-line before finding any
4f76459… drh 6451 ** columns in ASCII mode? If so, stop instead of NULL filling
4f76459… drh 6452 ** the remaining columns.
4f76459… drh 6453 */
4f76459… drh 6454 if( p->mode.eMode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
4f76459… drh 6455 /*
4f76459… drh 6456 ** For CSV mode, per RFC 4180, accept EOF in lieu of final
4f76459… drh 6457 ** record terminator but only for last field of multi-field row.
4f76459… drh 6458 ** (If there are too few fields, it's not valid CSV anyway.)
4f76459… drh 6459 */
4f76459… drh 6460 if( z==0 && (xRead==csv_read_one_field) && i==nCol-1 && i>0 ){
4f76459… drh 6461 z = "";
4f76459… drh 6462 }
4f76459… drh 6463 sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
4f76459… drh 6464 if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
b9ecacf… drh 6465 if( i==0 && (strcmp(z,"\n")==0 || strcmp(z,"\r\n")==0) ){
b9ecacf… drh 6466 /* Ignore trailing \n or \r\n when some other row separator */
b9ecacf… drh 6467 break;
b9ecacf… drh 6468 }
4f76459… drh 6469 cli_printf(stderr,"%s:%d: expected %d columns but found %d"
4f76459… drh 6470 " - filling the rest with NULL\n",
4f76459… drh 6471 sCtx.zFile, startLine, nCol, i+1);
4f76459… drh 6472 i += 2;
4f76459… drh 6473 while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
4f76459… drh 6474 }
4f76459… drh 6475 }
4f76459… drh 6476 if( sCtx.cTerm==sCtx.cColSep ){
4f76459… drh 6477 do{
4f76459… drh 6478 xRead(&sCtx);
4f76459… drh 6479 i++;
4f76459… drh 6480 }while( sCtx.cTerm==sCtx.cColSep );
4f76459… drh 6481 cli_printf(stderr,
4f76459… drh 6482 "%s:%d: expected %d columns but found %d - extras ignored\n",
4f76459… drh 6483 sCtx.zFile, startLine, nCol, i);
4f76459… drh 6484 }
4f76459… drh 6485 if( i>=nCol ){
4f76459… drh 6486 sqlite3_step(pStmt);
4f76459… drh 6487 rc = sqlite3_reset(pStmt);
4f76459… drh 6488 if( rc!=SQLITE_OK ){
4f76459… drh 6489 cli_printf(stderr,"%s:%d: INSERT failed: %s\n",
4f76459… drh 6490 sCtx.zFile, startLine, sqlite3_errmsg(p->db));
4f76459… drh 6491 sCtx.nErr++;
b9ecacf… drh 6492 if( bail_on_error ) break;
4f76459… drh 6493 }else{
4f76459… drh 6494 sCtx.nRow++;
4f76459… drh 6495 }
4f76459… drh 6496 }
4f76459… drh 6497 }while( sCtx.cTerm!=EOF );
4f76459… drh 6498
4f76459… drh 6499 import_cleanup(&sCtx);
4f76459… drh 6500 sqlite3_finalize(pStmt);
4f76459… drh 6501 if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
4f76459… drh 6502 if( eVerbose>0 ){
4f76459… drh 6503 cli_printf(p->out,
4f76459… drh 6504 "Added %d rows with %d errors using %d lines of input\n",
b9ecacf… drh 6505 sCtx.nRow, sCtx.nErr, sCtx.nLine-1-iLineOffset);
4f76459… drh 6506 }
b9ecacf… drh 6507 return sCtx.nErr ? 1 : 0;
4f76459… drh 6508 }
4f76459… drh 6509
4f76459… drh 6510
4f76459… drh 6511 /*
4f76459… drh 6512 ** This function computes what to show the user about the configured
4f76459… drh 6513 ** titles (or column-names). Output is an integer between 0 and 3:
4f76459… drh 6514 **
4f76459… drh 6515 ** 0: The titles do not matter. Never show anything.
4f76459… drh 6516 ** 1: Show "--titles off"
4f76459… drh 6517 ** 2: Show "--titles on"
4f76459… drh 6518 ** 3: Show "--title VALUE" where VALUE is an encoding method
4f76459… drh 6519 ** to use, one of: plain sql csv html tcl json
4f76459… drh 6520 **
4f76459… drh 6521 ** Inputs are:
4f76459… drh 6522 **
4f76459… drh 6523 ** spec.bTitles (bT) Whether or not to show the titles
4f76459… drh 6524 ** spec.eTitle (eT) The actual encoding to be used for titles
4f76459… drh 6525 ** ModeInfo.bHdr (bH) Default value for spec.bTitles
4f76459… drh 6526 ** ModeInfo.eHdr (eH) Default value for spec.eTitle
4f76459… drh 6527 ** bAll Whether the -v option is used
4f76459… drh 6528 */
4f76459… drh 6529 static int modeTitleDsply(ShellState *p, int bAll){
4f76459… drh 6530 int eMode = p->mode.eMode;
4f76459… drh 6531 const ModeInfo *pI = &aModeInfo[eMode];
4f76459… drh 6532 int bT = p->mode.spec.bTitles;
4f76459… drh 6533 int eT = p->mode.spec.eTitle;
4f76459… drh 6534 int bH = pI->bHdr;
4f76459… drh 6535 int eH = pI->eHdr;
4f76459… drh 6536
4f76459… drh 6537 /* Variable "v" is the truth table that will determine the answer
4f76459… drh 6538 **
4f76459… drh 6539 ** Actual encoding is different from default
cb89386… drh 6540 ** vvvvvvvv */
cb89386… drh 6541 sqlite3_uint64 v = UINT64_C(0x0133013311220102);
cb89386… drh 6542 /* ^^^^ ^^^^
4f76459… drh 6543 ** Upper 2-byte groups for when ON/OFF disagrees with
4f76459… drh 6544 ** the default. */
4f76459… drh 6545
4f76459… drh 6546 if( bH==0 ) return 0; /* Header not appliable. Ex: off, count */
4f76459… drh 6547
4f76459… drh 6548 if( eT==0 ) eT = eH; /* Fill in missing spec.eTitle */
4f76459… drh 6549 if( bT==0 ) bT = bH; /* Fill in missing spec.bTitles */
4f76459… drh 6550
4f76459… drh 6551 if( eT!=eH ) v >>= 32; /* Encoding disagree in upper 4-bytes */
4f76459… drh 6552 if( bT!=bH ) v >>= 16; /* ON/OFF disagree in upper 2-byte pairs */
4f76459… drh 6553 if( bT<2 ) v >>= 8; /* ON in even bytes, OFF in odd bytes (1st byte 0) */
4f76459… drh 6554 if( !bAll ) v >>= 4; /* bAll values are in the lower half-byte */
4f76459… drh 6555
4f76459… drh 6556 return v & 3; /* Return the selected truth-table entry */
4f76459… drh 6557 }
4f76459… drh 6558
4f76459… drh 6559 /*
4f76459… drh 6560 ** DOT-COMMAND: .mode
4f76459… drh 6561 **
4f76459… drh 6562 ** USAGE: .mode [MODE] [OPTIONS]
4f76459… drh 6563 **
45de97f… drh 6564 ** Change the output mode to MODE and/or apply OPTIONS to the output mode.
45de97f… drh 6565 ** Arguments are processed from left to right. If no arguments, show the
45de97f… drh 6566 ** current output mode and relevant options.
4f76459… drh 6567 **
4f76459… drh 6568 ** Options:
4f76459… drh 6569 ** --align STRING Set the alignment of text in columnar modes
4f76459… drh 6570 ** String consists of characters 'L', 'C', 'R'
4f76459… drh 6571 ** meaning "left", "centered", and "right", with
4f76459… drh 6572 ** one letter per column starting from the left.
4f76459… drh 6573 ** Unspecified alignment defaults to 'L'.
45de97f… drh 6574 ** --blob-quote ARG ARG can be "auto", "text", "sql", "hex", "tcl",
45de97f… drh 6575 ** "json", or "size". Default is "auto".
f4b3b59… drh 6576 ** --border on|off Show outer border on "box" and "table" modes.
4f76459… drh 6577 ** --charlimit N Set the maximum number of output characters to
4f76459… drh 6578 ** show for any single SQL value to N. Longer values
4f76459… drh 6579 ** truncated. Zero means "no limit".
4f76459… drh 6580 ** --colsep STRING Use STRING as the column separator
4f76459… drh 6581 ** --escape ESC Enable/disable escaping of control characters
45de97f… drh 6582 ** found in the output. ESC can be "off", "ascii",
45de97f… drh 6583 ** or "symbol".
4f76459… drh 6584 ** --linelimit N Set the maximum number of output lines to show for
4f76459… drh 6585 ** any single SQL value to N. Longer values are
4f76459… drh 6586 ** truncated. Zero means "no limit". Only works
4f76459… drh 6587 ** in "line" mode and in columnar modes.
ae7e3f0… drh 6588 ** --limits L,C,T Shorthand for "--linelimit L --charlimit C
ae7e3f0… drh 6589 ** --titlelimit T". The ",T" can be omitted in which
ae7e3f0… drh 6590 ** case the --titlelimit is unchanged. The argument
ae7e3f0… drh 6591 ** can also be "off" to mean "0,0,0" or "on" to
ae7e3f0… drh 6592 ** mean "5,300,20".
4f76459… drh 6593 ** --list List available modes
17f9878… drh 6594 ** --multiinsert N In "insert" mode, put multiple rows on a single
17f9878… drh 6595 ** INSERT statement until the size exceeds N bytes.
4f76459… drh 6596 ** --null STRING Render SQL NULL values as the given string
4f76459… drh 6597 ** --once Setting changes to the right are reverted after
4f76459… drh 6598 ** the next SQL command.
4f76459… drh 6599 ** --quote ARG Enable/disable quoting of text. ARG can be
709b566… drh 6600 ** "off", "on", "sql", "relaxed", "csv", "html",
709b566… drh 6601 ** "tcl", or "json". "off" means show the text as-is.
45de97f… drh 6602 ** "on" is an alias for "sql".
4f76459… drh 6603 ** --reset Changes all mode settings back to their default.
4f76459… drh 6604 ** --rowsep STRING Use STRING as the row separator
45de97f… drh 6605 ** --sw|--screenwidth N Declare the screen width of the output device
4f76459… drh 6606 ** to be N characters. An attempt may be made to
4f76459… drh 6607 ** wrap output text to fit within this limit. Zero
4f76459… drh 6608 ** means "no limit". Or N can be "auto" to set the
4f76459… drh 6609 ** width automatically.
4f76459… drh 6610 ** --tablename NAME Set the name of the table for "insert" mode.
4f76459… drh 6611 ** --tag NAME Save mode to the left as NAME.
4f76459… drh 6612 ** --textjsonb BOOLEAN If enabled, JSONB text is displayed as text JSON.
45de97f… drh 6613 ** --title ARG Whether or not to show column headers, and if so
4f76459… drh 6614 ** how to encode them. ARG can be "off", "on",
4f76459… drh 6615 ** "sql", "csv", "html", "tcl", or "json".
ae7e3f0… drh 6616 ** --titlelimit N Limit the length of column titles to N characters.
4f76459… drh 6617 ** -v|--verbose Verbose output
4f76459… drh 6618 ** --widths LIST Set the columns widths for columnar modes. The
4f76459… drh 6619 ** argument is a list of integers, one for each
4f76459… drh 6620 ** column. A "0" width means use a dynamic width
4f76459… drh 6621 ** based on the actual width of data. If there are
4f76459… drh 6622 ** fewer entries in LIST than columns, "0" is used
4f76459… drh 6623 ** for the unspecified widths.
4f76459… drh 6624 ** --wordwrap BOOLEAN Enable/disable word wrapping
4f76459… drh 6625 ** --wrap N Wrap columns wider than N characters
4f76459… drh 6626 ** --ww Shorthand for "--wordwrap on"
4f76459… drh 6627 */
4f76459… drh 6628 static int dotCmdMode(ShellState *p){
4f76459… drh 6629 int nArg = p->dot.nArg; /* Number of arguments */
4f76459… drh 6630 char **azArg = p->dot.azArg;/* Argument list */
4f76459… drh 6631 int eMode = -1; /* New mode value, or -1 for none */
4f76459… drh 6632 int iMode = -1; /* Index of the argument that is the mode name */
4f76459… drh 6633 int i; /* Loop counter */
4f76459… drh 6634 int k; /* Misc index variable */
4f76459… drh 6635 int chng = 0; /* True if anything has changed */
4f76459… drh 6636 int bAll = 0; /* Show all details of the mode */
4f76459… drh 6637
4f76459… drh 6638 for(i=1; i<nArg; i++){
4f76459… drh 6639 const char *z = azArg[i];
4f76459… drh 6640 if( z[0]=='-' && z[1]=='-' ) z++;
4f76459… drh 6641 if( z[0]!='-'
4f76459… drh 6642 && iMode<0
4f76459… drh 6643 && (eMode = modeFind(p, azArg[i]))>=0
4f76459… drh 6644 && eMode!=MODE_Www
4f76459… drh 6645 ){
4f76459… drh 6646 iMode = i;
4f76459… drh 6647 modeChange(p, eMode);
4f76459… drh 6648 /* (Legacy) If the mode is MODE_Insert and the next argument
4f76459… drh 6649 ** is not an option, then the next argument must be the table
4f76459… drh 6650 ** name.
4f76459… drh 6651 */
4f76459… drh 6652 if( i+1<nArg && azArg[i+1][0]!='-' ){
4f76459… drh 6653 i++;
4f76459… drh 6654 modeSetStr(&p->mode.spec.zTableName, azArg[i]);
4f76459… drh 6655 }
4f76459… drh 6656 chng = 1;
4f76459… drh 6657 }else if( optionMatch(z,"align") ){
4f76459… drh 6658 char *zAlign;
4f76459… drh 6659 int nAlign;
4f76459… drh 6660 int nErr = 0;
4f76459… drh 6661 if( i+1>=nArg ){
4f76459… drh 6662 dotCmdError(p, i, "missing argument", 0);
4f76459… drh 6663 return 1;
4f76459… drh 6664 }
4f76459… drh 6665 i++;
4f76459… drh 6666 zAlign = azArg[i];
4f76459… drh 6667 nAlign = 0x3fff & strlen(zAlign);
4f76459… drh 6668 free(p->mode.spec.aAlign);
4f76459… drh 6669 p->mode.spec.aAlign = malloc(nAlign);
4f76459… drh 6670 shell_check_oom(p->mode.spec.aAlign);
4f76459… drh 6671 for(k=0; k<nAlign; k++){
4f76459… drh 6672 unsigned char c = 0;
4f76459… drh 6673 switch( zAlign[k] ){
4f76459… drh 6674 case 'l': case 'L': c = QRF_ALIGN_Left; break;
4f76459… drh 6675 case 'c': case 'C': c = QRF_ALIGN_Center; break;
4f76459… drh 6676 case 'r': case 'R': c = QRF_ALIGN_Right; break;
4f76459… drh 6677 default: nErr++; break;
4f76459… drh 6678 }
4f76459… drh 6679 p->mode.spec.aAlign[k] = c;
4f76459… drh 6680 }
4f76459… drh 6681 p->mode.spec.nAlign = nAlign;
4f76459… drh 6682 chng = 1;
4f76459… drh 6683 if( nErr ){
4f76459… drh 6684 dotCmdError(p, i, "bad alignment string",
4f76459… drh 6685 "Should contain only characters L, C, and R.");
4f76459… drh 6686 return 1;
4f76459… drh 6687 }
45de97f… drh 6688 }else if( pickStr(z,0,"-blob","-blob-quote","")>=0 ){
45de97f… drh 6689 if( (++i)>=nArg ){
45de97f… drh 6690 dotCmdError(p, i-1, "missing argument", 0);
45de97f… drh 6691 return 1;
45de97f… drh 6692 }
45de97f… drh 6693 k = pickStr(azArg[i], 0,
45de97f… drh 6694 "auto", "text", "sql", "hex", "tcl", "json", "size", "");
45de97f… drh 6695 /* 0 1 2 3 4 5 6
45de97f… drh 6696 ** Must match QRF_BLOB_xxxx values. See also tag-20251124a */
45de97f… drh 6697 if( k>=0 ){
45de97f… drh 6698 p->mode.spec.eBlob = k & 0xff;
45de97f… drh 6699 }
45de97f… drh 6700 chng = 1;
f4b3b59… drh 6701 }else if( optionMatch(z,"border") ){
f4b3b59… drh 6702 if( (++i)>=nArg ){
f4b3b59… drh 6703 dotCmdError(p, i-1, "missing argument", 0);
f4b3b59… drh 6704 return 1;
f4b3b59… drh 6705 }
f4b3b59… drh 6706 k = pickStr(azArg[i], 0, "auto", "off", "on", "");
f4b3b59… drh 6707 if( k>=0 ){
f4b3b59… drh 6708 p->mode.spec.bBorder = k & 0x3;
f4b3b59… drh 6709 }
f4b3b59… drh 6710 chng = 1;
17f9878… drh 6711 }else if( 0<=(k=pickStr(z,0,
17f9878… drh 6712 "-charlimit","-linelimit","-titlelimit","-multiinsert","")) ){
17f9878… drh 6713 int w; /* 0 1 2 3 */
4f76459… drh 6714 if( i+1>=nArg ){
4f76459… drh 6715 dotCmdError(p, i, "missing argument", 0);
4f76459… drh 6716 return 1;
4f76459… drh 6717 }
4f76459… drh 6718 w = integerValue(azArg[++i]);
ae7e3f0… drh 6719 switch( k ){
17f9878… drh 6720 case 0: p->mode.spec.nCharLimit = w; break;
17f9878… drh 6721 case 1: p->mode.spec.nLineLimit = w; break;
17f9878… drh 6722 case 2: p->mode.spec.nTitleLimit = w; break;
17f9878… drh 6723 default: p->mode.spec.nMultiInsert = w; break;
4f76459… drh 6724 }
4f76459… drh 6725 chng = 1;
4f76459… drh 6726 }else if( 0<=(k=pickStr(z,0,"-tablename","-rowsep","-colsep","-null","")) ){
4f76459… drh 6727 /* 0 1 2 3 */
4f76459… drh 6728 if( i+1>=nArg ){
4f76459… drh 6729 dotCmdError(p, i, "missing argument", 0);
4f76459… drh 6730 return 1;
4f76459… drh 6731 }
4f76459… drh 6732 i++;
4f76459… drh 6733 switch( k ){
4f76459… drh 6734 case 0: modeSetStr(&p->mode.spec.zTableName, azArg[i]); break;
4f76459… drh 6735 case 1: modeSetStr(&p->mode.spec.zRowSep, azArg[i]); break;
4f76459… drh 6736 case 2: modeSetStr(&p->mode.spec.zColumnSep, azArg[i]); break;
4f76459… drh 6737 case 3: modeSetStr(&p->mode.spec.zNull, azArg[i]); break;
4f76459… drh 6738 }
4f76459… drh 6739 chng = 1;
4f76459… drh 6740 }else if( optionMatch(z,"escape") ){
4f76459… drh 6741 /* See similar code at tag-20250224-1 */
4f76459… drh 6742 char *zErr = 0;
45de97f… drh 6743 if( (++i)>=nArg ){
45de97f… drh 6744 dotCmdError(p, i-1, "missing argument", 0);
4f76459… drh 6745 return 1;
45de97f… drh 6746 } /* 0 1 2 <-- One less than QRF_ESC_ */
4f76459… drh 6747 k = pickStr(azArg[i],&zErr,"off","ascii","symbol","");
4f76459… drh 6748 if( k<0 ){
4f76459… drh 6749 dotCmdError(p, i, "unknown escape type", "%s", zErr);
4f76459… drh 6750 sqlite3_free(zErr);
4f76459… drh 6751 return 1;
4f76459… drh 6752 }
4f76459… drh 6753 p->mode.spec.eEsc = k+1;
45de97f… drh 6754 chng = 1;
45de97f… drh 6755 }else if( optionMatch(z,"limits") ){
45de97f… drh 6756 if( (++i)>=nArg ){
45de97f… drh 6757 dotCmdError(p, i-1, "missing argument", 0);
45de97f… drh 6758 return 1;
45de97f… drh 6759 }
45de97f… drh 6760 k = pickStr(azArg[i],0,"on","off","");
45de97f… drh 6761 if( k==0 ){
ae7e3f0… drh 6762 p->mode.spec.nLineLimit = DFLT_LINE_LIMIT;
ae7e3f0… drh 6763 p->mode.spec.nCharLimit = DFLT_CHAR_LIMIT;
ae7e3f0… drh 6764 p->mode.spec.nTitleLimit = DFLT_TITLE_LIMIT;
45de97f… drh 6765 }else if( k==1 ){
45de97f… drh 6766 p->mode.spec.nLineLimit = 0;
45de97f… drh 6767 p->mode.spec.nCharLimit = 0;
ae7e3f0… drh 6768 p->mode.spec.nTitleLimit = 0;
45de97f… drh 6769 }else{
ae7e3f0… drh 6770 int L, C, T = 0;
ae7e3f0… drh 6771 int nNum = sscanf(azArg[i], "%d,%d,%d", &L, &C, &T);
ae7e3f0… drh 6772 if( nNum<2 || L<0 || C<0 || T<0){
ae7e3f0… drh 6773 dotCmdError(p, i, "bad argument", "Should be \"L,C,T\" where L, C"
ae7e3f0… drh 6774 " and T are unsigned integers");
45de97f… drh 6775 return 1;
45de97f… drh 6776 }
45de97f… drh 6777 p->mode.spec.nLineLimit = L;
45de97f… drh 6778 p->mode.spec.nCharLimit = C;
ae7e3f0… drh 6779 if( nNum==3 ) p->mode.spec.nTitleLimit = T;
45de97f… drh 6780 }
4f76459… drh 6781 chng = 1;
4f76459… drh 6782 }else if( optionMatch(z,"list") ){
4f76459… drh 6783 int ii;
4f76459… drh 6784 cli_puts("available modes:", p->out);
4f76459… drh 6785 for(ii=0; ii<ArraySize(aModeInfo); ii++){
4f76459… drh 6786 if( ii==MODE_Www ) continue;
4f76459… drh 6787 cli_printf(p->out, " %s", aModeInfo[ii].zName);
4f76459… drh 6788 }
4f76459… drh 6789 for(ii=0; ii<p->nSavedModes; ii++){
4f76459… drh 6790 cli_printf(p->out, " %s", p->aSavedModes[ii].zTag);
4f76459… drh 6791 }
4f76459… drh 6792 cli_puts(" batch tty\n", p->out);
45de97f… drh 6793 chng = 1; /* Not really a change, but we still want to suppress the
45de97f… drh 6794 ** "current mode" output */
9aee493… drh 6795 }else if( optionMatch(z,"once") ){
9aee493… drh 6796 p->nPopMode = 0;
9aee493… drh 6797 modePush(p);
9aee493… drh 6798 p->nPopMode = 1;
9aee493… drh 6799 }else if( optionMatch(z,"noquote") ){
9aee493… drh 6800 /* (undocumented legacy) --noquote always turns quoting off */
9aee493… drh 6801 p->mode.spec.eText = QRF_TEXT_Plain;
45de97f… drh 6802 p->mode.spec.eBlob = QRF_BLOB_Auto;
9aee493… drh 6803 chng = 1;
4f76459… drh 6804 }else if( optionMatch(z,"quote") ){
4f76459… drh 6805 if( i+1<nArg
4f76459… drh 6806 && azArg[i+1][0]!='-'
4f76459… drh 6807 && (iMode>0 || strcmp(azArg[i+1],"off")==0 || modeFind(p, azArg[i+1])<0)
4f76459… drh 6808 ){
4f76459… drh 6809 /* --quote is followed by an argument other that is not an option
4f76459… drh 6810 ** or a mode name. See it must be a boolean or a keyword to describe
4f76459… drh 6811 ** how to set quoting. */
4f76459… drh 6812 i++;
4f76459… drh 6813 if( (k = pickStr(azArg[i],0,"no","yes","0","1",""))>=0 ){
4f76459… drh 6814 k &= 1; /* 0 for "off". 1 for "on". */
4f76459… drh 6815 }else{
709b566… drh 6816 char *zErr = 0;
709b566… drh 6817 k = pickStr(azArg[i],&zErr,
709b566… drh 6818 "off","on","sql","csv","html","tcl","json","relaxed","");
709b566… drh 6819 /* 0 1 2 3 4 5 6 7 */
4f76459… drh 6820 if( k<0 ){
4f76459… drh 6821 dotCmdError(p, i, "unknown", "%z", zErr);
4f76459… drh 6822 return 1;
4f76459… drh 6823 }
4f76459… drh 6824 }
4f76459… drh 6825 }else{
4f76459… drh 6826 /* (Legacy) no following boolean argument. Turn quoting on */
4f76459… drh 6827 k = 1;
4f76459… drh 6828 }
4f76459… drh 6829 switch( k ){
4f76459… drh 6830 case 1: /* on */
45de97f… drh 6831 modeSetStr(&p->mode.spec.zNull, "NULL");
45de97f… drh 6832 /* Fall through */
4f76459… drh 6833 case 2: /* sql */
4f76459… drh 6834 p->mode.spec.eText = QRF_TEXT_Sql;
4f76459… drh 6835 break;
4f76459… drh 6836 case 3: /* csv */
4f76459… drh 6837 p->mode.spec.eText = QRF_TEXT_Csv;
4f76459… drh 6838 break;
4f76459… drh 6839 case 4: /* html */
4f76459… drh 6840 p->mode.spec.eText = QRF_TEXT_Html;
4f76459… drh 6841 break;
4f76459… drh 6842 case 5: /* tcl */
4f76459… drh 6843 p->mode.spec.eText = QRF_TEXT_Tcl;
4f76459… drh 6844 break;
4f76459… drh 6845 case 6: /* json */
4f76459… drh 6846 p->mode.spec.eText = QRF_TEXT_Json;
709b566… drh 6847 break;
709b566… drh 6848 case 7: /* relaxed */
709b566… drh 6849 p->mode.spec.eText = QRF_TEXT_Relaxed;
9aee493… drh 6850 break;
45de97f… drh 6851 default: /* off */
9aee493… drh 6852 p->mode.spec.eText = QRF_TEXT_Plain;
9aee493… drh 6853 break;
9aee493… drh 6854 }
4f76459… drh 6855 chng = 1;
4f76459… drh 6856 }else if( optionMatch(z,"reset") ){
4f76459… drh 6857 int saved_eMode = p->mode.eMode;
4f76459… drh 6858 modeFree(&p->mode);
4f76459… drh 6859 modeChange(p, saved_eMode);
45de97f… drh 6860 }else if( optionMatch(z,"screenwidth") || optionMatch(z,"sw") ){
45de97f… drh 6861 if( (++i)>=nArg ){
45de97f… drh 6862 dotCmdError(p, i-1, "missing argument", 0);
4f76459… drh 6863 return 1;
4f76459… drh 6864 }
45de97f… drh 6865 k = pickStr(azArg[i],0,"off","auto","");
4f76459… drh 6866 if( k==0 ){
4f76459… drh 6867 p->mode.bAutoScreenWidth = 0;
4f76459… drh 6868 p->mode.spec.nScreenWidth = 0;
4f76459… drh 6869 }else if( k==1 ){
4f76459… drh 6870 p->mode.bAutoScreenWidth = 1;
4f76459… drh 6871 }else{
45de97f… drh 6872 i64 w = integerValue(azArg[i]);
4f76459… drh 6873 p->mode.bAutoScreenWidth = 0;
4f76459… drh 6874 if( w<0 ) w = 0;
4f76459… drh 6875 if( w>QRF_MAX_WIDTH ) w = QRF_MAX_WIDTH;
4f76459… drh 6876 p->mode.spec.nScreenWidth = w;
4f76459… drh 6877 }
4f76459… drh 6878 chng = 1;
4f76459… drh 6879 }else if( optionMatch(z,"tag") ){
4f76459… drh 6880 size_t nByte;
4f76459… drh 6881 int n;
4f76459… drh 6882 const char *zTag;
4f76459… drh 6883 if( i+1>=nArg ){
4f76459… drh 6884 dotCmdError(p, i, "missing argument", 0);
4f76459… drh 6885 return 1;
4f76459… drh 6886 }
4f76459… drh 6887 zTag = azArg[++i];
4f76459… drh 6888 if( modeFind(p, zTag)>=0 ){
4f76459… drh 6889 dotCmdError(p, i, "mode already exists", 0);
4f76459… drh 6890 return 1;
4f76459… drh 6891 }
4f76459… drh 6892 if( p->nSavedModes > MODE_N_USER ){
4f76459… drh 6893 dotCmdError(p, i-1, "cannot add more modes", 0);
4f76459… drh 6894 return 1;
4f76459… drh 6895 }
4f76459… drh 6896 n = p->nSavedModes++;
4f76459… drh 6897 nByte = sizeof(p->aSavedModes[0]);
4f76459… drh 6898 nByte *= n+1;
4f76459… drh 6899 p->aSavedModes = realloc( p->aSavedModes, nByte );
4f76459… drh 6900 shell_check_oom(p->aSavedModes);
4f76459… drh 6901 p->aSavedModes[n].zTag = strdup(zTag);
4f76459… drh 6902 shell_check_oom(p->aSavedModes[n].zTag);
4f76459… drh 6903 modeDup(&p->aSavedModes[n].mode, &p->mode);
4f76459… drh 6904 chng = 1;
4f76459… drh 6905 }else if( optionMatch(z,"textjsonb") ){
4f76459… drh 6906 if( i+1>=nArg ){
4f76459… drh 6907 dotCmdError(p, i, "missing argument", 0);
4f76459… drh 6908 return 1;
4f76459… drh 6909 }
4f76459… drh 6910 p->mode.spec.bTextJsonb = booleanValue(azArg[++i]) ? QRF_Yes : QRF_No;
4f76459… drh 6911 chng = 1;
4f76459… drh 6912 }else if( optionMatch(z,"titles") || optionMatch(z,"title") ){
4f76459… drh 6913 char *zErr = 0;
4f76459… drh 6914 if( i+1>=nArg ){
4f76459… drh 6915 dotCmdError(p, i, "missing argument", 0);
4f76459… drh 6916 return 1;
4f76459… drh 6917 }
4f76459… drh 6918 k = pickStr(azArg[++i],&zErr,
4f76459… drh 6919 "off","on","plain","sql","csv","html","tcl","json","");
4f76459… drh 6920 /* 0 1 2 3 4 5 6 7 */
4f76459… drh 6921 if( k<0 ){
4f76459… drh 6922 dotCmdError(p, i, "bad --titles value","%z", zErr);
4f76459… drh 6923 return 1;
4f76459… drh 6924 }
4f76459… drh 6925 p->mode.spec.bTitles = k>=1 ? QRF_Yes : QRF_No;
12e4a0f… drh 6926 p->mode.mFlags &= ~MFLG_HDR;
4f76459… drh 6927 p->mode.spec.eTitle = k>1 ? k-1 : aModeInfo[p->mode.eMode].eHdr;
4f76459… drh 6928 chng = 1;
4f76459… drh 6929 }else if( optionMatch(z,"widths") || optionMatch(z,"width") ){
4f76459… drh 6930 int nWidth = 0;
4f76459… drh 6931 short int *aWidth;
4f76459… drh 6932 const char *zW;
4f76459… drh 6933 if( i+1>=nArg ){
4f76459… drh 6934 dotCmdError(p, i, "missing argument", 0);
4f76459… drh 6935 return 1;
4f76459… drh 6936 }
4f76459… drh 6937 zW = azArg[++i];
4f76459… drh 6938 /* Every width value takes at least 2 bytes in the input string to
4f76459… drh 6939 ** specify, so strlen(zW) bytes should be plenty of space to hold the
4f76459… drh 6940 ** result. */
4f76459… drh 6941 aWidth = malloc( strlen(zW) );
f4b3b59… drh 6942 while( IsSpace(zW[0]) ) zW++;
4f76459… drh 6943 while( zW[0] ){
4f76459… drh 6944 int w = 0;
4f76459… drh 6945 int nDigit = 0;
f4b3b59… drh 6946 k = zW[0]=='-' && IsDigit(zW[1]);
f4b3b59… drh 6947 while( IsDigit(zW[k]) ){
4f76459… drh 6948 w = w*10 + zW[k] - '0';
4f76459… drh 6949 if( w>QRF_MAX_WIDTH ){
4f76459… drh 6950 dotCmdError(p,i+1,"width too big",
4f76459… drh 6951 "Maximum column width is %d", QRF_MAX_WIDTH);
4f76459… drh 6952 free(aWidth);
4f76459… drh 6953 return 1;
4f76459… drh 6954 }
4f76459… drh 6955 nDigit++;
4f76459… drh 6956 k++;
4f76459… drh 6957 }
4f76459… drh 6958 if( nDigit==0 ){
4f76459… drh 6959 dotCmdError(p,i+1,"syntax error",
4f76459… drh 6960 "should be a comma-separated list if integers");
4f76459… drh 6961 free(aWidth);
4f76459… drh 6962 return 1;
4f76459… drh 6963 }
4f76459… drh 6964 if( zW[0]=='-' ) w = -w;
4f76459… drh 6965 aWidth[nWidth++] = w;
4f76459… drh 6966 zW += k;
4f76459… drh 6967 if( zW[0]==',' ) zW++;
f4b3b59… drh 6968 while( IsSpace(zW[0]) ) zW++;
4f76459… drh 6969 }
4f76459… drh 6970 free(p->mode.spec.aWidth);
4f76459… drh 6971 p->mode.spec.aWidth = aWidth;
4f76459… drh 6972 p->mode.spec.nWidth = nWidth;
4f76459… drh 6973 chng = 1;
4f76459… drh 6974 }else if( optionMatch(z,"wrap") ){
4f76459… drh 6975 int w;
4f76459… drh 6976 if( i+1>=nArg ){
4f76459… drh 6977 dotCmdError(p, i, "missing argument", 0);
4f76459… drh 6978 return 1;
4f76459… drh 6979 }
4f76459… drh 6980 w = integerValue(azArg[++i]);
4f76459… drh 6981 if( w<(-QRF_MAX_WIDTH) ) w = -QRF_MAX_WIDTH;
4f76459… drh 6982 if( w>QRF_MAX_WIDTH ) w = QRF_MAX_WIDTH;
4f76459… drh 6983 p->mode.spec.nWrap = w;
4f76459… drh 6984 chng = 1;
4f76459… drh 6985 }else if( optionMatch(z,"ww") ){
4f76459… drh 6986 p->mode.spec.bWordWrap = QRF_Yes;
4f76459… drh 6987 chng = 1;
4f76459… drh 6988 }else if( optionMatch(z,"wordwrap") ){
4f76459… drh 6989 if( i+1>=nArg ){
4f76459… drh 6990 dotCmdError(p, i, "missing argument", 0);
4f76459… drh 6991 return 1;
4f76459… drh 6992 }
4f76459… drh 6993 p->mode.spec.bWordWrap = (u8)booleanValue(azArg[++i]) ? QRF_Yes : QRF_No;
4f76459… drh 6994 chng = 1;
4f76459… drh 6995 }else if( optionMatch(z,"v") || optionMatch(z,"verbose") ){
4f76459… drh 6996 bAll = 1;
4f76459… drh 6997 }else if( z[0]=='-' ){
4f76459… drh 6998 dotCmdError(p, i, "bad option", "Use \".help .mode\" for more info");
4f76459… drh 6999 return 1;
4f76459… drh 7000 }else{
4f76459… drh 7001 dotCmdError(p, i, iMode>0?"bad argument":"unknown mode",
4f76459… drh 7002 "Use \".help .mode\" for more info");
4f76459… drh 7003 return 1;
4f76459… drh 7004 }
4f76459… drh 7005 }
4f76459… drh 7006 if( !chng || bAll ){
4f76459… drh 7007 const ModeInfo *pI = aModeInfo + p->mode.eMode;
4f76459… drh 7008 sqlite3_str *pDesc = sqlite3_str_new(p->db);
4f76459… drh 7009 char *zDesc;
4f76459… drh 7010 const char *zSetting;
4f76459… drh 7011
4f76459… drh 7012 if( p->nPopMode ) sqlite3_str_appendall(pDesc, "--once ");
4f76459… drh 7013 sqlite3_str_appendall(pDesc,pI->zName);
4f76459… drh 7014 if( bAll || (p->mode.spec.nAlign && pI->eCx==2) ){
4f76459… drh 7015 int ii;
4f76459… drh 7016 sqlite3_str_appendall(pDesc, " --align \"");
4f76459… drh 7017 for(ii=0; ii<p->mode.spec.nAlign; ii++){
4f76459… drh 7018 unsigned char a = p->mode.spec.aAlign[ii];
4f76459… drh 7019 sqlite3_str_appendchar(pDesc, 1, "LLCR"[a&3]);
4f76459… drh 7020 }
4f76459… drh 7021 sqlite3_str_append(pDesc, "\"", 1);
4f76459… drh 7022 }
f4b3b59… drh 7023 if( bAll
f4b3b59… drh 7024 || (p->mode.spec.bBorder==QRF_No) != ((pI->mFlg&1)!=0)
f4b3b59… drh 7025 ){
f4b3b59… drh 7026 sqlite3_str_appendf(pDesc," --border %s",
f4b3b59… drh 7027 p->mode.spec.bBorder==QRF_No ? "off" : "on");
f4b3b59… drh 7028 }
45de97f… drh 7029 if( bAll || p->mode.spec.eBlob!=QRF_BLOB_Auto ){
45de97f… drh 7030 const char *azBQuote[] =
45de97f… drh 7031 { "auto", "text", "sql", "hex", "tcl", "json", "size" };
45de97f… drh 7032 /* 0 1 2 3 4 5 6
45de97f… drh 7033 ** Must match QRF_BLOB_xxxx values. See all instances of tag-20251124a */
45de97f… drh 7034 u8 e = p->mode.spec.eBlob;
45de97f… drh 7035 sqlite3_str_appendf(pDesc, " --blob-quote %s", azBQuote[e]);
4f76459… drh 7036 }
4f76459… drh 7037 zSetting = aModeStr[pI->eCSep];
4f76459… drh 7038 if( bAll || (zSetting && cli_strcmp(zSetting,p->mode.spec.zColumnSep)!=0) ){
4f76459… drh 7039 sqlite3_str_appendf(pDesc, " --colsep ");
4f76459… drh 7040 append_c_string(pDesc, p->mode.spec.zColumnSep);
4f76459… drh 7041 }
4f76459… drh 7042 if( bAll || p->mode.spec.eEsc!=QRF_Auto ){
4f76459… drh 7043 sqlite3_str_appendf(pDesc, " --escape %s",qrfEscNames[p->mode.spec.eEsc]);
4f76459… drh 7044 }
ae7e3f0… drh 7045 if( bAll
ae7e3f0… drh 7046 || (p->mode.spec.nLineLimit>0 && pI->eCx>0)
ae7e3f0… drh 7047 || p->mode.spec.nCharLimit>0
ae7e3f0… drh 7048 || (p->mode.spec.nTitleLimit>0 && pI->eCx>0)
ae7e3f0… drh 7049 ){
ae7e3f0… drh 7050 if( p->mode.spec.nLineLimit==0
ae7e3f0… drh 7051 && p->mode.spec.nCharLimit==0
ae7e3f0… drh 7052 && p->mode.spec.nTitleLimit==0
ae7e3f0… drh 7053 ){
45de97f… drh 7054 sqlite3_str_appendf(pDesc, " --limits off");
ae7e3f0… drh 7055 }else if( p->mode.spec.nLineLimit==DFLT_LINE_LIMIT
ae7e3f0… drh 7056 && p->mode.spec.nCharLimit==DFLT_CHAR_LIMIT
ae7e3f0… drh 7057 && p->mode.spec.nTitleLimit==DFLT_TITLE_LIMIT
ae7e3f0… drh 7058 ){
ae7e3f0… drh 7059 sqlite3_str_appendf(pDesc, " --limits on");
45de97f… drh 7060 }else{
ae7e3f0… drh 7061 sqlite3_str_appendf(pDesc, " --limits %d,%d,%d",
ae7e3f0… drh 7062 p->mode.spec.nLineLimit, p->mode.spec.nCharLimit,
ae7e3f0… drh 7063 p->mode.spec.nTitleLimit);
45de97f… drh 7064 }
17f9878… drh 7065 }
17f9878… drh 7066 if( bAll
17f9878… drh 7067 || (p->mode.spec.nMultiInsert && p->mode.spec.eStyle==QRF_STYLE_Insert)
17f9878… drh 7068 ){
17f9878… drh 7069 sqlite3_str_appendf(pDesc, " --multiinsert %u",
17f9878… drh 7070 p->mode.spec.nMultiInsert);
5f65ed5… drh 7071 }
4f76459… drh 7072 zSetting = aModeStr[pI->eNull];
4f76459… drh 7073 if( bAll || (zSetting && cli_strcmp(zSetting,p->mode.spec.zNull)!=0) ){
4f76459… drh 7074 sqlite3_str_appendf(pDesc, " --null ");
4f76459… drh 7075 append_c_string(pDesc, p->mode.spec.zNull);
4f76459… drh 7076 }
4f76459… drh 7077 if( bAll
4f76459… drh 7078 || (pI->eText!=p->mode.spec.eText && (pI->eText>1 || p->mode.spec.eText>1))
4f76459… drh 7079 ){
4f76459… drh 7080 sqlite3_str_appendf(pDesc," --quote %s",qrfQuoteNames[p->mode.spec.eText]);
4f76459… drh 7081 }
4f76459… drh 7082 zSetting = aModeStr[pI->eRSep];
4f76459… drh 7083 if( bAll || (zSetting && cli_strcmp(zSetting,p->mode.spec.zRowSep)!=0) ){
4f76459… drh 7084 sqlite3_str_appendf(pDesc, " --rowsep ");
4f76459… drh 7085 append_c_string(pDesc, p->mode.spec.zRowSep);
4f76459… drh 7086 }
4f76459… drh 7087 if( bAll
4f76459… drh 7088 || (pI->eCx && (p->mode.spec.nScreenWidth>0 || p->mode.bAutoScreenWidth))
4f76459… drh 7089 ){
4f76459… drh 7090 if( p->mode.bAutoScreenWidth ){
ae7e3f0… drh 7091 sqlite3_str_appendall(pDesc, " --sw auto");
4f76459… drh 7092 }else{
ae7e3f0… drh 7093 sqlite3_str_appendf(pDesc," --sw %d",
4f76459… drh 7094 p->mode.spec.nScreenWidth);
4f76459… drh 7095 }
4f76459… drh 7096 }
4f76459… drh 7097 if( bAll || p->mode.eMode==MODE_Insert ){
4f76459… drh 7098 sqlite3_str_appendf(pDesc," --tablename ");
4f76459… drh 7099 append_c_string(pDesc, p->mode.spec.zTableName);
4f76459… drh 7100 }
4f76459… drh 7101 if( bAll || p->mode.spec.bTextJsonb ){
4f76459… drh 7102 sqlite3_str_appendf(pDesc," --textjsonb %s",
4f76459… drh 7103 p->mode.spec.bTextJsonb==QRF_Yes ? "on" : "off");
4f76459… drh 7104 }
4f76459… drh 7105 k = modeTitleDsply(p, bAll);
4f76459… drh 7106 if( k==1 ){
4f76459… drh 7107 sqlite3_str_appendall(pDesc, " --titles off");
4f76459… drh 7108 }else if( k==2 ){
4f76459… drh 7109 sqlite3_str_appendall(pDesc, " --titles on");
4f76459… drh 7110 }else if( k==3 ){
4f76459… drh 7111 static const char *azTitle[] =
4f76459… drh 7112 { "plain", "sql", "csv", "html", "tcl", "json"};
4f76459… drh 7113 sqlite3_str_appendf(pDesc, " --titles %s",
4f76459… drh 7114 azTitle[p->mode.spec.eTitle-1]);
4f76459… drh 7115 }
4f76459… drh 7116 if( p->mode.spec.nWidth>0 && (bAll || pI->eCx==2) ){
4f76459… drh 7117 int ii;
4f76459… drh 7118 const char *zSep = " --widths ";
4f76459… drh 7119 for(ii=0; ii<p->mode.spec.nWidth; ii++){
4f76459… drh 7120 sqlite3_str_appendf(pDesc, "%s%d", zSep, (int)p->mode.spec.aWidth[ii]);
4f76459… drh 7121 zSep = ",";
4f76459… drh 7122 }
4f76459… drh 7123 }else if( bAll ){
4f76459… drh 7124 sqlite3_str_appendall(pDesc, " --widths \"\"");
4f76459… drh 7125 }
4f76459… drh 7126 if( bAll || (pI->eCx>0 && p->mode.spec.bWordWrap) ){
4f76459… drh 7127 if( bAll ){
4f76459… drh 7128 sqlite3_str_appendf(pDesc, " --wordwrap %s",
4f76459… drh 7129 p->mode.spec.bWordWrap==QRF_Yes ? "on" : "off");
4f76459… drh 7130 }
4f76459… drh 7131 if( p->mode.spec.nWrap ){
4f76459… drh 7132 sqlite3_str_appendf(pDesc, " --wrap %d", p->mode.spec.nWrap);
4f76459… drh 7133 }
4f76459… drh 7134 if( !bAll ) sqlite3_str_append(pDesc, " --ww", 5);
4f76459… drh 7135 }
4f76459… drh 7136 zDesc = sqlite3_str_finish(pDesc);
ae7e3f0… drh 7137 cli_printf(p->out, ".mode %s\n", zDesc);
4f76459… drh 7138 fflush(p->out);
4f76459… drh 7139 sqlite3_free(zDesc);
4f76459… drh 7140 }
4f76459… drh 7141 return 0;
4f76459… drh 7142 }
4f76459… drh 7143
4f76459… drh 7144 /*
4f76459… drh 7145 ** DOT-COMMAND: .output
4f76459… drh 7146 ** USAGE: .output [OPTIONS] [FILE]
4f76459… drh 7147 **
4f76459… drh 7148 ** Begin redirecting output to FILE. Or if FILE is omitted, revert
4f76459… drh 7149 ** to sending output to the console. If FILE begins with "|" then
4f76459… drh 7150 ** the remainder of file is taken as a pipe and output is directed
4f76459… drh 7151 ** into that pipe. If FILE is "memory" then output is captured in an
4f76459… drh 7152 ** internal memory buffer. If FILE is "off" then output is redirected
4f76459… drh 7153 ** into /dev/null or the equivalent.
4f76459… drh 7154 **
4f76459… drh 7155 ** Options:
4f76459… drh 7156 ** --bom Prepend a byte-order mark to the output
4f76459… drh 7157 ** -e Accumulate output in a temporary text file then
4f76459… drh 7158 ** launch a text editor when the redirection ends.
4f76459… drh 7159 ** --error-prefix X Use X as the left-margin prefix for error messages.
4f76459… drh 7160 ** Set to an empty string to restore the default.
5f65ed5… drh 7161 ** --keep Keep redirecting output to its current destination.
5f65ed5… drh 7162 ** Use this option in combination with --show or
5f65ed5… drh 7163 ** with --error-prefix when you do not want to stop
5f65ed5… drh 7164 ** a current redirection.
4f76459… drh 7165 ** --plain Use plain text rather than HTML tables with -w
5f65ed5… drh 7166 ** --show Show output text captured by .testcase or by
5f65ed5… drh 7167 ** redirecting to "memory".
4f76459… drh 7168 ** -w Show the output in a web browser. Output is
4f76459… drh 7169 ** written into a temporary HTML file until the
4f76459… drh 7170 ** redirect ends, then the web browser is launched.
4f76459… drh 7171 ** Query results are shown as HTML tables, unless
4f76459… drh 7172 ** the --plain is used too.
4f76459… drh 7173 ** -x Show the output in a spreadsheet. Output is
4f76459… drh 7174 ** written to a temp file as CSV then the spreadsheet
4f76459… drh 7175 ** is launched when
4f76459… drh 7176 **
4f76459… drh 7177 ** DOT-COMMAND: .once
4f76459… drh 7178 ** USAGE: .once [OPTIONS] FILE ...
4f76459… drh 7179 **
4f76459… drh 7180 ** Write the output for the next line of SQL or the next dot-command into
4f76459… drh 7181 ** FILE. If FILE begins with "|" then it is a program into which output
4f76459… drh 7182 ** is written. The FILE argument should be omitted if one of the -e, -w,
4f76459… drh 7183 ** or -x options is used.
4f76459… drh 7184 **
4f76459… drh 7185 ** Options:
4f76459… drh 7186 ** -e Capture output into a temporary file then bring up
4f76459… drh 7187 ** a text editor on that temporary file.
4f76459… drh 7188 ** --plain Use plain text rather than HTML tables with -w
4f76459… drh 7189 ** -w Capture output into an HTML file then bring up that
4f76459… drh 7190 ** file in a web browser
4f76459… drh 7191 ** -x Show the output in a spreadsheet. Output is
4f76459… drh 7192 ** written to a temp file as CSV then the spreadsheet
4f76459… drh 7193 ** is launched when
4f76459… drh 7194 **
4f76459… drh 7195 ** DOT-COMMAND: .excel
4f76459… drh 7196 ** Shorthand for ".once -x"
4f76459… drh 7197 **
4f76459… drh 7198 ** DOT-COMMAND: .www [--plain]
4f76459… drh 7199 ** Shorthand for ".once -w" or ".once --plain -w"
4f76459… drh 7200 */
4f76459… drh 7201 static int dotCmdOutput(ShellState *p){
4f76459… drh 7202 int nArg = p->dot.nArg; /* Number of arguments */
4f76459… drh 7203 char **azArg = p->dot.azArg; /* Text of the arguments */
4f76459… drh 7204 char *zFile = 0; /* The FILE argument */
4f76459… drh 7205 int i; /* Loop counter */
4f76459… drh 7206 int eMode = 0; /* 0: .outout/.once, 'x'=.excel, 'w'=.www */
4f76459… drh 7207 int bOnce = 0; /* 0: .output, 1: .once, 2: .excel/.www */
4f76459… drh 7208 int bPlain = 0; /* --plain option */
5f65ed5… drh 7209 int bKeep = 0; /* Keep redirecting */
4f76459… drh 7210 static const char *zBomUtf8 = "\357\273\277";
4f76459… drh 7211 const char *zBom = 0;
4f76459… drh 7212 char c = azArg[0][0];
4f76459… drh 7213 int n = strlen30(azArg[0]);
4f76459… drh 7214
4f76459… drh 7215 failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
4f76459… drh 7216 if( c=='e' ){
4f76459… drh 7217 eMode = 'x';
4f76459… drh 7218 bOnce = 2;
4f76459… drh 7219 }else if( c=='w' ){
4f76459… drh 7220 eMode = 'w';
4f76459… drh 7221 bOnce = 2;
4f76459… drh 7222 }else if( n>=2 && cli_strncmp(azArg[0],"once",n)==0 ){
4f76459… drh 7223 bOnce = 1;
4f76459… drh 7224 }
4f76459… drh 7225 for(i=1; i<nArg; i++){
4f76459… drh 7226 char *z = azArg[i];
4f76459… drh 7227 if( z[0]=='-' ){
4f76459… drh 7228 if( z[1]=='-' ) z++;
4f76459… drh 7229 if( cli_strcmp(z,"-bom")==0 ){
4f76459… drh 7230 zBom = zBomUtf8;
4f76459… drh 7231 }else if( cli_strcmp(z,"-plain")==0 ){
4f76459… drh 7232 bPlain = 1;
4f76459… drh 7233 }else if( c=='o' && z[0]=='1' && z[1]!=0 && z[2]==0
4f76459… drh 7234 && (z[1]=='x' || z[1]=='e' || z[1]=='w') ){
5f65ed5… drh 7235 if( bKeep || eMode ){
4f76459… drh 7236 dotCmdError(p, i, "incompatible with prior options",0);
4f76459… drh 7237 goto dotCmdOutput_error;
4f76459… drh 7238 }
4f76459… drh 7239 eMode = z[1];
4f76459… drh 7240 }else if( cli_strcmp(z,"-show")==0 ){
4f76459… drh 7241 if( cli_output_capture ){
4f76459… drh 7242 sqlite3_fprintf(stdout, "%s", sqlite3_str_value(cli_output_capture));
4f76459… drh 7243 }
5f65ed5… drh 7244 }else if( cli_strcmp(z,"-keep")==0 ){
4f76459… drh 7245 bKeep = 1;
4f76459… drh 7246 }else if( optionMatch(z,"error-prefix") ){
4f76459… drh 7247 if( i+1>=nArg ){
4f76459… drh 7248 dotCmdError(p, i, "missing argument", 0);
4f76459… drh 7249 return 1;
4f76459… drh 7250 }
4f76459… drh 7251 free(p->zErrPrefix);
4f76459… drh 7252 i++;
4f76459… drh 7253 p->zErrPrefix = azArg[i][0]==0 ? 0 : strdup(azArg[i]);
4f76459… drh 7254 }else{
4f76459… drh 7255 dotCmdError(p, i, "unknown option", 0);
4f76459… drh 7256 sqlite3_free(zFile);
4f76459… drh 7257 return 1;
4f76459… drh 7258 }
4f76459… drh 7259 }else if( zFile==0 && eMode==0 ){
5f65ed5… drh 7260 if( bKeep ){
4f76459… drh 7261 dotCmdError(p, i, "incompatible with prior options",0);
4f76459… drh 7262 goto dotCmdOutput_error;
4f76459… drh 7263 }
4f76459… drh 7264 if( cli_strcmp(z, "memory")==0 && bOnce ){
4f76459… drh 7265 dotCmdError(p, 0, "cannot redirect to \"memory\"", 0);
4f76459… drh 7266 goto dotCmdOutput_error;
4f76459… drh 7267 }
4f76459… drh 7268 if( cli_strcmp(z, "off")==0 ){
4f76459… drh 7269 #ifdef _WIN32
4f76459… drh 7270 zFile = sqlite3_mprintf("nul");
4f76459… drh 7271 #else
4f76459… drh 7272 zFile = sqlite3_mprintf("/dev/null");
4f76459… drh 7273 #endif
4f76459… drh 7274 }else{
4f76459… drh 7275 zFile = sqlite3_mprintf("%s", z);
4f76459… drh 7276 }
4f76459… drh 7277 if( zFile && zFile[0]=='|' ){
4f76459… drh 7278 while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]);
4f76459… drh 7279 break;
4f76459… drh 7280 }
4f76459… drh 7281 }else{
4f76459… drh 7282 dotCmdError(p, i, "surplus argument", 0);
4f76459… drh 7283 sqlite3_free(zFile);
4f76459… drh 7284 return 1;
4f76459… drh 7285 }
4f76459… drh 7286 }
4f76459… drh 7287 if( zFile==0 && !bKeep ){
4f76459… drh 7288 zFile = sqlite3_mprintf("stdout");
4f76459… drh 7289 shell_check_oom(zFile);
4f76459… drh 7290 }
4f76459… drh 7291 if( bOnce ){
4f76459… drh 7292 p->nPopOutput = 2;
4f76459… drh 7293 }else{
4f76459… drh 7294 p->nPopOutput = 0;
4f76459… drh 7295 }
4f76459… drh 7296 if( !bKeep ) output_reset(p);
4f76459… drh 7297 #ifndef SQLITE_NOHAVE_SYSTEM
4f76459… drh 7298 if( eMode=='e' || eMode=='x' || eMode=='w' ){
4f76459… drh 7299 p->doXdgOpen = 1;
4f76459… drh 7300 modePush(p);
4f76459… drh 7301 if( eMode=='x' ){
4f76459… drh 7302 /* spreadsheet mode. Output as CSV. */
4f76459… drh 7303 newTempFile(p, "csv");
4f76459… drh 7304 p->mode.mFlags &= ~MFLG_ECHO;
4f76459… drh 7305 p->mode.eMode = MODE_Csv;
4f76459… drh 7306 modeSetStr(&p->mode.spec.zColumnSep, SEP_Comma);
4f76459… drh 7307 modeSetStr(&p->mode.spec.zRowSep, SEP_CrLf);
4f76459… drh 7308 #ifdef _WIN32
4f76459… drh 7309 zBom = zBomUtf8; /* Always include the BOM on Windows, as Excel does
4f76459… drh 7310 ** not work without it. */
4f76459… drh 7311 #endif
4f76459… drh 7312 }else if( eMode=='w' ){
4f76459… drh 7313 /* web-browser mode. */
4f76459… drh 7314 newTempFile(p, "html");
4f76459… drh 7315 if( !bPlain ) p->mode.eMode = MODE_Www;
4f76459… drh 7316 }else{
4f76459… drh 7317 /* text editor mode */
4f76459… drh 7318 newTempFile(p, "txt");
4f76459… drh 7319 }
4f76459… drh 7320 sqlite3_free(zFile);
4f76459… drh 7321 zFile = sqlite3_mprintf("%s", p->zTempFile);
4f76459… drh 7322 }
4f76459… drh 7323 #endif /* SQLITE_NOHAVE_SYSTEM */
4f76459… drh 7324 if( !bKeep ) shell_check_oom(zFile);
4f76459… drh 7325 if( bKeep ){
4f76459… drh 7326 /* no-op */
4f76459… drh 7327 }else if( cli_strcmp(zFile,"memory")==0 ){
4f76459… drh 7328 if( cli_output_capture ){
4f76459… drh 7329 sqlite3_str_free(cli_output_capture);
4f76459… drh 7330 }
4f76459… drh 7331 cli_output_capture = sqlite3_str_new(0);
4f76459… drh 7332 }else if( zFile[0]=='|' ){
4f76459… drh 7333 #ifdef SQLITE_OMIT_POPEN
4f76459… drh 7334 eputz("Error: pipes are not supported in this OS\n");
4f76459… drh 7335 output_redir(p, stdout);
4f76459… drh 7336 goto dotCmdOutput_error;
4f76459… drh 7337 #else
4f76459… drh 7338 FILE *pfPipe = sqlite3_popen(zFile + 1, "w");
4f76459… drh 7339 if( pfPipe==0 ){
4f76459… drh 7340 assert( stderr!=NULL );
4f76459… drh 7341 cli_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
4f76459… drh 7342 goto dotCmdOutput_error;
4f76459… drh 7343 }else{
4f76459… drh 7344 output_redir(p, pfPipe);
4f76459… drh 7345 if( zBom ) cli_puts(zBom, pfPipe);
4f76459… drh 7346 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
4f76459… drh 7347 }
4f76459… drh 7348 #endif
4f76459… drh 7349 }else{
4f76459… drh 7350 FILE *pfFile = output_file_open(p, zFile);
4f76459… drh 7351 if( pfFile==0 ){
4f76459… drh 7352 if( cli_strcmp(zFile,"off")!=0 ){
4f76459… drh 7353 assert( stderr!=NULL );
4f76459… drh 7354 cli_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
4f76459… drh 7355 }
4f76459… drh 7356 goto dotCmdOutput_error;
4f76459… drh 7357 } else {
4f76459… drh 7358 output_redir(p, pfFile);
4f76459… drh 7359 if( zBom ) cli_puts(zBom, pfFile);
4f76459… drh 7360 if( bPlain && eMode=='w' ){
4f76459… drh 7361 cli_puts(
4f76459… drh 7362 "<!DOCTYPE html>\n<BODY>\n<PLAINTEXT>\n",
4f76459… drh 7363 pfFile
4f76459… drh 7364 );
4f76459… drh 7365 }
4f76459… drh 7366 sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
4f76459… drh 7367 }
4f76459… drh 7368 }
4f76459… drh 7369 sqlite3_free(zFile);
4f76459… drh 7370 return 0;
4f76459… drh 7371
4f76459… drh 7372 dotCmdOutput_error:
4f76459… drh 7373 sqlite3_free(zFile);
4f76459… drh 7374 return 1;
4f76459… drh 7375 }
9aee493… drh 7376
9aee493… drh 7377 /*
5f65ed5… drh 7378 ** DOT-COMMAND: .check
5f65ed5… drh 7379 ** USAGE: .check [OPTIONS] PATTERN
5f65ed5… drh 7380 **
5f65ed5… drh 7381 ** Verify results of commands since the most recent .testcase command.
5f65ed5… drh 7382 ** Restore output to the console, unless --keep is used.
5f65ed5… drh 7383 **
5f65ed5… drh 7384 ** If PATTERN starts with "<<ENDMARK" then the actual pattern is taken from
5f65ed5… drh 7385 ** subsequent lines of text up to the first line that begins with ENDMARK.
5f65ed5… drh 7386 ** All pattern lines and the ENDMARK are discarded.
5f65ed5… drh 7387 **
5f65ed5… drh 7388 ** Options:
5f65ed5… drh 7389 ** --exact Do an exact comparison including leading and
5f65ed5… drh 7390 ** trailing whitespace.
5f65ed5… drh 7391 ** --glob Treat PATTERN as a GLOB
5f65ed5… drh 7392 ** --keep Do not reset the testcase. More .check commands
5f65ed5… drh 7393 ** will follow.
5f65ed5… drh 7394 ** --notglob Output should not match PATTERN
5f65ed5… drh 7395 ** --show Write testcase output to the screen, for debugging.
5f65ed5… drh 7396 */
5f65ed5… drh 7397 static int dotCmdCheck(ShellState *p){
5f65ed5… drh 7398 int nArg = p->dot.nArg; /* Number of arguments */
5f65ed5… drh 7399 char **azArg = p->dot.azArg; /* Text of the arguments */
5f65ed5… drh 7400 int i; /* Loop counter */
5f65ed5… drh 7401 int k; /* Result of pickStr() */
5f65ed5… drh 7402 char *zTest; /* Textcase result */
5f65ed5… drh 7403 int bKeep = 0; /* --keep option */
5f65ed5… drh 7404 char *zCheck = 0; /* PATTERN argument */
5f65ed5… drh 7405 char *zPattern = 0; /* Actual test pattern */
5f65ed5… drh 7406 int eCheck = 0; /* 1: --glob, 2: --notglob, 3: --exact */
5f65ed5… drh 7407 int isOk; /* True if results are OK */
5f65ed5… drh 7408 sqlite3_int64 iStart = p->lineno; /* Line number of .check statement */
5f65ed5… drh 7409
5f65ed5… drh 7410 if( p->zTestcase[0]==0 ){
5f65ed5… drh 7411 dotCmdError(p, 0, "no .testcase is active", 0);
5f65ed5… drh 7412 return 1;
5f65ed5… drh 7413 }
5f65ed5… drh 7414 for(i=1; i<nArg; i++){
5f65ed5… drh 7415 char *z = azArg[i];
5f65ed5… drh 7416 if( z[0]=='-' && z[1]=='-' && z[2]!=0 ) z++;
5f65ed5… drh 7417 if( cli_strcmp(z,"-keep")==0 ){
5f65ed5… drh 7418 bKeep = 1;
5f65ed5… drh 7419 }else if( cli_strcmp(z,"-show")==0 ){
5f65ed5… drh 7420 if( cli_output_capture ){
5f65ed5… drh 7421 sqlite3_fprintf(stdout, "%s", sqlite3_str_value(cli_output_capture));
5f65ed5… drh 7422 }
5f65ed5… drh 7423 bKeep = 1;
5f65ed5… drh 7424 }else if( z[0]=='-'
5f65ed5… drh 7425 && (k = pickStr(&z[1],0,"glob","notglob","exact",""))>=0
5f65ed5… drh 7426 ){
5f65ed5… drh 7427 if( eCheck && eCheck!=k+1 ){
5f65ed5… drh 7428 dotCmdError(p, i, "incompatible with prior options",0);
5f65ed5… drh 7429 return 1;
5f65ed5… drh 7430 }
5f65ed5… drh 7431 eCheck = k+1;
5f65ed5… drh 7432 }else if( zCheck ){
5f65ed5… drh 7433 dotCmdError(p, i, "unknown option", 0);
5f65ed5… drh 7434 return 1;
5f65ed5… drh 7435 }else{
5f65ed5… drh 7436 zCheck = azArg[i];
5f65ed5… drh 7437 }
5f65ed5… drh 7438 }
5f65ed5… drh 7439 if( zCheck==0 ){
5f65ed5… drh 7440 dotCmdError(p, 0, "no PATTERN specified", 0);
5f65ed5… drh 7441 return 1;
5f65ed5… drh 7442 }
b9ecacf… drh 7443 if( cli_output_capture && sqlite3_str_length(cli_output_capture) ){
5f65ed5… drh 7444 zTest = sqlite3_str_value(cli_output_capture);
5f65ed5… drh 7445 shell_check_oom(zTest);
5f65ed5… drh 7446 }else{
5f65ed5… drh 7447 zTest = "";
5f65ed5… drh 7448 }
5f65ed5… drh 7449 p->nTestRun++;
5f65ed5… drh 7450 if( zCheck[0]=='<' && zCheck[1]=='<' && zCheck[2]!=0 ){
5f65ed5… drh 7451 int nCheck = strlen30(zCheck);
5f65ed5… drh 7452 sqlite3_str *pPattern = sqlite3_str_new(p->db);
5f65ed5… drh 7453 char zLine[2000];
5f65ed5… drh 7454 while( sqlite3_fgets(zLine,sizeof(zLine),p->in) ){
5f65ed5… drh 7455 if( strchr(zLine,'\n') ) p->lineno++;
5f65ed5… drh 7456 if( cli_strncmp(&zCheck[2],zLine,nCheck-2)==0 ) break;
5f65ed5… drh 7457 sqlite3_str_appendall(pPattern, zLine);
5f65ed5… drh 7458 }
5f65ed5… drh 7459 zPattern = sqlite3_str_finish(pPattern);
5f65ed5… drh 7460 if( zPattern==0 ){
5f65ed5… drh 7461 zPattern = sqlite3_mprintf("");
5f65ed5… drh 7462 }
5f65ed5… drh 7463 }else{
5f65ed5… drh 7464 zPattern = zCheck;
5f65ed5… drh 7465 }
5f65ed5… drh 7466 shell_check_oom(zPattern);
5f65ed5… drh 7467 switch( eCheck ){
5f65ed5… drh 7468 case 1: {
5f65ed5… drh 7469 char *zGlob = sqlite3_mprintf("*%s*", zPattern);
5f65ed5… drh 7470 isOk = testcase_glob(zGlob, zTest)!=0;
5f65ed5… drh 7471 sqlite3_free(zGlob);
5f65ed5… drh 7472 break;
5f65ed5… drh 7473 }
5f65ed5… drh 7474 case 2: {
5f65ed5… drh 7475 char *zGlob = sqlite3_mprintf("*%s*", zPattern);
5f65ed5… drh 7476 isOk = testcase_glob(zGlob, zTest)==0;
5f65ed5… drh 7477 sqlite3_free(zGlob);
5f65ed5… drh 7478 break;
5f65ed5… drh 7479 }
5f65ed5… drh 7480 case 3: {
5f65ed5… drh 7481 isOk = cli_strcmp(zTest,zPattern)==0;
5f65ed5… drh 7482 break;
5f65ed5… drh 7483 }
5f65ed5… drh 7484 default: {
5f65ed5… drh 7485 /* Skip leading and trailing \n and \r on both pattern and test output */
5f65ed5… drh 7486 const char *z1 = zPattern;
5f65ed5… drh 7487 const char *z2 = zTest;
5f65ed5… drh 7488 size_t n1, n2;
5f65ed5… drh 7489 while( z1[0]=='\n' || z1[0]=='\r' ) z1++;
5f65ed5… drh 7490 n1 = strlen(z1);
5f65ed5… drh 7491 while( n1>0 && (z1[n1-1]=='\n' || z1[n1-1]=='\r') ) n1--;
5f65ed5… drh 7492 while( z2[0]=='\n' || z2[0]=='\r' ) z2++;
5f65ed5… drh 7493 n2 = strlen(z2);
5f65ed5… drh 7494 while( n2>0 && (z2[n2-1]=='\n' || z2[n2-1]=='\r') ) n2--;
5f65ed5… drh 7495 isOk = n1==n2 && memcmp(z1,z2,n1)==0;
5f65ed5… drh 7496 break;
5f65ed5… drh 7497 }
5f65ed5… drh 7498 }
5f65ed5… drh 7499 if( !isOk ){
5f65ed5… drh 7500 sqlite3_fprintf(stderr,
5f65ed5… drh 7501 "%s:%lld: .check failed for testcase %s\n",
5f65ed5… drh 7502 p->zInFile, iStart, p->zTestcase);
5f65ed5… drh 7503 p->nTestErr++;
5f65ed5… drh 7504 sqlite3_fprintf(stderr, "Expected: [%s]\n", zPattern);
5f65ed5… drh 7505 sqlite3_fprintf(stderr, "Got: [%s]\n", zTest);
5f65ed5… drh 7506 }
5f65ed5… drh 7507 if( zPattern!=zCheck ){
5f65ed5… drh 7508 sqlite3_free(zPattern);
5f65ed5… drh 7509 }
5f65ed5… drh 7510 if( !bKeep ){
5f65ed5… drh 7511 output_reset(p);
5f65ed5… drh 7512 p->zTestcase[0] = 0;
5f65ed5… drh 7513 }
5f65ed5… drh 7514 return 0;
5f65ed5… drh 7515 }
5f65ed5… drh 7516
5f65ed5… drh 7517 /*
5f65ed5… drh 7518 ** DOT-COMMAND: .testcase
5f65ed5… drh 7519 ** USAGE: .testcase [OPTIONS] NAME
5f65ed5… drh 7520 **
5f65ed5… drh 7521 ** Start a new test case identified by NAME. All output
5f65ed5… drh 7522 ** through the next ".check" command is captured for comparison. See the
5f65ed5… drh 7523 ** ".check" commandn for additional informatioon.
5f65ed5… drh 7524 **
5f65ed5… drh 7525 ** Options:
5f65ed5… drh 7526 ** --error-prefix TEXT Change error message prefix text to TEXT
5f65ed5… drh 7527 */
5f65ed5… drh 7528 static int dotCmdTestcase(ShellState *p){
5f65ed5… drh 7529 int nArg = p->dot.nArg; /* Number of arguments */
5f65ed5… drh 7530 char **azArg = p->dot.azArg; /* Text of the arguments */
5f65ed5… drh 7531 int i; /* Loop counter */
5f65ed5… drh 7532 const char *zName = 0; /* Testcase name */
5f65ed5… drh 7533
5f65ed5… drh 7534 for(i=1; i<nArg; i++){
5f65ed5… drh 7535 char *z = azArg[i];
5f65ed5… drh 7536 if( z[0]=='-' && z[1]=='-' && z[2]!=0 ) z++;
5f65ed5… drh 7537 if( optionMatch(z,"error-prefix") ){
5f65ed5… drh 7538 if( i+1>=nArg ){
5f65ed5… drh 7539 dotCmdError(p, i, "missing argument", 0);
5f65ed5… drh 7540 return 1;
5f65ed5… drh 7541 }
5f65ed5… drh 7542 free(p->zErrPrefix);
5f65ed5… drh 7543 i++;
5f65ed5… drh 7544 p->zErrPrefix = azArg[i][0]==0 ? 0 : strdup(azArg[i]);
5f65ed5… drh 7545 }else if( zName ){
5f65ed5… drh 7546 dotCmdError(p, i, "unknown option", 0);
5f65ed5… drh 7547 return 1;
5f65ed5… drh 7548 }else{
5f65ed5… drh 7549 zName = azArg[i];
5f65ed5… drh 7550 }
5f65ed5… drh 7551 }
5f65ed5… drh 7552 output_reset(p);
5f65ed5… drh 7553 if( cli_output_capture ){
5f65ed5… drh 7554 sqlite3_str_free(cli_output_capture);
5f65ed5… drh 7555 }
5f65ed5… drh 7556 cli_output_capture = sqlite3_str_new(0);
5f65ed5… drh 7557 if( zName ){
5f65ed5… drh 7558 sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", zName);
5f65ed5… drh 7559 }else{
5f65ed5… drh 7560 sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s:%lld",
5f65ed5… drh 7561 p->zInFile, p->lineno);
5f65ed5… drh 7562 }
5f65ed5… drh 7563 return 0;
5f65ed5… drh 7564 }
5f65ed5… drh 7565
5f65ed5… drh 7566 /*
9aee493… drh 7567 ** Enlarge the space allocated in p->dot so that it can hold more
9aee493… drh 7568 ** than nArg parsed command-line arguments.
4f76459… drh 7569 */
4f76459… drh 7570 static void parseDotRealloc(ShellState *p, int nArg){
4f76459… drh 7571 p->dot.nAlloc = nArg+22;
4f76459… drh 7572 p->dot.azArg = realloc(p->dot.azArg,p->dot.nAlloc*sizeof(char*));
4f76459… drh 7573 shell_check_oom(p->dot.azArg);
4f76459… drh 7574 p->dot.aiOfst = realloc(p->dot.aiOfst,p->dot.nAlloc*sizeof(int));
4f76459… drh 7575 shell_check_oom(p->dot.aiOfst);
4f76459… drh 7576 p->dot.abQuot = realloc(p->dot.abQuot,p->dot.nAlloc);
4f76459… drh 7577 shell_check_oom(p->dot.abQuot);
4f76459… drh 7578 }
9aee493… drh 7579
9aee493… drh 7580
9aee493… drh 7581 /*
9aee493… drh 7582 ** Parse input line zLine up into individual arguments. Retain the
9aee493… drh 7583 ** parse in the p->dot substructure.
9aee493… drh 7584 */
4f76459… drh 7585 static void parseDotCmdArgs(const char *zLine, ShellState *p){
4f76459… drh 7586 char *z;
4f76459… drh 7587 int h = 1;
4f76459… drh 7588 int nArg = 0;
9aee493… drh 7589 size_t szLine;
4f76459… drh 7590
4f76459… drh 7591 p->dot.zOrig = zLine;
4f76459… drh 7592 free(p->dot.zCopy);
4f76459… drh 7593 z = p->dot.zCopy = strdup(zLine);
4f76459… drh 7594 shell_check_oom(z);
9aee493… drh 7595 szLine = strlen(z);
9aee493… drh 7596 while( szLine>0 && IsSpace(z[szLine-1]) ) szLine--;
5f65ed5… drh 7597 if( szLine>0 && z[szLine-1]==';' ){
9aee493… drh 7598 szLine--;
9aee493… drh 7599 while( szLine>0 && IsSpace(z[szLine-1]) ) szLine--;
9aee493… drh 7600 }
9aee493… drh 7601 z[szLine] = 0;
4f76459… drh 7602 parseDotRealloc(p, 2);
4f76459… drh 7603 while( z[h] ){
4f76459… drh 7604 while( IsSpace(z[h]) ){ h++; }
4f76459… drh 7605 if( z[h]==0 ) break;
4f76459… drh 7606 if( nArg+2>p->dot.nAlloc ){
4f76459… drh 7607 parseDotRealloc(p, nArg);
4f76459… drh 7608 }
4f76459… drh 7609 if( z[h]=='\'' || z[h]=='"' ){
4f76459… drh 7610 int delim = z[h++];
4f76459… drh 7611 p->dot.abQuot[nArg] = 1;
4f76459… drh 7612 p->dot.azArg[nArg] = &z[h];
4f76459… drh 7613 p->dot.aiOfst[nArg] = h;
4f76459… drh 7614 while( z[h] && z[h]!=delim ){
4f76459… drh 7615 if( z[h]=='\\' && delim=='"' && z[h+1]!=0 ) h++;
4f76459… drh 7616 h++;
4f76459… drh 7617 }
4f76459… drh 7618 if( z[h]==delim ){
4f76459… drh 7619 z[h++] = 0;
4f76459… drh 7620 }
4f76459… drh 7621 if( delim=='"' ) resolve_backslashes(p->dot.azArg[nArg]);
4f76459… drh 7622 }else{
4f76459… drh 7623 p->dot.abQuot[nArg] = 0;
4f76459… drh 7624 p->dot.azArg[nArg] = &z[h];
4f76459… drh 7625 p->dot.aiOfst[nArg] = h;
4f76459… drh 7626 while( z[h] && !IsSpace(z[h]) ){ h++; }
4f76459… drh 7627 if( z[h] ) z[h++] = 0;
4f76459… drh 7628 }
4f76459… drh 7629 nArg++;
4f76459… drh 7630 }
4f76459… drh 7631 p->dot.nArg = nArg;
4f76459… drh 7632 p->dot.azArg[nArg] = 0;
4f76459… drh 7633 }
4f76459… drh 7634
4f76459… drh 7635 /*
4f76459… drh 7636 static int do_meta_command(const char *zLine, ShellState *p){
4f76459… drh 7637 int nArg;
4f76459… drh 7638 char **azArg;
4f76459… drh 7639 /* Parse the input line into tokens stored in p->dot.
4f76459… drh 7640 parseDotCmdArgs(zLine, p);
4f76459… drh 7641 nArg = p->dot.nArg;
4f76459… drh 7642 azArg = p->dot.azArg;
4f76459… drh 7643 cli_printf(stderr, "Usage: .auth ON|OFF\n");
4f76459… drh 7644 dotCmdError(p, j, "unknown option", "should be -append or -async");
4f76459… drh 7645 cli_printf(stderr, "Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
4f76459… drh 7646 cli_printf(stderr, "missing FILENAME argument on .backup\n");
4f76459… drh 7647 cli_printf(stderr,"Error: cannot open \"%s\"\n", zDestFile);
4f76459… drh 7648 cli_printf(stderr,"Cannot change to directory \"%s\"\n", azArg[1]);
5f65ed5… drh 7649 rc = dotCmdCheck(p);
4f76459… drh 7650 cli_printf(stdout, "ACTIVE %d: %s\n", i, zFile);
4f76459… drh 7651 cli_printf(stdout, " %d: %s\n", i, zFile);
4f76459… drh 7652 if( booleanValue(azArg[1]) ){
4f76459… drh 7653 p->mode.mFlags |= MFLG_CRLF;
4f76459… drh 7654 }else{
4f76459… drh 7655 p->mode.mFlags &= ~MFLG_CRLF;
4f76459… drh 7656 }
4f76459… drh 7657 p->mode.mFlags &= ~MFLG_CRLF;
4f76459… drh 7658 cli_printf(stderr, "crlf is %s\n",
4f76459… drh 7659 (p->mode.mFlags & MFLG_CRLF)!=0 ? "ON" : "OFF");
4f76459… drh 7660 cli_printf(p->out, "%s: %s %s%s\n",
b8ab8b3… drh 7661 { "fp_digits", SQLITE_DBCONFIG_FP_DIGITS },
b8ab8b3… drh 7662 if( aDbConfig[ii].op==SQLITE_DBCONFIG_FP_DIGITS ){
b8ab8b3… drh 7663 sqlite3_db_config(p->db, aDbConfig[ii].op, atoi(azArg[2]), 0);
b8ab8b3… drh 7664 }else{
b8ab8b3… drh 7665 sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
b8ab8b3… drh 7666 }
b8ab8b3… drh 7667 if( aDbConfig[ii].op==SQLITE_DBCONFIG_FP_DIGITS ){
b8ab8b3… drh 7668 cli_printf(p->out, "%19s %d\n", aDbConfig[ii].zName, v);
b8ab8b3… drh 7669 }else{
b8ab8b3… drh 7670 cli_printf(p->out, "%19s %s\n",
b8ab8b3… drh 7671 aDbConfig[ii].zName, v ? "on" : "off");
b8ab8b3… drh 7672 }
4f76459… drh 7673 dotCmdError(p, 1, "unknown dbconfig",
4f76459… drh 7674 "Enter \".dbconfig\" with no arguments for a list");
4f76459… drh 7675 Mode saved_mode;
4f76459… drh 7676 SHFLG_PreserveRowid|SHFLG_DumpDataOnly|SHFLG_DumpNoSys);
4f76459… drh 7677 dotCmdError(p, i, "unable",
4f76459… drh 7678 "The --preserve-rowids option is not compatible"
4f76459… drh 7679 " with SQLITE_OMIT_VIRTUALTABLE");
4f76459… drh 7680 /*ShellSetFlag(p, SHFLG_Newlines);*/
4f76459… drh 7681 dotCmdError(p, i, "unknown option", 0);
4f76459… drh 7682 modeDup(&saved_mode, &p->mode);
4f76459… drh 7683 cli_puts("PRAGMA foreign_keys=OFF;\n", p->out);
4f76459… drh 7684 cli_puts("BEGIN TRANSACTION;\n", p->out);
4f76459… drh 7685 p->mode.spec.bTitles = QRF_No;
4f76459… drh 7686 cli_puts("PRAGMA writable_schema=OFF;\n", p->out);
4f76459… drh 7687 cli_puts(p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n", p->out);
4f76459… drh 7688 modeFree(&p->mode);
4f76459… drh 7689 p->mode = saved_mode;
4f76459… drh 7690 rc = p->nErr>0;
4f76459… drh 7691 if( booleanValue(azArg[1]) ){
4f76459… drh 7692 p->mode.mFlags |= MFLG_ECHO;
4f76459… drh 7693 }else{
4f76459… drh 7694 p->mode.mFlags &= ~MFLG_ECHO;
4f76459… drh 7695 }
70539ee… drh 7696 open_db(p, 0);
4f76459… drh 7697 if( p->mode.autoEQPtrace ){
4f76459… drh 7698 p->mode.autoEQPtrace = 0;
4f76459… drh 7699 p->mode.autoEQP = AUTOEQP_full;
4f76459… drh 7700 p->mode.autoEQP = AUTOEQP_trigger;
4f76459… drh 7701 p->mode.autoEQP = AUTOEQP_full;
4f76459… drh 7702 p->mode.autoEQPtrace = 1;
4f76459… drh 7703 p->mode.autoEQP = (u8)booleanValue(azArg[1]);
4f76459… drh 7704 if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) cli_exit(rc);
4f76459… drh 7705 p->mode.autoExplain = 1;
4f76459… drh 7706 p->mode.autoExplain = booleanValue(azArg[1]);
4f76459… drh 7707 }
4f76459… drh 7708 cli_printf(stderr,
4f76459… drh 7709 cli_puts("Available file-controls:\n", p->out);
4f76459… drh 7710 cli_printf(p->out,
4f76459… drh 7711 cli_printf(stderr,"Error: ambiguous file-control: \"%s\"\n"
4f76459… drh 7712 cli_printf(stderr,"Error: unknown file-control: %s\n"
4f76459… drh 7713 cli_printf(p->out, "%s\n", z);
4f76459… drh 7714 cli_printf(p->out, "%d\n", x);
4f76459… drh 7715 cli_printf(p->out, "Usage: .filectrl %s %s\n",
4f76459… drh 7716 cli_printf(p->out, "%s\n", zBuf);
4f76459… drh 7717 int hasStat[5];
4f76459… drh 7718 int flgs = 0;
4f76459… drh 7719 char *zSql;
4f76459… drh 7720 zSql = sqlite3_mprintf(
4f76459… drh 7721 "SELECT shell_format_schema(sql,%d) FROM"
4f76459… drh 7722 " AND name NOT LIKE 'sqlite__%%' ESCAPE '_' "
4f76459… drh 7723 "ORDER BY x", flgs);
4f76459… drh 7724 memcpy(&data, p, sizeof(data));
4f76459… drh 7725 data.mode.spec.bTitles = QRF_No;
4f76459… drh 7726 data.mode.eMode = MODE_List;
4f76459… drh 7727 data.mode.spec.eText = QRF_TEXT_Plain;
4f76459… drh 7728 data.mode.spec.nCharLimit = 0;
4f76459… drh 7729 data.mode.spec.zRowSep = "\n";
4f76459… drh 7730 rc = shell_exec(&data,zSql,0);
4f76459… drh 7731 sqlite3_free(zSql);
0276100… drh 7732 memset(hasStat, 0, sizeof(hasStat));
4f76459… drh 7733 "SELECT substr(name,12,1) FROM sqlite_schema"
4f76459… drh 7734 while( sqlite3_step(pStmt)==SQLITE_ROW ){
4f76459… drh 7735 int k = sqlite3_column_int(pStmt,0);
4f76459… drh 7736 assert( k==1 || k==3 || k==4 );
4f76459… drh 7737 hasStat[k] = 1;
4f76459… drh 7738 doStats = 1;
4f76459… drh 7739 }
4f76459… drh 7740 sqlite3_finalize(pStmt);
4f76459… drh 7741 cli_puts("/* No STAT tables available */\n", p->out);
4f76459… drh 7742 cli_puts("ANALYZE sqlite_schema;\n", p->out);
4f76459… drh 7743 data.mode.eMode = MODE_Insert;
4f76459… drh 7744 if( hasStat[1] ){
4f76459… drh 7745 data.mode.spec.zTableName = "sqlite_stat1";
4f76459… drh 7746 shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
4f76459… drh 7747 }
4f76459… drh 7748 if( hasStat[4] ){
4f76459… drh 7749 data.mode.spec.zTableName = "sqlite_stat4";
4f76459… drh 7750 shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
4f76459… drh 7751 }
4f76459… drh 7752 cli_puts("ANALYZE sqlite_schema;\n", p->out);
4f76459… drh 7753 p->mode.spec.bTitles = booleanValue(azArg[1]) ? QRF_Yes : QRF_No;
12e4a0f… drh 7754 p->mode.mFlags |= MFLG_HDR;
4f76459… drh 7755 p->mode.spec.eTitle = aModeInfo[p->mode.eMode].eHdr;
4f76459… drh 7756 cli_printf(p->out, "Nothing matches '%s'\n", azArg[1]);
4f76459… drh 7757 rc = dotCmdImport(p);
5f65ed5… drh 7758 " WHERE type='index' AND lower(name)=lower('%q')"
5f65ed5… drh 7759 " WHERE type='table' AND lower(name)=lower('%q')"
4f76459… drh 7760 cli_printf(stderr,"no such index: \"%s\"\n", azArg[1]);
4f76459… drh 7761 cli_printf(stderr,
4f76459… drh 7762 cli_printf(stdout, "%s;\n", zSql);
4f76459… drh 7763 cli_printf(stderr,"SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
b8ab8b3… drh 7764
17f9878… drh 7765 if( c=='i' && (cli_strncmp(azArg[0], "indices", n)==0
17f9878… drh 7766 || cli_strncmp(azArg[0], "indexes", n)==0)
17f9878… drh 7767 ){
17f9878… drh 7768 sqlite3_str *pSql;
17f9878… drh 7769 int i;
17f9878… drh 7770 int allFlag = 0;
17f9878… drh 7771 int sysFlag = 0;
17f9878… drh 7772 int exprFlag = 0;
17f9878… drh 7773 int debugFlag = 0; /* Undocument --debug flag */
17f9878… drh 7774 const char *zPattern = 0;
17f9878… drh 7775 const char *zSep = "WHERE";
17f9878… drh 7776
17f9878… drh 7777 for(i=1; i<nArg; i++){
17f9878… drh 7778 if( azArg[i][0]=='-' ){
17f9878… drh 7779 const char *z = azArg[i]+1;
17f9878… drh 7780 if( z[0]=='-' ) z++;
17f9878… drh 7781 if( cli_strcmp(z,"all")==0 || cli_strcmp(z,"a")==0 ){
17f9878… drh 7782 allFlag = 1;
17f9878… drh 7783 }else
17f9878… drh 7784 if( cli_strcmp(z,"sys")==0 ){
17f9878… drh 7785 sysFlag = 1;
17f9878… drh 7786 allFlag = 0;
17f9878… drh 7787 }else
17f9878… drh 7788 if( cli_strcmp(z,"expr")==0 ){
17f9878… drh 7789 exprFlag = 1;
17f9878… drh 7790 allFlag = 0;
17f9878… drh 7791 }else
17f9878… drh 7792 if( cli_strcmp(z,"debug")==0 ){
17f9878… drh 7793 debugFlag = 1;
17f9878… drh 7794 }else
17f9878… drh 7795 {
17f9878… drh 7796 dotCmdError(p, i, "unknown option", 0);
17f9878… drh 7797 rc = 1;
17f9878… drh 7798 goto meta_command_exit;
17f9878… drh 7799 }
17f9878… drh 7800 }else if( zPattern==0 ){
17f9878… drh 7801 zPattern = azArg[i];
17f9878… drh 7802 }else{
17f9878… drh 7803 dotCmdError(p, i, "unknown argument", 0);
17f9878… drh 7804 rc = 1;
17f9878… drh 7805 goto meta_command_exit;
17f9878… drh 7806 }
17f9878… drh 7807 }
17f9878… drh 7808
17f9878… drh 7809 open_db(p, 0);
17f9878… drh 7810 pSql = sqlite3_str_new(p->db);
17f9878… drh 7811 sqlite3_str_appendf(pSql,
17f9878… drh 7812 "SELECT if(t.schema='main',i.name,t.schema||'.'||i.name)\n"
17f9878… drh 7813 "FROM pragma_table_list t, pragma_index_list(t.name,t.schema) i\n"
17f9878… drh 7814 );
17f9878… drh 7815 if( exprFlag ){
17f9878… drh 7816 allFlag = 0;
17f9878… drh 7817 sqlite3_str_appendf(pSql,
17f9878… drh 7818 "%s (EXISTS(SELECT 1 FROM pragma_index_xinfo(i.name) WHERE cid=-2)\n"
17f9878… drh 7819 " OR\n"
17f9878… drh 7820 " EXISTS(SELECT cid FROM pragma_table_xinfo(t.name) WHERE hidden=2"
17f9878… drh 7821 " INTERSECT "
17f9878… drh 7822 " SELECT cid FROM pragma_index_info(i.name)))\n", zSep);
17f9878… drh 7823 zSep = "AND";
17f9878… drh 7824 }
17f9878… drh 7825 if( sysFlag ){
17f9878… drh 7826 sqlite3_str_appendf(pSql,
17f9878… drh 7827 "%s i.name LIKE 'sqlite__autoindex__%%' ESCAPE '_'\n", zSep);
17f9878… drh 7828 zSep = "AND";
17f9878… drh 7829 }else if( !allFlag ){
17f9878… drh 7830 sqlite3_str_appendf(pSql,
17f9878… drh 7831 "%s i.name NOT LIKE 'sqlite__%%' ESCAPE '_'\n", zSep);
17f9878… drh 7832 zSep = "AND";
17f9878… drh 7833 }
17f9878… drh 7834 if( zPattern ){
17f9878… drh 7835 sqlite3_str_appendf(pSql, "%s i.name LIKE '%%%q%%'\n", zSep, zPattern);
17f9878… drh 7836 }
17f9878… drh 7837 sqlite3_str_appendf(pSql, "ORDER BY 1");
17f9878… drh 7838
17f9878… drh 7839 /* Run the SQL statement in "split" mode. */
17f9878… drh 7840 if( debugFlag ){
17f9878… drh 7841 cli_printf(stdout,"%s;\n", sqlite3_str_value(pSql));
17f9878… drh 7842 }else{
17f9878… drh 7843 modePush(p);
17f9878… drh 7844 modeChange(p, MODE_Split);
17f9878… drh 7845 shell_exec(p, sqlite3_str_value(pSql), 0);
17f9878… drh 7846 modePop(p);
17f9878… drh 7847 }
17f9878… drh 7848 sqlite3_str_free(pSql);
17f9878… drh 7849 }else
17f9878… drh 7850
4f76459… drh 7851 cli_printf(stderr,"%s","Usage: .intck STEPS_PER_UNLOCK\n");
4f76459… drh 7852 cli_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
4f76459… drh 7853 { "parser_depth", SQLITE_LIMIT_PARSER_DEPTH },
4f76459… drh 7854 cli_printf(stdout, "%20s %d\n", aLimit[i].zLimitName,
4f76459… drh 7855 cli_printf(stderr,"ambiguous limit: \"%s\"\n", azArg[1]);
4f76459… drh 7856 cli_printf(stderr,"unknown limit: \"%s\"\n"
5f65ed5… drh 7857 }else{
5f65ed5… drh 7858 cli_printf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName,
5f65ed5… drh 7859 sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
4f76459… drh 7860 p->pLog = output_file_open(p, zFile);
4f76459… drh 7861 rc = dotCmdMode(p);
4f76459… drh 7862 cli_printf(stderr,"line %lld: incorrect nonce: \"%s\"\n",
4f76459… drh 7863 cli_exit(1);
4f76459… drh 7864 modeSetStr(&p->mode.spec.zNull, azArg[1]);
d326547… drh 7865 if( p->bSafeMode ) openFlags = SQLITE_OPEN_READONLY;
d326547… drh 7866
d326547… drh 7867 }else if( optionMatch(z, "zip") && !p->bSafeMode ){
d326547… drh 7868 }else if( optionMatch(z, "append") && !p->bSafeMode ){
92871e0… drh 7869 }else if( optionMatch(z, "normal") ){
92871e0… drh 7870 openMode = SHELL_OPEN_NORMAL;
4f76459… drh 7871 cli_printf(stderr,"unknown option: %s\n", z);
4f76459… drh 7872 cli_printf(stderr,"extra argument: \"%s\"\n", z);
70539ee… drh 7873 if( newFlag && zFN && !p->bSafeMode ){
70539ee… drh 7874 if( cli_strncmp(zFN,"file:",5)==0 ){
70539ee… drh 7875 char *zDel = shellFilenameFromUri(zFN);
70539ee… drh 7876 shell_check_oom(zDel);
70539ee… drh 7877 shellDeleteFile(zDel);
70539ee… drh 7878 sqlite3_free(zDel);
70539ee… drh 7879 }else{
70539ee… drh 7880 shellDeleteFile(zFN);
70539ee… drh 7881 }
70539ee… drh 7882 }
4f76459… drh 7883 cli_printf(stderr,"Error: cannot open '%s'\n", zNewFilename);
4f76459… drh 7884 rc = dotCmdOutput(p);
4f76459… drh 7885 cli_printf(p->out,
4f76459… drh 7886 cli_printf(p->out, "Error: %s\n", sqlite3_errmsg(p->db));
4f76459… drh 7887 if( i>1 ) cli_puts(" ", p->out);
4f76459… drh 7888 cli_puts(azArg[i], p->out);
4f76459… drh 7889 cli_puts("\n", p->out);
7b0960d… drh 7890 continue;
7b0960d… drh 7891 }
7b0960d… drh 7892 if( cli_strcmp(z,"timeout")==0 ){
7b0960d… drh 7893 if( i==nArg-1 ){
7b0960d… drh 7894 dotCmdError(p, i, "missing argument", 0);
7b0960d… drh 7895 return 1;
7b0960d… drh 7896 }
7b0960d… drh 7897 i++;
a10f931… drh 7898 p->tmProgress = atof(azArg[i]);
7b0960d… drh 7899 if( p->tmProgress>0.0 ){
7b0960d… drh 7900 p->flgProgress = SHELL_PROGRESS_QUIET|SHELL_PROGRESS_TMOUT;
7b0960d… drh 7901 if( nn==0 ) nn = 100;
7b0960d… drh 7902 }
2b2530d… drh 7903 continue;
2b2530d… drh 7904 }
4f76459… drh 7905 cli_printf(stderr,"Error: unknown option: \"%s\"\n", azArg[i]);
92871e0… drh 7906 i64 savedLineno = p->lineno;
4f76459… drh 7907 cli_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
92871e0… drh 7908 rc = process_input(p, "<pipe>");
4f76459… drh 7909 cli_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
4f76459… drh 7910 char *zFilename = strdup(azArg[1]);
4f76459… drh 7911 rc = process_input(p, zFilename);
4f76459… drh 7912 free(zFilename);
4f76459… drh 7913 cli_printf(stderr,"Error: cannot open \"%s\"\n", zSrcFile);
4f76459… drh 7914 p->mode.scanstatsOn = 3;
4f76459… drh 7915 p->mode.scanstatsOn = 2;
4f76459… drh 7916 p->mode.scanstatsOn = (u8)booleanValue(azArg[1]);
4f76459… drh 7917 p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, p->mode.scanstatsOn, (int*)0
4f76459… drh 7918 if( p->mode.scanstatsOn==3 ){
4f76459… drh 7919 int bIndent = 0;
4f76459… drh 7920 sqlite3_str *pSql;
4f76459… drh 7921 sqlite3_stmt *pStmt = 0;
4f76459… drh 7922
4f76459… drh 7923 data.mode.spec.bTitles = QRF_No;
4f76459… drh 7924 data.mode.eMode = MODE_List;
4f76459… drh 7925 data.mode.spec.eText = QRF_TEXT_Plain;
4f76459… drh 7926 data.mode.spec.nCharLimit = 0;
4f76459… drh 7927 data.mode.spec.zRowSep = "\n";
4f76459… drh 7928 bIndent = 1;
4f76459… drh 7929 cli_printf(stderr,"Unknown option: \"%s\"\n", azArg[ii]);
4f76459… drh 7930 cli_printf(p->out,
2b2530d… drh 7931 "CREATE TABLE %ssqlite_schema (\n"
2b2530d… drh 7932 ");\n",
2b2530d… drh 7933 sqlite3_strlike("sqlite_t%",zName,0)==0 ? "temp." : ""
2b2530d… drh 7934 );
4f76459… drh 7935 }
4f76459… drh 7936 }
b9ecacf… drh 7937 rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
4f76459… drh 7938 if( rc ){
4f76459… drh 7939 shellDatabaseError(p->db);
4f76459… drh 7940 sqlite3_finalize(pStmt);
4f76459… drh 7941
4f76459… drh 7942 rc = 1;
4f76459… drh 7943 goto meta_command_exit;
4f76459… drh 7944 }
4f76459… drh 7945 pSql = sqlite3_str_new(p->db);
4f76459… drh 7946 sqlite3_str_appendf(pSql, "SELECT sql FROM", 0);
4f76459… drh 7947 iSchema = 0;
4f76459… drh 7948 while( sqlite3_step(pStmt)==SQLITE_ROW ){
b9ecacf… drh 7949 const char *zDb = (const char*)sqlite3_column_text(pStmt, 1);
4f76459… drh 7950 char zScNum[30];
4f76459… drh 7951 sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
4f76459… drh 7952 sqlite3_str_appendall(pSql, zDiv);
4f76459… drh 7953 zDiv = " UNION ALL ";
4f76459… drh 7954 if( sqlite3_stricmp(zDb, "main")==0 ){
4f76459… drh 7955 sqlite3_str_appendf(pSql,
4f76459… drh 7956 "SELECT shell_format_schema(shell_add_schema(sql,NULL,name),%d)",
4f76459… drh 7957 bIndent);
4f76459… drh 7958 }else{
4f76459… drh 7959 sqlite3_str_appendf(pSql,
f07aa62… drh 7960 "SELECT shell_format_schema(shell_add_schema(sql,%Q,name),%d)",
4f76459… drh 7961 zDb, bIndent);
4f76459… drh 7962 }
4f76459… drh 7963 sqlite3_str_appendf(pSql,
4f76459… drh 7964 " AS sql, type, tbl_name, name, rowid, %d AS snum, %Q as sname",
4f76459… drh 7965 ++iSchema, zDb);
4f76459… drh 7966 sqlite3_str_appendf(pSql," FROM \"%w\".sqlite_schema", zDb);
4f76459… drh 7967 }
4f76459… drh 7968 sqlite3_finalize(pStmt);
b9ecacf… drh 7969 #if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) \
b9ecacf… drh 7970 && !defined(SQLITE_OMIT_VIRTUALTABLE)
4f76459… drh 7971 if( zName ){
4f76459… drh 7972 sqlite3_str_appendall(pSql,
4f76459… drh 7973 " UNION ALL SELECT shell_module_schema(name),"
4f76459… drh 7974 " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list");
4f76459… drh 7975 }
4f76459… drh 7976 #endif
4f76459… drh 7977 sqlite3_str_appendf(pSql, ") WHERE ", 0);
4f76459… drh 7978 if( zName ){
4f76459… drh 7979 int bGlob;
4f76459… drh 7980 bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 ||
4f76459… drh 7981 strchr(zName, '[') != 0;
4f76459… drh 7982 if( strchr(zName, '.') ){
4f76459… drh 7983 sqlite3_str_appendall(pSql, "lower(format('%%s.%%s',sname,tbl_name))");
4f76459… drh 7984 }else{
4f76459… drh 7985 sqlite3_str_appendall(pSql, "lower(tbl_name)");
4f76459… drh 7986 }
4f76459… drh 7987 if( bGlob ){
4f76459… drh 7988 sqlite3_str_appendf(pSql, " GLOB %Q AND ", zName);
4f76459… drh 7989 }else{
4f76459… drh 7990 sqlite3_str_appendf(pSql, " LIKE %Q ESCAPE '\\' AND ", zName);
4f76459… drh 7991 }
4f76459… drh 7992 }
4f76459… drh 7993 if( bNoSystemTabs ){
2b2530d… drh 7994 sqlite3_str_appendf(pSql, " name NOT LIKE 'sqlite__%%' ESCAPE '_' AND ");
4f76459… drh 7995 }
4f76459… drh 7996 sqlite3_str_appendf(pSql, "sql IS NOT NULL ORDER BY snum, rowid");
4f76459… drh 7997 if( bDebug ){
4f76459… drh 7998 cli_printf(p->out, "SQL: %s;\n", sqlite3_str_value(pSql));
4f76459… drh 7999 }else{
4f76459… drh 8000 rc = shell_exec(&data, sqlite3_str_value(pSql), &zErrMsg);
4f76459… drh 8001 }
4f76459… drh 8002 sqlite3_str_free(pSql);
4f76459… drh 8003
4f76459… drh 8004 cli_printf(stderr,
4f76459… drh 8005 cli_printf(stderr,"ERROR: cannot open \"%s\" for writing\n",
4f76459… drh 8006 cli_printf(stdout, "Error: error code %d\n", rc);
4f76459… drh 8007 cli_printf(stderr,
4f76459… drh 8008 cli_printf(p->out,
4f76459… drh 8009 cli_printf(p->out,
4f76459… drh 8010 cli_printf(p->out,
4f76459… drh 8011 cli_printf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName);
4f76459… drh 8012 cli_printf(stderr,"Session \"%s\" already exists\n", zName);
4f76459… drh 8013 cli_printf(stderr,
4f76459… drh 8014 cli_printf(stderr,"Cannot open session: error code=%d\n", rc);
4f76459… drh 8015 cli_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
4f76459… drh 8016 cli_puts(zBuf, p->out);
4f76459… drh 8017 cli_printf(stderr,
4f76459… drh 8018 cli_puts("Should be one of: --init -v\n", stderr);
4f76459… drh 8019 cli_printf(stdout, "%d: %s %s\n", tno, zOp, zSql);
4f76459… drh 8020 cli_printf(p->out, "%s\n", zSql);
4f76459… drh 8021 cli_printf(p->out, "Result: %s\n", str.zTxt);
4f76459… drh 8022 cli_printf(p->out, "%d: error-code-%d: %s\n", tno, rc,zErrMsg);
4f76459… drh 8023 cli_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
4f76459… drh 8024 cli_printf(p->out, "%d: Got: [%s]\n", tno, str.zTxt);
4f76459… drh 8025 cli_printf(stderr,
4f76459… drh 8026 cli_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
4f76459… drh 8027 modeSetStr(&p->mode.spec.zColumnSep, azArg[1]);
4f76459… drh 8028 modeSetStr(&p->mode.spec.zRowSep,azArg[2]);
4f76459… drh 8029 cli_printf(stderr,
4f76459… drh 8030 cli_printf(p->out, "%s\n", zSql);
4f76459… drh 8031 if( bDebug ) cli_printf(p->out, "%s\n", zRevText);
4f76459… drh 8032 if( bDebug ) cli_printf(p->out, "%s\n", zGenQuery);
4f76459… drh 8033 cli_printf(stderr,
4f76459… drh 8034 if( x ) cli_printf(stderr,"System command returns %d\n", x);
4f76459… drh 8035 cli_printf(p->out, "%12.12s: %s\n","echo",
4f76459… drh 8036 azBool[(p->mode.mFlags & MFLG_ECHO)!=0]);
4f76459… drh 8037 cli_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->mode.autoEQP&3]);
4f76459… drh 8038 cli_printf(p->out, "%12.12s: %s\n","explain",
4f76459… drh 8039 p->mode.autoExplain ? "auto" : "off");
4f76459… drh 8040 cli_printf(p->out, "%12.12s: %s\n","headers",
4f76459… drh 8041 azBool[p->mode.spec.bTitles==QRF_Yes]);
4f76459… drh 8042 if( p->mode.spec.eStyle==QRF_STYLE_Column
4f76459… drh 8043 || p->mode.spec.eStyle==QRF_STYLE_Box
4f76459… drh 8044 || p->mode.spec.eStyle==QRF_STYLE_Table
4f76459… drh 8045 || p->mode.spec.eStyle==QRF_STYLE_Markdown
4f76459… drh 8046 cli_printf(p->out,
4f76459… drh 8047 aModeInfo[p->mode.eMode].zName, p->mode.spec.nWrap,
4f76459… drh 8048 p->mode.spec.bWordWrap==QRF_Yes ? "on" : "off",
4f76459… drh 8049 p->mode.spec.eText==QRF_TEXT_Sql ? "" : "no");
4f76459… drh 8050 cli_printf(p->out, "%12.12s: %s\n","mode",
4f76459… drh 8051 aModeInfo[p->mode.eMode].zName);
4f76459… drh 8052 cli_printf(p->out, "%12.12s: ", "nullvalue");
4f76459… drh 8053 output_c_string(p->out, p->mode.spec.zNull);
4f76459… drh 8054 cli_puts("\n", p->out);
4f76459… drh 8055 cli_printf(p->out, "%12.12s: %s\n","output",
4f76459… drh 8056 cli_printf(p->out, "%12.12s: ", "colseparator");
4f76459… drh 8057 output_c_string(p->out, p->mode.spec.zColumnSep);
4f76459… drh 8058 cli_puts("\n", p->out);
4f76459… drh 8059 cli_printf(p->out, "%12.12s: ", "rowseparator");
4f76459… drh 8060 output_c_string(p->out, p->mode.spec.zRowSep);
4f76459… drh 8061 cli_puts("\n", p->out);
4f76459… drh 8062 cli_printf(p->out, "%12.12s: %s\n","stats", zOut);
4f76459… drh 8063 cli_printf(p->out, "%12.12s: ", "width");
4f76459… drh 8064 for(i=0; i<p->mode.spec.nWidth; i++){
4f76459… drh 8065 cli_printf(p->out, "%d ", (int)p->mode.spec.aWidth[i]);
4f76459… drh 8066 cli_puts("\n", p->out);
4f76459… drh 8067 cli_printf(p->out, "%12.12s: %s\n", "filename",
17f9878… drh 8068 if( (c=='t' && n>1 && cli_strncmp(azArg[0], "tables", n)==0) ){
9aee493… drh 8069 sqlite3_str *pSql;
9aee493… drh 8070 const char *zPattern = nArg>1 ? azArg[1] : 0;
9aee493… drh 8071
9aee493… drh 8072 pSql = sqlite3_str_new(p->db);
6ae9c9a… drh 8073 while( sqlite3_step(pStmt)==SQLITE_ROW ){
9aee493… drh 8074 if( sqlite3_str_length(pSql) ){
9aee493… drh 8075 sqlite3_str_appendall(pSql, " UNION ALL ");
9aee493… drh 8076 }
9aee493… drh 8077 sqlite3_str_appendall(pSql, "SELECT name FROM ");
9aee493… drh 8078 }else{
9aee493… drh 8079 sqlite3_str_appendf(pSql, "SELECT %Q||'.'||name FROM ", zDbName);
9aee493… drh 8080 }
9aee493… drh 8081 sqlite3_str_appendf(pSql, "\"%w\".sqlite_schema", zDbName);
17f9878… drh 8082 sqlite3_str_appendf(pSql,
17f9878… drh 8083 " WHERE type IN ('table','view')"
17f9878… drh 8084 " AND name NOT LIKE 'sqlite__%%' ESCAPE '_'"
17f9878… drh 8085 );
17f9878… drh 8086 if( zPattern ){
17f9878… drh 8087 sqlite3_str_appendf(pSql," AND name LIKE %Q", zPattern);
9aee493… drh 8088 sqlite3_str_appendall(pSql, " ORDER BY 1");
9aee493… drh 8089
9aee493… drh 8090 /* Run the SQL statement in "split" mode. */
9aee493… drh 8091 modePush(p);
9aee493… drh 8092 modeChange(p, MODE_Split);
9aee493… drh 8093 shell_exec(p, sqlite3_str_value(pSql), 0);
9aee493… drh 8094 sqlite3_str_free(pSql);
9aee493… drh 8095 modePop(p);
5f65ed5… drh 8096 /* Set the p->zTestcase name and begin redirecting output into
5f65ed5… drh 8097 ** the cli_output_capture sqlite3_str */
5f65ed5… drh 8098 rc = dotCmdTestcase(p);
4f76459… drh 8099 cli_puts("Available test-controls:\n", p->out);
4f76459… drh 8100 cli_printf(p->out, " .testctrl %s %s\n",
4f76459… drh 8101 cli_printf(stderr,"Error: ambiguous test-control: \"%s\"\n"
4f76459… drh 8102 cli_printf(stderr,"Error: unknown test-control: %s\n"
4f76459… drh 8103 cli_printf(stderr,
4f76459… drh 8104 cli_puts("Should be one of:", stderr);
4f76459… drh 8105 cli_printf(stderr," %s", aLabel[jj].zLabel);
4f76459… drh 8106 cli_puts("\n", stderr);
4f76459… drh 8107 cli_puts("+All", p->out);
4f76459… drh 8108 cli_printf(p->out, " -%s", aLabel[ii].zLabel);
4f76459… drh 8109 cli_puts("-All", p->out);
4f76459… drh 8110 cli_printf(p->out, " +%s", aLabel[ii].zLabel);
4f76459… drh 8111 cli_puts("\n", p->out);
4f76459… drh 8112 cli_printf(stdout, "-- random seed: %d\n", ii);
4f76459… drh 8113 cli_printf(p->out, "%llu\n", x);
4f76459… drh 8114 if( id>1 ) cli_puts(" ", p->out);
4f76459… drh 8115 cli_printf(p->out, "%d: %d", id, val);
4f76459… drh 8116 if( id>1 ) cli_puts("\n", p->out);
4f76459… drh 8117 cli_printf(stderr,
4f76459… drh 8118 cli_printf(p->out, "result: %d\n", x);
4f76459… drh 8119 cli_printf(p->out, "faultsim.iId: %d\n",
4f76459… drh 8120 cli_printf(p->out, "faultsim.iErr: %d\n",
4f76459… drh 8121 cli_printf(p->out, "faultsim.iCnt: %d\n",
4f76459… drh 8122 cli_printf(p->out, "faultsim.nHit: %d\n",
4f76459… drh 8123 cli_printf(p->out, "faultsim.iInterval: %d\n",
4f76459… drh 8124 cli_printf(p->out, "faultsim.eVerbose: %d\n",
4f76459… drh 8125 cli_printf(p->out, "faultsim.nRepeat: %d\n",
4f76459… drh 8126 cli_printf(p->out, "faultsim.nSkip: %d\n",
4f76459… drh 8127 cli_printf(stderr,
4f76459… drh 8128 cli_puts(
4f76459… drh 8129 cli_printf(p->out,
4f76459… drh 8130 cli_printf(p->out, "%d\n", rc2);
4f76459… drh 8131 cli_printf(p->out, "0x%08x\n", rc2);
7b0960d… drh 8132 if( cli_strcmp(azArg[1],"once")==0 ){
7b0960d… drh 8133 p->enableTimer = 1;
7b0960d… drh 8134 }else{
7b0960d… drh 8135 p->enableTimer = 2*booleanValue(azArg[1]);
7b0960d… drh 8136 }
7b0960d… drh 8137 if( p->enableTimer && !HAS_TIMER ){
7b0960d… drh 8138 p->enableTimer = 0;
7b0960d… drh 8139 eputz("Usage: .timer on|off|once\n");
4f76459… drh 8140 cli_printf(stderr,"Unknown option \"%s\" on \".trace\"\n", z);
4f76459… drh 8141 p->traceOut = output_file_open(p, z);
4f76459… drh 8142 cli_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
4f76459… drh 8143 cli_printf(p->out, "zlib version %s\n", zlibVersion());
4f76459… drh 8144 cli_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
4f76459… drh 8145 cli_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz);
4f76459… drh 8146 cli_printf(p->out, "gcc-" __VERSION__ " (%s)\n", zPtrSz);
4f76459… drh 8147 cli_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
4f76459… drh 8148 cli_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
4f76459… drh 8149 cli_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
4f76459… drh 8150 cli_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
4f76459… drh 8151 cli_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
4f76459… drh 8152 cli_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
4f76459… drh 8153 cli_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
4f76459… drh 8154 cli_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
4f76459… drh 8155 cli_puts("-----------------------------------\n", p->out);
4f76459… drh 8156 cli_printf(p->out, "%s\n", zVfsName);
4f76459… drh 8157 p->mode.spec.nWidth = nArg-1;
4f76459… drh 8158 p->mode.spec.aWidth = realloc(p->mode.spec.aWidth,
4f76459… drh 8159 (p->mode.spec.nWidth+1)*sizeof(short int));
4f76459… drh 8160 shell_check_oom(p->mode.spec.aWidth);
70539ee… drh 8161 i64 w = integerValue(azArg[j]);
4f76459… drh 8162 if( w < -QRF_MAX_WIDTH ) w = -QRF_MAX_WIDTH;
4f76459… drh 8163 if( w > QRF_MAX_WIDTH ) w = QRF_MAX_WIDTH;
4f76459… drh 8164 p->mode.spec.aWidth[j-1] = (short int)w;
4f76459… drh 8165 cli_printf(stderr,"Error: unknown command or invalid arguments: "
4f76459… drh 8166 if( p->nPopOutput ){
4f76459… drh 8167 p->nPopOutput--;
4f76459… drh 8168 if( p->nPopOutput==0 ) output_reset(p);
7b0960d… drh 8169 p->dot.nArg = 0;
17f9878… drh 8170 static int runOneSqlLine(
17f9878… drh 8171 ShellState *p, /* Execution context */
17f9878… drh 8172 char *zSql, /* SQL to be run */
17f9878… drh 8173 const char *zFilename, /* Source file of the sql */
17f9878… drh 8174 int startline /* linenumber */
17f9878… drh 8175 ){
7b0960d… drh 8176 BEGIN_TIMER(p);
7b0960d… drh 8177 END_TIMER(p);
17f9878… drh 8178 if( zFilename || !stdin_is_interactive ){
17f9878… drh 8179 if( cli_strcmp(zFilename,"cmdline")==0 ){
17f9878… drh 8180 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
17f9878… drh 8181 "%s in %r command line argument:", zErrorType, startline);
17f9878… drh 8182 }else if( cli_strcmp(zFilename,"<stdin>")==0 ){
17f9878… drh 8183 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
17f9878… drh 8184 "%s near line %d:", zErrorType, startline);
17f9878… drh 8185 }else{
17f9878… drh 8186 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
17f9878… drh 8187 "%s near line %d of %s:", zErrorType, startline, zFilename);
17f9878… drh 8188 }
4f76459… drh 8189 cli_printf(stderr,"%s %s\n", zPrefix, zErrorTail);
4f76459… drh 8190 cli_printf(p->out, "%s\n", zLineBuf);
4f76459… drh 8191 if( p->mode.mFlags & MFLG_ECHO ){
4f76459… drh 8192 cli_printf(p->out, "%s\n", zDo);
a10f931… drh 8193 static char *one_input_line(ShellState *p, char *zPrior, int isContinuation){
a10f931… drh 8194 FILE *in = p->in;
92871e0… drh 8195 static int process_input(ShellState *p, const char *zSrc){
4f76459… drh 8196 const char *saved_zInFile; /* Prior value of p->zInFile */
4f76459… drh 8197 i64 saved_lineno; /* Prior value of p->lineno */
4f76459… drh 8198 cli_printf(stderr,"%s: Input nesting limit (%d) reached at line %lld."
92871e0… drh 8199 " Check recursion.\n", zSrc, MAX_INPUT_NESTING, p->lineno);
4f76459… drh 8200 saved_zInFile = p->zInFile;
4f76459… drh 8201 p->zInFile = zSrc;
4f76459… drh 8202 saved_lineno = p->lineno;
a10f931… drh 8203 zLine = one_input_line(p, zLine, nSql>0);
4f76459… drh 8204 if( p->in==0 && stdin_is_interactive ) cli_puts("\n", p->out);
92871e0… drh 8205 if( nSql>0x7fff0000 ){
92871e0… drh 8206 char zSize[100];
92871e0… drh 8207 sqlite3_snprintf(sizeof(zSize),zSize,"%,lld",nSql);
4f76459… drh 8208 cli_printf(stderr, "%s:%lld: Input SQL is too big: %s bytes\n",
92871e0… drh 8209 zSrc, startline, zSize);
92871e0… drh 8210 nSql = 0;
92871e0… drh 8211 errCnt++;
92871e0… drh 8212 break;
92871e0… drh 8213 }else if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){
17f9878… drh 8214 errCnt += runOneSqlLine(p, zSql, p->zInFile, startline);
4f76459… drh 8215 if( p->nPopOutput ){
4f76459… drh 8216 p->nPopOutput = 0;
4f76459… drh 8217 }
4f76459… drh 8218 if( p->nPopMode ){
4f76459… drh 8219 modePop(p);
4f76459… drh 8220 p->nPopMode = 0;
17f9878… drh 8221 errCnt += runOneSqlLine(p, zSql, p->zInFile, startline);
4f76459… drh 8222 p->zInFile = saved_zInFile;
4f76459… drh 8223 p->lineno = saved_lineno;
92871e0… drh 8224 i64 savedLineno = p->lineno;
4f76459… drh 8225 cli_printf(stderr,"-- Loading resources from %s\n", sqliterc);
4f76459… drh 8226 if( process_input(p, sqliterc) && bail_on_error ) cli_exit(1);
4f76459… drh 8227 cli_printf(stderr,"cannot open: \"%s\"\n", sqliterc);
4f76459… drh 8228 if( bail_on_error ) cli_exit(1);
4f76459… drh 8229 " -column set output mode to 'column'\n"
4f76459… drh 8230 " -noinit Do not read the ~/.sqliterc file at startup\n"
4f76459… drh 8231 " -screenwidth N use N as the default screenwidth \n"
4f76459… drh 8232 cli_printf(stderr,"Usage: %s [OPTIONS] [FILENAME [SQL...]]\n"
4f76459… drh 8233 cli_printf(stderr,"OPTIONS include:\n%s", zOptions);
4f76459… drh 8234 static void main_init(ShellState *p) {
4f76459… drh 8235 memset(p, 0, sizeof(*p));
4f76459… drh 8236 p->pAuxDb = &p->aAuxDb[0];
4f76459… drh 8237 p->shellFlgs = SHFLG_Lookaside;
4f76459… drh 8238 sqlite3_config(SQLITE_CONFIG_LOG, shellLog, p);
4f76459… drh 8239 cli_printf(stdout, "\033[1m%s\033[0m", zText);
4f76459… drh 8240 cli_printf(stderr,
4f76459… drh 8241 cli_exit(1);
4f76459… drh 8242 cli_puts(z, p->out);
0201a1e… drh 8243 #if defined(SQLITE_DEBUG) && !defined(SQLITE_SHELL_FIDDLE)
0201a1e… drh 8244 /* Ensure that sqlite3_reset_auto_extension() clears auto-extension
0201a1e… drh 8245 ** memory. https://sqlite.org/forum/forumpost/310cb231b07c80d1.
0201a1e… drh 8246 ** Testing this: if we (inadvertently) remove the
0201a1e… drh 8247 ** sqlite3_reset_auto_extension() call from main(), most shell tests
0201a1e… drh 8248 ** will fail because of a leak message in their output. */
0201a1e… drh 8249 static int auto_ext_leak_tester(
0201a1e… drh 8250 sqlite3 *db, const char **pzErrMsg,
0201a1e… drh 8251 const struct sqlite3_api_routines *pThunk
0201a1e… drh 8252 ){
0201a1e… drh 8253 (void)db; (void)pzErrMsg; (void)pThunk;
0201a1e… drh 8254 return SQLITE_OK;
0201a1e… drh 8255 }
0201a1e… drh 8256 #endif
0201a1e… drh 8257
b9ecacf… drh 8258 /* Alternative name to the entry point for Fiddle */
b9ecacf… drh 8259 /* Use the wmain() entry point on Windows. Translate arguments to
b9ecacf… drh 8260 ** UTF8, then invoke the traditional main() entry point which is
b9ecacf… drh 8261 ** renamed using a #define to utf8_main() .
b9ecacf… drh 8262 */
17f9878… drh 8263 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(main)
b9ecacf… drh 8264 # define main utf8_main /* Rename entry point to utf_main() */
b9ecacf… drh 8265 int SQLITE_CDECL utf8_main(int,char**); /* Forward declaration */
b9ecacf… drh 8266 int rc, i;
b9ecacf… drh 8267 char **argv = malloc( sizeof(char*) * (argc+1) );
b9ecacf… drh 8268 char **orig = argv;
b9ecacf… drh 8269 if( argv==0 ){
b9ecacf… drh 8270 fprintf(stderr, "malloc failed\n");
b9ecacf… drh 8271 exit(1);
b9ecacf… drh 8272 }
b9ecacf… drh 8273 for(i=0; i<argc; i++){
b9ecacf… drh 8274 int nByte = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, 0, 0, 0, 0);
b9ecacf… drh 8275 if( nByte==0 ){
b9ecacf… drh 8276 argv[i] = 0;
b9ecacf… drh 8277 }else{
b9ecacf… drh 8278 argv[i] = malloc( nByte );
b9ecacf… drh 8279 if( argv[i]==0 ){
b9ecacf… drh 8280 fprintf(stderr, "malloc failed\n");
b9ecacf… drh 8281 exit(1);
b9ecacf… drh 8282 }
b9ecacf… drh 8283 nByte = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i],nByte,0,0);
b9ecacf… drh 8284 if( nByte==0 ){
b9ecacf… drh 8285 free(argv[i]);
b9ecacf… drh 8286 argv[i] = 0;
b9ecacf… drh 8287 }
b9ecacf… drh 8288 }
b9ecacf… drh 8289 }
b9ecacf… drh 8290 argv[argc] = 0;
b9ecacf… drh 8291 rc = utf8_main(argc, argv);
b9ecacf… drh 8292 for(i=0; i<argc; i++) free(orig[i]);
b9ecacf… drh 8293 free(argv);
b9ecacf… drh 8294 return rc;
b9ecacf… drh 8295 }
b9ecacf… drh 8296 #endif /* WIN32 */
b9ecacf… drh 8297
b9ecacf… drh 8298 /*
b9ecacf… drh 8299 ** This is the main entry point for the process. Everything starts here.
b9ecacf… drh 8300 **
b9ecacf… drh 8301 ** The "main" identifier may have been #defined to something else:
b9ecacf… drh 8302 **
b9ecacf… drh 8303 ** utf8_main On Windows
b9ecacf… drh 8304 ** fiddle_main In Fiddle
b9ecacf… drh 8305 ** sqlite3_shell Other projects that use shell.c as a subroutine
b9ecacf… drh 8306 */
b9ecacf… drh 8307 int SQLITE_CDECL main(int argc, char **argv){
4f76459… drh 8308 int noInit = 0; /* Do not read ~/.sqliterc if true */
4f76459… drh 8309 int *aiCmd = 0;
4f76459… drh 8310 cli_printf(stderr,
4f76459… drh 8311 cli_printf(stderr,
5f65ed5… drh 8312 /* Do an initial pass through the command-line arguments to locate
5f65ed5… drh 8313 if( data.aAuxDb->zDbFilename==0 && !isScriptFile(z,1) ){
4f76459… drh 8314 stdin_is_interactive = 0;
4f76459… drh 8315 aiCmd = realloc(aiCmd, sizeof(aiCmd[0])*nCmd);
4f76459… drh 8316 shell_check_oom(azCmd);
4f76459… drh 8317 aiCmd[nCmd-1] = i;
4f76459… drh 8318 stdout_is_console = 0;
4f76459… drh 8319 modeChange(&data, MODE_BATCH);
4f76459… drh 8320 }else if( cli_strcmp(z,"-screenwidth")==0 ){
4f76459… drh 8321 int n = atoi(cmdline_option_value(argc, argv, ++i));
4f76459… drh 8322 if( n<2 ){
4f76459… drh 8323 sqlite3_fprintf(stderr,"minimum --screenwidth is 2\n");
4f76459… drh 8324 exit(1);
4f76459… drh 8325 }
4f76459… drh 8326 stdout_tty_width = n;
4f76459… drh 8327 cli_printf(stdout, "Page cache size increased to %d to accommodate"
70539ee… drh 8328 if( (i64)sz*(i64)n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
4f76459… drh 8329 }else if( cli_strcmp(z,"-noinit")==0 ){
4f76459… drh 8330 noInit = 1;
b9ecacf… drh 8331 }else if( cli_strcmp(z,"-test-argv")==0 ){
b9ecacf… drh 8332 /* Undocumented test option. Print the values in argv[] and exit.
b9ecacf… drh 8333 ** Use this to verify that any translation of the argv[], for example
b9ecacf… drh 8334 ** on Windows that receives wargv[] from the OS and must convert
b9ecacf… drh 8335 ** to UTF8 prior to calling this routine. */
b9ecacf… drh 8336 int kk;
b9ecacf… drh 8337 for(kk=0; kk<argc; kk++){
b9ecacf… drh 8338 sqlite3_fprintf(stdout,"argv[%d] = \"%s\"\n", kk, argv[kk]);
b9ecacf… drh 8339 }
b9ecacf… drh 8340 return 0;
2b2530d… drh 8341 }
2b2530d… drh 8342 #if !defined(SQLITE_OMIT_LOAD_EXTENSION)
2b2530d… drh 8343 else if( access(zVfs,0)==0 ){
2b2530d… drh 8344 /* If the VFS name is not the name of an existing VFS, but it is
2b2530d… drh 8345 ** the name of a file, then try to load that file as an extension.
2b2530d… drh 8346 ** Presumably the extension implements the desired VFS. */
2b2530d… drh 8347 sqlite3 *db = 0;
2b2530d… drh 8348 char *zErr = 0;
2b2530d… drh 8349 sqlite3_open(":memory:", &db);
2b2530d… drh 8350 sqlite3_enable_load_extension(db, 1);
2b2530d… drh 8351 rc = sqlite3_load_extension(db, zVfs, 0, &zErr);
2b2530d… drh 8352 sqlite3_close(db);
2b2530d… drh 8353 if( (rc&0xff)!=SQLITE_OK ){
2b2530d… drh 8354 cli_printf(stderr, "could not load extension VFS \"%s\": %s\n",
2b2530d… drh 8355 zVfs, zErr);
2b2530d… drh 8356 exit(1);
2b2530d… drh 8357 }
2b2530d… drh 8358 }
2b2530d… drh 8359 #endif
2b2530d… drh 8360 else{
4f76459… drh 8361 cli_printf(stderr,"no such VFS: \"%s\"\n", zVfs);
4f76459… drh 8362 cli_printf(stderr,
f4b3b59… drh 8363 rc = 1;
f4b3b59… drh 8364 goto shell_main_exit;
0201a1e… drh 8365 #ifdef SQLITE_DEBUG
0201a1e… drh 8366 sqlite3_auto_extension( (void (*)())auto_ext_leak_tester );
0201a1e… drh 8367 #endif
4f76459… drh 8368 modeDefault(&data);
4f76459… drh 8369 if( !noInit ) process_sqliterc(&data,zInitFile);
5f65ed5… drh 8370 /* Make a second pass through the command-line arguments and set
4f76459… drh 8371 modeChange(&data, MODE_Html);
4f76459… drh 8372 modeChange(&data, MODE_List);
4f76459… drh 8373 modeChange(&data, MODE_Quote);
4f76459… drh 8374 modeChange(&data, MODE_Line);
4f76459… drh 8375 modeChange(&data, MODE_Column);
4f76459… drh 8376 modeChange(&data, MODE_Json);
4f76459… drh 8377 modeChange(&data, MODE_Markdown);
4f76459… drh 8378 modeChange(&data, MODE_Table);
f4b3b59… drh 8379 }else if( cli_strcmp(z,"-psql")==0 ){
f4b3b59… drh 8380 modeChange(&data, MODE_Psql);
4f76459… drh 8381 modeChange(&data, MODE_Box);
4f76459… drh 8382 modeChange(&data, MODE_Csv);
4f76459… drh 8383 for(k=0; k<ArraySize(qrfEscNames); k++){
4f76459… drh 8384 if( sqlite3_stricmp(zEsc,qrfEscNames[k])==0 ){
4f76459… drh 8385 data.mode.spec.eEsc = k;
4f76459… drh 8386 if( k>=ArraySize(qrfEscNames) ){
4f76459… drh 8387 cli_printf(stderr, "unknown control character escape mode \"%s\""
4f76459… drh 8388 for(k=0; k<ArraySize(qrfEscNames); k++){
4f76459… drh 8389 cli_printf(stderr, " %s", qrfEscNames[k]);
4f76459… drh 8390 cli_printf(stderr, "\n");
4f76459… drh 8391 }else if( cli_strcmp(z,"-noinit")==0 ){
4f76459… drh 8392 /* No-op */
4f76459… drh 8393 modeChange(&data, MODE_Ascii);
4f76459… drh 8394 modeChange(&data, MODE_Tabs);
4f76459… drh 8395 modeSetStr(&data.mode.spec.zColumnSep,
4f76459… drh 8396 cmdline_option_value(argc,argv,++i));
4f76459… drh 8397 modeSetStr(&data.mode.spec.zRowSep,
4f76459… drh 8398 cmdline_option_value(argc,argv,++i));
4f76459… drh 8399 modeSetStr(&data.mode.spec.zNull,
4f76459… drh 8400 cmdline_option_value(argc,argv,++i));
4f76459… drh 8401 data.mode.spec.bTitles = QRF_Yes;
4f76459… drh 8402 data.mode.spec.bTitles = QRF_No;
4f76459… drh 8403 data.mode.mFlags |= MFLG_ECHO;
4f76459… drh 8404 data.mode.autoEQP = AUTOEQP_on;
4f76459… drh 8405 data.mode.autoEQP = AUTOEQP_full;
4f76459… drh 8406 data.mode.scanstatsOn = 1;
4f76459… drh 8407 cli_printf(stdout, "%s %s (%d-bit)\n",
f4b3b59… drh 8408 rc = 0;
f4b3b59… drh 8409 goto shell_main_exit;
4f76459… drh 8410 }else if( cli_strcmp(z,"-screenwidth")==0 ){
4f76459… drh 8411 i++;
b8ab8b3… drh 8412 if( rc && (bail_on_error || rc==2) ){
f4b3b59… drh 8413 if( rc==2 ) rc = 0;
f4b3b59… drh 8414 goto shell_main_exit;
f4b3b59… drh 8415 }
17f9878… drh 8416 rc = runOneSqlLine(&data, z, "cmdline", i);
f4b3b59… drh 8417 if( bail_on_error ) goto shell_main_exit;
4f76459… drh 8418 cli_printf(stderr,"Error: cannot mix regular SQL or dot-commands"
f4b3b59… drh 8419 rc = 1;
f4b3b59… drh 8420 goto shell_main_exit;
4f76459… drh 8421 stdin_is_interactive = 0;
4f76459… drh 8422 cli_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
f4b3b59… drh 8423 rc = 1;
f4b3b59… drh 8424 goto shell_main_exit;
5f65ed5… drh 8425 if( isScriptFile(azCmd[i],0) ){
5f65ed5… drh 8426 FILE *inSaved = data.in;
5f65ed5… drh 8427 i64 savedLineno = data.lineno;
5f65ed5… drh 8428 int res = 1;
5f65ed5… drh 8429 if( (data.in = openChrSource(azCmd[i]))!=0 ){
5f65ed5… drh 8430 res = process_input(&data, azCmd[i]);
5f65ed5… drh 8431 fclose(data.in);
5f65ed5… drh 8432 }
5f65ed5… drh 8433 data.in = inSaved;
5f65ed5… drh 8434 data.lineno = savedLineno;
5f65ed5… drh 8435 if( res ) i = nCmd;
5f65ed5… drh 8436 }else if( azCmd[i][0]=='.' ){
4f76459… drh 8437 char *zErrCtx = malloc( 64 );
4f76459… drh 8438 shell_check_oom(zErrCtx);
4f76459… drh 8439 sqlite3_snprintf(64,zErrCtx,"argv[%i]:",aiCmd[i]);
4f76459… drh 8440 data.zInFile = "<cmdline>";
4f76459… drh 8441 data.zErrPrefix = zErrCtx;
4f76459… drh 8442 free(data.zErrPrefix);
4f76459… drh 8443 data.zErrPrefix = 0;
17f9878… drh 8444 rc = runOneSqlLine(&data, azCmd[i], "cmdline", aiCmd[i]);
9aee493… drh 8445 if( data.nPopMode ){
9aee493… drh 8446 modePop(&data);
9aee493… drh 8447 data.nPopMode = 0;
9aee493… drh 8448 }
9aee493… drh 8449 }
17f9878… drh 8450 if( data.nPopOutput && azCmd[i][0]!='.' ){
9aee493… drh 8451 output_reset(&data);
9aee493… drh 8452 data.nPopOutput = 0;
9aee493… drh 8453 }else{
9aee493… drh 8454 clearTempFile(&data);
4f76459… drh 8455 cli_printf(stdout,
92871e0… drh 8456 rc = process_input(&data, "<stdin>");
92871e0… drh 8457 rc = process_input(&data, "<stdin>");
4f76459… drh 8458 free(aiCmd);
4f76459… drh 8459 modeFree(&data.mode);
4f76459… drh 8460 if( data.nSavedModes ){
4f76459… drh 8461 int ii;
4f76459… drh 8462 for(ii=0; ii<data.nSavedModes; ii++){
4f76459… drh 8463 modeFree(&data.aSavedModes[ii].mode);
4f76459… drh 8464 free(data.aSavedModes[ii].zTag);
4f76459… drh 8465 }
4f76459… drh 8466 free(data.aSavedModes);
4f76459… drh 8467 }
4f76459… drh 8468 free(data.zErrPrefix);
4f76459… drh 8469 free(data.dot.zCopy);
4f76459… drh 8470 free(data.dot.azArg);
4f76459… drh 8471 free(data.dot.aiOfst);
4f76459… drh 8472 free(data.dot.abQuot);
4f76459… drh 8473 if( data.nTestRun ){
4f76459… drh 8474 sqlite3_fprintf(stdout, "%d test%s run with %d error%s\n",
4f76459… drh 8475 data.nTestRun, data.nTestRun==1 ? "" : "s",
4f76459… drh 8476 data.nTestErr, data.nTestErr==1 ? "" : "s");
4f76459… drh 8477 fflush(stdout);
4f76459… drh 8478 rc = data.nTestErr>0;
4f76459… drh 8479 }
0201a1e… drh 8480 sqlite3_reset_auto_extension();
4f76459… drh 8481 cli_printf(stderr,"Memory leaked: %u bytes\n",
4f76459… drh 8482 cli_printf(stdout, "fiddle_db_arg(%p)\n", (const void*)arg);
4f76459… drh 8483 cli_puts("Rolling back in-progress transaction.\n", stdout);
92871e0… drh 8484 process_input(&shellState, "<stdin>");
4f76459… drh 8485 /************************* End src/shell.c.in ******************/

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button