]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Initial prototype spec for the SQLite Query Result Formatter.
authordrh <>
Tue, 7 Oct 2025 20:11:19 +0000 (20:11 +0000)
committerdrh <>
Tue, 7 Oct 2025 20:11:19 +0000 (20:11 +0000)
FossilOrigin-Name: 87b5e41b999877a1d0b4bb049642909c1698dc1b24e4e45631eb13d02818f0ec

ext/misc/resfmt.md [new file with mode: 0644]
manifest
manifest.tags
manifest.uuid

diff --git a/ext/misc/resfmt.md b/ext/misc/resfmt.md
new file mode 100644 (file)
index 0000000..edcdbb2
--- /dev/null
@@ -0,0 +1,247 @@
+# SQLite Result Formatting Subsystem
+
+The "resfmt" subsystem is a set of C-language subroutines that work
+together to format the output from an SQLite query.  The output format
+is configurable.  The application can request CSV, or a table, or
+any of several other formats, according to needs.
+
+## 1.0 Overview Of Operation
+
+Suppose `pStmt` is a pointer to an SQLite prepared statement
+(a pointer to an `sqlite3_stmt` object) that has been reset and
+bound and is ready to run.  Then to format the output from this
+prepared statement, use code similar to the following:
+
+> ~~~
+ResfmtSpec spec;     /* Formatter spec */
+Resfmt *pFmt;        /* Formatter object */
+int errCode;         /* Error code */
+char *zErrMsg;       /* Text error message (optional) */
+
+memset(&spec, 0, sizeof(spec));
+// Additional spec initialization here
+pFmt = sqlite3_resfmt_begin(pStmt, &spec);
+while( SQLITE_ROW==sqlite3_step(pStmt) ){
+  sqlite3_resfmt_row(pFmt, pStmt);
+}
+sqlite3_resfmt_finish(pFmt, &errCode, &zErrMsg);
+// Do something with errcode and zErrMsg
+sqlite3_free(zErrMsg);
+~~~
+
+The `ResfmtSpec` structure (defined below) describes the desired
+output format.  The `pFmt` variable is a pointer to an opaque Resfmt
+object that maintains the statement of the formatter.
+The pFmt object is used as the first parameter to two other
+routines, `sqlite3_resfmt_row()` and `sqlite3_resfmt_finish()`, and
+is not usable for any other purpose by the caller.  The
+`sqlite3_resfmt_finish()` interface serves as a destructor for
+the pFmt object.
+
+## 2.0 The `ResfmtSpec` object
+
+A pointer to an instance of the following structure is the second
+parameter to the `sqlite3_resfmt_begin()` interface.  This structure
+defines how the rules of the statement are to be formatted.
+
+> ~~~
+typedef struct ResfmtSpec ResfmtSpec;
+struct ResfmtSpec {
+  int iVersion;               /* Version number of this structure */
+  int eFormat;                /* Output format */
+  unsigned char bShowCNames;  /* True to show column names */
+  unsigned char eEscMode;     /* How to deal with control characters */
+  unsigned char bQuote;       /* Quote output values as SQL literals */
+  unsigned char bWordWrap;    /* Try to wrap on word boundaries */
+  int mxWidth;                /* Maximum column width in columnar modes */
+  const char *zColumnSep;     /* Alternative column separator */
+  const char *zRowSep;        /* Alternative row separator */
+  const char *zTableName;     /* Output table name */
+  int nWidth;                 /* Number of column width parameters */
+  int *aWidth;                /* Column widths */
+  ssize_t (*pWrite)(void*,const unsigned char*,ssize_t);  /* Write callback */
+  void *pWriteArg;            /* First argument to write callback */
+  char **pzOutput;            /* Storage location for output string */
+  /* Additional fields may be added in the future */
+};
+~~~
+
+The ResfmtSpec object must be fully initialized prior
+to calling `sqlite3_resfmt_begin()` and its value must not change
+by the application until after the corresponding call to
+`sqlite3_resfmt_finish()`.  Note that the result formatter itself
+might change values in the ResfmtSpec object as it runs.
+But the application should not try to change or use any fields of
+the ResfmtSpec object while the formatter is running.
+
+### 2.1 Structure Version Number
+
+The ResfmtSpec.iVersion field must be 1.  Future enhancements to this
+subsystem might add new fields onto the bottom of the ResfmtSpec object.
+Those new fields will only be accessible if the iVersion is greater than 1.
+Thus the iVersion field is used to support upgradability.
+
+### 2.2 Output Deposition
+
+The formatted output can either be sent to a callback function
+or accumulated into an output buffer in memory obtained
+from system malloc().  If the ResfmtSpec.pWrite column is not NULL,
+then that function is invoked (using ResfmtSpec.pWriteArg as its
+first argument) to transmit the formatted output.  Or, if
+ResfmtSpec.pzOutput points to a pointer to a character, then that
+pointer is made to point to memory obtained from malloc() that
+contains the complete text of the formatted output.
+
+When `sqlite3_resfmt_begin()` is called,
+one of ResfmtSpec.pWrite and ResfmtSpec.pzOutput must be non-NULL
+and the other must be NULL.
+
+Output might be generated row by row, on each call to
+`sqlite3_resfmt_row()` or it might be written all at once
+on the final call to `sqlite3_resfmt_finish()`, depending
+on the output format.
+
+### 2.3 Output Format
+
+The ResfmtSpec.eFormat field is an integer code that defines the
+specific output format that will be generated.  See the
+output format describes below for additional detail.
+
+### 2.4 Show Column Names
+
+The ResfmtSpec.bShowCNames field is a boolean.  If true, then column
+names appear in the output.  If false, column names are omitted.
+
+### 2.5 Control Character Escapes
+
+The ResfmtSpec.eEscMode determines how ASCII control characters are
+formatted in the output.  If this value is zero, then the control character
+with value X is displayed as ^Y where Y is X+0x40.  Hence, a
+backspace character (U+0008) is shown as "^H".  This is the default.
+If eEscMode is one, then control characters in the range of U+0001
+through U+001f are mapped into U+2401 through U+241f, respectively.
+If eEscMode is 2, then control characters are output directly, with
+no translation.
+
+The TAB (U+0009), LF (U+000a) and CR-LF (U+000d,U+000a) character
+sequence are always output literally and are not mapped to alternative
+display values, regardless of this setting.
+
+### 2.6 Word Wrapping In Columnar Modes
+
+For output modes that attempt to display equal-width columns, the
+ResfmtSpec.bWordWrap boolean determines whether long values are broken
+at word boundaries, or at arbitrary characters.  The ResfmtSpec.mxWidth
+determines the maximum width of an output column.
+
+### 2.7 Row and Column Separator Strings
+
+The ResfmtSpec.zColumnSep and ResfmtSpec.zRowSep strings are alternative
+column and row separator character sequences.  If not specified (if these
+pointers are left as NULL) then appropriate defaults are used.
+
+### 2.8 The Output Table Name
+
+The ResfmtSpec.zTableName value is the name of the output table
+when the MODE_Insert output mode is used.
+
+### 2.9 Column Widths And Alignments
+
+The ResfmtSpec.aWidth[] array, if specified, is an array of integers
+that specify the minimum column width and the alignment for all columns
+in columnar output modes.  Negative values mean right-justify.  The
+absolute value is the minimum of the corresponding column.
+
+The ResfmtSpec.nWidth field is the number of values in the aWidth[]
+array.  Any column beyond the nWidth-th column are assumed to have
+a minimum width of 0.
+
+## 3.0 The `sqlite3_resfmt_begin()` Interface
+
+Invoke the `sqlite3_resfmt_begin(P,S)` interface to begin formatting
+the output of prepared statement P using format specification S.
+This routine returns a pointer to an opaque Resfmt object that is
+the current state of the formatter.  The `sqlite3_resfmt_finish()`
+routine is the destructor for the Resfmt object and must be called
+to prevent a memory leak.
+
+If an out-of-memory fault occurs while allocating space for the
+Resfmt object, then `sqlite3_resfmt_begin()` will return a NULL
+pointer.  The application need not check for this case as the
+other routines that use a pointer to the Resfmt object all
+interpret a NULL parameter in place of the Resfmt pointer as
+a harmless no-op.
+
+## 4.0 The `sqlite3_resfmt_step()` Interface
+
+Invoke the `sqlite3_resfmt_step(F,P)` interface for each row
+in the prepared statement that is to be output.  The prepared
+statement pointer P must be the same as the P argument passed
+into `sqlite3_resfmt_begin()`, or unpredictable things can happen.
+
+The formatter might choose to output some content as each row
+is processed, or it might accumulate the output and send it all
+at once when `sqlite3_resfmt_finish()` is called.  This is at
+the discretion of the output formatter.  Generally, rows are
+output one-by-one on each call to `sqlite3_resfmt_row()` when the
+output format is such that the row can be computed without knowing
+the value of subsequence, such as in CSV output mode, and
+the output is accumulated and sent all at once in columnar output
+modes where the complete output content is needed to compute column
+widths.
+
+### 5.0 The `sqlite3_resfmt_finish()` Interface
+
+Invoke the `sqlite3_resfmt_finish(F,C,E)` interface to finish
+the formatting.  C is an optional pointer to an integer.  If C
+is not a NULL pointer, then any error code associated with the
+formatting operation is written into *C.  E is an optional pointer
+to a human-readable text error message.  If E is not a NULL pointer,
+then an error message held in memory obtained from sqlite3_malloc()
+is written into *E.  It is the responsibility of the calling
+application to invoke sqlite3_free() on this error message to
+reclaim the space.
+
+### 6.0 Output Modes
+
+The result formatter supports a variety of output modes.  The
+set of supported output modes might increase in future versions.
+The following output modes are currently defined:
+
+> ~~~
+#define MODE_Line      0 /* One column per line. */
+#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_Explain   9 /* Like MODE_Column, but do not truncate data */
+#define MODE_Ascii    10 /* Use ASCII unit and record separators (0x1F/0x1E) */
+#define MODE_Pretty   11 /* Pretty-print schemas */
+#define MODE_EQP      12 /* Converts EXPLAIN QUERY PLAN output into a graph */
+#define MODE_Json     13 /* Output JSON */
+#define MODE_Markdown 14 /* Markdown formatting */
+#define MODE_Table    15 /* MySQL-style table formatting */
+#define MODE_Box      16 /* Unicode box-drawing characters */
+#define MODE_Count    17 /* Output only a count of the rows of output */
+#define MODE_Off      18 /* No query output shown */
+#define MODE_ScanExp  19 /* Like MODE_Explain, but for ".scanstats vm" */
+#define MODE_Www      20 /* Full web-page output */
+~~~
+
+Additional detail about the meaning of each of these output modes
+is pending.
+
+### 7.0 Source Code Files
+
+The SQLite result formatter is implemented in three source code files:
+
+   *  `resfmt.c` &rarr;  The implementation, written in portable C99
+   *  `resfmt.h` &rarr;  A header file defining interfaces
+   *  `resfmt.md` &rarr;  This documentation, in Markdown
+
+To use the SQLite result formatter, include the "`resfmt.h`" header file
+and link the application against the "`resfmt.c`" source file.
index 56446e17712115fe463805d6f44afa2bb059d1ea..7a54d48d8783d747d011553db69dce50edb3a630 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Improve\sthe\sinvariant\schecker\smodule\sso\sthat\sso\sthat\sit\sadded\s"+"\sbefore\n"column\sISNULL"\sin\squeries\swhere\sthe\sbase\squery\scontains\sa\sGROUP\sBY,\sto\nprevent\sthe\sISNULL\sterm\sfrom\sbeing\spushed\sdown\sinto\sthe\ssubquery,\ssince\nthat\scan\scause\sambiguities\sif\scolumn\sis\sUNIQUE.
-D 2025-10-07T18:06:05.110
+C Initial\sprototype\sspec\sfor\sthe\sSQLite\sQuery\sResult\sFormatter.
+D 2025-10-07T20:11:19.383
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -390,6 +390,7 @@ 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.md 33cf7edf5860e13e0fc17445e6b53e2f2a009f24d20a1d8d653066bfd1af8616
 F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
 F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
 F ext/misc/series.c cbbec483aa0246661e7656971ce4de8e62ecc3151be94218306206fe4f5b7a9e
