diff options
author | drh <drh@noemail.net> | 2014-11-10 16:49:56 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2014-11-10 16:49:56 +0000 |
commit | 1728bcb07f9e6784bdf5c223ffe2c035011f9123 (patch) | |
tree | c5eb72404faf47592b7b3e55635e35fa881f52b8 /ext/misc/eval.c | |
parent | 4ace5362c250de7d712ef107275427aaa8c2c304 (diff) | |
download | sqlite-1728bcb07f9e6784bdf5c223ffe2c035011f9123.tar.gz sqlite-1728bcb07f9e6784bdf5c223ffe2c035011f9123.zip |
Add the eval() SQL function extension in ext/misc/eval.c.
FossilOrigin-Name: 27cf665b957f2c0ced403e3032099e80c295598f
Diffstat (limited to 'ext/misc/eval.c')
-rw-r--r-- | ext/misc/eval.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/ext/misc/eval.c b/ext/misc/eval.c new file mode 100644 index 000000000..a5e297ad3 --- /dev/null +++ b/ext/misc/eval.c @@ -0,0 +1,119 @@ +/* +** 2014-11-10 +** +** 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. +** +****************************************************************************** +** +** This SQLite extension implements SQL function eval() which runs +** SQL statements recursively. +*/ +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 +#include <string.h> + +/* +** Structure used to accumulate the output +*/ +struct EvalResult { + char *z; /* Accumulated output */ + const char *zSep; /* Separator */ + int szSep; /* Size of the separator string */ + int nAlloc; /* Number of bytes allocated for z[] */ + int nUsed; /* Number of bytes of z[] actually used */ +}; + +/* +** Callback from sqlite_exec() for the eval() function. +*/ +static int callback(void *pCtx, int argc, char **argv, char **colnames){ + struct EvalResult *p = (struct EvalResult*)pCtx; + int i; + for(i=0; i<argc; i++){ + const char *z = argv[i] ? argv[i] : ""; + size_t sz = strlen(z); + if( sz+p->nUsed+p->szSep+1 > p->nAlloc ){ + char *zNew; + p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; + zNew = sqlite3_realloc(p->z, p->nAlloc); + if( zNew==0 ){ + sqlite3_free(p->z); + memset(p, 0, sizeof(*p)); + return 1; + } + p->z = zNew; + } + if( p->nUsed>0 ){ + memcpy(&p->z[p->nUsed], p->zSep, p->szSep); + p->nUsed += p->szSep; + } + memcpy(&p->z[p->nUsed], z, sz); + p->nUsed += sz; + } + return 0; +} + +/* +** Implementation of the eval(X) and eval(X,Y) SQL functions. +** +** Evaluate the SQL text in X. Return the results, using string +** Y as the separator. If Y is omitted, use a single space character. +*/ +static void sqlEvalFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zSql; + sqlite3 *db; + char *zErr = 0; + int rc; + struct EvalResult x; + + memset(&x, 0, sizeof(x)); + x.zSep = " "; + zSql = (const char*)sqlite3_value_text(argv[0]); + if( zSql==0 ) return; + if( argc>1 ){ + x.zSep = (const char*)sqlite3_value_text(argv[1]); + if( x.zSep==0 ) return; + } + x.szSep = (int)strlen(x.zSep); + db = sqlite3_context_db_handle(context); + rc = sqlite3_exec(db, zSql, callback, &x, &zErr); + if( rc!=SQLITE_OK ){ + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + }else if( x.zSep==0 ){ + sqlite3_result_error_nomem(context); + sqlite3_free(x.z); + }else{ + sqlite3_result_text(context, x.z, x.nUsed, sqlite3_free); + } +} + + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_eval_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, + sqlEvalFunc, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, + sqlEvalFunc, 0, 0); + } + return rc; +} |