From 2dab1fac1c08ac75c12708ae0cf10e2108a76256 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 22 Apr 2023 01:20:41 +0200 Subject: [PATCH] misc bugfixes in reserves_in batch logic --- .../taler-exchange-httpd_reserves_get.c | 40 +- .../exchange_do_reserves_in_insert.sql | 1349 ++++++++--------- src/exchangedb/pg_reserves_in_insert.c | 1018 +++++-------- src/testing/testing_api_cmd_exec_wirewatch.c | 1 - src/testing/testing_api_loop.c | 2 +- 5 files changed, 1082 insertions(+), 1328 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c b/src/exchange/taler-exchange-httpd_reserves_get.c index 003db9260..c22e62bf5 100644 --- a/src/exchange/taler-exchange-httpd_reserves_get.c +++ b/src/exchange/taler-exchange-httpd_reserves_get.c @@ -147,18 +147,13 @@ db_event_cb (void *cls, const void *extra, size_t extra_size) { - struct TEH_RequestContext *rc = cls; - struct ReservePoller *rp = rc->rh_ctx; + struct ReservePoller *rp = cls; struct GNUNET_AsyncScopeSave old_scope; (void) extra; (void) extra_size; if (! rp->suspended) return; /* might get multiple wake-up events */ - GNUNET_async_scope_enter (&rc->async_scope_id, - &old_scope); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Resuming from long-polling on reserve\n"); TEH_check_invariants (); rp->suspended = false; MHD_resume_connection (rp->connection); @@ -238,7 +233,8 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc, }; GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Starting DB event listening\n"); + "Starting DB event listening until %s\n", + GNUNET_TIME_absolute2s (rp->timeout)); rp->eh = TEH_plugin->event_listen ( TEH_plugin->cls, GNUNET_TIME_absolute_get_remaining (rp->timeout), @@ -256,49 +252,27 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc, { case GNUNET_DB_STATUS_SOFT_ERROR: GNUNET_break (0); /* single-shot query should never have soft-errors */ - if (NULL != rp->eh) - { - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - rp->eh); - rp->eh = NULL; - } return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_SOFT_FAILURE, "get_reserve_balance"); case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (0); - if (NULL != rp->eh) - { - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - rp->eh); - rp->eh = NULL; - } return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, "get_reserve_balance"); case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - if (NULL != rp->eh) - { - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - rp->eh); - rp->eh = NULL; - } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Got reserve balance of %s\n", + TALER_amount2s (&rp->balance)); return TALER_MHD_REPLY_JSON_PACK (rc->connection, MHD_HTTP_OK, TALER_JSON_pack_amount ("balance", &rp->balance)); case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - if ( (NULL != rp) || - (GNUNET_TIME_absolute_is_future (rp->timeout)) ) + if (! GNUNET_TIME_absolute_is_future (rp->timeout)) { - if (NULL != rp->eh) - { - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - rp->eh); - rp->eh = NULL; - } return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_NOT_FOUND, TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN, diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql index 3a217accf..e7506dc85 100644 --- a/src/exchangedb/exchange_do_reserves_in_insert.sql +++ b/src/exchangedb/exchange_do_reserves_in_insert.sql @@ -23,12 +23,12 @@ CREATE OR REPLACE FUNCTION exchange_do_batch_reserves_in_insert( IN in_credit_frac INT4, IN in_exchange_account_name VARCHAR, IN in_execution_date INT8, - IN in_wire_source_h_payto BYTEA, ---h_payto + IN in_wire_source_h_payto BYTEA, IN in_payto_uri VARCHAR, - IN in_notify text, - OUT out_reserve_found BOOLEAN, - OUT transaction_duplicate BOOLEAN, - OUT ruuid INT8) + IN in_notify TEXT, + OUT out_reserve_found0 BOOLEAN, + OUT transaction_duplicate0 BOOLEAN, + OUT ruuid0 INT8) LANGUAGE plpgsql AS $$ DECLARE @@ -38,11 +38,10 @@ DECLARE DECLARE curs_trans refcursor; BEGIN - ruuid = 0; - out_reserve_found = TRUE; - transaction_duplicate = TRUE; + ruuid0 = 0; + out_reserve_found0 = TRUE; + transaction_duplicate0 = TRUE; ---SIMPLE INSERT ON CONFLICT DO NOTHING INSERT INTO wire_targets (wire_target_h_payto ,payto_uri) @@ -65,18 +64,16 @@ BEGIN ,in_credit_frac ,in_reserve_expiration ,in_gc_date) - ON CONFLICT DO NOTHING - RETURNING reserve_uuid, reserve_pub) - SELECT * FROM reserve_changes; + ON CONFLICT DO NOTHING + RETURNING reserve_uuid, reserve_pub) + SELECT reserve_uuid, reserve_pub FROM reserve_changes; + FETCH FROM curs INTO i; IF FOUND THEN -- We made a change, so the reserve did not previously exist. - IF in_reserve_pub = i.reserve_pub - THEN - out_reserve_found = FALSE; - ruuid = i.reserve_uuid; - END IF; + out_reserve_found0 = FALSE; + ruuid0 = i.reserve_uuid; END IF; CLOSE curs; @@ -100,56 +97,56 @@ BEGIN ,in_execution_date) ON CONFLICT DO NOTHING RETURNING reserve_pub) - SELECT * FROM reserve_transaction; + SELECT reserve_pub FROM reserve_transaction; + FETCH FROM curs_trans INTO i; IF FOUND THEN - IF i.reserve_pub = in_reserve_pub - THEN - -- HAPPY PATH THERE IS NO DUPLICATE TRANS - transaction_duplicate = FALSE; - EXECUTE FORMAT ( + transaction_duplicate0 = FALSE; + EXECUTE FORMAT ( 'NOTIFY %s' ,in_notify); - END IF; END IF; + CLOSE curs_trans; + RETURN; END $$; + CREATE OR REPLACE FUNCTION exchange_do_batch2_reserves_insert( IN in_gc_date INT8, IN in_reserve_expiration INT8, - IN in_reserve_pub BYTEA, - IN in_wire_ref INT8, - IN in_credit_val INT8, - IN in_credit_frac INT4, - IN in_exchange_account_name VARCHAR, - IN in_execution_date INT8, - IN in_wire_source_h_payto BYTEA, ---h_payto - IN in_payto_uri VARCHAR, - IN in_notify text, - IN in2_notify text, - IN in2_reserve_pub BYTEA, - IN in2_wire_ref INT8, - IN in2_credit_val INT8, - IN in2_credit_frac INT4, - IN in2_exchange_account_name VARCHAR, - IN in2_execution_date INT8, - IN in2_wire_source_h_payto BYTEA, ---h_payto - IN in2_payto_uri VARCHAR, - OUT out_reserve_found BOOLEAN, - OUT out_reserve_found2 BOOLEAN, - OUT transaction_duplicate BOOLEAN, - OUT transaction_duplicate2 BOOLEAN, - OUT ruuid INT8, - OUT ruuid2 INT8) + IN in0_reserve_pub BYTEA, + IN in0_wire_ref INT8, + IN in0_credit_val INT8, + IN in0_credit_frac INT4, + IN in0_exchange_account_name VARCHAR, + IN in0_execution_date INT8, + IN in0_wire_source_h_payto BYTEA, + IN in0_payto_uri VARCHAR, + IN in0_notify TEXT, + IN in1_reserve_pub BYTEA, + IN in1_wire_ref INT8, + IN in1_credit_val INT8, + IN in1_credit_frac INT4, + IN in1_exchange_account_name VARCHAR, + IN in1_execution_date INT8, + IN in1_wire_source_h_payto BYTEA, + IN in1_payto_uri VARCHAR, + IN in1_notify TEXT, + OUT out_reserve_found0 BOOLEAN, + OUT out_reserve_found1 BOOLEAN, + OUT transaction_duplicate0 BOOLEAN, + OUT transaction_duplicate1 BOOLEAN, + OUT ruuid0 INT8, + OUT ruuid1 INT8) LANGUAGE plpgsql AS $$ DECLARE curs_reserve_exist REFCURSOR; DECLARE - curs_transaction_exist refcursor; + curs_transaction_exist REFCURSOR; DECLARE i RECORD; DECLARE @@ -157,21 +154,21 @@ DECLARE DECLARE k INT8; BEGIN - transaction_duplicate=TRUE; - transaction_duplicate2=TRUE; - out_reserve_found = TRUE; - out_reserve_found2 = TRUE; - ruuid=0; - ruuid2=0; - k=0; + transaction_duplicate0 = TRUE; + transaction_duplicate1 = TRUE; + out_reserve_found0 = TRUE; + out_reserve_found1 = TRUE; + ruuid0=0; + ruuid1=0; + INSERT INTO wire_targets (wire_target_h_payto ,payto_uri) VALUES - (in_wire_source_h_payto - ,in_payto_uri), - (in2_wire_source_h_payto - ,in2_payto_uri) + (in0_wire_source_h_payto + ,in0_payto_uri), + (in1_wire_source_h_payto + ,in1_payto_uri) ON CONFLICT DO NOTHING; OPEN curs_reserve_exist FOR @@ -183,39 +180,51 @@ BEGIN ,expiration_date ,gc_date) VALUES - (in_reserve_pub - ,in_credit_val - ,in_credit_frac + (in0_reserve_pub + ,in0_credit_val + ,in0_credit_frac ,in_reserve_expiration ,in_gc_date), - (in2_reserve_pub - ,in2_credit_val - ,in2_credit_frac + (in1_reserve_pub + ,in1_credit_val + ,in1_credit_frac ,in_reserve_expiration ,in_gc_date) - ON CONFLICT DO NOTHING - RETURNING reserve_uuid,reserve_pub) - SELECT * FROM reserve_changes; - WHILE k < 2 LOOP + ON CONFLICT DO NOTHING + RETURNING reserve_uuid, reserve_pub) + SELECT reserve_uuid, reserve_pub FROM reserve_changes; + + k=0; + <> LOOP FETCH FROM curs_reserve_exist INTO i; - IF FOUND + IF NOT FOUND THEN - IF in_reserve_pub = i.reserve_pub - THEN - ruuid = i.reserve_uuid; - IF in_reserve_pub <> in2_reserve_pub - THEN - out_reserve_found = FALSE; - END IF; - END IF; - IF in2_reserve_pub = i.reserve_pub - THEN - out_reserve_found2 = FALSE; - ruuid2 = i.reserve_uuid; - END IF; + EXIT loop_reserve; END IF; - k=k+1; - END LOOP; + + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = i.reserve_pub + THEN + ruuid0 = i.reserve_uuid; + out_reserve_found0 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 1 THEN + IF in1_reserve_pub = i.reserve_pub + THEN + ruuid1 = i.reserve_uuid; + out_reserve_found1 = FALSE; + EXIT loop_reserve; + END IF; + EXIT loop_k; + END CASE; + END LOOP loop_k; + END LOOP loop_reserve; + CLOSE curs_reserve_exist; OPEN curs_transaction_exist FOR @@ -229,160 +238,153 @@ BEGIN ,wire_source_h_payto ,execution_date) VALUES - (in_reserve_pub - ,in_wire_ref - ,in_credit_val - ,in_credit_frac - ,in_exchange_account_name - ,in_wire_source_h_payto - ,in_execution_date), - (in2_reserve_pub - ,in2_wire_ref - ,in2_credit_val - ,in2_credit_frac - ,in2_exchange_account_name - ,in2_wire_source_h_payto - ,in2_execution_date) + (in0_reserve_pub + ,in0_wire_ref + ,in0_credit_val + ,in0_credit_frac + ,in0_exchange_account_name + ,in0_wire_source_h_payto + ,in0_execution_date), + (in1_reserve_pub + ,in1_wire_ref + ,in1_credit_val + ,in1_credit_frac + ,in1_exchange_account_name + ,in1_wire_source_h_payto + ,in1_execution_date) ON CONFLICT DO NOTHING RETURNING reserve_pub) - SELECT * FROM reserve_in_exist; + SELECT reserve_pub FROM reserve_in_exist; + FETCH FROM curs_transaction_exist INTO r; - IF FOUND - THEN - IF in_reserve_pub = r.reserve_pub + + k=0; + <> LOOP + FETCH FROM curs_transaction_exist INTO i; + IF NOT FOUND THEN - transaction_duplicate = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in_notify); + EXIT loop_transaction; END IF; - IF in2_reserve_pub = r.reserve_pub - THEN - transaction_duplicate2 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in2_notify); - END IF; - FETCH FROM curs_transaction_exist INTO r; - IF FOUND - THEN - IF in_reserve_pub = r.reserve_pub - THEN - transaction_duplicate = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in_notify); - END IF; - IF in2_reserve_pub = r.reserve_pub - THEN - transaction_duplicate2 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in2_notify); - END IF; - END IF; - END IF; -/* IF transaction_duplicate - OR transaction_duplicate2 - THEN - CLOSE curs_transaction_exist; - ROLLBACK; - RETURN; - END IF;*/ + + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = r.reserve_pub + THEN + transaction_duplicate0 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in0_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 1 THEN + IF in0_reserve_pub = r.reserve_pub + THEN + transaction_duplicate1 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in1_notify); + EXIT loop_transaction; + END IF; + END CASE; + END LOOP loop2_k; + END LOOP loop_transaction; + CLOSE curs_transaction_exist; + RETURN; END $$; + CREATE OR REPLACE FUNCTION exchange_do_batch4_reserves_insert( IN in_gc_date INT8, IN in_reserve_expiration INT8, - IN in_reserve_pub BYTEA, - IN in_wire_ref INT8, - IN in_credit_val INT8, - IN in_credit_frac INT4, - IN in_exchange_account_name VARCHAR, - IN in_execution_date INT8, - IN in_wire_source_h_payto BYTEA, ---h_payto - IN in_payto_uri VARCHAR, - IN in_notify text, - IN in2_notify text, - IN in3_notify text, - IN in4_notify text, + IN in0_reserve_pub BYTEA, + IN in0_wire_ref INT8, + IN in0_credit_val INT8, + IN in0_credit_frac INT4, + IN in0_exchange_account_name VARCHAR, + IN in0_execution_date INT8, + IN in0_wire_source_h_payto BYTEA, + IN in0_payto_uri VARCHAR, + IN in0_notify TEXT, + IN in1_reserve_pub BYTEA, + IN in1_wire_ref INT8, + IN in1_credit_val INT8, + IN in1_credit_frac INT4, + IN in1_exchange_account_name VARCHAR, + IN in1_execution_date INT8, + IN in1_wire_source_h_payto BYTEA, + IN in1_payto_uri VARCHAR, + IN in1_notify TEXT, IN in2_reserve_pub BYTEA, IN in2_wire_ref INT8, IN in2_credit_val INT8, IN in2_credit_frac INT4, IN in2_exchange_account_name VARCHAR, IN in2_execute_date INT8, - IN in2_wire_source_h_payto BYTEA, ---h_payto + IN in2_wire_source_h_payto BYTEA, IN in2_payto_uri VARCHAR, + IN in2_notify TEXT, IN in3_reserve_pub BYTEA, IN in3_wire_ref INT8, IN in3_credit_val INT8, IN in3_credit_frac INT4, IN in3_exchange_account_name VARCHAR, IN in3_execute_date INT8, - IN in3_wire_source_h_payto BYTEA, ---h_payto + IN in3_wire_source_h_payto BYTEA, IN in3_payto_uri VARCHAR, - IN in4_reserve_pub BYTEA, - IN in4_wire_ref INT8, - IN in4_credit_val INT8, - IN in4_credit_frac INT4, - IN in4_exchange_account_name VARCHAR, - IN in4_execution_date INT8, - IN in4_wire_source_h_payto BYTEA, ---h_payto - IN in4_payto_uri VARCHAR, - OUT out_reserve_found BOOLEAN, + IN in3_notify TEXT, + OUT out_reserve_found0 BOOLEAN, + OUT out_reserve_found1 BOOLEAN, OUT out_reserve_found2 BOOLEAN, OUT out_reserve_found3 BOOLEAN, - OUT out_reserve_found4 BOOLEAN, - OUT transaction_duplicate BOOLEAN, + OUT transaction_duplicate0 BOOLEAN, + OUT transaction_duplicate1 BOOLEAN, OUT transaction_duplicate2 BOOLEAN, OUT transaction_duplicate3 BOOLEAN, - OUT transaction_duplicate4 BOOLEAN, - OUT ruuid INT8, + OUT ruuid0 INT8, + OUT ruuid1 INT8, OUT ruuid2 INT8, - OUT ruuid3 INT8, - OUT ruuid4 INT8) + OUT ruuid3 INT8) LANGUAGE plpgsql AS $$ DECLARE - curs_reserve_exist refcursor; + curs_reserve_exist REFCURSOR; DECLARE k INT8; DECLARE - curs_transaction_exist refcursor; + curs_transaction_exist REFCURSOR; DECLARE i RECORD; - BEGIN ---INITIALIZATION - transaction_duplicate=TRUE; + transaction_duplicate0=TRUE; + transaction_duplicate1=TRUE; transaction_duplicate2=TRUE; transaction_duplicate3=TRUE; - transaction_duplicate4=TRUE; - out_reserve_found = TRUE; + out_reserve_found0 = TRUE; + out_reserve_found1 = TRUE; out_reserve_found2 = TRUE; out_reserve_found3 = TRUE; - out_reserve_found4 = TRUE; - ruuid=0; + ruuid0=0; + ruuid1=0; ruuid2=0; ruuid3=0; - ruuid4=0; - k=0; - --SIMPLE INSERT ON CONFLICT DO NOTHING + INSERT INTO wire_targets (wire_target_h_payto ,payto_uri) VALUES - (in_wire_source_h_payto - ,in_payto_uri), + (in0_wire_source_h_payto + ,in0_payto_uri), + (in1_wire_source_h_payto + ,in1_payto_uri), (in2_wire_source_h_payto ,in2_payto_uri), (in3_wire_source_h_payto - ,in3_payto_uri), - (in4_wire_source_h_payto - ,in4_payto_uri) + ,in3_payto_uri) ON CONFLICT DO NOTHING; OPEN curs_reserve_exist FOR @@ -394,9 +396,14 @@ BEGIN ,expiration_date ,gc_date) VALUES - (in_reserve_pub - ,in_credit_val - ,in_credit_frac + (in0_reserve_pub + ,in0_credit_val + ,in0_credit_frac + ,in_reserve_expiration + ,in_gc_date), + (in1_reserve_pub + ,in1_credit_val + ,in1_credit_frac ,in_reserve_expiration ,in_gc_date), (in2_reserve_pub @@ -408,310 +415,313 @@ BEGIN ,in3_credit_val ,in3_credit_frac ,in_reserve_expiration - ,in_gc_date), - (in4_reserve_pub - ,in4_credit_val - ,in4_credit_frac - ,in_reserve_expiration ,in_gc_date) - ON CONFLICT DO NOTHING - RETURNING reserve_uuid,reserve_pub) - SELECT * FROM reserve_changes; - - WHILE k < 4 LOOP - FETCH FROM curs_reserve_exist INTO i; - IF FOUND - THEN - IF in_reserve_pub = i.reserve_pub - THEN - ruuid = i.reserve_uuid; - IF in_reserve_pub - NOT IN (in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub) - THEN - out_reserve_found = FALSE; - END IF; - END IF; - IF in2_reserve_pub = i.reserve_pub - THEN - ruuid2 = i.reserve_uuid; - IF in2_reserve_pub - NOT IN (in_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub) - THEN - out_reserve_found2 = FALSE; - END IF; - END IF; - IF in3_reserve_pub = i.reserve_pub - THEN - ruuid3 = i.reserve_uuid; - IF in3_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in4_reserve_pub) - THEN - out_reserve_found3 = FALSE; - END IF; - END IF; - IF in4_reserve_pub = i.reserve_pub - THEN - ruuid4 = i.reserve_uuid; - IF in4_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub) - THEN - out_reserve_found4 = FALSE; - END IF; - END IF; - END IF; - k=k+1; - END LOOP; - CLOSE curs_reserve_exist; + ON CONFLICT DO NOTHING + RETURNING reserve_uuid,reserve_pub) + SELECT reserve_uuid, reserve_pub FROM reserve_changes; k=0; - OPEN curs_transaction_exist FOR - WITH reserve_in_changes AS ( - INSERT INTO reserves_in - (reserve_pub - ,wire_reference - ,credit_val - ,credit_frac - ,exchange_account_section - ,wire_source_h_payto - ,execution_date) - VALUES - (in_reserve_pub - ,in_wire_ref - ,in_credit_val - ,in_credit_frac - ,in_exchange_account_name - ,in_wire_source_h_payto - ,in_execution_date), - (in2_reserve_pub - ,in2_wire_ref - ,in2_credit_val - ,in2_credit_frac - ,in2_exchange_account_name - ,in2_wire_source_h_payto - ,in2_execution_date), - (in3_reserve_pub - ,in3_wire_ref - ,in3_credit_val - ,in3_credit_frac - ,in3_exchange_account_name - ,in3_wire_source_h_payto - ,in3_execution_date), - (in4_reserve_pub - ,in4_wire_ref - ,in4_credit_val - ,in4_credit_frac - ,in4_exchange_account_name - ,in4_wire_source_h_payto - ,in4_execution_date) - ON CONFLICT DO NOTHING - RETURNING reserve_pub) - SELECT * FROM reserve_in_changes; - WHILE k < 4 LOOP - FETCH FROM curs_transaction_exist INTO i; - IF FOUND + <> LOOP + FETCH FROM curs_reserve_exist INTO i; + IF NOT FOUND THEN - IF in_reserve_pub = i.reserve_pub - THEN - transaction_duplicate = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in_notify); - END IF; - IF in2_reserve_pub = i.reserve_pub - THEN - transaction_duplicate2 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in2_notify); - END IF; - IF in3_reserve_pub = i.reserve_pub - THEN - transaction_duplicate3 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in3_notify); - END IF; - IF in4_reserve_pub = i.reserve_pub - THEN - transaction_duplicate4 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in4_notify); - END IF; + EXIT loop_reserve; END IF; - k=k+1; - END LOOP; - /**ROLLBACK TRANSACTION IN SORTED PROCEDURE IS IT PROSSIBLE ?**/ - /*IF transaction_duplicate - OR transaction_duplicate2 - OR transaction_duplicate3 - OR transaction_duplicate4 - THEN - RAISE EXCEPTION 'Reserve did not exist, but INSERT into reserves_in gave conflict'; - ROLLBACK; - CLOSE curs_transaction_exist; - RETURN; - END IF;*/ - CLOSE curs_transaction_exist; - RETURN; + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = i.reserve_pub + THEN + ruuid0 = i.reserve_uuid; + out_reserve_found0 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 1 THEN + k = k + 1; + IF in1_reserve_pub = i.reserve_pub + THEN + ruuid1 = i.reserve_uuid; + out_reserve_found1 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 2 THEN + k = k + 1; + IF in2_reserve_pub = i.reserve_pub + THEN + ruuid2 = i.reserve_uuid; + out_reserve_found2 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 3 THEN + IF in3_reserve_pub = i.reserve_pub + THEN + ruuid3 = i.reserve_uuid; + out_reserve_found3 = FALSE; + EXIT loop_reserve; + END IF; + EXIT loop_k; + END CASE; + END LOOP loop_k; + END LOOP loop_reserve; + + CLOSE curs_reserve_exist; + + OPEN curs_transaction_exist FOR + WITH reserve_changes AS ( + INSERT INTO reserves_in + (reserve_pub + ,wire_reference + ,credit_val + ,credit_frac + ,exchange_account_section + ,wire_source_h_payto + ,execution_date) + VALUES + (in0_reserve_pub + ,in0_wire_ref + ,in0_credit_val + ,in0_credit_frac + ,in0_exchange_account_name + ,in0_wire_source_h_payto + ,in0_execution_date), + (in1_reserve_pub + ,in1_wire_ref + ,in1_credit_val + ,in1_credit_frac + ,in1_exchange_account_name + ,in1_wire_source_h_payto + ,in1_execution_date), + (in2_reserve_pub + ,in2_wire_ref + ,in2_credit_val + ,in2_credit_frac + ,in2_exchange_account_name + ,in2_wire_source_h_payto + ,in2_execution_date), + (in3_reserve_pub + ,in3_wire_ref + ,in3_credit_val + ,in3_credit_frac + ,in3_exchange_account_name + ,in3_wire_source_h_payto + ,in3_execution_date) + ON CONFLICT DO NOTHING + RETURNING reserve_pub) + SELECT reserve_uuid, reserve_pub FROM reserve_changes; + + k=0; + <> LOOP + FETCH FROM curs_transaction_exist INTO i; + IF NOT FOUND + THEN + EXIT loop_transaction; + END IF; + + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = r.reserve_pub + THEN + transaction_duplicate0 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in0_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 1 THEN + k = k + 1; + IF in1_reserve_pub = r.reserve_pub + THEN + transaction_duplicate1 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in1_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 2 THEN + k = k + 1; + IF in2_reserve_pub = r.reserve_pub + THEN + transaction_duplicate2 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in2_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 3 THEN + IF in3_reserve_pub = r.reserve_pub + THEN + transaction_duplicate3 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in3_notify); + EXIT loop_transaction; + END IF; + END CASE; + END LOOP loop2_k; + END LOOP loop_transaction; + + CLOSE curs_transaction_exist; + + RETURN; END $$; + CREATE OR REPLACE FUNCTION exchange_do_batch8_reserves_insert( IN in_gc_date INT8, IN in_reserve_expiration INT8, - IN in_reserve_pub BYTEA, - IN in_wire_ref INT8, - IN in_credit_val INT8, - IN in_credit_frac INT4, - IN in_exchange_account_name VARCHAR, - IN in_execution_date INT8, - IN in_wire_source_h_payto BYTEA, ---h_payto - IN in_payto_uri VARCHAR, - IN in_notify text, - IN in2_notify text, - IN in3_notify text, - IN in4_notify text, - IN in5_notify text, - IN in6_notify text, - IN in7_notify text, - IN in8_notify text, + IN in0_reserve_pub BYTEA, + IN in0_wire_ref INT8, + IN in0_credit_val INT8, + IN in0_credit_frac INT4, + IN in0_exchange_account_name VARCHAR, + IN in0_execution_date INT8, + IN in0_wire_source_h_payto BYTEA, + IN in0_payto_uri VARCHAR, + IN in0_notify TEXT, + IN in1_reserve_pub BYTEA, + IN in1_wire_ref INT8, + IN in1_credit_val INT8, + IN in1_credit_frac INT4, + IN in1_exchange_account_name VARCHAR, + IN in1_execution_date INT8, + IN in1_wire_source_h_payto BYTEA, + IN in1_payto_uri VARCHAR, + IN in1_notify TEXT, IN in2_reserve_pub BYTEA, IN in2_wire_ref INT8, IN in2_credit_val INT8, IN in2_credit_frac INT4, IN in2_exchange_account_name VARCHAR, IN in2_execution_date INT8, - IN in2_wire_source_h_payto BYTEA, ---h_payto + IN in2_wire_source_h_payto BYTEA, IN in2_payto_uri VARCHAR, + IN in2_notify TEXT, IN in3_reserve_pub BYTEA, IN in3_wire_ref INT8, IN in3_credit_val INT8, IN in3_credit_frac INT4, IN in3_exchange_account_name VARCHAR, IN in3_execution_date INT8, - IN in3_wire_source_h_payto BYTEA, ---h_payto + IN in3_wire_source_h_payto BYTEA, IN in3_payto_uri VARCHAR, + IN in3_notify TEXT, IN in4_reserve_pub BYTEA, IN in4_wire_ref INT8, IN in4_credit_val INT8, IN in4_credit_frac INT4, IN in4_exchange_account_name VARCHAR, IN in4_execution_date INT8, - IN in4_wire_source_h_payto BYTEA, ---h_payto + IN in4_wire_source_h_payto BYTEA, IN in4_payto_uri VARCHAR, + IN in4_notify TEXT, IN in5_reserve_pub BYTEA, IN in5_wire_ref INT8, IN in5_credit_val INT8, IN in5_credit_frac INT4, IN in5_exchange_account_name VARCHAR, IN in5_execution_date INT8, - IN in5_wire_source_h_payto BYTEA, ---h_payto + IN in5_wire_source_h_payto BYTEA, IN in5_payto_uri VARCHAR, + IN in5_notify TEXT, IN in6_reserve_pub BYTEA, IN in6_wire_ref INT8, IN in6_credit_val INT8, IN in6_credit_frac INT4, IN in6_exchange_account_name VARCHAR, IN in6_execution_date INT8, - IN in6_wire_source_h_payto BYTEA, ---h_payto + IN in6_wire_source_h_payto BYTEA, IN in6_payto_uri VARCHAR, + IN in6_notify TEXT, IN in7_reserve_pub BYTEA, IN in7_wire_ref INT8, IN in7_credit_val INT8, IN in7_credit_frac INT4, IN in7_exchange_account_name VARCHAR, IN in7_execution_date INT8, - IN in7_wire_source_h_payto BYTEA, ---h_payto + IN in7_wire_source_h_payto BYTEA, IN in7_payto_uri VARCHAR, - IN in8_reserve_pub BYTEA, - IN in8_wire_ref INT8, - IN in8_credit_val INT8, - IN in8_credit_frac INT4, - IN in8_exchange_account_name VARCHAR, - IN in8_execution_date INT8, - IN in8_wire_source_h_payto BYTEA, ---h_payto - IN in8_payto_uri VARCHAR, - OUT out_reserve_found BOOLEAN, + IN in7_notify TEXT, + OUT out_reserve_found0 BOOLEAN, + OUT out_reserve_found1 BOOLEAN, OUT out_reserve_found2 BOOLEAN, OUT out_reserve_found3 BOOLEAN, OUT out_reserve_found4 BOOLEAN, OUT out_reserve_found5 BOOLEAN, OUT out_reserve_found6 BOOLEAN, OUT out_reserve_found7 BOOLEAN, - OUT out_reserve_found8 BOOLEAN, - OUT transaction_duplicate BOOLEAN, + OUT transaction_duplicate0 BOOLEAN, + OUT transaction_duplicate1 BOOLEAN, OUT transaction_duplicate2 BOOLEAN, OUT transaction_duplicate3 BOOLEAN, OUT transaction_duplicate4 BOOLEAN, OUT transaction_duplicate5 BOOLEAN, OUT transaction_duplicate6 BOOLEAN, OUT transaction_duplicate7 BOOLEAN, - OUT transaction_duplicate8 BOOLEAN, - OUT ruuid INT8, + OUT ruuid0 INT8, + OUT ruuid1 INT8, OUT ruuid2 INT8, OUT ruuid3 INT8, OUT ruuid4 INT8, OUT ruuid5 INT8, OUT ruuid6 INT8, - OUT ruuid7 INT8, - OUT ruuid8 INT8) + OUT ruuid7 INT8) LANGUAGE plpgsql AS $$ DECLARE - curs_reserve_existed refcursor; + curs_reserve_exist REFCURSOR; DECLARE k INT8; DECLARE - curs_transaction_existed refcursor; + curs_transaction_exist REFCURSOR; DECLARE i RECORD; DECLARE r RECORD; BEGIN ---INITIALIZATION - transaction_duplicate=TRUE; + transaction_duplicate0=TRUE; + transaction_duplicate1=TRUE; transaction_duplicate2=TRUE; transaction_duplicate3=TRUE; transaction_duplicate4=TRUE; transaction_duplicate5=TRUE; transaction_duplicate6=TRUE; transaction_duplicate7=TRUE; - transaction_duplicate8=TRUE; - out_reserve_found = TRUE; + out_reserve_found0 = TRUE; + out_reserve_found1 = TRUE; out_reserve_found2 = TRUE; out_reserve_found3 = TRUE; out_reserve_found4 = TRUE; out_reserve_found5 = TRUE; out_reserve_found6 = TRUE; out_reserve_found7 = TRUE; - out_reserve_found8 = TRUE; - ruuid=0; + ruuid0=0; + ruuid1=0; ruuid2=0; ruuid3=0; ruuid4=0; ruuid5=0; ruuid6=0; ruuid7=0; - ruuid8=0; - k=0; - --SIMPLE INSERT ON CONFLICT DO NOTHING INSERT INTO wire_targets (wire_target_h_payto ,payto_uri) VALUES - (in_wire_source_h_payto - ,in_payto_uri), + (in0_wire_source_h_payto + ,in0_payto_uri), + (in1_wire_source_h_payto + ,in1_payto_uri), (in2_wire_source_h_payto ,in2_payto_uri), (in3_wire_source_h_payto @@ -723,12 +733,10 @@ BEGIN (in6_wire_source_h_payto ,in6_payto_uri), (in7_wire_source_h_payto - ,in7_payto_uri), - (in8_wire_source_h_payto - ,in8_payto_uri) + ,in7_payto_uri) ON CONFLICT DO NOTHING; - OPEN curs_reserve_existed FOR + OPEN curs_reserve_exist FOR WITH reserve_changes AS ( INSERT INTO reserves (reserve_pub @@ -737,9 +745,14 @@ BEGIN ,expiration_date ,gc_date) VALUES - (in_reserve_pub - ,in_credit_val - ,in_credit_frac + (in0_reserve_pub + ,in0_credit_val + ,in0_credit_frac + ,in_reserve_expiration + ,in_gc_date), + (in1_reserve_pub + ,in1_credit_val + ,in1_credit_frac ,in_reserve_expiration ,in_gc_date), (in2_reserve_pub @@ -771,295 +784,269 @@ BEGIN ,in7_credit_val ,in7_credit_frac ,in_reserve_expiration - ,in_gc_date), - (in8_reserve_pub - ,in8_credit_val - ,in8_credit_frac - ,in_reserve_expiration ,in_gc_date) - ON CONFLICT DO NOTHING - RETURNING reserve_uuid,reserve_pub) - SELECT * FROM reserve_changes; - - WHILE k < 8 LOOP - - FETCH FROM curs_reserve_existed INTO i; - IF FOUND - THEN - IF in_reserve_pub = i.reserve_pub - THEN - ruuid = i.reserve_uuid; - IF in_reserve_pub - NOT IN (in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found = FALSE; - END IF; - END IF; - IF in2_reserve_pub = i.reserve_pub - THEN - ruuid2 = i.reserve_uuid; - IF in2_reserve_pub - NOT IN (in_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found2 = FALSE; - END IF; - END IF; - IF in3_reserve_pub = i.reserve_pub - THEN - ruuid3 = i.reserve_uuid; - IF in3_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found3 = FALSE; - END IF; - END IF; - IF in4_reserve_pub = i.reserve_pub - THEN - ruuid4 = i.reserve_uuid; - IF in4_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found4 = FALSE; - END IF; - END IF; - IF in5_reserve_pub = i.reserve_pub - THEN - ruuid5 = i.reserve_uuid; - IF in5_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found5 = FALSE; - END IF; - END IF; - IF in6_reserve_pub = i.reserve_pub - THEN - ruuid6 = i.reserve_uuid; - IF in6_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found6 = FALSE; - END IF; - END IF; - IF in7_reserve_pub = i.reserve_pub - THEN - ruuid7 = i.reserve_uuid; - IF in7_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found7 = FALSE; - END IF; - END IF; - IF in8_reserve_pub = i.reserve_pub - THEN - ruuid8 = i.reserve_uuid; - IF in8_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub) - THEN - out_reserve_found8 = FALSE; - END IF; - END IF; - END IF; - k=k+1; - END LOOP; - - CLOSE curs_reserve_existed; + ON CONFLICT DO NOTHING + RETURNING reserve_uuid,reserve_pub) + SELECT reserve_uuid, reserve_pub FROM reserve_changes; k=0; - OPEN curs_transaction_existed FOR - WITH reserve_in_changes AS ( - INSERT INTO reserves_in - (reserve_pub - ,wire_reference - ,credit_val - ,credit_frac - ,exchange_account_section - ,wire_source_h_payto - ,execution_date) - VALUES - (in_reserve_pub - ,in_wire_ref - ,in_credit_val - ,in_credit_frac - ,in_exchange_account_name - ,in_wire_source_h_payto - ,in_execution_date), - (in2_reserve_pub - ,in2_wire_ref - ,in2_credit_val - ,in2_credit_frac - ,in2_exchange_account_name - ,in2_wire_source_h_payto - ,in2_execution_date), - (in3_reserve_pub - ,in3_wire_ref - ,in3_credit_val - ,in3_credit_frac - ,in3_exchange_account_name - ,in3_wire_source_h_payto - ,in3_execution_date), - (in4_reserve_pub - ,in4_wire_ref - ,in4_credit_val - ,in4_credit_frac - ,in4_exchange_account_name - ,in4_wire_source_h_payto - ,in4_execution_date), - (in5_reserve_pub - ,in5_wire_ref - ,in5_credit_val - ,in5_credit_frac - ,in5_exchange_account_name - ,in5_wire_source_h_payto - ,in5_execution_date), - (in6_reserve_pub - ,in6_wire_ref - ,in6_credit_val - ,in6_credit_frac - ,in6_exchange_account_name - ,in6_wire_source_h_payto - ,in6_execution_date), - (in7_reserve_pub - ,in7_wire_ref - ,in7_credit_val - ,in7_credit_frac - ,in7_exchange_account_name - ,in7_wire_source_h_payto - ,in7_execution_date), - (in8_reserve_pub - ,in8_wire_ref - ,in8_credit_val - ,in8_credit_frac - ,in8_exchange_account_name - ,in8_wire_source_h_payto - ,in8_execution_date) - ON CONFLICT DO NOTHING - RETURNING reserve_pub) - SELECT * FROM reserve_in_changes; - - WHILE k < 8 LOOP - FETCH FROM curs_transaction_existed INTO r; - IF FOUND + <> LOOP + FETCH FROM curs_reserve_exist INTO i; + IF NOT FOUND THEN - IF in_reserve_pub = r.reserve_pub - THEN - transaction_duplicate = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in_notify); - END IF; - IF in2_reserve_pub = r.reserve_pub - THEN - transaction_duplicate2 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in2_notify); - END IF; - IF in3_reserve_pub = r.reserve_pub - THEN - transaction_duplicate3 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in3_notify); - END IF; - IF in4_reserve_pub = r.reserve_pub - THEN - transaction_duplicate4 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in4_notify); - END IF; - IF in5_reserve_pub = r.reserve_pub - THEN - transaction_duplicate5 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in5_notify); - END IF; - IF in6_reserve_pub = r.reserve_pub - THEN - transaction_duplicate6 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in6_notify); - END IF; - IF in7_reserve_pub = r.reserve_pub - THEN - transaction_duplicate7 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in7_notify); - END IF; - IF in8_reserve_pub = r.reserve_pub - THEN - transaction_duplicate8 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in8_notify); - END IF; + EXIT loop_reserve; END IF; - k=k+1; - END LOOP; - /* IF transaction_duplicate - OR transaction_duplicate2 - OR transaction_duplicate3 - OR transaction_duplicate4 - OR transaction_duplicate5 - OR transaction_duplicate6 - OR transaction_duplicate7 - OR transaction_duplicate8 - THEN - CLOSE curs_transaction_existed; - ROLLBACK; - RETURN; - END IF;*/ - CLOSE curs_transaction_existed; + + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = i.reserve_pub + THEN + ruuid0 = i.reserve_uuid; + out_reserve_found0 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 1 THEN + k = k + 1; + IF in1_reserve_pub = i.reserve_pub + THEN + ruuid1 = i.reserve_uuid; + out_reserve_found1 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 2 THEN + k = k + 1; + IF in2_reserve_pub = i.reserve_pub + THEN + ruuid2 = i.reserve_uuid; + out_reserve_found2 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 3 THEN + k = k + 1; + IF in3_reserve_pub = i.reserve_pub + THEN + ruuid3 = i.reserve_uuid; + out_reserve_found3 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 4 THEN + k = k + 1; + IF in4_reserve_pub = i.reserve_pub + THEN + ruuid4 = i.reserve_uuid; + out_reserve_found4 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 5 THEN + k = k + 1; + IF in5_reserve_pub = i.reserve_pub + THEN + ruuid5 = i.reserve_uuid; + out_reserve_found5 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 6 THEN + k = k + 1; + IF in6_reserve_pub = i.reserve_pub + THEN + ruuid6 = i.reserve_uuid; + out_reserve_found6 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 7 THEN + IF in7_reserve_pub = i.reserve_pub + THEN + ruuid7 = i.reserve_uuid; + out_reserve_found7 = FALSE; + EXIT loop_reserve; + END IF; + EXIT loop_k; + END CASE; + END LOOP loop_k; + END LOOP loop_reserve; + + CLOSE curs_reserve_exist; + + OPEN curs_transaction_exist FOR + WITH reserve_changes AS ( + INSERT INTO reserves_in + (reserve_pub + ,wire_reference + ,credit_val + ,credit_frac + ,exchange_account_section + ,wire_source_h_payto + ,execution_date) + VALUES + (in0_reserve_pub + ,in0_wire_ref + ,in0_credit_val + ,in0_credit_frac + ,in0_exchange_account_name + ,in0_wire_source_h_payto + ,in0_execution_date), + (in1_reserve_pub + ,in1_wire_ref + ,in1_credit_val + ,in1_credit_frac + ,in1_exchange_account_name + ,in1_wire_source_h_payto + ,in1_execution_date), + (in2_reserve_pub + ,in2_wire_ref + ,in2_credit_val + ,in2_credit_frac + ,in2_exchange_account_name + ,in2_wire_source_h_payto + ,in2_execution_date), + (in3_reserve_pub + ,in3_wire_ref + ,in3_credit_val + ,in3_credit_frac + ,in3_exchange_account_name + ,in3_wire_source_h_payto + ,in3_execution_date), + (in4_reserve_pub + ,in4_wire_ref + ,in4_credit_val + ,in4_credit_frac + ,in4_exchange_account_name + ,in4_wire_source_h_payto + ,in4_execution_date), + (in5_reserve_pub + ,in5_wire_ref + ,in5_credit_val + ,in5_credit_frac + ,in5_exchange_account_name + ,in5_wire_source_h_payto + ,in5_execution_date), + (in6_reserve_pub + ,in6_wire_ref + ,in6_credit_val + ,in6_credit_frac + ,in6_exchange_account_name + ,in6_wire_source_h_payto + ,in6_execution_date), + (in7_reserve_pub + ,in7_wire_ref + ,in7_credit_val + ,in7_credit_frac + ,in7_exchange_account_name + ,in7_wire_source_h_payto + ,in7_execution_date) + ON CONFLICT DO NOTHING + RETURNING reserve_pub) + SELECT reserve_pub FROM reserve_changes; + + k=0; + <> LOOP + FETCH FROM curs_transaction_exist INTO i; + IF NOT FOUND + THEN + EXIT loop_transaction; + END IF; + + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = r.reserve_pub + THEN + transaction_duplicate0 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in0_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 1 THEN + k = k + 1; + IF in1_reserve_pub = r.reserve_pub + THEN + transaction_duplicate1 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in1_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 2 THEN + k = k + 1; + IF in2_reserve_pub = r.reserve_pub + THEN + transaction_duplicate2 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in2_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 3 THEN + k = k + 1; + IF in3_reserve_pub = r.reserve_pub + THEN + transaction_duplicate3 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in3_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 4 THEN + k = k + 1; + IF in4_reserve_pub = r.reserve_pub + THEN + transaction_duplicate4 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in4_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 5 THEN + k = k + 1; + IF in5_reserve_pub = r.reserve_pub + THEN + transaction_duplicate2 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in5_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 6 THEN + k = k + 1; + IF in6_reserve_pub = r.reserve_pub + THEN + transaction_duplicate6 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in6_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 7 THEN + IF in7_reserve_pub = r.reserve_pub + THEN + transaction_duplicate7 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in7_notify); + EXIT loop_transaction; + END IF; + END CASE; + END LOOP loop2_k; + END LOOP loop_transaction; + + CLOSE curs_transaction_exist; RETURN; END $$; diff --git a/src/exchangedb/pg_reserves_in_insert.c b/src/exchangedb/pg_reserves_in_insert.c index 876774de9..2e29a1857 100644 --- a/src/exchangedb/pg_reserves_in_insert.c +++ b/src/exchangedb/pg_reserves_in_insert.c @@ -55,53 +55,107 @@ compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub) } +/** + * Record we keep per reserve to process. + */ +struct ReserveRecord +{ + /** + * Details about reserve to insert (input). + */ + const struct TALER_EXCHANGEDB_ReserveInInfo *reserve; + + /** + * Hash of the payto URI in @e reserve. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Notification to trigger on the reserve (input). + */ + char *notify_s; + + /** + * Set to UUID of the reserve (output); + */ + uint64_t reserve_uuid; + + /** + * Set to true if the transaction was an exact duplicate (output). + */ + bool transaction_duplicate; + + /** + * Set to true if the transaction conflicted with an existing reserve (output) + * and needs to be re-done with an UPDATE. + */ + bool conflicts; +}; + + +/** + * Generate the SQL parameters to insert the record @a rr at + * index @a index + */ +#define RR_QUERY_PARAM(rr,index) \ + GNUNET_PQ_query_param_auto_from_type (rr[index].reserve->reserve_pub), \ + GNUNET_PQ_query_param_uint64 (&rr[index].reserve->wire_reference), \ + TALER_PQ_query_param_amount (rr[index].reserve->balance), \ + GNUNET_PQ_query_param_string (rr[index].reserve->exchange_account_name), \ + GNUNET_PQ_query_param_timestamp (&rr[index].reserve->execution_time), \ + GNUNET_PQ_query_param_auto_from_type (&rr[index].h_payto), \ + GNUNET_PQ_query_param_string (rr[index].reserve->sender_account_details), \ + GNUNET_PQ_query_param_string (rr[index].notify_s) + + +/** + * Generate the SQL parameters to obtain results for record @a rr at + * index @a index + */ +#define RR_RESULT_PARAM(rr,index) \ + GNUNET_PQ_result_spec_bool ("conflicted" TALER_S (index), \ + &rr[index].conflicts), \ + GNUNET_PQ_result_spec_bool ("transaction_duplicate" TALER_S (index), \ + &rr[index].transaction_duplicate), \ + GNUNET_PQ_result_spec_uint64 ("reserve_uuid" TALER_S (index), \ + &rr[index].reserve_uuid) + + +/** + * Insert 1 reserve record @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert1 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[1], struct GNUNET_TIME_Timestamp gc, - char *const *notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid) + struct ReserveRecord *rr) { enum GNUNET_DB_QueryStatus qs; - struct TALER_PaytoHashP h_payto0; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_timestamp (&gc), GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto0), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - - GNUNET_PQ_query_param_string (notify_s[0]), + RR_QUERY_PARAM (rr, 0), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), + RR_RESULT_PARAM (rr, 0), GNUNET_PQ_result_spec_end }; PREPARE (pg, "batch1_reserve_create", "SELECT " - " out_reserve_found AS conflicted" - ",transaction_duplicate" - ",ruuid AS reserve_uuid" + " out_reserve_found0 AS conflicted0" + ",transaction_duplicate0 AS transaction_duplicate0" + ",ruuid0 AS reserve_uuid0" " FROM exchange_do_batch_reserves_in_insert" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);"); - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto0); qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "batch1_reserve_create", params, @@ -114,7 +168,7 @@ insert1 (struct PostgresClosure *pg, return qs; } GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); - if ((! conflict[0]) && transaction_duplicate[0]) + if ((! rr[0].conflicts) && rr[0].transaction_duplicate) { GNUNET_break (0); TEH_PG_rollback (pg); @@ -124,438 +178,418 @@ insert1 (struct PostgresClosure *pg, } +/** + * Insert 2 reserve records @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert2 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[2], struct GNUNET_TIME_Timestamp gc, - char *const*notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid) + struct ReserveRecord *rr) { - enum GNUNET_DB_QueryStatus qs1; - struct TALER_PaytoHashP h_payto[2]; + enum GNUNET_DB_QueryStatus qs; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_timestamp (&gc), GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[0]), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[1]), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), + RR_QUERY_PARAM (rr, 0), + RR_QUERY_PARAM (rr, 1), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), + RR_RESULT_PARAM (rr, 0), + RR_RESULT_PARAM (rr, 1), GNUNET_PQ_result_spec_end }; PREPARE (pg, "batch2_reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",out_reserve_found2 AS conflicted2" - ",transaction_duplicate" - ",transaction_duplicate2" - ",ruuid AS reserve_uuid" - ",ruuid2 AS reserve_uuid2" + "SELECT" + " out_reserve_found0 AS conflicted0" + ",out_reserve_found1 AS conflicted1" + ",transaction_duplicate0" + ",transaction_duplicate1" + ",ruuid0 AS reserve_uuid0" + ",ruuid1 AS reserve_uuid1" " FROM exchange_do_batch2_reserves_insert" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20);"); - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto[0]); - TALER_payto_hash (reserves[1].sender_account_details, - &h_payto[1]); - qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch2_reserve_create", - params, - rs); - if (qs1 < 0) + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch2_reserve_create", + params, + rs); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to create reserves 2(%d)\n", - qs1); - return qs1; + qs); + return qs; } - - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); - if ( ((! conflict[0]) && (transaction_duplicate[0])) || - ((! conflict[1]) && (transaction_duplicate[1])) ) + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); + for (unsigned int i = 0; i<2; i++) { - GNUNET_break (0); - TEH_PG_rollback (pg); - return GNUNET_DB_STATUS_HARD_ERROR; + if ((! rr[i].conflicts) && (rr[i].transaction_duplicate)) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + } } - return qs1; + return qs; } +/** + * Insert 4 reserve records @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert4 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[4], struct GNUNET_TIME_Timestamp gc, - char *const*notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid) + struct ReserveRecord *rr) { - enum GNUNET_DB_QueryStatus qs3; - struct TALER_PaytoHashP h_payto[4]; + enum GNUNET_DB_QueryStatus qs; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_timestamp (&gc), GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[0]), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - GNUNET_PQ_query_param_string (notify_s[2]), - GNUNET_PQ_query_param_string (notify_s[3]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[1]), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), - TALER_PQ_query_param_amount (reserves[2].balance), - GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[2]), - GNUNET_PQ_query_param_string (reserves[2].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), - TALER_PQ_query_param_amount (reserves[3].balance), - GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[3]), - GNUNET_PQ_query_param_string (reserves[3].sender_account_details), - + RR_QUERY_PARAM (rr, 0), + RR_QUERY_PARAM (rr, 1), + RR_QUERY_PARAM (rr, 2), + RR_QUERY_PARAM (rr, 3), GNUNET_PQ_query_param_end }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("conflicted3", - &conflict[2]), - GNUNET_PQ_result_spec_bool ("conflicted4", - &conflict[3]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate3", - &transaction_duplicate[2]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate4", - &transaction_duplicate[3]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", - &reserve_uuid[2]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", - &reserve_uuid[3]), + RR_RESULT_PARAM (rr, 0), + RR_RESULT_PARAM (rr, 1), + RR_RESULT_PARAM (rr, 2), + RR_RESULT_PARAM (rr, 3), GNUNET_PQ_result_spec_end }; PREPARE (pg, "batch4_reserve_create", - "SELECT " - "out_reserve_found AS conflicted" + "SELECT" + " out_reserve_found0 AS conflicted0" + ",out_reserve_found1 AS conflicted1" ",out_reserve_found2 AS conflicted2" ",out_reserve_found3 AS conflicted3" - ",out_reserve_found4 AS conflicted4" - ",transaction_duplicate" + ",transaction_duplicate0" + ",transaction_duplicate1" ",transaction_duplicate2" ",transaction_duplicate3" - ",transaction_duplicate4" - ",ruuid AS reserve_uuid" + ",ruuid0 AS reserve_uuid0" + ",ruuid1 AS reserve_uuid1" ",ruuid2 AS reserve_uuid2" ",ruuid3 AS reserve_uuid3" - ",ruuid4 AS reserve_uuid4" " FROM exchange_do_batch4_reserves_insert" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38);"); - - for (unsigned int i = 0; i<4; i++) - TALER_payto_hash (reserves[i].sender_account_details, - &h_payto[i]); - qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch4_reserve_create", - params, - rs); - if (qs3 < 0) + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch4_reserve_create", + params, + rs); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to create reserves4 (%d)\n", - qs3); - return qs3; + qs); + return qs; } - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); - - if ( - ((! conflict[0]) && (transaction_duplicate[0])) - || ((! conflict[1]) && (transaction_duplicate[1])) - || ((! conflict[2]) && (transaction_duplicate[2])) - || ((! conflict[3]) && (transaction_duplicate[3])) - ) + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); + for (unsigned int i = 0; i<4; i++) { - GNUNET_break (0); - TEH_PG_rollback (pg); - return GNUNET_DB_STATUS_HARD_ERROR; + if ((! rr[i].conflicts) && (rr[i].transaction_duplicate)) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + } } - return qs3; + return qs; } +/** + * Insert 8 reserve records @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert8 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[8], struct GNUNET_TIME_Timestamp gc, - char *const*notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid) + struct ReserveRecord *rr) { - enum GNUNET_DB_QueryStatus qs3; - struct TALER_PaytoHashP h_payto[8]; + enum GNUNET_DB_QueryStatus qs; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_timestamp (&gc), GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[0]), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - GNUNET_PQ_query_param_string (notify_s[2]), - GNUNET_PQ_query_param_string (notify_s[3]), - GNUNET_PQ_query_param_string (notify_s[4]), - GNUNET_PQ_query_param_string (notify_s[5]), - GNUNET_PQ_query_param_string (notify_s[6]), - GNUNET_PQ_query_param_string (notify_s[7]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[1]), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), - TALER_PQ_query_param_amount (reserves[2].balance), - GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[2]), - GNUNET_PQ_query_param_string (reserves[2].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), - TALER_PQ_query_param_amount (reserves[3].balance), - GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[3]), - GNUNET_PQ_query_param_string (reserves[3].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[4].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[4].wire_reference), - TALER_PQ_query_param_amount (reserves[4].balance), - GNUNET_PQ_query_param_string (reserves[4].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[4].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[4]), - GNUNET_PQ_query_param_string (reserves[4].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[5].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[5].wire_reference), - TALER_PQ_query_param_amount (reserves[5].balance), - GNUNET_PQ_query_param_string (reserves[5].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[5].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[5]), - GNUNET_PQ_query_param_string (reserves[5].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[6].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[6].wire_reference), - TALER_PQ_query_param_amount (reserves[6].balance), - GNUNET_PQ_query_param_string (reserves[6].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[6].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[6]), - GNUNET_PQ_query_param_string (reserves[6].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[7].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[7].wire_reference), - TALER_PQ_query_param_amount (reserves[7].balance), - GNUNET_PQ_query_param_string (reserves[7].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[7].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[7]), - GNUNET_PQ_query_param_string (reserves[7].sender_account_details), - + RR_QUERY_PARAM (rr, 0), + RR_QUERY_PARAM (rr, 1), + RR_QUERY_PARAM (rr, 2), + RR_QUERY_PARAM (rr, 3), + RR_QUERY_PARAM (rr, 4), + RR_QUERY_PARAM (rr, 5), + RR_QUERY_PARAM (rr, 6), + RR_QUERY_PARAM (rr, 7), GNUNET_PQ_query_param_end }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("conflicted3", - &conflict[2]), - GNUNET_PQ_result_spec_bool ("conflicted4", - &conflict[3]), - GNUNET_PQ_result_spec_bool ("conflicted5", - &conflict[4]), - GNUNET_PQ_result_spec_bool ("conflicted6", - &conflict[5]), - GNUNET_PQ_result_spec_bool ("conflicted7", - &conflict[6]), - GNUNET_PQ_result_spec_bool ("conflicted8", - &conflict[7]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate3", - &transaction_duplicate[2]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate4", - &transaction_duplicate[3]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate5", - &transaction_duplicate[4]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate6", - &transaction_duplicate[5]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate7", - &transaction_duplicate[6]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate8", - &transaction_duplicate[7]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", - &reserve_uuid[2]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", - &reserve_uuid[3]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid5", - &reserve_uuid[4]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid6", - &reserve_uuid[5]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid7", - &reserve_uuid[6]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid8", - &reserve_uuid[7]), + RR_RESULT_PARAM (rr, 0), + RR_RESULT_PARAM (rr, 1), + RR_RESULT_PARAM (rr, 2), + RR_RESULT_PARAM (rr, 3), + RR_RESULT_PARAM (rr, 4), + RR_RESULT_PARAM (rr, 5), + RR_RESULT_PARAM (rr, 6), + RR_RESULT_PARAM (rr, 7), GNUNET_PQ_result_spec_end }; PREPARE (pg, "batch8_reserve_create", "SELECT" - " out_reserve_found AS conflicted" + " out_reserve_found0 AS conflicted0" + ",out_reserve_found1 AS conflicted1" ",out_reserve_found2 AS conflicted2" ",out_reserve_found3 AS conflicted3" ",out_reserve_found4 AS conflicted4" ",out_reserve_found5 AS conflicted5" ",out_reserve_found6 AS conflicted6" ",out_reserve_found7 AS conflicted7" - ",out_reserve_found8 AS conflicted8" - ",transaction_duplicate" + ",transaction_duplicate0" + ",transaction_duplicate1" ",transaction_duplicate2" ",transaction_duplicate3" ",transaction_duplicate4" ",transaction_duplicate5" ",transaction_duplicate6" ",transaction_duplicate7" - ",transaction_duplicate8" - ",ruuid AS reserve_uuid" + ",ruuid0 AS reserve_uuid0" + ",ruuid1 AS reserve_uuid1" ",ruuid2 AS reserve_uuid2" ",ruuid3 AS reserve_uuid3" ",ruuid4 AS reserve_uuid4" ",ruuid5 AS reserve_uuid5" ",ruuid6 AS reserve_uuid6" ",ruuid7 AS reserve_uuid7" - ",ruuid8 AS reserve_uuid8" " FROM exchange_do_batch8_reserves_insert" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70,$71,$72,$73,$74);"); - for (unsigned int i = 0; i<8; i++) - TALER_payto_hash (reserves[i].sender_account_details, - &h_payto[i]); - qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch8_reserve_create", - params, - rs); - if (qs3 < 0) + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch8_reserve_create", + params, + rs); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to create reserves8 (%d)\n", - qs3); - return qs3; + qs); + return qs; } - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); - if ( - ((! conflict[0]) && (transaction_duplicate[0])) - || ((! conflict[1]) && (transaction_duplicate[1])) - || ((! conflict[2]) && (transaction_duplicate[2])) - || ((! conflict[3]) && (transaction_duplicate[3])) - || ((! conflict[4]) && (transaction_duplicate[4])) - || ((! conflict[5]) && (transaction_duplicate[5])) - || ((! conflict[6]) && (transaction_duplicate[6])) - || ((! conflict[7]) && (transaction_duplicate[7])) - ) + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); + for (unsigned int i = 0; i<8; i++) + { + if ((! rr[i].conflicts) && (rr[i].transaction_duplicate)) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + } + } + return qs; +} + + +static enum GNUNET_DB_QueryStatus +transact ( + struct PostgresClosure *pg, + struct ReserveRecord *rr, + unsigned int reserves_length, + unsigned int batch_size, + enum GNUNET_DB_QueryStatus *results) +{ + struct GNUNET_TIME_Timestamp reserve_expiration + = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); + struct GNUNET_TIME_Timestamp gc + = GNUNET_TIME_relative_to_timestamp (pg->legal_reserve_expiration_time); + bool need_update = false; + + if (GNUNET_OK != + TEH_PG_preflight (pg)) { GNUNET_break (0); - TEH_PG_rollback (pg); return GNUNET_DB_STATUS_HARD_ERROR; } - return qs3; + + if (GNUNET_OK != + TEH_PG_start_read_committed (pg, + "READ_COMMITED")) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + { + unsigned int i = 0; + + while (i < reserves_length) + { + enum GNUNET_DB_QueryStatus qs; + enum GNUNET_DB_QueryStatus + (*fun)(struct PostgresClosure *pg, + struct GNUNET_TIME_Timestamp gc, + struct GNUNET_TIME_Timestamp reserve_expiration, + struct ReserveRecord *rr); + unsigned int lim; + unsigned int bs; + + bs = GNUNET_MIN (batch_size, + reserves_length - i); + switch (bs) + { + case 7: + case 6: + case 5: + case 4: + fun = &insert4; + lim = 4; + break; + case 3: + case 2: + fun = &insert2; + lim = 2; + break; + case 1: + fun = &insert1; + lim = 1; + break; + case 0: + GNUNET_assert (0); + break; + default: + fun = insert8; + lim = 8; + break; + } + + qs = fun (pg, + gc, + reserve_expiration, + &rr[i]); + if (qs < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to create reserve batch_%u (%d)\n", + lim, + qs); + results[i] = qs; + return qs; + } + for (unsigned int j = 0; jreserve_pub), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + GNUNET_PQ_query_param_uint64 (&rr[i].reserve->wire_reference), + TALER_PQ_query_param_amount (rr[i].reserve->balance), + GNUNET_PQ_query_param_string (rr[i].reserve->exchange_account_name), + GNUNET_PQ_query_param_auto_from_type (&rr[i].h_payto), + GNUNET_PQ_query_param_string (rr[i].notify_s), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("duplicate", + &duplicate), + GNUNET_PQ_result_spec_end + }; + enum GNUNET_DB_QueryStatus qs; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "reserves_update", + params, + rs); + if (qs < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to update reserves (%d)\n", + qs); + results[i] = qs; + return qs; + } + results[i] = duplicate + ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS + : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + } + } + + { + enum GNUNET_DB_QueryStatus cs = TEH_PG_commit (pg); + + if (0 > cs) + return cs; + } + return reserves_length; } @@ -568,271 +602,31 @@ TEH_PG_reserves_in_insert ( enum GNUNET_DB_QueryStatus *results) { struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs1; - enum GNUNET_DB_QueryStatus qs2; - enum GNUNET_DB_QueryStatus qs4; - enum GNUNET_DB_QueryStatus qs5; - uint64_t reserve_uuid[reserves_length]; - bool transaction_duplicate[reserves_length]; - bool need_update = false; - struct GNUNET_TIME_Timestamp reserve_expiration - = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); - struct GNUNET_TIME_Timestamp gc - = GNUNET_TIME_relative_to_timestamp (pg->legal_reserve_expiration_time); - bool conflicts[reserves_length]; - char *notify_s[reserves_length]; + struct ReserveRecord rrs[reserves_length]; + enum GNUNET_DB_QueryStatus qs; - if (GNUNET_OK != - TEH_PG_preflight (pg)) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating reserve %s with expiration in %s\n", - TALER_B2S (&(reserves->reserve_pub)), - GNUNET_STRINGS_relative_time_to_string ( - pg->idle_reserve_expiration_time, - GNUNET_NO)); - - if (GNUNET_OK != - TEH_PG_start_read_committed (pg, - "READ_COMMITED")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - /* Optimistically assume this is a new reserve, create balance for the first - time; we do this before adding the actual transaction to "reserves_in", - as for a new reserve it can't be a duplicate 'add' operation, and as - the 'add' operation needs the reserve entry as a foreign key. */ for (unsigned int i = 0; ireserve_pub); + rr->reserve = reserve; + TALER_payto_hash (reserves->sender_account_details, + &rr->h_payto); + rr->notify_s = compute_notify_on_reserve (reserve->reserve_pub); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating reserve %s with expiration in %s\n", + TALER_B2S (&reserve->reserve_pub), + GNUNET_STRINGS_relative_time_to_string ( + pg->idle_reserve_expiration_time, + false)); } - - unsigned int i = 0; - - while (i < reserves_length) - { - unsigned int bs = GNUNET_MIN (batch_size, - reserves_length - i); - if (bs >= 8) - { - qs1 = insert8 (pg, - &reserves[i], - gc, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i]); - - if (qs1<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_8 (%d)\n", - qs1); - results[i] = qs1; - return qs1; - } - need_update |= conflicts[i]; - need_update |= conflicts[i + 1]; - need_update |= conflicts[i + 2]; - need_update |= conflicts[i + 3]; - need_update |= conflicts[i + 4]; - need_update |= conflicts[i + 5]; - need_update |= conflicts[i + 6]; - need_update |= conflicts[i + 7]; - for (unsigned int j = 0; j<8; j++) - results[i + j] = transaction_duplicate[i + j] - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - i += 8; - continue; - } - switch (bs) - { - case 7: - case 6: - case 5: - case 4: - qs4 = insert4 (pg, - &reserves[i], - gc, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i]); - if (qs4<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_4 (%d)\n", - qs4); - results[i] = qs4; - return qs4; - } - need_update |= conflicts[i]; - need_update |= conflicts[i + 1]; - need_update |= conflicts[i + 2]; - need_update |= conflicts[i + 3]; - for (unsigned int j = 0; j<4; j++) - results[i + j] = transaction_duplicate[i + j] - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - i += 4; - break; - case 3: - case 2: - qs5 = insert2 (pg, - &reserves[i], - gc, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i]); - if (qs5<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_2 (%d)\n", - qs5); - results[i] = qs5; - return qs5; - } - need_update |= conflicts[i]; - need_update |= conflicts[i + 1]; - for (unsigned int j = 0; j<2; j++) - results[i + j] = transaction_duplicate[i + j] - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - i += 2; - break; - case 1: - qs2 = insert1 (pg, - &reserves[i], - gc, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i]); - if (qs2<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_1 (%d)\n)", - qs2); - results[i] = qs2; - return qs2; - } - need_update |= conflicts[i]; - results[i] = (transaction_duplicate[i]) - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - i += 1; - break; - case 0: - GNUNET_assert (0); - break; - } - } /* end while */ - // commit - { - enum GNUNET_DB_QueryStatus cs; - - cs = TEH_PG_commit (pg); - if (cs < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to commit\n"); - return cs; - } - } - if (! need_update) - { - goto exit; - } - // begin serializable - { - if (GNUNET_OK != - TEH_PG_start (pg, - "reserve-insert-continued")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - } - - PREPARE (pg, - "reserves_update", - "SELECT" - " out_duplicate AS duplicate " - "FROM exchange_do_batch_reserves_update" - " ($1,$2,$3,$4,$5,$6,$7,$8);"); + qs = transact (pg, + rrs, + reserves_length, + batch_size, + results); for (unsigned int i = 0; iconn, - "reserves_update", - params, - rs); - if (qs3<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to update reserves (%d)\n", - qs3); - results[i] = qs3; - return qs3; - } - results[i] = duplicate - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - } - } - - { - enum GNUNET_DB_QueryStatus cs; - - cs = TEH_PG_commit (pg); - if (cs < 0) - { - for (unsigned int i = 0; ilabel); is->child_death_task = NULL;