summaryrefslogtreecommitdiff
path: root/src/backenddb/plugin_merchantdb_postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backenddb/plugin_merchantdb_postgres.c')
-rw-r--r--src/backenddb/plugin_merchantdb_postgres.c10787
1 files changed, 350 insertions, 10437 deletions
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c
index 823ad819..e5f3f2a1 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2014--2023 Taler Systems SA
+ (C) 2014--2024 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@@ -20,6 +20,7 @@
* @author Christian Grothoff
* @author Marcello Stanisci
* @author Priscilla Huang
+ * @author Iván Ávalos
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
@@ -29,6 +30,117 @@
#include <taler/taler_json_lib.h>
#include <taler/taler_mhd_lib.h>
#include "taler_merchantdb_plugin.h"
+#include "pg_helper.h"
+#include "pg_insert_otp.h"
+#include "pg_delete_otp.h"
+#include "pg_update_otp.h"
+#include "pg_select_otp.h"
+#include "pg_select_otp_serial.h"
+#include "pg_insert_login_token.h"
+#include "pg_delete_login_token.h"
+#include "pg_select_login_token.h"
+#include "pg_insert_account.h"
+#include "pg_update_account.h"
+#include "pg_lookup_instances.h"
+#include "pg_lookup_transfers.h"
+#include "pg_lookup_pending_deposits.h"
+#include "pg_update_wirewatch_progress.h"
+#include "pg_select_wirewatch_accounts.h"
+#include "pg_select_open_transfers.h"
+#include "pg_delete_exchange_accounts.h"
+#include "pg_select_accounts_by_exchange.h"
+#include "pg_insert_exchange_account.h"
+#include "pg_lookup_instance_auth.h"
+#include "pg_lookup_otp_devices.h"
+#include "pg_update_transfer_status.h"
+#include "pg_insert_instance.h"
+#include "pg_account_kyc_set_status.h"
+#include "pg_account_kyc_get_status.h"
+#include "pg_delete_instance_private_key.h"
+#include "pg_purge_instance.h"
+#include "pg_update_instance.h"
+#include "pg_update_instance_auth.h"
+#include "pg_inactivate_account.h"
+#include "pg_activate_account.h"
+#include "pg_lookup_products.h"
+#include "pg_lookup_product.h"
+#include "pg_delete_product.h"
+#include "pg_insert_product.h"
+#include "pg_update_product.h"
+#include "pg_lock_product.h"
+#include "pg_expire_locks.h"
+#include "pg_delete_order.h"
+#include "pg_lookup_order.h"
+#include "pg_lookup_order_summary.h"
+#include "pg_lookup_orders.h"
+#include "pg_insert_order.h"
+#include "pg_unlock_inventory.h"
+#include "pg_insert_order_lock.h"
+#include "pg_lookup_contract_terms3.h"
+#include "pg_lookup_contract_terms2.h"
+#include "pg_lookup_contract_terms.h"
+#include "pg_insert_contract_terms.h"
+#include "pg_update_contract_terms.h"
+#include "pg_delete_contract_terms.h"
+#include "pg_delete_template.h"
+#include "pg_insert_template.h"
+#include "pg_update_template.h"
+#include "pg_lookup_templates.h"
+#include "pg_lookup_template.h"
+#include "pg_lookup_deposits.h"
+#include "pg_insert_exchange_signkey.h"
+#include "pg_insert_deposit.h"
+#include "pg_insert_deposit_confirmation.h"
+#include "pg_lookup_refunds.h"
+#include "pg_mark_contract_paid.h"
+#include "pg_select_account_by_uri.h"
+#include "pg_refund_coin.h"
+#include "pg_lookup_order_status.h"
+#include "pg_lookup_order_status_by_serial.h"
+#include "pg_lookup_deposits_by_order.h"
+#include "pg_lookup_transfer_details_by_order.h"
+#include "pg_mark_order_wired.h"
+#include "pg_lookup_refunds_detailed.h"
+#include "pg_insert_refund_proof.h"
+#include "pg_lookup_refund_proof.h"
+#include "pg_lookup_order_by_fulfillment.h"
+#include "pg_delete_transfer.h"
+#include "pg_check_transfer_exists.h"
+#include "pg_lookup_account.h"
+#include "pg_lookup_wire_fee.h"
+#include "pg_lookup_deposits_by_contract_and_coin.h"
+#include "pg_lookup_transfer.h"
+#include "pg_lookup_transfer_summary.h"
+#include "pg_lookup_transfer_details.h"
+#include "pg_lookup_webhooks.h"
+#include "pg_lookup_webhook.h"
+#include "pg_delete_webhook.h"
+#include "pg_insert_webhook.h"
+#include "pg_update_webhook.h"
+#include "pg_lookup_webhook_by_event.h"
+#include "pg_delete_pending_webhook.h"
+#include "pg_insert_pending_webhook.h"
+#include "pg_update_pending_webhook.h"
+#include "pg_lookup_pending_webhooks.h"
+#include "pg_update_deposit_confirmation_status.h"
+#include "pg_set_transfer_status_to_confirmed.h"
+#include "pg_insert_exchange_keys.h"
+#include "pg_select_exchange_keys.h"
+#include "pg_insert_deposit_to_transfer.h"
+#include "pg_increase_refund.h"
+#include "pg_select_account.h"
+#include "pg_select_accounts.h"
+#include "pg_insert_transfer.h"
+#include "pg_insert_transfer_details.h"
+#include "pg_store_wire_fee_by_exchange.h"
+#include "pg_insert_token_family.h"
+#include "pg_lookup_token_family.h"
+#include "pg_lookup_token_families.h"
+#include "pg_delete_token_family.h"
+#include "pg_update_token_family.h"
+#include "pg_insert_token_family_key.h"
+#include "pg_lookup_token_family_key.h"
+
/**
* How often do we re-try if we run into a DB serialization error?
@@ -37,76 +149,6 @@
/**
- * Wrapper macro to add the currency from the plugin's state
- * when fetching amounts from the database.
- *
- * @param field name of the database field to fetch amount from
- * @param[out] amountp pointer to amount to set
- */
-#define TALER_PQ_RESULT_SPEC_AMOUNT(field,amountp) \
- TALER_PQ_result_spec_amount ( \
- field,pg->currency,amountp)
-
-/**
- * Wrapper macro to add the currency from the plugin's state
- * when fetching amounts from the database. NBO variant.
- *
- * @param field name of the database field to fetch amount from
- * @param[out] amountp pointer to amount to set
- */
-#define TALER_PQ_RESULT_SPEC_AMOUNT_NBO(field, amountp) \
- TALER_PQ_result_spec_amount_nbo ( \
- field,pg->currency,amountp)
-
-
-/**
- * Wrapper macro to add the currency from the plugin's state
- * when fetching amounts from the database.
- *
- * @param field name of the database field to fetch amount from
- * @param[out] amountp pointer to amount to set
- */
-#define TALER_PQ_RESULT_SPEC_AMOUNT(field,amountp) \
- TALER_PQ_result_spec_amount ( \
- field,pg->currency,amountp)
-
-
-/**
- * Type of the "cls" argument given to each of the functions in
- * our API.
- */
-struct PostgresClosure
-{
-
- /**
- * Postgres connection handle.
- */
- struct GNUNET_PQ_Context *conn;
-
- /**
- * Which currency do we deal in?
- */
- char *currency;
-
- /**
- * Directory with SQL statements to run to create tables.
- */
- char *sql_dir;
-
- /**
- * Underlying configuration.
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Name of the currently active transaction, NULL if none is active.
- */
- const char *transaction_name;
-
-};
-
-
-/**
* Drop all Taler tables. This should only be used by testcases.
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
@@ -148,6 +190,7 @@ postgres_create_tables (void *cls)
GNUNET_PQ_make_try_execute ("SET search_path TO merchant;"),
GNUNET_PQ_EXECUTE_STATEMENT_END
};
+ enum GNUNET_GenericReturnValue ret;
conn = GNUNET_PQ_connect_with_cfg (pc->cfg,
"merchantdb-postgres",
@@ -156,8 +199,10 @@ postgres_create_tables (void *cls)
NULL);
if (NULL == conn)
return GNUNET_SYSERR;
+ ret = GNUNET_PQ_exec_sql (conn,
+ "procedures");
GNUNET_PQ_disconnect (conn);
- return GNUNET_OK;
+ return ret;
}
@@ -224,14 +269,7 @@ postgres_event_notify (void *cls,
}
-/**
- * Do a pre-flight check that we are not in an uncommitted transaction.
- * If we are, die.
- * Does not return anything, as we will continue regardless of the outcome.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- */
-static void
+void
postgres_preflight (void *cls)
{
struct PostgresClosure *pg = cls;
@@ -245,14 +283,7 @@ postgres_preflight (void *cls)
}
-/**
- * Check that the database connection is still up
- * and automatically reconnects unless we are
- * already inside of a transaction.
- *
- * @param pg connection to check
- */
-static void
+void
check_connection (struct PostgresClosure *pg)
{
if (NULL != pg->transaction_name)
@@ -262,10250 +293,15 @@ check_connection (struct PostgresClosure *pg)
/**
- * Start a transaction.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param name unique name identifying the transaction (for debugging),
- * must point to a constant
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-postgres_start (void *cls,
- const char *name)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
-
- check_connection (pg);
- postgres_preflight (pg);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Starting merchant DB transaction `%s'\n",
- name);
- if (GNUNET_OK !=
- GNUNET_PQ_exec_statements (pg->conn,
- es))
- {
- TALER_LOG_ERROR ("Failed to start transaction\n");
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- pg->transaction_name = name;
- return GNUNET_OK;
-}
-
-
-/**
- * Start a transaction in 'read committed' mode.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param name unique name identifying the transaction (for debugging),
- * must point to a constant
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-postgres_start_read_committed (void *cls,
- const char *name)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL READ COMMITTED"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
-
- check_connection (pg);
- postgres_preflight (pg);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Starting merchant DB transaction %s (READ COMMITTED)\n",
- name);
- if (GNUNET_OK !=
- GNUNET_PQ_exec_statements (pg->conn,
- es))
- {
- TALER_LOG_ERROR ("Failed to start transaction\n");
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- pg->transaction_name = name;
- return GNUNET_OK;
-}
-
-
-/**
- * Roll back the current transaction of a database connection.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- */
-static void
-postgres_rollback (void *cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_execute ("ROLLBACK"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Rolling back merchant DB transaction `%s'\n",
- pg->transaction_name);
- GNUNET_break (GNUNET_OK ==
- GNUNET_PQ_exec_statements (pg->conn,
- es));
- pg->transaction_name = NULL;
-}
-
-
-/**
- * Commit the current transaction of a database connection.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_commit (void *cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_end
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Committing merchant DB transaction %s\n",
- pg->transaction_name);
- pg->transaction_name = NULL;
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "end_transaction",
- params);
-}
-
-
-/**
- * Context for lookup_instances().
- */
-struct LookupInstancesContext
-{
- /**
- * Function to call with the results.
- */
- TALER_MERCHANTDB_InstanceCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Database context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Instance settings, valid only during find_instances_cb().
- */
- struct TALER_MERCHANTDB_InstanceSettings is;
-
- /**
- * Instance authentication settings, valid only during find_instances_cb().
- */
- struct TALER_MERCHANTDB_InstanceAuthSettings ias;
-
- /**
- * Instance serial number, valid only during find_instances_cb().
- */
- uint64_t instance_serial;
-
- /**
- * Public key of the current instance, valid only during find_instances_cb().
- */
- struct TALER_MerchantPublicKeyP merchant_pub;
-
- /**
- * Set to the return value on errors.
- */
- enum GNUNET_DB_QueryStatus qs;
-
- /**
- * true if we only are interested in instances for which we have the private key.
- */
- bool active_only;
-};
-
-
-/**
- * We are processing an instances lookup and have the @a accounts.
- * Find the private key if possible, and invoke the callback.
- *
- * @param lic context we are handling
- * @param num_accounts length of @a accounts array
- * @param accounts information about accounts of the instance in @a lic
- */
-static void
-call_with_accounts (struct LookupInstancesContext *lic,
- unsigned int num_accounts,
- const struct TALER_MERCHANTDB_AccountDetails accounts[])
-{
- struct PostgresClosure *pg = lic->pg;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&lic->instance_serial),
- GNUNET_PQ_query_param_end
- };
- struct TALER_MerchantPrivateKeyP merchant_priv;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("merchant_priv",
- &merchant_priv),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_instance_private_key",
- params,
- rs);
- if (qs < 0)
- {
- GNUNET_break (0);
- lic->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- if ( (0 == qs) &&
- (lic->active_only) )
- return; /* skip, not interesting */
- lic->cb (lic->cb_cls,
- &lic->merchant_pub,
- (0 == qs) ? NULL : &merchant_priv,
- &lic->is,
- &lic->ias,
- num_accounts,
- accounts);
-}
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param cls of type `struct FindInstancesContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_accounts_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupInstancesContext *lic = cls;
- char *paytos[num_results];
- struct TALER_MERCHANTDB_AccountDetails accounts[num_results];
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- uint8_t active;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("h_wire",
- &accounts[i].h_wire),
- GNUNET_PQ_result_spec_auto_from_type ("salt",
- &accounts[i].salt),
- GNUNET_PQ_result_spec_string ("payto_uri",
- &paytos[i]),
- GNUNET_PQ_result_spec_auto_from_type ("active",
- &active),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- lic->qs = GNUNET_DB_STATUS_HARD_ERROR;
- for (unsigned int j = 0; j < i; j++)
- GNUNET_free (paytos[j]);
- return;
- }
- accounts[i].active = (0 != active);
- accounts[i].payto_uri = paytos[i];
- }
- call_with_accounts (lic,
- num_results,
- accounts);
- for (unsigned int i = 0; i < num_results; i++)
- GNUNET_free (paytos[i]);
-}
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about instances.
- *
- * @param cls of type `struct FindInstancesContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_instances_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupInstancesContext *lic = cls;
- struct PostgresClosure *pg = lic->pg;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- bool no_auth;
- bool no_salt;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("merchant_serial",
- &lic->instance_serial),
- GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
- &lic->merchant_pub),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_auto_from_type ("auth_hash",
- &lic->ias.auth_hash),
- &no_auth),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_auto_from_type ("auth_salt",
- &lic->ias.auth_salt),
- &no_salt),
- GNUNET_PQ_result_spec_string ("merchant_id",
- &lic->is.id),
- GNUNET_PQ_result_spec_string ("merchant_name",
- &lic->is.name),
- TALER_PQ_result_spec_json ("address",
- &lic->is.address),
- TALER_PQ_result_spec_json ("jurisdiction",
- &lic->is.jurisdiction),
- TALER_PQ_RESULT_SPEC_AMOUNT ("default_max_deposit_fee",
- &lic->is.default_max_deposit_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("default_max_wire_fee",
- &lic->is.default_max_wire_fee),
- GNUNET_PQ_result_spec_uint32 ("default_wire_fee_amortization",
- &lic->is.default_wire_fee_amortization),
- GNUNET_PQ_result_spec_relative_time ("default_wire_transfer_delay",
- &lic->is.default_wire_transfer_delay),
- GNUNET_PQ_result_spec_relative_time ("default_pay_delay",
- &lic->is.default_pay_delay),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("website",
- &lic->is.website),
- NULL),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("email",
- &lic->is.email),
- NULL),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("logo",
- &lic->is.logo),
- NULL),
- GNUNET_PQ_result_spec_end
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&lic->instance_serial),
- GNUNET_PQ_query_param_end
- };
-
- memset (&lic->ias.auth_salt,
- 0,
- sizeof (lic->ias.auth_salt));
- memset (&lic->ias.auth_hash,
- 0,
- sizeof (lic->ias.auth_hash));
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- lic->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- lic->qs = GNUNET_PQ_eval_prepared_multi_select (lic->pg->conn,
- "lookup_accounts",
- params,
- &lookup_accounts_cb,
- lic);
- if (0 > lic->qs)
- {
- /* lookup_accounts_cb() did not run, still notify about the
- account-less instance! */
- call_with_accounts (lic,
- 0,
- NULL);
- }
- GNUNET_PQ_cleanup_result (rs);
- if (0 > lic->qs)
- break;
- }
-}
-
-
-/**
- * Lookup all of the instances this backend has configured.
- *
- * @param cls closure
- * @param active_only only find 'active' instances
- * @param cb function to call on all instances found
- * @param cb_cls closure for @a cb
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_instances (void *cls,
- bool active_only,
- TALER_MERCHANTDB_InstanceCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupInstancesContext lic = {
- .cb = cb,
- .cb_cls = cb_cls,
- .active_only = active_only,
- .pg = pg
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_instances",
- params,
- &lookup_instances_cb,
- &lic);
- if (0 > lic.qs)
- return lic.qs;
- return qs;
-}
-
-
-/**
- * Lookup all one of the instances this backend has configured.
- *
- * @param cls closure
- * @param id instance ID to resolve
- * @param active_only only find 'active' instances
- * @param cb function to call on all instances found
- * @param cb_cls closure for @a cb
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_instance (void *cls,
- const char *id,
- bool active_only,
- TALER_MERCHANTDB_InstanceCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupInstancesContext lic = {
- .cb = cb,
- .cb_cls = cb_cls,
- .active_only = active_only,
- .pg = pg
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (id),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_instance",
- params,
- &lookup_instances_cb,
- &lic);
- if (0 > lic.qs)
- return lic.qs;
- return qs;
-}
-
-
-/**
- * Lookup authentication data of an instance.
- *
- * @param cls closure
- * @param instance_id instance to query
- * @param[out] ias where to store the auth data
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_instance_auth (
- void *cls,
- const char *instance_id,
- struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("auth_hash",
- &ias->auth_hash),
- GNUNET_PQ_result_spec_auto_from_type ("auth_salt",
- &ias->auth_salt),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_instance_auth",
- params,
- rs);
-}
-
-
-/**
- * Insert information about an instance into our database.
- *
- * @param cls closure
- * @param merchant_pub public key of the instance
- * @param merchant_priv private key of the instance
- * @param is details about the instance
- * @param ias authentication settings for the instance
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_instance (
- void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct TALER_MerchantPrivateKeyP *merchant_priv,
- const struct TALER_MERCHANTDB_InstanceSettings *is,
- const struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (&ias->auth_hash),
- GNUNET_PQ_query_param_auto_from_type (&ias->auth_salt),
- GNUNET_PQ_query_param_string (is->id),
- GNUNET_PQ_query_param_string (is->name),
- TALER_PQ_query_param_json (is->address),
- TALER_PQ_query_param_json (is->jurisdiction),
- TALER_PQ_query_param_amount (&is->default_max_deposit_fee),
- TALER_PQ_query_param_amount (&is->default_max_wire_fee),
- GNUNET_PQ_query_param_uint32 (&is->default_wire_fee_amortization),
- GNUNET_PQ_query_param_relative_time (
- &is->default_wire_transfer_delay),
- GNUNET_PQ_query_param_relative_time (&is->default_pay_delay),
- (NULL == is->website)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (is->website),
- (NULL == is->email)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (is->email),
- (NULL == is->logo)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (is->logo),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_QueryParam params_priv[] = {
- GNUNET_PQ_query_param_auto_from_type (merchant_priv),
- GNUNET_PQ_query_param_string (is->id),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_instance",
- params);
- if (qs <= 0)
- return qs;
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_keys",
- params_priv);
-}
-
-
-/**
- * Insert information about an instance's account into our database.
- *
- * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_account (
- void *cls,
- const char *id,
- const struct TALER_MERCHANTDB_AccountDetails *account_details)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (id),
- GNUNET_PQ_query_param_auto_from_type (&account_details->h_wire),
- GNUNET_PQ_query_param_auto_from_type (&account_details->salt),
- GNUNET_PQ_query_param_string (account_details->payto_uri),
- GNUNET_PQ_query_param_bool (account_details->active),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_account",
- params);
-}
-
-
-/**
- * Closure for kyc_status_cb().
- */
-struct KycStatusContext
-{
- /**
- * Function to call with results.
- */
- TALER_MERCHANTDB_KycCallback kyc_cb;
-
- /**
- * Closure for @e kyc_cb.
- */
- void *kyc_cb_cls;
-
- /**
- * Filter, NULL to not filter.
- */
- const struct TALER_MerchantWireHashP *h_wire;
-
- /**
- * Filter, NULL to not filter.
- */
- const char *exchange_url;
-
- /**
- * Number of results found.
- */
- unsigned int count;
-
- /**
- * Set to true on failure(s).
- */
- bool failure;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param[in,out] cls of type `struct KycStatusContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-kyc_status_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct KycStatusContext *ksc = cls;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- struct TALER_MerchantWireHashP h_wire;
- uint64_t kyc_serial;
- char *exchange_url;
- char *payto_uri;
- struct GNUNET_TIME_Timestamp last_check;
- uint8_t kyc_ok;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("h_wire",
- &h_wire),
- GNUNET_PQ_result_spec_uint64 ("exchange_kyc_serial",
- &kyc_serial),
- GNUNET_PQ_result_spec_string ("payto_uri",
- &payto_uri),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_PQ_result_spec_timestamp ("kyc_timestamp",
- &last_check),
- GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
- &kyc_ok),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ksc->failure = true;
- return;
- }
- if ( (NULL != ksc->exchange_url) &&
- (0 != strcmp (ksc->exchange_url,
- exchange_url)) )
- {
- GNUNET_PQ_cleanup_result (rs);
- continue;
- }
- if ( (NULL != ksc->h_wire) &&
- (0 != GNUNET_memcmp (ksc->h_wire,
- &h_wire)) )
- {
- GNUNET_PQ_cleanup_result (rs);
- continue;
- }
- ksc->count++;
- ksc->kyc_cb (ksc->kyc_cb_cls,
- &h_wire,
- kyc_serial,
- payto_uri,
- exchange_url,
- last_check,
- 0 != kyc_ok);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Check an instance's account's KYC status.
- *
- * @param cls closure
- * @param merchant_id merchant backend instance ID
- * @param h_wire hash of the wire account to check,
- * NULL to check all accounts of the merchant
- * @param exchange_url base URL of the exchange to check,
- * NULL to check all exchanges
- * @param kyc_cb KYC status callback to invoke
- * @param kyc_cb_cls closure for @a kyc_cb
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_account_kyc_get_status (void *cls,
- const char *merchant_id,
- const struct TALER_MerchantWireHashP *h_wire,
- const char *exchange_url,
- TALER_MERCHANTDB_KycCallback kyc_cb,
- void *kyc_cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct KycStatusContext ksc = {
- .kyc_cb = kyc_cb,
- .kyc_cb_cls = kyc_cb_cls,
- .exchange_url = exchange_url,
- .h_wire = h_wire
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (merchant_id),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_kyc_status",
- params,
- &kyc_status_cb,
- &ksc);
- if (ksc.failure)
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- if (0 > qs)
- return qs;
- return ksc.count;
-}
-
-
-/**
- * Update an instance's account's KYC status.
- *
- * @param cls closure
- * @param merchant_id merchant backend instance ID
- * @param h_wire hash of the wire account to check
- * @param exchange_url base URL of the exchange to check
- * @param exchange_kyc_serial serial number for our account at the exchange (0 if unknown)
- * @param exchange_sig signature of the exchange, or NULL for none
- * @param exchange_pub public key of the exchange, or NULL for none
- * @param timestamp timestamp to store
- * @param kyc_ok current KYC status (true for satisfied)
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_account_kyc_set_status (
- void *cls,
- const char *merchant_id,
- const struct TALER_MerchantWireHashP *h_wire,
- const char *exchange_url,
- uint64_t exchange_kyc_serial,
- const struct TALER_ExchangeSignatureP *exchange_sig,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- struct GNUNET_TIME_Timestamp timestamp,
- bool kyc_ok)
-{
- struct PostgresClosure *pg = cls;
- uint8_t ok = kyc_ok;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (merchant_id),
- GNUNET_PQ_query_param_auto_from_type (h_wire),
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_uint64 (&exchange_kyc_serial),
- GNUNET_PQ_query_param_timestamp (&timestamp),
- GNUNET_PQ_query_param_auto_from_type (&ok),
- exchange_pub
- ? GNUNET_PQ_query_param_auto_from_type (exchange_pub)
- : GNUNET_PQ_query_param_null (),
- exchange_sig
- ? GNUNET_PQ_query_param_auto_from_type (exchange_sig)
- : GNUNET_PQ_query_param_null (),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "upsert_account_kyc",
- params);
-}
-
-
-/**
- * Delete private key of an instance from our database.
- *
- * @param cls closure
- * @param merchant_id identifier of the instance
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_instance_private_key (
- void *cls,
- const char *merchant_id)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (merchant_id),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_key",
- params);
-}
-
-
-/**
- * Purge an instance and all associated information from our database.
- * Highly likely to cause undesired data loss. Use with caution.
- *
- * @param cls closure
- * @param merchant_id identifier of the instance
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_purge_instance (void *cls,
- const char *merchant_id)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (merchant_id),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "purge_instance",
- params);
-}
-
-
-/**
- * Update information about an instance into our database.
- *
- * @param cls closure
- * @param is details about the instance
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_instance (void *cls,
- const struct TALER_MERCHANTDB_InstanceSettings *is)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (is->id),
- GNUNET_PQ_query_param_string (is->name),
- TALER_PQ_query_param_json (is->address),
- TALER_PQ_query_param_json (is->jurisdiction),
- TALER_PQ_query_param_amount (&is->default_max_deposit_fee),
- TALER_PQ_query_param_amount (&is->default_max_wire_fee),
- GNUNET_PQ_query_param_uint32 (&is->default_wire_fee_amortization),
- GNUNET_PQ_query_param_relative_time (
- &is->default_wire_transfer_delay),
- GNUNET_PQ_query_param_relative_time (&is->default_pay_delay),
- (NULL == is->website)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (is->website),
- (NULL == is->email)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (is->email),
- (NULL == is->logo)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (is->logo),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_instance",
- params);
-}
-
-
-/**
- * Update information about an instance's authentication settings
- * into our database.
- *
- * @param cls closure
- * @param merchant_id identity of the instance
- * @param is authentication details about the instance
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_instance_auth (
- void *cls,
- const char *merchant_id,
- const struct TALER_MERCHANTDB_InstanceAuthSettings *is)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (merchant_id),
- GNUNET_PQ_query_param_auto_from_type (&is->auth_hash),
- GNUNET_PQ_query_param_auto_from_type (&is->auth_salt),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_instance_auth",
- params);
-}
-
-
-/**
- * Set an instance's account in our database to "inactive".
- *
- * @param cls closure
- * @param merchant_id merchant backend instance ID
- * @param h_wire hash of the wire account to set to inactive
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_inactivate_account (void *cls,
- const char *merchant_id,
- const struct TALER_MerchantWireHashP *h_wire)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (merchant_id),
- GNUNET_PQ_query_param_auto_from_type (h_wire),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "inactivate_account",
- params);
-}
-
-
-/**
- * Set an instance's account in our database to "active".
- *
- * @param cls closure
- * @param merchant_id merchant backend instance ID
- * @param h_wire hash of the wire account to set to active
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_activate_account (void *cls,
- const char *merchant_id,
- const struct TALER_MerchantWireHashP *h_wire)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (merchant_id),
- GNUNET_PQ_query_param_auto_from_type (h_wire),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "activate_account",
- params);
-}
-
-
-/**
- * Context used for postgres_lookup_products().
- */
-struct LookupProductsContext
-{
- /**
- * Function to call with the results.
- */
- TALER_MERCHANTDB_ProductsCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Did database result extraction fail?
- */
- bool extract_failed;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about products.
- *
- * @param[in,out] cls of type `struct LookupProductsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_products_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupProductsContext *plc = cls;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- char *product_id;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("product_id",
- &product_id),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- plc->extract_failed = true;
- return;
- }
- plc->cb (plc->cb_cls,
- product_id);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Lookup all of the products the given instance has configured.
- *
- * @param cls closure
- * @param instance_id instance to lookup products for
- * @param cb function to call on all products found
- * @param cb_cls closure for @a cb
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_products (void *cls,
- const char *instance_id,
- TALER_MERCHANTDB_ProductsCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupProductsContext plc = {
- .cb = cb,
- .cb_cls = cb_cls,
- /* Can be overwritten by the lookup_products_cb */
- .extract_failed = false,
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_products",
- params,
- &lookup_products_cb,
- &plc);
- /* If there was an error inside lookup_products_cb, return a hard error. */
- if (plc.extract_failed)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
-
-
-/**
- * Lookup details about a particular product.
- *
- * @param cls closure
- * @param instance_id instance to lookup products for
- * @param product_id product to lookup
- * @param[out] pd set to the product details on success, can be NULL
- * (in that case we only want to check if the product exists)
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_product (void *cls,
- const char *instance_id,
- const char *product_id,
- struct TALER_MERCHANTDB_ProductDetails *pd)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (product_id),
- GNUNET_PQ_query_param_end
- };
-
- if (NULL == pd)
- {
- struct GNUNET_PQ_ResultSpec rs_null[] = {
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_product",
- params,
- rs_null);
- }
- else
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("description",
- &pd->description),
- TALER_PQ_result_spec_json ("description_i18n",
- &pd->description_i18n),
- GNUNET_PQ_result_spec_string ("unit",
- &pd->unit),
- TALER_PQ_RESULT_SPEC_AMOUNT ("price",
- &pd->price),
- TALER_PQ_result_spec_json ("taxes",
- &pd->taxes),
- GNUNET_PQ_result_spec_uint64 ("total_stock",
- &pd->total_stock),
- GNUNET_PQ_result_spec_uint64 ("total_sold",
- &pd->total_sold),
- GNUNET_PQ_result_spec_uint64 ("total_lost",
- &pd->total_lost),
- GNUNET_PQ_result_spec_string ("image",
- &pd->image),
- TALER_PQ_result_spec_json ("address",
- &pd->address),
- GNUNET_PQ_result_spec_timestamp ("next_restock",
- &pd->next_restock),
- GNUNET_PQ_result_spec_uint32 ("minimum_age",
- &pd->minimum_age),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_product",
- params,
- rs);
- }
-}
-
-
-/**
- * Delete information about a product. Note that the transaction must
- * enforce that no stocks are currently locked.
- *
- * @param cls closure
- * @param instance_id instance to delete product of
- * @param product_id product to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- * if locks prevent deletion OR product unknown
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_product (void *cls,
- const char *instance_id,
- const char *product_id)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (product_id),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_product",
- params);
-}
-
-
-/**
- * Insert details about a particular product.
- *
- * @param cls closure
- * @param instance_id instance to insert product for
- * @param product_id product identifier of product to insert
- * @param pd the product details to insert
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_product (void *cls,
- const char *instance_id,
- const char *product_id,
- const struct TALER_MERCHANTDB_ProductDetails *pd)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (product_id),
- GNUNET_PQ_query_param_string (pd->description),
- TALER_PQ_query_param_json (pd->description_i18n),
- GNUNET_PQ_query_param_string (pd->unit),
- GNUNET_PQ_query_param_string (pd->image),
- TALER_PQ_query_param_json (pd->taxes),
- TALER_PQ_query_param_amount (&pd->price),
- GNUNET_PQ_query_param_uint64 (&pd->total_stock),
- TALER_PQ_query_param_json (pd->address),
- GNUNET_PQ_query_param_timestamp (&pd->next_restock),
- GNUNET_PQ_query_param_uint32 (&pd->minimum_age),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_product",
- params);
-}
-
-
-/**
- * Update details about a particular product. Note that the
- * transaction must enforce that the sold/stocked/lost counters
- * are not reduced (i.e. by expanding the WHERE clause on the existing
- * values).
- *
- * @param cls closure
- * @param instance_id instance to lookup products for
- * @param product_id product to lookup
- * @param[out] pd set to the product details on success, can be NULL
- * (in that case we only want to check if the product exists)
- * total_sold in @a pd is ignored, total_lost must not
- * exceed total_stock minus the existing total_sold;
- * total_sold and total_stock must be larger or equal to
- * the existing value;
- * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the
- * non-decreasing constraints are not met *or* if the product
- * does not yet exist.
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_product (void *cls,
- const char *instance_id,
- const char *product_id,
- const struct TALER_MERCHANTDB_ProductDetails *pd)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id), /* $1 */
- GNUNET_PQ_query_param_string (product_id),
- GNUNET_PQ_query_param_string (pd->description),
- TALER_PQ_query_param_json (pd->description_i18n),
- GNUNET_PQ_query_param_string (pd->unit),
- GNUNET_PQ_query_param_string (pd->image), /* $6 */
- TALER_PQ_query_param_json (pd->taxes),
- TALER_PQ_query_param_amount (&pd->price), /* $8+$9 */
- GNUNET_PQ_query_param_uint64 (&pd->total_stock), /* $10 */
- GNUNET_PQ_query_param_uint64 (&pd->total_lost),
- TALER_PQ_query_param_json (pd->address),
- GNUNET_PQ_query_param_timestamp (&pd->next_restock),
- GNUNET_PQ_query_param_uint32 (&pd->minimum_age),
- GNUNET_PQ_query_param_end
- };
-
- if ( (pd->total_stock < pd->total_lost + pd->total_sold) ||
- (pd->total_lost < pd->total_lost
- + pd->total_sold) /* integer overflow */)
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_product",
- params);
-}
-
-
-/**
- * Lock stocks of a particular product. Note that the transaction must
- * enforce that the "stocked-sold-lost >= locked" constraint holds.
- *
- * @param cls closure
- * @param instance_id instance to lookup products for
- * @param product_id product to lookup
- * @param uuid the UUID that holds the lock
- * @param quantity how many units should be locked
- * @param expiration_time when should the lock expire
- * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the
- * product is unknown OR if there insufficient stocks remaining
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lock_product (void *cls,
- const char *instance_id,
- const char *product_id,
- const struct GNUNET_Uuid *uuid,
- uint64_t quantity,
- struct GNUNET_TIME_Timestamp expiration_time)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (product_id),
- GNUNET_PQ_query_param_auto_from_type (uuid),
- GNUNET_PQ_query_param_uint64 (&quantity),
- GNUNET_PQ_query_param_timestamp (&expiration_time),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "lock_product",
- params);
-}
-
-
-/**
- * Release all expired product locks, including
- * those from expired offers -- across all
- * instances.
- *
- * @param cls closure
- */
-static void
-postgres_expire_locks (void *cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_absolute_time (&now),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs1;
- enum GNUNET_DB_QueryStatus qs2;
- enum GNUNET_DB_QueryStatus qs3;
-
- check_connection (pg);
- qs1 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "unlock_products",
- params);
- if (qs1 < 0)
- {
- GNUNET_break (0);
- return;
- }
- qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "unlock_orders",
- params);
- if (qs2 < 0)
- {
- GNUNET_break (0);
- return;
- }
- qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "unlock_contracts",
- params);
- if (qs3 < 0)
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Released %d+%d+%d locks\n",
- qs1,
- qs2,
- qs3);
-}
-
-
-/**
- * Delete information about an order. Note that the transaction must
- * enforce that the order is not awaiting payment anymore.
- *
- * @param cls closure
- * @param instance_id instance to delete order of
- * @param order_id order to delete
- * @param force delete claimed but unpaid orders as well
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- * if pending payment prevents deletion OR order unknown
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_order (void *cls,
- const char *instance_id,
- const char *order_id,
- bool force)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_absolute_time (&now),
- GNUNET_PQ_query_param_bool (force),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_QueryParam params2[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_order",
- params);
- if ( (qs <= 0) || (! force))
- return qs;
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_contract",
- params2);
-}
-
-
-/**
- * Retrieve order given its @a order_id and the @a instance_id.
- *
- * @param cls closure
- * @param instance_id instance to obtain order of
- * @param order_id order id used to perform the lookup
- * @param[out] claim_token the claim token generated for the order,
- * NULL to only test if the order exists
- * @param[out] h_post_data set to the hash of the POST data that created the order
- * @param[out] contract_terms where to store the retrieved contract terms,
- * NULL to only test if the order exists
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order (void *cls,
- const char *instance_id,
- const char *order_id,
- struct TALER_ClaimTokenP *claim_token,
- struct TALER_MerchantPostDataHashP *h_post_data,
- json_t **contract_terms)
-{
- struct PostgresClosure *pg = cls;
- json_t *j;
- struct TALER_ClaimTokenP ct;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_json ("contract_terms",
- &j),
- GNUNET_PQ_result_spec_auto_from_type ("claim_token",
- &ct),
- GNUNET_PQ_result_spec_auto_from_type ("h_post_data",
- h_post_data),
- GNUNET_PQ_result_spec_end
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Finding contract term, order_id: '%s', instance_id: '%s'.\n",
- order_id,
- instance_id);
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_order",
- params,
- rs);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- {
- if (NULL != contract_terms)
- *contract_terms = j;
- else
- json_decref (j);
- if (NULL != claim_token)
- *claim_token = ct;
- }
- else
- {
- /* just to be safe: NULL it */
- if (NULL != contract_terms)
- *contract_terms = NULL;
- if (NULL != claim_token)
- *claim_token = (struct TALER_ClaimTokenP) { 0 }
- ;
- }
- return qs;
-}
-
-
-/**
- * Retrieve order summary given its @a order_id and the @a instance_id.
- *
- * @param cls closure
- * @param instance_id instance to obtain order of
- * @param order_id order id used to perform the lookup
- * @param[out] timestamp when was the order created
- * @param[out] order_serial under which serial do we keep this order
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order_summary (void *cls,
- const char *instance_id,
- const char *order_id,
- struct GNUNET_TIME_Timestamp *timestamp,
- uint64_t *order_serial)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- order_serial),
- GNUNET_PQ_result_spec_timestamp ("creation_time",
- timestamp),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_order_summary",
- params,
- rs);
-}
-
-
-/**
- * Context used for postgres_lookup_orders().
- */
-struct LookupOrdersContext
-{
- /**
- * Function to call with the results.
- */
- TALER_MERCHANTDB_OrdersCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Did database result extraction fail?
- */
- bool extract_failed;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about orders.
- *
- * @param[in,out] cls of type `struct LookupOrdersContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_orders_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupOrdersContext *plc = cls;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- char *order_id;
- uint64_t order_serial;
- struct GNUNET_TIME_Timestamp ts;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("order_id",
- &order_id),
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- &order_serial),
- GNUNET_PQ_result_spec_timestamp ("creation_time",
- &ts),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- plc->extract_failed = true;
- return;
- }
- plc->cb (plc->cb_cls,
- order_id,
- order_serial,
- ts);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Retrieve orders given the @a instance_id.
- *
- * @param cls closure
- * @param instance_id instance to obtain order of
- * @param of filter to apply when looking up orders
- * @param cb callback to pass all the orders that are found
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_orders (void *cls,
- const char *instance_id,
- const struct TALER_MERCHANTDB_OrderFilter *of,
- TALER_MERCHANTDB_OrdersCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupOrdersContext plc = {
- .cb = cb,
- .cb_cls = cb_cls
- };
- uint64_t limit = (of->delta > 0) ? of->delta : -of->delta;
- uint8_t paid;
- uint8_t refunded;
- uint8_t wired;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&limit),
- GNUNET_PQ_query_param_uint64 (&of->start_row),
- GNUNET_PQ_query_param_timestamp (&of->date),
- GNUNET_PQ_query_param_auto_from_type (&paid),
- GNUNET_PQ_query_param_auto_from_type (&refunded),
- GNUNET_PQ_query_param_auto_from_type (&wired),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
- char stmt[128];
-
- paid = (TALER_EXCHANGE_YNA_YES == of->paid);
- refunded = (TALER_EXCHANGE_YNA_YES == of->refunded);
- wired = (TALER_EXCHANGE_YNA_YES == of->wired);
- /* painfully many cases..., note that "_xxx" being present in 'stmt' merely
- means that we filter by that variable, the value we filter for is
- computed above */
- GNUNET_snprintf (stmt,
- sizeof (stmt),
- "lookup_orders_%s%s%s%s",
- (of->delta > 0) ? "inc" : "dec",
- (TALER_EXCHANGE_YNA_ALL == of->paid) ? "" : "_paid",
- (TALER_EXCHANGE_YNA_ALL == of->refunded) ? "" :
- "_refunded",
- (TALER_EXCHANGE_YNA_ALL == of->wired) ? "" : "_wired");
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- stmt,
- params,
- &lookup_orders_cb,
- &plc);
- if (plc.extract_failed)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
-
-
-/**
- * Insert order into the DB.
- *
- * @param cls closure
- * @param instance_id identifies the instance responsible for the order
- * @param order_id alphanumeric string that uniquely identifies the proposal
- * @param h_post_data hash of the POST data for idempotency checks
- * @param pay_deadline how long does the customer have to pay for the order
- * @param claim_token token to use for access control
- * @param contract_terms proposal data to store
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_order (void *cls,
- const char *instance_id,
- const char *order_id,
- const struct TALER_MerchantPostDataHashP *h_post_data,
- struct GNUNET_TIME_Timestamp pay_deadline,
- const struct TALER_ClaimTokenP *claim_token,
- const json_t *contract_terms)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Timestamp now;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_timestamp (&pay_deadline),
- GNUNET_PQ_query_param_auto_from_type (claim_token),
- GNUNET_PQ_query_param_auto_from_type (h_post_data),
- GNUNET_PQ_query_param_timestamp (&now),
- TALER_PQ_query_param_json (contract_terms),
- GNUNET_PQ_query_param_end
- };
-
- now = GNUNET_TIME_timestamp_get ();
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "inserting order: order_id: %s, instance_id: %s.\n",
- order_id,
- instance_id);
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_order",
- params);
-}
-
-
-/**
- * Release an inventory lock by UUID. Releases ALL stocks locked under
- * the given UUID.
- *
- * @param cls closure
- * @param uuid the UUID to release locks for
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are no locks under @a uuid
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
- */
-static enum GNUNET_DB_QueryStatus
-postgres_unlock_inventory (void *cls,
- const struct GNUNET_Uuid *uuid)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (uuid),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "unlock_inventory",
- params);
-}
-
-
-/**
- * Lock inventory stock to a particular order.
- *
- * @param cls closure
- * @param instance_id identifies the instance responsible for the order
- * @param order_id alphanumeric string that uniquely identifies the order
- * @param product_id uniquely identifies the product to be locked
- * @param quantity how many units should be locked to the @a order_id
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are insufficient stocks
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_order_lock (void *cls,
- const char *instance_id,
- const char *order_id,
- const char *product_id,
- uint64_t quantity)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_string (product_id),
- GNUNET_PQ_query_param_uint64 (&quantity),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_order_lock",
- params);
-}
-
-
-/**
- * Retrieve contract terms given its @a order_id
- *
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order_id used to lookup.
- * @param[out] contract_terms where to store the result, NULL to only check for existence
- * @param[out] order_serial set to the order's serial number
- * @param[out] paid set to true if the order is fully paid
- * @param[out] claim_token set to the claim token, NULL to only check for existence
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_contract_terms (void *cls,
- const char *instance_id,
- const char *order_id,
- json_t **contract_terms,
- uint64_t *order_serial,
- bool *paid,
- struct TALER_ClaimTokenP *claim_token)
-{
- struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
- struct TALER_ClaimTokenP ct;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- /* contract_terms must be first! */
- TALER_PQ_result_spec_json ("contract_terms",
- contract_terms),
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- order_serial),
- GNUNET_PQ_result_spec_bool ("paid",
- paid),
- GNUNET_PQ_result_spec_auto_from_type ("claim_token",
- &ct),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_contract_terms",
- params,
- (NULL != contract_terms)
- ? rs
- : &rs[1]);
- if (NULL != claim_token)
- *claim_token = ct;
- return qs;
-}
-
-
-/**
- * Store contract terms given its @a order_id. Note that some attributes are
- * expected to be calculated inside of the function, like the hash of the
- * contract terms (to be hashed), the creation_time and pay_deadline (to be
- * obtained from the merchant_orders table). The "session_id" should be
- * initially set to the empty string. The "fulfillment_url" and "refund_deadline"
- * must be extracted from @a contract_terms.
- *
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order_id used to store
- * @param contract_terms contract terms to store
- * @param[out] order_serial set to the serial of the order
- * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a contract_terms
- * is malformed
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_contract_terms (void *cls,
- const char *instance_id,
- const char *order_id,
- json_t *contract_terms,
- uint64_t *order_serial)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Timestamp pay_deadline;
- struct GNUNET_TIME_Timestamp refund_deadline;
- const char *fulfillment_url;
- struct TALER_PrivateContractHashP h_contract_terms;
-
- if (GNUNET_OK !=
- TALER_JSON_contract_hash (contract_terms,
- &h_contract_terms))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_timestamp ("pay_deadline",
- &pay_deadline),
- GNUNET_JSON_spec_timestamp ("refund_deadline",
- &refund_deadline),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (NULL,
- contract_terms,
- spec);
- if (GNUNET_OK != res)
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- }
-
- fulfillment_url =
- json_string_value (json_object_get (contract_terms,
- "fulfillment_url"));
- check_connection (pg);
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- TALER_PQ_query_param_json (contract_terms),
- GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
- GNUNET_PQ_query_param_timestamp (&pay_deadline),
- GNUNET_PQ_query_param_timestamp (&refund_deadline),
- (NULL == fulfillment_url)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (fulfillment_url),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- order_serial),
- GNUNET_PQ_result_spec_end
- };
-
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "insert_contract_terms",
- params,
- rs);
- }
-}
-
-
-/**
- * Update the contract terms stored for @a order_id. Note that some attributes are
- * expected to be calculated inside of the function, like the hash of the
- * contract terms (to be hashed), the creation_time and pay_deadline (to be
- * obtained from the merchant_orders table). The "session_id" should be
- * initially set to the empty string. The "fulfillment_url" and "refund_deadline"
- * must be extracted from @a contract_terms.
- *
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order_id used to store
- * @param contract_terms contract to store
- * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a contract_terms
- * is malformed
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_contract_terms (void *cls,
- const char *instance_id,
- const char *order_id,
- json_t *contract_terms)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Timestamp pay_deadline;
- struct GNUNET_TIME_Timestamp refund_deadline;
- const char *fulfillment_url = NULL;
- struct TALER_PrivateContractHashP h_contract_terms;
-
- if (GNUNET_OK !=
- TALER_JSON_contract_hash (contract_terms,
- &h_contract_terms))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_timestamp ("pay_deadline",
- &pay_deadline),
- GNUNET_JSON_spec_timestamp ("refund_deadline",
- &refund_deadline),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("fulfillment_url",
- &fulfillment_url),
- NULL),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (NULL,
- contract_terms,
- spec);
- if (GNUNET_OK != res)
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- }
-
- check_connection (pg);
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- TALER_PQ_query_param_json (contract_terms),
- GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
- GNUNET_PQ_query_param_timestamp (&pay_deadline),
- GNUNET_PQ_query_param_timestamp (&refund_deadline),
- (NULL == fulfillment_url)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (fulfillment_url),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_contract_terms",
- params);
- }
-}
-
-
-/**
- * Delete information about a contract. Note that the transaction must
- * enforce that the contract is not awaiting payment anymore AND was not
- * paid, or is past the legal expiration.
- *
- * @param cls closure
- * @param instance_id instance to delete order of
- * @param order_id order to delete
- * @param legal_expiration how long do we need to keep (paid) contracts on
- * file for legal reasons (i.e. taxation)
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- * if locks prevent deletion OR order unknown
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_contract_terms (void *cls,
- const char *instance_id,
- const char *order_id,
- struct GNUNET_TIME_Relative legal_expiration)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_relative_time (&legal_expiration),
- GNUNET_PQ_query_param_absolute_time (&now),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_contract_terms",
- params);
-}
-
-
-/**
- * Closure for #lookup_deposits_cb().
- */
-struct LookupDepositsContext
-{
- /**
- * Function to call with results.
- */
- TALER_MERCHANTDB_DepositsCallback cb;
-
- /**
- * Closure for @e cls.
- */
- void *cb_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Transaction status (set).
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param[in,out] cls of type `struct LookupDepositsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_deposits_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupDepositsContext *ldc = cls;
- struct PostgresClosure *pg = ldc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
- struct TALER_Amount refund_fee;
- struct TALER_Amount wire_fee;
- char *exchange_url;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &amount_with_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
- &deposit_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_fee",
- &refund_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
- &wire_fee),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ldc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- ldc->cb (ldc->cb_cls,
- exchange_url,
- &coin_pub,
- &amount_with_fee,
- &deposit_fee,
- &refund_fee,
- &wire_fee);
- GNUNET_PQ_cleanup_result (rs);
- }
- ldc->qs = num_results;
-}
-
-
-/**
- * Lookup information about coins that were successfully deposited for a
- * given contract.
- *
- * @param cls closure
- * @param instance_id instance to lookup deposits for
- * @param h_contract_terms proposal data's hashcode
- * @param cb function to call with payment data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_deposits (
- void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- TALER_MERCHANTDB_DepositsCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_end
- };
- struct LookupDepositsContext ldc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg
- };
- enum GNUNET_DB_QueryStatus qs;
-
- /* no preflight check here, run in its own transaction by the caller! */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Finding deposits for h_contract_terms '%s'\n",
- GNUNET_h2s (&h_contract_terms->hash));
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_deposits",
- params,
- &lookup_deposits_cb,
- &ldc);
- if (qs <= 0)
- return qs;
- return ldc.qs;
-}
-
-
-/**
- * Insert an exchange signing key into our database.
- *
- * @param cls closure
- * @param master_pub exchange master public key used for @a master_sig
- * @param exchange_pub exchange signing key to insert
- * @param start_date when does the signing key become valid
- * @param expire_date when does the signing key stop being used
- * @param end_date when does the signing key become void as proof
- * @param master_sig signature of @a master_pub over the @a exchange_pub and the dates
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_exchange_signkey (
- void *cls,
- const struct TALER_MasterPublicKeyP *master_pub,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp expire_date,
- struct GNUNET_TIME_Timestamp end_date,
- const struct TALER_MasterSignatureP *master_sig)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (master_pub),
- GNUNET_PQ_query_param_auto_from_type (exchange_pub),
- GNUNET_PQ_query_param_timestamp (&start_date),
- GNUNET_PQ_query_param_timestamp (&expire_date),
- GNUNET_PQ_query_param_timestamp (&end_date),
- GNUNET_PQ_query_param_auto_from_type (master_sig),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- postgres_preflight (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_exchange_signkey",
- params);
-
-}
-
-
-/**
- * Insert payment confirmation from the exchange into the database.
- *
- * @param cls closure
- * @param instance_id instance to lookup deposits for
- * @param deposit_timestamp time when the exchange generated the deposit confirmation
- * @param h_contract_terms proposal data's hashcode
- * @param coin_pub public key of the coin
- * @param exchange_url URL of the exchange that issued @a coin_pub
- * @param amount_with_fee amount the exchange will deposit for this coin
- * @param deposit_fee fee the exchange will charge for this coin
- * @param wire_fee wire fee the exchange charges
- * @param refund_fee fee the exchange charges to refund this coin
- * @param h_wire hash of the wire details of the target account of the merchant
- * @param exchange_sig signature from exchange that coin was accepted
- * @param exchange_pub signgin key that was used for @a exchange_sig
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_deposit (
- void *cls,
- const char *instance_id,
- struct GNUNET_TIME_Timestamp deposit_timestamp,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const char *exchange_url,
- const struct TALER_Amount *amount_with_fee,
- const struct TALER_Amount *deposit_fee,
- const struct TALER_Amount *refund_fee,
- const struct TALER_Amount *wire_fee,
- const struct TALER_MerchantWireHashP *h_wire,
- const struct TALER_ExchangeSignatureP *exchange_sig,
- const struct TALER_ExchangePublicKeyP *exchange_pub)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_timestamp (&deposit_timestamp), /* $3 */
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_string (exchange_url),
- TALER_PQ_query_param_amount (amount_with_fee), /* $6/$7 */
- TALER_PQ_query_param_amount (deposit_fee), /* $8, $9 */
- TALER_PQ_query_param_amount (refund_fee), /* $10, $11 */
- TALER_PQ_query_param_amount (wire_fee), /* $12, $13 */
- GNUNET_PQ_query_param_auto_from_type (h_wire), /* $14 */
- GNUNET_PQ_query_param_auto_from_type (exchange_sig), /* $15 */
- GNUNET_PQ_query_param_auto_from_type (exchange_pub), /* $16 */
- GNUNET_PQ_query_param_end
- };
-
- /* no preflight check here, run in transaction by caller! */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Storing deposit for instance `%s' h_contract_terms `%s', coin_pub: `%s', amount_with_fee: %s\n",
- instance_id,
- GNUNET_h2s (&h_contract_terms->hash),
- TALER_B2S (coin_pub),
- TALER_amount2s (amount_with_fee));
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_deposit",
- params);
-
-}
-
-
-/**
- * Closure for #lookup_refunds_cb().
- */
-struct LookupRefundsContext
-{
- /**
- * Function to call for each refund.
- */
- TALER_MERCHANTDB_RefundCallback rc;
-
- /**
- * Closure for @e rc.
- */
- void *rc_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Transaction result.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupRefundsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_refunds_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupRefundsContext *lrc = cls;
- struct PostgresClosure *pg = lrc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount refund_amount;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
- &refund_amount),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- lrc->rc (lrc->rc_cls,
- &coin_pub,
- &refund_amount);
- GNUNET_PQ_cleanup_result (rs); /* technically useless here */
- }
- lrc->qs = num_results;
-}
-
-
-/**
- * Obtain refunds associated with a contract.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id instance to lookup refunds for
- * @param h_contract_terms hash code of the contract
- * @param rc function to call for each coin on which there is a refund
- * @param rc_cls closure for @a rc
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_refunds (
- void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- TALER_MERCHANTDB_RefundCallback rc,
- void *rc_cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_end
- };
- struct LookupRefundsContext lrc = {
- .rc = rc,
- .rc_cls = rc_cls,
- .pg = pg
- };
- enum GNUNET_DB_QueryStatus qs;
-
- /* no preflight check here, run in transaction by caller! */
- TALER_LOG_DEBUG ("Looking for refund of h_contract_terms %s at `%s'\n",
- GNUNET_h2s (&h_contract_terms->hash),
- instance_id);
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_refunds",
- params,
- &lookup_refunds_cb,
- &lrc);
- if (0 >= qs)
- return qs;
- return lrc.qs;
-}
-
-
-/**
- * Mark contract as paid and store the current @a session_id
- * for which the contract was paid. Deletes the underlying order
- * and marks the locked stocks of the order as sold.
- *
- * @param cls closure
- * @param instance_id instance to mark contract as paid for
- * @param h_contract_terms hash of the contract that is now paid
- * @param session_id the session that paid the contract
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_mark_contract_paid (
- void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- const char *session_id)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_string (session_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_QueryParam uparams[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- /* Session ID must always be given by the caller. */
- GNUNET_assert (NULL != session_id);
-
- /* no preflight check here, run in transaction by caller! */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Marking h_contract_terms '%s' of %s as paid for session `%s'\n",
- GNUNET_h2s (&h_contract_terms->hash),
- instance_id,
- session_id);
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "mark_contract_paid",
- params);
- if (qs <= 0)
- return qs;
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "mark_inventory_sold",
- uparams);
- if (qs < 0)
- return qs; /* 0: no inventory management, that's OK! */
- /* ON DELETE CASCADE deletes from merchant_order_locks */
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_completed_order",
- uparams);
-}
-
-
-/**
- * Function called during aborts to refund a coin. Marks the
- * respective coin as refunded.
- *
- * @param cls closure
- * @param instance_id instance to refund payment for
- * @param h_contract_terms hash of the contract to refund coin for
- * @param refund_timestamp timestamp of the refund
- * @param coin_pub public key of the coin to refund (fully)
- * @param reason text justifying the refund
- * @return transaction status
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a coin_pub is unknown to us;
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
- * regardless of whether it actually increased the refund
- */
-static enum GNUNET_DB_QueryStatus
-postgres_refund_coin (void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- struct GNUNET_TIME_Timestamp refund_timestamp,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const char *reason)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_timestamp (&refund_timestamp),
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_string (reason),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "refund_coin",
- params);
-}
-
-
-/**
- * Retrieve contract terms given its @a order_id
- *
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order to lookup contract for
- * @param[out] h_contract_terms set to the hash of the contract.
- * @param[out] paid set to the payment status of the contract
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order_status (void *cls,
- const char *instance_id,
- const char *order_id,
- struct TALER_PrivateContractHashP *
- h_contract_terms,
- bool *paid)
-{
- struct PostgresClosure *pg = cls;
- uint8_t paid8;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
- h_contract_terms),
- GNUNET_PQ_result_spec_auto_from_type ("paid",
- &paid8),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_order_status",
- params,
- rs);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- *paid = (0 != paid8);
- else
- *paid = false; /* just to be safe(r) */
- return qs;
-}
-
-
-/**
- * Retrieve contract terms given its @a order_serial
- *
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_serial serial ID of the order to look up
- * @param[out] order_id set to ID of the order
- * @param[out] h_contract_terms set to the hash of the contract.
- * @param[out] paid set to the payment status of the contract
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order_status_by_serial (void *cls,
- const char *instance_id,
- uint64_t order_serial,
- char **order_id,
- struct TALER_PrivateContractHashP *
- h_contract_terms,
- bool *paid)
-{
- struct PostgresClosure *pg = cls;
- uint8_t paid8;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
- h_contract_terms),
- GNUNET_PQ_result_spec_auto_from_type ("paid",
- &paid8),
- GNUNET_PQ_result_spec_string ("order_id",
- order_id),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_order_status_by_serial",
- params,
- rs);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- *paid = (0 != paid8);
- else
- *paid = false; /* just to be safe(r) */
- return qs;
-}
-
-
-/**
- * Retrieve payment and wire status for a given @a order_serial and session ID.
- *
- * @param cls closure
- * @param order_serial identifies the order
- * @param session_id session for which to check the payment status, NULL for any
- * @param[out] paid set to the payment status of the contract
- * @param[out] wired set to the wire transfer status of the exchange payment
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_payment_status (void *cls,
- uint64_t order_serial,
- const char *session_id,
- bool *paid,
- bool *wired)
-{
- struct PostgresClosure *pg = cls;
- uint8_t paid8;
- uint8_t wired8;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("paid",
- &paid8),
- GNUNET_PQ_result_spec_auto_from_type ("wired",
- &wired8),
- GNUNET_PQ_result_spec_end
- };
- check_connection (pg);
- if (NULL == session_id)
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_payment_status",
- params,
- rs);
- }
- else
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_string (session_id),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_payment_status_session_id",
- params,
- rs);
- }
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- {
- *paid = (0 != paid8);
- *wired = (0 != wired8);
- }
- else
- {
- *paid = false; /* just to be safe(r) */
- *wired = false; /* just to be safe(r) */
- }
- return qs;
-}
-
-
-/**
- * Closure for lookup_deposits_by_order_cb().
- */
-struct LookupDepositsByOrderContext
-{
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Function to call with all results.
- */
- TALER_MERCHANTDB_DepositedCoinsCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Set to the query result.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupDepositsByOrderContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_deposits_by_order_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupDepositsByOrderContext *ldoc = cls;
- struct PostgresClosure *pg = ldoc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- uint64_t deposit_serial;
- char *exchange_url;
- struct TALER_MerchantWireHashP h_wire;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("deposit_serial",
- &deposit_serial),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_PQ_result_spec_auto_from_type ("h_wire",
- &h_wire),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &amount_with_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
- &deposit_fee),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ldoc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- ldoc->cb (ldoc->cb_cls,
- deposit_serial,
- exchange_url,
- &h_wire,
- &amount_with_fee,
- &deposit_fee,
- &coin_pub);
- GNUNET_PQ_cleanup_result (rs); /* technically useless here */
- }
- ldoc->qs = num_results;
-}
-
-
-/**
- * Retrieve details about coins that were deposited for an order.
- *
- * @param cls closure
- * @param order_serial identifies the order
- * @param cb function to call for each deposited coin
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_deposits_by_order (void *cls,
- uint64_t order_serial,
- TALER_MERCHANTDB_DepositedCoinsCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupDepositsByOrderContext ldoc = {
- .pg = pg,
- .cb = cb,
- .cb_cls = cb_cls
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_deposits_by_order",
- params,
- &lookup_deposits_by_order_cb,
- &ldoc);
- if (qs < 0)
- return qs;
- return ldoc.qs;
-}
-
-
-/**
- * Closure for lookup_deposits_by_order_cb().
- */
-struct LookupTransferDetailsByOrderContext
-{
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Function to call with all results.
- */
- TALER_MERCHANTDB_OrderTransferDetailsCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Set to the query result.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupTransferDetailsByOrderContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_transfer_details_by_order_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupTransferDetailsByOrderContext *ltdo = cls;
- struct PostgresClosure *pg = ltdo->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- struct TALER_WireTransferIdentifierRawP wtid;
- char *exchange_url;
- uint64_t deposit_serial;
- struct GNUNET_TIME_Timestamp execution_time;
- struct TALER_Amount deposit_value;
- struct TALER_Amount deposit_fee;
- uint8_t transfer_confirmed;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("deposit_serial",
- &deposit_serial),
- GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
- &execution_time),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_PQ_result_spec_auto_from_type ("wtid",
- &wtid),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
- &deposit_value),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
- &deposit_fee),
- GNUNET_PQ_result_spec_auto_from_type ("transfer_confirmed",
- &transfer_confirmed),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ltdo->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- ltdo->cb (ltdo->cb_cls,
- &wtid,
- exchange_url,
- execution_time,
- &deposit_value,
- &deposit_fee,
- (0 != transfer_confirmed));
- GNUNET_PQ_cleanup_result (rs); /* technically useless here */
- }
- ltdo->qs = num_results;
-}
-
-
-/**
- * Retrieve wire transfer details for all deposits associated with
- * a given @a order_serial.
- *
- * @param cls closure
- * @param order_serial identifies the order
- * @param cb function called with the wire transfer details
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer_details_by_order (
- void *cls,
- uint64_t order_serial,
- TALER_MERCHANTDB_OrderTransferDetailsCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupTransferDetailsByOrderContext ltdo = {
- .pg = pg,
- .cb = cb,
- .cb_cls = cb_cls
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- "lookup_transfer_details_by_order",
- params,
- &lookup_transfer_details_by_order_cb,
- &ltdo);
- if (qs < 0)
- return qs;
- return ltdo.qs;
-}
-
-
-/**
- * Insert wire transfer details for a deposit.
- *
- * @param cls closure
- * @param deposit_serial serial number of the deposit
- * @param dd deposit transfer data from the exchange to store
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_deposit_to_transfer (
- void *cls,
- uint64_t deposit_serial,
- const struct TALER_EXCHANGE_DepositData *dd)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&deposit_serial),
- TALER_PQ_query_param_amount (&dd->coin_contribution),
- GNUNET_PQ_query_param_timestamp (&dd->execution_time),
- GNUNET_PQ_query_param_auto_from_type (&dd->exchange_sig),
- GNUNET_PQ_query_param_auto_from_type (&dd->exchange_pub),
- GNUNET_PQ_query_param_auto_from_type (&dd->wtid),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_deposit_to_transfer",
- params);
-}
-
-
-/**
- * Set 'wired' status for an order to 'true'.
- *
- * @param cls closure
- * @param order_serial serial number of the order
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_mark_order_wired (void *cls,
- uint64_t order_serial)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "mark_order_wired",
- params);
-}
-
-
-/**
- * Closure for #process_refund_cb().
- */
-struct FindRefundContext
-{
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Updated to reflect total amount refunded so far.
- */
- struct TALER_Amount refunded_amount;
-
- /**
- * Set to the largest refund transaction ID encountered.
- */
- uint64_t max_rtransaction_id;
-
- /**
- * Set to true on hard errors.
- */
- bool err;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls closure, our `struct FindRefundContext`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-process_refund_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct FindRefundContext *ictx = cls;
- struct PostgresClosure *pg = ictx->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- /* Sum up existing refunds */
- struct TALER_Amount acc;
- uint64_t rtransaction_id;
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
- &acc),
- GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
- &rtransaction_id),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ictx->err = true;
- return;
- }
- if (0 >
- TALER_amount_add (&ictx->refunded_amount,
- &ictx->refunded_amount,
- &acc))
- {
- GNUNET_break (0);
- ictx->err = true;
- return;
- }
- ictx->max_rtransaction_id = GNUNET_MAX (ictx->max_rtransaction_id,
- rtransaction_id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Found refund of %s\n",
- TALER_amount2s (&acc));
- }
-}
-
-
-/**
- * Closure for #process_deposits_for_refund_cb().
- */
-struct InsertRefundContext
-{
- /**
- * Used to provide a connection to the db
- */
- struct PostgresClosure *pg;
-
- /**
- * Amount to which increase the refund for this contract
- */
- const struct TALER_Amount *refund;
-
- /**
- * Human-readable reason behind this refund
- */
- const char *reason;
-
- /**
- * Transaction status code.
- */
- enum TALER_MERCHANTDB_RefundStatus rs;
-};
-
-
-/**
- * Data extracted per coin.
- */
-struct RefundCoinData
-{
-
- /**
- * Public key of a coin.
- */
- struct TALER_CoinSpendPublicKeyP coin_pub;
-
- /**
- * Amount deposited for this coin.
- */
- struct TALER_Amount deposited_with_fee;
-
- /**
- * Amount refunded already for this coin.
- */
- struct TALER_Amount refund_amount;
-
- /**
- * Order serial (actually not really per-coin).
- */
- uint64_t order_serial;
-
- /**
- * Maximum rtransaction_id for this coin so far.
- */
- uint64_t max_rtransaction_id;
-
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls closure, our `struct InsertRefundContext`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-process_deposits_for_refund_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct InsertRefundContext *ctx = cls;
- struct PostgresClosure *pg = ctx->pg;
- struct TALER_Amount current_refund;
- struct RefundCoinData rcd[GNUNET_NZL (num_results)];
- struct GNUNET_TIME_Timestamp now;
-
- now = GNUNET_TIME_timestamp_get ();
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (ctx->refund->currency,
- &current_refund));
- memset (rcd, 0, sizeof (rcd));
- /* Pass 1: Collect amount of existing refunds into current_refund.
- * Also store existing refunded amount for each deposit in deposit_refund. */
- for (unsigned int i = 0; i<num_results; i++)
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &rcd[i].coin_pub),
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- &rcd[i].order_serial),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &rcd[i].deposited_with_fee),
- GNUNET_PQ_result_spec_end
- };
- struct FindRefundContext ictx = {
- .pg = pg
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
- return;
- }
-
- {
- enum GNUNET_DB_QueryStatus ires;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&rcd[i].coin_pub),
- GNUNET_PQ_query_param_uint64 (&rcd[i].order_serial),
- GNUNET_PQ_query_param_end
- };
-
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (ctx->refund->currency,
- &ictx.refunded_amount));
- ires = GNUNET_PQ_eval_prepared_multi_select (ctx->pg->conn,
- "find_refunds_by_coin",
- params,
- &process_refund_cb,
- &ictx);
- if ( (ictx.err) ||
- (GNUNET_DB_STATUS_HARD_ERROR == ires) )
- {
- GNUNET_break (0);
- ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
- return;
- }
- if (GNUNET_DB_STATUS_SOFT_ERROR == ires)
- {
- ctx->rs = TALER_MERCHANTDB_RS_SOFT_ERROR;
- return;
- }
- }
- if (0 >
- TALER_amount_add (&current_refund,
- &current_refund,
- &ictx.refunded_amount))
- {
- GNUNET_break (0);
- ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
- return;
- }
- rcd[i].refund_amount = ictx.refunded_amount;
- rcd[i].max_rtransaction_id = ictx.max_rtransaction_id;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Existing refund for coin %s is %s\n",
- TALER_B2S (&rcd[i].coin_pub),
- TALER_amount2s (&ictx.refunded_amount));
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Total existing refund is %s\n",
- TALER_amount2s (&current_refund));
-
- /* stop immediately if we are 'done' === amount already
- * refunded. */
- if (0 >= TALER_amount_cmp (ctx->refund,
- &current_refund))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Existing refund of %s at or above requested refund. Finished early.\n",
- TALER_amount2s (&current_refund));
- ctx->rs = TALER_MERCHANTDB_RS_SUCCESS;
- return;
- }
-
- /* Phase 2: Try to increase current refund until it matches desired refund */
- for (unsigned int i = 0; i<num_results; i++)
- {
- const struct TALER_Amount *increment;
- struct TALER_Amount left;
- struct TALER_Amount remaining_refund;
-
- /* How much of the coin is left after the existing refunds? */
- if (0 >
- TALER_amount_subtract (&left,
- &rcd[i].deposited_with_fee,
- &rcd[i].refund_amount))
- {
- GNUNET_break (0);
- ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
- return;
- }
-
- if ( (0 == left.value) &&
- (0 == left.fraction) )
- {
- /* coin was fully refunded, move to next coin */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Coin %s fully refunded, moving to next coin\n",
- TALER_B2S (&rcd[i].coin_pub));
- continue;
- }
-
- rcd[i].max_rtransaction_id++;
- /* How much of the refund is still to be paid back? */
- if (0 >
- TALER_amount_subtract (&remaining_refund,
- ctx->refund,
- &current_refund))
- {
- GNUNET_break (0);
- ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
- return;
- }
-
- /* By how much will we increase the refund for this coin? */
- if (0 >= TALER_amount_cmp (&remaining_refund,
- &left))
- {
- /* remaining_refund <= left */
- increment = &remaining_refund;
- }
- else
- {
- increment = &left;
- }
-
- if (0 >
- TALER_amount_add (&current_refund,
- &current_refund,
- increment))
- {
- GNUNET_break (0);
- ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
- return;
- }
-
- /* actually run the refund */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Coin %s deposit amount is %s\n",
- TALER_B2S (&rcd[i].coin_pub),
- TALER_amount2s (&rcd[i].deposited_with_fee));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Coin %s refund will be incremented by %s\n",
- TALER_B2S (&rcd[i].coin_pub),
- TALER_amount2s (increment));
- {
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&rcd[i].order_serial),
- GNUNET_PQ_query_param_uint64 (&rcd[i].max_rtransaction_id), /* already inc'ed */
- GNUNET_PQ_query_param_timestamp (&now),
- GNUNET_PQ_query_param_auto_from_type (&rcd[i].coin_pub),
- GNUNET_PQ_query_param_string (ctx->reason),
- TALER_PQ_query_param_amount (increment),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_refund",
- params);
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- GNUNET_break (0);
- ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
- return;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- ctx->rs = TALER_MERCHANTDB_RS_SOFT_ERROR;
- return;
- default:
- ctx->rs = (enum TALER_MERCHANTDB_RefundStatus) qs;
- break;
- }
- }
-
- /* stop immediately if we are done */
- if (0 == TALER_amount_cmp (ctx->refund,
- &current_refund))
- {
- ctx->rs = TALER_MERCHANTDB_RS_SUCCESS;
- return;
- }
- }
-
- /**
- * We end up here if not all of the refund has been covered.
- * Although this should be checked as the business should never
- * issue a refund bigger than the contract's actual price, we cannot
- * rely upon the frontend being correct.
- *///
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "The refund of %s is bigger than the order's value\n",
- TALER_amount2s (ctx->refund));
- ctx->rs = TALER_MERCHANTDB_RS_TOO_HIGH;
-}
-
-
-/**
- * Function called when some backoffice staff decides to award or
- * increase the refund on an existing contract. This function
- * MUST be called from within a transaction scope setup by the
- * caller as it executes multiple SQL statements.
- *
- * @param cls closure
- * @param instance_id instance identifier
- * @param order_id the order to increase the refund for
- * @param refund maximum refund to return to the customer for this contract
- * @param reason 0-terminated UTF-8 string giving the reason why the customer
- * got a refund (free form, business-specific)
- * @return transaction status
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a refund is ABOVE the amount we
- * were originally paid and thus the transaction failed;
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
- * regardless of whether it actually increased the refund beyond
- * what was already refunded (idempotency!)
- */
-static enum TALER_MERCHANTDB_RefundStatus
-postgres_increase_refund (void *cls,
- const char *instance_id,
- const char *order_id,
- const struct TALER_Amount *refund,
- const char *reason)
-{
- struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_end
- };
- struct InsertRefundContext ctx = {
- .pg = pg,
- .refund = refund,
- .reason = reason
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Asked to refund %s on order %s\n",
- TALER_amount2s (refund),
- order_id);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "find_deposits_for_refund",
- params,
- &process_deposits_for_refund_cb,
- &ctx);
- switch (qs)
- {
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- /* never paid, means we clearly cannot refund anything */
- return TALER_MERCHANTDB_RS_NO_SUCH_ORDER;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- return TALER_MERCHANTDB_RS_SOFT_ERROR;
- case GNUNET_DB_STATUS_HARD_ERROR:
- return TALER_MERCHANTDB_RS_HARD_ERROR;
- default:
- /* Got one or more deposits */
- return ctx.rs;
- }
-}
-
-
-/**
- * Closure for #lookup_refunds_detailed_cb().
- */
-struct LookupRefundsDetailedContext
-{
- /**
- * Function to call for each refund.
- */
- TALER_MERCHANTDB_RefundDetailCallback rc;
-
- /**
- * Closure for @e rc.
- */
- void *rc_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Transaction result.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct GetRefundsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_refunds_detailed_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupRefundsDetailedContext *lrdc = cls;
- struct PostgresClosure *pg = lrdc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- uint64_t refund_serial;
- struct GNUNET_TIME_Timestamp timestamp;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- uint64_t rtransaction_id;
- struct TALER_Amount refund_amount;
- char *reason;
- char *exchange_url;
- uint8_t pending8;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("refund_serial",
- &refund_serial),
- GNUNET_PQ_result_spec_timestamp ("refund_timestamp",
- &timestamp),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
- &rtransaction_id),
- GNUNET_PQ_result_spec_string ("reason",
- &reason),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
- &refund_amount),
- GNUNET_PQ_result_spec_auto_from_type ("pending",
- &pending8),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- lrdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- lrdc->rc (lrdc->rc_cls,
- refund_serial,
- timestamp,
- &coin_pub,
- exchange_url,
- rtransaction_id,
- reason,
- &refund_amount,
- 0 != pending8);
- GNUNET_PQ_cleanup_result (rs);
- }
- lrdc->qs = num_results;
-}
-
-
-/**
- * Obtain detailed refund data associated with a contract.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id instance to lookup refunds for
- * @param h_contract_terms hash code of the contract
- * @param rc function to call for each coin on which there is a refund
- * @param rc_cls closure for @a rc
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_refunds_detailed (
- void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- TALER_MERCHANTDB_RefundDetailCallback rc,
- void *rc_cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_end
- };
- struct LookupRefundsDetailedContext lrdc = {
- .rc = rc,
- .rc_cls = rc_cls,
- .pg = pg
- };
- enum GNUNET_DB_QueryStatus qs;
-
- /* no preflight check here, run in transaction by caller! */
- TALER_LOG_DEBUG ("Looking for refund %s + %s\n",
- GNUNET_h2s (&h_contract_terms->hash),
- instance_id);
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_refunds_detailed",
- params,
- &lookup_refunds_detailed_cb,
- &lrdc);
- if (0 >= qs)
- return qs;
- return lrdc.qs;
-}
-
-
-/**
- * Insert refund proof data from the exchange into the database.
- *
- * @param cls closure
- * @param refund_serial serial number of the refund
- * @param exchange_sig signature from exchange that coin was refunded
- * @param exchange_pub signing key that was used for @a exchange_sig
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_refund_proof (
- void *cls,
- uint64_t refund_serial,
- const struct TALER_ExchangeSignatureP *exchange_sig,
- const struct TALER_ExchangePublicKeyP *exchange_pub)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&refund_serial),
- GNUNET_PQ_query_param_auto_from_type (exchange_sig),
- GNUNET_PQ_query_param_auto_from_type (exchange_pub),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_refund_proof",
- params);
-}
-
-
-/**
- * Lookup refund proof data.
- *
- * @param cls closure
- * @param refund_serial serial number of the refund
- * @param[out] exchange_sig set to signature from exchange
- * @param[out] exchange_pub signing key that was used for @a exchange_sig
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_refund_proof (void *cls,
- uint64_t refund_serial,
- struct TALER_ExchangeSignatureP *exchange_sig,
- struct TALER_ExchangePublicKeyP *exchange_pub)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&refund_serial),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
- exchange_sig),
- GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
- exchange_pub),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_refund_proof",
- params,
- rs);
-}
-
-
-/**
- * Retrieve the order ID that was used to pay for a resource within a session.
- *
- * @param cls closure
- * @param instance_id identifying the instance
- * @param fulfillment_url URL that canonically identifies the resource
- * being paid for
- * @param session_id session id
- * @param[out] order_id where to store the order ID that was used when
- * paying for the resource URL
- * @return transaction status
- */
-enum GNUNET_DB_QueryStatus
-postgres_lookup_order_by_fulfillment (void *cls,
- const char *instance_id,
- const char *fulfillment_url,
- const char *session_id,
- char **order_id)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (fulfillment_url),
- GNUNET_PQ_query_param_string (session_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("order_id",
- order_id),
- GNUNET_PQ_result_spec_end
- };
-
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_order_by_fulfillment",
- params,
- rs);
-}
-
-
-/**
- * Insert information about a wire transfer the merchant has received.
- *
- * @param cls closure
- * @param instance_id the instance that received the transfer
- * @param exchange_url which exchange made the transfer
- * @param wtid identifier of the wire transfer
- * @param credit_amount how much did we receive
- * @param payto_uri what is the merchant's bank account that received the transfer
- * @param confirmed whether the transfer was confirmed by the merchant or
- * was merely claimed by the exchange at this point
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_transfer (
- void *cls,
- const char *instance_id,
- const char *exchange_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *credit_amount,
- const char *payto_uri,
- bool confirmed)
-{
- struct PostgresClosure *pg = cls;
- uint8_t confirmed8 = confirmed;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- TALER_PQ_query_param_amount (credit_amount),
- GNUNET_PQ_query_param_string (payto_uri),
- GNUNET_PQ_query_param_auto_from_type (&confirmed8),
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_transfer",
- params);
-}
-
-
-/**
- * Delete information about a transfer. Note that transfers
- * confirmed by the exchange cannot be deleted anymore.
- *
- * @param cls closure
- * @param instance_id instance to delete transfer of
- * @param transfer_serial_id transfer to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- * if deletion is prohibited OR transfer is unknown
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_transfer (void *cls,
- const char *instance_id,
- uint64_t transfer_serial_id)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&transfer_serial_id),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_transfer",
- params);
-}
-
-
-/**
- * Check if information about a transfer exists with the
- * backend. Returns no data, only the query status.
- *
- * @param cls closure
- * @param instance_id instance to delete transfer of
- * @param transfer_serial_id transfer to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
- * if the transfer record exists
- */
-static enum GNUNET_DB_QueryStatus
-postgres_check_transfer_exists (void *cls,
- const char *instance_id,
- uint64_t transfer_serial_id)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&transfer_serial_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "check_transfer_exists",
- params,
- rs);
-}
-
-
-/**
- * Lookup account serial by payto URI.
- *
- * @param cls closure
- * @param instance_id instance to lookup the account from
- * @param payto_uri what is the merchant's bank account to lookup
- * @param[out] account_serial serial number of the account
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_account (void *cls,
- const char *instance_id,
- const char *payto_uri,
- uint64_t *account_serial)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (payto_uri),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("account_serial",
- account_serial),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_account",
- params,
- rs);
-}
-
-
-/**
- * Insert information about a wire transfer the merchant has received.
- *
- * @param cls closure
- * @param instance_id instance to provide transfer details for
- * @param exchange_url which exchange made the transfer
- * @param payto_uri what is the merchant's bank account that received the transfer
- * @param wtid identifier of the wire transfer
- * @param td transfer details to store
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the @a wtid and @a exchange_uri are not known for this @a instance_id
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT on success
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_transfer_details (
- void *cls,
- const char *instance_id,
- const char *exchange_url,
- const char *payto_uri,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_EXCHANGE_TransferData *td)
-{
- struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
- uint64_t credit_serial;
- unsigned int retries;
-
- retries = 0;
- check_connection (pg);
-RETRY:
- if (MAX_RETRIES < ++retries)
- return GNUNET_DB_STATUS_SOFT_ERROR;
- if (GNUNET_OK !=
- postgres_start_read_committed (pg,
- "insert transfer details"))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- /* lookup credit serial */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_string (payto_uri),
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("credit_serial",
- &credit_serial),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_credit_serial",
- params,
- rs);
- if (0 > qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'lookup_credit_serial' for account %s and amount %s failed with status %d\n",
- payto_uri,
- TALER_amount2s (&td->total_amount),
- qs);
- return qs;
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- postgres_rollback (pg);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'lookup_credit_serial' for account %s failed with transfer unknown\n",
- payto_uri);
- return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
- }
- }
-
- /* update merchant_transfer_signatures table */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&credit_serial),
- TALER_PQ_query_param_amount (&td->total_amount),
- TALER_PQ_query_param_amount (&td->wire_fee),
- GNUNET_PQ_query_param_timestamp (&td->execution_time),
- GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig),
- GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_transfer_signature",
- params);
- if (0 > qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'insert_transfer_signature' failed with status %d\n",
- qs);
- return qs;
- }
- if (0 == qs)
- {
- postgres_rollback (pg);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'insert_transfer_signature' failed with status %d\n",
- qs);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- }
-
- /* Update transfer-coin association table */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Updating transfer-coin association table\n");
- for (unsigned int i = 0; i<td->details_length; i++)
- {
- const struct TALER_TrackTransferDetails *d = &td->details[i];
- uint64_t i64 = (uint64_t) i;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&credit_serial),
- GNUNET_PQ_query_param_uint64 (&i64),
- TALER_PQ_query_param_amount (&d->coin_value),
- TALER_PQ_query_param_amount (&d->coin_fee), /* deposit fee */
- GNUNET_PQ_query_param_auto_from_type (&d->coin_pub),
- GNUNET_PQ_query_param_auto_from_type (&d->h_contract_terms),
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_transfer_to_coin_mapping",
- params);
- if (0 > qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'insert_transfer_to_coin_mapping' failed with status %d\n",
- qs);
- return qs;
- }
- if (0 == qs)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "'insert_transfer_to_coin_mapping' failed at %u: deposit unknown\n",
- i);
- }
- }
- /* Update merchant_contract_terms 'wired' status: for all coins
- that were wired, set the respective order's "wired" status to
- true, *if* all other deposited coins associated with that order
- have also been wired (this time or earlier) */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Updating contract terms 'wired' status\n");
- for (unsigned int i = 0; i<td->details_length; i++)
- {
- const struct TALER_TrackTransferDetails *d = &td->details[i];
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&d->coin_pub),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_wired_by_coin_pub",
- params);
- if (0 > qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'update_wired_by_coin_pub' failed with status %d\n",
- qs);
- return qs;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Committing transaction...\n");
- qs = postgres_commit (pg);
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return qs;
-}
-
-
-/**
- * Obtain information about wire fees charged by an exchange,
- * including signature (so we have proof).
- *
- * @param cls closure
- * @param master_pub public key of the exchange
- * @param wire_method the wire method
- * @param contract_date date of the contract to use for the lookup
- * @param[out] fees wire fees charged
- * @param[out] start_date start of fee being used
- * @param[out] end_date end of fee being used
- * @param[out] master_sig signature of exchange over fee structure
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_wire_fee (void *cls,
- const struct TALER_MasterPublicKeyP *master_pub,
- const char *wire_method,
- struct GNUNET_TIME_Timestamp contract_date,
- struct TALER_WireFeeSet *fees,
- struct GNUNET_TIME_Timestamp *start_date,
- struct GNUNET_TIME_Timestamp *end_date,
- struct TALER_MasterSignatureP *master_sig)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_HashCode h_wire_method;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (master_pub),
- GNUNET_PQ_query_param_auto_from_type (&h_wire_method),
- GNUNET_PQ_query_param_timestamp (&contract_date),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
- &fees->wire),
- TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
- &fees->closing),
- GNUNET_PQ_result_spec_timestamp ("start_date",
- start_date),
- GNUNET_PQ_result_spec_timestamp ("end_date",
- end_date),
- GNUNET_PQ_result_spec_auto_from_type ("master_sig",
- master_sig),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- GNUNET_CRYPTO_hash (wire_method,
- strlen (wire_method) + 1,
- &h_wire_method);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_wire_fee",
- params,
- rs);
-}
-
-
-/**
- * Closure for #lookup_deposits_by_contract_and_coin_cb().
- */
-struct LookupDepositsByCnCContext
-{
- /**
- * Function to call for each deposit.
- */
- TALER_MERCHANTDB_CoinDepositCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Transaction result.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupDepositsByCnCContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_deposits_by_contract_and_coin_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupDepositsByCnCContext *ldcc = cls;
- struct PostgresClosure *pg = ldcc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- char *exchange_url;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
- struct TALER_Amount refund_fee;
- struct TALER_Amount wire_fee;
- struct TALER_MerchantWireHashP h_wire;
- struct GNUNET_TIME_Timestamp deposit_timestamp;
- struct GNUNET_TIME_Timestamp refund_deadline;
- struct TALER_ExchangeSignatureP exchange_sig;
- struct TALER_ExchangePublicKeyP exchange_pub;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &amount_with_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
- &deposit_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_fee",
- &refund_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
- &wire_fee),
- GNUNET_PQ_result_spec_auto_from_type ("h_wire",
- &h_wire),
- GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
- &deposit_timestamp),
- GNUNET_PQ_result_spec_timestamp ("refund_deadline",
- &refund_deadline),
- GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
- &exchange_sig),
- GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
- &exchange_pub),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ldcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- ldcc->cb (ldcc->cb_cls,
- exchange_url,
- &amount_with_fee,
- &deposit_fee,
- &refund_fee,
- &wire_fee,
- &h_wire,
- deposit_timestamp,
- refund_deadline,
- &exchange_sig,
- &exchange_pub);
- GNUNET_PQ_cleanup_result (rs);
- }
- ldcc->qs = num_results;
-}
-
-
-/**
- * Lookup information about coin payments by @a h_contract_terms and
- * @a coin_pub.
- *
- * @param cls closure
- * @param instance_id instance to lookup payments for
- * @param h_contract_terms proposal data's hashcode
- * @param coin_pub public key to use for the search
- * @param cb function to call with payment data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_deposits_by_contract_and_coin (
- void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- TALER_MERCHANTDB_CoinDepositCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_end
- };
- struct LookupDepositsByCnCContext ldcc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- "lookup_deposits_by_contract_and_coin",
- params,
- &lookup_deposits_by_contract_and_coin_cb,
- &ldcc);
- if (0 >= qs)
- return qs;
- return ldcc.qs;
-}
-
-
-/**
- * Lookup transfer status.
- *
- * @param cls closure
- * @param instance_id at which instance should we resolve the transfer
- * @param exchange_url the exchange that made the transfer
- * @param wtid wire transfer subject
- * @param[out] total_amount amount that was debited from our
- * aggregate balance at the exchange (in total, sum of
- * the wire transfer amount and the @a wire_fee)
- * @param[out] wire_fee the wire fee the exchange charged (only set if @a have_exchange_sig is true)
- * @param[out] exchange_amount the amount the exchange claims was transferred (only set if @a have_exchange_sig is true)
- * @param[out] execution_time when the transfer was executed by the exchange (only set if @a have_exchange_sig is true)
- * @param[out] have_exchange_sig do we have a response from the exchange about this transfer
- * @param[out] verified did we confirm the transfer was OK
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer (
- void *cls,
- const char *instance_id,
- const char *exchange_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- struct TALER_Amount *total_amount,
- struct TALER_Amount *wire_fee,
- struct TALER_Amount *exchange_amount,
- struct GNUNET_TIME_Timestamp *execution_time,
- bool *have_exchange_sig,
- bool *verified)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_end
- };
- uint8_t verified8;
- /** Amount we got actually credited, _excludes_ the wire fee */
- bool no_sig;
- struct TALER_Amount credit_amount;
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("credit_amount",
- &credit_amount),
- GNUNET_PQ_result_spec_allow_null (
- TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
- wire_fee),
- &no_sig),
- GNUNET_PQ_result_spec_allow_null (
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_amount",
- exchange_amount),
- NULL),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_timestamp ("execution_time",
- execution_time),
- NULL),
- GNUNET_PQ_result_spec_auto_from_type ("verified",
- &verified8),
- GNUNET_PQ_result_spec_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- *execution_time = GNUNET_TIME_UNIT_ZERO_TS;
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_transfer",
- params,
- rs);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Lookup transfer returned %d\n",
- qs);
- if (qs > 0)
- {
- *have_exchange_sig = ! no_sig;
- *verified = (0 != verified8);
- if ( (! no_sig) &&
- (0 >
- TALER_amount_add (total_amount,
- &credit_amount,
- wire_fee)) )
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- }
- else
- {
- *verified = false;
- *have_exchange_sig = false;
- }
- return qs;
-}
-
-
-/**
- * Set transfer status to verified.
- *
- * @param cls closure
- * @param exchange_url the exchange that made the transfer
- * @param wtid wire transfer subject
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_set_transfer_status_to_verified (
- void *cls,
- const char *exchange_url,
- const struct TALER_WireTransferIdentifierRawP *wtid)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (
- pg->conn,
- "set_transfer_status_to_verified",
- params);
-}
-
-
-/**
- * Closure for #lookup_transfer_summary_cb().
- */
-struct LookupTransferSummaryContext
-{
- /**
- * Function to call for each order that was aggregated.
- */
- TALER_MERCHANTDB_TransferSummaryCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Transaction result.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupTransferSummaryContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_transfer_summary_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupTransferSummaryContext *ltdc = cls;
- struct PostgresClosure *pg = ltdc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- char *order_id;
- struct TALER_Amount deposit_value;
- struct TALER_Amount deposit_fee;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("order_id",
- &order_id),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
- &deposit_value),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
- &deposit_fee),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- ltdc->cb (ltdc->cb_cls,
- order_id,
- &deposit_value,
- &deposit_fee);
- GNUNET_PQ_cleanup_result (rs);
- }
- ltdc->qs = num_results;
-}
-
-
-/**
- * Lookup transfer summary.
- *
- * @param cls closure
- * @param exchange_url the exchange that made the transfer
- * @param wtid wire transfer subject
- * @param cb function to call with detailed transfer data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer_summary (
- void *cls,
- const char *exchange_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_MERCHANTDB_TransferSummaryCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_end
- };
- struct LookupTransferSummaryContext ltdc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- "lookup_transfer_summary",
- params,
- &lookup_transfer_summary_cb,
- &ltdc);
- if (0 >= qs)
- return qs;
- return ltdc.qs;
-}
-
-
-/**
- * Closure for #lookup_transfer_details_cb().
- */
-struct LookupTransferDetailsContext
-{
- /**
- * Function to call for each order that was aggregated.
- */
- TALER_MERCHANTDB_TransferDetailsCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Transaction result.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupTransferDetailsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_transfer_details_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupTransferDetailsContext *ltdc = cls;
- struct PostgresClosure *pg = ltdc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- uint64_t current_offset;
- struct TALER_TrackTransferDetails ttd;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("offset_in_exchange_list",
- &current_offset),
- GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
- &ttd.h_contract_terms),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &ttd.coin_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
- &ttd.coin_value),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
- &ttd.coin_fee),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- ltdc->cb (ltdc->cb_cls,
- (unsigned int) current_offset,
- &ttd);
- GNUNET_PQ_cleanup_result (rs);
- }
- ltdc->qs = num_results;
-}
-
-
-/**
- * Lookup transfer details.
- *
- * @param cls closure
- * @param exchange_url the exchange that made the transfer
- * @param wtid wire transfer subject
- * @param cb function to call with detailed transfer data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer_details (
- void *cls,
- const char *exchange_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_MERCHANTDB_TransferDetailsCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_end
- };
- struct LookupTransferDetailsContext ltdc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- "lookup_transfer_details",
- params,
- &lookup_transfer_details_cb,
- &ltdc);
- if (0 >= qs)
- return qs;
- return ltdc.qs;
-}
-
-
-/**
- * Closure for #lookup_transfers_cb().
- */
-struct LookupTransfersContext
-{
- /**
- * Function to call on results.
- */
- TALER_MERCHANTDB_TransferCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Postgres context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Transaction status (set).
- */
- enum GNUNET_DB_QueryStatus qs;
-
- /**
- * Filter to apply by verification status.
- */
- enum TALER_EXCHANGE_YesNoAll verified;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupTransfersContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_transfers_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupTransfersContext *ltc = cls;
- struct PostgresClosure *pg = ltc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- struct TALER_Amount credit_amount;
- struct TALER_WireTransferIdentifierRawP wtid;
- char *payto_uri;
- char *exchange_url;
- uint64_t transfer_serial_id;
- struct GNUNET_TIME_Timestamp execution_time;
- enum TALER_EXCHANGE_YesNoAll verified;
- uint8_t verified8;
- uint8_t confirmed8;
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("credit_amount",
- &credit_amount),
- GNUNET_PQ_result_spec_auto_from_type ("wtid",
- &wtid),
- GNUNET_PQ_result_spec_string ("payto_uri",
- &payto_uri),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_PQ_result_spec_uint64 ("credit_serial",
- &transfer_serial_id),
- GNUNET_PQ_result_spec_timestamp ("execution_time",
- &execution_time),
- GNUNET_PQ_result_spec_auto_from_type ("verified",
- &verified8),
- GNUNET_PQ_result_spec_auto_from_type ("confirmed",
- &confirmed8),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ltc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- if (0 == verified8)
- verified = TALER_EXCHANGE_YNA_NO;
- else
- verified = TALER_EXCHANGE_YNA_YES;
- if ( (ltc->verified == TALER_EXCHANGE_YNA_ALL) ||
- (ltc->verified == verified) )
- {
- ltc->cb (ltc->cb_cls,
- &credit_amount,
- &wtid,
- payto_uri,
- exchange_url,
- transfer_serial_id,
- execution_time,
- TALER_EXCHANGE_YNA_YES == verified,
- 0 != confirmed8);
- }
- GNUNET_PQ_cleanup_result (rs);
- }
- ltc->qs = num_results;
-}
-
-
-/**
- * Lookup transfers. Note that filtering by @a verified status is done
- * outside of SQL, as we already have 8 prepared statements and adding
- * a filter on verified would further double the number of statements for
- * a likely rather ineffective filter. So we apply that filter in
- * #lookup_transfers_cb().
- *
- * @param cls closure
- * @param instance_id instance to lookup payments for
- * @param payto_uri account that we are interested in transfers to
- * @param before timestamp for the earliest transfer we care about
- * @param after timestamp for the last transfer we care about
- * @param limit number of entries to return, negative for descending in execution time,
- * positive for ascending in execution time
- * @param offset transfer_serial number of the transfer we want to offset from
- * @param verified filter transfers by verification status
- * @param cb function to call with detailed transfer data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfers (void *cls,
- const char *instance_id,
- const char *payto_uri,
- struct GNUNET_TIME_Timestamp before,
- struct GNUNET_TIME_Timestamp after,
- int64_t limit,
- uint64_t offset,
- enum TALER_EXCHANGE_YesNoAll verified,
- TALER_MERCHANTDB_TransferCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- uint64_t plimit = (uint64_t) ((limit < 0) ? -limit : limit);
- struct LookupTransfersContext ltc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg,
- .verified = verified
- };
- enum GNUNET_DB_QueryStatus qs;
- bool by_time;
-
- by_time = ( (! GNUNET_TIME_absolute_is_never (before.abs_time)) ||
- (! GNUNET_TIME_absolute_is_zero (after.abs_time)) );
- check_connection (pg);
- if (by_time)
- {
- if (NULL != payto_uri)
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_timestamp (&before),
- GNUNET_PQ_query_param_timestamp (&after),
- GNUNET_PQ_query_param_uint64 (&offset),
- GNUNET_PQ_query_param_uint64 (&plimit),
- GNUNET_PQ_query_param_string (payto_uri),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- (limit > 0)
- ? "lookup_transfers_time_payto_asc"
- : "lookup_transfers_time_payto_desc",
- params,
- &lookup_transfers_cb,
- &ltc);
- }
- else
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_timestamp (&before),
- GNUNET_PQ_query_param_timestamp (&after),
- GNUNET_PQ_query_param_uint64 (&offset),
- GNUNET_PQ_query_param_uint64 (&plimit),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- (limit > 0)
- ? "lookup_transfers_time_asc"
- : "lookup_transfers_time_desc",
- params,
- &lookup_transfers_cb,
- &ltc);
- }
- }
- else
- {
- if (NULL != payto_uri)
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&offset),
- GNUNET_PQ_query_param_uint64 (&plimit),
- GNUNET_PQ_query_param_string (payto_uri),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- (limit > 0)
- ? "lookup_transfers_payto_asc"
- : "lookup_transfers_payto_desc",
- params,
- &lookup_transfers_cb,
- &ltc);
- }
- else
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&offset),
- GNUNET_PQ_query_param_uint64 (&plimit),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- (limit > 0)
- ? "lookup_transfers_asc"
- : "lookup_transfers_desc",
- params,
- &lookup_transfers_cb,
- &ltc);
- }
- }
- if (0 >= qs)
- return qs;
- return ltc.qs;
-}
-
-
-/**
- * Store information about wire fees charged by an exchange,
- * including signature (so we have proof).
- *
- * @param cls closure
- * @param master_pub public key of the exchange
- * @param h_wire_method hash of wire method
- * @param fees the fee charged
- * @param start_date start of fee being used
- * @param end_date end of fee being used
- * @param master_sig signature of exchange over fee structure
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_store_wire_fee_by_exchange (
- void *cls,
- const struct TALER_MasterPublicKeyP *master_pub,
- const struct GNUNET_HashCode *h_wire_method,
- const struct TALER_WireFeeSet *fees,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp end_date,
- const struct TALER_MasterSignatureP *master_sig)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (master_pub),
- GNUNET_PQ_query_param_auto_from_type (h_wire_method),
- TALER_PQ_query_param_amount (&fees->wire),
- TALER_PQ_query_param_amount (&fees->closing),
- GNUNET_PQ_query_param_timestamp (&start_date),
- GNUNET_PQ_query_param_timestamp (&end_date),
- GNUNET_PQ_query_param_auto_from_type (master_sig),
- GNUNET_PQ_query_param_end
- };
-
- /* no preflight check here, run in its own transaction by the caller */
- check_connection (pg);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Storing wire fee for %s starting at %s of %s\n",
- TALER_B2S (master_pub),
- GNUNET_TIME_timestamp2s (start_date),
- TALER_amount2s (&fees->wire));
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_wire_fee",
- params);
-}
-
-
-/**
- * Add @a credit to a reserve to be used for tipping. Note that
- * this function does not actually perform any wire transfers to
- * credit the reserve, it merely tells the merchant backend that
- * a reserve now exists. This has to happen before tips can be
- * authorized.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance is the reserve tied to
- * @param reserve_priv which reserve is topped up or created
- * @param reserve_pub which reserve is topped up or created
- * @param exchange_url what URL is the exchange reachable at where the reserve is located
- * @param payto_uri URI to use to fund the reserve
- * @param initial_balance how much money will be added to the reserve
- * @param expiration when does the reserve expire?
- * @return transaction status, usually
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- */
-static enum TALER_ErrorCode
-postgres_insert_reserve (void *cls,
- const char *instance_id,
- const struct TALER_ReservePrivateKeyP *reserve_priv,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const char *exchange_url,
- const char *payto_uri,
- const struct TALER_Amount *initial_balance,
- struct GNUNET_TIME_Timestamp expiration)
-{
- struct PostgresClosure *pg = cls;
- unsigned int retries;
- enum GNUNET_DB_QueryStatus qs;
-
- retries = 0;
- check_connection (pg);
-RETRY:
- if (MAX_RETRIES < ++retries)
- return TALER_EC_GENERIC_DB_SOFT_FAILURE;
- if (GNUNET_OK !=
- postgres_start (pg,
- "insert reserve"))
- {
- GNUNET_break (0);
- return TALER_EC_GENERIC_DB_START_FAILED;
- }
-
- /* Setup reserve */
- {
- struct GNUNET_TIME_Timestamp now;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_timestamp (&now),
- GNUNET_PQ_query_param_timestamp (&expiration),
- TALER_PQ_query_param_amount (initial_balance),
- GNUNET_PQ_query_param_end
- };
-
- now = GNUNET_TIME_timestamp_get ();
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_reserve",
- params);
- if (0 > qs)
- {
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return qs;
- }
- }
- /* Store private key */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_auto_from_type (reserve_priv),
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_string (payto_uri),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_reserve_key",
- params);
- if (0 > qs)
- {
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return qs;
- }
- }
- qs = postgres_commit (pg);
- if (0 <= qs)
- return TALER_EC_NONE; /* success */
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return qs;
-}
-
-
-/**
- * Confirms @a credit as the amount the exchange claims to have received and
- * thus really 'activates' the reserve. This has to happen before tips can
- * be authorized.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance is the reserve tied to
- * @param reserve_pub which reserve is topped up or created
- * @param initial_exchange_balance how much money was be added to the reserve
- * according to the exchange
- * @return transaction status, usually
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- */
-static enum GNUNET_DB_QueryStatus
-postgres_activate_reserve (void *cls,
- const char *instance_id,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_Amount *initial_exchange_balance)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- TALER_PQ_query_param_amount (initial_exchange_balance),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "activate_reserve",
- params);
-}
-
-
-/**
- * Closure for #lookup_reserves_cb.
- */
-struct LookupReservesContext
-{
- /**
- * Postgres context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Function to call with the results
- */
- TALER_MERCHANTDB_ReservesCallback cb;
-
- /**
- * Closure for @e cb
- */
- void *cb_cls;
-
- /**
- * Filter by active reserves.
- */
- enum TALER_EXCHANGE_YesNoAll active;
-
- /**
- * Filter by failures (mismatch in exchange claimed and
- * merchant claimed initial amounts).
- */
- enum TALER_EXCHANGE_YesNoAll failures;
-
- /**
- * Set in case of errors.
- */
- enum GNUNET_DB_QueryStatus qs;
-
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param[in,out] cls of type `struct LookupReservesContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_reserves_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupReservesContext *lrc = cls;
- struct PostgresClosure *pg = lrc->pg;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- struct TALER_ReservePublicKeyP reserve_pub;
- struct GNUNET_TIME_Timestamp creation_time;
- struct GNUNET_TIME_Timestamp expiration_time;
- struct TALER_Amount merchant_initial_balance;
- struct TALER_Amount exchange_initial_balance;
- struct TALER_Amount pickup_amount;
- struct TALER_Amount committed_amount;
- uint8_t active;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
- &reserve_pub),
- GNUNET_PQ_result_spec_timestamp ("creation_time",
- &creation_time),
- GNUNET_PQ_result_spec_timestamp ("expiration",
- &expiration_time),
- TALER_PQ_RESULT_SPEC_AMOUNT ("merchant_initial_balance",
- &merchant_initial_balance),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_initial_balance",
- &exchange_initial_balance),
- TALER_PQ_RESULT_SPEC_AMOUNT ("tips_committed",
- &committed_amount),
- TALER_PQ_RESULT_SPEC_AMOUNT ("tips_picked_up",
- &pickup_amount),
- GNUNET_PQ_result_spec_auto_from_type ("active",
- &active),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- switch (lrc->active)
- {
- case TALER_EXCHANGE_YNA_YES:
- if (0 == active)
- continue;
- break;
- case TALER_EXCHANGE_YNA_NO:
- if (0 != active)
- continue;
- break;
- case TALER_EXCHANGE_YNA_ALL:
- break;
- }
- switch (lrc->failures)
- {
- case TALER_EXCHANGE_YNA_YES:
- if (0 ==
- TALER_amount_cmp (&merchant_initial_balance,
- &exchange_initial_balance))
- continue;
- break;
- case TALER_EXCHANGE_YNA_NO:
- if (0 !=
- TALER_amount_cmp (&merchant_initial_balance,
- &exchange_initial_balance))
- continue;
- break;
- case TALER_EXCHANGE_YNA_ALL:
- break;
- }
- lrc->cb (lrc->cb_cls,
- &reserve_pub,
- creation_time,
- expiration_time,
- &merchant_initial_balance,
- &exchange_initial_balance,
- &pickup_amount,
- &committed_amount,
- (0 != active));
- }
-}
-
-
-/**
- * Lookup reserves.
- *
- * @param cls closure
- * @param instance_id instance to lookup payments for
- * @param created_after filter by reserves created after this date
- * @param active filter by active reserves
- * @param failures filter by reserves with a disagreement on the initial balance
- * @param cb function to call with reserve summary data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_reserves (void *cls,
- const char *instance_id,
- struct GNUNET_TIME_Timestamp created_after,
- enum TALER_EXCHANGE_YesNoAll active,
- enum TALER_EXCHANGE_YesNoAll failures,
- TALER_MERCHANTDB_ReservesCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupReservesContext lrc = {
- .pg = pg,
- .active = active,
- .failures = failures,
- .cb = cb,
- .cb_cls = cb_cls
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_timestamp (&created_after),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_reserves",
- params,
- &lookup_reserves_cb,
- &lrc);
- if (lrc.qs < 0)
- return lrc.qs;
- return qs;
-}
-
-
-/**
- * Closure for #lookup_pending_reserves_cb.
- */
-struct LookupPendingReservesContext
-{
- /**
- * Postgres context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Function to call with the results
- */
- TALER_MERCHANTDB_PendingReservesCallback cb;
-
- /**
- * Closure for @e cb
- */
- void *cb_cls;
-
- /**
- * Set in case of errors.
- */
- enum GNUNET_DB_QueryStatus qs;
-
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param[in,out] cls of type `struct LookupReservesContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_pending_reserves_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupPendingReservesContext *lrc = cls;
- struct PostgresClosure *pg = lrc->pg;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- struct TALER_ReservePublicKeyP reserve_pub;
- struct TALER_Amount merchant_initial_balance;
- char *exchange_url;
- char *instance_id;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
- &reserve_pub),
- GNUNET_PQ_result_spec_string ("merchant_id",
- &instance_id),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- TALER_PQ_RESULT_SPEC_AMOUNT ("merchant_initial_balance",
- &merchant_initial_balance),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- lrc->cb (lrc->cb_cls,
- instance_id,
- exchange_url,
- &reserve_pub,
- &merchant_initial_balance);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Lookup reserves pending activation across all instances.
- *
- * @param cls closure
- * @param cb function to call with reserve summary data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_pending_reserves (void *cls,
- TALER_MERCHANTDB_PendingReservesCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupPendingReservesContext lrc = {
- .pg = pg,
- .cb = cb,
- .cb_cls = cb_cls
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_pending_reserves",
- params,
- &lookup_pending_reserves_cb,
- &lrc);
- if (lrc.qs < 0)
- return lrc.qs;
- return qs;
-}
-
-
-/**
- * Closure for #lookup_reserve_tips_cb().
- */
-struct LookupTipsContext
-{
- /**
- * Postgres context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Array with information about tips generated from this reserve.
- */
- struct TALER_MERCHANTDB_TipDetails *tips;
-
- /**
- * Length of the @e tips array.
- */
- unsigned int tips_length;
-
- /**
- * Set in case of errors.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param[in,out] cls of type `struct LookupTipsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_reserve_tips_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupTipsContext *ltc = cls;
- struct PostgresClosure *pg = ltc->pg;
-
- GNUNET_array_grow (ltc->tips,
- ltc->tips_length,
- num_results);
- for (unsigned int i = 0; i < num_results; i++)
- {
- struct TALER_MERCHANTDB_TipDetails *td = &ltc->tips[i];
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("justification",
- &td->reason),
- GNUNET_PQ_result_spec_auto_from_type ("tip_id",
- &td->tip_id),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
- &td->total_amount),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ltc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- }
-}
-
-
-/**
- * Lookup reserve details.
- *
- * @param cls closure
- * @param instance_id instance to lookup payments for
- * @param reserve_pub public key of the reserve to inspect
- * @param fetch_tips if true, also return information about tips
- * @param cb function to call with reserve summary data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_reserve (void *cls,
- const char *instance_id,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- bool fetch_tips,
- TALER_MERCHANTDB_ReserveDetailsCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupTipsContext ltc = {
- .pg = pg,
- .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_TIME_Timestamp creation_time;
- struct GNUNET_TIME_Timestamp expiration_time;
- struct TALER_Amount merchant_initial_balance;
- struct TALER_Amount exchange_initial_balance;
- struct TALER_Amount pickup_amount;
- struct TALER_Amount committed_amount;
- uint8_t active;
- char *exchange_url = NULL;
- char *payto_uri = NULL;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_timestamp ("creation_time",
- &creation_time),
- GNUNET_PQ_result_spec_timestamp ("expiration",
- &expiration_time),
- TALER_PQ_RESULT_SPEC_AMOUNT ("merchant_initial_balance",
- &merchant_initial_balance),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_initial_balance",
- &exchange_initial_balance),
- TALER_PQ_RESULT_SPEC_AMOUNT ("tips_picked_up",
- &pickup_amount),
- TALER_PQ_RESULT_SPEC_AMOUNT ("tips_committed",
- &committed_amount),
- GNUNET_PQ_result_spec_auto_from_type ("active",
- &active),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- NULL),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("payto_uri",
- &payto_uri),
- NULL),
- GNUNET_PQ_result_spec_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_reserve",
- params,
- rs);
- if (qs < 0)
- return qs;
- if (! fetch_tips)
- {
- cb (cb_cls,
- creation_time,
- expiration_time,
- &merchant_initial_balance,
- &exchange_initial_balance,
- &pickup_amount,
- &committed_amount,
- (0 != active),
- exchange_url,
- payto_uri,
- 0,
- NULL);
- GNUNET_PQ_cleanup_result (rs);
- return qs;
- }
-
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_reserve_tips",
- params,
- &lookup_reserve_tips_cb,
- &ltc);
- if (qs < 0)
- return qs;
- if (ltc.qs >= 0)
- {
- cb (cb_cls,
- creation_time,
- expiration_time,
- &merchant_initial_balance,
- &exchange_initial_balance,
- &pickup_amount,
- &committed_amount,
- 0 != active,
- exchange_url,
- payto_uri,
- ltc.tips_length,
- ltc.tips);
- }
- for (unsigned int i = 0; i<ltc.tips_length; i++)
- GNUNET_free (ltc.tips[i].reason);
- GNUNET_array_grow (ltc.tips,
- ltc.tips_length,
- 0);
- GNUNET_PQ_cleanup_result (rs);
- return ltc.qs;
-}
-
-
-/**
- * Delete a reserve's private key.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance is the reserve tied to
- * @param reserve_pub which reserve is to be deleted
- * @return transaction status, usually
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_reserve (void *cls,
- const char *instance_id,
- const struct TALER_ReservePublicKeyP *reserve_pub)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_reserve",
- params);
-}
-
-
-/**
- * Purge all of the information about a reserve, including tips.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance is the reserve tied to
- * @param reserve_pub which reserve is to be purged
- * @return transaction status, usually
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- */
-static enum GNUNET_DB_QueryStatus
-postgres_purge_reserve (void *cls,
- const char *instance_id,
- const struct TALER_ReservePublicKeyP *reserve_pub)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "purge_reserve",
- params);
-}
-
-
-/**
- * Closure for #lookup_reserve_for_tip_cb().
- */
-struct LookupReserveForTipContext
-{
- /**
- * Postgres context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Public key of the reserve we found.
- */
- struct TALER_ReservePublicKeyP reserve_pub;
-
- /**
- * How much money must be left in the reserve.
- */
- struct TALER_Amount required_amount;
-
- /**
- * Set to the expiration time of the reserve we found.
- * #GNUNET_TIME_UNIT_FOREVER_ABS if we found none.
- */
- struct GNUNET_TIME_Timestamp expiration;
-
- /**
- * Error status.
- */
- enum TALER_ErrorCode ec;
-
- /**
- * Did we find a good reserve?
- */
- bool ok;
-};
-
-
-/**
- * How long must a reserve be at least still valid before we use
- * it for a tip?
- */
-#define MIN_EXPIRATION GNUNET_TIME_UNIT_HOURS
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param[in,out] cls of type `struct LookupReserveForTipContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_reserve_for_tip_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupReserveForTipContext *lac = cls;
- struct PostgresClosure *pg = lac->pg;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- struct TALER_ReservePublicKeyP reserve_pub;
- struct TALER_Amount committed_amount;
- struct TALER_Amount remaining;
- struct TALER_Amount initial_balance;
- struct GNUNET_TIME_Timestamp expiration;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
- &reserve_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_initial_balance",
- &initial_balance),
- TALER_PQ_RESULT_SPEC_AMOUNT ("tips_committed",
- &committed_amount),
- GNUNET_PQ_result_spec_timestamp ("expiration",
- &expiration),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- lac->ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
- return;
- }
- if (0 >
- TALER_amount_subtract (&remaining,
- &initial_balance,
- &committed_amount))
- {
- GNUNET_break (0);
- continue;
- }
- if (0 >
- TALER_amount_cmp (&remaining,
- &lac->required_amount))
- {
- /* insufficient balance */
- if (lac->ok)
- continue; /* got another reserve */
- lac->ec = TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_INSUFFICIENT_FUNDS;
- continue;
- }
- if ( (! GNUNET_TIME_absolute_is_never (lac->expiration.abs_time)) &&
- GNUNET_TIME_timestamp_cmp (expiration, >, lac->expiration) &&
- GNUNET_TIME_relative_cmp (
- GNUNET_TIME_absolute_get_remaining (lac->expiration.abs_time),
- >,
- MIN_EXPIRATION) )
- {
- /* reserve expired */
- if (lac->ok)
- continue; /* got another reserve */
- lac->ec = TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_EXPIRED;
- continue;
- }
- lac->ok = true;
- lac->ec = TALER_EC_NONE;
- lac->expiration = expiration;
- lac->reserve_pub = reserve_pub;
- }
-}
-
-
-/**
- * Authorize a tip over @a amount from reserve @a reserve_pub. Remember
- * the authorization under @a tip_id for later, together with the
- * @a justification.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance should generate the tip
- * @param reserve_pub which reserve is debited, NULL to pick one in the DB
- * @param amount how high is the tip (with fees)
- * @param justification why was the tip approved
- * @param next_url where to send the URL post tip pickup
- * @param[out] tip_id set to the unique ID for the tip
- * @param[out] expiration set to when the tip expires
- * @return transaction status,
- * #TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_EXPIRED if the reserve is known but has expired
- * #TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_NOT_FOUND if the reserve is not known
- * #TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_INSUFFICIENT_FUNDS if the reserve has insufficient funds left
- * #TALER_EC_GENERIC_DB_START_FAILED on hard DB errors
- * #TALER_EC_GENERIC_DB_FETCH_FAILED on hard DB errors
- * #TALER_EC_GENERIC_DB_STORE_FAILED on hard DB errors
- * #TALER_EC_GENERIC_DB_INVARIANT_FAILURE on hard DB errors
- * #TALER_EC_GENERIC_DB_SOFT_FAILURE soft DB errors (client should retry)
- * #TALER_EC_NONE upon success
- */
-static enum TALER_ErrorCode
-postgres_authorize_tip (void *cls,
- const char *instance_id,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_Amount *amount,
- const char *justification,
- const char *next_url,
- struct TALER_TipIdentifierP *tip_id,
- struct GNUNET_TIME_Timestamp *expiration)
-{
- struct PostgresClosure *pg = cls;
- unsigned int retries = 0;
- enum GNUNET_DB_QueryStatus qs;
- struct TALER_Amount tips_committed;
- struct TALER_Amount exchange_initial_balance;
- const struct TALER_ReservePublicKeyP *reserve_pubp;
- struct LookupReserveForTipContext lac = {
- .pg = pg,
- .required_amount = *amount,
- .expiration = GNUNET_TIME_UNIT_FOREVER_TS
- };
-
- check_connection (pg);
-RETRY:
- reserve_pubp = reserve_pub;
- if (MAX_RETRIES < ++retries)
- {
- GNUNET_break (0);
- return
- TALER_EC_GENERIC_DB_SOFT_FAILURE;
- }
- if (GNUNET_OK !=
- postgres_start (pg,
- "authorize tip"))
- {
- GNUNET_break (0);
- return TALER_EC_GENERIC_DB_START_FAILED;
- }
- if (NULL == reserve_pubp)
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_reserve_for_tip",
- params,
- &lookup_reserve_for_tip_cb,
- &lac);
- switch (qs)
- {
- case GNUNET_DB_STATUS_SOFT_ERROR:
- postgres_rollback (pg);
- goto RETRY;
- case GNUNET_DB_STATUS_HARD_ERROR:
- GNUNET_break (0);
- postgres_rollback (pg);
- return TALER_EC_GENERIC_DB_FETCH_FAILED;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- postgres_rollback (pg);
- return TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_NOT_FOUND;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- default:
- break;
- }
- if (TALER_EC_NONE != lac.ec)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Enabling tip reserved failed with status %d\n",
- lac.ec);
- postgres_rollback (pg);
- return lac.ec;
- }
- GNUNET_assert (lac.ok);
- reserve_pubp = &lac.reserve_pub;
- }
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pubp),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_timestamp ("expiration",
- expiration),
- TALER_PQ_RESULT_SPEC_AMOUNT ("tips_committed",
- &tips_committed),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_initial_balance",
- &exchange_initial_balance),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_reserve_status",
- params,
- rs);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- {
- postgres_rollback (pg);
- goto RETRY;
- }
- if (qs < 0)
- {
- GNUNET_break (0);
- postgres_rollback (pg);
- return TALER_EC_GENERIC_DB_FETCH_FAILED;
- }
- if (0 == qs)
- {
- postgres_rollback (pg);
- return TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_RESERVE_NOT_FOUND;
- }
- }
- {
- struct TALER_Amount remaining;
-
- if (0 >
- TALER_amount_subtract (&remaining,
- &exchange_initial_balance,
- &tips_committed))
- {
- GNUNET_break (0);
- postgres_rollback (pg);
- return TALER_EC_GENERIC_DB_INVARIANT_FAILURE;
- }
- if (0 >
- TALER_amount_cmp (&remaining,
- amount))
- {
- postgres_rollback (pg);
- return TALER_EC_MERCHANT_PRIVATE_POST_TIP_AUTHORIZE_INSUFFICIENT_FUNDS;
- }
- }
- GNUNET_assert (0 <=
- TALER_amount_add (&tips_committed,
- &tips_committed,
- amount));
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pubp),
- TALER_PQ_query_param_amount (&tips_committed),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_reserve_tips_committed",
- params);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- {
- postgres_rollback (pg);
- goto RETRY;
- }
- if (qs < 0)
- {
- GNUNET_break (0);
- postgres_rollback (pg);
- return TALER_EC_GENERIC_DB_STORE_FAILED;
- }
- }
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
- tip_id,
- sizeof (*tip_id));
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pubp),
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_string (justification),
- GNUNET_PQ_query_param_string (next_url),
- GNUNET_PQ_query_param_timestamp (expiration),
- TALER_PQ_query_param_amount (amount),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_tip",
- params);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- {
- postgres_rollback (pg);
- goto RETRY;
- }
- if (qs < 0)
- {
- GNUNET_break (0);
- postgres_rollback (pg);
- return TALER_EC_GENERIC_DB_STORE_FAILED;
- }
- }
- qs = postgres_commit (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- if (qs < 0)
- {
- GNUNET_break (0);
- postgres_rollback (pg);
- return TALER_EC_GENERIC_DB_COMMIT_FAILED;
- }
- return TALER_EC_NONE;
-}
-
-
-/**
- * Closure for #lookup_signatures_cb().
- */
-struct LookupSignaturesContext
-{
- /**
- * Length of the @e sigs array
- */
- unsigned int sigs_length;
-
- /**
- * Where to store the signatures.
- */
- struct TALER_BlindedDenominationSignature *sigs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param[in,out] cls of type `struct LookupSignaturesContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_signatures_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupSignaturesContext *lsc = cls;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- uint32_t offset;
- struct TALER_BlindedDenominationSignature bsig;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint32 ("coin_offset",
- &offset),
- TALER_PQ_result_spec_blinded_denom_sig ("blind_sig",
- &bsig),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- return;
- }
- if (offset >= lsc->sigs_length)
- {
- GNUNET_break_op (0);
- GNUNET_PQ_cleanup_result (rs);
- continue;
- }
- /* Must be NULL due to UNIQUE constraint on offset and
- requirement that client launched us with 'sigs'
- pre-initialized to NULL. */
- lsc->sigs[offset] = bsig;
- }
-}
-
-
-/**
- * Lookup pickup details for pickup @a pickup_id.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance should we lookup tip details for
- * @param tip_id which tip should we lookup details on
- * @param pickup_id which pickup should we lookup details on
- * @param[out] exchange_url which exchange is the tip withdrawn from
- * @param[out] reserve_priv private key the tip is withdrawn from (set if still available!)
- * @param sigs_length length of the @a sigs array
- * @param[out] sigs set to the (blind) signatures we have for this @a pickup_id,
- * those that are unavailable are left at NULL
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_pickup (void *cls,
- const char *instance_id,
- const struct TALER_TipIdentifierP *tip_id,
- const struct TALER_PickupIdentifierP *pickup_id,
- char **exchange_url,
- struct TALER_ReservePrivateKeyP *reserve_priv,
- unsigned int sigs_length,
- struct TALER_BlindedDenominationSignature sigs[])
-{
- struct PostgresClosure *pg = cls;
- uint64_t pickup_serial;
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_auto_from_type (pickup_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("exchange_url",
- exchange_url),
- GNUNET_PQ_result_spec_auto_from_type ("reserve_priv",
- reserve_priv),
- GNUNET_PQ_result_spec_uint64 ("pickup_serial",
- &pickup_serial),
- GNUNET_PQ_result_spec_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_pickup",
- params,
- rs);
- if (qs <= 0)
- return qs;
- }
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&pickup_serial),
- GNUNET_PQ_query_param_end
- };
- struct LookupSignaturesContext lsc = {
- .sigs_length = sigs_length,
- .sigs = sigs
- };
-
- return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_pickup_signatures",
- params,
- &lookup_signatures_cb,
- &lsc);
- }
-}
-
-
-/**
- * Lookup tip details for tip @a tip_id.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance should we lookup tip details for
- * @param tip_id which tip should we lookup details on
- * @param[out] total_authorized amount how high is the tip (with fees)
- * @param[out] total_picked_up how much of the tip was so far picked up (with fees)
- * @param[out] expiration set to when the tip expires
- * @param[out] exchange_url set to the exchange URL where the reserve is
- * @param[out] reserve_priv set to private key of reserve to be debited
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_tip (void *cls,
- const char *instance_id,
- const struct TALER_TipIdentifierP *tip_id,
- struct TALER_Amount *total_authorized,
- struct TALER_Amount *total_picked_up,
- struct GNUNET_TIME_Timestamp *expiration,
- char **exchange_url,
- struct TALER_ReservePrivateKeyP *reserve_priv)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
- total_authorized),
- TALER_PQ_RESULT_SPEC_AMOUNT ("picked_up",
- total_picked_up),
- GNUNET_PQ_result_spec_timestamp ("expiration",
- expiration),
- GNUNET_PQ_result_spec_string ("exchange_url",
- exchange_url),
- GNUNET_PQ_result_spec_auto_from_type ("reserve_priv",
- reserve_priv),
- GNUNET_PQ_result_spec_end
- };
-
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_tip",
- params,
- rs);
-}
-
-
-/**
- * Context used for postgres_lookup_tips().
- */
-struct LookupMerchantTipsContext
-{
- /**
- * Postgres context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Function to call with the results.
- */
- TALER_MERCHANTDB_TipsCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Internal result.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about tips.
- *
- * @param[in,out] cls of type `struct LookupTipsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_tips_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupMerchantTipsContext *plc = cls;
- struct PostgresClosure *pg = plc->pg;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- uint64_t row_id;
- struct TALER_TipIdentifierP tip_id;
- struct TALER_Amount tip_amount;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("tip_serial",
- &row_id),
- GNUNET_PQ_result_spec_auto_from_type ("tip_id",
- &tip_id),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
- &tip_amount),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- plc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- plc->cb (plc->cb_cls,
- row_id,
- tip_id,
- tip_amount);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Lookup tips
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance should we lookup tips for
- * @param expired should we include expired tips?
- * @param limit maximum number of results to return, positive for
- * ascending row id, negative for descending
- * @param offset row id to start returning results from
- * @param cb function to call with tip data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_tips (void *cls,
- const char *instance_id,
- enum TALER_EXCHANGE_YesNoAll expired,
- int64_t limit,
- uint64_t offset,
- TALER_MERCHANTDB_TipsCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupMerchantTipsContext plc = {
- .pg = pg,
- .cb = cb,
- .cb_cls = cb_cls
- };
- uint64_t ulimit = (limit > 0) ? limit : -limit;
- uint8_t bexpired;
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&ulimit),
- GNUNET_PQ_query_param_uint64 (&offset),
- GNUNET_PQ_query_param_absolute_time (&now),
- GNUNET_PQ_query_param_auto_from_type (&bexpired),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
- char stmt[128];
-
- bexpired = (TALER_EXCHANGE_YNA_YES == expired);
- GNUNET_snprintf (stmt,
- sizeof (stmt),
- "lookup_tips_%s%s",
- (limit > 0) ? "inc" : "dec",
- (TALER_EXCHANGE_YNA_ALL == expired) ? "" : "_expired");
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- stmt,
- params,
- &lookup_tips_cb,
- &plc);
- if (0 != plc.qs)
- return plc.qs;
- return qs;
-}
-
-
-/**
- * Closure for #lookup_pickup_details_cb().
- */
-struct LookupTipDetailsContext
-{
- /**
- * Length of the @e sigs array
- */
- unsigned int *pickups_length;
-
- /**
- * Where to store the signatures.
- */
- struct TALER_MERCHANTDB_PickupDetails **pickups;
-
- /**
- * Database handle.
- */
- struct PostgresClosure *pg;
-
- /**
- * Transaction status.
- */
- enum GNUNET_DB_QueryStatus qs;
-
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about pickups.
- *
- * @param[in,out] cls of type `struct LookupTipDetailsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_pickup_details_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupTipDetailsContext *ltdc = cls;
- struct PostgresClosure *pg = ltdc->pg;
-
- *ltdc->pickups_length = num_results;
- *ltdc->pickups = GNUNET_new_array (num_results,
- struct TALER_MERCHANTDB_PickupDetails);
- for (unsigned int i = 0; i < num_results; i++)
- {
- struct TALER_MERCHANTDB_PickupDetails *pd = &((*ltdc->pickups)[i]);
- uint64_t num_planchets = 0;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("pickup_id",
- &pd->pickup_id),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
- &pd->requested_amount),
- GNUNET_PQ_result_spec_uint64 ("num_planchets",
- &num_planchets),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- GNUNET_array_grow (*ltdc->pickups,
- *ltdc->pickups_length,
- 0);
- return;
- }
-
- pd->num_planchets = num_planchets;
- }
-}
-
-
-/**
- * Lookup tip details for tip @a tip_id.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance should we lookup tip details for
- * @param tip_id which tip should we lookup details on
- * @param fpu should we fetch details about individual pickups
- * @param[out] total_authorized amount how high is the tip (with fees)
- * @param[out] total_picked_up how much of the tip was so far picked up (with fees)
- * @param[out] justification why was the tip approved
- * @param[out] expiration set to when the tip expires
- * @param[out] reserve_pub set to which reserve is debited
- * @param[out] pickups_length set to the length of @e pickups
- * @param[out] pickups if @a fpu is true, set to details about the pickup operations
- * @return transaction status,
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_tip_details (void *cls,
- const char *instance_id,
- const struct TALER_TipIdentifierP *tip_id,
- bool fpu,
- struct TALER_Amount *total_authorized,
- struct TALER_Amount *total_picked_up,
- char **justification,
- struct GNUNET_TIME_Timestamp *expiration,
- struct TALER_ReservePublicKeyP *reserve_pub,
- unsigned int *pickups_length,
- struct TALER_MERCHANTDB_PickupDetails **pickups)
-{
- struct PostgresClosure *pg = cls;
- uint64_t tip_serial;
- enum GNUNET_DB_QueryStatus qs;
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("tip_serial",
- &tip_serial),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
- total_authorized),
- TALER_PQ_RESULT_SPEC_AMOUNT ("picked_up",
- total_picked_up),
- GNUNET_PQ_result_spec_string ("justification",
- justification),
- GNUNET_PQ_result_spec_timestamp ("expiration",
- expiration),
- GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
- reserve_pub),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_tip_details",
- params,
- rs);
- if (qs <= 0)
- return qs;
- if (! fpu)
- {
- *pickups_length = 0;
- *pickups = NULL;
- return qs;
- }
- }
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&tip_serial),
- GNUNET_PQ_query_param_end
- };
-
- struct LookupTipDetailsContext ltdc = {
- .pickups_length = pickups_length,
- .pickups = pickups,
- .pg = pg,
- .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
- };
-
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_pickup_details",
- params,
- &lookup_pickup_details_cb,
- &ltdc);
- if (qs < 0)
- return qs;
- return ltdc.qs;
- }
-}
-
-
-/**
- * Insert details about a tip pickup operation. The @a total_picked_up
- * UPDATES the total amount under the @a tip_id, while the @a
- * total_requested is the amount to be associated with this @a pickup_id.
- * While there is usually only one pickup event that picks up the entire
- * amount, our schema allows for wallets to pick up the amount incrementally
- * over multiple pick up operations.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance gave the tip
- * @param tip_id the unique ID for the tip
- * @param total_picked_up how much was picked up overall at this
- * point (includes @a total_requested)
- * @param pickup_id unique ID for the operation
- * @param total_requested how much is being picked up in this operation
- * @return transaction status, usually
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_pickup (void *cls,
- const char *instance_id,
- const struct TALER_TipIdentifierP *tip_id,
- const struct TALER_Amount *total_picked_up,
- const struct TALER_PickupIdentifierP *pickup_id,
- const struct TALER_Amount *total_requested)
-{
- struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_auto_from_type (pickup_id),
- TALER_PQ_query_param_amount (total_requested),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_pickup",
- params);
- if (0 > qs)
- return qs;
- }
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- TALER_PQ_query_param_amount (total_picked_up),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_picked_up_tip",
- params);
- if (0 > qs)
- return qs;
- }
- {
- uint64_t reserve_serial;
- struct TALER_Amount reserve_picked_up;
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (tip_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("reserve_serial",
- &reserve_serial),
- TALER_PQ_RESULT_SPEC_AMOUNT ("tips_picked_up",
- &reserve_picked_up),
- GNUNET_PQ_result_spec_end
-
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_picked_up_reserve",
- params,
- rs);
- if (0 > qs)
- return qs;
- }
- if (0 >=
- TALER_amount_add (&reserve_picked_up,
- &reserve_picked_up,
- total_requested))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&reserve_serial),
- TALER_PQ_query_param_amount (&reserve_picked_up),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_picked_up_reserve",
- params);
- if (0 > qs)
- return qs;
- }
- }
- return qs;
-}
-
-
-/**
- * Insert blind signature obtained from the exchange during a
- * tip pickup operation.
- *
- * @param cls closure, typically a connection to the db
- * @param pickup_id unique ID for the operation
- * @param offset offset of the blind signature for the pickup
- * @param blind_sig the blind signature
- * @return transaction status, usually
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_pickup_blind_signature (
- void *cls,
- const struct TALER_PickupIdentifierP *pickup_id,
- uint32_t offset,
- const struct TALER_BlindedDenominationSignature *blind_sig)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (pickup_id),
- GNUNET_PQ_query_param_uint32 (&offset),
- TALER_PQ_query_param_blinded_denom_sig (blind_sig),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_pickup_blind_signature",
- params);
-}
-
-
-/**
- * Delete information about a template.
- *
- * @param cls closure
- * @param instance_id instance to delete template of
- * @param template_id template to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- * if template unknown.
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_template (void *cls,
- const char *instance_id,
- const char *template_id)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (template_id),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_template",
- params);
-}
-
-
-/**
- * Insert details about a particular template.
- *
- * @param cls closure
- * @param instance_id instance to insert template for
- * @param template_id template identifier of template to insert
- * @param td the template details to insert
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_template (void *cls,
- const char *instance_id,
- const char *template_id,
- const struct TALER_MERCHANTDB_TemplateDetails *td)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (template_id),
- GNUNET_PQ_query_param_string (td->template_description),
- (NULL == td->image)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (td->image),
- TALER_PQ_query_param_json (td->template_contract),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_template",
- params);
-}
-
-
-/**
- * Update details about a particular template.
- *
- * @param cls closure
- * @param instance_id instance to update template for
- * @param template_id template to update
- * @param td update to the template details on success, can be NULL
- * (in that case we only want to check if the template exists)
- * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
- * does not yet exist.
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_template (void *cls,
- const char *instance_id,
- const char *template_id,
- const struct TALER_MERCHANTDB_TemplateDetails *td)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (template_id),
- GNUNET_PQ_query_param_string (td->template_description),
- (NULL == td->image)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (td->image),
- TALER_PQ_query_param_json (td->template_contract),
- GNUNET_PQ_query_param_end
- };
-
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_template",
- params);
-}
-
-
-/**
- * Context used for postgres_lookup_template().
- */
-struct LookupTemplateContext
-{
- /**
- * Function to call with the results.
- */
- TALER_MERCHANTDB_TemplatesCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Did database result extraction fail?
- */
- bool extract_failed;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about template.
- *
- * @param[in,out] cls of type `struct LookupTemplateContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_templates_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupTemplateContext *tlc = cls;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- char *template_id;
- char *template_description;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("template_id",
- &template_id),
- GNUNET_PQ_result_spec_string ("template_description",
- &template_description),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- tlc->extract_failed = true;
- return;
- }
- tlc->cb (tlc->cb_cls,
- template_id,
- template_description);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Lookup all of the templates the given instance has configured.
- *
- * @param cls closure
- * @param instance_id instance to lookup template for
- * @param cb function to call on all template found
- * @param cb_cls closure for @a cb
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_templates (void *cls,
- const char *instance_id,
- TALER_MERCHANTDB_TemplatesCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupTemplateContext tlc = {
- .cb = cb,
- .cb_cls = cb_cls,
- /* Can be overwritten by the lookup_template_cb */
- .extract_failed = false,
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_templates",
- params,
- &lookup_templates_cb,
- &tlc);
- /* If there was an error inside lookup_template_cb, return a hard error. */
- if (tlc.extract_failed)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
-
-
-/**
- * Lookup details about a particular template.
- *
- * @param cls closure
- * @param instance_id instance to lookup template for
- * @param template_id template to lookup
- * @param[out] td set to the template details on success, can be NULL
- * (in that case we only want to check if the template exists)
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_template (void *cls,
- const char *instance_id,
- const char *template_id,
- struct TALER_MERCHANTDB_TemplateDetails *td)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (template_id),
- GNUNET_PQ_query_param_end
- };
-
- if (NULL == td)
- {
- struct GNUNET_PQ_ResultSpec rs_null[] = {
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_template",
- params,
- rs_null);
- }
- else
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("template_description",
- &td->template_description),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("image",
- &td->image),
- NULL),
- TALER_PQ_result_spec_json ("template_contract",
- &td->template_contract),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- td->image = NULL;
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_template",
- params,
- rs);
- }
-}
-
-
-/**
- * Delete information about a webhook.
- *
- * @param cls closure
- * @param instance_id instance to delete webhook of
- * @param webhook_id webhook to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- * if webhook unknown.
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_webhook (void *cls,
- const char *instance_id,
- const char *webhook_id)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (webhook_id),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_webhook",
- params);
-}
-
-
-/**
- * Insert details about a particular webhook.
- *
- * @param cls closure
- * @param instance_id instance to insert webhook for
- * @param webhook_id webhook identifier of webhook to insert
- * @param wb the webhook details to insert
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_webhook (void *cls,
- const char *instance_id,
- const char *webhook_id,
- const struct TALER_MERCHANTDB_WebhookDetails *wb)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (webhook_id),
- GNUNET_PQ_query_param_string (wb->event_type),
- GNUNET_PQ_query_param_string (wb->url),
- GNUNET_PQ_query_param_string (wb->http_method),
- GNUNET_PQ_query_param_string (wb->header_template),
- GNUNET_PQ_query_param_string (wb->body_template),
- GNUNET_PQ_query_param_end
-
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_webhook",
- params);
-}
-
-
-/**
- * Update details about a particular webhook.
- *
- * @param cls closure
- * @param instance_id instance to update template for
- * @param webhook_id webhook to update
- * @param wb update to the webhook details on success, can be NULL
- * (in that case we only want to check if the webhook exists)
- * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the webhook
- * does not yet exist.
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_webhook (void *cls,
- const char *instance_id,
- const char *webhook_id,
- const struct TALER_MERCHANTDB_WebhookDetails *wb)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (webhook_id),
- GNUNET_PQ_query_param_string (wb->event_type),
- GNUNET_PQ_query_param_string (wb->url),
- GNUNET_PQ_query_param_string (wb->http_method),
- GNUNET_PQ_query_param_string (wb->header_template),
- GNUNET_PQ_query_param_string (wb->body_template),
- GNUNET_PQ_query_param_end
- };
-
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_webhook",
- params);
-}
-
-
-/**
- * Context used for postgres_lookup_webhook().
- */
-struct LookupWebhookContext
-{
- /**
- * Function to call with the results.
- */
- TALER_MERCHANTDB_WebhooksCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Did database result extraction fail?
- */
- bool extract_failed;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about webhook.
- *
- * @param[in,out] cls of type `struct LookupWebhookContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_webhooks_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupWebhookContext *wlc = cls;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- char *webhook_id;
- char *event_type;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("webhook_id",
- &webhook_id),
- GNUNET_PQ_result_spec_string ("event_type",
- &event_type),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- wlc->extract_failed = true;
- return;
- }
- wlc->cb (wlc->cb_cls,
- webhook_id,
- event_type);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Lookup all of the webhooks the given instance has configured.
- *
- * @param cls closure
- * @param instance_id instance to lookup webhook for
- * @param cb function to call on all webhook found
- * @param cb_cls closure for @a cb
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_webhooks (void *cls,
- const char *instance_id,
- TALER_MERCHANTDB_WebhooksCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupWebhookContext wlc = {
- .cb = cb,
- .cb_cls = cb_cls,
- /* Can be overwritten by the lookup_webhook_cb */
- .extract_failed = false,
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_webhooks",
- params,
- &lookup_webhooks_cb,
- &wlc);
- /* If there was an error inside lookup_webhook_cb, return a hard error. */
- if (wlc.extract_failed)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
-
-
-/**
- * Lookup details about a particular webhook.
- *
- * @param cls closure
- * @param instance_id instance to lookup webhook for
- * @param webhook_id webhook to lookup
- * @param[out] wb set to the webhook details on success, can be NULL
- * (in that case we only want to check if the webhook exists)
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_webhook (void *cls,
- const char *instance_id,
- const char *webhook_id,
- struct TALER_MERCHANTDB_WebhookDetails *wb)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (webhook_id),
- GNUNET_PQ_query_param_end
- };
-
- if (NULL == wb)
- {
- struct GNUNET_PQ_ResultSpec rs_null[] = {
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_webhook",
- params,
- rs_null);
- }
- else
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("event_type",
- &wb->event_type),
- GNUNET_PQ_result_spec_string ("url",
- &wb->url),
- GNUNET_PQ_result_spec_string ("http_method",
- &wb->http_method),
- GNUNET_PQ_result_spec_string ("header_template",
- &wb->header_template),
- GNUNET_PQ_result_spec_string ("body_template",
- &wb->body_template),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_webhook",
- params,
- rs);
- }
-}
-
-
-/**
- * Context used for postgres_lookup_webhook().
- */
-struct LookupWebhookDetailContext
-{
- /**
- * Function to call with the results.
- */
- TALER_MERCHANTDB_WebhookDetailCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Did database result extraction fail?
- */
- bool extract_failed;
-};
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about webhook.
- *
- * @param[in,out] cls of type `struct LookupPendingWebhookContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_webhook_by_event_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupWebhookDetailContext *wlc = cls;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- uint64_t webhook_serial;
- char *event_type;
- char *url;
- char *http_method;
- char *header_template;
- char *body_template;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("webhook_serial",
- &webhook_serial),
- GNUNET_PQ_result_spec_string ("event_type",
- &event_type),
- GNUNET_PQ_result_spec_string ("url",
- &url),
- GNUNET_PQ_result_spec_string ("http_method",
- &http_method),
- GNUNET_PQ_result_spec_string ("header_template",
- &header_template),
- GNUNET_PQ_result_spec_string ("body_template",
- &body_template),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- wlc->extract_failed = true;
- return;
- }
- wlc->cb (wlc->cb_cls,
- webhook_serial,
- event_type,
- url,
- http_method,
- header_template,
- body_template);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Lookup webhook by event
- *
- * @param cls closure
- * @param instance_id instance to lookup webhook for
- * @param event_type event that we need to put in the pending webhook
- * @param[out] cb set to the webhook details on success
- * @param cb_cls callback closure
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_webhook_by_event (void *cls,
- const char *instance_id,
- const char *event_type,
- TALER_MERCHANTDB_WebhookDetailCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupWebhookDetailContext wlc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .extract_failed = false,
- };
-
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (event_type),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_webhook_by_event",
- params,
- &lookup_webhook_by_event_cb,
- &wlc);
-
- if (wlc.extract_failed)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
-
-
-/**
- * Insert webhook in the pending webhook.
- *
- * @param cls closure
- * @param instance_id instance to insert webhook for
- * @param webhook_serial webhook to insert in the pending webhook
- * @param url to make the request to
- * @param http_method for the webhook
- * @param header of the webhook
- * @param body of the webhook
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_pending_webhook (void *cls,
- const char *instance_id,
- uint64_t webhook_serial,
- const char *url,
- const char *http_method,
- const char *header,
- const char *body)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&webhook_serial),
- GNUNET_PQ_query_param_string (url),
- GNUNET_PQ_query_param_string (http_method),
- NULL == header
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (header),
- NULL == body
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (body),
- GNUNET_PQ_query_param_end
- };
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_pending_webhook",
- params);
-}
-
-
-/**
- * Lookup details about a particular pending webhook.
- *
- * @param cls closure
- * @param instance_id instance to lookup webhook for
- * @param webhook_serial webhook to lookup
- * @param[out] pwb set to the pending webhook details on success, can be NULL
- * (in that case we only want to check if the webhook exists)
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_pending_webhook (void *cls,
- const char *instance_id,
- uint64_t *webhook_serial,
- struct TALER_MERCHANTDB_PendingWebhookDetails *
- pwb)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (webhook_serial),
- GNUNET_PQ_query_param_end
- };
-
- if (NULL == pwb)
- {
- struct GNUNET_PQ_ResultSpec rs_null[] = {
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_pending_webhook",
- params,
- rs_null);
- }
- else
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_absolute_time ("next_attempt",
- &pwb->next_attempt),
- GNUNET_PQ_result_spec_uint32 ("retries",
- &pwb->retries),
- GNUNET_PQ_result_spec_string ("url",
- &pwb->url),
- GNUNET_PQ_result_spec_string ("http_method",
- &pwb->http_method),
- GNUNET_PQ_result_spec_string ("header",
- &pwb->header),
- GNUNET_PQ_result_spec_string ("body",
- &pwb->body),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_pending_webhook",
- params,
- rs);
- }
-}
-
-
-/**
- * Context used for postgres_lookup_future_webhook().
- */
-struct LookupPendingWebhookContext
-{
- /**
- * Function to call with the results.
- */
- TALER_MERCHANTDB_PendingWebhooksCallback cb;
-
- /**
- * Closure for @a cb.
- */
- void *cb_cls;
-
- /**
- * Did database result extraction fail?
- */
- bool extract_failed;
-};
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about webhook.
- *
- * @param[in,out] cls of type `struct LookupPendingWebhookContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_pending_webhooks_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupPendingWebhookContext *pwlc = cls;
-
- for (unsigned int i = 0; i < num_results; i++)
- {
- uint64_t webhook_serial;
- struct GNUNET_TIME_Absolute next_attempt;
- uint32_t retries;
- char *url;
- char *http_method;
- char *header;
- char *body;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("webhook_serial",
- &webhook_serial),
- GNUNET_PQ_result_spec_absolute_time ("next_attempt",
- &next_attempt),
- GNUNET_PQ_result_spec_uint32 ("retries",
- &retries),
- GNUNET_PQ_result_spec_string ("url",
- &url),
- GNUNET_PQ_result_spec_string ("http_method",
- &http_method),
- GNUNET_PQ_result_spec_string ("header",
- &header),
- GNUNET_PQ_result_spec_string ("body",
- &body),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- pwlc->extract_failed = true;
- return;
- }
- pwlc->cb (pwlc->cb_cls,
- webhook_serial,
- next_attempt,
- retries,
- url,
- http_method,
- header,
- body);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-/**
- * Lookup the webhook that need to be send in priority.
- * send.
- *
- * @param cls closure
- * @param cb pending webhook callback
- * @param cb_cls callback closure
- */
-// WHERE next_attempt <= now ORDER BY next_attempt ASC
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_pending_webhooks (void *cls,
- TALER_MERCHANTDB_PendingWebhooksCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupPendingWebhookContext pwlc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .extract_failed = false,
- };
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_PQ_QueryParam params_null[] = {
- GNUNET_PQ_query_param_absolute_time (&now),
- GNUNET_PQ_query_param_end
- };
-
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_pending_webhooks",
- params_null,
- &lookup_pending_webhooks_cb,
- &pwlc);
-
- if (pwlc.extract_failed)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
-
-
-/**
- * Lookup future webhook in the pending webhook that need to be send.
- * With that we can know how long the system can 'sleep'.
- *
- * @param cls closure
- * @param cb pending webhook callback
- * @param cb_cls callback closure
- */
-// ORDER BY next_attempt ASC LIMIT 1
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_future_webhook (void *cls,
- TALER_MERCHANTDB_PendingWebhooksCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupPendingWebhookContext pwlc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .extract_failed = false,
- };
- struct GNUNET_PQ_QueryParam params_null[] = {
- GNUNET_PQ_query_param_end
- };
-
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_future_webhook",
- params_null,
- &lookup_pending_webhooks_cb,
- &pwlc);
-
- if (pwlc.extract_failed)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
-
-
-/**
- * Lookup all the webhooks in the pending webhook.
- * Use by the administrator
- *
- * @param cls closure
- * @param instance_id to lookup webhooks for this instance particularly
- * @param min_row to see the list of the pending webhook that it is started with this minimum row.
- * @param max_results to see the list of the pending webhook that it is end with this max results.
- * @param cb pending webhook callback
- * @param cb_cls callback closure
- */
-// WHERE webhook_pending_serial > min_row ORDER BY webhook_pending_serial ASC LIMIT max_results
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_all_webhooks (void *cls,
- const char *instance_id,
- uint64_t min_row,
- uint32_t max_results,
- TALER_MERCHANTDB_PendingWebhooksCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupPendingWebhookContext pwlc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .extract_failed = false,
- };
- uint64_t max_results64 = max_results;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&min_row),
- GNUNET_PQ_query_param_uint64 (&max_results64),
- GNUNET_PQ_query_param_end
- };
-
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_all_webhooks",
- params,
- &lookup_pending_webhooks_cb,
- &pwlc);
-
- if (pwlc.extract_failed)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
-
-
-/**
- * Update the pending webhook. It is use if the webhook can't be send.
- *
- * @param cls closure
- * @param webhook_serial webhook that need to be update
- * @param next_attempt when to try the webhook next
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_pending_webhook (void *cls,
- uint64_t webhook_serial,
- struct GNUNET_TIME_Absolute next_attempt)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&webhook_serial),
- GNUNET_PQ_query_param_absolute_time (&next_attempt),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_pending_webhook",
- params);
-}
-
-
-/**
- * Delete a webhook in the pending webhook after the
- * webhook was completed successfully.
- *
- * @param cls closure
- * @param webhook_serial webhook that need to be delete in the pending webhook
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_pending_webhook (void *cls,
- uint64_t webhook_serial)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&webhook_serial),
- GNUNET_PQ_query_param_end
- };
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_pending_webhook",
- params);
-}
-
-
-/**
* Establish connection to the database.
*
* @param cls plugin context
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-static int
+static enum GNUNET_GenericReturnValue
postgres_connect (void *cls)
{
struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_PreparedStatement ps[] = {
- GNUNET_PQ_make_prepare ("end_transaction",
- "COMMIT"),
- /* for call_with_accounts(), part of postgres_lookup_instances() */
- GNUNET_PQ_make_prepare ("lookup_instance_private_key",
- "SELECT"
- " merchant_priv"
- " FROM merchant_keys"
- " WHERE merchant_serial=$1"),
- /* for find_instances_cb(), part of postgres_lookup_instances() */
- GNUNET_PQ_make_prepare ("lookup_accounts",
- "SELECT"
- " h_wire"
- ",salt"
- ",payto_uri"
- ",active"
- " FROM merchant_accounts"
- " WHERE merchant_serial=$1"),
- /* for postgres_lookup_instances() */
- GNUNET_PQ_make_prepare ("lookup_instance_auth",
- "SELECT"
- " auth_hash"
- ",auth_salt"
- " FROM merchant_instances"
- " WHERE merchant_id=$1"),
- /* for postgres_lookup_instances() */
- GNUNET_PQ_make_prepare ("lookup_instances",
- "SELECT"
- " merchant_serial"
- ",merchant_pub"
- ",auth_hash"
- ",auth_salt"
- ",merchant_id"
- ",merchant_name"
- ",address"
- ",jurisdiction"
- ",default_max_deposit_fee_val"
- ",default_max_deposit_fee_frac"
- ",default_max_wire_fee_val"
- ",default_max_wire_fee_frac"
- ",default_wire_fee_amortization"
- ",default_wire_transfer_delay"
- ",default_pay_delay"
- ",website"
- ",email"
- ",logo"
- " FROM merchant_instances"),
- /* for postgres_lookup_instance() */
- GNUNET_PQ_make_prepare ("lookup_instance",
- "SELECT"
- " merchant_serial"
- ",merchant_pub"
- ",auth_hash"
- ",auth_salt"
- ",merchant_id"
- ",merchant_name"
- ",address"
- ",jurisdiction"
- ",default_max_deposit_fee_val"
- ",default_max_deposit_fee_frac"
- ",default_max_wire_fee_val"
- ",default_max_wire_fee_frac"
- ",default_wire_fee_amortization"
- ",default_wire_transfer_delay"
- ",default_pay_delay"
- ",website"
- ",email"
- ",logo"
- " FROM merchant_instances"
- " WHERE merchant_id=$1"),
- /* for postgres_insert_instance() */
- GNUNET_PQ_make_prepare ("insert_instance",
- "INSERT INTO merchant_instances"
- "(merchant_pub"
- ",auth_hash"
- ",auth_salt"
- ",merchant_id"
- ",merchant_name"
- ",address"
- ",jurisdiction"
- ",default_max_deposit_fee_val"
- ",default_max_deposit_fee_frac"
- ",default_max_wire_fee_val"
- ",default_max_wire_fee_frac"
- ",default_wire_fee_amortization"
- ",default_wire_transfer_delay"
- ",default_pay_delay"
- ",website"
- ",email"
- ",logo)"
- "VALUES"
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)"),
- /* for postgres_insert_instance() */
- GNUNET_PQ_make_prepare ("insert_keys",
- "INSERT INTO merchant_keys"
- "(merchant_priv"
- ",merchant_serial)"
- " SELECT $1, merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$2"),
- /* for postgres_account_kyc_set_status */
- GNUNET_PQ_make_prepare ("upsert_account_kyc",
- "INSERT INTO merchant_kyc"
- "(kyc_timestamp"
- ",kyc_ok"
- ",exchange_kyc_serial"
- ",account_serial"
- ",exchange_url"
- ",exchange_pub"
- ",exchange_sig)"
- " SELECT $5, $6, $4, account_serial, $3, $7, $8"
- " FROM merchant_instances"
- " JOIN merchant_accounts USING (merchant_serial)"
- " WHERE merchant_id=$1"
- " AND h_wire=$2"
- " ON CONFLICT(account_serial,exchange_url) DO "
- "UPDATE"
- " SET exchange_kyc_serial=$4"
- " ,kyc_timestamp=$5"
- " ,kyc_ok=$6"
- " ,exchange_pub=$7"
- " ,exchange_sig=$8"),
- /* for postgres_account_kyc_get_status */
- GNUNET_PQ_make_prepare ("lookup_kyc_status",
- "SELECT"
- " h_wire"
- ",exchange_kyc_serial"
- ",payto_uri"
- ",exchange_url"
- ",kyc_timestamp"
- ",kyc_ok"
- " FROM merchant_instances"
- " JOIN merchant_accounts"
- " USING (merchant_serial)"
- " JOIN merchant_kyc"
- " USING (account_serial)"
- " WHERE merchant_instances.merchant_id=$1"),
- /* for postgres_insert_account() */
- GNUNET_PQ_make_prepare ("insert_account",
- "INSERT INTO merchant_accounts"
- "(merchant_serial"
- ",h_wire"
- ",salt"
- ",payto_uri"
- ",active)"
- " SELECT merchant_serial, $2, $3, $4, $5"
- " FROM merchant_instances"
- " WHERE merchant_id=$1"),
- /* for postgres_delete_instance_private_key() */
- GNUNET_PQ_make_prepare ("delete_key",
- "DELETE FROM merchant_keys"
- " USING merchant_instances"
- " WHERE merchant_keys.merchant_serial"
- " = merchant_instances.merchant_serial"
- " AND merchant_instances.merchant_id = $1"),
- /* for postgres_purge_instance() */
- GNUNET_PQ_make_prepare ("purge_instance",
- "DELETE FROM merchant_instances"
- " WHERE merchant_instances.merchant_id = $1"),
- /* for postgres_update_instance() */
- GNUNET_PQ_make_prepare ("update_instance",
- "UPDATE merchant_instances SET"
- " merchant_name=$2"
- ",address=$3"
- ",jurisdiction=$4"
- ",default_max_deposit_fee_val=$5"
- ",default_max_deposit_fee_frac=$6"
- ",default_max_wire_fee_val=$7"
- ",default_max_wire_fee_frac=$8"
- ",default_wire_fee_amortization=$9"
- ",default_wire_transfer_delay=$10"
- ",default_pay_delay=$11"
- ",website=$12"
- ",email=$13"
- ",logo=$14"
- " WHERE merchant_id = $1"),
- /* for postgres_update_instance_auth() */
- GNUNET_PQ_make_prepare ("update_instance_auth",
- "UPDATE merchant_instances SET"
- " auth_hash=$2"
- ",auth_salt=$3"
- " WHERE merchant_id=$1"),
- /* for postgres_inactivate_account(); the merchant
- instance is implied from the random salt that
- is part of the h_wire calculation */
- GNUNET_PQ_make_prepare ("inactivate_account",
- "UPDATE merchant_accounts SET"
- " active=FALSE"
- " WHERE h_wire=$2 AND"
- " merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_activate_account() */
- GNUNET_PQ_make_prepare ("activate_account",
- "UPDATE merchant_accounts SET"
- " active=TRUE"
- " WHERE h_wire=$2 AND"
- " merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_lookup_products() */
- GNUNET_PQ_make_prepare ("lookup_products",
- "SELECT"
- " product_id"
- " FROM merchant_inventory"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"),
- /* for postgres_lookup_product() */
- GNUNET_PQ_make_prepare ("lookup_product",
- "SELECT"
- " description"
- ",description_i18n"
- ",unit"
- ",price_val"
- ",price_frac"
- ",taxes"
- ",total_stock"
- ",total_sold"
- ",total_lost"
- ",image"
- ",merchant_inventory.address"
- ",next_restock"
- ",minimum_age"
- " FROM merchant_inventory"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"
- " AND merchant_inventory.product_id=$2"),
- /* for postgres_delete_product() */
- GNUNET_PQ_make_prepare ("delete_product",
- "DELETE"
- " FROM merchant_inventory"
- " WHERE merchant_inventory.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND merchant_inventory.product_id=$2"
- " AND product_serial NOT IN "
- " (SELECT product_serial FROM merchant_order_locks)"
- " AND product_serial NOT IN "
- " (SELECT product_serial FROM merchant_inventory_locks)"),
- /* for postgres_insert_product() */
- GNUNET_PQ_make_prepare ("insert_product",
- "INSERT INTO merchant_inventory"
- "(merchant_serial"
- ",product_id"
- ",description"
- ",description_i18n"
- ",unit"
- ",image"
- ",taxes"
- ",price_val"
- ",price_frac"
- ",total_stock"
- ",address"
- ",next_restock"
- ",minimum_age"
- ")"
- " SELECT merchant_serial,"
- " $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13"
- " FROM merchant_instances"
- " WHERE merchant_id=$1"),
- /* for postgres_update_product() */
- GNUNET_PQ_make_prepare ("update_product",
- "UPDATE merchant_inventory SET"
- " description=$3"
- ",description_i18n=$4"
- ",unit=$5"
- ",image=$6"
- ",taxes=$7"
- ",price_val=$8"
- ",price_frac=$9"
- ",total_stock=$10"
- ",total_lost=$11"
- ",address=$12"
- ",next_restock=$13"
- ",minimum_age=$14"
- " WHERE merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND product_id=$2"
- " AND total_stock <= $10"
- " AND total_lost <= $11"),
-
- /* for postgres_lock_product() */
- GNUNET_PQ_make_prepare ("lock_product",
- "WITH ps AS"
- " (SELECT product_serial"
- " FROM merchant_inventory"
- " WHERE product_id=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"
- "INSERT INTO merchant_inventory_locks"
- "(product_serial"
- ",lock_uuid"
- ",total_locked"
- ",expiration)"
- " SELECT product_serial, $3, $4, $5"
- " FROM merchant_inventory"
- " JOIN ps USING (product_serial)"
- " WHERE "
- " total_stock - total_sold - total_lost - $4 >= "
- " (SELECT COALESCE(SUM(total_locked), 0)"
- " FROM merchant_inventory_locks"
- " WHERE product_serial=ps.product_serial) + "
- " (SELECT COALESCE(SUM(total_locked), 0)"
- " FROM merchant_order_locks"
- " WHERE product_serial=ps.product_serial)"),
-
- /* for postgres_expire_locks() */
- GNUNET_PQ_make_prepare ("unlock_products",
- "DELETE FROM merchant_inventory_locks"
- " WHERE expiration < $1"),
- /* for postgres_expire_locks() */
- GNUNET_PQ_make_prepare ("unlock_orders",
- "DELETE FROM merchant_orders"
- " WHERE pay_deadline < $1"),
- /* for postgres_expire_locks() */
- GNUNET_PQ_make_prepare ("unlock_contracts",
- "DELETE FROM merchant_contract_terms"
- " WHERE NOT paid"
- " AND pay_deadline < $1"),
-
- /* for postgres_delete_order() */
- GNUNET_PQ_make_prepare ("delete_order",
- "WITH ms AS"
- "(SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- ", mc AS"
- "(SELECT paid"
- " FROM merchant_contract_terms"
- " JOIN ms USING (merchant_serial)"
- " WHERE order_id=$2) "
- "DELETE"
- " FROM merchant_orders mo"
- " WHERE order_id=$2"
- " AND merchant_serial=(SELECT merchant_serial FROM ms)"
- " AND ( (pay_deadline < $3)"
- " OR (NOT EXISTS (SELECT paid FROM mc))"
- " OR ($4 AND (FALSE=(SELECT paid FROM mc))) );"),
- GNUNET_PQ_make_prepare ("delete_contract",
- "DELETE"
- " FROM merchant_contract_terms"
- " WHERE order_id=$2 AND"
- " merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND NOT paid;"),
- /* for postgres_lookup_order() */
- GNUNET_PQ_make_prepare ("lookup_order",
- "SELECT"
- " contract_terms"
- ",claim_token"
- ",h_post_data"
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND merchant_orders.order_id=$2"),
- /* for postgres_lookup_order_summary() */
- GNUNET_PQ_make_prepare ("lookup_order_summary",
- "(SELECT"
- " creation_time"
- ",order_serial"
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND merchant_contract_terms.order_id=$2)"
- "UNION"
- "(SELECT"
- " creation_time"
- ",order_serial"
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND merchant_orders.order_id=$2)"),
- /* for postgres_lookup_orders() */
- GNUNET_PQ_make_prepare ("lookup_orders_inc",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_paid",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($5) = paid"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_refunded",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " CAST($6 as BOOL) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_refunded",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_refunded_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_refunded_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_paid",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($5) = paid"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_refunded",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_refunded",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_refunded_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_refunded_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- /* for postgres_insert_order() */
- GNUNET_PQ_make_prepare ("insert_order",
- "INSERT INTO merchant_orders"
- "(merchant_serial"
- ",order_id"
- ",pay_deadline"
- ",claim_token"
- ",h_post_data"
- ",creation_time"
- ",contract_terms)"
- " SELECT merchant_serial,"
- " $2, $3, $4, $5, $6, $7"
- " FROM merchant_instances"
- " WHERE merchant_id=$1"),
- /* for postgres_unlock_inventory() */
- GNUNET_PQ_make_prepare ("unlock_inventory",
- "DELETE"
- " FROM merchant_inventory_locks"
- " WHERE lock_uuid=$1"),
- /* for postgres_insert_order_lock() */
- GNUNET_PQ_make_prepare ("insert_order_lock",
- "WITH tmp AS"
- " (SELECT "
- " product_serial"
- " ,merchant_serial"
- " ,total_stock"
- " ,total_sold"
- " ,total_lost"
- " FROM merchant_inventory"
- " WHERE product_id=$3"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"
- " INSERT INTO merchant_order_locks"
- " (product_serial"
- " ,total_locked"
- " ,order_serial)"
- " SELECT tmp.product_serial, $4, order_serial"
- " FROM merchant_orders"
- " JOIN tmp USING(merchant_serial)"
- " WHERE order_id=$2 AND"
- " tmp.total_stock - tmp.total_sold - tmp.total_lost - $4 >= "
- " (SELECT COALESCE(SUM(total_locked), 0)"
- " FROM merchant_inventory_locks"
- " WHERE product_serial=tmp.product_serial) + "
- " (SELECT COALESCE(SUM(total_locked), 0)"
- " FROM merchant_order_locks"
- " WHERE product_serial=tmp.product_serial)"),
- /* for postgres_lookup_contract_terms() */
- GNUNET_PQ_make_prepare ("lookup_contract_terms",
- "SELECT"
- " contract_terms"
- ",order_serial"
- ",claim_token"
- ",paid"
- " FROM merchant_contract_terms"
- " WHERE order_id=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_insert_contract_terms() */
- GNUNET_PQ_make_prepare ("insert_contract_terms",
- "INSERT INTO merchant_contract_terms"
- "(order_serial"
- ",merchant_serial"
- ",order_id"
- ",contract_terms"
- ",h_contract_terms"
- ",creation_time"
- ",pay_deadline"
- ",refund_deadline"
- ",fulfillment_url"
- ",claim_token)"
- "SELECT"
- " mo.order_serial"
- ",mo.merchant_serial"
- ",mo.order_id"
- ",$3" /* contract_terms */
- ",$4" /* h_contract_terms */
- ",mo.creation_time"
- ",$5" /* pay_deadline */
- ",$6" /* refund_deadline */
- ",$7" /* fulfillment_url */
- ",mo.claim_token "
- "FROM merchant_orders mo"
- " WHERE order_id=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " RETURNING order_serial"),
- /* for postgres_update_contract_terms() */
- GNUNET_PQ_make_prepare ("update_contract_terms",
- "UPDATE merchant_contract_terms SET"
- " contract_terms=$3"
- ",h_contract_terms=$4"
- ",pay_deadline=$5"
- ",refund_deadline=$6"
- ",fulfillment_url=$7"
- " WHERE order_id=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_delete_contract_terms() */
- GNUNET_PQ_make_prepare ("delete_contract_terms",
- "DELETE FROM merchant_contract_terms"
- " WHERE order_id=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND ( ( (pay_deadline < $4) AND"
- " (NOT paid) ) OR"
- " (creation_time + $3 < $4) )"),
- /* for postgres_lookup_deposits() */
- GNUNET_PQ_make_prepare ("lookup_deposits",
- "SELECT"
- " exchange_url"
- ",coin_pub"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",refund_fee_val"
- ",refund_fee_frac"
- ",wire_fee_val"
- ",wire_fee_frac"
- " FROM merchant_deposits"
- " WHERE order_serial="
- " (SELECT order_serial"
- " FROM merchant_contract_terms"
- " WHERE h_contract_terms=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"),
- /* for postgres_insert_exchange_signkey() */
- GNUNET_PQ_make_prepare ("insert_exchange_signkey",
- "INSERT INTO merchant_exchange_signing_keys"
- "(master_pub"
- ",exchange_pub"
- ",start_date"
- ",expire_date"
- ",end_date"
- ",master_sig)"
- "VALUES"
- "($1, $2, $3, $4, $5, $6)"),
- /* for postgres_insert_deposit() */
- GNUNET_PQ_make_prepare ("insert_deposit",
- "WITH md AS"
- " (SELECT account_serial, merchant_serial"
- " FROM merchant_accounts"
- " WHERE h_wire=$14"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"
- ", ed AS"
- " (SELECT signkey_serial"
- " FROM merchant_exchange_signing_keys"
- " WHERE exchange_pub=$16"
- " ORDER BY start_date DESC"
- " LIMIT 1)"
- "INSERT INTO merchant_deposits"
- "(order_serial"
- ",deposit_timestamp"
- ",coin_pub"
- ",exchange_url"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",refund_fee_val"
- ",refund_fee_frac"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",exchange_sig"
- ",signkey_serial"
- ",account_serial)"
- " SELECT "
- " order_serial"
- " ,$3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $15"
- " ,ed.signkey_serial"
- " ,md.account_serial"
- " FROM merchant_contract_terms"
- " JOIN md USING (merchant_serial)"
- " FULL OUTER JOIN ed ON TRUE"
- " WHERE h_contract_terms=$2"),
- /* for postgres_lookup_refunds() */
- GNUNET_PQ_make_prepare ("lookup_refunds",
- "SELECT"
- " coin_pub"
- ",refund_amount_val"
- ",refund_amount_frac"
- " FROM merchant_refunds"
- " WHERE order_serial="
- " (SELECT order_serial"
- " FROM merchant_contract_terms"
- " WHERE h_contract_terms=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"),
- /* for postgres_mark_contract_paid() */
- GNUNET_PQ_make_prepare ("mark_contract_paid",
- "UPDATE merchant_contract_terms SET"
- " paid=TRUE"
- ",session_id=$3"
- " WHERE h_contract_terms=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_mark_contract_paid() */
- GNUNET_PQ_make_prepare ("mark_inventory_sold",
- "UPDATE merchant_inventory SET"
- " total_sold=total_sold + order_locks.total_locked"
- " FROM (SELECT total_locked,product_serial"
- " FROM merchant_order_locks"
- " WHERE order_serial="
- " (SELECT order_serial"
- " FROM merchant_contract_terms"
- " WHERE h_contract_terms=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"
- " ) AS order_locks"
- " WHERE merchant_inventory.product_serial"
- " =order_locks.product_serial"),
- /* for postgres_mark_contract_paid() */
- GNUNET_PQ_make_prepare ("delete_completed_order",
- "WITH md AS"
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1) "
- "DELETE"
- " FROM merchant_orders"
- " WHERE order_serial="
- " (SELECT order_serial"
- " FROM merchant_contract_terms"
- " JOIN md USING (merchant_serial)"
- " WHERE h_contract_terms=$2)"),
- /* for postgres_refund_coin() */
- GNUNET_PQ_make_prepare ("refund_coin",
- "INSERT INTO merchant_refunds"
- "(order_serial"
- ",rtransaction_id"
- ",refund_timestamp"
- ",coin_pub"
- ",reason"
- ",refund_amount_val"
- ",refund_amount_frac"
- ") "
- "SELECT "
- " order_serial"
- ",0" /* rtransaction_id always 0 for /abort */
- ",$3"
- ",coin_pub"
- ",$5"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- " FROM merchant_deposits"
- " WHERE coin_pub=$4"
- " AND order_serial="
- " (SELECT order_serial"
- " FROM merchant_contract_terms"
- " WHERE h_contract_terms=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"),
-
- /* for postgres_lookup_order_status() */
- GNUNET_PQ_make_prepare ("lookup_order_status",
- "SELECT"
- " h_contract_terms"
- ",paid"
- " FROM merchant_contract_terms"
- " WHERE merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND order_id=$2"),
-
- /* for postgres_lookup_order_status_by_serial() */
- GNUNET_PQ_make_prepare ("lookup_order_status_by_serial",
- "SELECT"
- " h_contract_terms"
- ",order_id"
- ",paid"
- " FROM merchant_contract_terms"
- " WHERE merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND order_serial=$2"),
-
- /* for postgres_lookup_payment_status() */
- GNUNET_PQ_make_prepare ("lookup_payment_status",
- "SELECT"
- " wired"
- ",paid"
- " FROM merchant_contract_terms"
- " WHERE order_serial=$1"),
- /* for postgres_lookup_payment_status() */
- GNUNET_PQ_make_prepare ("lookup_payment_status_session_id",
- "SELECT"
- " wired"
- ",paid"
- " FROM merchant_contract_terms"
- " WHERE order_serial=$1"
- " AND session_id=$2"),
- /* for postgres_lookup_deposits_by_order() */
- GNUNET_PQ_make_prepare ("lookup_deposits_by_order",
- "SELECT"
- " deposit_serial"
- ",exchange_url"
- ",h_wire"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",coin_pub"
- " FROM merchant_deposits"
- " JOIN merchant_accounts USING (account_serial)"
- " WHERE order_serial=$1"),
- /* for postgres_lookup_transfer_details_by_order() */
- GNUNET_PQ_make_prepare ("lookup_transfer_details_by_order",
- "SELECT"
- " md.deposit_serial"
- ",md.exchange_url"
- ",mt.wtid"
- ",exchange_deposit_value_val"
- ",exchange_deposit_value_frac"
- ",exchange_deposit_fee_val"
- ",exchange_deposit_fee_frac"
- ",deposit_timestamp"
- ",mt.confirmed AS transfer_confirmed"
- " FROM merchant_transfer_to_coin"
- " JOIN merchant_deposits AS md USING (deposit_serial)"
- " JOIN merchant_transfers AS mt USING (credit_serial)"
- " WHERE deposit_serial IN"
- " (SELECT deposit_serial"
- " FROM merchant_deposits"
- " WHERE order_serial=$1)"),
- /* for postgres_insert_deposit_to_transfer() */
- GNUNET_PQ_make_prepare ("insert_deposit_to_transfer",
- "INSERT INTO merchant_deposit_to_transfer"
- "(deposit_serial"
- ",coin_contribution_value_val"
- ",coin_contribution_value_frac"
- ",credit_serial"
- ",execution_time"
- ",signkey_serial"
- ",exchange_sig"
- ") SELECT $1, $2, $3, credit_serial, $4, signkey_serial, $5"
- " FROM merchant_transfers"
- " CROSS JOIN merchant_exchange_signing_keys"
- " WHERE exchange_pub=$6"
- " AND wtid=$7"),
- /* for postgres_mark_order_wired() */
- GNUNET_PQ_make_prepare ("mark_order_wired",
- "UPDATE merchant_contract_terms SET"
- " wired=true"
- " WHERE order_serial=$1"),
- /* for process_refund_cb() used in postgres_increase_refund() */
- GNUNET_PQ_make_prepare ("find_refunds_by_coin",
- "SELECT"
- " refund_amount_val"
- ",refund_amount_frac"
- ",rtransaction_id"
- " FROM merchant_refunds"
- " WHERE coin_pub=$1"
- " AND order_serial=$2"),
- /* for process_deposits_for_refund_cb() used in postgres_increase_refund() */
- GNUNET_PQ_make_prepare ("insert_refund",
- "INSERT INTO merchant_refunds"
- "(order_serial"
- ",rtransaction_id"
- ",refund_timestamp"
- ",coin_pub"
- ",reason"
- ",refund_amount_val"
- ",refund_amount_frac"
- ") VALUES"
- "($1, $2, $3, $4, $5, $6, $7)"),
- /* for postgres_increase_refund() */
- GNUNET_PQ_make_prepare ("find_deposits_for_refund",
- "SELECT"
- " coin_pub"
- ",order_serial"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- " FROM merchant_deposits"
- " WHERE order_serial="
- " (SELECT order_serial"
- " FROM merchant_contract_terms"
- " WHERE order_id=$2"
- " AND paid=TRUE"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"),
- /* for postgres_lookup_refunds_detailed() */
- GNUNET_PQ_make_prepare ("lookup_refunds_detailed",
- "SELECT"
- " refund_serial"
- ",refund_timestamp"
- ",coin_pub"
- ",merchant_deposits.exchange_url"
- ",rtransaction_id"
- ",reason"
- ",refund_amount_val"
- ",refund_amount_frac"
- ",merchant_refund_proofs.exchange_sig IS NULL AS pending"
- " FROM merchant_refunds"
- " JOIN merchant_deposits USING (order_serial, coin_pub)"
- " LEFT JOIN merchant_refund_proofs USING (refund_serial)"
- " WHERE order_serial="
- " (SELECT order_serial"
- " FROM merchant_contract_terms"
- " WHERE h_contract_terms=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"),
- /* for postgres_insert_refund_proof() */
- GNUNET_PQ_make_prepare ("insert_refund_proof",
- "INSERT INTO merchant_refund_proofs"
- "(refund_serial"
- ",exchange_sig"
- ",signkey_serial)"
- "SELECT $1, $2, signkey_serial"
- " FROM merchant_exchange_signing_keys"
- " WHERE exchange_pub=$3"
- " ORDER BY start_date DESC"
- " LIMIT 1"),
- /* for postgres_lookup_refund_proof() */
- GNUNET_PQ_make_prepare ("lookup_refund_proof",
- "SELECT"
- " merchant_exchange_signing_keys.exchange_pub"
- ",exchange_sig"
- " FROM merchant_refund_proofs"
- " JOIN merchant_exchange_signing_keys"
- " USING (signkey_serial)"
- " WHERE"
- " refund_serial=$1"),
- /* for postgres_lookup_order_by_fulfillment() */
- GNUNET_PQ_make_prepare ("lookup_order_by_fulfillment",
- "SELECT"
- " order_id"
- " FROM merchant_contract_terms"
- " WHERE fulfillment_url=$2"
- " AND session_id=$3"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_insert_transfer() */
- GNUNET_PQ_make_prepare ("insert_transfer",
- "INSERT INTO merchant_transfers"
- "(exchange_url"
- ",wtid"
- ",credit_amount_val"
- ",credit_amount_frac"
- ",account_serial"
- ",confirmed)"
- "SELECT"
- " $1, $2, $3, $4, account_serial, $6"
- " FROM merchant_accounts"
- " WHERE payto_uri=$5"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$7)"),
- /* for postgres_delete_transfer() */
- GNUNET_PQ_make_prepare ("delete_transfer",
- "DELETE FROM merchant_transfers"
- " WHERE"
- " credit_serial=$2"
- " AND account_serial IN "
- " (SELECT account_serial "
- " FROM merchant_accounts"
- " WHERE merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"),
- /* for postgres_check_transfer_exists() */
- GNUNET_PQ_make_prepare ("check_transfer_exists",
- "SELECT"
- " 1"
- " FROM merchant_transfers"
- " JOIN merchant_accounts"
- " USING (account_serial)"
- " WHERE"
- " credit_serial=$2"
- " AND"
- " merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_lookup_account() */
- GNUNET_PQ_make_prepare ("lookup_account",
- "SELECT"
- " account_serial"
- " FROM merchant_accounts"
- " WHERE payto_uri=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_insert_transfer_details() */
- GNUNET_PQ_make_prepare ("lookup_credit_serial",
- "SELECT"
- " credit_serial"
- " FROM merchant_transfers"
- " WHERE exchange_url=$1"
- " AND wtid=$4"
- " AND account_serial="
- " (SELECT account_serial"
- " FROM merchant_accounts"
- " WHERE payto_uri=$2"
- " AND exchange_url=$1"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$3))"),
- /* for postgres_insert_transfer_details() */
- GNUNET_PQ_make_prepare ("insert_transfer_signature",
- "INSERT INTO merchant_transfer_signatures"
- "(credit_serial"
- ",signkey_serial"
- ",credit_amount_val"
- ",credit_amount_frac"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",execution_time"
- ",exchange_sig) "
- "SELECT $1, signkey_serial, $2, $3, $4, $5, $6, $7"
- " FROM merchant_exchange_signing_keys"
- " WHERE exchange_pub=$8"
- " ORDER BY start_date DESC"
- " LIMIT 1"),
- /* for postgres_insert_transfer_details() */
- GNUNET_PQ_make_prepare ("insert_transfer_to_coin_mapping",
- "INSERT INTO merchant_transfer_to_coin"
- "(deposit_serial"
- ",credit_serial"
- ",offset_in_exchange_list"
- ",exchange_deposit_value_val"
- ",exchange_deposit_value_frac"
- ",exchange_deposit_fee_val"
- ",exchange_deposit_fee_frac) "
- "SELECT deposit_serial, $1, $2, $3, $4, $5, $6"
- " FROM merchant_deposits"
- " JOIN merchant_contract_terms USING (order_serial)"
- " WHERE coin_pub=$7"
- " AND h_contract_terms=$8"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$9)"),
- /* for postgres_insert_transfer_details() */
- GNUNET_PQ_make_prepare ("update_wired_by_coin_pub",
- "WITH os AS" /* select orders affected by the coin */
- "(SELECT order_serial"
- " FROM merchant_deposits"
- " WHERE coin_pub=$1)"
- "UPDATE merchant_contract_terms "
- " SET wired=TRUE "
- " WHERE order_serial IN "
- " (SELECT order_serial FROM merchant_deposits" /* only orders for which NO un-wired coin exists*/
- " WHERE NOT EXISTS "
- " (SELECT order_serial FROM merchant_deposits" /* orders for which ANY un-wired coin exists */
- " JOIN os USING (order_serial)" /* filter early */
- " WHERE deposit_serial NOT IN"
- " (SELECT deposit_serial " /* all coins associated with order that WERE wired */
- " FROM merchant_deposits "
- " JOIN os USING (order_serial)" /* filter early */
- " JOIN merchant_deposit_to_transfer USING (deposit_serial)"
- " JOIN merchant_transfers USING (credit_serial)"
- " WHERE confirmed=TRUE)))"),
- /* for postgres_lookup_wire_fee() */
- GNUNET_PQ_make_prepare ("lookup_wire_fee",
- "SELECT"
- " wire_fee_val"
- ",wire_fee_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
- ",start_date"
- ",end_date"
- ",master_sig"
- " FROM merchant_exchange_wire_fees"
- " WHERE master_pub=$1"
- " AND h_wire_method=$2"
- " AND start_date <= $3"
- " AND end_date > $3"),
- /* for postgres_lookup_deposits_by_contract_and_coin() */
- GNUNET_PQ_make_prepare ("lookup_deposits_by_contract_and_coin",
- "SELECT"
- " exchange_url"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",deposit_fee_val"
- ",deposit_fee_frac"
- ",refund_fee_val"
- ",refund_fee_frac"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",h_wire"
- ",deposit_timestamp"
- ",refund_deadline"
- ",exchange_sig"
- ",exchange_pub"
- " FROM merchant_contract_terms"
- " JOIN merchant_deposits USING (order_serial)"
- " JOIN merchant_exchange_signing_keys USING (signkey_serial)"
- " JOIN merchant_accounts USING (account_serial)"
- " WHERE h_contract_terms=$2"
- " AND coin_pub=$3"
- " AND merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_lookup_transfer() */
- GNUNET_PQ_make_prepare ("lookup_transfer",
- "SELECT"
- " mt.credit_amount_val AS credit_amount_val"
- ",mt.credit_amount_frac AS credit_amount_frac"
- ",mts.credit_amount_val AS exchange_amount_val"
- ",mts.credit_amount_frac AS exchange_amount_frac"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",execution_time"
- ",verified"
- " FROM merchant_transfers mt"
- " JOIN merchant_accounts USING (account_serial)"
- " JOIN merchant_instances USING (merchant_serial)"
- " LEFT JOIN merchant_transfer_signatures mts USING (credit_serial)"
- " WHERE wtid=$2"
- " AND exchange_url=$1"
- " AND merchant_id=$3;"),
- /* for postgres_set_transfer_status_to_verified() */
- GNUNET_PQ_make_prepare ("set_transfer_status_to_verified",
- "UPDATE merchant_transfers SET"
- " verified=TRUE"
- " WHERE wtid=$1"
- " AND exchange_url=$2"),
- /* for postgres_lookup_transfer_summary() */
- GNUNET_PQ_make_prepare ("lookup_transfer_summary",
- "SELECT"
- " order_id"
- ",exchange_deposit_value_val"
- ",exchange_deposit_value_frac"
- ",exchange_deposit_fee_val"
- ",exchange_deposit_fee_frac"
- " FROM merchant_transfers"
- " JOIN merchant_transfer_to_coin USING (credit_serial)"
- " JOIN merchant_deposits USING (deposit_serial)"
- " JOIN merchant_contract_terms USING (order_serial)"
- " WHERE wtid=$2"
- " AND merchant_transfers.exchange_url=$1"),
- /* for postgres_lookup_transfer_details() */
- GNUNET_PQ_make_prepare ("lookup_transfer_details",
- "SELECT"
- " merchant_contract_terms.h_contract_terms"
- ",merchant_transfer_to_coin.offset_in_exchange_list"
- ",merchant_deposits.coin_pub"
- ",exchange_deposit_value_val"
- ",exchange_deposit_value_frac"
- ",exchange_deposit_fee_val"
- ",exchange_deposit_fee_frac"
- " FROM merchant_transfer_to_coin"
- " JOIN merchant_deposits USING (deposit_serial)"
- " JOIN merchant_contract_terms USING (order_serial)"
- " JOIN merchant_transfers USING (credit_serial)"
- " WHERE merchant_transfers.wtid=$2"
- " AND merchant_transfers.exchange_url=$1"),
- /* for postgres_lookup_transfers() */
- GNUNET_PQ_make_prepare ("lookup_transfers_time_payto_asc",
- "SELECT"
- " mt.credit_amount_val"
- ",mt.credit_amount_frac"
- ",wtid"
- ",merchant_accounts.payto_uri"
- ",exchange_url"
- ",credit_serial"
- ",merchant_transfer_signatures.execution_time"
- ",verified"
- ",confirmed"
- " FROM merchant_transfers mt"
- " JOIN merchant_accounts USING (account_serial)"
- " JOIN merchant_transfer_signatures USING (credit_serial)"
- " WHERE execution_time < $2"
- " AND execution_time >= $3"
- " AND credit_serial > $4"
- " AND payto_uri = $6"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " ORDER BY credit_serial ASC"
- " LIMIT $5"),
- /* for postgres_lookup_transfers() */
- GNUNET_PQ_make_prepare ("lookup_transfers_time_asc",
- "SELECT"
- " mt.credit_amount_val"
- ",mt.credit_amount_frac"
- ",wtid"
- ",merchant_accounts.payto_uri"
- ",exchange_url"
- ",credit_serial"
- ",merchant_transfer_signatures.execution_time"
- ",verified"
- ",confirmed"
- " FROM merchant_transfers mt"
- " JOIN merchant_accounts USING (account_serial)"
- " JOIN merchant_transfer_signatures USING (credit_serial)"
- " WHERE execution_time < $2"
- " AND execution_time >= $3"
- " AND credit_serial > $4"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " ORDER BY credit_serial ASC"
- " LIMIT $5"),
- /* for postgres_lookup_transfers() */
- GNUNET_PQ_make_prepare ("lookup_transfers_payto_asc",
- "SELECT"
- " mt.credit_amount_val"
- ",mt.credit_amount_frac"
- ",wtid"
- ",merchant_accounts.payto_uri"
- ",exchange_url"
- ",credit_serial"
- ",CASE WHEN (merchant_transfer_signatures.execution_time) IS NULL"
- " THEN 9223372036854775807" /* largest BIGINT possible */
- " ELSE merchant_transfer_signatures.execution_time"
- " END AS execution_time"
- ",verified"
- ",confirmed"
- " FROM merchant_transfers mt"
- " JOIN merchant_accounts USING (account_serial)"
- " LEFT JOIN merchant_transfer_signatures USING (credit_serial)"
- " WHERE credit_serial > $2"
- " AND payto_uri = $4"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " ORDER BY credit_serial ASC"
- " LIMIT $3"),
- /* for postgres_lookup_transfers() */
- GNUNET_PQ_make_prepare ("lookup_transfers_asc",
- "SELECT"
- " mt.credit_amount_val"
- ",mt.credit_amount_frac"
- ",wtid"
- ",merchant_accounts.payto_uri"
- ",exchange_url"
- ",credit_serial"
- ",CASE WHEN (merchant_transfer_signatures.execution_time) IS NULL"
- " THEN 9223372036854775807" /* largest BIGINT possible */
- " ELSE merchant_transfer_signatures.execution_time"
- " END AS execution_time"
- ",verified"
- ",confirmed"
- " FROM merchant_transfers mt"
- " JOIN merchant_accounts USING (account_serial)"
- " LEFT JOIN merchant_transfer_signatures USING (credit_serial)"
- " WHERE credit_serial > $2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " ORDER BY credit_serial ASC"
- " LIMIT $3"),
- /* for postgres_lookup_transfers() */
- GNUNET_PQ_make_prepare ("lookup_transfers_time_payto_desc",
- "SELECT"
- " mt.credit_amount_val"
- ",mt.credit_amount_frac"
- ",wtid"
- ",merchant_accounts.payto_uri"
- ",exchange_url"
- ",credit_serial"
- ",merchant_transfer_signatures.execution_time"
- ",verified"
- ",confirmed"
- " FROM merchant_transfers mt"
- " JOIN merchant_accounts USING (account_serial)"
- " JOIN merchant_transfer_signatures USING (credit_serial)"
- " WHERE execution_time < $2"
- " AND execution_time >= $3"
- " AND credit_serial < $4"
- " AND payto_uri = $6"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " ORDER BY credit_serial DESC"
- " LIMIT $5"),
- /* for postgres_lookup_transfers() */
- GNUNET_PQ_make_prepare ("lookup_transfers_time_desc",
- "SELECT"
- " mt.credit_amount_val"
- ",mt.credit_amount_frac"
- ",wtid"
- ",merchant_accounts.payto_uri"
- ",exchange_url"
- ",credit_serial"
- ",merchant_transfer_signatures.execution_time"
- ",verified"
- ",confirmed"
- " FROM merchant_transfers mt"
- " JOIN merchant_accounts USING (account_serial)"
- " JOIN merchant_transfer_signatures USING (credit_serial)"
- " WHERE execution_time < $2"
- " AND execution_time >= $3"
- " AND credit_serial < $4"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " ORDER BY credit_serial DESC"
- " LIMIT $5"),
- /* for postgres_lookup_transfers() */
- GNUNET_PQ_make_prepare ("lookup_transfers_payto_desc",
- "SELECT"
- " mt.credit_amount_val"
- ",mt.credit_amount_frac"
- ",wtid"
- ",merchant_accounts.payto_uri"
- ",exchange_url"
- ",credit_serial"
- ",CASE WHEN (merchant_transfer_signatures.execution_time) IS NULL"
- " THEN 9223372036854775807" /* largest BIGINT possible */
- " ELSE merchant_transfer_signatures.execution_time"
- " END AS execution_time"
- ",verified"
- ",confirmed"
- " FROM merchant_transfers mt"
- " JOIN merchant_accounts USING (account_serial)"
- " LEFT JOIN merchant_transfer_signatures USING (credit_serial)"
- " WHERE credit_serial < $2"
- " AND payto_uri = $4"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " ORDER BY credit_serial DESC"
- " LIMIT $3"),
- /* for postgres_lookup_transfers() */
- GNUNET_PQ_make_prepare ("lookup_transfers_desc",
- "SELECT"
- " mt.credit_amount_val"
- ",mt.credit_amount_frac"
- ",wtid"
- ",merchant_accounts.payto_uri"
- ",exchange_url"
- ",credit_serial"
- ",CASE WHEN (merchant_transfer_signatures.execution_time) IS NULL"
- " THEN 9223372036854775807" /* largest BIGINT possible */
- " ELSE merchant_transfer_signatures.execution_time"
- " END AS execution_time"
- ",verified"
- ",confirmed"
- " FROM merchant_transfers mt"
- " JOIN merchant_accounts USING (account_serial)"
- " LEFT JOIN merchant_transfer_signatures USING (credit_serial)"
- " WHERE credit_serial < $2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " ORDER BY credit_serial DESC"
- " LIMIT $3"),
- /* For postgres_store_wire_fee_by_exchange() */
- GNUNET_PQ_make_prepare ("insert_wire_fee",
- "INSERT INTO merchant_exchange_wire_fees"
- "(master_pub"
- ",h_wire_method"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
- ",start_date"
- ",end_date"
- ",master_sig)"
- " VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9)"),
- /* For postgres_insert_reserve() */
- GNUNET_PQ_make_prepare ("insert_reserve",
- "INSERT INTO merchant_tip_reserves"
- "(reserve_pub"
- ",merchant_serial"
- ",creation_time"
- ",expiration"
- ",merchant_initial_balance_val"
- ",merchant_initial_balance_frac"
- ")"
- "SELECT $2, merchant_serial, $3, $4, $5, $6"
- " FROM merchant_instances"
- " WHERE merchant_id=$1"),
- /* For postgres_activate_reserve() */
- GNUNET_PQ_make_prepare ("activate_reserve",
- "UPDATE merchant_tip_reserves SET"
- " exchange_initial_balance_val=$3"
- ",exchange_initial_balance_frac=$4"
- " WHERE reserve_pub=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* For postgres_insert_reserve() */
- GNUNET_PQ_make_prepare ("insert_reserve_key",
- "INSERT INTO merchant_tip_reserve_keys"
- "(reserve_serial"
- ",reserve_priv"
- ",exchange_url"
- ",payto_uri"
- ")"
- "SELECT reserve_serial, $3, $4, $5"
- " FROM merchant_tip_reserves"
- " WHERE reserve_pub=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* For postgres_lookup_reserves() */
- GNUNET_PQ_make_prepare ("lookup_reserves",
- "SELECT"
- " reserve_pub"
- ",creation_time"
- ",expiration"
- ",merchant_initial_balance_val"
- ",merchant_initial_balance_frac"
- ",exchange_initial_balance_val"
- ",exchange_initial_balance_frac"
- ",tips_committed_val"
- ",tips_committed_frac"
- ",tips_picked_up_val"
- ",tips_picked_up_frac"
- ",reserve_priv IS NOT NULL AS active"
- " FROM merchant_tip_reserves"
- " FULL OUTER JOIN merchant_tip_reserve_keys USING (reserve_serial)"
- " WHERE creation_time > $2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* For postgres_lookup_pending_reserves() */
- GNUNET_PQ_make_prepare ("lookup_pending_reserves",
- "SELECT"
- " reserve_pub"
- ",merchant_id"
- ",exchange_url"
- ",merchant_initial_balance_val"
- ",merchant_initial_balance_frac"
- " FROM merchant_tip_reserves"
- " JOIN merchant_instances USING (merchant_serial)"
- " JOIN merchant_tip_reserve_keys USING (reserve_serial)"
- " WHERE exchange_initial_balance_val=0"
- " AND exchange_initial_balance_frac=0"),
- /* For postgres_lookup_reserve() */
- GNUNET_PQ_make_prepare ("lookup_reserve",
- "SELECT"
- " creation_time"
- ",expiration"
- ",merchant_initial_balance_val"
- ",merchant_initial_balance_frac"
- ",exchange_initial_balance_val"
- ",exchange_initial_balance_frac"
- ",tips_committed_val"
- ",tips_committed_frac"
- ",tips_picked_up_val"
- ",tips_picked_up_frac"
- ",reserve_priv IS NOT NULL AS active"
- ",exchange_url"
- ",payto_uri"
- " FROM merchant_tip_reserves"
- " FULL OUTER JOIN merchant_tip_reserve_keys USING (reserve_serial)"
- " WHERE reserve_pub = $2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* For postgres_lookup_reserve() */
- GNUNET_PQ_make_prepare ("lookup_reserve_tips",
- "SELECT"
- " justification"
- ",tip_id"
- ",amount_val"
- ",amount_frac"
- " FROM merchant_tips"
- " WHERE reserve_serial ="
- " (SELECT reserve_serial"
- " FROM merchant_tip_reserves"
- " WHERE reserve_pub=$2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"),
- /* for postgres_delete_reserve() */
- GNUNET_PQ_make_prepare ("delete_reserve",
- "DELETE"
- " FROM merchant_tip_reserve_keys"
- " WHERE reserve_serial="
- " (SELECT reserve_serial"
- " FROM merchant_tip_reserves"
- " WHERE reserve_pub=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"),
- /* for postgres_purge_reserve() */
- GNUNET_PQ_make_prepare ("purge_reserve",
- "DELETE"
- " FROM merchant_tip_reserves"
- " WHERE reserve_pub=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* For postgres_authorize_tip() */
- GNUNET_PQ_make_prepare ("lookup_reserve_for_tip",
- "SELECT"
- " reserve_pub"
- ",expiration"
- ",exchange_initial_balance_val"
- ",exchange_initial_balance_frac"
- ",tips_committed_val"
- ",tips_committed_frac"
- " FROM merchant_tip_reserves"
- " WHERE"
- " merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
-
- /* For postgres_authorize_tip() */
- GNUNET_PQ_make_prepare ("lookup_reserve_status",
- "SELECT"
- " expiration"
- ",exchange_initial_balance_val"
- ",exchange_initial_balance_frac"
- ",tips_committed_val"
- ",tips_committed_frac"
- " FROM merchant_tip_reserves"
- " WHERE reserve_pub = $2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* For postgres_authorize_tip() */
- GNUNET_PQ_make_prepare ("update_reserve_tips_committed",
- "UPDATE merchant_tip_reserves SET"
- " tips_committed_val=$3"
- ",tips_committed_frac=$4"
- " WHERE reserve_pub = $2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* For postgres_authorize_tip() */
- GNUNET_PQ_make_prepare ("insert_tip",
- "INSERT INTO merchant_tips"
- "(reserve_serial"
- ",tip_id"
- ",justification"
- ",next_url"
- ",expiration"
- ",amount_val"
- ",amount_frac"
- ") "
- "SELECT"
- " reserve_serial, $3, $4, $5, $6, $7, $8"
- " FROM merchant_tip_reserves"
- " WHERE reserve_pub=$2"
- " AND merchant_serial = "
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* For postgres_lookup_pickup() */
- GNUNET_PQ_make_prepare ("lookup_pickup",
- "SELECT"
- " exchange_url"
- ",reserve_priv"
- ",pickup_serial"
- " FROM merchant_tip_pickups"
- " JOIN merchant_tips USING (tip_serial)"
- " JOIN merchant_tip_reserves USING (reserve_serial)"
- " JOIN merchant_tip_reserve_keys USING (reserve_serial)"
- " WHERE pickup_id = $3"
- " AND tip_id = $2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* For postgres_lookup_pickup() */
- GNUNET_PQ_make_prepare ("lookup_pickup_signatures",
- "SELECT"
- " coin_offset"
- ",blind_sig"
- " FROM merchant_tip_pickup_signatures"
- " WHERE pickup_serial = $1"),
-
- /* For postgres_lookup_tip() */
- GNUNET_PQ_make_prepare ("lookup_tip",
- "SELECT"
- " amount_val"
- ",amount_frac"
- ",picked_up_val"
- ",picked_up_frac"
- ",merchant_tips.expiration"
- ",exchange_url"
- ",reserve_priv"
- " FROM merchant_tips"
- " JOIN merchant_tip_reserves USING (reserve_serial)"
- " JOIN merchant_tip_reserve_keys USING (reserve_serial)"
- " WHERE tip_id = $2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* For postgres_lookup_tip() */
- GNUNET_PQ_make_prepare ("lookup_tips_inc",
- "SELECT"
- " tip_serial"
- ",tip_id"
- ",amount_val"
- ",amount_frac"
- ",CAST($4 as BIGINT)" /* otherwise $4 is unused and Postgres unhappy */
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- " FROM merchant_tips"
- " JOIN merchant_tip_reserves USING (reserve_serial)"
- " WHERE merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " tip_serial > $3"
- " ORDER BY tip_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_tips_dec",
- "SELECT"
- " tip_serial"
- ",tip_id"
- ",amount_val"
- ",amount_frac"
- ",CAST($4 as BIGINT)" /* otherwise $4 is unused and Postgres unhappy */
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
- " FROM merchant_tips"
- " JOIN merchant_tip_reserves USING (reserve_serial)"
- " WHERE merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " tip_serial < $3"
- " ORDER BY tip_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_tips_inc_expired",
- "SELECT"
- " tip_serial"
- ",tip_id"
- ",amount_val"
- ",amount_frac"
- " FROM merchant_tips"
- " JOIN merchant_tip_reserves USING (reserve_serial)"
- " WHERE merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " tip_serial > $3"
- " AND"
- " CAST($5 as BOOL) = (merchant_tips.expiration < $4)"
- " ORDER BY tip_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_tips_dec_expired",
- "SELECT"
- " tip_serial"
- ",tip_id"
- ",amount_val"
- ",amount_frac"
- " FROM merchant_tips"
- " JOIN merchant_tip_reserves USING (reserve_serial)"
- " WHERE merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " tip_serial < $3"
- " AND"
- " CAST($5 as BOOL) = (merchant_tips.expiration < $4)"
- " ORDER BY tip_serial DESC"
- " LIMIT $2"),
- /* for postgres_lookup_tip_details() */
- GNUNET_PQ_make_prepare ("lookup_tip_details",
- "SELECT"
- " tip_serial"
- ",amount_val"
- ",amount_frac"
- ",picked_up_val"
- ",picked_up_frac"
- ",justification"
- ",merchant_tips.expiration"
- ",reserve_pub"
- " FROM merchant_tips"
- " JOIN merchant_tip_reserves USING (reserve_serial)"
- " WHERE tip_id = $2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_lookup_tip_details() */
- GNUNET_PQ_make_prepare ("lookup_pickup_details",
- "SELECT"
- " pickup_id"
- ",amount_val"
- ",amount_frac"
- ",COUNT(blind_sig) AS num_planchets"
- " FROM merchant_tip_pickups"
- " JOIN merchant_tip_pickup_signatures USING (pickup_serial)"
- " WHERE tip_serial = $1"
- " GROUP BY pickup_serial"),
- /* for postgres_insert_pickup() */
- GNUNET_PQ_make_prepare ("insert_pickup",
- "INSERT INTO merchant_tip_pickups"
- "(tip_serial"
- ",pickup_id"
- ",amount_val"
- ",amount_frac"
- ") "
- "SELECT"
- " tip_serial, $3, $4, $5"
- " FROM merchant_tips"
- " JOIN merchant_tip_reserves USING (reserve_serial)"
- " WHERE tip_id=$2"
- " AND merchant_serial = "
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_insert_pickup() */
- GNUNET_PQ_make_prepare ("update_picked_up_tip",
- "UPDATE merchant_tips SET"
- " picked_up_val=$2"
- ",picked_up_frac=$3"
- ",was_picked_up = ($2 = amount_val AND $3 = amount_frac)"
- " WHERE tip_id = $1"),
- /* for postgres_insert_pickup() */
- GNUNET_PQ_make_prepare ("lookup_picked_up_reserve",
- "SELECT"
- " reserve_serial"
- ",tips_picked_up_val"
- ",tips_picked_up_frac"
- " FROM merchant_tip_reserves"
- " JOIN merchant_tips USING (reserve_serial)"
- " WHERE tip_id=$2"
- " AND merchant_serial ="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_insert_pickup() */
- GNUNET_PQ_make_prepare ("update_picked_up_reserve",
- "UPDATE merchant_tip_reserves SET"
- " tips_picked_up_val=$2"
- ",tips_picked_up_frac=$3"
- " WHERE reserve_serial = $1"),
- /* for postgres_insert_pickup_blind_signature() */
- GNUNET_PQ_make_prepare ("insert_pickup_blind_signature",
- "INSERT INTO merchant_tip_pickup_signatures"
- "(pickup_serial"
- ",coin_offset"
- ",blind_sig"
- ") "
- "SELECT"
- " pickup_serial, $2, $3"
- " FROM merchant_tip_pickups"
- " WHERE pickup_id=$1"),
- /* for postgres_lookup_templates() */
- GNUNET_PQ_make_prepare ("lookup_templates",
- "SELECT"
- " template_id"
- ",template_description"
- " FROM merchant_template"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"),
- /* for postgres_lookup_template() */
- GNUNET_PQ_make_prepare ("lookup_template",
- "SELECT"
- " template_description"
- ",image"
- ",template_contract"
- " FROM merchant_template"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"
- " AND merchant_template.template_id=$2"),
- /* for postgres_delete_template() */
- GNUNET_PQ_make_prepare ("delete_template",
- "DELETE"
- " FROM merchant_template"
- " WHERE merchant_template.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND merchant_template.template_id=$2"),
- /* for postgres_insert_template() */
- GNUNET_PQ_make_prepare ("insert_template",
- "INSERT INTO merchant_template"
- "(merchant_serial"
- ",template_id"
- ",template_description"
- ",image"
- ",template_contract"
- ")"
- " SELECT merchant_serial,"
- " $2, $3, $4, $5"
- " FROM merchant_instances"
- " WHERE merchant_id=$1"),
- /* for postgres_update_template() */
- GNUNET_PQ_make_prepare ("update_template",
- "UPDATE merchant_template SET"
- " template_description=$3"
- ",image=$4"
- ",template_contract=$5"
- " WHERE merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND template_id=$2"),
- /* for postgres_lookup_webhooks() */
- GNUNET_PQ_make_prepare ("lookup_webhooks",
- "SELECT"
- " webhook_id"
- ",event_type"
- " FROM merchant_webhook"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"),
- /* for postgres_lookup_webhook() */
- GNUNET_PQ_make_prepare ("lookup_webhook",
- "SELECT"
- " event_type"
- ",url"
- ",http_method"
- ",header_template"
- ",body_template"
- " FROM merchant_webhook"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"
- " AND merchant_webhook.webhook_id=$2"),
- /* for postgres_delete_webhook() */
- GNUNET_PQ_make_prepare ("delete_webhook",
- "DELETE"
- " FROM merchant_webhook"
- " WHERE merchant_webhook.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND merchant_webhook.webhook_id=$2"),
- /* for postgres_insert_webhook() */
- GNUNET_PQ_make_prepare ("insert_webhook",
- "INSERT INTO merchant_webhook"
- "(merchant_serial"
- ",webhook_id"
- ",event_type"
- ",url"
- ",http_method"
- ",header_template"
- ",body_template"
- ")"
- " SELECT merchant_serial,"
- " $2, $3, $4, $5, $6, $7"
- " FROM merchant_instances"
- " WHERE merchant_id=$1"),
- /* for postgres_update_webhook() */
- GNUNET_PQ_make_prepare ("update_webhook",
- "UPDATE merchant_webhook SET"
- " event_type=$3"
- ",url=$4"
- ",http_method=$5"
- ",header_template=$6"
- ",body_template=$7"
- " WHERE merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND webhook_id=$2"),
- /* for postgres_lookup_webhook_by_event() */
- GNUNET_PQ_make_prepare ("lookup_webhook_by_event",
- "SELECT"
- " webhook_serial"
- ",event_type"
- ",url"
- ",http_method"
- ",header_template"
- ",body_template"
- " FROM merchant_webhook"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"
- " AND event_type=$2"),
- /* for postgres_delete_pending_webhook() */
- GNUNET_PQ_make_prepare ("delete_pending_webhook",
- "DELETE"
- " FROM merchant_pending_webhooks"
- " WHERE merchant_pending_webhooks.webhook_serial="
- " (SELECT webhook_serial "
- " FROM merchant_webhook"
- " WHERE webhook_serial=$1)"),
- /* for postgres_insert_pending_webhook() */
- GNUNET_PQ_make_prepare ("insert_pending_webhook",
- "INSERT INTO merchant_pending_webhooks"
- "(merchant_serial"
- ",webhook_serial"
- ",url"
- ",http_method"
- ",header"
- ",body"
- ")"
- " SELECT mi.merchant_serial,"
- " $2, $3, $4, $5, $6"
- " FROM merchant_instances mi"
- " WHERE mi.merchant_id=$1"),
- /* for postgres_update_pending_webhook() */
- GNUNET_PQ_make_prepare ("update_pending_webhook",
- "UPDATE merchant_pending_webhooks SET"
- " retries=retries+1"
- ",next_attempt=$2"
- " WHERE webhook_serial="
- " (SELECT webhook_serial"
- " FROM merchant_webhook"
- " WHERE webhook_serial=$1)"),
- /* for postgres_lookup_pending_webhook() */
- GNUNET_PQ_make_prepare ("lookup_pending_webhook",
- "SELECT"
- " next_attempt"
- ",retries"
- ",url"
- ",http_method"
- ",header"
- ",body"
- " FROM merchant_pending_webhooks"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"
- " AND merchant_pending_webhooks.webhook_serial=$2"),
- /* for postgres_lookup_pending_webhooks() */
- GNUNET_PQ_make_prepare ("lookup_pending_webhooks",
- "SELECT"
- " webhook_serial"
- ",next_attempt"
- ",retries"
- ",url"
- ",http_method"
- ",header"
- ",body"
- " FROM merchant_pending_webhooks"
- " WHERE next_attempt <= $1"
- " ORDER BY next_attempt ASC"
- ),
- /* for postgres_lookup_future_webhook() */
- GNUNET_PQ_make_prepare ("lookup_future_webhook",
- "SELECT"
- " webhook_serial"
- ",next_attempt"
- ",retries"
- ",url"
- ",http_method"
- ",header"
- ",body"
- " FROM merchant_pending_webhooks"
- " ORDER BY next_attempt ASC LIMIT 1"
- ),
- /* for postgres_lookup_all_webhooks() */
- GNUNET_PQ_make_prepare ("lookup_all_webhooks",
- " SELECT"
- " webhook_serial"
- ",next_attempt"
- ",retries"
- ",url"
- ",http_method"
- ",header"
- ",body"
- " FROM merchant_pending_webhooks"
- " JOIN merchant_instances"
- " USING (merchant_serial)"
- " WHERE merchant_instances.merchant_id=$1"
- " AND webhook_serial > $2"
- " ORDER BY webhook_serial"
- " ASC LIMIT $3"),
- GNUNET_PQ_PREPARED_STATEMENT_END
- };
struct GNUNET_PQ_ExecuteStatement es[] = {
GNUNET_PQ_make_try_execute ("SET search_path TO merchant;"),
GNUNET_PQ_EXECUTE_STATEMENT_END
@@ -10515,7 +311,8 @@ postgres_connect (void *cls)
"merchantdb-postgres",
NULL,
es,
- ps);
+ NULL);
+ pg->prep_gen++;
if (NULL == pg->conn)
return GNUNET_SYSERR;
return GNUNET_OK;
@@ -10549,14 +346,6 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
GNUNET_free (pg);
return NULL;
}
- if (GNUNET_OK !=
- TALER_config_get_currency (cfg,
- &pg->currency))
- {
- GNUNET_free (pg->sql_dir);
- GNUNET_free (pg);
- return NULL;
- }
plugin = GNUNET_new (struct TALER_MERCHANTDB_Plugin);
plugin->cls = pg;
plugin->connect = &postgres_connect;
@@ -10566,111 +355,236 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
plugin->event_listen_cancel = &postgres_event_listen_cancel;
plugin->event_notify = &postgres_event_notify;
plugin->preflight = &postgres_preflight;
- plugin->start = &postgres_start;
- plugin->start_read_committed = &postgres_start_read_committed;
- plugin->rollback = &postgres_rollback;
- plugin->commit = &postgres_commit;
- plugin->lookup_instances = &postgres_lookup_instances;
- plugin->lookup_instance = &postgres_lookup_instance;
- plugin->lookup_instance_auth = &postgres_lookup_instance_auth;
- plugin->insert_instance = &postgres_insert_instance;
- plugin->insert_account = &postgres_insert_account;
+ plugin->start = &TMH_PG_start;
+ plugin->start_read_committed = &TMH_PG_start_read_committed;
+ plugin->rollback = &TMH_PG_rollback;
+ plugin->commit = &TMH_PG_commit;
+ plugin->insert_login_token
+ = &TMH_PG_insert_login_token;
+ plugin->delete_login_token
+ = &TMH_PG_delete_login_token;
+ plugin->select_login_token
+ = &TMH_PG_select_login_token;
+ plugin->select_account_by_uri
+ = &TMH_PG_select_account_by_uri;
+ plugin->lookup_instance_auth
+ = &TMH_PG_lookup_instance_auth;
+ plugin->insert_instance
+ = &TMH_PG_insert_instance;
+ plugin->insert_account
+ = &TMH_PG_insert_account;
+ plugin->lookup_otp_devices
+ = &TMH_PG_lookup_otp_devices;
+ plugin->delete_template
+ = &TMH_PG_delete_template;
+ plugin->insert_template
+ = &TMH_PG_insert_template;
+ plugin->update_template
+ = &TMH_PG_update_template;
+ plugin->lookup_templates
+ = &TMH_PG_lookup_templates;
+ plugin->lookup_template
+ = &TMH_PG_lookup_template;
+ plugin->update_account
+ = &TMH_PG_update_account;
plugin->account_kyc_set_status
- = &postgres_account_kyc_set_status;
+ = &TMH_PG_account_kyc_set_status;
plugin->account_kyc_get_status
- = &postgres_account_kyc_get_status;
- plugin->delete_instance_private_key = &postgres_delete_instance_private_key;
- plugin->purge_instance = &postgres_purge_instance;
- plugin->update_instance = &postgres_update_instance;
- plugin->update_instance_auth = &postgres_update_instance_auth;
- plugin->activate_account = &postgres_activate_account;
- plugin->inactivate_account = &postgres_inactivate_account;
- plugin->lookup_products = &postgres_lookup_products;
- plugin->lookup_product = &postgres_lookup_product;
- plugin->delete_product = &postgres_delete_product;
- plugin->insert_product = &postgres_insert_product;
- plugin->update_product = &postgres_update_product;
- plugin->lock_product = &postgres_lock_product;
- plugin->expire_locks = &postgres_expire_locks;
- plugin->delete_order = &postgres_delete_order;
- plugin->lookup_order = &postgres_lookup_order;
- plugin->lookup_order_summary = &postgres_lookup_order_summary;
- plugin->lookup_orders = &postgres_lookup_orders;
- plugin->insert_order = &postgres_insert_order;
- plugin->unlock_inventory = &postgres_unlock_inventory;
- plugin->insert_order_lock = &postgres_insert_order_lock;
- plugin->lookup_contract_terms = &postgres_lookup_contract_terms;
- plugin->insert_contract_terms = &postgres_insert_contract_terms;
- plugin->update_contract_terms = &postgres_update_contract_terms;
- plugin->delete_contract_terms = &postgres_delete_contract_terms;
- plugin->lookup_deposits = &postgres_lookup_deposits;
- plugin->insert_exchange_signkey = &postgres_insert_exchange_signkey;
- plugin->insert_deposit = &postgres_insert_deposit;
- plugin->lookup_refunds = &postgres_lookup_refunds;
- plugin->mark_contract_paid = &postgres_mark_contract_paid;
- plugin->refund_coin = &postgres_refund_coin;
- plugin->lookup_order_status = &postgres_lookup_order_status;
- plugin->lookup_order_status_by_serial =
- &postgres_lookup_order_status_by_serial;
- plugin->lookup_payment_status = &postgres_lookup_payment_status;
- plugin->lookup_deposits_by_order = &postgres_lookup_deposits_by_order;
- plugin->lookup_transfer_details_by_order =
- &postgres_lookup_transfer_details_by_order;
- plugin->insert_deposit_to_transfer = &postgres_insert_deposit_to_transfer;
- plugin->mark_order_wired = &postgres_mark_order_wired;
- plugin->increase_refund = &postgres_increase_refund;
- plugin->lookup_refunds_detailed = &postgres_lookup_refunds_detailed;
- plugin->insert_refund_proof = &postgres_insert_refund_proof;
- plugin->lookup_refund_proof = &postgres_lookup_refund_proof;
- plugin->lookup_order_by_fulfillment = &postgres_lookup_order_by_fulfillment;
- plugin->insert_transfer = &postgres_insert_transfer;
- plugin->delete_transfer = &postgres_delete_transfer;
- plugin->check_transfer_exists = &postgres_check_transfer_exists;
- plugin->lookup_account = &postgres_lookup_account;
- plugin->insert_transfer_details = &postgres_insert_transfer_details;
- plugin->lookup_wire_fee = &postgres_lookup_wire_fee;
- plugin->lookup_deposits_by_contract_and_coin =
- &postgres_lookup_deposits_by_contract_and_coin;
- plugin->lookup_transfer = &postgres_lookup_transfer;
- plugin->set_transfer_status_to_verified =
- &postgres_set_transfer_status_to_verified;
- plugin->lookup_transfer_summary = &postgres_lookup_transfer_summary;
- plugin->lookup_transfer_details = &postgres_lookup_transfer_details;
- plugin->lookup_transfers = &postgres_lookup_transfers;
- plugin->store_wire_fee_by_exchange = &postgres_store_wire_fee_by_exchange;
- plugin->insert_reserve = &postgres_insert_reserve;
- plugin->activate_reserve = &postgres_activate_reserve;
- plugin->lookup_reserves = &postgres_lookup_reserves;
- plugin->lookup_pending_reserves = &postgres_lookup_pending_reserves;
- plugin->lookup_reserve = &postgres_lookup_reserve;
- plugin->delete_reserve = &postgres_delete_reserve;
- plugin->purge_reserve = &postgres_purge_reserve;
- plugin->authorize_tip = &postgres_authorize_tip;
- plugin->lookup_pickup = &postgres_lookup_pickup;
- plugin->lookup_tip = &postgres_lookup_tip;
- plugin->lookup_tips = &postgres_lookup_tips;
- plugin->lookup_tip_details = &postgres_lookup_tip_details;
- plugin->insert_pickup = &postgres_insert_pickup;
- plugin->insert_pickup_blind_signature =
- &postgres_insert_pickup_blind_signature;
- plugin->lookup_templates = &postgres_lookup_templates;
- plugin->lookup_template = &postgres_lookup_template;
- plugin->delete_template = &postgres_delete_template;
- plugin->insert_template = &postgres_insert_template;
- plugin->update_template = &postgres_update_template;
- plugin->lookup_webhooks = &postgres_lookup_webhooks;
- plugin->lookup_webhook = &postgres_lookup_webhook;
- plugin->delete_webhook = &postgres_delete_webhook;
- plugin->insert_webhook = &postgres_insert_webhook;
- plugin->update_webhook = &postgres_update_webhook;
- plugin->lookup_pending_webhook = &postgres_lookup_pending_webhook;
- plugin->lookup_webhook_by_event = &postgres_lookup_webhook_by_event;
- plugin->lookup_all_webhooks = &postgres_lookup_all_webhooks;
- plugin->lookup_future_webhook = &postgres_lookup_future_webhook;
- plugin->lookup_pending_webhooks = &postgres_lookup_pending_webhooks;
- plugin->delete_pending_webhook = &postgres_delete_pending_webhook;
- plugin->insert_pending_webhook = &postgres_insert_pending_webhook;
- plugin->update_pending_webhook = &postgres_update_pending_webhook;
+ = &TMH_PG_account_kyc_get_status;
+ plugin->delete_instance_private_key
+ = &TMH_PG_delete_instance_private_key;
+ plugin->purge_instance
+ = &TMH_PG_purge_instance;
+ plugin->update_instance
+ = &TMH_PG_update_instance;
+ plugin->update_instance_auth
+ = &TMH_PG_update_instance_auth;
+ plugin->activate_account
+ = &TMH_PG_activate_account;
+ plugin->inactivate_account
+ = &TMH_PG_inactivate_account;
+ plugin->update_transfer_status
+ = &TMH_PG_update_transfer_status;
+ plugin->lookup_products
+ = &TMH_PG_lookup_products;
+ plugin->lookup_product
+ = &TMH_PG_lookup_product;
+ plugin->delete_product
+ = &TMH_PG_delete_product;
+ plugin->insert_product
+ = &TMH_PG_insert_product;
+ plugin->update_product
+ = &TMH_PG_update_product;
+ plugin->insert_otp
+ = &TMH_PG_insert_otp;
+ plugin->delete_otp
+ = &TMH_PG_delete_otp;
+ plugin->update_otp
+ = &TMH_PG_update_otp;
+ plugin->select_otp
+ = &TMH_PG_select_otp;
+ plugin->select_otp_serial
+ = &TMH_PG_select_otp_serial;
+ plugin->lock_product
+ = &TMH_PG_lock_product;
+ plugin->expire_locks
+ = &TMH_PG_expire_locks;
+ plugin->delete_order
+ = &TMH_PG_delete_order;
+ plugin->lookup_order
+ = &TMH_PG_lookup_order;
+ plugin->lookup_order_summary
+ = &TMH_PG_lookup_order_summary;
+ plugin->lookup_orders
+ = &TMH_PG_lookup_orders;
+ plugin->insert_order
+ = &TMH_PG_insert_order;
+ plugin->unlock_inventory
+ = &TMH_PG_unlock_inventory;
+ plugin->insert_order_lock
+ = &TMH_PG_insert_order_lock;
+ plugin->lookup_contract_terms
+ = &TMH_PG_lookup_contract_terms;
+ plugin->lookup_contract_terms2
+ = &TMH_PG_lookup_contract_terms2;
+ plugin->lookup_contract_terms3
+ = &TMH_PG_lookup_contract_terms3;
+ plugin->insert_contract_terms
+ = &TMH_PG_insert_contract_terms;
+ plugin->update_contract_terms
+ = &TMH_PG_update_contract_terms;
+ plugin->delete_contract_terms
+ = &TMH_PG_delete_contract_terms;
+ plugin->lookup_deposits
+ = &TMH_PG_lookup_deposits;
+ plugin->insert_exchange_signkey
+ = &TMH_PG_insert_exchange_signkey;
+ plugin->insert_deposit_confirmation
+ = &TMH_PG_insert_deposit_confirmation;
+ plugin->insert_deposit
+ = &TMH_PG_insert_deposit;
+ plugin->lookup_refunds
+ = &TMH_PG_lookup_refunds;
+ plugin->mark_contract_paid
+ = &TMH_PG_mark_contract_paid;
+ plugin->refund_coin
+ = &TMH_PG_refund_coin;
+ plugin->lookup_order_status
+ = &TMH_PG_lookup_order_status;
+ plugin->lookup_order_status_by_serial
+ = &TMH_PG_lookup_order_status_by_serial;
+ plugin->lookup_deposits_by_order
+ = &TMH_PG_lookup_deposits_by_order;
+ plugin->lookup_transfer_details_by_order
+ = &TMH_PG_lookup_transfer_details_by_order;
+ plugin->mark_order_wired
+ = &TMH_PG_mark_order_wired;
+ plugin->increase_refund
+ = &TMH_PG_increase_refund;
+ plugin->lookup_refunds_detailed
+ = &TMH_PG_lookup_refunds_detailed;
+ plugin->insert_refund_proof
+ = &TMH_PG_insert_refund_proof;
+ plugin->lookup_refund_proof
+ = &TMH_PG_lookup_refund_proof;
+ plugin->lookup_order_by_fulfillment
+ = &TMH_PG_lookup_order_by_fulfillment;
+ plugin->delete_transfer
+ = &TMH_PG_delete_transfer;
+ plugin->check_transfer_exists
+ = &TMH_PG_check_transfer_exists;
+ plugin->lookup_account
+ = &TMH_PG_lookup_account;
+ plugin->lookup_wire_fee
+ = &TMH_PG_lookup_wire_fee;
+ plugin->lookup_deposits_by_contract_and_coin
+ = &TMH_PG_lookup_deposits_by_contract_and_coin;
+ plugin->lookup_transfer
+ = &TMH_PG_lookup_transfer;
+ plugin->set_transfer_status_to_confirmed
+ = &TMH_PG_set_transfer_status_to_confirmed;
+ plugin->lookup_transfer_summary
+ = &TMH_PG_lookup_transfer_summary;
+ plugin->lookup_transfer_details
+ = &TMH_PG_lookup_transfer_details;
+ plugin->lookup_instances
+ = &TMH_PG_lookup_instances;
+ plugin->lookup_instance
+ = &TMH_PG_lookup_instance;
+ plugin->lookup_transfers
+ = &TMH_PG_lookup_transfers;
+ plugin->update_wirewatch_progress
+ = &TMH_PG_update_wirewatch_progress;
+ plugin->select_wirewatch_accounts
+ = &TMH_PG_select_wirewatch_accounts;
+ plugin->select_account
+ = &TMH_PG_select_account;
+ plugin->select_accounts
+ = &TMH_PG_select_accounts;
+ plugin->select_open_transfers
+ = &TMH_PG_select_open_transfers;
+ plugin->insert_exchange_keys
+ = &TMH_PG_insert_exchange_keys;
+ plugin->select_exchange_keys
+ = &TMH_PG_select_exchange_keys;
+ plugin->insert_deposit_to_transfer
+ = &TMH_PG_insert_deposit_to_transfer;
+ plugin->insert_transfer
+ = &TMH_PG_insert_transfer;
+ plugin->insert_transfer_details
+ = &TMH_PG_insert_transfer_details;
+ plugin->store_wire_fee_by_exchange
+ = &TMH_PG_store_wire_fee_by_exchange;
+ plugin->lookup_webhooks
+ = &TMH_PG_lookup_webhooks;
+ plugin->lookup_webhook
+ = &TMH_PG_lookup_webhook;
+ plugin->delete_webhook
+ = &TMH_PG_delete_webhook;
+ plugin->insert_webhook
+ = &TMH_PG_insert_webhook;
+ plugin->update_webhook
+ = &TMH_PG_update_webhook;
+ plugin->lookup_pending_deposits
+ = &TMH_PG_lookup_pending_deposits;
+ plugin->lookup_webhook_by_event
+ = &TMH_PG_lookup_webhook_by_event;
+ plugin->lookup_all_webhooks
+ = &TMH_PG_lookup_all_webhooks;
+ plugin->lookup_future_webhook
+ = &TMH_PG_lookup_future_webhook;
+ plugin->lookup_pending_webhooks
+ = &TMH_PG_lookup_pending_webhooks;
+ plugin->delete_pending_webhook
+ = &TMH_PG_delete_pending_webhook;
+ plugin->insert_pending_webhook
+ = &TMH_PG_insert_pending_webhook;
+ plugin->update_pending_webhook
+ = &TMH_PG_update_pending_webhook;
+ plugin->delete_exchange_accounts
+ = &TMH_PG_delete_exchange_accounts;
+ plugin->select_accounts_by_exchange
+ = &TMH_PG_select_accounts_by_exchange;
+ plugin->insert_exchange_account
+ = &TMH_PG_insert_exchange_account;
+ plugin->insert_token_family
+ = &TMH_PG_insert_token_family;
+ plugin->lookup_token_family
+ = &TMH_PG_lookup_token_family;
+ plugin->lookup_token_families
+ = &TMH_PG_lookup_token_families;
+ plugin->delete_token_family
+ = &TMH_PG_delete_token_family;
+ plugin->update_token_family
+ = &TMH_PG_update_token_family;
+ plugin->insert_token_family_key
+ = &TMH_PG_insert_token_family_key;
+ plugin->lookup_token_family_key
+ = &TMH_PG_lookup_token_family_key;
+ plugin->update_deposit_confirmation_status
+ = &TMH_PG_update_deposit_confirmation_status;
+
+
return plugin;
}
@@ -10693,7 +607,6 @@ libtaler_plugin_merchantdb_postgres_done (void *cls)
pg->conn = NULL;
}
GNUNET_free (pg->sql_dir);
- GNUNET_free (pg->currency);
GNUNET_free (pg);
GNUNET_free (plugin);
return NULL;