added postgres backend
This commit is contained in:
parent
c2a96f4cbd
commit
825e530a8d
|
|
@ -20,6 +20,9 @@ message(STATUS "Adding SQLite3 libs: ${SQLite3_LIBRARIES}")
|
||||||
message(STATUS "Adding MySQL include directory: ${MYSQL_INCLUDE_DIR}")
|
message(STATUS "Adding MySQL include directory: ${MYSQL_INCLUDE_DIR}")
|
||||||
message(STATUS "Adding MySQL libs: ${MYSQL_LIBRARY}")
|
message(STATUS "Adding MySQL libs: ${MYSQL_LIBRARY}")
|
||||||
|
|
||||||
|
message(STATUS "Adding PostgreSQL include directory: ${PostgreSQL_INCLUDE_DIR}")
|
||||||
|
message(STATUS "Adding PostgreSQL libs: ${PostgreSQL_LIBRARY}")
|
||||||
|
|
||||||
message(STATUS "Common flags ${CMAKE_CXX_FLAGS}")
|
message(STATUS "Common flags ${CMAKE_CXX_FLAGS}")
|
||||||
message(STATUS "Debug flags ${CMAKE_CXX_FLAGS_DEBUG}")
|
message(STATUS "Debug flags ${CMAKE_CXX_FLAGS_DEBUG}")
|
||||||
message(STATUS "Relase flags ${CMAKE_CXX_FLAGS_RELEASE}")
|
message(STATUS "Relase flags ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
add_subdirectory(sqlite)
|
add_subdirectory(sqlite)
|
||||||
|
add_subdirectory(postgres)
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,3 +19,7 @@ target_include_directories(matador-sqlite PRIVATE
|
||||||
${SQLite3_INCLUDE_DIRS})
|
${SQLite3_INCLUDE_DIRS})
|
||||||
|
|
||||||
target_link_libraries(matador-sqlite matador ${SQLite3_LIBRARIES})
|
target_link_libraries(matador-sqlite matador ${SQLite3_LIBRARIES})
|
||||||
|
set_target_properties(matador-sqlite
|
||||||
|
PROPERTIES
|
||||||
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/backends"
|
||||||
|
)
|
||||||
|
|
@ -16,6 +16,10 @@ sqlite_connection::sqlite_connection(const sql::connection_info &info)
|
||||||
|
|
||||||
void sqlite_connection::open()
|
void sqlite_connection::open()
|
||||||
{
|
{
|
||||||
|
if (is_open()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto ret = sqlite3_open(info().database.c_str(), &sqlite_db_);
|
const auto ret = sqlite3_open(info().database.c_str(), &sqlite_db_);
|
||||||
|
|
||||||
if (ret != SQLITE_OK) {
|
if (ret != SQLITE_OK) {
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,11 @@
|
||||||
#include "sqlite_result_reader.hpp"
|
#include "sqlite_result_reader.hpp"
|
||||||
|
|
||||||
|
#include "matador/sql/to_value.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace matador::backends::sqlite {
|
namespace matador::backends::sqlite {
|
||||||
|
|
||||||
template < class Type >
|
|
||||||
void read(Type &x, const char *val, typename std::enable_if<std::is_integral<Type>::value && std::is_signed<Type>::value>::type* = nullptr)
|
|
||||||
{
|
|
||||||
if (strlen(val) == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char *end;
|
|
||||||
x = static_cast<Type>(strtoll(val, &end, 10));
|
|
||||||
if (end == nullptr) {
|
|
||||||
// Todo: check error
|
|
||||||
throw std::logic_error("couldn't convert value to number");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template < class Type >
|
|
||||||
void read(Type &x, const char *val, typename std::enable_if<std::is_integral<Type>::value && std::is_unsigned<Type>::value>::type* = nullptr)
|
|
||||||
{
|
|
||||||
if (strlen(val) == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char *end;
|
|
||||||
x = static_cast<Type>(strtoull(val, &end, 10));
|
|
||||||
if (end == nullptr) {
|
|
||||||
// Todo: check error
|
|
||||||
throw std::logic_error("couldn't convert value to number");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template < class Type >
|
|
||||||
void read(Type &x, const char *val, typename std::enable_if<std::is_floating_point<Type>::value>::type* = nullptr)
|
|
||||||
{
|
|
||||||
if (strlen(val) == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char *end;
|
|
||||||
x = static_cast<Type>(strtold(val, &end));
|
|
||||||
if (end == nullptr) {
|
|
||||||
// Todo: check error
|
|
||||||
throw std::logic_error("couldn't convert value to number");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite_result_reader::sqlite_result_reader(sqlite_result_reader::rows result, size_t column_count)
|
sqlite_result_reader::sqlite_result_reader(sqlite_result_reader::rows result, size_t column_count)
|
||||||
: result_(std::move(result))
|
: result_(std::move(result))
|
||||||
, column_count_(column_count) {}
|
, column_count_(column_count) {}
|
||||||
|
|
@ -78,67 +36,67 @@ bool sqlite_result_reader::fetch()
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, char &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, char &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, short &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, short &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, int &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, int &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, long &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, long &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, long long int &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, long long int &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, unsigned char &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, unsigned char &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, unsigned short &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, unsigned short &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, unsigned int &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, unsigned int &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, unsigned long &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, unsigned long &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, unsigned long long int &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, unsigned long long int &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, bool &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, bool &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, float &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, float &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, double &value)
|
void sqlite_result_reader::read_value(const char *id, size_t index, double &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
sql::to_value(value, result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, char *value, size_t size)
|
void sqlite_result_reader::read_value(const char *id, size_t index, char *value, size_t size)
|
||||||
|
|
@ -175,7 +133,7 @@ template < typename Type >
|
||||||
void convert(const char *valstr, sql::any_type &value)
|
void convert(const char *valstr, sql::any_type &value)
|
||||||
{
|
{
|
||||||
Type val{};
|
Type val{};
|
||||||
read(val, valstr);
|
sql::to_value(val, valstr);
|
||||||
value = val;
|
value = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -220,7 +178,7 @@ void sqlite_result_reader::read_value(const char *id, size_t index, sql::any_typ
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_bool: {
|
case sql::data_type_t::type_bool: {
|
||||||
int val{};
|
int val{};
|
||||||
read(val, result_[row_index_][index]);
|
sql::to_value(val, result_[row_index_][index]);
|
||||||
value = val > 0;
|
value = val > 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
#ifndef QUERY_TO_VALUE_HPP
|
||||||
|
#define QUERY_TO_VALUE_HPP
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <climits>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cfloat>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
|
||||||
|
template < class Type >
|
||||||
|
void to_value(Type &value, const char *str, typename std::enable_if<std::is_integral<Type>::value && std::is_signed<Type>::value>::type* = nullptr)
|
||||||
|
{
|
||||||
|
if (strlen(str) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char *end;
|
||||||
|
errno = 0;
|
||||||
|
auto result = strtoll(str, &end, 10);
|
||||||
|
|
||||||
|
// Check for various possible errors
|
||||||
|
if ((errno == ERANGE && (result == LLONG_MAX || result == LLONG_MIN)) || (errno != 0 && result == 0)) {
|
||||||
|
throw std::logic_error(strerror(errno));
|
||||||
|
// Handle error
|
||||||
|
} else if (end == str) {
|
||||||
|
// No digits found
|
||||||
|
throw std::logic_error("failed to convert value to signed number: no digits were found");
|
||||||
|
}
|
||||||
|
|
||||||
|
value = static_cast<Type>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < class Type >
|
||||||
|
void to_value(Type &value, const char *str, typename std::enable_if<std::is_integral<Type>::value && std::is_unsigned<Type>::value>::type* = nullptr)
|
||||||
|
{
|
||||||
|
if (strlen(str) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *end;
|
||||||
|
errno = 0;
|
||||||
|
auto result = strtoull(str, &end, 10);
|
||||||
|
|
||||||
|
// Check for various possible errors
|
||||||
|
if ((errno == ERANGE && (result == LLONG_MAX || result == LLONG_MIN)) || (errno != 0 && result == 0)) {
|
||||||
|
throw std::logic_error(strerror(errno));
|
||||||
|
// Handle error
|
||||||
|
} else if (end == str) {
|
||||||
|
// No digits found
|
||||||
|
throw std::logic_error("failed to convert value to unsigned number: no digits were found");
|
||||||
|
}
|
||||||
|
|
||||||
|
value = static_cast<Type>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < class Type >
|
||||||
|
void to_value(Type &value, const char *str, typename std::enable_if<std::is_floating_point<Type>::value>::type* = nullptr)
|
||||||
|
{
|
||||||
|
if (strlen(str) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *end;
|
||||||
|
errno = 0;
|
||||||
|
auto result = strtold(str, &end);
|
||||||
|
|
||||||
|
// Check for various possible errors
|
||||||
|
if ((errno == ERANGE && (result == LDBL_MAX || result == LDBL_MIN)) || (errno != 0 && result == 0)) {
|
||||||
|
throw std::logic_error(strerror(errno));
|
||||||
|
// Handle error
|
||||||
|
} else if (end == str) {
|
||||||
|
// No digits found
|
||||||
|
throw std::logic_error("failed to convert value to floating point number: no digits were found");
|
||||||
|
}
|
||||||
|
|
||||||
|
value = static_cast<Type>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //QUERY_TO_VALUE_HPP
|
||||||
|
|
@ -46,9 +46,10 @@ set(SQL_HEADER
|
||||||
../include/matador/sql/key_value_generator.hpp
|
../include/matador/sql/key_value_generator.hpp
|
||||||
../include/matador/sql/entity.hpp
|
../include/matador/sql/entity.hpp
|
||||||
../include/matador/sql/fk_value_extractor.hpp
|
../include/matador/sql/fk_value_extractor.hpp
|
||||||
"../include/matador/sql/table_repository.hpp"
|
../include/matador/sql/table_repository.hpp
|
||||||
../include/matador/sql/any_type_to_visitor.hpp
|
../include/matador/sql/any_type_to_visitor.hpp
|
||||||
../include/matador/sql/query_result_reader.hpp)
|
../include/matador/sql/query_result_reader.hpp
|
||||||
|
../include/matador/sql/to_value.hpp)
|
||||||
|
|
||||||
set(UTILS_HEADER
|
set(UTILS_HEADER
|
||||||
../include/matador/utils/field_attributes.hpp
|
../include/matador/utils/field_attributes.hpp
|
||||||
|
|
|
||||||
|
|
@ -31,5 +31,6 @@ target_link_libraries(tests PRIVATE
|
||||||
Catch2::Catch2WithMain
|
Catch2::Catch2WithMain
|
||||||
matador
|
matador
|
||||||
${CMAKE_DL_LIBS}
|
${CMAKE_DL_LIBS}
|
||||||
${SQLite3_LIBRARIES})
|
${SQLite3_LIBRARIES}
|
||||||
|
${PostgreSQL_LIBRARY})
|
||||||
target_include_directories(tests PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>/include)
|
target_include_directories(tests PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>/include)
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <catch2/generators/catch_generators.hpp>
|
||||||
|
|
||||||
#include "matador/sql/connection.hpp"
|
#include "matador/sql/connection.hpp"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <catch2/generators/catch_generators.hpp>
|
||||||
|
|
||||||
#include <matador/sql/column.hpp>
|
#include <matador/sql/column.hpp>
|
||||||
#include <matador/sql/condition.hpp>
|
#include <matador/sql/condition.hpp>
|
||||||
|
|
@ -13,7 +14,12 @@ using namespace matador::sql;
|
||||||
using namespace matador::test;
|
using namespace matador::test;
|
||||||
|
|
||||||
TEST_CASE("Create table with foreign key relation", "[session]") {
|
TEST_CASE("Create table with foreign key relation", "[session]") {
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
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);
|
session s(pool);
|
||||||
|
|
||||||
auto res = s.create()
|
auto res = s.create()
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,23 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <catch2/generators/catch_generators.hpp>
|
#include <catch2/generators/catch_generators.hpp>
|
||||||
|
|
||||||
|
#include "matador/sql/connection.hpp"
|
||||||
|
|
||||||
|
using namespace matador;
|
||||||
|
|
||||||
TEST_CASE("Query test", "[query]") {
|
TEST_CASE("Query test", "[query]") {
|
||||||
auto dns = GENERATE(as<std::string>{}, "mssql", "sqlite", "postgres" );
|
auto dns = GENERATE(as<std::string>{},
|
||||||
|
"sqlite://sqlite.db",
|
||||||
|
"postgres://test:test123@127.0.0.1:5432/matador_test" );
|
||||||
|
|
||||||
|
sql::connection c(dns);
|
||||||
|
REQUIRE(!c.is_open());
|
||||||
|
|
||||||
|
c.open();
|
||||||
|
REQUIRE(c.is_open());
|
||||||
|
|
||||||
|
c.close();
|
||||||
|
REQUIRE(!c.is_open());
|
||||||
|
|
||||||
INFO(dns);
|
INFO(dns);
|
||||||
REQUIRE(!dns.empty());
|
REQUIRE(!dns.empty());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue