gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-exchange] 05/08: rework /reserve/history to address


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] 05/08: rework /reserve/history to address #5010
Date: Mon, 19 Jun 2017 00:18:22 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository exchange.

commit 2d5b238beb4661721afddd3c76262837d13ee8c4
Author: Christian Grothoff <address@hidden>
AuthorDate: Sun Jun 18 22:48:54 2017 +0200

    rework /reserve/history to address #5010
---
 src/exchange/Makefile.am                           |   1 +
 src/exchange/taler-exchange-httpd_db.c             |  49 +-
 src/exchange/taler-exchange-httpd_db.h             |  13 -
 src/exchange/taler-exchange-httpd_reserve.c        |  36 --
 src/exchange/taler-exchange-httpd_reserve_status.c | 137 +++++
 src/exchange/taler-exchange-httpd_reserve_status.h |  49 ++
 src/exchangedb/perf_taler_exchangedb_interpreter.c |   9 +-
 src/exchangedb/plugin_exchangedb_postgres.c        | 577 ++++++++++++---------
 src/exchangedb/test_exchangedb.c                   |   7 +-
 src/include/taler_exchangedb_plugin.h              |   8 +-
 10 files changed, 531 insertions(+), 355 deletions(-)

diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index 92a8556..96e9d7a 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -53,6 +53,7 @@ taler_exchange_httpd_SOURCES = \
   taler-exchange-httpd_refresh.c taler-exchange-httpd_refresh.h \
   taler-exchange-httpd_refund.c taler-exchange-httpd_refund.h \
   taler-exchange-httpd_reserve.c taler-exchange-httpd_reserve.h \
+  taler-exchange-httpd_reserve_status.c taler-exchange-httpd_reserve_status.h \
   taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \
   taler-exchange-httpd_tracking.c taler-exchange-httpd_tracking.h \
   taler-exchange-httpd_wire.c taler-exchange-httpd_wire.h \
diff --git a/src/exchange/taler-exchange-httpd_db.c 
b/src/exchange/taler-exchange-httpd_db.c
index 2cdf61d..4131e12 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -553,47 +553,6 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
 
 
 /**
- * Execute a /reserve/status.  Given the public key of a reserve,
- * return the associated transaction history.
- *
- * @param connection the MHD connection to handle
- * @param reserve_pub public key of the reserve to check
- * @return MHD result code
- */
-int
-TEH_DB_execute_reserve_status (struct MHD_Connection *connection,
-                               const struct TALER_ReservePublicKeyP 
*reserve_pub)
-{
-  struct TALER_EXCHANGEDB_Session *session;
-  struct TALER_EXCHANGEDB_ReserveHistory *rh;
-  int res;
-
-  if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
-  {
-    GNUNET_break (0);
-    return TEH_RESPONSE_reply_internal_db_error (connection,
-                                                TALER_EC_DB_SETUP_FAILED);
-  }
-  START_TRANSACTION (session, connection);
-  rh = TEH_plugin->get_reserve_history (TEH_plugin->cls,
-                                        session,
-                                        reserve_pub);
-  COMMIT_TRANSACTION (session, connection);
-  if (NULL == rh)
-    return TEH_RESPONSE_reply_json_pack (connection,
-                                         MHD_HTTP_NOT_FOUND,
-                                         "{s:s, s:s}",
-                                         "error", "Reserve not found",
-                                         "parameter", "withdraw_pub");
-  res = TEH_RESPONSE_reply_reserve_status_success (connection,
-                                                   rh);
-  TEH_plugin->free_reserve_history (TEH_plugin->cls,
-                                    rh);
-  return res;
-}
-
-
-/**
  * Try to execute /reserve/withdraw transaction.
  *
  * @param connection request we are handling
@@ -635,12 +594,16 @@ execute_reserve_withdraw_transaction (struct 
MHD_Connection *connection,
   struct TALER_Amount fee_withdraw;
   int res;
   int ret;
+  enum GNUNET_DB_QueryStatus qs;
 
   /* Check if balance is sufficient */
   START_TRANSACTION (session, connection);
