Compare commits

..

7 Commits

Author SHA1 Message Date
94e5193bff
[pq] added helper to load oids of composite types
- TALER_PQ_load_oids_for_composite_types added
- Called during postgres-initialization
2023-07-28 16:19:21 +02:00
1c923855a3
finalize v3/v4 -> v2 exchange schema merger 2023-07-28 14:29:25 +02:00
0d0494ee91
finalize v3/v4 -> v2 exchange schema merger 2023-07-28 14:28:20 +02:00
85020a9204
Merge branch 'master' of ssh://git.taler.net/exchange 2023-07-28 12:36:28 +02:00
963e84aad2
-added pq_common.h 2023-07-28 12:36:22 +02:00
Christian Grothoff
d083536786
combine v3 and v4 of exchange schema into v2 due to major incompatible tuple change forthcoming 2023-07-28 12:27:46 +02:00
Christian Grothoff
c93ce9ea2e
-fix type defs 2023-07-28 12:21:28 +02:00
29 changed files with 334 additions and 293 deletions

View File

@ -29,7 +29,7 @@ BEGIN
'(age_withdraw_id BIGINT GENERATED BY DEFAULT AS IDENTITY' '(age_withdraw_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',h_commitment BYTEA NOT NULL CONSTRAINT h_commitment_length CHECK(LENGTH(h_commitment)=64)' ',h_commitment BYTEA NOT NULL CONSTRAINT h_commitment_length CHECK(LENGTH(h_commitment)=64)'
',max_age SMALLINT NOT NULL CONSTRAINT max_age_positive CHECK(max_age>=0)' ',max_age SMALLINT NOT NULL CONSTRAINT max_age_positive CHECK(max_age>=0)'
',amount_with_fee TALER_AMOUNT NOT NULL' ',amount_with_fee taler_amount NOT NULL'
',reserve_pub BYTEA NOT NULL CONSTRAINT reserve_pub_length CHECK(LENGTH(reserve_pub)=32)' ',reserve_pub BYTEA NOT NULL CONSTRAINT reserve_pub_length CHECK(LENGTH(reserve_pub)=32)'
',reserve_sig BYTEA NOT NULL CONSTRAINT reserve_sig_length CHECK(LENGTH(reserve_sig)=64)' ',reserve_sig BYTEA NOT NULL CONSTRAINT reserve_sig_length CHECK(LENGTH(reserve_sig)=64)'
',noreveal_index SMALLINT NOT NULL CONSTRAINT noreveal_index_positive CHECK(noreveal_index>=0)' ',noreveal_index SMALLINT NOT NULL CONSTRAINT noreveal_index_positive CHECK(noreveal_index>=0)'
@ -138,7 +138,7 @@ BEGIN
'ALTER TABLE ' || table_name || 'ALTER TABLE ' || table_name ||
' ADD CONSTRAINT ' || table_name || '_foreign_reserve_pub' ' ADD CONSTRAINT ' || table_name || '_foreign_reserve_pub'
' FOREIGN KEY (reserve_pub)' ' FOREIGN KEY (reserve_pub)'
' REFERENCES reserves(reserve_pub);' -- ON DELETE CASCADE;' ' REFERENCES reserves(reserve_pub) ON DELETE CASCADE;'
); );
END END
$$; $$;
@ -151,6 +151,7 @@ INSERT INTO exchange_tables
,partitioned ,partitioned
,by_range) ,by_range)
VALUES VALUES
('age_withdraw', 'exchange-0003', 'create', TRUE ,FALSE), ('age_withdraw', 'exchange-0002', 'create', TRUE ,FALSE),
('age_withdraw', 'exchange-0003', 'constrain',TRUE ,FALSE), ('age_withdraw', 'exchange-0002', 'constrain',TRUE ,FALSE),
('age_withdraw', 'exchange-0003', 'foreign', TRUE ,FALSE); ('age_withdraw', 'exchange-0002', 'foreign', TRUE ,FALSE);

View File

@ -137,12 +137,12 @@ INSERT INTO exchange_tables
,by_range) ,by_range)
VALUES VALUES
('aml_history' ('aml_history'
,'exchange-0003' ,'exchange-0002'
,'create' ,'create'
,TRUE ,TRUE
,FALSE), ,FALSE),
('aml_history' ('aml_history'
,'exchange-0003' ,'exchange-0002'
,'constrain' ,'constrain'
,TRUE ,TRUE
,FALSE); ,FALSE);

View File

