1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-10-24 09:53:10 +03:00

Add test program for resfmt.c. Now compiles and runs.

FossilOrigin-Name: 7aaaeea319c7165284028ff8cf1b3448a818c5029de02e7199614bb45aa304c5
This commit is contained in:
drh
2025-10-20 17:19:30 +00:00
parent 5b5b35f6d6
commit a1f32824e2
6 changed files with 205 additions and 43 deletions

147
ext/misc/resfmt-tester.c Normal file
View File

@@ -0,0 +1,147 @@
/*
** 2025-10-20
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** A simple command-line program for testing the Result-Format or "resfmt"
** utility library for SQLite.
*/
#include <stdio.h>
#include <string.h>
#include "sqlite3.h"
#include "resfmt.h"
/* Report out-of-memory and die if the argument is NULL */
static void checkOOM(void *p){
if( p==0 ){
fprintf(stdout, "out-of-memory\n");
exit(1);
}
}
/* A block of memory */
typedef struct memblock memblock;
struct memblock {
memblock *pNext;
};
/* List of all memory to be freed */
static memblock *pToFree = 0;
/* Free all memory at exit */
static void tempFreeAll(void){
while( pToFree ){
memblock *pNext = pToFree->pNext;
sqlite3_free(pToFree);
pToFree = pNext;
}
}
/* Allocate memory that will be freed all at once by freeall() */
static void *tempMalloc(unsigned n){
memblock *p;
if( n>0x10000000 ) checkOOM(0);
p = sqlite3_malloc64( n+sizeof(memblock) );
checkOOM(p);
p->pNext = pToFree;
pToFree = p;
return (void*)&pToFree[1];
}
/* Function used for writing to the console */
ssize_t testWriter(void *pContext, const unsigned char *p, size_t n){
return fwrite(p,1,n,stdout);
}
int main(int argc, char **argv){
char *zSrc;
FILE *pSrc;
sqlite3_str *pBuf;
sqlite3 *db = 0;
sqlite3_stmt *pStmt;
int rc;
int lineNum = 0;
sqlite3_resfmt_spec spec;
char zLine[1000];
if( argc<2 ){
zSrc = "<stdin>";
pSrc = stdin;
}else{
zSrc = argv[1];
pSrc = fopen(zSrc, "rb");
if( pSrc==0 ){
fprintf(stderr, "cannot open \"%s\" for reading\n", zSrc);
exit(1);
}
}
memset(&spec, 0, sizeof(spec));
spec.iVersion = 1;
spec.eFormat = RESFMT_Line;
spec.xWrite = testWriter;
pBuf = sqlite3_str_new(0);
while( fgets(zLine, sizeof(zLine), pSrc) ){
size_t n = strlen(zLine);
lineNum++;
while( n>0 && zLine[n-1]>0 && zLine[n-1]<=' ' ) n--;
zLine[n] = 0;
printf("%s\n", zLine);
if( strncmp(zLine, "--open=", 7)==0 ){
if( db ) sqlite3_close(db);
db = 0;
rc = sqlite3_open(&zLine[7], &db);
if( rc!=SQLITE_OK ){
fprintf(stderr, "%s:%d: cannot open \"%s\": %s\n",
zSrc, lineNum, &zLine[7],
sqlite3_errmsg(db));
exit(1);
}
}else
if( strcmp(zLine, "--go")==0 ){
char *zSql;
sqlite3_resfmt *pFmt;
int iErr = 0;
char *zErr = 0;
if( db==0 ){
fprintf(stderr, "%s:%d: database not open\n", zSrc, lineNum);
exit(1);
}
zSql = sqlite3_str_value(pBuf);
pStmt = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc || pStmt==0 ){
fprintf(stderr, "%s:%d: sqlite3_prepare() fails: %s\n",
zSrc, lineNum, sqlite3_errmsg(db));
}
pFmt = sqlite3_resfmt_begin(pStmt, &spec);
while( sqlite3_step(pStmt)==SQLITE_ROW ){
sqlite3_resfmt_row(pFmt);
}
rc = sqlite3_resfmt_finish(pFmt, &iErr, &zErr);
printf("rc=%d. error-code=%d. error-message=%s\n",
rc, iErr, zErr ? zErr : "NULL");
sqlite3_free(zErr);
sqlite3_finalize(pStmt);
pStmt = 0;
sqlite3_str_reset(pBuf);
}else
if( strcmp(zLine, "--exit")==0 ){
break;
}else
{
if( sqlite3_str_length(pBuf) ) sqlite3_str_appendchar(pBuf, ' ', 1);
sqlite3_str_appendall(pBuf, zLine);
}
}
if( db ) sqlite3_close(db);
sqlite3_free(sqlite3_str_finish(pBuf));
tempFreeAll();
if( pSrc!=stdin ) fclose(pSrc);
return 0;
}

