diff options
author | Christian Grothoff <christian@grothoff.org> | 2022-12-06 13:29:23 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2022-12-06 13:29:23 +0100 |
commit | 87198f124c989d014adc9a2bae5098cf80555d62 (patch) | |
tree | 666ea877e53cebbe2ff9260f3efcdfff4a0b7c08 /src/exchangedb/exchange_do_reserve_open.sql | |
parent | 21959eebd2256a3fb72173488cf366868179ee13 (diff) | |
download | exchange-87198f124c989d014adc9a2bae5098cf80555d62.tar.xz |
refactor procedures.sql
Diffstat (limited to 'src/exchangedb/exchange_do_reserve_open.sql')
-rw-r--r-- | src/exchangedb/exchange_do_reserve_open.sql | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/src/exchangedb/exchange_do_reserve_open.sql b/src/exchangedb/exchange_do_reserve_open.sql new file mode 100644 index 000000000..5e80f713f --- /dev/null +++ b/src/exchangedb/exchange_do_reserve_open.sql @@ -0,0 +1,210 @@ +-- +-- This file is part of TALER +-- Copyright (C) 2014--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 <http://www.gnu.org/licenses/> +-- + +CREATE OR REPLACE FUNCTION exchange_do_reserve_open( + IN in_reserve_pub BYTEA, + IN in_total_paid_val INT8, + IN in_total_paid_frac INT4, + IN in_reserve_payment_val INT8, + IN in_reserve_payment_frac INT4, + IN in_min_purse_limit INT4, + IN in_default_purse_limit INT4, + IN in_reserve_sig BYTEA, + IN in_desired_expiration INT8, + IN in_reserve_gc_delay INT8, + IN in_now INT8, + IN in_open_fee_val INT8, + IN in_open_fee_frac INT4, + OUT out_open_cost_val INT8, + OUT out_open_cost_frac INT4, + OUT out_final_expiration INT8, + OUT out_no_funds BOOLEAN) +LANGUAGE plpgsql +AS $$ +DECLARE + my_balance_val INT8; +DECLARE + my_balance_frac INT4; +DECLARE + my_cost_val INT8; +DECLARE + my_cost_tmp INT8; +DECLARE + my_cost_frac INT4; +DECLARE + my_years_tmp INT4; +DECLARE + my_years INT4; +DECLARE + my_needs_update BOOL; +DECLARE + my_purses_allowed INT8; +DECLARE + my_expiration_date INT8; +DECLARE + my_reserve_expiration INT8; +BEGIN + +-- FIXME: use SELECT FOR UPDATE? +SELECT + purses_allowed + ,expiration_date + ,current_balance_val + ,current_balance_frac +INTO + my_purses_allowed + ,my_reserve_expiration + ,my_balance_val + ,my_balance_frac +FROM reserves +WHERE + reserve_pub=in_reserve_pub; + +IF NOT FOUND +THEN + -- FIXME: do we need to set a 'not found'? + RAISE NOTICE 'reserve not found'; + RETURN; +END IF; + +-- Do not allow expiration time to start in the past already +IF (my_reserve_expiration < in_now) +THEN + my_expiration_date = in_now; +ELSE + my_expiration_date = my_reserve_expiration; +END IF; + +my_cost_val = 0; +my_cost_frac = 0; +my_needs_update = FALSE; +my_years = 0; + +-- Compute years based on desired expiration time +IF (my_expiration_date < in_desired_expiration) +THEN + my_years = (31535999999999 + in_desired_expiration - my_expiration_date) / 31536000000000; + my_purses_allowed = in_default_purse_limit; + my_expiration_date = my_expiration_date + 31536000000000 * my_years; +END IF; + +-- Increase years based on purses requested +IF (my_purses_allowed < in_min_purse_limit) +THEN + my_years = (31535999999999 + in_desired_expiration - in_now) / 31536000000000; + my_expiration_date = in_now + 31536000000000 * my_years; + my_years_tmp = (in_min_purse_limit + in_default_purse_limit - my_purses_allowed - 1) / in_default_purse_limit; + my_years = my_years + my_years_tmp; + my_purses_allowed = my_purses_allowed + (in_default_purse_limit * my_years_tmp); +END IF; + + +-- Compute cost based on annual fees +IF (my_years > 0) +THEN + my_cost_val = my_years * in_open_fee_val; + my_cost_tmp = my_years * in_open_fee_frac / 100000000; + IF (CAST (my_cost_val + my_cost_tmp AS INT8) < my_cost_val) + THEN + out_open_cost_val=9223372036854775807; + out_open_cost_frac=2147483647; + out_final_expiration=my_expiration_date; + out_no_funds=FALSE; + RAISE NOTICE 'arithmetic issue computing amount'; + RETURN; + END IF; + my_cost_val = CAST (my_cost_val + my_cost_tmp AS INT8); + my_cost_frac = my_years * in_open_fee_frac % 100000000; + my_needs_update = TRUE; +END IF; + +-- check if we actually have something to do +IF NOT my_needs_update +THEN + out_final_expiration = my_reserve_expiration; + out_open_cost_val = 0; + out_open_cost_frac = 0; + out_no_funds=FALSE; + RAISE NOTICE 'no change required'; + RETURN; +END IF; + +-- Check payment (coins and reserve) would be sufficient. +IF ( (in_total_paid_val < my_cost_val) OR + ( (in_total_paid_val = my_cost_val) AND + (in_total_paid_frac < my_cost_frac) ) ) +THEN + out_open_cost_val = my_cost_val; + out_open_cost_frac = my_cost_frac; + out_no_funds=FALSE; + -- We must return a failure, which is indicated by + -- the expiration being below the desired expiration. + IF (my_reserve_expiration >= in_desired_expiration) + THEN + -- This case is relevant especially if the purse + -- count was to be increased and the payment was + -- insufficient to cover this for the full period. + RAISE NOTICE 'forcing low expiration time'; + out_final_expiration = 0; + ELSE + out_final_expiration = my_reserve_expiration; + END IF; + RAISE NOTICE 'amount paid too low'; + RETURN; +END IF; + +-- Check reserve balance is sufficient. +IF (my_balance_val > in_reserve_payment_val) +THEN + IF (my_balance_frac >= in_reserve_payment_frac) + THEN + my_balance_val=my_balance_val - in_reserve_payment_val; + my_balance_frac=my_balance_frac - in_reserve_payment_frac; + ELSE + my_balance_val=my_balance_val - in_reserve_payment_val - 1; + my_balance_frac=my_balance_frac + 100000000 - in_reserve_payment_frac; + END IF; +ELSE + IF (my_balance_val = in_reserve_payment_val) AND (my_balance_frac >= in_reserve_payment_frac) + THEN + my_balance_val=0; + my_balance_frac=my_balance_frac - in_reserve_payment_frac; + ELSE + out_final_expiration = my_reserve_expiration; + out_open_cost_val = my_cost_val; + out_open_cost_frac = my_cost_frac; + out_no_funds=TRUE; + RAISE NOTICE 'reserve balance too low'; + RETURN; + END IF; +END IF; + +UPDATE reserves SET + current_balance_val=my_balance_val + ,current_balance_frac=my_balance_frac + ,gc_date=my_reserve_expiration + in_reserve_gc_delay + ,expiration_date=my_expiration_date + ,purses_allowed=my_purses_allowed +WHERE + reserve_pub=in_reserve_pub; + +out_final_expiration=my_expiration_date; +out_open_cost_val = my_cost_val; +out_open_cost_frac = my_cost_frac; +out_no_funds=FALSE; +RETURN; + +END $$; |