pg_select_refunds_above_serial_id.c (7468B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022 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 exchangedb/pg_select_refunds_above_serial_id.c 18 * @brief Implementation of the select_refunds_above_serial_id function for Postgres 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_select_refunds_above_serial_id.h" 26 #include "pg_helper.h" 27 28 /** 29 * Closure for #refunds_serial_helper_cb(). 30 */ 31 struct RefundsSerialContext 32 { 33 34 /** 35 * Callback to call. 36 */ 37 TALER_EXCHANGEDB_RefundCallback cb; 38 39 /** 40 * Closure for @e cb. 41 */ 42 void *cb_cls; 43 44 /** 45 * Plugin context. 46 */ 47 struct PostgresClosure *pg; 48 49 /** 50 * Status code, set to #GNUNET_SYSERR on hard errors. 51 */ 52 enum GNUNET_GenericReturnValue status; 53 }; 54 55 56 /** 57 * Helper function to be called with the results of a SELECT statement 58 * that has returned @a num_results results. 59 * 60 * @param cls closure of type `struct RefundsSerialContext` 61 * @param result the postgres result 62 * @param num_results the number of results in @a result 63 */ 64 static void 65 refunds_serial_helper_cb (void *cls, 66 PGresult *result, 67 unsigned int num_results) 68 { 69 struct RefundsSerialContext *rsc = cls; 70 struct PostgresClosure *pg = rsc->pg; 71 72 for (unsigned int i = 0; i<num_results; i++) 73 { 74 struct TALER_EXCHANGEDB_Refund refund; 75 struct TALER_DenominationPublicKey denom_pub; 76 uint64_t rowid; 77 bool full_refund; 78 struct GNUNET_PQ_ResultSpec rs[] = { 79 GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", 80 &refund.details.merchant_pub), 81 GNUNET_PQ_result_spec_auto_from_type ("merchant_sig", 82 &refund.details.merchant_sig), 83 GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms", 84 &refund.details.h_contract_terms), 85 GNUNET_PQ_result_spec_uint64 ("rtransaction_id", 86 &refund.details.rtransaction_id), 87 TALER_PQ_result_spec_denom_pub ("denom_pub", 88 &denom_pub), 89 GNUNET_PQ_result_spec_auto_from_type ("coin_pub", 90 &refund.coin.coin_pub), 91 TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", 92 &refund.details.refund_amount), 93 GNUNET_PQ_result_spec_uint64 ("refund_serial_id", 94 &rowid), 95 GNUNET_PQ_result_spec_end 96 }; 97 enum GNUNET_GenericReturnValue ret; 98 99 if (GNUNET_OK != 100 GNUNET_PQ_extract_result (result, 101 rs, 102 i)) 103 { 104 GNUNET_break (0); 105 rsc->status = GNUNET_SYSERR; 106 return; 107 } 108 { 109 struct GNUNET_PQ_QueryParam params[] = { 110 GNUNET_PQ_query_param_uint64 (&rowid), 111 GNUNET_PQ_query_param_end 112 }; 113 struct TALER_Amount amount_with_fee; 114 uint64_t s_f; 115 uint64_t s_v; 116 struct GNUNET_PQ_ResultSpec rs2[] = { 117 GNUNET_PQ_result_spec_uint64 ("s_v", 118 &s_v), 119 GNUNET_PQ_result_spec_uint64 ("s_f", 120 &s_f), 121 TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", 122 &amount_with_fee), 123 GNUNET_PQ_result_spec_end 124 }; 125 enum GNUNET_DB_QueryStatus qs; 126 127 qs = GNUNET_PQ_eval_prepared_singleton_select ( 128 pg->conn, 129 "test_refund_full", 130 params, 131 rs2); 132 if (qs <= 0) 133 { 134 GNUNET_break (0); 135 rsc->status = GNUNET_SYSERR; 136 return; 137 } 138 /* normalize */ 139 s_v += s_f / TALER_AMOUNT_FRAC_BASE; 140 s_f %= TALER_AMOUNT_FRAC_BASE; 141 full_refund = (s_v >= amount_with_fee.value) && 142 (s_f >= amount_with_fee.fraction); 143 } 144 ret = rsc->cb (rsc->cb_cls, 145 rowid, 146 &denom_pub, 147 &refund.coin.coin_pub, 148 &refund.details.merchant_pub, 149 &refund.details.merchant_sig, 150 &refund.details.h_contract_terms, 151 refund.details.rtransaction_id, 152 full_refund, 153 &refund.details.refund_amount); 154 GNUNET_PQ_cleanup_result (rs); 155 if (GNUNET_OK != ret) 156 break; 157 } 158 } 159 160 161 enum GNUNET_DB_QueryStatus 162 TEH_PG_select_refunds_above_serial_id ( 163 void *cls, 164 uint64_t serial_id, 165 TALER_EXCHANGEDB_RefundCallback cb, 166 void *cb_cls) 167 { 168 struct PostgresClosure *pg = cls; 169 struct GNUNET_PQ_QueryParam params[] = { 170 GNUNET_PQ_query_param_uint64 (&serial_id), 171 GNUNET_PQ_query_param_end 172 }; 173 struct RefundsSerialContext rsc = { 174 .cb = cb, 175 .cb_cls = cb_cls, 176 .pg = pg, 177 .status = GNUNET_OK 178 }; 179 enum GNUNET_DB_QueryStatus qs; 180 181 /* Fetch refunds with rowid '\geq' the given parameter */ 182 PREPARE (pg, 183 "audit_get_refunds_incr", 184 "SELECT" 185 " bdep.merchant_pub" 186 ",ref.merchant_sig" 187 ",bdep.h_contract_terms" 188 ",ref.rtransaction_id" 189 ",denom.denom_pub" 190 ",kc.coin_pub" 191 ",ref.amount_with_fee" 192 ",ref.refund_serial_id" 193 " FROM refunds ref" 194 " JOIN batch_deposits bdep" 195 " ON (ref.batch_deposit_serial_id=bdep.batch_deposit_serial_id)" 196 " JOIN coin_deposits cdep" 197 " ON (ref.coin_pub=cdep.coin_pub AND ref.batch_deposit_serial_id=cdep.batch_deposit_serial_id)" 198 " JOIN known_coins kc" 199 " ON (cdep.coin_pub=kc.coin_pub)" 200 " JOIN denominations denom" 201 " ON (kc.denominations_serial=denom.denominations_serial)" 202 " WHERE ref.refund_serial_id>=$1" 203 " ORDER BY ref.refund_serial_id ASC;"); 204 PREPARE (pg, 205 "test_refund_full", 206 "SELECT" 207 " CAST(SUM(CAST((ref.amount_with_fee).frac AS INT8)) AS INT8) AS s_f" 208 ",CAST(SUM((ref.amount_with_fee).val) AS INT8) AS s_v" 209 ",cdep.amount_with_fee" 210 " FROM refunds ref" 211 " JOIN coin_deposits cdep" 212 " ON (ref.coin_pub=cdep.coin_pub AND ref.batch_deposit_serial_id=cdep.batch_deposit_serial_id)" 213 " WHERE ref.refund_serial_id=$1" 214 " GROUP BY (cdep.amount_with_fee);"); 215 qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, 216 "audit_get_refunds_incr", 217 params, 218 &refunds_serial_helper_cb, 219 &rsc); 220 if (GNUNET_OK != rsc.status) 221 return GNUNET_DB_STATUS_HARD_ERROR; 222 return qs; 223 }