iterate_money_pots.c (5284B)
1 /* 2 This file is part of TALER 3 Copyright (C) 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_money_pots.c 18 * @brief Implementation of the iterate_money_pots function for Postgres 19 * @author Christian Grothoff 20 */ 21 #include "platform.h" 22 #include <taler/taler_pq_lib.h> 23 #include "merchant-database/iterate_money_pots.h" 24 #include "helper.h" 25 26 27 /** 28 * Hard upper bound on the number of records returned by a single 29 * call, regardless of the limit requested by the client. 30 */ 31 #define MAX_RECORDS 50000 32 33 34 /** 35 * Context used for TALER_MERCHANTDB_iterate_money_pots(). 36 */ 37 struct LookupMoneyPotsContext 38 { 39 /** 40 * DB context. 41 */ 42 struct TALER_MERCHANTDB_PostgresContext *pg; 43 44 /** 45 * Function to call with the results. 46 */ 47 TALER_MERCHANTDB_MoneyPotsCallback cb; 48 49 /** 50 * Closure for @a cb. 51 */ 52 void *cb_cls; 53 54 /** 55 * Did database result extraction fail? 56 */ 57 bool extract_failed; 58 }; 59 60 61 /** 62 * Function to be called with the results of a SELECT statement 63 * that has returned @a num_results results about money pots. 64 * 65 * @param[in,out] cls of type `struct LookupMoneyPotsContext *` 66 * @param result the postgres result 67 * @param num_results the number of results in @a result 68 */ 69 static void 70 lookup_money_pots_cb (void *cls, 71 PGresult *result, 72 unsigned int num_results) 73 { 74 struct LookupMoneyPotsContext *plc = cls; 75 76 for (unsigned int i = 0; i < num_results; i++) 77 { 78 uint64_t money_pot_serial; 79 char *money_pot_name; 80 size_t pot_total_len; 81 struct TALER_Amount *pot_totals; 82 struct GNUNET_PQ_ResultSpec rs[] = { 83 GNUNET_PQ_result_spec_uint64 ("money_pot_serial", 84 &money_pot_serial), 85 GNUNET_PQ_result_spec_string ("money_pot_name", 86 &money_pot_name), 87 TALER_PQ_result_spec_array_amount_with_currency (plc->pg->conn, 88 "merchant", 89 "pot_totals", 90 &pot_total_len, 91 &pot_totals), 92 GNUNET_PQ_result_spec_end 93 }; 94 95 if (GNUNET_OK != 96 GNUNET_PQ_extract_result (result, 97 rs, 98 i)) 99 { 100 GNUNET_break (0); 101 plc->extract_failed = true; 102 return; 103 } 104 plc->cb (plc->cb_cls, 105 money_pot_serial, 106 money_pot_name, 107 pot_total_len, 108 pot_totals); 109 GNUNET_PQ_cleanup_result (rs); 110 } 111 } 112 113 114 enum GNUNET_DB_QueryStatus 115 TALER_MERCHANTDB_iterate_money_pots ( 116 struct TALER_MERCHANTDB_PostgresContext *pg, 117 const char *instance_id, 118 int64_t limit, 119 uint64_t offset, 120 TALER_MERCHANTDB_MoneyPotsCallback cb, 121 void *cb_cls) 122 { 123 uint64_t plimit = GNUNET_MIN ((uint64_t) MAX_RECORDS, 124 TALER_MERCHANTDB_abs_limit (limit)); 125 struct LookupMoneyPotsContext plc = { 126 .pg = pg, 127 .cb = cb, 128 .cb_cls = cb_cls, 129 /* Can be overwritten by the lookup_money_pots_cb */ 130 .extract_failed = false, 131 }; 132 struct GNUNET_PQ_QueryParam params[] = { 133 GNUNET_PQ_query_param_uint64 (&offset), 134 GNUNET_PQ_query_param_uint64 (&plimit), 135 GNUNET_PQ_query_param_end 136 }; 137 enum GNUNET_DB_QueryStatus qs; 138 139 GNUNET_assert (NULL != pg->current_merchant_id); 140 GNUNET_assert (0 == strcmp (instance_id, 141 pg->current_merchant_id)); 142 if (limit > 0) 143 { 144 TMH_PQ_prepare_anon (pg, 145 "SELECT" 146 " money_pot_serial" 147 " ,money_pot_name" 148 " ,pot_totals" 149 " FROM merchant_money_pots" 150 " WHERE money_pot_serial > $1" 151 " ORDER BY money_pot_serial ASC" 152 " LIMIT $2"); 153 } 154 else 155 { 156 TMH_PQ_prepare_anon (pg, 157 "SELECT" 158 " money_pot_serial" 159 " ,money_pot_name" 160 " ,pot_totals" 161 " FROM merchant_money_pots" 162 " WHERE money_pot_serial < $1" 163 " ORDER BY money_pot_serial DESC" 164 " LIMIT $2"); 165 } 166 qs = GNUNET_PQ_eval_prepared_multi_select ( 167 pg->conn, 168 "", 169 params, 170 &lookup_money_pots_cb, 171 &plc); 172 /* If there was an error inside lookup_money_pots_cb, return a hard error. */ 173 if (plc.extract_failed) 174 { 175 GNUNET_break (0); 176 return GNUNET_DB_STATUS_HARD_ERROR; 177 } 178 return qs; 179 }