1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
--
-- 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_insert_or_update_policy_details(
IN in_policy_hash_code BYTEA,
IN in_policy_json VARCHAR,
IN in_deadline INT8,
IN in_commitment_val INT8,
IN in_commitment_frac INT4,
IN in_accumulated_total_val INT8,
IN in_accumulated_total_frac INT4,
IN in_fee_val INT8,
IN in_fee_frac INT4,
IN in_transferable_val INT8,
IN in_transferable_frac INT4,
IN in_fulfillment_state SMALLINT,
OUT out_policy_details_serial_id INT8,
OUT out_accumulated_total_val INT8,
OUT out_accumulated_total_frac INT4,
OUT out_fulfillment_state SMALLINT)
LANGUAGE plpgsql
AS $$
DECLARE
cur_commitment_val INT8;
cur_commitment_frac INT4;
cur_accumulated_total_val INT8;
cur_accumulated_total_frac INT4;
BEGIN
-- First, try to create a new entry.
INSERT INTO policy_details
(policy_hash_code,
policy_json,
deadline,
commitment_val,
commitment_frac,
accumulated_total_val,
accumulated_total_frac,
fee_val,
fee_frac,
transferable_val,
transferable_frac,
fulfillment_state)
VALUES (in_policy_hash_code,
in_policy_json,
in_deadline,
in_commitment_val,
in_commitment_frac,
in_accumulated_total_val,
in_accumulated_total_frac,
in_fee_val,
in_fee_frac,
in_transferable_val,
in_transferable_frac,
in_fulfillment_state)
ON CONFLICT (policy_hash_code) DO NOTHING
RETURNING policy_details_serial_id INTO out_policy_details_serial_id;
-- If the insert was successful, return
-- We assume that the fullfilment_state was correct in first place.
IF FOUND THEN
out_accumulated_total_val = in_accumulated_total_val;
out_accumulated_total_frac = in_accumulated_total_frac;
out_fulfillment_state = in_fulfillment_state;
RETURN;
END IF;
-- We had a conflict, grab the parts we need to update.
SELECT policy_details_serial_id,
commitment_val,
commitment_frac,
accumulated_total_val,
accumulated_total_frac
INTO out_policy_details_serial_id,
cur_commitment_val,
cur_commitment_frac,
cur_accumulated_total_val,
cur_accumulated_total_frac
FROM policy_details
WHERE policy_hash_code = in_policy_hash_code;
-- calculate the new values (overflows throws exception)
out_accumulated_total_val = cur_accumulated_total_val + in_accumulated_total_val;
out_accumulated_total_frac = cur_accumulated_total_frac + in_accumulated_total_frac;
-- normalize
out_accumulated_total_val = out_accumulated_total_val + out_accumulated_total_frac / 100000000;
out_accumulated_total_frac = out_accumulated_total_frac % 100000000;
IF (out_accumulated_total_val > (1 << 52))
THEN
RAISE EXCEPTION 'accumulation overflow';
END IF;
-- Set the fulfillment_state according to the values.
-- For now, we only update the state when it was INSUFFICIENT.
-- FIXME: What to do in case of Failure or other state?
IF (out_fullfillment_state = 1) -- INSUFFICIENT
THEN
IF (out_accumulated_total_val >= cur_commitment_val OR
(out_accumulated_total_val = cur_commitment_val AND
out_accumulated_total_frac >= cur_commitment_frac))
THEN
out_fulfillment_state = 2; -- READY
END IF;
END IF;
-- Now, update the record
UPDATE exchange.policy_details
SET
accumulated_val = out_accumulated_total_val,
accumulated_frac = out_accumulated_total_frac,
fulfillment_state = out_fulfillment_state
WHERE
policy_details_serial_id = out_policy_details_serial_id;
END $$;
|