-  rh = TEH_plugin->get_reserve_history (TEH_plugin->cls,
+  qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
                                         session,
-                                        reserve);
+                                        reserve,
+                                       &rh);
+  (void) qs;
+  /* qs: #5010! */
   if (NULL == rh)
   {
     TEH_plugin->rollback (TEH_plugin->cls,
diff --git a/src/exchange/taler-exchange-httpd_db.h 
b/src/exchange/taler-exchange-httpd_db.h
index 6d0b7e3..0834db5 100644
--- a/src/exchange/taler-exchange-httpd_db.h
+++ b/src/exchange/taler-exchange-httpd_db.h
@@ -98,19 +98,6 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
 
 
 /**
- * Execute a "/reserve/status".  Given the public key of a reserve,
- * return the associated transaction history.
- *
- * @param connection the MHD connection to handle
- * @param reserve_pub public key of the reserve to check
- * @return MHD result code
- */
-int
-TEH_DB_execute_reserve_status (struct MHD_Connection *connection,
-                               const struct TALER_ReservePublicKeyP 
*reserve_pub);
-
-
-/**
  * Execute a "/reserve/withdraw".  Given a reserve and a properly signed
  * request to withdraw a coin, check the balance of the reserve and
  * if it is sufficient, store the request and return the signed
diff --git a/src/exchange/taler-exchange-httpd_reserve.c 
b/src/exchange/taler-exchange-httpd_reserve.c
index 78f8ff1..08c904c 100644
--- a/src/exchange/taler-exchange-httpd_reserve.c
+++ b/src/exchange/taler-exchange-httpd_reserve.c
@@ -30,42 +30,6 @@
 
 
 /**
- * Handle a "/reserve/status" request.  Parses the
- * given "reserve_pub" argument (which should contain the
- * EdDSA public key of a reserve) and then respond with the
- * status of the reserve.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TEH_RESERVE_handler_reserve_status (struct TEH_RequestHandler *rh,
-                                    struct MHD_Connection *connection,
-                                    void **connection_cls,
-                                    const char *upload_data,
-                                    size_t *upload_data_size)
-{
-  struct TALER_ReservePublicKeyP reserve_pub;
-  int res;
-
-  res = TEH_PARSE_mhd_request_arg_data (connection,
-                                        "reserve_pub",
-                                        &reserve_pub,
-                                        sizeof (struct 
TALER_ReservePublicKeyP));
-  if (GNUNET_SYSERR == res)
-    return MHD_NO; /* internal error */
-  if (GNUNET_NO == res)
-    return MHD_YES; /* parse error */
-  return TEH_DB_execute_reserve_status (connection,
-                                        &reserve_pub);
-}
-
-
-/**
  * Handle a "/reserve/withdraw" request.  Parses the "reserve_pub"
  * EdDSA key of the reserve and the requested "denom_pub" which
  * specifies the key/value of the coin to be withdrawn, and checks
diff --git a/src/exchange/taler-exchange-httpd_reserve_status.c 
b/src/exchange/taler-exchange-httpd_reserve_status.c
new file mode 100644
index 0000000..e13b8f3
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_reserve_status.c
@@ -0,0 +1,137 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_reserve_status.c
+ * @brief Handle /reserve/status requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include "taler-exchange-httpd_reserve_status.h"
+#include "taler-exchange-httpd_parsing.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler-exchange-httpd_keystate.h"
+
+
+/**
+ * Closure for #reserve_status_transaction.
+ */
+struct ReserveStatusContext
+{
+  /**
+   * Public key of the reserve the inquiry is about.
+   */
+  struct TALER_ReservePublicKeyP reserve_pub;
+
+  /**
+   * History of the reserve, set in the callback.
+   */
+  struct TALER_EXCHANGEDB_ReserveHistory *rh;
+
+};
+
+
+/**
+ * Function implementing /reserve/status transaction.  
+ * Execute a /reserve/status.  Given the public key of a reserve,
+ * return the associated transaction history.  Runs the
+ * transaction logic; IF it returns a non-error code, the transaction
+ * logic MUST NOT queue a MHD response.  IF it returns an hard error,
+ * the transaction logic MUST queue a MHD response and set @a mhd_ret.
+ * IF it returns the soft error code, the function MAY be called again
+ * to retry and MUST not queue a MHD response.
+ *
+ * @param cls a `struct ReserveStatusContext *`
+ * @param connection MHD request which triggered the transaction
+ * @param session database session to use
+ * @param[out] mhd_ret set to MHD response status for @a connection,
+ *             if transaction failed (!)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+reserve_status_transaction (void *cls,
+                           struct MHD_Connection *connection,
+                           struct TALER_EXCHANGEDB_Session *session,
+                           int *mhd_ret)
+{
+  struct ReserveStatusContext *rsc = cls;
+
+  return TEH_plugin->get_reserve_history (TEH_plugin->cls,
+                                         session,
+                                         &rsc->reserve_pub,
+                                         &rsc->rh);
+}
+
+
+/**
+ * Handle a "/reserve/status" request.  Parses the
+ * given "reserve_pub" argument (which should contain the
+ * EdDSA public key of a reserve) and then respond with the
+ * status of the reserve.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TEH_RESERVE_handler_reserve_status (struct TEH_RequestHandler *rh,
+                                    struct MHD_Connection *connection,
+                                    void **connection_cls,
+                                    const char *upload_data,
+                                    size_t *upload_data_size)
+{
+  struct ReserveStatusContext rsc;
+  int res;
+  int mhd_ret;
+
+  res = TEH_PARSE_mhd_request_arg_data (connection,
+                                        "reserve_pub",
+                                        &rsc.reserve_pub,
+                                        sizeof (struct 
TALER_ReservePublicKeyP));
+  if (GNUNET_SYSERR == res)
+    return MHD_NO; /* internal error */
+  if (GNUNET_NO == res)
+    return MHD_YES; /* parse error */
+  rsc.rh = NULL;
+  if (GNUNET_OK !=
+      TEH_DB_run_transaction (connection,
+                             &mhd_ret,
+                             &reserve_status_transaction,
+                             &rsc))
+    return mhd_ret;
+
+  /* generate proper response */
+  if (NULL == rsc.rh)
+    return TEH_RESPONSE_reply_json_pack (connection,
+                                         MHD_HTTP_NOT_FOUND,
+                                         "{s:s, s:s}",
+                                         "error", "Reserve not found",
+                                         "parameter", "withdraw_pub");
+  mhd_ret = TEH_RESPONSE_reply_reserve_status_success (connection,
+                                                      rsc.rh);
+  TEH_plugin->free_reserve_history (TEH_plugin->cls,
+                                    rsc.rh);
+  return mhd_ret;
+}
+
+
+/* end of taler-exchange-httpd_reserve_status.c */
diff --git a/src/exchange/taler-exchange-httpd_reserve_status.h 
b/src/exchange/taler-exchange-httpd_reserve_status.h
new file mode 100644
index 0000000..7bfd4dd
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_reserve_status.h
@@ -0,0 +1,49 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2014-2017 GNUnet e.V.
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_reserve_status.h
+ * @brief Handle /reserve/status requests
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_RESERVE_STATUS_H
+#define TALER_EXCHANGE_HTTPD_RESERVE_STATUS_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+/**
+ * Handle a "/reserve/status" request.  Parses the
+ * given "reserve_pub" argument (which should contain the
+ * EdDSA public key of a reserve) and then respond with the
+ * status of the reserve.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+  */
+int
+TEH_RESERVE_handler_reserve_status (struct TEH_RequestHandler *rh,
+                                    struct MHD_Connection *connection,
+                                    void **connection_cls,
+                                    const char *upload_data,
+                                    size_t *upload_data_size);
+
+#endif
diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.c 
b/src/exchangedb/perf_taler_exchangedb_interpreter.c
index 054df58..b584541 100644
--- a/src/exchangedb/perf_taler_exchangedb_interpreter.c
+++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c
@@ -1422,12 +1422,15 @@ interpret (struct 
PERF_TALER_EXCHANGEDB_interpreter_state *state)
           unsigned int reserve_index;
           struct TALER_EXCHANGEDB_ReserveHistory *history;
           struct PERF_TALER_EXCHANGEDB_Data *data;
