aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/exchangedb/exchange-0001-part.sql69
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c36
2 files changed, 100 insertions, 5 deletions
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;
}