From: drh <> Date: Tue, 21 Oct 2025 15:30:38 +0000 (+0000) Subject: Add separate quoting style for BLOB values. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8e544ca512d326a21cf19eba74ea5ee811634d82;p=thirdparty%2Fsqlite.git Add separate quoting style for BLOB values. FossilOrigin-Name: dfe537175e7d15507e8532817a06f76dc375c7eb00f5cdc4b4f8d71ec516137e --- diff --git a/ext/misc/resfmt-tester.c b/ext/misc/resfmt-tester.c index 81bcc91b75..96a120508b 100644 --- a/ext/misc/resfmt-tester.c +++ b/ext/misc/resfmt-tester.c @@ -218,13 +218,12 @@ int main(int argc, char **argv){ }else if( strncmp(zLine, "--eQuote=", 9)==0 ){ const struct { const char *z; int e; } aQuote[] = { - { "c", RESFMT_Q_C }, { "csv", RESFMT_Q_Csv }, { "html", RESFMT_Q_Html }, { "json", RESFMT_Q_Json }, { "off", RESFMT_Q_Off }, { "sql", RESFMT_Q_Sql }, - { "tcl", RESFMT_Q_C }, + { "tcl", RESFMT_Q_Tcl }, }; int i; for(i=0; i=COUNT(aBlob) ){ + sqlite3_str *pMsg = sqlite3_str_new(0); + for(i=0; ispec.eQuote ){ - case RESFMT_Q_Sql: { - int iStart = sqlite3_str_length(p->pOut); + switch( p->spec.eBlob ){ + case RESFMT_B_Hex: + case RESFMT_B_Sql: { + int iStart; int nBlob = sqlite3_column_bytes(p->pStmt,iCol); int i, j; char *zVal; const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol); - sqlite3_str_append(p->pOut, "x'", 2); + if( p->spec.eBlob==RESFMT_B_Sql ){ + sqlite3_str_append(p->pOut, "x'", 2); + } + iStart = sqlite3_str_length(p->pOut); sqlite3_str_appendchar(p->pOut, nBlob, ' '); sqlite3_str_appendchar(p->pOut, nBlob, ' '); - sqlite3_str_appendchar(p->pOut, 1, '\''); + if( p->spec.eBlob==RESFMT_B_Sql ){ + sqlite3_str_appendchar(p->pOut, 1, '\''); + } if( sqlite3_str_errcode(p->pOut) ) return; zVal = sqlite3_str_value(p->pOut); - for(i=0, j=iStart+2; i>4)&0xf]; zVal[j+1] = "0123456789abcdef"[(c)&0xf]; } break; } + case RESFMT_B_Tcl: + case RESFMT_B_Json: { + int iStart; + int nBlob = sqlite3_column_bytes(p->pStmt,iCol); + int i, j; + char *zVal; + const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol); + int szC = p->spec.eBlob==RESFMT_B_Json ? 6 : 4; + sqlite3_str_append(p->pOut, "\"", 1); + iStart = sqlite3_str_length(p->pOut); + for(i=szC; i>0; i--){ + sqlite3_str_appendchar(p->pOut, nBlob, ' '); + } + sqlite3_str_appendchar(p->pOut, 1, '"'); + if( sqlite3_str_errcode(p->pOut) ) return; + zVal = sqlite3_str_value(p->pOut); + for(i=0, j=iStart; i>6)&3); + zVal[j+2] = '0' + ((c>>3)&7); + zVal[j+3] = '0' + (c&7); + }else{ + zVal[j+1] = 'u'; + zVal[j+2] = '0'; + zVal[j+3] = '0'; + zVal[j+4] = "0123456789abcdef"[(c>>4)&0xf]; + zVal[j+5] = "0123456789abcdef"[(c)&0xf]; + } + } + break; + } default: { const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol); resfmtEncodeText(p, zTxt); @@ -255,6 +294,15 @@ sqlite3_resfmt *sqlite3_resfmt_begin( sz = sizeof(sqlite3_resfmt_spec); memcpy(&p->spec, pSpec, sz); if( p->spec.zNull==0 ) p->spec.zNull = ""; + if( p->spec.eBlob==RESFMT_B_Auto ){ + switch( p->spec.eQuote ){ + case RESFMT_Q_Sql: p->spec.eBlob = RESFMT_B_Sql; break; + case RESFMT_Q_Csv: p->spec.eBlob = RESFMT_B_Tcl; break; + case RESFMT_Q_Tcl: p->spec.eBlob = RESFMT_B_Tcl; break; + case RESFMT_Q_Json: p->spec.eBlob = RESFMT_B_Json; break; + default: p->spec.eBlob = RESFMT_B_Text; break; + } + } switch( p->spec.eFormat ){ case RESFMT_List: { if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = "|"; diff --git a/ext/misc/resfmt.h b/ext/misc/resfmt.h index 1ac93d5e2a..0de5b4a742 100644 --- a/ext/misc/resfmt.h +++ b/ext/misc/resfmt.h @@ -20,20 +20,21 @@ */ typedef struct sqlite3_resfmt_spec sqlite3_resfmt_spec; struct sqlite3_resfmt_spec { - int iVersion; /* Version number of this structure */ - int eFormat; /* Output format */ + short int 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 */ + unsigned char eQuote; /* Quoting style for text */ + unsigned char eBlob; /* Quoting style for BLOBs */ unsigned char bWordWrap; /* Try to wrap on word boundaries */ - int mxWidth; /* Maximum column width in columnar modes */ + short int mxWidth; /* Maximum column width in columnar modes */ + int nWidth; /* Number of column width parameters */ + short int *aWidth; /* Column widths */ const char *zColumnSep; /* Alternative column separator */ const char *zRowSep; /* Alternative row separator */ const char *zTableName; /* Output table name */ const char *zNull; /* Rendering of NULL */ const char *zFloatFmt; /* printf-style string for rendering floats */ - int nWidth; /* Number of column width parameters */ - short int *aWidth; /* Column widths */ char *(*xRender)(void*,sqlite3_value*); /* Render a value */ ssize_t (*xWrite)(void*,const unsigned char*,size_t); /* Write callback */ void *pRenderArg; /* First argument to the xRender callback */ @@ -77,16 +78,27 @@ int sqlite3_resfmt_finish(sqlite3_resfmt*,int*,char**); #define RESFMT_Www 17 /* Full web-page output */ /* -** Quoting styles. +** Quoting styles for text. ** Allowed values for sqlite3_resfmt_spec.eQuote */ #define RESFMT_Q_Off 0 /* Literal text */ #define RESFMT_Q_Sql 1 /* Quote as an SQL literal */ #define RESFMT_Q_Csv 2 /* CSV-style quoting */ #define RESFMT_Q_Html 3 /* HTML-style quoting */ -#define RESFMT_Q_C 4 /* C/Tcl quoting */ +#define RESFMT_Q_Tcl 4 /* C/Tcl quoting */ #define RESFMT_Q_Json 5 /* JSON quoting */ +/* +** Quoting styles for BLOBs +** Allowed values for sqlite3_resfmt_spec.eBlob +*/ +#define RESFMT_B_Auto 0 /* Determine BLOB quoting using eQuote */ +#define RESFMT_B_Text 1 /* Display content exactly as it is */ +#define RESFMT_B_Sql 2 /* Quote as an SQL literal */ +#define RESFMT_B_Hex 3 /* Hexadecimal representation */ +#define RESFMT_B_Tcl 4 /* "\000" notation */ +#define RESFMT_B_Json 5 /* A JSON string */ + /* ** Control-character escape modes. ** Allowed values for sqlite3_resfmt_spec.eEscape diff --git a/manifest b/manifest index 4f9f28a013..ae39ac0fbd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Control-character\sescaping -D 2025-10-21T13:07:51.412 +C Add\sseparate\squoting\sstyle\sfor\sBLOB\svalues. +D 2025-10-21T15:30:38.080 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 1cb1dae3f31caa13e4b7ef635eec05a5b1981aaa2202a72ca74cd995ceb5c677 -F ext/misc/resfmt.c cae8cff21efa71d0779999f715023488e96739d690c1f5bff17f947b7f43a10a -F ext/misc/resfmt.h 54937535c8d7bfda506ec3ecd9c9e6fe247f3621c0645d067809f2eb9d4bb70e +F ext/misc/resfmt-tester.c 4c493f3b74f1bc49c606a504ca8417e4a0c7bc114611c2b963df1e35f34f19bc +F ext/misc/resfmt.c 40cc38e8ca5ba02f3ee03bfdd02f305e6dc0db151ce6929629365ac356702692 +F ext/misc/resfmt.h 0abf02956c5f03ff7823861d0134e541e435426ed5ba7209bf6dfb8b61e0cd0e 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 3ee2a8775fcc557a53c36240ddc039024ff52e21d9ad9021d7cf5bf79f8b9ed4 -R 78c35db5d2e47632e3afeaff2a301639 +P fbb69764559f4333890860f4f3c010efa9cc994a82743766b948e7635fd079e8 +R 0b9bda5bbcc16ecc914edff675de2c46 U drh -Z dd3d4f12786ad3019ddd480d2d6b5f14 +Z 666fe7e2fd9d7f3f1b51180f13bf63cd # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b62a9bd402..8a56790ceb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fbb69764559f4333890860f4f3c010efa9cc994a82743766b948e7635fd079e8 +dfe537175e7d15507e8532817a06f76dc375c7eb00f5cdc4b4f8d71ec516137e