View File

@@ -13,6 +13,7 @@
** See the resfmt.md documentation for additional information. ** See the resfmt.md documentation for additional information.
*/ */
#include "resfmt.h" #include "resfmt.h"
#include <string.h>
/* /*
** Private state information. Subject to change from one release to the ** Private state information. Subject to change from one release to the
@@ -64,52 +65,63 @@ int sqlite3_resfmt_finish(sqlite3_resfmt *p, int *piErr, char **pzErrMsg){
/* /*
** Render value pVal into p->pOut ** Render value pVal into p->pOut
*/ */
static void resfmtRenderValue(sqlite3_resfmt *p, sqlite3_value *pVal){ static void resfmtRenderValue(sqlite3_resfmt *p, int iCol){
if( p->xRender ){ if( p->spec.xRender ){
char *z = p->xRender(p->pRenderArg, pVal); sqlite3_value *pVal;
char *z;
pVal = sqlite3_value_dup(sqlite3_column_value(p->pStmt,iCol));
z = p->spec.xRender(p->spec.pRenderArg, pVal);
sqlite3_value_free(pVal);
if( z ){ if( z ){
sqlite3_str_appendall(p->pOut, z); sqlite3_str_appendall(p->pOut, z);
sqlite3_free(z); sqlite3_free(z);
return; return;
} }
} }
switch( sqlite3_value_type(pVal) { switch( sqlite3_column_type(p->pStmt,iCol) ){
case SQLITE_INTEGER: { case SQLITE_INTEGER: {
sqlite3_str_appendf(p->pOut, "%lld", sqlite3_value_int64(pVal)); sqlite3_str_appendf(p->pOut, "%lld", sqlite3_column_int64(p->pStmt,iCol));
break; break;
} }
case SQLITE_FLOAT: { case SQLITE_FLOAT: {
sqlite3_str_appendf(p->pOut, p->zFloatFmt, sqlite3_value_double(pVal)); if( p->spec.zFloatFmt ){
double r = sqlite3_column_double(p->pStmt,iCol);
sqlite3_str_appendf(p->pOut, p->spec.zFloatFmt, r);
}else{
const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
sqlite3_str_appendall(p->pOut, zTxt);
}
break; break;
} }
case SQLITE_BLOB: { case SQLITE_BLOB: {
int iStart = sqlite3_str_length(p->pOut); int iStart = sqlite3_str_length(p->pOut);
int nBlob = sqlite3_value_bytes(pVal); int nBlob = sqlite3_column_bytes(p->pStmt,iCol);
int i, j; int i, j;
char *zVal; char *zVal;
unsigned char *a = sqlite3_value_blob(pVal); const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol);
sqlite3_str_append(p->pOut, "x'", 2); sqlite3_str_append(p->pOut, "x'", 2);
sqlite3_str_appendchar(p->pOut, nBlob, ' '); sqlite3_str_appendchar(p->pOut, nBlob, ' ');
sqlite3_str_appendchar(p->pOut, nBlob, ' '); sqlite3_str_appendchar(p->pOut, nBlob, ' ');
sqlite3_str_appendchar(p->pOut, 1, '\''); sqlite3_str_appendchar(p->pOut, 1, '\'');
if( sqlite3_str_errcode(p->pOut ) return; if( sqlite3_str_errcode(p->pOut) ) return;
zVal = sqlite3_str_value(p->pOut); zVal = sqlite3_str_value(p->pOut);
for(i=0, j=iStart+2; i<nBlob; i++, j+=2){ for(i=0, j=iStart+2; i<nBlob; i++, j+=2){
unsigned char c = a[i]; unsigned char c = a[i];
zVal[j] = "0123456789abcdef"[(c>>4)&0xf]); zVal[j] = "0123456789abcdef"[(c>>4)&0xf];
zVal[j+1] = "0123456789abcdef"[(c)&0xf]); zVal[j+1] = "0123456789abcdef"[(c)&0xf];
} }
break; break;
} }
case SQLITE_NULL: { case SQLITE_NULL: {
sqlite3_str_appendall(p->pOut, p->zNull); sqlite3_str_appendall(p->pOut, p->spec.zNull);
break; break;
} }
case SQLITE_TEXT: { case SQLITE_TEXT: {
const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
if( p->spec.bQuote ){ if( p->spec.bQuote ){
sqlite3_str_appendf(p->pOut, "%Q", sqlite3_value_text(pVal)); sqlite3_str_appendf(p->pOut, "%Q", zTxt);
}else{ }else{
sqlite3_str_appendall(p->pOut, sqlite3_value_text(pVal)); sqlite3_str_appendall(p->pOut, zTxt);
} }
break; break;
} }
@@ -148,31 +160,27 @@ sqlite3_resfmt *sqlite3_resfmt_begin(
p->pStmt = pStmt; p->pStmt = pStmt;
p->db = sqlite3_db_handle(pStmt); p->db = sqlite3_db_handle(pStmt);
p->pErr = 0; p->pErr = 0;
p->pOut = 0;
p->pBuf = sqlite3_str_new(p->db);
if( p->pBuf==0 ){
reffmtFree(p);
return 0;
}
if( pSpec->pzOutput ){
p->pOut = sqlite3_str_new(p->db); p->pOut = sqlite3_str_new(p->db);
if( p->pOut==0 ){ if( p->pOut==0 ){
reffmtFree(p); resfmtFree(p);
return 0; return 0;
} }
}
p->iErr = 0; p->iErr = 0;
p->nCol = sqlite3_column_count(p->pStmt); p->nCol = sqlite3_column_count(p->pStmt);
p->nRow = 0; p->nRow = 0;
sz = sizeof(sqlite3_resfmt_spec); break; sz = sizeof(sqlite3_resfmt_spec);
memcpy(&p->spec, pSpec, sz); memcpy(&p->spec, pSpec, sz);
if( p->spec.zNull==0 ) p->spec.zNull = "";
switch( p->spec.eFormat ){
case RESFMT_Line: {
if( p->spec.zColumnSep==0 ) p->spec.zColumnSep = ",";
if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n";
break;
}
}
return p; return p;
} }
/*
** Output text in the manner requested by the spec (either by direct
** write to
/* /*
** Render a single row of output. ** Render a single row of output.
*/ */
@@ -185,7 +193,7 @@ int sqlite3_resfmt_row(sqlite3_resfmt *p){
sqlite3_str_reset(p->pOut); sqlite3_str_reset(p->pOut);
for(i=0; i<p->nCol; i++){ for(i=0; i<p->nCol; i++){
if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep); if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
resfmtRenderValue(p, sqlite3_column_value(p->pStmt, i)); resfmtRenderValue(p, i);
} }
sqlite3_str_appendall(p->pOut, p->spec.zRowSep); sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
resfmtWrite(p); resfmtWrite(p);

View File

@@ -12,6 +12,7 @@
** Header file for the Result-Format or "resfmt" utility library for SQLite. ** Header file for the Result-Format or "resfmt" utility library for SQLite.
** See the resfmt.md documentation for additional information. ** See the resfmt.md documentation for additional information.
*/ */
#include <stdlib.h>
#include "sqlite3.h" #include "sqlite3.h"
/* /*
@@ -34,7 +35,7 @@ struct sqlite3_resfmt_spec {
int nWidth; /* Number of column width parameters */ int nWidth; /* Number of column width parameters */
short int *aWidth; /* Column widths */ short int *aWidth; /* Column widths */
char *(*xRender)(void*,sqlite3_value*); /* Render a value */ char *(*xRender)(void*,sqlite3_value*); /* Render a value */
ssize_t (*xWrite)(void*,const unsigned char*,ssize_t); /* Write callback */ ssize_t (*xWrite)(void*,const unsigned char*,size_t); /* Write callback */
void *pRenderArg; /* First argument to the xRender callback */ void *pRenderArg; /* First argument to the xRender callback */
void *pWriteArg; /* First argument to the xWrite callback */ void *pWriteArg; /* First argument to the xWrite callback */
char **pzOutput; /* Storage location for output string */ char **pzOutput; /* Storage location for output string */
@@ -50,7 +51,7 @@ typedef struct sqlite3_resfmt sqlite3_resfmt;
** Interfaces ** Interfaces
*/ */
sqlite3_resfmt *sqlite3_resfmt_begin(sqlite3_stmt*, sqlite3_resfmt_spec*); sqlite3_resfmt *sqlite3_resfmt_begin(sqlite3_stmt*, sqlite3_resfmt_spec*);
int sqlite3_resfmt_row(sqlite3_resfmt*) int sqlite3_resfmt_row(sqlite3_resfmt*);
int sqlite3_resfmt_finish(sqlite3_resfmt*,int*,char**); int sqlite3_resfmt_finish(sqlite3_resfmt*,int*,char**);
/* /*

View File

@@ -2154,6 +2154,11 @@ threadtest5: sqlite3.c $(TOP)/test/threadtest5.c
$(T.link) $(TOP)/test/threadtest5.c sqlite3.c -o $@ $(LDFLAGS.libsqlite3) $(T.link) $(TOP)/test/threadtest5.c sqlite3.c -o $@ $(LDFLAGS.libsqlite3)
xbin: threadtest5 xbin: threadtest5
resfmt-test: sqlite3.o $(TOP)/ext/misc/resfmt-tester.c $(TOP)/ext/misc/resfmt.c $(TOP)/ext/misc/resfmt.h
$(T.link) -I$(TOP)/ext/misc -I. \
$(TOP)/ext/misc/resfmt-tester.c $(TOP)/ext/misc/resfmt.c sqlite3.o \
-o $@ $(LDFLAGS.libsqlite3)
# #
# STATIC_CLI_SHELL = 1 to statically link sqlite3$(T.exe), else # STATIC_CLI_SHELL = 1 to statically link sqlite3$(T.exe), else
# 0. Requires static versions of all requisite libraries. Primarily # 0. Requires static versions of all requisite libraries. Primarily

View File

@@ -1,5 +1,5 @@
C Notes\son\sthe\sresult-formatter\sutility.\s\sNone\sof\sthe\scode\sworks.\s\sThese\nare\sjust\sideas\sI\shave\sjotted\sdown\sas\sI\stry\sto\sfigure\sout\show\sto\sdo\sthis. C Add\stest\sprogram\sfor\sresfmt.c.\s\sNow\scompiles\sand\sruns.
D 2025-10-20T14:28:57.161 D 2025-10-20T17:19:30.111
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -389,8 +389,9 @@ F ext/misc/qpvtab.c fc189e127f68f791af90a487f4460ec91539a716daf45a0c357e963fd47c
F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed
F ext/misc/regexp.c 548151f3e57506fda678e6a65e85a763f4eece653287e1ad44e167f9485e0c6b F ext/misc/regexp.c 548151f3e57506fda678e6a65e85a763f4eece653287e1ad44e167f9485e0c6b
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/resfmt.c 63285008be21bd71ac036f37e91b9c099e8c221613a25c437d1cf07c0d0d93c8 F ext/misc/resfmt-tester.c 51149ed2da237e5b927c1379cb6d5b9189191f60f4237d2bd5183a33a2b30776
F ext/misc/resfmt.h bac5dbf40c174d99d300ed34f3e94bea6854af73ea703d18d0897088c73473a9 F ext/misc/resfmt.c 3c82b41fa33a3b05a60fb43e96c3b3926edda1eb45a3432e94b30d769d094cc1
F ext/misc/resfmt.h 2cb13016806263897e4aad0689f26f07eb8b5b26619d09f07af5c64be3041f4b
F ext/misc/resfmt.md 6f6cefd95fa11ce30e4f34ea84052e7a8291dd48b7e666352bd7cf2e22c22ec4 F ext/misc/resfmt.md 6f6cefd95fa11ce30e4f34ea84052e7a8291dd48b7e666352bd7cf2e22c22ec4
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946 F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
@@ -661,7 +662,7 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca
F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2 F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61 F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0 F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
F main.mk 00dd631c66c1f7922b2d691631163899eff1c3d1da780ff37a62f8d997b368e1 F main.mk bf63775585a99e8e7158c4d67c30aeeae45b84572c474f9d41c7bba927788f46
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421 F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
@@ -2174,8 +2175,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 20c79a2cc1f9eedea12cbac0a657301614d042e3487ddf37cd4b0316e6f84f21 P c38f1c63247804486a6b368ead4c5122adaedd5c697487fadbed49e1acb155bc
R 894750e947c3f45bc6ad26f6f95da410 R c7be1ef7fe6eb1c112e628cf30c74761
U drh U drh
Z 310d7ad8c0408f77d8a61f85297aa2df Z 01552c3fb5b64b22ab51e3ac81071bb9
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
c38f1c63247804486a6b368ead4c5122adaedd5c697487fadbed49e1acb155bc 7aaaeea319c7165284028ff8cf1b3448a818c5029de02e7199614bb45aa304c5