Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014--2025 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 : /**
18 : * @file pg.c
19 : * @brief Low-level (statement-level) Postgres database access for the exchange
20 : * @author Florian Dold
21 : * @author Christian Grothoff
22 : * @author Sree Harsha Totakura
23 : * @author Marcello Stanisci
24 : * @author Özgür Kesim
25 : */
26 : #include <poll.h>
27 : #include <pthread.h>
28 : #include <libpq-fe.h>
29 : #include "helper.h"
30 : #include "taler/taler_exchangedb_lib.h"
31 : #include "exchange-database/preflight.h"
32 :
33 : /**
34 : * Set to 1 to enable Postgres auto_explain module. This will
35 : * slow down things a _lot_, but also provide extensive logging
36 : * in the Postgres database logger for performance analysis.
37 : */
38 : #define AUTO_EXPLAIN 0
39 :
40 :
41 : /**
42 : * Log a really unexpected PQ error with all the details we can get hold of.
43 : *
44 : * @param result PQ result object of the PQ operation that failed
45 : * @param conn SQL connection that was used
46 : */
47 : #define BREAK_DB_ERR(result,conn) do { \
48 : GNUNET_break (0); \
49 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \
50 : "Database failure: %s/%s/%s/%s/%s", \
51 : PQresultErrorField (result, PG_DIAG_MESSAGE_PRIMARY), \
52 : PQresultErrorField (result, PG_DIAG_MESSAGE_DETAIL), \
53 : PQresultErrorMessage (result), \
54 : PQresStatus (PQresultStatus (result)), \
55 : PQerrorMessage (conn)); \
56 : } while (0)
57 :
58 :
59 : struct TALER_EXCHANGEDB_PostgresContext *
60 229 : TALER_EXCHANGEDB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
61 : bool skip_preflight)
62 : {
63 : struct TALER_EXCHANGEDB_PostgresContext *pg;
64 : unsigned long long dpl;
65 :
66 229 : pg = GNUNET_new (struct TALER_EXCHANGEDB_PostgresContext);
67 229 : pg->cfg = cfg;
68 229 : if (GNUNET_OK !=
69 229 : GNUNET_CONFIGURATION_get_value_filename (cfg,
70 : "exchangedb-postgres",
71 : "SQL_DIR",
72 : &pg->sql_dir))
73 : {
74 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
75 : "exchangedb-postgres",
76 : "SQL_DIR");
77 0 : goto fail;
78 : }
79 229 : if (GNUNET_OK !=
80 229 : GNUNET_CONFIGURATION_get_value_string (cfg,
81 : "exchange",
82 : "BASE_URL",
83 : &pg->exchange_url))
84 : {
85 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
86 : "exchange",
87 : "BASE_URL");
88 0 : goto fail;
89 : }
90 229 : if (GNUNET_OK !=
91 229 : GNUNET_CONFIGURATION_get_value_time (cfg,
92 : "exchangedb",
93 : "IDLE_RESERVE_EXPIRATION_TIME",
94 : &pg->idle_reserve_expiration_time))
95 : {
96 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
97 : "exchangedb",
98 : "IDLE_RESERVE_EXPIRATION_TIME");
99 0 : goto fail;
100 : }
101 229 : if (GNUNET_OK !=
102 229 : GNUNET_CONFIGURATION_get_value_time (cfg,
103 : "exchangedb",
104 : "MAX_AML_PROGRAM_RUNTIME",
105 : &pg->max_aml_program_runtime))
106 : {
107 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
108 : "exchangedb",
109 : "MAX_AML_PROGRAM_RUNTIME");
110 0 : goto fail;
111 : }
112 229 : if (GNUNET_OK !=
113 229 : GNUNET_CONFIGURATION_get_value_time (cfg,
114 : "exchangedb",
115 : "LEGAL_RESERVE_EXPIRATION_TIME",
116 : &pg->legal_reserve_expiration_time))
117 : {
118 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
119 : "exchangedb",
120 : "LEGAL_RESERVE_EXPIRATION_TIME");
121 0 : goto fail;
122 : }
123 229 : if (GNUNET_OK !=
124 229 : GNUNET_CONFIGURATION_get_value_time (cfg,
125 : "exchangedb",
126 : "AGGREGATOR_SHIFT",
127 : &pg->aggregator_shift))
128 : {
129 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
130 : "exchangedb",
131 : "AGGREGATOR_SHIFT");
132 : }
133 229 : if (GNUNET_OK !=
134 229 : GNUNET_CONFIGURATION_get_value_number (cfg,
135 : "exchangedb",
136 : "DEFAULT_PURSE_LIMIT",
137 : &dpl))
138 : {
139 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
140 : "exchangedb",
141 : "DEFAULT_PURSE_LIMIT");
142 0 : pg->def_purse_limit = 1;
143 : }
144 : else
145 : {
146 229 : pg->def_purse_limit = (uint32_t) dpl;
147 : }
148 :
149 229 : if (GNUNET_OK !=
150 229 : TALER_config_get_currency (cfg,
151 : "exchange",
152 : &pg->currency))
153 : {
154 0 : goto fail;
155 : }
156 229 : if (! skip_preflight)
157 : {
158 208 : if (GNUNET_OK !=
159 208 : TALER_EXCHANGEDB_preflight (pg))
160 : {
161 0 : goto fail;
162 : }
163 : }
164 229 : return pg;
165 :
166 0 : fail:
167 0 : GNUNET_free (pg->exchange_url);
168 0 : GNUNET_free (pg->sql_dir);
169 0 : GNUNET_free (pg->currency);
170 0 : GNUNET_free (pg);
171 0 : return NULL;
172 : }
173 :
174 :
175 : void
176 229 : TALER_EXCHANGEDB_disconnect (struct TALER_EXCHANGEDB_PostgresContext *pg)
177 : {
178 229 : if (NULL == pg)
179 0 : return;
180 229 : if (NULL != pg->conn)
181 : {
182 208 : GNUNET_PQ_disconnect (pg->conn);
183 208 : pg->conn = NULL;
184 : }
185 229 : GNUNET_free (pg->exchange_url);
186 229 : GNUNET_free (pg->sql_dir);
187 229 : GNUNET_free (pg->currency);
188 229 : GNUNET_free (pg);
189 : }
190 :
191 :
192 : /* end of plugin_exchangedb_postgres.c */
|