@ -91,12 +91,12 @@ INSERT INTO exchange_tables
,by_range) ,by_range)
VALUES VALUES
('aml_status' ('aml_status'
,'exchange-0003' ,'exchange-0002'
,'create' ,'create'
,TRUE ,TRUE
,FALSE), ,FALSE),
('aml_status' ('aml_status'
,'exchange-0003' ,'exchange-0002'
,'constrain' ,'constrain'
,TRUE ,TRUE
,FALSE); ,FALSE);

View File

@ -29,7 +29,6 @@ BEGIN
',h_payto BYTEA PRIMARY KEY CHECK (LENGTH(h_payto)=32)' ',h_payto BYTEA PRIMARY KEY CHECK (LENGTH(h_payto)=32)'
',kyc_prox BYTEA NOT NULL CHECK (LENGTH(kyc_prox)=32)' ',kyc_prox BYTEA NOT NULL CHECK (LENGTH(kyc_prox)=32)'
',provider VARCHAR NOT NULL' ',provider VARCHAR NOT NULL'
',birthdate VARCHAR'
',collection_time INT8 NOT NULL' ',collection_time INT8 NOT NULL'
',expiration_time INT8 NOT NULL' ',expiration_time INT8 NOT NULL'
',encrypted_attributes BYTEA NOT NULL' ',encrypted_attributes BYTEA NOT NULL'
@ -56,12 +55,6 @@ BEGIN
,table_name ,table_name
,partition_suffix ,partition_suffix
); );
PERFORM comment_partitioned_column(
'birth date of the user, in format YYYY-MM-DD where a value of 0 is used to indicate unknown (in official documents); NULL if the birth date was not collected by the provider; used for KYC-driven age restrictions'
,'birthdate'
,table_name
,partition_suffix
);
PERFORM comment_partitioned_column( PERFORM comment_partitioned_column(
'time when the attributes were collected by the provider' 'time when the attributes were collected by the provider'
,'collection_time' ,'collection_time'
@ -145,12 +138,12 @@ INSERT INTO exchange_tables
,by_range) ,by_range)
VALUES VALUES
('kyc_attributes' ('kyc_attributes'
,'exchange-0003' ,'exchange-0002'
,'create' ,'create'
,TRUE ,TRUE
,FALSE), ,FALSE),
('kyc_attributes' ('kyc_attributes'
,'exchange-0003' ,'exchange-0002'
,'constrain' ,'constrain'
,TRUE ,TRUE
,FALSE); ,FALSE);

View File

@ -110,12 +110,12 @@ INSERT INTO exchange_tables
,by_range) ,by_range)
VALUES VALUES
('purse_actions' ('purse_actions'
,'exchange-0003' ,'exchange-0002'
,'create' ,'create'
,TRUE ,TRUE
,FALSE), ,FALSE),
('purse_actions' ('purse_actions'
,'exchange-0003' ,'exchange-0002'
,'master' ,'master'
,TRUE ,TRUE
,FALSE); ,FALSE);

View File

@ -94,17 +94,17 @@ INSERT INTO exchange_tables
,by_range) ,by_range)
VALUES VALUES
('purse_deletion' ('purse_deletion'
,'exchange-0003' ,'exchange-0002'
,'create' ,'create'
,TRUE ,TRUE
,FALSE), ,FALSE),
('purse_deletion' ('purse_deletion'
,'exchange-0003' ,'exchange-0002'
,'constrain' ,'constrain'
,TRUE ,TRUE
,FALSE), ,FALSE),
('purse_requests_was_deleted' ('purse_requests_was_deleted'
,'exchange-0003' ,'exchange-0002'
,'master' ,'master'
,TRUE ,TRUE
,FALSE); ,FALSE);

View File

