#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 #include #include namespace matador::sql { connection::connection(connection_info info, const std::shared_ptr &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 &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( connection&& x ) noexcept : connection_info_(std::move(x.connection_info_)) , connection_(std::move(x.connection_)) , logger_(std::move(x.logger_)) {} 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 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(); } utils::result connection::close() const { logger_->on_close(); return connection_->close(); } utils::result 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 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(); } utils::result 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(); } utils::result 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(); } utils::result, utils::error> connection::describe(const std::string &table_name) const { return connection_->describe(table_name); } utils::result connection::exists(const std::string &schema_name, const std::string &table_name) const { return connection_->exists(schema_name, table_name); } utils::result connection::exists(const std::string &table_name) const { return connection_->exists(dialect().default_schema_name(), table_name); } utils::result connection::execute(const std::string &sql) const { // logger_.debug(sql); return connection_->execute(sql); } bool has_unknown_columns(const std::vector &columns) { return std::any_of(std::begin(columns), std::end(columns), [](const auto &col) { return col.type() == utils::basic_type::type_null; }); } // query_result 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(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(col).type(rit->type()); // // } // // } // auto res = fetch(ctx.sql); // return query_result{std::move(res), ctx.prototype}; // } utils::result, 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 connection::execute(const query_context& ctx) const { return execute(ctx.sql); // return execute(dialect().compile(ctx, *connection_).sql); } utils::result 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(col).type(rit->type()); } } } } // return connection_->prepare(qry).and_then([](auto &&res) { // return statement(std::forward(res)); // }); if (auto result = connection_->prepare(ctx); result.is_ok()) { return utils::ok(statement(result.release())); } return utils::ok(statement(std::unique_ptr{})); } std::string connection::str( const query_context& ctx ) const { return ctx.sql; } const class dialect &connection::dialect() const { return connection_->dialect(); } }