+         enum GNUNET_DB_QueryStatus qs;
 
           reserve_index = 
state->cmd[state->i].details.get_reserve_history.index_reserve;
           data = &state->cmd[reserve_index].exposed;
-          history = state->plugin->get_reserve_history (state->plugin->cls,
-                                                        state->session,
-                                                        
&data->data.reserve->reserve.pub);
+          qs = state->plugin->get_reserve_history (state->plugin->cls,
+                                                  state->session,
+                                                  
&data->data.reserve->reserve.pub,
+                                                  &history);
+         GNUNET_assert (0 >= qs);
           GNUNET_assert (NULL != history);
           state->plugin->free_reserve_history (state->plugin->cls,
                                                history);
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index 954fca3..0f18ef5 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -2393,6 +2393,7 @@ postgres_insert_withdraw_info (void *cls,
   if (0 >= qs)
   {
     GNUNET_break (0);
+
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
@@ -2400,295 +2401,361 @@ postgres_insert_withdraw_info (void *cls,
 
 
 /**
- * Get all of the transaction history associated with the specified
- * reserve.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param session connection to use
- * @param reserve_pub public key of the reserve
- * @return known transaction history (NULL if reserve is unknown)
+ * Closure for callbacks invoked via #postgres_get_reserve_history.
  */
-static struct TALER_EXCHANGEDB_ReserveHistory *
-postgres_get_reserve_history (void *cls,
-                              struct TALER_EXCHANGEDB_Session *session,
-                              const struct TALER_ReservePublicKeyP 
*reserve_pub)
+struct ReserveHistoryContext
 {
-  PGresult *result;
+
+  /**
+   * Which reserve are we building the history for?
+   */ 
+  const struct TALER_ReservePublicKeyP *reserve_pub;
+  
+  /**
+   * Where we build the history.
+   */
   struct TALER_EXCHANGEDB_ReserveHistory *rh;
+ 
+  /**
+   * Tail of @e rh list.
+   */
   struct TALER_EXCHANGEDB_ReserveHistory *rh_tail;
-  int rows;
-  int ret;
 
-  rh = NULL;
-  rh_tail = NULL;
-  ret = GNUNET_SYSERR;
-  /** #TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE */
+  /**
+   * Set to #GNUNET_SYSERR on serious internal errors during
+   * the callbacks.
+   */ 
+  int status;
+};
+
+
+/**
+ * Append and return a fresh element to the reserve
+ * history kept in @a rhc.
+ *
+ * @param rhc where the history is kept
+ * @return the fresh element that was added
+ */ 
+static struct TALER_EXCHANGEDB_ReserveHistory *
+append_rh (struct ReserveHistoryContext *rhc)
+{
+  struct TALER_EXCHANGEDB_ReserveHistory *tail;
+
+  tail = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
+  if (NULL != rhc->rh_tail)
+  {
+    rhc->rh_tail->next = tail;
+    rhc->rh_tail = tail;
+  }
+  else
+  {
+    rhc->rh_tail = tail;
+    rhc->rh = tail;
+  }
+  return tail;
+}
+
+
+/**
+ * Add bank transfers to result set for #postgres_get_reserve_history.
+ *
+ * @param cls a `struct ReserveHistoryContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+add_bank_to_exchange (void *cls,
+                     PGresult *result,
+                     unsigned int num_results)
+{
+  struct ReserveHistoryContext *rhc = cls;
+  
+  while (0 < num_results)
   {
     struct TALER_EXCHANGEDB_BankTransfer *bt;
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-      GNUNET_PQ_query_param_end
-    };
+    struct TALER_EXCHANGEDB_ReserveHistory *tail;
 
-    result = GNUNET_PQ_exec_prepared (session->conn,
-                                      "reserves_in_get_transactions",
-                                      params);
-    if (PGRES_TUPLES_OK != PQresultStatus (result))
-    {
-      QUERY_ERR (result, session->conn);
-      goto cleanup;
-    }
-    if (0 == (rows = PQntuples (result)))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Asked to fetch history for an unknown reserve.\n");
-      goto cleanup;
-    }
-    while (0 < rows)
+    bt = GNUNET_new (struct TALER_EXCHANGEDB_BankTransfer);
     {
-      bt = GNUNET_new (struct TALER_EXCHANGEDB_BankTransfer);
-      {
-        struct GNUNET_PQ_ResultSpec rs[] = {
-          GNUNET_PQ_result_spec_variable_size ("wire_reference",
-                                               &bt->wire_reference,
-                                               &bt->wire_reference_size),
-          TALER_PQ_result_spec_amount ("credit",
-                                       &bt->amount),
-          GNUNET_PQ_result_spec_absolute_time ("execution_date",
-                                              &bt->execution_date),
-          TALER_PQ_result_spec_json ("sender_account_details",
-                                     &bt->sender_account_details),
-          GNUNET_PQ_result_spec_end
-        };
-        if (GNUNET_OK !=
-            GNUNET_PQ_extract_result (result,
-                                      rs,
-                                      --rows))
-        {
-          GNUNET_break (0);
-          GNUNET_free (bt);
-          PQclear (result);
-          goto cleanup;
-        }
-      }
-      bt->reserve_pub = *reserve_pub;
-      if (NULL != rh_tail)
-      {
-        rh_tail->next = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
-        rh_tail = rh_tail->next;
-      }
-      else
+      struct GNUNET_PQ_ResultSpec rs[] = {
+       GNUNET_PQ_result_spec_variable_size ("wire_reference",
+                                            &bt->wire_reference,
+                                            &bt->wire_reference_size),
+       TALER_PQ_result_spec_amount ("credit",
+                                    &bt->amount),
+       GNUNET_PQ_result_spec_absolute_time ("execution_date",
+                                            &bt->execution_date),
+       TALER_PQ_result_spec_json ("sender_account_details",
+                                  &bt->sender_account_details),
+       GNUNET_PQ_result_spec_end
+      };
+      
+      if (GNUNET_OK !=
+         GNUNET_PQ_extract_result (result,
+                                   rs,
+                                   --num_results))
       {
-        rh_tail = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
-        rh = rh_tail;
+       GNUNET_break (0);
+       GNUNET_free (bt);
+       rhc->status = GNUNET_SYSERR;
+       return;
       }
-      rh_tail->type = TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE;
-      rh_tail->details.bank = bt;
-    } /* end of 'while (0 < rows)' */
-    PQclear (result);
-  }
-  /** #TALER_EXCHANGEDB_RO_WITHDRAW_COIN */
-  {
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-      GNUNET_PQ_query_param_end
-    };
-
-    GNUNET_assert (NULL != rh);
-    GNUNET_assert (NULL != rh_tail);
-    GNUNET_assert (NULL == rh_tail->next);
-    result = GNUNET_PQ_exec_prepared (session->conn,
-                                      "get_reserves_out",
-                                      params);
-    if (PGRES_TUPLES_OK != PQresultStatus (result))
-    {
-      QUERY_ERR (result, session->conn);
-      PQclear (result);
-      goto cleanup;
     }
-    rows = PQntuples (result);
-    while (0 < rows)
-    {
-      struct TALER_EXCHANGEDB_CollectableBlindcoin *cbc;
+    bt->reserve_pub = *rhc->reserve_pub;
+    tail = append_rh (rhc);
+    tail->type = TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE;
+    tail->details.bank = bt;
+  } /* end of 'while (0 < rows)' */
+}
 
-      cbc = GNUNET_new (struct TALER_EXCHANGEDB_CollectableBlindcoin);
-      {
-        struct GNUNET_PQ_ResultSpec rs[] = {
-          GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
-                                               &cbc->h_coin_envelope),
-          GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
-                                               &cbc->denom_pub.rsa_public_key),
-          GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
-                                              &cbc->sig.rsa_signature),
-          GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
-                                               &cbc->reserve_sig),
-          TALER_PQ_result_spec_amount ("amount_with_fee",
-                                       &cbc->amount_with_fee),
-          TALER_PQ_result_spec_amount ("fee_withdraw",
-                                       &cbc->withdraw_fee),
-          GNUNET_PQ_result_spec_end
-        };
-        if (GNUNET_OK !=
-            GNUNET_PQ_extract_result (result,
-                                      rs,
-                                      --rows))
-        {
-          GNUNET_break (0);
-          GNUNET_free (cbc);
-          PQclear (result);
-          goto cleanup;
-        }
-        cbc->reserve_pub = *reserve_pub;
-      }
-      rh_tail->next = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
-      rh_tail = rh_tail->next;
-      rh_tail->type = TALER_EXCHANGEDB_RO_WITHDRAW_COIN;
-      rh_tail->details.withdraw = cbc;
-    } /* end of 'while (0 < rows)' */
-    ret = GNUNET_OK;
-    PQclear (result);
-  }
 
