Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2022-2024 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_transfers.c
18 : * @brief Implementation of the lookup_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_transfers.h"
26 : #include "pg_helper.h"
27 :
28 :
29 : /**
30 : * Closure for #lookup_transfers_cb().
31 : */
32 : struct LookupTransfersContext
33 : {
34 : /**
35 : * Function to call on results.
36 : */
37 : TALER_MERCHANTDB_TransferCallback 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 LookupTransfersContext *`
62 : * @param result the postgres result
63 : * @param num_results the number of results in @a result
64 : */
65 : static void
66 12 : lookup_transfers_cb (void *cls,
67 : PGresult *result,
68 : unsigned int num_results)
69 : {
70 12 : struct LookupTransfersContext *ltc = cls;
71 :
72 29 : for (unsigned int i = 0; i<num_results; i++)
73 : {
74 : struct TALER_Amount credit_amount;
75 : struct TALER_WireTransferIdentifierRawP wtid;
76 : struct TALER_FullPayto payto_uri;
77 : char *exchange_url;
78 : uint64_t transfer_serial_id;
79 17 : struct GNUNET_TIME_Timestamp execution_time = GNUNET_TIME_UNIT_FOREVER_TS;
80 : bool verified;
81 : bool confirmed;
82 17 : struct GNUNET_PQ_ResultSpec rs[] = {
83 17 : TALER_PQ_result_spec_amount_with_currency ("credit_amount",
84 : &credit_amount),
85 17 : GNUNET_PQ_result_spec_auto_from_type ("wtid",
86 : &wtid),
87 17 : GNUNET_PQ_result_spec_string ("payto_uri",
88 : &payto_uri.full_payto),
89 17 : GNUNET_PQ_result_spec_string ("exchange_url",
90 : &exchange_url),
91 17 : GNUNET_PQ_result_spec_uint64 ("credit_serial",
92 : &transfer_serial_id),
93 17 : GNUNET_PQ_result_spec_allow_null (
94 : GNUNET_PQ_result_spec_timestamp ("execution_time",
95 : &execution_time),
96 : NULL),
97 17 : GNUNET_PQ_result_spec_bool ("verified",
98 : &verified),
99 17 : GNUNET_PQ_result_spec_bool ("confirmed",
100 : &confirmed),
101 : GNUNET_PQ_result_spec_end
102 : };
103 :
104 17 : if (GNUNET_OK !=
105 17 : GNUNET_PQ_extract_result (result,
106 : rs,
107 : i))
108 : {
109 0 : GNUNET_break (0);
110 0 : ltc->qs = GNUNET_DB_STATUS_HARD_ERROR;
111 0 : return;
112 : }
113 17 : ltc->cb (ltc->cb_cls,
114 : &credit_amount,
115 : &wtid,
116 : payto_uri,
117 : exchange_url,
118 : transfer_serial_id,
119 : execution_time,
120 : verified,
121 : confirmed);
122 17 : GNUNET_PQ_cleanup_result (rs);
123 : }
124 12 : ltc->qs = num_results;
125 : }
126 :
127 :
128 : enum GNUNET_DB_QueryStatus
129 12 : TMH_PG_lookup_transfers (void *cls,
130 : const char *instance_id,
131 : struct TALER_FullPayto payto_uri,
132 : struct GNUNET_TIME_Timestamp before,
133 : struct GNUNET_TIME_Timestamp after,
134 : int64_t limit,
135 : uint64_t offset,
136 : enum TALER_EXCHANGE_YesNoAll verified,
137 : TALER_MERCHANTDB_TransferCallback cb,
138 : void *cb_cls)
139 : {
140 12 : struct PostgresClosure *pg = cls;
141 12 : uint64_t plimit = (uint64_t) ((limit < 0) ? -limit : limit);
142 24 : bool by_time = ( (! GNUNET_TIME_absolute_is_never (before.abs_time)) ||
143 12 : (! GNUNET_TIME_absolute_is_zero (after.abs_time)) );
144 12 : struct LookupTransfersContext ltc = {
145 : .cb = cb,
146 : .cb_cls = cb_cls,
147 : .pg = pg
148 : };
149 12 : struct GNUNET_PQ_QueryParam params[] = {
150 12 : GNUNET_PQ_query_param_string (instance_id),
151 12 : GNUNET_PQ_query_param_timestamp (&before),
152 12 : GNUNET_PQ_query_param_timestamp (&after),
153 12 : GNUNET_PQ_query_param_uint64 (&offset),
154 12 : GNUNET_PQ_query_param_uint64 (&plimit),
155 12 : NULL == payto_uri.full_payto
156 8 : ? GNUNET_PQ_query_param_null () /* NULL: do not filter by payto URI */
157 12 : : GNUNET_PQ_query_param_string (payto_uri.full_payto),
158 12 : GNUNET_PQ_query_param_bool (! by_time), /* $7: filter by time? */
159 12 : GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_ALL == verified), /* filter by verified? */
160 12 : GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_YES == verified),
161 : GNUNET_PQ_query_param_end
162 : };
163 : enum GNUNET_DB_QueryStatus qs;
164 :
165 12 : check_connection (pg);
166 12 : PREPARE (pg,
167 : "lookup_transfers_asc",
168 : "SELECT"
169 : " mt.credit_amount"
170 : ",wtid"
171 : ",mac.payto_uri"
172 : ",exchange_url"
173 : ",credit_serial"
174 : ",mts.execution_time"
175 : ",verified"
176 : ",confirmed"
177 : " FROM merchant_transfers mt"
178 : " JOIN merchant_accounts mac"
179 : " USING (account_serial)"
180 : " LEFT JOIN merchant_transfer_signatures mts"
181 : " USING (credit_serial)"
182 : " WHERE ( $7 OR "
183 : " (mts.execution_time IS NOT NULL AND"
184 : " mts.execution_time < $2 AND"
185 : " mts.execution_time >= $3) )"
186 : " AND ( $8 OR "
187 : " (verified = $9) )"
188 : " AND ( (CAST($6 AS TEXT) IS NULL) OR "
189 : " (REGEXP_REPLACE(mac.payto_uri,'\\?.*','')"
190 : " =REGEXP_REPLACE($6,'\\?.*','')) )"
191 : " AND merchant_serial ="
192 : " (SELECT merchant_serial"
193 : " FROM merchant_instances"
194 : " WHERE merchant_id=$1)"
195 : " AND (credit_serial > $4)"
196 : " ORDER BY credit_serial ASC"
197 : " LIMIT $5");
198 12 : PREPARE (pg,
199 : "lookup_transfers_desc",
200 : "SELECT"
201 : " mt.credit_amount"
202 : ",wtid"
203 : ",mac.payto_uri"
204 : ",exchange_url"
205 : ",credit_serial"
206 : ",mts.execution_time"
207 : ",verified"
208 : ",confirmed"
209 : " FROM merchant_transfers mt"
210 : " JOIN merchant_accounts mac"
211 : " USING (account_serial)"
212 : " LEFT JOIN merchant_transfer_signatures mts"
213 : " USING (credit_serial)"
214 : " WHERE ( $7 OR "
215 : " (mts.execution_time IS NOT NULL AND"
216 : " mts.execution_time < $2 AND"
217 : " mts.execution_time >= $3) )"
218 : " AND ( $8 OR "
219 : " (verified = $9) )"
220 : " AND ( (CAST($6 AS TEXT) IS NULL) OR "
221 : " (REGEXP_REPLACE(mac.payto_uri,'\\?.*','')"
222 : " =REGEXP_REPLACE($6,'\\?.*','')) )"
223 : " AND merchant_serial ="
224 : " (SELECT merchant_serial"
225 : " FROM merchant_instances"
226 : " WHERE merchant_id=$1)"
227 : " AND (credit_serial < $4)"
228 : " ORDER BY credit_serial DESC"
229 : " LIMIT $5");
230 12 : qs = GNUNET_PQ_eval_prepared_multi_select (
231 : pg->conn,
232 : (limit > 0)
233 : ? "lookup_transfers_asc"
234 : : "lookup_transfers_desc",
235 : params,
236 : &lookup_transfers_cb,
237 : <c);
238 12 : if (0 >= qs)
239 1 : return qs;
240 11 : return ltc.qs;
241 : }
|