@ -19,6 +19,9 @@ CREATE TABLE wire_accounts
,master_sig BYTEA CHECK (LENGTH(master_sig)=64) ,master_sig BYTEA CHECK (LENGTH(master_sig)=64)
,is_active BOOLEAN NOT NULL ,is_active BOOLEAN NOT NULL
,last_change INT8 NOT NULL ,last_change INT8 NOT NULL
,conversion_url VARCHAR DEFAULT (NULL)
,debit_restrictions VARCHAR DEFAULT (NULL)
,credit_restrictions VARCHAR DEFAULT (NULL)
); );
COMMENT ON TABLE wire_accounts COMMENT ON TABLE wire_accounts
IS 'Table with current and historic bank accounts of the exchange. Entries never expire as we need to remember the last_change column indefinitely.'; IS 'Table with current and historic bank accounts of the exchange. Entries never expire as we need to remember the last_change column indefinitely.';
@ -30,5 +33,13 @@ COMMENT ON COLUMN wire_accounts.is_active
IS 'true if we are currently supporting the use of this account.'; IS 'true if we are currently supporting the use of this account.';
COMMENT ON COLUMN wire_accounts.last_change COMMENT ON COLUMN wire_accounts.last_change
IS 'Latest time when active status changed. Used to detect replays of old messages.'; IS 'Latest time when active status changed. Used to detect replays of old messages.';
COMMENT ON COLUMN wire_accounts.conversion_url
IS 'URL of a currency conversion service if conversion is needed when this account is used; NULL if there is no conversion.';
COMMENT ON COLUMN wire_accounts.debit_restrictions
IS 'JSON array describing restrictions imposed when debiting this account. Empty for no restrictions, NULL if account was migrated from previous database revision or account is disabled.';
COMMENT ON COLUMN wire_accounts.credit_restrictions
IS 'JSON array describing restrictions imposed when crediting this account. Empty for no restrictions, NULL if account was migrated from previous database revision or account is disabled.';
-- "wire_accounts" has no sequence because it is a 'mutable' table -- "wire_accounts" has no sequence because it is a 'mutable' table
-- and is of no concern to the auditor -- and is of no concern to the auditor

View File

@ -1,44 +0,0 @@
--
-- This file is part of TALER
-- Copyright (C) 2023 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 master_table_kyc_attributes_V2()
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
table_name VARCHAR DEFAULT 'kyc_attributes';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
' DROP COLUMN birthdate;'
);
END $$;
COMMENT ON FUNCTION master_table_kyc_attributes_V2
IS 'Removes birthdate column from the kyc_attributes table';
INSERT INTO exchange_tables
(name
,version
,action
,partitioned
,by_range)
VALUES
('kyc_attributes_V2'
,'exchange-0004'
,'master'
,TRUE
,FALSE);

View File

@ -1,26 +0,0 @@
--
-- This file is part of TALER
-- Copyright (C) 2023 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/>
--
ALTER TABLE wire_accounts
ADD COLUMN conversion_url VARCHAR DEFAULT (NULL),
ADD COLUMN debit_restrictions VARCHAR DEFAULT (NULL),
ADD COLUMN credit_restrictions VARCHAR DEFAULT (NULL);
COMMENT ON COLUMN wire_accounts.conversion_url
IS 'URL of a currency conversion service if conversion is needed when this account is used; NULL if there is no conversion.';
COMMENT ON COLUMN wire_accounts.debit_restrictions
IS 'JSON array describing restrictions imposed when debiting this account. Empty for no restrictions, NULL if account was migrated from previous database revision or account is disabled.';
COMMENT ON COLUMN wire_accounts.credit_restrictions
IS 'JSON array describing restrictions imposed when crediting this account. Empty for no restrictions, NULL if account was migrated from previous database revision or account is disabled.';

View File

@ -18,19 +18,13 @@ sqlinputs = \
exchange_do_*.sql \ exchange_do_*.sql \
procedures.sql.in \ procedures.sql.in \
0002-*.sql \ 0002-*.sql \
exchange-0002.sql.in \ exchange-0002.sql.in
0003-*.sql \
exchange-0003.sql.in \
0004-*.sql \
exchange-0004.sql.in
sql_DATA = \ sql_DATA = \
benchmark-0001.sql \ benchmark-0001.sql \
versioning.sql \ versioning.sql \
exchange-0001.sql \ exchange-0001.sql \
exchange-0002.sql \ exchange-0002.sql \
exchange-0003.sql \
exchange-0004.sql \
drop.sql \ drop.sql \
procedures.sql procedures.sql
@ -41,9 +35,7 @@ BUILT_SOURCES = \
procedures.sql procedures.sql
CLEANFILES = \ CLEANFILES = \
exchange-0002.sql \ exchange-0002.sql
exchange-0003.sql \
exchange-0004.sql
procedures.sql: procedures.sql.in exchange_do_*.sql procedures.sql: procedures.sql.in exchange_do_*.sql
chmod +w $@ || true chmod +w $@ || true
@ -55,16 +47,6 @@ exchange-0002.sql: exchange-0002.sql.in 0002-*.sql
gcc -E -P -undef - < exchange-0002.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@ gcc -E -P -undef - < exchange-0002.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@
chmod ugo-w $@ chmod ugo-w $@
exchange-0003.sql: exchange-0003.sql.in 0003-*.sql
chmod +w $@ || true
gcc -E -P -undef - < exchange-0003.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@
chmod ugo-w $@
exchange-0004.sql: exchange-0004.sql.in 0004-*.sql
chmod +w $@ || true
gcc -E -P -undef - < exchange-0004.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@
chmod ugo-w $@
check_SCRIPTS = \ check_SCRIPTS = \
test_idempotency.sh test_idempotency.sh

