SQLite

Check-in [1f2944d1d6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment: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.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | shell-bindings
Files: files | file ages | folders
SHA3-256: 1f2944d1d64d36b729450685974c260295cf1e32c204b71e27d20ebc4d65f9e8
User & Date: drh 2018-04-27 17:39:22.740
Context
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)
15:17
Enhance the comments in the templatevtab.c implementation. (check-in: 05f6278a02 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to Makefile.in.
1008
1009
1010
1011
1012
1013
1014

1015
1016
1017
1018
1019
1020
1021
# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)/src/shell.c.in \
        $(TOP)/ext/misc/appendvfs.c \
	$(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/misc/fileio.c \
	$(TOP)/ext/misc/completion.c \

	$(TOP)/ext/misc/sqlar.c \
	$(TOP)/ext/expert/sqlite3expert.c \
	$(TOP)/ext/expert/sqlite3expert.h \
	$(TOP)/ext/misc/zipfile.c \
        $(TOP)/src/test_windirent.c

shell.c:	$(SHELL_SRC) $(TOP)/tool/mkshellc.tcl







>







1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)/src/shell.c.in \
        $(TOP)/ext/misc/appendvfs.c \
	$(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/misc/fileio.c \
	$(TOP)/ext/misc/completion.c \
        $(TOP)/ext/misc/bindvtab.c \
	$(TOP)/ext/misc/sqlar.c \
	$(TOP)/ext/expert/sqlite3expert.c \
	$(TOP)/ext/expert/sqlite3expert.h \
	$(TOP)/ext/misc/zipfile.c \
        $(TOP)/src/test_windirent.c

shell.c:	$(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
Changes to Makefile.msc.
2095
2096
2097
2098
2099
2100
2101

2102
2103
2104
2105
2106
2107
2108
# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)\src\shell.c.in \
	$(TOP)\ext\misc\appendvfs.c \
	$(TOP)\ext\misc\shathree.c \
	$(TOP)\ext\misc\fileio.c \
	$(TOP)\ext\misc\completion.c \

	$(TOP)\ext\expert\sqlite3expert.c \
	$(TOP)\ext\expert\sqlite3expert.h \
	$(TOP)\src\test_windirent.c

# If use of zlib is enabled, add the "zipfile.c" source file.
#
!IF $(USE_ZLIB)!=0







>







2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)\src\shell.c.in \
	$(TOP)\ext\misc\appendvfs.c \
	$(TOP)\ext\misc\shathree.c \
	$(TOP)\ext\misc\fileio.c \
	$(TOP)\ext\misc\completion.c \
        $(TOP)\ext\misc\bindvtab.c \
	$(TOP)\ext\expert\sqlite3expert.c \
	$(TOP)\ext\expert\sqlite3expert.h \
	$(TOP)\src\test_windirent.c

# If use of zlib is enabled, add the "zipfile.c" source file.
#
!IF $(USE_ZLIB)!=0
Added ext/misc/bindvtab.c.
























































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
/*
** 2018-04-27
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file implements a simple key/value store used to hold bind
** parameters for SQLite.  The key/value store is a singleton - there
** is exactly one per process.  The store can be accessed and controlled
** from SQLite using an eponymous virtual table.
*/
#if !defined(SQLITEINT_H)
#include "sqlite3ext.h"
#endif
SQLITE_EXTENSION_INIT1
#include <string.h>
#include <assert.h>
#include <stdlib.h>

/* Each entry in the key/value store */
typedef struct BindingEntry  BindingEntry;
struct BindingEntry {
  char *zKey;             /* Key */
  BindingEntry *pNext;    /* Next entry in the list */
  BindingEntry *pPrev;    /* Previous entry in the list */
  int eType;              /* SQLITE_INTEGER, _FLOAT, _TEXT, or _BLOB */
  int len;                /* Length for SQLITE_BLOB values */
  union {
    sqlite3_int64 i;         /* Integer value */
    double r;                /* Real value */
    char *z;                 /* Text value */
    unsigned char *b;        /* Blob value */
  } u;
};

/* Global list of all entries */
static BindingEntry *global_pAll = 0;

/* Locate any entry with the given key.  Return NULL if not found.
*/
static BindingEntry *shellBindingFind(const char *zKey){
  BindingEntry *p;
  for(p=global_pAll; p && strcmp(p->zKey,zKey)!=0; p = p->pNext){}
  return p;
}

/* Delete any entry with the given key, if it exists.
*/
static void shellBindingDelete(const char *zKey){
  BindingEntry *p;
  p = shellBindingFind(zKey);
  if( p ){
    if( p->pNext ){
      p->pNext->pPrev = p->pPrev;
    }
    if( p->pPrev ){
      p->pPrev->pNext = p->pNext;
    }else{
      global_pAll = p->pNext;
    }
    free(p);
  }
}

/* Insert a new shell binding */
static void shellBindingInsert(BindingEntry *p){
  p->pNext = global_pAll;
  if( global_pAll ) global_pAll->pPrev = p;
  global_pAll = p;
  p->pPrev = 0;
}

/*
** True if c is a valid ID character.
*/
static int shellBindIdChar(char c){
  if( c>='a' && c<='z' ) return 1;
  if( c>='A' && c<='Z' ) return 1;
  if( c=='_' ) return 1;
  if( c>='0' && c<='9' ) return 2;
  return 0;
}

/* Create a new binding given a string of the form "KEY=VALUE".  Return
** values:
**
**    0:    success
**    1:    out of memory
**    2:    Argument is not a valid KEY=VALUE string
**
** The type of VALUE is TEXT.
*/
int shell_bindings_new_text(const char *z){
  int i;
  int nKey;
  int nData;
  BindingEntry *p;
  for(i=0; shellBindIdChar(z[i]); i++){}
  if( i==0 ) return 2;
  if( shellBindIdChar(z[0])==2 ) return 2;
  nKey = i;
  if( z[i]!='=' ) return 2;
  for(nData=0; z[nKey+1+nData]; nData++){}
  p = malloc( sizeof(*p) + nKey + nData + 2 );
  if( p==0 ) return 1;
  memset(p, 0, sizeof(*p));
  p->zKey = (char*)&p[1];
  memcpy(p->zKey, z, nKey);
  p->zKey[nKey] = 0;
  p->u.z = &p->zKey[nKey+1];
  p->len = nData;
  p->eType = SQLITE_TEXT;
  memcpy(p->u.z, &z[nKey+1], nData+1);
  shellBindingDelete(p->zKey);
  shellBindingInsert(p);
  return 0;
}

/*
** Delete all shell bindings
*/
void shell_bindings_clear(void){
  BindingEntry *pNext;
  while( global_pAll ){
    pNext = global_pAll->pNext;
    free(global_pAll);
    global_pAll = pNext;
  }
}

/* Given a prepared statement, apply all bindings for which there are
** known values in the k-v store
*/
void shell_bindings_apply(sqlite3_stmt *pStmt){
  int n = sqlite3_bind_parameter_count(pStmt);
  int i;
  BindingEntry *p;
  for(i=1; i<=n; i++){
    const char *zKey = sqlite3_bind_parameter_name(pStmt, i);
    if( zKey==0 || zKey[0]==0 ) continue;
    zKey++;
    p = shellBindingFind(zKey);
    if( p==0 ) continue;
    switch( p->eType ){
      case SQLITE_INTEGER:
        sqlite3_bind_int64(pStmt, i, p->u.i);
        break;
      case SQLITE_FLOAT:
        sqlite3_bind_double(pStmt, i, p->u.r);
        break;
      case SQLITE_TEXT:
        sqlite3_bind_text(pStmt, i, p->u.z, p->len, SQLITE_TRANSIENT);
        break;
      case SQLITE_BLOB:
        sqlite3_bind_blob(pStmt, i, p->u.b, p->len, SQLITE_TRANSIENT);
        break;
    }
  }
}

/* bindvtab_vtab is a subclass of sqlite3_vtab which is
** underlying representation of the virtual table
*/
typedef struct bindvtab_vtab bindvtab_vtab;
struct bindvtab_vtab {
  sqlite3_vtab base;  /* Base class - must be first */
};

/* bindvtab_cursor is a subclass of sqlite3_vtab_cursor which will
** serve as the underlying representation of a cursor that scans
** over rows of the result
*/
typedef struct bindvtab_cursor bindvtab_cursor;
struct bindvtab_cursor {
  sqlite3_vtab_cursor base;  /* Base class - must be first */
  BindingEntry *p;           /* Current entry in the scan */
};

/*
** The bindvtabConnect() method is invoked to create a new
** template virtual table.
**
** Think of this routine as the constructor for bindvtab_vtab objects.
**
** All this routine needs to do is:
**
**    (1) Allocate the bindvtab_vtab object and initialize all fields.
**
**    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
**        result set of queries against the virtual table will look like.
*/
static int bindvtabConnect(
  sqlite3 *db,
  void *pAux,
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  bindvtab_vtab *pNew;
  int rc;

  rc = sqlite3_declare_vtab(db,
           "CREATE TABLE shell_bindings(k TEXT PRIMARY KEY,v)"
           " WITHOUT ROWID"
       );
  /* For convenience, define symbolic names for the index to each column. */
#define BINDVTAB_KEY    0
#define BINDVTAB_VALUE  1
  if( rc==SQLITE_OK ){
    pNew = sqlite3_malloc( sizeof(*pNew) );
    *ppVtab = (sqlite3_vtab*)pNew;
    if( pNew==0 ) return SQLITE_NOMEM;
    memset(pNew, 0, sizeof(*pNew));
  }
  return rc;
}

/*
** This method is the destructor for bindvtab_vtab objects.
*/
static int bindvtabDisconnect(sqlite3_vtab *pVtab){
  bindvtab_vtab *p = (bindvtab_vtab*)pVtab;
  sqlite3_free(p);
  return SQLITE_OK;
}

/*
** Constructor for a new bindvtab_cursor object.
*/
static int bindvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
  bindvtab_cursor *pCur;
  pCur = sqlite3_malloc( sizeof(*pCur) );
  if( pCur==0 ) return SQLITE_NOMEM;
  memset(pCur, 0, sizeof(*pCur));
  *ppCursor = &pCur->base;
  return SQLITE_OK;
}

/*
** Destructor for a bindvtab_cursor.
*/
static int bindvtabClose(sqlite3_vtab_cursor *cur){
  bindvtab_cursor *pCur = (bindvtab_cursor*)cur;
  sqlite3_free(pCur);
  return SQLITE_OK;
}


/*
** Advance a bindvtab_cursor to its next row of output.
*/
static int bindvtabNext(sqlite3_vtab_cursor *cur){
  bindvtab_cursor *pCur = (bindvtab_cursor*)cur;
  pCur->p = pCur->p->pNext;
  return SQLITE_OK;
}

/*
** Return values of columns for the row at which the bindvtab_cursor
** is currently pointing.
*/
static int bindvtabColumn(
  sqlite3_vtab_cursor *cur,   /* The cursor */
  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
  int i                       /* Which column to return */
){
  bindvtab_cursor *pCur = (bindvtab_cursor*)cur;
  BindingEntry *p = pCur->p;
  if( i==BINDVTAB_KEY ){
    sqlite3_result_text(ctx, p->zKey, -1, SQLITE_TRANSIENT);
  }else{
    assert( i==BINDVTAB_VALUE );
    switch( p->eType ){
      case SQLITE_INTEGER:
        sqlite3_result_int(ctx, p->u.i);
        break;
      case SQLITE_FLOAT:
        sqlite3_result_double(ctx, p->u.r);
        break;
      case SQLITE_TEXT:
        sqlite3_result_text(ctx, p->u.z, p->len, SQLITE_TRANSIENT);
        break;
      case SQLITE_BLOB:
        sqlite3_result_blob(ctx, p->u.b, p->len, SQLITE_TRANSIENT);
        break;
    }
  }
  return SQLITE_OK;
}

/*
** Return the rowid for the current row.  In this implementation, the
** rowid is the same as the output value.
*/
static int bindvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  return SQLITE_OK;
}

