diff options
Diffstat (limited to 'src/exchangedb')
-rw-r--r-- | src/exchangedb/Makefile.am | 1 | ||||
-rw-r--r-- | src/exchangedb/exchange-0001.sql | 3 | ||||
-rw-r--r-- | src/exchangedb/exchange-0002.sql | 64 | ||||
-rw-r--r-- | src/exchangedb/lrbt_callbacks.c | 847 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 615 |
5 files changed, 1454 insertions, 76 deletions
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index 78b5827e6..bfc42ec1e 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -25,6 +25,7 @@ EXTRA_DIST = \ exchangedb.conf \ exchangedb-postgres.conf \ plugin_exchangedb_common.c \ + lrbt_callbacks.c \ test-exchange-db-postgres.conf \ $(sql_DATA) diff --git a/src/exchangedb/exchange-0001.sql b/src/exchangedb/exchange-0001.sql index 8428a94b4..8ee5d0e06 100644 --- a/src/exchangedb/exchange-0001.sql +++ b/src/exchangedb/exchange-0001.sql @@ -103,7 +103,7 @@ CREATE TABLE IF NOT EXISTS reserves_in ); COMMENT ON TABLE reserves_in IS 'list of transfers of funds into the reserves, one per incoming wire transfer'; - +-- FIXME: explain 'wire_reference'! CREATE INDEX IF NOT EXISTS reserves_in_execution_index ON reserves_in (exchange_account_section @@ -151,6 +151,7 @@ COMMENT ON COLUMN reserves_out.h_blind_ev IS 'Hash of the blinded coin, used as primary key here so that broken clients that use a non-random coin or blinding factor fail to withdraw (otherwise they would fail on deposit when the coin is not unique there).'; COMMENT ON COLUMN reserves_out.denom_pub_hash IS 'We do not CASCADE ON DELETE here, we may keep the denomination data alive'; +-- FIXME: replace denom_pub_hash with denominations_serial *EVERYWHERE* CREATE INDEX IF NOT EXISTS reserves_out_reserve_pub_index ON reserves_out diff --git a/src/exchangedb/exchange-0002.sql b/src/exchangedb/exchange-0002.sql index a7b6b815e..11564367a 100644 --- a/src/exchangedb/exchange-0002.sql +++ b/src/exchangedb/exchange-0002.sql @@ -73,6 +73,8 @@ UPDATE reserves_in INNER JOIN reserves r USING(reserve_pub); ALTER TABLE reserves_in ALTER COLUMN reserve_uuid SET NOT NULL; +ALTER TABLE reserves_in + DROP COLUMN reserve_pub; ALTER TABLE reserves_out ADD COLUMN reserve_uuid INT8 REFERENCES reserves (reserve_uuid) ON DELETE CASCADE; UPDATE reserves_out @@ -81,6 +83,8 @@ UPDATE reserves_out INNER JOIN reserves r USING(reserve_pub); ALTER TABLE reserves_out ALTER COLUMN reserve_uuid SET NOT NULL; +ALTER TABLE reserves_out + DROP COLUMN reserve_pub; ALTER TABLE reserves_close ADD COLUMN reserve_uuid INT8 REFERENCES reserves (reserve_uuid) ON DELETE CASCADE; UPDATE reserves_close @@ -89,14 +93,56 @@ UPDATE reserves_close INNER JOIN reserves r USING(reserve_pub); ALTER TABLE reserves_close ALTER COLUMN reserve_uuid SET NOT NULL; - -ALTER TABLE reserves_in - DROP COLUMN reserve_pub; -ALTER TABLE reserves_out - DROP COLUMN reserve_pub; ALTER TABLE reserves_close DROP COLUMN reserve_pub; +-- change all foreign keys using 'denom_pub_hash' to using 'denominations_serial' instead +ALTER TABLE reserves_out + ADD COLUMN denominations_serial INT8 REFERENCES denominations (denominations_serial) ON DELETE CASCADE; +UPDATE reserves_out + SET denominations_serial=d.denominations_serial + FROM reserves_out o + INNER JOIN denominations d USING(denom_pub_hash); +ALTER TABLE reserves_out + ALTER COLUMN denominations_serial SET NOT NULL; +ALTER TABLE reserves_out + DROP COLUMN denom_pub_hash; + +ALTER TABLE known_coins + ADD COLUMN denominations_serial INT8 REFERENCES denominations (denominations_serial) ON DELETE CASCADE; +UPDATE known_coins + SET denominations_serial=d.denominations_serial + FROM known_coins o + INNER JOIN denominations d USING(denom_pub_hash); +ALTER TABLE known_coins + ALTER COLUMN denominations_serial SET NOT NULL; +ALTER TABLE known_coins + DROP COLUMN denom_pub_hash; + +ALTER TABLE denomination_revocations + ADD COLUMN denominations_serial INT8 REFERENCES denominations (denominations_serial) ON DELETE CASCADE; +UPDATE denomination_revocations + SET denominations_serial=d.denominations_serial + FROM denomination_revocations o + INNER JOIN denominations d USING(denom_pub_hash); +ALTER TABLE denomination_revocations + ALTER COLUMN denominations_serial SET NOT NULL; +ALTER TABLE denomination_revocations + DROP COLUMN denom_pub_hash; +ALTER TABLE denomination_revocations + ADD CONSTRAINT denominations_serial_pk PRIMARY KEY (denominations_serial); + +ALTER TABLE refresh_revealed_coins + ADD COLUMN denominations_serial INT8 REFERENCES denominations (denominations_serial) ON DELETE CASCADE; +UPDATE refresh_revealed_coins + SET denominations_serial=d.denominations_serial + FROM refresh_revealed_coins o + INNER JOIN denominations d USING(denom_pub_hash); +ALTER TABLE refresh_revealed_coins + ALTER COLUMN denominations_serial SET NOT NULL; +ALTER TABLE refresh_revealed_coins + DROP COLUMN denom_pub_hash; + CREATE TABLE IF NOT EXISTS auditors (auditor_uuid BIGSERIAL UNIQUE @@ -116,22 +162,20 @@ COMMENT ON COLUMN auditors.is_active IS 'true if we are currently supporting the use of this auditor.'; COMMENT ON COLUMN auditors.last_change IS 'Latest time when active status changed. Used to detect replays of old messages.'; --- "auditors" has no BIGSERIAL because it is a 'mutable' table --- and is of no concern to the auditor CREATE TABLE IF NOT EXISTS auditor_denom_sigs (auditor_denom_serial BIGSERIAL UNIQUE ,auditor_pub BYTEA NOT NULL REFERENCES auditors (auditor_pub) ON DELETE CASCADE - ,denom_pub_hash BYTEA NOT NULL REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE + ,denominations_serial INT8 NOT NULL REFERENCES denominations (denominations_serial) ON DELETE CASCADE ,auditor_sig BYTEA CHECK (LENGTH(auditor_sig)=64) - ,PRIMARY KEY (denom_pub_hash, auditor_pub) + ,PRIMARY KEY (denominations_serial, auditor_pub) ); COMMENT ON TABLE auditor_denom_sigs IS 'Table with auditor signatures on exchange denomination keys.'; COMMENT ON COLUMN auditor_denom_sigs.auditor_pub IS 'Public key of the auditor.'; -COMMENT ON COLUMN auditor_denom_sigs.denom_pub_hash +COMMENT ON COLUMN auditor_denom_sigs.denominations_serial IS 'Denomination the signature is for.'; COMMENT ON COLUMN auditor_denom_sigs.auditor_sig IS 'Signature of the auditor, of purpose TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS.'; diff --git a/src/exchangedb/lrbt_callbacks.c b/src/exchangedb/lrbt_callbacks.c new file mode 100644 index 000000000..71bc2ae7a --- /dev/null +++ b/src/exchangedb/lrbt_callbacks.c @@ -0,0 +1,847 @@ +/* + This file is part of GNUnet + Copyright (C) 2020 Taler Systems SA + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/** + * @file exchangedb/lrbt_callbacks.c + * @brief callbacks used by postgres_lookup_records_by_table, to be + * inlined into the plugin + * @author Christian Grothoff + */ + + +/** + * Function called with denominations table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_denominations (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_DENOMINATIONS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with denomination_revocations table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_denomination_revocations (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with reserves table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_reserves (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_RESERVES + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with reserves_in table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_reserves_in (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_RESERVES_IN + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with reserves_close table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_reserves_close (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_RESERVES_CLOSE + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with reserves_out table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_reserves_out (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_RESERVES_OUT + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with auditors table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_auditors (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_AUDITORS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with auditor_denom_sigs table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_auditor_denom_sigs (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with exchange_sign_keys table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_exchange_sign_keys (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with signkey_revocations table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_signkey_revocations (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with known_coins table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_known_coins (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_KNOWN_COINS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with refresh_commitments table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_refresh_commitments (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_REFRESH_COMMITMENTS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with refresh_revealed_coins table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_refresh_revealed_coins (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_REFRESH_REVEALED_COINS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with refresh_transfer_keys table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_refresh_transfer_keys (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_REFRESH_TRANSFER_KEYS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with deposits table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_deposits (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_DEPOSITS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with refunds table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_refunds (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_REFUNDS + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with wire_out table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_wire_out (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_WIRE_OUT + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with aggregation_tracking table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_aggregation_tracking (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with wire_fee table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_wire_fee (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_WIRE_FEE + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with recoup table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_recoup (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_RECOUP + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Function called with recoup_refresh table entries. + * + * @param cls closure + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lrbt_cb_table_recoup_refresh (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupRecordsByTableContext *ctx = cls; + struct TALER_EXCHANGEDB_TableData td = { + .table = TALER_EXCHANGEDB_RT_RECOUP_REFRESH + }; + + for (unsigned int i = 0; i<num_results; i++) + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->error = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + +/* end of lrbt_callbacks.c */ diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 3df1af74b..4169da2c4 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -336,7 +336,7 @@ postgres_get_session (void *cls) ",denom_pub" " FROM denominations" " LEFT JOIN " - " denomination_revocations USING (denom_pub_hash);", + " denomination_revocations USING (denominations_serial);", 0), /* Used in #postgres_iterate_active_signkeys() */ GNUNET_PQ_make_prepare ("select_signkeys", @@ -358,10 +358,11 @@ postgres_get_session (void *cls) GNUNET_PQ_make_prepare ("select_auditor_denoms", "SELECT" " auditor_denom_sigs.auditor_pub" - ",auditor_denom_sigs.denom_pub_hash" + ",denominations.denom_pub_hash" ",auditor_denom_sigs.auditor_sig" " FROM auditor_denom_sigs" " JOIN auditors USING (auditor_pub)" + " JOIN denominations USING (denominations_serial)" " WHERE auditors.is_active;", 0), /* Used in #postgres_iterate_active_auditors() */ @@ -399,10 +400,11 @@ postgres_get_session (void *cls) /* Used in #postgres_insert_denomination_revocation() */ GNUNET_PQ_make_prepare ("denomination_revocation_insert", "INSERT INTO denomination_revocations " - "(denom_pub_hash" + "(denominations_serial" ",master_sig" - ") VALUES " - "($1, $2);", + ") SELECT denominations_serial,$2" + " FROM denominations" + " WHERE denom_pub_hash=$1;", 2), /* Used in #postgres_get_denomination_revocation() */ GNUNET_PQ_make_prepare ("denomination_revocation_get", @@ -410,7 +412,10 @@ postgres_get_session (void *cls) " master_sig" ",denom_revocations_serial_id" " FROM denomination_revocations" - " WHERE denom_pub_hash=$1;", + " WHERE denominations_serial=" + " (SELECT denominations_serial" + " FROM denominations" + " WHERE denom_pub_hash=$1);", 1), /* Used in #postgres_reserves_get() */ GNUNET_PQ_make_prepare ("reserves_get", @@ -549,17 +554,22 @@ postgres_get_session (void *cls) is being withdrawn from and the signature of the message authorizing the withdrawal. */ GNUNET_PQ_make_prepare ("insert_withdraw_info", + "WITH ds AS" + " (SELECT denominations_serial" + " FROM denominations" + " WHERE denom_pub_hash=$2)" "INSERT INTO reserves_out " "(h_blind_ev" - ",denom_pub_hash" + ",denominations_serial" ",denom_sig" ",reserve_uuid" ",reserve_sig" ",execution_date" ",amount_with_fee_val" ",amount_with_fee_frac" - ") SELECT $1, $2, $3, reserve_uuid, $5, $6, $7, $8" + ") SELECT $1, ds.denominations_serial, $3, reserve_uuid, $5, $6, $7, $8" " FROM reserves" + " CROSS JOIN ds" " WHERE reserve_pub=$4;", 8), /* Used in #postgres_get_withdraw_info() to @@ -568,7 +578,7 @@ postgres_get_session (void *cls) make sure /reserve/withdraw requests are idempotent. */ GNUNET_PQ_make_prepare ("get_withdraw_info", "SELECT" - " denom_pub_hash" + " denom.denom_pub_hash" ",denom_sig" ",reserve_sig" ",reserves.reserve_pub" @@ -581,7 +591,7 @@ postgres_get_session (void *cls) " JOIN reserves" " USING (reserve_uuid)" " JOIN denominations denom" - " USING (denom_pub_hash)" + " USING (denominations_serial)" " WHERE h_blind_ev=$1;", 1), /* Used during #postgres_get_reserve_history() to @@ -591,7 +601,7 @@ postgres_get_session (void *cls) GNUNET_PQ_make_prepare ("get_reserves_out", "SELECT" " h_blind_ev" - ",denom_pub_hash" + ",denom.denom_pub_hash" ",denom_sig" ",reserve_sig" ",execution_date" @@ -601,7 +611,7 @@ postgres_get_session (void *cls) ",denom.fee_withdraw_frac" " FROM reserves_out" " JOIN denominations denom" - " USING (denom_pub_hash)" + " USING (denominations_serial)" " WHERE reserve_uuid=" " (SELECT reserve_uuid" " FROM reserves" @@ -622,7 +632,7 @@ postgres_get_session (void *cls) " JOIN reserves" " USING (reserve_uuid)" " JOIN denominations denom" - " USING (denom_pub_hash)" + " USING (denominations_serial)" " WHERE reserve_out_serial_id>=$1" " ORDER BY reserve_out_serial_id ASC;", 1), @@ -632,23 +642,28 @@ postgres_get_session (void *cls) "SELECT" " COUNT(*) AS count" " FROM known_coins" - " WHERE denom_pub_hash=$1;", + " WHERE denominations_serial=" + " (SELECT denominations_serial" + " FROM denominations" + " WHERE denom_pub_hash=$1);", 1), /* Used in #postgres_get_known_coin() to fetch the denomination public key and signature for a coin known to the exchange. */ GNUNET_PQ_make_prepare ("get_known_coin", "SELECT" - " denom_pub_hash" + " denominations.denom_pub_hash" ",denom_sig" " FROM known_coins" + " JOIN denominations USING (denominations_serial)" " WHERE coin_pub=$1;", 1), /* Used in #postgres_ensure_coin_known() */ GNUNET_PQ_make_prepare ("get_known_coin_dh", "SELECT" - " denom_pub_hash" + " denominations.denom_pub_hash" " FROM known_coins" + " JOIN denominations USING (denominations_serial)" " WHERE coin_pub=$1;", 1), /* Used in #postgres_get_coin_denomination() to fetch @@ -656,8 +671,9 @@ postgres_get_session (void *cls) a coin known to the exchange. */ GNUNET_PQ_make_prepare ("get_coin_denomination", "SELECT" - " denom_pub_hash" + " denominations.denom_pub_hash" " FROM known_coins" + " JOIN denominations USING (denominations_serial)" " WHERE coin_pub=$1" " FOR SHARE;", 1), @@ -673,10 +689,11 @@ postgres_get_session (void *cls) GNUNET_PQ_make_prepare ("insert_known_coin", "INSERT INTO known_coins " "(coin_pub" - ",denom_pub_hash" + ",denominations_serial" ",denom_sig" - ") VALUES " - "($1,$2,$3);", + ") SELECT $1, denominations_serial, $3 " + " FROM denominations" + " WHERE denom_pub_hash=$2;", 3), /* Used in #postgres_insert_melt() to store @@ -696,9 +713,9 @@ postgres_get_session (void *cls) high-level information about a melt operation */ GNUNET_PQ_make_prepare ("get_melt", "SELECT" - " kc.denom_pub_hash" - ",denom.fee_refresh_val" - ",denom.fee_refresh_frac" + " denoms.denom_pub_hash" + ",denoms.fee_refresh_val" + ",denoms.fee_refresh_frac" ",old_coin_pub" ",old_coin_sig" ",amount_with_fee_val" @@ -707,8 +724,8 @@ postgres_get_session (void *cls) " FROM refresh_commitments" " JOIN known_coins kc" " ON (refresh_commitments.old_coin_pub = kc.coin_pub)" - " JOIN denominations denom" - " ON (kc.denom_pub_hash = denom.denom_pub_hash)" + " JOIN denominations denoms" + " ON (kc.denominations_serial = denoms.denominations_serial)" " WHERE rc=$1;", 1), /* Used in #postgres_get_melt_index() to fetch @@ -735,7 +752,7 @@ postgres_get_session (void *cls) " JOIN known_coins kc" " ON (refresh_commitments.old_coin_pub = kc.coin_pub)" " JOIN denominations denom" - " ON (kc.denom_pub_hash = denom.denom_pub_hash)" + " ON (kc.denominations_serial = denom.denominations_serial)" " WHERE melt_serial_id>=$1" " ORDER BY melt_serial_id ASC;", 1), @@ -746,15 +763,15 @@ postgres_get_session (void *cls) ",old_coin_sig" ",amount_with_fee_val" ",amount_with_fee_frac" - ",kc.denom_pub_hash" - ",denom.fee_refresh_val " - ",denom.fee_refresh_frac " + ",denoms.denom_pub_hash" + ",denoms.fee_refresh_val " + ",denoms.fee_refresh_frac " ",melt_serial_id" " FROM refresh_commitments" " JOIN known_coins kc" " ON (refresh_commitments.old_coin_pub = kc.coin_pub)" - " JOIN denominations denom" - " USING (denom_pub_hash)" + " JOIN denominations denoms" + " USING (denominations_serial)" " WHERE old_coin_pub=$1;", 1), @@ -765,12 +782,13 @@ postgres_get_session (void *cls) "(rc " ",freshcoin_index " ",link_sig " - ",denom_pub_hash " + ",denominations_serial " ",coin_ev" ",h_coin_ev" ",ev_sig" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7);", + ") SELECT $1, $2, $3, denominations_serial, $5, $6, $7 " + " FROM denominations" + " WHERE denom_pub_hash=$4;", 7), /* Obtain information about the coins created in a refresh operation, used in #postgres_get_refresh_reveal() */ @@ -783,7 +801,7 @@ postgres_get_session (void *cls) ",ev_sig" " FROM refresh_revealed_coins" " JOIN denominations denom " - " USING (denom_pub_hash)" + " USING (denominations_serial)" " WHERE rc=$1" " ORDER BY freshcoin_index ASC;", 1), @@ -836,7 +854,7 @@ postgres_get_session (void *cls) ",refund_serial_id" " FROM refunds" " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" + " JOIN denominations denom USING (denominations_serial)" " WHERE coin_pub=$1;", 1), /* Query the 'refunds' by coin public key, merchant_pub and contract hash */ @@ -864,7 +882,7 @@ postgres_get_session (void *cls) ",refund_serial_id" " FROM refunds" " JOIN known_coins kc USING (coin_pub)" - " JOIN denominations denom ON (kc.denom_pub_hash = denom.denom_pub_hash)" + " JOIN denominations denom ON (kc.denominations_serial = denom.denominations_serial)" " WHERE refund_serial_id>=$1" " ORDER BY refund_serial_id ASC;", 1), @@ -910,7 +928,7 @@ postgres_get_session (void *cls) ",h_wire" " FROM deposits" " JOIN known_coins USING (coin_pub)" - " JOIN denominations USING (denom_pub_hash)" + " JOIN denominations USING (denominations_serial)" " WHERE ((coin_pub=$1)" " AND (merchant_pub=$3)" " AND (h_contract_terms=$2));", @@ -934,7 +952,7 @@ postgres_get_session (void *cls) ",deposit_serial_id" " FROM deposits" " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" + " JOIN denominations denom USING (denominations_serial)" " WHERE (" " (deposit_serial_id>=$1)" " )" @@ -951,7 +969,7 @@ postgres_get_session (void *cls) ",wire_deadline" " FROM deposits" " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" + " JOIN denominations denom USING (denominations_serial)" " WHERE (" " (coin_pub=$1)" " AND (merchant_pub=$2)" @@ -976,7 +994,7 @@ postgres_get_session (void *cls) ",wallet_timestamp" " FROM deposits" " JOIN known_coins USING (coin_pub)" - " JOIN denominations denom USING (denom_pub_hash)" + " JOIN denominations denom USING (denominations_serial)" " WHERE tiny=FALSE" " AND done=FALSE" " AND wire_deadline<=$1" @@ -998,7 +1016,7 @@ postgres_get_session (void *cls) " JOIN known_coins" " USING (coin_pub)" " JOIN denominations denom" - " USING (denom_pub_hash)" + " USING (denominations_serial)" " WHERE" " merchant_pub=$1 AND" " h_wire=$2 AND" @@ -1035,9 +1053,9 @@ postgres_get_session (void *cls) "SELECT" " amount_with_fee_val" ",amount_with_fee_frac" - ",denom.fee_deposit_val" - ",denom.fee_deposit_frac" - ",kc.denom_pub_hash" + ",denoms.fee_deposit_val" + ",denoms.fee_deposit_frac" + ",denoms.denom_pub_hash" ",wallet_timestamp" ",refund_deadline" ",wire_deadline" @@ -1051,8 +1069,8 @@ postgres_get_session (void *cls) " FROM deposits" " JOIN known_coins kc" " USING (coin_pub)" - " JOIN denominations denom" - " USING (denom_pub_hash)" + " JOIN denominations denoms" + " USING (denominations_serial)" " WHERE coin_pub=$1;", 1), @@ -1069,7 +1087,7 @@ postgres_get_session (void *cls) " JOIN refresh_transfer_keys tp" " USING (rc)" " JOIN denominations denoms" - " ON (rrc.denom_pub_hash = denoms.denom_pub_hash)" + " ON (rrc.denominations_serial = denoms.denominations_serial)" " WHERE old_coin_pub=$1" " ORDER BY tp.transfer_pub", 1), @@ -1094,7 +1112,7 @@ postgres_get_session (void *cls) " JOIN known_coins" " USING (coin_pub)" " JOIN denominations denom" - " USING (denom_pub_hash)" + " USING (denominations_serial)" " JOIN wire_out" " USING (wtid_raw)" " WHERE wtid_raw=$1;", @@ -1114,7 +1132,7 @@ postgres_get_session (void *cls) " JOIN known_coins" " USING (coin_pub)" " JOIN denominations denom" - " USING (denom_pub_hash)" + " USING (denominations_serial)" " JOIN wire_out" " USING (wtid_raw)" " WHERE coin_pub=$1" @@ -1290,7 +1308,7 @@ postgres_get_session (void *cls) ",coin_sig" ",coin_blind" ",h_blind_ev" - ",coins.denom_pub_hash" + ",denoms.denom_pub_hash" ",coins.denom_sig" ",denoms.denom_pub" ",amount_val" @@ -1303,7 +1321,7 @@ postgres_get_session (void *cls) " JOIN reserves" " USING (reserve_uuid)" " JOIN denominations denoms" - " ON (coins.denom_pub_hash = denoms.denom_pub_hash)" + " ON (coins.denominations_serial = denoms.denominations_serial)" " WHERE recoup_uuid>=$1" " ORDER BY recoup_uuid ASC;", 1), @@ -1314,13 +1332,13 @@ postgres_get_session (void *cls) " recoup_refresh_uuid" ",timestamp" ",rc.old_coin_pub" - ",old_coins.denom_pub_hash AS old_denom_pub_hash" + ",old_denoms.denom_pub_hash AS old_denom_pub_hash" ",recoup_refresh.coin_pub" ",coin_sig" ",coin_blind" - ",denoms.denom_pub" + ",new_denoms.denom_pub" ",h_blind_ev" - ",new_coins.denom_pub_hash" + ",new_denoms.denom_pub_hash" ",new_coins.denom_sig" ",amount_val" ",amount_frac" @@ -1333,8 +1351,10 @@ postgres_get_session (void *cls) " ON (rc.old_coin_pub = old_coins.coin_pub)" " INNER JOIN known_coins new_coins" " ON (new_coins.coin_pub = recoup_refresh.coin_pub)" - " INNER JOIN denominations denoms" - " ON (new_coins.denom_pub_hash = denoms.denom_pub_hash)" + " INNER JOIN denominations new_denoms" + " ON (new_coins.denominations_serial = new_denoms.denominations_serial)" + " INNER JOIN denominations old_denoms" + " ON (old_coins.denominations_serial = old_denoms.denominations_serial)" " WHERE recoup_refresh_uuid>=$1" " ORDER BY recoup_refresh_uuid ASC;", 1), @@ -1367,11 +1387,13 @@ postgres_get_session (void *cls) ",amount_val" ",amount_frac" ",timestamp" - ",coins.denom_pub_hash" + ",denoms.denom_pub_hash" ",coins.denom_sig" " FROM recoup" " JOIN known_coins coins" " USING (coin_pub)" + " JOIN denominations denoms" + " USING (denominations_serial)" " JOIN reserves_out ro" " USING (h_blind_ev)" " WHERE ro.reserve_uuid=" @@ -1389,12 +1411,14 @@ postgres_get_session (void *cls) ",amount_val" ",amount_frac" ",timestamp" - ",coins.denom_pub_hash" + ",denoms.denom_pub_hash" ",coins.denom_sig" ",recoup_refresh_uuid" " FROM recoup_refresh" " JOIN known_coins coins" " USING (coin_pub)" + " JOIN denominations denoms" + " USING (denominations_serial)" " WHERE h_blind_ev IN" " (SELECT rrc.h_coin_ev" " FROM refresh_commitments" @@ -1438,7 +1462,7 @@ postgres_get_session (void *cls) GNUNET_PQ_make_prepare ("recoup_by_coin", "SELECT" " reserves.reserve_pub" - ",coins.denom_pub_hash" + ",denoms.denom_pub_hash" ",coin_sig" ",coin_blind" ",amount_val" @@ -1452,6 +1476,8 @@ postgres_get_session (void *cls) " USING (reserve_uuid)" " JOIN known_coins coins" " USING (coin_pub)" + " JOIN denominations denoms" + " ON (denoms.denominations_serial = coins.denominations_serial)" " WHERE recoup.coin_pub=$1;", 1), /* Used in #postgres_get_coin_transactions() to obtain recoup transactions @@ -1464,7 +1490,7 @@ postgres_get_session (void *cls) ",amount_val" ",amount_frac" ",timestamp" - ",coins.denom_pub_hash" + ",denoms.denom_pub_hash" ",coins.denom_sig" ",recoup_refresh_uuid" " FROM recoup_refresh" @@ -1474,6 +1500,8 @@ postgres_get_session (void *cls) " ON (rrc.rc = rc.rc)" " JOIN known_coins coins" " USING (coin_pub)" + " JOIN denominations denoms" + " ON (denoms.denominations_serial = coins.denominations_serial)" " WHERE coin_pub=$1;", 1), /* Used in #postgres_get_reserve_by_h_blind() */ @@ -1637,10 +1665,11 @@ postgres_get_session (void *cls) GNUNET_PQ_make_prepare ("insert_auditor_denom_sig", "INSERT INTO auditor_denom_sigs " "(auditor_pub" - ",denom_pub_hash" + ",denominations_serial" ",auditor_sig" - ") VALUES " - "($1, $2, $3);", + ") SELECT $1, denominations_serial, $3 " + " FROM denominations" + " WHERE denom_pub_hash=$2;", 3), /* used in #postgres_select_auditor_denom_sig() */ GNUNET_PQ_make_prepare ("select_auditor_denom_sig", @@ -1648,7 +1677,10 @@ postgres_get_session (void *cls) " auditor_sig" " FROM auditor_denom_sigs" " WHERE auditor_pub=$1" - " AND denom_pub_hash=$2", + " AND denominations_serial=" + " (SELECT denominations_serial" + " FROM denominations" + " WHERE denom_pub_hash=$2);", 2), /* used in #postgres_lookup_wire_fee_by_time() */ GNUNET_PQ_make_prepare ("lookup_wire_fee_by_time", @@ -1666,6 +1698,158 @@ postgres_get_session (void *cls) GNUNET_PQ_make_prepare ("do_commit", "COMMIT", 0), + /* used in #postgres_lookup_serial_by_table() */ + GNUNET_PQ_make_prepare ("select_serial_by_table_denominations", + "SELECT" + " denominations_serial AS serial" + " FROM denominations" + " ORDER BY denominations_serial DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_denomination_revocations", + "SELECT" + " denom_revocations_serial_id AS serial" + " FROM denomination_revocations" + " ORDER BY denom_revocations_serial_id DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_reserves", + "SELECT" + " reserve_uuid AS serial" + " FROM reserves" + " ORDER BY reserve_uuid DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_reserves_in", + "SELECT" + " reserve_in_serial_id AS serial" + " FROM reserves_in" + " ORDER BY reserve_in_serial_id DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_reserves_close", + "SELECT" + " close_uuid AS serial" + " FROM reserves_close" + " ORDER BY close_uuid DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_reserves_out", + "SELECT" + " reserve_out_serial_id AS serial" + " FROM reserves_out" + " ORDER BY reserve_out_serial_id DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_auditors", + "SELECT" + " auditor_uuid AS serial" + " FROM auditors" + " ORDER BY auditor_uuid DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_auditor_denom_sigs", + "SELECT" + " auditor_denom_serial AS serial" + " FROM auditor_denom_sigs" + " ORDER BY auditor_denom_serial DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_exchange_sign_keys", + "SELECT" + " esk_serial AS serial" + " FROM exchange_sign_keys" + " ORDER BY esk_serial DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_signkey_revocations", + "SELECT" + " signkey_revocations_serial_id AS serial" + " FROM signkey_revocations" + " ORDER BY signkey_revocations_serial_id DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_known_coins", + "SELECT" + " known_coin_id AS serial" + " FROM known_coins" + " ORDER BY known_coin_id DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_refresh_commitments", + "SELECT" + " melt_serial_id AS serial" + " FROM refresh_commitments" + " ORDER BY melt_serial_id DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_refresh_revealed_coins", + "SELECT" + " rrc_serial AS serial" + " FROM refresh_revealed_coins" + " ORDER BY rrc_serial DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_refresh_transfer_keys", + "SELECT" + " rtc_serial AS serial" + " FROM refresh_transfer_keys" + " ORDER BY rtc_serial DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_deposits", + "SELECT" + " deposit_serial_id AS serial" + " FROM deposits" + " ORDER BY deposit_serial_id DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_refunds", + "SELECT" + " refund_serial_id AS serial" + " FROM refunds" + " ORDER BY refund_serial_id DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_wire_out", + "SELECT" + " wireout_uuid AS serial" + " FROM wire_out" + " ORDER BY wireout_uuid DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_aggregation_tracking", + "SELECT" + " aggregation_serial_id AS serial" + " FROM aggregation_tracking" + " ORDER BY aggregation_serial_id DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_wire_fee", + "SELECT" + " wire_fee_serial AS serial" + " FROM wire_fee" + " ORDER BY wire_fee_serial DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_recoup", + "SELECT" + " recoup_uuid AS serial" + " FROM recoup" + " ORDER BY recoup_uuid DESC" + " LIMIT 1;", + 0), + GNUNET_PQ_make_prepare ("select_serial_by_table_recoup_refresh", + "SELECT" + " recoup_refresh_uuid AS serial" + " FROM recoup_refresh" + " ORDER BY recoup_refresh_uuid DESC" + " LIMIT 1;", + 0), + /* For postgres_lookup_records_by_table */ + // FIXME... + /* For postgres_insert_records_by_table */ + // FIXME... GNUNET_PQ_PREPARED_STATEMENT_END }; @@ -8988,6 +9172,301 @@ postgres_lookup_wire_fee_by_time ( /** + * Lookup the latest serial number of @a table. Used in + * exchange-auditor database replication. + * + * @param cls closure + * @param session a session + * @param table table for which we should return the serial + * @param[out] latest serial number in use + * @return transaction status code, GNUNET_DB_STATUS_HARD_ERROR if + * @a table does not have a serial number + */ +static enum GNUNET_DB_QueryStatus +postgres_lookup_serial_by_table (void *cls, + struct TALER_EXCHANGEDB_Session *session, + enum TALER_EXCHANGEDB_ReplicatedTable table, + uint64_t *serial) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("serial", + serial), + GNUNET_PQ_result_spec_end + }; + const char *statement; + + switch (table) + { + case TALER_EXCHANGEDB_RT_DENOMINATIONS: + statement = "select_serial_by_table_denominations"; + break; + case TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS: + statement = "select_serial_by_table_denomination_revocations"; + break; + case TALER_EXCHANGEDB_RT_RESERVES: + statement = "select_serial_by_table_reserves"; + break; + case TALER_EXCHANGEDB_RT_RESERVES_IN: + statement = "select_serial_by_table_reserves_in"; + break; + case TALER_EXCHANGEDB_RT_RESERVES_CLOSE: + statement = "select_serial_by_table_reserves_close"; + break; + case TALER_EXCHANGEDB_RT_RESERVES_OUT: + statement = "select_serial_by_table_reserves_out"; + break; + case TALER_EXCHANGEDB_RT_AUDITORS: + statement = "select_serial_by_table_auditors"; + break; + case TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS: + statement = "select_serial_by_table_auditor_denom_sigs"; + break; + case TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS: + statement = "select_serial_by_table_exchange_sign_keys"; + break; + case TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS: + statement = "select_serial_by_table_signkey_revocations"; + break; + case TALER_EXCHANGEDB_RT_KNOWN_COINS: + statement = "select_serial_by_table_known_coins"; + break; + case TALER_EXCHANGEDB_RT_REFRESH_COMMITMENTS: + statement = "select_serial_by_table_refresh_commitments"; + break; + case TALER_EXCHANGEDB_RT_REFRESH_REVEALED_COINS: + statement = "select_serial_by_table_refresh_revealed_coins"; + break; + case TALER_EXCHANGEDB_RT_REFRESH_TRANSFER_KEYS: + statement = "select_serial_by_table_refresh_transfer_keys"; + break; + case TALER_EXCHANGEDB_RT_DEPOSITS: + statement = "select_serial_by_table_deposits"; + break; + case TALER_EXCHANGEDB_RT_REFUNDS: + statement = "select_serial_by_table_refunds"; + break; + case TALER_EXCHANGEDB_RT_WIRE_OUT: + statement = "select_serial_by_table_wire_out"; + break; + case TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING: + statement = "select_serial_by_table_aggregation_tracking"; + break; + case TALER_EXCHANGEDB_RT_WIRE_FEE: + statement = "select_serial_by_table_wire_fee"; + break; + case TALER_EXCHANGEDB_RT_RECOUP: + statement = "select_serial_by_table_recoup"; + break; + case TALER_EXCHANGEDB_RT_RECOUP_REFRESH: + statement = "select_serial_by_table_recoup_refresh"; + break; + default: + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + (void) cls; + return GNUNET_PQ_eval_prepared_singleton_select (session->conn, + statement, + params, + rs); +} + + +/** + * Closure for callbacks used by #postgres_lookup_records_by_table. + */ +struct LookupRecordsByTableContext +{ + /** + * Plugin context. + */ + struct PostgresClosure *pc; + + /** + * Function to call with the results. + */ + TALER_EXCHANGEDB_ReplicationCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Set to true on errors. + */ + bool error; +}; + + +#include "lrbt_callbacks.c" + + +/** + * Lookup records above @a serial number in @a table. Used in + * exchange-auditor database replication. + * + * @param cls closure + * @param session a session + * @param table table for which we should return the serial + * @param serial largest serial number to exclude + * @param cb function to call on the records + * @param cb_cls closure for @a cb + * @return transaction status code, GNUNET_DB_STATUS_HARD_ERROR if + * @a table does not have a serial number + */ +static enum GNUNET_DB_QueryStatus +postgres_lookup_records_by_table (void *cls, + struct TALER_EXCHANGEDB_Session *session, + enum TALER_EXCHANGEDB_ReplicatedTable table, + uint64_t serial, + TALER_EXCHANGEDB_ReplicationCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pc = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&serial), + GNUNET_PQ_query_param_end + }; + struct LookupRecordsByTableContext ctx = { + .pc = pc, + .cb = cb, + .cb_cls = cb_cls + }; + GNUNET_PQ_PostgresResultHandler rh; + const char *statement; + enum GNUNET_DB_QueryStatus qs; + + switch (table) + { + case TALER_EXCHANGEDB_RT_DENOMINATIONS: + statement = "select_above_serial_by_table_denominations"; + rh = &lrbt_cb_table_denominations; + break; + case TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS: + statement = "select_above_serial_by_table_denomination_revocations"; + rh = &lrbt_cb_table_denomination_revocations; + break; + case TALER_EXCHANGEDB_RT_RESERVES: + statement = "select_above_serial_by_table_reserves"; + rh = &lrbt_cb_table_reserves; + break; + case TALER_EXCHANGEDB_RT_RESERVES_IN: + statement = "select_above_serial_by_table_reserves_in"; + rh = &lrbt_cb_table_reserves_in; + break; + case TALER_EXCHANGEDB_RT_RESERVES_CLOSE: + statement = "select_above_serial_by_table_reserves_close"; + rh = &lrbt_cb_table_reserves_close; + break; + case TALER_EXCHANGEDB_RT_RESERVES_OUT: + statement = "select_above_serial_by_table_reserves_out"; + rh = &lrbt_cb_table_reserves_out; + break; + case TALER_EXCHANGEDB_RT_AUDITORS: + statement = "select_above_serial_by_table_auditors"; + rh = &lrbt_cb_table_auditors; + break; + case TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS: + statement = "select_above_serial_by_table_auditor_denom_sigs"; + rh = &lrbt_cb_table_auditor_denom_sigs; + break; + case TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS: + statement = "select_above_serial_by_table_exchange_sign_keys"; + rh = &lrbt_cb_table_exchange_sign_keys; + break; + case TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS: + statement = "select_above_serial_by_table_signkey_revocations"; + rh = &lrbt_cb_table_signkey_revocations; + break; + case TALER_EXCHANGEDB_RT_KNOWN_COINS: + statement = "select_above_serial_by_table_known_coins"; + rh = &lrbt_cb_table_known_coins; + break; + case TALER_EXCHANGEDB_RT_REFRESH_COMMITMENTS: + statement = "select_above_serial_by_table_refresh_commitments"; + rh = &lrbt_cb_table_refresh_commitments; + break; + case TALER_EXCHANGEDB_RT_REFRESH_REVEALED_COINS: + statement = "select_above_serial_by_table_refresh_revealed_coins"; + rh = &lrbt_cb_table_refresh_revealed_coins; + break; + case TALER_EXCHANGEDB_RT_REFRESH_TRANSFER_KEYS: + statement = "select_above_serial_by_table_refresh_transfer_keys"; + rh = &lrbt_cb_table_refresh_transfer_keys; + break; + case TALER_EXCHANGEDB_RT_DEPOSITS: + statement = "select_above_serial_by_table_deposits"; + rh = &lrbt_cb_table_deposits; + break; + case TALER_EXCHANGEDB_RT_REFUNDS: + statement = "select_above_serial_by_table_refunds"; + rh = &lrbt_cb_table_refunds; + break; + case TALER_EXCHANGEDB_RT_WIRE_OUT: + statement = "select_above_serial_by_table_wire_out"; + rh = &lrbt_cb_table_wire_out; + break; + case TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING: + statement = "select_above_serial_by_table_aggregation_tracking"; + rh = &lrbt_cb_table_aggregation_tracking; + break; + case TALER_EXCHANGEDB_RT_WIRE_FEE: + statement = "select_above_serial_by_table_wire_fee"; + rh = &lrbt_cb_table_wire_fee; + break; + case TALER_EXCHANGEDB_RT_RECOUP: + statement = "select_above_serial_by_table_recoup"; + rh = &lrbt_cb_table_recoup; + break; + case TALER_EXCHANGEDB_RT_RECOUP_REFRESH: + statement = "select_above_serial_by_table_recoup_refresh"; + rh = &lrbt_cb_table_recoup_refresh; + break; + default: + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + (void) cls; + qs = GNUNET_PQ_eval_prepared_multi_select (session->conn, + statement, + params, + rh, + &ctx); + if (qs < 0) + return qs; + if (ctx.error) + return GNUNET_DB_STATUS_HARD_ERROR; + return qs; +} + + +/** + * Insert record set into @a table. Used in exchange-auditor database + * replication. + * + * @param cls closure + * @param session a session + * @param tb table data to insert + * @return transaction status code, #GNUNET_DB_STATUS_HARD_ERROR if + * @a table does not have a serial number + */ +static enum GNUNET_DB_QueryStatus +postgres_insert_records_by_table (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_EXCHANGEDB_TableData *td) +{ + GNUNET_break (0); // FIXME: not implemented! + return GNUNET_DB_STATUS_HARD_ERROR; +} + + +/** * Initialize Postgres database subsystem. * * @param cls a configuration instance @@ -9185,6 +9664,12 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &postgres_activate_signing_key; plugin->lookup_signing_key = &postgres_lookup_signing_key; + plugin->lookup_serial_by_table + = &postgres_lookup_serial_by_table; + plugin->lookup_records_by_table + = &postgres_lookup_records_by_table; + plugin->insert_records_by_table + = &postgres_insert_records_by_table; return plugin; } |