pg_get_expired_reserves.c (5103B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022, 2024 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 pg_get_expired_reserves.c 18 * @brief Low-level (statement-level) Postgres database access for the exchange 19 * @author Christian Grothoff 20 */ 21 #include "taler/platform.h" 22 #include "taler/taler_error_codes.h" 23 #include "taler/taler_dbevents.h" 24 #include "taler/taler_pq_lib.h" 25 #include "pg_get_expired_reserves.h" 26 #include "pg_helper.h" 27 28 29 /** 30 * Closure for #reserve_expired_cb(). 31 */ 32 struct ExpiredReserveContext 33 { 34 /** 35 * Function to call for each expired reserve. 36 */ 37 TALER_EXCHANGEDB_ReserveExpiredCallback rec; 38 39 /** 40 * Closure to give to @e rec. 41 */ 42 void *rec_cls; 43 44 /** 45 * Plugin context. 46 */ 47 struct PostgresClosure *pg; 48 49 /** 50 * Set to #GNUNET_SYSERR on error. 51 */ 52 enum GNUNET_GenericReturnValue status; 53 }; 54 55 56 /** 57 * Function to be called with the results of a SELECT statement 58 * that has returned @a num_results results. 59 * 60 * @param cls closure 61 * @param result the postgres result 62 * @param num_results the number of results in @a result 63 */ 64 static void 65 reserve_expired_cb (void *cls, 66 PGresult *result, 67 unsigned int num_results) 68 { 69 struct ExpiredReserveContext *erc = cls; 70 struct PostgresClosure *pg = erc->pg; 71 enum GNUNET_GenericReturnValue ret = GNUNET_OK; 72 73 for (unsigned int i = 0; i<num_results; i++) 74 { 75 struct GNUNET_TIME_Timestamp exp_date; 76 struct TALER_FullPayto account_details; 77 struct TALER_ReservePublicKeyP reserve_pub; 78 struct TALER_Amount remaining_balance; 79 struct GNUNET_PQ_ResultSpec rs[] = { 80 GNUNET_PQ_result_spec_timestamp ("expiration_date", 81 &exp_date), 82 GNUNET_PQ_result_spec_string ("account_details", 83 &account_details.full_payto), 84 GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", 85 &reserve_pub), 86 TALER_PQ_result_spec_amount ("current_balance", 87 pg->currency, 88 &remaining_balance), 89 GNUNET_PQ_result_spec_end 90 }; 91 92 if (GNUNET_OK != 93 GNUNET_PQ_extract_result (result, 94 rs, 95 i)) 96 { 97 GNUNET_break (0); 98 ret = GNUNET_SYSERR; 99 break; 100 } 101 ret = erc->rec (erc->rec_cls, 102 &reserve_pub, 103 &remaining_balance, 104 account_details, 105 exp_date, 106 0); 107 GNUNET_PQ_cleanup_result (rs); 108 if (GNUNET_OK != ret) 109 break; 110 } 111 erc->status = ret; 112 } 113 114 115 enum GNUNET_DB_QueryStatus 116 TEH_PG_get_expired_reserves ( 117 void *cls, 118 struct GNUNET_TIME_Timestamp now, 119 TALER_EXCHANGEDB_ReserveExpiredCallback rec, 120 void *rec_cls) 121 { 122 struct PostgresClosure *pg = cls; 123 struct GNUNET_PQ_QueryParam params[] = { 124 GNUNET_PQ_query_param_timestamp (&now), 125 GNUNET_PQ_query_param_end 126 }; 127 struct ExpiredReserveContext ectx = { 128 .rec = rec, 129 .rec_cls = rec_cls, 130 .pg = pg, 131 .status = GNUNET_OK 132 }; 133 enum GNUNET_DB_QueryStatus qs; 134 135 PREPARE (pg, 136 "get_expired_reserves", 137 "WITH ed AS MATERIALIZED ( " 138 " SELECT expiration_date" 139 " ,wire_source_h_payto" 140 " ,current_balance" 141 " ,r.reserve_pub" 142 " FROM reserves r" 143 " JOIN reserves_in" 144 " USING (reserve_pub)" 145 " WHERE expiration_date <= $1 " 146 " AND ((current_balance).val != 0 OR (current_balance).frac != 0) " 147 " ORDER BY expiration_date ASC " 148 " LIMIT 1 " 149 ") " 150 "SELECT" 151 " wt.payto_uri AS account_details" 152 " ,ed.expiration_date" 153 " ,ed.reserve_pub" 154 " ,ed.current_balance" 155 " FROM wire_targets wt" 156 " JOIN ed" 157 " ON (ed.wire_source_h_payto=wt.wire_target_h_payto);"); 158 qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, 159 "get_expired_reserves", 160 params, 161 &reserve_expired_cb, 162 &ectx); 163 switch (ectx.status) 164 { 165 case GNUNET_SYSERR: 166 return GNUNET_DB_STATUS_HARD_ERROR; 167 case GNUNET_NO: 168 return GNUNET_DB_STATUS_SOFT_ERROR; 169 case GNUNET_OK: 170 break; 171 } 172 return qs; 173 }