/*
** Return TRUE if the cursor has been moved off of the last
** row of output.
*/
static int bindvtabEof(sqlite3_vtab_cursor *cur){
  bindvtab_cursor *pCur = (bindvtab_cursor*)cur;
  return pCur->p==0;
}

/*
** This method is called to "rewind" the bindvtab_cursor object back
** to the first row of output.  This method is always called at least
** once prior to any call to bindvtabColumn() or bindvtabRowid() or 
** bindvtabEof().
*/
static int bindvtabFilter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  bindvtab_cursor *pCur = (bindvtab_cursor *)pVtabCursor;
  pCur->p = global_pAll;
  return SQLITE_OK;
}

/*
** SQLite will invoke this method one or more times while planning a query
** that uses the virtual table.  This routine needs to create
** a query plan for each invocation and compute an estimated cost for that
** plan.
*/
static int bindvtabBestIndex(
  sqlite3_vtab *tab,
  sqlite3_index_info *pIdxInfo
){
  pIdxInfo->estimatedCost = (double)10;
  pIdxInfo->estimatedRows = 10;
  return SQLITE_OK;
}

/*
** Called to make changes to the shell bindings
*/
static int bindvtabUpdate(
  sqlite3_vtab *pVTab,
  int argc,
  sqlite3_value **argv,
  sqlite_int64 *pRowid
){
  const char *zKey;
  BindingEntry *p;
  int nKey;
  int len;
  int eType;
  if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){
    zKey = (const char*)sqlite3_value_text(argv[0]);
    if( zKey ) shellBindingDelete(zKey);
  }
  if( argc==1 ) return SQLITE_OK;
  eType = sqlite3_value_type(argv[3]);
  if( eType==SQLITE_NULL ) return SQLITE_OK;
  zKey = (const char*)sqlite3_value_text(argv[2]);
  if( zKey==0 ) return SQLITE_OK;
  nKey = sqlite3_value_bytes(argv[2]);
  shellBindingDelete(zKey);
  if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
    len = sqlite3_value_bytes(argv[3]);
  }else{
    len = 0;
  }
  p = malloc( sizeof(*p) + nKey + len + 2 );
  if( p==0 ) return SQLITE_NOMEM;
  memset(p, 0, sizeof(*p));
  p->zKey = (char*)&p[1];
  memcpy(p->zKey, zKey, nKey+1);
  p->eType = eType;
  switch( eType ){
    case SQLITE_INTEGER: 
       p->u.i = sqlite3_value_int64(argv[3]);
       break;
    case SQLITE_FLOAT: 
       p->u.r = sqlite3_value_double(argv[3]);
       break;
    case SQLITE_TEXT:
       p->u.z = &p->zKey[nKey+1];
       memcpy(p->u.z, sqlite3_value_text(argv[3]), len);
       break;
    case SQLITE_BLOB:
       p->u.b = (unsigned char*)&p->zKey[nKey+1];
       memcpy(p->u.b, sqlite3_value_blob(argv[3]), len);
       break;
  }
  shellBindingInsert(p);
  return SQLITE_OK;
}

