Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch shell-bindings Excluding Merge-Ins
This is equivalent to a diff from 05f6278a02 to 7b2a65a654
2018-04-27
| ||
20:49 | Better comments on the bindvtab.c implementation. All the two-argument version of the .set command. All bindings from .set and -D are still string. (Leaf check-in: 7b2a65a654 user: drh tags: shell-bindings) | |
17:39 | Add the ability to use bind parameters in the CLI. The new ".set KEY=VALUE" dot-command works to set bindings. Or use the "-Dkey=value" command-line option. Or use the built-in shell_bindings(k,v) virtual table to set, delete, or changing bindings. (check-in: 1f2944d1d6 user: drh tags: shell-bindings) | |
16:35 | Fix a test script error causing tests to fail in soak.test. (check-in: 462b52b121 user: dan tags: trunk) | |
15:17 | Enhance the comments in the templatevtab.c implementation. (check-in: 05f6278a02 user: drh tags: trunk) | |
2018-04-26
| ||
18:34 | The previous fix for ticket [d85fffd6ffe856092ed8da] in check-in [0a514e62ad1ebe5c12da8dae] did not completely address the probably in that it only worked for cases where the OP_SCopy that loaded the register was the last instruction in the sequence for the expression, which is not necessarily the case for expressions like CASE...END. This revision prevents the registered that will be recomputed from being cached in the first place. (check-in: 9fd0faf517 user: drh tags: trunk) | |
Changes to Makefile.in.
1008 1008 # Source files that go into making shell.c 1009 1009 SHELL_SRC = \ 1010 1010 $(TOP)/src/shell.c.in \ 1011 1011 $(TOP)/ext/misc/appendvfs.c \ 1012 1012 $(TOP)/ext/misc/shathree.c \ 1013 1013 $(TOP)/ext/misc/fileio.c \ 1014 1014 $(TOP)/ext/misc/completion.c \ 1015 + $(TOP)/ext/misc/bindvtab.c \ 1015 1016 $(TOP)/ext/misc/sqlar.c \ 1016 1017 $(TOP)/ext/expert/sqlite3expert.c \ 1017 1018 $(TOP)/ext/expert/sqlite3expert.h \ 1018 1019 $(TOP)/ext/misc/zipfile.c \ 1019 1020 $(TOP)/src/test_windirent.c 1020 1021 1021 1022 shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
Changes to Makefile.msc.
2095 2095 # Source files that go into making shell.c 2096 2096 SHELL_SRC = \ 2097 2097 $(TOP)\src\shell.c.in \ 2098 2098 $(TOP)\ext\misc\appendvfs.c \ 2099 2099 $(TOP)\ext\misc\shathree.c \ 2100 2100 $(TOP)\ext\misc\fileio.c \ 2101 2101 $(TOP)\ext\misc\completion.c \ 2102 + $(TOP)\ext\misc\bindvtab.c \ 2102 2103 $(TOP)\ext\expert\sqlite3expert.c \ 2103 2104 $(TOP)\ext\expert\sqlite3expert.h \ 2104 2105 $(TOP)\src\test_windirent.c 2105 2106 2106 2107 # If use of zlib is enabled, add the "zipfile.c" source file. 2107 2108 # 2108 2109 !IF $(USE_ZLIB)!=0
Added ext/misc/bindvtab.c.
1 +/* 2 +** 2018-04-27 3 +** 4 +** The author disclaims copyright to this source code. In place of 5 +** a legal notice, here is a blessing: 6 +** 7 +** May you do good and not evil. 8 +** May you find forgiveness for yourself and forgive others. 9 +** May you share freely, never taking more than you give. 10 +** 11 +************************************************************************* 12 +** 13 +** This file implements a simple key/value store used to hold bind 14 +** parameters for SQLite. The key/value store is a singleton - there 15 +** is exactly one per process. The store can be accessed and controlled 16 +** from SQLite using an eponymous virtual table. 17 +** 18 +** This is used to do parameter binding in the command-line shell. 19 +** 20 +** The ".set key=value" command and the "-Dkey=value" command-line option 21 +** invoke shell_bindings_new_text() on the argument ("key=value") in order 22 +** to create entries in the store. The CLI then invokes 23 +** shell_bindings_apply() on each prepared statement just prior to 24 +** running it. 25 +** 26 +** All bindings are accessible through an eponymous-only virtual table 27 +** named shell_bindings. Ex: 28 +** 29 +** INSERT INTO shell_bindings(k,v) VALUES('p1',12345); 30 +** SELECT $p1, typeof($p1); 31 +** 32 +** The above results in an answer of 12345,'integer'. Bindings generated 33 +** using the virtual table can have any type other than NULL. But bindings 34 +** generated by the .set command and the -D command-line option are always 35 +** text. 36 +** 37 +** The CLI is single-threaded, so there is no attempt to make this code 38 +** threadsafe. 39 +** 40 +** The key/value store is kept in a global list, and uses malloc/free rather 41 +** than sqlite3_malloc64/sqlite3_free so that it can be completely independent 42 +** of SQLite, can exist both before sqlite3_initialize() and after 43 +** sqlite3_shutdown(), and so that it will persist across multiple 44 +** connections created using ".open". 45 +** 46 +** The number of parameters is expected to be small, so they are stored 47 +** on a simple linked list. If this proves to be too inefficient, some other 48 +** algorithm can be substituted in the future without changing the interface. 49 +*/ 50 +#if !defined(SQLITEINT_H) 51 +#include "sqlite3ext.h" 52 +#endif 53 +SQLITE_EXTENSION_INIT1 54 +#include <string.h> 55 +#include <assert.h> 56 +#include <stdlib.h> 57 + 58 +/* Each entry in the key/value store */ 59 +typedef struct BindingEntry BindingEntry; 60 +struct BindingEntry { 61 + char *zKey; /* Key */ 62 + BindingEntry *pNext; /* Next entry in the list */ 63 + BindingEntry *pPrev; /* Previous entry in the list */ 64 + int eType; /* SQLITE_INTEGER, _FLOAT, _TEXT, or _BLOB */ 65 + int len; /* Length for SQLITE_BLOB values */ 66 + union { 67 + sqlite3_int64 i; /* Integer value */ 68 + double r; /* Real value */ 69 + char *z; /* Text value */ 70 + unsigned char *b; /* Blob value */ 71 + } u; 72 +}; 73 + 74 +/* Global list of all entries */ 75 +static BindingEntry *global_pAll = 0; 76 + 77 +/* Locate any entry with the given key. Return NULL if not found. 78 +*/ 79 +static BindingEntry *shellBindingFind(const char *zKey){ 80 + BindingEntry *p; 81 + for(p=global_pAll; p && strcmp(p->zKey,zKey)!=0; p = p->pNext){} 82 + return p; 83 +} 84 + 85 +/* Delete any entry with the given key, if it exists. 86 +*/ 87 +static void shellBindingDelete(const char *zKey){ 88 + BindingEntry *p; 89 + p = shellBindingFind(zKey); 90 + if( p ){ 91 + if( p->pNext ){ 92 + p->pNext->pPrev = p->pPrev; 93 + } 94 + if( p->pPrev ){ 95 + p->pPrev->pNext = p->pNext; 96 + }else{ 97 + global_pAll = p->pNext; 98 + } 99 + free(p); 100 + } 101 +} 102 + 103 +/* Insert a new shell binding */ 104 +static void shellBindingInsert(BindingEntry *p){ 105 + p->pNext = global_pAll; 106 + if( global_pAll ) global_pAll->pPrev = p; 107 + global_pAll = p; 108 + p->pPrev = 0; 109 +} 110 + 111 +/* 112 +** True if c is a valid ID character. 113 +*/ 114 +static int shellBindIdChar(char c){ 115 + if( c>='a' && c<='z' ) return 1; 116 + if( c>='A' && c<='Z' ) return 1; 117 + if( c=='_' ) return 1; 118 + if( c>='0' && c<='9' ) return 2; 119 + return 0; 120 +} 121 + 122 +/* Create a new binding given a string of the form "KEY=VALUE". Return 123 +** values: 124 +** 125 +** 0: success 126 +** 1: out of memory 127 +** 2: Argument is not a valid KEY=VALUE string 128 +** 129 +** The type of VALUE is TEXT. 130 +*/ 131 +int shell_bindings_new_text(const char *z){ 132 + int i; 133 + int nKey; 134 + int nData; 135 + BindingEntry *p; 136 + for(i=0; shellBindIdChar(z[i]); i++){} 137 + if( i==0 ) return 2; 138 + if( shellBindIdChar(z[0])==2 ) return 2; 139 + nKey = i; 140 + if( z[i]!='=' ) return 2; 141 + for(nData=0; z[nKey+1+nData]; nData++){} 142 + p = malloc( sizeof(*p) + nKey + nData + 2 ); 143 + if( p==0 ) return 1; 144 + memset(p, 0, sizeof(*p)); 145 + p->zKey = (char*)&p[1]; 146 + memcpy(p->zKey, z, nKey); 147 + p->zKey[nKey] = 0; 148 + p->u.z = &p->zKey[nKey+1]; 149 + p->len = nData; 150 + p->eType = SQLITE_TEXT; 151 + memcpy(p->u.z, &z[nKey+1], nData+1); 152 + shellBindingDelete(p->zKey); 153 + shellBindingInsert(p); 154 + return 0; 155 +} 156 + 157 +/* 158 +** Delete all shell bindings 159 +*/ 160 +void shell_bindings_clear(void){ 161 + BindingEntry *pNext; 162 + while( global_pAll ){ 163 + pNext = global_pAll->pNext; 164 + free(global_pAll); 165 + global_pAll = pNext; 166 + } 167 +} 168 + 169 +/* Given a prepared statement, apply all bindings for which there are 170 +** known values in the k-v store 171 +*/ 172 +void shell_bindings_apply(sqlite3_stmt *pStmt){ 173 + int n = sqlite3_bind_parameter_count(pStmt); 174 + int i; 175 + BindingEntry *p; 176 + for(i=1; i<=n; i++){ 177 + const char *zKey = sqlite3_bind_parameter_name(pStmt, i); 178 + if( zKey==0 || zKey[0]==0 ) continue; 179 + zKey++; 180 + p = shellBindingFind(zKey); 181 + if( p==0 ) continue; 182 + switch( p->eType ){ 183 + case SQLITE_INTEGER: 184 + sqlite3_bind_int64(pStmt, i, p->u.i); 185 + break; 186 + case SQLITE_FLOAT: 187 + sqlite3_bind_double(pStmt, i, p->u.r); 188 + break; 189 + case SQLITE_TEXT: 190 + sqlite3_bind_text(pStmt, i, p->u.z, p->len, SQLITE_TRANSIENT); 191 + break; 192 + case SQLITE_BLOB: 193 + sqlite3_bind_blob(pStmt, i, p->u.b, p->len, SQLITE_TRANSIENT); 194 + break; 195 + } 196 + } 197 +} 198 + 199 +/* bindvtab_vtab is a subclass of sqlite3_vtab which is 200 +** underlying representation of the virtual table 201 +*/ 202 +typedef struct bindvtab_vtab bindvtab_vtab; 203 +struct bindvtab_vtab { 204 + sqlite3_vtab base; /* Base class - must be first */ 205 +}; 206 + 207 +/* bindvtab_cursor is a subclass of sqlite3_vtab_cursor which will 208 +** serve as the underlying representation of a cursor that scans 209 +** over rows of the result 210 +*/ 211 +typedef struct bindvtab_cursor bindvtab_cursor; 212 +struct bindvtab_cursor { 213 + sqlite3_vtab_cursor base; /* Base class - must be first */ 214 + BindingEntry *p; /* Current entry in the scan */ 215 +}; 216 + 217 +/* 218 +** The bindvtabConnect() method is invoked to create a new 219 +** template virtual table. 220 +** 221 +** Think of this routine as the constructor for bindvtab_vtab objects. 222 +** 223 +** All this routine needs to do is: 224 +** 225 +** (1) Allocate the bindvtab_vtab object and initialize all fields. 226 +** 227 +** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the 228 +** result set of queries against the virtual table will look like. 229 +*/ 230 +static int bindvtabConnect( 231 + sqlite3 *db, 232 + void *pAux, 233 + int argc, const char *const*argv, 234 + sqlite3_vtab **ppVtab, 235 + char **pzErr 236 +){ 237 + bindvtab_vtab *pNew; 238 + int rc; 239 + 240 + rc = sqlite3_declare_vtab(db, 241 + "CREATE TABLE shell_bindings(k TEXT PRIMARY KEY,v)" 242 + " WITHOUT ROWID" 243 + ); 244 + /* For convenience, define symbolic names for the index to each column. */ 245 +#define BINDVTAB_KEY 0 246 +#define BINDVTAB_VALUE 1 247 + if( rc==SQLITE_OK ){ 248 + pNew = sqlite3_malloc( sizeof(*pNew) ); 249 + *ppVtab = (sqlite3_vtab*)pNew; 250 + if( pNew==0 ) return SQLITE_NOMEM; 251 + memset(pNew, 0, sizeof(*pNew)); 252 + } 253 + return rc; 254 +} 255 + 256 +/* 257 +** This method is the destructor for bindvtab_vtab objects. 258 +*/ 259 +static int bindvtabDisconnect(sqlite3_vtab *pVtab){ 260 + bindvtab_vtab *p = (bindvtab_vtab*)pVtab; 261 + sqlite3_free(p); 262 + return SQLITE_OK; 263 +} 264 + 265 +/* 266 +** Constructor for a new bindvtab_cursor object. 267 +*/ 268 +static int bindvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ 269 + bindvtab_cursor *pCur; 270 + pCur = sqlite3_malloc( sizeof(*pCur) ); 271 + if( pCur==0 ) return SQLITE_NOMEM; 272 + memset(pCur, 0, sizeof(*pCur)); 273 + *ppCursor = &pCur->base; 274 + return SQLITE_OK; 275 +} 276 + 277 +/* 278 +** Destructor for a bindvtab_cursor. 279 +*/ 280 +static int bindvtabClose(sqlite3_vtab_cursor *cur){ 281 + bindvtab_cursor *pCur = (bindvtab_cursor*)cur; 282 + sqlite3_free(pCur); 283 + return SQLITE_OK; 284 +} 285 + 286 + 287 +/* 288 +** Advance a bindvtab_cursor to its next row of output. 289 +*/ 290 +static int bindvtabNext(sqlite3_vtab_cursor *cur){ 291 + bindvtab_cursor *pCur = (bindvtab_cursor*)cur; 292 + pCur->p = pCur->p->pNext; 293 + return SQLITE_OK; 294 +} 295 + 296 +/* 297 +** Return values of columns for the row at which the bindvtab_cursor 298 +** is currently pointing. 299 +*/ 300 +static int bindvtabColumn( 301 + sqlite3_vtab_cursor *cur, /* The cursor */ 302 + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ 303 + int i /* Which column to return */ 304 +){ 305 + bindvtab_cursor *pCur = (bindvtab_cursor*)cur; 306 + BindingEntry *p = pCur->p; 307 + if( i==BINDVTAB_KEY ){ 308 + sqlite3_result_text(ctx, p->zKey, -1, SQLITE_TRANSIENT); 309 + }else{ 310 + assert( i==BINDVTAB_VALUE ); 311 + switch( p->eType ){ 312 + case SQLITE_INTEGER: 313 + sqlite3_result_int(ctx, p->u.i); 314 + break; 315 + case SQLITE_FLOAT: 316 + sqlite3_result_double(ctx, p->u.r); 317 + break; 318 + case SQLITE_TEXT: 319 + sqlite3_result_text(ctx, p->u.z, p->len, SQLITE_TRANSIENT); 320 + break; 321 + case SQLITE_BLOB: 322 + sqlite3_result_blob(ctx, p->u.b, p->len, SQLITE_TRANSIENT); 323 + break; 324 + } 325 + } 326 + return SQLITE_OK; 327 +} 328 + 329 +/* 330 +** Return the rowid for the current row. In this implementation, the 331 +** rowid is the same as the output value. 332 +*/ 333 +static int bindvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ 334 + return SQLITE_OK; 335 +} 336 + 337 +/* 338 +** Return TRUE if the cursor has been moved off of the last 339 +** row of output. 340 +*/ 341 +static int bindvtabEof(sqlite3_vtab_cursor *cur){ 342 + bindvtab_cursor *pCur = (bindvtab_cursor*)cur; 343 + return pCur->p==0; 344 +} 345 + 346 +/* 347 +** This method is called to "rewind" the bindvtab_cursor object back 348 +** to the first row of output. This method is always called at least 349 +** once prior to any call to bindvtabColumn() or bindvtabRowid() or 350 +** bindvtabEof(). 351 +*/ 352 +static int bindvtabFilter( 353 + sqlite3_vtab_cursor *pVtabCursor, 354 + int idxNum, const char *idxStr, 355 + int argc, sqlite3_value **argv 356 +){ 357 + bindvtab_cursor *pCur = (bindvtab_cursor *)pVtabCursor; 358 + pCur->p = global_pAll; 359 + return SQLITE_OK; 360 +} 361 + 362 +/* 363 +** SQLite will invoke this method one or more times while planning a query 364 +** that uses the virtual table. This routine needs to create 365 +** a query plan for each invocation and compute an estimated cost for that 366 +** plan. 367 +*/ 368 +static int bindvtabBestIndex( 369 + sqlite3_vtab *tab, 370 + sqlite3_index_info *pIdxInfo 371 +){ 372 + pIdxInfo->estimatedCost = (double)10; 373 + pIdxInfo->estimatedRows = 10; 374 + return SQLITE_OK; 375 +} 376 + 377 +/* 378 +** Called to make changes to the shell bindings 379 +*/ 380 +static int bindvtabUpdate( 381 + sqlite3_vtab *pVTab, 382 + int argc, 383 + sqlite3_value **argv, 384 + sqlite_int64 *pRowid 385 +){ 386 + const char *zKey; 387 + BindingEntry *p; 388 + int nKey; 389 + int len; 390 + int eType; 391 + if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){ 392 + zKey = (const char*)sqlite3_value_text(argv[0]); 393 + if( zKey ) shellBindingDelete(zKey); 394 + } 395 + if( argc==1 ) return SQLITE_OK; 396 + eType = sqlite3_value_type(argv[3]); 397 + if( eType==SQLITE_NULL ) return SQLITE_OK; 398 + zKey = (const char*)sqlite3_value_text(argv[2]); 399 + if( zKey==0 ) return SQLITE_OK; 400 + nKey = sqlite3_value_bytes(argv[2]); 401 + shellBindingDelete(zKey); 402 + if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){ 403 + len = sqlite3_value_bytes(argv[3]); 404 + }else{ 405 + len = 0; 406 + } 407 + p = malloc( sizeof(*p) + nKey + len + 2 ); 408 + if( p==0 ) return SQLITE_NOMEM; 409 + memset(p, 0, sizeof(*p)); 410 + p->zKey = (char*)&p[1]; 411 + memcpy(p->zKey, zKey, nKey+1); 412 + p->eType = eType; 413 + switch( eType ){ 414 + case SQLITE_INTEGER: 415 + p->u.i = sqlite3_value_int64(argv[3]); 416 + break; 417 + case SQLITE_FLOAT: 418 + p->u.r = sqlite3_value_double(argv[3]); 419 + break; 420 + case SQLITE_TEXT: 421 + p->u.z = &p->zKey[nKey+1]; 422 + memcpy(p->u.z, sqlite3_value_text(argv[3]), len); 423 + break; 424 + case SQLITE_BLOB: 425 + p->u.b = (unsigned char*)&p->zKey[nKey+1]; 426 + memcpy(p->u.b, sqlite3_value_blob(argv[3]), len); 427 + break; 428 + } 429 + shellBindingInsert(p); 430 + return SQLITE_OK; 431 +} 432 + 433 +/* 434 +** This following structure defines all the methods for the 435 +** virtual table. 436 +*/ 437 +static sqlite3_module bindvtabModule = { 438 + /* iVersion */ 0, 439 + /* xCreate */ 0, 440 + /* xConnect */ bindvtabConnect, 441 + /* xBestIndex */ bindvtabBestIndex, 442 + /* xDisconnect */ bindvtabDisconnect, 443 + /* xDestroy */ 0, 444 + /* xOpen */ bindvtabOpen, 445 + /* xClose */ bindvtabClose, 446 + /* xFilter */ bindvtabFilter, 447 + /* xNext */ bindvtabNext, 448 + /* xEof */ bindvtabEof, 449 + /* xColumn */ bindvtabColumn, 450 + /* xRowid */ bindvtabRowid, 451 + /* xUpdate */ bindvtabUpdate, 452 + /* xBegin */ 0, 453 + /* xSync */ 0, 454 + /* xCommit */ 0, 455 + /* xRollback */ 0, 456 + /* xFindMethod */ 0, 457 + /* xRename */ 0, 458 + /* xSavepoint */ 0, 459 + /* xRelease */ 0, 460 + /* xRollbackTo */ 0 461 +}; 462 + 463 + 464 +#ifdef _WIN32 465 +__declspec(dllexport) 466 +#endif 467 +int sqlite3_bindvtab_init( 468 + sqlite3 *db, 469 + char **pzErrMsg, 470 + const sqlite3_api_routines *pApi 471 +){ 472 + int rc = SQLITE_OK; 473 + SQLITE_EXTENSION_INIT2(pApi); 474 + rc = sqlite3_create_module(db, "shell_bindings", &bindvtabModule, 0); 475 + return rc; 476 +}
Changes to main.mk.
703 703 # Source files that go into making shell.c 704 704 SHELL_SRC = \ 705 705 $(TOP)/src/shell.c.in \ 706 706 $(TOP)/ext/misc/appendvfs.c \ 707 707 $(TOP)/ext/misc/shathree.c \ 708 708 $(TOP)/ext/misc/fileio.c \ 709 709 $(TOP)/ext/misc/completion.c \ 710 + $(TOP)/ext/misc/bindvtab.c \ 710 711 $(TOP)/ext/misc/sqlar.c \ 711 712 $(TOP)/ext/expert/sqlite3expert.c \ 712 713 $(TOP)/ext/expert/sqlite3expert.h \ 713 714 $(TOP)/ext/misc/zipfile.c \ 714 715 $(TOP)/src/test_windirent.c 715 716 716 717 shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
Changes to src/shell.c.in.
936 936 INCLUDE test_windirent.c 937 937 #define dirent DIRENT 938 938 #endif 939 939 INCLUDE ../ext/misc/shathree.c 940 940 INCLUDE ../ext/misc/fileio.c 941 941 INCLUDE ../ext/misc/completion.c 942 942 INCLUDE ../ext/misc/appendvfs.c 943 +INCLUDE ../ext/misc/bindvtab.c 943 944 #ifdef SQLITE_HAVE_ZLIB 944 945 INCLUDE ../ext/misc/zipfile.c 945 946 INCLUDE ../ext/misc/sqlar.c 946 947 #endif 947 948 INCLUDE ../ext/expert/sqlite3expert.h 948 949 INCLUDE ../ext/expert/sqlite3expert.c 949 950 ................................................................................ 3003 3004 /* If the shell is currently in ".explain" mode, gather the extra 3004 3005 ** data required to add indents to the output.*/ 3005 3006 if( pArg->cMode==MODE_Explain ){ 3006 3007 explain_data_prepare(pArg, pStmt); 3007 3008 } 3008 3009 } 3009 3010 3011 + shell_bindings_apply(pStmt); 3010 3012 exec_prepared_stmt(pArg, pStmt); 3011 3013 explain_data_delete(pArg); 3012 3014 eqp_render(pArg); 3013 3015 3014 3016 /* print usage stats if stats on */ 3015 3017 if( pArg && pArg->statsOn ){ 3016 3018 display_stats(db, pArg, 0); ................................................................................ 3402 3404 " Add --indent for pretty-printing\n" 3403 3405 ".selftest ?--init? Run tests defined in the SELFTEST table\n" 3404 3406 ".separator COL ?ROW? Change the column separator and optionally the row\n" 3405 3407 " separator for both the output mode and .import\n" 3406 3408 #if defined(SQLITE_ENABLE_SESSION) 3407 3409 ".session CMD ... Create or control sessions\n" 3408 3410 #endif 3411 + ".set KEY=VALUE Set bind parameter KEY to be string VALUE\n" 3409 3412 ".sha3sum ?OPTIONS...? Compute a SHA3 hash of database content\n" 3410 3413 #ifndef SQLITE_NOHAVE_SYSTEM 3411 3414 ".shell CMD ARGS... Run CMD ARGS... in a system shell\n" 3412 3415 #endif 3413 3416 ".show Show the current values for various settings\n" 3414 3417 ".stats ?on|off? Show stats or turn stats on or off\n" 3415 3418 #ifndef SQLITE_NOHAVE_SYSTEM ................................................................................ 3614 3617 } 3615 3618 #ifndef SQLITE_OMIT_LOAD_EXTENSION 3616 3619 sqlite3_enable_load_extension(p->db, 1); 3617 3620 #endif 3618 3621 sqlite3_fileio_init(p->db, 0, 0); 3619 3622 sqlite3_shathree_init(p->db, 0, 0); 3620 3623 sqlite3_completion_init(p->db, 0, 0); 3624 + sqlite3_bindvtab_init(p->db, 0, 0); 3621 3625 #ifdef SQLITE_HAVE_ZLIB 3622 3626 sqlite3_zipfile_init(p->db, 0, 0); 3623 3627 sqlite3_sqlar_init(p->db, 0, 0); 3624 3628 #endif 3625 3629 sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, 3626 3630 shellAddSchemaName, 0, 0); 3627 3631 sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0, ................................................................................ 7143 7147 "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]); 7144 7148 } 7145 7149 if( nArg>=3 ){ 7146 7150 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, 7147 7151 "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]); 7148 7152 } 7149 7153 }else 7154 + 7155 + if( c=='s' && n==3 && strncmp(azArg[0],"set",3)==0 ){ 7156 + int x; 7157 + char *zKey = 0; 7158 + char *zToFree = 0; 7159 + if( nArg==2 ){ 7160 + zKey = azArg[1]; 7161 + }else if( nArg==3 ){ 7162 + zKey = zToFree = sqlite3_mprintf("%s=%s",azArg[1],azArg[2]); 7163 + }else{ 7164 + raw_printf(stderr, 7165 + "Usage: .set KEY VALUE\n Or: .set KEY=VALUE\n" 7166 + "Use SQL on the \"shell_bindings\" table to query or delete keys.\n" 7167 + ); 7168 + rc = 1; 7169 + goto meta_command_exit; 7170 + } 7171 + x = shell_bindings_new_text(zKey); 7172 + if( x ){ 7173 + utf8_printf(stderr, "Error: bad setting: %s\n", zKey); 7174 + } 7175 + sqlite3_free(zToFree); 7176 + }else 7177 + 7150 7178 7151 7179 if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){ 7152 7180 const char *zLike = 0; /* Which table to checksum. 0 means everything */ 7153 7181 int i; /* Loop counter */ 7154 7182 int bSchema = 0; /* Also hash the schema */ 7155 7183 int bSeparate = 0; /* Hash each table separately */ 7156 7184 int iSize = 224; /* Hash algorithm to use */ ................................................................................ 8112 8140 " -append append the database to the end of the file\n" 8113 8141 " -ascii set output mode to 'ascii'\n" 8114 8142 " -bail stop after hitting an error\n" 8115 8143 " -batch force batch I/O\n" 8116 8144 " -column set output mode to 'column'\n" 8117 8145 " -cmd COMMAND run \"COMMAND\" before reading stdin\n" 8118 8146 " -csv set output mode to 'csv'\n" 8147 + " -Dkey=value set shell binding variable \"key\" to \"value\"\n" 8119 8148 " -echo print commands before execution\n" 8120 8149 " -init FILENAME read/process named file\n" 8121 8150 " -[no]header turn headers on or off\n" 8122 8151 #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) 8123 8152 " -heap SIZE Size of heap for memsys3 or memsys5\n" 8124 8153 #endif 8125 8154 " -help show this message\n" ................................................................................ 8415 8444 data.openMode = SHELL_OPEN_READONLY; 8416 8445 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) 8417 8446 }else if( strncmp(z, "-A",2)==0 ){ 8418 8447 /* All remaining command-line arguments are passed to the ".archive" 8419 8448 ** command, so ignore them */ 8420 8449 break; 8421 8450 #endif 8451 + }else if( strncmp(z, "-D",2)==0 ){ 8452 + int x; 8453 + x = shell_bindings_new_text(z+2); 8454 + if( x ){ 8455 + utf8_printf(stderr, "Error: bad binding: %s\n", z); 8456 + } 8422 8457 } 8423 8458 } 8424 8459 verify_uninitialized(); 8425 8460 8426 8461 8427 8462 #ifdef SQLITE_SHELL_INIT_PROC 8428 8463 { ................................................................................ 8611 8646 arDotCommand(&data, argv+(i-1), argc-(i-1)); 8612 8647 }else{ 8613 8648 arDotCommand(&data, argv+i, argc-i); 8614 8649 } 8615 8650 readStdin = 0; 8616 8651 break; 8617 8652 #endif 8653 + }else if( strncmp(z, "-D", 2)==0 ){ 8654 + /* Noop */ 8618 8655 }else{ 8619 8656 utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); 8620 8657 raw_printf(stderr,"Use -help for a list of options.\n"); 8621 8658 return 1; 8622 8659 } 8623 8660 data.cMode = data.mode; 8624 8661 } ................................................................................ 8689 8726 set_table_name(&data, 0); 8690 8727 if( data.db ){ 8691 8728 session_close_all(&data); 8692 8729 sqlite3_close(data.db); 8693 8730 } 8694 8731 sqlite3_free(data.zFreeOnClose); 8695 8732 find_home_dir(1); 8733 + shell_bindings_clear(); 8696 8734 output_reset(&data); 8697 8735 data.doXdgOpen = 0; 8698 8736 clearTempFile(&data); 8699 8737 #if !SQLITE_SHELL_IS_UTF8 8700 8738 for(i=0; i<argc; i++) free(argv[i]); 8701 8739 free(argv); 8702 8740 #endif 8703 8741 return rc; 8704 8742 }