mirror of
https://github.com/tursodatabase/libsql.git
synced 2025-05-20 12:38:12 +00:00
108 lines
3.2 KiB
C
108 lines
3.2 KiB
C
![]() |
// Created by by D. Richard Hipp, Public Domain
|
||
|
// https://www.sqlite.org/src/file/ext/misc/eval.c
|
||
|
|
||
|
// Modified by Anton Zhiyanov, MIT License
|
||
|
// https://github.com/nalgeon/sqlean/
|
||
|
|
||
|
// Evaluate dynamic SQL.
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "sqlite3ext.h"
|
||
|
SQLITE_EXTENSION_INIT3
|
||
|
|
||
|
/*
|
||
|
* Structure used to accumulate the output
|
||
|
*/
|
||
|
struct EvalResult {
|
||
|
char* z; /* Accumulated output */
|
||
|
const char* zSep; /* Separator */
|
||
|
int szSep; /* Size of the separator string */
|
||
|
sqlite3_int64 nAlloc; /* Number of bytes allocated for z[] */
|
||
|
sqlite3_int64 nUsed; /* Number of bytes of z[] actually used */
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Callback from sqlite_exec() for the eval() function.
|
||
|
*/
|
||
|
static int eval_callback(void* pCtx, int argc, char** argv, char** colnames) {
|
||
|
struct EvalResult* p = (struct EvalResult*)pCtx;
|
||
|
int i;
|
||
|
if (argv == 0) {
|
||
|
return SQLITE_OK;
|
||
|
}
|
||
|
for (i = 0; i < argc; i++) {
|
||
|
const char* z = argv[i] ? argv[i] : "";
|
||
|
size_t sz = strlen(z);
|
||
|
if ((sqlite3_int64)sz + p->nUsed + p->szSep + 1 > p->nAlloc) {
|
||
|
char* zNew;
|
||
|
p->nAlloc = p->nAlloc * 2 + sz + p->szSep + 1;
|
||
|
/* Using sqlite3_realloc64() would be better, but it is a recent
|
||
|
** addition and will cause a segfault if loaded by an older version
|
||
|
** of SQLite. */
|
||
|
zNew = p->nAlloc <= 0x7fffffff ? sqlite3_realloc64(p->z, p->nAlloc) : 0;
|
||
|
if (zNew == 0) {
|
||
|
sqlite3_free(p->z);
|
||
|
memset(p, 0, sizeof(*p));
|
||
|
return SQLITE_NOMEM;
|
||
|
}
|
||
|
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 SQLITE_OK;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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 define_eval(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, eval_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, (int)x.nUsed, sqlite3_free);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int define_eval_init(sqlite3* db) {
|
||
|
const int flags = SQLITE_UTF8 | SQLITE_DIRECTONLY;
|
||
|
sqlite3_create_function(db, "eval", 1, flags, NULL, define_eval, NULL, NULL);
|
||
|
sqlite3_create_function(db, "eval", 2, flags, NULL, define_eval, NULL, NULL);
|
||
|
return SQLITE_OK;
|
||
|
}
|