/*
** This following structure defines all the methods for the 
** virtual table.
*/
static sqlite3_module bindvtabModule = {
  /* iVersion    */ 0,
  /* xCreate     */ 0,
  /* xConnect    */ bindvtabConnect,
  /* xBestIndex  */ bindvtabBestIndex,
  /* xDisconnect */ bindvtabDisconnect,
  /* xDestroy    */ 0,
  /* xOpen       */ bindvtabOpen,
  /* xClose      */ bindvtabClose,
  /* xFilter     */ bindvtabFilter,
  /* xNext       */ bindvtabNext,
  /* xEof        */ bindvtabEof,
  /* xColumn     */ bindvtabColumn,
  /* xRowid      */ bindvtabRowid,
  /* xUpdate     */ bindvtabUpdate,
  /* xBegin      */ 0,
  /* xSync       */ 0,
  /* xCommit     */ 0,
  /* xRollback   */ 0,
  /* xFindMethod */ 0,
  /* xRename     */ 0,
  /* xSavepoint  */ 0,
  /* xRelease    */ 0,
  /* xRollbackTo */ 0
};


#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_bindvtab_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
  rc = sqlite3_create_module(db, "shell_bindings", &bindvtabModule, 0);
  return rc;
}
Changes to main.mk.
703
704
705
706
707
708
709

