]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Rewrite the ".schema" and ".fullschema" commands in the CLI so as to
authordrh <>
Mon, 10 Nov 2025 15:01:57 +0000 (15:01 +0000)
committerdrh <>
Mon, 10 Nov 2025 15:01:57 +0000 (15:01 +0000)
eliminate the need for MODE_Pretty and MODE_Semi.

FossilOrigin-Name: 0eb0410f725eed44973cf8712ab2d24c16fb5cbb249b5780f8fe5d41b2193d79

manifest
manifest.uuid
src/shell.c.in

index b4903ea05e582d0bc2eee3d4cf6794a76cb89952..3ddcb3f09e2a03a4828c0d7750903f6f5c411e28 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sbTextNull\sfield\sto\ssqlite3_qrf_spec.\s\sUse\sQRF\sto\simplement\s"tcl"\nmode\sin\sthe\sCLI.
-D 2025-11-10T12:32:04.765
+C Rewrite\sthe\s".schema"\sand\s".fullschema"\scommands\sin\sthe\sCLI\sso\sas\sto\neliminate\sthe\sneed\sfor\sMODE_Pretty\sand\sMODE_Semi.
+D 2025-11-10T15:01:57.916
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -735,7 +735,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c 5616fbcf3b833c7c705b24371828215ad0925d0c0073216c4f153348d5753f0a
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 F src/select.c ba9cd07ffa3277883c1986085f6ddc4320f4d35d5f212ab58df79a7ecc1a576a
-F src/shell.c.in 188ed543703abf77edc83e4f8b18d3f635999de7eee88b0cf873ba37ac8d8454
+F src/shell.c.in 67b7893f9f9c992d616a3de8b20a0ae7b9add36f533e752497e259555c354977
 F src/sqlite.h.in 7403a952a8f1239de7525b73c4e3a0f9540ec0607ed24fec887f5832642d44b8
 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
 F src/sqlite3ext.h 7f236ca1b175ffe03316d974ef57df79b3938466c28d2f95caef5e08c57f3a52
@@ -2173,8 +2173,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 07a5523cf27fd7c1d8fbc5cde80cb45fadef49317ca59fec9f8e42b2839c3e19
-R 87f6415d434e97597df92d062309a39f
+P 2ba92320db3c16c3c91e29ea935ae92da546261f25846d242bd2dd27e0b7e032
+R 9da3decf0638564c4eb7bbfbd4a9d2e1
 U drh
-Z f07f7fec67c974040146f4f7655e4ed4
+Z ddcc91cce64e019052cede211043e861
 # Remove this line to create a well-formed Fossil manifest.
index 39f7789b360017bb8f87e42f4dd133c049deb41c..01ed5b13482dadc6c7aeee88edfd9c525fe5da90 100644 (file)
@@ -1 +1 @@
-2ba92320db3c16c3c91e29ea935ae92da546261f25846d242bd2dd27e0b7e032
+0eb0410f725eed44973cf8712ab2d24c16fb5cbb249b5780f8fe5d41b2193d79
index 148650c74c1cf8240d94b34e85b0eb100f08f166..134464aa7b578ec43452181fc801c8d37db98310 100644 (file)
@@ -1343,37 +1343,33 @@ static const char *shell_EscModeNames[] = { "ascii", "symbol", "off" };
 /*
 ** These are the allowed modes.
 */
