exchange_do_insert_or_update_policy_details.sql (4328B)
1 -- 2 -- This file is part of TALER 3 -- Copyright (C) 2014--2022 Taler Systems SA 4 -- 5 -- TALER is free software; you can redistribute it and/or modify it under the 6 -- terms of the GNU General Public License as published by the Free Software 7 -- Foundation; either version 3, or (at your option) any later version. 8 -- 9 -- TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 -- A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 -- 13 -- You should have received a copy of the GNU General Public License along with 14 -- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 -- 16 17 CREATE OR REPLACE FUNCTION exchange_do_insert_or_update_policy_details( 18 IN in_policy_hash_code BYTEA, 19 IN in_policy_json TEXT, 20 IN in_deadline INT8, 21 IN in_commitment taler_amount, 22 IN in_accumulated_total taler_amount, 23 IN in_fee taler_amount, 24 IN in_transferable taler_amount, 25 IN in_fulfillment_state SMALLINT, 26 OUT out_policy_details_serial_id INT8, 27 OUT out_accumulated_total taler_amount, 28 OUT out_fulfillment_state SMALLINT) 29 LANGUAGE plpgsql 30 AS $$ 31 DECLARE 32 cur_commitment taler_amount; 33 DECLARE 34 cur_accumulated_total taler_amount; 35 DECLARE 36 rval RECORD; 37 BEGIN 38 -- First, try to create a new entry. 39 INSERT INTO policy_details 40 (policy_hash_code, 41 policy_json, 42 deadline, 43 commitment, 44 accumulated_total, 45 fee, 46 transferable, 47 fulfillment_state) 48 VALUES (in_policy_hash_code, 49 in_policy_json, 50 in_deadline, 51 in_commitment, 52 in_accumulated_total, 53 in_fee, 54 in_transferable, 55 in_fulfillment_state) 56 ON CONFLICT (policy_hash_code) DO NOTHING 57 RETURNING policy_details_serial_id INTO out_policy_details_serial_id; 58 59 -- If the insert was successful, return 60 -- We assume that the fullfilment_state was correct in first place. 61 IF FOUND THEN 62 out_accumulated_total = in_accumulated_total; 63 out_fulfillment_state = in_fulfillment_state; 64 RETURN; 65 END IF; 66 67 -- We had a conflict, grab the parts we need to update. 68 SELECT policy_details_serial_id 69 ,commitment 70 ,accumulated_total 71 INTO rval 72 FROM policy_details 73 WHERE policy_hash_code = in_policy_hash_code; 74 75 -- We use rval as workaround as we cannot select 76 -- directly into the amount due to Postgres limitations. 77 out_policy_details_serial_id := rval.policy_details_serial_id; 78 cur_commitment := rval.commitment; 79 cur_accumulated_total := rval.accumulated_total; 80 81 -- calculate the new values (overflows throws exception) 82 out_accumulated_total.val = cur_accumulated_total.val + in_accumulated_total.val; 83 out_accumulated_total.frac = cur_accumulated_total.frac + in_accumulated_total.frac; 84 -- normalize 85 out_accumulated_total.val = out_accumulated_total.val + out_accumulated_total.frac / 100000000; 86 out_accumulated_total.frac = out_accumulated_total.frac % 100000000; 87 88 IF (out_accumulated_total.val > (1 << 52)) 89 THEN 90 RAISE EXCEPTION 'accumulation overflow'; 91 END IF; 92 93 94 -- Set the fulfillment_state according to the values. 95 -- For now, we only update the state when it was INSUFFICIENT. 96 -- FIXME[oec] #7999: What to do in case of Failure or other state? 97 IF (out_fullfillment_state = 2) -- INSUFFICIENT 98 THEN 99 IF (out_accumulated_total.val >= cur_commitment.val OR 100 (out_accumulated_total.val = cur_commitment.val AND 101 out_accumulated_total.frac >= cur_commitment.frac)) 102 THEN 103 out_fulfillment_state = 3; -- READY 104 END IF; 105 END IF; 106 107 -- Now, update the record 108 UPDATE exchange.policy_details 109 SET 110 accumulated = out_accumulated_total, 111 fulfillment_state = out_fulfillment_state 112 WHERE 113 policy_details_serial_id = out_policy_details_serial_id; 114 END $$;