]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the eval() SQL function extension in ext/misc/eval.c.
authordrh <drh@noemail.net>
Mon, 10 Nov 2014 16:49:56 +0000 (16:49 +0000)
committerdrh <drh@noemail.net>
Mon, 10 Nov 2014 16:49:56 +0000 (16:49 +0000)
FossilOrigin-Name: 27cf665b957f2c0ced403e3032099e80c295598f

Makefile.in
Makefile.msc
ext/misc/eval.c [new file with mode: 0644]
main.mk
manifest
manifest.uuid
src/test1.c
test/misc8.test [new file with mode: 0644]

index a2213e89e574e73483f41b10e6fe85a5721962c2..646cb39756f380187f5ad41c9379de2cda047beb 100644 (file)
@@ -394,6 +394,7 @@ TESTSRC = \
 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 \
index 4173eaae27ef3c1d95336327734ab9877d0f8dce..4aaa2894a7fc72ac57d8252e65aaad2338dd4517 100644 (file)
@@ -863,6 +863,7 @@ TESTSRC = \
 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 \
diff --git a/ext/misc/eval.c b/ext/misc/eval.c
new file mode 100644 (file)
index 0000000..a5e297a
--- /dev/null
@@ -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;
+}
diff --git a/main.mk b/main.mk
index c8bf72b48bcdc5493a52fa3526f73838d31dd0dc..cac996864d828548924fd07ad2702f83f3d4986e 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -281,6 +281,7 @@ TESTSRC = \
 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 \
index 5e62c4081ef619cc48b57d669240c578ad0cccea..7f7fe158b926f10d67c0f36b65f604cbd1466490 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-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
@@ -109,6 +109,7 @@ F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
 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
@@ -151,7 +152,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
 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
@@ -237,7 +238,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 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
@@ -729,6 +730,7 @@ F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6
 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
@@ -1213,7 +1215,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 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
index 541a9c512c3ec5e69a753cf8f312ec7d46bda1f9..f90ad5421384cc52afe549df83114addf23ab063 100644 (file)
@@ -1 +1 @@
-7f3819f6422badd344c1264b0cd2f2c7afe077df
\ No newline at end of file
+27cf665b957f2c0ced403e3032099e80c295598f
\ No newline at end of file
index e7a5929323fa151235c5a31199a3048b9f107708..ca3b54a5135a7993bf653b5158c228f617f5313f 100644 (file)
@@ -6260,6 +6260,7 @@ static int tclLoadStaticExtensionCmd(
 ){
   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*);
@@ -6275,6 +6276,7 @@ static int tclLoadStaticExtensionCmd(
   } 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                 },
diff --git a/test/misc8.test b/test/misc8.test
new file mode 100644 (file)
index 0000000..06ee314
--- /dev/null
@@ -0,0 +1,41 @@
+# 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