diff --git a/src/exchangedb/exchange-0001-part.sql b/src/exchangedb/exchange-0001-part.sql index dc4f29c84..97c26cb05 100644 --- a/src/exchangedb/exchange-0001-part.sql +++ b/src/exchangedb/exchange-0001-part.sql @@ -1977,7 +1977,7 @@ BEGIN END; $$; -COMMENT ON FUNCTION exchange_do_recoup_by_reserve +COMMENT ON FUNCTION exchange_do_recoup_by_reserve IS 'Recoup by reserve as a function to make sure we hit only the needed partition and not all when joining as joins on distributed tables fetch ALL rows from the shards'; @@ -2505,7 +2505,8 @@ UPDATE known_coins THEN 1 ELSE 0 END - WHERE coin_pub=in_coin_pub; + WHERE coin_pub=in_coin_pub + LIMIT 1; -- just to be extra safe out_conflict=FALSE; @@ -3360,6 +3361,70 @@ BEGIN END $$; + +CREATE OR REPLACE FUNCTION exchange_do_expire_purse( + IN in_partner_id INT8, + IN in_start_time INT8, + IN in_end_time INT8, + OUT out_found BOOLEAN) +LANGUAGE plpgsql +AS $$ +DECLARE + my_purse_pub BYTEA; +DECLARE + my_deposit record; +BEGIN + +UPDATE purse_requests + SET refunded=TRUE, + finished=TRUE + WHERE (purse_expiration >= in_start_time) AND + (purse_expiration < in_end_time) AND + (NOT finished) AND + (NOT refunded) + RETURNING purse_pub + ,in_reserve_quota + ,flags + INTO my_purse_pub + ,my_rq + ,my_flags; +out_found = FOUND; +IF NOT FOUND +THEN + RETURN; +END IF; + +-- restore balance to each coin deposited into the purse +FOR my_deposit IN + SELECT coin_pub + ,amount_with_fee_val + ,amount_with_fee_frac + FROM purse_deposits + WHERE purse_pub = my_purse_pub +LOOP + UPDATE + remaining_frac=remaining_frac+my_deposit.amount_with_fee_frac + - CASE + WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000 + THEN 100000000 + ELSE 0 + END, + remaining_val=remaining_val+my_deposit.amount_with_fee_val + + CASE + WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000 + THEN 1 + ELSE 0 + END + FROM known_coins + WHERE coin_pub = my_deposit.coin_pub + LIMIT 1; -- just to be extra safe + END LOOP; +END $$; + +COMMENT ON FUNCTION exchange_do_expire_purse(INT8,INT8) + IS 'Finds an expired purse in the given time range and refunds the coins (if any).'; + + CREATE OR REPLACE FUNCTION exchange_do_history_request( IN in_reserve_pub BYTEA, IN in_reserve_sig BYTEA, diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index ab282f4ff..2c113cf19 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -904,6 +904,14 @@ prepare_statements (struct PostgresClosure *pg) " FROM exchange_do_purse_deposit" " ($1,$2,$3,$4,$5,$6,$7,$8);", 8), + /* used in #postgres_expire_purse() */ + GNUNET_PQ_make_prepare ( + "call_expire_purse", + "SELECT " + " out_found AS found" + " FROM exchange_do_expire_purse" + " ($1,$2);", + 2), /* Used in #postgres_do_melt() to melt a coin. */ GNUNET_PQ_make_prepare ( "call_melt", @@ -13337,7 +13345,7 @@ postgres_select_contract_by_purse (void *cls, * @param[out] in_conflict set to true if @a econtract * conflicts with an existing contract; * in this case, the return value will be - * #GNUNET_DB_STATUS_SUCCESS_ONE despite the failure + * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure * @return transaction status code */ static enum GNUNET_DB_QueryStatus @@ -13568,8 +13576,30 @@ postgres_expire_purse ( struct GNUNET_TIME_Absolute start_time, struct GNUNET_TIME_Absolute end_time) { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_absolute_time (&start_time), + GNUNET_PQ_query_param_absolute_time (&end_time), + GNUNET_PQ_query_param_end + }; + bool found = false; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("found", + &found), + GNUNET_PQ_result_spec_end + }; + enum GNUNET_DB_QueryStatus qs; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "call_expire_purse", + params, + rs); + if (qs < 0) + return qs; + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs); + return found + ? GNUNET_DB_STATUS_SUCCESS_ONE_RESULT + : GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; }