View File

@ -20,8 +20,6 @@ BEGIN;
SELECT _v.unregister_patch('exchange-0001'); SELECT _v.unregister_patch('exchange-0001');
SELECT _v.unregister_patch('exchange-0002'); SELECT _v.unregister_patch('exchange-0002');
SELECT _v.unregister_patch('exchange-0003');
SELECT _v.unregister_patch('exchange-0004');
DROP SCHEMA exchange CASCADE; DROP SCHEMA exchange CASCADE;

View File

@ -137,102 +137,10 @@ COMMENT ON FUNCTION comment_partitioned_column
IS 'Generic function to create a comment on column of a table that is partitioned.'; IS 'Generic function to create a comment on column of a table that is partitioned.';
--------------------------------------------------------------
-- Taler amounts and helper functiosn
-------------------------------------------------------------
DO $$
BEGIN
CREATE TYPE TALER_AMOUNT
AS (val INT8
,frac INT4);
COMMENT ON TYPE TALER_AMOUNT
IS 'Type to store a TALER-amount as (val, frac) pair.';
EXCEPTION
WHEN duplicate_object THEN null;
END
$$;
CREATE PROCEDURE amount_normalize(
IN amount TALER_AMOUNT
,OUT normalized TALER_AMOUNT
)
LANGUAGE plpgsql
AS $$
BEGIN
normalized.val = amount.val + amount.frac / 100000000;
normalized.frac = amount.frac % 100000000;
END $$;
COMMENT ON PROCEDURE amount_normalize
IS 'Returns the normalized amount by adding to the .val the value of (.frac / 100000000) and removing the modulus 100000000 from .frac.';
CREATE PROCEDURE amount_add(
IN a TALER_AMOUNT
,IN b TALER_AMOUNT
,OUT sum TALER_AMOUNT
)
LANGUAGE plpgsql
AS $$
BEGIN
sum = (a.val + b.val, a.frac + b.frac);
CALL amount_normalize(sum ,sum);
IF (sum.val > (1<<52))
THEN
RAISE EXCEPTION 'addition overflow';
END IF;
END $$;
COMMENT ON PROCEDURE amount_add
IS 'Returns the normalized sum of two amounts. It raises an exception when the resulting .val is larger than 2^52';
CREATE FUNCTION amount_left_minus_right(
IN l TALER_AMOUNT
,IN r TALER_AMOUNT
,OUT diff TALER_AMOUNT
,OUT ok BOOLEAN
)
LANGUAGE plpgsql
AS $$
BEGIN
IF (l.val > r.val)
THEN
ok = TRUE;
IF (l.frac >= r.frac)
THEN
diff.val = l.val - r.val;
diff.frac = l.frac - r.frac;
ELSE
diff.val = l.val - r.val - 1;
diff.frac = l.frac + 100000000 - r.frac;
END IF;
ELSE
IF (l.val = r.val) AND (l.frac >= r.frac)
THEN
diff.val = 0;
diff.frac = l.frac - r.frac;
ok = TRUE;
ELSE
diff = (-1, -1);
ok = FALSE;
END IF;
END IF;
RETURN;
END $$;
COMMENT ON FUNCTION amount_left_minus_right
IS 'Subtracts the right amount from the left and returns the difference and TRUE, if the left amount is larger than the right, or an invalid amount and FALSE otherwise.';
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- Main DB setup loop -- Main DB setup loop
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
CREATE FUNCTION do_create_tables( CREATE FUNCTION do_create_tables(
num_partitions INTEGER num_partitions INTEGER
-- NULL: no partitions, add foreign constraints -- NULL: no partitions, add foreign constraints

View File

@ -19,6 +19,22 @@ BEGIN;
SELECT _v.register_patch('exchange-0002', NULL, NULL); SELECT _v.register_patch('exchange-0002', NULL, NULL);
SET search_path TO exchange; SET search_path TO exchange;
CREATE TYPE taler_amount
AS
(val INT8
,frac INT4
);
COMMENT ON TYPE taler_amount
IS 'Stores an amount, fraction is in units of 1/100000000 of the base value';
CREATE TYPE exchange_do_array_reserve_insert_return_type
AS
(transaction_duplicate BOOLEAN
,ruuid INT8
);
COMMENT ON TYPE exchange_do_array_reserve_insert_return_type
IS 'Return type for exchange_do_array_reserves_insert() stored procedure';
#include "0002-denominations.sql" #include "0002-denominations.sql"
#include "0002-denomination_revocations.sql" #include "0002-denomination_revocations.sql"
#include "0002-wire_targets.sql" #include "0002-wire_targets.sql"
@ -71,5 +87,13 @@ SET search_path TO exchange;
#include "0002-revolving_work_shards.sql" #include "0002-revolving_work_shards.sql"
#include "0002-partners.sql" #include "0002-partners.sql"
#include "0002-partner_accounts.sql" #include "0002-partner_accounts.sql"
#include "0002-purse_actions.sql"
#include "0002-purse_deletion.sql"
#include "0002-kyc_attributes.sql"
#include "0002-aml_status.sql"
#include "0002-aml_staff.sql"
#include "0002-aml_history.sql"
#include "0002-age_withdraw.sql"
COMMIT; COMMIT;

View File

@ -1,31 +0,0 @@
--
-- 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/>
--
BEGIN;
SELECT _v.register_patch('exchange-0003', NULL, NULL);
SET search_path TO exchange;
#include "0003-purse_actions.sql"
#include "0003-purse_deletion.sql"
#include "0003-kyc_attributes.sql"
#include "0003-aml_status.sql"
#include "0003-aml_staff.sql"
#include "0003-aml_history.sql"
#include "0003-age_withdraw.sql"
COMMIT;

View File

@ -1,25 +0,0 @@
--
-- This file is part of TALER
-- Copyright (C) 2023 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/>
--
BEGIN;
SELECT _v.register_patch('exchange-0004', NULL, NULL);
SET search_path TO exchange;
#include "0004-kyc_attributes.sql"
#include "0004-wire_accounts.sql"
COMMIT;

View File

@ -16,7 +16,7 @@
-- @author Özgür Kesim -- @author Özgür Kesim
CREATE OR REPLACE FUNCTION exchange_do_age_withdraw( CREATE OR REPLACE FUNCTION exchange_do_age_withdraw(
IN amount_with_fee TALER_AMOUNT, IN amount_with_fee taler_amount,
IN rpub BYTEA, IN rpub BYTEA,
IN rsig BYTEA, IN rsig BYTEA,
IN now INT8, IN now INT8,
@ -38,8 +38,8 @@ AS $$
DECLARE DECLARE
reserve_gc INT8; reserve_gc INT8;
difference RECORD; difference RECORD;
balance TALER_AMOUNT; balance taler_amount;
new_balance TALER_AMOUNT; new_balance taler_amount;
not_before date; not_before date;
earliest_date date; earliest_date date;
BEGIN BEGIN
@ -104,9 +104,9 @@ required_age=0;
-- Check reserve balance is sufficient. -- Check reserve balance is sufficient.
SELECT * SELECT *
INTO INTO
difference difference
FROM FROM
amount_left_minus_right( amount_left_minus_right(
balance balance
,amount_with_fee); ,amount_with_fee);
@ -114,7 +114,7 @@ FROM
balance_ok = difference.ok; balance_ok = difference.ok;
IF NOT balance_ok IF NOT balance_ok
THEN THEN
RETURN; RETURN;
END IF; END IF;
@ -166,6 +166,5 @@ END IF;
END $$; END $$;
COMMENT ON FUNCTION exchange_do_age_withdraw(TALER_AMOUNT, BYTEA, BYTEA, INT8, INT8, BYTEA, INT2, INT2, BYTEA[], INT8[], BYTEA[]) COMMENT ON FUNCTION exchange_do_age_withdraw(taler_amount, BYTEA, BYTEA, INT8, INT8, BYTEA, INT2, INT2, BYTEA[], INT8[], BYTEA[])
IS 'Checks whether the reserve has sufficient balance for an age-withdraw operation (or the request is repeated and was previously approved) and that age requirements are met. If so updates the database with the result. Includes storing the blinded planchets and denomination signatures, or signaling conflict'; IS 'Checks whether the reserve has sufficient balance for an age-withdraw operation (or the request is repeated and was previously approved) and that age requirements are met. If so updates the database with the result. Includes storing the blinded planchets and denomination signatures, or signaling conflict';

View File

@ -0,0 +1,78 @@
--------------------------------------------------------------
-- Taler amounts and helper functiosn
-------------------------------------------------------------
CREATE OR REPLACE PROCEDURE amount_normalize(
IN amount taler_amount
,OUT normalized taler_amount
)
LANGUAGE plpgsql
AS $$
BEGIN
normalized.val = amount.val + amount.frac / 100000000;
normalized.frac = amount.frac % 100000000;
END $$;
COMMENT ON PROCEDURE amount_normalize
IS 'Returns the normalized amount by adding to the .val the value of (.frac / 100000000) and removing the modulus 100000000 from .frac.';
CREATE OR REPLACE PROCEDURE amount_add(
IN a taler_amount
,IN b taler_amount
,OUT sum taler_amount
)
LANGUAGE plpgsql
AS $$
BEGIN
sum = (a.val + b.val, a.frac + b.frac);
CALL amount_normalize(sum ,sum);
IF (sum.val > (1<<52))
THEN
RAISE EXCEPTION 'addition overflow';
END IF;
END $$;
COMMENT ON PROCEDURE amount_add
IS 'Returns the normalized sum of two amounts. It raises an exception when the resulting .val is larger than 2^52';
CREATE OR REPLACE FUNCTION amount_left_minus_right(
IN l taler_amount
,IN r taler_amount
,OUT diff taler_amount
,OUT ok BOOLEAN
)
LANGUAGE plpgsql
AS $$
BEGIN
IF (l.val > r.val)
THEN
ok = TRUE;
IF (l.frac >= r.frac)
THEN
diff.val = l.val - r.val;
diff.frac = l.frac - r.frac;
ELSE
diff.val = l.val - r.val - 1;
diff.frac = l.frac + 100000000 - r.frac;
END IF;
ELSE
IF (l.val = r.val) AND (l.frac >= r.frac)
THEN
diff.val = 0;
diff.frac = l.frac - r.frac;
ok = TRUE;
ELSE
diff = (-1, -1);
ok = FALSE;
END IF;
END IF;
RETURN;
END $$;
COMMENT ON FUNCTION amount_left_minus_right
IS 'Subtracts the right amount from the left and returns the difference and TRUE, if the left amount is larger than the right, or an invalid amount and FALSE otherwise.';

View File

@ -966,21 +966,6 @@ END $$;
DO $$
BEGIN
CREATE TYPE exchange_do_array_reserve_insert_return_type
AS
(transaction_duplicate BOOLEAN
,ruuid INT8);
EXCEPTION
WHEN duplicate_object THEN null;
END
$$;
CREATE OR REPLACE FUNCTION exchange_do_array_reserves_insert( CREATE OR REPLACE FUNCTION exchange_do_array_reserves_insert(
IN in_gc_date INT8, IN in_gc_date INT8,
IN in_reserve_expiration INT8, IN in_reserve_expiration INT8,
@ -1019,7 +1004,7 @@ BEGIN
,UNNEST (ina_payto_uri) AS payto_uri ,UNNEST (ina_payto_uri) AS payto_uri
ON CONFLICT DO NOTHING; ON CONFLICT DO NOTHING;
FOR i IN FOR i IN
SELECT SELECT
reserve_pub reserve_pub
,wire_ref ,wire_ref

View File

@ -293,6 +293,15 @@ TEH_PG_internal_setup (struct PostgresClosure *pg)
NULL); NULL);
if (NULL == db_conn) if (NULL == db_conn)
return GNUNET_SYSERR; return GNUNET_SYSERR;
if (GNUNET_OK != TALER_PQ_load_oids_for_composite_types (db_conn))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to load OIDs for composite types\n");
GNUNET_PQ_disconnect (db_conn);
return GNUNET_SYSERR;
}
pg->prep_gen++; pg->prep_gen++;
pg->conn = db_conn; pg->conn = db_conn;
} }

View File

@ -18,6 +18,7 @@ BEGIN;
SET search_path TO exchange; SET search_path TO exchange;
#include "exchange_do_amount_specific.sql"
#include "exchange_do_withdraw.sql" #include "exchange_do_withdraw.sql"
#include "exchange_do_batch_withdraw.sql" #include "exchange_do_batch_withdraw.sql"
#include "exchange_do_batch_withdraw_insert.sql" #include "exchange_do_batch_withdraw_insert.sql"

View File

@ -46,7 +46,6 @@ TALER_EXCHANGEDB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg);
void void
TALER_EXCHANGEDB_plugin_unload (struct TALER_EXCHANGEDB_Plugin *plugin); TALER_EXCHANGEDB_plugin_unload (struct TALER_EXCHANGEDB_Plugin *plugin);
/** /**
* Information about an account from the configuration. * Information about an account from the configuration.
*/ */

