> ~~~
sqlite3_qrf_spec spec; /* Format specification */
char *zErrMsg; /* Text error message (optional) */
+char *zResult = 0; /* Formatted output written here */
int rc; /* Result code */
memset(&spec, 0, sizeof(spec));
-// Fill out the spec object to describe the desired output format
+spec.iVersion = 1;
+spec.pzOutput = &zResult;
+// Optionally fill other settings in spec, as needed
zErrMsg = 0;
rc = sqlite3_format_query_result(pStmt, &spec, &zErrMsg);
-if( rc ) printf("Error (%d): %s\n", rc, zErrMsg);
-sqlite3_free(zErrMsg);
+if( rc ){
+ printf("Error (%d): %s\n", rc, zErrMsg);
+ sqlite3_free(zErrMsg);
+}else{
+ printf("%s", zResult);
+ sqlite3_free(zResult);
+}
~~~
The `sqlite3_qrf_spec` object describes the desired output format
~~~
The sqlite3_qrf_spec object must be fully initialized prior
-to calling `sqlite3_format_query_result()`.
+to calling `sqlite3_format_query_result()`. Initialization can be mostly
+accomplished using memset() to zero the spec object, as most fields
+use a zero value as a reasonable default. However, the iVersion
+field must be set to 1 and one of either the pzOutput or xWrite fields
+must be initialized to a non-NULL value to tell QRF where to send
+its output.
### 2.1 Structure Version Number
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 sqlite3_qrf_spec.xWrite column is not NULL,
+from sqlite3_malloc(). If the sqlite3_qrf_spec.xWrite column is not NULL,
then that function is invoked (using sqlite3_qrf_spec.xWriteArg as its
first argument) to transmit the formatted output. Or, if
sqlite3_qrf_spec.pzOutput points to a pointer to a character, then that
pointer is made to point to memory obtained from sqlite3_malloc() that
-contains the complete text of the formatted output.
+contains the complete text of the formatted output. If spec.pzOutput\[0\]
+is initially non-NULL, then it is assumed to point to memory obtained
+from sqlite3_malloc(). In that case, the buffer is resized using
+sqlite3_realloc() and the new text is appended.
One of sqlite3_qrf_spec.xWrite and sqlite3_qrf_spec.pzOutput must be
non-NULL and the other must be NULL.
values:
> ~~~
-#define QRF_ESC_Ascii 0 /* Unix-style escapes. Ex: U+0007 shows ^G */
-#define QRF_ESC_Symbol 1 /* Unicode escapes. Ex: U+0007 shows U+2407 */
-#define QRF_ESC_Off 2 /* Do not escape control characters */
+#define QRF_ESC_Auto 0 /* Choose the ctrl-char escape automatically */
+#define QRF_ESC_Off 1 /* Do not escape control characters */
+#define QRF_ESC_Ascii 2 /* Unix-style escapes. Ex: U+0007 shows ^G */
+#define QRF_ESC_Symbol 3 /* Unicode escapes. Ex: U+0007 shows U+2407 */
~~~
-If the value of eEsc is zero, then the control character
+If the value of eEsc is QRF_ESC_Ascii, 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.
+backspace character (U+0008) is shown as "^H".
-If eEsc is one, then control characters in the range of U+0001
+If eEsc is QRF_ESC_Symbol, then control characters in the range of U+0001
through U+001f are mapped into U+2401 through U+241f, respectively.
-If the value of eEsc is two, then no translation occurs
+If the value of eEsc is QRF_ESC_Off, then no translation occurs
and control characters that appear in TEXT string are transmitted
to the formatted output as-is. This an be dangerous in applications,
since an adversary who can control TEXT values might be able to
inject ANSI cursor movement sequences to hide nefarious values.
+The QRF_ESC_Auto value for eEsc means that the query result formatter
+gets to pick whichever control-character encoding it things is best for
+the situation. This will usually be QRF_ESC_Ascii.
+
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.
The sqlite3_qrf_spec.eText field can have one of the following values:
> ~~~
-#define QRF_TEXT_Off 0 /* Literal text */
-#define QRF_TEXT_Sql 1 /* Quote as an SQL literal */
-#define QRF_TEXT_Csv 2 /* CSV-style quoting */
-#define QRF_TEXT_Html 3 /* HTML-style quoting */
-#define QRF_TEXT_Tcl 4 /* C/Tcl quoting */
-#define QRF_TEXT_Json 5 /* JSON quoting */
+#define QRF_TEXT_Auto 0 /* Choose text encoding automatically */
+#define QRF_TEXT_Off 1 /* Literal text */
+#define QRF_TEXT_Sql 2 /* Quote as an SQL literal */
+#define QRF_TEXT_Csv 3 /* CSV-style quoting */
+#define QRF_TEXT_Html 4 /* HTML-style quoting */
+#define QRF_TEXT_Tcl 5 /* C/Tcl quoting */
+#define QRF_TEXT_Json 6 /* JSON quoting */
~~~
+A value of QRF_TEXT_Auto means that the query result formatter will choose
+what it things will be the best text encoding.
+
A value of QRF_TEXT_Off means that text value appear in the output exactly
as they are found in the database file, with no translation.
The following output modes are currently defined:
> ~~~
-#define QRF_STYLE_List 0 /* One record per line with a separator */
-#define QRF_STYLE_Line 1 /* One column per line. */
-#define QRF_STYLE_Html 2 /* Generate an XHTML table */
-#define QRF_STYLE_Json 3 /* Output is a list of JSON objects */
-#define QRF_STYLE_Insert 4 /* Generate SQL "insert" statements */
-#define QRF_STYLE_Csv 5 /* Comma-separated-value */
-#define QRF_STYLE_Quote 6 /* SQL-quoted, comma-separated */
-#define QRF_STYLE_Explain 7 /* EXPLAIN output */
-#define QRF_STYLE_ScanExp 8 /* EXPLAIN output with vm stats */
-#define QRF_STYLE_EQP 9 /* Format EXPLAIN QUERY PLAN output */
-#define QRF_STYLE_Markdown 10 /* Markdown formatting */
-#define QRF_STYLE_Column 11 /* One record per line in neat columns */
-#define QRF_STYLE_Table 12 /* MySQL-style table formatting */
-#define QRF_STYLE_Box 13 /* Unicode box-drawing characters */
-#define QRF_STYLE_Count 14 /* Output only a count of the rows of output */
-#define QRF_STYLE_Off 15 /* No query output shown */
+#define QRF_STYLE_Auto 0 /* Choose a style automatically */
+#define QRF_STYLE_List 1 /* One record per line with a separator */
+#define QRF_STYLE_Line 2 /* One column per line. */
+#define QRF_STYLE_Html 3 /* Generate an XHTML table */
+#define QRF_STYLE_Json 4 /* Output is a list of JSON objects */
+#define QRF_STYLE_Insert 5 /* Generate SQL "insert" statements */
+#define QRF_STYLE_Csv 6 /* Comma-separated-value */
+#define QRF_STYLE_Quote 7 /* SQL-quoted, comma-separated */
+#define QRF_STYLE_Explain 8 /* EXPLAIN output */
+#define QRF_STYLE_ScanExp 9 /* EXPLAIN output with vm stats */
+#define QRF_STYLE_EQP 10 /* Format EXPLAIN QUERY PLAN output */
+#define QRF_STYLE_Markdown 11 /* Markdown formatting */
+#define QRF_STYLE_Column 12 /* One record per line in neat columns */
+#define QRF_STYLE_Table 13 /* MySQL-style table formatting */
+#define QRF_STYLE_Box 14 /* Unicode box-drawing characters */
+#define QRF_STYLE_Count 15 /* Output only a count of the rows of output */
+#define QRF_STYLE_Off 16 /* No query output shown */
~~~
### 5.0 Source Code Files
sz = sizeof(sqlite3_qrf_spec);
memcpy(&p->spec, pSpec, sz);
if( p->spec.zNull==0 ) p->spec.zNull = "";
+qrf_reinit:
switch( p->spec.eStyle ){
+ case QRF_STYLE_Auto: {
+ switch( sqlite3_stmt_isexplain(pStmt) ){
+ case 0: p->spec.eStyle = QRF_STYLE_Box; break;
+ case 1: p->spec.eStyle = QRF_STYLE_Explain; break;
+ default: p->spec.eStyle = QRF_STYLE_EQP; break;
+ }
+ goto qrf_reinit;
+ }
case QRF_STYLE_List: {
if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = "|";
if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n";
break;
}
}
+ if( p->spec.eEsc==QRF_ESC_Auto ){
+ p->spec.eEsc = QRF_ESC_Ascii;
+ }
+ if( p->spec.eText==QRF_TEXT_Auto ){
+ p->spec.eText = QRF_TEXT_Off;
+ }
if( p->spec.eBlob==QRF_BLOB_Auto ){
switch( p->spec.eText ){
case QRF_TEXT_Sql: p->spec.eBlob = QRF_BLOB_Sql; break;
case QRF_TEXT_Csv: p->spec.eBlob = QRF_BLOB_Tcl; break;
case QRF_TEXT_Tcl: p->spec.eBlob = QRF_BLOB_Tcl; break;
case QRF_TEXT_Json: p->spec.eBlob = QRF_BLOB_Json; break;
- default: p->spec.eBlob = QRF_BLOB_Text; break;
- }
- }
- switch( p->spec.eStyle ){
- case QRF_STYLE_List: {
- if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = "|";
- if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n";
- break;
+ default: p->spec.eBlob = QRF_BLOB_Text; break;
}
}
}
}
}
if( p->spec.pzOutput ){
- *p->spec.pzOutput = sqlite3_str_finish(p->pOut);
+ if( p->spec.pzOutput[0] ){
+ sqlite3_int64 n, sz;
+ char *zCombined;
+ sz = strlen(p->spec.pzOutput[0]);
+ n = sqlite3_str_length(p->pOut);
+ zCombined = sqlite3_realloc(p->spec.pzOutput[0], sz+n+1);
+ if( zCombined==0 ){
+ sqlite3_free(p->spec.pzOutput[0]);
+ p->spec.pzOutput[0] = 0;
+ qrfOom(p);
+ }else{
+ p->spec.pzOutput[0] = zCombined;
+ memcpy(zCombined+sz, sqlite3_str_value(p->pOut), n+1);
+ }
+ sqlite3_free(sqlite3_str_finish(p->pOut));
+ }else{
+ p->spec.pzOutput[0] = sqlite3_str_finish(p->pOut);
+ }
}else if( p->pOut ){
sqlite3_free(sqlite3_str_finish(p->pOut));
}
/*
** Output styles:
*/
-#define QRF_STYLE_List 0 /* One record per line with a separator */
-#define QRF_STYLE_Line 1 /* One column per line. */
-#define QRF_STYLE_Html 2 /* Generate an XHTML table */
-#define QRF_STYLE_Json 3 /* Output is a list of JSON objects */
-#define QRF_STYLE_Insert 4 /* Generate SQL "insert" statements */
-#define QRF_STYLE_Csv 5 /* Comma-separated-value */
-#define QRF_STYLE_Quote 6 /* SQL-quoted, comma-separated */
-#define QRF_STYLE_Explain 7 /* EXPLAIN output */
-#define QRF_STYLE_ScanExp 8 /* EXPLAIN output with vm stats */
-#define QRF_STYLE_EQP 9 /* Format EXPLAIN QUERY PLAN output */
-#define QRF_STYLE_Markdown 10 /* Markdown formatting */
-#define QRF_STYLE_Column 11 /* One record per line in neat columns */
-#define QRF_STYLE_Table 12 /* MySQL-style table formatting */
-#define QRF_STYLE_Box 13 /* Unicode box-drawing characters */
-#define QRF_STYLE_Count 14 /* Output only a count of the rows of output */
-#define QRF_STYLE_Off 15 /* No query output shown */
+#define QRF_STYLE_Auto 0 /* Choose a style automatically */
+#define QRF_STYLE_List 1 /* One record per line with a separator */
+#define QRF_STYLE_Line 2 /* One column per line. */
+#define QRF_STYLE_Html 3 /* Generate an XHTML table */
+#define QRF_STYLE_Json 4 /* Output is a list of JSON objects */
+#define QRF_STYLE_Insert 5 /* Generate SQL "insert" statements */
+#define QRF_STYLE_Csv 6 /* Comma-separated-value */
+#define QRF_STYLE_Quote 7 /* SQL-quoted, comma-separated */
+#define QRF_STYLE_Explain 8 /* EXPLAIN output */
+#define QRF_STYLE_ScanExp 9 /* EXPLAIN output with vm stats */
+#define QRF_STYLE_EQP 10 /* Format EXPLAIN QUERY PLAN output */
+#define QRF_STYLE_Markdown 11 /* Markdown formatting */
+#define QRF_STYLE_Column 12 /* One record per line in neat columns */
+#define QRF_STYLE_Table 13 /* MySQL-style table formatting */
+#define QRF_STYLE_Box 14 /* Unicode box-drawing characters */
+#define QRF_STYLE_Count 15 /* Output only a count of the rows of output */
+#define QRF_STYLE_Off 16 /* No query output shown */
/*
** Quoting styles for text.
** Allowed values for sqlite3_qrf_spec.eText
*/
-#define QRF_TEXT_Off 0 /* Literal text */
-#define QRF_TEXT_Sql 1 /* Quote as an SQL literal */
-#define QRF_TEXT_Csv 2 /* CSV-style quoting */
-#define QRF_TEXT_Html 3 /* HTML-style quoting */
-#define QRF_TEXT_Tcl 4 /* C/Tcl quoting */
-#define QRF_TEXT_Json 5 /* JSON quoting */
+#define QRF_TEXT_Auto 0 /* Choose text encoding automatically */
+#define QRF_TEXT_Off 1 /* Literal text */
+#define QRF_TEXT_Sql 2 /* Quote as an SQL literal */
+#define QRF_TEXT_Csv 3 /* CSV-style quoting */
+#define QRF_TEXT_Html 4 /* HTML-style quoting */
+#define QRF_TEXT_Tcl 5 /* C/Tcl quoting */
+#define QRF_TEXT_Json 6 /* JSON quoting */
/*
** Quoting styles for BLOBs
** Control-character escape modes.
** Allowed values for sqlite3_qrf_spec.eEscape
*/
-#define QRF_ESC_Off 0 /* Do not escape control characters */
-#define QRF_ESC_Ascii 1 /* Unix-style escapes. Ex: U+0007 shows ^G */
-#define QRF_ESC_Symbol 2 /* Unicode escapes. Ex: U+0007 shows U+2407 */
+#define QRF_ESC_Auto 0 /* Choose the ctrl-char escape automatically */
+#define QRF_ESC_Off 1 /* Do not escape control characters */
+#define QRF_ESC_Ascii 2 /* Unix-style escapes. Ex: U+0007 shows ^G */
+#define QRF_ESC_Symbol 3 /* Unicode escapes. Ex: U+0007 shows U+2407 */
#endif /* !defined(SQLITE_QRF_H) */
-C The\snew\s"format"\smethod\sin\sthe\sTCL\sinterface\sis\snow\spartially\sfunctional.
-D 2025-11-05T14:07:16.182
+C New\sstyle\ssetting\sQRF_STYLE_Auto\swhich\schooses\sbox,\sexplain,\sor\sEQP\sdepending\non\sthe\sstatement\sto\sbe\srendered.\s\sImprovements\sto\smemory\smanagement.\nUpdates\sto\sthe\sdocumentation.
+D 2025-11-05T15:44:11.056
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c
F ext/misc/zipfile.c 09e6e3a3ff40a99677de3c0bc6569bd5f4709b1844ac3d1c1452a456c5a62f1c
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
-F ext/qrf/README.md 1aa6f58a9442d329eff1d890dd33f565df636a47d8d0e878dbbf5c0ecba3b4c3
+F ext/qrf/README.md 6bfe3047478b8901694cab91ccc98b35a8e14678f38475dc726be485190d4433
F ext/qrf/qrf-tester.c 3a733b25a25ba7390cd3df055edd76ac72f488a9c5d9eb523a7508b0b8ac8900
-F ext/qrf/qrf.c 02b67fdd18903ff31ee6df545cc6816d55405c53deaec8c193afb7d9435a49db
-F ext/qrf/qrf.h 701ddceb12e6b7957eeb4d77d057fddb66328840c189514b35daf27d1edb3a0e
+F ext/qrf/qrf.c 75cbdde120e336b10190d7d1a90aa4855e25eb2e733bbdd44321b489167a816b
+F ext/qrf/qrf.h 4542c723805550b48ca81ed53e3beea95e793ecc7d2b01d34a780fbea366323f
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
-F src/tclsqlite.c dbf58baacccc93ad413f6afbd10436c99c737ad9613fd04d4d6d3fcab1895166
+F src/tclsqlite.c bb00869df54bdbb8f214d37e915eaa3033df4db7c758eed58e6f706a97714fd9
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
F src/test1.c f880ab766eeedf2c063662bd9538b923fd42c4341b7bfc2150a6d93ab8b9341c
F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P e08d21fe1365176f268f1dcca4048fb5ff043356e5817c8622b4ed9a1a5a58cf
-R 396eb99826668e7bea68d6dbddbadb5d
+P ace1ebda08740bb248c009cc4a6c99da318a2bba3e43ef20bd0c365c5021705f
+R c324dd72d4cef65f02505ddc83f97922
U drh
-Z 00c395c0339b4e9e4eacf1741e0dac01
+Z 32bacd6d63b86433ef5068a18f2ed528
# Remove this line to create a well-formed Fossil manifest.
-ace1ebda08740bb248c009cc4a6c99da318a2bba3e43ef20bd0c365c5021705f
+468ba188f034b23398e1f07b915cf7c8b337dcf7f56a13511947c5322ae98722
char *zResult = 0; /* Result to be returned */
const char *zSql = 0; /* SQL to run */
int i; /* Loop counter */
- sqlite3_str *pPrior = 0; /* Prior results */
int rc; /* Result code */
sqlite3_qrf_spec qrf; /* Formatting spec */
memset(&qrf, 0, sizeof(qrf));
qrf.iVersion = 1;
- qrf.eStyle = QRF_STYLE_Box;
qrf.pzOutput = &zResult;
for(i=2; i<objc; i++){
const char *zArg = Tcl_GetString(objv[i]);
zSql = zArg;
}else if( strcmp(zArg,"-style")==0 && i<objc-1 ){
static const char *azStyles[] = {
- "box", "column", "count",
- "csv", "eqp", "explain",
- "html", "insert", "json",
- "line", "list", "markdown",
- "quote", "scanexp", "table"
+ "auto", "box", "column",
+ "count", "csv", "eqp",
+ "explain", "html", "insert",
+ "json", "line", "list",
+ "markdown", "quote", "scanexp",
+ "table"
};
static unsigned char aStyleMap[] = {
- QRF_STYLE_Box, QRF_STYLE_Column, QRF_STYLE_Count,
- QRF_STYLE_Csv, QRF_STYLE_EQP, QRF_STYLE_Explain,
- QRF_STYLE_Html, QRF_STYLE_Insert, QRF_STYLE_Json,
- QRF_STYLE_Line, QRF_STYLE_List, QRF_STYLE_Markdown,
- QRF_STYLE_Quote, QRF_STYLE_ScanExp, QRF_STYLE_Table
+ QRF_STYLE_Auto, QRF_STYLE_Box, QRF_STYLE_Column,
+ QRF_STYLE_Count, QRF_STYLE_Csv, QRF_STYLE_EQP,
+ QRF_STYLE_Explain, QRF_STYLE_Html, QRF_STYLE_Insert,
+ QRF_STYLE_Json, QRF_STYLE_Line, QRF_STYLE_List,
+ QRF_STYLE_Markdown, QRF_STYLE_Quote, QRF_STYLE_ScanExp,
+ QRF_STYLE_Table
};
int style;
if( Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azStyles,
}
}
while( zSql && zSql[0] ){
- const char *zNext; /* Next statement after current */
SqlPreparedStmt *pStmt = 0; /* Next statement to run */
char *zErr = 0; /* Error message from QRF */
- rc = dbPrepareAndBind(pDb, zSql, &zNext, &pStmt);
+ rc = dbPrepareAndBind(pDb, zSql, &zSql, &pStmt);
if( rc ) goto format_failed;
- if( zResult ){
- if( pPrior==0 ){
- pPrior = sqlite3_str_new(pDb->db);
- if( pPrior==0 ) goto format_oom;
- }
- sqlite3_str_appendall(pPrior, zResult);
- zResult = 0;
- }
+ if( pStmt==0 ) continue;
rc = sqlite3_format_query_result(pStmt->pStmt, &qrf, &zErr);
dbReleaseStmt(pDb, pStmt, 0);
if( rc ){
rc = TCL_ERROR;
goto format_failed;
}
- zSql = zNext;
- }
-
- if( pPrior ){
- sqlite3_str_appendall(pPrior, zResult);
- sqlite3_free(zResult);
- zResult = sqlite3_str_finish(pPrior);
- pPrior = 0;
}
Tcl_SetResult(pDb->interp, zResult, TCL_VOLATILE);
sqlite3_free(zResult);
return TCL_OK;
-format_oom:
- Tcl_AppendResult(pDb->interp, "out of memory", (char*)0);
-
format_failed:
- if( zResult ) sqlite3_free(zResult);
- if( pPrior ) sqlite3_free(sqlite3_str_finish(pPrior));
+ sqlite3_free(zResult);
return rc;
#endif