Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2023 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 src/backenddb/helper.h
18 : * @brief shared internal definitions for postgres logic
19 : * @author Christian Grothoff
20 : */
21 : #ifndef HELPER_H
22 : #define HELPER_H
23 :
24 : #include <gnunet/gnunet_util_lib.h>
25 : #include <gnunet/gnunet_db_lib.h>
26 : #include <gnunet/gnunet_time_lib.h>
27 : #include <taler/taler_util.h>
28 :
29 : /**
30 : * Type of the "cls" argument given to each of the functions in
31 : * our API.
32 : */
33 : struct TALER_MERCHANTDB_PostgresContext
34 : {
35 :
36 : /**
37 : * Postgres connection handle.
38 : */
39 : struct GNUNET_PQ_Context *conn;
40 :
41 : /**
42 : * Underlying configuration.
43 : */
44 : const struct GNUNET_CONFIGURATION_Handle *cfg;
45 :
46 : /**
47 : * Name of the currently active transaction, NULL if none is active.
48 : */
49 : const char *transaction_name;
50 :
51 : /**
52 : * Instance id ("merchant_id") that the search_path is currently
53 : * pointing at, or NULL if no per-instance schema is selected.
54 : * Owned by this struct; set by TALER_MERCHANTDB_set_instance().
55 : */
56 : char *current_merchant_id;
57 :
58 : /**
59 : * merchant_serial corresponding to @e current_merchant_id, or 0
60 : * if no per-instance schema is selected. Used as the suffix in
61 : * per-instance prepared-statement names.
62 : */
63 : uint64_t current_merchant_serial;
64 :
65 : /**
66 : * Public key of the currently selected instance. Populated by
67 : * TALER_MERCHANTDB_set_instance() together with @e current_merchant_id
68 : * and @e current_merchant_serial. Used by call sites that emit
69 : * cross-process events (e.g. order-pay notifications) which carry the
70 : * instance public key in their payload.
71 : */
72 : struct TALER_MerchantPublicKeyP current_merchant_pub;
73 :
74 : };
75 :
76 :
77 : /**
78 : * How many times have we connected to the DB.
79 : */
80 : extern uint64_t TMH_PG_prep_gen_;
81 :
82 :
83 : /**
84 : * Convert the signed @a limit of a paginated listing into the row
85 : * limit to pass to SQL. The sign selects the iteration direction and
86 : * the magnitude the number of rows, but computing `-limit` directly is
87 : * undefined behaviour for `INT64_MIN`, and the resulting value would
88 : * reach Postgres as `LIMIT -9223372036854775808`, which errors out.
89 : * `INT64_MIN` is therefore saturated to `INT64_MAX`.
90 : *
91 : * @param limit signed limit as given by the caller
92 : * @return absolute value of @a limit, without signed overflow
93 : */
94 : static inline uint64_t
95 60 : TALER_MERCHANTDB_abs_limit (int64_t limit)
96 : {
97 : /* Postgres binds INT8 as a *signed* 64-bit integer, so a magnitude
98 : above INT64_MAX would reach LIMIT as a negative number. */
99 60 : if (INT64_MIN == limit)
100 0 : return (uint64_t) INT64_MAX;
101 60 : if (limit < 0)
102 20 : return (uint64_t) -limit;
103 40 : return (uint64_t) limit;
104 : }
105 :
106 :
107 : /**
108 : * Prepares SQL statement @a sql under @a name for
109 : * connection @a pg once.
110 : * Returns with #GNUNET_DB_STATUS_HARD_ERROR on failure.
111 : *
112 : * @param pg a `struct TALER_MERCHANTDB_PostgresContext`
113 : * @param name name to prepare the statement under
114 : * @param sql actual SQL text
115 : */
116 : #define PREPARE(pg,name,sql) \
117 : do { \
118 : static unsigned long long gen; \
119 : \
120 : if (gen < TMH_PG_prep_gen_) \
121 : { \
122 : struct GNUNET_PQ_PreparedStatement ps[] = { \
123 : GNUNET_PQ_make_prepare (name, sql), \
124 : GNUNET_PQ_PREPARED_STATEMENT_END \
125 : }; \
126 : \
127 : if (GNUNET_OK != \
128 : GNUNET_PQ_prepare_statements (pg->conn, \
129 : ps)) \
130 : { \
131 : GNUNET_break (0); \
132 : return GNUNET_DB_STATUS_HARD_ERROR; \
133 : } \
134 : gen = TMH_PG_prep_gen_; \
135 : } \
136 : } while (0)
137 :
138 :
139 : /**
140 : * Prepares SQL statement @a sql under no name ("") for
141 : * connection @a pg. Useful for prepared statements that
142 : * should not be cached.
143 : * Returns with #GNUNET_DB_STATUS_HARD_ERROR on failure.
144 : *
145 : * @param pg a `struct TALER_MERCHANTDB_PostgresContext`
146 : * @param sql actual SQL text
147 : */
148 : #define TMH_PQ_prepare_anon(pg,sql) \
149 : do { \
150 : if (GNUNET_OK != \
151 : GNUNET_PQ_prepare_anon (pg->conn, \
152 : sql)) { \
153 : GNUNET_break (0); \
154 : return GNUNET_DB_STATUS_HARD_ERROR; \
155 : } } while (0)
156 :
157 :
158 : #endif
|