228 lines
8.7 KiB
C++
228 lines
8.7 KiB
C++
#pragma once
|
|
|
|
#include <sqlite3.h>
|
|
#include <string> // std::string
|
|
#include <functional> // std::function
|
|
#include <memory> // std::shared_ptr
|
|
#include <vector> // std::vector
|
|
#include <sstream>
|
|
|
|
#include "error_code.h"
|
|
#include "row_extractor.h"
|
|
#include "journal_mode.h"
|
|
#include "connection_holder.h"
|
|
#include "util.h"
|
|
#include "serializing_util.h"
|
|
|
|
namespace sqlite_orm {
|
|
|
|
namespace internal {
|
|
struct storage_base;
|
|
|
|
template<class T>
|
|
int getPragmaCallback(void* data, int argc, char** argv, char** x) {
|
|
return extract_single_value<T>(data, argc, argv, x);
|
|
}
|
|
|
|
template<>
|
|
inline int getPragmaCallback<std::vector<std::string>>(void* data, int argc, char** argv, char**) {
|
|
auto& res = *(std::vector<std::string>*)data;
|
|
res.reserve(argc);
|
|
for(decltype(argc) i = 0; i < argc; ++i) {
|
|
auto rowString = row_extractor<std::string>().extract(argv[i]);
|
|
res.push_back(std::move(rowString));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
struct pragma_t {
|
|
using get_connection_t = std::function<internal::connection_ref()>;
|
|
|
|
pragma_t(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {}
|
|
|
|
void busy_timeout(int value) {
|
|
this->set_pragma("busy_timeout", value);
|
|
}
|
|
|
|
int busy_timeout() {
|
|
return this->get_pragma<int>("busy_timeout");
|
|
}
|
|
|
|
sqlite_orm::journal_mode journal_mode() {
|
|
return this->get_pragma<sqlite_orm::journal_mode>("journal_mode");
|
|
}
|
|
|
|
void journal_mode(sqlite_orm::journal_mode value) {
|
|
this->_journal_mode = -1;
|
|
this->set_pragma("journal_mode", value);
|
|
this->_journal_mode = static_cast<decltype(this->_journal_mode)>(value);
|
|
}
|
|
|
|
/**
|
|
* https://www.sqlite.org/pragma.html#pragma_application_id
|
|
*/
|
|
int application_id() {
|
|
return this->get_pragma<int>("application_id");
|
|
}
|
|
|
|
/**
|
|
* https://www.sqlite.org/pragma.html#pragma_application_id
|
|
*/
|
|
void application_id(int value) {
|
|
this->set_pragma("application_id", value);
|
|
}
|
|
|
|
int synchronous() {
|
|
return this->get_pragma<int>("synchronous");
|
|
}
|
|
|
|
void synchronous(int value) {
|
|
this->_synchronous = -1;
|
|
this->set_pragma("synchronous", value);
|
|
this->_synchronous = value;
|
|
}
|
|
|
|
int user_version() {
|
|
return this->get_pragma<int>("user_version");
|
|
}
|
|
|
|
void user_version(int value) {
|
|
this->set_pragma("user_version", value);
|
|
}
|
|
|
|
int auto_vacuum() {
|
|
return this->get_pragma<int>("auto_vacuum");
|
|
}
|
|
|
|
void auto_vacuum(int value) {
|
|
this->set_pragma("auto_vacuum", value);
|
|
}
|
|
|
|
std::vector<std::string> integrity_check() {
|
|
return this->get_pragma<std::vector<std::string>>("integrity_check");
|
|
}
|
|
|
|
template<class T>
|
|
std::vector<std::string> integrity_check(T table_name) {
|
|
std::ostringstream ss;
|
|
ss << "integrity_check(" << table_name << ")" << std::flush;
|
|
return this->get_pragma<std::vector<std::string>>(ss.str());
|
|
}
|
|
|
|
std::vector<std::string> integrity_check(int n) {
|
|
std::ostringstream ss;
|
|
ss << "integrity_check(" << n << ")" << std::flush;
|
|
return this->get_pragma<std::vector<std::string>>(ss.str());
|
|
}
|
|
|
|
// will include generated columns in response as opposed to table_info
|
|
std::vector<sqlite_orm::table_xinfo> table_xinfo(const std::string& tableName) const {
|
|
auto connection = this->get_connection();
|
|
|
|
std::vector<sqlite_orm::table_xinfo> result;
|
|
std::ostringstream ss;
|
|
ss << "PRAGMA "
|
|
"table_xinfo("
|
|
<< streaming_identifier(tableName) << ")" << std::flush;
|
|
perform_exec(
|
|
connection.get(),
|
|
ss.str(),
|
|
[](void* data, int argc, char** argv, char**) -> int {
|
|
auto& res = *(std::vector<sqlite_orm::table_xinfo>*)data;
|
|
if(argc) {
|
|
auto index = 0;
|
|
auto cid = std::atoi(argv[index++]);
|
|
std::string name = argv[index++];
|
|
std::string type = argv[index++];
|
|
bool notnull = !!std::atoi(argv[index++]);
|
|
std::string dflt_value = argv[index] ? argv[index] : "";
|
|
++index;
|
|
auto pk = std::atoi(argv[index++]);
|
|
auto hidden = std::atoi(argv[index++]);
|
|
res.emplace_back(cid,
|
|
std::move(name),
|
|
std::move(type),
|
|
notnull,
|
|
std::move(dflt_value),
|
|
pk,
|
|
hidden);
|
|
}
|
|
return 0;
|
|
},
|
|
&result);
|
|
return result;
|
|
}
|
|
|
|
std::vector<sqlite_orm::table_info> table_info(const std::string& tableName) const {
|
|
auto connection = this->get_connection();
|
|
|
|
std::ostringstream ss;
|
|
ss << "PRAGMA "
|
|
"table_info("
|
|
<< streaming_identifier(tableName) << ")" << std::flush;
|
|
std::vector<sqlite_orm::table_info> result;
|
|
perform_exec(
|
|
connection.get(),
|
|
ss.str(),
|
|
[](void* data, int argc, char** argv, char**) -> int {
|
|
auto& res = *(std::vector<sqlite_orm::table_info>*)data;
|
|
if(argc) {
|
|
auto index = 0;
|
|
auto cid = std::atoi(argv[index++]);
|
|
std::string name = argv[index++];
|
|
std::string type = argv[index++];
|
|
bool notnull = !!std::atoi(argv[index++]);
|
|
std::string dflt_value = argv[index] ? argv[index] : "";
|
|
++index;
|
|
auto pk = std::atoi(argv[index++]);
|
|
res.emplace_back(cid, std::move(name), std::move(type), notnull, std::move(dflt_value), pk);
|
|
}
|
|
return 0;
|
|
},
|
|
&result);
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
friend struct storage_base;
|
|
|
|
int _synchronous = -1;
|
|
signed char _journal_mode = -1; // if != -1 stores static_cast<sqlite_orm::journal_mode>(journal_mode)
|
|
get_connection_t get_connection;
|
|
|
|
template<class T>
|
|
T get_pragma(const std::string& name) {
|
|
auto connection = this->get_connection();
|
|
T result;
|
|
perform_exec(connection.get(), "PRAGMA " + name, getPragmaCallback<T>, &result);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Yevgeniy Zakharov: I wanted to refactor this function with statements and value bindings
|
|
* but it turns out that bindings in pragma statements are not supported.
|
|
*/
|
|
template<class T>
|
|
void set_pragma(const std::string& name, const T& value, sqlite3* db = nullptr) {
|
|
auto con = this->get_connection();
|
|
if(!db) {
|
|
db = con.get();
|
|
}
|
|
std::stringstream ss;
|
|
ss << "PRAGMA " << name << " = " << value << std::flush;
|
|
perform_void_exec(db, ss.str());
|
|
}
|
|
|
|
void set_pragma(const std::string& name, const sqlite_orm::journal_mode& value, sqlite3* db = nullptr) {
|
|
auto con = this->get_connection();
|
|
if(!db) {
|
|
db = con.get();
|
|
}
|
|
std::stringstream ss;
|
|
ss << "PRAGMA " << name << " = " << to_string(value) << std::flush;
|
|
perform_void_exec(db, ss.str());
|
|
}
|
|
};
|
|
}
|
|
}
|