710
711
712
713
714
715
716
# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)/src/shell.c.in \
        $(TOP)/ext/misc/appendvfs.c \
	$(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/misc/fileio.c \
	$(TOP)/ext/misc/completion.c \

	$(TOP)/ext/misc/sqlar.c \
	$(TOP)/ext/expert/sqlite3expert.c \
	$(TOP)/ext/expert/sqlite3expert.h \
	$(TOP)/ext/misc/zipfile.c \
        $(TOP)/src/test_windirent.c

shell.c:	$(SHELL_SRC) $(TOP)/tool/mkshellc.tcl







>







703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
# Source files that go into making shell.c
SHELL_SRC = \
	$(TOP)/src/shell.c.in \
        $(TOP)/ext/misc/appendvfs.c \
	$(TOP)/ext/misc/shathree.c \
	$(TOP)/ext/misc/fileio.c \
	$(TOP)/ext/misc/completion.c \
        $(TOP)/ext/misc/bindvtab.c \
	$(TOP)/ext/misc/sqlar.c \
	$(TOP)/ext/expert/sqlite3expert.c \
	$(TOP)/ext/expert/sqlite3expert.h \
	$(TOP)/ext/misc/zipfile.c \
        $(TOP)/src/test_windirent.c

shell.c:	$(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
Changes to src/shell.c.in.
936
937
938
939
940
941
942

943
944
945
946
947
948
949
INCLUDE test_windirent.c
#define dirent DIRENT
#endif
INCLUDE ../ext/misc/shathree.c
INCLUDE ../ext/misc/fileio.c
INCLUDE ../ext/misc/completion.c
INCLUDE ../ext/misc/appendvfs.c

#ifdef SQLITE_HAVE_ZLIB
INCLUDE ../ext/misc/zipfile.c
INCLUDE ../ext/misc/sqlar.c
#endif
INCLUDE ../ext/expert/sqlite3expert.h
INCLUDE ../ext/expert/sqlite3expert.c








>







936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
INCLUDE test_windirent.c
#define dirent DIRENT
#endif
INCLUDE ../ext/misc/shathree.c
INCLUDE ../ext/misc/fileio.c
INCLUDE ../ext/misc/completion.c
INCLUDE ../ext/misc/appendvfs.c
INCLUDE ../ext/misc/bindvtab.c
#ifdef SQLITE_HAVE_ZLIB
INCLUDE ../ext/misc/zipfile.c
INCLUDE ../ext/misc/sqlar.c
#endif
INCLUDE ../ext/expert/sqlite3expert.h
INCLUDE ../ext/expert/sqlite3expert.c

3003
3004
3005
3006
3007
3008
3009

3010
3011
3012
3013
3014
3015
3016
        /* If the shell is currently in ".explain" mode, gather the extra
        ** data required to add indents to the output.*/
        if( pArg->cMode==MODE_Explain ){
          explain_data_prepare(pArg, pStmt);
        }
      }


      exec_prepared_stmt(pArg, pStmt);
      explain_data_delete(pArg);
      eqp_render(pArg);

      /* print usage stats if stats on */
      if( pArg && pArg->statsOn ){
        display_stats(db, pArg, 0);







>







3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
        /* If the shell is currently in ".explain" mode, gather the extra
        ** data required to add indents to the output.*/
        if( pArg->cMode==MODE_Explain ){
          explain_data_prepare(pArg, pStmt);
        }
      }

      shell_bindings_apply(pStmt);
      exec_prepared_stmt(pArg, pStmt);
      explain_data_delete(pArg);
      eqp_render(pArg);

      /* print usage stats if stats on */
      if( pArg && pArg->statsOn ){
        display_stats(db, pArg, 0);
3402
3403
3404
3405
3406
3407
3408

3409
3410
3411
3412
3413
3414
3415
  "                          Add --indent for pretty-printing\n"
  ".selftest ?--init?     Run tests defined in the SELFTEST table\n"
  ".separator COL ?ROW?   Change the column separator and optionally the row\n"
  "                         separator for both the output mode and .import\n"
#if defined(SQLITE_ENABLE_SESSION)
  ".session CMD ...       Create or control sessions\n"
#endif

  ".sha3sum ?OPTIONS...?  Compute a SHA3 hash of database content\n"
#ifndef SQLITE_NOHAVE_SYSTEM
  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
#endif
  ".show                  Show the current values for various settings\n"
  ".stats ?on|off?        Show stats or turn stats on or off\n"
#ifndef SQLITE_NOHAVE_SYSTEM







>







3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
  "                          Add --indent for pretty-printing\n"
  ".selftest ?--init?     Run tests defined in the SELFTEST table\n"
  ".separator COL ?ROW?   Change the column separator and optionally the row\n"
  "                         separator for both the output mode and .import\n"
#if defined(SQLITE_ENABLE_SESSION)
  ".session CMD ...       Create or control sessions\n"
#endif
  ".set KEY=VALUE         Set bind parameter KEY to be string VALUE\n"
  ".sha3sum ?OPTIONS...?  Compute a SHA3 hash of database content\n"
#ifndef SQLITE_NOHAVE_SYSTEM
  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
#endif
  ".show                  Show the current values for various settings\n"
  ".stats ?on|off?        Show stats or turn stats on or off\n"
#ifndef SQLITE_NOHAVE_SYSTEM
3614
3615
3616
3617
3618
3619
3620

3621
3622
3623
3624
3625
3626
3627
    }
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    sqlite3_enable_load_extension(p->db, 1);
#endif
    sqlite3_fileio_init(p->db, 0, 0);
    sqlite3_shathree_init(p->db, 0, 0);
    sqlite3_completion_init(p->db, 0, 0);

#ifdef SQLITE_HAVE_ZLIB
    sqlite3_zipfile_init(p->db, 0, 0);
    sqlite3_sqlar_init(p->db, 0, 0);
#endif
    sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
                            shellAddSchemaName, 0, 0);
    sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,







