]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
CLI resource management applied to about 30% of shell source. A few minor flaws fixed...
authorlarrybr <larrybr@noemail.net>
Fri, 12 May 2023 21:21:37 +0000 (21:21 +0000)
committerlarrybr <larrybr@noemail.net>
Fri, 12 May 2023 21:21:37 +0000 (21:21 +0000)
FossilOrigin-Name: ce25a07950e10e5f0c33f179f9b7d307a73b23ad859b5a97e5c6d7bc9e68b254

1  2  3 
manifest
manifest.uuid
src/resmanage.c
src/resmanage.h
src/shell.c.in

diff --cc manifest
index abc358978619032e5fda21ea73a6453e5b17aa94,b708b2f95c871ea775cfad5731762711a375d201,be8887dde618ebfc9e0f99ad5c71344217702b06..9b21651f1032b63f6d6c087910113d751c22c417
+++ b/manifest
@@@@ -1,5 -1,5 -1,5 +1,5 @@@@
-  C More\sCLI\sresource\smanager\suse.\sCatch\smore\sOOMs.\sEliminate\ssome\sopportunities\sto\slose\sresources\sunder\sOOM\sconditions.\sConform\sto\scoding\sguidelines.
-  D 2023-05-11T21:47:01.654
 - C Make\sthe\sregexp\sextension\smore\srobust\sagainst\sOOM\serrors\sduring\scompilation\nof\sthe\srecognizer\sengine.\n[forum:/forumpost/f50aecd5e8|Forum\spost\sf50aecd5e8].
 - D 2023-05-12T15:45:34.949
  -C Ensure\sthe\s_O_U16TEXT\sis\sdefined\sfor\sWindows\sbuilds\sof\sthe\sCLI.\n[forum:/forumpost/c80aa942dc6bf2|Forum\spost\sc80aa942dc6bf2].
  -D 2023-05-12T13:20:57.273
+++C CLI\sresource\smanagement\sapplied\sto\sabout\s30%\sof\sshell\ssource.\sA\sfew\sminor\sflaws\sfixed.\sComments\sbegin\sto\sdescribe\sOOM\sresponses.
+++D 2023-05-12T21:21:37.123
   F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
   F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
   F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@@@ -38,10 -38,8 -38,8 +38,10 @@@@ F configure.ac 510be9293c7efca69c0cc7f4
   F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
   F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
   F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
-  F doc/lemon.html efc0cd2345d66905505d98f862e1c571512def0ceb5b016cb658fd4918eb76a3
+  F doc/lemon.html d2862dbef72496e87f7996f37e814b146848190a742c12161d13fd15346051b0
   F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
 ++F doc/shell_extend.html c2ce1584bd976613c984a0b7ea4680ef2d2c0ab0642540d730e0a899648e2294
 ++F doc/tcl_extension_intro.md 216e29662703881e25c857875d6b2b3cba0dfd93c1f718ec27a3bb79b0049066
   F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
   F doc/vdbesort-memory.md 4da2639c14cd24a31e0af694b1a8dd37eaf277aff3867e9a8cc14046bc49df56
   F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
@@@@ -637,13 -633,10 -633,10 +637,13 @@@@ F src/pragma.h e690a356c18e98414d2e870e
   F src/prepare.c 6350675966bd0e7ac3a464af9dbfe26db6f0d4237f4e1f1acdb17b12ad371e6e
   F src/printf.c b9320cdbeca0b336c3f139fd36dd121e4167dd62b35fbe9ccaa9bab44c0af38d
   F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
-  F src/resmanage.c eecf8c4f7584d994e64d24a359b404710b198b34b6a00392f1c8b55f7cffa23f
-  F src/resmanage.h b5bf691153bb083386c526a3f834905cf9d9e0dc182d1c48e5c5e06527b40ab1
+++F src/resmanage.c e013c6a7703cfa11db74fd6269e9cecd5eb5ae371c3702bff0ddd1205e5a555a
+++F src/resmanage.h 4f4c0359cee4b3cdfff404851c5a877dfdd075ffdc8206c289fc05ea39a9c685
   F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032
   F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
   F src/select.c 12aa3168be4ff175702fe0ebeaf544312be22d275d378a28e7b2fad32d552d36
-  F src/shell.c.in 33598a4967aefba67ce3309fba6a612846e1ef5c3237b24d7a5ddc47c1888e48
 - F src/shell.c.in 1e18312f58d365042036fc9d19dcef416074f783702b168f07814332c2268ee0
  -F src/shell.c.in f2878df634b9d13ef7944f0d2d516d0b1abaf69302c26b4a8f1878b8be9f8411
+++F src/shell.c.in 924a3467c33c4cc6211c1f35d534f57f88d0e79005370982aeb2428d0951d6f0
 ++F src/shext_linkage.h 27dcf7624df05b2a7a6d367834339a6db3636f3035157f641f7db2ec499f8f6d
   F src/sqlite.h.in 27ca1d4b2eda8feee468af5735182390e8fe4696522751eec0136d17323201ad
   F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
   F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
@@@@ -2079,8 -2068,8 -2068,8 +2079,8 @@@@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a9
   F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
   F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
   F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-  P 0f55868e2c51775eaa717564f220acf6ddb2094d358d2011e6736f033e77d8dc 607cfb5bc5c0fb8b789944c2326cfdebf0629e45fbf0a61dd5f667ed685a1bbe
-  R 79d40353dac451fd08d6986e8e615333
 - P ab3797e844c97fed344b36f30cfb788aca9e0d68c574fb833712219eb712db44
 - R 273fa6b9f32e4223b5b45d8fc6394dc6
  -P 48139fb904de4b7b383e7f8c29bed83ad878eb22b1dd773c366a0aee74613d23
  -R 48448dc19b809c692b0d7c49b41acf2c
 --U drh
 - Z f78e0028467b93abd16e9ed3e77ee0f5
  -Z 99702f4eff9217b484a47a30f0a1c45c
+++P efdcf1093b4a327da36b5854cff32a8244244302a5f979859c1398e8d191fc6b 0772ddf56713d013cd1bd44f9c75977ca14f852e3a8f038b0a6b9814f6519d79 504effa89b48c0dc6cd12b3eaf6017be3f32017c601af17759a3cc185346d868
+++R 54bc1318f5a495f2da0644115fe872c7
 ++U larrybr
-  Z 44139e30849c6cbe0b94cb231c0378c9
+++Z d6d73699c601b55c7b4dec78c2a1df9f
   # Remove this line to create a well-formed Fossil manifest.
diff --cc manifest.uuid
index b6d0f98ef1d2b17b6b058a8b4e652d16356f398a,0bfa56a9685544efae6c699f99248b955431348f,6425bb986f866d7c65aabda036fe82f3c32109c2..6f5fcbf80b1fc1b3ff4dcf4f2cfcddd9aab4b40f
@@@@ -1,1 -1,1 -1,1 +1,1 @@@@
-  efdcf1093b4a327da36b5854cff32a8244244302a5f979859c1398e8d191fc6b
 - 0772ddf56713d013cd1bd44f9c75977ca14f852e3a8f038b0a6b9814f6519d79
  -504effa89b48c0dc6cd12b3eaf6017be3f32017c601af17759a3cc185346d868
+++ce25a07950e10e5f0c33f179f9b7d307a73b23ad859b5a97e5c6d7bc9e68b254
diff --cc src/resmanage.c
index 92d1b43fd811235554130eacb914dc29eb3430a4,0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b4ae2aecf09f43df3d77908f12756c4f4873c013
mode 100644,000000,000000..100644
--- /dev/null
--- /dev/null
@@@@ -1,294 -1,0 -1,0 +1,302 @@@@
-    if( z!=0 ) res_hold(z, FRK_Malloc);
 ++/*
 ++** 2023 May 8
 ++**
 ++** 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 resource management package, interface
 ++** and function of which is described in resmanage.h .
 ++*/
 ++
 ++#include <stdlib.h>
 ++#include <stdio.h>
 ++
 ++#include <assert.h>
 ++#include "resmanage.h"
 ++
 ++/* Track how to free various held resources. */
 ++typedef enum FreeableResourceKind {
 ++  FRK_Malloc = 0, FRK_DbConn = 1, FRK_DbStmt = 2,
 ++  FRK_DbMem = 3, FRK_File = 4,
 ++#if (!defined(_WIN32) && !defined(WIN32)) || !SQLITE_OS_WINRT
 ++  FRK_Pipe,
 ++#endif
 ++#ifdef SHELL_MANAGE_TEXT
 ++  FRK_Text,
 ++#endif
 ++  FRK_CustomBase /* series of values for custom freers */
 ++} FreeableResourceKind;
 ++
 ++#if defined(_WIN32) || defined(WIN32)
 ++# if !SQLITE_OS_WINRT
 ++#  include <io.h>
 ++#  include <fcntl.h>
 ++#  undef pclose
 ++#  define pclose _pclose
 ++# endif
 ++#else
 ++extern int pclose(FILE*);
 ++#endif
 ++
 ++typedef struct ResourceHeld {
 ++  union {
 ++    void *p_any;
 ++    void *p_malloced;
 ++    sqlite3 *p_conn;
 ++    sqlite3_stmt *p_stmt;
 ++    void *p_s3mem;
 ++    FILE *p_stream;
 ++#ifdef SHELL_MANAGE_TEXT
 ++    ShellText *p_text;
 ++#endif
 ++  } held;
 ++  FreeableResourceKind frk;
 ++} ResourceHeld;
 ++
 ++/* The held-resource stack. This is for single-threaded use only. */
 ++static ResourceHeld *pResHold = 0;
 ++static ResourceCount numResHold = 0;
 ++static ResourceCount numResAlloc = 0;
 ++
 ++/* A small set of custom freers. It is linearly searched, used for
 ++** layered heap-allocated (and other-allocated) data structures, so
 ++** tends to have use limited to where slow things are happening.
 ++*/
 ++static ResourceCount numCustom = 0; /* number of the set */
 ++static ResourceCount numCustomAlloc = 0; /* allocated space */
 ++typedef void (*FreerFunction)(void *);
 ++static FreerFunction *aCustomFreers = 0; /* content of set */
 ++
 ++const char *resmanage_oom_message = "out of memory, aborting";
 ++
 ++/* Info recorded in support of quit_moan(...) and stack-ripping */
 ++static ResourceMark exit_mark = 0;
 ++#ifndef SHELL_OMIT_LONGJMP
 ++static jmp_buf *p_exit_ripper = 0;
 ++#endif
 ++
 ++/* Current position of the held-resource stack */
 ++ResourceMark holder_mark(){
 ++  return numResHold;
 ++}
 ++
 ++/* Strip resource stack then strip call stack (or exit.) */
 ++void quit_moan(const char *zMoan, int errCode){
 ++  if( zMoan ){
 ++    fprintf(stderr, "Quitting due to %s, freeing %d resources.\n",
 ++            zMoan, numResHold);
 ++  }
 ++  holder_free(exit_mark);
 ++#ifndef SHELL_OMIT_LONGJMP
 ++  if( p_exit_ripper!=0 ){
 ++    longjmp(*p_exit_ripper, errCode);
 ++  } else
 ++#endif
 ++    exit(errCode);
 ++}
 ++
 ++/* Free a single resource item. (ignorant of stack) */
 ++static void free_rk( ResourceHeld *pRH ){
 ++  if( pRH->held.p_any == 0 ) return;
 ++  switch( pRH->frk ){
 ++  case FRK_Malloc:
 ++    free(pRH->held.p_malloced);
 ++    break;
 ++  case FRK_DbConn:
 ++    sqlite3_close_v2(pRH->held.p_conn);
 ++    break;
 ++  case FRK_DbStmt:
 ++    sqlite3_clear_bindings(pRH->held.p_stmt);
 ++    sqlite3_finalize(pRH->held.p_stmt);
 ++    break;
 ++  case FRK_DbMem:
 ++    sqlite3_free(pRH->held.p_s3mem);
 ++    break;
 ++  case FRK_File:
 ++    fclose(pRH->held.p_stream);
 ++    break;
 ++#if (!defined(_WIN32) && !defined(WIN32)) || !SQLITE_OS_WINRT
 ++  case FRK_Pipe:
 ++    pclose(pRH->held.p_stream);
 ++    break;
 ++#endif
 ++#ifdef SHELL_MANAGE_TEXT
 ++  case FRK_Text:
 ++    freeText(pRH->held.p_text);
 ++    break;
 ++#endif
 ++  default:
 ++    {
 ++      int ck = pRH->frk - FRK_CustomBase;
 ++      assert(ck>=0);
 ++      if( ck < numCustom ){
 ++        aCustomFreers[ck]( pRH->held.p_any );
 ++      }
 ++    }
 ++  }
 ++  pRH->held.p_any = 0;
 ++}
 ++
 ++/* Take back a held resource pointer, leaving held as NULL. (no-op) */
 ++void* take_held(ResourceMark mark, ResourceCount offset){
 ++  return swap_held(mark,offset,0);
 ++}
 ++
 ++/* Swap a held resource pointer for a new one. */
 ++void* swap_held(ResourceMark mark, ResourceCount offset, void *pNew){
 ++  ResourceCount rix = mark + offset;
 ++  assert(rix < numResHold && numResHold > 0);
 ++  if( rix < numResHold && numResHold > 0 ){
 ++    void *rv = pResHold[rix].held.p_any;
 ++    pResHold[rix].held.p_any = pNew;
 ++    return rv;
 ++  }else return 0;
 ++}
 ++
 ++/* Reserve room for at least count additional holders, with no chance
 ++** of an OOM abrupt exit. This is used internally only by this package.
 ++** The return is either 1 for success, or 0 indicating an OOM failure.
 ++ */
 ++static int more_holders_try(ResourceCount count){
 ++  ResourceHeld *prh;
 ++  ResourceCount newAlloc = numResHold + count;
 ++  if( newAlloc < numResHold ) return 0; /* Overflow, sorry. */
 ++  if( newAlloc <= numResAlloc ) return 1;
 ++  prh = (ResourceHeld*)realloc(pResHold, newAlloc*sizeof(ResourceHeld));
 ++  if( prh == 0 ) return 0;
 ++  pResHold = prh;
 ++  numResAlloc = newAlloc;
 ++  return 1;
 ++}
 ++
 ++/* Shared resource-stack pushing code */
 ++static void res_hold(void *pv, FreeableResourceKind frk){
 ++  ResourceHeld rh = { pv, frk };
 ++  if( numResHold == numResAlloc ){
 ++    ResourceCount nrn = (ResourceCount)((numResAlloc>>2) + 5);
 ++    if( !more_holders_try(nrn) ){
 ++      free_rk(&rh);
 ++      quit_moan(resmanage_oom_message,1);
 ++    }
 ++  }
 ++  pResHold[numResHold++] = rh;
 ++}
 ++
 ++/* Hold a NULL (Assure swap_held() cannot fail.) */
 ++void more_holders(ResourceCount more){
 ++  if( !more_holders_try(more) ) quit_moan(resmanage_oom_message,1);
 ++}
 ++
 ++/* Hold anything in the malloc() heap */
 ++void* mmem_holder(void *pm){
 ++  res_hold(pm, FRK_Malloc);
 ++  return pm;
 ++}
 ++/* Hold a C string in the malloc() heap */
 ++char* mstr_holder(char *z){
-    if( z!=0 ) res_hold(z, FRK_DbMem);
+++  res_hold(z, FRK_Malloc);
 ++  return z;
 ++}
 ++/* Hold a C string in the SQLite heap */
 ++char* sstr_holder(char *z){
-    if( pf!=0 ) res_hold(pf, FRK_File);
+++  res_hold(z, FRK_DbMem);
 ++  return z;
 ++}
 ++/* Hold an open C runtime FILE */
 ++void file_holder(FILE *pf){
-    if( pp!=0 ) res_hold(pp, FRK_Pipe);
+++  res_hold(pf, FRK_File);
 ++}
 ++#if (!defined(_WIN32) && !defined(WIN32)) || !SQLITE_OS_WINRT
 ++/* Hold an open C runtime pipe */
 ++void pipe_holder(FILE *pp){
-        numCustomAlloc = ncf;
+++  res_hold(pp, FRK_Pipe);
 ++}
 ++#endif
 ++#ifdef SHELL_MANAGE_TEXT
 ++/* a reference to a ShellText object, (storage for which not managed) */
 ++static void text_holder(ShellText *pt){
 ++  res_hold(pt, FRK_Text);
 ++}
 ++#endif
 ++/* Hold anything together with arbitrary freeing function */
 ++void* any_holder(void *pm, void (*its_freer)(void*)){
 ++  int i = 0;
 ++  while( i < numCustom ){
 ++    if( its_freer == aCustomFreers[i] ) break;
 ++    ++i;
 ++  }
 ++  if( i == numCustom ){
 ++    size_t ncf = numCustom + 2;
 ++    FreerFunction *pcf;
 ++    pcf = (FreerFunction *)realloc(aCustomFreers, ncf*sizeof(FreerFunction));
 ++    if( pcf!=0 ){
-  /* Free all held resources in excess of given resource stack mark. */
-  void holder_free(ResourceMark mark){
+++      assert(ncf < (1<<16));
+++      numCustomAlloc = (ResourceCount)ncf;
 ++      aCustomFreers = pcf;
 ++      aCustomFreers[numCustom++] = its_freer;
 ++    }else{
 ++      quit_moan(resmanage_oom_message,1);
 ++    }
 ++  }
 ++  res_hold(pm, i + FRK_CustomBase);
 ++  return pm;
 ++}
 ++/* Hold some SQLite-allocated memory */
 ++void* smem_holder(void *pm){
 ++  res_hold(pm, FRK_DbMem);
 ++  return pm;
 ++}
 ++/* Hold a SQLite database "connection" */
 ++void conn_holder(sqlite3 *pdb){
 ++  res_hold(pdb, FRK_DbConn);
 ++}
 ++/* Hold a SQLite prepared statement */
 ++void stmt_holder(sqlite3_stmt *pstmt){
 ++  res_hold(pstmt, FRK_DbStmt);
 ++}
 ++
-      free_rk(&pResHold[--numResHold]);
+++/* Free all held resources in excess of given resource stack mark,
+++** then return how many needed freeing. */
+++int holder_free(ResourceMark mark){
+++  int rv = 0;
 ++  while( numResHold > mark ){
+++    --numResHold;
+++    if( pResHold[numResHold].held.p_any!=0 ){
+++      free_rk(&pResHold[numResHold]);
+++      ++rv;
+++    }
 ++  }
 ++  if( mark==0 ){
 ++    if( numResAlloc>0 ){
 ++      free(pResHold);
 ++      pResHold = 0;
 ++      numResAlloc = 0;
 ++    }
 ++    if( numCustomAlloc>0 ){
 ++      free(aCustomFreers);
 ++      aCustomFreers = 0;
 ++      numCustom = 0;
 ++      numCustomAlloc = 0;
 ++    }
 ++  }
+++  return rv;
 ++}
 ++
 ++#ifndef SHELL_OMIT_LONGJMP
 ++/* Record a resource stack and call stack rip-to position */
 ++void register_exit_ripper(jmp_buf *pjb, ResourceMark rip_mark){
 ++  exit_mark = rip_mark;
 ++  p_exit_ripper = pjb;
 ++}
 ++/* Undo register_exit_ripper effect, back to default state. */
 ++void forget_exit_ripper(jmp_buf *pjb){
 ++  exit_mark = 0;
 ++  assert(p_exit_ripper == pjb);
 ++  p_exit_ripper = 0;
 ++}
 ++#endif
diff --cc src/resmanage.h
index 5ee75178e9aa19fa6279656880b35352fa8b4859,0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bb276de61140c0c4b6e086c0c3188b02f5c135a3
mode 100644,000000,000000..100644
--- /dev/null
--- /dev/null
@@@@ -1,131 -1,0 -1,0 +1,132 @@@@
-  /* Free all held resources in excess of given resource stack mark. */
-  extern void holder_free(ResourceMark mark);
 ++/*
 ++** 2023 May 8
 ++**
 ++** 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 declares the interface of a simple resource management package
 ++** which supports freeing of resources upon an abrupt, program-initiated
 ++** termination of a function from somewhere in a call tree. The package is
 ++** designed to be used with setjmp()/longjmp() to effect a pattern similar
 ++** to the try/throw/catch available in some programming languages. (But see
 ++** below regarding usage when the setmp()/longjmp() pair is unavailable.)
 ++**
 ++** The general scheme is that routines whose pre-return code might be
 ++** bypassed, thereby leaking resources, do not rely on pre-return code
 ++** to release locally held resources. Instead, they give ownership of
 ++** such resources to this package, via xxxx_holder(...) calls, and use
 ++** its holder_mark() and holder_free(...) functions to release locally
 ++** acquired resources.
 ++**
 ++** For environments where setmp()/longjmp() are unavailable, (indicated by
 ++** SHELL_OMIT_LONGJMP defined), the package substitutes a process exit for
 ++** resumption of execution at a chosen code location. The resources in the
 ++** package's held resource stack are still released. And the ability to
 ++** free locally acquired resources as functions return is retained. This
 ++** can simplify early function exit logic, but a body of code relying on
 ++** process exit to ease error handling is unsuitable for use as a called
 ++** routine within a larger application. That use is most of the reason for
 ++** this package's existence.
 ++*/
 ++
 ++#ifndef RES_MANAGE_H
 ++# define RES_MANAGE_H
 ++
 ++#ifndef SHELL_OMIT_LONGJMP
 ++# include <setjmp.h>
 ++# define RIP_STATE(jb) jmp_buf jb
 ++# define RIP_TO_HERE(jb) setjmp(jb)
 ++#else
 ++# define RIP_STATE(jb)
 ++# define RIP_TO_HERE(jb) 0
 ++#endif
 ++#include <stdio.h>
 ++#include <assert.h>
 ++
 ++#ifdef __cplusplus
 ++extern "C" {
 ++#endif
 ++
 ++#include "sqlite3.h"
 ++
 ++/* Type used for marking positions within a held-resource stack */
 ++typedef unsigned short ResourceMark;
 ++typedef unsigned short ResourceCount;
 ++
 ++/* Current position of the held-resource stack */
 ++extern ResourceMark holder_mark();
 ++
 ++/* Assure no allocation failure for some more xxx_holder() calls.
 ++** Note that this call may fail with an OOM abrupt exit. */
 ++extern void more_holders(ResourceCount more);
 ++
 ++/* Routines for holding resources on held-resource stack together
 ++** with enough information for them to be freed by this package.
 ++*/
 ++/* anything together with arbitrary freeing function */
 ++extern void* any_holder(void *pm, void (*its_freer)(void*));
 ++/* anything in the malloc() heap */
 ++extern void* mmem_holder(void *pm);
 ++/* a C string in the malloc() heap */
 ++extern char* mstr_holder(char *z);
 ++/* some SQLite-allocated memory */
 ++extern void* smem_holder(void *pm);
 ++/* a C string in the SQLite heap */
 ++extern char* sstr_holder(char *z);
 ++/* a SQLite database "connection" */
 ++extern void conn_holder(sqlite3 *pdb);
 ++/* a SQLite prepared statement */
 ++extern void stmt_holder(sqlite3_stmt *pstmt);
 ++/* an open C runtime FILE */
 ++extern void file_holder(FILE *);
 ++#if (!defined(_WIN32) && !defined(WIN32)) || !SQLITE_OS_WINRT
 ++/* an open C runtime pipe */
 ++extern void pipe_holder(FILE *);
 ++#endif
 ++#ifdef SHELL_MANAGE_TEXT
 ++/* a reference to a ShellText object, (storage for which not managed) */
 ++static void text_holder(ShellText *);
 ++#endif
 ++
 ++/* Take back a held resource pointer, leaving held as NULL. (no-op) */
 ++extern void* take_held(ResourceMark mark, ResourceCount offset);
 ++
 ++/* Swap a held resource pointer for a new one. */
 ++extern void* swap_held(ResourceMark mark, ResourceCount offset, void *pNew);
 ++
+++/* Free all held resources in excess of given resource stack mark.
+++** Return count of number actually freed (rather than being 0.) */
+++extern int holder_free(ResourceMark mark);
 ++
 ++#ifndef SHELL_OMIT_LONGJMP
 ++/* Remember a longjmp() destination together with a resource stack
 ++** mark which determines how far the resource stack may be stripped.
 ++** This info determines how far the execution and resource stacks
 ++** will be stripped back should quit_moan(...) be called.
 ++*/
 ++extern void register_exit_ripper(jmp_buf *pjb, ResourceMark rip_mark);
 ++/* Forget whatever register_exit_ripper() has been recorded. */
 ++extern void forget_exit_ripper(jmp_buf *pjb);
 ++#else
 ++#define register_exit_ripper(jb, rm)
 ++#define forget_exit_ripper()
 ++#endif
 ++
 ++/* Strip resource stack and execute previously registered longjmp() as
 ++** previously prepared by register_exit_ripper() call. Or, if no such
 ++** prep done (or possible), strip the whole stack and exit the process.
 ++*/
 ++extern void quit_moan(const char *zMoan, int errCode);
 ++
 ++/* What the complaint will be for OOM failures and abrupt exits. */
 ++extern const char *resmanage_oom_message;
 ++
 ++#ifdef __cplusplus
 ++}  /* End of the 'extern "C"' block */
 ++#endif
 ++#endif /* RES_MANAGE_H */
diff --cc src/shell.c.in
index 9cca5e31d469889204c3952fa264f034a41192ab,ccaed896d92b818254fcb5bfae0f4f8a79b126c9,b29e4029133ca05656472c9057e8cf01011d6cc0..72496ae665710145b7d310af9366fca46b57ae7c
@@@@ -462,6 -431,6 -431,6 +462,12 @@@@ static void endTimer(void)
   */
   #define UNUSED_PARAMETER(x) (void)(x)
   
+++#ifdef SQLITE_DEBUG
+++# define CHECK_RETURN_EQUAL(val, func) assert((val)==(func))
+++#else
+++# define CHECK_RETURN_EQUAL(val, func) func
+++#endif
+++
   /*
   ** Number of elements in an array
   */
@@@@ -506,10 -475,9 -475,9 +512,13 @@@@ static int stdout_is_console = 1
   ** by the SIGINT handler to interrupt database processing.
   */
   static sqlite3 *globalDb = 0;
+++/*
+++** Mutex used to access *globalDb from main thread or ^C handler.
+++*/
 ++static sqlite3_mutex *pGlobalDbLock = 0;
   
   /*
 --** True if an interrupt (Control-C) has been received.
 ++** Greater than 0 if an interrupt (Control-C) has been received.
   */
   static volatile int seenInterrupt = 0;
   
@@@@ -2033,16 -1619,16 -1619,16 +2046,18 @@@@ static void shellLog(void *pArg, int iE
   ** SQL function:  shell_putsnl(X)
   **
   ** Write the text X to the screen (or whatever output is being directed)
---** adding a newline at the end, and then return X.
+++** adding a newline at the end, and then return X. If X is the NULL
+++** equivalent (due to OOM or otherwise), it acts as an empty string.
   */
   static void shellPutsFunc(
     sqlite3_context *pCtx,
     int nVal,
     sqlite3_value **apVal
   ){
 --  ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
 ++  ShellExState *psx = (ShellExState*)sqlite3_user_data(pCtx);
+++  const unsigned char *s = sqlite3_value_text(apVal[0]);
     (void)nVal;
-    utf8_printf(ISS(psx)->out, "%s\n", sqlite3_value_text(apVal[0]));
 --  utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
+++  utf8_printf(ISS(psx)->out, "%s\n", (s!=0)?(char*)s:"");
     sqlite3_result_value(pCtx, apVal[0]);
   }
   
@@@@ -2068,32 -1645,12 -1645,12 +2083,32 @@@@ static int failIfSafeMode
       va_list ap;
       char *zMsg;
       va_start(ap, zErrMsg);
---    zMsg = sqlite3_vmprintf(zErrMsg, ap);
+++    shell_check_oom(zMsg = sqlite3_vmprintf(zErrMsg, ap));
       va_end(ap);
 --    raw_printf(stderr, "line %d: ", p->lineno);
 --    utf8_printf(stderr, "%s\n", zMsg);
 --    exit(1);
 ++    raw_printf(STD_ERR, "line %d: ", ISS(psx)->pInSource->lineno);
 ++    utf8_printf(STD_ERR, "%s\n", zMsg);
 ++    sqlite3_free(zMsg);
 ++    psx->shellAbruptExit = 0x202;
 ++    return 1;
     }
 ++  return 0;
 ++}
 ++
 ++/*
 ++** Emit formatted output to shell's current output, possibly translated
 ++** for the legacy console on the Windows platform. This is exposed as
 ++** a helper for extensions so that they may share a common buffering
 ++** for FILE* output or share output capture when/if that is implemented.
 ++*/
 ++static void utf8_out_printf(ShellExState *p, const char *zFormat, ...){
 ++  va_list ap;
 ++  va_start(ap, zFormat);
 ++#if defined(_WIN32) || defined(WIN32)
 ++  vf_utf8_printf(ISS(p)->out, zFormat, ap);
 ++#else
 ++  vfprintf(ISS(p)->out, zFormat, ap);
 ++#endif
 ++  va_end(ap);
   }
   
   /*
@@@@ -2132,8 -1689,8 -1689,8 +2147,13 @@@@ static void editFunc
   
     if( argc==2 ){
       zEditor = (const char*)sqlite3_value_text(argv[1]);
+++    /* If that failed for OOM, just pretend it is not there. */
     }else{
       zEditor = getenv("VISUAL");
+++    /* Note that this code NOT threadsafe due to use of the getenv()
+++    ** result. Because the shell is single-threaded, this is fine.
+++    ** But if the CLI is called as a subroutine in a multi-threaded
+++    ** program, adjustments may have to be made. */
     }
     if( zEditor==0 ){
       sqlite3_result_error(context, "no editor for edit()", -1);
       return;
     }
     db = sqlite3_context_db_handle(context);
