added date_type_t, time_type_t and timestamp, ensure allocated postgres resources are released, split repository into basic_repository and repository.

This commit is contained in:
2026-01-06 15:43:20 +01:00
parent f07a360da2
commit 0c6b5a0a93
60 changed files with 1132 additions and 1225 deletions
+11 -5
View File
@@ -86,15 +86,18 @@ utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_co
PGresult *res = PQexec(conn_, context.sql.c_str());
if (is_result_error(res)) {
return utils::failure(make_error(sql::error_code::FETCH_FAILED, res, conn_, "Failed to fetch", context.sql));
const auto err = make_error(sql::error_code::FETCH_FAILED, res, conn_, "Failed to fetch", context.sql);
PQclear(res);
return utils::failure(err);
}
std::vector<object::attribute> prototype = context.prototype;
const int num_col = PQnfields(res);
if (prototype.size() != static_cast<size_t>(num_col)) {
return utils::failure(make_error(sql::error_code::FETCH_FAILED, res, conn_,
"Number of received columns doesn't match expected columns.", context.sql));
const auto err = make_error(sql::error_code::FETCH_FAILED, res, conn_, "Number of received columns doesn't match expected columns.", context.sql);
PQclear(res);
return utils::failure(err);
}
for (int i = 0; i < num_col; ++i) {
if (!prototype.at(i).is_null()) {
@@ -127,13 +130,13 @@ utils::result<std::unique_ptr<sql::statement_impl>, utils::error> postgres_conne
const sql::query_context &context) {
auto statement_name = generate_statement_name(context);
const PGresult *result = PQprepare(conn_, statement_name.c_str(), context.sql.c_str(), static_cast<int>(context.bind_vars.size()), nullptr);
PGresult *result = PQprepare(conn_, statement_name.c_str(), context.sql.c_str(), static_cast<int>(context.bind_vars.size()), nullptr);
if (is_result_error(result)) {
return utils::failure(make_error(sql::error_code::PREPARE_FAILED, result, conn_, "Failed to prepare", context.sql));
}
std::unique_ptr<sql::statement_impl> s(std::make_unique<postgres_statement>(conn_, statement_name, context));
std::unique_ptr<sql::statement_impl> s(std::make_unique<postgres_statement>(conn_, result, statement_name, context));
return utils::ok(std::move(s));
}
@@ -277,8 +280,11 @@ utils::result<bool, utils::error> postgres_connection::exists(const std::string
const auto result = utils::to<size_t>(PQcmdTuples(res));
if (!result) {
PQclear(res);
return utils::failure(make_error(sql::error_code::FAILURE, res, conn_, "Failed to convert result value", stmt));
}
PQclear(res);
return utils::ok(*result == 1);
}
@@ -47,15 +47,15 @@ void bind_value(postgres_parameter_binder::bind_data &data, const size_t index,
postgres_parameter_binder::bind_data::bind_data(const size_t size)
: strings(size)
, bytes(size)
, values(size)
, lengths(size)
, formats(size)
{}
, bytes(size)
, values(size)
, lengths(size)
, formats(size) {
}
postgres_parameter_binder::postgres_parameter_binder(const size_t size)
: bind_data_(size)
{}
: bind_data_(size) {
}
void postgres_parameter_binder::write_value(const size_t pos, const int8_t &x) {
detail::bind_value(bind_data_, pos, x);
@@ -123,31 +123,34 @@ void postgres_parameter_binder::write_value(const size_t pos, const std::string
write_value(pos, x);
}
void postgres_parameter_binder::write_value(const size_t pos, const time &/*x*/) {
// bind_data_.strings[pos] = utils::to_string(x, "%Y-%m-%d %T.%f");
bind_data_.values[pos] = bind_data_.strings[pos].data();
bind_data_.lengths[pos] = static_cast<int>(bind_data_.strings[pos].size());
bind_data_.formats[pos] = 0;
void postgres_parameter_binder::write_value(const size_t pos, const utils::date_type_t &/*x*/) {
// bind_data_.strings[pos] = utils::to_string(x, utils::date_format::ISO8601);
bind_data_.values[pos] = bind_data_.strings[pos].data();
bind_data_.lengths[pos] = static_cast<int>(bind_data_.strings[pos].size());
bind_data_.formats[pos] = 0;
}
void postgres_parameter_binder::write_value(const size_t pos, const date &/*x*/) {
// bind_data_.strings[pos] = utils::to_string(x, utils::date_format::ISO8601);
bind_data_.values[pos] = bind_data_.strings[pos].data();
bind_data_.lengths[pos] = static_cast<int>(bind_data_.strings[pos].size());
bind_data_.formats[pos] = 0;
void postgres_parameter_binder::write_value(const size_t pos, const utils::time_type_t &/*x*/) {
// bind_data_.strings[pos] = utils::to_string(x, "%Y-%m-%d %T.%f");
bind_data_.values[pos] = bind_data_.strings[pos].data();
bind_data_.lengths[pos] = static_cast<int>(bind_data_.strings[pos].size());
bind_data_.formats[pos] = 0;
}
void postgres_parameter_binder::write_value(size_t pos, const utils::timestamp &x) {
}
void postgres_parameter_binder::write_value(const size_t pos, const utils::blob &x) {
bind_data_.bytes[pos] = x;
bind_data_.values[pos] = reinterpret_cast<char*>(bind_data_.bytes[pos].data());
bind_data_.values[pos] = reinterpret_cast<char *>(bind_data_.bytes[pos].data());
bind_data_.lengths[pos] = static_cast<int>(bind_data_.bytes[pos].size());
bind_data_.formats[pos] = 1;
}
void postgres_parameter_binder::write_value(const size_t /*pos*/, const utils::value &/*x*/, size_t /*size*/) {}
void postgres_parameter_binder::write_value(const size_t /*pos*/, const utils::value &/*x*/, size_t /*size*/) {
}
const postgres_parameter_binder::bind_data &postgres_parameter_binder::params() const {
return bind_data_;
}
}
@@ -153,6 +153,8 @@ void postgres_result_reader::read_value( const char* /*id*/, const size_t index,
unsigned char* unescaped = PQunescapeBytea(data, &length);
value.assign(unescaped, unescaped+length);
PQfreemem(unescaped);
}
template <typename Type>
@@ -168,6 +170,8 @@ void set_value<utils::blob>(const char* str, utils::value& value) {
unsigned char* unescaped = PQunescapeBytea(reinterpret_cast<const unsigned char*>(str), &length);
value = utils::blob(unescaped, unescaped+length);
PQfreemem(unescaped);
}
void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::value &val, size_t) {
+12 -5
View File
@@ -5,12 +5,17 @@
namespace matador::backends::postgres {
postgres_statement::postgres_statement(PGconn *db, std::string name, const sql::query_context &query)
postgres_statement::postgres_statement(PGconn *db, PGresult *res, std::string name, const sql::query_context &query)
: statement_impl(query, 0)
, db_(db)
, res_(res)
, name_(std::move(name))
{}
postgres_statement::~postgres_statement() {
PQclear(res_);
}
utils::result<size_t, utils::error> postgres_statement::execute(const sql::parameter_binder& bindings) {
const auto* postgres_bindings = dynamic_cast<const postgres_parameter_binder*>(&bindings);
if (!postgres_bindings) {
@@ -28,12 +33,14 @@ utils::result<size_t, utils::error> postgres_statement::execute(const sql::param
return utils::failure(make_error(sql::error_code::EXECUTE_FAILED, res, db_, "Failed to execute statement", query_.sql));
}
const auto *tuples = PQcmdTuples(res);
if (strlen(tuples) == 0) {
return utils::ok(static_cast<size_t>(0));
size_t value{0};
if (const auto *tuples = PQcmdTuples(res); strlen(tuples) != 0) {
value = std::stoul(tuples);
}
return utils::ok(static_cast<size_t>(std::stoul(tuples)));
PQclear(res);
return utils::ok(value);
}
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_statement::fetch(const sql::parameter_binder& bindings) {