View File

@ -19,15 +19,42 @@
* @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Sree Harsha Totakura <sreeharsha@totakura.in>
* @author Florian Dold * @author Florian Dold
* @author Christian Grothoff * @author Christian Grothoff
* @author Özgür Kesim
*/ */
#ifndef TALER_PQ_LIB_H_ #ifndef TALER_PQ_LIB_H_
#define TALER_PQ_LIB_H_ #define TALER_PQ_LIB_H_
#include <libpq-fe.h> #include <libpq-fe.h>
#include <jansson.h> #include <jansson.h>
#include <gnunet/gnunet_common.h>
#include <gnunet/gnunet_pq_lib.h> #include <gnunet/gnunet_pq_lib.h>
#include "taler_util.h" #include "taler_util.h"
/**
* Enumerates the composite types that Taler defines in Postgres.
* The corresponding OIDs (which are assigned by postgres at time of
* declaration) are stored in TALER_PQ_CompositeOIDs.
*/
enum TALER_PQ_CompositeType
{
TALER_PQ_CompositeAmount,
TALER_PQ_CompositeMAX /* MUST be last */
};
/**
* The correspondence of the Composite types and their OID in Postgres
*/
extern Oid TALER_PQ_CompositeOIDs[TALER_PQ_CompositeMAX];
/**
* Initialize the list of OIDs in TALER_PQ_CompositeOIDs. MUST be called
* before any composite type is used in arrays-specs/-params.
*
* @return GNUNET_SYSERR on failure
*/
enum GNUNET_GenericReturnValue
TALER_PQ_load_oids_for_composite_types (struct GNUNET_PQ_Context *db);
/** /**
* Generate query parameter for a currency, consisting of the three * Generate query parameter for a currency, consisting of the three
* components "value", "fraction" and "currency" in this order. The * components "value", "fraction" and "currency" in this order. The

View File

@ -10,6 +10,8 @@ lib_LTLIBRARIES = \
libtalerpq.la libtalerpq.la
libtalerpq_la_SOURCES = \ libtalerpq_la_SOURCES = \
pq_common.h \
pq_composite_types.c \
pq_query_helper.c \ pq_query_helper.c \
pq_result_helper.c pq_result_helper.c
libtalerpq_la_LIBADD = \ libtalerpq_la_LIBADD = \

83
src/pq/pq_common.h Normal file
View File

@ -0,0 +1,83 @@
/*
This file is part of TALER
Copyright (C) 2023 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/>
*/
/**
* @file pq/pq_common.h
* @brief common defines for the pq functions
* @author Özgür Kesim
*/
#ifndef TALER_PQ_COMMON_H_
#define TALER_PQ_COMMON_H_
#include "platform.h"
/**
* Internal types that are supported as TALER-exchange-specific array types.
*
* To support a new type,
* 1. add a new entry into this list,
* 2. for query-support, implement the size calculation and memory copying in
* qconv_array() accordingly, in pq_query_helper.c
* 3. provide a query-API for arrays of the type, by calling
* query_param_array_generic with the appropriate parameters,
* in pq_query_helper.c
* 4. for result-support, implement memory copying by adding another case
* to extract_array_generic, in pq_result_helper.c
* 5. provide a result-spec-API for arrays of the type,
* in pq_result_helper.c
* 6. expose the API's in taler_pq_lib.h
*/
enum TALER_PQ_ArrayType
{
TALER_PQ_array_of_blinded_denom_sig,
TALER_PQ_array_of_blinded_coin_hash,
TALER_PQ_array_of_denom_hash,
/* TODO[oec]: Next up: TALER_PQ_array_of_amount, */
TALER_PQ_array_of_MAX, /* must be last */
};
/**
* Memory representation of an taler amount record for Postgres.
*
* All values need to be in network-byte-order.
*/
struct TALER_PQ_Amount_P
{
uint32_t oid_v; /* oid of .v */
uint32_t sz_v; /* size of .v */
uint64_t v; /* value */
uint32_t oid_f; /* oid of .f */
uint32_t sz_f; /* size of .f */
uint32_t f; /* fraction */
} __attribute__((packed));
/**
* Create a `struct TALER_PQ_Amount_P` for initialization
*
* @param db postgres-context of type `struct GNUNET_PQ_Context *`
* @param amount amount of type `struct TALER_Amount *`
*/
#define MAKE_TALER_PQ_AMOUNT_P(db,amount) \
{ \
.oid_v = htonl (GNUNET_PQ_get_oid ((db), GNUNET_PQ_DATATYPE_INT8)), \
.oid_f = htonl (GNUNET_PQ_get_oid ((db), GNUNET_PQ_DATATYPE_INT4)), \
.sz_v = htonl (sizeof((amount)->value)), \
.sz_f = htonl (sizeof((amount)->fraction)), \
.v = GNUNET_htonll ((amount)->value), \
.f = htonl ((amount)->fraction) \
}
#endif /* TALER_PQ_COMMON_H_ */
/* end of pg/pq_common.h */

