Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2022,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 backenddb/pg_lookup_orders.c
18 : * @brief Implementation of the lookup_orders function for Postgres
19 : * @author Iván Ávalos
20 : * @author Christian Grothoff
21 : */
22 : #include "platform.h"
23 : #include <taler/taler_error_codes.h>
24 : #include <taler/taler_dbevents.h>
25 : #include <taler/taler_pq_lib.h>
26 : #include "pg_lookup_orders.h"
27 : #include "pg_helper.h"
28 :
29 : /**
30 : * Context used for TMH_PG_lookup_orders().
31 : */
32 : struct LookupOrdersContext
33 : {
34 : /**
35 : * Function to call with the results.
36 : */
37 : TALER_MERCHANTDB_OrdersCallback cb;
38 :
39 : /**
40 : * Closure for @a cb.
41 : */
42 : void *cb_cls;
43 :
44 : /**
45 : * Did database result extraction fail?
46 : */
47 : bool extract_failed;
48 : };
49 :
50 :
51 : /**
52 : * Function to be called with the results of a SELECT statement
53 : * that has returned @a num_results results about orders.
54 : *
55 : * @param[in,out] cls of type `struct LookupOrdersContext *`
56 : * @param result the postgres result
57 : * @param num_results the number of results in @a result
58 : */
59 : static void
60 14 : lookup_orders_cb (void *cls,
61 : PGresult *result,
62 : unsigned int num_results)
63 : {
64 14 : struct LookupOrdersContext *plc = cls;
65 :
66 27 : for (unsigned int i = 0; i < num_results; i++)
67 : {
68 : char *order_id;
69 : uint64_t order_serial;
70 : struct GNUNET_TIME_Timestamp ts;
71 13 : struct GNUNET_PQ_ResultSpec rs[] = {
72 13 : GNUNET_PQ_result_spec_string ("order_id",
73 : &order_id),
74 13 : GNUNET_PQ_result_spec_uint64 ("order_serial",
75 : &order_serial),
76 13 : GNUNET_PQ_result_spec_timestamp ("creation_time",
77 : &ts),
78 : GNUNET_PQ_result_spec_end
79 : };
80 :
81 13 : if (GNUNET_OK !=
82 13 : GNUNET_PQ_extract_result (result,
83 : rs,
84 : i))
85 : {
86 0 : GNUNET_break (0);
87 0 : plc->extract_failed = true;
88 0 : return;
89 : }
90 13 : plc->cb (plc->cb_cls,
91 : order_id,
92 : order_serial,
93 : ts);
94 13 : GNUNET_PQ_cleanup_result (rs);
95 : }
96 : }
97 :
98 :
99 : enum GNUNET_DB_QueryStatus
100 14 : TMH_PG_lookup_orders (void *cls,
101 : const char *instance_id,
102 : const struct TALER_MERCHANTDB_OrderFilter *of,
103 : TALER_MERCHANTDB_OrdersCallback cb,
104 : void *cb_cls)
105 : {
106 14 : struct PostgresClosure *pg = cls;
107 14 : struct LookupOrdersContext plc = {
108 : .cb = cb,
109 : .cb_cls = cb_cls
110 : };
111 14 : uint64_t limit = (of->delta > 0) ? of->delta : -of->delta;
112 14 : struct GNUNET_PQ_QueryParam params[] = {
113 : /* $1 */
114 14 : GNUNET_PQ_query_param_string (instance_id),
115 14 : GNUNET_PQ_query_param_uint64 (&limit),
116 14 : GNUNET_PQ_query_param_uint64 (&of->start_row),
117 14 : GNUNET_PQ_query_param_timestamp (&of->date),
118 14 : GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->paid)),
119 : /* $6 */
120 14 : GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->paid)),
121 14 : GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->refunded)),
122 14 : GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->refunded)),
123 14 : GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->wired)),
124 14 : GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->wired)),
125 : /* $11 */
126 14 : GNUNET_PQ_query_param_bool (NULL == of->session_id),
127 14 : NULL == of->session_id
128 14 : ? GNUNET_PQ_query_param_null ()
129 14 : : GNUNET_PQ_query_param_string (of->session_id),
130 14 : GNUNET_PQ_query_param_bool (NULL == of->fulfillment_url),
131 14 : NULL == of->fulfillment_url
132 14 : ? GNUNET_PQ_query_param_null ()
133 14 : : GNUNET_PQ_query_param_string (of->fulfillment_url),
134 : GNUNET_PQ_query_param_end
135 : };
136 : enum GNUNET_DB_QueryStatus qs;
137 : char stmt[128];
138 :
139 14 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
140 : "Looking up orders, using filter paid:%d, refunded: %d, wired: %d\n",
141 : of->paid,
142 : of->refunded,
143 : of->wired);
144 14 : GNUNET_snprintf (stmt,
145 : sizeof (stmt),
146 : "lookup_orders_%s",
147 14 : (of->delta > 0) ? "inc" : "dec");
148 14 : PREPARE (pg,
149 : "lookup_orders_dec",
150 : "(SELECT"
151 : " order_id"
152 : ",order_serial"
153 : ",creation_time"
154 : " FROM merchant_orders"
155 : " WHERE merchant_orders.merchant_serial="
156 : " (SELECT merchant_serial "
157 : " FROM merchant_instances"
158 : " WHERE merchant_id=$1)"
159 : " AND"
160 : " order_serial < $3"
161 : " AND"
162 : " creation_time < $4"
163 : " AND ($5 OR "
164 : " NOT CAST($6 AS BOOL))" /* unclaimed orders are never paid */
165 : " AND ($7 OR "
166 : " NOT CAST($8 AS BOOL))"/* unclaimed orders are never refunded */
167 : " AND ($9 OR "
168 : " NOT CAST($10 AS BOOL))" /* unclaimed orders are never wired */
169 : " AND"
170 : " order_serial NOT IN"
171 : " (SELECT order_serial"
172 : " FROM merchant_contract_terms)" /* only select unclaimed orders */
173 : " AND ($11 OR "
174 : " ($12 = session_id))"
175 : " AND ($13 OR "
176 : " ($14 = fulfillment_url))"
177 : " ORDER BY order_serial DESC"
178 : " LIMIT $2)"
179 : "UNION " /* union ensures elements are distinct! */
180 : "(SELECT"
181 : " order_id"
182 : ",order_serial"
183 : ",creation_time"
184 : " FROM merchant_contract_terms"
185 : " WHERE merchant_contract_terms.merchant_serial="
186 : " (SELECT merchant_serial "
187 : " FROM merchant_instances"
188 : " WHERE merchant_id=$1)"
189 : " AND"
190 : " order_serial < $3"
191 : " AND"
192 : " creation_time < $4"
193 : " AND ($5 OR "
194 : " (CAST($6 AS BOOL) = paid))"
195 : " AND ($7 OR "
196 : " (CAST($8 AS BOOL) = (order_serial IN"
197 : " (SELECT order_serial "
198 : " FROM merchant_refunds))))"
199 : " AND ($9 OR"
200 : " (CAST($10 AS BOOL) = wired))"
201 : " AND ($11 OR "
202 : " ($12 = session_id))"
203 : " AND ($13 OR "
204 : " ($14 = fulfillment_url))"
205 : " ORDER BY order_serial DESC"
206 : " LIMIT $2)"
207 : " ORDER BY order_serial DESC"
208 : " LIMIT $2");
209 :
210 14 : PREPARE (pg,
211 : "lookup_orders_inc",
212 : "(SELECT"
213 : " order_id"
214 : ",order_serial"
215 : ",creation_time"
216 : " FROM merchant_orders"
217 : " WHERE merchant_orders.merchant_serial="
218 : " (SELECT merchant_serial "
219 : " FROM merchant_instances"
220 : " WHERE merchant_id=$1)"
221 : " AND"
222 : " order_serial > $3"
223 : " AND"
224 : " creation_time > $4"
225 : " AND ($5 OR "
226 : " NOT CAST($6 AS BOOL))" /* unclaimed orders are never paid */
227 : " AND ($7 OR "
228 : " NOT CAST($8 AS BOOL))"/* unclaimed orders are never refunded */
229 : " AND ($9 OR "
230 : " NOT CAST($10 AS BOOL))" /* unclaimed orders are never wired */
231 : " AND"
232 : " (order_serial NOT IN"
233 : " (SELECT order_serial"
234 : " FROM merchant_contract_terms))" /* only select unclaimed orders */
235 : " AND ($11 OR "
236 : " ($12 = session_id))"
237 : " AND ($13 OR "
238 : " ($14 = fulfillment_url))"
239 : " ORDER BY order_serial ASC"
240 : " LIMIT $2)"
241 : "UNION " /* union ensures elements are distinct! */
242 : "(SELECT"
243 : " order_id"
244 : ",order_serial"
245 : ",creation_time"
246 : " FROM merchant_contract_terms"
247 : " WHERE merchant_contract_terms.merchant_serial="
248 : " (SELECT merchant_serial "
249 : " FROM merchant_instances"
250 : " WHERE merchant_id=$1)"
251 : " AND"
252 : " order_serial > $3"
253 : " AND"
254 : " creation_time > $4"
255 : " AND ($5 OR "
256 : " (CAST($6 AS BOOL) = paid))"
257 : " AND ($7 OR "
258 : " (CAST($8 AS BOOL) = (order_serial IN"
259 : " (SELECT order_serial "
260 : " FROM merchant_refunds))))"
261 : " AND ($9 OR"
262 : " (CAST($10 AS BOOL) = wired))"
263 : " AND ($11 OR "
264 : " ($12 = session_id))"
265 : " AND ($13 OR "
266 : " ($14 = fulfillment_url))"
267 : " ORDER BY order_serial ASC"
268 : " LIMIT $2)"
269 : " ORDER BY order_serial ASC"
270 : " LIMIT $2");
271 :
272 14 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
273 : stmt,
274 : params,
275 : &lookup_orders_cb,
276 : &plc);
277 14 : if (plc.extract_failed)
278 0 : return GNUNET_DB_STATUS_HARD_ERROR;
279 14 : return qs;
280 : }
|