/* 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 exchangedb/pg_select_refunds_by_coin.c * @brief Implementation of the select_refunds_by_coin function for Postgres * @author Christian Grothoff */ #include "platform.h" #include "taler_error_codes.h" #include "taler_dbevents.h" #include "taler_pq_lib.h" #include "pg_select_refunds_by_coin.h" #include "pg_helper.h" /** * Closure for #get_refunds_cb(). */ struct SelectRefundContext { /** * Function to call on each result. */ TALER_EXCHANGEDB_RefundCoinCallback cb; /** * Closure for @a cb. */ void *cb_cls; /** * Plugin context. */ struct PostgresClosure *pg; /** * Set to #GNUNET_SYSERR on error. */ int status; }; /** * Function to be called with the results of a SELECT statement * that has returned @a num_results results. * * @param cls closure of type `struct SelectRefundContext *` * @param result the postgres result * @param num_results the number of results in @a result */ static void get_refunds_cb (void *cls, PGresult *result, unsigned int num_results) { struct SelectRefundContext *srctx = cls; struct PostgresClosure *pg = srctx->pg; for (unsigned int i = 0; istatus = GNUNET_SYSERR; return; } if (GNUNET_OK != srctx->cb (srctx->cb_cls, &amount_with_fee)) return; } } enum GNUNET_DB_QueryStatus TEH_PG_select_refunds_by_coin ( void *cls, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_PrivateContractHashP *h_contract, TALER_EXCHANGEDB_RefundCoinCallback cb, void *cb_cls) { struct PostgresClosure *pg = cls; enum GNUNET_DB_QueryStatus qs; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (coin_pub), GNUNET_PQ_query_param_auto_from_type (merchant_pub), GNUNET_PQ_query_param_auto_from_type (h_contract), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_QueryParam params5[] = { GNUNET_PQ_query_param_auto_from_type (coin_pub), GNUNET_PQ_query_param_end }; struct SelectRefundContext srctx = { .cb = cb, .cb_cls = cb_cls, .pg = pg, .status = GNUNET_OK }; static int percent_refund = -2; const char *query; struct GNUNET_PQ_QueryParam *xparams = params; if (-2 == percent_refund) { const char *mode = getenv ("TALER_POSTGRES_SELECT_REFUNDS_BY_COIN_LOGIC"); char dummy; if ( (NULL==mode) || (1 != sscanf (mode, "%d%c", &percent_refund, &dummy)) ) { if (NULL != mode) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Bad mode `%s' specified\n", mode); percent_refund = 0; } } switch (percent_refund) { case 0: query = "get_refunds_by_coin_and_contract-v0"; PREPARE (pg, query, "SELECT" " ref.amount_with_fee_val" ",ref.amount_with_fee_frac" " FROM refunds ref" " JOIN deposits dep" " USING (coin_pub,deposit_serial_id)" " WHERE ref.coin_pub=$1" " AND dep.merchant_pub=$2" " AND dep.h_contract_terms=$3;"); break; case 1: query = "get_refunds_by_coin_and_contract-v1"; PREPARE (pg, query, "SELECT" " ref.amount_with_fee_val" ",ref.amount_with_fee_frac" " FROM refunds ref" " LEFT JOIN deposits dep" " ON dep.coin_pub = ref.coin_pub" " AND ref.deposit_serial_id = dep.deposit_serial_id" " WHERE ref.coin_pub=$1" " AND dep.merchant_pub=$2" " AND dep.h_contract_terms=$3;"); break; case 2: query = "get_refunds_by_coin_and_contract-v2"; PREPARE (pg, query, "WITH rc AS MATERIALIZED(" "SELECT" " amount_with_fee_val" ",amount_with_fee_frac" ",coin_pub" ",deposit_serial_id" " FROM refunds ref" " WHERE ref.coin_pub=$1)" "SELECT" " rc.amount_with_fee_val" " ,rc.amount_with_fee_frac" " FROM deposits dep" " JOIN rc" " ON rc.deposit_serial_id = dep.deposit_serial_id" " WHERE" " dep.coin_pub = $1" " AND dep.merchant_pub = $2" " AND dep.h_contract_terms = $3"); break; case 3: query = "get_refunds_by_coin_and_contract-v3"; PREPARE (pg, query, "WITH rc AS MATERIALIZED(" "SELECT" " amount_with_fee_val" ",amount_with_fee_frac" ",deposit_serial_id" " FROM refunds" " WHERE coin_pub=$1)" "SELECT" " rc.amount_with_fee_val" " ,rc.amount_with_fee_frac" " FROM (" "SELECT" " amount_with_fee_val" ",amount_with_fee_frac" " FROM deposits depos" " WHERE" " depos.coin_pub = $1" " AND depos.merchant_pub = $2" " AND depos.h_contract_terms = $3) dep, rc;"); break; case 4: query = "get_refunds_by_coin_and_contract-v4"; PREPARE (pg, query, "WITH rc AS MATERIALIZED(" "SELECT" " amount_with_fee_val" ",amount_with_fee_frac" ",coin_pub" ",deposit_serial_id" " FROM refunds ref" " WHERE ref.coin_pub=$1)" "SELECT" " rc.amount_with_fee_val" " ,rc.amount_with_fee_frac" " ,deposit_serial_id" " FROM (" "SELECT" " amount_with_fee_val" ",amount_with_fee_frac" " FROM deposits depos" " WHERE" " depos.merchant_pub = $2" " AND depos.h_contract_terms = $3) dep JOIN rc " "USING(deposit_serial_id, coin_pub);"); break; case 5: query = "get_refunds_by_coin_and_contract-v-broken"; xparams = params5; PREPARE (pg, query, "SELECT" " amount_with_fee_val" ",amount_with_fee_frac" ",coin_pub" ",deposit_serial_id" " FROM refunds" " WHERE coin_pub=$1;"); break; case 8: query = "get_refunds_by_coin_and_contract-v8"; PREPARE (pg, query, "WITH" " rc AS MATERIALIZED(" " SELECT" " amount_with_fee_val" " ,amount_with_fee_frac" " ,coin_pub" " ,deposit_serial_id" " FROM refunds" " WHERE coin_pub=$1)," " dep AS MATERIALIZED(" " SELECT" " deposit_serial_id" " FROM deposits" " WHERE coin_pub = $1" " AND merchant_pub = $2" " AND h_contract_terms = $3" ")" "SELECT" " rc.amount_with_fee_val" " ,rc.amount_with_fee_frac" " FROM " " rc JOIN dep USING (deposit_serial_id);"); break; case 9: query = "get_refunds_by_coin_and_contract-v9-broken"; PREPARE (pg, query, "SELECT" " ref.amount_with_fee_val" " ,ref.amount_with_fee_frac" " FROM deposits dep" " JOIN refunds ref USING(deposit_serial_id)" " WHERE dep.coin_pub IN (" " SELECT coin_pub" " FROM refunds" " WHERE coin_pub=$1)" " AND merchant_pub = $2" " AND h_contract_terms = $3;"); break; case 10: query = "get_refunds_by_coin_and_contract-v10-broken"; PREPARE (pg, query, "SELECT" " *" " FROM" " exchange_do_refund_by_coin" " ($1, $2, $3) " " AS (amount_with_fee_val INT8, amount_with_fee_frac INT4);"); break; default: GNUNET_break (0); return GNUNET_DB_STATUS_HARD_ERROR; } qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, query, xparams, &get_refunds_cb, &srctx); if (GNUNET_SYSERR == srctx.status) return GNUNET_DB_STATUS_HARD_ERROR; return qs; }