esql/source/Sqlite.cpp
2024-05-30 14:28:44 +02:00

177 lines
4.4 KiB
C++

#include <Sqlite.hpp>
#include <string.h>
char * Sqlite::top() {
static const char * const r =
"/* This source file was generated with esql.\n"
" */\n"
"\n"
"/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,\n"
" They are private implementation details that can be changed or\n"
" removed. */\n"
"\n"
"#include <sqlite3.h>\n"
;
return (char*)r;
}
char * Sqlite::connect(const char * const to, const char * const as) {
char * r;
/* XXX: check for duplicates; check for not being open
*/
connection = as;
const int a = asprintf(&r,
"sqlite3 *%s;\n"
"sqlite3_open(\"%s\", &%s);\n",
as, to, as
);
(void)a;
return r;
}
char * Sqlite::disconnect() {
char * r;
const int a = asprintf(&r,
"sqlite3_close(%s);\n",
connection.c_str()
);
(void)a;
return r;
}
void Sqlite::declare(const char * const type, const char * const name) {
variables.push_back({name, type, scope});
}
void Sqlite::scope_push() {
++scope;
}
void Sqlite::scope_pop() {
--scope;
for(int i = variables.size()-1; i > -1; i--) {
if (variables[i].scope > scope) {
variables.erase(variables.begin() + i);
}
}
}
void Sqlite::scope_clear() {
scope = 0;
variables.clear();
}
static
size_t c_var_parser(const char * const s) {
size_t r = 0;
if (s[0] == '$'
|| (s[0] >= 'a' && s[0] <= 'z')
|| (s[0] >= 'A' && s[0] <= 'Z')) {
++r;
} else {
return 0;
}
for (const char * i = s+1; *i != '\0'; i++) {
if ((*i >= 'a' && *i <= 'z')
|| (*i >= 'A' && *i <= 'Z')
|| (*i >= '0' && *i <= '9')) {
++r;
} else {
break;
}
}
return r;
}
std::string Sqlite::var_collect_and_placehold(const char * const sql, std::vector<variable*> &collection) {
std::string r;
for (int i = 0; sql[i] != '\0'; i++) {
if (sql[i] == ':') {
++i;
std::string var(sql + i, c_var_parser(sql + i));
bool is_real_var = false;
for (auto&& i : variables) {
if (var == i.name) {
collection.push_back(&i);
is_real_var = true;
break;
}
}
if (not is_real_var) {
std::string e = std::string() + "No variable declared under the name '" + var + "'";
esql_error(e.c_str());
return "";
}
r += '?';
} else {
r += sql[i];
}
}
return r;
}
std::string Sqlite::statement_to_format_string(const char * const sql, const std::vector<variable*> collection) {
std::string r;
// XXX: what if there is a '?' in the sql to begin with?
struct { // XXX this table is horrible
const char * type_name;
const char * placeholder;
} placeholder_table[] = {
{"char", "%c"},
{"short", "%hd"},
{"int", "%d"},
{"long", "%ld"},
{"float", "%f"},
{"double", "%lf"},
{"void*", "%p"},
{"char*", "%s"},
};
auto lookup_placeholder = [&](const char* type_name) -> const char* {
for (const auto& entry : placeholder_table) {
if (not strcmp(entry.type_name, type_name)) {
return entry.placeholder;
}
}
return NULL;
};
int var_counter = 0;
for (const char * c = sql; *c != '\0'; c++) {
if (*c == '?') {
r += lookup_placeholder(collection[var_counter]->type.c_str());
} else {
r += *c;
}
}
return r;
}
char * Sqlite::exec(const char * const sql) {
char * r;
std::vector<variable*> variable_collection;
std::string sql_with_placeholders = var_collect_and_placehold(sql, variable_collection);
int v = validate(sql_with_placeholders.c_str());
if (v) {
std::string e = std::string() + "Invalid SQL \'" + sql + '\'';
esql_error(e.c_str());
return NULL;
}
if (not variable_collection.size()) {
asprintf(&r, "sqlite3_exec(%s, \"%s\", 0, 0, 0);",
this->connection.c_str(),
sql_with_placeholders.c_str()
);
} else {
std::string s =
"char * _esql_s;\n"
"asprintf(&_esql_s,"
;
s += ");";
}
return r;
}