sqlite basics
This commit is contained in:
parent
c4b34ea22a
commit
2856f3f1d5
2
Makefile
2
Makefile
@ -13,7 +13,7 @@ endif
|
||||
CXXFLAGS += -Isource/ -Iobject/ -Isource/sqlfun/source/
|
||||
LDLIBS += $$(pkg-config --cflags --libs sqlite3 jansson)
|
||||
|
||||
SOURCE := main.cpp Database.cpp
|
||||
SOURCE := main.cpp Database.cpp Sqlite.cpp
|
||||
OBJECT := $(subst .cpp,.o,${SOURCE})
|
||||
SOURCE := $(addprefix source/,${SOURCE})
|
||||
OBJECT := $(addprefix object/,${OBJECT})
|
||||
|
176
source/Sqlite.cpp
Normal file
176
source/Sqlite.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
#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;
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
#ifndef EMBEDED_SQLITE_HPP
|
||||
#define EMBEDED_SQLITE_HPP
|
||||
#include "Database.hpp"
|
||||
|
||||
#include <vector>
|
||||
@ -18,62 +20,19 @@ class Sqlite : public Database {
|
||||
|
||||
std::vector<variable> variables = {};
|
||||
|
||||
char * connect(const char * const to, const char * const as) override {
|
||||
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 * top();
|
||||
|
||||
virtual char * disconnect() {
|
||||
char * r;
|
||||
const int a = asprintf(&r,
|
||||
"sqlite3_close(%s);\n",
|
||||
connection.c_str()
|
||||
);
|
||||
(void)a;
|
||||
return r;
|
||||
}
|
||||
char * connect(const char * const to, const char * const as);
|
||||
char * disconnect();
|
||||
|
||||
virtual char * declare(const char * const from) {
|
||||
return NULL;
|
||||
}
|
||||
void declare(const char * const type, const char * const name);
|
||||
void scope_push();
|
||||
void scope_pop();
|
||||
void scope_clear();
|
||||
|
||||
virtual void scope_push() {
|
||||
++scope;
|
||||
}
|
||||
virtual void scope_pop() {
|
||||
--scope;
|
||||
for(int i = variables.size()-1; i > -1; i--) {
|
||||
if (variables[i].scope > scope) {
|
||||
variables.erase(variables.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void scope_clear() {
|
||||
scope = 0;
|
||||
variables.clear();
|
||||
}
|
||||
char * exec(const char * const sql);
|
||||
|
||||
char * exec(const char * const sql) override {
|
||||
char * r;
|
||||
int v = validate(sql);
|
||||
if (v) {
|
||||
std::string e = std::string() + "Invalid SQL \'" + sql + '\'';
|
||||
esql_error(e.c_str());
|
||||
}
|
||||
const int a = asprintf(&r,
|
||||
"sqlite3_exec(%s, \"%s\", 0, 0, NULL);\n",
|
||||
connection.c_str(), sql
|
||||
);
|
||||
(void)a;
|
||||
return r;
|
||||
}
|
||||
std::string var_collect_and_placehold(const char * const sql, std::vector<variable*> &collection);
|
||||
std::string statement_to_format_string(const char * const sql, const std::vector<variable*> collection);
|
||||
};
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user