iterate_unfinished_close_requests.c (5367B)
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 iterate_unfinished_close_requests.c 18 * @brief Low-level (statement-level) Postgres database access for the exchange 19 * @author Christian Grothoff 20 */ 21 #include "taler/taler_pq_lib.h" 22 #include "exchange-database/iterate_unfinished_close_requests.h" 23 #include "helper.h" 24 25 26 /** 27 * Closure for #reserve_close_cb(). 28 */ 29 struct CloseReserveContext 30 { 31 /** 32 * Function to call for each to be closed reserve. 33 */ 34 TALER_EXCHANGEDB_ReserveExpiredCallback rec; 35 36 /** 37 * Closure to give to @e rec. 38 */ 39 void *rec_cls; 40 41 /** 42 * Plugin context. 43 */ 44 struct TALER_EXCHANGEDB_PostgresContext *pg; 45 46 /** 47 * Set to #GNUNET_SYSERR on error. 48 */ 49 enum GNUNET_GenericReturnValue status; 50 }; 51 52 53 /** 54 * Function to be called with the results of a SELECT statement 55 * that has returned @a num_results results. 56 * 57 * @param cls closure 58 * @param result the postgres result 59 * @param num_results the number of results in @a result 60 */ 61 static void 62 reserve_cb (void *cls, 63 PGresult *result, 64 unsigned int num_results) 65 { 66 struct CloseReserveContext *erc = cls; 67 struct TALER_EXCHANGEDB_PostgresContext *pg = erc->pg; 68 enum GNUNET_GenericReturnValue ret = GNUNET_OK; 69 70 for (unsigned int i = 0; i<num_results; i++) 71 { 72 struct GNUNET_TIME_Timestamp exp_date; 73 struct TALER_FullPayto account_details; 74 struct TALER_ReservePublicKeyP reserve_pub; 75 struct TALER_Amount remaining_balance; 76 uint64_t close_request_row; 77 struct GNUNET_PQ_ResultSpec rs[] = { 78 GNUNET_PQ_result_spec_timestamp ("expiration_date", 79 &exp_date), 80 GNUNET_PQ_result_spec_allow_null ( 81 GNUNET_PQ_result_spec_string ("account_details", 82 &account_details.full_payto), 83 NULL), 84 GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", 85 &reserve_pub), 86 TALER_PQ_RESULT_SPEC_AMOUNT ("close", 87 &remaining_balance), 88 GNUNET_PQ_result_spec_uint64 ("close_request_serial_id", 89 &close_request_row), 90 GNUNET_PQ_result_spec_end 91 }; 92 93 /* If neither the close request nor the reserve identifies a bank 94 account, the callback is given a NULL payto URI. */ 95 account_details.full_payto = NULL; 96 if (GNUNET_OK != 97 GNUNET_PQ_extract_result (result, 98 rs, 99 i)) 100 { 101 GNUNET_break (0); 102 ret = GNUNET_SYSERR; 103 break; 104 } 105 ret = erc->rec (erc->rec_cls, 106 &reserve_pub, 107 &remaining_balance, 108 account_details, 109 exp_date, 110 close_request_row); 111 GNUNET_PQ_cleanup_result (rs); 112 if (GNUNET_OK != ret) 113 break; 114 } 115 erc->status = ret; 116 } 117 118 119 enum GNUNET_DB_QueryStatus 120 TALER_EXCHANGEDB_iterate_unfinished_close_requests ( 121 struct TALER_EXCHANGEDB_PostgresContext *pg, 122 TALER_EXCHANGEDB_ReserveExpiredCallback rec, 123 void *rec_cls) 124 { 125 struct GNUNET_PQ_QueryParam params[] = { 126 GNUNET_PQ_query_param_end 127 }; 128 struct CloseReserveContext ectx = { 129 .rec = rec, 130 .rec_cls = rec_cls, 131 .pg = pg, 132 .status = GNUNET_OK 133 }; 134 enum GNUNET_DB_QueryStatus qs; 135 136 PREPARE (pg, 137 "iterate_unfinished_close_requests", 138 "UPDATE close_requests AS rc" 139 " SET done=TRUE" 140 " WHERE NOT done" 141 " RETURNING" 142 " reserve_pub" 143 " ,close_request_serial_id" 144 " ,close_timestamp AS expiration_date" 145 " ,close" 146 /* The account designated by the client (and covered by the KYC 147 check done at the time of the request) takes precedence over 148 the account the reserve was funded from. */ 149 " ,COALESCE(rc.payto_uri" 150 " ,(SELECT payto_uri" 151 " FROM reserves_in ri" 152 " JOIN wire_targets wt" 153 " ON (ri.wire_source_h_payto = wt.wire_target_h_payto)" 154 " WHERE ri.reserve_pub=rc.reserve_pub))" 155 " AS account_details;"); 156 qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, 157 "iterate_unfinished_close_requests", 158 params, 159 &reserve_cb, 160 &ectx); 161 switch (ectx.status) 162 { 163 case GNUNET_SYSERR: 164 return GNUNET_DB_STATUS_HARD_ERROR; 165 case GNUNET_NO: 166 return GNUNET_DB_STATUS_SOFT_ERROR; 167 case GNUNET_OK: 168 break; 169 } 170 return qs; 171 }