---  zTempFile = 0;
     sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, &zTempFile);
     if( zTempFile==0 ){
       sqlite3_uint64 r = 0;
       sqlite3_result_blob64(context, p, sz, sqlite3_free);
     }else{
       sqlite3_int64 i, j;
 --    if( hasCRNL ){
 --      /* If the original contains \r\n then do no conversions back to \n */
 --    }else{
 ++    if( !hasCRNL ){
         /* If the file did not originally contain \r\n then convert any new
         ** \r\n back into \n */
+ +      p[sz] = 0;
         for(i=j=0; i<sz; i++){
           if( p[i]=='\r' && p[i+1]=='\n' ) i++;
           p[j++] = p[i];
@@@@ -2238,97 -1798,19 -1797,19 +2258,100 @@@@ edit_func_end
   #endif /* SQLITE_NOHAVE_SYSTEM */
   
   /*
 --** Save or restore the current output mode
 ++** Save or restore the current output mode, partially per spec. (OM_STATE)
 ++*/
 ++typedef enum {
 ++  SWM_showHeader = 1, SWM_shellFlags = 2, SWM_mode = 4, SWM_cmOpts = 8,
 ++  SWM_colSeparator = 0x10, SWM_rowSeparator = 0x20, SWM_everything = 0x3F,
 ++  SWM_CountOf = 6
 ++} SaveWhatMode;
 ++
 ++/* This is available in most C89+ C compilers as offsetof(...), but since we
 ++ * cater to the most arcane C89-like compilers around, define it for sure:
 ++ */
 ++#define MEMBER_OFFSET(stype, member) ((size_t)&(((stype*)0)->member))
 ++#define MEMBER_SIZEOF(stype, member) (sizeof(((stype*)0)->member))
 ++static struct {
 ++  size_t offset;
 ++  size_t size;
 ++} outputModeCopy[] = {
 ++#define SS_MEMBER_COPY(mn) \
 ++  { MEMBER_OFFSET(ShellInState,mn), MEMBER_SIZEOF(ShellInState,mn) }
 ++  SS_MEMBER_COPY(showHeader), SS_MEMBER_COPY(shellFlgs),
 ++  SS_MEMBER_COPY(mode), SS_MEMBER_COPY(cmOpts),
 ++  SS_MEMBER_COPY(colSeparator), SS_MEMBER_COPY(rowSeparator)
 ++#undef SS_MEMBER_COPY
 ++};
 ++
-  /* Allocate a buffer, copy requested output mode data to it, and return it. */
+++/* Allocate a buffer, copy requested output mode data to it, and return it.
+++ * This never fails under OOM conditions. Instead, it returns 0.
+++ */
 ++static OutputModeSave *outputModeSave(ShellInState *psi, SaveWhatMode w){
 ++  u16 what = (u16)w;
 ++  int i, nAlloc = sizeof(what)+1, mask = 1;
 ++  char *pSaved = 0, *pFill;
 ++  for( i=0; i<SWM_CountOf; mask<<=1, ++i ){
 ++    if( (what & mask)!=0 ) nAlloc += (int)outputModeCopy[i].size;
 ++  }
 ++  assert(i==ArraySize(outputModeCopy));
 ++  pSaved = sqlite3_malloc(nAlloc);
 ++  if( pSaved==0 ) return 0;
 ++  *(u16 *)pSaved = what;
 ++  pFill = pSaved + sizeof(what);
 ++  for( mask=1, i=0; i<SWM_CountOf; mask<<=1, ++i ){
 ++    if( (what & mask)!=0 ){
 ++      size_t nb = outputModeCopy[i].size;
 ++      memcpy(pFill, ((char*)psi)+outputModeCopy[i].offset, nb);
 ++      pFill += nb;
 ++    }
 ++  }
 ++  *pFill = 0xA5;
 ++  return (OutputModeSave *)pSaved;
 ++}
 ++
 ++/* From a buffer returned by outputModeSave, restore output mode data.
 ++ * The buffer is freed and its pointer is invalidated.
 ++ * If called with some other buffer, results are undefined, likely bad.
 ++ */
 ++static void outputModeRestore(ShellInState *psi, OutputModeSave *pSaved){
 ++  sqlite3_uint64 nA = sqlite3_msize(pSaved);
 ++  u16 what = (nA>sizeof(what))? *((u16 *)pSaved) : 0;
 ++  int i, nAlloc = sizeof(what)+1, mask = 1;
 ++  char *pTake = (char *)pSaved + sizeof(what);
 ++  for( i=0; i<SWM_CountOf && nAlloc<nA; mask<<=1, ++i ){
 ++    if( (what & mask)!=0 ){
 ++      size_t nb = outputModeCopy[i].size;
 ++      memcpy(((char*)psi)+outputModeCopy[i].offset, pTake, nb);
 ++      pTake += nb;
 ++    }
 ++  }
 ++  assert(*pTake==0xA5);
 ++  sqlite3_free(pSaved);
 ++}
 ++
 ++/*
 ++** Save or restore the current output mode, in whole or in part.
+++** A save may abort on OOM.
   */
 --static void outputModePush(ShellState *p){
 --  p->modePrior = p->mode;
 --  p->priorShFlgs = p->shellFlgs;
 --  memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
 --  memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
 ++static void outputModePushSome(ShellInState *psi, SaveWhatMode w){
 ++  OutputModeSave *pOMS;
 ++  assert(psi->nSavedModes<MODE_STACK_MAX); /* Fail hard for this logic error. */
 ++  if( psi->nSavedModes>=MODE_STACK_MAX ) return;
 ++  pOMS = outputModeSave(psi, w);
 ++  shell_check_oom(pOMS);
 ++  psi->pModeStack[psi->nSavedModes++] = pOMS;
  +}
 - static void outputModePop(ShellState *p){
 -   p->mode = p->modePrior;
 -   p->shellFlgs = p->priorShFlgs;
 -   memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
 -   memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
 ++static void outputModePush(ShellInState *psi){
 ++  outputModePushSome(psi, SWM_everything);
 + }
  -static void outputModePop(ShellState *p){
  -  p->mode = p->modePrior;
  -  p->shellFlgs = p->priorShFlgs;
  -  memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
  -  memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
 ++static void outputModePop(ShellInState *p){
 ++  OutputModeSave *pOMS;
 ++  assert(p->nSavedModes>0); /* Should not be here unless something pushed. */
 ++  if( p->nSavedModes==0 ) return;
 ++  pOMS = p->pModeStack[--p->nSavedModes];
 ++  assert(pOMS!=0);
 ++  p->pModeStack[p->nSavedModes] = 0;
 ++  outputModeRestore(p, pOMS);
   }
   
   /*
@@@@ -2359,7 -1843,7 -1842,7 +2382,9 @@@@ static void output_hex_blob(FILE *out, 
   **
   ** Try to use zA and zB first.  If both of those are already found in z[]
   ** then make up some string and store it in the buffer zBuf.
+++** The length of this buffer must be no less than SHELL_QESC_GENLEN .
   */
+++#define SHELL_QESC_GENLEN 20
   static const char *unused_string(
     const char *z,                    /* Result must not appear anywhere in z */
     const char *zA, const char *zB,   /* Try these first */
     if( strstr(z, zA)==0 ) return zA;
     if( strstr(z, zB)==0 ) return zB;
     do{
---    sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
+++    sqlite3_snprintf(SHELL_QESC_GENLEN, zBuf,"(%s%u)", zA, i++);
     }while( strstr(z,zBuf)!=0 );
     return zBuf;
   }
@@@@ -2431,7 -1915,7 -1914,7 +2456,7 @@@@ static void output_quoted_escaped_strin
       const char *zCR = 0;
       int nNL = 0;
       int nCR = 0;
---    char zBuf1[20], zBuf2[20];
+++    char zBuf1[SHELL_QESC_GENLEN], zBuf2[SHELL_QESC_GENLEN];
       for(i=0; z[i]; i++){
         if( z[i]=='\n' ) nNL++;
         if( z[i]=='\r' ) nCR++;
@@@@ -2606,12 -2090,11 -2089,11 +2631,13 @@@@ static const char needCsvQuote[] = 
   ** the separator, which may or may not be a comma.  p->nullValue is
   ** the null value.  Strings are quoted if necessary.  The separator
   ** is only issued if bSep is true.
+++** This routine may abort under OOM conditions.
   */
 --static void output_csv(ShellState *p, const char *z, int bSep){
 --  FILE *out = p->out;
 ++static void output_csv(ShellExState *psx, const char *z, int bSep){
 ++  FILE *out = ISS(psx)->out;
 ++  char *zColSep = psx->zFieldSeparator;
     if( z==0 ){
 --    utf8_printf(out,"%s",p->nullValue);
 ++    utf8_printf(out,"%s",psx->zNullValue);
     }else{
       unsigned i;
       for(i=0; z[i]; i++){
   */
   static void interrupt_handler(int NotUsed){
     UNUSED_PARAMETER(NotUsed);
 --  if( ++seenInterrupt>1 ) exit(1);
 --  if( globalDb ) sqlite3_interrupt(globalDb);
 ++  if( ++seenInterrupt>1 ){
-      sqlite3_mutex_free(pGlobalDbLock);
 ++    exit(1);
 ++  }
 ++  if( globalDb ){
-      sqlite3_mutex_enter(pGlobalDbLock);
-      sqlite3_interrupt(globalDb);
-      sqlite3_mutex_leave(pGlobalDbLock);
+++    int itry = 0;
+++    while( itry < 10 ){
+++      if( sqlite3_mutex_try(pGlobalDbLock)==SQLITE_OK ){
+++        sqlite3_interrupt(globalDb);
+++        sqlite3_mutex_leave(pGlobalDbLock);
+++        return;
+++      }else{
+++        sqlite3_sleep(50);
+++        ++itry;
+++      }
+++    }
+++    /* Apparently, no polite interruption is working. (Something is
+++    ** very busy under mutex protection.) So quit altother. */
+++    exit(1);
 ++  }
   }
   
   #if (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
@@@@ -2780,11 -2253,11 -2252,11 +2816,11 @@@@ static void printSchemaLine(FILE *out, 
     if( zTail[0]==';' && (strstr(z, "/*")!=0 || strstr(z,"--")!=0) ){
       const char *zOrig = z;
       static const char *azTerm[] = { "", "*/", "\n" };
---    int i;
+++    int i, rc;
       for(i=0; i<ArraySize(azTerm); i++){
---      char *zNew = sqlite3_mprintf("%s%s;", zOrig, azTerm[i]);
+++      char *zNew = smprintf("%s%s;", zOrig, azTerm[i]);
         shell_check_oom(zNew);
---      if( sqlite3_complete(zNew) ){
+++      if( 1==(rc = sqlite3_complete(zNew)) ){
           size_t n = strlen(zNew);
           zNew[n-1] = 0;
           zToFree = zNew;
           break;
         }
         sqlite3_free(zNew);
+++      if( rc==SQLITE_NOMEM ) shell_out_of_memory();
       }
     }
     if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
@@@@ -2937,106 -2408,9 -2407,9 +2974,106 @@@@ static int progress_handler(void *pClie
   }
   #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
   
  -/*
  -** Print N dashes
  -*/
 ++/* For debugging or experimentation, the shell DB can be made file-based. */
 ++#ifndef SHELL_DB_FILE
 ++# define SHELL_DB_STORE ":memory:"
 ++#else
 ++# define SHELL_DB_STORE SHELL_STRINGIFY(SHELL_DB_FILE)
 ++#endif
 ++
 ++#define SHELL_DISP_SCHEMA "main"
 ++#define SHELL_DISP_TAB "ShellCommands"
 ++#define SHELL_AHELP_TAB "ShellAdHocHelp"
 ++#define SHELL_DISP_VIEW "ShellActiveCmds"
 ++#define SHELL_HELP_VIEW "ShellHelpedCmds"
 ++
 ++/*
 ++** Ensure dbShell exists and return SQLITE_OK,
 ++** or complain and return SQLITE_ERROR.
 ++*/
 ++static int ensure_shell_db(ShellExState *psx){
 ++  if( psx->dbShell!=0 ) return SQLITE_OK;
 ++  else{
 ++    int rc = sqlite3_open(SHELL_DB_STORE, &psx->dbShell);
 ++    if( rc!=SQLITE_OK ){
 ++      utf8_printf(STD_ERR, "Shell DB open failure: %s\n", sqlite3_errstr(rc));
 ++      return SQLITE_ERROR;
 ++    }
 ++#ifndef SQLITE_NOHAVE_SYSTEM
 ++    sqlite3_create_function(psx->dbShell, "edit", 1,
 ++                            SQLITE_UTF8, 0, editFunc, 0, 0);
 ++    sqlite3_create_function(psx->dbShell, "edit", 2,
 ++                            SQLITE_UTF8, 0, editFunc, 0, 0);
 ++#endif
 ++    return rc;
 ++  }
 ++}
 ++
 ++/* Tell whether the above-created table exists, return true iff exists. */
 ++static int dispatch_table_exists(sqlite3 *dbs){
 ++  return sqlite3_table_column_metadata
 ++    (dbs, SHELL_DISP_SCHEMA, SHELL_DISP_TAB, 0, 0, 0, 0, 0, 0)==SQLITE_OK;
 ++}
 ++
 ++static int ensure_dispatch_table(ShellExState *psx){
 ++  int rc = ensure_shell_db(psx);
 ++  if( rc==SQLITE_OK ){
 ++    char *zErr = 0;
 ++    int rc1, rc2;
 ++    if( dispatch_table_exists(psx->dbShell) ) return rc;
 ++    /* Create the dispatch table and view on it. */
 ++#ifdef SHELL_DB_FILE
 ++    sqlite3_exec(psx->dbShell, "DROP TABLE IF EXISTS "SHELL_DISP_TAB, 0,0,0);
 ++    sqlite3_exec(psx->dbShell, "DROP VIEW IF EXISTS "SHELL_DISP_VIEW, 0,0,0);
 ++    sqlite3_exec(psx->dbShell, "DROP TABLE IF EXISTS "SHELL_AHELP_TAB, 0,0,0);
 ++    sqlite3_exec(psx->dbShell, "DROP VIEW IF EXISTS "SHELL_HELP_VIEW, 0,0,0);
 ++#endif
 ++    rc1 = sqlite3_exec(psx->dbShell, "CREATE TABLE "SHELL_AHELP_TAB"("
 ++                       "name TEXT, extIx INT, helpText TEXT,"
 ++                       "PRIMARY KEY(name,extIx)) WITHOUT ROWID", 0, 0, &zErr);
 ++    rc1 = sqlite3_exec(psx->dbShell, "CREATE TABLE "SHELL_DISP_TAB"("
 ++                       "name TEXT, extIx INT, cmdIx INT,"
 ++                       "PRIMARY KEY(extIx,cmdIx)) WITHOUT ROWID", 0, 0, &zErr);
 ++    rc2 = sqlite3_exec(psx->dbShell,
 ++                       /* name, extIx, cmdIx */
 ++                       "CREATE VIEW "SHELL_DISP_VIEW" AS"
 ++                       " SELECT s.name AS name,"
 ++                       " max(s.extIx) AS extIx, s.cmdIx AS cmdIx"
 ++                       " FROM "SHELL_DISP_TAB" s GROUP BY name"
 ++                       " ORDER BY name",
 ++                       0, 0, &zErr);
 ++    rc2 = sqlite3_exec(psx->dbShell,
 ++                       /* name, extIx, cmdIx, help */
 ++                       "CREATE VIEW "SHELL_HELP_VIEW" AS"
 ++                       " SELECT s.name AS name, max(s.extIx) AS extIx,"
 ++                       " s.cmdIx AS cmdIx, NULL as help"
 ++                       " FROM "SHELL_DISP_TAB" s GROUP BY name"
 ++                       " UNION"
 ++                       " SELECT s.name AS name, max(s.extIx) AS extIx,"
 ++                       " -1 AS cmdIx, s.helpText AS help"
 ++                       " FROM "SHELL_AHELP_TAB" s GROUP BY name"
 ++                       " ORDER BY name",
 ++                       0, 0, &zErr);
 ++    if( rc1!=SQLITE_OK || rc2!=SQLITE_OK || zErr!=0 ){
 ++      utf8_printf(STD_ERR, "Shell DB init failure, %s\n", zErr? zErr : "?");
 ++      rc = SQLITE_ERROR;
 ++    }else rc = SQLITE_OK;
 ++    sqlite3_free(zErr);
 ++  }
 ++  return rc;
 ++}
 ++
 ++/*
 ++** Skip over whitespace, returning remainder.
 ++*/
 ++static const char *skipWhite( const char *z ){
 ++  while( IsSpace(*z) ) ++z;
 ++  return z;
 ++}
 ++
  +/*
  +** Print N dashes
  +*/
   static void print_dashes(FILE *out, int N){
     const char zDash[] = "--------------------------------------------------";
     const int nDash = sizeof(zDash) - 1;
@@@@ -3656,6 -3025,6 -3024,6 +3693,7 @@@@ static int run_table_dump_query
   
   /*
   ** Allocate space and save off string indicating current error.
+++** The return must be passed to sqlite3_free() sometime.
   */
   static char *save_err_msg(
     sqlite3 *db,           /* Database to query */
@@@@ -4145,151 -3516,22 -3515,22 +4183,151 @@@@ static void restore_debug_trace_modes(v
     sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &savedWhereTrace);
   }
   
 ++/* DB schema protection for use by next two utility functions */
 ++typedef struct DbProtectState {
 ++  int wrSchema;
 ++  int defensiveMode;
 ++} DbProtectState;
 ++
 ++/* Allow system (sqlite_*) schema changes, return prior protection state. */
 ++static DbProtectState allow_sys_schema_change(sqlite3 *db){
 ++  DbProtectState rv;
 ++  sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, -1, &rv.defensiveMode);
 ++  sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
 ++  sqlite3_db_config(db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &rv.wrSchema);
 ++  sqlite3_db_config(db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0);
 ++  return rv;
 ++}
 ++
 ++/* Restore protection state using allow_sys_schema_change() return. */
 ++static void restore_sys_schema_protection( sqlite3 *db, DbProtectState *pPS ){
 ++  sqlite3_db_config(db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, pPS->wrSchema, 0);
 ++  sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, pPS->defensiveMode, 0);
 ++}
 ++
 ++/* Partition the temp.sqlite_parameters and main.sqlite_variables
 ++ * key namespace according to use.
 ++ */
 ++typedef enum {
 ++  PTU_Binding = 0, /* Binding parameter, value to be bound */
 ++#define SPTU_Binding SHELL_STRINGIFY(0)
 ++  PTU_Script  = 1, /* A value containing shell SQL and dot-commands */
 ++#define SPTU_Script SHELL_STRINGIFY(1)
 ++  PTU_Entry   = 2, /* Value as entered for non-text binding parameters */
 ++#define SPTU_Entry SHELL_STRINGIFY(2)
 ++  PTU_Nil     = 3  /* Unspecified */
 ++} ParamTableUse;
 ++
 ++static ParamTableUse classify_param_name( const char *zName ){
 ++  char c = *zName;
 ++  switch( c ){
 ++  case '$': case ':': case '@': case '?': return PTU_Binding;
 ++  default: return isalpha(c)? PTU_Script : PTU_Nil;
 ++  }
 ++}
 ++
 ++#ifndef SQLITE_NOHAVE_SYSTEM
 ++/* Possibly using a -editor=X argument and env-var VISUAL, attempt
 ++ * to get the zEditor shell state member set iff not already set.
 ++ * If there is no such argument, the env-var is retrieved if set.
 ++ * If the argument is -editor=X or --editor=X, use that and leave
 ++ * the zEditor member set accordingly. Returns are:
 ++ * 0 => editor set, zEd was not the -editor option
 ++ * 1 => editor set, zEd consumed as -editor option
 ++ * -1 => editor not set, and error/advice message issued.
 ++ *
 ++ * This implements an undocumented fall-back for the .vars and
 ++ * .parameters edit subcommands, so that users need not restart
 ++ * a shell session to get an editor specified upon need for it. */
 ++int attempt_editor_set(ShellInState *psi, char *zDot, const char *zEd){
 ++  if( psi->zEditor==0 ){
 ++    const char *zE = getenv("VISUAL");
 ++    if( zE!=0 ) psi->zEditor = smprintf("%s", zE);
 ++  }
 ++  if( zEd && zEd[0]=='-' ){
 ++    zEd += 1 + (zEd[1]=='-');
 ++    if( cli_strncmp(zEd,"editor=",7)==0 ){
 ++      sqlite3_free(psi->zEditor);
 ++      /* Accept an initial -editor=? option. */
 ++      psi->zEditor = smprintf("%s", zEd+7);
 ++      return 1;
 ++    }
 ++  }
 ++  if( psi->zEditor==0 ){
 ++    utf8_printf(STD_ERR,
 ++                "Either set env-var VISUAL to name an"
 ++                " editor and restart, or rerun\n "
 ++                ".%s edit with an initial edit option,"
 ++                " --editor=EDITOR_COMMAND .\n", zDot);
 ++    return -1;
 ++  }
 ++  return 0;
 ++}
 ++#endif
 ++
 ++/* The table kept for user DBs if .parameter command is used usefully. */
 ++#define PARAM_TABLE_NAME "sqlite_parameters"
 ++#define PARAM_TABLE_SCHEMA "temp"
 ++#define PARAM_TABLE_SNAME PARAM_TABLE_SCHEMA"."PARAM_TABLE_NAME
 ++
 ++/* The table kept for the shell DB if .vars command is used usefully. */
 ++#define SHVAR_TABLE_NAME "sqlite_variables"
 ++#define SHVAR_TABLE_SCHEMA "main"
 ++#define SHVAR_TABLE_SNAME SHVAR_TABLE_SCHEMA"."SHVAR_TABLE_NAME
 ++
 ++#ifndef SH_KV_STORE_NAME
 ++/* Name for table keeping user's saved parameters */
 ++# define SH_KV_STORE_NAME "SQLiteShell_KeyValuePairs"
 ++#endif
 ++#ifndef SH_KV_STORE_SCHEMA
 ++/* Schema name used to attach saved parameters DB during load/save */
 ++# define SH_KV_STORE_SCHEMA "SQLiteShell"
 ++#endif
 ++#define SH_KV_STORE_SNAME SH_KV_STORE_SCHEMA"."SH_KV_STORE_NAME
 ++
   /* Create the TEMP table used to store parameter bindings */
 --static void bind_table_init(ShellState *p){
 --  int wrSchema = 0;
 --  int defensiveMode = 0;
 --  sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, -1, &defensiveMode);
 --  sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
 --  sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema);
 --  sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0);
 --  sqlite3_exec(p->db,
 --    "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n"
 ++static void param_table_init(sqlite3 *db){
 ++  DbProtectState dps = allow_sys_schema_change(db);
 ++  sqlite3_exec(db,
 ++    "CREATE TABLE IF NOT EXISTS "PARAM_TABLE_SNAME"(\n"
  +    "  key TEXT PRIMARY KEY,\n"
 -     "  value\n"
 ++    "  value,\n"
 ++    "  uses INT DEFAULT ("SPTU_Binding")"
  +    ") WITHOUT ROWID;",
  +    0, 0, 0);
 -   sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0);
 -   sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, defensiveMode, 0);
 ++  restore_sys_schema_protection( db, &dps );
 ++}
 ++
 ++/* Tell whether the above-created table exists, return true iff exists. */
 ++static int param_table_exists( sqlite3 *db ){
 ++  return sqlite3_table_column_metadata
 ++    (db, PARAM_TABLE_SCHEMA, PARAM_TABLE_NAME, 0, 0, 0, 0, 0, 0)==SQLITE_OK;
 ++}
 ++
 ++/* Create the shell DB table used to store shell variables or scripts */
 ++static int shvars_table_init(sqlite3 *db){
 ++  DbProtectState dps = allow_sys_schema_change(db);
 ++  int rc = sqlite3_exec(db,
 ++    "CREATE TABLE IF NOT EXISTS "SHVAR_TABLE_SNAME"(\n"
 +     "  key TEXT PRIMARY KEY,\n"
  -    "  value\n"
 ++    "  value,\n"
 ++    "  uses INT DEFAULT ("SPTU_Script")"
 +     ") WITHOUT ROWID;",
 +     0, 0, 0);
  -  sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0);
  -  sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, defensiveMode, 0);
 ++  restore_sys_schema_protection( db, &dps );
 ++  return rc!=SQLITE_OK;
 ++}
 ++
 ++/* Tell whether the above-created table exists, return true iff exists. */
 ++static int shvars_table_exists( sqlite3 *db ){
 ++  return sqlite3_table_column_metadata
 ++    (db, SHVAR_TABLE_SCHEMA, SHVAR_TABLE_NAME, 0, 0, 0, 0, 0, 0)==SQLITE_OK;
 ++}
 ++
 ++/* Make shell vars table exist. */
 ++static int ensure_shvars_table(sqlite3 *dbs){
 ++  if( shvars_table_exists(dbs) ) return SQLITE_OK;
 ++  else return shvars_table_init(dbs);
   }
   
   /*
@@@@ -4975,102 -4244,93 -4243,93 +5013,116 @@@@ static int shell_exec
     const char *zSql,                         /* SQL to be evaluated */
     char **pzErrMsg                           /* Error msg written here */
   ){
 ++  ShellInState *psi = ISS(psx);
     sqlite3_stmt *pStmt = NULL;     /* Statement to execute. */
+++  sqlite3_stmt *pExplain = NULL;  /* For explain generate */
+++  char *zEQP = NULL;              /* For explain report */
     int rc = SQLITE_OK;             /* Return Code */
     int rc2;
     const char *zLeftover;          /* Tail of unprocessed SQL */
 --  sqlite3 *db = pArg->db;
 --
 ++  sqlite3 *db = DBX(psx);
-  
+++  ResourceMark mark = holder_mark();
     if( pzErrMsg ){
       *pzErrMsg = NULL;
     }
   
   #ifndef SQLITE_OMIT_VIRTUALTABLE
 --  if( pArg->expert.pExpert ){
 --    rc = expertHandleSQL(pArg, zSql, pzErrMsg);
 --    return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg);
 ++  if( psi->expert.pExpert ){
 ++    rc = expertHandleSQL(psi, zSql, pzErrMsg);
 ++    return expertFinish(psi, (rc!=SQLITE_OK), pzErrMsg);
     }
   #endif
---
+++  stmt_holder(pStmt);    /* offset 0 */
+++  stmt_holder(pExplain); /* offset 1 */
+++  sstr_holder(zEQP);     /* offset 2 */
     while( zSql[0] && (SQLITE_OK == rc) ){
       static const char *zStmtSql;
       rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
       if( SQLITE_OK != rc ){
+++      if( rc==SQLITE_NOMEM ) shell_out_of_memory();
         if( pzErrMsg ){
           *pzErrMsg = save_err_msg(db, "in prepare", rc, zSql);
+++        shell_check_oom(*pzErrMsg);
         }
       }else{
         if( !pStmt ){
           /* this happens for a comment or white-space */
 --        zSql = zLeftover;
 --        while( IsSpace(zSql[0]) ) zSql++;
 ++        zSql = skipWhite(zLeftover);
           continue;
         }
+++      swap_held(mark, 0, pStmt);
         zStmtSql = sqlite3_sql(pStmt);
         if( zStmtSql==0 ) zStmtSql = "";
 --      while( IsSpace(zStmtSql[0]) ) zStmtSql++;
 ++      else zStmtSql = skipWhite(zStmtSql);
   
         /* save off the prepared statment handle and reset row count */
 --      if( pArg ){
 --        pArg->pStmt = pStmt;
 --        pArg->cnt = 0;
 ++      if( psx ){
 ++        psi->pStmt = pStmt;
 ++        psx->resultCount = 0;
         }
   
         /* Show the EXPLAIN QUERY PLAN if .eqp is on */
 --      if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){
 --        sqlite3_stmt *pExplain;
 --        char *zEQP;
 ++      if( psx && psi->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){
-          sqlite3_stmt *pExplain;
-          char *zEQP;
           int triggerEQP = 0;
           disable_debug_trace_modes();
           sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP);
 --        if( pArg->autoEQP>=AUTOEQP_trigger ){
 ++        if( psi->autoEQP>=AUTOEQP_trigger ){
             sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0);
           }
 --        zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
 ++        zEQP = smprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
           shell_check_oom(zEQP);
+++        swap_held(mark, 2, zEQP);
           rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
           if( rc==SQLITE_OK ){
+++          swap_held(mark, 1, pExplain);
             while( sqlite3_step(pExplain)==SQLITE_ROW ){
               const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3);
               int iEqpId = sqlite3_column_int(pExplain, 0);
               int iParentId = sqlite3_column_int(pExplain, 1);
               if( zEQPLine==0 ) zEQPLine = "";
 --            if( zEQPLine[0]=='-' ) eqp_render(pArg, 0);
 --            eqp_append(pArg, iEqpId, iParentId, zEQPLine);
 ++            if( zEQPLine[0]=='-' ) eqp_render(psi, 0);
 ++            eqp_append(psi, iEqpId, iParentId, zEQPLine);
             }
 --          eqp_render(pArg, 0);
 ++          eqp_render(psi, 0);
           }
           sqlite3_finalize(pExplain);
+++        swap_held(mark, 1, 0);
           sqlite3_free(zEQP);
 --        if( pArg->autoEQP>=AUTOEQP_full ){
+++        swap_held(mark, 2, 0);
 ++        if( psi->autoEQP>=AUTOEQP_full ){
             /* Also do an EXPLAIN for ".eqp full" mode */
 --          zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
 ++          zEQP = smprintf("EXPLAIN %s", zStmtSql);
             shell_check_oom(zEQP);
+++          swap_held(mark, 2, zEQP);
             rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
             if( rc==SQLITE_OK ){
 --            pArg->cMode = MODE_Explain;
 --            explain_data_prepare(pArg, pExplain);
 --            exec_prepared_stmt(pArg, pExplain);
 --            explain_data_delete(pArg);
+++            swap_held(mark, 1, pExplain);
 ++            explain_data_prepare(psi, pExplain);
 ++            psi->cMode = MODE_Explain;
 ++#if SHELL_DATAIO_EXT
 ++            {
 ++              ExportHandler *pexSave = psi->pActiveExporter;
 ++              psi->pActiveExporter = psi->pFreeformExporter;
 ++              exec_prepared_stmt(psx, pExplain);
 ++              psi->pActiveExporter = pexSave;
 ++            }
 ++#else
 ++            exec_prepared_stmt(psx, pExplain);
 ++#endif
 ++            explain_data_delete(psi);
             }
             sqlite3_finalize(pExplain);
+++          swap_held(mark, 1, 0);
             sqlite3_free(zEQP);
+++          swap_held(mark, 2, 0);
           }
 --        if( pArg->autoEQP>=AUTOEQP_trigger && triggerEQP==0 ){
 ++        if( psi->autoEQP>=AUTOEQP_trigger && triggerEQP==0 ){
             sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 0, 0);
             /* Reprepare pStmt before reactiving trace modes */
             sqlite3_finalize(pStmt);
             sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
 --          if( pArg ) pArg->pStmt = pStmt;
+++          swap_held(mark, 0, pStmt);
 ++          if( psx ) psi->pStmt = pStmt;
           }
           restore_debug_trace_modes();
         }
         ** copy of the error message. Otherwise, set zSql to point to the
         ** next statement to execute. */
         rc2 = sqlite3_finalize(pStmt);
+++      swap_held(mark, 0, 0);
         if( rc!=SQLITE_NOMEM ) rc = rc2;
         if( rc==SQLITE_OK ){
 --        zSql = zLeftover;
 --        while( IsSpace(zSql[0]) ) zSql++;
 ++        zSql = skipWhite(zLeftover);
         }else if( pzErrMsg ){
           *pzErrMsg = save_err_msg(db, "stepping", rc, 0);
         }
         }
       }
     } /* end while */
+++  CHECK_RETURN_EQUAL(0, holder_free(mark));
   
     return rc;
   }
@@@@ -5419,958 -4681,1304 -4680,1304 +5473,959 @@@@ static int run_schema_dump_query
     return rc;
   }
   
 ++/* Configure help text generation to have coalesced secondary help lines
 ++ * with trailing newlines on all help lines. This allow help text to be
 ++ * representable as an array of two C-strings per dot-command.
 ++ */
 ++DISPATCH_CONFIG[
 ++  HELP_COALESCE=1
 ++];
 ++#define HELP_TEXT_FMTP ".%s"
 ++#define HELP_TEXT_FMTS "%s"
 ++/* Above HELP_COALESCE config and HELP_TEXT_FMT PP vars must track.
 ++ * Alternative is 0, ".%s\n" and "%s\n" .
 ++ */
 ++
 ++/* Forward references */
 ++static int showHelp(FILE *out, const char *zPattern, ShellExState *);
 ++static DotCmdRC process_input(ShellInState *psx);
 ++static DotCommand *builtInCommand(int ix);
 ++
   /*
 --** Text of help messages.
 ++** Read the content of file zName into memory obtained from sqlite3_malloc64()
 ++** and return a pointer to the buffer. The caller is responsible for freeing
 ++** the memory.
 ++**
 ++** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
 ++** read.
   **
 --** The help text for each individual command begins with a line that starts
 --** with ".".  Subsequent lines are supplemental information.
 ++** For convenience, a nul-terminator byte is always appended to the data read
 ++** from the file before the buffer is returned. This byte is not included in
 ++** the final value of (*pnByte), if applicable.
   **
 --** There must be two or more spaces between the end of the command and the
 --** start of the description of what that command does.
 ++** NULL is returned if any error is encountered. The final value of *pnByte
 ++** is undefined in this case.
   */
 --static const char *(azHelp[]) = {
 --#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) \
 --  && !defined(SQLITE_SHELL_FIDDLE)
 --  ".archive ...             Manage SQL archives",
 --  "   Each command must have exactly one of the following options:",
 --  "     -c, --create               Create a new archive",
 --  "     -u, --update               Add or update files with changed mtime",
 --  "     -i, --insert               Like -u but always add even if unchanged",
 --  "     -r, --remove               Remove files from archive",
 --  "     -t, --list                 List contents of archive",
 --  "     -x, --extract              Extract files from archive",
 --  "   Optional arguments:",
 --  "     -v, --verbose              Print each filename as it is processed",
 --  "     -f FILE, --file FILE       Use archive FILE (default is current db)",
 --  "     -a FILE, --append FILE     Open FILE using the apndvfs VFS",
 --  "     -C DIR, --directory DIR    Read/extract files from directory DIR",
 --  "     -g, --glob                 Use glob matching for names in archive",
 --  "     -n, --dryrun               Show the SQL that would have occurred",
 --  "   Examples:",
 --  "     .ar -cf ARCHIVE foo bar  # Create ARCHIVE from files foo and bar",
 --  "     .ar -tf ARCHIVE          # List members of ARCHIVE",
 --  "     .ar -xvf ARCHIVE         # Verbosely extract files from ARCHIVE",
 --  "   See also:",
 --  "      http://sqlite.org/cli.html#sqlite_archive_support",
 ++static char *readFile(const char *zName, int *pnByte){
 ++  FILE *in = fopen(zName, "rb");
 ++  long nIn;
 ++  size_t nRead;
 ++  char *pBuf;
 ++  int rc;
 ++  if( in==0 ) return 0;
 ++  rc = fseek(in, 0, SEEK_END);
 ++  if( rc!=0 ){
 ++    raw_printf(stderr, "Error: '%s' not seekable\n", zName);
 ++    fclose(in);
 ++    return 0;
 ++  }
 ++  nIn = ftell(in);
 ++  rewind(in);
 ++  pBuf = sqlite3_malloc64( nIn+1 );
 ++  if( pBuf==0 ){
 ++    raw_printf(stderr, "Error: out of memory\n");
 ++    fclose(in);
 ++    return 0;
 ++  }
 ++  nRead = fread(pBuf, nIn, 1, in);
 ++  fclose(in);
 ++  if( nRead!=1 ){
 ++    sqlite3_free(pBuf);
 ++    raw_printf(stderr, "Error: cannot read '%s'\n", zName);
 ++    return 0;
 ++  }
 ++  pBuf[nIn] = 0;
 ++  if( pnByte ) *pnByte = nIn;
 ++  return pBuf;
 ++}
 ++
 ++#if defined(SQLITE_ENABLE_SESSION)
 ++/*
 ++** Close a single OpenSession object and release all of its associated
 ++** resources.
 ++*/
 ++static void session_close(OpenSession *pSession){
 ++  int i;
 ++  sqlite3session_delete(pSession->p);
 ++  sqlite3_free(pSession->zName);
 ++  for(i=0; i<pSession->nFilter; i++){
 ++    sqlite3_free(pSession->azFilter[i]);
 ++  }
 ++  sqlite3_free(pSession->azFilter);
 ++  memset(pSession, 0, sizeof(OpenSession));
 ++}
   #endif
 --#ifndef SQLITE_OMIT_AUTHORIZATION
 --  ".auth ON|OFF             Show authorizer callbacks",
 ++
 ++/*
 ++** Close all OpenSession objects and release all associated resources.
 ++*/
 ++#if defined(SQLITE_ENABLE_SESSION)
 ++static void session_close_all(ShellInState *psi, int i){
 ++  int j;
 ++  struct AuxDb *pAuxDb = i<0 ? psi->pAuxDb : &psi->aAuxDb[i];
 ++  for(j=0; j<pAuxDb->nSession; j++){
 ++    session_close(&pAuxDb->aSession[j]);
 ++  }
 ++  pAuxDb->nSession = 0;
 ++}
 ++#else
 ++# define session_close_all(X,Y)
   #endif
 --#ifndef SQLITE_SHELL_FIDDLE
 --  ".backup ?DB? FILE        Backup DB (default \"main\") to FILE",
 --  "   Options:",
 --  "       --append            Use the appendvfs",
 --  "       --async             Write to FILE without journal and fsync()",
 ++
 ++/*
 ++** Implementation of the xFilter function for an open session.  Omit
 ++** any tables named by ".session filter" but let all other table through.
 ++*/
 ++#if defined(SQLITE_ENABLE_SESSION)
 ++static int session_filter(void *pCtx, const char *zTab){
 ++  OpenSession *pSession = (OpenSession*)pCtx;
 ++  int i;
 ++  for(i=0; i<pSession->nFilter; i++){
 ++    if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
 ++  }
 ++  return 1;
 ++}
   #endif
 --  ".bail on|off             Stop after hitting an error.  Default OFF",
 --  ".binary on|off           Turn binary output on or off.  Default OFF",
 --#ifndef SQLITE_SHELL_FIDDLE
 --  ".cd DIRECTORY            Change the working directory to DIRECTORY",
 ++
 ++#if SHELL_DYNAMIC_EXTENSION
 ++static int notify_subscribers(ShellInState *psi, NoticeKind nk, void *pvs) {
 ++  int six = 0;
 ++  int rcFlags = 0;
 ++  ShellExState *psx = XSS(psi);
 ++  while( six < psi->numSubscriptions ){
 ++    struct EventSubscription *pes = psi->pSubscriptions + six++;
 ++    rcFlags |= pes->eventHandler(pes->pvUserData, nk, pvs, psx);
 ++  }
 ++  return rcFlags;
 ++}
   #endif
 --  ".changes on|off          Show number of rows changed by SQL",
 ++
 ++/*
 ++** Try to deduce the type of file for zName based on its content.  Return
 ++** one of the SHELL_OPEN_* constants.
 ++**
 ++** If the file does not exist or is empty but its name looks like a ZIP
 ++** archive and the dfltZip flag is true, then assume it is a ZIP archive.
 ++** Otherwise, assume an ordinary database regardless of the filename if
 ++** the type cannot be determined from content.
 ++*/
 ++u8 deduceDatabaseType(const char *zName, int dfltZip){
 ++  FILE *f = fopen(zName, "rb");
 ++  size_t n;
 ++  u8 rc = SHELL_OPEN_UNSPEC;
 ++  char zBuf[100];
 ++  if( f==0 ){
 ++    if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
 ++       return SHELL_OPEN_ZIPFILE;
 ++    }else{
 ++       return SHELL_OPEN_NORMAL;
 ++    }
 ++  }
 ++  n = fread(zBuf, 16, 1, f);
 ++  if( n==1 && memcmp(zBuf, "SQLite format 3", 16)==0 ){
 ++    fclose(f);
 ++    return SHELL_OPEN_NORMAL;
 ++  }
 ++  fseek(f, -25, SEEK_END);
 ++  n = fread(zBuf, 25, 1, f);
 ++  if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){
 ++    rc = SHELL_OPEN_APPENDVFS;
 ++  }else{
 ++    fseek(f, -22, SEEK_END);
 ++    n = fread(zBuf, 22, 1, f);
 ++    if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05
 ++       && zBuf[3]==0x06 ){
 ++      rc = SHELL_OPEN_ZIPFILE;
 ++    }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
 ++      rc = SHELL_OPEN_ZIPFILE;
 ++    }
 ++  }
 ++  fclose(f);
 ++  return rc;
 ++}
 ++
 ++#ifndef SQLITE_OMIT_DESERIALIZE
 ++/*
 ++** Reconstruct an in-memory database using the output from the "dbtotxt"
 ++** program.  Read content from the file in p->aAuxDb[].zDbFilename.
 ++** If p->aAuxDb[].zDbFilename is 0, then read from the present input.
 ++*/
 ++static unsigned char *readHexDb(ShellInState *psi, int *pnData){
 ++  unsigned char *a = 0;
 ++  int n = 0;
 ++  int pgsz = 0;
 ++  int iOffset = 0;
 ++  int j, k, nlError;
 ++  int rc;
 ++  static const char *zEndMarker = "| end ";
 ++  const char *zDbFilename = psi->pAuxDb->zDbFilename;
 ++  /* Need next two objects only if redirecting input to get the hex. */
 ++  InSource inRedir = INSOURCE_FILE_REDIR(0, zDbFilename, psi->pInSource);
 ++  unsigned int x[16];
 ++  char zLine[1000];
 ++  if( zDbFilename ){
 ++    inRedir.inFile = fopen(zDbFilename, "r");
 ++    if( inRedir.inFile==0 ){
 ++      utf8_printf(STD_ERR, "cannot open \"%s\" for reading\n", zDbFilename);
 ++      return 0;
 ++    }
 ++    psi->pInSource = &inRedir;
 ++  }else{
 ++    /* Will read hex DB lines inline from present input, without redirect. */
 ++    if( INSOURCE_IS_INTERACTIVE(psi->pInSource) ){
 ++      printf("Reading hex DB from \"%s\", until end-marker input like:\n%s\n",
 ++             psi->pInSource->zSourceSay, zEndMarker);
 ++      fflush(STD_OUT);
 ++    }
 ++  }
 ++  *pnData = 0;
 ++  if( strLineGet(zLine,sizeof(zLine), psi->pInSource)==0 ) goto readHexDb_error;
 ++  rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
 ++  if( rc!=2 ) goto readHexDb_error;
 ++  if( n<0 ) goto readHexDb_error;
 ++  if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error;
 ++  n = (n+pgsz-1)&~(pgsz-1);  /* Round n up to the next multiple of pgsz */
 ++  a = sqlite3_malloc( n ? n : 1 );
 ++  shell_check_oom(a);
 ++  memset(a, 0, n);
 ++  if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
 ++    utf8_printf(STD_ERR, "invalid pagesize\n");
 ++    goto readHexDb_error;
 ++  }
 ++  while( strLineGet(zLine,sizeof(zLine), psi->pInSource)!=0 ){
 ++    rc = sscanf(zLine, "| page %d offset %d", &j, &k);
 ++    if( rc==2 ){
 ++      iOffset = k;
 ++      continue;
 ++    }
 ++    if( cli_strncmp(zLine, zEndMarker, 6)==0 ){
 ++      break;
 ++    }
 ++    rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
 ++                &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
 ++                &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
 ++    if( rc==17 ){
 ++      k = iOffset+j;
 ++      if( k+16<=n && k>=0 ){
 ++        int ii;
 ++        for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff;
 ++      }
 ++    }
 ++  }
 ++  *pnData = n; /* Record success and size. */
 ++ readHexDb_cleanup:
 ++  if( psi->pInSource==&inRedir ){
 ++    fclose( inRedir.inFile );
 ++    psi->pInSource = inRedir.pFrom;
 ++  }
 ++  return a;
 ++
 ++ readHexDb_error:
 ++  nlError = psi->pInSource->lineno;
 ++  if( psi->pInSource!=&inRedir ){
 ++    /* Since taking input inline, consume through its end marker. */
 ++    while( strLineGet(zLine, sizeof(zLine), psi->pInSource)!=0 ){
 ++      if(cli_strncmp(zLine, zEndMarker, 6)==0 ) break;
 ++    }
 ++  }
 ++  sqlite3_free(a);
 ++  a = 0;
 ++  utf8_printf(STD_ERR,"Error on line %d within --hexdb input\n", nlError);
 ++  goto readHexDb_cleanup;
 ++}
 ++#endif /* SQLITE_OMIT_DESERIALIZE */
 ++
 ++/*
 ++** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X.
 ++*/
 ++static void shellUSleepFunc(
 ++  sqlite3_context *context,
 ++  int argcUnused,
 ++  sqlite3_value **argv
 ++){
 ++  int sleep = sqlite3_value_int(argv[0]);
 ++  (void)argcUnused;
 ++  sqlite3_sleep(sleep/1000);
 ++  sqlite3_result_int(context, sleep);
 ++}
 ++
 ++/* Flags for open_db().
 ++**
 ++** The default behavior of open_db() is to exit(1) if the database fails to
 ++** open.  The OPEN_DB_KEEPALIVE flag changes that so that it prints an error
 ++** but still returns without calling exit.
 ++**
 ++** The OPEN_DB_ZIPFILE flag causes open_db() to prefer to open files as a
 ++** ZIP archive if the file does not exist or is empty and its name matches
 ++** the *.zip pattern.
 ++*/
 ++#define OPEN_DB_KEEPALIVE   0x001   /* Return after error if true */
 ++#define OPEN_DB_ZIPFILE     0x002   /* Open as ZIP if name matches *.zip */
 ++
 ++/*
 ++** Make sure the database is open.  If it is not, then open it.  If
 ++** the database fails to open, print an error message and exit.
 ++*/
 ++static void open_db(ShellExState *psx, int openFlags){
 ++  ShellInState *psi = ISS(psx);
 ++  if( DBX(psx)==0 ){
 ++    sqlite3 **pDb = &DBX(psx);
 ++    const char *zDbFilename = psi->pAuxDb->zDbFilename;
 ++    if( psi->openMode==SHELL_OPEN_UNSPEC ){
 ++      if( zDbFilename==0 || zDbFilename[0]==0 ){
 ++        psi->openMode = SHELL_OPEN_NORMAL;
 ++      }else{
 ++        psi->openMode = deduceDatabaseType(zDbFilename,
 ++                                           (openFlags & OPEN_DB_ZIPFILE)!=0);
 ++      }
 ++    }
 ++    switch( psi->openMode ){
 ++      case SHELL_OPEN_APPENDVFS: {
 ++        sqlite3_open_v2
 ++          (zDbFilename, pDb,
 ++           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|psi->openFlags,
 ++           "apndvfs");
 ++        break;
 ++      }
 ++      case SHELL_OPEN_HEXDB:
 ++      case SHELL_OPEN_DESERIALIZE: {
 ++        sqlite3_open(0, pDb);
 ++        break;
 ++      }
 ++      case SHELL_OPEN_ZIPFILE: {
 ++        sqlite3_open(":memory:", pDb);
 ++        break;
 ++      }
 ++      case SHELL_OPEN_READONLY: {
 ++        sqlite3_open_v2(zDbFilename, pDb,
 ++            SQLITE_OPEN_READONLY|psi->openFlags, 0);
 ++        break;
 ++      }
 ++      case SHELL_OPEN_UNSPEC:
 ++      case SHELL_OPEN_NORMAL: {
 ++        sqlite3_open_v2(zDbFilename, pDb,
 ++           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|psi->openFlags, 0);
 ++        break;
 ++      }
 ++    }
 ++    globalDb = DBX(psx);
 ++    if( DBX(psx)==0 || SQLITE_OK!=sqlite3_errcode(DBX(psx)) ){
 ++      const char *zWhy = (DBX(psx)==0)? "(?)" : sqlite3_errmsg(DBX(psx));
 ++      utf8_printf(STD_ERR,"Error: unable to open database \"%s\": %s\n",
 ++          zDbFilename, zWhy);
 ++      if( (openFlags & OPEN_DB_KEEPALIVE)==0 ){
 ++        exit(1);
 ++      }
 ++      sqlite3_close(DBX(psx));
 ++      sqlite3_open(":memory:", &DBX(psx));
 ++      if( DBX(psx)==0 || SQLITE_OK!=sqlite3_errcode(DBX(psx)) ){
 ++        utf8_printf(stderr,
 ++          "Also: unable to open substitute in-memory database.\n"
 ++        );
 ++        exit(1);
 ++      }else{
 ++        utf8_printf(stderr,
 ++          "Notice: using substitute in-memory database instead of \"%s\"\n",
 ++          zDbFilename);
 ++      }
 ++    }
 ++    sqlite3_db_config(globalDb, SQLITE_DBCONFIG_STMT_SCANSTATUS,(int)0,(int*)0);
 ++
 ++    /* Reflect the use or absence of --unsafe-testing invocation. */
 ++    {
 ++      int testmode_on = ShellHasFlag(psx,SHFLG_TestingMode);
 ++      sqlite3_db_config(globalDb, SQLITE_DBCONFIG_TRUSTED_SCHEMA,testmode_on,0);
 ++      sqlite3_db_config(globalDb, SQLITE_DBCONFIG_DEFENSIVE, !testmode_on,0);
 ++    }
 ++#ifndef SQLITE_OMIT_LOAD_EXTENSION
 ++    sqlite3_enable_load_extension(globalDb, 1);
 ++#endif
 ++    sqlite3_shathree_init(globalDb, 0, 0);
 ++    sqlite3_uint_init(globalDb, 0, 0);
 ++    sqlite3_decimal_init(globalDb, 0, 0);
 ++    sqlite3_base64_init(globalDb, 0, 0);
 ++    sqlite3_base85_init(globalDb, 0, 0);
 ++    sqlite3_regexp_init(globalDb, 0, 0);
 ++    sqlite3_ieee_init(globalDb, 0, 0);
 ++    sqlite3_series_init(globalDb, 0, 0);
   #ifndef SQLITE_SHELL_FIDDLE
 --  ".check GLOB              Fail if output since .testcase does not match",
 --  ".clone NEWDB             Clone data into NEWDB from the existing database",
 ++    sqlite3_fileio_init(globalDb, 0, 0);
 ++    sqlite3_completion_init(globalDb, 0, 0);
   #endif
 --  ".connection [close] [#]  Open or close an auxiliary database connection",
 --  ".databases               List names and files of attached databases",
 --  ".dbconfig ?op? ?val?     List or change sqlite3_db_config() options",
   #if SQLITE_SHELL_HAVE_RECOVER
 --  ".dbinfo ?DB?             Show status information about the database",
 - #endif
 -   ".dump ?OBJECTS?          Render database content as SQL",
 -   "   Options:",
 -   "     --data-only            Output only INSERT statements",
 -   "     --newlines             Allow unescaped newline characters in output",
 -   "     --nosys                Omit system tables (ex: \"sqlite_stat1\")",
 -   "     --preserve-rowids      Include ROWID values in the output",
 -   "   OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump",
 -   "   Additional LIKE patterns can be given in subsequent arguments",
 -   ".echo on|off             Turn command echo on or off",
 -   ".eqp on|off|full|...     Enable or disable automatic EXPLAIN QUERY PLAN",
 -   "   Other Modes:",
 - #ifdef SQLITE_DEBUG
 -   "      test                  Show raw EXPLAIN QUERY PLAN output",
 -   "      trace                 Like \"full\" but enable \"PRAGMA vdbe_trace\"",
 ++    sqlite3_dbdata_init(globalDb, 0, 0);
   #endif
 -   "      trigger               Like \"full\" but also show trigger bytecode",
 - #ifndef SQLITE_SHELL_FIDDLE
 -   ".excel                   Display the output of next command in spreadsheet",
 -   "   --bom                   Put a UTF8 byte-order mark on intermediate file",
 - #endif
 - #ifndef SQLITE_SHELL_FIDDLE
 -   ".exit ?CODE?             Exit this program with return-code CODE",
  -  ".dump ?OBJECTS?          Render database content as SQL",
  -  "   Options:",
  -  "     --data-only            Output only INSERT statements",
  -  "     --newlines             Allow unescaped newline characters in output",
  -  "     --nosys                Omit system tables (ex: \"sqlite_stat1\")",
  -  "     --preserve-rowids      Include ROWID values in the output",
  -  "   OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump",
  -  "   Additional LIKE patterns can be given in subsequent arguments",
  -  ".echo on|off             Turn command echo on or off",
  -  ".eqp on|off|full|...     Enable or disable automatic EXPLAIN QUERY PLAN",
  -  "   Other Modes:",
  -#ifdef SQLITE_DEBUG
  -  "      test                  Show raw EXPLAIN QUERY PLAN output",
  -  "      trace                 Like \"full\" but enable \"PRAGMA vdbe_trace\"",
 ++#ifdef SQLITE_HAVE_ZLIB
 ++    if( !psi->bSafeModeFuture ){
 ++      sqlite3_zipfile_init(globalDb, 0, 0);
 ++      sqlite3_sqlar_init(globalDb, 0, 0);
 ++    }
   #endif
 -   ".expert                  EXPERIMENTAL. Suggest indexes for queries",
 -   ".explain ?on|off|auto?   Change the EXPLAIN formatting mode.  Default: auto",
 -   ".filectrl CMD ...        Run various sqlite3_file_control() operations",
 -   "   --schema SCHEMA         Use SCHEMA instead of \"main\"",
 -   "   --help                  Show CMD details",
 -   ".fullschema ?--indent?   Show schema and the content of sqlite_stat tables",
 -   ".headers on|off          Turn display of headers on or off",
 -   ".help ?-all? ?PATTERN?   Show help text for PATTERN",
  -  "      trigger               Like \"full\" but also show trigger bytecode",
 --#ifndef SQLITE_SHELL_FIDDLE
 -   ".import FILE TABLE       Import data from FILE into TABLE",
 -   "   Options:",
 -   "     --ascii               Use \\037 and \\036 as column and row separators",
 -   "     --csv                 Use , and \\n as column and row separators",
 -   "     --skip N              Skip the first N rows of input",
 -   "     --schema S            Target table to be S.TABLE",
 -   "     -v                    \"Verbose\" - increase auxiliary output",
 -   "   Notes:",
 -   "     *  If TABLE does not exist, it is created.  The first row of input",
 -   "        determines the column names.",
 -   "     *  If neither --csv or --ascii are used, the input mode is derived",
 -   "        from the \".mode\" output mode",
 -   "     *  If FILE begins with \"|\" then it is a command that generates the",
 -   "        input text.",
  -  ".excel                   Display the output of next command in spreadsheet",
  -  "   --bom                   Put a UTF8 byte-order mark on intermediate file",
 ++
 ++#ifdef SQLITE_SHELL_EXTFUNCS
 ++    /* Create a preprocessing mechanism for extensions to make
 ++     * their own provisions for being built into the shell.
 ++     * This is a short-span macro. See further below for usage.
 ++     */
 ++#define SHELL_SUB_MACRO(base, variant) base ## _ ## variant
 ++#define SHELL_SUBMACRO(base, variant) SHELL_SUB_MACRO(base, variant)
 ++    /* Let custom-included extensions get their ..._init() called.
 ++     * The WHATEVER_INIT( db, pzErrorMsg, pApi ) macro should cause
 ++     * the extension's sqlite3_*_init( db, pzErrorMsg, pApi )
 ++     * inititialization routine to be called.
 ++     */
 ++    {
 ++      int irc = SHELL_SUBMACRO(SQLITE_SHELL_EXTFUNCS, INIT)(p->db);
 ++    /* Let custom-included extensions expose their functionality.
 ++     * The WHATEVER_EXPOSE( db, pzErrorMsg ) macro should cause
 ++     * the SQL functions, virtual tables, collating sequences or
 ++     * VFS's implemented by the extension to be registered.
 ++     */
 ++      if( irc==SQLITE_OK
 ++          || irc==SQLITE_OK_LOAD_PERMANENTLY ){
 ++        SHELL_SUBMACRO(SQLITE_SHELL_EXTFUNCS, EXPOSE)(p->db, 0);
 ++      }
 ++#undef SHELL_SUB_MACRO
 ++#undef SHELL_SUBMACRO
 ++    }
   #endif
  -#ifndef SQLITE_SHELL_FIDDLE
  -  ".exit ?CODE?             Exit this program with return-code CODE",
  -#endif
  -  ".expert                  EXPERIMENTAL. Suggest indexes for queries",
  -  ".explain ?on|off|auto?   Change the EXPLAIN formatting mode.  Default: auto",
  -  ".filectrl CMD ...        Run various sqlite3_file_control() operations",
  -  "   --schema SCHEMA         Use SCHEMA instead of \"main\"",
  -  "   --help                  Show CMD details",
  -  ".fullschema ?--indent?   Show schema and the content of sqlite_stat tables",
  -  ".headers on|off          Turn display of headers on or off",
  -  ".help ?-all? ?PATTERN?   Show help text for PATTERN",
  -#ifndef SQLITE_SHELL_FIDDLE
  -  ".import FILE TABLE       Import data from FILE into TABLE",
  -  "   Options:",
  -  "     --ascii               Use \\037 and \\036 as column and row separators",
  -  "     --csv                 Use , and \\n as column and row separators",
  -  "     --skip N              Skip the first N rows of input",
  -  "     --schema S            Target table to be S.TABLE",
  -  "     -v                    \"Verbose\" - increase auxiliary output",
  -  "   Notes:",
  -  "     *  If TABLE does not exist, it is created.  The first row of input",
  -  "        determines the column names.",
  -  "     *  If neither --csv or --ascii are used, the input mode is derived",
  -  "        from the \".mode\" output mode",
  -  "     *  If FILE begins with \"|\" then it is a command that generates the",
  -  "        input text.",
  -#endif
 --#ifndef SQLITE_OMIT_TEST_CONTROL
 --  ",imposter INDEX TABLE    Create imposter table TABLE on index INDEX",
 --#endif
 --  ".indexes ?TABLE?         Show names of indexes",
 --  "                           If TABLE is specified, only show indexes for",
 --  "                           tables matching TABLE using the LIKE operator.",
 --#ifdef SQLITE_ENABLE_IOTRACE
 --  ",iotrace FILE            Enable I/O diagnostic logging to FILE",
 --#endif
 --  ".limit ?LIMIT? ?VAL?     Display or change the value of an SQLITE_LIMIT",
 --  ".lint OPTIONS            Report potential schema issues.",
 --  "     Options:",
 --  "        fkey-indexes     Find missing foreign key indexes",
 --#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_FIDDLE)
 --  ".load FILE ?ENTRY?       Load an extension library",
 --#endif
 --#if !defined(SQLITE_SHELL_FIDDLE)
 --  ".log FILE|on|off         Turn logging on or off.  FILE can be stderr/stdout",
 --#else
 --  ".log on|off              Turn logging on or off.",
 --#endif
 --  ".mode MODE ?OPTIONS?     Set output mode",
 --  "   MODE is one of:",
 --  "     ascii       Columns/rows delimited by 0x1F and 0x1E",
 --  "     box         Tables using unicode box-drawing characters",
 --  "     csv         Comma-separated values",
 --  "     column      Output in columns.  (See .width)",
 --  "     html        HTML <table> code",
 --  "     insert      SQL insert statements for TABLE",
 --  "     json        Results in a JSON array",
 --  "     line        One value per line",
 --  "     list        Values delimited by \"|\"",
 --  "     markdown    Markdown table format",
 --  "     qbox        Shorthand for \"box --wrap 60 --quote\"",
 --  "     quote       Escape answers as for SQL",
 --  "     table       ASCII-art table",
 --  "     tabs        Tab-separated values",
 --  "     tcl         TCL list elements",
 --  "   OPTIONS: (for columnar modes or insert mode):",
 --  "     --wrap N       Wrap output lines to no longer than N characters",
 --  "     --wordwrap B   Wrap or not at word boundaries per B (on/off)",
 --  "     --ww           Shorthand for \"--wordwrap 1\"",
 --  "     --quote        Quote output text as SQL literals",
 --  "     --noquote      Do not quote output text",
 --  "     TABLE          The name of SQL table used for \"insert\" mode",
 --#ifndef SQLITE_SHELL_FIDDLE
 --  ".nonce STRING            Suspend safe mode for one command if nonce matches",
 --#endif
 --  ".nullvalue STRING        Use STRING in place of NULL values",
 --#ifndef SQLITE_SHELL_FIDDLE
 --  ".once ?OPTIONS? ?FILE?   Output for the next SQL command only to FILE",
 --  "     If FILE begins with '|' then open as a pipe",
 --  "       --bom  Put a UTF8 byte-order mark at the beginning",
 --  "       -e     Send output to the system text editor",
 --  "       -x     Send output as CSV to a spreadsheet (same as \".excel\")",
 --  /* Note that .open is (partially) available in WASM builds but is
 --  ** currently only intended to be used by the fiddle tool, not
 --  ** end users, so is "undocumented." */
 --  ".open ?OPTIONS? ?FILE?   Close existing database and reopen FILE",
 --  "     Options:",
 --  "        --append        Use appendvfs to append database to the end of FILE",
 ++
 ++    sqlite3_create_function(globalDb, "shell_add_schema", 3, SQLITE_UTF8, 0,
 ++                            shellAddSchemaName, 0, 0);
 ++    sqlite3_create_function(globalDb, "shell_module_schema", 1, SQLITE_UTF8, 0,
 ++                            shellModuleSchema, 0, 0);
 ++    sqlite3_create_function(globalDb, "shell_putsnl", 1, SQLITE_UTF8, psx,
 ++                            shellPutsFunc, 0, 0);
 ++    sqlite3_create_function(globalDb, "usleep",1,SQLITE_UTF8, 0,
 ++                            shellUSleepFunc, 0, 0);
 ++#ifndef SQLITE_NOHAVE_SYSTEM
 ++    sqlite3_create_function(globalDb, "edit", 1, SQLITE_UTF8, 0,
 ++                            editFunc, 0, 0);
 ++    sqlite3_create_function(globalDb, "edit", 2, SQLITE_UTF8, 0,
 ++                            editFunc, 0, 0);
   #endif
 ++    if( psi->openMode==SHELL_OPEN_ZIPFILE ){
 ++      char *zSql = smprintf("CREATE VIRTUAL TABLE zip USING zipfile(%Q);",
 ++                            zDbFilename);
 ++      shell_check_oom(zSql);
 ++      sqlite3_exec(DBX(psx), zSql, 0, 0, 0);
 ++      sqlite3_free(zSql);
 ++    }
   #ifndef SQLITE_OMIT_DESERIALIZE
 --  "        --deserialize   Load into memory using sqlite3_deserialize()",
 --  "        --hexdb         Load the output of \"dbtotxt\" as an in-memory db",
 --  "        --maxsize N     Maximum size for --hexdb or --deserialized database",
 --#endif
 --  "        --new           Initialize FILE to an empty database",
 --  "        --nofollow      Do not follow symbolic links",
 --  "        --readonly      Open FILE readonly",
 --  "        --zip           FILE is a ZIP archive",
 --#ifndef SQLITE_SHELL_FIDDLE
 --  ".output ?FILE?           Send output to FILE or stdout if FILE is omitted",
 --  "   If FILE begins with '|' then open it as a pipe.",
 --  "   Options:",
 --  "     --bom                 Prefix output with a UTF8 byte-order mark",
 --  "     -e                    Send output to the system text editor",
 --  "     -x                    Send output as CSV to a spreadsheet",
 --#endif
 --  ".parameter CMD ...       Manage SQL parameter bindings",
 --  "   clear                   Erase all bindings",
 --  "   init                    Initialize the TEMP table that holds bindings",
 --  "   list                    List the current parameter bindings",
 --  "   set PARAMETER VALUE     Given SQL parameter PARAMETER a value of VALUE",
 --  "                           PARAMETER should start with one of: $ : @ ?",
 --  "   unset PARAMETER         Remove PARAMETER from the binding table",
 --  ".print STRING...         Print literal STRING",
 --#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
 --  ".progress N              Invoke progress handler after every N opcodes",
 --  "   --limit N                 Interrupt after N progress callbacks",
 --  "   --once                    Do no more than one progress interrupt",
 --  "   --quiet|-q                No output except at interrupts",
 --  "   --reset                   Reset the count for each input and interrupt",
 --#endif
 --  ".prompt MAIN CONTINUE    Replace the standard prompts",
 --#ifndef SQLITE_SHELL_FIDDLE
 --  ".quit                    Stop interpreting input stream, exit if primary.",
 --  ".read FILE               Read input from FILE or command output",
 --  "    If FILE begins with \"|\", it is a command that generates the input.",
 --#endif
 --#if SQLITE_SHELL_HAVE_RECOVER
 --  ".recover                 Recover as much data as possible from corrupt db.",
 --  "   --ignore-freelist        Ignore pages that appear to be on db freelist",
 --  "   --lost-and-found TABLE   Alternative name for the lost-and-found table",
 --  "   --no-rowids              Do not attempt to recover rowid values",
 --  "                            that are not also INTEGER PRIMARY KEYs",
 --#endif
 --#ifndef SQLITE_SHELL_FIDDLE
 --  ".restore ?DB? FILE       Restore content of DB (default \"main\") from FILE",
 --  ".save ?OPTIONS? FILE     Write database to FILE (an alias for .backup ...)",
 --#endif
 --  ".scanstats on|off|est    Turn sqlite3_stmt_scanstatus() metrics on or off",
 --  ".schema ?PATTERN?        Show the CREATE statements matching PATTERN",
 --  "   Options:",
 --  "      --indent             Try to pretty-print the schema",
 --  "      --nosys              Omit objects whose names start with \"sqlite_\"",
 --  ",selftest ?OPTIONS?      Run tests defined in the SELFTEST table",
 --  "    Options:",
 --  "       --init               Create a new SELFTEST table",
 --  "       -v                   Verbose output",
 --  ".separator COL ?ROW?     Change the column and row separators",
 --#if defined(SQLITE_ENABLE_SESSION)
 --  ".session ?NAME? CMD ...  Create or control sessions",
 --  "   Subcommands:",
 --  "     attach TABLE             Attach TABLE",
 --  "     changeset FILE           Write a changeset into FILE",
 --  "     close                    Close one session",
 --  "     enable ?BOOLEAN?         Set or query the enable bit",
 --  "     filter GLOB...           Reject tables matching GLOBs",
 --  "     indirect ?BOOLEAN?       Mark or query the indirect status",
 --  "     isempty                  Query whether the session is empty",
 --  "     list                     List currently open session names",
 --  "     open DB NAME             Open a new session on DB",
 --  "     patchset FILE            Write a patchset into FILE",
 --  "   If ?NAME? is omitted, the first defined session is used.",
 --#endif
 --  ".sha3sum ...             Compute a SHA3 hash of database content",
 --  "    Options:",
 --  "      --schema              Also hash the sqlite_schema table",
 --  "      --sha3-224            Use the sha3-224 algorithm",
 --  "      --sha3-256            Use the sha3-256 algorithm (default)",
 --  "      --sha3-384            Use the sha3-384 algorithm",
 --  "      --sha3-512            Use the sha3-512 algorithm",
 --  "    Any other argument is a LIKE pattern for tables to hash",
 --#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
 --  ".shell CMD ARGS...       Run CMD ARGS... in a system shell",
 --#endif
 --  ".show                    Show the current values for various settings",
 --  ".stats ?ARG?             Show stats or turn stats on or off",
 --  "   off                      Turn off automatic stat display",
 --  "   on                       Turn on automatic stat display",
 --  "   stmt                     Show statement stats",
 --  "   vmstep                   Show the virtual machine step count only",
 --#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
 --  ".system CMD ARGS...      Run CMD ARGS... in a system shell",
 --#endif
 --  ".tables ?TABLE?          List names of tables matching LIKE pattern TABLE",
 --#ifndef SQLITE_SHELL_FIDDLE
 --  ",testcase NAME           Begin redirecting output to 'testcase-out.txt'",
 --#endif
 --  ",testctrl CMD ...        Run various sqlite3_test_control() operations",
 --  "                           Run \".testctrl\" with no arguments for details",
 --  ".timeout MS              Try opening locked tables for MS milliseconds",
 --  ".timer on|off            Turn SQL timer on or off",
 --#ifndef SQLITE_OMIT_TRACE
 --  ".trace ?OPTIONS?         Output each SQL statement as it is run",
 --  "    FILE                    Send output to FILE",
 --  "    stdout                  Send output to stdout",
 --  "    stderr                  Send output to stderr",
 --  "    off                     Disable tracing",
 --  "    --expanded              Expand query parameters",
 --#ifdef SQLITE_ENABLE_NORMALIZE
 --  "    --normalized            Normal the SQL statements",
 --#endif
 --  "    --plain                 Show SQL as it is input",
 --  "    --stmt                  Trace statement execution (SQLITE_TRACE_STMT)",
 --  "    --profile               Profile statements (SQLITE_TRACE_PROFILE)",
 --  "    --row                   Trace each row (SQLITE_TRACE_ROW)",
 --  "    --close                 Trace connection close (SQLITE_TRACE_CLOSE)",
 --#endif /* SQLITE_OMIT_TRACE */
 --#ifdef SQLITE_DEBUG
 --  ".unmodule NAME ...       Unregister virtual table modules",
 --  "    --allexcept             Unregister everything except those named",
 --#endif
 --  ".version                 Show source, library and compiler versions",
 --  ".vfsinfo ?AUX?           Information about the top-level VFS",
 --  ".vfslist                 List all available VFSes",
 --  ".vfsname ?AUX?           Print the name of the VFS stack",
 --  ".width NUM1 NUM2 ...     Set minimum column widths for columnar output",
 --  "     Negative values right-justify",
 --};
 --
 --/*
 --** Output help text.
 --**
 --** zPattern describes the set of commands for which help text is provided.
 --** If zPattern is NULL, then show all commands, but only give a one-line
 --** description of each.
 --**
 --** Return the number of matches.
 --*/
 --static int showHelp(FILE *out, const char *zPattern){
 --  int i = 0;
 --  int j = 0;
 --  int n = 0;
 --  char *zPat;
 --  if( zPattern==0
 --   || zPattern[0]=='0'
 --   || cli_strcmp(zPattern,"-a")==0
 --   || cli_strcmp(zPattern,"-all")==0
 --   || cli_strcmp(zPattern,"--all")==0
 --  ){
 --    enum HelpWanted { HW_NoCull = 0, HW_SummaryOnly = 1, HW_Undoc = 2 };
 --    enum HelpHave { HH_Undoc = 2, HH_Summary = 1, HH_More = 0 };
 --    /* Show all or most commands
 --    ** *zPattern==0   => summary of documented commands only
 --    ** *zPattern=='0' => whole help for undocumented commands
 --    ** Otherwise      => whole help for documented commands
 --    */
 --    enum HelpWanted hw = HW_SummaryOnly;
 --    enum HelpHave hh = HH_More;
 --    if( zPattern!=0 ){
 --      hw = (*zPattern=='0')? HW_NoCull|HW_Undoc : HW_NoCull;
 --    }
 --    for(i=0; i<ArraySize(azHelp); i++){
 --      switch( azHelp[i][0] ){
 --      case ',':
 --        hh = HH_Summary|HH_Undoc;
 --        break;
 --      case '.':
 --        hh = HH_Summary;
 --        break;
 --      default:
 --        hh &= ~HH_Summary;
 --        break;
 --      }
 --      if( ((hw^hh)&HH_Undoc)==0 ){
 --        if( (hh&HH_Summary)!=0 ){
 --          utf8_printf(out, ".%s\n", azHelp[i]+1);
 --          ++n;
 --        }else if( (hw&HW_SummaryOnly)==0 ){
 --          utf8_printf(out, "%s\n", azHelp[i]);
 ++    else
 ++    if( psi->openMode==SHELL_OPEN_DESERIALIZE
 ++        || psi->openMode==SHELL_OPEN_HEXDB ){
 ++      int rc;
 ++      int nData = 0;
 ++      unsigned char *aData;
 ++      if( psi->openMode==SHELL_OPEN_DESERIALIZE ){
 ++        aData = (unsigned char*)readFile(zDbFilename, &nData);
 ++      }else{
 ++        aData = readHexDb(psi, &nData);
 ++        if( aData==0 ){
 ++          return;
           }
         }
 --    }
 --  }else{
 --    /* Seek documented commands for which zPattern is an exact prefix */
 --    zPat = sqlite3_mprintf(".%s*", zPattern);
 --    shell_check_oom(zPat);
 --    for(i=0; i<ArraySize(azHelp); i++){
 --      if( sqlite3_strglob(zPat, azHelp[i])==0 ){
 --        utf8_printf(out, "%s\n", azHelp[i]);
 --        j = i+1;
 --        n++;
 ++      rc = sqlite3_deserialize(DBX(psx), "main", aData, nData, nData,
 ++                   SQLITE_DESERIALIZE_RESIZEABLE |
 ++                   SQLITE_DESERIALIZE_FREEONCLOSE);
 ++      if( rc ){
 ++        utf8_printf(STD_ERR, "Error: sqlite3_deserialize() returns %d\n", rc);
         }
 --    }
 --    sqlite3_free(zPat);
 --    if( n ){
 --      if( n==1 ){
 --        /* when zPattern is a prefix of exactly one command, then include
 --        ** the details of that command, which should begin at offset j */
 --        while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){
 --          utf8_printf(out, "%s\n", azHelp[j]);
 --          j++;
 --        }
 ++      if( psi->szMax>0 ){
 ++        sqlite3_file_control(DBX(psx), "main", SQLITE_FCNTL_SIZE_LIMIT,
 ++                             &psi->szMax);
         }
 --      return n;
       }
 --    /* Look for documented commands that contain zPattern anywhere.
 --    ** Show complete text of all documented commands that match. */
 --    zPat = sqlite3_mprintf("%%%s%%", zPattern);
 --    shell_check_oom(zPat);
 --    for(i=0; i<ArraySize(azHelp); i++){
 --      if( azHelp[i][0]==',' ){
 --        while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i;
 --        continue;
 --      }
 --      if( azHelp[i][0]=='.' ) j = i;
 --      if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
 --        utf8_printf(out, "%s\n", azHelp[j]);
 --        while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){
 --          j++;
 --          utf8_printf(out, "%s\n", azHelp[j]);
 --        }
 --        i = j;
 --        n++;
 ++#endif
 ++    if( DBX(psx)!=0 ){
 ++      if( psi->bSafeModeFuture ){
 ++        sqlite3_set_authorizer(DBX(psx), safeModeAuth, psx);
         }
 ++      sqlite3_db_config(
 ++           DBX(psx), SQLITE_DBCONFIG_STMT_SCANSTATUS, psi->scanstatsOn,(int*)0);
       }
 --    sqlite3_free(zPat);
 ++#if SHELL_DYNAMIC_EXTENSION
 ++    notify_subscribers(psi, NK_DbUserAppeared, DBX(psx));
 ++#endif
     }
 --  return n;
   }
   
 --/* Forward reference */
 --static int process_input(ShellState *p);
 --
   /*
 --** Read the content of file zName into memory obtained from sqlite3_malloc64()
 --** and return a pointer to the buffer. The caller is responsible for freeing
 --** the memory.
 --**
 --** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
 --** read.
 --**
 --** For convenience, a nul-terminator byte is always appended to the data read
 --** from the file before the buffer is returned. This byte is not included in
 --** the final value of (*pnByte), if applicable.
 --**
 --** NULL is returned if any error is encountered. The final value of *pnByte
 --** is undefined in this case.
 ++** Attempt to close the database connection. Report errors.
   */
 --static char *readFile(const char *zName, int *pnByte){
 --  FILE *in = fopen(zName, "rb");
 --  long nIn;
 --  size_t nRead;
 --  char *pBuf;
 ++void close_db(sqlite3 *db){
     int rc;
 --  if( in==0 ) return 0;
 --  rc = fseek(in, 0, SEEK_END);
 --  if( rc!=0 ){
 --    raw_printf(stderr, "Error: '%s' not seekable\n", zName);
 --    fclose(in);
 --    return 0;
 --  }
 --  nIn = ftell(in);
 --  rewind(in);
 --  pBuf = sqlite3_malloc64( nIn+1 );
 --  if( pBuf==0 ){
 --    raw_printf(stderr, "Error: out of memory\n");
 --    fclose(in);
 --    return 0;
 ++  if( db==globalDb ){
+++    /* This should only block for the time needed to handle ^C interrupt. */
 ++    sqlite3_mutex_enter(pGlobalDbLock);
 ++    globalDb = 0;
 ++    rc = sqlite3_close(db);
 ++    sqlite3_mutex_leave(pGlobalDbLock);
 ++  }else{
 ++    rc = sqlite3_close(db);
     }
 --  nRead = fread(pBuf, nIn, 1, in);
 --  fclose(in);
 --  if( nRead!=1 ){
 --    sqlite3_free(pBuf);
 --    raw_printf(stderr, "Error: cannot read '%s'\n", zName);
 --    return 0;
 ++  if( rc ){
 ++    utf8_printf(STD_ERR, "Error: sqlite3_close() returns %d: %s\n",
 ++        rc, sqlite3_errmsg(db));
     }
 --  pBuf[nIn] = 0;
 --  if( pnByte ) *pnByte = nIn;
 --  return pBuf;
   }
   
 --#if defined(SQLITE_ENABLE_SESSION)
 ++#if HAVE_READLINE || HAVE_EDITLINE
   /*
 --** Close a single OpenSession object and release all of its associated
 --** resources.
 ++** Readline completion callbacks
   */
 --static void session_close(OpenSession *pSession){
 --  int i;
 --  sqlite3session_delete(pSession->p);
 --  sqlite3_free(pSession->zName);
 --  for(i=0; i<pSession->nFilter; i++){
 --    sqlite3_free(pSession->azFilter[i]);
 ++static char *readline_completion_generator(const char *text, int state){
 ++  static sqlite3_stmt *pStmt = 0;
 ++  char *zRet;
 ++  if( state==0 ){
 ++    char *zSql;
 ++    sqlite3_finalize(pStmt);
 ++    zSql = smprintf("SELECT DISTINCT candidate COLLATE nocase"
 ++                    " FROM completion(%Q) ORDER BY 1", text);
 ++    shell_check_oom(zSql);
 ++    sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
 ++    sqlite3_free(zSql);
     }
 --  sqlite3_free(pSession->azFilter);
 --  memset(pSession, 0, sizeof(OpenSession));
 --}
 --#endif
 --
 --/*
 --** Close all OpenSession objects and release all associated resources.
 --*/
 --#if defined(SQLITE_ENABLE_SESSION)
 --static void session_close_all(ShellState *p, int i){
 --  int j;
 --  struct AuxDb *pAuxDb = i<0 ? p->pAuxDb : &p->aAuxDb[i];
 --  for(j=0; j<pAuxDb->nSession; j++){
 --    session_close(&pAuxDb->aSession[j]);
 ++  if( sqlite3_step(pStmt)==SQLITE_ROW ){
 ++    const char *z = (const char*)sqlite3_column_text(pStmt,0);
 ++    if( z!=0 ){
 ++      zRet = strdup(z);
 ++      shell_check_oom(zRet);
 ++    }
 ++  }else{
 ++    sqlite3_finalize(pStmt);
 ++    pStmt = 0;
 ++    zRet = 0;
     }
 --  pAuxDb->nSession = 0;
 ++  return zRet;
 ++}
 ++static char **readline_completion(const char *zText, int iStart, int iEnd){
 ++  (void)iStart;
 ++  (void)iEnd;
 ++  rl_attempted_completion_over = 1;
 ++  return rl_completion_matches(zText, readline_completion_generator);
   }
 --#else
 --# define session_close_all(X,Y)
 --#endif
   
 ++#elif HAVE_LINENOISE
   /*
 --** Implementation of the xFilter function for an open session.  Omit
 --** any tables named by ".session filter" but let all other table through.
 ++** Linenoise completion callback
   */
 --#if defined(SQLITE_ENABLE_SESSION)
 --static int session_filter(void *pCtx, const char *zTab){
 --  OpenSession *pSession = (OpenSession*)pCtx;
 --  int i;
 --  for(i=0; i<pSession->nFilter; i++){
 --    if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
 ++static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
 ++  i64 nLine = strlen(zLine);
 ++  i64 i, iStart;
 ++  sqlite3_stmt *pStmt = 0;
 ++  char *zSql;
 ++  char zBuf[1000];
 ++
 ++  if( nLine>(i64)sizeof(zBuf)-30 ) return;
 ++  if( zLine[0]=='.' || zLine[0]=='#') return;
 ++  for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
 ++  if( i==nLine-1 ) return;
 ++  iStart = i+1;
 ++  memcpy(zBuf, zLine, iStart);
 ++  zSql = smprintf("SELECT DISTINCT candidate COLLATE nocase"
 ++                  " FROM completion(%Q,%Q) ORDER BY 1",
 ++                  &zLine[iStart], zLine);
 ++  shell_check_oom(zSql);
 ++  sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
 ++  sqlite3_free(zSql);
 ++  sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
 ++  while( sqlite3_step(pStmt)==SQLITE_ROW ){
 ++    const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
 ++    int nCompletion = sqlite3_column_bytes(pStmt, 0);
 ++    if( iStart+nCompletion < (i64)sizeof(zBuf)-1 && zCompletion ){
 ++      memcpy(zBuf+iStart, zCompletion, nCompletion+1);
 ++      linenoiseAddCompletion(lc, zBuf);
 ++    }
     }
 --  return 1;
 ++  sqlite3_finalize(pStmt);
   }
   #endif
   
   /*
 --** Try to deduce the type of file for zName based on its content.  Return
 --** one of the SHELL_OPEN_* constants.
 ++** Do C-language style escape sequence translation.
   **
 --** If the file does not exist or is empty but its name looks like a ZIP
 --** archive and the dfltZip flag is true, then assume it is a ZIP archive.
 --** Otherwise, assume an ordinary database regardless of the filename if
 --** the type cannot be determined from content.
 ++**    \a    -> alarm
 ++**    \b    -> backspace
 ++**    \t    -> tab
 ++**    \n    -> newline
 ++**    \v    -> vertical tab
 ++**    \f    -> form feed
 ++**    \r    -> carriage return
 ++**    \s    -> space
 ++**    \"    -> "
 ++**    \'    -> '
 ++**    \\    -> backslash
 ++**    \NNN  -> ascii character NNN in octal
 ++**    \xHH  -> ascii character HH in hexadecimal
   */
 --int deduceDatabaseType(const char *zName, int dfltZip){
 --  FILE *f = fopen(zName, "rb");
 --  size_t n;
 --  int rc = SHELL_OPEN_UNSPEC;
 --  char zBuf[100];
 --  if( f==0 ){
 --    if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
 --       return SHELL_OPEN_ZIPFILE;
 --    }else{
 --       return SHELL_OPEN_NORMAL;
 --    }
 --  }
 --  n = fread(zBuf, 16, 1, f);
 --  if( n==1 && memcmp(zBuf, "SQLite format 3", 16)==0 ){
 --    fclose(f);
 --    return SHELL_OPEN_NORMAL;
 --  }
 --  fseek(f, -25, SEEK_END);
 --  n = fread(zBuf, 25, 1, f);
 --  if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){
 --    rc = SHELL_OPEN_APPENDVFS;
 --  }else{
 --    fseek(f, -22, SEEK_END);
 --    n = fread(zBuf, 22, 1, f);
 --    if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05
 --       && zBuf[3]==0x06 ){
 --      rc = SHELL_OPEN_ZIPFILE;
 --    }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
 --      rc = SHELL_OPEN_ZIPFILE;
 ++static void resolve_backslashes(char *z){
 ++  int i, j;
 ++  char c;
 ++  while( *z && *z!='\\' ) z++;
 ++  for(i=j=0; (c = z[i])!=0; i++, j++){
 ++    if( c=='\\' && z[i+1]!=0 ){
 ++      c = z[++i];
 ++      if( c=='a' ){
 ++        c = '\a';
 ++      }else if( c=='b' ){
 ++        c = '\b';
 ++      }else if( c=='t' ){
 ++        c = '\t';
 ++      }else if( c=='n' ){
 ++        c = '\n';
 ++      }else if( c=='v' ){
 ++        c = '\v';
 ++      }else if( c=='f' ){
 ++        c = '\f';
 ++      }else if( c=='r' ){
 ++        c = '\r';
 ++      }else if( c=='"' ){
 ++        c = '"';
 ++      }else if( c=='\'' ){
 ++        c = '\'';
 ++      }else if( c=='\\' ){
 ++        c = '\\';
 ++      }else if( c=='x' ){
 ++        int nhd = 0, hdv;
 ++        u8 hv = 0;
 ++        while( nhd<2 && (c=z[i+1+nhd])!=0 && (hdv=hexDigitValue(c))>=0 ){
 ++          hv = (u8)((hv<<4)|hdv);
 ++          ++nhd;
 ++        }
 ++        i += nhd;
 ++        c = hv;
 ++      }else if( c>='0' && c<='7' ){
 ++        c -= '0';
 ++        if( z[i+1]>='0' && z[i+1]<='7' ){
 ++          i++;
 ++          c = (c<<3) + z[i] - '0';
 ++          if( z[i+1]>='0' && z[i+1]<='7' ){
 ++            i++;
 ++            c = (c<<3) + z[i] - '0';
 ++          }
 ++        }
 ++      }
       }
 ++    z[j] = c;
     }
 --  fclose(f);
 --  return rc;
 ++  if( j<i ) z[j] = 0;
   }
   
 --#ifndef SQLITE_OMIT_DESERIALIZE
   /*
 --** Reconstruct an in-memory database using the output from the "dbtotxt"
 --** program.  Read content from the file in p->aAuxDb[].zDbFilename.
 --** If p->aAuxDb[].zDbFilename is 0, then read from standard input.
 ++** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
 ++** for TRUE and FALSE.  Return the integer value if appropriate.
   */
 --static unsigned char *readHexDb(ShellState *p, int *pnData){
 --  unsigned char *a = 0;
 --  int nLine;
 --  int n = 0;
 --  int pgsz = 0;
 --  int iOffset = 0;
 --  int j, k;
 --  int rc;
 --  FILE *in;
 --  const char *zDbFilename = p->pAuxDb->zDbFilename;
 --  unsigned int x[16];
 --  char zLine[1000];
 --  if( zDbFilename ){
 --    in = fopen(zDbFilename, "r");
 --    if( in==0 ){
 --      utf8_printf(stderr, "cannot open \"%s\" for reading\n", zDbFilename);
 --      return 0;
 --    }
 --    nLine = 0;
 ++static int booleanValue(const char *zArg){
 ++  static const char *zBoolNames[] = {
 ++    "no","yes", "off","on",
 ++#ifdef BOOLNAMES_ARE_BOOLEAN
 ++    "false","true",
 ++#endif
 ++    0
 ++  };
 ++  int i;
 ++  if( zArg[0]=='0' && zArg[1]=='x' ){
 ++    for(i=2; hexDigitValue(zArg[i])>=0; i++){}
     }else{
 --    in = p->in;
 --    nLine = p->lineno;
 --    if( in==0 ) in = stdin;
 --  }
 --  *pnData = 0;
 --  nLine++;
 --  if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
 --  rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
 --  if( rc!=2 ) goto readHexDb_error;
 --  if( n<0 ) goto readHexDb_error;
 --  if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error;
 --  n = (n+pgsz-1)&~(pgsz-1);  /* Round n up to the next multiple of pgsz */
 --  a = sqlite3_malloc( n ? n : 1 );
 --  shell_check_oom(a);
 --  memset(a, 0, n);
 --  if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
 --    utf8_printf(stderr, "invalid pagesize\n");
 --    goto readHexDb_error;
 --  }
 --  for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
 --    rc = sscanf(zLine, "| page %d offset %d", &j, &k);
 --    if( rc==2 ){
 --      iOffset = k;
 --      continue;
 --    }
 --    if( cli_strncmp(zLine, "| end ", 6)==0 ){
 --      break;
 --    }
 --    rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
 --                &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
 --                &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
 --    if( rc==17 ){
 --      k = iOffset+j;
 --      if( k+16<=n && k>=0 ){
 --        int ii;
 --        for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff;
 --      }
 --    }
 ++    for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
     }
 --  *pnData = n;
 --  if( in!=p->in ){
 --    fclose(in);
 --  }else{
 --    p->lineno = nLine;
 ++  if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
 ++  for( i=0; zBoolNames[i]!=0; ++i ){
 ++    if( sqlite3_stricmp(zArg, zBoolNames[i])==0 ) return i&1;
     }
 --  return a;
 ++  utf8_printf(STD_ERR, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
 ++              zArg);
 ++  return 0;
 ++}
   
 --readHexDb_error:
 --  if( in!=p->in ){
 --    fclose(in);
 ++/*
 ++** Set or clear a shell flag according to a boolean value.
 ++*/
 ++static void setOrClearFlag(ShellExState *psx, unsigned mFlag, const char *zArg){
 ++  if( booleanValue(zArg) ){
 ++    ShellSetFlag(psx, mFlag);
     }else{
 --    while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
 --      nLine++;
 --      if(cli_strncmp(zLine, "| end ", 6)==0 ) break;
 --    }
 --    p->lineno = nLine;
 ++    ShellClearFlag(psx, mFlag);
     }
 --  sqlite3_free(a);
 --  utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine);
 --  return 0;
   }
 --#endif /* SQLITE_OMIT_DESERIALIZE */
   
   /*
 --** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X.
 ++** Close an output file, provided it is not stderr or stdout
   */
 --static void shellUSleepFunc(
 --  sqlite3_context *context,
 --  int argcUnused,
 --  sqlite3_value **argv
 --){
 --  int sleep = sqlite3_value_int(argv[0]);
 --  (void)argcUnused;
 --  sqlite3_sleep(sleep/1000);
 --  sqlite3_result_int(context, sleep);
 ++static void output_file_close(FILE *f){
 ++  if( f && f!=STD_OUT && f!=STD_ERR ) fclose(f);
   }
   
 --/* Flags for open_db().
 --**
 --** The default behavior of open_db() is to exit(1) if the database fails to
 --** open.  The OPEN_DB_KEEPALIVE flag changes that so that it prints an error
 --** but still returns without calling exit.
 --**
 --** The OPEN_DB_ZIPFILE flag causes open_db() to prefer to open files as a
 --** ZIP archive if the file does not exist or is empty and its name matches
 --** the *.zip pattern.
 ++/*
 ++** Try to open an output file.   The names "stdout" and "stderr" are
 ++** recognized and do the right thing.  NULL is returned if the output
 ++** filename is "off".
   */
 --#define OPEN_DB_KEEPALIVE   0x001   /* Return after error if true */
 --#define OPEN_DB_ZIPFILE     0x002   /* Open as ZIP if name matches *.zip */
 ++static FILE *output_file_open(const char *zFile, int bTextMode){
 ++  FILE *f;
 ++  if( cli_strcmp(zFile,"stdout")==0 ){
 ++    f = STD_OUT;
 ++  }else if( cli_strcmp(zFile, "stderr")==0 ){
 ++    f = STD_ERR;
 ++  }else if( cli_strcmp(zFile, "off")==0 ){
 ++    f = 0;
 ++  }else{
 ++    f = fopen(zFile, bTextMode ? "w" : "wb");
 ++    if( f==0 ){
 ++      utf8_printf(STD_ERR, "Error: cannot open \"%s\"\n", zFile);
 ++    }
 ++  }
 ++  return f;
 ++}
   
 ++#ifndef SQLITE_OMIT_TRACE
   /*
 --** Make sure the database is open.  If it is not, then open it.  If
 --** the database fails to open, print an error message and exit.
 ++** A routine for handling output from sqlite3_trace().
   */
 --static void open_db(ShellState *p, int openFlags){
 --  if( p->db==0 ){
 --    const char *zDbFilename = p->pAuxDb->zDbFilename;
 --    if( p->openMode==SHELL_OPEN_UNSPEC ){
 --      if( zDbFilename==0 || zDbFilename[0]==0 ){
 --        p->openMode = SHELL_OPEN_NORMAL;
 --      }else{
 --        p->openMode = (u8)deduceDatabaseType(zDbFilename,
 --                             (openFlags & OPEN_DB_ZIPFILE)!=0);
 --      }
 --    }
 --    switch( p->openMode ){
 --      case SHELL_OPEN_APPENDVFS: {
 --        sqlite3_open_v2(zDbFilename, &p->db,
 --           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs");
 --        break;
 --      }
 --      case SHELL_OPEN_HEXDB:
 --      case SHELL_OPEN_DESERIALIZE: {
 --        sqlite3_open(0, &p->db);
 --        break;
 --      }
 --      case SHELL_OPEN_ZIPFILE: {
 --        sqlite3_open(":memory:", &p->db);
 --        break;
 --      }
 --      case SHELL_OPEN_READONLY: {
 --        sqlite3_open_v2(zDbFilename, &p->db,
 --            SQLITE_OPEN_READONLY|p->openFlags, 0);
 ++static int sql_trace_callback(
 ++  unsigned mType,         /* The trace type */
 ++  void *pArg,             /* The shell state pointer */
 ++  void *pP,               /* Usually a pointer to sqlite_stmt */
 ++  void *pX                /* Auxiliary output */
 ++){
 ++  ShellInState *psi = (ShellInState*)pArg;
 ++  sqlite3_stmt *pStmt;
 ++  const char *zSql;
 ++  i64 nSql;
 ++  if( psi->traceOut==0 ) return 0;
 ++  if( mType==SQLITE_TRACE_CLOSE ){
 ++    utf8_printf(psi->traceOut, "-- closing database connection\n");
 ++    return 0;
 ++  }
 ++  if( mType!=SQLITE_TRACE_ROW && pX!=0 && ((const char*)pX)[0]=='-' ){
 ++    zSql = (const char*)pX;
 ++  }else{
 ++    pStmt = (sqlite3_stmt*)pP;
 ++    switch( psi->eTraceType ){
 ++      case SHELL_TRACE_EXPANDED: {
 ++        zSql = sqlite3_expanded_sql(pStmt);
           break;
         }
 --      case SHELL_OPEN_UNSPEC:
 --      case SHELL_OPEN_NORMAL: {
 --        sqlite3_open_v2(zDbFilename, &p->db,
 --           SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
 ++#ifdef SQLITE_ENABLE_NORMALIZE
 ++      case SHELL_TRACE_NORMALIZED: {
 ++        zSql = sqlite3_normalized_sql(pStmt);
           break;
         }
 --    }
 --    globalDb = p->db;
 --    if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
 --      utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
 --          zDbFilename, sqlite3_errmsg(p->db));
 --      if( (openFlags & OPEN_DB_KEEPALIVE)==0 ){
 --        exit(1);
 --      }
 --      sqlite3_close(p->db);
 --      sqlite3_open(":memory:", &p->db);
 --      if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
 --        utf8_printf(stderr,
 --          "Also: unable to open substitute in-memory database.\n"
 --        );
 --        exit(1);
 --      }else{
 --        utf8_printf(stderr,
 --          "Notice: using substitute in-memory database instead of \"%s\"\n",
 --          zDbFilename);
 --      }
 --    }
 --    sqlite3_db_config(p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, (int)0, (int*)0);
 --
 --    /* Reflect the use or absence of --unsafe-testing invocation. */
 --    {
 --      int testmode_on = ShellHasFlag(p,SHFLG_TestingMode);
 --      sqlite3_db_config(p->db, SQLITE_DBCONFIG_TRUSTED_SCHEMA, testmode_on,0);
 --      sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, !testmode_on,0);
 --    }
 --
 --#ifndef SQLITE_OMIT_LOAD_EXTENSION
 --    sqlite3_enable_load_extension(p->db, 1);
 --#endif
 --    sqlite3_shathree_init(p->db, 0, 0);
 --    sqlite3_uint_init(p->db, 0, 0);
 --    sqlite3_decimal_init(p->db, 0, 0);
 --    sqlite3_base64_init(p->db, 0, 0);
 --    sqlite3_base85_init(p->db, 0, 0);
 --    sqlite3_regexp_init(p->db, 0, 0);
 --    sqlite3_ieee_init(p->db, 0, 0);
 --    sqlite3_series_init(p->db, 0, 0);
 --#if SQLITE_SHELL_HAVE_RECOVER
 --    sqlite3_dbdata_init(p->db, 0, 0);
 --#endif
 --#ifndef SQLITE_SHELL_FIDDLE
 --    sqlite3_fileio_init(p->db, 0, 0);
 --    sqlite3_completion_init(p->db, 0, 0);
 --#endif
 --#ifdef SQLITE_HAVE_ZLIB
 --    if( !p->bSafeModePersist ){
 --      sqlite3_zipfile_init(p->db, 0, 0);
 --      sqlite3_sqlar_init(p->db, 0, 0);
 --    }
 --#endif
 --#ifdef SQLITE_SHELL_EXTFUNCS
 --    /* Create a preprocessing mechanism for extensions to make
 --     * their own provisions for being built into the shell.
 --     * This is a short-span macro. See further below for usage.
 --     */
 --#define SHELL_SUB_MACRO(base, variant) base ## _ ## variant
 --#define SHELL_SUBMACRO(base, variant) SHELL_SUB_MACRO(base, variant)
 --    /* Let custom-included extensions get their ..._init() called.
 --     * The WHATEVER_INIT( db, pzErrorMsg, pApi ) macro should cause
 --     * the extension's sqlite3_*_init( db, pzErrorMsg, pApi )
 --     * inititialization routine to be called.
 --     */
 --    {
 --      int irc = SHELL_SUBMACRO(SQLITE_SHELL_EXTFUNCS, INIT)(p->db);
 --    /* Let custom-included extensions expose their functionality.
 --     * The WHATEVER_EXPOSE( db, pzErrorMsg ) macro should cause
 --     * the SQL functions, virtual tables, collating sequences or
 --     * VFS's implemented by the extension to be registered.
 --     */
 --      if( irc==SQLITE_OK
 --          || irc==SQLITE_OK_LOAD_PERMANENTLY ){
 --        SHELL_SUBMACRO(SQLITE_SHELL_EXTFUNCS, EXPOSE)(p->db, 0);
 --      }
 --#undef SHELL_SUB_MACRO
 --#undef SHELL_SUBMACRO
 --    }
 --#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,
 --                            shellModuleSchema, 0, 0);
 --    sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
 --                            shellPutsFunc, 0, 0);
 --    sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0,
 --                            shellUSleepFunc, 0, 0);
 --#ifndef SQLITE_NOHAVE_SYSTEM
 --    sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
 --                            editFunc, 0, 0);
 --    sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
 --                            editFunc, 0, 0);
   #endif
 --
 --    if( p->openMode==SHELL_OPEN_ZIPFILE ){
 --      char *zSql = sqlite3_mprintf(
 --         "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename);
 --      shell_check_oom(zSql);
 --      sqlite3_exec(p->db, zSql, 0, 0, 0);
 --      sqlite3_free(zSql);
 --    }
 --#ifndef SQLITE_OMIT_DESERIALIZE
 --    else
 --    if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){
 --      int rc;
 --      int nData = 0;
 --      unsigned char *aData;
 --      if( p->openMode==SHELL_OPEN_DESERIALIZE ){
 --        aData = (unsigned char*)readFile(zDbFilename, &nData);
 --      }else{
 --        aData = readHexDb(p, &nData);
 --      }
 --      if( aData==0 ){
 --        return;
 --      }
 --      rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
 --                   SQLITE_DESERIALIZE_RESIZEABLE |
 --                   SQLITE_DESERIALIZE_FREEONCLOSE);
 --      if( rc ){
 --        utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc);
 --      }
 --      if( p->szMax>0 ){
 --        sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
 ++      default: {
 ++        zSql = sqlite3_sql(pStmt);
 ++        break;
         }
       }
 --#endif
     }
 --  if( p->db!=0 ){
 --    if( p->bSafeModePersist ){
 --      sqlite3_set_authorizer(p->db, safeModeAuth, p);
 ++  if( zSql==0 ) return 0;
 ++  nSql = strlen(zSql);
 ++  if( nSql>1000000000 ) nSql = 1000000000; /* clamp to 1 billion */
 ++  while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
 ++  switch( mType ){
 ++    case SQLITE_TRACE_ROW:
 ++    case SQLITE_TRACE_STMT: {
 ++      utf8_printf(psi->traceOut, "%.*s;\n", (int)nSql, zSql);
 ++      break;
 ++    }
 ++    case SQLITE_TRACE_PROFILE: {
 ++      sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0;
 ++      utf8_printf(psi->traceOut,"%.*s; -- %lld ns\n", (int)nSql,zSql,nNanosec);
 ++      break;
       }
 --    sqlite3_db_config(
 --        p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, p->scanstatsOn, (int*)0
 --    );
     }
 ++  return 0;
   }
 ++#endif
   
   /*
 --** Attempt to close the databaes connection.  Report errors.
 ++** A no-op routine that runs with the ".breakpoint" dot-command.
 ++** This is a useful spot to set a debugger breakpoint.
 ++**
 ++** This routine does not do anything practical.  The code are there simply
 ++** to prevent the compiler from optimizing this routine out.
   */
 --void close_db(sqlite3 *db){
 --  int rc = sqlite3_close(db);
 --  if( rc ){
 --    utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n",
 --        rc, sqlite3_errmsg(db));
 --  }
 ++static void test_breakpoint(void){
 ++  static int nCall = 0;
 ++  if( (nCall++)==0xffffffff ) printf("Many .breakpoints have run\n");
   }
   
 --#if HAVE_READLINE || HAVE_EDITLINE
   /*
 --** Readline completion callbacks
 ++** An object used to read a CSV and other files for import.
   */
 --static char *readline_completion_generator(const char *text, int state){
 --  static sqlite3_stmt *pStmt = 0;
 --  char *zRet;
 --  if( state==0 ){
 --    char *zSql;
 --    sqlite3_finalize(pStmt);
 --    zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
 --                           "  FROM completion(%Q) ORDER BY 1", text);
 --    shell_check_oom(zSql);
 --    sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
 --    sqlite3_free(zSql);
 --  }
 --  if( sqlite3_step(pStmt)==SQLITE_ROW ){
 --    const char *z = (const char*)sqlite3_column_text(pStmt,0);
 --    zRet = z ? strdup(z) : 0;
 --  }else{
 --    sqlite3_finalize(pStmt);
 --    pStmt = 0;
 --    zRet = 0;
 ++typedef struct ImportCtx ImportCtx;
 ++struct ImportCtx {
 ++  const char *zFile;  /* Name of the input file */
 ++  FILE *in;           /* Read the CSV text from this input stream */
 ++  int (SQLITE_CDECL *xCloser)(FILE*);      /* Func to close in */
 ++  char *z;            /* Accumulated text for a field */
 ++  int n;              /* Number of bytes in z */
 ++  int nAlloc;         /* Space allocated for z[] */
 ++  int nLine;          /* Current line number */
 ++  int nRow;           /* Number of rows imported */
 ++  int nErr;           /* Number of errors encountered */
 ++  int bNotFirst;      /* True if one or more bytes already read */
 ++  int cTerm;          /* Character that terminated the most recent field */
 ++  int cColSep;        /* The column separator character.  (Usually ",") */
 ++  int cRowSep;        /* The row separator character.  (Usually "\n") */
 ++};
 ++
 ++/* Clean up resourced used by an ImportCtx */
 ++static void import_cleanup(ImportCtx *p){
 ++  if( p->in!=0 && p->xCloser!=0 ){
 ++    p->xCloser(p->in);
 ++    p->in = 0;
     }
 --  return zRet;
 ++  sqlite3_free(p->z);
 ++  p->z = 0;
   }
 --static char **readline_completion(const char *zText, int iStart, int iEnd){
 --  (void)iStart;
 --  (void)iEnd;
 --  rl_attempted_completion_over = 1;
 --  return rl_completion_matches(zText, readline_completion_generator);
 ++
 ++/* Append a single byte to z[] */
 ++static void import_append_char(ImportCtx *p, int c){
 ++  if( p->n+1>=p->nAlloc ){
 ++    p->nAlloc += p->nAlloc + 100;
 ++    p->z = sqlite3_realloc64(p->z, p->nAlloc);
 ++    shell_check_oom(p->z);
 ++  }
 ++  p->z[p->n++] = (char)c;
   }
   
 --#elif HAVE_LINENOISE
 --/*
 --** Linenoise completion callback
 - */
 - static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
 -   i64 nLine = strlen(zLine);
 -   i64 i, iStart;
 -   sqlite3_stmt *pStmt = 0;
 -   char *zSql;
 -   char zBuf[1000];
 - 
 -   if( nLine>(i64)sizeof(zBuf)-30 ) return;
 -   if( zLine[0]=='.' || zLine[0]=='#') return;
 -   for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
 -   if( i==nLine-1 ) return;
 -   iStart = i+1;
 -   memcpy(zBuf, zLine, iStart);
 -   zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
 -                          "  FROM completion(%Q,%Q) ORDER BY 1",
 -                          &zLine[iStart], zLine);
 -   shell_check_oom(zSql);
 -   sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
 -   sqlite3_free(zSql);
 -   sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
 -   while( sqlite3_step(pStmt)==SQLITE_ROW ){
 -     const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
 -     int nCompletion = sqlite3_column_bytes(pStmt, 0);
 -     if( iStart+nCompletion < (i64)sizeof(zBuf)-1 && zCompletion ){
 -       memcpy(zBuf+iStart, zCompletion, nCompletion+1);
 -       linenoiseAddCompletion(lc, zBuf);
 -     }
 -   }
 -   sqlite3_finalize(pStmt);
 - }
 - #endif
 - 
 - /*
 - ** Do C-language style dequoting.
 - **
 - **    \a    -> alarm
 - **    \b    -> backspace
 - **    \t    -> tab
 - **    \n    -> newline
 - **    \v    -> vertical tab
 - **    \f    -> form feed
 - **    \r    -> carriage return
 - **    \s    -> space
 - **    \"    -> "
 - **    \'    -> '
 - **    \\    -> backslash
 - **    \NNN  -> ascii character NNN in octal
 - **    \xHH  -> ascii character HH in hexadecimal
 - */
 - static void resolve_backslashes(char *z){
 -   int i, j;
 -   char c;
 -   while( *z && *z!='\\' ) z++;
 -   for(i=j=0; (c = z[i])!=0; i++, j++){
 -     if( c=='\\' && z[i+1]!=0 ){
 -       c = z[++i];
 -       if( c=='a' ){
 -         c = '\a';
 -       }else if( c=='b' ){
 -         c = '\b';
 -       }else if( c=='t' ){
 -         c = '\t';
 -       }else if( c=='n' ){
 -         c = '\n';
 -       }else if( c=='v' ){
 -         c = '\v';
 -       }else if( c=='f' ){
 -         c = '\f';
 -       }else if( c=='r' ){
 -         c = '\r';
 -       }else if( c=='"' ){
 -         c = '"';
 -       }else if( c=='\'' ){
 -         c = '\'';
 -       }else if( c=='\\' ){
 -         c = '\\';
 -       }else if( c=='x' ){
 -         int nhd = 0, hdv;
 -         u8 hv = 0;
 -         while( nhd<2 && (c=z[i+1+nhd])!=0 && (hdv=hexDigitValue(c))>=0 ){
 -           hv = (u8)((hv<<4)|hdv);
 -           ++nhd;
 -         }
 -         i += nhd;
 -         c = (u8)hv;
 -       }else if( c>='0' && c<='7' ){
 -         c -= '0';
 -         if( z[i+1]>='0' && z[i+1]<='7' ){
 -           i++;
 -           c = (c<<3) + z[i] - '0';
 -           if( z[i+1]>='0' && z[i+1]<='7' ){
 -             i++;
 -             c = (c<<3) + z[i] - '0';
 -           }
 -         }
 -       }
 -     }
 -     z[j] = c;
 -   }
 -   if( j<i ) z[j] = 0;
 - }
 - 
 - /*
 - ** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
 - ** for TRUE and FALSE.  Return the integer value if appropriate.
 - */
 - static int booleanValue(const char *zArg){
 -   int i;
 -   if( zArg[0]=='0' && zArg[1]=='x' ){
 -     for(i=2; hexDigitValue(zArg[i])>=0; i++){}
 -   }else{
 -     for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
 -   }
 -   if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
 -   if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
 -     return 1;
 -   }
 -   if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
 -     return 0;
 -   }
 -   utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
 -           zArg);
 -   return 0;
 - }
 - 
 - /*
 - ** Set or clear a shell flag according to a boolean value.
 - */
 - static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){
 -   if( booleanValue(zArg) ){
 -     ShellSetFlag(p, mFlag);
 -   }else{
 -     ShellClearFlag(p, mFlag);
 -   }
 - }
 - 
 - /*
 - ** Close an output file, assuming it is not stderr or stdout
 - */
 - static void output_file_close(FILE *f){
 -   if( f && f!=stdout && f!=stderr ) fclose(f);
 - }
 - 
 - /*
 - ** Try to open an output file.   The names "stdout" and "stderr" are
 - ** recognized and do the right thing.  NULL is returned if the output
 - ** filename is "off".
 - */
 - static FILE *output_file_open(const char *zFile, int bTextMode){
 -   FILE *f;
 -   if( cli_strcmp(zFile,"stdout")==0 ){
 -     f = stdout;
 -   }else if( cli_strcmp(zFile, "stderr")==0 ){
 -     f = stderr;
 -   }else if( cli_strcmp(zFile, "off")==0 ){
 -     f = 0;
 -   }else{
 -     f = fopen(zFile, bTextMode ? "w" : "wb");
 -     if( f==0 ){
 -       utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
 -     }
 -   }
 -   return f;
 - }
 - 
 - #ifndef SQLITE_OMIT_TRACE
 - /*
 - ** A routine for handling output from sqlite3_trace().
 - */
 - static int sql_trace_callback(
 -   unsigned mType,         /* The trace type */
 -   void *pArg,             /* The ShellState pointer */
 -   void *pP,               /* Usually a pointer to sqlite_stmt */
 -   void *pX                /* Auxiliary output */
 - ){
 -   ShellState *p = (ShellState*)pArg;
 -   sqlite3_stmt *pStmt;
 -   const char *zSql;
 -   i64 nSql;
 -   if( p->traceOut==0 ) return 0;
 -   if( mType==SQLITE_TRACE_CLOSE ){
 -     utf8_printf(p->traceOut, "-- closing database connection\n");
 -     return 0;
 -   }
 -   if( mType!=SQLITE_TRACE_ROW && pX!=0 && ((const char*)pX)[0]=='-' ){
 -     zSql = (const char*)pX;
 -   }else{
 -     pStmt = (sqlite3_stmt*)pP;
 -     switch( p->eTraceType ){
 -       case SHELL_TRACE_EXPANDED: {
 -         zSql = sqlite3_expanded_sql(pStmt);
 -         break;
 -       }
 - #ifdef SQLITE_ENABLE_NORMALIZE
 -       case SHELL_TRACE_NORMALIZED: {
 -         zSql = sqlite3_normalized_sql(pStmt);
 -         break;
 -       }
 - #endif
 -       default: {
 -         zSql = sqlite3_sql(pStmt);
 -         break;
 -       }
 -     }
 -   }
 -   if( zSql==0 ) return 0;
 -   nSql = strlen(zSql);
 -   if( nSql>1000000000 ) nSql = 1000000000;
 -   while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
 -   switch( mType ){
 -     case SQLITE_TRACE_ROW:
 -     case SQLITE_TRACE_STMT: {
 -       utf8_printf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
 -       break;
 -     }
 -     case SQLITE_TRACE_PROFILE: {
 -       sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0;
 -       utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
 -       break;
 -     }
 -   }
 -   return 0;
 - }
 - #endif
 - 
 - /*
 - ** A no-op routine that runs with the ".breakpoint" doc-command.  This is
 - ** a useful spot to set a debugger breakpoint.
 - **
 - ** This routine does not do anything practical.  The code are there simply
 - ** to prevent the compiler from optimizing this routine out.
 - */
 - static void test_breakpoint(void){
 -   static unsigned int nCall = 0;
 -   if( (nCall++)==0xffffffff ) printf("Many .breakpoints have run\n");
 - }
 - 
 - /*
 - ** An object used to read a CSV and other files for import.
 - */
 - typedef struct ImportCtx ImportCtx;
 - struct ImportCtx {
 -   const char *zFile;  /* Name of the input file */
 -   FILE *in;           /* Read the CSV text from this input stream */
 -   int (SQLITE_CDECL *xCloser)(FILE*);      /* Func to close in */
 -   char *z;            /* Accumulated text for a field */
 -   int n;              /* Number of bytes in z */
 -   int nAlloc;         /* Space allocated for z[] */
 -   int nLine;          /* Current line number */
 -   int nRow;           /* Number of rows imported */
 -   int nErr;           /* Number of errors encountered */
 -   int bNotFirst;      /* True if one or more bytes already read */
 -   int cTerm;          /* Character that terminated the most recent field */
 -   int cColSep;        /* The column separator character.  (Usually ",") */
 -   int cRowSep;        /* The row separator character.  (Usually "\n") */
 - };
 - 
 - /* Clean up resourced used by an ImportCtx */
 - static void import_cleanup(ImportCtx *p){
 -   if( p->in!=0 && p->xCloser!=0 ){
 -     p->xCloser(p->in);
 -     p->in = 0;
 -   }
 -   sqlite3_free(p->z);
 -   p->z = 0;
 - }
 - 
 - /* Append a single byte to z[] */
 - static void import_append_char(ImportCtx *p, int c){
 -   if( p->n+1>=p->nAlloc ){
 -     p->nAlloc += p->nAlloc + 100;
 -     p->z = sqlite3_realloc64(p->z, p->nAlloc);
 -     shell_check_oom(p->z);
 -   }
 -   p->z[p->n++] = (char)c;
 - }
 - 
 - /* Read a single field of CSV text.  Compatible with rfc4180 and extended
 - ** with the option of having a separator other than ",".
 - **
 - **   +  Input comes from p->in.
 - **   +  Store results in p->z of length p->n.  Space to hold p->z comes
 - **      from sqlite3_malloc64().
 - **   +  Use p->cSep as the column separator.  The default is ",".
 - **   +  Use p->rSep as the row separator.  The default is "\n".
 - **   +  Keep track of the line number in p->nLine.
 - **   +  Store the character that terminates the field in p->cTerm.  Store
 - **      EOF on end-of-file.
 - **   +  Report syntax errors on stderr
 ++/* Read a single field of CSV text.  Compatible with rfc4180 and extended
 ++** with the option of having a separator other than ",".
 ++**
 ++**   +  Input comes from p->in.
 ++**   +  Store results in p->z of length p->n.  Space to hold p->z comes
 ++**      from sqlite3_malloc64().
 ++**   +  Use p->cSep as the column separator.  The default is ",".
 ++**   +  Use p->rSep as the row separator.  The default is "\n".
 ++**   +  Keep track of the line number in p->nLine.
 ++**   +  Store the character that terminates the field in p->cTerm.  Store
 ++**      EOF on end-of-file.
 ++**   +  Report syntax errors on stderr
   */
  -static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
  -  i64 nLine = strlen(zLine);
  -  i64 i, iStart;
  -  sqlite3_stmt *pStmt = 0;
  -  char *zSql;
  -  char zBuf[1000];
  -
  -  if( nLine>(i64)sizeof(zBuf)-30 ) return;
  -  if( zLine[0]=='.' || zLine[0]=='#') return;
  -  for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
  -  if( i==nLine-1 ) return;
  -  iStart = i+1;
  -  memcpy(zBuf, zLine, iStart);
  -  zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
  -                         "  FROM completion(%Q,%Q) ORDER BY 1",
  -                         &zLine[iStart], zLine);
  -  shell_check_oom(zSql);
  -  sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
  -  sqlite3_free(zSql);
  -  sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
  -  while( sqlite3_step(pStmt)==SQLITE_ROW ){
  -    const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
  -    int nCompletion = sqlite3_column_bytes(pStmt, 0);
  -    if( iStart+nCompletion < (i64)sizeof(zBuf)-1 && zCompletion ){
  -      memcpy(zBuf+iStart, zCompletion, nCompletion+1);
  -      linenoiseAddCompletion(lc, zBuf);
  -    }
  +static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
  +  int c;
  +  int cSep = (u8)p->cColSep;
  +  int rSep = (u8)p->cRowSep;
  +  p->n = 0;
  +  c = fgetc(p->in);
  +  if( c==EOF || seenInterrupt ){
  +    p->cTerm = EOF;
  +    return 0;
     }
  -  sqlite3_finalize(pStmt);
  -}
  -#endif
  -
  -/*
  -** Do C-language style dequoting.
  -**
  -**    \a    -> alarm
  -**    \b    -> backspace
  -**    \t    -> tab
  -**    \n    -> newline
  -**    \v    -> vertical tab
  -**    \f    -> form feed
  -**    \r    -> carriage return
  -**    \s    -> space
  -**    \"    -> "
  -**    \'    -> '
  -**    \\    -> backslash
  -**    \NNN  -> ascii character NNN in octal
  -**    \xHH  -> ascii character HH in hexadecimal
  -*/
  -static void resolve_backslashes(char *z){
  -  int i, j;
  -  char c;
  -  while( *z && *z!='\\' ) z++;
  -  for(i=j=0; (c = z[i])!=0; i++, j++){
  -    if( c=='\\' && z[i+1]!=0 ){
  -      c = z[++i];
  -      if( c=='a' ){
  -        c = '\a';
  -      }else if( c=='b' ){
  -        c = '\b';
  -      }else if( c=='t' ){
  -        c = '\t';
  -      }else if( c=='n' ){
  -        c = '\n';
  -      }else if( c=='v' ){
  -        c = '\v';
  -      }else if( c=='f' ){
  -        c = '\f';
  -      }else if( c=='r' ){
  -        c = '\r';
  -      }else if( c=='"' ){
  -        c = '"';
  -      }else if( c=='\'' ){
  -        c = '\'';
  -      }else if( c=='\\' ){
  -        c = '\\';
  -      }else if( c=='x' ){
  -        int nhd = 0, hdv;
  -        u8 hv = 0;
  -        while( nhd<2 && (c=z[i+1+nhd])!=0 && (hdv=hexDigitValue(c))>=0 ){
  -          hv = (u8)((hv<<4)|hdv);
  -          ++nhd;
  +  if( c=='"' ){
  +    int pc, ppc;
  +    int startLine = p->nLine;
  +    int cQuote = c;
  +    pc = ppc = 0;
  +    while( 1 ){
  +      c = fgetc(p->in);
  +      if( c==rSep ) p->nLine++;
  +      if( c==cQuote ){
  +        if( pc==cQuote ){
  +          pc = 0;
  +          continue;
           }
  -        i += nhd;
  -        c = (u8)hv;
  -      }else if( c>='0' && c<='7' ){
  -        c -= '0';
  -        if( z[i+1]>='0' && z[i+1]<='7' ){
  -          i++;
  -          c = (c<<3) + z[i] - '0';
  -          if( z[i+1]>='0' && z[i+1]<='7' ){
  -            i++;
  -            c = (c<<3) + z[i] - '0';
  -          }
  +      }
  +      if( (c==cSep && pc==cQuote)
  +       || (c==rSep && pc==cQuote)
  +       || (c==rSep && pc=='\r' && ppc==cQuote)
  +       || (c==EOF && pc==cQuote)
  +      ){
  +        do{ p->n--; }while( p->z[p->n]!=cQuote );
  +        p->cTerm = c;
  +        break;
  +      }
  +      if( pc==cQuote && c!='\r' ){
 -         utf8_printf(stderr, "%s:%d: unescaped %c character\n",
 ++        utf8_printf(STD_ERR, "%s:%d: unescaped %c character\n",
  +                p->zFile, p->nLine, cQuote);
  +      }
  +      if( c==EOF ){
 -         utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n",
 ++        utf8_printf(STD_ERR, "%s:%d: unterminated %c-quoted field\n",
  +                p->zFile, startLine, cQuote);
  +        p->cTerm = c;
  +        break;
  +      }
  +      import_append_char(p, c);
  +      ppc = pc;
  +      pc = c;
  +    }
  +  }else{
  +    /* If this is the first field being parsed and it begins with the
  +    ** UTF-8 BOM  (0xEF BB BF) then skip the BOM */
  +    if( (c&0xff)==0xef && p->bNotFirst==0 ){
  +      import_append_char(p, c);
  +      c = fgetc(p->in);
  +      if( (c&0xff)==0xbb ){
  +        import_append_char(p, c);
  +        c = fgetc(p->in);
  +        if( (c&0xff)==0xbf ){
  +          p->bNotFirst = 1;
  +          p->n = 0;
  +          return csv_read_one_field(p);
           }
         }
       }
  -    z[j] = c;
  +    while( c!=EOF && c!=cSep && c!=rSep ){
  +      import_append_char(p, c);
  +      c = fgetc(p->in);
  +    }
  +    if( c==rSep ){
  +      p->nLine++;
  +      if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
  +    }
  +    p->cTerm = c;
     }
  -  if( j<i ) z[j] = 0;
  +  if( p->z ) p->z[p->n] = 0;
  +  p->bNotFirst = 1;
  +  return p->z;
   }
   
  -/*
  -** Interpret zArg as either an integer or a boolean value.  Return 1 or 0
  -** for TRUE and FALSE.  Return the integer value if appropriate.
  +/* Read a single field of ASCII delimited text.
  +**
  +**   +  Input comes from p->in.
  +**   +  Store results in p->z of length p->n.  Space to hold p->z comes
  +**      from sqlite3_malloc64().
  +**   +  Use p->cSep as the column separator.  The default is "\x1F".
  +**   +  Use p->rSep as the row separator.  The default is "\x1E".
  +**   +  Keep track of the row number in p->nLine.
  +**   +  Store the character that terminates the field in p->cTerm.  Store
  +**      EOF on end-of-file.
  +**   +  Report syntax errors on stderr
   */
  -static int booleanValue(const char *zArg){
  -  int i;
  -  if( zArg[0]=='0' && zArg[1]=='x' ){
  -    for(i=2; hexDigitValue(zArg[i])>=0; i++){}
  -  }else{
  -    for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
  -  }
  -  if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
  -  if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
  -    return 1;
  -  }
  -  if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
  +static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
  +  int c;
  +  int cSep = (u8)p->cColSep;
  +  int rSep = (u8)p->cRowSep;
  +  p->n = 0;
  +  c = fgetc(p->in);
  +  if( c==EOF || seenInterrupt ){
  +    p->cTerm = EOF;
       return 0;
     }
  -  utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
  -          zArg);
  -  return 0;
  -}
  -
  -/*
  -** Set or clear a shell flag according to a boolean value.
  -*/
  -static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){
  -  if( booleanValue(zArg) ){
  -    ShellSetFlag(p, mFlag);
  -  }else{
  -    ShellClearFlag(p, mFlag);
  +  while( c!=EOF && c!=cSep && c!=rSep ){
  +    import_append_char(p, c);
  +    c = fgetc(p->in);
     }
  -}
  -
  -/*
  -** Close an output file, assuming it is not stderr or stdout
  -*/
  -static void output_file_close(FILE *f){
  -  if( f && f!=stdout && f!=stderr ) fclose(f);
  -}
  -
  -/*
  -** Try to open an output file.   The names "stdout" and "stderr" are
  -** recognized and do the right thing.  NULL is returned if the output
  -** filename is "off".
  -*/
  -static FILE *output_file_open(const char *zFile, int bTextMode){
  -  FILE *f;
  -  if( cli_strcmp(zFile,"stdout")==0 ){
  -    f = stdout;
  -  }else if( cli_strcmp(zFile, "stderr")==0 ){
  -    f = stderr;
  -  }else if( cli_strcmp(zFile, "off")==0 ){
  -    f = 0;
  -  }else{
  -    f = fopen(zFile, bTextMode ? "w" : "wb");
  -    if( f==0 ){
  -      utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
  -    }
  +  if( c==rSep ){
  +    p->nLine++;
     }
  -  return f;
  +  p->cTerm = c;
  +  if( p->z ) p->z[p->n] = 0;
  +  return p->z;
   }
   
  -#ifndef SQLITE_OMIT_TRACE
   /*
  -** A routine for handling output from sqlite3_trace().
  +** Try to transfer data for table zTable.  If an error is seen while
  +** moving forward, try to go backwards.  The backwards movement won't
  +** work for WITHOUT ROWID tables.
   */
  -static int sql_trace_callback(
  -  unsigned mType,         /* The trace type */
  -  void *pArg,             /* The ShellState pointer */
  -  void *pP,               /* Usually a pointer to sqlite_stmt */
  -  void *pX                /* Auxiliary output */
  -){
  -  ShellState *p = (ShellState*)pArg;
  -  sqlite3_stmt *pStmt;
  -  const char *zSql;
  -  i64 nSql;
  -  if( p->traceOut==0 ) return 0;
  -  if( mType==SQLITE_TRACE_CLOSE ){
  -    utf8_printf(p->traceOut, "-- closing database connection\n");
  -    return 0;
  -  }
  -  if( mType!=SQLITE_TRACE_ROW && pX!=0 && ((const char*)pX)[0]=='-' ){
  -    zSql = (const char*)pX;
  -  }else{
  -    pStmt = (sqlite3_stmt*)pP;
  -    switch( p->eTraceType ){
  -      case SHELL_TRACE_EXPANDED: {
  -        zSql = sqlite3_expanded_sql(pStmt);
  -        break;
  -      }
  -#ifdef SQLITE_ENABLE_NORMALIZE
  -      case SHELL_TRACE_NORMALIZED: {
  -        zSql = sqlite3_normalized_sql(pStmt);
  -        break;
  -      }
  -#endif
  -      default: {
  -        zSql = sqlite3_sql(pStmt);
  -        break;
  -      }
  -    }
  -  }
  -  if( zSql==0 ) return 0;
  -  nSql = strlen(zSql);
  -  if( nSql>1000000000 ) nSql = 1000000000;
  -  while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
  -  switch( mType ){
  -    case SQLITE_TRACE_ROW:
  -    case SQLITE_TRACE_STMT: {
  -      utf8_printf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
  -      break;
  -    }
  -    case SQLITE_TRACE_PROFILE: {
  -      sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0;
  -      utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
  -      break;
  -    }
  -  }
  -  return 0;
  -}
  -#endif
  -
  -/*
  -** A no-op routine that runs with the ".breakpoint" doc-command.  This is
  -** a useful spot to set a debugger breakpoint.
  -**
  -** This routine does not do anything practical.  The code are there simply
  -** to prevent the compiler from optimizing this routine out.
  -*/
  -static void test_breakpoint(void){
  -  static unsigned int nCall = 0;
  -  if( (nCall++)==0xffffffff ) printf("Many .breakpoints have run\n");
  -}
  -
  -/*
  -** An object used to read a CSV and other files for import.
  -*/
  -typedef struct ImportCtx ImportCtx;
  -struct ImportCtx {
  -  const char *zFile;  /* Name of the input file */
  -  FILE *in;           /* Read the CSV text from this input stream */
  -  int (SQLITE_CDECL *xCloser)(FILE*);      /* Func to close in */
  -  char *z;            /* Accumulated text for a field */
  -  int n;              /* Number of bytes in z */
  -  int nAlloc;         /* Space allocated for z[] */
  -  int nLine;          /* Current line number */
  -  int nRow;           /* Number of rows imported */
  -  int nErr;           /* Number of errors encountered */
  -  int bNotFirst;      /* True if one or more bytes already read */
  -  int cTerm;          /* Character that terminated the most recent field */
  -  int cColSep;        /* The column separator character.  (Usually ",") */
  -  int cRowSep;        /* The row separator character.  (Usually "\n") */
  -};
  -
  -/* Clean up resourced used by an ImportCtx */
  -static void import_cleanup(ImportCtx *p){
  -  if( p->in!=0 && p->xCloser!=0 ){
  -    p->xCloser(p->in);
  -    p->in = 0;
  -  }
  -  sqlite3_free(p->z);
  -  p->z = 0;
  -}
  -
  -/* Append a single byte to z[] */
  -static void import_append_char(ImportCtx *p, int c){
  -  if( p->n+1>=p->nAlloc ){
  -    p->nAlloc += p->nAlloc + 100;
  -    p->z = sqlite3_realloc64(p->z, p->nAlloc);
  -    shell_check_oom(p->z);
  -  }
  -  p->z[p->n++] = (char)c;
  -}
  -
  -/* Read a single field of CSV text.  Compatible with rfc4180 and extended
  -** with the option of having a separator other than ",".
  -**
  -**   +  Input comes from p->in.
  -**   +  Store results in p->z of length p->n.  Space to hold p->z comes
  -**      from sqlite3_malloc64().
  -**   +  Use p->cSep as the column separator.  The default is ",".
  -**   +  Use p->rSep as the row separator.  The default is "\n".
  -**   +  Keep track of the line number in p->nLine.
  -**   +  Store the character that terminates the field in p->cTerm.  Store
  -**      EOF on end-of-file.
  -**   +  Report syntax errors on stderr
  -*/
  -static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
  -  int c;
  -  int cSep = (u8)p->cColSep;
  -  int rSep = (u8)p->cRowSep;
  -  p->n = 0;
  -  c = fgetc(p->in);
  -  if( c==EOF || seenInterrupt ){
  -    p->cTerm = EOF;
  -    return 0;
  -  }
  -  if( c=='"' ){
  -    int pc, ppc;
  -    int startLine = p->nLine;
  -    int cQuote = c;
  -    pc = ppc = 0;
  -    while( 1 ){
  -      c = fgetc(p->in);
  -      if( c==rSep ) p->nLine++;
  -      if( c==cQuote ){
  -        if( pc==cQuote ){
  -          pc = 0;
  -          continue;
  -        }
  -      }
  -      if( (c==cSep && pc==cQuote)
  -       || (c==rSep && pc==cQuote)
  -       || (c==rSep && pc=='\r' && ppc==cQuote)
  -       || (c==EOF && pc==cQuote)
  -      ){
  -        do{ p->n--; }while( p->z[p->n]!=cQuote );
  -        p->cTerm = c;
  -        break;
  -      }
  -      if( pc==cQuote && c!='\r' ){
  -        utf8_printf(stderr, "%s:%d: unescaped %c character\n",
  -                p->zFile, p->nLine, cQuote);
  -      }
  -      if( c==EOF ){
  -        utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n",
  -                p->zFile, startLine, cQuote);
  -        p->cTerm = c;
  -        break;
  -      }
  -      import_append_char(p, c);
  -      ppc = pc;
  -      pc = c;
  -    }
  -  }else{
  -    /* If this is the first field being parsed and it begins with the
  -    ** UTF-8 BOM  (0xEF BB BF) then skip the BOM */
  -    if( (c&0xff)==0xef && p->bNotFirst==0 ){
  -      import_append_char(p, c);
  -      c = fgetc(p->in);
  -      if( (c&0xff)==0xbb ){
  -        import_append_char(p, c);
  -        c = fgetc(p->in);
  -        if( (c&0xff)==0xbf ){
  -          p->bNotFirst = 1;
  -          p->n = 0;
  -          return csv_read_one_field(p);
  -        }
  -      }
  -    }
  -    while( c!=EOF && c!=cSep && c!=rSep ){
  -      import_append_char(p, c);
  -      c = fgetc(p->in);
  -    }
  -    if( c==rSep ){
  -      p->nLine++;
  -      if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
  -    }
  -    p->cTerm = c;
  -  }
  -  if( p->z ) p->z[p->n] = 0;
  -  p->bNotFirst = 1;
  -  return p->z;
  -}
  -
  -/* Read a single field of ASCII delimited text.
  -**
  -**   +  Input comes from p->in.
  -**   +  Store results in p->z of length p->n.  Space to hold p->z comes
  -**      from sqlite3_malloc64().
  -**   +  Use p->cSep as the column separator.  The default is "\x1F".
  -**   +  Use p->rSep as the row separator.  The default is "\x1E".
  -**   +  Keep track of the row number in p->nLine.
  -**   +  Store the character that terminates the field in p->cTerm.  Store
  -**      EOF on end-of-file.
  -**   +  Report syntax errors on stderr
  -*/
  -static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
  -  int c;
  -  int cSep = (u8)p->cColSep;
  -  int rSep = (u8)p->cRowSep;
  -  p->n = 0;
  -  c = fgetc(p->in);
  -  if( c==EOF || seenInterrupt ){
  -    p->cTerm = EOF;
  -    return 0;
  -  }
  -  while( c!=EOF && c!=cSep && c!=rSep ){
  -    import_append_char(p, c);
  -    c = fgetc(p->in);
  -  }
  -  if( c==rSep ){
  -    p->nLine++;
  -  }
  -  p->cTerm = c;
  -  if( p->z ) p->z[p->n] = 0;
  -  return p->z;
  -}
  -
  -/*
  -** Try to transfer data for table zTable.  If an error is seen while
  -** moving forward, try to go backwards.  The backwards movement won't
  -** work for WITHOUT ROWID tables.
  -*/
  -static void tryToCloneData(
  -  ShellState *p,
  -  sqlite3 *newDb,
  -  const char *zTable
  +static void tryToCloneData(
 -   ShellState *p,
 ++  ShellExState *psx,
  +  sqlite3 *newDb,
  +  const char *zTable
   ){
     sqlite3_stmt *pQuery = 0;
     sqlite3_stmt *pInsert = 0;
@@@@ -7008,38 -6590,235 -6589,235 +7063,38 @@@@ static void shellFkeyCollateClause
     }
   }
   
 - 
 - /*
 - ** The implementation of dot-command ".lint fkey-indexes".
 - */
 - static int lintFkeyIndexes(
 -   ShellState *pState,             /* Current shell tool state */
 -   char **azArg,                   /* Array of arguments passed to dot command */
 -   int nArg                        /* Number of entries in azArg[] */
 - ){
 -   sqlite3 *db = pState->db;       /* Database handle to query "main" db of */
 -   FILE *out = pState->out;        /* Stream to write non-error output to */
 -   int bVerbose = 0;               /* If -verbose is present */
 -   int bGroupByParent = 0;         /* If -groupbyparent is present */
 -   int i;                          /* To iterate through azArg[] */
 -   const char *zIndent = "";       /* How much to indent CREATE INDEX by */
 -   int rc;                         /* Return code */
 -   sqlite3_stmt *pSql = 0;         /* Compiled version of SQL statement below */
 - 
 -   /*
 -   ** This SELECT statement returns one row for each foreign key constraint
 -   ** in the schema of the main database. The column values are:
 -   **
 -   ** 0. The text of an SQL statement similar to:
 -   **
 -   **      "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
 -   **
 -   **    This SELECT is similar to the one that the foreign keys implementation
 -   **    needs to run internally on child tables. If there is an index that can
 -   **    be used to optimize this query, then it can also be used by the FK
 -   **    implementation to optimize DELETE or UPDATE statements on the parent
 -   **    table.
 -   **
 -   ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
 -   **    the EXPLAIN QUERY PLAN command matches this pattern, then the schema
 -   **    contains an index that can be used to optimize the query.
 -   **
 -   ** 2. Human readable text that describes the child table and columns. e.g.
 -   **
 -   **       "child_table(child_key1, child_key2)"
 -   **
 -   ** 3. Human readable text that describes the parent table and columns. e.g.
 -   **
 -   **       "parent_table(parent_key1, parent_key2)"
 -   **
 -   ** 4. A full CREATE INDEX statement for an index that could be used to
 -   **    optimize DELETE or UPDATE statements on the parent table. e.g.
 -   **
 -   **       "CREATE INDEX child_table_child_key ON child_table(child_key)"
 -   **
 -   ** 5. The name of the parent table.
 -   **
 -   ** These six values are used by the C logic below to generate the report.
 -   */
 -   const char *zSql =
 -   "SELECT "
 -     "     'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
 -     "  || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
 -     "  || fkey_collate_clause("
 -     "       f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
 -     ", "
 -     "     'SEARCH ' || s.name || ' USING COVERING INDEX*('"
 -     "  || group_concat('*=?', ' AND ') || ')'"
 -     ", "
 -     "     s.name  || '(' || group_concat(f.[from],  ', ') || ')'"
 -     ", "
 -     "     f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
 -     ", "
 -     "     'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
 -     "  || ' ON ' || quote(s.name) || '('"
 -     "  || group_concat(quote(f.[from]) ||"
 -     "        fkey_collate_clause("
 -     "          f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
 -     "  || ');'"
 -     ", "
 -     "     f.[table] "
 -     "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f "
 -     "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
 -     "GROUP BY s.name, f.id "
 -     "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
 -   ;
 -   const char *zGlobIPK = "SEARCH * USING INTEGER PRIMARY KEY (rowid=?)";
 - 
 -   for(i=2; i<nArg; i++){
 -     int n = strlen30(azArg[i]);
 -     if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
 -       bVerbose = 1;
 -     }
 -     else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
 -       bGroupByParent = 1;
 -       zIndent = "    ";
 -     }
 -     else{
 -       raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
 -           azArg[0], azArg[1]
 -       );
 -       return SQLITE_ERROR;
 -     }
 -   }
 - 
 -   /* Register the fkey_collate_clause() SQL function */
 -   rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
 -       0, shellFkeyCollateClause, 0, 0
 -   );
 - 
 - 
 -   if( rc==SQLITE_OK ){
 -     rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
 -   }
 -   if( rc==SQLITE_OK ){
 -     sqlite3_bind_int(pSql, 1, bGroupByParent);
 -   }
 - 
 -   if( rc==SQLITE_OK ){
 -     int rc2;
 -     char *zPrev = 0;
 -     while( SQLITE_ROW==sqlite3_step(pSql) ){
 -       int res = -1;
 -       sqlite3_stmt *pExplain = 0;
 -       const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
 -       const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
 -       const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
 -       const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
 -       const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
 -       const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
 - 
 -       if( zEQP==0 ) continue;
 -       if( zGlob==0 ) continue;
 -       rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
 -       if( rc!=SQLITE_OK ) break;
 -       if( SQLITE_ROW==sqlite3_step(pExplain) ){
 -         const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
 -         res = zPlan!=0 && (  0==sqlite3_strglob(zGlob, zPlan)
 -                           || 0==sqlite3_strglob(zGlobIPK, zPlan));
 -       }
 -       rc = sqlite3_finalize(pExplain);
 -       if( rc!=SQLITE_OK ) break;
 - 
 -       if( res<0 ){
 -         raw_printf(stderr, "Error: internal error");
 -         break;
 -       }else{
 -         if( bGroupByParent
 -         && (bVerbose || res==0)
 -         && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
 -         ){
 -           raw_printf(out, "-- Parent table %s\n", zParent);
 -           sqlite3_free(zPrev);
 -           zPrev = sqlite3_mprintf("%s", zParent);
 -         }
 - 
 -         if( res==0 ){
 -           raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
 -         }else if( bVerbose ){
 -           raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
 -               zIndent, zFrom, zTarget
 -           );
 -         }
 -       }
 -     }
 -     sqlite3_free(zPrev);
 - 
 -     if( rc!=SQLITE_OK ){
 -       raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
 -     }
 - 
 -     rc2 = sqlite3_finalize(pSql);
 -     if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
 -       rc = rc2;
 -       raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
 -     }
 -   }else{
 -     raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
 -   }
 - 
 -   return rc;
 - }
 - 
 - /*
 - ** Implementation of ".lint" dot command.
 - */
 - static int lintDotCommand(
 -   ShellState *pState,             /* Current shell tool state */
 -   char **azArg,                   /* Array of arguments passed to dot command */
 -   int nArg                        /* Number of entries in azArg[] */
 - ){
 -   int n;
 -   n = (nArg>=2 ? strlen30(azArg[1]) : 0);
 -   if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
 -   return lintFkeyIndexes(pState, azArg, nArg);
 - 
 -  usage:
 -   raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
 -   raw_printf(stderr, "Where sub-commands are:\n");
 -   raw_printf(stderr, "    fkey-indexes\n");
 -   return SQLITE_ERROR;
 - }
 - 
  +#if !defined SQLITE_OMIT_VIRTUALTABLE
  +static void shellPrepare(
  +  sqlite3 *db,
  +  int *pRc,
  +  const char *zSql,
  +  sqlite3_stmt **ppStmt
  +){
  +  *ppStmt = 0;
  +  if( *pRc==SQLITE_OK ){
  +    int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
  +    if( rc!=SQLITE_OK ){
 -       raw_printf(stderr, "sql error: %s (%d)\n",
 ++      raw_printf(STD_ERR, "sql error: %s (%d)\n",
  +          sqlite3_errmsg(db), sqlite3_errcode(db)
  +      );
  +      *pRc = rc;
  +    }
  +  }
  +}
   
   /*
  -** The implementation of dot-command ".lint fkey-indexes".
  +** Create a prepared statement using printf-style arguments for the SQL.
  +**
  +** This routine is could be marked "static".  But it is not always used,
  +** depending on compile-time options.  By omitting the "static", we avoid
  +** nuisance compiler warnings about "defined but not used".
   */
  -static int lintFkeyIndexes(
  -  ShellState *pState,             /* Current shell tool state */
  -  char **azArg,                   /* Array of arguments passed to dot command */
  -  int nArg                        /* Number of entries in azArg[] */
  -){
  -  sqlite3 *db = pState->db;       /* Database handle to query "main" db of */
  -  FILE *out = pState->out;        /* Stream to write non-error output to */
  -  int bVerbose = 0;               /* If -verbose is present */
  -  int bGroupByParent = 0;         /* If -groupbyparent is present */
  -  int i;                          /* To iterate through azArg[] */
  -  const char *zIndent = "";       /* How much to indent CREATE INDEX by */
  -  int rc;                         /* Return code */
  -  sqlite3_stmt *pSql = 0;         /* Compiled version of SQL statement below */
  -
  -  /*
  -  ** This SELECT statement returns one row for each foreign key constraint
  -  ** in the schema of the main database. The column values are:
  -  **
  -  ** 0. The text of an SQL statement similar to:
  -  **
  -  **      "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
  -  **
  -  **    This SELECT is similar to the one that the foreign keys implementation
  -  **    needs to run internally on child tables. If there is an index that can
  -  **    be used to optimize this query, then it can also be used by the FK
  -  **    implementation to optimize DELETE or UPDATE statements on the parent
  -  **    table.
  -  **
  -  ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
  -  **    the EXPLAIN QUERY PLAN command matches this pattern, then the schema
  -  **    contains an index that can be used to optimize the query.
  -  **
  -  ** 2. Human readable text that describes the child table and columns. e.g.
  -  **
  -  **       "child_table(child_key1, child_key2)"
  -  **
  -  ** 3. Human readable text that describes the parent table and columns. e.g.
  -  **
  -  **       "parent_table(parent_key1, parent_key2)"
  -  **
  -  ** 4. A full CREATE INDEX statement for an index that could be used to
  -  **    optimize DELETE or UPDATE statements on the parent table. e.g.
  -  **
  -  **       "CREATE INDEX child_table_child_key ON child_table(child_key)"
  -  **
  -  ** 5. The name of the parent table.
  -  **
  -  ** These six values are used by the C logic below to generate the report.
  -  */
  -  const char *zSql =
  -  "SELECT "
  -    "     'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
  -    "  || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
  -    "  || fkey_collate_clause("
  -    "       f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
  -    ", "
  -    "     'SEARCH ' || s.name || ' USING COVERING INDEX*('"
  -    "  || group_concat('*=?', ' AND ') || ')'"
  -    ", "
  -    "     s.name  || '(' || group_concat(f.[from],  ', ') || ')'"
  -    ", "
  -    "     f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
  -    ", "
  -    "     'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
  -    "  || ' ON ' || quote(s.name) || '('"
  -    "  || group_concat(quote(f.[from]) ||"
  -    "        fkey_collate_clause("
  -    "          f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
  -    "  || ');'"
  -    ", "
  -    "     f.[table] "
  -    "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f "
  -    "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
  -    "GROUP BY s.name, f.id "
  -    "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
  -  ;
  -  const char *zGlobIPK = "SEARCH * USING INTEGER PRIMARY KEY (rowid=?)";
  -
  -  for(i=2; i<nArg; i++){
  -    int n = strlen30(azArg[i]);
  -    if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
  -      bVerbose = 1;
  -    }
  -    else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
  -      bGroupByParent = 1;
  -      zIndent = "    ";
  -    }
  -    else{
  -      raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
  -          azArg[0], azArg[1]
  -      );
  -      return SQLITE_ERROR;
  -    }
  -  }
  -
  -  /* Register the fkey_collate_clause() SQL function */
  -  rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
  -      0, shellFkeyCollateClause, 0, 0
  -  );
  -
  -
  -  if( rc==SQLITE_OK ){
  -    rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
  -  }
  -  if( rc==SQLITE_OK ){
  -    sqlite3_bind_int(pSql, 1, bGroupByParent);
  -  }
  -
  -  if( rc==SQLITE_OK ){
  -    int rc2;
  -    char *zPrev = 0;
  -    while( SQLITE_ROW==sqlite3_step(pSql) ){
  -      int res = -1;
  -      sqlite3_stmt *pExplain = 0;
  -      const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
  -      const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
  -      const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
  -      const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
  -      const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
  -      const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
  -
  -      if( zEQP==0 ) continue;
  -      if( zGlob==0 ) continue;
  -      rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
  -      if( rc!=SQLITE_OK ) break;
  -      if( SQLITE_ROW==sqlite3_step(pExplain) ){
  -        const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
  -        res = zPlan!=0 && (  0==sqlite3_strglob(zGlob, zPlan)
  -                          || 0==sqlite3_strglob(zGlobIPK, zPlan));
  -      }
  -      rc = sqlite3_finalize(pExplain);
  -      if( rc!=SQLITE_OK ) break;
  -
  -      if( res<0 ){
  -        raw_printf(stderr, "Error: internal error");
  -        break;
  -      }else{
  -        if( bGroupByParent
  -        && (bVerbose || res==0)
  -        && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
  -        ){
  -          raw_printf(out, "-- Parent table %s\n", zParent);
  -          sqlite3_free(zPrev);
  -          zPrev = sqlite3_mprintf("%s", zParent);
  -        }
  -
  -        if( res==0 ){
  -          raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
  -        }else if( bVerbose ){
  -          raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
  -              zIndent, zFrom, zTarget
  -          );
  -        }
  -      }
  -    }
  -    sqlite3_free(zPrev);
  -
  -    if( rc!=SQLITE_OK ){
  -      raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
  -    }
  -
  -    rc2 = sqlite3_finalize(pSql);
  -    if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
  -      rc = rc2;
  -      raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
  -    }
  -  }else{
  -    raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
  -  }
  -
  -  return rc;
  -}
  -
  -/*
  -** Implementation of ".lint" dot command.
  -*/
  -static int lintDotCommand(
  -  ShellState *pState,             /* Current shell tool state */
  -  char **azArg,                   /* Array of arguments passed to dot command */
  -  int nArg                        /* Number of entries in azArg[] */
  -){
  -  int n;
  -  n = (nArg>=2 ? strlen30(azArg[1]) : 0);
  -  if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
  -  return lintFkeyIndexes(pState, azArg, nArg);
  -
  - usage:
  -  raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
  -  raw_printf(stderr, "Where sub-commands are:\n");
  -  raw_printf(stderr, "    fkey-indexes\n");
  -  return SQLITE_ERROR;
  -}
  -
  -#if !defined SQLITE_OMIT_VIRTUALTABLE
  -static void shellPrepare(
  -  sqlite3 *db,
  -  int *pRc,
  -  const char *zSql,
  -  sqlite3_stmt **ppStmt
  -){
  -  *ppStmt = 0;
  -  if( *pRc==SQLITE_OK ){
  -    int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
  -    if( rc!=SQLITE_OK ){
  -      raw_printf(stderr, "sql error: %s (%d)\n",
  -          sqlite3_errmsg(db), sqlite3_errcode(db)
  -      );
  -      *pRc = rc;
  -    }
  -  }
  -}
  -
  -/*
  -** Create a prepared statement using printf-style arguments for the SQL.
  -**
  -** This routine is could be marked "static".  But it is not always used,
  -** depending on compile-time options.  By omitting the "static", we avoid
  -** nuisance compiler warnings about "defined but not used".
  -*/
  -void shellPreparePrintf(
  -  sqlite3 *db,
  -  int *pRc,
  -  sqlite3_stmt **ppStmt,
  -  const char *zFmt,
  -  ...
  +void shellPreparePrintf(
  +  sqlite3 *db,
  +  int *pRc,
  +  sqlite3_stmt **ppStmt,
  +  const char *zFmt,
  +  ...
   ){
     *ppStmt = 0;
     if( *pRc==SQLITE_OK ){
@@@@ -7877,74 -7646,71 -7645,71 +7932,74 @@@@ static int recoverSqlCb(void *pCtx, con
     return SQLITE_OK;
   }
   
 --/*
 --** This function is called to recover data from the database. A script
 --** to construct a new database containing all recovered data is output
 --** on stream pState->out.
 --*/
 --static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
 --  int rc = SQLITE_OK;
 --  const char *zRecoveryDb = "";   /* Name of "recovery" database.  Debug only */
 --  const char *zLAF = "lost_and_found";
 --  int bFreelist = 1;              /* 0 if --ignore-freelist is specified */
 --  int bRowids = 1;                /* 0 if --no-rowids */
 --  sqlite3_recover *p = 0;
 --  int i = 0;
 ++#endif /* SQLITE_SHELL_HAVE_RECOVER */
   
 --  for(i=1; i<nArg; i++){
 --    char *z = azArg[i];
 --    int n;
 --    if( z[0]=='-' && z[1]=='-' ) z++;
 --    n = strlen30(z);
 --    if( n<=17 && memcmp("-ignore-freelist", z, n)==0 ){
 --      bFreelist = 0;
 --    }else
 --    if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){
 --      /* This option determines the name of the ATTACH-ed database used
 --      ** internally by the recovery extension.  The default is "" which
 --      ** means to use a temporary database that is automatically deleted
 --      ** when closed.  This option is undocumented and might disappear at
 --      ** any moment. */
 --      i++;
 --      zRecoveryDb = azArg[i];
 --    }else
 --    if( n<=15 && memcmp("-lost-and-found", z, n)==0 && i<(nArg-1) ){
 --      i++;
 --      zLAF = azArg[i];
 --    }else
 --    if( n<=10 && memcmp("-no-rowids", z, n)==0 ){
 --      bRowids = 0;
 --    }
 --    else{
 --      utf8_printf(stderr, "unexpected option: %s\n", azArg[i]);
 --      showHelp(pState->out, azArg[0]);
 --      return 1;
 ++#ifndef SQLITE_SHELL_FIDDLE
 ++static DotCmdRC
 ++writeDb( char *azArg[], int nArg, ShellExState *psx, char **pzErr ){
 ++  int rc = 0;
 ++  const char *zDestFile = 0;
 ++  const char *zDb = 0;
 ++  sqlite3 *pDest;
 ++  sqlite3_backup *pBackup;
 ++  int j;
 ++  int bAsync = 0;
 ++  const char *zVfs = 0;
 ++  if( ISS(psx)->bSafeMode ) return DCR_AbortError;
 ++  for(j=1; j<nArg; j++){
 ++    const char *z = azArg[j];
 ++    if( z[0]=='-' ){
 ++      if( z[1]=='-' ) z++;
 ++      if( cli_strcmp(z, "-append")==0 ){
 ++        zVfs = "apndvfs";
 ++      }else if( cli_strcmp(z, "-async")==0 ){
 ++        bAsync = 1;
 ++      }else{
 ++        return DCR_Unknown|j;
 ++      }
 ++    }else if( zDestFile==0 ){
 ++      zDestFile = azArg[j];
 ++    }else if( zDb==0 ){
 ++      zDb = zDestFile;
 ++      zDestFile = azArg[j];
 ++    }else{
 ++      return DCR_TooMany|j;
       }
     }
 --
 --  p = sqlite3_recover_init_sql(
 --      pState->db, "main", recoverSqlCb, (void*)pState
 --  );
 --
 --  sqlite3_recover_config(p, 789, (void*)zRecoveryDb);  /* Debug use only */
 --  sqlite3_recover_config(p, SQLITE_RECOVER_LOST_AND_FOUND, (void*)zLAF);
 --  sqlite3_recover_config(p, SQLITE_RECOVER_ROWIDS, (void*)&bRowids);
 --  sqlite3_recover_config(p, SQLITE_RECOVER_FREELIST_CORRUPT,(void*)&bFreelist);
 --
 --  sqlite3_recover_run(p);
 --  if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
 --    const char *zErr = sqlite3_recover_errmsg(p);
 --    int errCode = sqlite3_recover_errcode(p);
 --    raw_printf(stderr, "sql error: %s (%d)\n", zErr, errCode);
 ++  if( zDestFile==0 ){
 ++    return DCR_Missing;
     }
 --  rc = sqlite3_recover_finish(p);
 --  return rc;
  -}
  -#endif /* SQLITE_SHELL_HAVE_RECOVER */
  -
 ++  if( zDb==0 ) zDb = "main";
 ++  rc = sqlite3_open_v2(zDestFile, &pDest,
 ++                       SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs);
 ++  if( rc!=SQLITE_OK ){
 ++    *pzErr = smprintf("cannot open \"%s\"\n", zDestFile);
 ++    close_db(pDest);
 ++    return DCR_Error;
 ++  }
 ++  if( bAsync ){
 ++    sqlite3_exec(pDest, "PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF;",
 ++                 0, 0, 0);
 ++  }
 ++  open_db(psx, 0);
 ++  pBackup = sqlite3_backup_init(pDest, "main", DBX(psx), zDb);
 ++  if( pBackup==0 ){
 ++    *pzErr = smprintf("%s failed, %s\n", azArg[0], sqlite3_errmsg(pDest));
 ++    close_db(pDest);
 ++    return DCR_Error;
 ++  }
 ++  while(  (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
 ++  sqlite3_backup_finish(pBackup);
 ++  if( rc==SQLITE_DONE ){
 ++    rc = 0;
 ++  }else{
 ++    *pzErr = smprintf("%s\n", sqlite3_errmsg(pDest));
 ++    rc = 1;
 ++  }
 ++  close_db(pDest);
 ++  return DCR_Ok|rc;
  +}
 - #endif /* SQLITE_SHELL_HAVE_RECOVER */
 - 
 ++#endif /* !defined(SQLITE_SHELL_FIDDLE) */
   
   /*
    * zAutoColumn(zCol, &db, ?) => Maybe init db, add column zCol to it.
@@@@ -15155,6 -11426,6 -11425,6 +15210,7 @@@@ static int line_is_complete(char *zSql
     zSql[nSql] = ';';
     zSql[nSql+1] = 0;
     rc = sqlite3_complete(zSql);
+++  if( rc==SQLITE_NOMEM ) shell_out_of_memory();
     zSql[nSql] = 0;
     return rc;
   }
@@@@ -15178,519 -11447,193 -11446,193 +15234,520 @@@@ static int runOneSqlLine(ShellExState *
       char zPrefix[100];
       const char *zErrorTail;
       const char *zErrorType;
 --    if( zErrMsg==0 ){
 --      zErrorType = "Error";
 --      zErrorTail = sqlite3_errmsg(p->db);
 --    }else if( cli_strncmp(zErrMsg, "in prepare, ",12)==0 ){
 --      zErrorType = "Parse error";
 --      zErrorTail = &zErrMsg[12];
 --    }else if( cli_strncmp(zErrMsg, "stepping, ", 10)==0 ){
 --      zErrorType = "Runtime error";
 --      zErrorTail = &zErrMsg[10];
 --    }else{
 --      zErrorType = "Error";
 --      zErrorTail = zErrMsg;
 --    }
 --    if( in!=0 || !stdin_is_interactive ){
 --      sqlite3_snprintf(sizeof(zPrefix), zPrefix,
 --                       "%s near line %d:", zErrorType, startline);
 --    }else{
 --      sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType);
 ++    if( psx->shellAbruptExit==0 ){
 ++      if( zErrMsg==0 ){
 ++        zErrorType = "Error";
 ++        zErrorTail = sqlite3_errmsg(DBX(psx));
 ++      }else if( cli_strncmp(zErrMsg, "in prepare, ",12)==0 ){
 ++        zErrorType = "Parse error";
 ++        zErrorTail = &zErrMsg[12];
 ++      }else if( cli_strncmp(zErrMsg, "stepping, ", 10)==0 ){
 ++        zErrorType = "Runtime error";
 ++        zErrorTail = &zErrMsg[10];
 ++      }else{
 ++        zErrorType = "Error";
 ++        zErrorTail = zErrMsg;
 ++      }
 ++      if( bAltIn || !stdin_is_interactive ){
 ++        sqlite3_snprintf(sizeof(zPrefix), zPrefix,
 ++                         "%s near line %d:", zErrorType, startline);
 ++      }else{
 ++        sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType);
 ++      }
 ++      utf8_printf(STD_ERR, "%s %s\n", zPrefix, zErrorTail);
       }
 --    utf8_printf(stderr, "%s %s\n", zPrefix, zErrorTail);
       sqlite3_free(zErrMsg);
 --    zErrMsg = 0;
       return 1;
 --  }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
 --    char zLineBuf[2000];
 ++  }else if( ShellHasFlag(psx, SHFLG_CountChanges) ){
-      char zLineBuf[2000];
+++    char zLineBuf[36+2*20];
       sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
               "changes: %lld   total_changes: %lld",
 --            sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
 --    raw_printf(p->out, "%s\n", zLineBuf);
 ++            sqlite3_changes64(DBX(psx)), sqlite3_total_changes64(DBX(psx)));
 ++    raw_printf(ISS(psx)->out, "%s\n", zLineBuf);
     }
     return 0;
   }
   
 --static void echo_group_input(ShellState *p, const char *zDo){
 --  if( ShellHasFlag(p, SHFLG_Echo) ) utf8_printf(p->out, "%s\n", zDo);
 ++#if SHELL_EXTENDED_PARSING
 ++/* Resumable line classsifier for dot-commands
 ++**
 ++** Determines if a dot-command is open, having either an unclosed
 ++** quoted argument or an escape sequence opener ('\') at its end.
 ++**
 ++** The FSM design/behavior assumes/requires that a terminating '\'
 ++** is not part of the character sequence being classified -- that
 ++** it represents an escaped newline which is removed as physical
 ++** lines are spliced to accumulate logical lines.
 ++**
 ++** The line or added line-portion is passed as zCmd.
 ++** The pScanState pointer must reference an (opaque) DCmd_ScanState,
 ++** which must be set to DCSS_Start to initialize the scanner state.
 ++** Resumed scanning should always be done with zCmd logically just
 ++** past the last non-0 char of the text previously passed in, with
 ++** any previously scanned, trailing newline escape first trimmed.
 ++** Returns are: 0 => not open (aka complete), 1 => is open (incomplete)
 ++** The following macros may be applied to the scan state:
 ++*/
 ++#define DCSS_InDarkArg(dcss) (((dcss)&argPosMask)==inDqArg)
 ++#define DCSS_EndEscaped(dcss) (((dcss)&endEscaped)!=0)
 ++#define DCSS_IsOpen(dcss) (((dcss)&isOpenMask)!=0)
 ++typedef enum {
 ++  DCSS_Start = 0,
 ++  twixtArgs = 0, inSqArg = 1, inDarkArg = 2, inDqArg = 3, /* ordered */
 ++  endEscaped = 4, /* bit used */
 ++  argPosMask = 3, /* bits used */
 ++  isOpenMask = 1|4 /* bit test */
 ++} DCmd_ScanState;
 ++
 ++static void dot_command_scan(char *zCmd, DCmd_ScanState *pScanState,
 ++                             SCAN_TRACKER_REFTYPE pst){
 ++  DCmd_ScanState ss = *pScanState & ~endEscaped;
 ++  char c = (ss&isOpenMask)? 1 : *zCmd++;
 ++  while( c!=0 ){
 ++    switch( ss ){
 ++    case twixtArgs:
 ++      CONTINUE_PROMPT_AWAITC(pst, 0);
 ++      while( IsSpace(c) ){
 ++        if( (c=*zCmd++)==0 ) goto atEnd;
 ++      }
 ++      switch( c ){
 ++      case '\\':
 ++        if( *zCmd==0 ){
 ++          ss |= endEscaped;
 ++          goto atEnd;
 ++        }else goto inDark;
 ++      case '\'': ss = inSqArg; goto inSq;
 ++      case '"': ss = inDqArg; goto inDq;
 ++      default: ss = inDarkArg; goto inDark;
 ++      }
 ++    inSq:
 ++    case inSqArg:
 ++      CONTINUE_PROMPT_AWAITC(pst, '\'');
 ++      while( (c=*zCmd++)!='\'' ){
 ++        if( c==0 ) goto atEnd;
 ++        if( c=='\\' && *zCmd==0 ){
 ++          ss |= endEscaped;
 ++          goto atEnd;
 ++        }
 ++      }
 ++      ss = twixtArgs;
 ++      c = *zCmd++;
 ++      continue;
 ++    inDq:
 ++    case inDqArg:
 ++      CONTINUE_PROMPT_AWAITC(pst, '"');
 ++      do {
 ++        if( (c=*zCmd++)==0 ) goto atEnd;
 ++        if( c=='\\' ){
 ++          if( (c=*zCmd++)==0 ){
 ++            ss |= endEscaped;
 ++            goto atEnd;
 ++          }
 ++          if( (c=*zCmd++)==0 ) goto atEnd;
 ++        }
 ++      } while( c!='"' );
 ++      ss = twixtArgs;
 ++      c = *zCmd++;
 ++      continue;
 ++    inDark:
 ++    case inDarkArg:
 ++      CONTINUE_PROMPT_AWAITC(pst, 0);
 ++      while( !IsSpace(c) ){
 ++        if( c=='\\' && *zCmd==0 ){
 ++          ss |= endEscaped;
 ++          goto atEnd;
 ++        }
 ++        if( (c=*zCmd++)==0 ) goto atEnd;
 ++      }
 ++      ss = twixtArgs;
 ++      c = *zCmd++;
 ++      continue;
 ++    case endEscaped: case isOpenMask: default:
 ++      ; /* Not reachable, but quiet compilers unable to see this. */
 ++    }
 ++  }
 ++ atEnd:
 ++  *pScanState = ss;
   }
 ++#else
 ++# define dot_command_scan(x,y,z)
 ++#endif
   
 --#ifdef SQLITE_SHELL_FIDDLE
 ++/* Utility functions for process_input. */
 ++
 ++#if SHELL_EXTENDED_PARSING
   /*
 --** Alternate one_input_line() impl for wasm mode. This is not in the primary
 --** impl because we need the global shellState and cannot access it from that
 --** function without moving lots of code around (creating a larger/messier diff).
 ++** Process dot-command line with its scan state to:
 ++** 1. Setup for requested line-splicing; and
 ++** 2. Say whether it is complete.
 ++** The last two out parameters are the line's length, which may be
 ++** adjusted, and the char to be used for joining a subsequent line.
 ++** This is broken out of process_input() mainly for readability.
 ++** The return is TRUE for dot-command ready to run, else false.
   */
 --static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
 --  /* Parse the next line from shellState.wasm.zInput. */
 --  const char *zBegin = shellState.wasm.zPos;
 --  const char *z = zBegin;
 --  char *zLine = 0;
 --  i64 nZ = 0;
 --
 --  UNUSED_PARAMETER(in);
 --  UNUSED_PARAMETER(isContinuation);
 --  if(!z || !*z){
 ++static int line_join_done(DCmd_ScanState dcss, char *zLine,
 ++                          i64 *pnLength, char *pcLE){
 ++  /* It is ready only if has no open argument or escaped newline. */
 ++  int bOpen = DCSS_IsOpen(dcss);
 ++  if( !DCSS_EndEscaped(dcss) ){
 ++    *pcLE = '\n';
 ++    return !bOpen;
 ++  }else{
 ++    *pcLE = (bOpen || DCSS_InDarkArg(dcss))? 0 : ' ';
 ++    /* Swallow the trailing escape character. */
 ++    zLine[--*pnLength] = 0;
       return 0;
     }
 --  while(*z && isspace(*z)) ++z;
 --  zBegin = z;
 --  for(; *z && '\n'!=*z; ++nZ, ++z){}
 --  if(nZ>0 && '\r'==zBegin[nZ-1]){
 --    --nZ;
 ++}
 ++#endif
 ++
 ++/*
 ++** Grow the accumulation line buffer to accommodate ncNeed chars.
 ++** In/out parameters pz and pna reference the buffer and its size.
 ++** The buffer must eventually be sqlite3_free()'ed by the caller.
 ++*/
 ++static void grow_line_buffer(char **pz, i64 *pna, int ncNeed){
 ++
 ++  if( ncNeed > *pna ){
 ++    *pna += *pna + (*pna>>1) + 100;
 ++    *pz = sqlite3_realloc(*pz, *pna);
 ++    shell_check_oom(*pz);
     }
 --  shellState.wasm.zPos = z;
 --  zLine = realloc(zPrior, nZ+1);
 --  shell_check_oom(zLine);
 --  memcpy(zLine, zBegin, nZ);
 --  zLine[nZ] = 0;
 --  return zLine;
   }
 --#endif /* SQLITE_SHELL_FIDDLE */
   
   /*
 --** Read input from *in and process it.  If *in==0 then input
 --** is interactive - the user is typing it it.  Otherwise, input
 --** is coming from a file or device.  A prompt is issued and history
 --** is saved only if input is interactive.  An interrupt signal will
 --** cause this routine to exit immediately, unless input is interactive.
 ++** Read input from designated source (p->pInSource) and process it.
 ++** If pInSource==0 then input is interactive - the user is typing it.
 ++** Otherwise, input is coming from a file, stream device or string.
 ++** Prompts issue and history is saved only for interactive input.
 ++** An interrupt signal will cause this routine to exit immediately,
 ++** with "exit demanded" code returned, unless input is interactive.
   **
 --** Return the number of errors.
 --*/
 --static int process_input(ShellState *p){
 --  char *zLine = 0;          /* A single input line */
 --  char *zSql = 0;           /* Accumulated SQL text */
 --  i64 nLine;                /* Length of current line */
 --  i64 nSql = 0;             /* Bytes of zSql[] used */
 --  i64 nAlloc = 0;           /* Allocated zSql[] space */
 --  int rc;                   /* Error code */
 --  int errCnt = 0;           /* Number of errors seen */
 --  i64 startline = 0;        /* Line number for start of current input */
 --  QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
 --
 --  if( p->inputNesting==MAX_INPUT_NESTING ){
 --    /* This will be more informative in a later version. */
 --    utf8_printf(stderr,"Input nesting limit (%d) reached at line %d."
 --                " Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
 --    return 1;
 --  }
 --  ++p->inputNesting;
 --  p->lineno = 0;
 --  CONTINUE_PROMPT_RESET;
 --  while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
 --    fflush(p->out);
 --    zLine = one_input_line(p->in, zLine, nSql>0);
 --    if( zLine==0 ){
 --      /* End of input */
 --      if( p->in==0 && stdin_is_interactive ) printf("\n");
 --      break;
 --    }
 --    if( seenInterrupt ){
 --      if( p->in!=0 ) break;
 --      seenInterrupt = 0;
 --    }
 --    p->lineno++;
 --    if( QSS_INPLAIN(qss)
 --        && line_is_command_terminator(zLine)
 --        && line_is_complete(zSql, nSql) ){
 --      memcpy(zLine,";",2);
 --    }
 --    qss = quickscan(zLine, qss, CONTINUE_PROMPT_PSTATE);
 --    if( QSS_PLAINWHITE(qss) && nSql==0 ){
 --      /* Just swallow single-line whitespace */
 --      echo_group_input(p, zLine);
 --      qss = QSS_Start;
 --      continue;
 --    }
 --    if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){
 --      CONTINUE_PROMPT_RESET;
 --      echo_group_input(p, zLine);
 --      if( zLine[0]=='.' ){
 --        rc = do_meta_command(zLine, p);
 --        if( rc==2 ){ /* exit requested */
 ++** Returns are the post-execute values of enum DotCmdRC:
 ++**   DCR_Ok, DCR_Return, DCR_Exit, DCR_Abort
 ++** each of which may be bit-wise or'ed with DCR_Error.
 ++*/
 ++static DotCmdRC process_input(ShellInState *psi){
 ++  char *zLineInput = 0;  /* a line-at-a-time input buffer or usable result */
 ++  char *zLineAccum = 0;  /* accumulation buffer, used for multi-line input */
 ++  /* Above two pointers could be local to the group handling loop, but are
 ++   * not so that the number of memory allocations can be reduced. They are
 ++   * reused from one incoming group to another, realloc()'ed as needed. */
 ++  i64 naAccum = 0;       /* tracking how big zLineAccum buffer has become */
 ++  /* Some flags for ending the overall group processing loop, always 1 or 0 */
 ++  u8 bInputEnd=0, bInterrupted=0;
 ++  /* Termination kind: DCR_Ok, DCR_Error, DCR_Return, DCR_Exit, DCR_Abort,
 ++   * the greatest of whichever is applicable */
 ++  u8 termKind = DCR_Ok;
 ++  /* Flag to affect prompting and interrupt action */
 ++  u8 bInteractive = INSOURCE_IS_INTERACTIVE(psi->pInSource);
 ++  int nErrors = 0;       /* count of errors during execution or its prep */
 ++
 ++  /* Block overly-recursive or absurdly nested input redirects. */
 ++  if( psi->inputNesting>=MAX_INPUT_NESTING ){
 ++    InSource *pInSrc = psi->pInSource->pFrom;
 ++    const char *zLead = "Input nesting limit ("
 ++      SHELL_STRINGIFY(MAX_INPUT_NESTING)") reached,";
 ++    int i = 3;
 ++    assert(pInSrc!=0 && MAX_INPUT_NESTING>0);
 ++    while( i-->0 && pInSrc!=0 ){
 ++      utf8_printf(STD_ERR,
 ++                  "%s from line %d of \"%s\"",
 ++                  zLead, pInSrc->lineno, pInSrc->zSourceSay);
 ++      zLead = (i%2==0)? "\n" : "";
 ++      pInSrc=pInSrc->pFrom;
 ++    }
 ++    utf8_printf(STD_ERR, " ...\nError: Check recursion.\n");
 ++    return DCR_Error;
 ++  }
 ++  ++psi->inputNesting;
 ++
 ++  /* line-group processing loop (per SQL block, dot-command or comment) */
 ++  while( !bInputEnd && termKind==DCR_Ok && !bInterrupted ){
 ++#if SHELL_DYNAMIC_EXTENSION
 ++    ScriptSupport *pSS = psi->script;
 ++#endif
 ++    int nGroupLines = 0;  /* count of lines belonging to this group */
 ++    i64 ncLineIn = 0;     /* how many (non-zero) chars are in zLineInput  */
 ++    i64 ncLineAcc = 0;    /* how many (non-zero) chars are in zLineAccum  */
 ++    i64 iLastLine = 0;    /* index of last accumulated line start */
 ++    /* Initialize resumable scanner(s). */
 ++    SqlScanState sqScanState = SSS_Start; /* for SQL scan */
 ++#if SHELL_EXTENDED_PARSING
 ++    DCmd_ScanState dcScanState = DCSS_Start;  /* for dot-command scan */
 ++    int nLeadWhite = 0; /* skips over initial whitespace to . or # */
 ++    char cLineEnd = '\n'; /* May be swallowed or replaced with space. */
 ++#else
 ++# define nLeadWhite 0     /* For legacy parsing, no white before . or # . */
 ++# define cLineEnd '\n'    /* For legacy parsing, this always joins lines. */
 ++#endif
 ++    /* An ordered enum to record kind of incoming line group. Its ordering
 ++     * means than a value greater than Comment implies something runnable.
 ++     */
 ++    enum { Tbd = 0, Eof, Comment, Sql, Cmd
 ++#if SHELL_DYNAMIC_EXTENSION
 ++      , Script
 ++#endif
 ++    } inKind = Tbd;
 ++    /* An enum signifying the group disposition state */
 ++    enum {
 ++      Incoming, Runnable, Dumpable, Erroneous, Ignore
 ++    } disposition = Incoming;
 ++    char **pzLineUse = &zLineInput;   /* ref line to be processed */
 ++    i64 *pncLineUse = &ncLineIn;      /* ref that line's char count */
 ++    int iStartline = 0;               /* starting line number of group */
 ++
+++    seenInterrupt = 0;
 ++    fflush(psi->out);
 ++    CONTINUE_PROMPT_RESET;
 ++    zLineInput = one_input_line(psi->pInSource, zLineInput,
 ++                                nGroupLines>0, &shellPrompts);
 ++    if( zLineInput==0 ){
 ++      bInputEnd = 1;
 ++      inKind = Eof;
 ++      disposition = Ignore;
 ++      if( bInteractive ) printf("\n");
 ++    }else{
 ++      ++nGroupLines;
 ++      iStartline = psi->pInSource->lineno;
 ++      ncLineIn = strlen30(zLineInput);
 ++      if( seenInterrupt ){
 ++        if( psi->pInSource!=0 ) break;
 ++        bInterrupted = 1; /* This will be honored, or not, later. */
 ++        seenInterrupt = 0;
 ++        disposition = Dumpable;
 ++      }
 ++      /* Classify and check for single-line dispositions, prep for more. */
 ++#if SHELL_EXTENDED_PARSING
 ++      nLeadWhite = (SHEXT_PARSING(psi))
 ++        ? skipWhite(zLineInput)-zLineInput
 ++        : 0; /* Disallow leading whitespace for . or # in legacy mode. */
 ++#endif
 ++#if SHELL_DYNAMIC_EXTENSION
 ++      if( pSS && pSS->pMethods->isScriptLeader(pSS, zLineInput+nLeadWhite) ){
 ++        inKind = Script;
 ++      }else
 ++#endif
 ++      {
 ++        switch( zLineInput[nLeadWhite] ){
 ++        case '.':
 ++          inKind = Cmd;
 ++          dot_command_scan(zLineInput+nLeadWhite, &dcScanState,
 ++                           CONTINUE_PROMPT_PSTATE);
 ++          break;
 ++        case '#':
 ++          inKind = Comment;
 ++          break;
 ++        default:
 ++          /* Might be SQL, or a swallowable whole SQL comment. */
 ++          sql_prescan(zLineInput, &sqScanState, CONTINUE_PROMPT_PSTATE);
 ++          if( SSS_PLAINWHITE(sqScanState) ){
 ++            /* It's either all blank or a whole SQL comment. Swallowable. */
 ++            inKind = Comment;
 ++          }else{
 ++            /* Something dark, not a # comment or dot-command. Must be SQL. */
 ++            inKind = Sql;
 ++          }
             break;
 --        }else if( rc ){
 --          errCnt++;
           }
         }
 --      qss = QSS_Start;
 --      continue;
 --    }
 --    /* No single-line dispositions remain; accumulate line(s). */
 --    nLine = strlen(zLine);
 --    if( nSql+nLine+2>=nAlloc ){
 --      /* Grow buffer by half-again increments when big. */
 --      nAlloc = nSql+(nSql>>1)+nLine+100;
 --      zSql = realloc(zSql, nAlloc);
 --      shell_check_oom(zSql);
 --    }
 --    if( nSql==0 ){
 --      i64 i;
 --      for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
 --      assert( nAlloc>0 && zSql!=0 );
 --      memcpy(zSql, zLine+i, nLine+1-i);
 --      startline = p->lineno;
 --      nSql = nLine-i;
 --    }else{
 --      zSql[nSql++] = '\n';
 --      memcpy(zSql+nSql, zLine, nLine+1);
 --      nSql += nLine;
 --    }
 --    if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){
 --      echo_group_input(p, zSql);
 --      errCnt += runOneSqlLine(p, zSql, p->in, startline);
 --      CONTINUE_PROMPT_RESET;
 --      nSql = 0;
 --      if( p->outCount ){
 --        output_reset(p);
 --        p->outCount = 0;
 --      }else{
 --        clearTempFile(p);
 ++    } /* end read/classify initial group input line */
 ++
 ++    /* Here, if not at end of input, the initial line of group is in, and
 ++     * it has been scanned and classified. Next, do the processing needed
 ++     * to recognize whether the initial line or accumulated group so far
 ++     * is complete such that it may be run, and perform joining of more
 ++     * lines into the group while it is not so complete. This loop ends
 ++     * with the input group line(s) ready to be run, or if the input ends
 ++     * before it is ready, with the group marked as erroneous.
 ++     */
 ++    while( disposition==Incoming ){
 ++      PROMPTS_UPDATE(inKind == Sql || inKind == Cmd);
 ++      /* Check whether more to accumulate, or ready for final disposition. */
 ++      switch( inKind ){
 ++      case Comment:
 ++        disposition = Dumpable;
 ++      case Cmd:
 ++#if SHELL_EXTENDED_PARSING
 ++        if( SHEXT_PARSING(psi) ){
 ++          if( line_join_done(dcScanState, *pzLineUse, pncLineUse, &cLineEnd) ){
 ++            disposition = Runnable;
 ++          }
 ++        }else
 ++#endif
 ++          disposition = Runnable; /* Legacy, any dot-command line is ready. */
 ++        break;
 ++#if SHELL_DYNAMIC_EXTENSION
 ++      case Script:
 ++        if( pSS==0
 ++            || pSS->pMethods->scriptIsComplete(pSS, *pzLineUse+nLeadWhite, 0) ){
 ++          disposition = Runnable;
 ++        }
 ++        break;
 ++#endif
 ++      case Sql:
 ++        /* Check to see if it is complete and ready to run. */
-          if( SSS_SEMITERM(sqScanState) && sqlite3_complete(*pzLineUse)){
+++        if( SSS_SEMITERM(sqScanState) && 1==sqlite3_complete(*pzLineUse)){
 ++          disposition = Runnable;
 ++        }else if( SSS_PLAINWHITE(sqScanState) ){
 ++          /* It is a leading single-line or multi-line comment. */
 ++          disposition = Runnable;
 ++          inKind = Comment;
 ++        }else{
 ++          char *zT = line_is_command_terminator(zLineInput);
 ++          if( zT!=0  ){
 ++            /* Last line is a lone go or / -- prep for running it. */
 ++            if( nGroupLines>1 ){
 ++              disposition = Runnable;
 ++              memcpy(*pzLineUse+iLastLine,";\n",3);
 ++              *pncLineUse = iLastLine + 2;
 ++            }else{
 ++              /* Unless nothing preceded it, then dump it. */
 ++              disposition = Dumpable;
 ++            }
 ++          }
 ++        }
 ++        break;
 ++      case Tbd: case Eof: default: assert(0); /* Not reachable */
 ++      } /* end switch on inKind */
 ++      /* Collect and accumulate more input if group not yet complete. */
 ++      if( disposition==Incoming ){
 ++        if( nGroupLines==1 ){
 ++          grow_line_buffer(&zLineAccum, &naAccum, ncLineIn+2);
 ++          /* Copy line just input */
 ++          memcpy(zLineAccum, zLineInput, ncLineIn);
 ++          zLineAccum[ncLineIn] = 0;
 ++          ncLineAcc = ncLineIn;
 ++          pzLineUse = &zLineAccum;
 ++          pncLineUse = &ncLineAcc;
 ++        }
 ++        /* Read in next line of group, (if available.) */
 ++        zLineInput = one_input_line(psi->pInSource, zLineInput,
 ++                                    nGroupLines>0, &shellPrompts);
 ++        if( zLineInput==0 ){
 ++          bInputEnd = 1;
 ++          if( inKind==Sql && psi->pInSource==&cmdInSource ){
 ++            /* As a special dispensation, SQL arguments on the command line
 ++            ** do not need to end with ';' (or a lone go.) */
 ++            if( nGroupLines>1 ){
 ++              grow_line_buffer(&zLineAccum, &naAccum, ncLineAcc+2);
 ++            }
 ++            strcpy( zLineAccum+ncLineAcc, ";" );
 ++            if( 1==sqlite3_complete(*pzLineUse) ){
 ++              zLineAccum[ncLineAcc] = 0;
 ++              disposition = Runnable;
 ++              continue;
 ++            }
 ++          }
 ++          disposition = Erroneous;
 ++          inKind = Eof;
 ++          if( bInteractive ) printf("\n");
 ++          continue;
 ++        }
 ++        ++nGroupLines;
 ++        ncLineIn = strlen30(zLineInput);
 ++        /* Scan line just input (if needed) and append to accumulation. */
 ++        switch( inKind ){
 ++        case Cmd:
 ++          dot_command_scan(zLineInput, &dcScanState, CONTINUE_PROMPT_PSTATE);
 ++          break;
 ++        case Sql:
 ++          sql_prescan(zLineInput, &sqScanState, CONTINUE_PROMPT_PSTATE);
 ++          break;
 ++        default:
 ++          break;
 ++        }
 ++        grow_line_buffer(&zLineAccum, &naAccum, ncLineAcc+ncLineIn+2);
 ++        /* Join lines as setup by exam of previous line(s). */
 ++        if( cLineEnd!=0 ) zLineAccum[ncLineAcc++] = cLineEnd;
 ++#if SHELL_EXTENDED_PARSING
 ++        cLineEnd = '\n'; /* reset to default after use */
 ++#endif
 ++        memcpy(zLineAccum+ncLineAcc, zLineInput, ncLineIn);
 ++        iLastLine = ncLineAcc;
 ++        ncLineAcc += ncLineIn;
 ++        zLineAccum[ncLineAcc] = 0;
 ++      } /* end glom another line */
 ++    } /* end group collection loop */
 ++    /* Here, the group is fully collected or known to be incomplete forever. */
 ++    CONTINUE_PROMPT_RESET;
 ++    switch( disposition ){
 ++    case Dumpable:
 ++      echo_group_input(psi, *pzLineUse);
 ++#if SHELL_DYNAMIC_EXTENSION
 ++      if( inKind==Script && pSS!=0 ) pSS->pMethods->resetCompletionScan(pSS);
 ++#endif
 ++      break;
 ++    case Runnable:
 ++      switch( inKind ){
 ++      case Sql:
 ++        echo_group_input(psi, *pzLineUse);
 ++        nErrors += runOneSqlLine(XSS(psi), *pzLineUse,
 ++                                 INSOURCE_IS_INTERACTIVE(psi->pInSource),
 ++                                 iStartline);
 ++        break;
 ++      case Cmd: {
 ++        DotCmdRC dcr;
 ++        echo_group_input(psi, *pzLineUse);
 ++        dcr = do_dot_command(*pzLineUse+nLeadWhite, XSS(psi));
 ++        nErrors += (dcr & DCR_Error);
 ++        dcr &= ~DCR_Error;
 ++        if( dcr > termKind ) termKind = dcr;
 ++        break;
 ++      }
 ++#if SHELL_DYNAMIC_EXTENSION
 ++      case Script: {
 ++        char *zErr = 0;
 ++        DotCmdRC dcr;
 ++        assert(pSS!=0);
 ++        /* Consider: Should echo flag be honored here? */
 ++        pSS->pMethods->resetCompletionScan(pSS);
 ++        dcr = pSS->pMethods->runScript(pSS, *pzLineUse+nLeadWhite,
 ++                                       XSS(psi), &zErr);
 ++        if( dcr!=DCR_Ok || zErr!=0 ){
 ++          /* Future: Handle errors more informatively and like dot commands. */
 ++          nErrors += (dcr!=DCR_Ok);
 ++          if( zErr!=0 ){
 ++            utf8_printf(STD_ERR, "Error: %s\n", zErr);
 ++            sqlite3_free(zErr);
 ++          }
 ++        }
 ++        break;
 ++      }
 ++#endif
 ++      default:
 ++        assert(inKind!=Tbd);
 ++        break;
 ++      }
 ++      if( XSS(psi)->shellAbruptExit!=0 ){
 ++        termKind = DCR_Exit;
         }
 --      p->bSafeMode = p->bSafeModePersist;
 --      qss = QSS_Start;
 --    }else if( nSql && QSS_PLAINWHITE(qss) ){
 --      echo_group_input(p, zSql);
 --      nSql = 0;
 --      qss = QSS_Start;
 ++      break;
 ++    case Erroneous:
 ++      utf8_printf(STD_ERR, "Error: Input incomplete at line %d of \"%s\"\n",
 ++                  psi->pInSource->lineno, psi->pInSource->zSourceSay);
 ++#if SHELL_DYNAMIC_EXTENSION
 ++      if( inKind==Script && pSS!=0 ) pSS->pMethods->resetCompletionScan(pSS);
 ++#endif
 ++      ++nErrors;
 ++      break;
 ++    case Ignore:
 ++      break;
 ++    default: assert(0);
       }
 ++    if( bail_on_error && nErrors>0 && termKind==DCR_Ok ) termKind = DCR_Error;
 ++  } /* end group consume/prep/(run, dump or complain) loop */
 ++
 ++  /* Cleanup and determine return value based on flags and error count. */
 ++  free(zLineInput); /* Allocated via malloc() by readline or equivalents. */
 ++  sqlite3_free(zLineAccum);
 ++
 ++  /* Translate DCR_Return because it has been done here, not to propagate
 ++   * unless input is from shell invocation argument. */
 ++  if( termKind==DCR_Return && psi->pInSource!=&cmdInSource ){
 ++    termKind = DCR_Ok;
     }
 --  if( nSql ){
 --    /* This may be incomplete. Let the SQL parser deal with that. */
 --    echo_group_input(p, zSql);
 --    errCnt += runOneSqlLine(p, zSql, p->in, startline);
 --    CONTINUE_PROMPT_RESET;
 --  }
 --  free(zSql);
 --  free(zLine);
 --  --p->inputNesting;
 --  return errCnt>0;
 ++  return termKind|(nErrors>0);
   }
   
   /*
@@@@ -16039,6 -11937,6 -11936,6 +16096,12 @@@@ static char *cmdline_option_value(int a
     return argv[i];
   }
   
+++static void zapGlobalDbLock(void){
+++  if( pGlobalDbLock ){
+++    sqlite3_mutex_free(pGlobalDbLock);
+++    pGlobalDbLock = 0;
+++  }
+++}
   static void sayAbnormalExit(void){
     if( seenInterrupt ) fprintf(stderr, "Program interrupted.\n");
   }
@@@@ -16518,258 -12035,536 -12034,536 +16581,263 @@@@ int SQLITE_CDECL SHELL_MAIN(int argc, w
       exit(1);
     }
   #endif
 --  main_init(&data);
 ++  main_init(&datai,&datax);
 ++#if SHELL_DATAIO_EXT
 ++  datai.pFreeformExporter = (ExportHandler*)&ffExporter;
 ++  datai.pColumnarExporter = (ExportHandler*)&cmExporter;
 ++  datai.pActiveExporter = (ExportHandler*)&ffExporter;
 ++#endif
   
 --  /* On Windows, we must translate command-line arguments into UTF-8.
 --  ** The SQLite memory allocator subsystem has to be enabled in order to
 --  ** do this.  But we want to run an sqlite3_shutdown() afterwards so that
 --  ** subsequent sqlite3_config() calls will work.  So copy all results into
 --  ** memory that does not come from the SQLite memory allocator.
 ++  /* From here on, within the true clause of this next test, various
 ++  ** heap allocations are made which may fail, resulting in an abrupt
 ++  ** shell exit. Such an exit happens in 1 of 2 ways: A held resource
 ++  ** stack and the call stack are ripped back to this point; or just
 ++  ** the held resource stack is ripped back and a process exit occurs.
     */
 ++  register_exit_ripper(&exit_jb, entry_mark);
 ++  if( 0==RIP_TO_HERE(exit_jb) ){
 ++
 ++    /* On Windows, we must translate command-line arguments into UTF-8.
 ++    ** The SQLite memory allocator subsystem has to be enabled in order to
 ++    ** do this.  But we want to run an sqlite3_shutdown() afterwards so that
 ++    ** subsequent sqlite3_config() calls will work.  So copy all results into
 ++    ** memory that does not come from the SQLite memory allocator.
 ++    */
   #if !SQLITE_SHELL_IS_UTF8
 --  sqlite3_initialize();
 --  argvToFree = malloc(sizeof(argv[0])*argc*2);
 --  shell_check_oom(argvToFree);
 --  argcToFree = argc;
 --  argv = argvToFree + argc;
 --  for(i=0; i<argc; i++){
 --    char *z = sqlite3_win32_unicode_to_utf8(wargv[i]);
 --    i64 n;
 --    shell_check_oom(z);
 --    n = strlen(z);
 --    argv[i] = malloc( n+1 );
 --    shell_check_oom(argv[i]);
 --    memcpy(argv[i], z, n+1);
 --    argvToFree[i] = argv[i];
 --    sqlite3_free(z);
 --  }
 --  sqlite3_shutdown();
 ++    sqlite3_initialize();
 ++    argvToFree = malloc(sizeof(argv[0])*argc*2);
 ++    shell_check_oom(argvToFree);
 ++    argcToFree = argc;
 ++    argv = argvToFree + argc;
 ++    for(i=0; i<argc; i++){
 ++      char *z = sqlite3_win32_unicode_to_utf8(wargv[i]);
 ++      i64 n;
 ++      shell_check_oom(z);
 ++      n = strlen(z);
 ++      argv[i] = malloc( n+1 );
 ++      shell_check_oom(argv[i]);
 ++      memcpy(argv[i], z, n+1);
 ++      argvToFree[i] = argv[i];
 ++      sqlite3_free(z);
 ++    }
 ++    sqlite3_shutdown();
   #endif
   
 --  assert( argc>=1 && argv && argv[0] );
 --  Argv0 = argv[0];
 ++    assert( argc>=1 && argv && argv[0] );
 ++    Argv0 = argv[0];
 ++#if SHELL_DYNAMIC_EXTENSION
 ++    initStartupDir();
 ++    if( isExtendedBasename(Argv0) ){
 ++      datai.bExtendedDotCmds = SHELL_ALL_EXTENSIONS;
 ++    }
 ++#endif
   
   #ifdef SQLITE_SHELL_DBNAME_PROC
 --  {
 --    /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
 --    ** of a C-function that will provide the name of the database file.  Use
 --    ** this compile-time option to embed this shell program in larger
 --    ** applications. */
 --    extern void SQLITE_SHELL_DBNAME_PROC(const char**);
 --    SQLITE_SHELL_DBNAME_PROC(&data.pAuxDb->zDbFilename);
 --    warnInmemoryDb = 0;
 --  }
 ++    {
 ++      /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
 ++      ** of a C-function that will provide the name of the database file.  Use
 ++      ** this compile-time option to embed this shell program in larger
 ++      ** applications. */
 ++      extern void SQLITE_SHELL_DBNAME_PROC(const char**);
 ++      SQLITE_SHELL_DBNAME_PROC(&datai.pAuxDb->zDbFilename);
 ++      warnInmemoryDb = 0;
 ++    }
   #endif
   
 --  /* Do an initial pass through the command-line argument to locate
 --  ** the name of the database file, the name of the initialization file,
 --  ** the size of the alternative malloc heap,
 --  ** and the first command to execute.
 --  */
 ++    /* Do an initial pass through the command-line argument to locate
 ++    ** the name of the database file, the name of the initialization file,
 ++    ** the size of the alternative malloc heap,
 ++    ** and the first command to execute.
 ++    */
   #ifndef SQLITE_SHELL_FIDDLE
 --  verify_uninitialized();
 --#endif
 --  for(i=1; i<argc; i++){
 --    char *z;
 --    z = argv[i];
 --    if( z[0]!='-' || i>nOptsEnd ){
 --      if( data.aAuxDb->zDbFilename==0 ){
 --        data.aAuxDb->zDbFilename = z;
 --      }else{
 --        /* Excesss arguments are interpreted as SQL (or dot-commands) and
 --        ** mean that nothing is read from stdin */
 --        readStdin = 0;
 --        nCmd++;
 --        azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
 --        shell_check_oom(azCmd);
 --        azCmd[nCmd-1] = z;
 --      }
 --      continue;
 --    }
 --    if( z[1]=='-' ) z++;
 --    if( cli_strcmp(z, "-")==0 ){
 --      nOptsEnd = i;
 --      continue;
 --    }else if( cli_strcmp(z,"-separator")==0
 --     || cli_strcmp(z,"-nullvalue")==0
 --     || cli_strcmp(z,"-newline")==0
 --     || cli_strcmp(z,"-cmd")==0
 --    ){
 --      (void)cmdline_option_value(argc, argv, ++i);
 --    }else if( cli_strcmp(z,"-init")==0 ){
 --      zInitFile = cmdline_option_value(argc, argv, ++i);
 --    }else if( cli_strcmp(z,"-batch")==0 ){
 --      /* Need to check for batch mode here to so we can avoid printing
 --      ** informational messages (like from process_sqliterc) before
 --      ** we do the actual processing of arguments later in a second pass.
 --      */
 --      stdin_is_interactive = 0;
 --    }else if( cli_strcmp(z,"-heap")==0 ){
 --#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
 --      const char *zSize;
 --      sqlite3_int64 szHeap;
 --
 --      zSize = cmdline_option_value(argc, argv, ++i);
 --      szHeap = integerValue(zSize);
 --      if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
 --      verify_uninitialized();
 --      sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
 --#else
 --      (void)cmdline_option_value(argc, argv, ++i);
 --#endif
 --    }else if( cli_strcmp(z,"-pagecache")==0 ){
 --      sqlite3_int64 n, sz;
 --      sz = integerValue(cmdline_option_value(argc,argv,++i));
 --      if( sz>70000 ) sz = 70000;
 --      if( sz<0 ) sz = 0;
 --      n = integerValue(cmdline_option_value(argc,argv,++i));
 --      if( sz>0 && n>0 && 0xffffffffffffLL/sz<n ){
 --        n = 0xffffffffffffLL/sz;
 --      }
 --      verify_uninitialized();
 --      sqlite3_config(SQLITE_CONFIG_PAGECACHE,
 --                    (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
 --      data.shellFlgs |= SHFLG_Pagecache;
 --    }else if( cli_strcmp(z,"-lookaside")==0 ){
 --      int n, sz;
 --      sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
 --      if( sz<0 ) sz = 0;
 --      n = (int)integerValue(cmdline_option_value(argc,argv,++i));
 --      if( n<0 ) n = 0;
 --      verify_uninitialized();
 --      sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
 --      if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
 --    }else if( cli_strcmp(z,"-threadsafe")==0 ){
 --      int n;
 --      n = (int)integerValue(cmdline_option_value(argc,argv,++i));
 --      verify_uninitialized();
 --      switch( n ){
 --         case 0:  sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);  break;
 --         case 2:  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);   break;
 --         default: sqlite3_config(SQLITE_CONFIG_SERIALIZED);    break;
 --      }
 --#ifdef SQLITE_ENABLE_VFSTRACE
 --    }else if( cli_strcmp(z,"-vfstrace")==0 ){
 --      extern int vfstrace_register(
 --         const char *zTraceName,
 --         const char *zOldVfsName,
 --         int (*xOut)(const char*,void*),
 --         void *pOutArg,
 --         int makeDefault
 --      );
 --      vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
 --#endif
 --#ifdef SQLITE_ENABLE_MULTIPLEX
 --    }else if( cli_strcmp(z,"-multiplex")==0 ){
 --      extern int sqlite3_multiple_initialize(const char*,int);
 --      sqlite3_multiplex_initialize(0, 1);
 --#endif
 --    }else if( cli_strcmp(z,"-mmap")==0 ){
 --      sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
 --      verify_uninitialized();
 --      sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
 --#if defined(SQLITE_ENABLE_SORTER_REFERENCES)
 --    }else if( cli_strcmp(z,"-sorterref")==0 ){
 --      sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
 --      verify_uninitialized();
 --      sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, (int)sz);
 --#endif
 --    }else if( cli_strcmp(z,"-vfs")==0 ){
 --      zVfs = cmdline_option_value(argc, argv, ++i);
 --#ifdef SQLITE_HAVE_ZLIB
 --    }else if( cli_strcmp(z,"-zip")==0 ){
 --      data.openMode = SHELL_OPEN_ZIPFILE;
 --#endif
 --    }else if( cli_strcmp(z,"-append")==0 ){
 --      data.openMode = SHELL_OPEN_APPENDVFS;
 --#ifndef SQLITE_OMIT_DESERIALIZE
 --    }else if( cli_strcmp(z,"-deserialize")==0 ){
 --      data.openMode = SHELL_OPEN_DESERIALIZE;
 --    }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){
 --      data.szMax = integerValue(argv[++i]);
 --#endif
 --    }else if( cli_strcmp(z,"-readonly")==0 ){
 --      data.openMode = SHELL_OPEN_READONLY;
 --    }else if( cli_strcmp(z,"-nofollow")==0 ){
 --      data.openFlags = SQLITE_OPEN_NOFOLLOW;
 --#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
 --    }else if( cli_strncmp(z, "-A",2)==0 ){
 --      /* All remaining command-line arguments are passed to the ".archive"
 --      ** command, so ignore them */
 --      break;
 ++    verify_uninitialized();
   #endif
 --    }else if( cli_strcmp(z, "-memtrace")==0 ){
 --      sqlite3MemTraceActivate(stderr);
 --    }else if( cli_strcmp(z,"-bail")==0 ){
 --      bail_on_error = 1;
 --    }else if( cli_strcmp(z,"-nonce")==0 ){
 --      free(data.zNonce);
 --      data.zNonce = strdup(argv[++i]);
 --    }else if( cli_strcmp(z,"-unsafe-testing")==0 ){
 --      ShellSetFlag(&data,SHFLG_TestingMode);
 --    }else if( cli_strcmp(z,"-safe")==0 ){
 --      /* no-op - catch this on the second pass */
 --    }
 --  }
 ++    i = scanInvokeArgs(argc, argv, 1, &datai, &cmdArgs, &argsData);
   #ifndef SQLITE_SHELL_FIDDLE
 --  verify_uninitialized();
 ++    verify_uninitialized();
   #endif
   
 --
   #ifdef SQLITE_SHELL_INIT_PROC
 --  {
 --    /* If the SQLITE_SHELL_INIT_PROC macro is defined, then it is the name
 --    ** of a C-function that will perform initialization actions on SQLite that
 --    ** occur just before or after sqlite3_initialize(). Use this compile-time
 --    ** option to embed this shell program in larger applications. */
 --    extern void SQLITE_SHELL_INIT_PROC(void);
 --    SQLITE_SHELL_INIT_PROC();
 --  }
 ++    {
 ++      /* If the SQLITE_SHELL_INIT_PROC macro is defined, then it is the name
 ++      ** of a C-function that will perform initialization actions on SQLite that
 ++      ** occur just before or after sqlite3_initialize(). Use this compile-time
 ++      ** option to embed this shell program in larger applications. */
 ++      extern void SQLITE_SHELL_INIT_PROC(void);
 ++      SQLITE_SHELL_INIT_PROC();
 ++    }
   #else
 --  /* All the sqlite3_config() calls have now been made. So it is safe
 --  ** to call sqlite3_initialize() and process any command line -vfs option. */
 --  sqlite3_initialize();
 ++    /* All the sqlite3_config() calls have now been made. So it is safe
 ++    ** to call sqlite3_initialize() and process any command line -vfs option. */
 ++    sqlite3_initialize();
   #endif
   
 --  if( zVfs ){
 --    sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs);
 --    if( pVfs ){
 --      sqlite3_vfs_register(pVfs, 1);
 --    }else{
 --      utf8_printf(stderr, "no such VFS: \"%s\"\n", zVfs);
 --      exit(1);
+++    /* Create a mutex for thread-safe query execution interruption. */
+++    pGlobalDbLock = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+++    atexit(zapGlobalDbLock);
 ++    /* Register the control-C (SIGINT) handler.
 ++    ** Make sure we have a valid signal handler early, before anything
 ++    ** is done that might take long. */
-      pGlobalDbLock = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
 ++#ifdef SIGINT
 ++    signal(SIGINT, interrupt_handler);
 ++#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
 ++    SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
 ++#endif
 ++
 ++    if( argsData.zVfs ){
 ++      sqlite3_vfs *pVfs = sqlite3_vfs_find(argsData.zVfs);
 ++      if( pVfs ){
 ++        sqlite3_vfs_register(pVfs, 1);
 ++      }else{
 ++        utf8_printf(STD_ERR, "no such VFS: \"%s\"\n", argsData.zVfs);
 ++        rc = 1;
 ++        goto shell_bail;
 ++      }
       }
 --  }
   
 --  if( data.pAuxDb->zDbFilename==0 ){
 ++    if( datai.pAuxDb->zDbFilename==0 ){
   #ifndef SQLITE_OMIT_MEMORYDB
 --    data.pAuxDb->zDbFilename = ":memory:";
 --    warnInmemoryDb = argc==1;
 ++      datai.pAuxDb->zDbFilename = ":memory:";
 ++      warnInmemoryDb = argc==1;
   #else
 --    utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
 --    return 1;
 ++      utf8_printf(STD_ERR,"%s: Error: no database filename specified\n", Argv0);
 ++      rc = 1;
 ++      goto shell_bail;
   #endif
 --  }
 --  data.out = stdout;
 ++    }
 ++    datai.out = STD_OUT;
   #ifndef SQLITE_SHELL_FIDDLE
 --  sqlite3_appendvfs_init(0,0,0);
 ++    sqlite3_appendvfs_init(0,0,0);
   #endif
   
 --  /* Go ahead and open the database file if it already exists.  If the
 --  ** file does not exist, delay opening it.  This prevents empty database
 --  ** files from being created if a user mistypes the database name argument
 --  ** to the sqlite command-line tool.
 --  */
 --  if( access(data.pAuxDb->zDbFilename, 0)==0 ){
 --    open_db(&data, 0);
 --  }
 ++    /* Go ahead and open the database file if it already exists.  If the
 ++    ** file does not exist, delay opening it.  This prevents empty database
 ++    ** files from being created if a user mistypes the database name argument
 ++    ** to the sqlite command-line tool.
 ++    */
 ++    if( access(datai.pAuxDb->zDbFilename, 0)==0 ){
 ++      open_db(&datax, 0);
 ++    }
   
 --  /* Process the initialization file if there is one.  If no -init option
 --  ** is given on the command line, look for a file named ~/.sqliterc and
 --  ** try to process it.
 --  */
 --  process_sqliterc(&data,zInitFile);
 ++    /* Process the initialization file if there is one.  If no -init option
 ++    ** is given on the command line, look for a file named ~/.sqliterc and
 ++    ** try to process it, without any quitting or bail-on-error.
 ++    */
 ++    process_sqliterc(&datai,argsData.zInitFile);
 ++
 ++    /* Make a second pass through the command-line argument and set
 ++    ** options.  This second pass is delayed until after the initialization
 ++    ** file is processed so that the command-line arguments will override
 ++    ** settings in the initialization file.
 ++    */
 ++    rc = scanInvokeArgs(argc, argv, 2, &datai, &cmdArgs, &argsData);
 ++    if( rc>0 ){
 ++      goto shell_bail;
 ++    }
   
 --  /* Make a second pass through the command-line argument and set
 --  ** options.  This second pass is delayed until after the initialization
 --  ** file is processed so that the command-line arguments will override
 --  ** settings in the initialization file.
 --  */
 --  for(i=1; i<argc; i++){
 --    char *z = argv[i];
 --    if( z[0]!='-' || i>=nOptsEnd ) continue;
 --    if( z[1]=='-' ){ z++; }
 --    if( cli_strcmp(z,"-init")==0 ){
 --      i++;
 --    }else if( cli_strcmp(z,"-html")==0 ){
 --      data.mode = MODE_Html;
 --    }else if( cli_strcmp(z,"-list")==0 ){
 --      data.mode = MODE_List;
 --    }else if( cli_strcmp(z,"-quote")==0 ){
 --      data.mode = MODE_Quote;
 --      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Comma);
 --      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
 --    }else if( cli_strcmp(z,"-line")==0 ){
 --      data.mode = MODE_Line;
 --    }else if( cli_strcmp(z,"-column")==0 ){
 --      data.mode = MODE_Column;
 --    }else if( cli_strcmp(z,"-json")==0 ){
 --      data.mode = MODE_Json;
 --    }else if( cli_strcmp(z,"-markdown")==0 ){
 --      data.mode = MODE_Markdown;
 --    }else if( cli_strcmp(z,"-table")==0 ){
 --      data.mode = MODE_Table;
 --    }else if( cli_strcmp(z,"-box")==0 ){
 --      data.mode = MODE_Box;
 --    }else if( cli_strcmp(z,"-csv")==0 ){
 --      data.mode = MODE_Csv;
 --      memcpy(data.colSeparator,",",2);
 --#ifdef SQLITE_HAVE_ZLIB
 --    }else if( cli_strcmp(z,"-zip")==0 ){
 --      data.openMode = SHELL_OPEN_ZIPFILE;
 --#endif
 --    }else if( cli_strcmp(z,"-append")==0 ){
 --      data.openMode = SHELL_OPEN_APPENDVFS;
 --#ifndef SQLITE_OMIT_DESERIALIZE
 --    }else if( cli_strcmp(z,"-deserialize")==0 ){
 --      data.openMode = SHELL_OPEN_DESERIALIZE;
 --    }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){
 --      data.szMax = integerValue(argv[++i]);
 --#endif
 --    }else if( cli_strcmp(z,"-readonly")==0 ){
 --      data.openMode = SHELL_OPEN_READONLY;
 --    }else if( cli_strcmp(z,"-nofollow")==0 ){
 --      data.openFlags |= SQLITE_OPEN_NOFOLLOW;
 --    }else if( cli_strcmp(z,"-ascii")==0 ){
 --      data.mode = MODE_Ascii;
 --      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,SEP_Unit);
 --      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,SEP_Record);
 --    }else if( cli_strcmp(z,"-tabs")==0 ){
 --      data.mode = MODE_List;
 --      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,SEP_Tab);
 --      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,SEP_Row);
 --    }else if( cli_strcmp(z,"-separator")==0 ){
 --      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
 --                       "%s",cmdline_option_value(argc,argv,++i));
 --    }else if( cli_strcmp(z,"-newline")==0 ){
 --      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
 --                       "%s",cmdline_option_value(argc,argv,++i));
 --    }else if( cli_strcmp(z,"-nullvalue")==0 ){
 --      sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
 --                       "%s",cmdline_option_value(argc,argv,++i));
 --    }else if( cli_strcmp(z,"-header")==0 ){
 --      data.showHeader = 1;
 --      ShellSetFlag(&data, SHFLG_HeaderSet);
 --     }else if( cli_strcmp(z,"-noheader")==0 ){
 --      data.showHeader = 0;
 --      ShellSetFlag(&data, SHFLG_HeaderSet);
 --    }else if( cli_strcmp(z,"-echo")==0 ){
 --      ShellSetFlag(&data, SHFLG_Echo);
 --    }else if( cli_strcmp(z,"-eqp")==0 ){
 --      data.autoEQP = AUTOEQP_on;
 --    }else if( cli_strcmp(z,"-eqpfull")==0 ){
 --      data.autoEQP = AUTOEQP_full;
 --    }else if( cli_strcmp(z,"-stats")==0 ){
 --      data.statsOn = 1;
 --    }else if( cli_strcmp(z,"-scanstats")==0 ){
 --      data.scanstatsOn = 1;
 --    }else if( cli_strcmp(z,"-backslash")==0 ){
 --      /* Undocumented command-line option: -backslash
 --      ** Causes C-style backslash escapes to be evaluated in SQL statements
 --      ** prior to sending the SQL into SQLite.  Useful for injecting
 --      ** crazy bytes in the middle of SQL statements for testing and debugging.
 --      */
 --      ShellSetFlag(&data, SHFLG_Backslash);
 --    }else if( cli_strcmp(z,"-bail")==0 ){
 --      /* No-op.  The bail_on_error flag should already be set. */
 --    }else if( cli_strcmp(z,"-version")==0 ){
 --      printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
 --      return 0;
 --    }else if( cli_strcmp(z,"-interactive")==0 ){
 --      stdin_is_interactive = 1;
 --    }else if( cli_strcmp(z,"-batch")==0 ){
 --      stdin_is_interactive = 0;
 --    }else if( cli_strcmp(z,"-utf8")==0 ){
   #if SHELL_WIN_UTF8_OPT
 --      console_utf8 = 1;
 --#endif /* SHELL_WIN_UTF8_OPT */
 --    }else if( cli_strcmp(z,"-heap")==0 ){
 --      i++;
 --    }else if( cli_strcmp(z,"-pagecache")==0 ){
 --      i+=2;
 --    }else if( cli_strcmp(z,"-lookaside")==0 ){
 --      i+=2;
 --    }else if( cli_strcmp(z,"-threadsafe")==0 ){
 --      i+=2;
 --    }else if( cli_strcmp(z,"-nonce")==0 ){
 --      i += 2;
 --    }else if( cli_strcmp(z,"-mmap")==0 ){
 --      i++;
 --    }else if( cli_strcmp(z,"-memtrace")==0 ){
 --      i++;
 --#ifdef SQLITE_ENABLE_SORTER_REFERENCES
 --    }else if( cli_strcmp(z,"-sorterref")==0 ){
 --      i++;
 --#endif
 --    }else if( cli_strcmp(z,"-vfs")==0 ){
 --      i++;
 --#ifdef SQLITE_ENABLE_VFSTRACE
 --    }else if( cli_strcmp(z,"-vfstrace")==0 ){
 --      i++;
 --#endif
 --#ifdef SQLITE_ENABLE_MULTIPLEX
 --    }else if( cli_strcmp(z,"-multiplex")==0 ){
 --      i++;
 --#endif
 --    }else if( cli_strcmp(z,"-help")==0 ){
 --      usage(1);
 --    }else if( cli_strcmp(z,"-cmd")==0 ){
 --      /* Run commands that follow -cmd first and separately from commands
 --      ** that simply appear on the command-line.  This seems goofy.  It would
 --      ** be better if all commands ran in the order that they appear.  But
 --      ** we retain the goofy behavior for historical compatibility. */
 --      if( i==argc-1 ) break;
 --      z = cmdline_option_value(argc,argv,++i);
 --      if( z[0]=='.' ){
 --        rc = do_meta_command(z, &data);
 --        if( rc && bail_on_error ) return rc==2 ? 0 : rc;
 --      }else{
 --        open_db(&data, 0);
 --        rc = shell_exec(&data, z, &zErrMsg);
 --        if( zErrMsg!=0 ){
 --          utf8_printf(stderr,"Error: %s\n", zErrMsg);
 --          if( bail_on_error ) return rc!=0 ? rc : 1;
 --        }else if( rc!=0 ){
 --          utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z);
 --          if( bail_on_error ) return rc;
 --        }
 --      }
 --#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
 --    }else if( cli_strncmp(z, "-A", 2)==0 ){
 --      if( nCmd>0 ){
 --        utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands"
 --                            " with \"%s\"\n", z);
 --        return 1;
 --      }
 --      open_db(&data, OPEN_DB_ZIPFILE);
 --      if( z[2] ){
 --        argv[i] = &z[2];
 --        arDotCommand(&data, 1, argv+(i-1), argc-(i-1));
 --      }else{
 --        arDotCommand(&data, 1, argv+i, argc-i);
 --      }
 --      readStdin = 0;
 --      break;
 --#endif
 --    }else if( cli_strcmp(z,"-safe")==0 ){
 --      data.bSafeMode = data.bSafeModePersist = 1;
 --    }else if( cli_strcmp(z,"-unsafe-testing")==0 ){
 --      /* Acted upon in first pass. */
 ++    if( console_utf8 && stdin_is_interactive ){
 ++      console_prepare();
       }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;
 ++      setBinaryMode(stdin, 0);
 ++      console_utf8 = 0;
       }
 --    data.cMode = data.mode;
 --  }
 --#if SHELL_WIN_UTF8_OPT
 --  if( console_utf8 && stdin_is_interactive ){
 --    console_prepare();
 --  }else{
 --    setBinaryMode(stdin, 0);
 --    console_utf8 = 0;
 --  }
   #endif
   
 --  if( !readStdin ){
 --    /* Run all arguments that do not begin with '-' as if they were separate
 --    ** command-line inputs, except for the argToSkip argument which contains
 --    ** the database filename.
 --    */
 --    for(i=0; i<nCmd; i++){
 --      if( azCmd[i][0]=='.' ){
 --        rc = do_meta_command(azCmd[i], &data);
 --        if( rc ){
 --          free(azCmd);
 --          return rc==2 ? 0 : rc;
 --        }
 --      }else{
 --        open_db(&data, 0);
 --        echo_group_input(&data, azCmd[i]);
 --        rc = shell_exec(&data, azCmd[i], &zErrMsg);
 --        if( zErrMsg || rc ){
 --          if( zErrMsg!=0 ){
 --            utf8_printf(stderr,"Error: %s\n", zErrMsg);
 --          }else{
 --            utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
 --          }
 --          sqlite3_free(zErrMsg);
 --          free(azCmd);
 --          return rc!=0 ? rc : 1;
 --        }
 --      }
 --    }
 --  }else{
 --    /* Run commands received from standard input
 --    */
 --    if( stdin_is_interactive ){
 --      char *zHome;
 --      char *zHistory;
 --      int nHistory;
 --      printf(
 --        "SQLite version %s %.19s\n" /*extra-version-info*/
 --        "Enter \".help\" for usage hints.\n",
 --        sqlite3_libversion(), sqlite3_sourceid()
 --      );
 --      if( warnInmemoryDb ){
 --        printf("Connected to a ");
 --        printBold("transient in-memory database");
 --        printf(".\nUse \".open FILENAME\" to reopen on a "
 --               "persistent database.\n");
 --      }
 --      zHistory = getenv("SQLITE_HISTORY");
 --      if( zHistory ){
 --        zHistory = strdup(zHistory);
 --      }else if( (zHome = find_home_dir(0))!=0 ){
 --        nHistory = strlen30(zHome) + 20;
 --        if( (zHistory = malloc(nHistory))!=0 ){
 --          sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
 ++    if( !argsData.readStdin ){
 ++      /* Run all arguments that are not the DB name or do not begin with '-'
 ++      ** as if they were separate command-line inputs. */
 ++      for(i=0; i<cmdArgs.nCmd && rc<2; i++){
 ++        set_invocation_cmd(cmdArgs.azCmd[i]);
 ++        drc = process_input(&datai);
 ++        rc = (drc>2)? 2 : drc;
 ++        if( rc>0 ){
 ++          goto shell_bail;
           }
         }
 --      if( zHistory ){ shell_read_history(zHistory); }
 ++    }else{
 ++      /* Run commands received from standard input
 ++      */
 ++      if( stdin_is_interactive ){
 ++        char *zHome;
 ++        char *zHistory = 0;
 ++        if( argsData.bQuiet ){
 ++          /* bQuiet is almost like normal interactive, but quieter
 ++          ** and avoids history keeping and line editor completions. */
 ++          mainPrompt[0] = 0;
 ++          continuePrompt[0] = 0;
 ++        }else{
 ++          fprintf(STD_OUT,
 ++            "SQLite version %s %.19s\n" /*extra-version-info*/
 ++            "Enter \".help\" for usage hints.\n",
 ++            sqlite3_libversion(), sqlite3_sourceid()
 ++          );
 ++          if( warnInmemoryDb ){
 ++            fprintf(STD_OUT, "Connected to a ");
 ++            printBold("transient in-memory database");
 ++            fprintf(STD_OUT, ".\nUse \".open FILENAME\" to reopen on a "
 ++                   "persistent database.\n");
 ++          }
 ++          zHistory = getenv("SQLITE_HISTORY");
 ++          if( zHistory ){
 ++            zHistory = strdup(zHistory);
 ++          }else if( (zHome = find_home_dir(0))!=0 ){
 ++            int nHistory = strlen30(zHome) + 20;
 ++            if( (zHistory = malloc(nHistory))!=0 ){
 ++              sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
 ++            }
 ++          }
 ++          if( zHistory ){ shell_read_history(zHistory); }
   #if HAVE_READLINE || HAVE_EDITLINE
 --      rl_attempted_completion_function = readline_completion;
 ++          rl_attempted_completion_function = readline_completion;
   #elif HAVE_LINENOISE
 --      linenoiseSetCompletionCallback(linenoise_completion);
 ++          linenoiseSetCompletionCallback(linenoise_completion);
   #endif
 --      data.in = 0;
 --      rc = process_input(&data);
 --      if( zHistory ){
 --        shell_stifle_history(2000);
 --        shell_write_history(zHistory);
 --        free(zHistory);
 ++        }
 ++        datai.pInSource = &termInSource; /* read from stdin interactively */
 ++        drc = process_input(&datai);
 ++        rc = (drc>2)? 2 : drc;
 ++        if( !bQuiet ){
 ++          if( zHistory ){
 ++            shell_stifle_history(2000);
 ++            shell_write_history(zHistory);
 ++            free(zHistory);
 ++          }
 ++        }
 ++      }else{
 ++        datai.pInSource = &stdInSource; /* read from stdin without prompts */
 ++        drc = process_input(&datai);
 ++        rc = (drc>2)? 2 : drc;
         }
 --    }else{
 --      data.in = stdin;
 --      rc = process_input(&data);
       }
 ++  }else{
 ++    /* An abrupt, stack-ripping exit arrives here. */
     }
 ++ shell_bail:
 ++  holder_free(entry_mark);
   #ifndef SQLITE_SHELL_FIDDLE
     /* In WASM mode we have to leave the db state in place so that
 --  ** client code can "push" SQL into it after this call returns. */
 --  free(azCmd);
 --  set_table_name(&data, 0);
 --  if( data.db ){
 --    session_close_all(&data, -1);
 --    close_db(data.db);
 ++  ** client code can "push" SQL into it after this call returns.
 ++  ** For that build, just bypass freeing all acquired resources.
 ++  */
 ++  set_table_name(&datax, 0);
 ++  if( datax.dbUser ){
 ++    session_close_all(&datai, -1);
 ++# if SHELL_DYNAMIC_EXTENSION
 ++    notify_subscribers(&datai, NK_DbAboutToClose, datax.dbUser);
 ++# endif
 ++    close_db(datax.dbUser);
     }
 --  for(i=0; i<ArraySize(data.aAuxDb); i++){
 --    sqlite3_free(data.aAuxDb[i].zFreeOnClose);
 --    if( data.aAuxDb[i].db ){
 --      session_close_all(&data, i);
 --      close_db(data.aAuxDb[i].db);
+++# ifdef SQLITE_DEBUG
+++  /* Do this redundantly with atexit() to aid memory leak reporting. */
 ++  sqlite3_mutex_free(pGlobalDbLock);
 ++  pGlobalDbLock = 0;
+++# endif
 ++  for(i=0; i<ArraySize(datai.aAuxDb); i++){
 ++    sqlite3_free(datai.aAuxDb[i].zFreeOnClose);
 ++    if( datai.aAuxDb[i].db ){
 ++      session_close_all(&datai, i);
 ++      close_db(datai.aAuxDb[i].db);
       }
     }
     find_home_dir(1);