]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Simplify the interface to use just a single API.
authordrh <>
Wed, 22 Oct 2025 12:09:50 +0000 (12:09 +0000)
committerdrh <>
Wed, 22 Oct 2025 12:09:50 +0000 (12:09 +0000)
FossilOrigin-Name: 82dc13ec4887f90995bd984ede9c2670fb7512962ccceb1848a7e9aab7891c00

ext/misc/resfmt-tester.c
ext/misc/resfmt.c
ext/misc/resfmt.h
manifest
manifest.uuid

index cd7ccd75250bfaac0aa94c2e7f14ca44aace0735..e0d159117f300a0a47c9b76b945cb4595ea29475 100644 (file)
@@ -134,8 +134,6 @@ int main(int argc, char **argv){
     }else
     if( strcmp(zLine, "--go")==0 ){
       const char *zSql, *zTail;
-      sqlite3_resfmt *pFmt;
-      int iErr = 0;
       char *zErr = 0;
       int n;
       if( db==0 ){
@@ -166,17 +164,16 @@ int main(int argc, char **argv){
             spec.pzOutput = &zOut;
             spec.xWrite = 0;
           }
-          pFmt = sqlite3_resfmt_begin(pStmt, &spec);
-          while( sqlite3_step(pStmt)==SQLITE_ROW ){
-            sqlite3_resfmt_row(pFmt);
-          }
-          rc = sqlite3_resfmt_finish(pFmt, &iErr, &zErr);
-          if( !bUseWriter && zOut ){
-            fputs(zOut, stdout);
-            sqlite3_free(zOut);
+          rc = sqlite3_format_query_result(pStmt, &spec, &zErr);
+          if( rc!=SQLITE_OK ){
+            fprintf(stderr, "%s:%d: Error %d: %s\n", zSrc, lineNum,
+                            rc, zErr);
+          }else{
+            if( !bUseWriter && zOut ){
+              fputs(zOut, stdout);
+              sqlite3_free(zOut);
+            }
           }
-          printf("/* rc=%d.  error-code=%d.  error-message=%s */\n",
-                 rc, iErr, zErr ? zErr : "NULL");
           sqlite3_free(zErr);
         }
         sqlite3_finalize(pStmt);
@@ -190,7 +187,6 @@ int main(int argc, char **argv){
          { "box",      RESFMT_Box,      },
          { "column",   RESFMT_Column,   },
          { "count",    RESFMT_Count,    },
-         { "csv",      RESFMT_Csv,      },
          { "eqp",      RESFMT_EQP,      },
          { "explain",  RESFMT_Explain,  },
          { "html",     RESFMT_Html,     },
@@ -200,9 +196,7 @@ int main(int argc, char **argv){
          { "list",     RESFMT_List,     },
          { "markdown", RESFMT_Markdown, },
          { "off",      RESFMT_Off,      },
-         { "pretty",   RESFMT_Pretty,   },
          { "table",    RESFMT_Table,    },
-         { "tcl",      RESFMT_Tcl,      },
          { "scanexp",  RESFMT_ScanExp,  },
       };
       int i;
index 1bbbce2dcd953d31c6a3af4e3437ec94e7a6a7c7..0ac046271dda265d31f8b79a1414be452fc561fd 100644 (file)
 ** Private state information.  Subject to change from one release to the
 ** next.
 */
+typedef struct sqlite3_resfmt sqlite3_resfmt;
 struct sqlite3_resfmt {
   sqlite3_stmt *pStmt;        /* The statement whose output is to be rendered */
   sqlite3 *db;                /* The corresponding database connection */
-  sqlite3_str *pErr;          /* Error message, or NULL */
+  char **pzErr;               /* Write error message here, if not NULL */
   sqlite3_str *pOut;          /* Accumulated output */
   int iErr;                   /* Error code */
   int nCol;                   /* Number of output columns */
@@ -30,14 +31,33 @@ struct sqlite3_resfmt {
   sqlite3_resfmt_spec spec;   /* Copy of the original spec */
 };
 
+/*
+** Set an error code and error message.
+*/
+static void resfmtError(
+  sqlite3_resfmt *p,       /* Query result state */
+  int iCode,               /* Error code */
+  const char *zFormat,     /* Message format (or NULL) */
+  ...
+){
+  p->iErr = iCode;
+  if( p->pzErr!=0 ){
+    sqlite3_free(*p->pzErr);
+    *p->pzErr = 0;
+    if( zFormat ){
+      va_list ap;
+      va_start(ap, zFormat);
+      *p->pzErr = sqlite3_mprintf(zFormat, ap);
+      va_end(ap);
+    }
+  }
+}
 
 /*
-** Free memory associated with pResfmt
+** Out-of-memory error.
 */
-static void resfmtFree(sqlite3_resfmt *p){
-  if( p->pErr ) sqlite3_free(sqlite3_str_finish(p->pErr));
-  if( p->pOut ) sqlite3_free(sqlite3_str_finish(p->pOut));
-  sqlite3_free(p);
+static void resfmtOom(sqlite3_resfmt *p){
+  resfmtError(p, SQLITE_NOMEM, "out of memory");
 }
 
 /*
@@ -361,27 +381,29 @@ static void resfmtRenderValue(sqlite3_resfmt *p, int iCol){
 }
 
 /*
-** Create a new rendering object
+** Initialize the internal sqlite3_resfmt object.
 */
-sqlite3_resfmt *sqlite3_resfmt_begin(
-  sqlite3_stmt *pStmt,
-  sqlite3_resfmt_spec *pSpec
+static void resfmtInitialize(
+  sqlite3_resfmt *p,                 /* State object to be initialized */
+  sqlite3_stmt *pStmt,               /* Query whose output to be formatted */
+  const sqlite3_resfmt_spec *pSpec,  /* Format specification */
+  char **pzErr                       /* Write errors here */
 ){
-  sqlite3_resfmt *p;          /* The new sqlite3_resfmt being created */
   size_t sz;                  /* Size of pSpec[], based on pSpec->iVersion */
-
-  if( pStmt==0 ) return 0;
-  if( pSpec==0 ) return 0;
-  if( pSpec->iVersion!=1 ) return 0;
-  p = sqlite3_malloc64( sizeof(*p) );
-  if( p==0 ) return 0;
+  memset(p, 0, sizeof(*p));
+  p->pzErr = pzErr;
+  if( pSpec->iVersion!=1 ){
+    resfmtError(p, SQLITE_ERROR,
+       "unusable sqlite3_resfmt_spec.iVersion (%d)",
+       pSpec->iVersion);
+    return;
+  }
   p->pStmt = pStmt;
   p->db = sqlite3_db_handle(pStmt);
-  p->pErr = 0;
   p->pOut = sqlite3_str_new(p->db);
   if( p->pOut==0 ){
-    resfmtFree(p);
-    return 0;
+    resfmtOom(p);
+    return;
   }
   p->iErr = 0;
   p->nCol = sqlite3_column_count(p->pStmt);
@@ -405,16 +427,13 @@ sqlite3_resfmt *sqlite3_resfmt_begin(
       break;
     }
   }
-  return p;
 }
 
 /*
 ** Render a single row of output.
 */
-int sqlite3_resfmt_row(sqlite3_resfmt *p){
-  int rc = SQLITE_OK;
+static void resfmtDoOneRow(sqlite3_resfmt *p){
   int i;
-  if( p==0 ) return SQLITE_DONE;
   switch( p->spec.eFormat ){
     case RESFMT_Off:
     case RESFMT_Count: {
@@ -441,16 +460,12 @@ int sqlite3_resfmt_row(sqlite3_resfmt *p){
     }
   }
   p->nRow++;
-  return rc;
 }
 
 /*
 ** Finish rendering the results
 */
-int sqlite3_resfmt_finish(sqlite3_resfmt *p, int *piErr, char **pzErrMsg){
-  if( p==0 ){
-    return SQLITE_OK;
-  }
+static void resfmtFinalize(sqlite3_resfmt *p){
   switch( p->spec.eFormat ){
     case RESFMT_Count: {
       sqlite3_str_appendf(p->pOut, "%lld\n", p->nRow);
@@ -460,15 +475,36 @@ int sqlite3_resfmt_finish(sqlite3_resfmt *p, int *piErr, char **pzErrMsg){
   }
   if( p->spec.pzOutput ){
     *p->spec.pzOutput = sqlite3_str_finish(p->pOut);
-    p->pOut = 0;
+  }else if( p->pOut ){
+    sqlite3_free(sqlite3_str_finish(p->pOut));
   }
-  if( piErr ){
-    *piErr = p->iErr;
+}
+
+/*
+** Run the prepared statement pStmt and format the results according
+** to the specification provided in pSpec.  Return an error code.
+** If pzErr is not NULL and if an error occurs, write an error message
+** into *pzErr.
+*/
+int sqlite3_format_query_result(
+  sqlite3_stmt *pStmt,                    /* Statement to evaluate */
+  const sqlite3_resfmt_spec *pSpec,       /* Format specification */
+  char **pzErr                            /* Write error message here */
+){
+  sqlite3_resfmt fmt;         /* The new sqlite3_resfmt being created */
+
+  if( pStmt==0 ) return SQLITE_OK;       /* No-op */
+  if( pSpec==0 ) return SQLITE_MISUSE;
+  resfmtInitialize(&fmt, pStmt, pSpec, pzErr);
+  while( fmt.iErr==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
+    resfmtDoOneRow(&fmt);
   }
-  if( pzErrMsg ){
-    *pzErrMsg = sqlite3_str_finish(p->pErr);
-    p->pErr = 0;
+  if( fmt.iErr==SQLITE_OK ){
+    int rc = sqlite3_reset(fmt.pStmt);
+    if( rc!=SQLITE_OK ){
+      resfmtError(&fmt, rc, "%s", sqlite3_errmsg(fmt.db));
+    }
   }
-  resfmtFree(p); 
-  return SQLITE_OK;
+  resfmtFinalize(&fmt);
+  return fmt.iErr;
 }
index c13c077e845c4ad83cb281c82a1a3e414b7b041f..ab8f0accf2cbf22ca0826823d1429a4ea832707d 100644 (file)
 */
 typedef struct sqlite3_resfmt_spec sqlite3_resfmt_spec;
 struct sqlite3_resfmt_spec {
-  short int iVersion;         /* Version number of this structure */
+  unsigned char iVersion;     /* Version number of this structure */
   unsigned char eFormat;      /* Output format */
   unsigned char bShowCNames;  /* True to show column names */
   unsigned char eEscape;      /* How to deal with control characters */
   unsigned char eQuote;       /* Quoting style for text */
   unsigned char eBlob;        /* Quoting style for BLOBs */
   unsigned char bWordWrap;    /* Try to wrap on word boundaries */
-  short int mxWidth;          /* Maximum column width in columnar modes */
+  short int mxWidth;          /* Maximum width of any column */
   int nWidth;                 /* Number of column width parameters */
   short int *aWidth;          /* Column widths */
   const char *zColumnSep;     /* Alternative column separator */
@@ -43,17 +43,14 @@ struct sqlite3_resfmt_spec {
   /* Additional fields may be added in the future */
 };
 
-/*
-** Opaque state structure used by this library.
-*/
-typedef struct sqlite3_resfmt sqlite3_resfmt;
-
 /*
 ** Interfaces
 */
-sqlite3_resfmt *sqlite3_resfmt_begin(sqlite3_stmt*, sqlite3_resfmt_spec*);
-int sqlite3_resfmt_row(sqlite3_resfmt*);
-int sqlite3_resfmt_finish(sqlite3_resfmt*,int*,char**);
+int sqlite3_format_query_result(
+  sqlite3_stmt *pStmt,                /* SQL statement to run */
+  const sqlite3_resfmt_spec *pSpec,   /* Result format specification */
+  char **pzErr                        /* OUT: Write error message here */
+);
 
 /*
 ** Output styles:
@@ -61,16 +58,17 @@ int sqlite3_resfmt_finish(sqlite3_resfmt*,int*,char**);
 #define RESFMT_List      0 /* One record per line with a separator */
 #define RESFMT_Line      1 /* One column per line. */
 #define RESFMT_Html      2 /* Generate an XHTML table */
-#define RESFMT_Insert    3 /* Generate SQL "insert" statements */
-#define RESFMT_Explain   4 /* EXPLAIN output */
-#define RESFMT_ScanExp   5 /* EXPLAIN output with vm stats */
-#define RESFMT_EQP       6 /* Converts EXPLAIN QUERY PLAN output into a graph */
-#define RESFMT_Markdown  7 /* Markdown formatting */
-#define RESFMT_Column    8 /* One record per line in neat columns */
-#define RESFMT_Table     9 /* MySQL-style table formatting */
-#define RESFMT_Box      10 /* Unicode box-drawing characters */
-#define RESFMT_Count    11 /* Output only a count of the rows of output */
-#define RESFMT_Off      12 /* No query output shown */
+#define RESFMT_Json      3 /* Output is a list of JSON objects */
+#define RESFMT_Insert    4 /* Generate SQL "insert" statements */
+#define RESFMT_Explain   5 /* EXPLAIN output */
+#define RESFMT_ScanExp   6 /* EXPLAIN output with vm stats */
+#define RESFMT_EQP       7 /* Converts EXPLAIN QUERY PLAN output into a graph */
+#define RESFMT_Markdown  8 /* Markdown formatting */
+#define RESFMT_Column    9 /* One record per line in neat columns */
+#define RESFMT_Table    10 /* MySQL-style table formatting */
+#define RESFMT_Box      11 /* Unicode box-drawing characters */
+#define RESFMT_Count    12 /* Output only a count of the rows of output */
+#define RESFMT_Off      13 /* No query output shown */
 
 /*
 ** Quoting styles for text.
index aabdd8d3c94b252a93c34f67eb65335ed70dc67e..a1e3b264239a6e06b54bc1392602e5a1555aba65 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Simplify\sthe\sset\sof\sformatting\schoices.
-D 2025-10-21T20:10:44.822
+C Simplify\sthe\sinterface\sto\suse\sjust\sa\ssingle\sAPI.
+D 2025-10-22T12:09:50.023
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -389,9 +389,9 @@ F ext/misc/qpvtab.c fc189e127f68f791af90a487f4460ec91539a716daf45a0c357e963fd47c
 F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed
 F ext/misc/regexp.c 548151f3e57506fda678e6a65e85a763f4eece653287e1ad44e167f9485e0c6b
 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
-F ext/misc/resfmt-tester.c 64b799da88145f7bd1b70635ffc629b2058dfa31e33d04c266ebeae36d1381a0
-F ext/misc/resfmt.c aedb80cf3eae75d85457b116c840c7a834aef867ae4efa1b45926656f13d4c4d
-F ext/misc/resfmt.h 35b86324479f51ac0a5a2e39ffb7ca0ca4663667b2892583a393c8a8fc6c6264
+F ext/misc/resfmt-tester.c 3188324e10f945429fd684c1d1a468a1bde43e1379af60f0d34c5411a04b0edc
+F ext/misc/resfmt.c 86c6e1a4e77a64423de38942fcbc1c07ba052b405be3550f1e72980173e0d7f1
+F ext/misc/resfmt.h ebb635f87324499a1487cdad812f64ab9f98a1b09accf0ba45fea0e274e2bd3b
 F ext/misc/resfmt.md 6f6cefd95fa11ce30e4f34ea84052e7a8291dd48b7e666352bd7cf2e22c22ec4
 F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
 F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
@@ -2175,8 +2175,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 1a28eae74ed354d556f5ba45c716b03ff36d26b8a6729a5428d7895d8337af78
-R 6892d861551a00de62fd7fcb651f12e2
+P 1f364ea3c08badd555a9ce70bb96cb8f862d6cc6425e9ff41da228fdd2f29361
+R e9ac91203f0abef1ee5b35000bb54fe9
 U drh
-Z 7c407302cce92000d1b62ee6c390d8da
+Z 7963d538858020e5fc3e5fc1a9ddc9f8
 # Remove this line to create a well-formed Fossil manifest.
index f8322532f60d3e5e2b38cdaf29104fec4853daae..c8b8c4c1460c714b723acc8c72ccfda5e0ddd892 100644 (file)
@@ -1 +1 @@
-1f364ea3c08badd555a9ce70bb96cb8f862d6cc6425e9ff41da228fdd2f29361
+82dc13ec4887f90995bd984ede9c2670fb7512962ccceb1848a7e9aab7891c00