>







3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
    }
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    sqlite3_enable_load_extension(p->db, 1);
#endif
    sqlite3_fileio_init(p->db, 0, 0);
    sqlite3_shathree_init(p->db, 0, 0);
    sqlite3_completion_init(p->db, 0, 0);
    sqlite3_bindvtab_init(p->db, 0, 0);
#ifdef SQLITE_HAVE_ZLIB
    sqlite3_zipfile_init(p->db, 0, 0);
    sqlite3_sqlar_init(p->db, 0, 0);
#endif
    sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
                            shellAddSchemaName, 0, 0);
    sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
7143
7144
7145
7146
7147
7148
7149














7150
7151
7152
7153
7154
7155
7156
                       "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
    }
    if( nArg>=3 ){
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
                       "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
    }
  }else















  if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){
    const char *zLike = 0;   /* Which table to checksum. 0 means everything */
    int i;                   /* Loop counter */
    int bSchema = 0;         /* Also hash the schema */
    int bSeparate = 0;       /* Hash each table separately */
    int iSize = 224;         /* Hash algorithm to use */







>
>
>
>
>
>
>
>
>
>
>
>
>
>







7147
7148
7149
7150
7151
7152
7153
7154
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174
                       "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
    }
    if( nArg>=3 ){
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
                       "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
    }
  }else

  if( c=='s' && n==3 && strncmp(azArg[0],"set",3)==0 ){
    int x;
    if( nArg<2 ){
      raw_printf(stderr, "Usage: .set KEY=VALUE\n");
      rc = 1;
      goto meta_command_exit;
    }
    x = shell_bindings_new_text(azArg[1]);
    if( x ){
      utf8_printf(stderr, "Error: bad setting: %s\n", azArg[1]);
    }
  }else


  if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){
    const char *zLike = 0;   /* Which table to checksum. 0 means everything */
    int i;                   /* Loop counter */
    int bSchema = 0;         /* Also hash the schema */
    int bSeparate = 0;       /* Hash each table separately */
    int iSize = 224;         /* Hash algorithm to use */
8112
8113
8114
8115
8116
8117
8118

8119
8120
8121
8122
8123
8124
8125
  "   -append              append the database to the end of the file\n"
  "   -ascii               set output mode to 'ascii'\n"
  "   -bail                stop after hitting an error\n"
  "   -batch               force batch I/O\n"
  "   -column              set output mode to 'column'\n"
  "   -cmd COMMAND         run \"COMMAND\" before reading stdin\n"
  "   -csv                 set output mode to 'csv'\n"

  "   -echo                print commands before execution\n"
  "   -init FILENAME       read/process named file\n"
  "   -[no]header          turn headers on or off\n"
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
  "   -heap SIZE           Size of heap for memsys3 or memsys5\n"
#endif
  "   -help                show this message\n"







>







8130
8131
8132
8133
8134
8135
8136
8137
8138
8139
8140
8141
8142
8143
8144
  "   -append              append the database to the end of the file\n"
  "   -ascii               set output mode to 'ascii'\n"
  "   -bail                stop after hitting an error\n"
  "   -batch               force batch I/O\n"
  "   -column              set output mode to 'column'\n"
  "   -cmd COMMAND         run \"COMMAND\" before reading stdin\n"
  "   -csv                 set output mode to 'csv'\n"
  "   -Dkey=value          set shell binding variable \"key\" to \"value\"\n"
  "   -echo                print commands before execution\n"
  "   -init FILENAME       read/process named file\n"
  "   -[no]header          turn headers on or off\n"
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
  "   -heap SIZE           Size of heap for memsys3 or memsys5\n"
#endif
  "   -help                show this message\n"
8415
8416
8417
8418
8419
8420
8421






8422
8423
8424
8425
8426
8427
8428
      data.openMode = SHELL_OPEN_READONLY;
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
    }else if( strncmp(z, "-A",2)==0 ){
      /* All remaining command-line arguments are passed to the ".archive"
      ** command, so ignore them */
      break;
#endif






    }
  }
  verify_uninitialized();


