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:
@@ -31,8 +31,9 @@ public:
|
||||
void write_value(size_t pos, const bool &x) override;
|
||||
void write_value(size_t pos, const float &x) override;
|
||||
void write_value(size_t pos, const double &x) override;
|
||||
void write_value(size_t pos, const time &x ) override;
|
||||
void write_value(size_t pos, const date &x ) override;
|
||||
void write_value(size_t pos, const utils::date_type_t &x ) override;
|
||||
void write_value(size_t pos, const utils::time_type_t &x ) override;
|
||||
void write_value(size_t pos, const utils::timestamp &x ) override;
|
||||
void write_value(size_t pos, const char *x) override;
|
||||
void write_value(size_t pos, const char *x, size_t size) override;
|
||||
void write_value(size_t pos, const std::string &x) override;
|
||||
|
||||
@@ -11,7 +11,8 @@ namespace matador::backends::postgres {
|
||||
class postgres_statement final : public sql::statement_impl
|
||||
{
|
||||
public:
|
||||
postgres_statement(PGconn *db, std::string name, const sql::query_context &query);
|
||||
postgres_statement(PGconn *db, PGresult *res, std::string name, const sql::query_context &query);
|
||||
~postgres_statement() override;
|
||||
|
||||
utils::result<size_t, utils::error> execute(const sql::parameter_binder& bindings) override;
|
||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::parameter_binder& bindings) override;
|
||||
@@ -21,6 +22,7 @@ protected:
|
||||
|
||||
private:
|
||||
PGconn *db_{nullptr};
|
||||
PGresult *res_ = nullptr;
|
||||
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user