131 lines
4.3 KiB
C++
131 lines
4.3 KiB
C++
#pragma once
|
|
|
|
#include <sqlite3.h>
|
|
#include <string> // std::string
|
|
#include <utility> // 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<int expected = SQLITE_DONE>
|
|
void perform_step(sqlite3_stmt* stmt) {
|
|
int rc = sqlite3_step(stmt);
|
|
if(rc != expected) {
|
|
throw_translated_sqlite_error(stmt);
|
|
}
|
|
}
|
|
|
|
template<class L>
|
|
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<class L>
|
|
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);
|
|
}
|
|
}
|
|
}
|