/* 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_reserve.c * @brief Implementation of the insert_reserve function for Postgres * @author Christian Grothoff */ #include "platform.h" #include #include #include #include "pg_insert_reserve.h" #include "pg_helper.h" /** * How often do we re-try if we run into a DB serialization error? */ #define MAX_RETRIES 3 enum TALER_ErrorCode TMH_PG_insert_reserve (void *cls, const char *instance_id, const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_MasterPublicKeyP *master_pub, const char *exchange_url, const struct TALER_Amount *initial_balance, struct GNUNET_TIME_Timestamp expiration) { struct PostgresClosure *pg = cls; unsigned int retries; enum GNUNET_DB_QueryStatus qs; retries = 0; check_connection (pg); PREPARE (pg, "insert_reserve", "INSERT INTO merchant_reward_reserves" "(reserve_pub" ",merchant_serial" ",creation_time" ",expiration" ",merchant_initial_balance" ",exchange_initial_balance" ",rewards_committed" ",rewards_picked_up" ")" "SELECT $2, merchant_serial, $3, $4, $5, $6, $6, $6" " FROM merchant_instances" " WHERE merchant_id=$1"); RETRY: if (MAX_RETRIES < ++retries) return TALER_EC_GENERIC_DB_SOFT_FAILURE; if (GNUNET_OK != TMH_PG_start (pg, "insert reserve")) { GNUNET_break (0); return TALER_EC_GENERIC_DB_START_FAILED; } /* Setup reserve */ { struct TALER_Amount zero; struct GNUNET_TIME_Timestamp now; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (instance_id), GNUNET_PQ_query_param_auto_from_type (reserve_pub), GNUNET_PQ_query_param_timestamp (&now), GNUNET_PQ_query_param_timestamp (&expiration), TALER_PQ_query_param_amount_with_currency (pg->conn, initial_balance), TALER_PQ_query_param_amount_with_currency (pg->conn, &zero), GNUNET_PQ_query_param_end }; now = GNUNET_TIME_timestamp_get (); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (initial_balance->currency, &zero)); qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, "insert_reserve", params); if (0 > qs) { TMH_PG_rollback (pg); if (GNUNET_DB_STATUS_SOFT_ERROR == qs) goto RETRY; return qs; } } /* Store private key */ { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (instance_id), GNUNET_PQ_query_param_auto_from_type (reserve_pub), GNUNET_PQ_query_param_auto_from_type (reserve_priv), GNUNET_PQ_query_param_string (exchange_url), GNUNET_PQ_query_param_auto_from_type (master_pub), GNUNET_PQ_query_param_end }; PREPARE(pg, "insert_reserve_key", "INSERT INTO merchant_reward_reserve_keys" "(reserve_serial" ",reserve_priv" ",exchange_url" ",master_pub" ")" "SELECT reserve_serial, $3, $4, $5" " FROM merchant_reward_reserves" " WHERE reserve_pub=$2" " AND merchant_serial=" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"); qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, "insert_reserve_key", params); if (0 > qs) { TMH_PG_rollback (pg); if (GNUNET_DB_STATUS_SOFT_ERROR == qs) goto RETRY; return qs; } } qs = TMH_PG_commit (pg); if (0 <= qs) return TALER_EC_NONE; /* success */ if (GNUNET_DB_STATUS_SOFT_ERROR == qs) goto RETRY; return qs; }