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