165 return kcenon::common::error_info{-1,
"Not initialized",
"postgres_manager"};
170 pqxx::connection* conn =
static_cast<pqxx::connection*
>(
connection_);
171 pqxx::work txn(*conn);
172 pqxx::result result = txn.exec(query_string);
174 return static_cast<uint64_t
>(result.affected_rows());
175 }
catch (
const std::exception& e) {
176 last_error_ = std::string(
"Modification query error: ") + e.what();
178 return kcenon::common::error_info{-2,
last_error_,
"postgres_manager"};
180#elif defined(HAVE_LIBPQ)
182 PGresult* result = PQexec(
static_cast<PGconn*
>(
connection_), query_string.c_str());
183 if (PQresultStatus(result) != PGRES_COMMAND_OK) {
186 return kcenon::common::error_info{-2,
last_error_,
"postgres_manager"};
188 const char* affected_rows = PQcmdTuples(result);
190 if (affected_rows && *affected_rows) {
191 count =
static_cast<uint64_t
>(std::stoull(affected_rows));
195 }
catch (
const std::exception& e) {
196 last_error_ = std::string(
"Modification query error: ") + e.what();
198 return kcenon::common::error_info{-2,
last_error_,
"postgres_manager"};
201 POSTGRES_LOG_WARNING(
"PostgreSQL support not compiled. Mock modification: " + query_string.substr(0, 20) +
"...");
209 return kcenon::common::error_info{-1,
"Not initialized",
"postgres_manager"};
216 pqxx::connection* conn =
static_cast<pqxx::connection*
>(
connection_);
217 pqxx::work txn(*conn);
218 pqxx::result pqxx_result = txn.exec(query_string);
221 for (
const auto& row : pqxx_result) {
223 for (
size_t i = 0; i < row.size(); ++i) {
224 std::string column_name = pqxx_result.column_name(i);
225 if (row[i].is_null()) {
226 db_row[column_name] =
nullptr;
228 if (row[i].
type() == PG_INT8OID ||
229 row[i].
type() == PG_INT4OID) {
230 db_row[column_name] = row[i].as<int64_t>();
231 }
else if (row[i].
type() == PG_FLOAT8OID ||
232 row[i].
type() == PG_FLOAT4OID) {
233 db_row[column_name] = row[i].as<
double>();
234 }
else if (row[i].
type() == PG_BOOLOID) {
235 db_row[column_name] = row[i].as<
bool>();
237 db_row[column_name] = row[i].as<std::string>();
241 result.push_back(std::move(db_row));
244 }
catch (
const std::exception& e) {
245 last_error_ = std::string(
"Select query error: ") + e.what();
247 return kcenon::common::error_info{-2,
last_error_,
"postgres_manager"};
249#elif defined(HAVE_LIBPQ)
251 PGresult* pg_result = PQexec(
static_cast<PGconn*
>(
connection_), query_string.c_str());
252 if (PQresultStatus(pg_result) != PGRES_TUPLES_OK) {
255 return kcenon::common::error_info{-2,
last_error_,
"postgres_manager"};
258 int rows = PQntuples(pg_result);
259 int cols = PQnfields(pg_result);
261 for (
int row = 0; row < rows; ++row) {
263 for (
int col = 0; col < cols; ++col) {
264 std::string column_name = PQfname(pg_result, col);
265 if (PQgetisnull(pg_result, row, col)) {
266 db_row[column_name] =
nullptr;
268 const char* value = PQgetvalue(pg_result, row, col);
269 Oid type_oid = PQftype(pg_result, col);
271 if (type_oid == 20 || type_oid == 21 || type_oid == 23) {
272 db_row[column_name] =
static_cast<int64_t
>(std::stoll(value));
273 }
else if (type_oid == 700 || type_oid == 701) {
274 db_row[column_name] = std::stod(value);
275 }
else if (type_oid == 16) {
276 db_row[column_name] = (*value ==
't' || *value ==
'1');
278 db_row[column_name] = std::string(value);
282 result.push_back(std::move(db_row));
286 }
catch (
const std::exception& e) {
287 last_error_ = std::string(
"Select query error: ") + e.what();
289 return kcenon::common::error_info{-2,
last_error_,
"postgres_manager"};
292 POSTGRES_LOG_WARNING(
"PostgreSQL support not compiled. Mock select: " + query_string.substr(0, 20) +
"...");
293 if (query_string.find(
"SELECT") != std::string::npos) {
295 mock_row[
"id"] = int64_t(1);
296 mock_row[
"name"] = std::string(
"mock_data");
297 mock_row[
"active"] =
true;
298 result.push_back(mock_row);
307 return kcenon::common::error_info{-1,
"Not initialized",
"postgres_manager"};
312 pqxx::work txn{*
static_cast<pqxx::connection*
>(
connection_)};
313 txn.exec(query_string);
315 return kcenon::common::ok();
316 }
catch (
const std::exception& e) {
317 last_error_ = std::string(
"Execute error: ") + e.what();
319 return kcenon::common::error_info{-2,
last_error_,
"postgres_manager"};
321#elif defined(HAVE_LIBPQ)
322 PGresult* result = PQexec(
static_cast<PGconn*
>(
connection_), query_string.c_str());
323 if (result ==
nullptr) {
326 return kcenon::common::error_info{-2,
last_error_,
"postgres_manager"};
329 ExecStatusType status = PQresultStatus(result);
330 bool success = (status == PGRES_COMMAND_OK) || (status == PGRES_TUPLES_OK);
336 return kcenon::common::error_info{-2,
last_error_,
"postgres_manager"};
340 return kcenon::common::ok();
342 POSTGRES_LOG_INFO(
"PostgreSQL support not compiled. Mock execute: " + query_string);
343 return kcenon::common::ok();
410 std::map<std::string, std::string> info;
411 info[
"backend"] =
"postgresql";
416 info[
"driver"] =
"libpqxx";
418 auto* conn =
static_cast<pqxx::connection*
>(
connection_);
419 info[
"server_version"] = std::to_string(conn->server_version());
420 info[
"protocol_version"] = std::to_string(conn->protocol_version());
422#elif defined(HAVE_LIBPQ)
423 info[
"driver"] =
"libpq";
426 info[
"server_version"] = std::to_string(PQserverVersion(conn));
427 info[
"protocol_version"] = std::to_string(PQprotocolVersion(conn));
430 info[
"driver"] =
"mock";
kcenon::common::VoidResult begin_transaction() override
Begin a transaction.
std::string last_error() const override
Get last error message from backend.
bool in_transaction_
Whether a transaction is active.
kcenon::common::VoidResult shutdown() override
Shutdown the database backend gracefully.
kcenon::common::Result< uint64_t > execute_modification_query(const std::string &query_string)
Common implementation for INSERT, UPDATE, and DELETE queries.
virtual ~postgres_manager(void)
Destructor.
bool initialized_
Whether the backend is initialized.
std::map< std::string, std::string > connection_info() const override
Get backend-specific connection information.
kcenon::common::VoidResult initialize(const core::connection_config &config) override
Initialize the database backend.
kcenon::common::VoidResult execute_query(const std::string &query_string) override
Executes a general SQL query (DDL, DML) on PostgreSQL.
bool is_initialized() const override
Check if backend is initialized and ready.
kcenon::common::VoidResult commit_transaction() override
Commit the current transaction.
std::string connection_string_
Connection string for connection_info.
kcenon::common::VoidResult rollback_transaction() override
Rollback the current transaction.
database_types type() const override
Returns the specific type of the database.
bool in_transaction() const override
Check if backend is currently in a transaction.
void * connection_
Pointer to the underlying PostgreSQL connection object.
kcenon::common::Result< core::database_result > select_query(const std::string &query_string) override
Executes a SELECT query on the connected PostgreSQL database and returns the resulting data.
#define POSTGRES_LOG_INFO(message)
#define POSTGRES_LOG_ERROR(context, message)
#define POSTGRES_LOG_WARNING(message)