View File

@ -0,0 +1,57 @@
/*
This file is part of TALER
Copyright (C) 2023 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/>
*/
/**
* @file pq/pq_composite_types.c
* @brief helper functions for Taler-specific libpq (PostGres) interactions with composite types
* @author Özgür Kesim
*/
#include "platform.h"
#include <gnunet/gnunet_common.h>
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_pq_lib.h>
#include "taler_pq_lib.h"
#include "pq_common.h"
Oid TALER_PQ_CompositeOIDs[TALER_PQ_CompositeMAX] = {0};
enum GNUNET_GenericReturnValue
TALER_PQ_load_oids_for_composite_types (
struct GNUNET_PQ_Context *db)
{
static char *names[] = {
[TALER_PQ_CompositeAmount] = "taler_amount"
};
size_t num = sizeof(names) / sizeof(names[0]);
GNUNET_static_assert (num == TALER_PQ_CompositeMAX);
for (size_t i = 0; i < num; i++)
{
enum GNUNET_GenericReturnValue ret;
enum TALER_PQ_CompositeType typ = i;
ret = GNUNET_PQ_get_oid_by_name (db,
names[i],
&TALER_PQ_CompositeOIDs[typ]);
if (GNUNET_OK != ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to load OID for type %s\n",
names[i]);
return GNUNET_SYSERR;
}
}
return GNUNET_OK;
}

