xref: /sqlite-3.40.0/ext/misc/eval.c (revision 2b1c2aad)
1 /*
2 ** 2014-11-10
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 ******************************************************************************
12 **
13 ** This SQLite extension implements SQL function eval() which runs
14 ** SQL statements recursively.
15 */
16 #include "sqlite3ext.h"
17 SQLITE_EXTENSION_INIT1
18 #include <string.h>
19 
20 /*
21 ** Structure used to accumulate the output
22 */
23 struct EvalResult {
24   char *z;               /* Accumulated output */
25   const char *zSep;      /* Separator */
26   int szSep;             /* Size of the separator string */
27   sqlite3_int64 nAlloc;  /* Number of bytes allocated for z[] */
28   sqlite3_int64 nUsed;   /* Number of bytes of z[] actually used */
29 };
30 
31 /*
32 ** Callback from sqlite_exec() for the eval() function.
33 */
callback(void * pCtx,int argc,char ** argv,char ** colnames)34 static int callback(void *pCtx, int argc, char **argv, char **colnames){
35   struct EvalResult *p = (struct EvalResult*)pCtx;
36   int i;
37   if( argv==0 ) return 0;
38   for(i=0; i<argc; i++){
39     const char *z = argv[i] ? argv[i] : "";
40     size_t sz = strlen(z);
41     if( (sqlite3_int64)sz+p->nUsed+p->szSep+1 > p->nAlloc ){
42       char *zNew;
43       p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1;
44       /* Using sqlite3_realloc64() would be better, but it is a recent
45       ** addition and will cause a segfault if loaded by an older version
46       ** of SQLite.  */
47       zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc64(p->z, p->nAlloc) : 0;
48       if( zNew==0 ){
49         sqlite3_free(p->z);
50         memset(p, 0, sizeof(*p));
51         return 1;
52       }
53       p->z = zNew;
54     }
55     if( p->nUsed>0 ){
56       memcpy(&p->z[p->nUsed], p->zSep, p->szSep);
57       p->nUsed += p->szSep;
58     }
59     memcpy(&p->z[p->nUsed], z, sz);
60     p->nUsed += sz;
61   }
62   return 0;
63 }
64 
65 /*
66 ** Implementation of the eval(X) and eval(X,Y) SQL functions.
67 **
68 ** Evaluate the SQL text in X.  Return the results, using string
69 ** Y as the separator.  If Y is omitted, use a single space character.
70 */
sqlEvalFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)71 static void sqlEvalFunc(
72   sqlite3_context *context,
73   int argc,
74   sqlite3_value **argv
75 ){
76   const char *zSql;
77   sqlite3 *db;
78   char *zErr = 0;
79   int rc;
80   struct EvalResult x;
81 
82   memset(&x, 0, sizeof(x));
83   x.zSep = " ";
84   zSql = (const char*)sqlite3_value_text(argv[0]);
85   if( zSql==0 ) return;
86   if( argc>1 ){
87     x.zSep = (const char*)sqlite3_value_text(argv[1]);
88     if( x.zSep==0 ) return;
89   }
90   x.szSep = (int)strlen(x.zSep);
91   db = sqlite3_context_db_handle(context);
92   rc = sqlite3_exec(db, zSql, callback, &x, &zErr);
93   if( rc!=SQLITE_OK ){
94     sqlite3_result_error(context, zErr, -1);
95     sqlite3_free(zErr);
96   }else if( x.zSep==0 ){
97     sqlite3_result_error_nomem(context);
98     sqlite3_free(x.z);
99   }else{
100     sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free);
101   }
102 }
103 
104 
105 #ifdef _WIN32
106 __declspec(dllexport)
107 #endif
sqlite3_eval_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)108 int sqlite3_eval_init(
109   sqlite3 *db,
110   char **pzErrMsg,
111   const sqlite3_api_routines *pApi
112 ){
113   int rc = SQLITE_OK;
114   SQLITE_EXTENSION_INIT2(pApi);
115   (void)pzErrMsg;  /* Unused parameter */
116   rc = sqlite3_create_function(db, "eval", 1,
117                                SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
118                                sqlEvalFunc, 0, 0);
119   if( rc==SQLITE_OK ){
120     rc = sqlite3_create_function(db, "eval", 2,
121                                  SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
122                                  sqlEvalFunc, 0, 0);
123   }
124   return rc;
125 }
126