-#define MODE_Line     0  /* One column per line.  Blank line between records */
-#define MODE_Column   1  /* One record per line in neat columns */
-#define MODE_List     2  /* One record per line with a separator */
-#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
-#define MODE_Html     4  /* Generate an XHTML table */
-#define MODE_Insert   5  /* Generate SQL "insert" statements */
-#define MODE_Quote    6  /* Quote values as for SQL */
-#define MODE_Tcl      7  /* Generate ANSI-C or TCL quoted elements */
-#define MODE_Csv      8  /* Quote strings, numbers are plain */
-#define MODE_Ascii    9  /* Use ASCII unit and record separators (0x1F/0x1E) */
-#define MODE_Pretty  10  /* Pretty-print schemas */
-#define MODE_Json    11  /* Output JSON */
-#define MODE_Markdown 12 /* Markdown formatting */
-#define MODE_Table   13  /* MySQL-style table formatting */
-#define MODE_Box     14  /* Unicode box-drawing characters */
-#define MODE_Count   15  /* Output only a count of the rows of output */
-#define MODE_Off     16  /* No query output shown */
-#define MODE_Www     17  /* Full web-page output */
+#define MODE_Line      0  /* One column per line.  Blank line between records */
+#define MODE_Column    1  /* One record per line in neat columns */
+#define MODE_List      2  /* One record per line with a separator */
+#define MODE_Html      3  /* Generate an XHTML table */
+#define MODE_Insert    4  /* Generate SQL "insert" statements */
+#define MODE_Quote     5  /* Quote values as for SQL */
+#define MODE_Tcl       6  /* Generate ANSI-C or TCL quoted elements */
+#define MODE_Csv       7  /* Quote strings, numbers are plain */
+#define MODE_Ascii     8  /* Use ASCII unit and record separators (0x1F/0x1E) */
+#define MODE_Json      9  /* Output JSON */
+#define MODE_Markdown 10 /* Markdown formatting */
+#define MODE_Table    11  /* MySQL-style table formatting */
+#define MODE_Box      12  /* Unicode box-drawing characters */
+#define MODE_Count    13  /* Output only a count of the rows of output */
+#define MODE_Off      14  /* No query output shown */
+#define MODE_Www      15  /* Full web-page output */
 
 static const char *modeDescr[] = {
   "line",
   "column",
   "list",
-  "semi",
   "html",
   "insert",
   "quote",
   "tcl",
   "csv",
   "ascii",
-  "prettyprint",
   "json",
   "markdown",
   "table",
@@ -1388,14 +1384,12 @@ static const unsigned char aQrfStyle[] = {
   /* line */         QRF_STYLE_Line,
   /* column */       QRF_STYLE_Column,
   /* list */         QRF_STYLE_List,
-  /* semi */         101,
   /* html */         QRF_STYLE_Html,
   /* insert */       QRF_STYLE_Insert,
   /* quote */        QRF_STYLE_Quote,
   /* tcl */          QRF_STYLE_List,
   /* csv */          QRF_STYLE_Csv,
   /* ascii */        QRF_STYLE_List,
-  /* prettyprint */  105,
   /* json */         QRF_STYLE_Json,
   /* markdown */     QRF_STYLE_Markdown,
   /* table */        QRF_STYLE_Table,
@@ -1898,7 +1892,7 @@ static int shellAuth(
 #endif
 
 /*
-** Print a schema statement.  Part of MODE_Semi and MODE_Pretty output.
+** Print a schema statement.  This is helper routine to dump_callbac().
 **
 ** This routine converts some CREATE TABLE statements for shadow tables
 ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
@@ -1935,12 +1929,6 @@ static void printSchemaLine(FILE *out, const char *z, const char *zTail){
   }
   sqlite3_free(zToFree);
 }
-static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
-  char c = z[n];
-  z[n] = 0;
-  printSchemaLine(out, z, zTail);
-  z[n] = c;
-}
 
 /*
 ** Return true if string z[] has nothing but whitespace and comments to the
@@ -1957,6 +1945,131 @@ static int wsToEol(const char *z){
   return 1;
 }
 
+/*
+** SQL Function:  shell_format_schema(SQL,FLAGS)
+**
+** This function is internally by the CLI to assist with the
+** ".schema", ".fullschema", and ".dump" commands.  The first
+** argument is the value from sqlite_schema.sql.  The value returned
+** is a modification of the input that can actually be run as SQL
+** to recreate the schema object.
+**
+** When FLAGS is zero, the only changes is to append ";".  If the
+** 0x01 bit of FLAGS is set, then transformations are made to implement
+** ".schema --indent".
+*/
+static void shellFormatSchema(
+  sqlite3_context *pCtx,
+  int nVal,
+  sqlite3_value **apVal
+){
+  int flags;          /* Value of 2nd parameter */
+  const char *zSql;   /* Value of 1st parameter */
+  int nSql;           /* Bytes of text in zSql[] */
+  sqlite3_str *pOut;  /* Output buffer */
+  char *z;            /* Writable copy of zSql */
+  int i, j;           /* Loop counters */
+  int nParen = 0;
+  char cEnd = 0;
+  char c;
+  int nLine = 0;
+  int isIndex;
+  int isWhere = 0;
+
+  assert( nVal==2 );
+  pOut = sqlite3_str_new(sqlite3_context_db_handle(pCtx));
+  nSql = sqlite3_value_bytes(apVal[0]);
+  zSql = (const char*)sqlite3_value_text(apVal[0]);
+  if( zSql==0 || zSql[0]==0 ) goto shellFormatSchema_finish;
+  flags = sqlite3_value_int(apVal[1]);
+  if( (flags & 0x01)==0 ){
+    sqlite3_str_append(pOut, zSql, nSql);
+    sqlite3_str_append(pOut, ";", 1);
+    goto shellFormatSchema_finish;
+  }
+  if( sqlite3_strlike("CREATE VIEW%", zSql, 0)==0
+   || sqlite3_strlike("CREATE TRIG%", zSql, 0)==0
+  ){
+    sqlite3_str_append(pOut, zSql, nSql);
+    sqlite3_str_append(pOut, ";", 1);
+    goto shellFormatSchema_finish;
+  }
+  isIndex = sqlite3_strlike("CREATE INDEX%", zSql, 0)==0
+         || sqlite3_strlike("CREATE UNIQUE INDEX%", zSql, 0)==0;
+  z = sqlite3_mprintf("%s", zSql);
+  if( z==0 ){
+    sqlite3_free(sqlite3_str_finish(pOut));
+    sqlite3_result_error_nomem(pCtx);
+    return;
+  }
+  j = 0;
+  for(i=0; IsSpace(z[i]); i++){}
+  for(; (c = z[i])!=0; i++){
+    if( IsSpace(c) ){
+      if( z[j-1]=='\r' ) z[j-1] = '\n';
+      if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
+    }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
+      j--;
+    }
+    z[j++] = c;
+  }
+  while( j>0 && IsSpace(z[j-1]) ){ j--; }
+  z[j] = 0;
+  if( strlen30(z)>=79 ){
+    for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */
+      if( c==cEnd ){
+        cEnd = 0;
+      }else if( c=='"' || c=='\'' || c=='`' ){
+        cEnd = c;
+      }else if( c=='[' ){
+        cEnd = ']';
+      }else if( c=='-' && z[i+1]=='-' ){
+        cEnd = '\n';
+      }else if( c=='(' ){
+        nParen++;
+      }else if( c==')' ){
+        nParen--;
+        if( nLine>0 && nParen==0 && j>0 && !isWhere ){
+          sqlite3_str_append(pOut, z, j);
+          sqlite3_str_append(pOut, "\n", 1);
+          j = 0;
+        }
+      }else if( (c=='w' || c=='W')
+             && nParen==0 && isIndex
+             && sqlite3_strnicmp("WHERE",&z[i],5)==0
+             && !IsAlnum(z[i+5]) && z[i+5]!='_' ){
+        isWhere = 1;
+      }else if( isWhere && (c=='A' || c=='a')
+             && nParen==0
+             && sqlite3_strnicmp("AND",&z[i],3)==0
+             && !IsAlnum(z[i+3]) && z[i+3]!='_' ){
+        sqlite3_str_append(pOut, z, j);
+        sqlite3_str_append(pOut, "\n    ", 5);
+        j = 0;
+      }
+      z[j++] = c;
+      if( nParen==1 && cEnd==0
+       && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
+       && !isWhere
+      ){
+        if( c=='\n' ) j--;
+        sqlite3_str_append(pOut, z, j);
+        sqlite3_str_append(pOut, "\n  ", 3);
+        j = 0;
+        nLine++;
+        while( IsSpace(z[i+1]) ){ i++; }
+      }
+    }
+    z[j] = 0;
+  }
+  sqlite3_str_appendall(pOut, z);
+  sqlite3_str_append(pOut, ";", 1);
+  sqlite3_free(z);
+
+shellFormatSchema_finish:
+  sqlite3_result_text(pCtx, sqlite3_str_finish(pOut), -1, sqlite3_free);
+}
+
 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
 /*
 ** Progress handler callback.
@@ -1996,92 +2109,6 @@ static int shell_callback(
     case MODE_Count:  assert(0);   break;
     case MODE_Off:    assert(0);   break;
     case MODE_Line:   assert(0);   break;
-    case MODE_Semi: {   /* .schema and .fullschema output */
-      printSchemaLine(p->out, azArg[0], ";\n");
-      break;
-    }
-    case MODE_Pretty: {  /* .schema and .fullschema with --indent */
-      char *z;
-      int j;
-      int nParen = 0;
-      char cEnd = 0;
-      char c;
-      int nLine = 0;
-      int isIndex;
-      int isWhere = 0;
-      assert( nArg==1 );
-      if( azArg[0]==0 ) break;
-      if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
-       || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
-      ){
-        sqlite3_fprintf(p->out, "%s;\n", azArg[0]);
-        break;
-      }
-      isIndex = sqlite3_strlike("CREATE INDEX%", azArg[0], 0)==0
-             || sqlite3_strlike("CREATE UNIQUE INDEX%", azArg[0], 0)==0;
-      z = sqlite3_mprintf("%s", azArg[0]);
-      shell_check_oom(z);
-      j = 0;
-      for(i=0; IsSpace(z[i]); i++){}
-      for(; (c = z[i])!=0; i++){
-        if( IsSpace(c) ){
-          if( z[j-1]=='\r' ) z[j-1] = '\n';
-          if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
-        }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
-          j--;
-        }
-        z[j++] = c;
-      }
-      while( j>0 && IsSpace(z[j-1]) ){ j--; }
-      z[j] = 0;
-      if( strlen30(z)>=79 ){
-        for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */
-          if( c==cEnd ){
-            cEnd = 0;
-          }else if( c=='"' || c=='\'' || c=='`' ){
-            cEnd = c;
-          }else if( c=='[' ){
-            cEnd = ']';
-          }else if( c=='-' && z[i+1]=='-' ){
-            cEnd = '\n';
-          }else if( c=='(' ){
-            nParen++;
-          }else if( c==')' ){
-            nParen--;
-            if( nLine>0 && nParen==0 && j>0 && !isWhere ){
-              printSchemaLineN(p->out, z, j, "\n");
-              j = 0;
-            }
-          }else if( (c=='w' || c=='W')
-                 && nParen==0 && isIndex
-                 && sqlite3_strnicmp("WHERE",&z[i],5)==0
-                 && !IsAlnum(z[i+5]) && z[i+5]!='_' ){
-            isWhere = 1;
-          }else if( isWhere && (c=='A' || c=='a')
-                 && nParen==0
-                 && sqlite3_strnicmp("AND",&z[i],3)==0
-                 && !IsAlnum(z[i+3]) && z[i+3]!='_' ){
-            printSchemaLineN(p->out, z, j, "\n    ");
-            j = 0;
-          }
-          z[j++] = c;
-          if( nParen==1 && cEnd==0
-           && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
-           && !isWhere
-          ){
-            if( c=='\n' ) j--;
-            printSchemaLineN(p->out, z, j, "\n  ");
-            j = 0;
-            nLine++;
-            while( IsSpace(z[i+1]) ){ i++; }
-          }
-        }
-        z[j] = 0;
-      }
-      printSchemaLine(p->out, z, ";\n");
-      sqlite3_free(z);
-      break;
-    }
     case MODE_List:  assert(0);   break;
     case MODE_Html:  assert(0);   break;
     case MODE_Www: {
@@ -2122,15 +2149,6 @@ static int shell_callback(
   return 0;
 }
 
-/*
-** This is the callback routine that the SQLite library
-** invokes for each row of a query result.
-*/
-static int callback(void *pArg, int nArg, char **azArg, char **azCol){
-  /* since we don't have type info, call the shell_callback with a NULL value */
-  return shell_callback(pArg, nArg, azArg, azCol, NULL);
-}
-
 /*
 ** This is the callback routine from sqlite3_exec() that appends all
 ** output onto the end of a ShellText object.
@@ -4274,6 +4292,8 @@ static void open_db(ShellState *p, int openFlags){
                             shellModuleSchema, 0, 0);
     sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
                             shellPutsFunc, 0, 0);
+    sqlite3_create_function(p->db, "shell_format_schema", 2, SQLITE_UTF8, p,
+                            shellFormatSchema, 0, 0);
     sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0,
                             shellUSleepFunc, 0, 0);
 #ifndef SQLITE_NOHAVE_SYSTEM
@@ -7768,11 +7788,15 @@ static int do_meta_command(char *zLine, ShellState *p){
   if( c=='f' && cli_strncmp(azArg[0], "fullschema", n)==0 ){
     ShellState data;
     int doStats = 0;
+    int hasStat[5];
+    int flgs = 0;
+    char *zSql;
     memcpy(&data, p, sizeof(data));
     data.showHeader = 0;
-    data.cMode = data.mode = MODE_Semi;
+    data.cMode = data.mode = MODE_List;
+    data.rowSeparator[0] = '\n';
+    data.rowSeparator[1] = 0;
     if( nArg==2 && optionMatch(azArg[1], "indent") ){
-      data.cMode = data.mode = MODE_Pretty;
       nArg = 1;
     }
     if( nArg!=1 ){
@@ -7781,36 +7805,46 @@ static int do_meta_command(char *zLine, ShellState *p){
       goto meta_command_exit;
     }
     open_db(p, 0);
-    rc = sqlite3_exec(p->db,
-       "SELECT sql FROM"
+    zSql = sqlite3_mprintf(
+       "SELECT shell_format_schema(sql,%d) FROM"
        "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
        "     FROM sqlite_schema UNION ALL"
        "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) "
        "WHERE type!='meta' AND sql NOTNULL"
-       "  AND name NOT LIKE 'sqlite__%' ESCAPE '_' "
-       "ORDER BY x",
-       callback, &data, 0
-    );
+       "  AND name NOT LIKE 'sqlite__%%' ESCAPE '_' "
+       "ORDER BY x", flgs);
+    rc = shell_exec(&data,zSql,0);
+    sqlite3_free(zSql);
     if( rc==SQLITE_OK ){
+      memset(hasStat, 0, sizeof(hasStat));
       sqlite3_stmt *pStmt;
       rc = sqlite3_prepare_v2(p->db,
-               "SELECT rowid FROM sqlite_schema"
+               "SELECT substr(name,12,1) FROM sqlite_schema"
                " WHERE name GLOB 'sqlite_stat[134]'",
                -1, &pStmt, 0);
       if( rc==SQLITE_OK ){
-        doStats = sqlite3_step(pStmt)==SQLITE_ROW;
-        sqlite3_finalize(pStmt);
+        while( sqlite3_step(pStmt)==SQLITE_ROW ){
+          int k = sqlite3_column_int(pStmt,0);
+          assert( k==1 || k==3 || k==4 );
+          hasStat[k] = 1;
+          doStats = 1;
+        }
       }
+      sqlite3_finalize(pStmt);
     }
     if( doStats==0 ){
       sqlite3_fputs("/* No STAT tables available */\n", p->out);
     }else{
       sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
       data.cMode = data.mode = MODE_Insert;
-      data.zDestTable = "sqlite_stat1";
-      shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
-      data.zDestTable = "sqlite_stat4";
-      shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
+      if( hasStat[1] ){
+        data.zDestTable = "sqlite_stat1";
+        shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
+      }
+      if( hasStat[4] ){
+        data.zDestTable = "sqlite_stat4";
+        shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
+      }
       sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
     }
   }else
