pg_lookup_orders.c (10171B)
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 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 lookup_orders_cb (void *cls, 61 PGresult *result, 62 unsigned int num_results) 63 { 64 struct LookupOrdersContext *plc = cls; 65 66 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 struct GNUNET_PQ_ResultSpec rs[] = { 72 GNUNET_PQ_result_spec_string ("order_id", 73 &order_id), 74 GNUNET_PQ_result_spec_uint64 ("order_serial", 75 &order_serial), 76 GNUNET_PQ_result_spec_timestamp ("creation_time", 77 &ts), 78 GNUNET_PQ_result_spec_end 79 }; 80 81 if (GNUNET_OK != 82 GNUNET_PQ_extract_result (result, 83 rs, 84 i)) 85 { 86 GNUNET_break (0); 87 plc->extract_failed = true; 88 return; 89 } 90 plc->cb (plc->cb_cls, 91 order_id, 92 order_serial, 93 ts); 94 GNUNET_PQ_cleanup_result (rs); 95 } 96 } 97 98 99 enum GNUNET_DB_QueryStatus 100 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 struct PostgresClosure *pg = cls; 107 struct LookupOrdersContext plc = { 108 .cb = cb, 109 .cb_cls = cb_cls 110 }; 111 uint64_t limit = (of->delta > 0) ? of->delta : -of->delta; 112 struct GNUNET_PQ_QueryParam params[] = { 113 /* $1 */ 114 GNUNET_PQ_query_param_string (instance_id), 115 GNUNET_PQ_query_param_uint64 (&limit), 116 GNUNET_PQ_query_param_uint64 (&of->start_row), 117 GNUNET_PQ_query_param_timestamp (&of->date), 118 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->paid)), 119 /* $6 */ 120 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->paid)), 121 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->refunded)), 122 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->refunded)), 123 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->wired)), 124 GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->wired)), 125 /* $11 */ 126 GNUNET_PQ_query_param_bool (NULL == of->session_id), 127 NULL == of->session_id 128 ? GNUNET_PQ_query_param_null () 129 : GNUNET_PQ_query_param_string (of->session_id), 130 GNUNET_PQ_query_param_bool (NULL == of->fulfillment_url), 131 NULL == of->fulfillment_url 132 ? GNUNET_PQ_query_param_null () 133 : GNUNET_PQ_query_param_string (of->fulfillment_url), 134 NULL == of->summary_filter 135 ? GNUNET_PQ_query_param_null () 136 : GNUNET_PQ_query_param_string (of->summary_filter), 137 GNUNET_PQ_query_param_end 138 }; 139 enum GNUNET_DB_QueryStatus qs; 140 char stmt[128]; 141 142 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 143 "Looking up orders, using filter paid: %d, refunded: %d, wired: %d\n", 144 of->paid, 145 of->refunded, 146 of->wired); 147 GNUNET_snprintf (stmt, 148 sizeof (stmt), 149 "lookup_orders_%s", 150 (of->delta > 0) ? "inc" : "dec"); 151 PREPARE (pg, 152 "lookup_orders_dec", 153 "(SELECT" 154 " order_id" 155 ",order_serial" 156 ",creation_time" 157 " FROM merchant_orders" 158 " WHERE merchant_orders.merchant_serial=" 159 " (SELECT merchant_serial " 160 " FROM merchant_instances" 161 " WHERE merchant_id=$1)" 162 " AND" 163 " order_serial < $3" 164 " AND" 165 " creation_time < $4" 166 " AND ($5 OR " 167 " NOT CAST($6 AS BOOL))" /* unclaimed orders are never paid */ 168 " AND ($7 OR " 169 " NOT CAST($8 AS BOOL))"/* unclaimed orders are never refunded */ 170 " AND ($9 OR " 171 " NOT CAST($10 AS BOOL))" /* unclaimed orders are never wired */ 172 " AND" 173 " order_serial NOT IN" 174 " (SELECT order_serial" 175 " FROM merchant_contract_terms)" /* only select unclaimed orders */ 176 " AND ($11 OR " 177 " ($12 = session_id))" 178 " AND ($13 OR " 179 " ($14 = fulfillment_url))" 180 " AND ( ($15::TEXT IS NULL) OR " 181 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($15)) )" 182 " ORDER BY order_serial DESC" 183 " LIMIT $2)" 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 merchant_contract_terms.merchant_serial=" 191 " (SELECT merchant_serial " 192 " FROM merchant_instances" 193 " WHERE merchant_id=$1)" 194 " AND" 195 " order_serial < $3" 196 " AND" 197 " creation_time < $4" 198 " AND ($5 OR " 199 " (CAST($6 AS BOOL) = paid))" 200 " AND ($7 OR " 201 " (CAST($8 AS BOOL) = (order_serial IN" 202 " (SELECT order_serial " 203 " FROM merchant_refunds))))" 204 " AND ($9 OR" 205 " (CAST($10 AS BOOL) = wired))" 206 " AND ($11 OR " 207 " ($12 = session_id))" 208 " AND ($13 OR " 209 " ($14 = fulfillment_url))" 210 " AND ( ($15::TEXT IS NULL) OR " 211 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($15)) )" 212 " ORDER BY order_serial DESC" 213 " LIMIT $2)" 214 " ORDER BY order_serial DESC" 215 " LIMIT $2"); 216 217 PREPARE (pg, 218 "lookup_orders_inc", 219 "(SELECT" 220 " order_id" 221 ",order_serial" 222 ",creation_time" 223 " FROM merchant_orders" 224 " WHERE merchant_orders.merchant_serial=" 225 " (SELECT merchant_serial " 226 " FROM merchant_instances" 227 " WHERE merchant_id=$1)" 228 " AND" 229 " order_serial > $3" 230 " AND" 231 " creation_time > $4" 232 " AND ($5 OR " 233 " NOT CAST($6 AS BOOL))" /* unclaimed orders are never paid */ 234 " AND ($7 OR " 235 " NOT CAST($8 AS BOOL))"/* unclaimed orders are never refunded */ 236 " AND ($9 OR " 237 " NOT CAST($10 AS BOOL))" /* unclaimed orders are never wired */ 238 " AND" 239 " (order_serial NOT IN" 240 " (SELECT order_serial" 241 " FROM merchant_contract_terms))" /* only select unclaimed orders */ 242 " AND ($11 OR " 243 " ($12 = session_id))" 244 " AND ($13 OR " 245 " ($14 = fulfillment_url))" 246 " AND ( ($15::TEXT IS NULL) OR " 247 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($15)) )" 248 " ORDER BY order_serial ASC" 249 " LIMIT $2)" 250 "UNION " /* union ensures elements are distinct! */ 251 "(SELECT" 252 " order_id" 253 ",order_serial" 254 ",creation_time" 255 " FROM merchant_contract_terms" 256 " WHERE merchant_contract_terms.merchant_serial=" 257 " (SELECT merchant_serial " 258 " FROM merchant_instances" 259 " WHERE merchant_id=$1)" 260 " AND" 261 " order_serial > $3" 262 " AND" 263 " creation_time > $4" 264 " AND ($5 OR " 265 " (CAST($6 AS BOOL) = paid))" 266 " AND ($7 OR " 267 " (CAST($8 AS BOOL) = (order_serial IN" 268 " (SELECT order_serial " 269 " FROM merchant_refunds))))" 270 " AND ($9 OR" 271 " (CAST($10 AS BOOL) = wired))" 272 " AND ($11 OR " 273 " ($12 = session_id))" 274 " AND ($13 OR " 275 " ($14 = fulfillment_url))" 276 " AND ( ($15::TEXT IS NULL) OR " 277 " (LOWER(contract_terms ->> 'summary') LIKE LOWER($15)) )" 278 " ORDER BY order_serial ASC" 279 " LIMIT $2)" 280 " ORDER BY order_serial ASC" 281 " LIMIT $2"); 282 283 qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, 284 stmt, 285 params, 286 &lookup_orders_cb, 287 &plc); 288 if (plc.extract_failed) 289 return GNUNET_DB_STATUS_HARD_ERROR; 290 return qs; 291 }