]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Further CLI resmanage use. (69% by LOC, 53% by command count) Some renames for clarity.
authorlarrybr <larrybr@noemail.net>
Wed, 17 May 2023 03:57:12 +0000 (03:57 +0000)
committerlarrybr <larrybr@noemail.net>
Wed, 17 May 2023 03:57:12 +0000 (03:57 +0000)
FossilOrigin-Name: c010e1a7b2120d44c096b7d4216a8a51601972581f232d537b577617dfa6195a

manifest
manifest.uuid
src/resmanage.c
src/resmanage.h
src/shell.c.in

index f29654a599841b89fb95351855a07b24f94864af..40f8523caf2a0a5ef8f133bbe71927f91b38f5f4 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Further\sextend\suse\sof\sCLI\sresmanage.\s(40%\sof\sdot\scommands)
-D 2023-05-16T20:37:38.246
+C Further\sCLI\sresmanage\suse.\s(69%\sby\sLOC,\s53%\sby\scommand\scount)\sSome\srenames\sfor\sclarity.
+D 2023-05-17T03:57:12.866
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -638,12 +638,12 @@ F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
 F src/prepare.c 6350675966bd0e7ac3a464af9dbfe26db6f0d4237f4e1f1acdb17b12ad371e6e
 F src/printf.c b9320cdbeca0b336c3f139fd36dd121e4167dd62b35fbe9ccaa9bab44c0af38d
 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
-F src/resmanage.c 5bea79cfe8b41b68489aed39f135270c937133338937088d2336dea3c005215d
-F src/resmanage.h 28a5f41d55cc6d159cb14977e162de3c265ae8798d51ccd942fd218624195d99
+F src/resmanage.c 8fbaf2c6af64db4ce5fa2cdd97ce89415575ecb3d2984978214275b414bb5724
+F src/resmanage.h 755e58c5b0ee03a3fd11c019c4003242b01524c3bba4e4521439bd00564eccfa
 F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c 738c3a3d6929f8be66c319bad17f6b297bd60a4eb14006075c48a28487dc7786
-F src/shell.c.in a12f9ed7617194f2a09493d4fa83ac232303dd9a0a607988c2f05190aa842818
+F src/shell.c.in 19c383fbbbc2198cb7047de523a0c57c2328dd839ca03340ca7eae1ee804db26
 F src/shext_linkage.h 27dcf7624df05b2a7a6d367834339a6db3636f3035157f641f7db2ec499f8f6d
 F src/sqlite.h.in c14a4471fcd897a03631ac7ad3d05505e895e7b6419ec5b96cae9bc4df7a9fc6
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
@@ -2081,8 +2081,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 243085279c6f8c51ad85bdc1e7c07ef6f858067640a7330f77d0bf94ed11b438 831d0fb2836b71c9bc51067c49fee4b8f18047814f2ff22d817d25195cf350b0
-R 932236b86f0cebfd2719e06bd539117f
+P 0cdab9f17a2ceaa4d4228e535c3d780ed5fd2cb4e36cc50becba99e8ebff362d
+R dcacca614f0ea4561b47767a0b44bde3
 U larrybr
-Z 2527b5a4612bc8b8d004f77ba865da77
+Z 17f12779e20d1bf08e9f288d6ce2800a
 # Remove this line to create a well-formed Fossil manifest.
