/* 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 */ /** * @file plugin_exchangedb_postgres.c * @brief Low-level (statement-level) Postgres database access for the exchange * @author Florian Dold * @author Christian Grothoff * @author Sree Harsha Totakura * @author Marcello Stanisci */ #include "platform.h" #include "taler_error_codes.h" #include "taler_dbevents.h" #include "taler_pq_lib.h" #include "taler_util.h" #include "taler_json_lib.h" #include "taler_exchangedb_plugin.h" #include "plugin_exchangedb_common.h" #include "pg_delete_aggregation_transient.h" #include "pg_get_link_data.h" #include "pg_helper.h" #include "pg_do_reserve_open.h" #include "pg_do_withdraw.h" #include "pg_get_coin_transactions.h" #include "pg_get_expired_reserves.h" #include "pg_get_purse_request.h" #include "pg_get_reserve_history.h" #include "pg_get_unfinished_close_requests.h" #include "pg_insert_close_request.h" #include "pg_insert_records_by_table.h" #include "pg_insert_reserve_open_deposit.h" #include "pg_iterate_kyc_reference.h" #include "pg_iterate_reserve_close_info.h" #include "pg_lookup_records_by_table.h" #include "pg_lookup_serial_by_table.h" #include "pg_select_account_merges_above_serial_id.h" #include "pg_select_all_purse_decisions_above_serial_id.h" #include "pg_select_purse.h" #include "pg_select_purse_deposits_above_serial_id.h" #include "pg_select_purse_merges_above_serial_id.h" #include "pg_select_purse_requests_above_serial_id.h" #include "pg_select_reserve_close_info.h" #include "pg_select_reserve_closed_above_serial_id.h" #include "pg_select_reserve_open_above_serial_id.h" #include #include #include /**WHAT I ADD**/ #include "pg_insert_purse_request.h" #include "pg_iterate_active_signkeys.h" #include "pg_preflight.h" #include "pg_commit.h" #include "pg_insert_aggregation_tracking.h" #include "pg_drop_tables.h" #include "pg_select_satisfied_kyc_processes.h" #include "pg_select_aggregation_amounts_for_kyc_check.h" #include "pg_kyc_provider_account_lookup.h" #include "pg_lookup_kyc_requirement_by_row.h" #include "pg_insert_kyc_requirement_for_account.h" #include "pg_lookup_kyc_process_by_account.h" #include "pg_update_kyc_process_by_row.h" #include "pg_insert_kyc_requirement_process.h" #include "pg_select_withdraw_amounts_for_kyc_check.h" #include "pg_select_merge_amounts_for_kyc_check.h" #include "pg_profit_drains_set_finished.h" #include "pg_profit_drains_get_pending.h" #include "pg_get_drain_profit.h" #include "pg_get_purse_deposit.h" #include "pg_insert_contract.h" #include "pg_select_contract.h" #include "pg_select_purse_merge.h" #include "pg_select_contract_by_purse.h" #include "pg_insert_drain_profit.h" #include "pg_do_reserve_purse.h" #include "pg_lookup_global_fee_by_time.h" #include "pg_do_purse_deposit.h" #include "pg_activate_signing_key.h" #include "pg_update_auditor.h" #include "pg_begin_revolving_shard.h" #include "pg_get_extension_manifest.h" #include "pg_insert_history_request.h" #include "pg_do_purse_merge.h" #include "pg_start_read_committed.h" #include "pg_start_read_only.h" #include "pg_insert_denomination_info.h" #include "pg_do_batch_withdraw_insert.h" #include "pg_lookup_wire_fee_by_time.h" #include "pg_start.h" #include "pg_rollback.h" #include "pg_create_tables.h" #include "pg_event_listen.h" #include "pg_event_listen_cancel.h" #include "pg_event_notify.h" #include "pg_get_denomination_info.h" #include "pg_iterate_denomination_info.h" #include "pg_iterate_denominations.h" #include "pg_iterate_active_auditors.h" #include "pg_iterate_auditor_denominations.h" #include "pg_reserves_get.h" #include "pg_reserves_get_origin.h" #include "pg_drain_kyc_alert.h" #include "pg_reserves_in_insert.h" #include "pg_get_withdraw_info.h" #include "pg_do_batch_withdraw.h" #include "pg_get_policy_details.h" #include "pg_persist_policy_details.h" #include "pg_do_deposit.h" #include "pg_add_policy_fulfillment_proof.h" #include "pg_do_melt.h" #include "pg_do_refund.h" #include "pg_do_recoup.h" #include "pg_do_recoup_refresh.h" #include "pg_get_reserve_balance.h" #include "pg_count_known_coins.h" #include "pg_ensure_coin_known.h" #include "pg_get_known_coin.h" #include "pg_get_coin_denomination.h" #include "pg_have_deposit2.h" #include "pg_aggregate.h" #include "pg_create_aggregation_transient.h" #include "pg_select_aggregation_transient.h" #include "pg_find_aggregation_transient.h" #include "pg_update_aggregation_transient.h" #include "pg_get_ready_deposit.h" #include "pg_insert_deposit.h" #include "pg_insert_refund.h" #include "pg_select_refunds_by_coin.h" #include "pg_get_melt.h" #include "pg_insert_refresh_reveal.h" #include "pg_get_refresh_reveal.h" #include "pg_lookup_wire_transfer.h" #include "pg_lookup_transfer_by_deposit.h" #include "pg_insert_wire_fee.h" #include "pg_insert_global_fee.h" #include "pg_get_wire_fee.h" #include "pg_get_global_fee.h" #include "pg_get_global_fees.h" #include "pg_insert_reserve_closed.h" #include "pg_wire_prepare_data_insert.h" #include "pg_wire_prepare_data_mark_finished.h" #include "pg_wire_prepare_data_mark_failed.h" #include "pg_wire_prepare_data_get.h" #include "pg_start_deferred_wire_out.h" #include "pg_store_wire_transfer_out.h" #include "pg_gc.h" #include "pg_select_deposits_above_serial_id.h" #include "pg_select_history_requests_above_serial_id.h" #include "pg_select_purse_decisions_above_serial_id.h" #include "pg_select_purse_deposits_by_purse.h" #include "pg_select_refreshes_above_serial_id.h" #include "pg_select_refunds_above_serial_id.h" #include "pg_select_reserves_in_above_serial_id.h" #include "pg_select_reserves_in_above_serial_id_by_account.h" #include "pg_select_withdrawals_above_serial_id.h" #include "pg_select_wire_out_above_serial_id.h" #include "pg_select_wire_out_above_serial_id_by_account.h" #include "pg_select_recoup_above_serial_id.h" #include "pg_select_recoup_refresh_above_serial_id.h" #include "pg_get_reserve_by_h_blind.h" #include "pg_get_old_coin_by_h_blind.h" #include "pg_insert_denomination_revocation.h" #include "pg_get_denomination_revocation.h" #include "pg_select_deposits_missing_wire.h" #include "pg_lookup_auditor_timestamp.h" #include "pg_lookup_auditor_status.h" #include "pg_insert_auditor.h" #include "pg_lookup_wire_timestamp.h" #include "pg_insert_wire.h" #include "pg_update_wire.h" #include "pg_get_wire_accounts.h" #include "pg_get_wire_fees.h" #include "pg_insert_signkey_revocation.h" #include "pg_lookup_signkey_revocation.h" #include "pg_lookup_denomination_key.h" #include "pg_insert_auditor_denom_sig.h" #include "pg_select_auditor_denom_sig.h" #include "pg_add_denomination_key.h" #include "pg_lookup_signing_key.h" #include "pg_begin_shard.h" #include "pg_abort_shard.h" #include "pg_complete_shard.h" #include "pg_release_revolving_shard.h" #include "pg_delete_shard_locks.h" #include "pg_set_extension_manifest.h" #include "pg_insert_partner.h" #include "pg_expire_purse.h" #include "pg_select_purse_by_merge_pub.h" #include "pg_set_purse_balance.h" #include "pg_reserves_update.h" #include "pg_setup_wire_target.h" #include "pg_compute_shard.h" #include "pg_batch_reserves_in_insert.h" #include "pg_batch2_reserves_in_insert.h" /** * Set to 1 to enable Postgres auto_explain module. This will * slow down things a _lot_, but also provide extensive logging * in the Postgres database logger for performance analysis. */ #define AUTO_EXPLAIN 1 /** * Log a really unexpected PQ error with all the details we can get hold of. * * @param result PQ result object of the PQ operation that failed * @param conn SQL connection that was used */ #define BREAK_DB_ERR(result,conn) do { \ GNUNET_break (0); \ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \ "Database failure: %s/%s/%s/%s/%s", \ PQresultErrorField (result, PG_DIAG_MESSAGE_PRIMARY), \ PQresultErrorField (result, PG_DIAG_MESSAGE_DETAIL), \ PQresultErrorMessage (result), \ PQresStatus (PQresultStatus (result)), \ PQerrorMessage (conn)); \ } while (0) /** * Initialize prepared statements for @a pg. * * @param[in,out] pg connection to initialize * @return #GNUNET_OK on success */ enum GNUNET_GenericReturnValue prepare_statements (struct PostgresClosure *pg) { enum GNUNET_GenericReturnValue ret; struct GNUNET_PQ_PreparedStatement ps[] = { GNUNET_PQ_make_prepare ( "get_kyc_h_payto", "SELECT" " wire_target_h_payto" " FROM wire_targets" " WHERE wire_target_h_payto=$1" " LIMIT 1;"), /* Used in #postgres_ensure_coin_known() */ GNUNET_PQ_make_prepare ( "get_known_coin_dh", "SELECT" " denominations.denom_pub_hash" " FROM known_coins" " JOIN denominations USING (denominations_serial)" " WHERE coin_pub=$1;"), /* Store information about the desired denominations for a refresh operation, used in #postgres_insert_refresh_reveal() */ GNUNET_PQ_make_prepare ( "insert_refresh_revealed_coin", "INSERT INTO refresh_revealed_coins " "(melt_serial_id " ",freshcoin_index " ",link_sig " ",denominations_serial " ",coin_ev" ",ewv" ",h_coin_ev" ",ev_sig" ") SELECT $1, $2, $3, " " denominations_serial, $5, $6, $7, $8" " FROM denominations" " WHERE denom_pub_hash=$4" " ON CONFLICT DO NOTHING;"), GNUNET_PQ_make_prepare ( "test_refund_full", "SELECT" " CAST(SUM(CAST(ref.amount_with_fee_frac AS INT8)) AS INT8) AS s_f" ",CAST(SUM(ref.amount_with_fee_val) AS INT8) AS s_v" ",dep.amount_with_fee_val" ",dep.amount_with_fee_frac" " FROM refunds ref" " JOIN deposits dep" " ON (ref.coin_pub=dep.coin_pub AND ref.deposit_serial_id=dep.deposit_serial_id)" " WHERE ref.refund_serial_id=$1" " GROUP BY (dep.amount_with_fee_val, dep.amount_with_fee_frac);"), /* Used in #postgres_update_kyc_requirement_by_row() */ GNUNET_PQ_make_prepare ( "update_legitimization_process", "UPDATE legitimization_processes" " SET provider_user_id=$4" " ,provider_legitimization_id=$5" " ,expiration_time=GREATEST(expiration_time,$6)" " WHERE" " h_payto=$3" " AND legitimization_process_serial_id=$1" " AND provider_section=$2;"), GNUNET_PQ_PREPARED_STATEMENT_END }; ret = GNUNET_PQ_prepare_statements (pg->conn, ps); if (GNUNET_OK != ret) return ret; pg->init = true; return GNUNET_OK; } /** * Connect to the database if the connection does not exist yet. * * @param pg the plugin-specific state * @param skip_prepare true if we should skip prepared statement setup * @return #GNUNET_OK on success */ enum GNUNET_GenericReturnValue TEH_PG_internal_setup (struct PostgresClosure *pg, bool skip_prepare) { if (NULL == pg->conn) { #if AUTO_EXPLAIN /* Enable verbose logging to see where queries do not properly use indices */ struct GNUNET_PQ_ExecuteStatement es[] = { GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"), GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"), GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"), GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"), /* https://wiki.postgresql.org/wiki/Serializable suggests to really force the default to 'serializable' if SSI is to be used. */ GNUNET_PQ_make_try_execute ( "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"), GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"), GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"), GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"), GNUNET_PQ_EXECUTE_STATEMENT_END }; #else struct GNUNET_PQ_ExecuteStatement es[] = { GNUNET_PQ_make_try_execute ( "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"), GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"), GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"), GNUNET_PQ_make_try_execute ("SET autocommit=OFF;"), GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"), GNUNET_PQ_EXECUTE_STATEMENT_END }; #endif struct GNUNET_PQ_Context *db_conn; db_conn = GNUNET_PQ_connect_with_cfg (pg->cfg, "exchangedb-postgres", NULL, es, NULL); if (NULL == db_conn) return GNUNET_SYSERR; pg->prep_gen++; pg->conn = db_conn; } if (NULL == pg->transaction_name) GNUNET_PQ_reconnect_if_down (pg->conn); if (pg->init) return GNUNET_OK; if (skip_prepare) return GNUNET_OK; return prepare_statements (pg); } /** * Initialize Postgres database subsystem. * * @param cls a configuration instance * @return NULL on error, otherwise a `struct * TALER_EXCHANGEDB_Plugin` */ void * libtaler_plugin_exchangedb_postgres_init (void *cls) { const struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct PostgresClosure *pg; struct TALER_EXCHANGEDB_Plugin *plugin; unsigned long long dpl; pg = GNUNET_new (struct PostgresClosure); pg->cfg = cfg; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "exchangedb-postgres", "SQL_DIR", &pg->sql_dir)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "exchangedb-postgres", "CONFIG"); GNUNET_free (pg); return NULL; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "exchange", "BASE_URL", &pg->exchange_url)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "exchange", "BASE_URL"); GNUNET_free (pg->sql_dir); GNUNET_free (pg); return NULL; } if ( (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "exchangedb", "IDLE_RESERVE_EXPIRATION_TIME", &pg->idle_reserve_expiration_time)) || (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "exchangedb", "LEGAL_RESERVE_EXPIRATION_TIME", &pg->legal_reserve_expiration_time)) ) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "exchangedb", "LEGAL/IDLE_RESERVE_EXPIRATION_TIME"); GNUNET_free (pg->exchange_url); GNUNET_free (pg->sql_dir); GNUNET_free (pg); return NULL; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "exchangedb", "AGGREGATOR_SHIFT", &pg->aggregator_shift)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, "exchangedb", "AGGREGATOR_SHIFT"); } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "exchangedb", "DEFAULT_PURSE_LIMIT", &dpl)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, "exchangedb", "DEFAULT_PURSE_LIMIT"); pg->def_purse_limit = 1; } else { pg->def_purse_limit = (uint32_t) dpl; } if (GNUNET_OK != TALER_config_get_currency (cfg, &pg->currency)) { GNUNET_free (pg->exchange_url); GNUNET_free (pg->sql_dir); GNUNET_free (pg); return NULL; } if (GNUNET_OK != TEH_PG_internal_setup (pg, true)) { GNUNET_free (pg->exchange_url); GNUNET_free (pg->currency); GNUNET_free (pg->sql_dir); GNUNET_free (pg); return NULL; } plugin = GNUNET_new (struct TALER_EXCHANGEDB_Plugin); plugin->cls = pg; plugin->get_policy_details = &postgres_get_policy_details; plugin->add_policy_fulfillment_proof = &postgres_add_policy_fulfillment_proof; plugin->do_melt = &postgres_do_melt; plugin->do_refund = &postgres_do_refund; plugin->do_recoup = &postgres_do_recoup; plugin->do_recoup_refresh = &postgres_do_recoup_refresh; plugin->get_reserve_balance = &postgres_get_reserve_balance; plugin->count_known_coins = &postgres_count_known_coins; plugin->ensure_coin_known = &postgres_ensure_coin_known; plugin->get_known_coin = &postgres_get_known_coin; plugin->get_coin_denomination = &postgres_get_coin_denomination; plugin->have_deposit2 = &postgres_have_deposit2; plugin->aggregate = &postgres_aggregate; plugin->create_aggregation_transient = &postgres_create_aggregation_transient; plugin->select_aggregation_transient = &postgres_select_aggregation_transient; plugin->find_aggregation_transient = &postgres_find_aggregation_transient; plugin->update_aggregation_transient = &postgres_update_aggregation_transient; plugin->get_ready_deposit = &postgres_get_ready_deposit; plugin->insert_deposit = &postgres_insert_deposit; plugin->insert_refund = &postgres_insert_refund; plugin->select_refunds_by_coin = &postgres_select_refunds_by_coin; plugin->get_melt = &postgres_get_melt; plugin->insert_refresh_reveal = &postgres_insert_refresh_reveal; plugin->get_refresh_reveal = &postgres_get_refresh_reveal; plugin->lookup_wire_transfer = &postgres_lookup_wire_transfer; plugin->lookup_transfer_by_deposit = &postgres_lookup_transfer_by_deposit; plugin->insert_wire_fee = &postgres_insert_wire_fee; plugin->insert_global_fee = &postgres_insert_global_fee; plugin->get_wire_fee = &postgres_get_wire_fee; plugin->get_global_fee = &postgres_get_global_fee; plugin->get_global_fees = &postgres_get_global_fees; plugin->insert_reserve_closed = &postgres_insert_reserve_closed; plugin->wire_prepare_data_insert = &postgres_wire_prepare_data_insert; plugin->wire_prepare_data_mark_finished = &postgres_wire_prepare_data_mark_finished; plugin->wire_prepare_data_mark_failed = &postgres_wire_prepare_data_mark_failed; plugin->wire_prepare_data_get = &postgres_wire_prepare_data_get; plugin->start_deferred_wire_out = &postgres_start_deferred_wire_out; plugin->store_wire_transfer_out = &postgres_store_wire_transfer_out; plugin->gc = &postgres_gc; plugin->select_deposits_above_serial_id = &postgres_select_deposits_above_serial_id; plugin->select_history_requests_above_serial_id = &postgres_select_history_requests_above_serial_id; plugin->select_purse_decisions_above_serial_id = &postgres_select_purse_decisions_above_serial_id; plugin->select_purse_deposits_by_purse = &postgres_select_purse_deposits_by_purse; plugin->select_refreshes_above_serial_id = &postgres_select_refreshes_above_serial_id; plugin->select_refunds_above_serial_id = &postgres_select_refunds_above_serial_id; plugin->select_reserves_in_above_serial_id = &postgres_select_reserves_in_above_serial_id; plugin->select_reserves_in_above_serial_id_by_account = &postgres_select_reserves_in_above_serial_id_by_account; plugin->select_withdrawals_above_serial_id = &postgres_select_withdrawals_above_serial_id; plugin->select_wire_out_above_serial_id = &postgres_select_wire_out_above_serial_id; plugin->select_wire_out_above_serial_id_by_account = &postgres_select_wire_out_above_serial_id_by_account; plugin->select_recoup_above_serial_id = &postgres_select_recoup_above_serial_id; plugin->select_recoup_refresh_above_serial_id = &postgres_select_recoup_refresh_above_serial_id; plugin->get_reserve_by_h_blind = &postgres_get_reserve_by_h_blind; /* New style, sort alphabetically! */ plugin->do_reserve_open = &TEH_PG_do_reserve_open; plugin->drop_tables = &TEH_PG_drop_tables; plugin->do_withdraw = &TEH_PG_do_withdraw; plugin->free_coin_transaction_list = &TEH_COMMON_free_coin_transaction_list; plugin->free_reserve_history = &TEH_COMMON_free_reserve_history; plugin->get_coin_transactions = &TEH_PG_get_coin_transactions; plugin->get_expired_reserves = &TEH_PG_get_expired_reserves; plugin->get_purse_request = &TEH_PG_get_purse_request; plugin->get_reserve_history = &TEH_PG_get_reserve_history; plugin->get_reserve_status = &TEH_PG_get_reserve_status; plugin->get_unfinished_close_requests = &TEH_PG_get_unfinished_close_requests; plugin->insert_records_by_table = &TEH_PG_insert_records_by_table; plugin->insert_reserve_open_deposit = &TEH_PG_insert_reserve_open_deposit; plugin->insert_close_request = &TEH_PG_insert_close_request; plugin->delete_aggregation_transient = &TEH_PG_delete_aggregation_transient; plugin->get_link_data = &TEH_PG_get_link_data; plugin->iterate_reserve_close_info = &TEH_PG_iterate_reserve_close_info; plugin->iterate_kyc_reference = &TEH_PG_iterate_kyc_reference; plugin->lookup_records_by_table = &TEH_PG_lookup_records_by_table; plugin->lookup_serial_by_table = &TEH_PG_lookup_serial_by_table; plugin->select_account_merges_above_serial_id = &TEH_PG_select_account_merges_above_serial_id; plugin->select_all_purse_decisions_above_serial_id = &TEH_PG_select_all_purse_decisions_above_serial_id; plugin->select_purse = &TEH_PG_select_purse; plugin->select_purse_deposits_above_serial_id = &TEH_PG_select_purse_deposits_above_serial_id; plugin->select_purse_merges_above_serial_id = &TEH_PG_select_purse_merges_above_serial_id; plugin->select_purse_requests_above_serial_id = &TEH_PG_select_purse_requests_above_serial_id; plugin->select_reserve_close_info = &TEH_PG_select_reserve_close_info; plugin->select_reserve_closed_above_serial_id = &TEH_PG_select_reserve_closed_above_serial_id; plugin->select_reserve_open_above_serial_id = &TEH_PG_select_reserve_open_above_serial_id; /*need to sort*/ plugin->insert_purse_request = &TEH_PG_insert_purse_request; plugin->iterate_active_signkeys = &TEH_PG_iterate_active_signkeys; plugin->commit = &TEH_PG_commit; plugin->preflight = &TEH_PG_preflight; plugin->insert_aggregation_tracking = &TEH_PG_insert_aggregation_tracking; plugin->select_aggregation_amounts_for_kyc_check = &TEH_PG_select_aggregation_amounts_for_kyc_check; plugin->select_satisfied_kyc_processes = &TEH_PG_select_satisfied_kyc_processes; plugin->kyc_provider_account_lookup = &TEH_PG_kyc_provider_account_lookup; plugin->lookup_kyc_requirement_by_row = &TEH_PG_lookup_kyc_requirement_by_row; plugin->insert_kyc_requirement_for_account = &TEH_PG_insert_kyc_requirement_for_account; plugin->lookup_kyc_process_by_account = &TEH_PG_lookup_kyc_process_by_account; plugin->update_kyc_process_by_row = &TEH_PG_update_kyc_process_by_row; plugin->insert_kyc_requirement_process = &TEH_PG_insert_kyc_requirement_process; plugin->select_withdraw_amounts_for_kyc_check = &TEH_PG_select_withdraw_amounts_for_kyc_check; plugin->select_merge_amounts_for_kyc_check = &TEH_PG_select_merge_amounts_for_kyc_check; plugin->profit_drains_set_finished = &TEH_PG_profit_drains_set_finished; plugin->profit_drains_get_pending = &TEH_PG_profit_drains_get_pending; plugin->get_drain_profit = &TEH_PG_get_drain_profit; plugin->get_purse_deposit = &TEH_PG_get_purse_deposit; plugin->insert_contract = &TEH_PG_insert_contract; plugin->select_contract = &TEH_PG_select_contract; plugin->select_purse_merge = &TEH_PG_select_purse_merge; plugin->select_contract_by_purse = &TEH_PG_select_contract_by_purse; plugin->insert_drain_profit = &TEH_PG_insert_drain_profit; plugin->do_reserve_purse = &TEH_PG_do_reserve_purse; plugin->lookup_global_fee_by_time = &TEH_PG_lookup_global_fee_by_time; plugin->do_purse_deposit = &TEH_PG_do_purse_deposit; plugin->activate_signing_key = &TEH_PG_activate_signing_key; plugin->update_auditor = &TEH_PG_update_auditor; plugin->begin_revolving_shard = &TEH_PG_begin_revolving_shard; plugin->get_extension_manifest = &TEH_PG_get_extension_manifest; plugin->insert_history_request = &TEH_PG_insert_history_request; plugin->do_purse_merge = &TEH_PG_do_purse_merge; plugin->start_read_committed = &TEH_PG_start_read_committed; plugin->start_read_only = &TEH_PG_start_read_only; plugin->insert_denomination_info = &TEH_PG_insert_denomination_info; plugin->do_batch_withdraw_insert = &TEH_PG_do_batch_withdraw_insert; plugin->lookup_wire_fee_by_time = &TEH_PG_lookup_wire_fee_by_time; plugin->start = &TEH_PG_start; plugin->rollback = &TEH_PG_rollback; plugin->create_tables = &TEH_PG_create_tables; plugin->event_listen = &TEH_PG_event_listen; plugin->event_listen_cancel = &TEH_PG_event_listen_cancel; plugin->event_notify = &TEH_PG_event_notify; plugin->get_denomination_info = &TEH_PG_get_denomination_info; plugin->iterate_denomination_info = &TEH_PG_iterate_denomination_info; plugin->iterate_denominations = &TEH_PG_iterate_denominations; plugin->iterate_active_auditors = &TEH_PG_iterate_active_auditors; plugin->iterate_auditor_denominations = &TEH_PG_iterate_auditor_denominations; plugin->reserves_get = &TEH_PG_reserves_get; plugin->reserves_get_origin = &TEH_PG_reserves_get_origin; plugin->drain_kyc_alert = &TEH_PG_drain_kyc_alert; plugin->reserves_in_insert = &TEH_PG_reserves_in_insert; plugin->get_withdraw_info = &TEH_PG_get_withdraw_info; plugin->do_batch_withdraw = &TEH_PG_do_batch_withdraw; plugin->get_policy_details = &TEH_PG_get_policy_details; plugin->persist_policy_details = &TEH_PG_persist_policy_details; plugin->do_deposit = &TEH_PG_do_deposit; plugin->add_policy_fulfillment_proof = &TEH_PG_add_policy_fulfillment_proof; plugin->do_melt = &TEH_PG_do_melt; plugin->do_refund = &TEH_PG_do_refund; plugin->do_recoup = &TEH_PG_do_recoup; plugin->do_recoup_refresh = &TEH_PG_do_recoup_refresh; plugin->get_reserve_balance = &TEH_PG_get_reserve_balance; plugin->count_known_coins = &TEH_PG_count_known_coins; plugin->ensure_coin_known = &TEH_PG_ensure_coin_known; plugin->get_known_coin = &TEH_PG_get_known_coin; plugin->get_coin_denomination = &TEH_PG_get_coin_denomination; plugin->have_deposit2 = &TEH_PG_have_deposit2; plugin->aggregate = &TEH_PG_aggregate; plugin->create_aggregation_transient = &TEH_PG_create_aggregation_transient; plugin->select_aggregation_transient = &TEH_PG_select_aggregation_transient; plugin->find_aggregation_transient = &TEH_PG_find_aggregation_transient; plugin->update_aggregation_transient = &TEH_PG_update_aggregation_transient; plugin->get_ready_deposit = &TEH_PG_get_ready_deposit; plugin->insert_deposit = &TEH_PG_insert_deposit; plugin->insert_refund = &TEH_PG_insert_refund; plugin->select_refunds_by_coin = &TEH_PG_select_refunds_by_coin; plugin->get_melt = &TEH_PG_get_melt; plugin->insert_refresh_reveal = &TEH_PG_insert_refresh_reveal; plugin->get_refresh_reveal = &TEH_PG_get_refresh_reveal; plugin->lookup_wire_transfer = &TEH_PG_lookup_wire_transfer; plugin->lookup_transfer_by_deposit = &TEH_PG_lookup_transfer_by_deposit; plugin->insert_wire_fee = &TEH_PG_insert_wire_fee; plugin->insert_global_fee = &TEH_PG_insert_global_fee; plugin->get_wire_fee = &TEH_PG_get_wire_fee; plugin->get_global_fee = &TEH_PG_get_global_fee; plugin->get_global_fees = &TEH_PG_get_global_fees; plugin->insert_reserve_closed = &TEH_PG_insert_reserve_closed; plugin->wire_prepare_data_insert = &TEH_PG_wire_prepare_data_insert; plugin->wire_prepare_data_mark_finished = &TEH_PG_wire_prepare_data_mark_finished; plugin->wire_prepare_data_mark_failed = &TEH_PG_wire_prepare_data_mark_failed; plugin->wire_prepare_data_get = &TEH_PG_wire_prepare_data_get; plugin->start_deferred_wire_out = &TEH_PG_start_deferred_wire_out; plugin->store_wire_transfer_out = &TEH_PG_store_wire_transfer_out; plugin->gc = &TEH_PG_gc; plugin->select_deposits_above_serial_id = &TEH_PG_select_deposits_above_serial_id; plugin->select_history_requests_above_serial_id = &TEH_PG_select_history_requests_above_serial_id; plugin->select_purse_decisions_above_serial_id = &TEH_PG_select_purse_decisions_above_serial_id; plugin->select_purse_deposits_by_purse = &TEH_PG_select_purse_deposits_by_purse; plugin->select_refreshes_above_serial_id = &TEH_PG_select_refreshes_above_serial_id; plugin->select_refunds_above_serial_id = &TEH_PG_select_refunds_above_serial_id; plugin->select_reserves_in_above_serial_id = &TEH_PG_select_reserves_in_above_serial_id; plugin->select_reserves_in_above_serial_id_by_account = &TEH_PG_select_reserves_in_above_serial_id_by_account; plugin->select_withdrawals_above_serial_id = &TEH_PG_select_withdrawals_above_serial_id; plugin->select_wire_out_above_serial_id = &TEH_PG_select_wire_out_above_serial_id; plugin->select_wire_out_above_serial_id_by_account = &TEH_PG_select_wire_out_above_serial_id_by_account; plugin->select_recoup_above_serial_id = &TEH_PG_select_recoup_above_serial_id; plugin->select_recoup_refresh_above_serial_id = &TEH_PG_select_recoup_refresh_above_serial_id; plugin->get_reserve_by_h_blind = &TEH_PG_get_reserve_by_h_blind; plugin->get_old_coin_by_h_blind = &TEH_PG_get_old_coin_by_h_blind; plugin->insert_denomination_revocation = &TEH_PG_insert_denomination_revocation; plugin->get_denomination_revocation = &TEH_PG_get_denomination_revocation; plugin->select_deposits_missing_wire = &TEH_PG_select_deposits_missing_wire; plugin->lookup_auditor_timestamp = &TEH_PG_lookup_auditor_timestamp; plugin->lookup_auditor_status = &TEH_PG_lookup_auditor_status; plugin->insert_auditor = &TEH_PG_insert_auditor; plugin->lookup_wire_timestamp = &TEH_PG_lookup_wire_timestamp; plugin->insert_wire = &TEH_PG_insert_wire; plugin->update_wire = &TEH_PG_update_wire; plugin->get_wire_accounts = &TEH_PG_get_wire_accounts; plugin->get_wire_fees = &TEH_PG_get_wire_fees; plugin->insert_signkey_revocation = &TEH_PG_insert_signkey_revocation; plugin->lookup_signkey_revocation = &TEH_PG_lookup_signkey_revocation; plugin->lookup_denomination_key = &TEH_PG_lookup_denomination_key; plugin->insert_auditor_denom_sig = &TEH_PG_insert_auditor_denom_sig; plugin->select_auditor_denom_sig = &TEH_PG_select_auditor_denom_sig; plugin->add_denomination_key = &TEH_PG_add_denomination_key; plugin->lookup_signing_key = &TEH_PG_lookup_signing_key; plugin->begin_shard = &TEH_PG_begin_shard; plugin->abort_shard = &TEH_PG_abort_shard; plugin->complete_shard = &TEH_PG_complete_shard; plugin->release_revolving_shard = &TEH_PG_release_revolving_shard; plugin->delete_shard_locks = &TEH_PG_delete_shard_locks; plugin->set_extension_manifest = &TEH_PG_set_extension_manifest; plugin->insert_partner = &TEH_PG_insert_partner; plugin->expire_purse = &TEH_PG_expire_purse; plugin->select_purse_by_merge_pub = &TEH_PG_select_purse_by_merge_pub; plugin->set_purse_balance = &TEH_PG_set_purse_balance; plugin->batch_reserves_in_insert = &TEH_PG_batch_reserves_in_insert; plugin->batch2_reserves_in_insert = &TEH_PG_batch2_reserves_in_insert; return plugin; } /** * Shutdown Postgres database subsystem. * * @param cls a `struct TALER_EXCHANGEDB_Plugin` * @return NULL (always) */ void * libtaler_plugin_exchangedb_postgres_done (void *cls) { struct TALER_EXCHANGEDB_Plugin *plugin = cls; struct PostgresClosure *pg = plugin->cls; if (NULL != pg->conn) { GNUNET_PQ_disconnect (pg->conn); pg->conn = NULL; } GNUNET_free (pg->exchange_url); GNUNET_free (pg->sql_dir); GNUNET_free (pg->currency); GNUNET_free (pg); GNUNET_free (plugin); return NULL; } /* end of plugin_exchangedb_postgres.c */