get_balance.c (5016B)
1 /* 2 This file is part of TALER 3 Copyright (C) 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 src/auditordb/get_balance.c 18 * @brief Implementation of the get_balance function for Postgres 19 * @author Christian Grothoff 20 */ 21 #include "taler/taler_error_codes.h" 22 #include "taler/taler_pq_lib.h" 23 #include "auditor-database/get_balance.h" 24 #include "pg_helper.h" 25 26 27 /** 28 * Closure for #balance_cb(). 29 */ 30 struct BalanceContext 31 { 32 33 /** 34 * Where to store results. 35 */ 36 struct TALER_Amount **dst; 37 38 /** 39 * Offset in @e dst. 40 */ 41 unsigned int off; 42 43 /** 44 * Length of array at @e dst. 45 */ 46 unsigned int len; 47 48 /** 49 * Plugin context. 50 */ 51 struct TALER_AUDITORDB_PostgresContext *pg; 52 53 /** 54 * Set to true on failure. 55 */ 56 bool failure; 57 58 }; 59 60 61 /** 62 * Helper function for #TALER_AUDITORDB_get_balance(). 63 * To be called with the results of a SELECT statement 64 * that has returned @a num_results results. 65 * 66 * @param cls closure of type `struct BalanceContext *` 67 * @param result the postgres result 68 * @param num_results the number of results in @a result 69 */ 70 static void 71 balance_cb (void *cls, 72 PGresult *result, 73 unsigned int num_results) 74 { 75 struct BalanceContext *ctx = cls; 76 struct TALER_AUDITORDB_PostgresContext *pg = ctx->pg; 77 78 GNUNET_assert (num_results <= ctx->len); 79 for (unsigned int i = 0; i < num_results; i++) 80 { 81 bool is_missing; 82 struct GNUNET_PQ_ResultSpec rs[] = { 83 GNUNET_PQ_result_spec_allow_null ( 84 TALER_PQ_result_spec_amount ("balance", 85 pg->currency, 86 ctx->dst[i]), 87 &is_missing), 88 GNUNET_PQ_result_spec_end 89 }; 90 91 if (GNUNET_OK != 92 GNUNET_PQ_extract_result (result, 93 rs, 94 i)) 95 { 96 GNUNET_break (0); 97 ctx->failure = true; 98 return; 99 } 100 if (is_missing) 101 { 102 GNUNET_assert (GNUNET_OK == 103 TALER_amount_set_zero (pg->currency, 104 ctx->dst[i])); 105 } 106 ctx->off++; 107 } 108 } 109 110 111 enum GNUNET_DB_QueryStatus 112 TALER_AUDITORDB_get_balance ( 113 struct TALER_AUDITORDB_PostgresContext *pg, 114 const char *balance_key, 115 struct TALER_Amount *balance_value, 116 ...) 117 { 118 unsigned int cnt = 1; 119 va_list ap; 120 121 GNUNET_assert (GNUNET_OK == 122 TALER_amount_set_zero (pg->currency, 123 balance_value)); 124 va_start (ap, 125 balance_value); 126 while (NULL != va_arg (ap, 127 const char *)) 128 { 129 struct TALER_Amount *dst; 130 131 cnt++; 132 dst = va_arg (ap, 133 struct TALER_Amount *); 134 GNUNET_assert (GNUNET_OK == 135 TALER_amount_set_zero (pg->currency, 136 dst)); 137 } 138 va_end (ap); 139 { 140 const char *keys[cnt]; 141 struct TALER_Amount *dsts[cnt]; 142 unsigned int off = 1; 143 struct GNUNET_PQ_QueryParam params[] = { 144 GNUNET_PQ_query_param_array_ptrs_string (cnt, 145 keys, 146 pg->conn), 147 GNUNET_PQ_query_param_end 148 }; 149 struct BalanceContext ctx = { 150 .dst = dsts, 151 .len = cnt, 152 .pg = pg 153 }; 154 enum GNUNET_DB_QueryStatus qs; 155 156 keys[0] = balance_key; 157 dsts[0] = balance_value; 158 va_start (ap, 159 balance_value); 160 while (off < cnt) 161 { 162 keys[off] = va_arg (ap, 163 const char *); 164 dsts[off] = va_arg (ap, 165 struct TALER_Amount *); 166 off++; 167 } 168 GNUNET_assert (NULL == va_arg (ap, 169 const char *)); 170 va_end (ap); 171 172 PREPARE (pg, 173 "get_balance", 174 "SELECT " 175 " auditor_do_get_balance AS balance" 176 " FROM auditor_do_get_balance " 177 "($1);"); 178 qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, 179 "get_balance", 180 params, 181 &balance_cb, 182 &ctx); 183 GNUNET_PQ_cleanup_query_params_closures (params); 184 if (ctx.failure) 185 return GNUNET_DB_STATUS_HARD_ERROR; 186 if (qs < 0) 187 return qs; 188 GNUNET_assert (qs == ctx.off); 189 return qs; 190 } 191 }