View File

@ -872,7 +872,7 @@ qconv_array (
RETURN_UNLESS ((0 == num) || (y / num == x)); RETURN_UNLESS ((0 == num) || (y / num == x));
/* size of header */ /* size of header */
total_size = x = sizeof(struct TALER_PQ_ArrayHeader_P); total_size = x = sizeof(struct GNUNET_PQ_ArrayHeader_P);
total_size += y; total_size += y;
RETURN_UNLESS (total_size >= x); RETURN_UNLESS (total_size >= x);
@ -941,7 +941,7 @@ qconv_array (
/* Write data */ /* Write data */
{ {
char *out = elements; char *out = elements;
struct TALER_PQ_ArrayHeader_P h = { struct GNUNET_PQ_ArrayHeader_P h = {
.ndim = htonl (1), /* We only support one-dimensional arrays */ .ndim = htonl (1), /* We only support one-dimensional arrays */
.has_null = htonl (0), /* We do not support NULL entries in arrays */ .has_null = htonl (0), /* We do not support NULL entries in arrays */
.lbound = htonl (1), /* Default start index value */ .lbound = htonl (1), /* Default start index value */

View File

@ -1166,7 +1166,7 @@ extract_array_generic (
int data_sz; int data_sz;
char *data; char *data;
void *out = NULL; void *out = NULL;
struct TALER_PQ_ArrayHeader_P header; struct GNUNET_PQ_ArrayHeader_P header;
int col_num; int col_num;
GNUNET_assert (NULL != dst); GNUNET_assert (NULL != dst);
@ -1192,8 +1192,8 @@ extract_array_generic (
FAIL_IF (NULL == data); FAIL_IF (NULL == data);
{ {
struct TALER_PQ_ArrayHeader_P *h = struct GNUNET_PQ_ArrayHeader_P *h =
(struct TALER_PQ_ArrayHeader_P *) data; (struct GNUNET_PQ_ArrayHeader_P *) data;
header.ndim = ntohl (h->ndim); header.ndim = ntohl (h->ndim);
header.has_null = ntohl (h->has_null); header.has_null = ntohl (h->has_null);

View File

@ -194,6 +194,16 @@ main (int argc,
GNUNET_PQ_disconnect (conn); GNUNET_PQ_disconnect (conn);
return 1; return 1;
} }
ret = TALER_PQ_load_oids_for_composite_types (conn);
if (GNUNET_OK != ret)
{
fprintf (stderr,
"Failed to load oids for composites\n");
GNUNET_PQ_disconnect (conn);
return 1;
}
ret = run_queries (conn); ret = run_queries (conn);
{ {
struct GNUNET_PQ_ExecuteStatement ds[] = { struct GNUNET_PQ_ExecuteStatement ds[] = {