1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-10-21 11:13:54 +03:00
Files
sqlite/ext/misc/resfmt-tester.c
drh 6e334ef616 More capabilities being added. Incremental check-in.
FossilOrigin-Name: 9adaf791f88875c5afeba7e7aa72efb59df42c6052898f8d7e2f83aede00a044
2025-10-20 19:55:26 +00:00

245 lines
6.7 KiB
C

/*
** 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 <ctype.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(size_t 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];
}
/* Make a copy of a string using tempMalloc() */
static char *tempStrdup(char *zIn){
size_t n;
char *z;
if( zIn==0 ) zIn = "";
n = strlen(zIn);
if( n>0x10000000 ) checkOOM(0);
z = tempMalloc( n+1 );
checkOOM(z);
memcpy(z, zIn, n+1);
return z;
}
/* 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;
int bUseWriter = 1;
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_List;
spec.xWrite = testWriter;
pBuf = sqlite3_str_new(0);
rc = sqlite3_open(":memory:", &db);
if( rc ){
fprintf(stderr, "unable to open an in-memory database: %s\n",
sqlite3_errmsg(db));
exit(1);
}
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 ){
const char *zSql, *zTail;
sqlite3_resfmt *pFmt;
int iErr = 0;
char *zErr = 0;
int n;
if( db==0 ){
fprintf(stderr, "%s:%d: database not open\n", zSrc, lineNum);
exit(1);
}
zSql = sqlite3_str_value(pBuf);
pStmt = 0;
while( zSql[0] ){
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zTail);
if( rc || pStmt==0 ){
fprintf(stderr, "%s:%d: sqlite3_prepare() fails: %s\n",
zSrc, lineNum, sqlite3_errmsg(db));
sqlite3_finalize(pStmt);
break;
}
zSql = sqlite3_sql(pStmt);
while( isspace(zSql[0]) ) zSql++;
n = (int)strlen(zSql);
while( n>0 && isspace(zSql[n-1]) ) n--;
if( n>0 ){
char *zOut = 0;
printf("/* %.*s */\n", n, zSql);
if( bUseWriter ){
spec.pzOutput = 0;
spec.xWrite = testWriter;
}else{
spec.pzOutput = &zOut;
spec.xWrite = 0;
}
pFmt = sqlite3_resfmt_begin(pStmt, &spec);
while( sqlite3_step(pStmt)==SQLITE_ROW ){
sqlite3_resfmt_row(pFmt);
}
rc = sqlite3_resfmt_finish(pFmt, &iErr, &zErr);
if( !bUseWriter && zOut ){
fputs(zOut, stdout);
sqlite3_free(zOut);
}
printf("/* rc=%d. error-code=%d. error-message=%s */\n",
rc, iErr, zErr ? zErr : "NULL");
sqlite3_free(zErr);
}
sqlite3_finalize(pStmt);
pStmt = 0;
zSql = zTail;
}
sqlite3_str_reset(pBuf);
}else
if( strncmp(zLine, "--eFormat=", 10)==0 ){
const struct { const char *zFmt; int eMode; } aFmt[] = {
{ "line", RESFMT_Line, },
{ "column", RESFMT_Column, },
{ "list", RESFMT_List, },
{ "html", RESFMT_Html, },
{ "insert", RESFMT_Insert, },
{ "tcl", RESFMT_Tcl, },
{ "csv", RESFMT_Csv, },
{ "explain", RESFMT_Explain, },
{ "pretty", RESFMT_Pretty, },
{ "eqp", RESFMT_EQP, },
{ "json", RESFMT_Json, },
{ "markdown", RESFMT_Markdown, },
{ "table", RESFMT_Table, },
{ "box", RESFMT_Box, },
{ "count", RESFMT_Count, },
{ "off", RESFMT_Off, },
{ "scanexp", RESFMT_ScanExp, },
{ "www", RESFMT_Www, },
};
int i;
for(i=0; i<sizeof(aFmt)/sizeof(aFmt[0]); i++){
if( strcmp(aFmt[i].zFmt,&zLine[10])==0 ){
spec.eFormat = aFmt[i].eMode;
break;
}
}
if( i>=sizeof(aFmt)/sizeof(aFmt[0]) ){
fprintf(stderr, "%s:%d: no such format: \"%s\"\n",
zSrc, lineNum, &zLine[10]);
}
}else
if( strncmp(zLine, "--bQuote=", 9)==0 ){
spec.bQuote = atoi(&zLine[9])!=0;
}else
if( strncmp(zLine, "--bShowCNames=", 14)==0 ){
spec.bShowCNames = atoi(&zLine[14])!=0;
}else
if( strncmp(zLine, "--zNull=", 8)==0 ){
spec.zNull = tempStrdup(&zLine[8]);
}else
if( strncmp(zLine, "--zColumnSep=", 13)==0 ){
spec.zColumnSep = tempStrdup(&zLine[13]);
}else
if( strncmp(zLine, "--zRowSep=", 10)==0 ){
spec.zRowSep = tempStrdup(&zLine[10]);
}else
if( strcmp(zLine, "--exit")==0 ){
break;
}else
if( strncmp(zLine, "--use-writer=",13)==0 ){
bUseWriter = atoi(&zLine[13])!=0;
}else
{
if( sqlite3_str_length(pBuf) ) sqlite3_str_append(pBuf, "\n", 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;
}