added postgres backend

This commit is contained in:
2023-11-25 12:33:51 +01:00
parent c2a96f4cbd
commit 825e530a8d
20 changed files with 547 additions and 65 deletions
+26
View File
@@ -0,0 +1,26 @@
set(HEADER
include/postgres_connection.hpp
include/postgres_error.hpp
include/postgres_result_reader.hpp
include/postgres_dialect.hpp
)
set(SOURCES
src/postgres_connection.cpp
src/postgres_error.cpp
src/postgres_result_reader.cpp
src/postgres_dialect.cpp
)
add_library(matador-postgres SHARED ${SOURCES} ${HEADER})
target_include_directories(matador-postgres PRIVATE
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/backends/postgres/include
${PostgreSQL_INCLUDE_DIRS})
target_link_libraries(matador-postgres matador ${PostgreSQL_LIBRARIES})
set_target_properties(matador-postgres
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/backends"
)
@@ -0,0 +1,51 @@
#ifndef QUERY_POSTGRES_CONNECTION_HPP
#define QUERY_POSTGRES_CONNECTION_HPP
#ifdef _MSC_VER
#ifdef matador_postgres_EXPORTS
#define MATADOR_POSTGRES_API __declspec(dllexport)
#else
#define MATADOR_POSTGRES_API __declspec(dllimport)
#endif
#pragma warning(disable: 4355)
#else
#define MATADOR_POSTGRES_API
#endif
#include "matador/sql/connection_impl.hpp"
#include <libpq-fe.h>
namespace matador::backends::postgres {
class postgres_connection : public matador::sql::connection_impl
{
public:
explicit postgres_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;
void prepare(const std::string &stmt) override;
size_t execute(const std::string &stmt) override;
sql::record describe(const std::string& table) override;
bool exists(const std::string &table_name) override;
private:
PGconn *conn_{nullptr};
};
}
extern "C"
{
MATADOR_POSTGRES_API matador::sql::connection_impl* create_database(const matador::sql::connection_info &info);
MATADOR_POSTGRES_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_postgres_EXPORTS
#define MATADOR_POSTGRES_API __declspec(dllexport)
#else
#define MATADOR_POSTGRES_API __declspec(dllimport)
#endif
#pragma warning(disable: 4355)
#else
#define MATADOR_POSTGRES_API
#endif
#include "matador/sql/dialect.hpp"
extern "C" [[maybe_unused]] MATADOR_POSTGRES_API const matador::sql::dialect* get_dialect();
#endif //QUERY_POSTGRES_DIALECT_HPP
@@ -0,0 +1,16 @@
#ifndef QUERY_POSTGRES_ERROR_HPP
#define QUERY_POSTGRES_ERROR_HPP
#include <libpq-fe.h>
#include <string>
namespace matador::backends::postgres {
void throw_postgres_error(const char *what, const std::string &source);
void throw_postgres_error(PGconn *db, const std::string &source);
void throw_postgres_error(PGresult *res, PGconn *db, const std::string &source, const std::string &sql);
}
#endif //QUERY_POSTGRES_ERROR_HPP
@@ -0,0 +1,47 @@
#ifndef QUERY_POSTGRES_RESULT_READER_HPP
#define QUERY_POSTGRES_RESULT_READER_HPP
#include <libpq-fe.h>
#include "matador/sql/query_result_reader.hpp"
namespace matador::backends::postgres {
class postgres_result_reader : public sql::query_result_reader
{
public:
explicit postgres_result_reader(PGresult *result);
~postgres_result_reader() override;
[[nodiscard]] size_t column_count() const override;
[[nodiscard]] const char *column(size_t index) const override;
bool fetch() override;
void read_value(const char *id, size_t index, char &value) override;
void read_value(const char *id, size_t index, short &value) override;
void read_value(const char *id, size_t index, int &value) override;
void read_value(const char *id, size_t index, long &value) override;
void read_value(const char *id, size_t index, long long int &value) override;
void read_value(const char *id, size_t index, unsigned char &value) override;
void read_value(const char *id, size_t index, unsigned short &value) override;
void read_value(const char *id, size_t index, unsigned int &value) override;
void read_value(const char *id, size_t index, unsigned long &value) override;
void read_value(const char *id, size_t index, unsigned long long int &value) override;
void read_value(const char *id, size_t index, bool &value) override;
void read_value(const char *id, size_t index, float &value) override;
void read_value(const char *id, size_t index, double &value) override;
void read_value(const char *id, size_t index, char *value, size_t s) override;
void read_value(const char *id, size_t index, std::string &value) override;
void read_value(const char *id, size_t index, std::string &value, size_t s) override;
void read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size) override;
private:
PGresult *result_{};
size_t row_count_{};
size_t column_count_{};
size_t row_index_{0};
};
}
#endif //QUERY_POSTGRES_RESULT_READER_HPP
@@ -0,0 +1,84 @@
#include "postgres_connection.hpp"
#include "postgres_error.hpp"
namespace matador::backends::postgres {
postgres_connection::postgres_connection(const sql::connection_info &info)
: connection_impl(info) {}
void postgres_connection::open()
{
if (is_open()) {
return;
}
std::string connection("user=" + info().user + " password=" + info().password + " host=" + info().hostname + " dbname=" + info().database + " port=" + std::to_string(info().port));
conn_ = PQconnectdb(connection.c_str());
if (PQstatus(conn_) == CONNECTION_BAD) {
const auto msg = PQerrorMessage(conn_);
PQfinish(conn_);
throw_postgres_error(msg, "postgres");
}
}
void postgres_connection::close()
{
if (conn_) {
PQfinish(conn_);
conn_ = nullptr;
}
}
bool postgres_connection::is_open()
{
return conn_ != nullptr;
}
std::unique_ptr<sql::query_result_impl> postgres_connection::fetch(const std::string &stmt)
{
PGresult *res = PQexec(conn_, stmt.c_str());
throw_postgres_error(res, conn_, "postgres", stmt);
return {};
}
void postgres_connection::prepare(const std::string &stmt)
{
}
size_t postgres_connection::execute(const std::string &stmt)
{
PGresult *res = PQexec(conn_, stmt.c_str());
throw_postgres_error(res, conn_, "postgres", stmt);
return 0;
}
sql::record postgres_connection::describe(const std::string &table)
{
return {};
}
bool postgres_connection::exists(const std::string &table_name)
{
return false;
}
}
extern "C"
{
MATADOR_POSTGRES_API matador::sql::connection_impl *create_database(const matador::sql::connection_info &info)
{
return new matador::backends::postgres::postgres_connection(info);
}
MATADOR_POSTGRES_API void destroy_database(matador::sql::connection_impl *db)
{
delete db;
}
}
@@ -0,0 +1,7 @@
#include "postgres_dialect.hpp"
[[maybe_unused]] const matador::sql::dialect* get_dialect() {
using namespace matador::sql;
const static dialect d{};
return &d;
}
+34
View File
@@ -0,0 +1,34 @@
#include "postgres_error.hpp"
#include <sstream>
#include <libpq-fe.h>
namespace matador::backends::postgres {
void throw_postgres_error(const char *what, const std::string &source)
{
std::stringstream msg;
msg << "postgres error (" << source << "): " << what;
throw std::logic_error(msg.str());
}
void throw_postgres_error(PGconn *db, const std::string &source)
{
if (PQstatus(db) == CONNECTION_BAD) {
throw_postgres_error(PQerrorMessage(db), source);
}
}
void throw_postgres_error(PGresult *res, PGconn *db, const std::string &source, const std::string &sql)
{
if (res == nullptr ||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
PQresultStatus(res) != PGRES_TUPLES_OK)) {
std::stringstream msg;
msg << "postgres error (" << source << ", " << PQresultErrorField(res, PG_DIAG_SQLSTATE) << ") " << PQerrorMessage(db) << ": " << sql;
throw std::logic_error(msg.str());
}
}
}
@@ -0,0 +1,120 @@
#include "postgres_result_reader.hpp"
#include "matador/sql/to_value.hpp"
namespace matador::backends::postgres {
postgres_result_reader::postgres_result_reader(PGresult *result)
: result_(result)
, row_count_(PQntuples(result_))
, column_count_(PQnfields(result_))
{}
postgres_result_reader::~postgres_result_reader()
{
if (result_) {
PQclear(result_);
}
}
size_t postgres_result_reader::column_count() const
{
return column_count_;
}
const char *postgres_result_reader::column(size_t index) const
{
return nullptr;
}
bool postgres_result_reader::fetch()
{
return ++row_index_ < row_count_;
}
void postgres_result_reader::read_value(const char *id, size_t index, char &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, short &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, int &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, long &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, long long int &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, unsigned char &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, unsigned short &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, unsigned int &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, unsigned long &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, unsigned long long int &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, bool &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, float &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, double &value)
{
sql::to_value(value, PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index)));
}
void postgres_result_reader::read_value(const char *id, size_t index, char *value, size_t s)
{
}
void postgres_result_reader::read_value(const char *id, size_t index, std::string &value)
{
}
void postgres_result_reader::read_value(const char *id, size_t index, std::string &value, size_t s)
{
}
void postgres_result_reader::read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type,
size_t size)
{
}
}