Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 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 : * @file backenddb/pg_lookup_expected_transfers.c
18 : * @brief Implementation of the lookup_expected_transfers function for Postgres
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <taler/taler_error_codes.h>
23 : #include <taler/taler_dbevents.h>
24 : #include <taler/taler_pq_lib.h>
25 : #include "pg_lookup_expected_transfers.h"
26 : #include "pg_helper.h"
27 : #include <microhttpd.h> /* for HTTP status codes */
28 :
29 : /**
30 : * Closure for #lookup_expected_transfers_cb().
31 : */
32 : struct LookupExpectedTransfersContext
33 : {
34 : /**
35 : * Function to call on results.
36 : */
37 : TALER_MERCHANTDB_IncomingCallback cb;
38 :
39 : /**
40 : * Closure for @e cb.
41 : */
42 : void *cb_cls;
43 :
44 : /**
45 : * Postgres context.
46 : */
47 : struct PostgresClosure *pg;
48 :
49 : /**
50 : * Transaction status (set).
51 : */
52 : enum GNUNET_DB_QueryStatus qs;
53 :
54 : };
55 :
56 :
57 : /**
58 : * Function to be called with the results of a SELECT statement
59 : * that has returned @a num_results results.
60 : *
61 : * @param cls of type `struct LookupExpectedTransfersContext *`
62 : * @param result the postgres result
63 : * @param num_results the number of results in @a result
64 : */
65 : static void
66 0 : lookup_expected_transfers_cb (void *cls,
67 : PGresult *result,
68 : unsigned int num_results)
69 : {
70 0 : struct LookupExpectedTransfersContext *ltc = cls;
71 :
72 0 : for (unsigned int i = 0; i<num_results; i++)
73 : {
74 : struct TALER_Amount expected_credit_amount;
75 : struct TALER_WireTransferIdentifierRawP wtid;
76 : struct TALER_FullPayto payto_uri;
77 : char *exchange_url;
78 : uint64_t expected_transfer_serial_id;
79 : struct GNUNET_TIME_Timestamp execution_time;
80 : bool confirmed;
81 : bool validated;
82 0 : char *last_detail = NULL;
83 0 : uint32_t last_http_status = 0;
84 0 : uint32_t last_ec = TALER_EC_NONE;
85 0 : struct GNUNET_PQ_ResultSpec rs[] = {
86 0 : TALER_PQ_result_spec_amount_with_currency ("expected_credit_amount",
87 : &expected_credit_amount),
88 0 : GNUNET_PQ_result_spec_auto_from_type ("wtid",
89 : &wtid),
90 0 : GNUNET_PQ_result_spec_string ("payto_uri",
91 : &payto_uri.full_payto),
92 0 : GNUNET_PQ_result_spec_string ("exchange_url",
93 : &exchange_url),
94 0 : GNUNET_PQ_result_spec_uint64 ("expected_credit_serial",
95 : &expected_transfer_serial_id),
96 0 : GNUNET_PQ_result_spec_timestamp ("execution_time",
97 : &execution_time),
98 0 : GNUNET_PQ_result_spec_bool ("confirmed",
99 : &confirmed),
100 0 : GNUNET_PQ_result_spec_allow_null (
101 : GNUNET_PQ_result_spec_uint32 ("last_http_status",
102 : &last_http_status),
103 : NULL),
104 0 : GNUNET_PQ_result_spec_allow_null (
105 : GNUNET_PQ_result_spec_uint32 ("last_ec",
106 : &last_ec),
107 : NULL),
108 0 : GNUNET_PQ_result_spec_allow_null (
109 : GNUNET_PQ_result_spec_string ("last_detail",
110 : &last_detail),
111 : NULL),
112 : GNUNET_PQ_result_spec_end
113 : };
114 :
115 0 : if (GNUNET_OK !=
116 0 : GNUNET_PQ_extract_result (result,
117 : rs,
118 : i))
119 : {
120 0 : GNUNET_break (0);
121 0 : ltc->qs = GNUNET_DB_STATUS_HARD_ERROR;
122 0 : return;
123 : }
124 0 : validated = ( (MHD_HTTP_OK == last_http_status) &&
125 0 : (TALER_EC_NONE == last_ec) );
126 0 : ltc->cb (ltc->cb_cls,
127 : &expected_credit_amount,
128 : &wtid,
129 : payto_uri,
130 : exchange_url,
131 : expected_transfer_serial_id,
132 : execution_time,
133 : confirmed,
134 : validated,
135 : last_http_status,
136 : last_ec,
137 : last_detail);
138 0 : GNUNET_PQ_cleanup_result (rs);
139 : }
140 0 : ltc->qs = num_results;
141 : }
142 :
143 :
144 : enum GNUNET_DB_QueryStatus
145 0 : TMH_PG_lookup_expected_transfers (
146 : void *cls,
147 : const char *instance_id,
148 : struct TALER_FullPayto payto_uri,
149 : struct GNUNET_TIME_Timestamp before,
150 : struct GNUNET_TIME_Timestamp after,
151 : int64_t limit,
152 : uint64_t offset,
153 : enum TALER_EXCHANGE_YesNoAll confirmed,
154 : enum TALER_EXCHANGE_YesNoAll verified,
155 : TALER_MERCHANTDB_IncomingCallback cb,
156 : void *cb_cls)
157 : {
158 0 : struct PostgresClosure *pg = cls;
159 0 : uint64_t plimit = (uint64_t) ((limit < 0) ? -limit : limit);
160 0 : bool by_time = ( (! GNUNET_TIME_absolute_is_never (before.abs_time)) ||
161 0 : (! GNUNET_TIME_absolute_is_zero (after.abs_time)) );
162 0 : struct LookupExpectedTransfersContext ltc = {
163 : .cb = cb,
164 : .cb_cls = cb_cls,
165 : .pg = pg
166 : };
167 0 : struct GNUNET_PQ_QueryParam params[] = {
168 0 : GNUNET_PQ_query_param_string (instance_id),
169 0 : GNUNET_PQ_query_param_timestamp (&before),
170 0 : GNUNET_PQ_query_param_timestamp (&after),
171 0 : GNUNET_PQ_query_param_uint64 (&offset),
172 0 : GNUNET_PQ_query_param_uint64 (&plimit),
173 0 : NULL == payto_uri.full_payto
174 0 : ? GNUNET_PQ_query_param_null () /* NULL: do not filter by payto URI */
175 0 : : GNUNET_PQ_query_param_string (payto_uri.full_payto),
176 0 : GNUNET_PQ_query_param_bool (! by_time), /* $7: filter by time? */
177 0 : GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_ALL == confirmed), /* filter by confirmed? */
178 0 : GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_YES == confirmed),
179 0 : GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_ALL == verified), /* filter by verified? */
180 0 : GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_YES == verified),
181 :
182 : GNUNET_PQ_query_param_end
183 : };
184 : enum GNUNET_DB_QueryStatus qs;
185 :
186 0 : check_connection (pg);
187 0 : PREPARE (pg,
188 : "lookup_expected_transfers_asc",
189 : "SELECT"
190 : " met.expected_credit_amount"
191 : ",met.wtid"
192 : ",mac.payto_uri"
193 : ",met.exchange_url"
194 : ",met.expected_credit_serial"
195 : ",mts.execution_time"
196 : ",met.confirmed"
197 : ",met.last_http_status"
198 : ",met.last_ec"
199 : ",met.last_detail"
200 : " FROM merchant_expected_transfers met"
201 : " JOIN merchant_accounts mac"
202 : " USING (account_serial)"
203 : " LEFT JOIN merchant_transfer_signatures mts"
204 : " USING (expected_credit_serial)"
205 : " WHERE ( $7 OR "
206 : " (mts.execution_time IS NOT NULL AND"
207 : " mts.execution_time < $2 AND"
208 : " mts.execution_time >= $3) )"
209 : " AND ( (CAST($6 AS TEXT) IS NULL) OR "
210 : " (REGEXP_REPLACE(mac.payto_uri,'\\?.*','')"
211 : " =REGEXP_REPLACE($6,'\\?.*','')) )"
212 : " AND ( $8 OR "
213 : " (mt.confirmed = $9) )"
214 : " AND ( $10 OR "
215 : " ($11 = (200=mt.last_http_status) AND"
216 : " (0=mt.last_ec) ) )"
217 : " AND merchant_serial ="
218 : " (SELECT merchant_serial"
219 : " FROM merchant_instances"
220 : " WHERE merchant_id=$1)"
221 : " AND (met.expected_credit_serial > $4)"
222 : " ORDER BY met.expected_credit_serial ASC"
223 : " LIMIT $5");
224 0 : PREPARE (pg,
225 : "lookup_expected_transfers_desc",
226 : "SELECT"
227 : " met.expected_credit_amount"
228 : ",met.wtid"
229 : ",mac.payto_uri"
230 : ",met.exchange_url"
231 : ",met.expected_credit_serial"
232 : ",mts.execution_time"
233 : ",met.confirmed"
234 : ",met.last_http_status"
235 : ",met.last_ec"
236 : ",met.last_detail"
237 : " FROM merchant_expected_transfers met"
238 : " JOIN merchant_accounts mac"
239 : " USING (account_serial)"
240 : " LEFT JOIN merchant_transfer_signatures mts"
241 : " USING (expected_credit_serial)"
242 : " WHERE ( $7 OR "
243 : " (mts.execution_time IS NOT NULL AND"
244 : " mts.execution_time < $2 AND"
245 : " mts.execution_time >= $3) )"
246 : " AND ( (CAST($6 AS TEXT) IS NULL) OR "
247 : " (REGEXP_REPLACE(mac.payto_uri,'\\?.*','')"
248 : " =REGEXP_REPLACE($6,'\\?.*','')) )"
249 : " AND ( $8 OR "
250 : " (mt.expected = $9) )"
251 : " AND ( $10 OR "
252 : " ($11 = (200=mt.last_http_status) AND"
253 : " (0=mt.last_ec) ) )"
254 : " AND merchant_serial ="
255 : " (SELECT merchant_serial"
256 : " FROM merchant_instances"
257 : " WHERE merchant_id=$1)"
258 : " AND (met.expected_credit_serial < $4)"
259 : " ORDER BY met.expected_credit_serial DESC"
260 : " LIMIT $5");
261 0 : qs = GNUNET_PQ_eval_prepared_multi_select (
262 : pg->conn,
263 : (limit > 0)
264 : ? "lookup_expected_transfers_asc"
265 : : "lookup_expected_transfers_desc",
266 : params,
267 : &lookup_expected_transfers_cb,
268 : <c);
269 0 : if (0 >= qs)
270 0 : return qs;
271 0 : return ltc.qs;
272 : }
|