#include #include 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 \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 &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 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_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; }