added mysql backend
This commit is contained in:
parent
2893f749b6
commit
320d06bb20
|
|
@ -1,2 +1,3 @@
|
|||
add_subdirectory(sqlite)
|
||||
add_subdirectory(postgres)
|
||||
add_subdirectory(postgres)
|
||||
add_subdirectory(mysql)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
set(HEADER
|
||||
include/mysql_connection.hpp
|
||||
include/mysql_error.hpp
|
||||
include/mysql_result_reader.hpp
|
||||
include/mysql_dialect.hpp
|
||||
include/mysql_statement.hpp
|
||||
include/mysql_parameter_binder.hpp
|
||||
include/mysql_prepared_result_reader.hpp
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
src/mysql_connection.cpp
|
||||
src/mysql_error.cpp
|
||||
src/mysql_result_reader.cpp
|
||||
src/mysql_dialect.cpp
|
||||
src/mysql_statement.cpp
|
||||
src/mysql_parameter_binder.cpp
|
||||
src/mysql_prepared_result_reader.cpp
|
||||
)
|
||||
|
||||
set(LIBRARY_TARGET matador-mysql)
|
||||
|
||||
add_library(${LIBRARY_TARGET} MODULE ${SOURCES} ${HEADER})
|
||||
|
||||
set_target_properties(${LIBRARY_TARGET}
|
||||
PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/backends"
|
||||
)
|
||||
|
||||
target_include_directories(${LIBRARY_TARGET} PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
${PROJECT_SOURCE_DIR}/backends/mysql/include
|
||||
${MYSQL_INCLUDE_DIR})
|
||||
|
||||
target_link_libraries(${LIBRARY_TARGET} matador ${MYSQL_LIBRARY})
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef QUERY_POSTGRES_CONNECTION_HPP
|
||||
#define QUERY_POSTGRES_CONNECTION_HPP
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef matador_mysql_EXPORTS
|
||||
#define MATADOR_MYSQL_API __declspec(dllexport)
|
||||
#else
|
||||
#define MATADOR_MYSQL_API __declspec(dllimport)
|
||||
#endif
|
||||
#pragma warning(disable: 4355)
|
||||
#else
|
||||
#define MATADOR_MYSQL_API
|
||||
#endif
|
||||
|
||||
#include "matador/sql/connection_impl.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <mysql.h>
|
||||
#else
|
||||
#include <mysql/mysql.h>
|
||||
#endif
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
class mysql_connection : public matador::sql::connection_impl
|
||||
{
|
||||
public:
|
||||
explicit mysql_connection(const sql::connection_info &info);
|
||||
void open() override;
|
||||
void close() override;
|
||||
bool is_open() override;
|
||||
|
||||
std::unique_ptr<sql::query_result_impl> fetch(const std::string &stmt) override;
|
||||
std::unique_ptr<sql::statement_impl> prepare(sql::query_context context) override;
|
||||
|
||||
size_t execute(const std::string &stmt) override;
|
||||
|
||||
sql::record describe(const std::string& table) override;
|
||||
|
||||
bool exists(const std::string &schema_name, const std::string &table_name) override;
|
||||
|
||||
private:
|
||||
mutable std::unique_ptr<MYSQL> mysql_;
|
||||
|
||||
using string_to_int_map = std::unordered_map<std::string, unsigned long>;
|
||||
|
||||
static string_to_int_map statement_name_map_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
MATADOR_MYSQL_API matador::sql::connection_impl* create_database(const matador::sql::connection_info &info);
|
||||
|
||||
MATADOR_MYSQL_API void destroy_database(matador::sql::connection_impl *db);
|
||||
}
|
||||
|
||||
#endif //QUERY_POSTGRES_CONNECTION_HPP
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef QUERY_POSTGRES_DIALECT_HPP
|
||||
#define QUERY_POSTGRES_DIALECT_HPP
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef matador_mysql_EXPORTS
|
||||
#define MATADOR_MYSQL_API __declspec(dllexport)
|
||||
#else
|
||||
#define MATADOR_MYSQL_API __declspec(dllimport)
|
||||
#endif
|
||||
#pragma warning(disable: 4355)
|
||||
#else
|
||||
#define MATADOR_MYSQL_API
|
||||
#endif
|
||||
|
||||
#include "matador/sql/dialect.hpp"
|
||||
|
||||
extern "C" [[maybe_unused]] MATADOR_MYSQL_API const matador::sql::dialect* get_dialect();
|
||||
|
||||
#endif //QUERY_POSTGRES_DIALECT_HPP
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef QUERY_POSTGRES_ERROR_HPP
|
||||
#define QUERY_POSTGRES_ERROR_HPP
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <mysql.h>
|
||||
#else
|
||||
#include <mysql/mysql.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
void throw_mysql_error(const char *what, const std::string &source);
|
||||
void throw_mysql_error(MYSQL *db, const std::string &source);
|
||||
void throw_mysql_error(MYSQL_STMT *stmt, const std::string &source, const std::string &sql);
|
||||
|
||||
}
|
||||
|
||||
#endif //QUERY_POSTGRES_ERROR_HPP
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
#ifndef QUERY_POSTGRES_PARAMETER_BINDER_H
|
||||
#define QUERY_POSTGRES_PARAMETER_BINDER_H
|
||||
|
||||
#include "matador/sql/parameter_binder.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <mysql.h>
|
||||
#else
|
||||
#include <mysql/mysql.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
struct mysql_result_info
|
||||
{
|
||||
unsigned long length = 0;
|
||||
my_bool is_null = false;
|
||||
my_bool error = false;
|
||||
// std::unique_ptr<char[]> buffer;
|
||||
char *buffer = nullptr;
|
||||
unsigned long buffer_length = 0;
|
||||
bool is_allocated = false;
|
||||
|
||||
~mysql_result_info()
|
||||
{
|
||||
if (is_allocated) {
|
||||
delete [] buffer;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class mysql_parameter_binder final : public sql::parameter_binder
|
||||
{
|
||||
public:
|
||||
explicit mysql_parameter_binder(size_t size);
|
||||
|
||||
void bind(size_t pos, char i) override;
|
||||
void bind(size_t pos, short i) override;
|
||||
void bind(size_t pos, int i) override;
|
||||
void bind(size_t pos, long i) override;
|
||||
void bind(size_t pos, long long int i) override;
|
||||
void bind(size_t pos, unsigned char i) override;
|
||||
void bind(size_t pos, unsigned short i) override;
|
||||
void bind(size_t pos, unsigned int i) override;
|
||||
void bind(size_t pos, unsigned long i) override;
|
||||
void bind(size_t pos, unsigned long long int i) override;
|
||||
void bind(size_t pos, bool b) override;
|
||||
void bind(size_t pos, float d) override;
|
||||
void bind(size_t pos, double d) override;
|
||||
void bind(size_t pos, const char *string) override;
|
||||
void bind(size_t pos, const char *string, size_t size) override;
|
||||
void bind(size_t pos, const std::string &string) override;
|
||||
void bind(size_t pos, const std::string &x, size_t size) override;
|
||||
|
||||
[[nodiscard]] std::vector<MYSQL_BIND>& bind_params();
|
||||
|
||||
private:
|
||||
struct is_null_t
|
||||
{
|
||||
my_bool is_null = false;
|
||||
};
|
||||
|
||||
std::vector<MYSQL_BIND> bind_params_;
|
||||
std::vector<is_null_t> is_null_vector;
|
||||
std::vector<mysql_result_info> info_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //QUERY_POSTGRES_PARAMETER_BINDER_H
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef QUERY_MYSQL_PREPARED_RESULT_READER_HPP
|
||||
#define QUERY_MYSQL_PREPARED_RESULT_READER_HPP
|
||||
|
||||
#include "matador/sql/query_result_reader.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <mysql.h>
|
||||
#else
|
||||
#include <mysql/mysql.h>
|
||||
#endif
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
class mysql_prepared_result_reader : public sql::query_result_reader
|
||||
{
|
||||
public:
|
||||
explicit mysql_prepared_result_reader(MYSQL_STMT *stmt);
|
||||
~mysql_prepared_result_reader() override;
|
||||
|
||||
[[nodiscard]] size_t column_count() const override;
|
||||
[[nodiscard]] const char *column(size_t index) const override;
|
||||
bool fetch() override;
|
||||
|
||||
private:
|
||||
MYSQL_STMT *stmt_{};
|
||||
|
||||
MYSQL_ROW current_row_{};
|
||||
|
||||
size_t row_count_{};
|
||||
size_t column_count_{};
|
||||
int row_index_{-1};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //QUERY_MYSQL_PREPARED_RESULT_READER_HPP
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef QUERY_POSTGRES_RESULT_READER_HPP
|
||||
#define QUERY_POSTGRES_RESULT_READER_HPP
|
||||
|
||||
#include "matador/sql/query_result_reader.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <mysql.h>
|
||||
#else
|
||||
#include <mysql/mysql.h>
|
||||
#endif
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
class mysql_result_reader : public sql::query_result_reader
|
||||
{
|
||||
public:
|
||||
explicit mysql_result_reader(MYSQL_RES *result, unsigned int column_count);
|
||||
~mysql_result_reader() override;
|
||||
|
||||
[[nodiscard]] size_t column_count() const override;
|
||||
[[nodiscard]] const char *column(size_t index) const override;
|
||||
bool fetch() override;
|
||||
|
||||
private:
|
||||
MYSQL_RES *result_{};
|
||||
|
||||
MYSQL_ROW current_row_{};
|
||||
|
||||
size_t row_count_{};
|
||||
size_t column_count_{};
|
||||
int row_index_{-1};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //QUERY_POSTGRES_RESULT_READER_HPP
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef QUERY_POSTGRES_STATEMENT_HPP
|
||||
#define QUERY_POSTGRES_STATEMENT_HPP
|
||||
|
||||
#include "matador/sql/statement_impl.hpp"
|
||||
|
||||
#include "mysql_parameter_binder.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <mysql.h>
|
||||
#else
|
||||
#include <mysql/mysql.h>
|
||||
#endif
|
||||
|
||||
namespace matador::backends::mysql {
|
||||
|
||||
class mysql_statement final : public sql::statement_impl
|
||||
{
|
||||
public:
|
||||
mysql_statement(MYSQL_STMT *stmt, const sql::query_context &query);
|
||||
|
||||
size_t execute() override;
|
||||
std::unique_ptr<sql::query_result_impl> fetch() override;
|
||||
void reset() override;
|
||||
protected:
|
||||
sql::parameter_binder& binder() override;
|
||||
|
||||
private:
|
||||
MYSQL_STMT *stmt_{nullptr};
|
||||
|
||||
std::string name_;
|
||||
|
||||
mysql_parameter_binder binder_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //QUERY_POSTGRES_STATEMENT_HPP
|
||||
|
|
@ -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_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ public:
|
|||
|
||||
sql::record describe(const std::string& table) override;
|
||||
|
||||
bool exists(const std::string &table_name) override;
|
||||
bool exists(const std::string &schema_name, const std::string &table_name) override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] static std::string generate_statement_name(const sql::query_context &query) ;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace matador::backends::postgres {
|
|||
class postgres_statement final : public sql::statement_impl
|
||||
{
|
||||
public:
|
||||
postgres_statement(PGconn *db, PGresult *result, const std::string &name, const sql::query_context &query);
|
||||
postgres_statement(PGconn *db, PGresult *result, std::string name, const sql::query_context &query);
|
||||
|
||||
size_t execute() override;
|
||||
std::unique_ptr<sql::query_result_impl> fetch() override;
|
||||
|
|
|
|||
|
|
@ -161,9 +161,9 @@ sql::record postgres_connection::describe(const std::string &table)
|
|||
return std::move(prototype);
|
||||
}
|
||||
|
||||
bool postgres_connection::exists(const std::string &table_name)
|
||||
bool postgres_connection::exists(const std::string &schema_name, const std::string &table_name)
|
||||
{
|
||||
std::string stmt("SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '" + table_name + "'");
|
||||
std::string stmt("SELECT 1 FROM information_schema.tables WHERE table_schema = '" + schema_name + "' AND table_name = '" + table_name + "'");
|
||||
|
||||
PGresult *res = PQexec(conn_, stmt.c_str());
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
|
||||
namespace matador::backends::postgres {
|
||||
|
||||
postgres_statement::postgres_statement(PGconn *db, PGresult *result, const std::string &name, const sql::query_context &query)
|
||||
postgres_statement::postgres_statement(PGconn *db, PGresult *result, std::string name, const sql::query_context &query)
|
||||
: statement_impl(query)
|
||||
, db_(db)
|
||||
, result_(result)
|
||||
, name_(name)
|
||||
, name_(std::move(name))
|
||||
, binder_(query_.bind_vars.size())
|
||||
{}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public:
|
|||
|
||||
sql::record describe(const std::string& table) override;
|
||||
|
||||
bool exists(const std::string &table_name) override;
|
||||
bool exists(const std::string &schema_name, const std::string &table_name) override;
|
||||
|
||||
private:
|
||||
struct fetch_context
|
||||
|
|
|
|||
|
|
@ -156,7 +156,6 @@ sql::record sqlite_connection::describe(const std::string& table)
|
|||
auto index = strtoul(reader.column(0), &end, 10);
|
||||
std::string name = reader.column(1);
|
||||
|
||||
// Todo: extract size
|
||||
auto type = (string2type(reader.column(2)));
|
||||
end = nullptr;
|
||||
utils::constraints options{};
|
||||
|
|
@ -170,7 +169,7 @@ sql::record sqlite_connection::describe(const std::string& table)
|
|||
return std::move(prototype);
|
||||
}
|
||||
|
||||
bool sqlite_connection::exists(const std::string &table_name)
|
||||
bool sqlite_connection::exists(const std::string &schema_name, const std::string &table_name)
|
||||
{
|
||||
const auto result = fetch_internal("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND tbl_name='" + table_name + "' LIMIT 1");
|
||||
sqlite_result_reader reader(result.rows, result.prototype.size());
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public:
|
|||
[[nodiscard]] const connection_info& info() const;
|
||||
|
||||
[[nodiscard]] record describe(const std::string &table_name) const;
|
||||
[[nodiscard]] bool exists(const std::string &table_name) const;
|
||||
[[nodiscard]] bool exists(const std::string &schema_name, const std::string &table_name) const;
|
||||
|
||||
[[nodiscard]] std::unique_ptr<query_result_impl> fetch(const std::string &sql) const;
|
||||
[[nodiscard]] size_t execute(const std::string &sql) const;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public:
|
|||
virtual std::unique_ptr<statement_impl> prepare(query_context context) = 0;
|
||||
|
||||
virtual record describe(const std::string &table) = 0;
|
||||
virtual bool exists(const std::string &table_name) = 0;
|
||||
virtual bool exists(const std::string &schema_name, const std::string &table_name) = 0;
|
||||
|
||||
protected:
|
||||
explicit connection_impl(const connection_info &info);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef QUERY_OBJECT_BINDER_HPP
|
||||
#define QUERY_OBJECT_BINDER_HPP
|
||||
#ifndef QUERY_OBJECT_PARAMETER_BINDER_HPP
|
||||
#define QUERY_OBJECT_PARAMETER_BINDER_HPP
|
||||
|
||||
#include "matador/sql/parameter_binder.hpp"
|
||||
#include "matador/sql/types.hpp"
|
||||
|
|
@ -49,10 +49,10 @@ private:
|
|||
|
||||
}
|
||||
|
||||
class object_binder
|
||||
class object_parameter_binder
|
||||
{
|
||||
public:
|
||||
explicit object_binder(parameter_binder &binder);
|
||||
explicit object_parameter_binder(parameter_binder &binder);
|
||||
|
||||
void reset();
|
||||
|
||||
|
|
@ -101,4 +101,4 @@ void fk_binder::on_primary_key(const char *id, ValueType &value, typename std::e
|
|||
|
||||
}
|
||||
}
|
||||
#endif //QUERY_OBJECT_BINDER_HPP
|
||||
#endif //QUERY_OBJECT_PARAMETER_BINDER_HPP
|
||||
|
|
@ -11,7 +11,7 @@ struct query_context
|
|||
std::string command_name;
|
||||
std::string table_name;
|
||||
record prototype;
|
||||
std::vector<any_type> host_vars;
|
||||
std::vector<std::string> result_vars;
|
||||
std::vector<std::string> bind_vars;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,133 @@
|
|||
#ifndef QUERY_RESULT_PARAMETER_BINDER_HPP
|
||||
#define QUERY_RESULT_PARAMETER_BINDER_HPP
|
||||
|
||||
#include "matador/utils/access.hpp"
|
||||
#include "matador/utils/cascade_type.hpp"
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
|
||||
#include "matador/sql/any_type.hpp"
|
||||
#include "matador/sql/types.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
class result_parameter_binder;
|
||||
|
||||
namespace detail {
|
||||
class fk_result_binder
|
||||
{
|
||||
public:
|
||||
explicit fk_result_binder(result_parameter_binder &result_binder);
|
||||
|
||||
template<class Type>
|
||||
void bind_result(Type &obj, size_t column_index)
|
||||
{
|
||||
column_index_ = column_index;
|
||||
utils::access::process(*this, obj);
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0);
|
||||
void on_primary_key(const char *id, std::string &value, size_t size);
|
||||
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
|
||||
|
||||
template < class Type >
|
||||
void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
template < class Pointer >
|
||||
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, utils::cascade_type) {}
|
||||
template < class Pointer >
|
||||
void on_has_one(const char * /*id*/, Pointer &/*x*/, utils::cascade_type) {}
|
||||
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char *, ContainerType &, utils::cascade_type) {}
|
||||
|
||||
private:
|
||||
size_t column_index_{};
|
||||
result_parameter_binder &result_binder_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class result_parameter_binder
|
||||
{
|
||||
public:
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char * /*id*/, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
|
||||
{
|
||||
data_type_traits<ValueType>::bind_result_value(*this, column_index_++, value);
|
||||
}
|
||||
void on_primary_key(const char *id, std::string &value, size_t size);
|
||||
void on_revision(const char *id, unsigned long long &rev);
|
||||
|
||||
template < class Type >
|
||||
void on_attribute(const char * /*id*/, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes)
|
||||
{
|
||||
data_type_traits<Type>::bind_result_value(*this, column_index_++, x);
|
||||
}
|
||||
void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes);
|
||||
void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr = utils::null_attributes);
|
||||
void on_attribute(const char *id, any_type &value, data_type_t type, const utils::field_attributes &attr = utils::null_attributes);
|
||||
|
||||
template < class Pointer >
|
||||
void on_belongs_to(const char * /*id*/, Pointer &x, utils::cascade_type)
|
||||
{
|
||||
if (!x.get()) {
|
||||
x.reset(new typename Pointer::value_type);
|
||||
}
|
||||
fk_result_binder_.bind_result(*x, column_index_++);
|
||||
}
|
||||
template < class Pointer >
|
||||
void on_has_one(const char * /*id*/, Pointer &x, utils::cascade_type)
|
||||
{
|
||||
if (!x.get()) {
|
||||
x.reset(new typename Pointer::value_type);
|
||||
}
|
||||
fk_result_binder_.bind_result(*x, column_index_++);
|
||||
}
|
||||
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char *, ContainerType &, utils::cascade_type) {}
|
||||
|
||||
virtual void bind_result_value(size_t index, char &value) {}
|
||||
virtual void bind_result_value(size_t index, short &value) {}
|
||||
virtual void bind_result_value(size_t index, int &value) {}
|
||||
virtual void bind_result_value(size_t index, long &value) {}
|
||||
virtual void bind_result_value(size_t index, long long &value) {}
|
||||
virtual void bind_result_value(size_t index, unsigned char &value) {}
|
||||
virtual void bind_result_value(size_t index, unsigned short &value) {}
|
||||
virtual void bind_result_value(size_t index, unsigned int &value) {}
|
||||
virtual void bind_result_value(size_t index, unsigned long &value) {}
|
||||
virtual void bind_result_value(size_t index, unsigned long long &value) {}
|
||||
virtual void bind_result_value(size_t index, bool &value) {}
|
||||
virtual void bind_result_value(size_t index, float &value) {}
|
||||
virtual void bind_result_value(size_t index, double &value) {}
|
||||
// virtual void bind_result_value(size_t index, matador::time &value) {}
|
||||
// virtual void bind_result_value(size_t index, matador::date &value) {}
|
||||
virtual void bind_result_value(size_t index, char *value, size_t s) {}
|
||||
virtual void bind_result_value(size_t index, std::string &value) {}
|
||||
virtual void bind_result_value(size_t index, std::string &value, size_t s) {}
|
||||
virtual void bind_result_value(size_t index, any_type &value, data_type_t type, size_t size) {}
|
||||
|
||||
private:
|
||||
size_t column_index_{};
|
||||
detail::fk_result_binder fk_result_binder_;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename ValueType>
|
||||
void fk_result_binder::on_primary_key(const char * /*id*/, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type *)
|
||||
{
|
||||
data_type_traits<ValueType>::bind_result_value(result_binder_, column_index_++, value);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif //QUERY_RESULT_PARAMETER_BINDER_HPP
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef QUERY_STATEMENT_HPP
|
||||
#define QUERY_STATEMENT_HPP
|
||||
|
||||
#include "matador/sql/object_binder.hpp"
|
||||
#include "matador/sql/object_parameter_binder.hpp"
|
||||
#include "matador/sql/query_result.hpp"
|
||||
#include "matador/sql/statement_impl.hpp"
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ public:
|
|||
private:
|
||||
std::unique_ptr<statement_impl> statement_;
|
||||
const utils::logger &logger_;
|
||||
object_binder object_binder_;
|
||||
object_parameter_binder object_binder_;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ namespace matador::sql {
|
|||
|
||||
class query_result_reader;
|
||||
class parameter_binder;
|
||||
class result_parameter_binder;
|
||||
|
||||
/**
|
||||
* @brief Enumeration type of all supported builtin data types
|
||||
|
|
@ -65,6 +66,7 @@ template <> struct data_type_traits<char, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_char; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, char &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, char &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, char &value);
|
||||
inline static any_type create_value(char &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -73,6 +75,7 @@ template <> struct data_type_traits<short, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_short; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, short &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, short &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, short &value);
|
||||
inline static any_type create_value(short &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -81,6 +84,7 @@ template <> struct data_type_traits<int, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_int; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, int &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, int &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, int &value);
|
||||
inline static any_type create_value(int &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -89,6 +93,7 @@ template <> struct data_type_traits<long, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_long; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, long &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, long &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, long &value);
|
||||
inline static any_type create_value(long &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -97,6 +102,7 @@ template <> struct data_type_traits<long long, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_long_long; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, long long &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, long long &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, long long &value);
|
||||
inline static any_type create_value(long long &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -105,6 +111,7 @@ template <> struct data_type_traits<unsigned char, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_char; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned char &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, unsigned char &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned char &value);
|
||||
inline static any_type create_value(unsigned char &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -113,6 +120,7 @@ template <> struct data_type_traits<unsigned short, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_short; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned short &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, unsigned short &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned short &value);
|
||||
inline static any_type create_value(unsigned short &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -121,6 +129,7 @@ template <> struct data_type_traits<unsigned int, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_int; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned int &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, unsigned int &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned int &value);
|
||||
inline static any_type create_value(unsigned int &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -129,6 +138,7 @@ template <> struct data_type_traits<unsigned long, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/ = 0) { return data_type_t::type_unsigned_long; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, unsigned long &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned long &value);
|
||||
inline static any_type create_value(unsigned long &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -137,6 +147,7 @@ template <> struct data_type_traits<unsigned long long, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_long_long; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long long &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, unsigned long long &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned long long &value);
|
||||
inline static any_type create_value(unsigned long long &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -145,6 +156,7 @@ template <> struct data_type_traits<bool, void>
|
|||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_bool; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, bool &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, bool &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, bool &value);
|
||||
inline static any_type create_value(bool &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -152,6 +164,7 @@ template <> struct data_type_traits<float, void>
|
|||
{
|
||||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_float; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, float &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, float &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, float &value);
|
||||
inline static any_type create_value(float &value) { return value; }
|
||||
};
|
||||
|
|
@ -160,6 +173,7 @@ template <> struct data_type_traits<double, void>
|
|||
{
|
||||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_double; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, double &value);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, double &value);
|
||||
static void bind_value(parameter_binder &binder, size_t index, double &value);
|
||||
inline static any_type create_value(double &value) { return value; }
|
||||
};
|
||||
|
|
@ -169,6 +183,7 @@ template <> struct data_type_traits<const char*, void>
|
|||
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_char_pointer; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, const char* value, size_t size);
|
||||
static void bind_value(parameter_binder &binder, size_t index, const char *value, size_t size = 0);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, const char *value, size_t size = 0);
|
||||
inline static any_type create_value(const char *value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -177,6 +192,7 @@ template <> struct data_type_traits<char*, void>
|
|||
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_varchar; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, char *value, size_t size);
|
||||
static void bind_value(parameter_binder &binder, size_t index, char *value, size_t size = 0);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, char *value, size_t size = 0);
|
||||
inline static any_type create_value(const char *value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -185,6 +201,7 @@ template <> struct data_type_traits<std::string, void>
|
|||
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_varchar; }
|
||||
static void read_value(query_result_reader &reader, const char *id, size_t index, std::string &value, size_t size);
|
||||
static void bind_value(parameter_binder &binder, size_t index, std::string &value, size_t size = 0);
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, std::string &value, size_t size = 0);
|
||||
inline static any_type create_value(std::string &value) { return value; }
|
||||
};
|
||||
|
||||
|
|
@ -216,6 +233,10 @@ struct data_type_traits<EnumType, typename std::enable_if<std::is_enum<EnumType>
|
|||
{
|
||||
data_type_traits<int>::bind_value(binder, index, (int&)value);
|
||||
}
|
||||
static void bind_result_value(result_parameter_binder &binder, size_t index, EnumType &value)
|
||||
{
|
||||
data_type_traits<int>::bind_result_value(binder, index, (int&)value);
|
||||
}
|
||||
inline static any_type create_value(EnumType &value) { return (int)value; }
|
||||
};
|
||||
/// @endcond
|
||||
|
|
|
|||
|
|
@ -23,9 +23,10 @@ set(SQL_SOURCES
|
|||
sql/statement_cache.cpp
|
||||
sql/statement_impl.cpp
|
||||
sql/dialect_builder.cpp
|
||||
sql/object_binder.cpp
|
||||
sql/object_parameter_binder.cpp
|
||||
sql/placeholder_generator.cpp
|
||||
sql/types.cpp
|
||||
sql/result_parameter_binder.cpp
|
||||
)
|
||||
|
||||
set(SQL_HEADER
|
||||
|
|
@ -64,8 +65,9 @@ set(SQL_HEADER
|
|||
sql/statement.cpp
|
||||
../include/matador/sql/parameter_binder.hpp
|
||||
../include/matador/sql/dialect_builder.hpp
|
||||
../include/matador/sql/object_binder.hpp
|
||||
../include/matador/sql/object_parameter_binder.hpp
|
||||
../include/matador/sql/placeholder_generator.hpp
|
||||
../include/matador/sql/result_parameter_binder.hpp
|
||||
)
|
||||
|
||||
set(UTILS_HEADER
|
||||
|
|
|
|||
|
|
@ -71,9 +71,9 @@ record connection::describe(const std::string &table_name) const
|
|||
return std::move(connection_->describe(table_name));
|
||||
}
|
||||
|
||||
bool connection::exists(const std::string &table_name) const
|
||||
bool connection::exists(const std::string &schema_name, const std::string &table_name) const
|
||||
{
|
||||
return connection_->exists(table_name);
|
||||
return connection_->exists(schema_name, table_name);
|
||||
}
|
||||
|
||||
size_t connection::execute(const std::string &sql) const
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "matador/sql/object_binder.hpp"
|
||||
#include "matador/sql/object_parameter_binder.hpp"
|
||||
#include "matador/sql/parameter_binder.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
|
@ -15,21 +15,21 @@ void fk_binder::on_primary_key(const char *id, std::string &value, size_t size)
|
|||
|
||||
}
|
||||
|
||||
object_binder::object_binder(parameter_binder &binder)
|
||||
object_parameter_binder::object_parameter_binder(parameter_binder &binder)
|
||||
: binder_(binder)
|
||||
, fk_binder_(binder) {}
|
||||
|
||||
void object_binder::reset()
|
||||
void object_parameter_binder::reset()
|
||||
{
|
||||
index_ = 0;
|
||||
}
|
||||
|
||||
void object_binder::on_primary_key(const char *id, std::string &val, size_t size)
|
||||
void object_parameter_binder::on_primary_key(const char *id, std::string &val, size_t size)
|
||||
{
|
||||
data_type_traits<std::string>::bind_value(binder_, index_++, val, size);
|
||||
}
|
||||
|
||||
void object_binder::on_revision(const char *id, unsigned long long int &rev)
|
||||
void object_parameter_binder::on_revision(const char *id, unsigned long long int &rev)
|
||||
{
|
||||
data_type_traits<unsigned long long>::bind_value(binder_, index_++, rev);
|
||||
}
|
||||
|
|
@ -125,15 +125,18 @@ query_builder &query_builder::select(const std::vector<column> &columns)
|
|||
if (columns.size() < 2) {
|
||||
for (const auto &col: columns) {
|
||||
result.append(dialect_.prepare_identifier(col));
|
||||
query_.result_vars.emplace_back(col.name());
|
||||
query_.prototype.append(col);
|
||||
}
|
||||
} else {
|
||||
auto it = columns.begin();
|
||||
result.append(dialect_.prepare_identifier(*it));
|
||||
query_.result_vars.emplace_back(it->name());
|
||||
query_.prototype.append(column{*it++});
|
||||
for (; it != columns.end(); ++it) {
|
||||
result.append(", ");
|
||||
result.append(dialect_.prepare_identifier(*it));
|
||||
query_.result_vars.emplace_back(it->name());
|
||||
query_.prototype.append(column{*it});
|
||||
}
|
||||
}
|
||||
|
|
@ -284,20 +287,20 @@ query_builder &query_builder::values(const std::vector<any_type> &values)
|
|||
std::string result{"("};
|
||||
if (values.size() < 2) {
|
||||
for (auto val: values) {
|
||||
query_.host_vars.push_back(val);
|
||||
// query_.result_vars.push_back(val);
|
||||
std::visit(value_to_string_, val);
|
||||
result.append(value_to_string_.result);
|
||||
}
|
||||
} else {
|
||||
auto it = values.begin();
|
||||
auto val = *it++;
|
||||
query_.host_vars.push_back(val);
|
||||
// query_.result_vars.push_back(val);
|
||||
std::visit(value_to_string_, val);
|
||||
result.append(value_to_string_.result);
|
||||
for (; it != values.end(); ++it) {
|
||||
result.append(", ");
|
||||
val = *it;
|
||||
query_.host_vars.push_back(val);
|
||||
// query_.result_vars.push_back(val);
|
||||
std::visit(value_to_string_, val);
|
||||
result.append(value_to_string_.result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
#include "matador/sql/result_parameter_binder.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
namespace detail {
|
||||
fk_result_binder::fk_result_binder(result_parameter_binder &result_binder)
|
||||
: result_binder_(result_binder)
|
||||
{}
|
||||
|
||||
void fk_result_binder::on_primary_key(const char * /*id*/, std::string &value, size_t size)
|
||||
{
|
||||
data_type_traits<std::string>::bind_result_value(result_binder_, column_index_++, value, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void result_parameter_binder::on_primary_key(const char * /*id*/, std::string &value, size_t size)
|
||||
{
|
||||
data_type_traits<std::string>::bind_result_value(*this, column_index_++, value, size);
|
||||
}
|
||||
|
||||
void result_parameter_binder::on_revision(const char * /*id*/, unsigned long long &rev)
|
||||
{
|
||||
data_type_traits<unsigned long long>::bind_result_value(*this, column_index_++, rev);
|
||||
}
|
||||
|
||||
void result_parameter_binder::on_attribute(const char * /*id*/, char *value, const utils::field_attributes &attr)
|
||||
{
|
||||
data_type_traits<char*>::bind_result_value(*this, column_index_++, value, attr.size());
|
||||
}
|
||||
|
||||
void result_parameter_binder::on_attribute(const char * /*id*/, std::string &value, const utils::field_attributes &attr)
|
||||
{
|
||||
data_type_traits<std::string>::bind_result_value(*this, column_index_++, value, attr.size());
|
||||
}
|
||||
|
||||
void result_parameter_binder::on_attribute(const char * /*id*/, any_type &value, data_type_t type, const utils::field_attributes &attr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ bool session::table_exists(const std::string &table_name) const
|
|||
if (!c.valid()) {
|
||||
throw std::logic_error("no database connection available");
|
||||
}
|
||||
return c->exists(table_name);
|
||||
return c->exists(dialect_.default_schema_name(), table_name);
|
||||
}
|
||||
|
||||
const table_repository& session::tables() const
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "matador/sql/parameter_binder.hpp"
|
||||
#include "matador/sql/query_result_reader.hpp"
|
||||
#include "matador/sql/result_parameter_binder.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
|
|
@ -15,6 +16,11 @@ void data_type_traits<char>::bind_value(parameter_binder &binder, size_t index,
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<char>::bind_result_value(result_parameter_binder &binder, size_t index, char &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<short>::read_value(query_result_reader &reader, const char *id, size_t index, short &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -25,6 +31,11 @@ void data_type_traits<short>::bind_value(parameter_binder &binder, size_t index,
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<short>::bind_result_value(result_parameter_binder &binder, size_t index, short &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<int>::read_value(query_result_reader &reader, const char *id, size_t index, int &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -35,6 +46,11 @@ void data_type_traits<int>::bind_value(parameter_binder &binder, size_t index, i
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<int>::bind_result_value(result_parameter_binder &binder, size_t index, int &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<long>::read_value(query_result_reader &reader, const char *id, size_t index, long &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -45,6 +61,11 @@ void data_type_traits<long>::bind_value(parameter_binder &binder, size_t index,
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<long>::bind_result_value(result_parameter_binder &binder, size_t index, long &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<long long>::read_value(query_result_reader &reader, const char *id, size_t index, long long &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -55,6 +76,11 @@ void data_type_traits<long long int>::bind_value(parameter_binder &binder, size_
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<long long int>::bind_result_value(result_parameter_binder &binder, size_t index, long long int &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned char>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned char &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -65,6 +91,11 @@ void data_type_traits<unsigned char>::bind_value(parameter_binder &binder, size_
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned char>::bind_result_value(result_parameter_binder &binder, size_t index, unsigned char &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned short>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned short &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -75,6 +106,11 @@ void data_type_traits<unsigned short>::bind_value(parameter_binder &binder, size
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned short>::bind_result_value(result_parameter_binder &binder, size_t index, unsigned short &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned int>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned int &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -85,6 +121,11 @@ void data_type_traits<unsigned int>::bind_value(parameter_binder &binder, size_t
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned int>::bind_result_value(result_parameter_binder &binder, size_t index, unsigned int &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned long>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned long &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -95,16 +136,26 @@ void data_type_traits<unsigned long>::bind_value(parameter_binder &binder, size_
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned long>::bind_result_value(result_parameter_binder &binder, size_t index, unsigned long &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned long long>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned long long &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned long long int>::bind_value(parameter_binder &binder, size_t index, unsigned long long int &value)
|
||||
void data_type_traits<unsigned long long>::bind_value(parameter_binder &binder, size_t index, unsigned long long &value)
|
||||
{
|
||||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<unsigned long long>::bind_result_value(result_parameter_binder &binder, size_t index, unsigned long long &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<bool>::read_value(query_result_reader &reader, const char *id, size_t index, bool &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -115,6 +166,11 @@ void data_type_traits<bool>::bind_value(parameter_binder &binder, size_t index,
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<bool>::bind_result_value(result_parameter_binder &binder, size_t index, bool &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<float>::read_value(query_result_reader &reader, const char *id, size_t index, float &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -125,6 +181,11 @@ void data_type_traits<float>::bind_value(parameter_binder &binder, size_t index,
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<float>::bind_result_value(result_parameter_binder &binder, size_t index, float &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<double>::read_value(query_result_reader &reader, const char *id, size_t index, double &value)
|
||||
{
|
||||
reader.read_value(id, index, value);
|
||||
|
|
@ -135,6 +196,11 @@ void data_type_traits<double>::bind_value(parameter_binder &binder, size_t index
|
|||
binder.bind(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<double>::bind_result_value(result_parameter_binder &binder, size_t index, double &value)
|
||||
{
|
||||
binder.bind_result_value(index, value);
|
||||
}
|
||||
|
||||
void data_type_traits<const char*>::read_value(query_result_reader &reader, const char *id, size_t index, const char* value, size_t size)
|
||||
{
|
||||
reader.read_value(id, index, const_cast<char*>(value), size);
|
||||
|
|
@ -145,6 +211,11 @@ void data_type_traits<const char *>::bind_value(parameter_binder &binder, size_t
|
|||
binder.bind(index, value, size);
|
||||
}
|
||||
|
||||
void data_type_traits<const char *>::bind_result_value(result_parameter_binder &binder, size_t index, const char *value, size_t size)
|
||||
{
|
||||
binder.bind_result_value(index, const_cast<char*>(value), size);
|
||||
}
|
||||
|
||||
void data_type_traits<char*>::read_value(query_result_reader &reader, const char *id, size_t index, char* value, size_t size)
|
||||
{
|
||||
reader.read_value(id, index, value, size);
|
||||
|
|
@ -155,6 +226,11 @@ void data_type_traits<char *>::bind_value(parameter_binder &binder, size_t index
|
|||
binder.bind(index, value, size);
|
||||
}
|
||||
|
||||
void data_type_traits<char *, void>::bind_result_value(result_parameter_binder &binder, size_t index, char *value, size_t size)
|
||||
{
|
||||
binder.bind_result_value(index, value, size);
|
||||
}
|
||||
|
||||
void data_type_traits<std::string>::read_value(query_result_reader &reader, const char *id, size_t index, std::string &value, size_t size)
|
||||
{
|
||||
reader.read_value(id, index, value, size);
|
||||
|
|
@ -165,4 +241,8 @@ void data_type_traits<std::string>::bind_value(parameter_binder &binder, size_t
|
|||
binder.bind(index, value, size);
|
||||
}
|
||||
|
||||
void data_type_traits<std::string, void>::bind_result_value(result_parameter_binder &binder, size_t index, std::string &value, size_t size)
|
||||
{
|
||||
binder.bind_result_value(index, value, size);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,25 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
|
||||
#include "matador/sql/connection.hpp"
|
||||
|
||||
#include "Databases.hpp"
|
||||
|
||||
using namespace matador::sql;
|
||||
|
||||
TEST_CASE("Create connection", "[connection]") {
|
||||
auto dns = GENERATE(as<std::string>{},
|
||||
"sqlite://sqlite.db",
|
||||
"postgres://test:test123@127.0.0.1:5432/matador_test" );
|
||||
template<class Type>
|
||||
class ConnectionTestFixture
|
||||
{
|
||||
public:
|
||||
ConnectionTestFixture() = default;
|
||||
~ConnectionTestFixture() = default;
|
||||
|
||||
connection c(dns);
|
||||
std::string dns() { return Type::dns; }
|
||||
};
|
||||
|
||||
TEMPLATE_TEST_CASE_METHOD(ConnectionTestFixture, "Create connection", "[connection]", Sqlite, Postgres, MySql) {
|
||||
|
||||
connection c(ConnectionTestFixture<TestType>::dns());
|
||||
REQUIRE(!c.is_open());
|
||||
|
||||
c.open();
|
||||
|
|
|
|||
|
|
@ -12,4 +12,9 @@ struct Sqlite
|
|||
constexpr static const char *dns{"sqlite://sqlite.db"};
|
||||
};
|
||||
|
||||
struct MySql
|
||||
{
|
||||
constexpr static const char *dns{"mysql://test:test123!@127.0.0.1:3306/matador_test"};
|
||||
};
|
||||
|
||||
#endif //QUERY_DATABASES_HPP
|
||||
|
|
|
|||
|
|
@ -1,20 +1,35 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
|
||||
#include <matador/sql/condition.hpp>
|
||||
#include <matador/sql/session.hpp>
|
||||
|
||||
#include "Databases.hpp"
|
||||
|
||||
#include <list>
|
||||
|
||||
using namespace matador::sql;
|
||||
|
||||
TEST_CASE("Create and drop table statement", "[session record]")
|
||||
template<class Type>
|
||||
class SessionRecordTestFixture
|
||||
{
|
||||
auto dns = GENERATE(as < std::string > {},
|
||||
"sqlite://sqlite.db",
|
||||
"postgres://test:test123@127.0.0.1:5432/matador_test");
|
||||
connection_pool<connection> pool(dns, 4);
|
||||
session s(pool);
|
||||
public:
|
||||
SessionRecordTestFixture()
|
||||
: pool_(Type::dns, 4), session_(pool_)
|
||||
{}
|
||||
|
||||
matador::sql::session &session()
|
||||
{ return session_; }
|
||||
|
||||
private:
|
||||
matador::sql::connection_pool<matador::sql::connection> pool_;
|
||||
matador::sql::session session_;
|
||||
};
|
||||
|
||||
TEMPLATE_TEST_CASE_METHOD(SessionRecordTestFixture, "Create and drop table statement", "[session record]", Sqlite, Postgres, MySql)
|
||||
{
|
||||
auto &s = SessionRecordTestFixture<TestType>::session();
|
||||
|
||||
REQUIRE(!s.table_exists("person"));
|
||||
s.create()
|
||||
|
|
|
|||
Loading…
Reference in New Issue