/* 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 */ /** * @file backenddb/pg_insert_transfer_details.c * @brief Implementation of the insert_transfer_details function for Postgres * @author Christian Grothoff */ #include "platform.h" #include #include #include #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; idetails[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; }