-  /** #TALER_EXCHANGEDB_RO_PAYBACK_COIN */
+/**
+ * Add coin withdrawals to result set for #postgres_get_reserve_history.
+ *
+ * @param cls a `struct ReserveHistoryContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+add_withdraw_coin (void *cls,
+                  PGresult *result,
+                  unsigned int num_results)
+{
+  struct ReserveHistoryContext *rhc = cls;
+  
+  while (0 < num_results)
   {
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-      GNUNET_PQ_query_param_end
-    };
+    struct TALER_EXCHANGEDB_CollectableBlindcoin *cbc;
+    struct TALER_EXCHANGEDB_ReserveHistory *tail;
 
-    result = GNUNET_PQ_exec_prepared (session->conn,
-                                      "payback_by_reserve",
-                                      params);
-    if (PGRES_TUPLES_OK != PQresultStatus (result))
-    {
-      QUERY_ERR (result, session->conn);
-      goto cleanup;
-    }
-    rows = PQntuples (result);
-    while (0 < rows)
+    cbc = GNUNET_new (struct TALER_EXCHANGEDB_CollectableBlindcoin);
     {
-      struct TALER_EXCHANGEDB_Payback *payback;
-
-      payback = GNUNET_new (struct TALER_EXCHANGEDB_Payback);
-      {
-        struct GNUNET_PQ_ResultSpec rs[] = {
-          TALER_PQ_result_spec_amount ("amount",
-                                       &payback->value),
-          GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
-                                                &payback->coin.coin_pub),
-          GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
-                                                &payback->coin_blind),
-          GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
-                                                &payback->coin_sig),
-          GNUNET_PQ_result_spec_absolute_time ("timestamp",
-                                               &payback->timestamp),
-          GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
-                                               
&payback->coin.denom_pub.rsa_public_key),
-          GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
-                                               
&payback->coin.denom_sig.rsa_signature),
-          GNUNET_PQ_result_spec_end
-        };
-        if (GNUNET_OK !=
-            GNUNET_PQ_extract_result (result,
-                                      rs,
-                                      --rows))
-        {
-          GNUNET_break (0);
-          GNUNET_free (payback);
-          PQclear (result);
-          goto cleanup;
-        }
-      }
-      payback->reserve_pub = *reserve_pub;
-      if (NULL != rh_tail)
-      {
-        rh_tail->next = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
-        rh_tail = rh_tail->next;
-      }
-      else
+      struct GNUNET_PQ_ResultSpec rs[] = {
+       GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
+                                             &cbc->h_coin_envelope),
+       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
+                                             &cbc->denom_pub.rsa_public_key),
+       GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
+                                            &cbc->sig.rsa_signature),
+       GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
+                                             &cbc->reserve_sig),
+       TALER_PQ_result_spec_amount ("amount_with_fee",
+                                    &cbc->amount_with_fee),
+       TALER_PQ_result_spec_amount ("fee_withdraw",
+                                    &cbc->withdraw_fee),
+       GNUNET_PQ_result_spec_end
+      };
+      
+      if (GNUNET_OK !=
+         GNUNET_PQ_extract_result (result,
+                                   rs,
+                                   --num_results))
       {
-        rh_tail = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
-        rh = rh_tail;
+       GNUNET_break (0);
+       GNUNET_free (cbc);
+       rhc->status = GNUNET_SYSERR;
+       return;
       }
-      rh_tail->type = TALER_EXCHANGEDB_RO_PAYBACK_COIN;
-      rh_tail->details.payback = payback;
-    } /* end of 'while (0 < rows)' */
-    PQclear (result);
+    }
+    cbc->reserve_pub = *rhc->reserve_pub;
+    tail = append_rh (rhc);
+    tail->type = TALER_EXCHANGEDB_RO_WITHDRAW_COIN;
+    tail->details.withdraw = cbc;
   }
