Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2022 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file pg_helper.h
18 : * @brief shared internal definitions for postgres DB plugin
19 : * @author Christian Grothoff
20 : */
21 : #ifndef PG_HELPER_H
22 : #define PG_HELPER_H
23 :
24 :
25 : #include "auditordb_lib.h"
26 :
27 : /**
28 : * Postgres database connection handle.
29 : */
30 : struct TALER_AUDITORDB_PostgresContext
31 : {
32 :
33 : /**
34 : * Postgres connection handle.
35 : */
36 : struct GNUNET_PQ_Context *conn;
37 :
38 : /**
39 : * Name of the ongoing transaction, used to debug cases where
40 : * a transaction is not properly terminated via COMMIT or
41 : * ROLLBACK.
42 : */
43 : const char *transaction_name;
44 :
45 : /**
46 : * Our configuration.
47 : */
48 : const struct GNUNET_CONFIGURATION_Handle *cfg;
49 : /**
50 : * How often have we connected to the DB so far?
51 : */
52 : unsigned long long prep_gen;
53 :
54 : /**
55 : * Which currency should we assume all amounts to be in?
56 : */
57 : char *currency;
58 : };
59 :
60 :
61 : // FIXME: comment
62 : const char *
63 : TALER_AUDITORDB_get_deletable_suppressable_table_name (
64 : enum TALER_AUDITORDB_DeletableSuppressableTables table);
65 :
66 :
67 : /**
68 : * Convert the signed @a limit of a monitoring listing into the row
69 : * limit to pass to SQL. The sign selects the iteration direction and
70 : * the magnitude the number of rows, but computing `-limit` directly is
71 : * undefined behaviour for `INT64_MIN`, and the resulting value would
72 : * reach Postgres as `LIMIT -9223372036854775808`, which errors out.
73 : * `INT64_MIN` is therefore saturated to `INT64_MAX`.
74 : *
75 : * @param limit signed limit as given by the caller
76 : * @return absolute value of @a limit, without signed overflow
77 : */
78 : static inline uint64_t
79 10 : TALER_AUDITORDB_abs_limit (int64_t limit)
80 : {
81 : /* Postgres binds INT8 as a *signed* 64-bit integer, so a magnitude
82 : above INT64_MAX would reach LIMIT as a negative number. */
83 10 : if (INT64_MIN == limit)
84 0 : return (uint64_t) INT64_MAX;
85 10 : if (limit < 0)
86 0 : return (uint64_t) -limit;
87 10 : return (uint64_t) limit;
88 : }
89 :
90 :
91 : /**
92 : * Prepares SQL statement @a sql under @a name for
93 : * connection @a pg once.
94 : * Returns with #GNUNET_DB_STATUS_HARD_ERROR on failure.
95 : *
96 : * @param pg a `struct PostgresClosure`
97 : * @param name name to prepare the statement under
98 : * @param sql actual SQL text
99 : */
100 : #define PREPARE(pg,name,sql) \
101 : do { \
102 : static struct { \
103 : unsigned long long cnt; \
104 : struct TALER_AUDITORDB_PostgresContext *pg; \
105 : } preps_[2]; /* 2 ctrs for taler-auditor-sync*/ \
106 : unsigned int off_ = 0; \
107 : \
108 : while ( (NULL != preps_[off_].pg) && \
109 : (pg != preps_[off_].pg) && \
110 : (off_ < sizeof(preps_) / sizeof(*preps_)) ) \
111 : off_++; \
112 : GNUNET_assert (off_ < \
113 : sizeof(preps_) / sizeof(*preps_)); \
114 : if (preps_[off_].cnt < pg->prep_gen) \
115 : { \
116 : struct GNUNET_PQ_PreparedStatement ps[] = { \
117 : GNUNET_PQ_make_prepare (name, sql), \
118 : GNUNET_PQ_PREPARED_STATEMENT_END \
119 : }; \
120 : \
121 : if (GNUNET_OK != \
122 : GNUNET_PQ_prepare_statements (pg->conn, \
123 : ps)) \
124 : { \
125 : GNUNET_break (0); \
126 : return GNUNET_DB_STATUS_HARD_ERROR; \
127 : } \
128 : preps_[off_].pg = pg; \
129 : preps_[off_].cnt = pg->prep_gen; \
130 : } \
131 : } while (0)
132 :
133 :
134 : /**
135 : * Wrapper macro to add the currency from the plugin's state
136 : * when fetching amounts from the database.
137 : *
138 : * @param field name of the database field to fetch amount from
139 : * @param[out] amountp pointer to amount to set
140 : */
141 : #define TALER_PQ_RESULT_SPEC_AMOUNT(field, \
142 : amountp) \
143 : TALER_PQ_result_spec_amount ( \
144 : field,pg->currency,amountp)
145 :
146 :
147 : #endif
|