exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

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 $$;