+}
 
 
-  /** #TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK */
+/**
+ * Add paybacks to result set for #postgres_get_reserve_history.
+ *
+ * @param cls a `struct ReserveHistoryContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+add_payback (void *cls,
+                  PGresult *result,
+                  unsigned int num_results)
+{
+  struct ReserveHistoryContext *rhc = cls;
+  
+  while (0 < num_results)
   {
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-      GNUNET_PQ_query_param_end
-    };
+    struct TALER_EXCHANGEDB_Payback *payback;
+    struct TALER_EXCHANGEDB_ReserveHistory *tail;
 
-    result = GNUNET_PQ_exec_prepared (session->conn,
-                                      "close_by_reserve",
-                                      params);
-    if (PGRES_TUPLES_OK != PQresultStatus (result))
-    {
-      QUERY_ERR (result, session->conn);
-      goto cleanup;
-    }
-    rows = PQntuples (result);
-    while (0 < rows)
+    payback = GNUNET_new (struct TALER_EXCHANGEDB_Payback);
     {
-      struct TALER_EXCHANGEDB_ClosingTransfer *closing;
-
-      closing = GNUNET_new (struct TALER_EXCHANGEDB_ClosingTransfer);
-      {
-        struct GNUNET_PQ_ResultSpec rs[] = {
-          TALER_PQ_result_spec_amount ("amount",
-                                       &closing->amount),
-          TALER_PQ_result_spec_amount ("closing_fee",
-                                       &closing->closing_fee),
-          GNUNET_PQ_result_spec_absolute_time ("execution_date",
-                                               &closing->execution_date),
-          TALER_PQ_result_spec_json ("receiver_account",
-                                    &closing->receiver_account_details),
-          GNUNET_PQ_result_spec_auto_from_type ("wtid",
-                                               &closing->wtid),
-          GNUNET_PQ_result_spec_end
-        };
-        if (GNUNET_OK !=
-            GNUNET_PQ_extract_result (result,
-                                      rs,
-                                      --rows))
-        {
-          GNUNET_break (0);
-          GNUNET_free (closing);
-          PQclear (result);
-          goto cleanup;
-        }
-      }
-      closing->reserve_pub = *reserve_pub;
-      if (NULL != rh_tail)
+      struct GNUNET_PQ_ResultSpec rs[] = {
+       TALER_PQ_result_spec_amount ("amount",
+                                    &payback->value),
+       GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+                                             &payback->coin.coin_pub),
+       GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
+                                             &payback->coin_blind),
+       GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
+                                             &payback->coin_sig),
+       GNUNET_PQ_result_spec_absolute_time ("timestamp",
+                                            &payback->timestamp),
+       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
+                                             
&payback->coin.denom_pub.rsa_public_key),
+       GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
+                                            
&payback->coin.denom_sig.rsa_signature),
+       GNUNET_PQ_result_spec_end
+      };
+      
+      if (GNUNET_OK !=
+         GNUNET_PQ_extract_result (result,
+                                   rs,
+                                   --num_results))
       {
-        rh_tail->next = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
-        rh_tail = rh_tail->next;
+       GNUNET_break (0);
+       GNUNET_free (payback);
+       rhc->status = GNUNET_SYSERR;
+       return;
       }
-      else
+    }
+    payback->reserve_pub = *rhc->reserve_pub;
+    tail = append_rh (rhc);
+    tail->type = TALER_EXCHANGEDB_RO_PAYBACK_COIN;
+    tail->details.payback = payback;
+  } /* end of 'while (0 < rows)' */
+}
+
+
+/**
+ * Add exchange-to-bank transfers to result set for
+ * #postgres_get_reserve_history.
+ *
+ * @param cls a `struct ReserveHistoryContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+add_exchange_to_bank (void *cls,
+                     PGresult *result,
+                     unsigned int num_results)
+{
+  struct ReserveHistoryContext *rhc = cls;
+  
+  while (0 < num_results)
+  {
+    struct TALER_EXCHANGEDB_ClosingTransfer *closing;
+    struct TALER_EXCHANGEDB_ReserveHistory *tail;
+      
+    closing = GNUNET_new (struct TALER_EXCHANGEDB_ClosingTransfer);
+    {
+      struct GNUNET_PQ_ResultSpec rs[] = {
+       TALER_PQ_result_spec_amount ("amount",
+                                    &closing->amount),
+       TALER_PQ_result_spec_amount ("closing_fee",
+                                    &closing->closing_fee),
+       GNUNET_PQ_result_spec_absolute_time ("execution_date",
+                                            &closing->execution_date),
+       TALER_PQ_result_spec_json ("receiver_account",
+                                  &closing->receiver_account_details),
+       GNUNET_PQ_result_spec_auto_from_type ("wtid",
+                                             &closing->wtid),
+       GNUNET_PQ_result_spec_end
+      };
+      
+      if (GNUNET_OK !=
+         GNUNET_PQ_extract_result (result,
+                                   rs,
+                                   --num_results))
       {
-        rh_tail = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
-        rh = rh_tail;
+       GNUNET_break (0);
+       GNUNET_free (closing);
+       rhc->status = GNUNET_SYSERR;
+       return;
       }
-      rh_tail->type = TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK;
-      rh_tail->details.closing = closing;
-    } /* end of 'while (0 < rows)' */
-    PQclear (result);
-  }
+    }
+    closing->reserve_pub = *rhc->reserve_pub;
+    tail = append_rh (rhc);
+    tail->type = TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK;
+    tail->details.closing = closing;
+  } /* end of 'while (0 < rows)' */
+}
 
 
- cleanup:
-  if (GNUNET_SYSERR == ret)
+/**
+ * Get all of the transaction history associated with the specified
+ * reserve.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session connection to use
+ * @param reserve_pub public key of the reserve
+ * @param[out] rhp set to known transaction history (NULL if reserve is 
unknown)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_get_reserve_history (void *cls,
+                              struct TALER_EXCHANGEDB_Session *session,
+                              const struct TALER_ReservePublicKeyP 
*reserve_pub,
+                             struct TALER_EXCHANGEDB_ReserveHistory **rhp)
+{
+  struct ReserveHistoryContext rhc;
+  struct {
+    /**
+     * Name of the prepared statement to run.
+     */
+    const char *statement;
+    /**
+     * Function to use to process the results.
+     */
+    GNUNET_PQ_PostgresResultHandler cb;
+  } work[] = {
+    /** #TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE */
+    { "reserves_in_get_transactions",
+      add_bank_to_exchange },
+    /** #TALER_EXCHANGEDB_RO_WITHDRAW_COIN */
+    { "get_reserves_out",
+      &add_withdraw_coin },
+    /** #TALER_EXCHANGEDB_RO_PAYBACK_COIN */
+    { "payback_by_reserve",
+      &add_payback },
+    /** #TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK */
+    { "close_by_reserve",
+      &add_exchange_to_bank },
+    /* List terminator */
+    { NULL,
+      NULL }
+  };
+  enum GNUNET_DB_QueryStatus qs;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+    GNUNET_PQ_query_param_end
+  };
+
+  rhc.reserve_pub = reserve_pub;
+  rhc.rh = NULL;
+  rhc.rh_tail = NULL;
+  rhc.status = GNUNET_OK;
+  for (unsigned int i=0;NULL != work[i].cb;i++)
+  {
+    qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
+                                              work[i].statement,
+                                              params,
+                                              work[i].cb,
+                                              &rhc);
+    if ( (0 > qs) ||
+        (GNUNET_OK != rhc.status) )
+      break;
+  }
+  if ( (qs < 0) ||
+       (rhc.status != GNUNET_OK) )
   {
     common_free_reserve_history (cls,
-                                 rh);
-    rh = NULL;
+                                 rhc.rh);
+    rhc.rh = NULL;
+    if (qs >= 0)
+    {
+      /* status == SYSERR is a very hard error... */
+      qs = GNUNET_DB_STATUS_HARD_ERROR;
+    }
   }
