boat
C++23 geospatial library
Loading...
Searching...
No Matches
command.hpp
Go to the documentation of this file.
1// Andrew Naplavkov
2
3#ifndef BOAT_SQL_LIBPQ_COMMAND_HPP
4#define BOAT_SQL_LIBPQ_COMMAND_HPP
5
6#include <boat/db/command.hpp>
7#include <boat/sql/libpq/detail/fetch.hpp>
8#include <boat/sql/libpq/detail/params.hpp>
9
11
12class command : public db::command {
13 unique_ptr<PGconn, PQfinish> dbc_;
14 std::string prepared_;
15
16public:
17 explicit command(char const* connection) : dbc_(PQconnectdb(connection))
18 {
19 check(dbc_ && PQstatus(dbc_.get()) == CONNECTION_OK, dbc_.get());
20 }
21
22 db::rowset exec(db::query const& qry, std::stop_token tok = {}) override
23 {
24 auto cxl = unique_ptr<PGcancel, PQfreeCancel>{PQgetCancel(dbc_.get())};
25 check(!!cxl, dbc_.get());
26 char err[256]{};
27 auto stop = std::stop_callback{
28 tok, [&] { PQcancel(cxl.get(), err, sizeof(err)); }};
29 auto txt = qry.text(id_quote(), param_mark());
30 auto ps = qry.params() | std::views::transform(params::make) |
31 std::ranges::to<std::vector>();
32 if (ps.empty()) {
33 auto res =
34 unique_ptr<PGresult, PQclear>{PQexec(dbc_.get(), txt.data())};
35 return fetch(res.get());
36 }
37 if (prepared_ != txt) {
38 auto types = std::vector<Oid>(ps.size());
39 for (size_t i{}; i < ps.size(); ++i)
40 types[i] = params::type(ps[i]);
41 auto res = unique_ptr<PGresult, PQclear>{PQprepare( //
42 dbc_.get(),
43 "",
44 txt.data(),
45 static_cast<int>(types.size()),
46 types.data())};
47 auto ec = PQresultStatus(res.get());
48 check(ec == PGRES_COMMAND_OK || ec == PGRES_TUPLES_OK, dbc_.get());
49 prepared_ = txt;
50 }
51 auto values = std::vector<char const*>(ps.size());
52 auto lengths = std::vector<int>(ps.size());
53 auto formats = std::vector<int>(ps.size());
54 for (size_t i{}; i < ps.size(); ++i) {
55 auto& p = ps[i];
56 values[i] = params::value(p);
57 lengths[i] = params::length(p);
58 formats[i] = params::format(p);
59 }
60 auto res = unique_ptr<PGresult, PQclear>{PQexecPrepared( //
61 dbc_.get(),
62 "",
63 int(ps.size()),
64 values.data(),
65 lengths.data(),
66 formats.data(),
67 text_fmt)};
68 return fetch(res.get());
69 }
70
71 void set_autocommit(bool on) override { exec(on ? "rollback;" : "begin;"); }
72 void commit() override { exec("commit;begin;"); }
73 char id_quote() override { return '"'; }
74 std::string param_mark() override { return "${}"; }
75 std::string dbms() override { return "postgres"; }
76};
77
78} // namespace boat::sql::libpq
79
80#endif // BOAT_SQL_LIBPQ_COMMAND_HPP
Definition query.hpp:20
std::string text(char id_quote, std::string_view param_mark) const
Definition query.hpp:47
std::generator< std::reference_wrapper< variant const > > params() const
Definition query.hpp:73
char id_quote() override
Definition command.hpp:73
command(char const *connection)
Definition command.hpp:17
db::rowset exec(db::query const &qry, std::stop_token tok={}) override
Definition command.hpp:22
void set_autocommit(bool on) override
Definition command.hpp:71
std::string param_mark() override
"{}" in the result is replaced with the parameter number.
Definition command.hpp:74
std::string dbms() override
The result is lower-case.
Definition command.hpp:75
void commit() override
Definition command.hpp:72
Definition command.hpp:10
Definition command.hpp:12
Definition rowset.hpp:12