#ifdef SQLITE_SHELL_INIT_PROC
  {







>
>
>
>
>
>







8434
8435
8436
8437
8438
8439
8440
8441
8442
8443
8444
8445
8446
8447
8448
8449
8450
8451
8452
8453
      data.openMode = SHELL_OPEN_READONLY;
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
    }else if( strncmp(z, "-A",2)==0 ){
      /* All remaining command-line arguments are passed to the ".archive"
      ** command, so ignore them */
      break;
#endif
    }else if( strncmp(z, "-D",2)==0 ){
      int x;
      x = shell_bindings_new_text(z+2);
      if( x ){
        utf8_printf(stderr, "Error: bad binding: %s\n", z);
      }
    }
  }
  verify_uninitialized();


#ifdef SQLITE_SHELL_INIT_PROC
  {
8611
8612
8613
8614
8615
8616
8617


8618
8619
8620
8621
8622
8623
8624
        arDotCommand(&data, argv+(i-1), argc-(i-1));
      }else{
        arDotCommand(&data, argv+i, argc-i);
      }
      readStdin = 0;
      break;
#endif


    }else{
      utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
      raw_printf(stderr,"Use -help for a list of options.\n");
      return 1;
    }
    data.cMode = data.mode;
  }







>
>







8636
8637
8638
8639
8640
8641
8642
8643
8644
8645
8646
8647
8648
8649
8650
8651
        arDotCommand(&data, argv+(i-1), argc-(i-1));
      }else{
        arDotCommand(&data, argv+i, argc-i);
      }
      readStdin = 0;
      break;