-  return rh;
+  *rhp = rhc.rh;  
+  return qs;
 }
 
 
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index ba47c2d..8c7e4b9 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -1447,6 +1447,7 @@ run (void *cls)
   unsigned int cnt;
   void *rr;
   size_t rr_size;
+  enum GNUNET_DB_QueryStatus qs;
 
   dkp = NULL;
   rh = NULL;
@@ -1671,9 +1672,11 @@ run (void *cls)
 
   json_decref (sndr);
   result = 7;
-  rh = plugin->get_reserve_history (plugin->cls,
+  qs = plugin->get_reserve_history (plugin->cls,
                                     session,
-                                    &reserve_pub);
+                                    &reserve_pub,
+                                   &rh);
+  FAILIF (0 > qs);
   FAILIF (NULL == rh);
   rh_head = rh;
   for (cnt=0; NULL != rh_head; rh_head=rh_head->next, cnt++)
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index 2cf553b..843c627 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -1268,12 +1268,14 @@ struct TALER_EXCHANGEDB_Plugin
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session connection to use
    * @param reserve_pub public key of the reserve
-   * @return known transaction history (NULL if reserve is unknown)
+   * @param[out] rhp set to known transaction history (NULL if reserve is 
unknown)
+   * @return transaction status
    */
-  struct TALER_EXCHANGEDB_ReserveHistory *
+  enum GNUNET_DB_QueryStatus
   (*get_reserve_history) (void *cls,
                           struct TALER_EXCHANGEDB_Session *session,
-                          const struct TALER_ReservePublicKeyP *reserve_pub);
+                          const struct TALER_ReservePublicKeyP *reserve_pub,
+                         struct TALER_EXCHANGEDB_ReserveHistory **rhp);
 
 
   /**

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]