@@ -2168,8 +2169,11 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 06b4bd2aba22c57f5a5fed606c3bee225dee6fdc13bb16cc58194040ef0d7d85
-R 453915b0b72d47b5291d37cc0a19ae2f
+P b4ff920fbeef9a8590219596d73c09976da3da53c08a685be56f6b2cd2cdc70c
+R 51927445b0466af2ada0962ee88c55c2
+T *branch * resfmt
+T *sym-resfmt *
+T -sym-trunk *
 U drh
-Z 1eb68a79b24ce28ad8c3cdcce7ce295e
+Z eb3a746c4a23932f9916a7ae201a8054
 # Remove this line to create a well-formed Fossil manifest.
index bec971799ff1b8ee641c166c7aeb22d12c785393..192167730056ef4c0cd51bbe960de296032ba9b7 100644 (file)
@@ -1,2 +1,2 @@
-branch trunk
-tag trunk
+branch resfmt
+tag resfmt
index 3cdeabada1d95c386a6ac869bb11dfeef47e2d49..f9d0c62afe20b471920fe140ad8fbf579d992325 100644 (file)
@@ -1 +1 @@
-b4ff920fbeef9a8590219596d73c09976da3da53c08a685be56f6b2cd2cdc70c
+87b5e41b999877a1d0b4bb049642909c1698dc1b24e4e45631eb13d02818f0ec