#endif
    }else if( strncmp(z, "-D", 2)==0 ){
      /* Noop */
    }else{
      utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
      raw_printf(stderr,"Use -help for a list of options.\n");
      return 1;
    }
    data.cMode = data.mode;
  }
8689
8690
8691
8692
8693
8694
8695

8696
8697
8698
8699
8700
8701
8702
8703
8704
  set_table_name(&data, 0);
  if( data.db ){
    session_close_all(&data);
    sqlite3_close(data.db);
  }
  sqlite3_free(data.zFreeOnClose);
  find_home_dir(1);

  output_reset(&data);
  data.doXdgOpen = 0;
  clearTempFile(&data);
#if !SQLITE_SHELL_IS_UTF8
  for(i=0; i<argc; i++) free(argv[i]);
  free(argv);
#endif
  return rc;
}







>









8716
8717
8718
8719
8720
8721
8722
8723
8724
8725
8726
8727
8728
8729
8730
8731
8732
  set_table_name(&data, 0);
  if( data.db ){
    session_close_all(&data);
    sqlite3_close(data.db);
  }
  sqlite3_free(data.zFreeOnClose);
  find_home_dir(1);
  shell_bindings_clear();
  output_reset(&data);
  data.doXdgOpen = 0;
  clearTempFile(&data);
#if !SQLITE_SHELL_IS_UTF8
  for(i=0; i<argc; i++) free(argv[i]);
  free(argv);
#endif
  return rc;
}