lookup_orders.c (10653B)
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/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_pq_lib.h> 24 #include "merchant-database/lookup_orders.h" 25 #include "helper.h" 26 27 /** 28 * Context used for TALER_MERCHANTDB_lookup_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_lookup_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_PQ_QueryParam params[] = { 111 /* $1 */ 112 GNUNET_PQ_query_param_uint64 (&limit), 113 GNUNET_PQ_query_param_uint64 (&of->start_row), 114 GNUNET_PQ_query_param_timestamp (&of->date), 115 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->paid)), 116 /* $5 */ 117 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->paid)), 118 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->refunded)), 119 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->refunded)), 120 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->wired)), 121 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->wired)), 122 /* $10 */ 123 GNUNET_PQ_query_param_bool (NULL == of->session_id), 124 NULL == of->session_id 125 ? GNUNET_PQ_query_param_null () 126 : GNUNET_PQ_query_param_string (of->session_id), 127 GNUNET_PQ_query_param_bool (NULL == of->fulfillment_url), 128 NULL == of->fulfillment_url 129 ? GNUNET_PQ_query_param_null () 130 : GNUNET_PQ_query_param_string (of->fulfillment_url), 131 NULL == of->summary_filter 132 ? GNUNET_PQ_query_param_null () 133 : GNUNET_PQ_query_param_string (of->summary_filter), 134 GNUNET_PQ_query_param_end 135 }; 136 enum GNUNET_DB_QueryStatus qs; 137 138 GNUNET_assert (NULL != pg->current_merchant_id); 139 GNUNET_assert (0 == strcmp (instance_id, 140 pg->current_merchant_id)); 141 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 142 "Looking up orders, using filter paid: %d, refunded: %d, wired: %d\n", 143 of->paid, 144 of->refunded, 145 of->wired); 146 147 if (of->delta > 0) 148 { 149 TMH_PQ_prepare_anon (pg, 150 "(SELECT" 151 " order_id" 152 ",order_serial" 153 ",creation_time" 154 " FROM merchant_orders" 155 " WHERE order_serial > $2" 156 " AND" 157 " creation_time > $3" 158 " AND ($4 OR " 159 " NOT CAST($5 AS BOOL))" /* unclaimed orders are never paid */ 160 " AND ($6 OR " 161 " NOT CAST($7 AS BOOL))"/* unclaimed orders are never refunded */ 162 " AND ($8 OR " 163 " NOT CAST($9 AS BOOL))" /* unclaimed orders are never wired */ 164 " AND" 165 " (order_serial NOT IN" 166 " (SELECT order_serial" 167 " FROM merchant_contract_terms))" /* only select unclaimed orders */ 168 " AND ($10 OR " 169 " ($11 = session_id))" 170 " AND ($12 OR " 171 " ($13 = fulfillment_url))" 172 " AND ( ($14::TEXT IS NULL) OR " 173 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )" 174 " ORDER BY order_serial ASC" 175 " LIMIT $1)" 176 "UNION " /* union ensures elements are distinct! */ 177 "(SELECT" 178 " order_id" 179 ",order_serial" 180 ",creation_time" 181 " FROM merchant_contract_terms" 182 " WHERE order_serial > $2" 183 " AND" 184 " creation_time > $3" 185 " AND ($4 OR " 186 " (CAST($5 AS BOOL) = paid))" 187 " AND ($6 OR " 188 " (CAST($7 AS BOOL) = (order_serial IN" 189 " (SELECT order_serial " 190 " FROM merchant_refunds))))" 191 " AND ($8 OR" 192 " (CAST($9 AS BOOL) = wired))" 193 " AND ($10 OR " 194 " ($11 = session_id))" 195 " AND ($12 OR " 196 " ($13 = fulfillment_url))" 197 " AND ( ($14::TEXT IS NULL) OR " 198 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )" 199 " ORDER BY order_serial ASC" 200 " LIMIT $1)" 201 " ORDER BY order_serial ASC" 202 " LIMIT $1"); 203 } 204 else 205 { 206 TMH_PQ_prepare_anon (pg, 207 "(SELECT" 208 " order_id" 209 ",order_serial" 210 ",creation_time" 211 " FROM merchant_orders" 212 " WHERE order_serial < $2" 213 " AND" 214 " creation_time < $3" 215 " AND ($4 OR " 216 " NOT CAST($5 AS BOOL))" /* unclaimed orders are never paid */ 217 " AND ($6 OR " 218 " NOT CAST($7 AS BOOL))"/* unclaimed orders are never refunded */ 219 " AND ($8 OR " 220 " NOT CAST($9 AS BOOL))" /* unclaimed orders are never wired */ 221 " AND" 222 " order_serial NOT IN" 223 " (SELECT order_serial" 224 " FROM merchant_contract_terms)" /* only select unclaimed orders */ 225 " AND ($10 OR " 226 " ($11 = session_id))" 227 " AND ($12 OR " 228 " ($13 = fulfillment_url))" 229 " AND ( ($14::TEXT IS NULL) OR " 230 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )" 231 " ORDER BY order_serial DESC" 232 " LIMIT $1)" 233 "UNION " /* union ensures elements are distinct! */ 234 "(SELECT" 235 " order_id" 236 ",order_serial" 237 ",creation_time" 238 " FROM merchant_contract_terms" 239 " WHERE order_serial < $2" 240 " AND" 241 " creation_time < $3" 242 " AND ($4 OR " 243 " (CAST($5 AS BOOL) = paid))" 244 " AND ($6 OR " 245 " (CAST($7 AS BOOL) = (order_serial IN" 246 " (SELECT order_serial " 247 " FROM merchant_refunds))))" 248 " AND ($8 OR" 249 " (CAST($9 AS BOOL) = wired))" 250 " AND ($10 OR " 251 " ($11 = session_id))" 252 " AND ($12 OR " 253 " ($13 = fulfillment_url))" 254 " AND ( ($14::TEXT IS NULL) OR " 255 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )" 256 " ORDER BY order_serial DESC" 257 " LIMIT $1)" 258 " ORDER BY order_serial DESC" 259 " LIMIT $1"); 260 } 261 qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, 262 "", 263 params, 264 &lookup_orders_cb, 265 &plc); 266 if (plc.extract_failed) 267 return GNUNET_DB_STATUS_HARD_ERROR; 268 return qs; 269 }