iterate_orders.c (11881B)
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 " NOT EXISTS" 171 " (SELECT 1" 172 " FROM merchant_contract_terms mct" 173 " WHERE mct.order_serial=merchant_orders.order_serial)" /* only select unclaimed orders */ 174 " AND ($10 OR " 175 " ($11 = session_id))" 176 " AND ($12 OR " 177 " ($13 = fulfillment_url))" 178 " AND ( ($14::TEXT IS NULL) OR " 179 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )" 180 " AND ($15 OR" 181 " (CAST($16 AS BOOL) = (pay_deadline < $17)))" 182 " ORDER BY order_serial ASC" 183 " LIMIT $1)" 184 "UNION " /* union ensures elements are distinct! */ 185 "(SELECT" 186 " order_id" 187 ",order_serial" 188 ",creation_time" 189 " FROM merchant_contract_terms" 190 " WHERE order_serial > $2" 191 " AND" 192 " creation_time > $3" 193 " AND ($4 OR " 194 " (CAST($5 AS BOOL) = paid))" 195 " AND ($6 OR " 196 " (CAST($7 AS BOOL) = EXISTS" 197 " (SELECT 1" 198 " FROM merchant_refunds mr" 199 " WHERE mr.order_serial=merchant_contract_terms.order_serial)))" 200 " AND ($8 OR" 201 " (CAST($9 AS BOOL) = wired))" 202 " AND ($10 OR " 203 " ($11 = session_id))" 204 " AND ($12 OR " 205 " ($13 = fulfillment_url))" 206 " AND ( ($14::TEXT IS NULL) OR " 207 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )" 208 " AND ($15 OR" 209 " (CAST($16 AS BOOL) = ((NOT paid) AND" 210 " (pay_deadline < $17))))" 211 " ORDER BY order_serial ASC" 212 " LIMIT $1)" 213 " ORDER BY order_serial ASC" 214 " LIMIT $1"); 215 } 216 else 217 { 218 TMH_PQ_prepare_anon (pg, 219 "(SELECT" 220 " order_id" 221 ",order_serial" 222 ",creation_time" 223 " FROM merchant_orders" 224 " WHERE order_serial < $2" 225 " AND" 226 " creation_time < $3" 227 " AND ($4 OR " 228 " NOT CAST($5 AS BOOL))" /* unclaimed orders are never paid */ 229 " AND ($6 OR " 230 " NOT CAST($7 AS BOOL))"/* unclaimed orders are never refunded */ 231 " AND ($8 OR " 232 " NOT CAST($9 AS BOOL))" /* unclaimed orders are never wired */ 233 " AND" 234 " NOT EXISTS" 235 " (SELECT 1" 236 " FROM merchant_contract_terms mct" 237 " WHERE mct.order_serial=merchant_orders.order_serial)" /* only select unclaimed orders */ 238 " AND ($10 OR " 239 " ($11 = session_id))" 240 " AND ($12 OR " 241 " ($13 = fulfillment_url))" 242 " AND ( ($14::TEXT IS NULL) OR " 243 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )" 244 " AND ($15 OR" 245 " (CAST($16 AS BOOL) = (pay_deadline < $17)))" 246 " ORDER BY order_serial DESC" 247 " LIMIT $1)" 248 "UNION " /* union ensures elements are distinct! */ 249 "(SELECT" 250 " order_id" 251 ",order_serial" 252 ",creation_time" 253 " FROM merchant_contract_terms" 254 " WHERE order_serial < $2" 255 " AND" 256 " creation_time < $3" 257 " AND ($4 OR " 258 " (CAST($5 AS BOOL) = paid))" 259 " AND ($6 OR " 260 " (CAST($7 AS BOOL) = EXISTS" 261 " (SELECT 1" 262 " FROM merchant_refunds mr" 263 " WHERE mr.order_serial=merchant_contract_terms.order_serial)))" 264 " AND ($8 OR" 265 " (CAST($9 AS BOOL) = wired))" 266 " AND ($10 OR " 267 " ($11 = session_id))" 268 " AND ($12 OR " 269 " ($13 = fulfillment_url))" 270 " AND ( ($14::TEXT IS NULL) OR " 271 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )" 272 " AND ($15 OR" 273 " (CAST($16 AS BOOL) = ((NOT paid) AND" 274 " (pay_deadline < $17))))" 275 " ORDER BY order_serial DESC" 276 " LIMIT $1)" 277 " ORDER BY order_serial DESC" 278 " LIMIT $1"); 279 } 280 qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, 281 "", 282 params, 283 &lookup_orders_cb, 284 &plc); 285 if (plc.extract_failed) 286 return GNUNET_DB_STATUS_HARD_ERROR; 287 return qs; 288 }