#pragma once #include #include // std::string #include // std::move #include "error_code.h" namespace sqlite_orm { /** * Escape the provided character in the given string by doubling it. * @param str A copy of the original string * @param char2Escape The character to escape */ inline std::string sql_escape(std::string str, char char2Escape) { for(size_t pos = 0; (pos = str.find(char2Escape, pos)) != str.npos; pos += 2) { str.replace(pos, 1, 2, char2Escape); } return str; } /** * Quote the given string value using single quotes, * escape containing single quotes by doubling them. */ inline std::string quote_string_literal(std::string v) { constexpr char quoteChar = '\''; return quoteChar + sql_escape(std::move(v), quoteChar) + quoteChar; } /** * Quote the given string value using single quotes, * escape containing single quotes by doubling them. */ inline std::string quote_blob_literal(std::string v) { constexpr char quoteChar = '\''; return std::string{char('x'), quoteChar} + std::move(v) + quoteChar; } /** * Quote the given identifier using double quotes, * escape containing double quotes by doubling them. */ inline std::string quote_identifier(std::string identifier) { constexpr char quoteChar = '"'; return quoteChar + sql_escape(std::move(identifier), quoteChar) + quoteChar; } namespace internal { // Wrapper to reduce boiler-plate code inline sqlite3_stmt* reset_stmt(sqlite3_stmt* stmt) { sqlite3_reset(stmt); return stmt; } // note: query is deliberately taken by value, such that it is thrown away early inline sqlite3_stmt* prepare_stmt(sqlite3* db, std::string query) { sqlite3_stmt* stmt; if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { throw_translated_sqlite_error(db); } return stmt; } inline void perform_void_exec(sqlite3* db, const std::string& query) { int rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr); if(rc != SQLITE_OK) { throw_translated_sqlite_error(db); } } inline void perform_exec(sqlite3* db, const char* query, int (*callback)(void* data, int argc, char** argv, char**), void* user_data) { int rc = sqlite3_exec(db, query, callback, user_data, nullptr); if(rc != SQLITE_OK) { throw_translated_sqlite_error(db); } } inline void perform_exec(sqlite3* db, const std::string& query, int (*callback)(void* data, int argc, char** argv, char**), void* user_data) { return perform_exec(db, query.c_str(), callback, user_data); } template void perform_step(sqlite3_stmt* stmt) { int rc = sqlite3_step(stmt); if(rc != expected) { throw_translated_sqlite_error(stmt); } } template void perform_step(sqlite3_stmt* stmt, L&& lambda) { switch(int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; case SQLITE_DONE: break; default: { throw_translated_sqlite_error(stmt); } } } template void perform_steps(sqlite3_stmt* stmt, L&& lambda) { int rc; do { switch(rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; case SQLITE_DONE: break; default: { throw_translated_sqlite_error(stmt); } } } while(rc != SQLITE_DONE); } } }