From 057ac0fa95c29421b3868f43696023af3ec4cdd6 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 25 Jun 2020 17:27:49 +0200 Subject: logic to update 'wired' status of an order --- src/backenddb/plugin_merchantdb_postgres.c | 85 +++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) (limited to 'src/backenddb') diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index ba08d934..efb58918 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -214,6 +214,41 @@ postgres_start (void *cls, } +/** + * 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 int +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_DEBUG, + "Starting merchant DB transaction (READ COMMITTED)\n"); + 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. * @@ -3226,8 +3261,8 @@ RETRY: if (MAX_RETRIES < ++retries) return GNUNET_DB_STATUS_SOFT_ERROR; if (GNUNET_OK != - postgres_start (pg, - "insert transfer details")) + postgres_start_read_committed (pg, + "insert transfer details")) { GNUNET_break (0); return GNUNET_DB_STATUS_HARD_ERROR; @@ -3320,6 +3355,30 @@ RETRY: return qs; } } + /* 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) */ + for (unsigned int i = 0; idetails_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; + return qs; + } + } qs = postgres_commit (pg); if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; @@ -7425,6 +7484,27 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " WHERE coin_pub=$7" " AND h_contract_terms=$8", 8), + /* 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)))", + 1), /* for postgres_lookup_wire_fee() */ GNUNET_PQ_make_prepare ("lookup_wire_fee", "SELECT" @@ -8206,6 +8286,7 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) plugin->drop_tables = &postgres_drop_tables; 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; -- cgit v1.2.3