4 #ifndef DBALLE_SQL_POSTGRESQL_H 5 #define DBALLE_SQL_POSTGRESQL_H 11 #include <unordered_set> 29 const char* what()
const noexcept
override {
return msg.c_str(); }
31 static void throwf(PGconn* db,
const char* fmt, ...)
33 static void throwf(PGresult* db,
const char* fmt, ...)
37 namespace postgresql {
39 int64_t encode_datetime(
const Datetime& arg);
40 int64_t encode_int64_t(int64_t arg);
43 template <
typename... ARGS>
struct Params 45 static const int count =
sizeof...(ARGS);
46 const char* args[
sizeof...(ARGS)];
47 int lengths[
sizeof...(ARGS)];
48 int formats[
sizeof...(ARGS)];
49 void* local[
sizeof...(ARGS)];
51 Params(
const ARGS&... args) {
_add(0, args...); }
68 template <
typename... REST>
69 void _add(
unsigned pos, std::nullptr_t arg,
const REST&... rest)
75 _add(pos + 1, rest...);
79 template <
typename... REST>
80 void _add(
unsigned pos, int32_t arg,
const REST&... rest)
82 local[pos] = malloc(
sizeof(int32_t));
83 *(int32_t*)local[pos] = (int32_t)htonl((uint32_t)arg);
84 args[pos] = (
const char*)local[pos];
85 lengths[pos] =
sizeof(int32_t);
87 _add(pos + 1, rest...);
91 template <
typename... REST>
92 void _add(
unsigned pos, uint64_t arg,
const REST&... rest)
94 local[pos] = malloc(
sizeof(int64_t));
95 *(int64_t*)local[pos] = encode_int64_t(arg);
96 args[pos] = (
const char*)local[pos];
97 lengths[pos] =
sizeof(int64_t);
99 _add(pos + 1, rest...);
103 template <
typename... REST>
104 void _add(
unsigned pos,
const char* arg,
const REST&... rest)
106 local[pos] =
nullptr;
110 _add(pos + 1, rest...);
114 template <
typename... REST>
115 void _add(
unsigned pos,
const std::string& arg,
const REST&... rest)
117 local[pos] =
nullptr;
118 args[pos] = arg.data();
119 lengths[pos] = arg.size();
121 _add(pos + 1, rest...);
125 template <
typename... REST>
126 void _add(
unsigned pos,
const std::vector<uint8_t>& arg,
129 local[pos] =
nullptr;
130 args[pos] = (
const char*)arg.data();
131 lengths[pos] = arg.size();
133 _add(pos + 1, rest...);
137 template <
typename... REST>
140 local[pos] = malloc(
sizeof(int64_t));
141 *(int64_t*)local[pos] = encode_datetime(arg);
142 args[pos] = (
const char*)local[pos];
143 lengths[pos] =
sizeof(int64_t);
145 _add(pos + 1, rest...);
154 Result() : res(
nullptr) {}
155 Result(PGresult* res) : res(res) {}
156 ~
Result() { PQclear(res); }
170 operator bool()
const {
return res !=
nullptr; }
171 operator PGresult*() {
return res; }
172 operator const PGresult*()
const {
return res; }
187 unsigned rowcount()
const {
return PQntuples(res); }
190 bool is_null(
unsigned row,
unsigned col)
const 192 return PQgetisnull(res, row, col);
198 char* val = PQgetvalue(res, row, col);
203 uint16_t
get_int2(
unsigned row,
unsigned col)
const 205 char* val = PQgetvalue(res, row, col);
206 return ntohs(*(uint16_t*)val);
210 uint32_t
get_int4(
unsigned row,
unsigned col)
const 212 char* val = PQgetvalue(res, row, col);
213 return ntohl(*(uint32_t*)val);
217 uint64_t
get_int8(
unsigned row,
unsigned col)
const;
220 std::vector<uint8_t>
get_bytea(
unsigned row,
unsigned col)
const;
225 return PQgetvalue(res, row, col);
243 PGconn*
db =
nullptr;
244 std::unordered_set<std::string> prepared_names;
249 void init_after_connect();
253 void fork_prepare()
override;
254 void fork_parent()
override;
255 void fork_child()
override;
257 void check_connection();
266 static std::shared_ptr<PostgreSQLConnection> create();
268 operator PGconn*() {
return db; }
276 void open_url(
const std::string& connection_string);
279 std::unique_ptr<Transaction>
transaction(
bool readonly =
false)
override;
282 void prepare(
const std::string& name,
const std::string& query);
288 PQexecParams(
db, query, 0,
nullptr,
nullptr,
nullptr,
nullptr, 1);
295 postgresql::Result exec_unchecked(
const std::string& query)
298 auto res = PQexecParams(
db, query.c_str(), 0,
nullptr,
nullptr,
nullptr,
301 throw error_postgresql(
db,
"cannot execute query " + query);
305 template <
typename STRING>
void exec_no_data(STRING query)
307 postgresql::Result res(exec_unchecked(query));
308 res.expect_no_data(query);
311 template <
typename STRING> postgresql::Result exec(STRING query)
313 postgresql::Result res(exec_unchecked(query));
314 res.expect_result(query);
318 template <
typename STRING> postgresql::Result exec_one_row(STRING query)
320 postgresql::Result res(exec_unchecked(query));
321 res.expect_one_row(query);
325 template <
typename... ARGS>
326 postgresql::Result exec_unchecked(
const char* query, ARGS... args)
329 postgresql::Params<ARGS...> params(args...);
330 auto res = PQexecParams(
db, query, params.count,
nullptr, params.args,
331 params.lengths, params.formats, 1);
333 throw error_postgresql(
db, std::string(
"cannot execute query ") +
338 template <
typename... ARGS>
339 postgresql::Result exec_unchecked(
const std::string& query, ARGS... args)
342 postgresql::Params<ARGS...> params(args...);
343 auto res = PQexecParams(
db, query.c_str(), params.count,
nullptr,
344 params.args, params.lengths, params.formats, 1);
346 throw error_postgresql(
db,
"cannot execute query " + query);
350 template <
typename STRING,
typename... ARGS>
351 void exec_no_data(STRING query, ARGS... args)
353 postgresql::Result res(exec_unchecked(query, args...));
354 res.expect_no_data(query);
357 template <
typename STRING,
typename... ARGS>
358 postgresql::Result exec(STRING query, ARGS... args)
360 postgresql::Result res(exec_unchecked(query, args...));
361 res.expect_result(query);
365 template <
typename STRING,
typename... ARGS>
366 postgresql::Result exec_one_row(STRING query, ARGS... args)
368 postgresql::Result res(exec_unchecked(query, args...));
369 res.expect_one_row(query);
373 postgresql::Result exec_prepared_unchecked(
const char* name)
376 auto res = PQexecPrepared(
db, name, 0,
nullptr,
nullptr,
nullptr, 1);
378 throw error_postgresql(
379 db, std::string(
"cannot execute prepared query ") + name);
383 postgresql::Result exec_prepared_unchecked(
const std::string& name)
387 PQexecPrepared(
db, name.c_str(), 0,
nullptr,
nullptr,
nullptr, 1);
389 throw error_postgresql(
db,
"cannot execute prepared query " + name);
393 template <
typename STRING>
void exec_prepared_no_data(STRING name)
395 postgresql::Result res(exec_prepared_unchecked(name));
396 res.expect_no_data(name);
399 template <
typename STRING> postgresql::Result exec_prepared(STRING name)
401 postgresql::Result res(exec_prepared_unchecked(name));
402 res.expect_result(name);
406 template <
typename STRING>
407 postgresql::Result exec_prepared_one_row(STRING name)
409 postgresql::Result res(exec_prepared_unchecked(name));
410 res.expect_one_row(name);
414 template <
typename... ARGS>
415 postgresql::Result exec_prepared_unchecked(
const char* name, ARGS... args)
417 postgresql::Params<ARGS...> params(args...);
418 return PQexecPrepared(
db, name, params.count, params.args,
419 params.lengths, params.formats, 1);
422 template <
typename... ARGS>
423 postgresql::Result exec_prepared_unchecked(
const std::string& name,
426 postgresql::Params<ARGS...> params(args...);
427 return PQexecPrepared(
db, name.c_str(), params.count, params.args,
428 params.lengths, params.formats, 1);
431 template <
typename STRING,
typename... ARGS>
432 void exec_prepared_no_data(STRING name, ARGS... args)
434 postgresql::Result res(exec_prepared_unchecked(name, args...));
435 res.expect_no_data(name);
438 template <
typename STRING,
typename... ARGS>
439 postgresql::Result exec_prepared(STRING name, ARGS... args)
441 postgresql::Result res(exec_prepared_unchecked(name, args...));
442 res.expect_result(name);
446 template <
typename STRING,
typename... ARGS>
447 postgresql::Result exec_prepared_one_row(STRING name, ARGS... args)
449 postgresql::Result res(exec_prepared_unchecked(name, args...));
450 res.expect_one_row(name);
464 void execute(const
std::
string& query) override;
465 void explain(const
std::
string& query, FILE* out) override;
489 std::function<
void(const postgresql::Result&)> dest);
void open_url(const std::string &connection_string)
Connect to PostgreSQL using a connection URI.
Database connection.
Definition: postgresql.h:239
Result(Result &&o)
Implement move.
Definition: postgresql.h:159
void set_setting(const std::string &key, const std::string &value) override
Set a value in the settings table.
Argument list for PQexecParams built at compile time.
Definition: postgresql.h:43
void _add(unsigned pos, const char *arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:104
void _add(unsigned pos, uint64_t arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:92
void run_single_row_mode(const std::string &query_desc, std::function< void(const postgresql::Result &)> dest)
Retrieve query results in single row mode.
bool forked
Marker to catch attempts to reuse connections in forked processes.
Definition: postgresql.h:246
int changes()
Count the number of rows modified by the last query that was run.
void cancel_running_query_nothrow() noexcept
Send a cancellation command to the server.
bool has_table(const std::string &name) override
Check if the database contains a table.
unsigned rowcount() const
Get the number of rows in the result.
Definition: postgresql.h:187
void _add(unsigned pos)
Terminating condition for compile-time arg expansion.
Definition: postgresql.h:65
void _add(unsigned pos, const std::vector< uint8_t > &arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:126
uint16_t get_int2(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a 2 bit integer.
Definition: postgresql.h:203
void prepare(const std::string &name, const std::string &query)
Precompile a query.
bool is_null(unsigned row, unsigned col) const
Check if a result value is null.
Definition: postgresql.h:190
std::vector< uint8_t > get_bytea(unsigned row, unsigned col) const
Return a result value, transmitted in binary as an 8 bit integer.
uint32_t get_int4(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a 4 bit integer.
Definition: postgresql.h:210
void pqexec(const std::string &query)
Wrap PQexec.
Datetime get_timestamp(unsigned row, unsigned col) const
Return a result value, transmitted as a timestamp without timezone.
void pqexec_nothrow(const std::string &query) noexcept
Wrap PQexec but do not throw an exception in case of errors.
void expect_one_row(const std::string &query)
Check that the result successfully returned one row of data.
Wrap a PGresult, taking care of its memory management.
Definition: postgresql.h:150
bool get_bool(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a byte (?)
Definition: postgresql.h:196
void _add(unsigned pos, int32_t arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:80
void append_escaped(Querybuf &qb, const char *str)
Escape the string as a literal value and append it to qb.
void expect_result(const std::string &query)
Check that the result successfully returned some (possibly empty) data.
void expect_no_data(const std::string &query)
Check that the result successfully returned no data.
void drop_table_if_exists(const char *name)
Delete a table in the database if it exists, otherwise do nothing.
Report an PostgreSQL error.
Definition: postgresql.h:20
Common infrastructure for talking with SQL databases.
Error in case of failed database operations.
Definition: error.h:21
void _add(unsigned pos, const std::string &arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:115
PGconn * db
Database connection.
Definition: postgresql.h:243
void discard_all_input_nothrow() noexcept
Discard all input from an asynchronous request.
void _add(unsigned pos, const Datetime &arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:138
void explain(const std::string &query, FILE *out) override
Format and print the EXPLAIN output for the query to the given file.
Date and time.
Definition: types.h:163
std::unique_ptr< Transaction > transaction(bool readonly=false) override
Begin a transaction.
void drop_settings() override
Drop the settings table.
#define WREPORT_THROWF_ATTRS(a, b)
void _add(unsigned pos, std::nullptr_t arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:69
const char * get_string(unsigned row, unsigned col) const
Return a result value, transmitted as a string.
Definition: postgresql.h:223
uint64_t get_int8(unsigned row, unsigned col) const
Return a result value, transmitted in binary as an 8 bit integer.
void execute(const std::string &query) override
Execute a query without reading its results.
std::string get_setting(const std::string &key) override
Get a value from the settings table.
void expect_success(const std::string &query)
Check that the result was successful.