TESTSRC += \
$(TOP)/ext/misc/amatch.c \
$(TOP)/ext/misc/closure.c \
+ $(TOP)/ext/misc/eval.c \
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/fuzzer.c \
$(TOP)/ext/misc/ieee754.c \
TESTEXT = \
$(TOP)\ext\misc\amatch.c \
$(TOP)\ext\misc\closure.c \
+ $(TOP)\ext\misc\eval.c \
$(TOP)\ext\misc\fileio.c \
$(TOP)\ext\misc\fuzzer.c \
$(TOP)\ext\misc\ieee754.c \
--- /dev/null
+/*
+** 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;
+}
TESTSRC += \
$(TOP)/ext/misc/amatch.c \
$(TOP)/ext/misc/closure.c \
+ $(TOP)/ext/misc/eval.c \
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/fuzzer.c \
$(TOP)/ext/misc/ieee754.c \
-C Shorten\sover-length\ssource\scode\slines\sin\sshell.c.
-D 2014-11-10T14:42:28.114
+C Add\sthe\seval()\sSQL\sfunction\sextension\sin\sext/misc/eval.c.
+D 2014-11-10T16:49:56.620
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
-F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
+F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
-F Makefile.msc e31dee24038965fb6269d6d61073fd6b7e331dec
+F Makefile.msc 788f1288633a0c3c3cbbe0f3e4827d033f7ba530
F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0
F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8
F VERSION d846487aff892625eb8e75960234e7285f0462fe
F ext/misc/amatch.c 678056a4bfcd83c4e82dea81d37543cd1d6dbee1
F ext/misc/closure.c 636024302cde41b2bf0c542f81c40c624cfb7012
F ext/misc/compress.c 76e45655f4046e756064ab10c62e18f2eb846b9f
+F ext/misc/eval.c 04e630bde869aa1fec6b993d40591f963be2f868
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
F ext/misc/fuzzer.c 136533c53cfce0957f0b48fa11dba27e21c5c01d
F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 3fececc835c5c23637c3e0af970e27a81a9ba476
+F main.mk 084976077a4aa3bd985154b5423e7aed88e4a2e9
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F src/status.c 81712116e826b0089bb221b018929536b2b5406f
F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc
F src/tclsqlite.c 0a874655dd39a9875e39c5d3c464db662171d228
-F src/test1.c cce6ad0effe8c66a62d2634d9714ffdc7372ef11
+F src/test1.c 6b0469b8e06c77b1de1d3e4a3834cf26edea9cc7
F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2
+F test/misc8.test e538d122d5faacadbaa6fc02403f1e1427df684f
F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912
F test/mmap1.test 1bfd611b9841eafb44f7d83c0788e146d84a33c9
F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P ecbccd0e594d22b3ae7fabc8037951dc49570bc3
-R 1a35da25c621486ba7906429ccbf946c
+P 7f3819f6422badd344c1264b0cd2f2c7afe077df
+R a579eb1c0cce07efa12ad49b9c702f07
U drh
-Z 427c2830707548878070627d5502fc48
+Z 4009c695bea2e084a946ee86095e7182
-7f3819f6422badd344c1264b0cd2f2c7afe077df
\ No newline at end of file
+27cf665b957f2c0ced403e3032099e80c295598f
\ No newline at end of file
){
extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
+ extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
} aExtension[] = {
{ "amatch", sqlite3_amatch_init },
{ "closure", sqlite3_closure_init },
+ { "eval", sqlite3_eval_init },
{ "fileio", sqlite3_fileio_init },
{ "fuzzer", sqlite3_fuzzer_init },
{ "ieee754", sqlite3_ieee_init },
--- /dev/null
+# 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 file implements regression tests for SQLite library.
+# The focus of this script is testing the "eval.c" loadable extension.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+load_static_extension db eval
+do_execsql_test misc8-1.0 {
+ CREATE TABLE t1(a,b,c);
+ INSERT INTO t1 VALUES(1,2,3),(4,5,6);
+ SELECT quote(eval('SELECT * FROM t1 ORDER BY a','-abc-'));
+} {'1-abc-2-abc-3-abc-4-abc-5-abc-6'}
+do_execsql_test misc8-1.1 {
+ SELECT quote(eval('SELECT * FROM t1 ORDER BY a'));
+} {{'1 2 3 4 5 6'}}
+do_catchsql_test misc8-1.2 {
+ SELECT quote(eval('SELECT d FROM t1 ORDER BY a'));
+} {1 {no such column: d}}
+do_execsql_test misc8-1.3 {
+ INSERT INTO t1 VALUES(7,null,9);
+ SELECT eval('SELECT * FROM t1 ORDER BY a',',');
+} {1,2,3,4,5,6,7,,9}
+do_catchsql_test misc8-1.4 {
+ BEGIN;
+ INSERT INTO t1 VALUES(10,11,12);
+ SELECT coalesce(b, eval('ROLLBACK')) FROM t1 ORDER BY a;
+} {1 {abort due to ROLLBACK}}
+
+
+finish_test