pg_lookup_aml_history.c (5826B)
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 exchangedb/pg_lookup_aml_history.c 18 * @brief Implementation of the lookup_aml_history 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_lookup_aml_history.h" 26 #include "pg_helper.h" 27 28 29 /** 30 * Closure for callbacks called from #TEH_PG_lookup_aml_history() 31 */ 32 struct AmlHistoryContext 33 { 34 35 /** 36 * Function to call on each result. 37 */ 38 TALER_EXCHANGEDB_AmlHistoryCallback cb; 39 40 /** 41 * Closure for @e cb. 42 */ 43 void *cb_cls; 44 45 /** 46 * Plugin context. 47 */ 48 struct PostgresClosure *pg; 49 50 /** 51 * Set to 'true' if the transaction failed. 52 */ 53 bool failed; 54 55 }; 56 57 58 /** 59 * Function to be called with the results of a SELECT statement 60 * that has returned @a num_results results. 61 * 62 * @param cls closure of type `struct AmlHistoryContext` 63 * @param result the postgres result 64 * @param num_results the number of results in @a result 65 */ 66 static void 67 handle_aml_entry (void *cls, 68 PGresult *result, 69 unsigned int num_results) 70 { 71 struct AmlHistoryContext *ahc = cls; 72 73 for (unsigned int i = 0; i < num_results; i++) 74 { 75 uint64_t outcome_serial_id; 76 struct GNUNET_TIME_Timestamp decision_time; 77 char *justification; 78 struct TALER_AmlOfficerPublicKeyP decider_pub; 79 json_t *jproperties; 80 json_t *jnew_rules = NULL; 81 bool to_investigate; 82 bool is_active; 83 struct GNUNET_PQ_ResultSpec rs[] = { 84 GNUNET_PQ_result_spec_uint64 ("outcome_serial_id", 85 &outcome_serial_id), 86 GNUNET_PQ_result_spec_timestamp ("decision_time", 87 &decision_time), 88 GNUNET_PQ_result_spec_string ("justification", 89 &justification), 90 GNUNET_PQ_result_spec_auto_from_type ("decider_pub", 91 &decider_pub), 92 GNUNET_PQ_result_spec_allow_null ( 93 TALER_PQ_result_spec_json ("jproperties", 94 &jproperties), 95 NULL), 96 TALER_PQ_result_spec_json ("jnew_rules", 97 &jnew_rules), 98 GNUNET_PQ_result_spec_bool ("to_investigate", 99 &to_investigate), 100 GNUNET_PQ_result_spec_bool ("is_active", 101 &is_active), 102 GNUNET_PQ_result_spec_end 103 }; 104 105 if (GNUNET_OK != 106 GNUNET_PQ_extract_result (result, 107 rs, 108 i)) 109 { 110 GNUNET_break (0); 111 ahc->failed = true; 112 return; 113 } 114 ahc->cb (ahc->cb_cls, 115 outcome_serial_id, 116 decision_time, 117 justification, 118 &decider_pub, 119 jproperties, 120 jnew_rules, 121 to_investigate, 122 is_active); 123 GNUNET_PQ_cleanup_result (rs); 124 } 125 } 126 127 128 enum GNUNET_DB_QueryStatus 129 TEH_PG_lookup_aml_history ( 130 void *cls, 131 const struct TALER_NormalizedPaytoHashP *h_payto, 132 uint64_t offset, 133 int64_t limit, 134 TALER_EXCHANGEDB_AmlHistoryCallback cb, 135 void *cb_cls) 136 { 137 struct PostgresClosure *pg = cls; 138 struct AmlHistoryContext ahc = { 139 .pg = pg, 140 .cb = cb, 141 .cb_cls = cb_cls 142 }; 143 uint64_t ulimit = (limit < 0) ? (-limit) : limit; 144 struct GNUNET_PQ_QueryParam params[] = { 145 GNUNET_PQ_query_param_auto_from_type (h_payto), 146 GNUNET_PQ_query_param_uint64 (&offset), 147 GNUNET_PQ_query_param_uint64 (&ulimit), 148 GNUNET_PQ_query_param_end 149 }; 150 enum GNUNET_DB_QueryStatus qs; 151 152 PREPARE (pg, 153 "lookup_aml_history_desc", 154 "SELECT" 155 " lo.decision_time" 156 ",lo.outcome_serial_id" 157 ",ah.justification" 158 ",ah.decider_pub" 159 ",lo.jproperties::TEXT" 160 ",lo.jnew_rules::TEXT" 161 ",lo.to_investigate" 162 ",lo.is_active" 163 " FROM aml_history ah" 164 " JOIN legitimization_outcomes lo" 165 " USING (outcome_serial_id)" 166 " WHERE ah.h_payto=$1" 167 " AND lo.outcome_serial_id < $2" 168 " ORDER BY outcome_serial_id DESC" 169 " LIMIT $3;"); 170 PREPARE (pg, 171 "lookup_aml_history_asc", 172 "SELECT" 173 " lo.decision_time" 174 ",lo.outcome_serial_id" 175 ",ah.justification" 176 ",ah.decider_pub" 177 ",lo.jproperties::TEXT" 178 ",lo.jnew_rules::TEXT" 179 ",lo.to_investigate" 180 ",lo.is_active" 181 " FROM aml_history ah" 182 " JOIN legitimization_outcomes lo" 183 " USING (outcome_serial_id)" 184 " WHERE ah.h_payto=$1" 185 " AND lo.outcome_serial_id > $2" 186 " ORDER BY outcome_serial_id ASC" 187 " LIMIT $3;"); 188 qs = GNUNET_PQ_eval_prepared_multi_select ( 189 pg->conn, 190 (limit < 0) 191 ? "lookup_aml_history_desc" 192 : "lookup_aml_history_asc", 193 params, 194 &handle_aml_entry, 195 &ahc); 196 if (qs <= 0) 197 return qs; 198 if (ahc.failed) 199 { 200 GNUNET_break (0); 201 return GNUNET_DB_STATUS_HARD_ERROR; 202 } 203 return qs; 204 }