index e4dddb57c15ee1a04d98c960bc7fb3ecb5ccadd3..3b19e333b2481aca1dacd4eecd0b23b48b70065b 100644 (file)
@@ -1 +1 @@
-0cdab9f17a2ceaa4d4228e535c3d780ed5fd2cb4e36cc50becba99e8ebff362d
\ No newline at end of file
+c010e1a7b2120d44c096b7d4216a8a51601972581f232d537b577617dfa6195a
\ No newline at end of file
index 41945e33f3ee1f7eef17496d350ccee00c9ff930..6d121d680857692f9f8f5b07f36bfbb2c2a47305 100644 (file)
@@ -22,8 +22,8 @@
 /* Track how to free various held resources. */
 typedef enum FreeableResourceKind {
   FRK_Indirect = 1<<15,
-  FRK_Malloc = 0, FRK_DbConn = 1, FRK_DbStmt = 2,
-  FRK_DbMem = 3, FRK_File = 4,
+  FRK_Malloc = 0, FRK_DbConn, FRK_DbStmt, FRK_SqStr,
+  FRK_DbMem, FRK_File,
 #if (!defined(_WIN32) && !defined(WIN32)) || !SQLITE_OS_WINRT
   FRK_Pipe,
 #endif
@@ -56,6 +56,7 @@ typedef struct ResourceHeld {
 #ifdef SHELL_MANAGE_TEXT
     ShellText *p_text;
 #endif
+    sqlite3_str *p_sqst;
     AnyResourceHolder *p_any_rh;
     VirtualDtorNthObject *p_vdfo;
   } held;
@@ -100,10 +101,12 @@ void quit_moan(const char *zMoan, int errCode){
 /* Free a single resource item. (ignorant of stack) */
 static int free_rk( ResourceHeld *pRH ){
   int rv = 0;
-  if( pRH->held.p_any == 0 ) return rv;
+  if( pRH->held.p_any == 0 ) return 0;
   if( pRH->frk & FRK_Indirect ){
-    pRH->held.p_any = *(void**)pRH->held.p_any;
-    if( pRH->held.p_any == 0 ) return rv;
+    void **ppv = (void**)pRH->held.p_any;
+    pRH->held.p_any = *ppv;
+    *ppv = (void*)0;
+    if( pRH->held.p_any == 0 ) return 0;
     pRH->frk &= ~FRK_Indirect;
   }
   ++rv;
@@ -134,6 +137,12 @@ static int free_rk( ResourceHeld *pRH ){
     freeText(pRH->held.p_text);
     break;
 #endif
+  case FRK_SqStr:
+    {
+      char *z = sqlite3_str_finish(pRH->held.p_sqst);
+      if( z!=0 ) sqlite3_free(z);
+    }
+    break;
   case FRK_AnyRef:
     (pRH->held.p_any_rh->its_freer)(pRH->held.p_any_rh->pAny);
     break;
@@ -183,12 +192,12 @@ static int more_holders_try(ResourceCount count){
 }
 
 /* Lose one or more holders. */
-void* pop_holder(void){
+void* drop_holder(void){
   assert(numResHold>0);
   if( numResHold>0 ) return pResHold[--numResHold].held.p_any;
   return 0;
 }
-void pop_holders(ResourceCount num){
+void drop_holders(ResourceCount num){
   assert(numResHold>=num);
   if( numResHold>=num ) numResHold -= num;
   else numResHold = 0;
@@ -235,11 +244,21 @@ char* mstr_holder(char *z){
   res_hold(z, FRK_Malloc);
   return z;
 }
+/* Hold a SQLite dynamic string */
+sqlite3_str * sqst_holder(sqlite3_str *psqst){
+  res_hold(psqst, FRK_SqStr);
+  return psqst;
+}
 /* Hold a C string in the SQLite heap */
 char* sstr_holder(char *z){
   res_hold(z, FRK_DbMem);
   return z;
 }
+/* Hold a SQLite dynamic string, reference to */
+void sqst_ptr_holder(sqlite3_str **ppsqst){
+  assert(ppsqst!=0);
+  res_hold(ppsqst, FRK_SqStr|FRK_Indirect);
+}
 /* Hold a C string in the SQLite heap, reference to */
 void sstr_ptr_holder(char **pz){
   assert(pz!=0);
index eb6907c12b6ad377909e959dd0094ecc9221fac8..f269bf9c2f46213a7a4b5dee91092e557efe4b04 100644 (file)
@@ -82,8 +82,8 @@ extern ResourceMark holder_mark();
 extern void more_holders(ResourceCount more);
 
 /* Lose one or more holders, without freeing anything. */
-extern void* pop_holder(void);
-extern void pop_holders(ResourceCount num);
+extern void* drop_holder(void);
+extern void drop_holders(ResourceCount num);
 
 /* Drop one or more holders while freeing their holdees. */
 extern void release_holder(void);
@@ -110,6 +110,8 @@ extern char* sstr_holder(char *z);
 extern void conn_holder(sqlite3 *pdb);
 /* a SQLite prepared statement */
 extern void stmt_holder(sqlite3_stmt *pstmt);
+/* a SQLite dynamic string */
+extern sqlite3_str *sqst_holder(sqlite3_str *psqst);
 /* an open C runtime FILE */
 extern void file_holder(FILE *);
 #if (!defined(_WIN32) && !defined(WIN32)) || !SQLITE_OS_WINRT
@@ -148,7 +150,9 @@ extern void sstr_ptr_holder(char **pz);
 extern void stmt_ptr_holder(sqlite3_stmt **ppstmt);
 /* a SQLite database ("connection"), reference to */
 extern void conn_ptr_holder(sqlite3 **ppdb);
-/* an object with v-table (ref) whose dtor is the 0th member, reference to */
+/* a SQLite dynamic string, reference to */
+extern void sqst_ptr_holder(sqlite3_str **ppsqst);
+/* an object with (by-ref) v-table whose dtor is nth member, reference to */
 extern void dtor_ref_holder(VirtualDtorNthObject *pvdfo, unsigned char n);
 #ifdef SHELL_MANAGE_TEXT
 /* a ShellText object, reference to (storage for which not managed) */
index c865a3d49794f8e46443c96dff32ba1f012d2181..db0c74bcffc562b97ffea246b41c46240d37de01 100644 (file)
@@ -5820,7 +5820,7 @@ static unsigned char *readHexDb(ShellInState *psi, int *pnData){
     }
   }
   *pnData = n; /* Record success and size. */
-  pop_holder();
+  drop_holder();
  readHexDb_cleanup:
   holder_free(mark);
   return a;
@@ -10643,7 +10643,7 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){
                   "%s\n", sCtx.zFile, zRenames);
     }
     assert(dbCols==0);
-    pop_holder(); /* dbCols */
+    drop_holder(); /* dbCols */
     if( zColDefs==0 ){
       *pzErr = smprintf("%s: empty file\n", sCtx.zFile);
     import_fail: /* entry from outer blocks */
@@ -10816,14 +10816,16 @@ COLLECT_HELP_TEXT[
 ];
 DISPATCHABLE_COMMAND( imposter ? 3 3 ){
   int rc = 0;
-  char *zSql;
+  char *zSql = 0;
   char *zCollist = 0;
-  sqlite3_stmt *pStmt;
+  sqlite3_stmt *pStmt = 0;
   sqlite3 *db;
   int tnum = 0;
   int isWO = 0;  /* True if making an imposter of a WITHOUT ROWID table */
   int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
   int i;
+  ResourceMark mark = holder_mark();
+
   if( !ShellHasFlag(p,SHFLG_TestingMode) ){
     utf8_printf(stderr, ".%s unavailable without --unsafe-testing\n",
                 "imposter");
@@ -10847,6 +10849,7 @@ DISPATCHABLE_COMMAND( imposter ? 3 3 ){
     sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 0, 1);
     return DCR_Ok;
   }
+  sstr_ptr_holder(&zSql);
   zSql = smprintf("SELECT rootpage, 0 FROM sqlite_schema"
                   " WHERE name='%q' AND type='index'"
                   "UNION ALL "
@@ -10854,17 +10857,24 @@ DISPATCHABLE_COMMAND( imposter ? 3 3 ){
                   " WHERE name='%q' AND type='table'"
                   "  AND sql LIKE '%%without%%rowid%%'",
                   azArg[1], azArg[1]);
-  sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
-  sqlite3_free(zSql);
+  shell_check_ooms(zSql);
+  rc = shell_check_nomem(sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0));
+  if( rc!=SQLITE_OK ){
+    release_holder();
+    return DCR_Error;
+  }
+  stmt_ptr_holder(&pStmt);
   if( sqlite3_step(pStmt)==SQLITE_ROW ){
     tnum = sqlite3_column_int(pStmt, 0);
     isWO = sqlite3_column_int(pStmt, 1);
   }
-  sqlite3_finalize(pStmt);
-  zSql = smprintf("PRAGMA index_xinfo='%q'", azArg[1]);
-  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
   sqlite3_free(zSql);
+  zSql = smprintf("PRAGMA index_xinfo='%q'", azArg[1]);
+  sqlite3_finalize(pStmt);
+  pStmt = 0;
+  rc = shell_check_nomem(sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0));
   i = 0;
+  sstr_ptr_holder(&zCollist);
   while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
     char zLabel[20];
     const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
@@ -10886,19 +10896,19 @@ DISPATCHABLE_COMMAND( imposter ? 3 3 ){
       zCollist = smprintf("%z,\"%w\"", zCollist, zCol);
     }
   }
-  sqlite3_finalize(pStmt);
   if( i==0 || tnum==0 ){
     *pzErr = smprintf("no such index: \"%s\"\n", azArg[1]);
-    sqlite3_free(zCollist);
+    holder_free(mark);
     return DCR_Error;
   }
   if( lenPK==0 ) lenPK = 100000;
+  sqlite3_free(zSql);
   zSql = smprintf("CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))"
                   "WITHOUT ROWID", azArg[2], zCollist, lenPK, zCollist);
-  sqlite3_free(zCollist);
+  shell_check_ooms(zSql);
   rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 1, tnum);
   if( rc==SQLITE_OK ){
-    rc = sqlite3_exec(db, zSql, 0, 0, 0);
+    rc = shell_check_nomem(sqlite3_exec(db, zSql, 0, 0, 0));
     sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 0, 0);
     if( rc ){
       *pzErr = smprintf("Error in [%s]: %s\n", zSql, sqlite3_errmsg(db));
@@ -10912,8 +10922,8 @@ DISPATCHABLE_COMMAND( imposter ? 3 3 ){
   }else{
     *pzErr = smprintf("SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
   }
-  sqlite3_free(zSql);
-  return rc != 0;
+  holder_free(mark);
+  return DCR_Ok|(rc != 0);
 }
 DISPATCHABLE_COMMAND( iotrace ? 2 2 ){
   SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
@@ -11012,6 +11022,7 @@ DISPATCHABLE_COMMAND( lint 3 1 0 ){
   const char *zIndent = "";       /* How much to indent CREATE INDEX by */
   int rc;                         /* Return code */
   sqlite3_stmt *pSql = 0;         /* Compiled version of SQL statement below */
+  ResourceMark mark = holder_mark();
 
   i = (nArg>=2 ? strlen30(azArg[1]) : 0);
   if( i==0 || 0!=sqlite3_strnicmp(azArg[1], "fkey-indexes", i) ){
@@ -11111,8 +11122,10 @@ DISPATCHABLE_COMMAND( lint 3 1 0 ){
   );
 
   if( rc==SQLITE_OK ){
-    rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
+    rc = shell_check_nomem(sqlite3_prepare_v2(db, zSql, -1, &pSql, 0));
   }
+  /* Track resources after here. */
+  stmt_ptr_holder(&pSql);
   if( rc==SQLITE_OK ){
     sqlite3_bind_int(pSql, 1, bGroupByParent);
   }
@@ -11120,9 +11133,11 @@ DISPATCHABLE_COMMAND( lint 3 1 0 ){
   if( rc==SQLITE_OK ){
     int rc2;
     char *zPrev = 0;
+    sqlite3_stmt *pExplain = 0;
+    sstr_ptr_holder(&zPrev);
+    stmt_ptr_holder(&pExplain);
     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);
@@ -11131,14 +11146,16 @@ DISPATCHABLE_COMMAND( lint 3 1 0 ){
       const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
 
       if( zEQP==0 || zGlob==0 ) continue;
-      rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
+      rc = shell_check_nomem(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);
+        shell_check_ooms(zPlan);
         res = zPlan!=0 && (  0==sqlite3_strglob(zGlob, zPlan)
                              || 0==sqlite3_strglob(zGlobIPK, zPlan));
       }
       rc = sqlite3_finalize(pExplain);
+      pExplain = 0;
       if( rc!=SQLITE_OK ) break;
 
       if( res<0 ){
@@ -11152,6 +11169,7 @@ DISPATCHABLE_COMMAND( lint 3 1 0 ){
           raw_printf(out, "-- Parent table %s\n", zParent);
           sqlite3_free(zPrev);
           zPrev = smprintf("%s", zParent);
+          shell_check_ooms(zPrev);
         }
 
         if( res==0 ){
@@ -11162,13 +11180,13 @@ DISPATCHABLE_COMMAND( lint 3 1 0 ){
         }
       }
     }
-    sqlite3_free(zPrev);
 
     if( rc!=SQLITE_OK ){
       *pzErr = smprintf("%s\n", sqlite3_errmsg(db));
     }
 
     rc2 = sqlite3_finalize(pSql);
+    pSql = 0;
     if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
       rc = rc2;
       *pzErr = smprintf("%s\n", sqlite3_errmsg(db));
@@ -11176,6 +11194,7 @@ DISPATCHABLE_COMMAND( lint 3 1 0 ){
   }else{
     *pzErr = smprintf("%s\n", sqlite3_errmsg(db));
   }
+  holder_free(mark);
 
   return DCR_Ok|(rc!=0);
 }
@@ -11203,21 +11222,19 @@ DISPATCHABLE_COMMAND( log ? 2 2 ){
   const char *zFile = azArg[1];
   int bOn = cli_strcmp(zFile,"on")==0;
   int bOff = cli_strcmp(zFile,"off")==0;
-  if( ISS(p)->bSafeMode && !bOn && !bOff ){
-    return DCR_AbortError;
-  }
+#if defined(SQLITE_SHELL_FIDDLE)
+  if( !bOn && !bOff ) return DCR_SayUsage;
+#else
+  if( ISS(p)->bSafeMode && !bOn && !bOff ) return DCR_AbortError;
+#endif
   output_file_close(ISS(p)->pLog);
   if( bOff ){
     ISS(p)->pLog = 0;
     return DCR_Ok;
   }
-#if defined(SQLITE_SHELL_FIDDLE)
-  if( !bOn ) return DCR_SayUsage;
-#else
   if( bOn ) zFile = "stdout";
-#endif
   ISS(p)->pLog = output_file_open(zFile, 0);
-  return DCR_Ok;
+  return DCR_Ok|(ISS(p)->pLog==0);
 }
 
 static void effectMode(ShellInState *psi, u8 modeRequest, u8 modeNominal){
@@ -11439,7 +11456,6 @@ DISPATCHABLE_COMMAND( oomfake ? 1 2 azArg nArg p ){
 #else
 # define HOPEN ".open"
 #endif
-/* ToDo: Get defined help text collection into macro processor. */
 /*****************
  * The .nonce, .nullvalue and .open commands
  */
@@ -11546,8 +11562,7 @@ DISPATCHABLE_COMMAND( open 3 1 0 ){
     psi->szMax = szMax;
     open_db(p, OPEN_DB_KEEPALIVE);
     if( DBX(p)==0 ){
-      *pzErr = smprintf("cannot open '%s'\n", zNewFilename);
-      sqlite3_free(zNewFilename);
+      *pzErr = smprintf("cannot open '%z'\n", zNewFilename);
       rc = 1;
     }else{
       psi->pAuxDb->zFreeOnClose = zNewFilename;
@@ -11566,7 +11581,8 @@ DISPATCHABLE_COMMAND( nonce ? 2 2 ){
   if( psi->zNonce==0 || cli_strcmp(azArg[1],psi->zNonce)!=0 ){
     raw_printf(STD_ERR, "line %d: incorrect nonce: \"%s\"\n",
                psi->pInSource->lineno, azArg[1]);
-    exit(1);
+    p->shellAbruptExit = 0x102;
+    return DCR_Abort;
   }
   /* Suspend safe mode for 1 dot-command after this. */
   psi->bSafeModeFuture = 2;
@@ -11643,14 +11659,14 @@ static char *home_based_path( const char *zPath ){
 static int kv_xfr_table(sqlite3 *db, const char *zStoreDbName,
                         int bSaveNotLoad, ParamTableUse ptu,
                         const char *azNames[], int nNames){
-  int rc = 0;
   char *zSql = 0; /* to be sqlite3_free()'ed */
   sqlite3_str *sbCopy = 0;
+  sqlite3 *dbStore = 0;
   const char *zHere = 0;
   const char *zThere = SH_KV_STORE_SNAME;
   const char *zTo;
   const char *zFrom;
-  sqlite3 *dbStore = 0;
+  int rc = 0;
   int openFlags = (bSaveNotLoad)
     ? SQLITE_OPEN_URI|SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE
     : SQLITE_OPEN_READONLY;
@@ -11663,7 +11679,7 @@ static int kv_xfr_table(sqlite3 *db, const char *zStoreDbName,
   zTo = (bSaveNotLoad)? zThere : zHere;
   zFrom = (bSaveNotLoad)? zHere : zThere;
   /* Ensure store DB can be opened and/or created appropriately. */
-  rc = sqlite3_open_v2(zStoreDbName, &dbStore, openFlags, 0);
+  rc = shell_check_nomem(sqlite3_open_v2(zStoreDbName,&dbStore,openFlags,0));
   if( rc!=SQLITE_OK ){
     utf8_printf(STD_ERR, "Error: Cannot %s key/value store DB %s\n",
                 bSaveNotLoad? "open/create" : "read", zStoreDbName);
@@ -11671,6 +11687,7 @@ static int kv_xfr_table(sqlite3 *db, const char *zStoreDbName,
   }
   /* Ensure it has the kv store table, or handle its absence. */
   assert(dbStore!=0);
+  conn_ptr_holder(&dbStore);
   if( sqlite3_table_column_metadata
       (dbStore, "main", SH_KV_STORE_NAME, 0, 0, 0, 0, 0, 0)!=SQLITE_OK ){
     if( !bSaveNotLoad ){
@@ -11685,32 +11702,37 @@ static int kv_xfr_table(sqlite3 *db, const char *zStoreDbName,
         "  value,\n"
         "  uses INT\n"
         ") WITHOUT ROWID;";
-      rc = sqlite3_exec(dbStore, zCT, 0, 0, 0);
+      rc = shell_check_nomem(sqlite3_exec(dbStore, zCT, 0, 0, 0));
       if( rc!=SQLITE_OK ){
         utf8_printf(STD_ERR, "Cannot create table %s. Nothing saved.", zThere);
       }
     }
   }
-  sqlite3_close(dbStore);
+  release_holder();
+  assert(dbStore==0);
   if( rc!=0 ) return rc;
 
   zSql = smprintf("ATTACH %Q AS %s;", zStoreDbName, SH_KV_STORE_SCHEMA);
   shell_check_ooms(zSql);
+  sstr_ptr_holder(&zSql);
   rc = sqlite3_exec(db, zSql, 0, 0, 0);
-  sqlite3_free(zSql);
+  release_holder();
   if( rc!=SQLITE_OK ) return rc;
 
   sbCopy = sqlite3_str_new(db);
+  sqst_ptr_holder(&sbCopy);
   sqlite3_str_appendf
       (sbCopy, "INSERT OR REPLACE INTO %s(key,value,uses)"
        "SELECT key, value, uses FROM %s WHERE key ", zTo, zFrom);
   append_in_clause(sbCopy, azNames, azNames+nNames);
   zSql = sqlite3_str_finish(sbCopy);
+  drop_holder();
   shell_check_ooms(zSql);
+  sstr_ptr_holder(&zSql);
   rc = sqlite3_exec(db, zSql, 0, 0, 0);
-  sqlite3_free(zSql);
+  release_holder();
 
-  sqlite3_exec(db, "DETACH "SH_KV_STORE_SCHEMA";", 0, 0, 0);
+  shell_check_nomem(sqlite3_exec(db, "DETACH "SH_KV_STORE_SCHEMA";", 0, 0, 0));
   return rc;
 }
 
@@ -11722,10 +11744,9 @@ static const char *zDefaultVarStore = "~/sqlite_vars.sdb";
  * and conversion of leading (or only) tilde as home directory.
  * The above-set default is used for zSpec NULL, "" or "~".
  * When return is 0, there is an error; what needs doing cannnot be done.
- * If the return is exactly the input, it must not be sqlite3_free()'ed.
- * If the return differs from the input, it must be sqlite3_free()'ed.
+ * The return must eventually be sqlite3_free()'ed.
  */
-  static const char *kv_store_path(const char *zSpec, ParamTableUse ptu){
+static char *kv_store_path(const char *zSpec, ParamTableUse ptu){
   if( zSpec==0 || zSpec[0]==0 || cli_strcmp(zSpec,"~")==0 ){
     const char *zDef;
     switch( ptu ){
@@ -11737,21 +11758,23 @@ static const char *zDefaultVarStore = "~/sqlite_vars.sdb";
   }else if ( zSpec[0]=='~' ){
     return home_based_path(zSpec);
   }
-  return zSpec;
+  return smprintf("%s", zSpec);
 }
 
 /* Load some or all kv pairs. Arguments are "load FILE ?NAMES?". */
 static int kv_pairs_load(sqlite3 *db, ParamTableUse ptu,
                          const char *azArg[], int nArg){
-  const char *zStore = kv_store_path((nArg>1)? azArg[1] : 0, ptu);
+  char *zStore = kv_store_path((nArg>1)? azArg[1] : 0, ptu);
   if( zStore==0 ){
     utf8_printf(STD_ERR, "Cannot form parameter load path. Nothing loaded.\n");
     return DCR_Error;
   }else{
     const char **pzFirst = (nArg>2)? azArg+2 : 0;
     int nNames = (nArg>2)? nArg-2 : 0;
-    int rc = kv_xfr_table(db, zStore, 0, ptu, pzFirst, nNames);
-    if( nArg>1 && zStore!=azArg[1] ) sqlite3_free((void*)zStore);
+    int rc;
+    sstr_holder(zStore);
+    rc = kv_xfr_table(db, zStore, 0, ptu, pzFirst, nNames);
+    release_holder();
     return rc;
   }
 }
@@ -11759,15 +11782,17 @@ static int kv_pairs_load(sqlite3 *db, ParamTableUse ptu,
 /* Save some or all parameters. Arguments are "save FILE ?NAMES?". */
 static int kv_pairs_save(sqlite3 *db, ParamTableUse ptu,
                          const char *azArg[], int nArg){
-  const char *zStore = kv_store_path((nArg>1)? azArg[1] : 0, ptu);
+  char *zStore = kv_store_path((nArg>1)? azArg[1] : 0, ptu);
   if( zStore==0 ){
     utf8_printf(STD_ERR, "Cannot form parameter save path. Nothing saved.\n");
     return DCR_Error;
   }else{
     const char **pzFirst = (nArg>2)? azArg+2 : 0;
     int nNames = (nArg>2)? nArg-2 : 0;
-    int rc = kv_xfr_table(db, zStore, 1, ptu, pzFirst, nNames);
-    if( nArg>1 && zStore!=azArg[1] ) sqlite3_free((void*)zStore);
+    int rc;
+    sstr_holder(zStore);
+    rc = kv_xfr_table(db, zStore, 1, ptu, pzFirst, nNames);
+    release_holder();
     return rc;
   }
 }
@@ -11796,17 +11821,21 @@ static int edit_one_kvalue(sqlite3 *db, char *name, int eval,
   zSql = smprintf("SELECT value, uses FROM %s "
                   "WHERE key=%Q AND uses=%d", zTab, name, uses);
   shell_check_ooms(zSql);
-  sqlite3_exec(db, zSql, kv_find_callback, &kvRow, 0);
-  sqlite3_free(zSql);
+  sstr_ptr_holder(&kvRow.value);
+  sstr_holder(zSql);
+  shell_check_nomem(sqlite3_exec(db, zSql, kv_find_callback, &kvRow, 0));
+  release_holder();
   assert(kvRow.hits<2);
   if( kvRow.hits==1 && kvRow.uses==uses){
     /* Editing an existing value of same kind. */
-    sqlite3_free(kvRow.value);
+    release_holder(); /* kvRow.value */
     if( eval!=0 ){
       zSql = smprintf("SELECT edit(value, %Q) FROM %s "
                       "WHERE key=%Q AND uses=%d", zEditor, zTab, name, uses);
       shell_check_ooms(zSql);
+      sstr_holder(zSql);
       zVal = db_text(db, zSql, 1);
+      release_holder();
       sqlite3_free(zSql);
       zSql = smprintf("UPDATE %s SET value=(SELECT %s) "
                       "WHERE key=%Q AND uses=%d", zTab, zVal, name, uses);
@@ -11817,10 +11846,12 @@ static int edit_one_kvalue(sqlite3 *db, char *name, int eval,
   }else{
     /* Editing a new value of same kind. */
     assert(kvRow.value==0 || kvRow.uses!=uses);
+    drop_holder(); /* kvRow.value */
     if( eval!=0 ){
       zSql = smprintf("SELECT edit('-- %q%s', %Q)", name, "\n", zEditor);
+      sstr_holder(zSql);
       zVal = db_text(db, zSql, 1);
-      sqlite3_free(zSql);
+      release_holder();
       zSql = smprintf("INSERT INTO %s(key,value,uses)"
          " VALUES (%Q,(SELECT %s LIMIT 1),%d)",
          zTab, name, zVal, uses);
@@ -11831,9 +11862,10 @@ static int edit_one_kvalue(sqlite3 *db, char *name, int eval,
     }
   }
   shell_check_ooms(zSql);
+  sstr_holder(zSql);
+  sstr_holder(zVal);
   rc = sqlite3_exec(db, zSql, 0, 0, 0);
-  sqlite3_free(zSql);
-  sqlite3_free(zVal);
+  release_holders(2);
   return rc!=SQLITE_OK;
 }
 #endif
@@ -11888,12 +11920,14 @@ static int shvar_set(sqlite3 *db, char *name, char **valBeg, char **valLim){
     = smprintf("REPLACE INTO "SHVAR_TABLE_SNAME"(key,value,uses)"
                "VALUES(%Q,%Q,"SPTU_Script");", name, zValue);
   shell_check_ooms(zSql);
-  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmtSet, 0);
+  sstr_holder(zValGlom);
+  sstr_holder(zSql);
+  rc = shell_check_nomem(sqlite3_prepare_v2(db, zSql, -1, &pStmtSet, 0));
   assert(rc==SQLITE_OK);
-  sqlite3_free(zSql);
-  rc = (SQLITE_DONE==sqlite3_step(pStmtSet))? SQLITE_OK : SQLITE_ERROR;
-  sqlite3_finalize(pStmtSet);
-  sqlite3_free(zValGlom);
+  stmt_holder(pStmtSet);
+  rc = shell_check_nomem(sqlite3_step(pStmtSet));
+  rc = (SQLITE_DONE==rc)? SQLITE_OK : SQLITE_ERROR;
+  release_holders(3);
   return rc;
 }
 
@@ -16810,11 +16844,11 @@ int SQLITE_CDECL SHELL_MAIN(int argc, wchar_t **wargv){
       sstr_holder(z);
       n = strlen(z);
       argsUtf8.azCmd[i] = malloc( n+1 );
-      if( argsUtf8.azCmd[i] ) ++argsUtf8.nCmd;
-      else shell_out_of_memory();
-      sqlite3_free(pop_holder());
-      --main_resource_mark;
+      shell_check_oomm(argsUtf8.azCmd[i]);
+      ++argsUtf8.nCmd;
       memcpy(argsUtf8.azCmd[i], z, n+1);
+      release_holder();
+      --main_resource_mark;
     }
     sqlite3_shutdown();
     argv = argsUtf8.azCmd;