diff options
Diffstat (limited to 'src/backenddb/pg_insert_transfer_details.c')
-rw-r--r-- | src/backenddb/pg_insert_transfer_details.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/backenddb/pg_insert_transfer_details.c b/src/backenddb/pg_insert_transfer_details.c new file mode 100644 index 00000000..aa0ccc53 --- /dev/null +++ b/src/backenddb/pg_insert_transfer_details.c @@ -0,0 +1,171 @@ +/* + This file is part of TALER + Copyright (C) 2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file backenddb/pg_insert_transfer_details.c + * @brief Implementation of the insert_transfer_details function for Postgres + * @author Christian Grothoff + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_insert_transfer_details.h" +#include "pg_helper.h" + + +/** + * How often do we re-try if we run into a DB serialization error? + */ +#define MAX_RETRIES 3 + + +enum GNUNET_DB_QueryStatus +TMH_PG_insert_transfer_details ( + void *cls, + const char *instance_id, + const char *exchange_url, + const char *payto_uri, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_EXCHANGE_TransferData *td) +{ + struct PostgresClosure *pg = cls; + unsigned int len = td->details_length; + struct TALER_Amount coin_values[GNUNET_NZL (len)]; + struct TALER_Amount deposit_fees[GNUNET_NZL (len)]; + const struct TALER_CoinSpendPublicKeyP *coin_pubs[GNUNET_NZL (len)]; + const struct TALER_PrivateContractHashP *contract_terms[GNUNET_NZL (len)]; + enum GNUNET_DB_QueryStatus qs; + + for (unsigned int i = 0; i<len; i++) + { + const struct TALER_TrackTransferDetails *tdd = &td->details[i]; + + coin_values[i] = tdd->coin_value; + deposit_fees[i] = tdd->coin_fee; + coin_pubs[i] = &tdd->coin_pub; + contract_terms[i] = &tdd->h_contract_terms; + } + + check_connection (pg); + PREPARE (pg, + "insert_transfer_details", + "SELECT" + " out_no_instance" + ",out_no_account" + ",out_no_exchange" + ",out_duplicate" + ",out_conflict" + " FROM merchant_do_insert_transfer_details" + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);"); + + for (unsigned int retries = 0; + retries < MAX_RETRIES; + retries++) + { + if (GNUNET_OK != + TMH_PG_start (pg, + "insert transfer details")) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (exchange_url), + GNUNET_PQ_query_param_string (payto_uri), + GNUNET_PQ_query_param_auto_from_type (wtid), + GNUNET_PQ_query_param_timestamp (&td->execution_time), + GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub), + GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig), + TALER_PQ_query_param_amount_with_currency (pg->conn, + &td->total_amount), + TALER_PQ_query_param_amount_with_currency (pg->conn, + &td->wire_fee), + TALER_PQ_query_param_array_amount_with_currency ( + len, + coin_values, + pg->conn), + TALER_PQ_query_param_array_amount_with_currency ( + len, + deposit_fees, + pg->conn), + GNUNET_PQ_query_param_array_ptrs_auto_from_type ( + len, + coin_pubs, + pg->conn), + GNUNET_PQ_query_param_array_ptrs_auto_from_type ( + len, + contract_terms, + pg->conn), + GNUNET_PQ_query_param_end + }; + bool no_instance; + bool no_account; + bool no_exchange; + bool duplicate; + bool conflict; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("out_no_instance", + &no_instance), + GNUNET_PQ_result_spec_bool ("out_no_account", + &no_account), + GNUNET_PQ_result_spec_bool ("out_no_exchange", + &no_exchange), + GNUNET_PQ_result_spec_bool ("out_duplicate", + &duplicate), + GNUNET_PQ_result_spec_bool ("out_conflict", + &conflict), + GNUNET_PQ_result_spec_end + }; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "insert_transfer_details", + params, + rs); + GNUNET_PQ_cleanup_query_params_closures (params); + if (0 >= qs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + TMH_PG_rollback (pg); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + continue; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "'insert_transfer_details' failed with status %d\n", + qs); + return qs; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Transfer details inserted: %s%s%s%s%s\n", + no_instance ? "no instance " : "", + no_account ? "no account " : "", + no_exchange ? "no exchange ": "", + duplicate ? "duplicate ": "", + conflict ? "conflict" : ""); + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Committing transaction...\n"); + qs = TMH_PG_commit (pg); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; + } + return qs; +} |