@@ -9154,7 +9188,6 @@ static int do_meta_command(char *zLine, ShellState *p){
   }else
 
   if( c=='s' && cli_strncmp(azArg[0], "schema", n)==0 ){
-    ShellText sSelect;
     ShellState data;
     char *zErrMsg = 0;
     const char *zDiv = "(";
@@ -9162,16 +9195,19 @@ static int do_meta_command(char *zLine, ShellState *p){
     int iSchema = 0;
     int bDebug = 0;
     int bNoSystemTabs = 0;
+    int bIndent = 0;
     int ii;
-
+    sqlite3_str *pSql;
+    sqlite3_stmt *pStmt = 0;
     open_db(p, 0);
     memcpy(&data, p, sizeof(data));
     data.showHeader = 0;
-    data.cMode = data.mode = MODE_Semi;
-    initText(&sSelect);
+    data.cMode = data.mode = MODE_List;
+    memcpy(data.rowSeparator,"\n",2);
     for(ii=1; ii<nArg; ii++){
       if( optionMatch(azArg[ii],"indent") ){
-        data.cMode = data.mode = MODE_Pretty;
+        bIndent = 1;
       }else if( optionMatch(azArg[ii],"debug") ){
         bDebug = 1;
       }else if( optionMatch(azArg[ii],"nosys") ){
@@ -9194,96 +9230,84 @@ static int do_meta_command(char *zLine, ShellState *p){
                   || sqlite3_strlike(zName,"sqlite_temp_master", '\\')==0
                   || sqlite3_strlike(zName,"sqlite_temp_schema", '\\')==0;
       if( isSchema ){
-        char *new_argv[2], *new_colv[2];
-        new_argv[0] = sqlite3_mprintf(
+        sqlite3_fprintf(p->out,
                       "CREATE TABLE %s (\n"
                       "  type text,\n"
                       "  name text,\n"
                       "  tbl_name text,\n"
                       "  rootpage integer,\n"
                       "  sql text\n"
-                      ")", zName);
-        shell_check_oom(new_argv[0]);
-        new_argv[1] = 0;
-        new_colv[0] = "sql";
-        new_colv[1] = 0;
-        callback(&data, 1, new_argv, new_colv);
-        sqlite3_free(new_argv[0]);
+                      ");\n", zName);
       }
     }
-    if( zDiv ){
-      sqlite3_stmt *pStmt = 0;
-      rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
-                              -1, &pStmt, 0);
-      if( rc ){
-        shellDatabaseError(p->db);
-        sqlite3_finalize(pStmt);
-        rc = 1;
-        goto meta_command_exit;
-      }
-      appendText(&sSelect, "SELECT sql FROM", 0);
-      iSchema = 0;
-      while( sqlite3_step(pStmt)==SQLITE_ROW ){
-        const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
-        char zScNum[30];
-        sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
-        appendText(&sSelect, zDiv, 0);
-        zDiv = " UNION ALL ";
-        appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
-        if( sqlite3_stricmp(zDb, "main")!=0 ){
-          appendText(&sSelect, zDb, '\'');
-        }else{
-          appendText(&sSelect, "NULL", 0);
-        }
-        appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0);
-        appendText(&sSelect, zScNum, 0);
-        appendText(&sSelect, " AS snum, ", 0);
-        appendText(&sSelect, zDb, '\'');
-        appendText(&sSelect, " AS sname FROM ", 0);
-        appendText(&sSelect, zDb, quoteChar(zDb));
-        appendText(&sSelect, ".sqlite_schema", 0);
-      }
+    rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
+                            -1, &pStmt, 0);
+    if( rc ){
+      shellDatabaseError(p->db);
       sqlite3_finalize(pStmt);
-#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
-      if( zName ){
-        appendText(&sSelect,
-           " UNION ALL SELECT shell_module_schema(name),"
-           " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list",
-        0);
-      }
-#endif
-      appendText(&sSelect, ") WHERE ", 0);
-      if( zName ){
-        char *zQarg = sqlite3_mprintf("%Q", zName);
-        int bGlob;
-        shell_check_oom(zQarg);
-        bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 ||
-                strchr(zName, '[') != 0;
-        if( strchr(zName, '.') ){
-          appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
-        }else{
-          appendText(&sSelect, "lower(tbl_name)", 0);
-        }
-        appendText(&sSelect, bGlob ? " GLOB " : " LIKE ", 0);
-        appendText(&sSelect, zQarg, 0);
-        if( !bGlob ){
-          appendText(&sSelect, " ESCAPE '\\' ", 0);
-        }
-        appendText(&sSelect, " AND ", 0);
-        sqlite3_free(zQarg);
+      
+      rc = 1;
+      goto meta_command_exit;
+    }
+    pSql = sqlite3_str_new(p->db);
+    sqlite3_str_appendf(pSql, "SELECT sql FROM", 0);
+    iSchema = 0;
+    while( sqlite3_step(pStmt)==SQLITE_ROW ){
+      const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
+      char zScNum[30];
+      sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
+      sqlite3_str_appendall(pSql, zDiv);
+      zDiv = " UNION ALL ";
+      if( sqlite3_stricmp(zDb, "main")==0 ){
+        sqlite3_str_appendf(pSql,
+            "SELECT shell_format_schema(shell_add_schema(sql,NULL,name),%d)",
+            bIndent);
+      }else{
+        sqlite3_str_appendf(pSql,
+            "SELECT shell_format_schema(shell_add_schema(sql,%Q,name),%d))",
+            zDb, bIndent);
       }
-      if( bNoSystemTabs ){
-        appendText(&sSelect, "name NOT LIKE 'sqlite__%%' ESCAPE '_' AND ", 0);
+      sqlite3_str_appendf(pSql,
+         " AS sql, type, tbl_name, name, rowid, %d AS snum, %Q as sname",
+         ++iSchema, zDb);
+      sqlite3_str_appendf(pSql," FROM \"%w\".sqlite_schema", zDb);
+    }
+    sqlite3_finalize(pStmt);
+#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
+    if( zName ){
+      sqlite3_str_appendf(pSql,
+         " UNION ALL SELECT shell_module_schema(name),"
+         " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list",
+      0);
+    }
+#endif
+    sqlite3_str_appendf(pSql, ") WHERE ", 0);
+    if( zName ){
+      int bGlob;
+      bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 ||
+              strchr(zName, '[') != 0;
+      if( strchr(zName, '.') ){
+        sqlite3_str_appendf(pSql, "lower(format('%s.%s',sname,tbl_name))", 0);
+      }else{
+        sqlite3_str_appendf(pSql, "lower(tbl_name)", 0);
       }
-      appendText(&sSelect, "sql IS NOT NULL"
-                           " ORDER BY snum, rowid", 0);
-      if( bDebug ){
-        sqlite3_fprintf(p->out, "SQL: %s;\n", sSelect.zTxt);
+      if( bGlob ){
+        sqlite3_str_appendf(pSql, " GLOB %Q AND ", zName);
       }else{
-        rc = sqlite3_exec(p->db, sSelect.zTxt, callback, &data, &zErrMsg);
+        sqlite3_str_appendf(pSql, " LIKE %Q ESCAPE '\\' AND ", zName);
       }
-      freeText(&sSelect);
     }
+    if( bNoSystemTabs ){
+      sqlite3_str_appendf(pSql, " name NOT LIKE 'sqlite__%%' ESCALE '_' AND ");
+    }
+    sqlite3_str_appendf(pSql, "sql IS NOT NULL ORDER BY snum, rowid");
+    if( bDebug ){
+      sqlite3_fprintf(p->out, "SQL: %s;\n", sqlite3_str_value(pSql));
+    }else{
+      rc = shell_exec(&data, sqlite3_str_value(pSql), &zErrMsg);
+    }
+    sqlite3_free(sqlite3_str_finish(pSql));
+
     if( zErrMsg ){
       shellEmitError(zErrMsg);
       sqlite3_free(zErrMsg);