1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-10-19 23:49:30 +03:00

Initial prototype spec for the SQLite Query Result Formatter.

FossilOrigin-Name: 87b5e41b999877a1d0b4bb049642909c1698dc1b24e4e45631eb13d02818f0ec
This commit is contained in:
drh
2025-10-07 20:11:19 +00:00
parent 308831d1c7
commit c02f8fdfe2
4 changed files with 259 additions and 8 deletions

247
ext/misc/resfmt.md Normal file
View File

@@ -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` → The implementation, written in portable C99
* `resfmt.h` → A header file defining interfaces
* `resfmt.md` → 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.

View File

@@ -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.

View File

@@ -1,2 +1,2 @@
branch trunk
tag trunk
branch resfmt
tag resfmt

View File

@@ -1 +1 @@
b4ff920fbeef9a8590219596d73c09976da3da53c08a685be56f6b2cd2cdc70c
87b5e41b999877a1d0b4bb049642909c1698dc1b24e4e45631eb13d02818f0ec