initial matador ng commit
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
#include "matador/sql/backend_provider.hpp"
|
||||
// #include "matador/sql/noop_connection.hpp"
|
||||
// #include "matador/sql/dialect_builder.hpp"
|
||||
|
||||
#include "matador/sql/interface/connection_impl.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <cstdint>
|
||||
|
||||
namespace matador::sql {
|
||||
backend_provider::backend_provider() = default;
|
||||
// {
|
||||
// backends_.emplace("noop", std::make_unique<noop_backend_context>());
|
||||
// }
|
||||
|
||||
backend_provider &backend_provider::instance() {
|
||||
static backend_provider provider;
|
||||
return provider;
|
||||
}
|
||||
|
||||
connection_impl *backend_provider::create_connection(const std::string &connection_type, const connection_info &info)
|
||||
{
|
||||
auto it = backends_.find(connection_type);
|
||||
if (it == backends_.end()) {
|
||||
it = backends_.emplace(connection_type, std::make_unique<backend_service>(connection_type)).first;
|
||||
}
|
||||
return it->second->create(info);
|
||||
}
|
||||
|
||||
void backend_provider::destroy_connection(const std::string &connection_type, connection_impl *c)
|
||||
{
|
||||
auto it = backends_.find(connection_type);
|
||||
if (it == backends_.end()) {
|
||||
it = backends_.emplace(connection_type, std::make_unique<backend_service>(connection_type)).first;
|
||||
}
|
||||
return it->second->destroy(c);
|
||||
}
|
||||
|
||||
const dialect &backend_provider::connection_dialect(const std::string &connection_type) {
|
||||
auto it = backends_.find(connection_type);
|
||||
if (it == backends_.end()) {
|
||||
it = backends_.emplace(connection_type, std::make_unique<backend_service>(connection_type)).first;
|
||||
}
|
||||
return *it->second->dialect();
|
||||
}
|
||||
void backend_provider::register_backend(const std::string &connection_type, std::unique_ptr<basic_backend_service> &&service) {
|
||||
backends_.emplace(connection_type, std::move(service));
|
||||
}
|
||||
|
||||
backend_provider::backend_service::backend_service(const std::string &connection_type)
|
||||
{
|
||||
if (!lib.load("matador-" + connection_type)) {
|
||||
throw std::runtime_error("couldn't load library '" + connection_type + "'");
|
||||
}
|
||||
|
||||
create_connection = reinterpret_cast<create_func>(reinterpret_cast<std::uintptr_t>(lib.function("create_database")));
|
||||
destroy_connection = reinterpret_cast<destroy_func>(reinterpret_cast<std::uintptr_t>(lib.function("destroy_database")));
|
||||
get_dialect = reinterpret_cast<dialect_func >(reinterpret_cast<std::uintptr_t>(lib.function("get_dialect")));
|
||||
}
|
||||
|
||||
connection_impl *backend_provider::backend_service::create(const connection_info &info)
|
||||
{
|
||||
return (create_connection)(info);
|
||||
}
|
||||
|
||||
void backend_provider::backend_service::destroy(connection_impl *conn)
|
||||
{
|
||||
(destroy_connection)(conn);
|
||||
}
|
||||
|
||||
const dialect *backend_provider::backend_service::dialect() const
|
||||
{
|
||||
return (get_dialect)();
|
||||
}
|
||||
|
||||
backend_provider::backend_service::~backend_service()
|
||||
{
|
||||
lib.unload();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#include <utility>
|
||||
|
||||
#include "matador/sql/column.hpp"
|
||||
#include "matador/sql/table.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
column operator ""_col(const char *name, size_t len)
|
||||
{
|
||||
return column{{name, len}};
|
||||
}
|
||||
|
||||
column::column(const char *name, const std::string& as)
|
||||
: column(std::string(name), as)
|
||||
{}
|
||||
|
||||
column::column(std::string name, std::string as)
|
||||
: table_(std::make_shared<sql::table>())
|
||||
, name(std::move(name))
|
||||
, alias(std::move(as)) {}
|
||||
|
||||
column::column(const sql_function_t func, std::string name)
|
||||
: table_(std::make_shared<sql::table>())
|
||||
, name(std::move(name))
|
||||
, function_(func) {}
|
||||
|
||||
column::column(const struct sql::table& t, std::string name, std::string as)
|
||||
: table_(std::make_shared<sql::table>(t))
|
||||
, name(std::move(name))
|
||||
, alias(std::move(as)) {
|
||||
table_->columns.push_back(*this);
|
||||
}
|
||||
|
||||
column::column(const std::shared_ptr<table>& t, std::string name, std::string as)
|
||||
: table_(t)
|
||||
, name(std::move(name))
|
||||
, alias(std::move(as)) {
|
||||
}
|
||||
|
||||
bool column::equals(const column &x) const
|
||||
{
|
||||
return *table_ == *x.table_ &&
|
||||
name == x.name &&
|
||||
alias == x.alias &&
|
||||
function_ == x.function_;
|
||||
}
|
||||
|
||||
column &column::as(std::string a)
|
||||
{
|
||||
alias = std::move(a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool column::is_function() const
|
||||
{
|
||||
return function_ != sql_function_t::NONE;
|
||||
}
|
||||
|
||||
bool column::has_alias() const {
|
||||
return !alias.empty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
#include "matador/sql/column_definition.hpp"
|
||||
|
||||
#include <ostream>
|
||||
#include <utility>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
column_definition::column_definition(const char *name)
|
||||
: name_(name)
|
||||
, attributes_(utils::null_attributes)
|
||||
{}
|
||||
|
||||
column_definition::column_definition(std::string name)
|
||||
: name_(std::move(name))
|
||||
, attributes_(utils::null_attributes)
|
||||
{}
|
||||
|
||||
column_definition::column_definition(std::string name, const utils::basic_type type, const utils::field_attributes& attr, const null_option null_opt, const size_t index)
|
||||
: name_(std::move(name))
|
||||
, index_(index)
|
||||
, attributes_(attr)
|
||||
, null_option_(null_opt)
|
||||
, value_(type, attr.size())
|
||||
{}
|
||||
|
||||
column_definition::column_definition(std::string name,
|
||||
const utils::basic_type type,
|
||||
const size_t index,
|
||||
std::string ref_table,
|
||||
std::string ref_column,
|
||||
const utils::field_attributes& attr, const null_option null_opt)
|
||||
: name_(std::move(name))
|
||||
, index_(index)
|
||||
, attributes_(attr)
|
||||
, null_option_(null_opt)
|
||||
, value_(type, attr.size())
|
||||
, ref_table_(std::move(ref_table))
|
||||
, ref_column_(std::move(ref_column))
|
||||
{}
|
||||
|
||||
const std::string &column_definition::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
std::string column_definition::full_name() const
|
||||
{
|
||||
return table_ + "." + name_;
|
||||
}
|
||||
|
||||
std::string column_definition::table_name() const
|
||||
{
|
||||
return table_;
|
||||
}
|
||||
|
||||
int column_definition::index() const
|
||||
{
|
||||
return index_;
|
||||
}
|
||||
|
||||
const utils::field_attributes &column_definition::attributes() const
|
||||
{
|
||||
return attributes_;
|
||||
}
|
||||
|
||||
bool column_definition::is_nullable() const
|
||||
{
|
||||
return null_option_ == null_option::NULLABLE;
|
||||
}
|
||||
|
||||
utils::basic_type column_definition::type() const
|
||||
{
|
||||
return value_.type();
|
||||
}
|
||||
|
||||
const std::string &column_definition::ref_table() const
|
||||
{
|
||||
return ref_table_;
|
||||
}
|
||||
|
||||
const std::string &column_definition::ref_column() const
|
||||
{
|
||||
return ref_column_;
|
||||
}
|
||||
|
||||
bool column_definition::is_foreign_reference() const
|
||||
{
|
||||
return !ref_column_.empty() && !ref_table_.empty();
|
||||
}
|
||||
|
||||
bool column_definition::is_integer() const
|
||||
{
|
||||
return value_.is_integer();
|
||||
}
|
||||
|
||||
bool column_definition::is_floating_point() const
|
||||
{
|
||||
return value_.is_floating_point();
|
||||
}
|
||||
|
||||
bool column_definition::is_bool() const
|
||||
{
|
||||
return value_.is_bool();
|
||||
}
|
||||
|
||||
bool column_definition::is_string() const
|
||||
{
|
||||
return value_.is_string();
|
||||
}
|
||||
|
||||
bool column_definition::is_varchar() const
|
||||
{
|
||||
return value_.is_varchar();
|
||||
}
|
||||
|
||||
bool column_definition::is_date() const
|
||||
{
|
||||
return value_.is_date();
|
||||
}
|
||||
|
||||
bool column_definition::is_time() const
|
||||
{
|
||||
return value_.is_time();
|
||||
}
|
||||
|
||||
bool column_definition::is_blob() const
|
||||
{
|
||||
return value_.is_blob();
|
||||
}
|
||||
|
||||
bool column_definition::is_null() const
|
||||
{
|
||||
return value_.is_null();
|
||||
}
|
||||
|
||||
void column_definition::type(utils::basic_type /*type*/)
|
||||
{
|
||||
// type_ = type;
|
||||
// utils::initialize_by_utils::basic_type(type, value_);
|
||||
}
|
||||
|
||||
std::string column_definition::str() const
|
||||
{
|
||||
return value_.str();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream &out, const column_definition &col)
|
||||
{
|
||||
out << col.str();
|
||||
return out;
|
||||
}
|
||||
|
||||
column_definition make_column(const std::string &name, utils::basic_type type, utils::field_attributes attr, null_option null_opt)
|
||||
{
|
||||
return {name, type, attr, null_opt};
|
||||
}
|
||||
|
||||
template<>
|
||||
column_definition make_column<std::string>(const std::string &name, utils::field_attributes attr, null_option null_opt)
|
||||
{
|
||||
return make_column(name, utils::data_type_traits<std::string>::type(attr.size()), attr, null_opt);
|
||||
}
|
||||
|
||||
template<>
|
||||
column_definition make_pk_column<std::string>(const std::string &name, size_t size)
|
||||
{
|
||||
return make_column<std::string>(name, {size, utils::constraints::FOREIGN_KEY});
|
||||
}
|
||||
|
||||
template<>
|
||||
[[maybe_unused]] column_definition make_fk_column<std::string>(const std::string &name, size_t size, const std::string &ref_table,
|
||||
const std::string &ref_column)
|
||||
{
|
||||
return {name, utils::data_type_traits<std::string>::type(size), 0, ref_table, ref_column, {size, utils::constraints::FOREIGN_KEY}, null_option::NOT_NULL};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
#include "matador/sql/connection.hpp"
|
||||
|
||||
#include "matador/sql/backend_provider.hpp"
|
||||
#include "matador/sql/dialect.hpp"
|
||||
#include "matador/sql/dialect_token.hpp"
|
||||
// #include "matador/sql/schema.hpp"
|
||||
// #include "matador/sql/query_compile_context.hpp"
|
||||
#include "matador/sql/interface/connection_impl.hpp"
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
connection::connection(connection_info info, const std::shared_ptr<abstract_sql_logger> &sql_logger)
|
||||
: connection_info_(std::move(info))
|
||||
, logger_(sql_logger)
|
||||
{
|
||||
connection_.reset(backend_provider::instance().create_connection(connection_info_.type, connection_info_));
|
||||
}
|
||||
|
||||
connection::connection(const std::string& dns, const std::shared_ptr<abstract_sql_logger> &sql_logger)
|
||||
: connection(connection_info::parse(dns), sql_logger)
|
||||
{}
|
||||
|
||||
connection::connection(const connection &x)
|
||||
: connection_info_(x.connection_info_)
|
||||
{
|
||||
if (x.connection_) {
|
||||
throw std::runtime_error("couldn't copy connection with valid connection impl");
|
||||
}
|
||||
}
|
||||
|
||||
connection &connection::operator=(const connection &x) {
|
||||
if (this == &x) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
connection_info_ = x.connection_info_;
|
||||
if (x.connection_) {
|
||||
throw std::runtime_error("couldn't copy connection with valid connection impl");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
connection & connection::operator=(connection &&x) noexcept {
|
||||
connection_info_ = std::move(x.connection_info_);
|
||||
connection_ = std::move(x.connection_);
|
||||
logger_ = std::move(x.logger_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
connection::~connection()
|
||||
{
|
||||
if (connection_->is_open()) {
|
||||
connection_->close();
|
||||
}
|
||||
backend_provider::instance().destroy_connection(connection_info_.type, connection_.release());
|
||||
connection_ = nullptr;
|
||||
}
|
||||
|
||||
utils::result<void, utils::error> connection::open() const
|
||||
{
|
||||
const auto res = is_open();
|
||||
if (res.is_error()) {
|
||||
return utils::failure(res.err());
|
||||
}
|
||||
if (*res) {
|
||||
logger_->on_connect();
|
||||
return connection_->open();
|
||||
}
|
||||
return utils::ok<void>();
|
||||
}
|
||||
|
||||
utils::result<void, utils::error> connection::close() const
|
||||
{
|
||||
logger_->on_close();
|
||||
return connection_->close();
|
||||
}
|
||||
|
||||
utils::result<bool, utils::error> connection::is_open() const
|
||||
{
|
||||
return connection_->is_open();
|
||||
}
|
||||
|
||||
const connection_info &connection::info() const
|
||||
{
|
||||
return connection_info_;
|
||||
}
|
||||
|
||||
std::string connection::type() const {
|
||||
return connection_info_.type;
|
||||
}
|
||||
|
||||
utils::result<void, utils::error> connection::begin() const {
|
||||
const auto res = connection_->execute(dialect().token_at(dialect_token::BEGIN));
|
||||
if (res.is_error()) {
|
||||
return utils::failure(res.err());
|
||||
}
|
||||
|
||||
return utils::ok<void>();
|
||||
}
|
||||
|
||||
utils::result<void, utils::error> connection::commit() const {
|
||||
const auto res = connection_->execute(dialect().token_at(dialect_token::COMMIT));
|
||||
if (res.is_error()) {
|
||||
return utils::failure(res.err());
|
||||
}
|
||||
|
||||
return utils::ok<void>();
|
||||
}
|
||||
|
||||
utils::result<void, utils::error> connection::rollback() const {
|
||||
const auto res = connection_->execute(dialect().token_at(dialect_token::ROLLBACK));
|
||||
if (res.is_error()) {
|
||||
return utils::failure(res.err());
|
||||
}
|
||||
|
||||
return utils::ok<void>();
|
||||
}
|
||||
|
||||
utils::result<std::vector<column_definition>, utils::error> connection::describe(const std::string &table_name) const
|
||||
{
|
||||
return connection_->describe(table_name);
|
||||
}
|
||||
|
||||
utils::result<bool, utils::error> connection::exists(const std::string &schema_name, const std::string &table_name) const
|
||||
{
|
||||
return connection_->exists(schema_name, table_name);
|
||||
}
|
||||
|
||||
utils::result<bool, utils::error> connection::exists(const std::string &table_name) const
|
||||
{
|
||||
return connection_->exists(dialect().default_schema_name(), table_name);
|
||||
}
|
||||
|
||||
utils::result<size_t, utils::error> connection::execute(const std::string &sql) const
|
||||
{
|
||||
// logger_.debug(sql);
|
||||
return connection_->execute(sql);
|
||||
}
|
||||
|
||||
bool has_unknown_columns(const std::vector<sql::column_definition> &columns) {
|
||||
return std::any_of(std::begin(columns), std::end(columns), [](const auto &col) {
|
||||
return col.type() == utils::basic_type::type_null;
|
||||
});
|
||||
}
|
||||
|
||||
// query_result<record> connection::fetch(const query_context &ctx) const
|
||||
// {
|
||||
// if (ctx.prototype.empty() || is_unknown(ctx.prototype)) {
|
||||
// const auto table_prototype = describe(ctx.table.name);
|
||||
// for (auto &col : ctx.prototype) {
|
||||
// const auto rit = std::find_if(std::begin(table_prototype), std::end(table_prototype), [&col](const auto &value) {
|
||||
// return value.name() == col.name();
|
||||
// });
|
||||
// if (col.type() == data_type::type_unknown && rit != table_prototype.end()) {
|
||||
// const_cast<column_definition&>(col).type(rit->type());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // auto it = prototypes_.find(q.table_name);
|
||||
// // if (it == prototypes_.end()) {
|
||||
// // it = prototypes_.emplace(q.table_name, describe(q.table_name)).first;
|
||||
// // }
|
||||
// // // adjust columns from given query
|
||||
// // for (auto &col : q.prototype) {
|
||||
// // if (const auto rit = it->second.find(col.name()); col.type() == data_type_t::type_unknown && rit != it->second.end()) {
|
||||
// // const_cast<column&>(col).type(rit->type());
|
||||
// // }
|
||||
// // }
|
||||
// auto res = fetch(ctx.sql);
|
||||
// return query_result<record>{std::move(res), ctx.prototype};
|
||||
// }
|
||||
|
||||
utils::result<std::unique_ptr<query_result_impl>, utils::error> connection::fetch(const query_context &ctx) const
|
||||
{
|
||||
// logger_.debug(sql);
|
||||
return connection_->fetch(ctx);
|
||||
// return connection_->fetch(dialect().compile(ctx, *connection_));
|
||||
}
|
||||
|
||||
utils::result<size_t, utils::error> connection::execute(const query_context& ctx) const
|
||||
{
|
||||
return execute(ctx.sql);
|
||||
// return execute(dialect().compile(ctx, *connection_).sql);
|
||||
}
|
||||
|
||||
utils::result<statement, utils::error> connection::prepare(const query_context &ctx) const
|
||||
{
|
||||
if (ctx.command != sql_command::SQL_CMD_CREATE && (ctx.prototype.empty() || has_unknown_columns(ctx.prototype))) {
|
||||
if (const auto result = describe(ctx.table.name); result.is_ok()) {
|
||||
for (auto &col: ctx.prototype) {
|
||||
const auto rit = std::find_if(std::begin(*result), std::end(*result),
|
||||
[&col](const auto &value) {
|
||||
return value.name() == col.name();
|
||||
});
|
||||
if (col.type() == utils::basic_type::type_null && rit != result->end()) {
|
||||
const_cast<column_definition &>(col).type(rit->type());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return connection_->prepare(qry).and_then([](auto &&res) {
|
||||
// return statement(std::forward<decltype(res)>(res));
|
||||
// });
|
||||
if (auto result = connection_->prepare(ctx); result.is_ok()) {
|
||||
return utils::ok(statement(result.release()));
|
||||
}
|
||||
|
||||
return utils::ok(statement(std::unique_ptr<statement_impl>{}));
|
||||
}
|
||||
|
||||
std::string connection::str( const query_context& ctx ) const
|
||||
{
|
||||
return ctx.sql;
|
||||
}
|
||||
|
||||
const class dialect &connection::dialect() const
|
||||
{
|
||||
return connection_->dialect();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "matador/sql/connection_info.hpp"
|
||||
|
||||
#include <regex>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
connection_info connection_info::parse(const std::string &info, unsigned short default_port, const std::string &default_driver) {
|
||||
static const std::regex DNS_RGX (R"((\w+):\/\/((([\w]+)(:([\w!]+))?)@)?((((([\w.\(\)\\]+)([:]([\d]+))?)?)\/)?(([\w.]+)( \((.*)\))?)))");
|
||||
|
||||
std::smatch what;
|
||||
|
||||
if (!std::regex_match(info, what, DNS_RGX)) {
|
||||
throw std::logic_error("connect invalid dns: " + info);
|
||||
}
|
||||
|
||||
connection_info ci{};
|
||||
ci.type = what[1].str();
|
||||
ci.user = what[4].str();
|
||||
ci.password = what[6].str();
|
||||
|
||||
// get connection part
|
||||
ci.hostname = what[11].str();
|
||||
if (what[13].matched) {
|
||||
char *end;
|
||||
ci.port = static_cast<unsigned short>(std::strtoul(what[13].str().c_str(), &end, 10));
|
||||
} else {
|
||||
ci.port = default_port;
|
||||
}
|
||||
|
||||
// Should we just ignore the "instance" part?
|
||||
// const std::string instance = what[5].str();
|
||||
ci.database = what[15].str();
|
||||
|
||||
if (what[17].matched) {
|
||||
ci.driver = what[17].str();
|
||||
} else {
|
||||
ci.driver = default_driver;
|
||||
}
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
std::string connection_info::to_string(const connection_info &ci) {
|
||||
std::string dns{ci.type};
|
||||
dns += "://";
|
||||
|
||||
if (!ci.user.empty()) {
|
||||
dns += ci.user;
|
||||
if (!ci.password.empty()) {
|
||||
dns += ":" + ci.password;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ci.hostname.empty()) {
|
||||
dns += "@" + ci.hostname;
|
||||
if (ci.port > 0) {
|
||||
dns += ":" + std::to_string(ci.port);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dns.empty()) {
|
||||
dns += "/";
|
||||
}
|
||||
dns += ci.database;
|
||||
|
||||
if (!ci.driver.empty()) {
|
||||
dns += " (" + ci.driver +")";
|
||||
}
|
||||
return dns;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
#include "matador/sql/dialect.hpp"
|
||||
|
||||
#include "matador/sql/interface/connection_impl.hpp"
|
||||
|
||||
#include "matador/utils/string.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
const std::string& dialect::token_at(const dialect_token token) const
|
||||
{
|
||||
return tokens_.at(token);
|
||||
}
|
||||
|
||||
const std::string &dialect::data_type_at(const utils::basic_type type) const
|
||||
{
|
||||
return data_types_.at(type);
|
||||
}
|
||||
|
||||
std::string dialect::prepare_identifier(const column &col) const
|
||||
{
|
||||
std::string result;
|
||||
if (!col.is_function()) {
|
||||
if (!col.table_->name.empty()) {
|
||||
result = prepare_identifier_string(col.table_->has_alias() ? col.table_->alias : col.table_->name) + ".";
|
||||
}
|
||||
result += prepare_identifier_string(col.name);
|
||||
} else {
|
||||
result = sql_func_map_.at(col.function_) + "(" + col.name + ")";
|
||||
}
|
||||
if (!col.alias.empty()) {
|
||||
result += " AS " + col.alias;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string dialect::prepare_condition(const column& col) const
|
||||
{
|
||||
std::string result;
|
||||
if (!col.is_function()) {
|
||||
// if (!col.alias.empty()) {
|
||||
// result = col.alias;
|
||||
// } else {
|
||||
if (!col.table_->name.empty()) {
|
||||
result = prepare_identifier_string(col.table_->has_alias() ? col.table_->alias : col.table_->name) + ".";
|
||||
}
|
||||
result += prepare_identifier_string(col.name);
|
||||
// }
|
||||
} else {
|
||||
result = sql_func_map_.at(col.function_) + "(" + col.name + ")";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string& dialect::to_string(const bool val) const
|
||||
{
|
||||
return bool_strings_[static_cast<int>(val)];
|
||||
}
|
||||
|
||||
void dialect::bool_strings(const std::string &true_string, const std::string &false_string)
|
||||
{
|
||||
bool_strings_[0] = false_string;
|
||||
bool_strings_[1] = true_string;
|
||||
}
|
||||
|
||||
std::string dialect::prepare_identifier_string(const std::string &col) const
|
||||
{
|
||||
auto parts = utils::split(col, '.');
|
||||
|
||||
for (auto &part : parts) {
|
||||
escape_quotes_in_identifier(part);
|
||||
quote_identifier(part);
|
||||
}
|
||||
return utils::join(parts, ".");
|
||||
}
|
||||
|
||||
std::string dialect::prepare_literal(const std::string &str) const
|
||||
{
|
||||
std::string result(str);
|
||||
escape_quotes_in_literals(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void dialect::quote_identifier(std::string &str) const
|
||||
{
|
||||
str.insert(0, token_at(dialect_token::START_QUOTE));
|
||||
str += token_at(dialect_token::END_QUOTE);
|
||||
}
|
||||
|
||||
void dialect::escape_quotes_in_identifier(std::string &str) const
|
||||
{
|
||||
const std::string open_char(token_at(dialect_token::START_QUOTE));
|
||||
const std::string close_char(token_at(dialect_token::END_QUOTE));
|
||||
if (identifier_escape_type() == escape_identifier_t::ESCAPE_CLOSING_BRACKET) {
|
||||
utils::replace_all(str, close_char, close_char + close_char);
|
||||
} else {
|
||||
utils::replace_all(str, open_char, open_char + open_char);
|
||||
}
|
||||
}
|
||||
|
||||
void dialect::escape_quotes_in_literals(std::string &str) const
|
||||
{
|
||||
const std::string single_quote(token_at(dialect_token::STRING_QUOTE));
|
||||
const std::string double_quote(token_at(dialect_token::STRING_QUOTE) + token_at(dialect_token::STRING_QUOTE));
|
||||
utils::replace_all(str, single_quote, double_quote);
|
||||
}
|
||||
|
||||
dialect::escape_identifier_t dialect::identifier_escape_type() const {
|
||||
return identifier_escape_type_;
|
||||
}
|
||||
|
||||
void dialect::identifier_escape_type(escape_identifier_t escape_identifier) {
|
||||
identifier_escape_type_ = escape_identifier;
|
||||
}
|
||||
|
||||
std::string dialect::next_placeholder(const std::vector<std::string> &bind_vars) const
|
||||
{
|
||||
return placeholder_func_(bind_vars.size());
|
||||
}
|
||||
|
||||
std::string dialect::to_escaped_string(const utils::blob &value, const connection_impl *conn) const
|
||||
{
|
||||
if (conn != nullptr) {
|
||||
return conn->to_escaped_string(value);
|
||||
}
|
||||
|
||||
return {};
|
||||
// return to_escaped_string_func_(value);
|
||||
}
|
||||
|
||||
std::string dialect::default_schema_name() const
|
||||
{
|
||||
return default_schema_name_;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "matador/sql/dialect_builder.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
dialect_builder &dialect_builder::builder()
|
||||
{
|
||||
static dialect_builder instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
dialect_builder &dialect_builder::create()
|
||||
{
|
||||
dialect_ = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
dialect_builder& dialect_builder::with_token_replace_map(const dialect::token_to_string_map &token_replace_map)
|
||||
{
|
||||
for (const auto &token : token_replace_map) {
|
||||
dialect_.tokens_[token.first] = token.second;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dialect_builder& dialect_builder::with_data_type_replace_map(const dialect::data_type_to_string_map &data_type_replace_map)
|
||||
{
|
||||
for (const auto &data_type : data_type_replace_map) {
|
||||
dialect_.data_types_[data_type.first] = data_type.second;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dialect_builder& dialect_builder::with_placeholder_func(const dialect::next_placeholder_func &func)
|
||||
{
|
||||
dialect_.placeholder_func_ = func;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dialect_builder &dialect_builder::with_default_schema_name(const std::string &schema_name)
|
||||
{
|
||||
dialect_.default_schema_name_ = schema_name;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dialect_builder &dialect_builder::with_bool_strings(const std::string &true_string, const std::string &false_string)
|
||||
{
|
||||
dialect_.bool_strings(true_string, false_string);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dialect dialect_builder::build()
|
||||
{
|
||||
return std::move(dialect_);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "matador/sql/error_code.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
const char * sql_category_impl::name() const noexcept {
|
||||
return "sql";
|
||||
}
|
||||
|
||||
std::string sql_category_impl::message(const int ev) const {
|
||||
switch (static_cast<error_code>(ev)) {
|
||||
case error_code::OK:
|
||||
return "OK";
|
||||
case error_code::INVALID_QUERY:
|
||||
return "Invalid query";
|
||||
case error_code::UNKNOWN_TABLE:
|
||||
return "Unknown table";
|
||||
case error_code::UNKNOWN_COLUMN:
|
||||
return "Unknown column";
|
||||
case error_code::BIND_FAILED:
|
||||
return "Bind failed";
|
||||
case error_code::EXECUTE_FAILED:
|
||||
return "Execute failed";
|
||||
case error_code::FETCH_FAILED:
|
||||
return "Fetch failed";
|
||||
case error_code::PREPARE_FAILED:
|
||||
return "Prepare failed";
|
||||
case error_code::DESCRIBE_FAILED:
|
||||
return "Describe failed";
|
||||
case error_code::TABLE_EXISTS_FAILED:
|
||||
return "Table exists failed";
|
||||
case error_code::RETRIEVE_DATA_FAILED:
|
||||
return "Retrieve data failed";
|
||||
case error_code::RESET_FAILED:
|
||||
return "Reset failed";
|
||||
case error_code::OPEN_ERROR:
|
||||
return "Open failed";
|
||||
case error_code::CLOSE_ERROR:
|
||||
return "Close failed";
|
||||
case error_code::FAILURE:
|
||||
return "Failure";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
const std::error_category & sql_category() {
|
||||
static sql_category_impl instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::error_code make_error_code(error_code e) {
|
||||
return {static_cast<int>(e), sql_category()};
|
||||
}
|
||||
|
||||
std::error_condition make_error_condition(error_code e) {
|
||||
return {static_cast<int>(e), sql_category()};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include "matador/sql/executor.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
executor::~executor() = default;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "matador/sql/field.hpp"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
field::field(std::string name)
|
||||
: name_(std::move(name))
|
||||
, value_(nullptr)
|
||||
{}
|
||||
|
||||
field::field(std::string name, const utils::basic_type dt, const size_t size, const int index)
|
||||
: name_(std::move(name))
|
||||
, index_(index)
|
||||
, value_(dt, size) {}
|
||||
|
||||
field::field(field &&x) noexcept
|
||||
: name_(std::move(x.name_))
|
||||
, index_(x.index_)
|
||||
, value_(std::move(x.value_))
|
||||
{
|
||||
x.value_ = nullptr;
|
||||
x.index_ = -1;
|
||||
}
|
||||
|
||||
field &field::operator=(field &&x) noexcept
|
||||
{
|
||||
name_ = std::move(x.name_);
|
||||
index_ = x.index_;
|
||||
value_ = std::move(x.value_);
|
||||
x.index_ = -1;
|
||||
x.value_ = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::string &field::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
size_t field::size() const
|
||||
{
|
||||
return value_.size();
|
||||
}
|
||||
|
||||
int field::index() const
|
||||
{
|
||||
return index_;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const field &col)
|
||||
{
|
||||
out << col.str();
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string field::str() const
|
||||
{
|
||||
return as<std::string>().value_or("");
|
||||
}
|
||||
|
||||
bool field::is_integer() const
|
||||
{
|
||||
return value_.is_integer();
|
||||
}
|
||||
|
||||
bool field::is_floating_point() const
|
||||
{
|
||||
return value_.is_floating_point();
|
||||
}
|
||||
|
||||
bool field::is_bool() const
|
||||
{
|
||||
return value_.is_bool();
|
||||
}
|
||||
|
||||
bool field::is_string() const
|
||||
{
|
||||
return value_.is_string();
|
||||
}
|
||||
|
||||
bool field::is_varchar() const
|
||||
{
|
||||
return value_.is_varchar();
|
||||
}
|
||||
|
||||
bool field::is_blob() const
|
||||
{
|
||||
return value_.is_blob();
|
||||
}
|
||||
|
||||
bool field::is_null() const
|
||||
{
|
||||
return value_.is_null();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "matador/sql/interface/connection_impl.hpp"
|
||||
|
||||
#include "matador/sql/backend_provider.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
connection_impl::connection_impl(const connection_info &info)
|
||||
: info_(info)
|
||||
, dialect_(backend_provider::instance().connection_dialect(info.type))
|
||||
{}
|
||||
|
||||
const connection_info &connection_impl::info() const {
|
||||
return info_;
|
||||
}
|
||||
|
||||
const class dialect & connection_impl::dialect() const {
|
||||
return dialect_;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "matador/sql/interface/query_result_reader.hpp"
|
||||
|
||||
#include "matador/utils/basic_types.hpp"
|
||||
#include "matador/utils/convert.hpp"
|
||||
#include "matador/utils/string.hpp"
|
||||
#include "matador/utils/value.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
template < typename Type >
|
||||
void convert(const char *val_str, utils::value &val)
|
||||
{
|
||||
if (val_str == nullptr) {
|
||||
val = utils::value(Type{});
|
||||
return;
|
||||
}
|
||||
Type local_val{};
|
||||
const auto res = utils::to<Type>(val_str);
|
||||
val = *res;
|
||||
}
|
||||
|
||||
// utils::blob query_result_reader::read_blob(const size_t index)
|
||||
// {
|
||||
// const auto *data = column(index);
|
||||
// if (data == nullptr) {
|
||||
// return {};
|
||||
// }
|
||||
// const auto len = strlen(data);
|
||||
// const auto *bytes = reinterpret_cast<const unsigned char*>(data);
|
||||
// return utils::blob{bytes, bytes+len};
|
||||
// }
|
||||
|
||||
// utils::attribute_reader &query_result_reader::result_binder()
|
||||
// {
|
||||
// return empty_result_binder_;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "matador/sql/interface/statement_impl.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
statement_impl::statement_impl(query_context query)
|
||||
: query_(std::move(query))
|
||||
{}
|
||||
|
||||
void statement_impl::bind(const size_t pos, const char *value, const size_t size)
|
||||
{
|
||||
utils::data_type_traits<const char*>::bind_value(binder(), adjust_index(pos), value, size);
|
||||
}
|
||||
|
||||
void statement_impl::bind(const size_t pos, std::string &val, const size_t size)
|
||||
{
|
||||
utils::data_type_traits<std::string>::bind_value(binder(), adjust_index(pos), val, size);
|
||||
}
|
||||
|
||||
const std::vector<std::string> &statement_impl::bind_vars() const
|
||||
{
|
||||
return query_.bind_vars;
|
||||
}
|
||||
|
||||
bool statement_impl::is_valid_host_var(const std::string &host_var, const size_t pos) const
|
||||
{
|
||||
const auto host_var_at_pos = bind_vars().at(pos);
|
||||
|
||||
return host_var_at_pos == host_var;
|
||||
}
|
||||
|
||||
size_t statement_impl::start_index() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t statement_impl::adjust_index( size_t index ) const
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "matador/sql/internal/object_result_binder.hpp"
|
||||
|
||||
#include "matador/utils/data_type_traits.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
namespace detail {
|
||||
|
||||
void fk_result_binder::on_primary_key(const char * /*id*/, std::string &value, const size_t size)
|
||||
{
|
||||
utils::data_type_traits<std::string>::read_value(*binder_, id_, index_++, value, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void object_result_binder::reset()
|
||||
{
|
||||
index_ = 0;
|
||||
}
|
||||
|
||||
void object_result_binder::on_primary_key(const char *id, std::string &value, const size_t size)
|
||||
{
|
||||
utils::data_type_traits<std::string>::read_value(*binder_, id, index_++, value, size);
|
||||
}
|
||||
|
||||
void object_result_binder::on_revision(const char *id, uint64_t &value)
|
||||
{
|
||||
utils::data_type_traits<uint64_t>::read_value(*binder_, id, index_++, value);
|
||||
}
|
||||
|
||||
void object_result_binder::on_attribute(const char *id, char *value, const utils::field_attributes &attr)
|
||||
{
|
||||
utils::data_type_traits<char*>::read_value(*binder_, id, index_++, value, attr.size());
|
||||
}
|
||||
|
||||
void object_result_binder::on_attribute(const char *id, std::string &value, const utils::field_attributes &attr)
|
||||
{
|
||||
utils::data_type_traits<std::string>::read_value(*binder_, id, index_++, value, attr.size());
|
||||
}
|
||||
|
||||
void object_result_binder::on_attribute(const char * /*id*/, utils::value &/*val*/, const utils::field_attributes &/*attr*/)
|
||||
{
|
||||
// utils::data_type_traits<utils::value>::read_value(*binder_, id, index_++, val);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "matador/sql/object_parameter_binder.hpp"
|
||||
#include "matador/sql/interface/parameter_binder.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
namespace detail {
|
||||
|
||||
void fk_binder::on_primary_key(const char * /*id*/, std::string &value, size_t /*size*/)
|
||||
{
|
||||
utils::data_type_traits<std::string>::bind_value(*binder_, index_++, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void object_parameter_binder::reset(const size_t start_index)
|
||||
{
|
||||
index_ = start_index;
|
||||
}
|
||||
|
||||
void object_parameter_binder::on_primary_key(const char * /*id*/, std::string &val, const size_t size)
|
||||
{
|
||||
utils::data_type_traits<std::string>::bind_value(*binder_, index_++, val, size);
|
||||
}
|
||||
|
||||
void object_parameter_binder::on_revision(const char * /*id*/, uint64_t &rev)
|
||||
{
|
||||
utils::data_type_traits<uint64_t>::bind_value(*binder_, index_++, rev);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "matador/sql/query_result.hpp"
|
||||
#include "matador/sql/record.hpp"
|
||||
|
||||
#include "matador/sql/internal/query_result_impl.hpp"
|
||||
|
||||
namespace matador::sql::detail {
|
||||
|
||||
template<>
|
||||
record *create_prototype<record>(const std::vector<column_definition> &prototype)
|
||||
{
|
||||
auto result = std::make_unique<record>();
|
||||
for (const auto &col: prototype) {
|
||||
result->append({col.name(), col.type(), col.attributes().size(), col.index()});
|
||||
}
|
||||
return result.release();
|
||||
}
|
||||
|
||||
|
||||
} // namespace matador::sql
|
||||
@@ -0,0 +1,165 @@
|
||||
#include "matador/sql/record.hpp"
|
||||
#include "matador/sql/column.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
record::record(std::initializer_list<field> columns)
|
||||
{
|
||||
for (auto &&col :columns) {
|
||||
const auto it = fields_by_name_.emplace(col.name(), field_index_pair {col, fields_.size()});
|
||||
fields_.push_back(std::ref(it.first->second.first));
|
||||
}
|
||||
}
|
||||
|
||||
record::record(const std::vector<field> &columns)
|
||||
{
|
||||
for (auto &&col :columns) {
|
||||
const auto it = fields_by_name_.emplace(col.name(), field_index_pair {col, fields_.size()});
|
||||
fields_.push_back(std::ref(it.first->second.first));
|
||||
}
|
||||
}
|
||||
|
||||
record::record(const record &x)
|
||||
: fields_by_name_(x.fields_by_name_)
|
||||
//, pk_index_(x.pk_index_)
|
||||
{
|
||||
for (auto& col : x.fields_) {
|
||||
auto &it = fields_by_name_.at(col.get().name());
|
||||
fields_.push_back(std::ref(it.first));
|
||||
}
|
||||
}
|
||||
|
||||
record &record::operator=(const record &x)
|
||||
{
|
||||
if (&x == this) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
fields_by_name_ = x.fields_by_name_;
|
||||
fields_.clear();
|
||||
// pk_index_ = x.pk_index_;
|
||||
for (auto& col : x.fields_) {
|
||||
auto &it = fields_by_name_.at(col.get().name());
|
||||
fields_.push_back(std::ref(it.first));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::vector<record::field_ref> &record::columns() const
|
||||
{
|
||||
return fields_;
|
||||
}
|
||||
|
||||
//bool record::has_primary_key() const
|
||||
//{
|
||||
// return pk_index_ > -1;
|
||||
//}
|
||||
//
|
||||
//std::optional<field> record::primary_key() const
|
||||
//{
|
||||
// if (!has_primary_key()) {
|
||||
// return std::nullopt;
|
||||
// }
|
||||
//
|
||||
// return columns_[pk_index_];
|
||||
//}
|
||||
|
||||
const field &record::at(const column &col) const
|
||||
{
|
||||
const auto &res = fields_by_name_.at(col.name);
|
||||
const auto &f = res.first;
|
||||
return f;
|
||||
}
|
||||
|
||||
const field &record::at(size_t index) const
|
||||
{
|
||||
return fields_.at(index);
|
||||
}
|
||||
|
||||
record::iterator record::find(const std::string &column_name)
|
||||
{
|
||||
auto it = fields_by_name_.find(column_name);
|
||||
return it != fields_by_name_.end() ? fields_.begin() + it->second.second : fields_.end();
|
||||
}
|
||||
|
||||
record::const_iterator record::find(const std::string &column_name) const {
|
||||
auto it = fields_by_name_.find(column_name);
|
||||
return it != fields_by_name_.end() ? fields_.begin() + it->second.second : fields_.end();
|
||||
}
|
||||
|
||||
void record::append(const field &col)
|
||||
{
|
||||
const auto it = fields_by_name_.emplace(col.name(), field_index_pair {col, fields_.size()});
|
||||
fields_.push_back(std::ref(it.first->second.first));
|
||||
}
|
||||
|
||||
record::iterator record::begin()
|
||||
{
|
||||
return fields_.begin();
|
||||
}
|
||||
|
||||
record::const_iterator record::begin() const
|
||||
{
|
||||
return fields_.begin();
|
||||
}
|
||||
|
||||
record::const_iterator record::cbegin() const
|
||||
{
|
||||
return fields_.cbegin();
|
||||
}
|
||||
|
||||
record::iterator record::end()
|
||||
{
|
||||
return fields_.end();
|
||||
}
|
||||
|
||||
record::const_iterator record::end() const
|
||||
{
|
||||
return fields_.end();
|
||||
}
|
||||
|
||||
record::const_iterator record::cend() const
|
||||
{
|
||||
return fields_.cend();
|
||||
}
|
||||
|
||||
size_t record::size() const
|
||||
{
|
||||
return fields_.size();
|
||||
}
|
||||
|
||||
bool record::empty() const
|
||||
{
|
||||
return fields_.empty();
|
||||
}
|
||||
|
||||
void record::clear()
|
||||
{
|
||||
fields_.clear();
|
||||
fields_by_name_.clear();
|
||||
}
|
||||
|
||||
//bool record::unknown() const
|
||||
//{
|
||||
// return std::all_of(std::begin(columns_), std::end(columns_), [](const auto &col) {
|
||||
// return col.type() == data_type_t::type_unknown;
|
||||
// });
|
||||
//}
|
||||
|
||||
void record::init()
|
||||
{
|
||||
size_t index{0};
|
||||
for(auto &col : fields_) {
|
||||
add_to_map(col, index++);
|
||||
}
|
||||
}
|
||||
|
||||
void record::add_to_map(field &col, size_t index)
|
||||
{
|
||||
fields_by_name_.emplace(col.name(), field_index_pair {std::ref(col), index});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "matador/sql/statement.hpp"
|
||||
#include "matador/sql/record.hpp"
|
||||
#include "matador/sql/field.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
statement::statement(std::unique_ptr<statement_impl> impl, const std::shared_ptr<abstract_sql_logger> &logger)
|
||||
: statement_(std::move(impl))
|
||||
, logger_(logger)
|
||||
{}
|
||||
|
||||
statement &statement::bind(const size_t pos, const char *value)
|
||||
{
|
||||
statement_->bind(pos, value, 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
statement &statement::bind(const size_t pos, std::string &val, const size_t size)
|
||||
{
|
||||
statement_->bind(pos, val, size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
utils::result<size_t, utils::error> statement::execute() const
|
||||
{
|
||||
// logger_.info(statement_->query_.sql);
|
||||
return statement_->execute();
|
||||
}
|
||||
|
||||
//bool is_unknown(const std::vector<sql::column_definition> &columns) {
|
||||
// return std::all_of(std::begin(columns), std::end(columns), [](const auto &col) {
|
||||
// return col.is_unknown();
|
||||
// });
|
||||
//}
|
||||
|
||||
utils::result<query_result<record>, utils::error> statement::fetch() const
|
||||
{
|
||||
// if (is_unknown(statement_->query_.prototype)) {
|
||||
//
|
||||
// }
|
||||
|
||||
auto result = statement_->fetch();
|
||||
if (!result.is_ok()) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
// logger_.info(statement_->query_.sql);
|
||||
return utils::ok(query_result<record>{std::move(*result)});
|
||||
}
|
||||
|
||||
utils::result<std::optional<record>, utils::error> statement::fetch_one() const {
|
||||
// logger_.info(statement_->query_.sql);
|
||||
auto result = statement_->fetch();
|
||||
if (!result.is_ok()) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
|
||||
query_result<record> records(std::move(*result));
|
||||
auto first = records.begin();
|
||||
if (first == records.end()) {
|
||||
return utils::ok(std::optional<record>{std::nullopt});
|
||||
}
|
||||
|
||||
return utils::ok(std::optional{*first.release()});
|
||||
}
|
||||
|
||||
void statement::reset() const
|
||||
{
|
||||
statement_->reset();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "matador/sql/table.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
table::table(const char* name)
|
||||
: table(std::string(name))
|
||||
{}
|
||||
|
||||
table::table(std::string name)
|
||||
: name(std::move(name))
|
||||
{}
|
||||
|
||||
table::table(const char *name, std::string as)
|
||||
: name(name)
|
||||
, alias(std::move(as))
|
||||
{}
|
||||
|
||||
table::table(std::string name, std::string as)
|
||||
: name(std::move(name))
|
||||
, alias(std::move(as))
|
||||
{}
|
||||
|
||||
bool table::operator==( const table& x ) const {
|
||||
return name == x.name;
|
||||
}
|
||||
|
||||
table & table::as(const std::string &a) {
|
||||
alias = a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
table table::as(const std::string &a) const {
|
||||
return { name, a, columns };
|
||||
}
|
||||
|
||||
bool table::has_alias() const {
|
||||
return !alias.empty();
|
||||
}
|
||||
|
||||
table operator ""_tab(const char *name, size_t len) {
|
||||
return {{name, len}};
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user