added mysql backend
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
#include "mysql_connection.hpp"
|
||||
#include "mysql_error.hpp"
|
||||
#include "mysql_result_reader.hpp"
|
||||
#include "mysql_statement.hpp"
|
||||
|
||||
#include "matador/sql/record.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
mysql_connection::string_to_int_map mysql_connection::statement_name_map_{};
|
||||
|
||||
mysql_connection::mysql_connection(const sql::connection_info &info)
|
||||
: connection_impl(info) {}
|
||||
|
||||
void mysql_connection::open()
|
||||
{
|
||||
if (is_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mysql_ = std::make_unique<MYSQL>();
|
||||
|
||||
if (!mysql_init(mysql_.get())) {
|
||||
throw_mysql_error(mysql_.get(), "mysql_init");
|
||||
}
|
||||
|
||||
if (!mysql_real_connect(mysql_.get(),
|
||||
info().hostname.c_str(),
|
||||
info().user.c_str(),
|
||||
!info().password.empty() ? info().password.c_str() : nullptr,
|
||||
info().database.c_str(),
|
||||
info().port,
|
||||
nullptr,
|
||||
0)) {
|
||||
// disconnect all handles
|
||||
const std::string error_message = mysql_error(mysql_.get());
|
||||
mysql_close(mysql_.get());
|
||||
|
||||
mysql_.reset();
|
||||
// throw exception
|
||||
throw_mysql_error(error_message.c_str(), "mysql_real_connect");
|
||||
}
|
||||
}
|
||||
|
||||
void mysql_connection::close()
|
||||
{
|
||||
if (mysql_) {
|
||||
mysql_close(mysql_.get());
|
||||
mysql_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool mysql_connection::is_open()
|
||||
{
|
||||
return mysql_ != nullptr;
|
||||
}
|
||||
|
||||
sql::data_type_t to_type(enum_field_types type, unsigned int flags)
|
||||
{
|
||||
switch (type) {
|
||||
case MYSQL_TYPE_TINY:
|
||||
return flags & UNSIGNED_FLAG ? sql::data_type_t::type_unsigned_char : sql::data_type_t::type_char;
|
||||
case MYSQL_TYPE_SHORT:
|
||||
return flags & UNSIGNED_FLAG ? sql::data_type_t::type_unsigned_short : sql::data_type_t::type_short;
|
||||
case MYSQL_TYPE_LONG:
|
||||
return flags & UNSIGNED_FLAG ? sql::data_type_t::type_unsigned_int : sql::data_type_t::type_int;
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
return flags & UNSIGNED_FLAG ? sql::data_type_t::type_unsigned_long_long : sql::data_type_t::type_long_long;
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
return sql::data_type_t::type_float;
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
return sql::data_type_t::type_double;
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
return sql::data_type_t::type_varchar;
|
||||
case MYSQL_TYPE_BLOB:
|
||||
return sql::data_type_t::type_blob;
|
||||
case MYSQL_TYPE_STRING:
|
||||
return sql::data_type_t::type_text;
|
||||
case MYSQL_TYPE_DATE:
|
||||
return sql::data_type_t::type_date;
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
return sql::data_type_t::type_time;
|
||||
default:
|
||||
return sql::data_type_t::type_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
utils::constraints to_options(unsigned int flags)
|
||||
{
|
||||
utils::constraints options{utils::constraints::NONE};
|
||||
if (flags & NOT_NULL_FLAG) {
|
||||
options |= utils::constraints::NOT_NULL;
|
||||
}
|
||||
if (flags & PRI_KEY_FLAG) {
|
||||
options |= utils::constraints::PRIMARY_KEY;
|
||||
}
|
||||
if (flags & UNIQUE_KEY_FLAG) {
|
||||
options |= utils::constraints::UNIQUE;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
sql::data_type_t string2type(const std::string &type_string)
|
||||
{
|
||||
// if (strcmp(type_string.c_str(), "int")
|
||||
return sql::data_type_t::type_unknown;
|
||||
}
|
||||
|
||||
struct type_info
|
||||
{
|
||||
sql::data_type_t type{sql::data_type_t::type_unknown};
|
||||
size_t size{};
|
||||
};
|
||||
|
||||
type_info determine_type_info(const std::string &type_string)
|
||||
{
|
||||
static const std::regex TYPE_REGEX(R"(^(\w+)(\((\d+)(,(\d+))?\))?$)");
|
||||
std::smatch matcher;
|
||||
|
||||
type_info result;
|
||||
if (std::regex_match(type_string, matcher, TYPE_REGEX)) {
|
||||
result.type = string2type(matcher[1].str());
|
||||
if (matcher[3].matched) {
|
||||
result.size = std::stoi(matcher[3].str());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<sql::query_result_impl> mysql_connection::fetch(const std::string &stmt)
|
||||
{
|
||||
if (mysql_query(mysql_.get(), stmt.c_str())) {
|
||||
throw_mysql_error(mysql_.get(), stmt);
|
||||
}
|
||||
|
||||
auto result = mysql_store_result(mysql_.get());
|
||||
if (result == nullptr) {
|
||||
throw_mysql_error(mysql_.get(), stmt);
|
||||
}
|
||||
|
||||
auto field_count = mysql_num_fields(result);
|
||||
auto fields = mysql_fetch_fields(result);
|
||||
sql::record prototype;
|
||||
for (unsigned i = 0; i < field_count; ++i) {
|
||||
auto type = to_type(fields[i].type, fields[i].flags);
|
||||
auto options = to_options(fields[i].flags);
|
||||
|
||||
prototype.append({fields[i].name, type, options});
|
||||
}
|
||||
|
||||
return std::move(std::make_unique<sql::query_result_impl>(std::make_unique<mysql_result_reader>(result, field_count), std::move(prototype)));
|
||||
}
|
||||
|
||||
std::unique_ptr<sql::statement_impl> mysql_connection::prepare(sql::query_context context)
|
||||
{
|
||||
MYSQL_STMT *stmt = mysql_stmt_init(mysql_.get());
|
||||
if (stmt == nullptr) {
|
||||
throw_mysql_error(mysql_.get(), "mysql_stmt_init");
|
||||
}
|
||||
|
||||
if (mysql_stmt_prepare(stmt, context.sql.c_str(), static_cast<unsigned long>(context.sql.size())) != 0) {
|
||||
throw_mysql_error(stmt, "mysql_stmt_prepare", context.sql);
|
||||
}
|
||||
|
||||
return std::make_unique<mysql_statement>(stmt, std::move(context));
|
||||
}
|
||||
|
||||
size_t mysql_connection::execute(const std::string &stmt)
|
||||
{
|
||||
if (mysql_query(mysql_.get(), stmt.c_str())) {
|
||||
throw_mysql_error(mysql_.get(), stmt);
|
||||
}
|
||||
|
||||
return mysql_affected_rows(mysql_.get());
|
||||
}
|
||||
|
||||
sql::record mysql_connection::describe(const std::string &table)
|
||||
{
|
||||
std::string stmt("SHOW COLUMNS FROM " + table);
|
||||
|
||||
if (mysql_query(mysql_.get(), stmt.c_str())) {
|
||||
throw_mysql_error(mysql_.get(), stmt);
|
||||
}
|
||||
|
||||
auto result = mysql_store_result(mysql_.get());
|
||||
if (result == nullptr) {
|
||||
throw_mysql_error(mysql_.get(), stmt);
|
||||
}
|
||||
|
||||
mysql_result_reader reader(result, mysql_num_fields(result));
|
||||
sql::record prototype;
|
||||
while (reader.fetch()) {
|
||||
|
||||
char *end = nullptr;
|
||||
// Todo: Handle error
|
||||
auto index = strtoul(reader.column(0), &end, 10);
|
||||
std::string name = reader.column(1);
|
||||
|
||||
// Todo: extract size
|
||||
auto typeinfo = determine_type_info(reader.column(2));
|
||||
end = nullptr;
|
||||
utils::constraints options{};
|
||||
if (strtoul(reader.column(4), &end, 10) == 0) {
|
||||
options = utils::constraints::NOT_NULL;
|
||||
}
|
||||
// f.default_value(res->column(4));
|
||||
prototype.append({name, typeinfo.type, {typeinfo.size, options}});
|
||||
}
|
||||
|
||||
return prototype;
|
||||
}
|
||||
|
||||
bool mysql_connection::exists(const std::string &/*schema_name*/, const std::string &table_name)
|
||||
{
|
||||
std::string stmt("SELECT 1 FROM information_schema.tables WHERE table_schema = '" + info().database + "' AND table_name = '" + table_name + "'");
|
||||
|
||||
if (mysql_query(mysql_.get(), stmt.c_str())) {
|
||||
throw_mysql_error(mysql_.get(), stmt);
|
||||
}
|
||||
|
||||
auto result = mysql_store_result(mysql_.get());
|
||||
if (result == nullptr) {
|
||||
throw_mysql_error(mysql_.get(), stmt);
|
||||
}
|
||||
|
||||
return result->row_count == 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
MATADOR_MYSQL_API matador::sql::connection_impl *create_database(const matador::sql::connection_info &info)
|
||||
{
|
||||
return new matador::backends::mysql::mysql_connection(info);
|
||||
}
|
||||
|
||||
MATADOR_MYSQL_API void destroy_database(matador::sql::connection_impl *db)
|
||||
{
|
||||
delete db;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "mysql_dialect.hpp"
|
||||
|
||||
#include "matador/sql/dialect_builder.hpp"
|
||||
|
||||
[[maybe_unused]] const matador::sql::dialect *get_dialect()
|
||||
{
|
||||
using namespace matador::sql;
|
||||
const static dialect d = dialect_builder::builder()
|
||||
.create()
|
||||
.with_placeholder_func([](size_t index) {
|
||||
return "$" + std::to_string(index);
|
||||
})
|
||||
.with_token_replace_map({
|
||||
{dialect::token_t::START_QUOTE, "`"},
|
||||
{dialect::token_t::END_QUOTE, "`"},
|
||||
})
|
||||
.with_default_schema_name("public")
|
||||
.build();
|
||||
return &d;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "mysql_error.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
void throw_mysql_error(const char *what, const std::string &source)
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "mysql error (" << source << "): " << what;
|
||||
throw std::logic_error(msg.str());
|
||||
}
|
||||
|
||||
void throw_mysql_error(MYSQL *db, const std::string &source)
|
||||
{
|
||||
if (mysql_errno(db) != 0) {
|
||||
throw_mysql_error(mysql_error(db), source);
|
||||
}
|
||||
}
|
||||
|
||||
void throw_mysql_error(MYSQL_STMT *stmt, const std::string &source, const std::string &sql)
|
||||
{
|
||||
if (mysql_stmt_errno(stmt) != 0) {
|
||||
std::stringstream msg;
|
||||
msg << "mysql error (" << source << ") " << mysql_stmt_error(stmt) << ": " << sql;
|
||||
throw std::logic_error(msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
#include "mysql_parameter_binder.hpp"
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template < class T >
|
||||
void bind_value(enum_field_types type, T value, MYSQL_BIND &bind, my_bool &is_null)
|
||||
{
|
||||
if (bind.buffer == nullptr) {
|
||||
// allocating memory
|
||||
bind.buffer = new char[sizeof(T)];
|
||||
bind.buffer_type = type;
|
||||
bind.buffer_length = sizeof(T);
|
||||
bind.is_null = &is_null;
|
||||
bind.is_unsigned = std::is_unsigned<T>::value;
|
||||
}
|
||||
*static_cast<T*>(bind.buffer) = value;
|
||||
is_null = false;
|
||||
}
|
||||
|
||||
void bind_value(enum_field_types type, const char *value, size_t, MYSQL_BIND &bind, my_bool &is_null)
|
||||
{
|
||||
std::size_t len(strlen(value) + 1);
|
||||
if (bind.buffer_length < len) {
|
||||
// reallocate memory
|
||||
delete [] static_cast<char*>(bind.buffer);
|
||||
bind.buffer = nullptr;
|
||||
bind.buffer_length = 0;
|
||||
bind.buffer_type = type;
|
||||
bind.is_null = &is_null;
|
||||
}
|
||||
if (bind.buffer == nullptr) {
|
||||
// allocating memory
|
||||
bind.buffer = new char[len];
|
||||
memset(bind.buffer, 0, len);
|
||||
}
|
||||
bind.buffer_length = (unsigned long)(len - 1);
|
||||
#ifdef _MSC_VER
|
||||
strncpy_s(static_cast<char*>(bind.buffer), len, value, _TRUNCATE);
|
||||
#else
|
||||
strncpy(static_cast<char*>(bind.buffer), value, len);
|
||||
#endif
|
||||
is_null = false;
|
||||
}
|
||||
|
||||
//void bind_value(enum_field_types type, const matador::date &x, MYSQL_BIND &bind, my_bool &is_null)
|
||||
//{
|
||||
// if (bind.buffer == nullptr) {
|
||||
// size_t s = sizeof(MYSQL_TIME);
|
||||
// bind.buffer = new char[s];
|
||||
// bind.buffer_length = (unsigned long)s;
|
||||
// bind.is_null = &is_null;
|
||||
// bind.buffer_type = type;
|
||||
// bind.length = nullptr;
|
||||
// }
|
||||
// memset(bind.buffer, 0, sizeof(MYSQL_TIME));
|
||||
// is_null = false;
|
||||
// auto *mt = static_cast<MYSQL_TIME*>(bind.buffer);
|
||||
// mt->day = (unsigned int)x.day();
|
||||
// mt->month = (unsigned int)x.month();
|
||||
// mt->year = (unsigned int)x.year();
|
||||
// mt->time_type = MYSQL_TIMESTAMP_DATE;
|
||||
//}
|
||||
//
|
||||
//void bind_value(enum_field_types type, const matador::time &x, MYSQL_BIND &bind, my_bool &is_null)
|
||||
//{
|
||||
// if (bind.buffer == nullptr) {
|
||||
// size_t s = sizeof(MYSQL_TIME);
|
||||
// bind.buffer = new char[s];
|
||||
// bind.buffer_length = (unsigned long)s;
|
||||
// bind.buffer_type = type;
|
||||
// bind.length = nullptr;
|
||||
// bind.is_null = &is_null;
|
||||
// }
|
||||
// memset(bind.buffer, 0, sizeof(MYSQL_TIME));
|
||||
// is_null = false;
|
||||
// auto *mt = static_cast<MYSQL_TIME*>(bind.buffer);
|
||||
// mt->day = (unsigned int)x.day();
|
||||
// mt->month = (unsigned int)x.month();
|
||||
// mt->year = (unsigned int)x.year();
|
||||
// mt->hour = (unsigned int)x.hour();
|
||||
// mt->minute = (unsigned int)x.minute();
|
||||
// mt->second = (unsigned int)x.second();
|
||||
// mt->second_part = (unsigned long)x.milli_second() * 1000;
|
||||
// mt->time_type = MYSQL_TIMESTAMP_DATETIME;
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
mysql_parameter_binder::mysql_parameter_binder(size_t size)
|
||||
: bind_params_(size)
|
||||
, info_(size)
|
||||
{}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, char i)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_TINY, i, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, short i)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_SHORT, i, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, int i)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_LONG, i, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, long i)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_LONG, i, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, long long int i)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_LONGLONG, i, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, unsigned char i)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_TINY, i, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, unsigned short i)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_SHORT, i, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, unsigned int i)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_LONG, i, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, unsigned long i)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_LONG, i, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, unsigned long long int i)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_LONGLONG, i, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, bool b)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_TINY, b, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, float d)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_FLOAT, d, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, double d)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_DOUBLE, d, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, const char *str)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_STRING, str, strlen(str), bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, const char *str, size_t size)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_VAR_STRING, str, size, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, const std::string &str)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_STRING, str.data(), str.size(), bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
void mysql_parameter_binder::bind(size_t pos, const std::string &str, size_t size)
|
||||
{
|
||||
detail::bind_value(MYSQL_TYPE_VAR_STRING, str.data(), size, bind_params_[pos], is_null_vector[pos].is_null);
|
||||
}
|
||||
|
||||
std::vector<MYSQL_BIND> &mysql_parameter_binder::bind_params()
|
||||
{
|
||||
return bind_params_;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "mysql_prepared_result_reader.hpp"
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
mysql_prepared_result_reader::mysql_prepared_result_reader(MYSQL_STMT *stmt)
|
||||
: stmt_(stmt)
|
||||
{}
|
||||
|
||||
mysql_prepared_result_reader::~mysql_prepared_result_reader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
size_t mysql_prepared_result_reader::column_count() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *mysql_prepared_result_reader::column(size_t index) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool mysql_prepared_result_reader::fetch()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "mysql_result_reader.hpp"
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
mysql_result_reader::mysql_result_reader(MYSQL_RES *result, unsigned int column_count)
|
||||
: result_(result)
|
||||
, row_count_(mysql_num_rows(result_))
|
||||
, column_count_(column_count)
|
||||
{}
|
||||
|
||||
mysql_result_reader::~mysql_result_reader()
|
||||
{
|
||||
if (result_) {
|
||||
mysql_free_result(result_);
|
||||
}
|
||||
}
|
||||
|
||||
size_t mysql_result_reader::column_count() const
|
||||
{
|
||||
return column_count_;
|
||||
}
|
||||
|
||||
const char *mysql_result_reader::column(size_t index) const
|
||||
{
|
||||
return current_row_[index];
|
||||
}
|
||||
|
||||
bool mysql_result_reader::fetch()
|
||||
{
|
||||
current_row_ = mysql_fetch_row(result_);
|
||||
|
||||
return current_row_ != nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "mysql_statement.hpp"
|
||||
#include "mysql_error.hpp"
|
||||
#include "mysql_prepared_result_reader.hpp"
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
mysql_statement::mysql_statement(MYSQL_STMT *stmt, const sql::query_context &query)
|
||||
: statement_impl(query)
|
||||
, stmt_(stmt)
|
||||
, binder_(query_.bind_vars.size())
|
||||
{}
|
||||
|
||||
size_t mysql_statement::execute()
|
||||
{
|
||||
if (!binder_.bind_params().empty()) {
|
||||
if (mysql_stmt_bind_param(stmt_, binder_.bind_params().data()) != 0) {
|
||||
throw_mysql_error(stmt_, "mysql", query_.sql);
|
||||
}
|
||||
}
|
||||
|
||||
if (mysql_stmt_execute(stmt_) != 0) {
|
||||
throw_mysql_error(stmt_, "mysql", query_.sql);
|
||||
}
|
||||
|
||||
return mysql_stmt_affected_rows(stmt_);
|
||||
}
|
||||
|
||||
std::unique_ptr<sql::query_result_impl> mysql_statement::fetch()
|
||||
{
|
||||
if (!binder_.bind_params().empty()) {
|
||||
if (mysql_stmt_bind_param(stmt_, binder_.bind_params().data()) != 0) {
|
||||
throw_mysql_error(stmt_, "mysql", query_.sql);
|
||||
}
|
||||
}
|
||||
|
||||
if (mysql_stmt_execute(stmt_) != 0) {
|
||||
throw_mysql_error(stmt_, "mysql", query_.sql);
|
||||
}
|
||||
if (mysql_stmt_store_result(stmt_) != 0) {
|
||||
throw_mysql_error(stmt_, "mysql", query_.sql);
|
||||
}
|
||||
|
||||
return std::move(std::make_unique<sql::query_result_impl>(std::make_unique<mysql_prepared_result_reader>(stmt_), std::move(query_.prototype)));
|
||||
}
|
||||
|
||||
void mysql_statement::reset() {}
|
||||
|
||||
sql::parameter_binder& mysql_statement::binder()
|
||||
{
|
||||
return binder_;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user