LCOV - code coverage report
Current view: top level - exchangedb - plugin_exchangedb_postgres.c (source / functions) Hit Total Coverage
Test: GNU Taler coverage report Lines: 1723 2539 67.9 %
Date: 2021-04-12 06:08:44 Functions: 98 134 73.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014--2020 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : 
      17             : /**
      18             :  * @file plugin_exchangedb_postgres.c
      19             :  * @brief Low-level (statement-level) Postgres database access for the exchange
      20             :  * @author Florian Dold
      21             :  * @author Christian Grothoff
      22             :  * @author Sree Harsha Totakura
      23             :  * @author Marcello Stanisci
      24             :  */
      25             : #include "platform.h"
      26             : #include "taler_error_codes.h"
      27             : #include "taler_pq_lib.h"
      28             : #include "taler_json_lib.h"
      29             : #include "taler_exchangedb_plugin.h"
      30             : #include <pthread.h>
      31             : #include <libpq-fe.h>
      32             : 
      33             : #include "plugin_exchangedb_common.c"
      34             : 
      35             : /**
      36             :  * Set to 1 to enable Postgres auto_explain module. This will
      37             :  * slow down things a _lot_, but also provide extensive logging
      38             :  * in the Postgres database logger for performance analysis.
      39             :  */
      40             : #define AUTO_EXPLAIN 1
      41             : 
      42             : /**
      43             :  * Should we explicitly lock certain individual tables prior to SELECT+INSERT
      44             :  * combis?
      45             :  */
      46             : #define EXPLICIT_LOCKS 0
      47             : 
      48             : /**
      49             :  * Wrapper macro to add the currency from the plugin's state
      50             :  * when fetching amounts from the database.
      51             :  *
      52             :  * @param field name of the database field to fetch amount from
      53             :  * @param[out] amountp pointer to amount to set
      54             :  */
      55             : #define TALER_PQ_RESULT_SPEC_AMOUNT(field,amountp) TALER_PQ_result_spec_amount ( \
      56             :     field,pg->currency,amountp)
      57             : 
      58             : /**
      59             :  * Wrapper macro to add the currency from the plugin's state
      60             :  * when fetching amounts from the database.  NBO variant.
      61             :  *
      62             :  * @param field name of the database field to fetch amount from
      63             :  * @param[out] amountp pointer to amount to set
      64             :  */
      65             : #define TALER_PQ_RESULT_SPEC_AMOUNT_NBO(field,                          \
      66             :                                         amountp) TALER_PQ_result_spec_amount_nbo ( \
      67             :     field,pg->currency,amountp)
      68             : 
      69             : /**
      70             :  * Log a really unexpected PQ error with all the details we can get hold of.
      71             :  *
      72             :  * @param result PQ result object of the PQ operation that failed
      73             :  * @param conn SQL connection that was used
      74             :  */
      75             : #define BREAK_DB_ERR(result,conn) do {                                  \
      76             :     GNUNET_break (0);                                                   \
      77             :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                                \
      78             :                 "Database failure: %s/%s/%s/%s/%s",                     \
      79             :                 PQresultErrorField (result, PG_DIAG_MESSAGE_PRIMARY),   \
      80             :                 PQresultErrorField (result, PG_DIAG_MESSAGE_DETAIL),    \
      81             :                 PQresultErrorMessage (result),                          \
      82             :                 PQresStatus (PQresultStatus (result)),                  \
      83             :                 PQerrorMessage (conn));                                 \
      84             : } while (0)
      85             : 
      86             : 
      87             : /**
      88             :  * Handler for a database session (per-thread, for transactions).
      89             :  */
      90             : struct TALER_EXCHANGEDB_Session
      91             : {
      92             :   /**
      93             :    * Postgres connection handle.
      94             :    */
      95             :   struct GNUNET_PQ_Context *conn;
      96             : 
      97             :   /**
      98             :    * Name of the current transaction, for debugging.
      99             :    */
     100             :   const char *transaction_name;
     101             : 
     102             : };
     103             : 
     104             : 
     105             : /**
     106             :  * Type of the "cls" argument given to each of the functions in
     107             :  * our API.
     108             :  */
     109             : struct PostgresClosure
     110             : {
     111             : 
     112             :   /**
     113             :    * Thread-local database connection.
     114             :    * Contains a pointer to `struct GNUNET_PQ_Context` or NULL.
     115             :    */
     116             :   pthread_key_t db_conn_threadlocal;
     117             : 
     118             :   /**
     119             :    * Our configuration.
     120             :    */
     121             :   const struct GNUNET_CONFIGURATION_Handle *cfg;
     122             : 
     123             :   /**
     124             :    * Directory with SQL statements to run to create tables.
     125             :    */
     126             :   char *sql_dir;
     127             : 
     128             :   /**
     129             :    * After how long should idle reserves be closed?
     130             :    */
     131             :   struct GNUNET_TIME_Relative idle_reserve_expiration_time;
     132             : 
     133             :   /**
     134             :    * After how long should reserves that have seen withdraw operations
     135             :    * be garbage collected?
     136             :    */
     137             :   struct GNUNET_TIME_Relative legal_reserve_expiration_time;
     138             : 
     139             :   /**
     140             :    * Which currency should we assume all amounts to be in?
     141             :    */
     142             :   char *currency;
     143             : 
     144             :   /**
     145             :    * Session to be used if the thread is @e main_self.
     146             :    */
     147             :   struct TALER_EXCHANGEDB_Session *main_session;
     148             : 
     149             :   /**
     150             :    * Handle for the main() thread of the program.
     151             :    */
     152             :   pthread_t main_self;
     153             : };
     154             : 
     155             : 
     156             : /**
     157             :  * Drop all Taler tables.  This should only be used by testcases.
     158             :  *
     159             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
     160             :  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
     161             :  */
     162             : static int
     163          12 : postgres_drop_tables (void *cls)
     164             : {
     165          12 :   struct PostgresClosure *pc = cls;
     166             :   struct GNUNET_PQ_Context *conn;
     167             : 
     168          12 :   conn = GNUNET_PQ_connect_with_cfg (pc->cfg,
     169             :                                      "exchangedb-postgres",
     170             :                                      "drop",
     171             :                                      NULL,
     172             :                                      NULL);
     173          12 :   if (NULL == conn)
     174           2 :     return GNUNET_SYSERR;
     175          10 :   GNUNET_PQ_disconnect (conn);
     176          10 :   return GNUNET_OK;
     177             : }
     178             : 
     179             : 
     180             : /**
     181             :  * Create the necessary tables if they are not present
     182             :  *
     183             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
     184             :  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
     185             :  */
     186             : static int
     187          13 : postgres_create_tables (void *cls)
     188             : {
     189          13 :   struct PostgresClosure *pc = cls;
     190             :   struct GNUNET_PQ_Context *conn;
     191             : 
     192          13 :   conn = GNUNET_PQ_connect_with_cfg (pc->cfg,
     193             :                                      "exchangedb-postgres",
     194             :                                      "exchange-",
     195             :                                      NULL,
     196             :                                      NULL);
     197          13 :   if (NULL == conn)
     198           0 :     return GNUNET_SYSERR;
     199          13 :   GNUNET_PQ_disconnect (conn);
     200          13 :   return GNUNET_OK;
     201             : }
     202             : 
     203             : 
     204             : /**
     205             :  * Close thread-local database connection when a thread is destroyed.
     206             :  *
     207             :  * @param cls closure we get from pthreads (the db handle)
     208             :  */
     209             : static void
     210         108 : db_conn_destroy (void *cls)
     211             : {
     212         108 :   struct TALER_EXCHANGEDB_Session *session = cls;
     213             :   struct GNUNET_PQ_Context *db_conn;
     214             : 
     215         108 :   if (NULL == session)
     216          24 :     return;
     217          84 :   db_conn = session->conn;
     218          84 :   session->conn = NULL;
     219          84 :   if (NULL != db_conn)
     220          84 :     GNUNET_PQ_disconnect (db_conn);
     221          84 :   GNUNET_free (session);
     222             : }
     223             : 
     224             : 
     225             : /**
     226             :  * Get the thread-local database-handle.
     227             :  * Connect to the db if the connection does not exist yet.
     228             :  *
     229             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
     230             :  * @return the database connection, or NULL on error
     231             :  */
     232             : static struct TALER_EXCHANGEDB_Session *
     233         208 : postgres_get_session (void *cls)
     234             : {
     235         208 :   struct PostgresClosure *pc = cls;
     236             :   struct GNUNET_PQ_Context *db_conn;
     237             :   struct TALER_EXCHANGEDB_Session *session;
     238             : 
     239         208 :   if (pthread_equal (pc->main_self,
     240             :                      pthread_self ()))
     241          76 :     session = pc->main_session;
     242             :   else
     243         132 :     session = pthread_getspecific (pc->db_conn_threadlocal);
     244         208 :   if (NULL != session)
     245             :   {
     246         124 :     GNUNET_PQ_reconnect_if_down (session->conn);
     247         124 :     return session;
     248             :   }
     249             :   {
     250             : #if AUTO_EXPLAIN
     251             :     /* Enable verbose logging to see where queries do not
     252             :        properly use indices */
     253          84 :     struct GNUNET_PQ_ExecuteStatement es[] = {
     254          84 :       GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
     255          84 :       GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
     256          84 :       GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
     257          84 :       GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
     258             :       /* https://wiki.postgresql.org/wiki/Serializable suggests to really
     259             :          force the default to 'serializable' if SSI is to be used. */
     260          84 :       GNUNET_PQ_make_try_execute (
     261             :         "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
     262          84 :       GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
     263          84 :       GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
     264             :       GNUNET_PQ_EXECUTE_STATEMENT_END
     265             :     };
     266             : #else
     267             :     struct GNUNET_PQ_ExecuteStatement *es = NULL;
     268             : #endif
     269          84 :     struct GNUNET_PQ_PreparedStatement ps[] = {
     270             :       /* Used in #postgres_insert_denomination_info() and
     271             :          #postgres_add_denomination_key() */
     272          84 :       GNUNET_PQ_make_prepare ("denomination_insert",
     273             :                               "INSERT INTO denominations "
     274             :                               "(denom_pub_hash"
     275             :                               ",denom_pub"
     276             :                               ",master_sig"
     277             :                               ",valid_from"
     278             :                               ",expire_withdraw"
     279             :                               ",expire_deposit"
     280             :                               ",expire_legal"
     281             :                               ",coin_val"                                          /* value of this denom */
     282             :                               ",coin_frac"                                          /* fractional value of this denom */
     283             :                               ",fee_withdraw_val"
     284             :                               ",fee_withdraw_frac"
     285             :                               ",fee_deposit_val"
     286             :                               ",fee_deposit_frac"
     287             :                               ",fee_refresh_val"
     288             :                               ",fee_refresh_frac"
     289             :                               ",fee_refund_val"
     290             :                               ",fee_refund_frac"
     291             :                               ") VALUES "
     292             :                               "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
     293             :                               " $11, $12, $13, $14, $15, $16, $17);",
     294             :                               17),
     295             :       /* Used in #postgres_iterate_denomination_info() */
     296          84 :       GNUNET_PQ_make_prepare ("denomination_iterate",
     297             :                               "SELECT"
     298             :                               " master_sig"
     299             :                               ",valid_from"
     300             :                               ",expire_withdraw"
     301             :                               ",expire_deposit"
     302             :                               ",expire_legal"
     303             :                               ",coin_val"                                          /* value of this denom */
     304             :                               ",coin_frac"                                          /* fractional value of this denom */
     305             :                               ",fee_withdraw_val"
     306             :                               ",fee_withdraw_frac"
     307             :                               ",fee_deposit_val"
     308             :                               ",fee_deposit_frac"
     309             :                               ",fee_refresh_val"
     310             :                               ",fee_refresh_frac"
     311             :                               ",fee_refund_val"
     312             :                               ",fee_refund_frac"
     313             :                               ",denom_pub"
     314             :                               " FROM denominations;",
     315             :                               0),
     316             :       /* Used in #postgres_iterate_denominations() */
     317          84 :       GNUNET_PQ_make_prepare ("select_denominations",
     318             :                               "SELECT"
     319             :                               " denominations.master_sig"
     320             :                               ",denom_revocations_serial_id IS NOT NULL AS revoked"
     321             :                               ",valid_from"
     322             :                               ",expire_withdraw"
     323             :                               ",expire_deposit"
     324             :                               ",expire_legal"
     325             :                               ",coin_val"                                          /* value of this denom */
     326             :                               ",coin_frac"                                          /* fractional value of this denom */
     327             :                               ",fee_withdraw_val"
     328             :                               ",fee_withdraw_frac"
     329             :                               ",fee_deposit_val"
     330             :                               ",fee_deposit_frac"
     331             :                               ",fee_refresh_val"
     332             :                               ",fee_refresh_frac"
     333             :                               ",fee_refund_val"
     334             :                               ",fee_refund_frac"
     335             :                               ",denom_pub"
     336             :                               " FROM denominations"
     337             :                               " LEFT JOIN "
     338             :                               "   denomination_revocations USING (denominations_serial);",
     339             :                               0),
     340             :       /* Used in #postgres_iterate_active_signkeys() */
     341          84 :       GNUNET_PQ_make_prepare ("select_signkeys",
     342             :                               "SELECT"
     343             :                               " master_sig"
     344             :                               ",exchange_pub"
     345             :                               ",valid_from"
     346             :                               ",expire_sign"
     347             :                               ",expire_legal"
     348             :                               " FROM exchange_sign_keys esk"
     349             :                               " WHERE"
     350             :                               "   expire_sign > $1"
     351             :                               " AND NOT EXISTS "
     352             :                               "  (SELECT esk_serial "
     353             :                               "     FROM signkey_revocations skr"
     354             :                               "    WHERE esk.esk_serial = skr.esk_serial);",
     355             :                               1),
     356             :       /* Used in #postgres_iterate_auditor_denominations() */
     357          84 :       GNUNET_PQ_make_prepare ("select_auditor_denoms",
     358             :                               "SELECT"
     359             :                               " auditors.auditor_pub"
     360             :                               ",denominations.denom_pub_hash"
     361             :                               ",auditor_denom_sigs.auditor_sig"
     362             :                               " FROM auditor_denom_sigs"
     363             :                               " JOIN auditors USING (auditor_uuid)"
     364             :                               " JOIN denominations USING (denominations_serial)"
     365             :                               " WHERE auditors.is_active;",
     366             :                               0),
     367             :       /* Used in #postgres_iterate_active_auditors() */
     368          84 :       GNUNET_PQ_make_prepare ("select_auditors",
     369             :                               "SELECT"
     370             :                               " auditor_pub"
     371             :                               ",auditor_url"
     372             :                               ",auditor_name"
     373             :                               " FROM auditors"
     374             :                               " WHERE"
     375             :                               "   is_active;",
     376             :                               0),
     377             :       /* Used in #postgres_get_denomination_info() */
     378          84 :       GNUNET_PQ_make_prepare ("denomination_get",
     379             :                               "SELECT"
     380             :                               " master_sig"
     381             :                               ",valid_from"
     382             :                               ",expire_withdraw"
     383             :                               ",expire_deposit"
     384             :                               ",expire_legal"
     385             :                               ",coin_val"                                          /* value of this denom */
     386             :                               ",coin_frac"                                          /* fractional value of this denom */
     387             :                               ",fee_withdraw_val"
     388             :                               ",fee_withdraw_frac"
     389             :                               ",fee_deposit_val"
     390             :                               ",fee_deposit_frac"
     391             :                               ",fee_refresh_val"
     392             :                               ",fee_refresh_frac"
     393             :                               ",fee_refund_val"
     394             :                               ",fee_refund_frac"
     395             :                               " FROM denominations"
     396             :                               " WHERE denom_pub_hash=$1;",
     397             :                               1),
     398             :       /* Used in #postgres_insert_denomination_revocation() */
     399          84 :       GNUNET_PQ_make_prepare ("denomination_revocation_insert",
     400             :                               "INSERT INTO denomination_revocations "
     401             :                               "(denominations_serial"
     402             :                               ",master_sig"
     403             :                               ") SELECT denominations_serial,$2"
     404             :                               "    FROM denominations"
     405             :                               "   WHERE denom_pub_hash=$1;",
     406             :                               2),
     407             :       /* Used in #postgres_get_denomination_revocation() */
     408          84 :       GNUNET_PQ_make_prepare ("denomination_revocation_get",
     409             :                               "SELECT"
     410             :                               " master_sig"
     411             :                               ",denom_revocations_serial_id"
     412             :                               " FROM denomination_revocations"
     413             :                               " WHERE denominations_serial="
     414             :                               "  (SELECT denominations_serial"
     415             :                               "    FROM denominations"
     416             :                               "    WHERE denom_pub_hash=$1);",
     417             :                               1),
     418             :       /* Used in #postgres_reserves_get() */
     419          84 :       GNUNET_PQ_make_prepare ("reserves_get",
     420             :                               "SELECT"
     421             :                               " current_balance_val"
     422             :                               ",current_balance_frac"
     423             :                               ",expiration_date"
     424             :                               ",gc_date"
     425             :                               " FROM reserves"
     426             :                               " WHERE reserve_pub=$1"
     427             :                               " LIMIT 1;",
     428             :                               1),
     429             :       /* Used in #postgres_reserves_in_insert() when the reserve is new */
     430          84 :       GNUNET_PQ_make_prepare ("reserve_create",
     431             :                               "INSERT INTO reserves "
     432             :                               "(reserve_pub"
     433             :                               ",account_details"
     434             :                               ",current_balance_val"
     435             :                               ",current_balance_frac"
     436             :                               ",expiration_date"
     437             :                               ",gc_date"
     438             :                               ") VALUES "
     439             :                               "($1, $2, $3, $4, $5, $6);",
     440             :                               6),
     441             :       /* Used in #postgres_insert_reserve_closed() */
     442          84 :       GNUNET_PQ_make_prepare ("reserves_close_insert",
     443             :                               "INSERT INTO reserves_close "
     444             :                               "(reserve_uuid"
     445             :                               ",execution_date"
     446             :                               ",wtid"
     447             :                               ",receiver_account"
     448             :                               ",amount_val"
     449             :                               ",amount_frac"
     450             :                               ",closing_fee_val"
     451             :                               ",closing_fee_frac"
     452             :                               ") SELECT reserve_uuid, $2, $3, $4, $5, $6, $7, $8"
     453             :                               "  FROM reserves"
     454             :                               "  WHERE reserve_pub=$1;",
     455             :                               8),
     456             :       /* Used in #reserves_update() when the reserve is updated */
     457          84 :       GNUNET_PQ_make_prepare ("reserve_update",
     458             :                               "UPDATE reserves"
     459             :                               " SET"
     460             :                               " expiration_date=$1"
     461             :                               ",gc_date=$2"
     462             :                               ",current_balance_val=$3"
     463             :                               ",current_balance_frac=$4"
     464             :                               " WHERE reserve_pub=$5;",
     465             :                               5),
     466             :       /* Used in #postgres_reserves_in_insert() to store transaction details */
     467          84 :       GNUNET_PQ_make_prepare ("reserves_in_add_transaction",
     468             :                               "INSERT INTO reserves_in "
     469             :                               "(reserve_uuid"
     470             :                               ",wire_reference"
     471             :                               ",credit_val"
     472             :                               ",credit_frac"
     473             :                               ",exchange_account_section"
     474             :                               ",sender_account_details"
     475             :                               ",execution_date"
     476             :                               ") SELECT reserve_uuid, $2, $3, $4, $5, $6, $7"
     477             :                               "  FROM reserves"
     478             :                               "  WHERE reserve_pub=$1"
     479             :                               " ON CONFLICT DO NOTHING;",
     480             :                               7),
     481             :       /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound
     482             :          transactions for reserves with serial id '\geq' the given parameter */
     483          84 :       GNUNET_PQ_make_prepare ("reserves_in_get_latest_wire_reference",
     484             :                               "SELECT"
     485             :                               " wire_reference"
     486             :                               " FROM reserves_in"
     487             :                               " WHERE exchange_account_section=$1"
     488             :                               " ORDER BY reserve_in_serial_id DESC"
     489             :                               " LIMIT 1;",
     490             :                               1),
     491             :       /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound
     492             :          transactions for reserves with serial id '\geq' the given parameter */
     493          84 :       GNUNET_PQ_make_prepare ("audit_reserves_in_get_transactions_incr",
     494             :                               "SELECT"
     495             :                               " reserves.reserve_pub"
     496             :                               ",wire_reference"
     497             :                               ",credit_val"
     498             :                               ",credit_frac"
     499             :                               ",execution_date"
     500             :                               ",sender_account_details"
     501             :                               ",reserve_in_serial_id"
     502             :                               " FROM reserves_in"
     503             :                               " JOIN reserves"
     504             :                               "   USING (reserve_uuid)"
     505             :                               " WHERE reserve_in_serial_id>=$1"
     506             :                               " ORDER BY reserve_in_serial_id;",
     507             :                               1),
     508             :       /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound
     509             :          transactions for reserves with serial id '\geq' the given parameter */
     510          84 :       GNUNET_PQ_make_prepare (
     511             :         "audit_reserves_in_get_transactions_incr_by_account",
     512             :         "SELECT"
     513             :         " reserves.reserve_pub"
     514             :         ",wire_reference"
     515             :         ",credit_val"
     516             :         ",credit_frac"
     517             :         ",execution_date"
     518             :         ",sender_account_details"
     519             :         ",reserve_in_serial_id"
     520             :         " FROM reserves_in"
     521             :         " JOIN reserves "
     522             :         "   USING (reserve_uuid)"
     523             :         " WHERE reserve_in_serial_id>=$1 AND exchange_account_section=$2"
     524             :         " ORDER BY reserve_in_serial_id;",
     525             :         2),
     526             :       /* Used in #postgres_get_reserve_history() to obtain inbound transactions
     527             :          for a reserve */
     528          84 :       GNUNET_PQ_make_prepare ("reserves_in_get_transactions",
     529             :                               "SELECT"
     530             :                               " wire_reference"
     531             :                               ",credit_val"
     532             :                               ",credit_frac"
     533             :                               ",execution_date"
     534             :                               ",sender_account_details"
     535             :                               " FROM reserves_in"
     536             :                               " WHERE reserve_uuid="
     537             :                               " (SELECT reserve_uuid "
     538             :                               "   FROM reserves"
     539             :                               "   WHERE reserve_pub=$1);",
     540             :                               1),
     541             :       /* Lock withdraw table; NOTE: we may want to eventually shard the
     542             :          deposit table to avoid this lock being the main point of
     543             :          contention limiting transaction performance. */
     544          84 :       GNUNET_PQ_make_prepare ("lock_withdraw",
     545             :                               "LOCK TABLE reserves_out;",
     546             :                               0),
     547             :       /* Used in #postgres_insert_withdraw_info() to store
     548             :          the signature of a blinded coin with the blinded coin's
     549             :          details before returning it during /reserve/withdraw. We store
     550             :          the coin's denomination information (public key, signature)
     551             :          and the blinded message as well as the reserve that the coin
     552             :          is being withdrawn from and the signature of the message
     553             :          authorizing the withdrawal. */
     554          84 :       GNUNET_PQ_make_prepare ("insert_withdraw_info",
     555             :                               "WITH ds AS"
     556             :                               " (SELECT denominations_serial"
     557             :                               "    FROM denominations"
     558             :                               "   WHERE denom_pub_hash=$2)"
     559             :                               "INSERT INTO reserves_out "
     560             :                               "(h_blind_ev"
     561             :                               ",denominations_serial"
     562             :                               ",denom_sig"
     563             :                               ",reserve_uuid"
     564             :                               ",reserve_sig"
     565             :                               ",execution_date"
     566             :                               ",amount_with_fee_val"
     567             :                               ",amount_with_fee_frac"
     568             :                               ") SELECT $1, ds.denominations_serial, $3, reserve_uuid, $5, $6, $7, $8"
     569             :                               "    FROM reserves"
     570             :                               "    CROSS JOIN ds"
     571             :                               "    WHERE reserve_pub=$4;",
     572             :                               8),
     573             :       /* Used in #postgres_get_withdraw_info() to
     574             :          locate the response for a /reserve/withdraw request
     575             :          using the hash of the blinded message.  Used to
     576             :          make sure /reserve/withdraw requests are idempotent. */
     577          84 :       GNUNET_PQ_make_prepare ("get_withdraw_info",
     578             :                               "SELECT"
     579             :                               " denom.denom_pub_hash"
     580             :                               ",denom_sig"
     581             :                               ",reserve_sig"
     582             :                               ",reserves.reserve_pub"
     583             :                               ",execution_date"
     584             :                               ",amount_with_fee_val"
     585             :                               ",amount_with_fee_frac"
     586             :                               ",denom.fee_withdraw_val"
     587             :                               ",denom.fee_withdraw_frac"
     588             :                               " FROM reserves_out"
     589             :                               "    JOIN reserves"
     590             :                               "      USING (reserve_uuid)"
     591             :                               "    JOIN denominations denom"
     592             :                               "      USING (denominations_serial)"
     593             :                               " WHERE h_blind_ev=$1;",
     594             :                               1),
     595             :       /* Used during #postgres_get_reserve_history() to
     596             :          obtain all of the /reserve/withdraw operations that
     597             :          have been performed on a given reserve. (i.e. to
     598             :          demonstrate double-spending) */
     599          84 :       GNUNET_PQ_make_prepare ("get_reserves_out",
     600             :                               "SELECT"
     601             :                               " h_blind_ev"
     602             :                               ",denom.denom_pub_hash"
     603             :                               ",denom_sig"
     604             :                               ",reserve_sig"
     605             :                               ",execution_date"
     606             :                               ",amount_with_fee_val"
     607             :                               ",amount_with_fee_frac"
     608             :                               ",denom.fee_withdraw_val"
     609             :                               ",denom.fee_withdraw_frac"
     610             :                               " FROM reserves_out"
     611             :                               "    JOIN denominations denom"
     612             :                               "      USING (denominations_serial)"
     613             :                               " WHERE reserve_uuid="
     614             :                               "   (SELECT reserve_uuid"
     615             :                               "      FROM reserves"
     616             :                               "     WHERE reserve_pub=$1);",
     617             :                               1),
     618             :       /* Used in #postgres_select_withdrawals_above_serial_id() */
     619          84 :       GNUNET_PQ_make_prepare ("audit_get_reserves_out_incr",
     620             :                               "SELECT"
     621             :                               " h_blind_ev"
     622             :                               ",denom.denom_pub"
     623             :                               ",reserve_sig"
     624             :                               ",reserves.reserve_pub"
     625             :                               ",execution_date"
     626             :                               ",amount_with_fee_val"
     627             :                               ",amount_with_fee_frac"
     628             :                               ",reserve_out_serial_id"
     629             :                               " FROM reserves_out"
     630             :                               "    JOIN reserves"
     631             :                               "      USING (reserve_uuid)"
     632             :                               "    JOIN denominations denom"
     633             :                               "      USING (denominations_serial)"
     634             :                               " WHERE reserve_out_serial_id>=$1"
     635             :                               " ORDER BY reserve_out_serial_id ASC;",
     636             :                               1),
     637             : 
     638             :       /* Used in #postgres_count_known_coins() */
     639          84 :       GNUNET_PQ_make_prepare ("count_known_coins",
     640             :                               "SELECT"
     641             :                               " COUNT(*) AS count"
     642             :                               " FROM known_coins"
     643             :                               " WHERE denominations_serial="
     644             :                               "  (SELECT denominations_serial"
     645             :                               "    FROM denominations"
     646             :                               "    WHERE denom_pub_hash=$1);",
     647             :                               1),
     648             :       /* Used in #postgres_get_known_coin() to fetch
     649             :          the denomination public key and signature for
     650             :          a coin known to the exchange. */
     651          84 :       GNUNET_PQ_make_prepare ("get_known_coin",
     652             :                               "SELECT"
     653             :                               " denominations.denom_pub_hash"
     654             :                               ",denom_sig"
     655             :                               " FROM known_coins"
     656             :                               " JOIN denominations USING (denominations_serial)"
     657             :                               " WHERE coin_pub=$1;",
     658             :                               1),
     659             :       /* Used in #postgres_ensure_coin_known() */
     660          84 :       GNUNET_PQ_make_prepare ("get_known_coin_dh",
     661             :                               "SELECT"
     662             :                               " denominations.denom_pub_hash"
     663             :                               " FROM known_coins"
     664             :                               " JOIN denominations USING (denominations_serial)"
     665             :                               " WHERE coin_pub=$1;",
     666             :                               1),
     667             :       /* Used in #postgres_get_coin_denomination() to fetch
     668             :          the denomination public key hash for
     669             :          a coin known to the exchange. */
     670          84 :       GNUNET_PQ_make_prepare ("get_coin_denomination",
     671             :                               "SELECT"
     672             :                               " denominations.denom_pub_hash"
     673             :                               " FROM known_coins"
     674             :                               " JOIN denominations USING (denominations_serial)"
     675             :                               " WHERE coin_pub=$1"
     676             :                               " FOR SHARE;",
     677             :                               1),
     678             :       /* Lock deposit table; NOTE: we may want to eventually shard the
     679             :          deposit table to avoid this lock being the main point of
     680             :          contention limiting transaction performance. */
     681          84 :       GNUNET_PQ_make_prepare ("lock_known_coins",
     682             :                               "LOCK TABLE known_coins;",
     683             :                               0),
     684             :       /* Used in #postgres_insert_known_coin() to store
     685             :          the denomination public key and signature for
     686             :          a coin known to the exchange. */
     687          84 :       GNUNET_PQ_make_prepare ("insert_known_coin",
     688             :                               "INSERT INTO known_coins "
     689             :                               "(coin_pub"
     690             :                               ",denominations_serial"
     691             :                               ",denom_sig"
     692             :                               ") SELECT $1, denominations_serial, $3 "
     693             :                               "    FROM denominations"
     694             :                               "   WHERE denom_pub_hash=$2;",
     695             :                               3),
     696             : 
     697             :       /* Used in #postgres_insert_melt() to store
     698             :          high-level information about a melt operation */
     699          84 :       GNUNET_PQ_make_prepare ("insert_melt",
     700             :                               "INSERT INTO refresh_commitments "
     701             :                               "(rc "
     702             :                               ",old_known_coin_id "
     703             :                               ",old_coin_sig "
     704             :                               ",amount_with_fee_val "
     705             :                               ",amount_with_fee_frac "
     706             :                               ",noreveal_index "
     707             :                               ") SELECT $1, known_coin_id, $3, $4, $5, $6"
     708             :                               "    FROM known_coins"
     709             :                               "   WHERE coin_pub=$2",
     710             :                               6),
     711             :       /* Used in #postgres_get_melt() to fetch
     712             :          high-level information about a melt operation */
     713          84 :       GNUNET_PQ_make_prepare ("get_melt",
     714             :                               "SELECT"
     715             :                               " denoms.denom_pub_hash"
     716             :                               ",denoms.fee_refresh_val"
     717             :                               ",denoms.fee_refresh_frac"
     718             :                               ",kc.coin_pub AS old_coin_pub"
     719             :                               ",old_coin_sig"
     720             :                               ",amount_with_fee_val"
     721             :                               ",amount_with_fee_frac"
     722             :                               ",noreveal_index"
     723             :                               " FROM refresh_commitments"
     724             :                               "   JOIN known_coins kc"
     725             :                               "     ON (refresh_commitments.old_known_coin_id = kc.known_coin_id)"
     726             :                               "   JOIN denominations denoms"
     727             :                               "     ON (kc.denominations_serial = denoms.denominations_serial)"
     728             :                               " WHERE rc=$1;",
     729             :                               1),
     730             :       /* Used in #postgres_get_melt_index() to fetch
     731             :          the noreveal index from a previous melt operation */
     732          84 :       GNUNET_PQ_make_prepare ("get_melt_index",
     733             :                               "SELECT"
     734             :                               " noreveal_index"
     735             :                               " FROM refresh_commitments"
     736             :                               " WHERE rc=$1;",
     737             :                               1),
     738             :       /* Used in #postgres_select_refreshes_above_serial_id() to fetch
     739             :          refresh session with id '\geq' the given parameter */
     740          84 :       GNUNET_PQ_make_prepare ("audit_get_refresh_commitments_incr",
     741             :                               "SELECT"
     742             :                               " denom.denom_pub"
     743             :                               ",kc.coin_pub AS old_coin_pub"
     744             :                               ",old_coin_sig"
     745             :                               ",amount_with_fee_val"
     746             :                               ",amount_with_fee_frac"
     747             :                               ",noreveal_index"
     748             :                               ",melt_serial_id"
     749             :                               ",rc"
     750             :                               " FROM refresh_commitments"
     751             :                               "   JOIN known_coins kc"
     752             :                               "     ON (refresh_commitments.old_known_coin_id = kc.known_coin_id)"
     753             :                               "   JOIN denominations denom"
     754             :                               "     ON (kc.denominations_serial = denom.denominations_serial)"
     755             :                               " WHERE melt_serial_id>=$1"
     756             :                               " ORDER BY melt_serial_id ASC;",
     757             :                               1),
     758             :       /* Query the 'refresh_commitments' by coin public key */
     759          84 :       GNUNET_PQ_make_prepare ("get_refresh_session_by_coin",
     760             :                               "SELECT"
     761             :                               " rc"
     762             :                               ",old_coin_sig"
     763             :                               ",amount_with_fee_val"
     764             :                               ",amount_with_fee_frac"
     765             :                               ",denoms.denom_pub_hash"
     766             :                               ",denoms.fee_refresh_val"
     767             :                               ",denoms.fee_refresh_frac"
     768             :                               ",melt_serial_id"
     769             :                               " FROM refresh_commitments"
     770             :                               " JOIN known_coins kc"
     771             :                               "   ON (refresh_commitments.old_known_coin_id = kc.known_coin_id)"
     772             :                               " JOIN denominations denoms"
     773             :                               "   USING (denominations_serial)"
     774             :                               " WHERE old_known_coin_id="
     775             :                               "(SELECT known_coin_id"
     776             :                               "   FROM known_coins"
     777             :                               "  WHERE coin_pub=$1);",
     778             :                               1),
     779             :       /* Store information about the desired denominations for a
     780             :          refresh operation, used in #postgres_insert_refresh_reveal() */
     781          84 :       GNUNET_PQ_make_prepare ("insert_refresh_revealed_coin",
     782             :                               "WITH rcx AS"
     783             :                               " (SELECT melt_serial_id"
     784             :                               "    FROM refresh_commitments"
     785             :                               "   WHERE rc=$1)"
     786             :                               "INSERT INTO refresh_revealed_coins "
     787             :                               "(melt_serial_id "
     788             :                               ",freshcoin_index "
     789             :                               ",link_sig "
     790             :                               ",denominations_serial "
     791             :                               ",coin_ev"
     792             :                               ",h_coin_ev"
     793             :                               ",ev_sig"
     794             :                               ") SELECT rcx.melt_serial_id, $2, $3, "
     795             :                               "         denominations_serial, $5, $6, $7"
     796             :                               "    FROM denominations"
     797             :                               "   CROSS JOIN rcx"
     798             :                               "   WHERE denom_pub_hash=$4;",
     799             :                               7),
     800             :       /* Obtain information about the coins created in a refresh
     801             :          operation, used in #postgres_get_refresh_reveal() */
     802          84 :       GNUNET_PQ_make_prepare ("get_refresh_revealed_coins",
     803             :                               "SELECT "
     804             :                               " freshcoin_index"
     805             :                               ",denom.denom_pub"
     806             :                               ",link_sig"
     807             :                               ",coin_ev"
     808             :                               ",ev_sig"
     809             :                               " FROM refresh_revealed_coins"
     810             :                               "    JOIN denominations denom "
     811             :                               "      USING (denominations_serial)"
     812             :                               "    JOIN refresh_commitments"
     813             :                               "      USING (melt_serial_id)"
     814             :                               " WHERE rc=$1"
     815             :                               "   ORDER BY freshcoin_index ASC;",
     816             :                               1),
     817             : 
     818             :       /* Used in #postgres_insert_refresh_reveal() to store the transfer
     819             :          keys we learned */
     820          84 :       GNUNET_PQ_make_prepare ("insert_refresh_transfer_keys",
     821             :                               "INSERT INTO refresh_transfer_keys "
     822             :                               "(melt_serial_id"
     823             :                               ",transfer_pub"
     824             :                               ",transfer_privs"
     825             :                               ") SELECT melt_serial_id, $2, $3"
     826             :                               "    FROM refresh_commitments"
     827             :                               "   WHERE rc=$1",
     828             :                               3),
     829             :       /* Used in #postgres_get_refresh_reveal() to retrieve transfer
     830             :          keys from /refresh/reveal */
     831          84 :       GNUNET_PQ_make_prepare ("get_refresh_transfer_keys",
     832             :                               "SELECT"
     833             :                               " transfer_pub"
     834             :                               ",transfer_privs"
     835             :                               " FROM refresh_transfer_keys"
     836             :                               " JOIN refresh_commitments"
     837             :                               "   USING (melt_serial_id)"
     838             :                               " WHERE rc=$1;",
     839             :                               1),
     840             :       /* Used in #postgres_insert_refund() to store refund information */
     841          84 :       GNUNET_PQ_make_prepare ("insert_refund",
     842             :                               "INSERT INTO refunds "
     843             :                               "(deposit_serial_id "
     844             :                               ",merchant_sig "
     845             :                               ",rtransaction_id "
     846             :                               ",amount_with_fee_val "
     847             :                               ",amount_with_fee_frac "
     848             :                               ") SELECT deposit_serial_id, $3, $5, $6, $7"
     849             :                               "    FROM deposits"
     850             :                               "    JOIN known_coins USING (known_coin_id)"
     851             :                               "   WHERE coin_pub=$1"
     852             :                               "     AND h_contract_terms=$4"
     853             :                               "     AND merchant_pub=$2",
     854             :                               7),
     855             :       /* Query the 'refunds' by coin public key */
     856          84 :       GNUNET_PQ_make_prepare ("get_refunds_by_coin",
     857             :                               "SELECT"
     858             :                               " merchant_pub"
     859             :                               ",merchant_sig"
     860             :                               ",h_contract_terms"
     861             :                               ",rtransaction_id"
     862             :                               ",refunds.amount_with_fee_val"
     863             :                               ",refunds.amount_with_fee_frac"
     864             :                               ",denom.fee_refund_val "
     865             :                               ",denom.fee_refund_frac "
     866             :                               ",refund_serial_id"
     867             :                               " FROM refunds"
     868             :                               " JOIN deposits USING (deposit_serial_id)"
     869             :                               " JOIN known_coins USING (known_coin_id)"
     870             :                               " JOIN denominations denom USING (denominations_serial)"
     871             :                               " WHERE coin_pub=$1;",
     872             :                               1),
     873             :       /* Query the 'refunds' by coin public key, merchant_pub and contract hash */
     874          84 :       GNUNET_PQ_make_prepare ("get_refunds_by_coin_and_contract",
     875             :                               "SELECT"
     876             :                               " refunds.amount_with_fee_val"
     877             :                               ",refunds.amount_with_fee_frac"
     878             :                               " FROM refunds"
     879             :                               " JOIN deposits USING (deposit_serial_id)"
     880             :                               " JOIN known_coins USING (known_coin_id)"
     881             :                               " WHERE coin_pub=$1"
     882             :                               "   AND merchant_pub=$2"
     883             :                               "   AND h_contract_terms=$3;",
     884             :                               3),
     885             :       /* Fetch refunds with rowid '\geq' the given parameter */
     886          84 :       GNUNET_PQ_make_prepare ("audit_get_refunds_incr",
     887             :                               "SELECT"
     888             :                               " merchant_pub"
     889             :                               ",merchant_sig"
     890             :                               ",h_contract_terms"
     891             :                               ",rtransaction_id"
     892             :                               ",denom.denom_pub"
     893             :                               ",kc.coin_pub"
     894             :                               ",refunds.amount_with_fee_val"
     895             :                               ",refunds.amount_with_fee_frac"
     896             :                               ",refund_serial_id"
     897             :                               " FROM refunds"
     898             :                               "   JOIN deposits USING (deposit_serial_id)"
     899             :                               "   JOIN known_coins kc USING (known_coin_id)"
     900             :                               "   JOIN denominations denom ON (kc.denominations_serial = denom.denominations_serial)"
     901             :                               " WHERE refund_serial_id>=$1"
     902             :                               " ORDER BY refund_serial_id ASC;",
     903             :                               1),
     904             :       /* Lock deposit table; NOTE: we may want to eventually shard the
     905             :          deposit table to avoid this lock being the main point of
     906             :          contention limiting transaction performance. */
     907          84 :       GNUNET_PQ_make_prepare ("lock_deposit",
     908             :                               "LOCK TABLE deposits;",
     909             :                               0),
     910             :       /* Store information about a /deposit the exchange is to execute.
     911             :          Used in #postgres_insert_deposit(). */
     912          84 :       GNUNET_PQ_make_prepare ("insert_deposit",
     913             :                               "INSERT INTO deposits "
     914             :                               "(known_coin_id"
     915             :                               ",amount_with_fee_val"
     916             :                               ",amount_with_fee_frac"
     917             :                               ",wallet_timestamp"
     918             :                               ",refund_deadline"
     919             :                               ",wire_deadline"
     920             :                               ",merchant_pub"
     921             :                               ",h_contract_terms"
     922             :                               ",h_wire"
     923             :                               ",coin_sig"
     924             :                               ",wire"
     925             :                               ",exchange_timestamp"
     926             :                               ") SELECT known_coin_id, $2, $3, $4, $5, $6, "
     927             :                               " $7, $8, $9, $10, $11, $12"
     928             :                               "    FROM known_coins"
     929             :                               "   WHERE coin_pub=$1;",
     930             :                               12),
     931             :       /* Fetch an existing deposit request, used to ensure idempotency
     932             :          during /deposit processing. Used in #postgres_have_deposit(). */
     933          84 :       GNUNET_PQ_make_prepare ("get_deposit",
     934             :                               "SELECT"
     935             :                               " amount_with_fee_val"
     936             :                               ",amount_with_fee_frac"
     937             :                               ",denominations.fee_deposit_val"
     938             :                               ",denominations.fee_deposit_frac"
     939             :                               ",wallet_timestamp"
     940             :                               ",exchange_timestamp"
     941             :                               ",refund_deadline"
     942             :                               ",wire_deadline"
     943             :                               ",h_contract_terms"
     944             :                               ",h_wire"
     945             :                               " FROM deposits"
     946             :                               " JOIN known_coins USING (known_coin_id)"
     947             :                               " JOIN denominations USING (denominations_serial)"
     948             :                               " WHERE ((coin_pub=$1)"
     949             :                               "    AND (merchant_pub=$3)"
     950             :                               "    AND (h_contract_terms=$2));",
     951             :                               3),
     952             :       /* Fetch deposits with rowid '\geq' the given parameter */
     953          84 :       GNUNET_PQ_make_prepare ("audit_get_deposits_incr",
     954             :                               "SELECT"
     955             :                               " amount_with_fee_val"
     956             :                               ",amount_with_fee_frac"
     957             :                               ",wallet_timestamp"
     958             :                               ",exchange_timestamp"
     959             :                               ",merchant_pub"
     960             :                               ",denom.denom_pub"
     961             :                               ",kc.coin_pub"
     962             :                               ",coin_sig"
     963             :                               ",refund_deadline"
     964             :                               ",wire_deadline"
     965             :                               ",h_contract_terms"
     966             :                               ",wire"
     967             :                               ",done"
     968             :                               ",deposit_serial_id"
     969             :                               " FROM deposits"
     970             :                               "    JOIN known_coins kc USING (known_coin_id)"
     971             :                               "    JOIN denominations denom USING (denominations_serial)"
     972             :                               " WHERE ("
     973             :                               "  (deposit_serial_id>=$1)"
     974             :                               " )"
     975             :                               " ORDER BY deposit_serial_id ASC;",
     976             :                               1),
     977             :       /* Fetch an existing deposit request.
     978             :          Used in #postgres_lookup_transfer_by_deposit(). */
     979          84 :       GNUNET_PQ_make_prepare ("get_deposit_for_wtid",
     980             :                               "SELECT"
     981             :                               " amount_with_fee_val"
     982             :                               ",amount_with_fee_frac"
     983             :                               ",denom.fee_deposit_val"
     984             :                               ",denom.fee_deposit_frac"
     985             :                               ",wire_deadline"
     986             :                               " FROM deposits"
     987             :                               "    JOIN known_coins USING (known_coin_id)"
     988             :                               "    JOIN denominations denom USING (denominations_serial)"
     989             :                               " WHERE ((coin_pub=$1)"
     990             :                               "    AND (merchant_pub=$2)"
     991             :                               "    AND (h_contract_terms=$3)"
     992             :                               "    AND (h_wire=$4)"
     993             :                               " );",
     994             :                               4),
     995             :       /* Used in #postgres_get_ready_deposit() */
     996          84 :       GNUNET_PQ_make_prepare ("deposits_get_ready",
     997             :                               "SELECT"
     998             :                               " deposit_serial_id"
     999             :                               ",amount_with_fee_val"
    1000             :                               ",amount_with_fee_frac"
    1001             :                               ",denom.fee_deposit_val"
    1002             :                               ",denom.fee_deposit_frac"
    1003             :                               ",wire_deadline"
    1004             :                               ",h_contract_terms"
    1005             :                               ",wire"
    1006             :                               ",merchant_pub"
    1007             :                               ",kc.coin_pub"
    1008             :                               ",exchange_timestamp"
    1009             :                               ",wallet_timestamp"
    1010             :                               " FROM deposits"
    1011             :                               "    JOIN known_coins kc USING (known_coin_id)"
    1012             :                               "    JOIN denominations denom USING (denominations_serial)"
    1013             :                               " WHERE tiny=FALSE"
    1014             :                               "    AND done=FALSE"
    1015             :                               "    AND wire_deadline<=$1"
    1016             :                               "    AND refund_deadline<$1"
    1017             :                               " ORDER BY wire_deadline ASC"
    1018             :                               " LIMIT 1;",
    1019             :                               1),
    1020             :       /* Used in #postgres_iterate_matching_deposits() */
    1021          84 :       GNUNET_PQ_make_prepare ("deposits_iterate_matching",
    1022             :                               "SELECT"
    1023             :                               " deposit_serial_id"
    1024             :                               ",amount_with_fee_val"
    1025             :                               ",amount_with_fee_frac"
    1026             :                               ",denom.fee_deposit_val"
    1027             :                               ",denom.fee_deposit_frac"
    1028             :                               ",h_contract_terms"
    1029             :                               ",kc.coin_pub"
    1030             :                               " FROM deposits"
    1031             :                               "    JOIN known_coins kc USING (known_coin_id)"
    1032             :                               "    JOIN denominations denom USING (denominations_serial)"
    1033             :                               " WHERE"
    1034             :                               "     merchant_pub=$1 AND"
    1035             :                               "     h_wire=$2 AND"
    1036             :                               "     done=FALSE"
    1037             :                               " ORDER BY wire_deadline ASC"
    1038             :                               " LIMIT "
    1039             :                               TALER_QUOTE (
    1040             :                                 TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT) ";",
    1041             :                               2),
    1042             :       /* Used in #postgres_mark_deposit_tiny() */
    1043          84 :       GNUNET_PQ_make_prepare ("mark_deposit_tiny",
    1044             :                               "UPDATE deposits"
    1045             :                               " SET tiny=TRUE"
    1046             :                               " WHERE deposit_serial_id=$1",
    1047             :                               1),
    1048             :       /* Used in #postgres_mark_deposit_done() */
    1049          84 :       GNUNET_PQ_make_prepare ("mark_deposit_done",
    1050             :                               "UPDATE deposits"
    1051             :                               " SET done=TRUE"
    1052             :                               " WHERE deposit_serial_id=$1;",
    1053             :                               1),
    1054             :       /* Used in #postgres_test_deposit_done() */
    1055          84 :       GNUNET_PQ_make_prepare ("test_deposit_done",
    1056             :                               "SELECT done"
    1057             :                               " FROM deposits"
    1058             :                               " JOIN known_coins USING (known_coin_id)"
    1059             :                               " WHERE coin_pub=$1"
    1060             :                               "   AND merchant_pub=$2"
    1061             :                               "   AND h_contract_terms=$3"
    1062             :                               "   AND h_wire=$4;",
    1063             :                               5),
    1064             :       /* Used in #postgres_get_coin_transactions() to obtain information
    1065             :          about how a coin has been spend with /deposit requests. */
    1066          84 :       GNUNET_PQ_make_prepare ("get_deposit_with_coin_pub",
    1067             :                               "SELECT"
    1068             :                               " amount_with_fee_val"
    1069             :                               ",amount_with_fee_frac"
    1070             :                               ",denoms.fee_deposit_val"
    1071             :                               ",denoms.fee_deposit_frac"
    1072             :                               ",denoms.denom_pub_hash"
    1073             :                               ",wallet_timestamp"
    1074             :                               ",refund_deadline"
    1075             :                               ",wire_deadline"
    1076             :                               ",merchant_pub"
    1077             :                               ",h_contract_terms"
    1078             :                               ",h_wire"
    1079             :                               ",wire"
    1080             :                               ",coin_sig"
    1081             :                               ",deposit_serial_id"
    1082             :                               ",done"
    1083             :                               " FROM deposits"
    1084             :                               "    JOIN known_coins kc"
    1085             :                               "      USING (known_coin_id)"
    1086             :                               "    JOIN denominations denoms"
    1087             :                               "      USING (denominations_serial)"
    1088             :                               " WHERE coin_pub=$1;",
    1089             :                               1),
    1090             : 
    1091             :       /* Used in #postgres_get_link_data(). */
    1092          84 :       GNUNET_PQ_make_prepare ("get_link",
    1093             :                               "SELECT "
    1094             :                               " tp.transfer_pub"
    1095             :                               ",denoms.denom_pub"
    1096             :                               ",rrc.ev_sig"
    1097             :                               ",rrc.link_sig"
    1098             :                               " FROM refresh_commitments"
    1099             :                               "     JOIN refresh_revealed_coins rrc"
    1100             :                               "       USING (melt_serial_id)"
    1101             :                               "     JOIN refresh_transfer_keys tp"
    1102             :                               "       USING (melt_serial_id)"
    1103             :                               "     JOIN denominations denoms"
    1104             :                               "       ON (rrc.denominations_serial = denoms.denominations_serial)"
    1105             :                               " WHERE old_known_coin_id="
    1106             :                               "   (SELECT known_coin_id "
    1107             :                               "      FROM known_coins"
    1108             :                               "     WHERE coin_pub=$1)"
    1109             :                               " ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC",
    1110             :                               1),
    1111             :       /* Used in #postgres_lookup_wire_transfer */
    1112          84 :       GNUNET_PQ_make_prepare ("lookup_transactions",
    1113             :                               "SELECT"
    1114             :                               " aggregation_serial_id"
    1115             :                               ",deposits.h_contract_terms"
    1116             :                               ",deposits.wire"
    1117             :                               ",deposits.h_wire"
    1118             :                               ",kc.coin_pub"
    1119             :                               ",deposits.merchant_pub"
    1120             :                               ",wire_out.execution_date"
    1121             :                               ",deposits.amount_with_fee_val"
    1122             :                               ",deposits.amount_with_fee_frac"
    1123             :                               ",denom.fee_deposit_val"
    1124             :                               ",denom.fee_deposit_frac"
    1125             :                               ",denom.denom_pub"
    1126             :                               " FROM aggregation_tracking"
    1127             :                               "    JOIN deposits"
    1128             :                               "      USING (deposit_serial_id)"
    1129             :                               "    JOIN known_coins kc"
    1130             :                               "      USING (known_coin_id)"
    1131             :                               "    JOIN denominations denom"
    1132             :                               "      USING (denominations_serial)"
    1133             :                               "    JOIN wire_out"
    1134             :                               "      USING (wtid_raw)"
    1135             :                               " WHERE wtid_raw=$1;",
    1136             :                               1),
    1137             :       /* Used in #postgres_lookup_transfer_by_deposit */
    1138          84 :       GNUNET_PQ_make_prepare ("lookup_deposit_wtid",
    1139             :                               "SELECT"
    1140             :                               " aggregation_tracking.wtid_raw"
    1141             :                               ",wire_out.execution_date"
    1142             :                               ",amount_with_fee_val"
    1143             :                               ",amount_with_fee_frac"
    1144             :                               ",denom.fee_deposit_val"
    1145             :                               ",denom.fee_deposit_frac"
    1146             :                               " FROM deposits"
    1147             :                               "    JOIN aggregation_tracking"
    1148             :                               "      USING (deposit_serial_id)"
    1149             :                               "    JOIN known_coins"
    1150             :                               "      USING (known_coin_id)"
    1151             :                               "    JOIN denominations denom"
    1152             :                               "      USING (denominations_serial)"
    1153             :                               "    JOIN wire_out"
    1154             :                               "      USING (wtid_raw)"
    1155             :                               " WHERE coin_pub=$1"
    1156             :                               "  AND h_contract_terms=$2"
    1157             :                               "  AND h_wire=$3"
    1158             :                               "  AND merchant_pub=$4;",
    1159             :                               4),
    1160             :       /* Used in #postgres_insert_aggregation_tracking */
    1161          84 :       GNUNET_PQ_make_prepare ("insert_aggregation_tracking",
    1162             :                               "INSERT INTO aggregation_tracking "
    1163             :                               "(deposit_serial_id"
    1164             :                               ",wtid_raw"
    1165             :                               ") VALUES "
    1166             :                               "($1, $2);",
    1167             :                               2),
    1168             :       /* Used in #postgres_get_wire_fee() */
    1169          84 :       GNUNET_PQ_make_prepare ("get_wire_fee",
    1170             :                               "SELECT "
    1171             :                               " start_date"
    1172             :                               ",end_date"
    1173             :                               ",wire_fee_val"
    1174             :                               ",wire_fee_frac"
    1175             :                               ",closing_fee_val"
    1176             :                               ",closing_fee_frac"
    1177             :                               ",master_sig"
    1178             :                               " FROM wire_fee"
    1179             :                               " WHERE wire_method=$1"
    1180             :                               "   AND start_date <= $2"
    1181             :                               "   AND end_date > $2;",
    1182             :                               2),
    1183             :       /* Used in #postgres_insert_wire_fee */
    1184          84 :       GNUNET_PQ_make_prepare ("insert_wire_fee",
    1185             :                               "INSERT INTO wire_fee "
    1186             :                               "(wire_method"
    1187             :                               ",start_date"
    1188             :                               ",end_date"
    1189             :                               ",wire_fee_val"
    1190             :                               ",wire_fee_frac"
    1191             :                               ",closing_fee_val"
    1192             :                               ",closing_fee_frac"
    1193             :                               ",master_sig"
    1194             :                               ") VALUES "
    1195             :                               "($1, $2, $3, $4, $5, $6, $7, $8);",
    1196             :                               8),
    1197             :       /* Used in #postgres_store_wire_transfer_out */
    1198          84 :       GNUNET_PQ_make_prepare ("insert_wire_out",
    1199             :                               "INSERT INTO wire_out "
    1200             :                               "(execution_date"
    1201             :                               ",wtid_raw"
    1202             :                               ",wire_target"
    1203             :                               ",exchange_account_section"
    1204             :                               ",amount_val"
    1205             :                               ",amount_frac"
    1206             :                               ") VALUES "
    1207             :                               "($1, $2, $3, $4, $5, $6);",
    1208             :                               6),
    1209             :       /* Used in #postgres_wire_prepare_data_insert() to store
    1210             :          wire transfer information before actually committing it with the bank */
    1211          84 :       GNUNET_PQ_make_prepare ("wire_prepare_data_insert",
    1212             :                               "INSERT INTO prewire "
    1213             :                               "(type"
    1214             :                               ",buf"
    1215             :                               ") VALUES "
    1216             :                               "($1, $2);",
    1217             :                               2),
    1218             :       /* Used in #postgres_wire_prepare_data_mark_finished() */
    1219          84 :       GNUNET_PQ_make_prepare ("wire_prepare_data_mark_done",
    1220             :                               "UPDATE prewire"
    1221             :                               " SET finished=TRUE"
    1222             :                               " WHERE prewire_uuid=$1;",
    1223             :                               1),
    1224             :       /* Used in #postgres_wire_prepare_data_mark_failed() */
    1225          84 :       GNUNET_PQ_make_prepare ("wire_prepare_data_mark_failed",
    1226             :                               "UPDATE prewire"
    1227             :                               " SET failed=TRUE"
    1228             :                               " WHERE prewire_uuid=$1;",
    1229             :                               1),
    1230             :       /* Used in #postgres_wire_prepare_data_get() */
    1231          84 :       GNUNET_PQ_make_prepare ("wire_prepare_data_get",
    1232             :                               "SELECT"
    1233             :                               " prewire_uuid"
    1234             :                               ",type"
    1235             :                               ",buf"
    1236             :                               " FROM prewire"
    1237             :                               " WHERE finished=FALSE"
    1238             :                               "   AND failed=FALSE"
    1239             :                               " ORDER BY prewire_uuid ASC"
    1240             :                               " LIMIT 1;",
    1241             :                               0),
    1242             :       /* Used in #postgres_select_deposits_missing_wire */
    1243          84 :       GNUNET_PQ_make_prepare ("deposits_get_overdue",
    1244             :                               "SELECT"
    1245             :                               " deposit_serial_id"
    1246             :                               ",coin_pub"
    1247             :                               ",amount_with_fee_val"
    1248             :                               ",amount_with_fee_frac"
    1249             :                               ",wire"
    1250             :                               ",wire_deadline"
    1251             :                               ",tiny"
    1252             :                               ",done"
    1253             :                               " FROM deposits d"
    1254             :                               " JOIN known_coins USING (known_coin_id)"
    1255             :                               " WHERE wire_deadline >= $1"
    1256             :                               " AND wire_deadline < $2"
    1257             :                               " AND NOT (EXISTS (SELECT 1"
    1258             :                               "            FROM refunds"
    1259             :                               "            JOIN deposits dx USING (deposit_serial_id)"
    1260             :                               "            WHERE (dx.known_coin_id = d.known_coin_id))"
    1261             :                               "       OR EXISTS (SELECT 1"
    1262             :                               "            FROM aggregation_tracking"
    1263             :                               "            WHERE (aggregation_tracking.deposit_serial_id = d.deposit_serial_id)))"
    1264             :                               " ORDER BY wire_deadline ASC",
    1265             :                               2),
    1266             :       /* Used in #postgres_select_wire_out_above_serial_id() */
    1267          84 :       GNUNET_PQ_make_prepare ("audit_get_wire_incr",
    1268             :                               "SELECT"
    1269             :                               " wireout_uuid"
    1270             :                               ",execution_date"
    1271             :                               ",wtid_raw"
    1272             :                               ",wire_target"
    1273             :                               ",amount_val"
    1274             :                               ",amount_frac"
    1275             :                               " FROM wire_out"
    1276             :                               " WHERE wireout_uuid>=$1"
    1277             :                               " ORDER BY wireout_uuid ASC;",
    1278             :                               1),
    1279             :       /* Used in #postgres_select_wire_out_above_serial_id_by_account() */
    1280          84 :       GNUNET_PQ_make_prepare ("audit_get_wire_incr_by_account",
    1281             :                               "SELECT"
    1282             :                               " wireout_uuid"
    1283             :                               ",execution_date"
    1284             :                               ",wtid_raw"
    1285             :                               ",wire_target"
    1286             :                               ",amount_val"
    1287             :                               ",amount_frac"
    1288             :                               " FROM wire_out"
    1289             :                               " WHERE wireout_uuid>=$1 AND exchange_account_section=$2"
    1290             :                               " ORDER BY wireout_uuid ASC;",
    1291             :                               2),
    1292             :       /* Used in #postgres_insert_recoup_request() to store recoup
    1293             :          information */
    1294          84 :       GNUNET_PQ_make_prepare ("recoup_insert",
    1295             :                               "WITH rx AS"
    1296             :                               " (SELECT reserve_out_serial_id"
    1297             :                               "    FROM reserves_out"
    1298             :                               "   WHERE h_blind_ev=$7)"
    1299             :                               "INSERT INTO recoup "
    1300             :                               "(known_coin_id"
    1301             :                               ",coin_sig"
    1302             :                               ",coin_blind"
    1303             :                               ",amount_val"
    1304             :                               ",amount_frac"
    1305             :                               ",timestamp"
    1306             :                               ",reserve_out_serial_id"
    1307             :                               ") SELECT known_coin_id, $2, $3, $4, $5, $6, rx.reserve_out_serial_id"
    1308             :                               "    FROM known_coins"
    1309             :                               "   CROSS JOIN rx"
    1310             :                               "   WHERE coin_pub=$1;",
    1311             :                               7),
    1312             :       /* Used in #postgres_insert_recoup_refresh_request() to store recoup-refresh
    1313             :          information */
    1314          84 :       GNUNET_PQ_make_prepare ("recoup_refresh_insert",
    1315             :                               "WITH rrx AS"
    1316             :                               " (SELECT rrc_serial"
    1317             :                               "    FROM refresh_revealed_coins"
    1318             :                               "   WHERE h_coin_ev=$7)"
    1319             :                               "INSERT INTO recoup_refresh "
    1320             :                               "(known_coin_id"
    1321             :                               ",coin_sig"
    1322             :                               ",coin_blind"
    1323             :                               ",amount_val"
    1324             :                               ",amount_frac"
    1325             :                               ",timestamp"
    1326             :                               ",rrc_serial"
    1327             :                               ") SELECT known_coin_id, $2, $3, $4, $5, $6, rrx.rrc_serial"
    1328             :                               "    FROM known_coins"
    1329             :                               "   CROSS JOIN rrx"
    1330             :                               "   WHERE coin_pub=$1;",
    1331             :                               7),
    1332             :       /* Used in #postgres_select_recoup_above_serial_id() to obtain recoup transactions */
    1333          84 :       GNUNET_PQ_make_prepare ("recoup_get_incr",
    1334             :                               "SELECT"
    1335             :                               " recoup_uuid"
    1336             :                               ",timestamp"
    1337             :                               ",reserves.reserve_pub"
    1338             :                               ",coins.coin_pub"
    1339             :                               ",coin_sig"
    1340             :                               ",coin_blind"
    1341             :                               ",ro.h_blind_ev"
    1342             :                               ",denoms.denom_pub_hash"
    1343             :                               ",coins.denom_sig"
    1344             :                               ",denoms.denom_pub"
    1345             :                               ",amount_val"
    1346             :                               ",amount_frac"
    1347             :                               " FROM recoup"
    1348             :                               "    JOIN known_coins coins"
    1349             :                               "      USING (known_coin_id)"
    1350             :                               "    JOIN reserves_out ro"
    1351             :                               "      USING (reserve_out_serial_id)"
    1352             :                               "    JOIN reserves"
    1353             :                               "      USING (reserve_uuid)"
    1354             :                               "    JOIN denominations denoms"
    1355             :                               "      ON (coins.denominations_serial = denoms.denominations_serial)"
    1356             :                               " WHERE recoup_uuid>=$1"
    1357             :                               " ORDER BY recoup_uuid ASC;",
    1358             :                               1),
    1359             :       /* Used in #postgres_select_recoup_refresh_above_serial_id() to obtain
    1360             :          recoup-refresh transactions */
    1361          84 :       GNUNET_PQ_make_prepare ("recoup_refresh_get_incr",
    1362             :                               "SELECT"
    1363             :                               " recoup_refresh_uuid"
    1364             :                               ",timestamp"
    1365             :                               ",old_coins.coin_pub AS old_coin_pub"
    1366             :                               ",old_denoms.denom_pub_hash AS old_denom_pub_hash"
    1367             :                               ",new_coins.coin_pub As coin_pub"
    1368             :                               ",coin_sig"
    1369             :                               ",coin_blind"
    1370             :                               ",new_denoms.denom_pub AS denom_pub"
    1371             :                               ",rrc.h_coin_ev AS h_blind_ev"
    1372             :                               ",new_denoms.denom_pub_hash"
    1373             :                               ",new_coins.denom_sig AS denom_sig"
    1374             :                               ",amount_val"
    1375             :                               ",amount_frac"
    1376             :                               " FROM recoup_refresh"
    1377             :                               "    INNER JOIN refresh_revealed_coins rrc"
    1378             :                               "      USING (rrc_serial)"
    1379             :                               "    INNER JOIN refresh_commitments rfc"
    1380             :                               "      ON (rrc.melt_serial_id = rfc.melt_serial_id)"
    1381             :                               "    INNER JOIN known_coins old_coins"
    1382             :                               "      ON (rfc.old_known_coin_id = old_coins.known_coin_id)"
    1383             :                               "    INNER JOIN known_coins new_coins"
    1384             :                               "      ON (new_coins.known_coin_id = recoup_refresh.known_coin_id)"
    1385             :                               "    INNER JOIN denominations new_denoms"
    1386             :                               "      ON (new_coins.denominations_serial = new_denoms.denominations_serial)"
    1387             :                               "    INNER JOIN denominations old_denoms"
    1388             :                               "      ON (old_coins.denominations_serial = old_denoms.denominations_serial)"
    1389             :                               " WHERE recoup_refresh_uuid>=$1"
    1390             :                               " ORDER BY recoup_refresh_uuid ASC;",
    1391             :                               1),
    1392             :       /* Used in #postgres_select_reserve_closed_above_serial_id() to
    1393             :          obtain information about closed reserves */
    1394          84 :       GNUNET_PQ_make_prepare ("reserves_close_get_incr",
    1395             :                               "SELECT"
    1396             :                               " close_uuid"
    1397             :                               ",reserves.reserve_pub"
    1398             :                               ",execution_date"
    1399             :                               ",wtid"
    1400             :                               ",receiver_account"
    1401             :                               ",amount_val"
    1402             :                               ",amount_frac"
    1403             :                               ",closing_fee_val"
    1404             :                               ",closing_fee_frac"
    1405             :                               " FROM reserves_close"
    1406             :                               " JOIN reserves"
    1407             :                               "   USING (reserve_uuid)"
    1408             :                               " WHERE close_uuid>=$1"
    1409             :                               " ORDER BY close_uuid ASC;",
    1410             :                               1),
    1411             :       /* Used in #postgres_get_reserve_history() to obtain recoup transactions
    1412             :          for a reserve */
    1413          84 :       GNUNET_PQ_make_prepare ("recoup_by_reserve",
    1414             :                               "SELECT"
    1415             :                               " coins.coin_pub"
    1416             :                               ",coin_sig"
    1417             :                               ",coin_blind"
    1418             :                               ",amount_val"
    1419             :                               ",amount_frac"
    1420             :                               ",timestamp"
    1421             :                               ",denoms.denom_pub_hash"
    1422             :                               ",coins.denom_sig"
    1423             :                               " FROM recoup"
    1424             :                               "    JOIN known_coins coins"
    1425             :                               "      USING (known_coin_id)"
    1426             :                               "    JOIN denominations denoms"
    1427             :                               "      USING (denominations_serial)"
    1428             :                               "    JOIN reserves_out ro"
    1429             :                               "      USING (reserve_out_serial_id)"
    1430             :                               " WHERE ro.reserve_uuid="
    1431             :                               "   (SELECT reserve_uuid"
    1432             :                               "     FROM reserves"
    1433             :                               "    WHERE reserve_pub=$1);",
    1434             :                               1),
    1435             :       /* Used in #postgres_get_coin_transactions() to obtain recoup transactions
    1436             :          affecting old coins of refreshed coins */
    1437          84 :       GNUNET_PQ_make_prepare ("recoup_by_old_coin",
    1438             :                               "SELECT"
    1439             :                               " coins.coin_pub"
    1440             :                               ",coin_sig"
    1441             :                               ",coin_blind"
    1442             :                               ",amount_val"
    1443             :                               ",amount_frac"
    1444             :                               ",timestamp"
    1445             :                               ",denoms.denom_pub_hash"
    1446             :                               ",coins.denom_sig"
    1447             :                               ",recoup_refresh_uuid"
    1448             :                               " FROM recoup_refresh"
    1449             :                               " JOIN known_coins coins"
    1450             :                               "   USING (known_coin_id)"
    1451             :                               " JOIN denominations denoms"
    1452             :                               "   USING (denominations_serial)"
    1453             :                               " WHERE rrc_serial IN"
    1454             :                               "   (SELECT rrc.rrc_serial"
    1455             :                               "    FROM refresh_commitments"
    1456             :                               "       JOIN refresh_revealed_coins rrc"
    1457             :                               "           USING (melt_serial_id)"
    1458             :                               "    WHERE old_known_coin_id="
    1459             :                               "       (SELECT known_coin_id"
    1460             :                               "          FROM known_coins"
    1461             :                               "         WHERE coin_pub=$1));",
    1462             :                               1),
    1463             :       /* Used in #postgres_get_reserve_history() */
    1464          84 :       GNUNET_PQ_make_prepare ("close_by_reserve",
    1465             :                               "SELECT"
    1466             :                               " amount_val"
    1467             :                               ",amount_frac"
    1468             :                               ",closing_fee_val"
    1469             :                               ",closing_fee_frac"
    1470             :                               ",execution_date"
    1471             :                               ",receiver_account"
    1472             :                               ",wtid"
    1473             :                               " FROM reserves_close"
    1474             :                               " WHERE reserve_uuid="
    1475             :                               "   (SELECT reserve_uuid"
    1476             :                               "     FROM reserves"
    1477             :                               "    WHERE reserve_pub=$1);",
    1478             :                               1),
    1479             :       /* Used in #postgres_get_expired_reserves() */
    1480          84 :       GNUNET_PQ_make_prepare ("get_expired_reserves",
    1481             :                               "SELECT"
    1482             :                               " expiration_date"
    1483             :                               ",account_details"
    1484             :                               ",reserve_pub"
    1485             :                               ",current_balance_val"
    1486             :                               ",current_balance_frac"
    1487             :                               " FROM reserves"
    1488             :                               " WHERE expiration_date<=$1"
    1489             :                               "   AND (current_balance_val != 0 "
    1490             :                               "        OR current_balance_frac != 0)"
    1491             :                               " ORDER BY expiration_date ASC"
    1492             :                               " LIMIT 1;",
    1493             :                               1),
    1494             :       /* Used in #postgres_get_coin_transactions() to obtain recoup transactions
    1495             :          for a coin */
    1496          84 :       GNUNET_PQ_make_prepare ("recoup_by_coin",
    1497             :                               "SELECT"
    1498             :                               " reserves.reserve_pub"
    1499             :                               ",denoms.denom_pub_hash"
    1500             :                               ",coin_sig"
    1501             :                               ",coin_blind"
    1502             :                               ",amount_val"
    1503             :                               ",amount_frac"
    1504             :                               ",timestamp"
    1505             :                               ",recoup_uuid"
    1506             :                               " FROM recoup"
    1507             :                               " JOIN reserves_out ro"
    1508             :                               "   USING (reserve_out_serial_id)"
    1509             :                               " JOIN reserves"
    1510             :                               "   USING (reserve_uuid)"
    1511             :                               " JOIN known_coins coins"
    1512             :                               "   USING (known_coin_id)"
    1513             :                               " JOIN denominations denoms"
    1514             :                               "   ON (denoms.denominations_serial = coins.denominations_serial)"
    1515             :                               " WHERE coins.coin_pub=$1;",
    1516             :                               1),
    1517             :       /* Used in #postgres_get_coin_transactions() to obtain recoup transactions
    1518             :          for a refreshed coin */
    1519          84 :       GNUNET_PQ_make_prepare ("recoup_by_refreshed_coin",
    1520             :                               "SELECT"
    1521             :                               " old_coins.coin_pub AS old_coin_pub"
    1522             :                               ",coin_sig"
    1523             :                               ",coin_blind"
    1524             :                               ",amount_val"
    1525             :                               ",amount_frac"
    1526             :                               ",timestamp"
    1527             :                               ",denoms.denom_pub_hash"
    1528             :                               ",coins.denom_sig"
    1529             :                               ",recoup_refresh_uuid"
    1530             :                               " FROM recoup_refresh"
    1531             :                               "    JOIN refresh_revealed_coins rrc"
    1532             :                               "      USING (rrc_serial)"
    1533             :                               "    JOIN refresh_commitments rfc"
    1534             :                               "      ON (rrc.melt_serial_id = rfc.melt_serial_id)"
    1535             :                               "    JOIN known_coins old_coins"
    1536             :                               "      ON (rfc.old_known_coin_id = old_coins.known_coin_id)"
    1537             :                               "    JOIN known_coins coins"
    1538             :                               "      ON (recoup_refresh.known_coin_id = coins.known_coin_id)"
    1539             :                               "    JOIN denominations denoms"
    1540             :                               "      ON (denoms.denominations_serial = coins.denominations_serial)"
    1541             :                               " WHERE coins.coin_pub=$1;",
    1542             :                               1),
    1543             :       /* Used in #postgres_get_reserve_by_h_blind() */
    1544          84 :       GNUNET_PQ_make_prepare ("reserve_by_h_blind",
    1545             :                               "SELECT"
    1546             :                               " reserves.reserve_pub"
    1547             :                               " FROM reserves_out"
    1548             :                               " JOIN reserves"
    1549             :                               "   USING (reserve_uuid)"
    1550             :                               " WHERE h_blind_ev=$1"
    1551             :                               " LIMIT 1;",
    1552             :                               1),
    1553             :       /* Used in #postgres_get_old_coin_by_h_blind() */
    1554          84 :       GNUNET_PQ_make_prepare ("old_coin_by_h_blind",
    1555             :                               "SELECT"
    1556             :                               " okc.coin_pub AS old_coin_pub"
    1557             :                               " FROM refresh_revealed_coins rrc"
    1558             :                               " JOIN refresh_commitments rcom USING (melt_serial_id)"
    1559             :                               " JOIN known_coins okc ON (rcom.old_known_coin_id = okc.known_coin_id)"
    1560             :                               " WHERE h_coin_ev=$1"
    1561             :                               " LIMIT 1;",
    1562             :                               1),
    1563             :       /* Used in #postgres_lookup_auditor_timestamp() */
    1564          84 :       GNUNET_PQ_make_prepare ("lookup_auditor_timestamp",
    1565             :                               "SELECT"
    1566             :                               " last_change"
    1567             :                               " FROM auditors"
    1568             :                               " WHERE auditor_pub=$1;",
    1569             :                               1),
    1570             :       /* Used in #postgres_lookup_auditor_status() */
    1571          84 :       GNUNET_PQ_make_prepare ("lookup_auditor_status",
    1572             :                               "SELECT"
    1573             :                               " auditor_url"
    1574             :                               ",is_active"
    1575             :                               " FROM auditors"
    1576             :                               " WHERE auditor_pub=$1;",
    1577             :                               1),
    1578             :       /* Used in #postgres_lookup_wire_timestamp() */
    1579          84 :       GNUNET_PQ_make_prepare ("lookup_wire_timestamp",
    1580             :                               "SELECT"
    1581             :                               " last_change"
    1582             :                               " FROM wire_accounts"
    1583             :                               " WHERE payto_uri=$1;",
    1584             :                               1),
    1585             :       /* used in #postgres_insert_auditor() */
    1586          84 :       GNUNET_PQ_make_prepare ("insert_auditor",
    1587             :                               "INSERT INTO auditors "
    1588             :                               "(auditor_pub"
    1589             :                               ",auditor_name"
    1590             :                               ",auditor_url"
    1591             :                               ",is_active"
    1592             :                               ",last_change"
    1593             :                               ") VALUES "
    1594             :                               "($1, $2, $3, true, $4);",
    1595             :                               4),
    1596             :       /* used in #postgres_update_auditor() */
    1597          84 :       GNUNET_PQ_make_prepare ("update_auditor",
    1598             :                               "UPDATE auditors"
    1599             :                               " SET"
    1600             :                               "  auditor_url=$2"
    1601             :                               " ,auditor_name=$3"
    1602             :                               " ,is_active=$4"
    1603             :                               " ,last_change=$5"
    1604             :                               " WHERE auditor_pub=$1",
    1605             :                               5),
    1606             :       /* used in #postgres_insert_wire() */
    1607          84 :       GNUNET_PQ_make_prepare ("insert_wire",
    1608             :                               "INSERT INTO wire_accounts "
    1609             :                               "(payto_uri"
    1610             :                               ",master_sig"
    1611             :                               ",is_active"
    1612             :                               ",last_change"
    1613             :                               ") VALUES "
    1614             :                               "($1, $2, true, $3);",
    1615             :                               3),
    1616             :       /* used in #postgres_update_wire() */
    1617          84 :       GNUNET_PQ_make_prepare ("update_wire",
    1618             :                               "UPDATE wire_accounts"
    1619             :                               " SET"
    1620             :                               "  is_active=$2"
    1621             :                               " ,last_change=$3"
    1622             :                               " WHERE payto_uri=$1",
    1623             :                               3),
    1624             :       /* used in #postgres_update_wire() */
    1625          84 :       GNUNET_PQ_make_prepare ("get_wire_accounts",
    1626             :                               "SELECT"
    1627             :                               " payto_uri"
    1628             :                               ",master_sig"
    1629             :                               " FROM wire_accounts"
    1630             :                               " WHERE is_active",
    1631             :                               0),
    1632             :       /* used in #postgres_update_wire() */
    1633          84 :       GNUNET_PQ_make_prepare ("get_wire_fees",
    1634             :                               "SELECT"
    1635             :                               " wire_fee_val"
    1636             :                               ",wire_fee_frac"
    1637             :                               ",closing_fee_val"
    1638             :                               ",closing_fee_frac"
    1639             :                               ",start_date"
    1640             :                               ",end_date"
    1641             :                               ",master_sig"
    1642             :                               " FROM wire_fee"
    1643             :                               " WHERE wire_method=$1",
    1644             :                               1),
    1645             :       /* used in #postgres_insert_signkey_revocation() */
    1646          84 :       GNUNET_PQ_make_prepare ("insert_signkey_revocation",
    1647             :                               "INSERT INTO signkey_revocations "
    1648             :                               "(esk_serial"
    1649             :                               ",master_sig"
    1650             :                               ") SELECT esk_serial, $2 "
    1651             :                               "    FROM exchange_sign_keys"
    1652             :                               "   WHERE exchange_pub=$1;",
    1653             :                               2),
    1654             :       /* used in #postgres_insert_signkey_revocation() */
    1655          84 :       GNUNET_PQ_make_prepare ("lookup_signkey_revocation",
    1656             :                               "SELECT "
    1657             :                               " master_sig"
    1658             :                               " FROM signkey_revocations"
    1659             :                               " WHERE esk_serial="
    1660             :                               "   (SELECT esk_serial"
    1661             :                               "      FROM exchange_sign_keys"
    1662             :                               "     WHERE exchange_pub=$1);",
    1663             :                               1),
    1664             :       /* used in #postgres_insert_signkey() */
    1665          84 :       GNUNET_PQ_make_prepare ("insert_signkey",
    1666             :                               "INSERT INTO exchange_sign_keys "
    1667             :                               "(exchange_pub"
    1668             :                               ",valid_from"
    1669             :                               ",expire_sign"
    1670             :                               ",expire_legal"
    1671             :                               ",master_sig"
    1672             :                               ") VALUES "
    1673             :                               "($1, $2, $3, $4, $5);",
    1674             :                               5),
    1675             :       /* used in #postgres_lookup_signing_key() */
    1676          84 :       GNUNET_PQ_make_prepare ("lookup_signing_key",
    1677             :                               "SELECT"
    1678             :                               " valid_from"
    1679             :                               ",expire_sign"
    1680             :                               ",expire_legal"
    1681             :                               " FROM exchange_sign_keys"
    1682             :                               " WHERE exchange_pub=$1",
    1683             :                               1),
    1684             :       /* used in #postgres_lookup_denomination_key() */
    1685          84 :       GNUNET_PQ_make_prepare ("lookup_denomination_key",
    1686             :                               "SELECT"
    1687             :                               " valid_from"
    1688             :                               ",expire_withdraw"
    1689             :                               ",expire_deposit"
    1690             :                               ",expire_legal"
    1691             :                               ",coin_val"
    1692             :                               ",coin_frac"
    1693             :                               ",fee_withdraw_val"
    1694             :                               ",fee_withdraw_frac"
    1695             :                               ",fee_deposit_val"
    1696             :                               ",fee_deposit_frac"
    1697             :                               ",fee_refresh_val"
    1698             :                               ",fee_refresh_frac"
    1699             :                               ",fee_refund_val"
    1700             :                               ",fee_refund_frac"
    1701             :                               " FROM denominations"
    1702             :                               " WHERE denom_pub_hash=$1;",
    1703             :                               1),
    1704             :       /* used in #postgres_insert_auditor_denom_sig() */
    1705          84 :       GNUNET_PQ_make_prepare ("insert_auditor_denom_sig",
    1706             :                               "WITH ax AS"
    1707             :                               " (SELECT auditor_uuid"
    1708             :                               "    FROM auditors"
    1709             :                               "   WHERE auditor_pub=$1)"
    1710             :                               "INSERT INTO auditor_denom_sigs "
    1711             :                               "(auditor_uuid"
    1712             :                               ",denominations_serial"
    1713             :                               ",auditor_sig"
    1714             :                               ") SELECT ax.auditor_uuid, denominations_serial, $3 "
    1715             :                               "    FROM denominations"
    1716             :                               "   CROSS JOIN ax"
    1717             :                               "   WHERE denom_pub_hash=$2;",
    1718             :                               3),
    1719             :       /* used in #postgres_select_auditor_denom_sig() */
    1720          84 :       GNUNET_PQ_make_prepare ("select_auditor_denom_sig",
    1721             :                               "SELECT"
    1722             :                               " auditor_sig"
    1723             :                               " FROM auditor_denom_sigs"
    1724             :                               " WHERE auditor_uuid="
    1725             :                               "  (SELECT auditor_uuid"
    1726             :                               "    FROM auditors"
    1727             :                               "    WHERE auditor_pub=$1)"
    1728             :                               " AND denominations_serial="
    1729             :                               "  (SELECT denominations_serial"
    1730             :                               "    FROM denominations"
    1731             :                               "    WHERE denom_pub_hash=$2);",
    1732             :                               2),
    1733             :       /* used in #postgres_lookup_wire_fee_by_time() */
    1734          84 :       GNUNET_PQ_make_prepare ("lookup_wire_fee_by_time",
    1735             :                               "SELECT"
    1736             :                               " wire_fee_val"
    1737             :                               ",wire_fee_frac"
    1738             :                               ",closing_fee_val"
    1739             :                               ",closing_fee_frac"
    1740             :                               " FROM wire_fee"
    1741             :                               " WHERE wire_method=$1"
    1742             :                               " AND end_date > $2"
    1743             :                               " AND start_date < $3;",
    1744             :                               1),
    1745             :       /* used in #postgres_commit */
    1746          84 :       GNUNET_PQ_make_prepare ("do_commit",
    1747             :                               "COMMIT",
    1748             :                               0),
    1749             :       /* used in #postgres_lookup_serial_by_table() */
    1750          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_denominations",
    1751             :                               "SELECT"
    1752             :                               " denominations_serial AS serial"
    1753             :                               " FROM denominations"
    1754             :                               " ORDER BY denominations_serial DESC"
    1755             :                               " LIMIT 1;",
    1756             :                               0),
    1757          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_denomination_revocations",
    1758             :                               "SELECT"
    1759             :                               " denom_revocations_serial_id AS serial"
    1760             :                               " FROM denomination_revocations"
    1761             :                               " ORDER BY denom_revocations_serial_id DESC"
    1762             :                               " LIMIT 1;",
    1763             :                               0),
    1764          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_reserves",
    1765             :                               "SELECT"
    1766             :                               " reserve_uuid AS serial"
    1767             :                               " FROM reserves"
    1768             :                               " ORDER BY reserve_uuid DESC"
    1769             :                               " LIMIT 1;",
    1770             :                               0),
    1771          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_reserves_in",
    1772             :                               "SELECT"
    1773             :                               " reserve_in_serial_id AS serial"
    1774             :                               " FROM reserves_in"
    1775             :                               " ORDER BY reserve_in_serial_id DESC"
    1776             :                               " LIMIT 1;",
    1777             :                               0),
    1778          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_reserves_close",
    1779             :                               "SELECT"
    1780             :                               " close_uuid AS serial"
    1781             :                               " FROM reserves_close"
    1782             :                               " ORDER BY close_uuid DESC"
    1783             :                               " LIMIT 1;",
    1784             :                               0),
    1785          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_reserves_out",
    1786             :                               "SELECT"
    1787             :                               " reserve_out_serial_id AS serial"
    1788             :                               " FROM reserves_out"
    1789             :                               " ORDER BY reserve_out_serial_id DESC"
    1790             :                               " LIMIT 1;",
    1791             :                               0),
    1792          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_auditors",
    1793             :                               "SELECT"
    1794             :                               " auditor_uuid AS serial"
    1795             :                               " FROM auditors"
    1796             :                               " ORDER BY auditor_uuid DESC"
    1797             :                               " LIMIT 1;",
    1798             :                               0),
    1799          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_auditor_denom_sigs",
    1800             :                               "SELECT"
    1801             :                               " auditor_denom_serial AS serial"
    1802             :                               " FROM auditor_denom_sigs"
    1803             :                               " ORDER BY auditor_denom_serial DESC"
    1804             :                               " LIMIT 1;",
    1805             :                               0),
    1806          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_exchange_sign_keys",
    1807             :                               "SELECT"
    1808             :                               " esk_serial AS serial"
    1809             :                               " FROM exchange_sign_keys"
    1810             :                               " ORDER BY esk_serial DESC"
    1811             :                               " LIMIT 1;",
    1812             :                               0),
    1813          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_signkey_revocations",
    1814             :                               "SELECT"
    1815             :                               " signkey_revocations_serial_id AS serial"
    1816             :                               " FROM signkey_revocations"
    1817             :                               " ORDER BY signkey_revocations_serial_id DESC"
    1818             :                               " LIMIT 1;",
    1819             :                               0),
    1820          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_known_coins",
    1821             :                               "SELECT"
    1822             :                               " known_coin_id AS serial"
    1823             :                               " FROM known_coins"
    1824             :                               " ORDER BY known_coin_id DESC"
    1825             :                               " LIMIT 1;",
    1826             :                               0),
    1827          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_refresh_commitments",
    1828             :                               "SELECT"
    1829             :                               " melt_serial_id AS serial"
    1830             :                               " FROM refresh_commitments"
    1831             :                               " ORDER BY melt_serial_id DESC"
    1832             :                               " LIMIT 1;",
    1833             :                               0),
    1834          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_refresh_revealed_coins",
    1835             :                               "SELECT"
    1836             :                               " rrc_serial AS serial"
    1837             :                               " FROM refresh_revealed_coins"
    1838             :                               " ORDER BY rrc_serial DESC"
    1839             :                               " LIMIT 1;",
    1840             :                               0),
    1841          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_refresh_transfer_keys",
    1842             :                               "SELECT"
    1843             :                               " rtc_serial AS serial"
    1844             :                               " FROM refresh_transfer_keys"
    1845             :                               " ORDER BY rtc_serial DESC"
    1846             :                               " LIMIT 1;",
    1847             :                               0),
    1848          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_deposits",
    1849             :                               "SELECT"
    1850             :                               " deposit_serial_id AS serial"
    1851             :                               " FROM deposits"
    1852             :                               " ORDER BY deposit_serial_id DESC"
    1853             :                               " LIMIT 1;",
    1854             :                               0),
    1855          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_refunds",
    1856             :                               "SELECT"
    1857             :                               " refund_serial_id AS serial"
    1858             :                               " FROM refunds"
    1859             :                               " ORDER BY refund_serial_id DESC"
    1860             :                               " LIMIT 1;",
    1861             :                               0),
    1862          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_wire_out",
    1863             :                               "SELECT"
    1864             :                               " wireout_uuid AS serial"
    1865             :                               " FROM wire_out"
    1866             :                               " ORDER BY wireout_uuid DESC"
    1867             :                               " LIMIT 1;",
    1868             :                               0),
    1869          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_aggregation_tracking",
    1870             :                               "SELECT"
    1871             :                               " aggregation_serial_id AS serial"
    1872             :                               " FROM aggregation_tracking"
    1873             :                               " ORDER BY aggregation_serial_id DESC"
    1874             :                               " LIMIT 1;",
    1875             :                               0),
    1876          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_wire_fee",
    1877             :                               "SELECT"
    1878             :                               " wire_fee_serial AS serial"
    1879             :                               " FROM wire_fee"
    1880             :                               " ORDER BY wire_fee_serial DESC"
    1881             :                               " LIMIT 1;",
    1882             :                               0),
    1883          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_recoup",
    1884             :                               "SELECT"
    1885             :                               " recoup_uuid AS serial"
    1886             :                               " FROM recoup"
    1887             :                               " ORDER BY recoup_uuid DESC"
    1888             :                               " LIMIT 1;",
    1889             :                               0),
    1890          84 :       GNUNET_PQ_make_prepare ("select_serial_by_table_recoup_refresh",
    1891             :                               "SELECT"
    1892             :                               " recoup_refresh_uuid AS serial"
    1893             :                               " FROM recoup_refresh"
    1894             :                               " ORDER BY recoup_refresh_uuid DESC"
    1895             :                               " LIMIT 1;",
    1896             :                               0),
    1897             :       /* For postgres_lookup_records_by_table */
    1898          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_denominations",
    1899             :                               "SELECT"
    1900             :                               " denominations_serial AS serial"
    1901             :                               ",denom_pub"
    1902             :                               ",master_sig"
    1903             :                               ",valid_from"
    1904             :                               ",expire_withdraw"
    1905             :                               ",expire_deposit"
    1906             :                               ",expire_legal"
    1907             :                               ",coin_val"
    1908             :                               ",coin_frac"
    1909             :                               ",fee_withdraw_val"
    1910             :                               ",fee_withdraw_frac"
    1911             :                               ",fee_deposit_val"
    1912             :                               ",fee_deposit_frac"
    1913             :                               ",fee_refresh_val"
    1914             :                               ",fee_refresh_frac"
    1915             :                               ",fee_refund_val"
    1916             :                               ",fee_refund_frac"
    1917             :                               " FROM denominations"
    1918             :                               " WHERE denominations_serial > $1"
    1919             :                               " ORDER BY denominations_serial ASC;",
    1920             :                               1),
    1921          84 :       GNUNET_PQ_make_prepare (
    1922             :         "select_above_serial_by_table_denomination_revocations",
    1923             :         "SELECT"
    1924             :         " denom_revocations_serial_id AS serial"
    1925             :         ",master_sig"
    1926             :         ",denominations_serial"
    1927             :         " FROM denomination_revocations"
    1928             :         " WHERE denom_revocations_serial_id > $1"
    1929             :         " ORDER BY denom_revocations_serial_id ASC;",
    1930             :         1),
    1931          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_reserves",
    1932             :                               "SELECT"
    1933             :                               " reserve_uuid AS serial"
    1934             :                               ",reserve_pub"
    1935             :                               ",account_details"
    1936             :                               ",current_balance_val"
    1937             :                               ",current_balance_frac"
    1938             :                               ",expiration_date"
    1939             :                               ",gc_date"
    1940             :                               " FROM reserves"
    1941             :                               " WHERE reserve_uuid > $1"
    1942             :                               " ORDER BY reserve_uuid ASC;",
    1943             :                               1),
    1944          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_reserves_in",
    1945             :                               "SELECT"
    1946             :                               " reserve_in_serial_id AS serial"
    1947             :                               ",wire_reference"
    1948             :                               ",credit_val"
    1949             :                               ",credit_frac"
    1950             :                               ",sender_account_details"
    1951             :                               ",exchange_account_section"
    1952             :                               ",execution_date"
    1953             :                               ",reserve_uuid"
    1954             :                               " FROM reserves_in"
    1955             :                               " WHERE reserve_in_serial_id > $1"
    1956             :                               " ORDER BY reserve_in_serial_id ASC;",
    1957             :                               1),
    1958          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_reserves_close",
    1959             :                               "SELECT"
    1960             :                               " close_uuid AS serial"
    1961             :                               ",execution_date"
    1962             :                               ",wtid"
    1963             :                               ",receiver_account"
    1964             :                               ",amount_val"
    1965             :                               ",amount_frac"
    1966             :                               ",closing_fee_val"
    1967             :                               ",closing_fee_frac"
    1968             :                               ",reserve_uuid"
    1969             :                               " FROM reserves_close"
    1970             :                               " WHERE close_uuid > $1"
    1971             :                               " ORDER BY close_uuid ASC;",
    1972             :                               1),
    1973          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_reserves_out",
    1974             :                               "SELECT"
    1975             :                               " reserve_out_serial_id AS serial"
    1976             :                               ",h_blind_ev"
    1977             :                               ",denom_sig"
    1978             :                               ",reserve_sig"
    1979             :                               ",execution_date"
    1980             :                               ",amount_with_fee_val"
    1981             :                               ",amount_with_fee_frac"
    1982             :                               ",reserve_uuid"
    1983             :                               ",denominations_serial"
    1984             :                               " FROM reserves_out"
    1985             :                               " WHERE reserve_out_serial_id > $1"
    1986             :                               " ORDER BY reserve_out_serial_id ASC;",
    1987             :                               1),
    1988          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_auditors",
    1989             :                               "SELECT"
    1990             :                               " auditor_uuid AS serial"
    1991             :                               ",auditor_pub"
    1992             :                               ",auditor_name"
    1993             :                               ",auditor_url"
    1994             :                               ",is_active"
    1995             :                               ",last_change"
    1996             :                               " FROM auditors"
    1997             :                               " WHERE auditor_uuid > $1"
    1998             :                               " ORDER BY auditor_uuid ASC;",
    1999             :                               1),
    2000          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_auditor_denom_sigs",
    2001             :                               "SELECT"
    2002             :                               " auditor_denom_serial AS serial"
    2003             :                               ",auditor_uuid"
    2004             :                               ",denominations_serial"
    2005             :                               ",auditor_sig"
    2006             :                               " FROM auditor_denom_sigs"
    2007             :                               " WHERE auditor_denom_serial > $1"
    2008             :                               " ORDER BY auditor_denom_serial ASC;",
    2009             :                               1),
    2010          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_exchange_sign_keys",
    2011             :                               "SELECT"
    2012             :                               " esk_serial AS serial"
    2013             :                               ",exchange_pub"
    2014             :                               ",master_sig"
    2015             :                               ",valid_from"
    2016             :                               ",expire_sign"
    2017             :                               ",expire_legal"
    2018             :                               " FROM exchange_sign_keys"
    2019             :                               " WHERE esk_serial > $1"
    2020             :                               " ORDER BY esk_serial ASC;",
    2021             :                               1),
    2022          84 :       GNUNET_PQ_make_prepare (
    2023             :         "select_above_serial_by_table_signkey_revocations",
    2024             :         "SELECT"
    2025             :         " signkey_revocations_serial_id AS serial"
    2026             :         ",esk_serial"
    2027             :         ",master_sig"
    2028             :         " FROM signkey_revocations"
    2029             :         " WHERE signkey_revocations_serial_id > $1"
    2030             :         " ORDER BY signkey_revocations_serial_id ASC;",
    2031             :         1),
    2032          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_known_coins",
    2033             :                               "SELECT"
    2034             :                               " known_coin_id AS serial"
    2035             :                               ",coin_pub"
    2036             :                               ",denom_sig"
    2037             :                               ",denominations_serial"
    2038             :                               " FROM known_coins"
    2039             :                               " WHERE known_coin_id > $1"
    2040             :                               " ORDER BY known_coin_id ASC;",
    2041             :                               1),
    2042          84 :       GNUNET_PQ_make_prepare (
    2043             :         "select_above_serial_by_table_refresh_commitments",
    2044             :         "SELECT"
    2045             :         " melt_serial_id AS serial"
    2046             :         ",rc"
    2047             :         ",old_known_coin_id"
    2048             :         ",old_coin_sig"
    2049             :         ",amount_with_fee_val"
    2050             :         ",amount_with_fee_frac"
    2051             :         ",noreveal_index"
    2052             :         " FROM refresh_commitments"
    2053             :         " WHERE melt_serial_id > $1"
    2054             :         " ORDER BY melt_serial_id ASC;",
    2055             :         1),
    2056          84 :       GNUNET_PQ_make_prepare (
    2057             :         "select_above_serial_by_table_refresh_revealed_coins",
    2058             :         "SELECT"
    2059             :         " rrc_serial AS serial"
    2060             :         ",freshcoin_index"
    2061             :         ",link_sig"
    2062             :         ",coin_ev"
    2063             :         ",h_coin_ev"
    2064             :         ",ev_sig"
    2065             :         ",melt_serial_id"
    2066             :         ",denominations_serial"
    2067             :         " FROM refresh_revealed_coins"
    2068             :         " WHERE rrc_serial > $1"
    2069             :         " ORDER BY rrc_serial ASC;",
    2070             :         1),
    2071          84 :       GNUNET_PQ_make_prepare (
    2072             :         "select_above_serial_by_table_refresh_transfer_keys",
    2073             :         "SELECT"
    2074             :         " rtc_serial AS serial"
    2075             :         ",transfer_pub"
    2076             :         ",transfer_privs"
    2077             :         ",melt_serial_id"
    2078             :         " FROM refresh_transfer_keys"
    2079             :         " WHERE rtc_serial > $1"
    2080             :         " ORDER BY rtc_serial ASC;",
    2081             :         1),
    2082          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_deposits",
    2083             :                               "SELECT"
    2084             :                               " deposit_serial_id AS serial"
    2085             :                               ",amount_with_fee_val"
    2086             :                               ",amount_with_fee_frac"
    2087             :                               ",wallet_timestamp"
    2088             :                               ",exchange_timestamp"
    2089             :                               ",refund_deadline"
    2090             :                               ",wire_deadline"
    2091             :                               ",merchant_pub"
    2092             :                               ",h_contract_terms"
    2093             :                               ",h_wire"
    2094             :                               ",coin_sig"
    2095             :                               ",wire"
    2096             :                               ",tiny"
    2097             :                               ",done"
    2098             :                               ",known_coin_id"
    2099             :                               " FROM deposits"
    2100             :                               " WHERE deposit_serial_id > $1"
    2101             :                               " ORDER BY deposit_serial_id ASC;",
    2102             :                               1),
    2103          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_refunds",
    2104             :                               "SELECT"
    2105             :                               " refund_serial_id AS serial"
    2106             :                               ",merchant_sig"
    2107             :                               ",rtransaction_id"
    2108             :                               ",amount_with_fee_val"
    2109             :                               ",amount_with_fee_frac"
    2110             :                               ",deposit_serial_id"
    2111             :                               " FROM refunds"
    2112             :                               " WHERE refund_serial_id > $1"
    2113             :                               " ORDER BY refund_serial_id ASC;",
    2114             :                               1),
    2115          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_wire_out",
    2116             :                               "SELECT"
    2117             :                               " wireout_uuid AS serial"
    2118             :                               ",execution_date"
    2119             :                               ",wtid_raw"
    2120             :                               ",wire_target"
    2121             :                               ",exchange_account_section"
    2122             :                               ",amount_val"
    2123             :                               ",amount_frac"
    2124             :                               " FROM wire_out"
    2125             :                               " WHERE wireout_uuid > $1"
    2126             :                               " ORDER BY wireout_uuid ASC;",
    2127             :                               1),
    2128          84 :       GNUNET_PQ_make_prepare (
    2129             :         "select_above_serial_by_table_aggregation_tracking",
    2130             :         "SELECT"
    2131             :         " aggregation_serial_id AS serial"
    2132             :         ",deposit_serial_id"
    2133             :         ",wtid_raw"
    2134             :         " FROM aggregation_tracking"
    2135             :         " WHERE aggregation_serial_id > $1"
    2136             :         " ORDER BY aggregation_serial_id ASC;",
    2137             :         1),
    2138          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_wire_fee",
    2139             :                               "SELECT"
    2140             :                               " wire_fee_serial AS serial"
    2141             :                               ",wire_method"
    2142             :                               ",start_date"
    2143             :                               ",end_date"
    2144             :                               ",wire_fee_val"
    2145             :                               ",wire_fee_frac"
    2146             :                               ",closing_fee_val"
    2147             :                               ",closing_fee_frac"
    2148             :                               ",master_sig"
    2149             :                               " FROM wire_fee"
    2150             :                               " WHERE wire_fee_serial > $1"
    2151             :                               " ORDER BY wire_fee_serial ASC;",
    2152             :                               1),
    2153          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_recoup",
    2154             :                               "SELECT"
    2155             :                               " recoup_uuid AS serial"
    2156             :                               ",coin_sig"
    2157             :                               ",coin_blind"
    2158             :                               ",amount_val"
    2159             :                               ",amount_frac"
    2160             :                               ",timestamp"
    2161             :                               ",known_coin_id"
    2162             :                               ",reserve_out_serial_id"
    2163             :                               " FROM recoup"
    2164             :                               " WHERE recoup_uuid > $1"
    2165             :                               " ORDER BY recoup_uuid ASC;",
    2166             :                               1),
    2167          84 :       GNUNET_PQ_make_prepare ("select_above_serial_by_table_recoup_refresh",
    2168             :                               "SELECT"
    2169             :                               " recoup_refresh_uuid AS serial"
    2170             :                               ",coin_sig"
    2171             :                               ",coin_blind"
    2172             :                               ",amount_val"
    2173             :                               ",amount_frac"
    2174             :                               ",timestamp"
    2175             :                               ",known_coin_id"
    2176             :                               ",rrc_serial"
    2177             :                               " FROM recoup_refresh"
    2178             :                               " WHERE recoup_refresh_uuid > $1"
    2179             :                               " ORDER BY recoup_refresh_uuid ASC;",
    2180             :                               1),
    2181             :       /* For postgres_insert_records_by_table */
    2182          84 :       GNUNET_PQ_make_prepare ("insert_into_table_denominations",
    2183             :                               "INSERT INTO denominations"
    2184             :                               "(denominations_serial"
    2185             :                               ",denom_pub_hash"
    2186             :                               ",denom_pub"
    2187             :                               ",master_sig"
    2188             :                               ",valid_from"
    2189             :                               ",expire_withdraw"
    2190             :                               ",expire_deposit"
    2191             :                               ",expire_legal"
    2192             :                               ",coin_val"
    2193             :                               ",coin_frac"
    2194             :                               ",fee_withdraw_val"
    2195             :                               ",fee_withdraw_frac"
    2196             :                               ",fee_deposit_val"
    2197             :                               ",fee_deposit_frac"
    2198             :                               ",fee_refresh_val"
    2199             :                               ",fee_refresh_frac"
    2200             :                               ",fee_refund_val"
    2201             :                               ",fee_refund_frac"
    2202             :                               ") VALUES "
    2203             :                               "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
    2204             :                               " $11, $12, $13, $14, $15, $16, $17, $18);",
    2205             :                               18),
    2206          84 :       GNUNET_PQ_make_prepare ("insert_into_table_denomination_revocations",
    2207             :                               "INSERT INTO denomination_revocations"
    2208             :                               "(denom_revocations_serial_id"
    2209             :                               ",master_sig"
    2210             :                               ",denominations_serial"
    2211             :                               ") VALUES "
    2212             :                               "($1, $2, $3);",
    2213             :                               3),
    2214          84 :       GNUNET_PQ_make_prepare ("insert_into_table_reserves",
    2215             :                               "INSERT INTO reserves"
    2216             :                               "(reserve_uuid"
    2217             :                               ",reserve_pub"
    2218             :                               ",account_details"
    2219             :                               ",current_balance_val"
    2220             :                               ",current_balance_frac"
    2221             :                               ",expiration_date"
    2222             :                               ",gc_date"
    2223             :                               ") VALUES "
    2224             :                               "($1, $2, $3, $4, $5, $6, $7);",
    2225             :                               7),
    2226          84 :       GNUNET_PQ_make_prepare ("insert_into_table_reserves_in",
    2227             :                               "INSERT INTO reserves_in"
    2228             :                               "(reserve_in_serial_id"
    2229             :                               ",wire_reference"
    2230             :                               ",credit_val"
    2231             :                               ",credit_frac"
    2232             :                               ",sender_account_details"
    2233             :                               ",exchange_account_section"
    2234             :                               ",execution_date"
    2235             :                               ",reserve_uuid"
    2236             :                               ") VALUES "
    2237             :                               "($1, $2, $3, $4, $5, $6, $7, $8);",
    2238             :                               8),
    2239          84 :       GNUNET_PQ_make_prepare ("insert_into_table_reserves_close",
    2240             :                               "INSERT INTO reserves_close"
    2241             :                               "(close_uuid"
    2242             :                               ",execution_date"
    2243             :                               ",wtid"
    2244             :                               ",receiver_account"
    2245             :                               ",amount_val"
    2246             :                               ",amount_frac"
    2247             :                               ",closing_fee_val"
    2248             :                               ",closing_fee_frac"
    2249             :                               ",reserve_uuid"
    2250             :                               ") VALUES "
    2251             :                               "($1, $2, $3, $4, $5, $6, $7, $8, $9);",
    2252             :                               9),
    2253          84 :       GNUNET_PQ_make_prepare ("insert_into_table_reserves_out",
    2254             :                               "INSERT INTO reserves_out"
    2255             :                               "(reserve_out_serial_id"
    2256             :                               ",h_blind_ev"
    2257             :                               ",denom_sig"
    2258             :                               ",reserve_sig"
    2259             :                               ",execution_date"
    2260             :                               ",amount_with_fee_val"
    2261             :                               ",amount_with_fee_frac"
    2262             :                               ",reserve_uuid"
    2263             :                               ",denominations_serial"
    2264             :                               ") VALUES "
    2265             :                               "($1, $2, $3, $4, $5, $6, $7, $8, $9);",
    2266             :                               9),
    2267          84 :       GNUNET_PQ_make_prepare ("insert_into_table_auditors",
    2268             :                               "INSERT INTO auditors"
    2269             :                               "(auditor_uuid"
    2270             :                               ",auditor_pub"
    2271             :                               ",auditor_name"
    2272             :                               ",auditor_url"
    2273             :                               ",is_active"
    2274             :                               ",last_change"
    2275             :                               ") VALUES "
    2276             :                               "($1, $2, $3, $4, $5, $6);",
    2277             :                               6),
    2278          84 :       GNUNET_PQ_make_prepare ("insert_into_table_auditor_denom_sigs",
    2279             :                               "INSERT INTO auditor_denom_sigs"
    2280             :                               "(auditor_denom_serial"
    2281             :                               ",auditor_uuid"
    2282             :                               ",denominations_serial"
    2283             :                               ",auditor_sig"
    2284             :                               ") VALUES "
    2285             :                               "($1, $2, $3, $4);",
    2286             :                               4),
    2287          84 :       GNUNET_PQ_make_prepare ("insert_into_table_exchange_sign_keys",
    2288             :                               "INSERT INTO exchange_sign_keys"
    2289             :                               "(esk_serial"
    2290             :                               ",exchange_pub"
    2291             :                               ",master_sig"
    2292             :                               ",valid_from"
    2293             :                               ",expire_sign"
    2294             :                               ",expire_legal"
    2295             :                               ") VALUES "
    2296             :                               "($1, $2, $3, $4, $5, $6);",
    2297             :                               6),
    2298          84 :       GNUNET_PQ_make_prepare ("insert_into_table_signkey_revocations",
    2299             :                               "INSERT INTO signkey_revocations"
    2300             :                               "(signkey_revocations_serial_id"
    2301             :                               ",esk_serial"
    2302             :                               ",master_sig"
    2303             :                               ") VALUES "
    2304             :                               "($1, $2, $3);",
    2305             :                               3),
    2306          84 :       GNUNET_PQ_make_prepare ("insert_into_table_known_coins",
    2307             :                               "INSERT INTO known_coins"
    2308             :                               "(known_coin_id"
    2309             :                               ",coin_pub"
    2310             :                               ",denom_sig"
    2311             :                               ",denominations_serial"
    2312             :                               ") VALUES "
    2313             :                               "($1, $2, $3, $4);",
    2314             :                               4),
    2315          84 :       GNUNET_PQ_make_prepare ("insert_into_table_refresh_commitments",
    2316             :                               "INSERT INTO refresh_commitments"
    2317             :                               "(melt_serial_id"
    2318             :                               ",rc"
    2319             :                               ",old_coin_sig"
    2320             :                               ",amount_with_fee_val"
    2321             :                               ",amount_with_fee_frac"
    2322             :                               ",noreveal_index"
    2323             :                               ",old_known_coin_id"
    2324             :                               ") VALUES "
    2325             :                               "($1, $2, $3, $4, $5, $6, $7);",
    2326             :                               7),
    2327          84 :       GNUNET_PQ_make_prepare ("insert_into_table_refresh_revealed_coins",
    2328             :                               "INSERT INTO refresh_revealed_coins"
    2329             :                               "(rrc_serial"
    2330             :                               ",freshcoin_index"
    2331             :                               ",link_sig"
    2332             :                               ",coin_ev"
    2333             :                               ",h_coin_ev"
    2334             :                               ",ev_sig"
    2335             :                               ",denominations_serial"
    2336             :                               ",melt_serial_id"
    2337             :                               ") VALUES "
    2338             :                               "($1, $2, $3, $4, $5, $6, $7, $8);",
    2339             :                               8),
    2340          84 :       GNUNET_PQ_make_prepare ("insert_into_table_refresh_transfer_keys",
    2341             :                               "INSERT INTO refresh_transfer_keys"
    2342             :                               "(rtc_serial"
    2343             :                               ",transfer_pub"
    2344             :                               ",transfer_privs"
    2345             :                               ",melt_serial_id"
    2346             :                               ") VALUES "
    2347             :                               "($1, $2, $3, $4);",
    2348             :                               4),
    2349          84 :       GNUNET_PQ_make_prepare ("insert_into_table_deposits",
    2350             :                               "INSERT INTO deposits"
    2351             :                               "(deposit_serial_id"
    2352             :                               ",amount_with_fee_val"
    2353             :                               ",amount_with_fee_frac"
    2354             :                               ",wallet_timestamp"
    2355             :                               ",exchange_timestamp"
    2356             :                               ",refund_deadline"
    2357             :                               ",wire_deadline"
    2358             :                               ",merchant_pub"
    2359             :                               ",h_contract_terms"
    2360             :                               ",h_wire"
    2361             :                               ",coin_sig"
    2362             :                               ",wire"
    2363             :                               ",tiny"
    2364             :                               ",done"
    2365             :                               ",known_coin_id"
    2366             :                               ") VALUES "
    2367             :                               "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
    2368             :                               " $11, $12, $13, $14, $15);",
    2369             :                               15),
    2370          84 :       GNUNET_PQ_make_prepare ("insert_into_table_refunds",
    2371             :                               "INSERT INTO refunds"
    2372             :                               "(refund_serial_id"
    2373             :                               ",merchant_sig"
    2374             :                               ",rtransaction_id"
    2375             :                               ",amount_with_fee_val"
    2376             :                               ",amount_with_fee_frac"
    2377             :                               ",deposit_serial_id"
    2378             :                               ") VALUES "
    2379             :                               "($1, $2, $3, $4, $5, $6);",
    2380             :                               6),
    2381          84 :       GNUNET_PQ_make_prepare ("insert_into_table_wire_out",
    2382             :                               "INSERT INTO wire_out"
    2383             :                               "(wireout_uuid"
    2384             :                               ",execution_date"
    2385             :                               ",wtid_raw"
    2386             :                               ",wire_target"
    2387             :                               ",exchange_account_section"
    2388             :                               ",amount_val"
    2389             :                               ",amount_frac"
    2390             :                               ") VALUES "
    2391             :                               "($1, $2, $3, $4, $5, $6, $7);",
    2392             :                               7),
    2393          84 :       GNUNET_PQ_make_prepare ("insert_into_table_aggregation_tracking",
    2394             :                               "INSERT INTO aggregation_tracking"
    2395             :                               "(aggregation_serial_id"
    2396             :                               ",deposit_serial_id"
    2397             :                               ",wtid_raw"
    2398             :                               ") VALUES "
    2399             :                               "($1, $2, $3);",
    2400             :                               3),
    2401          84 :       GNUNET_PQ_make_prepare ("insert_into_table_wire_fee",
    2402             :                               "INSERT INTO wire_fee"
    2403             :                               "(wire_fee_serial"
    2404             :                               ",wire_method"
    2405             :                               ",start_date"
    2406             :                               ",end_date"
    2407             :                               ",wire_fee_val"
    2408             :                               ",wire_fee_frac"
    2409             :                               ",closing_fee_val"
    2410             :                               ",closing_fee_frac"
    2411             :                               ",master_sig"
    2412             :                               ") VALUES "
    2413             :                               "($1, $2, $3, $4, $5, $6, $7, $8, $9);",
    2414             :                               9),
    2415          84 :       GNUNET_PQ_make_prepare ("insert_into_table_recoup",
    2416             :                               "INSERT INTO recoup"
    2417             :                               "(recoup_uuid"
    2418             :                               ",coin_sig"
    2419             :                               ",coin_blind"
    2420             :                               ",amount_val"
    2421             :                               ",amount_frac"
    2422             :                               ",timestamp"
    2423             :                               ",known_coin_id"
    2424             :                               ",reserve_out_serial_id"
    2425             :                               ") VALUES "
    2426             :                               "($1, $2, $3, $4, $5, $6, $7, $8);",
    2427             :                               8),
    2428          84 :       GNUNET_PQ_make_prepare ("insert_into_table_recoup_refresh",
    2429             :                               "INSERT INTO recoup_refresh"
    2430             :                               "(recoup_refresh_uuid"
    2431             :                               ",coin_sig"
    2432             :                               ",coin_blind"
    2433             :                               ",amount_val"
    2434             :                               ",amount_frac"
    2435             :                               ",timestamp"
    2436             :                               ",known_coin_id"
    2437             :                               ",rrc_serial"
    2438             :                               ") VALUES "
    2439             :                               "($1, $2, $3, $4, $5, $6, $7, $8);",
    2440             :                               8),
    2441             :       GNUNET_PQ_PREPARED_STATEMENT_END
    2442             :     };
    2443             : 
    2444          84 :     db_conn = GNUNET_PQ_connect_with_cfg (pc->cfg,
    2445             :                                           "exchangedb-postgres",
    2446             :                                           NULL,
    2447             :                                           es,
    2448             :                                           ps);
    2449             :   }
    2450          84 :   if (NULL == db_conn)
    2451           0 :     return NULL;
    2452          84 :   session = GNUNET_new (struct TALER_EXCHANGEDB_Session);
    2453          84 :   session->conn = db_conn;
    2454          84 :   if (pthread_equal (pc->main_self,
    2455             :                      pthread_self ()))
    2456             :   {
    2457          46 :     pc->main_session = session;
    2458             :   }
    2459             :   else
    2460             :   {
    2461          38 :     if (0 != pthread_setspecific (pc->db_conn_threadlocal,
    2462             :                                   session))
    2463             :     {
    2464           0 :       GNUNET_break (0);
    2465           0 :       GNUNET_PQ_disconnect (db_conn);
    2466           0 :       GNUNET_free (session);
    2467           0 :       return NULL;
    2468             :     }
    2469             :   }
    2470          84 :   return session;
    2471             : }
    2472             : 
    2473             : 
    2474             : /**
    2475             :  * Do a pre-flight check that we are not in an uncommitted transaction.
    2476             :  * If we are, try to commit the previous transaction and output a warning.
    2477             :  * Does not return anything, as we will continue regardless of the outcome.
    2478             :  *
    2479             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    2480             :  * @param session the database connection
    2481             :  */
    2482             : static void
    2483             : postgres_preflight (void *cls,
    2484             :                     struct TALER_EXCHANGEDB_Session *session);
    2485             : 
    2486             : /**
    2487             :  * Start a transaction.
    2488             :  *
    2489             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    2490             :  * @param session the database connection
    2491             :  * @param name unique name identifying the transaction (for debugging)
    2492             :  *             must point to a constant
    2493             :  * @return #GNUNET_OK on success
    2494             :  */
    2495             : static int
    2496         192 : postgres_start (void *cls,
    2497             :                 struct TALER_EXCHANGEDB_Session *session,
    2498             :                 const char *name)
    2499             : {
    2500         192 :   struct GNUNET_PQ_ExecuteStatement es[] = {
    2501         192 :     GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
    2502             :     GNUNET_PQ_EXECUTE_STATEMENT_END
    2503             :   };
    2504             : 
    2505             :   (void) cls;
    2506         192 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2507             :               "Starting transaction named: %s\n",
    2508             :               name);
    2509         192 :   postgres_preflight (cls,
    2510             :                       session);
    2511         192 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2512             :               "Starting transaction on %p\n",
    2513             :               session->conn);
    2514         192 :   if (GNUNET_OK !=
    2515         192 :       GNUNET_PQ_exec_statements (session->conn,
    2516             :                                  es))
    2517             :   {
    2518           0 :     TALER_LOG_ERROR ("Failed to start transaction\n");
    2519           0 :     GNUNET_break (0);
    2520           0 :     return GNUNET_SYSERR;
    2521             :   }
    2522         192 :   session->transaction_name = name;
    2523         192 :   return GNUNET_OK;
    2524             : }
    2525             : 
    2526             : 
    2527             : /**
    2528             :  * Roll back the current transaction of a database connection.
    2529             :  *
    2530             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    2531             :  * @param session the database connection
    2532             :  */
    2533             : static void
    2534          66 : postgres_rollback (void *cls,
    2535             :                    struct TALER_EXCHANGEDB_Session *session)
    2536             : {
    2537          66 :   struct GNUNET_PQ_ExecuteStatement es[] = {
    2538          66 :     GNUNET_PQ_make_execute ("ROLLBACK"),
    2539             :     GNUNET_PQ_EXECUTE_STATEMENT_END
    2540             :   };
    2541             : 
    2542             :   (void) cls;
    2543          66 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2544             :               "Rolling back transaction on %p\n",
    2545             :               session->conn);
    2546          66 :   GNUNET_break (GNUNET_OK ==
    2547             :                 GNUNET_PQ_exec_statements (session->conn,
    2548             :                                            es));
    2549          66 :   session->transaction_name = NULL;
    2550          66 : }
    2551             : 
    2552             : 
    2553             : /**
    2554             :  * Commit the current transaction of a database connection.
    2555             :  *
    2556             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    2557             :  * @param session the database connection
    2558             :  * @return final transaction status
    2559             :  */
    2560             : static enum GNUNET_DB_QueryStatus
    2561         127 : postgres_commit (void *cls,
    2562             :                  struct TALER_EXCHANGEDB_Session *session)
    2563             : {
    2564         127 :   struct GNUNET_PQ_QueryParam params[] = {
    2565             :     GNUNET_PQ_query_param_end
    2566             :   };
    2567             :   enum GNUNET_DB_QueryStatus qs;
    2568             : 
    2569             :   (void) cls;
    2570         127 :   qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    2571             :                                            "do_commit",
    2572             :                                            params);
    2573         127 :   session->transaction_name = NULL;
    2574         127 :   return qs;
    2575             : }
    2576             : 
    2577             : 
    2578             : /**
    2579             :  * Do a pre-flight check that we are not in an uncommitted transaction.
    2580             :  * If we are, try to commit the previous transaction and output a warning.
    2581             :  * Does not return anything, as we will continue regardless of the outcome.
    2582             :  *
    2583             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    2584             :  * @param session the database connection
    2585             :  */
    2586             : static void
    2587         330 : postgres_preflight (void *cls,
    2588             :                     struct TALER_EXCHANGEDB_Session *session)
    2589             : {
    2590         330 :   struct GNUNET_PQ_ExecuteStatement es[] = {
    2591         330 :     GNUNET_PQ_make_execute ("ROLLBACK"),
    2592             :     GNUNET_PQ_EXECUTE_STATEMENT_END
    2593             :   };
    2594             : 
    2595             :   (void) cls;
    2596         330 :   if (NULL == session)
    2597             :   {
    2598           0 :     GNUNET_break (0);
    2599         330 :     return;
    2600             :   }
    2601         330 :   if (NULL == session->transaction_name)
    2602         330 :     return; /* all good */
    2603           0 :   if (GNUNET_OK ==
    2604           0 :       GNUNET_PQ_exec_statements (session->conn,
    2605             :                                  es))
    2606             :   {
    2607           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2608             :                 "BUG: Preflight check rolled back transaction `%s'!\n",
    2609             :                 session->transaction_name);
    2610             :   }
    2611             :   else
    2612             :   {
    2613           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2614             :                 "BUG: Preflight check failed to rollback transaction `%s'!\n",
    2615             :                 session->transaction_name);
    2616             :   }
    2617           0 :   session->transaction_name = NULL;
    2618             : }
    2619             : 
    2620             : 
    2621             : /**
    2622             :  * Insert a denomination key's public information into the database for
    2623             :  * reference by auditors and other consistency checks.
    2624             :  *
    2625             :  * @param cls the @e cls of this struct with the plugin-specific state
    2626             :  * @param session connection to use
    2627             :  * @param denom_pub the public key used for signing coins of this denomination
    2628             :  * @param issue issuing information with value, fees and other info about the coin
    2629             :  * @return status of the query
    2630             :  */
    2631             : static enum GNUNET_DB_QueryStatus
    2632          32 : postgres_insert_denomination_info (
    2633             :   void *cls,
    2634             :   struct TALER_EXCHANGEDB_Session *session,
    2635             :   const struct TALER_DenominationPublicKey *denom_pub,
    2636             :   const struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue)
    2637             : {
    2638          32 :   struct GNUNET_PQ_QueryParam params[] = {
    2639          32 :     GNUNET_PQ_query_param_auto_from_type (&issue->properties.denom_hash),
    2640          32 :     GNUNET_PQ_query_param_rsa_public_key (denom_pub->rsa_public_key),
    2641          32 :     GNUNET_PQ_query_param_auto_from_type (&issue->signature),
    2642          32 :     TALER_PQ_query_param_absolute_time_nbo (&issue->properties.start),
    2643          32 :     TALER_PQ_query_param_absolute_time_nbo (&issue->properties.expire_withdraw),
    2644          32 :     TALER_PQ_query_param_absolute_time_nbo (&issue->properties.expire_deposit),
    2645          32 :     TALER_PQ_query_param_absolute_time_nbo (&issue->properties.expire_legal),
    2646          32 :     TALER_PQ_query_param_amount_nbo (&issue->properties.value),
    2647          32 :     TALER_PQ_query_param_amount_nbo (&issue->properties.fee_withdraw),
    2648          32 :     TALER_PQ_query_param_amount_nbo (&issue->properties.fee_deposit),
    2649          32 :     TALER_PQ_query_param_amount_nbo (&issue->properties.fee_refresh),
    2650          32 :     TALER_PQ_query_param_amount_nbo (&issue->properties.fee_refund),
    2651             :     GNUNET_PQ_query_param_end
    2652             :   };
    2653             : 
    2654             :   (void) cls;
    2655             :   /* check fees match coin currency */
    2656          32 :   GNUNET_assert (GNUNET_YES ==
    2657             :                  TALER_amount_cmp_currency_nbo (&issue->properties.value,
    2658             :                                                 &issue->properties.fee_withdraw));
    2659          32 :   GNUNET_assert (GNUNET_YES ==
    2660             :                  TALER_amount_cmp_currency_nbo (&issue->properties.value,
    2661             :                                                 &issue->properties.fee_deposit));
    2662          32 :   GNUNET_assert (GNUNET_YES ==
    2663             :                  TALER_amount_cmp_currency_nbo (&issue->properties.value,
    2664             :                                                 &issue->properties.fee_refresh));
    2665          32 :   GNUNET_assert (GNUNET_YES ==
    2666             :                  TALER_amount_cmp_currency_nbo (&issue->properties.value,
    2667             :                                                 &issue->properties.fee_refund));
    2668             : 
    2669          32 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    2670             :                                              "denomination_insert",
    2671             :                                              params);
    2672             : }
    2673             : 
    2674             : 
    2675             : /**
    2676             :  * Fetch information about a denomination key.
    2677             :  *
    2678             :  * @param cls the @e cls of this struct with the plugin-specific state
    2679             :  * @param session connection to use
    2680             :  * @param denom_pub_hash hash of the public key used for signing coins of this denomination
    2681             :  * @param[out] issue set to issue information with value, fees and other info about the coin
    2682             :  * @return transaction status code
    2683             :  */
    2684             : static enum GNUNET_DB_QueryStatus
    2685           9 : postgres_get_denomination_info (
    2686             :   void *cls,
    2687             :   struct TALER_EXCHANGEDB_Session *session,
    2688             :   const struct GNUNET_HashCode *denom_pub_hash,
    2689             :   struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue)
    2690             : {
    2691           9 :   struct PostgresClosure *pg = cls;
    2692             :   enum GNUNET_DB_QueryStatus qs;
    2693           9 :   struct GNUNET_PQ_QueryParam params[] = {
    2694           9 :     GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
    2695             :     GNUNET_PQ_query_param_end
    2696             :   };
    2697           9 :   struct GNUNET_PQ_ResultSpec rs[] = {
    2698           9 :     GNUNET_PQ_result_spec_auto_from_type ("master_sig",
    2699             :                                           &issue->signature),
    2700           9 :     TALER_PQ_result_spec_absolute_time_nbo ("valid_from",
    2701             :                                             &issue->properties.start),
    2702           9 :     TALER_PQ_result_spec_absolute_time_nbo ("expire_withdraw",
    2703             :                                             &issue->properties.expire_withdraw),
    2704           9 :     TALER_PQ_result_spec_absolute_time_nbo ("expire_deposit",
    2705             :                                             &issue->properties.expire_deposit),
    2706           9 :     TALER_PQ_result_spec_absolute_time_nbo ("expire_legal",
    2707             :                                             &issue->properties.expire_legal),
    2708           9 :     TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("coin",
    2709             :                                      &issue->properties.value),
    2710           9 :     TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("fee_withdraw",
    2711             :                                      &issue->properties.fee_withdraw),
    2712           9 :     TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("fee_deposit",
    2713             :                                      &issue->properties.fee_deposit),
    2714           9 :     TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("fee_refresh",
    2715             :                                      &issue->properties.fee_refresh),
    2716           9 :     TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("fee_refund",
    2717             :                                      &issue->properties.fee_refund),
    2718             :     GNUNET_PQ_result_spec_end
    2719             :   };
    2720             : 
    2721           9 :   memset (&issue->properties.master,
    2722             :           0,
    2723             :           sizeof (issue->properties.master));
    2724           9 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    2725             :                                                  "denomination_get",
    2726             :                                                  params,
    2727             :                                                  rs);
    2728           9 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    2729           1 :     return qs;
    2730           8 :   issue->properties.purpose.size = htonl (sizeof (struct
    2731             :                                                   TALER_DenominationKeyValidityPS));
    2732           8 :   issue->properties.purpose.purpose = htonl (
    2733             :     TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
    2734           8 :   issue->properties.denom_hash = *denom_pub_hash;
    2735           8 :   return qs;
    2736             : }
    2737             : 
    2738             : 
    2739             : /**
    2740             :  * Closure for #domination_cb_helper()
    2741             :  */
    2742             : struct DenomIteratorContext
    2743             : {
    2744             :   /**
    2745             :    * Function to call with the results.
    2746             :    */
    2747             :   TALER_EXCHANGEDB_DenominationCallback cb;
    2748             : 
    2749             :   /**
    2750             :    * Closure to pass to @e cb
    2751             :    */
    2752             :   void *cb_cls;
    2753             : 
    2754             :   /**
    2755             :    * Plugin context.
    2756             :    */
    2757             :   struct PostgresClosure *pg;
    2758             : };
    2759             : 
    2760             : 
    2761             : /**
    2762             :  * Helper function for #postgres_iterate_denomination_info().
    2763             :  * Calls the callback with each denomination key.
    2764             :  *
    2765             :  * @param cls a `struct DenomIteratorContext`
    2766             :  * @param result db results
    2767             :  * @param num_results number of results in @a result
    2768             :  */
    2769             : static void
    2770           0 : domination_cb_helper (void *cls,
    2771             :                       PGresult *result,
    2772             :                       unsigned int num_results)
    2773             : {
    2774           0 :   struct DenomIteratorContext *dic = cls;
    2775           0 :   struct PostgresClosure *pg = dic->pg;
    2776             : 
    2777           0 :   for (unsigned int i = 0; i<num_results; i++)
    2778             :   {
    2779             :     struct TALER_EXCHANGEDB_DenominationKeyInformationP issue;
    2780             :     struct TALER_DenominationPublicKey denom_pub;
    2781           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
    2782           0 :       GNUNET_PQ_result_spec_auto_from_type ("master_sig",
    2783             :                                             &issue.signature),
    2784           0 :       TALER_PQ_result_spec_absolute_time_nbo ("valid_from",
    2785             :                                               &issue.properties.start),
    2786           0 :       TALER_PQ_result_spec_absolute_time_nbo ("expire_withdraw",
    2787             :                                               &issue.properties.expire_withdraw),
    2788           0 :       TALER_PQ_result_spec_absolute_time_nbo ("expire_deposit",
    2789             :                                               &issue.properties.expire_deposit),
    2790           0 :       TALER_PQ_result_spec_absolute_time_nbo ("expire_legal",
    2791             :                                               &issue.properties.expire_legal),
    2792           0 :       TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("coin",
    2793             :                                        &issue.properties.value),
    2794           0 :       TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("fee_withdraw",
    2795             :                                        &issue.properties.fee_withdraw),
    2796           0 :       TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("fee_deposit",
    2797             :                                        &issue.properties.fee_deposit),
    2798           0 :       TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("fee_refresh",
    2799             :                                        &issue.properties.fee_refresh),
    2800           0 :       TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("fee_refund",
    2801             :                                        &issue.properties.fee_refund),
    2802           0 :       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    2803             :                                             &denom_pub.rsa_public_key),
    2804             :       GNUNET_PQ_result_spec_end
    2805             :     };
    2806             : 
    2807           0 :     memset (&issue.properties.master,
    2808             :             0,
    2809             :             sizeof (issue.properties.master));
    2810           0 :     if (GNUNET_OK !=
    2811           0 :         GNUNET_PQ_extract_result (result,
    2812             :                                   rs,
    2813             :                                   i))
    2814             :     {
    2815           0 :       GNUNET_break (0);
    2816           0 :       return;
    2817             :     }
    2818             :     issue.properties.purpose.size
    2819           0 :       = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
    2820             :     issue.properties.purpose.purpose
    2821           0 :       = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
    2822           0 :     GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key,
    2823             :                                        &issue.properties.denom_hash);
    2824           0 :     dic->cb (dic->cb_cls,
    2825             :              &denom_pub,
    2826             :              &issue);
    2827           0 :     GNUNET_CRYPTO_rsa_public_key_free (denom_pub.rsa_public_key);
    2828             :   }
    2829             : }
    2830             : 
    2831             : 
    2832             : /**
    2833             :  * Fetch information about all known denomination keys.
    2834             :  *
    2835             :  * @param cls the @e cls of this struct with the plugin-specific state
    2836             :  * @param session connection to use
    2837             :  * @param cb function to call on each denomination key
    2838             :  * @param cb_cls closure for @a cb
    2839             :  * @return transaction status code
    2840             :  */
    2841             : static enum GNUNET_DB_QueryStatus
    2842           0 : postgres_iterate_denomination_info (void *cls,
    2843             :                                     struct TALER_EXCHANGEDB_Session *session,
    2844             :                                     TALER_EXCHANGEDB_DenominationCallback cb,
    2845             :                                     void *cb_cls)
    2846             : {
    2847           0 :   struct PostgresClosure *pc = cls;
    2848           0 :   struct GNUNET_PQ_QueryParam params[] = {
    2849             :     GNUNET_PQ_query_param_end
    2850             :   };
    2851           0 :   struct DenomIteratorContext dic = {
    2852             :     .cb = cb,
    2853             :     .cb_cls = cb_cls,
    2854             :     .pg = pc
    2855             :   };
    2856             : 
    2857           0 :   if (NULL == session)
    2858           0 :     session = postgres_get_session (pc);
    2859           0 :   if (NULL == session)
    2860           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    2861           0 :   return GNUNET_PQ_eval_prepared_multi_select (session->conn,
    2862             :                                                "denomination_iterate",
    2863             :                                                params,
    2864             :                                                &domination_cb_helper,
    2865             :                                                &dic);
    2866             : }
    2867             : 
    2868             : 
    2869             : /**
    2870             :  * Closure for #dominations_cb_helper()
    2871             :  */
    2872             : struct DenomsIteratorContext
    2873             : {
    2874             :   /**
    2875             :    * Function to call with the results.
    2876             :    */
    2877             :   TALER_EXCHANGEDB_DenominationsCallback cb;
    2878             : 
    2879             :   /**
    2880             :    * Closure to pass to @e cb
    2881             :    */
    2882             :   void *cb_cls;
    2883             : 
    2884             :   /**
    2885             :    * Plugin context.
    2886             :    */
    2887             :   struct PostgresClosure *pg;
    2888             : };
    2889             : 
    2890             : 
    2891             : /**
    2892             :  * Helper function for #postgres_iterate_denominations().
    2893             :  * Calls the callback with each denomination key.
    2894             :  *
    2895             :  * @param cls a `struct DenomsIteratorContext`
    2896             :  * @param result db results
    2897             :  * @param num_results number of results in @a result
    2898             :  */
    2899             : static void
    2900           0 : dominations_cb_helper (void *cls,
    2901             :                        PGresult *result,
    2902             :                        unsigned int num_results)
    2903             : {
    2904           0 :   struct DenomsIteratorContext *dic = cls;
    2905           0 :   struct PostgresClosure *pg = dic->pg;
    2906             : 
    2907           0 :   for (unsigned int i = 0; i<num_results; i++)
    2908             :   {
    2909             :     struct TALER_EXCHANGEDB_DenominationKeyMetaData meta;
    2910             :     struct TALER_DenominationPublicKey denom_pub;
    2911             :     struct TALER_MasterSignatureP master_sig;
    2912             :     struct GNUNET_HashCode h_denom_pub;
    2913             :     uint8_t revoked;
    2914           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
    2915           0 :       GNUNET_PQ_result_spec_auto_from_type ("master_sig",
    2916             :                                             &master_sig),
    2917           0 :       GNUNET_PQ_result_spec_auto_from_type ("revoked",
    2918             :                                             &revoked),
    2919           0 :       TALER_PQ_result_spec_absolute_time ("valid_from",
    2920             :                                           &meta.start),
    2921           0 :       TALER_PQ_result_spec_absolute_time ("expire_withdraw",
    2922             :                                           &meta.expire_withdraw),
    2923           0 :       TALER_PQ_result_spec_absolute_time ("expire_deposit",
    2924             :                                           &meta.expire_deposit),
    2925           0 :       TALER_PQ_result_spec_absolute_time ("expire_legal",
    2926             :                                           &meta.expire_legal),
    2927           0 :       TALER_PQ_RESULT_SPEC_AMOUNT ("coin",
    2928             :                                    &meta.value),
    2929           0 :       TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
    2930             :                                    &meta.fee_withdraw),
    2931           0 :       TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
    2932             :                                    &meta.fee_deposit),
    2933           0 :       TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
    2934             :                                    &meta.fee_refresh),
    2935           0 :       TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
    2936             :                                    &meta.fee_refund),
    2937           0 :       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    2938             :                                             &denom_pub.rsa_public_key),
    2939             :       GNUNET_PQ_result_spec_end
    2940             :     };
    2941             : 
    2942           0 :     if (GNUNET_OK !=
    2943           0 :         GNUNET_PQ_extract_result (result,
    2944             :                                   rs,
    2945             :                                   i))
    2946             :     {
    2947           0 :       GNUNET_break (0);
    2948           0 :       return;
    2949             :     }
    2950           0 :     GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key,
    2951             :                                        &h_denom_pub);
    2952           0 :     dic->cb (dic->cb_cls,
    2953             :              &denom_pub,
    2954             :              &h_denom_pub,
    2955             :              &meta,
    2956             :              &master_sig,
    2957             :              (0 != revoked));
    2958           0 :     GNUNET_PQ_cleanup_result (rs);
    2959             :   }
    2960             : }
    2961             : 
    2962             : 
    2963             : /**
    2964             : * Function called to invoke @a cb on every known denomination key (revoked
    2965             : * and non-revoked) that has been signed by the master key. Runs in its own
    2966             : * read-only transaction (hence no session provided).
    2967             : *
    2968             : *
    2969             :  * @param cls the @e cls of this struct with the plugin-specific state
    2970             :  * @param cb function to call on each denomination key
    2971             :  * @param cb_cls closure for @a cb
    2972             :  * @return transaction status code
    2973             :  */
    2974             : static enum GNUNET_DB_QueryStatus
    2975           0 : postgres_iterate_denominations (void *cls,
    2976             :                                 TALER_EXCHANGEDB_DenominationsCallback cb,
    2977             :                                 void *cb_cls)
    2978             : {
    2979           0 :   struct PostgresClosure *pc = cls;
    2980           0 :   struct GNUNET_PQ_QueryParam params[] = {
    2981             :     GNUNET_PQ_query_param_end
    2982             :   };
    2983           0 :   struct DenomsIteratorContext dic = {
    2984             :     .cb = cb,
    2985             :     .cb_cls = cb_cls,
    2986             :     .pg = pc
    2987             :   };
    2988             :   struct TALER_EXCHANGEDB_Session *session;
    2989             : 
    2990           0 :   session = postgres_get_session (pc);
    2991           0 :   if (NULL == session)
    2992           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    2993           0 :   return GNUNET_PQ_eval_prepared_multi_select (session->conn,
    2994             :                                                "select_denominations",
    2995             :                                                params,
    2996             :                                                &dominations_cb_helper,
    2997             :                                                &dic);
    2998             : }
    2999             : 
    3000             : 
    3001             : /**
    3002             :  * Closure for #signkeys_cb_helper()
    3003             :  */
    3004             : struct SignkeysIteratorContext
    3005             : {
    3006             :   /**
    3007             :    * Function to call with the results.
    3008             :    */
    3009             :   TALER_EXCHANGEDB_ActiveSignkeysCallback cb;
    3010             : 
    3011             :   /**
    3012             :    * Closure to pass to @e cb
    3013             :    */
    3014             :   void *cb_cls;
    3015             : 
    3016             : };
    3017             : 
    3018             : 
    3019             : /**
    3020             :  * Helper function for #postgres_iterate_active_signkeys().
    3021             :  * Calls the callback with each signkey.
    3022             :  *
    3023             :  * @param cls a `struct SignkeysIteratorContext`
    3024             :  * @param result db results
    3025             :  * @param num_results number of results in @a result
    3026             :  */
    3027             : static void
    3028           0 : signkeys_cb_helper (void *cls,
    3029             :                     PGresult *result,
    3030             :                     unsigned int num_results)
    3031             : {
    3032           0 :   struct SignkeysIteratorContext *dic = cls;
    3033             : 
    3034           0 :   for (unsigned int i = 0; i<num_results; i++)
    3035             :   {
    3036             :     struct TALER_EXCHANGEDB_SignkeyMetaData meta;
    3037             :     struct TALER_ExchangePublicKeyP exchange_pub;
    3038             :     struct TALER_MasterSignatureP master_sig;
    3039           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
    3040           0 :       GNUNET_PQ_result_spec_auto_from_type ("master_sig",
    3041             :                                             &master_sig),
    3042           0 :       GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
    3043             :                                             &exchange_pub),
    3044           0 :       TALER_PQ_result_spec_absolute_time ("valid_from",
    3045             :                                           &meta.start),
    3046           0 :       TALER_PQ_result_spec_absolute_time ("expire_sign",
    3047             :                                           &meta.expire_sign),
    3048           0 :       TALER_PQ_result_spec_absolute_time ("expire_legal",
    3049             :                                           &meta.expire_legal),
    3050             :       GNUNET_PQ_result_spec_end
    3051             :     };
    3052             : 
    3053           0 :     if (GNUNET_OK !=
    3054           0 :         GNUNET_PQ_extract_result (result,
    3055             :                                   rs,
    3056             :                                   i))
    3057             :     {
    3058           0 :       GNUNET_break (0);
    3059           0 :       return;
    3060             :     }
    3061           0 :     dic->cb (dic->cb_cls,
    3062             :              &exchange_pub,
    3063             :              &meta,
    3064             :              &master_sig);
    3065             :   }
    3066             : }
    3067             : 
    3068             : 
    3069             : /**
    3070             :  * Function called to invoke @a cb on every non-revoked exchange signing key
    3071             :  * that has been signed by the master key.  Revoked and (for signing!)
    3072             :  * expired keys are skipped. Runs in its own read-only transaction (hence no
    3073             :  * session provided).
    3074             :  *
    3075             :  * @param cls the @e cls of this struct with the plugin-specific state
    3076             :  * @param cb function to call on each signing key
    3077             :  * @param cb_cls closure for @a cb
    3078             :  * @return transaction status code
    3079             :  */
    3080             : static enum GNUNET_DB_QueryStatus
    3081           0 : postgres_iterate_active_signkeys (void *cls,
    3082             :                                   TALER_EXCHANGEDB_ActiveSignkeysCallback cb,
    3083             :                                   void *cb_cls)
    3084             : {
    3085           0 :   struct PostgresClosure *pc = cls;
    3086             :   struct GNUNET_TIME_Absolute now;
    3087           0 :   struct GNUNET_PQ_QueryParam params[] = {
    3088           0 :     GNUNET_PQ_query_param_absolute_time (&now),
    3089             :     GNUNET_PQ_query_param_end
    3090             :   };
    3091           0 :   struct SignkeysIteratorContext dic = {
    3092             :     .cb = cb,
    3093             :     .cb_cls = cb_cls,
    3094             :   };
    3095             :   struct TALER_EXCHANGEDB_Session *session;
    3096             : 
    3097           0 :   now = GNUNET_TIME_absolute_get ();
    3098           0 :   session = postgres_get_session (pc);
    3099           0 :   if (NULL == session)
    3100           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    3101           0 :   return GNUNET_PQ_eval_prepared_multi_select (session->conn,
    3102             :                                                "select_signkeys",
    3103             :                                                params,
    3104             :                                                &signkeys_cb_helper,
    3105             :                                                &dic);
    3106             : }
    3107             : 
    3108             : 
    3109             : /**
    3110             :  * Closure for #auditors_cb_helper()
    3111             :  */
    3112             : struct AuditorsIteratorContext
    3113             : {
    3114             :   /**
    3115             :    * Function to call with the results.
    3116             :    */
    3117             :   TALER_EXCHANGEDB_AuditorsCallback cb;
    3118             : 
    3119             :   /**
    3120             :    * Closure to pass to @e cb
    3121             :    */
    3122             :   void *cb_cls;
    3123             : 
    3124             : };
    3125             : 
    3126             : 
    3127             : /**
    3128             :  * Helper function for #postgres_iterate_active_auditors().
    3129             :  * Calls the callback with each auditor.
    3130             :  *
    3131             :  * @param cls a `struct SignkeysIteratorContext`
    3132             :  * @param result db results
    3133             :  * @param num_results number of results in @a result
    3134             :  */
    3135             : static void
    3136           0 : auditors_cb_helper (void *cls,
    3137             :                     PGresult *result,
    3138             :                     unsigned int num_results)
    3139             : {
    3140           0 :   struct AuditorsIteratorContext *dic = cls;
    3141             : 
    3142           0 :   for (unsigned int i = 0; i<num_results; i++)
    3143             :   {
    3144             :     struct TALER_AuditorPublicKeyP auditor_pub;
    3145             :     char *auditor_url;
    3146             :     char *auditor_name;
    3147           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
    3148           0 :       GNUNET_PQ_result_spec_auto_from_type ("auditor_pub",
    3149             :                                             &auditor_pub),
    3150           0 :       GNUNET_PQ_result_spec_string ("auditor_url",
    3151             :                                     &auditor_url),
    3152           0 :       GNUNET_PQ_result_spec_string ("auditor_name",
    3153             :                                     &auditor_name),
    3154             :       GNUNET_PQ_result_spec_end
    3155             :     };
    3156             : 
    3157           0 :     if (GNUNET_OK !=
    3158           0 :         GNUNET_PQ_extract_result (result,
    3159             :                                   rs,
    3160             :                                   i))
    3161             :     {
    3162           0 :       GNUNET_break (0);
    3163           0 :       return;
    3164             :     }
    3165           0 :     dic->cb (dic->cb_cls,
    3166             :              &auditor_pub,
    3167             :              auditor_url,
    3168             :              auditor_name);
    3169           0 :     GNUNET_PQ_cleanup_result (rs);
    3170             :   }
    3171             : }
    3172             : 
    3173             : 
    3174             : /**
    3175             :  * Function called to invoke @a cb on every active auditor. Disabled
    3176             :  * auditors are skipped. Runs in its own read-only transaction (hence no
    3177             :  * session provided).
    3178             :   *
    3179             :  * @param cls the @e cls of this struct with the plugin-specific state
    3180             :  * @param cb function to call on each active auditor
    3181             :  * @param cb_cls closure for @a cb
    3182             :  * @return transaction status code
    3183             :  */
    3184             : static enum GNUNET_DB_QueryStatus
    3185           0 : postgres_iterate_active_auditors (void *cls,
    3186             :                                   TALER_EXCHANGEDB_AuditorsCallback cb,
    3187             :                                   void *cb_cls)
    3188             : {
    3189           0 :   struct PostgresClosure *pc = cls;
    3190           0 :   struct GNUNET_PQ_QueryParam params[] = {
    3191             :     GNUNET_PQ_query_param_end
    3192             :   };
    3193           0 :   struct AuditorsIteratorContext dic = {
    3194             :     .cb = cb,
    3195             :     .cb_cls = cb_cls,
    3196             :   };
    3197             :   struct TALER_EXCHANGEDB_Session *session;
    3198             : 
    3199           0 :   session = postgres_get_session (pc);
    3200           0 :   if (NULL == session)
    3201           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    3202           0 :   return GNUNET_PQ_eval_prepared_multi_select (session->conn,
    3203             :                                                "select_auditors",
    3204             :                                                params,
    3205             :                                                &auditors_cb_helper,
    3206             :                                                &dic);
    3207             : }
    3208             : 
    3209             : 
    3210             : /**
    3211             :  * Closure for #auditor_denoms_cb_helper()
    3212             :  */
    3213             : struct AuditorDenomsIteratorContext
    3214             : {
    3215             :   /**
    3216             :    * Function to call with the results.
    3217             :    */
    3218             :   TALER_EXCHANGEDB_AuditorDenominationsCallback cb;
    3219             : 
    3220             :   /**
    3221             :    * Closure to pass to @e cb
    3222             :    */
    3223             :   void *cb_cls;
    3224             : };
    3225             : 
    3226             : 
    3227             : /**
    3228             :  * Helper function for #postgres_iterate_auditor_denominations().
    3229             :  * Calls the callback with each auditor and denomination pair.
    3230             :  *
    3231             :  * @param cls a `struct AuditorDenomsIteratorContext`
    3232             :  * @param result db results
    3233             :  * @param num_results number of results in @a result
    3234             :  */
    3235             : static void
    3236           0 : auditor_denoms_cb_helper (void *cls,
    3237             :                           PGresult *result,
    3238             :                           unsigned int num_results)
    3239             : {
    3240           0 :   struct AuditorDenomsIteratorContext *dic = cls;
    3241             : 
    3242           0 :   for (unsigned int i = 0; i<num_results; i++)
    3243             :   {
    3244             :     struct TALER_AuditorPublicKeyP auditor_pub;
    3245             :     struct GNUNET_HashCode h_denom_pub;
    3246             :     struct TALER_AuditorSignatureP auditor_sig;
    3247           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
    3248           0 :       GNUNET_PQ_result_spec_auto_from_type ("auditor_pub",
    3249             :                                             &auditor_pub),
    3250           0 :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    3251             :                                             &h_denom_pub),
    3252           0 :       GNUNET_PQ_result_spec_auto_from_type ("auditor_sig",
    3253             :                                             &auditor_sig),
    3254             :       GNUNET_PQ_result_spec_end
    3255             :     };
    3256             : 
    3257           0 :     if (GNUNET_OK !=
    3258           0 :         GNUNET_PQ_extract_result (result,
    3259             :                                   rs,
    3260             :                                   i))
    3261             :     {
    3262           0 :       GNUNET_break (0);
    3263           0 :       return;
    3264             :     }
    3265           0 :     dic->cb (dic->cb_cls,
    3266             :              &auditor_pub,
    3267             :              &h_denom_pub,
    3268             :              &auditor_sig);
    3269             :   }
    3270             : }
    3271             : 
    3272             : 
    3273             : /**
    3274             :  * Function called to invoke @a cb on every denomination with an active
    3275             :  * auditor. Disabled auditors and denominations without auditor are
    3276             :  * skipped. Runs in its own read-only transaction (hence no session
    3277             :  * provided).
    3278             :  *
    3279             :  * @param cls the @e cls of this struct with the plugin-specific state
    3280             :  * @param cb function to call on each active auditor
    3281             :  * @param cb_cls closure for @a cb
    3282             :  * @return transaction status code
    3283             :  */
    3284             : static enum GNUNET_DB_QueryStatus
    3285           0 : postgres_iterate_auditor_denominations (
    3286             :   void *cls,
    3287             :   TALER_EXCHANGEDB_AuditorDenominationsCallback cb,
    3288             :   void *cb_cls)
    3289             : {
    3290           0 :   struct PostgresClosure *pc = cls;
    3291           0 :   struct GNUNET_PQ_QueryParam params[] = {
    3292             :     GNUNET_PQ_query_param_end
    3293             :   };
    3294           0 :   struct AuditorDenomsIteratorContext dic = {
    3295             :     .cb = cb,
    3296             :     .cb_cls = cb_cls,
    3297             :   };
    3298             :   struct TALER_EXCHANGEDB_Session *session;
    3299             : 
    3300           0 :   session = postgres_get_session (pc);
    3301           0 :   if (NULL == session)
    3302           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    3303           0 :   return GNUNET_PQ_eval_prepared_multi_select (session->conn,
    3304             :                                                "select_auditor_denoms",
    3305             :                                                params,
    3306             :                                                &auditor_denoms_cb_helper,
    3307             :                                                &dic);
    3308             : }
    3309             : 
    3310             : 
    3311             : /**
    3312             :  * Get the summary of a reserve.
    3313             :  *
    3314             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    3315             :  * @param session the database connection handle
    3316             :  * @param[in,out] reserve the reserve data.  The public key of the reserve should be
    3317             :  *          set in this structure; it is used to query the database.  The balance
    3318             :  *          and expiration are then filled accordingly.
    3319             :  * @return transaction status
    3320             :  */
    3321             : static enum GNUNET_DB_QueryStatus
    3322          12 : postgres_reserves_get (void *cls,
    3323             :                        struct TALER_EXCHANGEDB_Session *session,
    3324             :                        struct TALER_EXCHANGEDB_Reserve *reserve)
    3325             : {
    3326          12 :   struct PostgresClosure *pg = cls;
    3327          12 :   struct GNUNET_PQ_QueryParam params[] = {
    3328          12 :     GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
    3329             :     GNUNET_PQ_query_param_end
    3330             :   };
    3331          12 :   struct GNUNET_PQ_ResultSpec rs[] = {
    3332          12 :     TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance", &reserve->balance),
    3333          12 :     TALER_PQ_result_spec_absolute_time ("expiration_date", &reserve->expiry),
    3334          12 :     TALER_PQ_result_spec_absolute_time ("gc_date", &reserve->gc),
    3335             :     GNUNET_PQ_result_spec_end
    3336             :   };
    3337             : 
    3338          12 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    3339             :                                                    "reserves_get",
    3340             :                                                    params,
    3341             :                                                    rs);
    3342             : }
    3343             : 
    3344             : 
    3345             : /**
    3346             :  * Updates a reserve with the data from the given reserve structure.
    3347             :  *
    3348             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    3349             :  * @param session the database connection
    3350             :  * @param reserve the reserve structure whose data will be used to update the
    3351             :  *          corresponding record in the database.
    3352             :  * @return transaction status
    3353             :  */
    3354             : static enum GNUNET_DB_QueryStatus
    3355           5 : reserves_update (void *cls,
    3356             :                  struct TALER_EXCHANGEDB_Session *session,
    3357             :                  const struct TALER_EXCHANGEDB_Reserve *reserve)
    3358             : {
    3359           5 :   struct GNUNET_PQ_QueryParam params[] = {
    3360           5 :     TALER_PQ_query_param_absolute_time (&reserve->expiry),
    3361           5 :     TALER_PQ_query_param_absolute_time (&reserve->gc),
    3362           5 :     TALER_PQ_query_param_amount (&reserve->balance),
    3363           5 :     GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
    3364             :     GNUNET_PQ_query_param_end
    3365             :   };
    3366             : 
    3367             :   (void) cls;
    3368           5 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    3369             :                                              "reserve_update",
    3370             :                                              params);
    3371             : }
    3372             : 
    3373             : 
    3374             : /**
    3375             :  * Insert an incoming transaction into reserves.  New reserves are also created
    3376             :  * through this function.
    3377             :  *
    3378             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    3379             :  * @param session the database connection handle
    3380             :  * @param reserve_pub public key of the reserve
    3381             :  * @param balance the amount that has to be added to the reserve
    3382             :  * @param execution_time when was the amount added
    3383             :  * @param sender_account_details account information for the sender (payto://-URL)
    3384             :  * @param exchange_account_section name of the section in the configuration for the exchange's
    3385             :  *                       account into which the deposit was made
    3386             :  * @param wire_ref unique reference identifying the wire transfer
    3387             :  * @return transaction status code
    3388             :  */
    3389             : static enum GNUNET_DB_QueryStatus
    3390           2 : postgres_reserves_in_insert (void *cls,
    3391             :                              struct TALER_EXCHANGEDB_Session *session,
    3392             :                              const struct TALER_ReservePublicKeyP *reserve_pub,
    3393             :                              const struct TALER_Amount *balance,
    3394             :                              struct GNUNET_TIME_Absolute execution_time,
    3395             :                              const char *sender_account_details,
    3396             :                              const char *exchange_account_section,
    3397             :                              uint64_t wire_ref)
    3398             : {
    3399           2 :   struct PostgresClosure *pg = cls;
    3400             :   enum GNUNET_DB_QueryStatus reserve_exists;
    3401             :   enum GNUNET_DB_QueryStatus qs;
    3402             :   struct TALER_EXCHANGEDB_Reserve reserve;
    3403             :   struct GNUNET_TIME_Absolute expiry;
    3404             : 
    3405           2 :   reserve.pub = *reserve_pub;
    3406           2 :   reserve_exists = postgres_reserves_get (cls,
    3407             :                                           session,
    3408             :                                           &reserve);
    3409           2 :   if (0 > reserve_exists)
    3410             :   {
    3411           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == reserve_exists);
    3412           0 :     return reserve_exists;
    3413             :   }
    3414           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3415             :               "Creating reserve %s with expiration in %s\n",
    3416             :               TALER_B2S (reserve_pub),
    3417             :               GNUNET_STRINGS_relative_time_to_string (
    3418             :                 pg->idle_reserve_expiration_time,
    3419             :                 GNUNET_NO));
    3420           2 :   expiry = GNUNET_TIME_absolute_add (execution_time,
    3421             :                                      pg->idle_reserve_expiration_time);
    3422           2 :   (void) GNUNET_TIME_round_abs (&expiry);
    3423           2 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == reserve_exists)
    3424             :   {
    3425             :     /* New reserve, create balance for the first time; we do this
    3426             :        before adding the actual transaction to "reserves_in", as
    3427             :        for a new reserve it can't be a duplicate 'add' operation,
    3428             :        and as the 'add' operation may need the reserve entry
    3429             :        as a foreign key. */
    3430           1 :     struct GNUNET_PQ_QueryParam params[] = {
    3431           1 :       GNUNET_PQ_query_param_auto_from_type (reserve_pub),
    3432           1 :       GNUNET_PQ_query_param_string (sender_account_details),
    3433           1 :       TALER_PQ_query_param_amount (balance),
    3434           1 :       TALER_PQ_query_param_absolute_time (&expiry),
    3435           1 :       TALER_PQ_query_param_absolute_time (&expiry),
    3436             :       GNUNET_PQ_query_param_end
    3437             :     };
    3438             : 
    3439           1 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    3440             :                 "Reserve does not exist; creating a new one\n");
    3441           1 :     qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    3442             :                                              "reserve_create",
    3443             :                                              params);
    3444           1 :     if (0 > qs)
    3445             :     {
    3446           0 :       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
    3447           0 :       return qs;
    3448             :     }
    3449           1 :     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    3450             :     {
    3451             :       /* Maybe DB did not detect serializiability error already,
    3452             :          but clearly there must be one. Still odd. */
    3453           0 :       GNUNET_break (0);
    3454           0 :       return GNUNET_DB_STATUS_SOFT_ERROR;
    3455             :     }
    3456             :   }
    3457             :   /* Create new incoming transaction, "ON CONFLICT DO NOTHING"
    3458             :      is used to guard against duplicates. */
    3459             :   {
    3460           2 :     struct GNUNET_PQ_QueryParam params[] = {
    3461           2 :       GNUNET_PQ_query_param_auto_from_type (&reserve.pub),
    3462           2 :       GNUNET_PQ_query_param_uint64 (&wire_ref),
    3463           2 :       TALER_PQ_query_param_amount (balance),
    3464           2 :       GNUNET_PQ_query_param_string (exchange_account_section),
    3465           2 :       GNUNET_PQ_query_param_string (sender_account_details),
    3466           2 :       TALER_PQ_query_param_absolute_time (&execution_time),
    3467             :       GNUNET_PQ_query_param_end
    3468             :     };
    3469             : 
    3470           2 :     qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    3471             :                                              "reserves_in_add_transaction",
    3472             :                                              params);
    3473           2 :     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    3474             :     {
    3475           0 :       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
    3476           0 :       return qs;
    3477             :     }
    3478             :   }
    3479             : 
    3480           2 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == reserve_exists)
    3481             :   {
    3482             :     /* If the reserve already existed, we need to still update the
    3483             :        balance; we do this after checking for duplication, as
    3484             :        otherwise we might have to actually pay the cost to roll this
    3485             :        back for duplicate transactions; like this, we should virtually
    3486             :        never actually have to rollback anything. */struct TALER_EXCHANGEDB_Reserve updated_reserve;
    3487             : 
    3488           1 :     updated_reserve.pub = reserve.pub;
    3489           1 :     if (0 >
    3490           1 :         TALER_amount_add (&updated_reserve.balance,
    3491             :                           &reserve.balance,
    3492             :                           balance))
    3493             :     {
    3494             :       /* currency overflow or incompatible currency */
    3495           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3496             :                   "Attempt to deposit incompatible amount into reserve\n");
    3497           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
    3498             :     }
    3499           1 :     updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry,
    3500             :                                                        reserve.expiry);
    3501           1 :     (void) GNUNET_TIME_round_abs (&updated_reserve.expiry);
    3502           1 :     updated_reserve.gc = GNUNET_TIME_absolute_max (updated_reserve.expiry,
    3503             :                                                    reserve.gc);
    3504           1 :     (void) GNUNET_TIME_round_abs (&updated_reserve.gc);
    3505           1 :     return reserves_update (cls,
    3506             :                             session,
    3507             :                             &updated_reserve);
    3508             :   }
    3509           1 :   return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    3510             : }
    3511             : 
    3512             : 
    3513             : /**
    3514             :  * Obtain the most recent @a wire_reference that was inserted via @e reserves_in_insert.
    3515             :  *
    3516             :  * @param cls the @e cls of this struct with the plugin-specific state
    3517             :  * @param session the database session handle
    3518             :  * @param exchange_account_name name of the section in the exchange's configuration
    3519             :  *                       for the account that we are tracking here
    3520             :  * @param[out] wire_reference set to unique reference identifying the wire transfer
    3521             :  * @return transaction status code
    3522             :  */
    3523             : static enum GNUNET_DB_QueryStatus
    3524           4 : postgres_get_latest_reserve_in_reference (
    3525             :   void *cls,
    3526             :   struct TALER_EXCHANGEDB_Session *session,
    3527             :   const char *exchange_account_name,
    3528             :   uint64_t *wire_reference)
    3529             : {
    3530           4 :   struct GNUNET_PQ_QueryParam params[] = {
    3531           4 :     GNUNET_PQ_query_param_string (exchange_account_name),
    3532             :     GNUNET_PQ_query_param_end
    3533             :   };
    3534           4 :   struct GNUNET_PQ_ResultSpec rs[] = {
    3535           4 :     GNUNET_PQ_result_spec_uint64 ("wire_reference",
    3536             :                                   wire_reference),
    3537             :     GNUNET_PQ_result_spec_end
    3538             :   };
    3539             : 
    3540             :   (void) cls;
    3541           4 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    3542             :                                                    "reserves_in_get_latest_wire_reference",
    3543             :                                                    params,
    3544             :                                                    rs);
    3545             : }
    3546             : 
    3547             : 
    3548             : /**
    3549             :  * Locate the response for a /reserve/withdraw request under the
    3550             :  * key of the hash of the blinded message.
    3551             :  *
    3552             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    3553             :  * @param session database connection to use
    3554             :  * @param h_blind hash of the blinded coin to be signed (will match
    3555             :  *                `h_coin_envelope` in the @a collectable to be returned)
    3556             :  * @param collectable corresponding collectable coin (blind signature)
    3557             :  *                    if a coin is found
    3558             :  * @return statement execution status
    3559             :  */
    3560             : static enum GNUNET_DB_QueryStatus
    3561           1 : postgres_get_withdraw_info (
    3562             :   void *cls,
    3563             :   struct TALER_EXCHANGEDB_Session *session,
    3564             :   const struct GNUNET_HashCode *h_blind,
    3565             :   struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
    3566             : {
    3567           1 :   struct PostgresClosure *pg = cls;
    3568           1 :   struct GNUNET_PQ_QueryParam params[] = {
    3569           1 :     GNUNET_PQ_query_param_auto_from_type (h_blind),
    3570             :     GNUNET_PQ_query_param_end
    3571             :   };
    3572           1 :   struct GNUNET_PQ_ResultSpec rs[] = {
    3573           1 :     GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    3574             :                                           &collectable->denom_pub_hash),
    3575           1 :     GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
    3576             :                                          &collectable->sig.rsa_signature),
    3577           1 :     GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
    3578             :                                           &collectable->reserve_sig),
    3579           1 :     GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
    3580             :                                           &collectable->reserve_pub),
    3581           1 :     TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    3582             :                                  &collectable->amount_with_fee),
    3583           1 :     TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
    3584             :                                  &collectable->withdraw_fee),
    3585             :     GNUNET_PQ_result_spec_end
    3586             :   };
    3587             : #if EXPLICIT_LOCKS
    3588             :   struct GNUNET_PQ_QueryParam no_params[] = {
    3589             :     GNUNET_PQ_query_param_end
    3590             :   };
    3591             :   enum GNUNET_DB_QueryStatus qs;
    3592             : 
    3593             :   if (0 > (qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    3594             :                                                     "lock_withdraw",
    3595             :                                                     no_params)))
    3596             :     return qs;
    3597             : #endif
    3598           1 :   collectable->h_coin_envelope = *h_blind;
    3599           1 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    3600             :                                                    "get_withdraw_info",
    3601             :                                                    params,
    3602             :                                                    rs);
    3603             : }
    3604             : 
    3605             : 
    3606             : /**
    3607             :  * Store collectable bit coin under the corresponding
    3608             :  * hash of the blinded message.
    3609             :  *
    3610             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    3611             :  * @param session database connection to use
    3612             :  * @param collectable corresponding collectable coin (blind signature)
    3613             :  *                    if a coin is found
    3614             :  * @return query execution status
    3615             :  */
    3616             : static enum GNUNET_DB_QueryStatus
    3617           1 : postgres_insert_withdraw_info (
    3618             :   void *cls,
    3619             :   struct TALER_EXCHANGEDB_Session *session,
    3620             :   const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
    3621             : {
    3622           1 :   struct PostgresClosure *pg = cls;
    3623             :   struct TALER_EXCHANGEDB_Reserve reserve;
    3624             :   struct GNUNET_TIME_Absolute now;
    3625             :   struct GNUNET_TIME_Absolute expiry;
    3626           1 :   struct GNUNET_PQ_QueryParam params[] = {
    3627           1 :     GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
    3628           1 :     GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
    3629           1 :     GNUNET_PQ_query_param_rsa_signature (collectable->sig.rsa_signature),
    3630           1 :     GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub),
    3631           1 :     GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
    3632           1 :     TALER_PQ_query_param_absolute_time (&now),
    3633           1 :     TALER_PQ_query_param_amount (&collectable->amount_with_fee),
    3634             :     GNUNET_PQ_query_param_end
    3635             :   };
    3636             :   enum GNUNET_DB_QueryStatus qs;
    3637             : 
    3638           1 :   now = GNUNET_TIME_absolute_get ();
    3639           1 :   (void) GNUNET_TIME_round_abs (&now);
    3640           1 :   qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    3641             :                                            "insert_withdraw_info",
    3642             :                                            params);
    3643           1 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    3644             :   {
    3645           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    3646           0 :     return qs;
    3647             :   }
    3648             : 
    3649             :   /* update reserve balance */
    3650           1 :   reserve.pub = collectable->reserve_pub;
    3651           1 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    3652           1 :       (qs = postgres_reserves_get (cls,
    3653             :                                    session,
    3654             :                                    &reserve)))
    3655             :   {
    3656             :     /* Should have been checked before we got here... */
    3657           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    3658           0 :     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    3659           0 :       qs = GNUNET_DB_STATUS_HARD_ERROR;
    3660           0 :     return qs;
    3661             :   }
    3662           1 :   if (0 >
    3663           1 :       TALER_amount_subtract (&reserve.balance,
    3664             :                              &reserve.balance,
    3665             :                              &collectable->amount_with_fee))
    3666             :   {
    3667             :     /* The reserve history was checked to make sure there is enough of a balance
    3668             :        left before we tried this; however, concurrent operations may have changed
    3669             :        the situation by now, causing us to fail here. As reserves can no longer
    3670             :        be topped up, retrying should not help either.  */
    3671           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3672             :                 "Withdrawal from reserve `%s' refused due to insufficient balance.\n",
    3673             :                 TALER_B2S (&collectable->reserve_pub));
    3674           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    3675             :   }
    3676           1 :   expiry = GNUNET_TIME_absolute_add (now,
    3677             :                                      pg->legal_reserve_expiration_time);
    3678           1 :   reserve.gc = GNUNET_TIME_absolute_max (expiry,
    3679             :                                          reserve.gc);
    3680           1 :   (void) GNUNET_TIME_round_abs (&reserve.gc);
    3681           1 :   qs = reserves_update (cls,
    3682             :                         session,
    3683             :                         &reserve);
    3684           1 :   GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
    3685           1 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    3686             :   {
    3687           0 :     GNUNET_break (0);
    3688           0 :     qs = GNUNET_DB_STATUS_HARD_ERROR;
    3689             :   }
    3690           1 :   return qs;
    3691             : }
    3692             : 
    3693             : 
    3694             : /**
    3695             :  * Closure for callbacks invoked via #postgres_get_reserve_history.
    3696             :  */
    3697             : struct ReserveHistoryContext
    3698             : {
    3699             : 
    3700             :   /**
    3701             :    * Which reserve are we building the history for?
    3702             :    */
    3703             :   const struct TALER_ReservePublicKeyP *reserve_pub;
    3704             : 
    3705             :   /**
    3706             :    * Where we build the history.
    3707             :    */
    3708             :   struct TALER_EXCHANGEDB_ReserveHistory *rh;
    3709             : 
    3710             :   /**
    3711             :    * Tail of @e rh list.
    3712             :    */
    3713             :   struct TALER_EXCHANGEDB_ReserveHistory *rh_tail;
    3714             : 
    3715             :   /**
    3716             :    * Plugin context.
    3717             :    */
    3718             :   struct PostgresClosure *pg;
    3719             : 
    3720             :   /**
    3721             :    * Set to #GNUNET_SYSERR on serious internal errors during
    3722             :    * the callbacks.
    3723             :    */
    3724             :   int status;
    3725             : };
    3726             : 
    3727             : 
    3728             : /**
    3729             :  * Append and return a fresh element to the reserve
    3730             :  * history kept in @a rhc.
    3731             :  *
    3732             :  * @param rhc where the history is kept
    3733             :  * @return the fresh element that was added
    3734             :  */
    3735             : static struct TALER_EXCHANGEDB_ReserveHistory *
    3736           5 : append_rh (struct ReserveHistoryContext *rhc)
    3737             : {
    3738             :   struct TALER_EXCHANGEDB_ReserveHistory *tail;
    3739             : 
    3740           5 :   tail = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory);
    3741           5 :   if (NULL != rhc->rh_tail)
    3742             :   {
    3743           4 :     rhc->rh_tail->next = tail;
    3744           4 :     rhc->rh_tail = tail;
    3745             :   }
    3746             :   else
    3747             :   {
    3748           1 :     rhc->rh_tail = tail;
    3749           1 :     rhc->rh = tail;
    3750             :   }
    3751           5 :   return tail;
    3752             : }
    3753             : 
    3754             : 
    3755             : /**
    3756             :  * Add bank transfers to result set for #postgres_get_reserve_history.
    3757             :  *
    3758             :  * @param cls a `struct ReserveHistoryContext *`
    3759             :  * @param result SQL result
    3760             :  * @param num_results number of rows in @a result
    3761             :  */
    3762             : static void
    3763           1 : add_bank_to_exchange (void *cls,
    3764             :                       PGresult *result,
    3765             :                       unsigned int num_results)
    3766             : {
    3767           1 :   struct ReserveHistoryContext *rhc = cls;
    3768           1 :   struct PostgresClosure *pg = rhc->pg;
    3769             : 
    3770           3 :   while (0 < num_results)
    3771             :   {
    3772             :     struct TALER_EXCHANGEDB_BankTransfer *bt;
    3773             :     struct TALER_EXCHANGEDB_ReserveHistory *tail;
    3774             : 
    3775           2 :     bt = GNUNET_new (struct TALER_EXCHANGEDB_BankTransfer);
    3776             :     {
    3777           2 :       struct GNUNET_PQ_ResultSpec rs[] = {
    3778           2 :         GNUNET_PQ_result_spec_uint64 ("wire_reference",
    3779             :                                       &bt->wire_reference),
    3780           2 :         TALER_PQ_RESULT_SPEC_AMOUNT ("credit",
    3781             :                                      &bt->amount),
    3782           2 :         TALER_PQ_result_spec_absolute_time ("execution_date",
    3783             :                                             &bt->execution_date),
    3784           2 :         GNUNET_PQ_result_spec_string ("sender_account_details",
    3785             :                                       &bt->sender_account_details),
    3786             :         GNUNET_PQ_result_spec_end
    3787             :       };
    3788             : 
    3789           2 :       if (GNUNET_OK !=
    3790           2 :           GNUNET_PQ_extract_result (result,
    3791             :                                     rs,
    3792             :                                     --num_results))
    3793             :       {
    3794           0 :         GNUNET_break (0);
    3795           0 :         GNUNET_free (bt);
    3796           0 :         rhc->status = GNUNET_SYSERR;
    3797           0 :         return;
    3798             :       }
    3799             :     }
    3800           2 :     bt->reserve_pub = *rhc->reserve_pub;
    3801           2 :     tail = append_rh (rhc);
    3802           2 :     tail->type = TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE;
    3803           2 :     tail->details.bank = bt;
    3804             :   }   /* end of 'while (0 < rows)' */
    3805             : }
    3806             : 
    3807             : 
    3808             : /**
    3809             :  * Add coin withdrawals to result set for #postgres_get_reserve_history.
    3810             :  *
    3811             :  * @param cls a `struct ReserveHistoryContext *`
    3812             :  * @param result SQL result
    3813             :  * @param num_results number of rows in @a result
    3814             :  */
    3815             : static void
    3816           1 : add_withdraw_coin (void *cls,
    3817             :                    PGresult *result,
    3818             :                    unsigned int num_results)
    3819             : {
    3820           1 :   struct ReserveHistoryContext *rhc = cls;
    3821           1 :   struct PostgresClosure *pg = rhc->pg;
    3822             : 
    3823           2 :   while (0 < num_results)
    3824             :   {
    3825             :     struct TALER_EXCHANGEDB_CollectableBlindcoin *cbc;
    3826             :     struct TALER_EXCHANGEDB_ReserveHistory *tail;
    3827             : 
    3828           1 :     cbc = GNUNET_new (struct TALER_EXCHANGEDB_CollectableBlindcoin);
    3829             :     {
    3830           1 :       struct GNUNET_PQ_ResultSpec rs[] = {
    3831           1 :         GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
    3832             :                                               &cbc->h_coin_envelope),
    3833           1 :         GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    3834             :                                               &cbc->denom_pub_hash),
    3835           1 :         GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
    3836             :                                              &cbc->sig.rsa_signature),
    3837           1 :         GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
    3838             :                                               &cbc->reserve_sig),
    3839           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    3840             :                                      &cbc->amount_with_fee),
    3841           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("fee_withdraw",
    3842             :                                      &cbc->withdraw_fee),
    3843             :         GNUNET_PQ_result_spec_end
    3844             :       };
    3845             : 
    3846           1 :       if (GNUNET_OK !=
    3847           1 :           GNUNET_PQ_extract_result (result,
    3848             :                                     rs,
    3849             :                                     --num_results))
    3850             :       {
    3851           0 :         GNUNET_break (0);
    3852           0 :         GNUNET_free (cbc);
    3853           0 :         rhc->status = GNUNET_SYSERR;
    3854           0 :         return;
    3855             :       }
    3856             :     }
    3857           1 :     cbc->reserve_pub = *rhc->reserve_pub;
    3858           1 :     tail = append_rh (rhc);
    3859           1 :     tail->type = TALER_EXCHANGEDB_RO_WITHDRAW_COIN;
    3860           1 :     tail->details.withdraw = cbc;
    3861             :   }
    3862             : }
    3863             : 
    3864             : 
    3865             : /**
    3866             :  * Add recoups to result set for #postgres_get_reserve_history.
    3867             :  *
    3868             :  * @param cls a `struct ReserveHistoryContext *`
    3869             :  * @param result SQL result
    3870             :  * @param num_results number of rows in @a result
    3871             :  */
    3872             : static void
    3873           1 : add_recoup (void *cls,
    3874             :             PGresult *result,
    3875             :             unsigned int num_results)
    3876             : {
    3877           1 :   struct ReserveHistoryContext *rhc = cls;
    3878           1 :   struct PostgresClosure *pg = rhc->pg;
    3879             : 
    3880           2 :   while (0 < num_results)
    3881             :   {
    3882             :     struct TALER_EXCHANGEDB_Recoup *recoup;
    3883             :     struct TALER_EXCHANGEDB_ReserveHistory *tail;
    3884             : 
    3885           1 :     recoup = GNUNET_new (struct TALER_EXCHANGEDB_Recoup);
    3886             :     {
    3887           1 :       struct GNUNET_PQ_ResultSpec rs[] = {
    3888           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
    3889             :                                      &recoup->value),
    3890           1 :         GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
    3891             :                                               &recoup->coin.coin_pub),
    3892           1 :         GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
    3893             :                                               &recoup->coin_blind),
    3894           1 :         GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
    3895             :                                               &recoup->coin_sig),
    3896           1 :         TALER_PQ_result_spec_absolute_time ("timestamp",
    3897             :                                             &recoup->timestamp),
    3898           1 :         GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    3899             :                                               &recoup->coin.denom_pub_hash),
    3900           1 :         GNUNET_PQ_result_spec_rsa_signature (
    3901             :           "denom_sig",
    3902             :           &recoup->coin.denom_sig.rsa_signature),
    3903             :         GNUNET_PQ_result_spec_end
    3904             :       };
    3905             : 
    3906           1 :       if (GNUNET_OK !=
    3907           1 :           GNUNET_PQ_extract_result (result,
    3908             :                                     rs,
    3909             :                                     --num_results))
    3910             :       {
    3911           0 :         GNUNET_break (0);
    3912           0 :         GNUNET_free (recoup);
    3913           0 :         rhc->status = GNUNET_SYSERR;
    3914           0 :         return;
    3915             :       }
    3916             :     }
    3917           1 :     recoup->reserve_pub = *rhc->reserve_pub;
    3918           1 :     tail = append_rh (rhc);
    3919           1 :     tail->type = TALER_EXCHANGEDB_RO_RECOUP_COIN;
    3920           1 :     tail->details.recoup = recoup;
    3921             :   }   /* end of 'while (0 < rows)' */
    3922             : }
    3923             : 
    3924             : 
    3925             : /**
    3926             :  * Add exchange-to-bank transfers to result set for
    3927             :  * #postgres_get_reserve_history.
    3928             :  *
    3929             :  * @param cls a `struct ReserveHistoryContext *`
    3930             :  * @param result SQL result
    3931             :  * @param num_results number of rows in @a result
    3932             :  */
    3933             : static void
    3934           1 : add_exchange_to_bank (void *cls,
    3935             :                       PGresult *result,
    3936             :                       unsigned int num_results)
    3937             : {
    3938           1 :   struct ReserveHistoryContext *rhc = cls;
    3939           1 :   struct PostgresClosure *pg = rhc->pg;
    3940             : 
    3941           2 :   while (0 < num_results)
    3942             :   {
    3943             :     struct TALER_EXCHANGEDB_ClosingTransfer *closing;
    3944             :     struct TALER_EXCHANGEDB_ReserveHistory *tail;
    3945             : 
    3946           1 :     closing = GNUNET_new (struct TALER_EXCHANGEDB_ClosingTransfer);
    3947             :     {
    3948           1 :       struct GNUNET_PQ_ResultSpec rs[] = {
    3949           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
    3950             :                                      &closing->amount),
    3951           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
    3952             :                                      &closing->closing_fee),
    3953           1 :         TALER_PQ_result_spec_absolute_time ("execution_date",
    3954             :                                             &closing->execution_date),
    3955           1 :         GNUNET_PQ_result_spec_string ("receiver_account",
    3956             :                                       &closing->receiver_account_details),
    3957           1 :         GNUNET_PQ_result_spec_auto_from_type ("wtid",
    3958             :                                               &closing->wtid),
    3959             :         GNUNET_PQ_result_spec_end
    3960             :       };
    3961             : 
    3962           1 :       if (GNUNET_OK !=
    3963           1 :           GNUNET_PQ_extract_result (result,
    3964             :                                     rs,
    3965             :                                     --num_results))
    3966             :       {
    3967           0 :         GNUNET_break (0);
    3968           0 :         GNUNET_free (closing);
    3969           0 :         rhc->status = GNUNET_SYSERR;
    3970           0 :         return;
    3971             :       }
    3972             :     }
    3973           1 :     closing->reserve_pub = *rhc->reserve_pub;
    3974           1 :     tail = append_rh (rhc);
    3975           1 :     tail->type = TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK;
    3976           1 :     tail->details.closing = closing;
    3977             :   }   /* end of 'while (0 < rows)' */
    3978             : }
    3979             : 
    3980             : 
    3981             : /**
    3982             :  * Get all of the transaction history associated with the specified
    3983             :  * reserve.
    3984             :  *
    3985             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    3986             :  * @param session connection to use
    3987             :  * @param reserve_pub public key of the reserve
    3988             :  * @param[out] rhp set to known transaction history (NULL if reserve is unknown)
    3989             :  * @return transaction status
    3990             :  */
    3991             : static enum GNUNET_DB_QueryStatus
    3992           1 : postgres_get_reserve_history (void *cls,
    3993             :                               struct TALER_EXCHANGEDB_Session *session,
    3994             :                               const struct TALER_ReservePublicKeyP *reserve_pub,
    3995             :                               struct TALER_EXCHANGEDB_ReserveHistory **rhp)
    3996             : {
    3997           1 :   struct PostgresClosure *pg = cls;
    3998             :   struct ReserveHistoryContext rhc;
    3999             :   struct
    4000             :   {
    4001             :     /**
    4002             :      * Name of the prepared statement to run.
    4003             :      */
    4004             :     const char *statement;
    4005             :     /**
    4006             :      * Function to use to process the results.
    4007             :      */
    4008             :     GNUNET_PQ_PostgresResultHandler cb;
    4009           1 :   } work[] = {
    4010             :     /** #TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE */
    4011             :     { "reserves_in_get_transactions",
    4012             :       add_bank_to_exchange },
    4013             :     /** #TALER_EXCHANGEDB_RO_WITHDRAW_COIN */
    4014             :     { "get_reserves_out",
    4015             :       &add_withdraw_coin },
    4016             :     /** #TALER_EXCHANGEDB_RO_RECOUP_COIN */
    4017             :     { "recoup_by_reserve",
    4018             :       &add_recoup },
    4019             :     /** #TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK */
    4020             :     { "close_by_reserve",
    4021             :       &add_exchange_to_bank },
    4022             :     /* List terminator */
    4023             :     { NULL,
    4024             :       NULL }
    4025             :   };
    4026             :   enum GNUNET_DB_QueryStatus qs;
    4027           1 :   struct GNUNET_PQ_QueryParam params[] = {
    4028           1 :     GNUNET_PQ_query_param_auto_from_type (reserve_pub),
    4029             :     GNUNET_PQ_query_param_end
    4030             :   };
    4031             : 
    4032           1 :   rhc.reserve_pub = reserve_pub;
    4033           1 :   rhc.rh = NULL;
    4034           1 :   rhc.rh_tail = NULL;
    4035           1 :   rhc.pg = pg;
    4036           1 :   rhc.status = GNUNET_OK;
    4037           1 :   qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* make static analysis happy */
    4038           5 :   for (unsigned int i = 0; NULL != work[i].cb; i++)
    4039             :   {
    4040           4 :     qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    4041             :                                                work[i].statement,
    4042             :                                                params,
    4043             :                                                work[i].cb,
    4044             :                                                &rhc);
    4045           4 :     if ( (0 > qs) ||
    4046           4 :          (GNUNET_OK != rhc.status) )
    4047             :       break;
    4048             :   }
    4049           1 :   if ( (qs < 0) ||
    4050           1 :        (rhc.status != GNUNET_OK) )
    4051             :   {
    4052           0 :     common_free_reserve_history (cls,
    4053             :                                  rhc.rh);
    4054           0 :     rhc.rh = NULL;
    4055           0 :     if (qs >= 0)
    4056             :     {
    4057             :       /* status == SYSERR is a very hard error... */
    4058           0 :       qs = GNUNET_DB_STATUS_HARD_ERROR;
    4059             :     }
    4060             :   }
    4061           1 :   *rhp = rhc.rh;
    4062           1 :   return qs;
    4063             : }
    4064             : 
    4065             : 
    4066             : /**
    4067             :  * Check if we have the specified deposit already in the database.
    4068             :  *
    4069             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    4070             :  * @param session database connection
    4071             :  * @param deposit deposit to search for
    4072             :  * @param check_extras whether to check extra fields match or not
    4073             :  * @param[out] deposit_fee set to the deposit fee the exchange charged
    4074             :  * @param[out] exchange_timestamp set to the time when the exchange received the deposit
    4075             :  * @return 1 if we know this operation,
    4076             :  *         0 if this exact deposit is unknown to us,
    4077             :  *         otherwise transaction error status
    4078             :  */
    4079             : static enum GNUNET_DB_QueryStatus
    4080           3 : postgres_have_deposit (void *cls,
    4081             :                        struct TALER_EXCHANGEDB_Session *session,
    4082             :                        const struct TALER_EXCHANGEDB_Deposit *deposit,
    4083             :                        int check_extras,
    4084             :                        struct TALER_Amount *deposit_fee,
    4085             :                        struct GNUNET_TIME_Absolute *exchange_timestamp)
    4086             : {
    4087           3 :   struct PostgresClosure *pg = cls;
    4088           3 :   struct GNUNET_PQ_QueryParam params[] = {
    4089           3 :     GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
    4090           3 :     GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract_terms),
    4091           3 :     GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
    4092             :     GNUNET_PQ_query_param_end
    4093             :   };
    4094             :   struct TALER_EXCHANGEDB_Deposit deposit2;
    4095           3 :   struct GNUNET_PQ_ResultSpec rs[] = {
    4096           3 :     TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    4097             :                                  &deposit2.amount_with_fee),
    4098           3 :     TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
    4099             :                                         &deposit2.timestamp),
    4100           3 :     TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
    4101             :                                         exchange_timestamp),
    4102           3 :     TALER_PQ_result_spec_absolute_time ("refund_deadline",
    4103             :                                         &deposit2.refund_deadline),
    4104           3 :     TALER_PQ_result_spec_absolute_time ("wire_deadline",
    4105             :                                         &deposit2.wire_deadline),
    4106           3 :     TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
    4107             :                                  deposit_fee),
    4108           3 :     GNUNET_PQ_result_spec_auto_from_type ("h_wire",
    4109             :                                           &deposit2.h_wire),
    4110             :     GNUNET_PQ_result_spec_end
    4111             :   };
    4112             :   enum GNUNET_DB_QueryStatus qs;
    4113             : #if EXPLICIT_LOCKS
    4114             :   struct GNUNET_PQ_QueryParam no_params[] = {
    4115             :     GNUNET_PQ_query_param_end
    4116             :   };
    4117             : 
    4118             :   if (0 > (qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    4119             :                                                     "lock_deposit",
    4120             :                                                     no_params)))
    4121             :     return qs;
    4122             : #endif
    4123           3 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    4124             :               "Getting deposits for coin %s\n",
    4125             :               TALER_B2S (&deposit->coin.coin_pub));
    4126           3 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    4127             :                                                  "get_deposit",
    4128             :                                                  params,
    4129             :                                                  rs);
    4130           3 :   if (0 >= qs)
    4131           2 :     return qs;
    4132             :   /* Now we check that the other information in @a deposit
    4133             :      also matches, and if not report inconsistencies. */
    4134           2 :   if ( ( (check_extras) &&
    4135           1 :          ( (0 != TALER_amount_cmp (&deposit->amount_with_fee,
    4136           1 :                                    &deposit2.amount_with_fee)) ||
    4137           1 :            (deposit->timestamp.abs_value_us !=
    4138           1 :             deposit2.timestamp.abs_value_us) ) ) ||
    4139           1 :        (deposit->refund_deadline.abs_value_us !=
    4140           1 :         deposit2.refund_deadline.abs_value_us) ||
    4141           1 :        (0 != GNUNET_memcmp (&deposit->h_wire,
    4142             :                             &deposit2.h_wire) ) )
    4143             :   {
    4144             :     /* Inconsistencies detected! Does not match!  (We might want to
    4145             :        expand the API with a 'get_deposit' function to return the
    4146             :        original transaction details to be used for an error message
    4147             :        in the future!) #3838 */
    4148           0 :     return 0;   /* Counts as if the transaction was not there */
    4149             :   }
    4150           1 :   return 1;
    4151             : }
    4152             : 
    4153             : 
    4154             : /**
    4155             :  * Mark a deposit as tiny, thereby declaring that it cannot be
    4156             :  * executed by itself and should no longer be returned by
    4157             :  * @e iterate_ready_deposits()
    4158             :  *
    4159             :  * @param cls the @e cls of this struct with the plugin-specific state
    4160             :  * @param session connection to the database
    4161             :  * @param rowid identifies the deposit row to modify
    4162             :  * @return query result status
    4163             :  */
    4164             : static enum GNUNET_DB_QueryStatus
    4165          10 : postgres_mark_deposit_tiny (void *cls,
    4166             :                             struct TALER_EXCHANGEDB_Session *session,
    4167             :                             uint64_t rowid)
    4168             : {
    4169          10 :   struct GNUNET_PQ_QueryParam params[] = {
    4170          10 :     GNUNET_PQ_query_param_uint64 (&rowid),
    4171             :     GNUNET_PQ_query_param_end
    4172             :   };
    4173             : 
    4174             :   (void) cls;
    4175          10 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    4176             :                                              "mark_deposit_tiny",
    4177             :                                              params);
    4178             : }
    4179             : 
    4180             : 
    4181             : /**
    4182             :  * Test if a deposit was marked as done, thereby declaring that it cannot be
    4183             :  * refunded anymore.
    4184             :  *
    4185             :  * @param cls the @e cls of this struct with the plugin-specific state
    4186             :  * @param session connection to the database
    4187             :  * @param coin_pub the coin to check for deposit
    4188             :  * @param merchant_pub merchant to receive the deposit
    4189             :  * @param h_contract_terms contract terms of the deposit
    4190             :  * @param h_wire hash of the merchant's wire details
    4191             :  * @return #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if is is marked done,
    4192             :  *         #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if not,
    4193             :  *         otherwise transaction error status (incl. deposit unknown)
    4194             :  */
    4195             : static enum GNUNET_DB_QueryStatus
    4196           2 : postgres_test_deposit_done (void *cls,
    4197             :                             struct TALER_EXCHANGEDB_Session *session,
    4198             :                             const struct TALER_CoinSpendPublicKeyP *coin_pub,
    4199             :                             const struct TALER_MerchantPublicKeyP *merchant_pub,
    4200             :                             const struct GNUNET_HashCode *h_contract_terms,
    4201             :                             const struct GNUNET_HashCode *h_wire)
    4202             : {
    4203           2 :   struct GNUNET_PQ_QueryParam params[] = {
    4204           2 :     GNUNET_PQ_query_param_auto_from_type (coin_pub),
    4205           2 :     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
    4206           2 :     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
    4207           2 :     GNUNET_PQ_query_param_auto_from_type (h_wire),
    4208             :     GNUNET_PQ_query_param_end
    4209             :   };
    4210           2 :   uint8_t done = 0;
    4211           2 :   struct GNUNET_PQ_ResultSpec rs[] = {
    4212           2 :     GNUNET_PQ_result_spec_auto_from_type ("done",
    4213             :                                           &done),
    4214             :     GNUNET_PQ_result_spec_end
    4215             :   };
    4216             :   enum GNUNET_DB_QueryStatus qs;
    4217             : 
    4218             :   (void) cls;
    4219           2 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    4220             :                                                  "test_deposit_done",
    4221             :                                                  params,
    4222             :                                                  rs);
    4223           2 :   if (qs < 0)
    4224           0 :     return qs;
    4225           2 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    4226           0 :     return GNUNET_DB_STATUS_HARD_ERROR; /* deposit MUST exist */
    4227             :   return (done
    4228             :           ? GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
    4229           2 :           : GNUNET_DB_STATUS_SUCCESS_NO_RESULTS);
    4230             : }
    4231             : 
    4232             : 
    4233             : /**
    4234             :  * Mark a deposit as done, thereby declaring that it cannot be
    4235             :  * executed at all anymore, and should no longer be returned by
    4236             :  * @e iterate_ready_deposits() or @e iterate_matching_deposits().
    4237             :  *
    4238             :  * @param cls the @e cls of this struct with the plugin-specific state
    4239             :  * @param session connection to the database
    4240             :  * @param rowid identifies the deposit row to modify
    4241             :  * @return query result status
    4242             :  */
    4243             : static enum GNUNET_DB_QueryStatus
    4244          34 : postgres_mark_deposit_done (void *cls,
    4245             :                             struct TALER_EXCHANGEDB_Session *session,
    4246             :                             uint64_t rowid)
    4247             : {
    4248          34 :   struct GNUNET_PQ_QueryParam params[] = {
    4249          34 :     GNUNET_PQ_query_param_uint64 (&rowid),
    4250             :     GNUNET_PQ_query_param_end
    4251             :   };
    4252             : 
    4253             :   (void) cls;
    4254          34 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    4255             :                                              "mark_deposit_done",
    4256             :                                              params);
    4257             : }
    4258             : 
    4259             : 
    4260             : /**
    4261             :  * Obtain information about deposits that are ready to be executed.
    4262             :  * Such deposits must not be marked as "tiny" or "done", and the
    4263             :  * execution time must be in the past.
    4264             :  *
    4265             :  * @param cls the @e cls of this struct with the plugin-specific state
    4266             :  * @param session connection to the database
    4267             :  * @param deposit_cb function to call for ONE such deposit
    4268             :  * @param deposit_cb_cls closure for @a deposit_cb
    4269             :  * @return transaction status code
    4270             :  */
    4271             : static enum GNUNET_DB_QueryStatus
    4272          40 : postgres_get_ready_deposit (void *cls,
    4273             :                             struct TALER_EXCHANGEDB_Session *session,
    4274             :                             TALER_EXCHANGEDB_DepositIterator deposit_cb,
    4275             :                             void *deposit_cb_cls)
    4276             : {
    4277          40 :   struct PostgresClosure *pg = cls;
    4278          40 :   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
    4279          40 :   struct GNUNET_PQ_QueryParam params[] = {
    4280          40 :     TALER_PQ_query_param_absolute_time (&now),
    4281             :     GNUNET_PQ_query_param_end
    4282             :   };
    4283             :   struct TALER_Amount amount_with_fee;
    4284             :   struct TALER_Amount deposit_fee;
    4285             :   struct GNUNET_TIME_Absolute wire_deadline;
    4286             :   struct GNUNET_TIME_Absolute wallet_timestamp;
    4287             :   struct GNUNET_TIME_Absolute exchange_timestamp;
    4288             :   struct GNUNET_HashCode h_contract_terms;
    4289             :   struct TALER_MerchantPublicKeyP merchant_pub;
    4290             :   struct TALER_CoinSpendPublicKeyP coin_pub;
    4291             :   uint64_t serial_id;
    4292             :   json_t *wire;
    4293          40 :   struct GNUNET_PQ_ResultSpec rs[] = {
    4294          40 :     GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
    4295             :                                   &serial_id),
    4296          40 :     TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    4297             :                                  &amount_with_fee),
    4298          40 :     TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
    4299             :                                  &deposit_fee),
    4300          40 :     TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
    4301             :                                         &exchange_timestamp),
    4302          40 :     TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
    4303             :                                         &wallet_timestamp),
    4304          40 :     TALER_PQ_result_spec_absolute_time ("wire_deadline",
    4305             :                                         &wire_deadline),
    4306          40 :     GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
    4307             :                                           &h_contract_terms),
    4308          40 :     GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
    4309             :                                           &merchant_pub),
    4310          40 :     GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
    4311             :                                           &coin_pub),
    4312          40 :     TALER_PQ_result_spec_json ("wire",
    4313             :                                &wire),
    4314             :     GNUNET_PQ_result_spec_end
    4315             :   };
    4316             :   enum GNUNET_DB_QueryStatus qs;
    4317             : 
    4318          40 :   (void) GNUNET_TIME_round_abs (&now);
    4319          40 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4320             :               "Finding ready deposits by deadline %s (%llu)\n",
    4321             :               GNUNET_STRINGS_absolute_time_to_string (now),
    4322             :               (unsigned long long) now.abs_value_us);
    4323             : 
    4324          40 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    4325             :                                                  "deposits_get_ready",
    4326             :                                                  params,
    4327             :                                                  rs);
    4328          40 :   if (qs <= 0)
    4329          22 :     return qs;
    4330             : 
    4331          18 :   qs = deposit_cb (deposit_cb_cls,
    4332             :                    serial_id,
    4333             :                    exchange_timestamp,
    4334             :                    wallet_timestamp,
    4335             :                    &merchant_pub,
    4336             :                    &coin_pub,
    4337             :                    &amount_with_fee,
    4338             :                    &deposit_fee,
    4339             :                    &h_contract_terms,
    4340             :                    wire_deadline,
    4341             :                    wire);
    4342          18 :   GNUNET_PQ_cleanup_result (rs);
    4343          18 :   return qs;
    4344             : }
    4345             : 
    4346             : 
    4347             : /**
    4348             :  * Closure for #match_deposit_cb().
    4349             :  */
    4350             : struct MatchingDepositContext
    4351             : {
    4352             :   /**
    4353             :    * Function to call for each result
    4354             :    */
    4355             :   TALER_EXCHANGEDB_MatchingDepositIterator deposit_cb;
    4356             : 
    4357             :   /**
    4358             :    * Closure for @e deposit_cb.
    4359             :    */
    4360             :   void *deposit_cb_cls;
    4361             : 
    4362             :   /**
    4363             :    * Public key of the merchant against which we are matching.
    4364             :    */
    4365             :   const struct TALER_MerchantPublicKeyP *merchant_pub;
    4366             : 
    4367             :   /**
    4368             :    * Plugin context.
    4369             :    */
    4370             :   struct PostgresClosure *pg;
    4371             : 
    4372             :   /**
    4373             :    * Maximum number of results to return.
    4374             :    */
    4375             :   uint32_t limit;
    4376             : 
    4377             :   /**
    4378             :    * Loop counter, actual number of results returned.
    4379             :    */
    4380             :   unsigned int i;
    4381             : 
    4382             :   /**
    4383             :    * Set to #GNUNET_SYSERR on hard errors.
    4384             :    */
    4385             :   int status;
    4386             : };
    4387             : 
    4388             : 
    4389             : /**
    4390             :  * Helper function for #postgres_iterate_matching_deposits().
    4391             :  * To be called with the results of a SELECT statement
    4392             :  * that has returned @a num_results results.
    4393             :  *
    4394             :  * @param cls closure of type `struct MatchingDepositContext *`
    4395             :  * @param result the postgres result
    4396             :  * @param num_results the number of results in @a result
    4397             :  */
    4398             : static void
    4399          17 : match_deposit_cb (void *cls,
    4400             :                   PGresult *result,
    4401             :                   unsigned int num_results)
    4402             : {
    4403          17 :   struct MatchingDepositContext *mdc = cls;
    4404          17 :   struct PostgresClosure *pg = mdc->pg;
    4405             : 
    4406          17 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    4407             :               "Found %u/%u matching deposits\n",
    4408             :               num_results,
    4409             :               mdc->limit);
    4410          17 :   num_results = GNUNET_MIN (num_results,
    4411             :                             mdc->limit);
    4412          35 :   for (mdc->i = 0; mdc->i<num_results; mdc->i++)
    4413             :   {
    4414             :     struct TALER_Amount amount_with_fee;
    4415             :     struct TALER_Amount deposit_fee;
    4416             :     struct GNUNET_HashCode h_contract_terms;
    4417             :     struct TALER_CoinSpendPublicKeyP coin_pub;
    4418             :     uint64_t serial_id;
    4419             :     enum GNUNET_DB_QueryStatus qs;
    4420          18 :     struct GNUNET_PQ_ResultSpec rs[] = {
    4421          18 :       GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
    4422             :                                     &serial_id),
    4423          18 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    4424             :                                    &amount_with_fee),
    4425          18 :       TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
    4426             :                                    &deposit_fee),
    4427          18 :       GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
    4428             :                                             &h_contract_terms),
    4429          18 :       GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
    4430             :                                             &coin_pub),
    4431             :       GNUNET_PQ_result_spec_end
    4432             :     };
    4433             : 
    4434          18 :     if (GNUNET_OK !=
    4435          18 :         GNUNET_PQ_extract_result (result,
    4436             :                                   rs,
    4437          18 :                                   mdc->i))
    4438             :     {
    4439           0 :       GNUNET_break (0);
    4440           0 :       mdc->status = GNUNET_SYSERR;
    4441           0 :       return;
    4442             :     }
    4443          18 :     qs = mdc->deposit_cb (mdc->deposit_cb_cls,
    4444             :                           serial_id,
    4445             :                           &coin_pub,
    4446             :                           &amount_with_fee,
    4447             :                           &deposit_fee,
    4448             :                           &h_contract_terms);
    4449          18 :     GNUNET_PQ_cleanup_result (rs);
    4450          18 :     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    4451           0 :       break;
    4452             :   }
    4453             : }
    4454             : 
    4455             : 
    4456             : /**
    4457             :  * Obtain information about other pending deposits for the same
    4458             :  * destination.  Those deposits must not already be "done".
    4459             :  *
    4460             :  * @param cls the @e cls of this struct with the plugin-specific state
    4461             :  * @param session connection to the database
    4462             :  * @param h_wire destination of the wire transfer
    4463             :  * @param merchant_pub public key of the merchant
    4464             :  * @param deposit_cb function to call for each deposit
    4465             :  * @param deposit_cb_cls closure for @a deposit_cb
    4466             :  * @param limit maximum number of matching deposits to return
    4467             :  * @return transaction status code, if positive:
    4468             :  *         number of rows processed, 0 if none exist
    4469             :  */
    4470             : static enum GNUNET_DB_QueryStatus
    4471          17 : postgres_iterate_matching_deposits (
    4472             :   void *cls,
    4473             :   struct TALER_EXCHANGEDB_Session *session,
    4474             :   const struct GNUNET_HashCode *h_wire,
    4475             :   const struct TALER_MerchantPublicKeyP *merchant_pub,
    4476             :   TALER_EXCHANGEDB_MatchingDepositIterator deposit_cb,
    4477             :   void *deposit_cb_cls,
    4478             :   uint32_t limit)
    4479             : {
    4480          17 :   struct PostgresClosure *pg = cls;
    4481          17 :   struct GNUNET_PQ_QueryParam params[] = {
    4482          17 :     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
    4483          17 :     GNUNET_PQ_query_param_auto_from_type (h_wire),
    4484             :     GNUNET_PQ_query_param_end
    4485             :   };
    4486             :   struct MatchingDepositContext mdc;
    4487             :   enum GNUNET_DB_QueryStatus qs;
    4488             : 
    4489          17 :   mdc.deposit_cb = deposit_cb;
    4490          17 :   mdc.deposit_cb_cls = deposit_cb_cls;
    4491          17 :   mdc.merchant_pub = merchant_pub;
    4492          17 :   mdc.pg = pg;
    4493          17 :   mdc.limit = limit;
    4494          17 :   mdc.status = GNUNET_OK;
    4495          17 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    4496             :                                              "deposits_iterate_matching",
    4497             :                                              params,
    4498             :                                              &match_deposit_cb,
    4499             :                                              &mdc);
    4500          17 :   if (GNUNET_OK != mdc.status)
    4501             :   {
    4502           0 :     GNUNET_break (0);
    4503           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    4504             :   }
    4505          17 :   if (qs >= 0)
    4506          17 :     return mdc.i;
    4507           0 :   return qs;
    4508             : }
    4509             : 
    4510             : 
    4511             : /**
    4512             :  * Retrieve the record for a known coin.
    4513             :  *
    4514             :  * @param cls the plugin closure
    4515             :  * @param session the database session handle
    4516             :  * @param coin_pub the public key of the coin to search for
    4517             :  * @param coin_info place holder for the returned coin information object
    4518             :  * @return transaction status code
    4519             :  */
    4520             : static enum GNUNET_DB_QueryStatus
    4521           0 : postgres_get_known_coin (void *cls,
    4522             :                          struct TALER_EXCHANGEDB_Session *session,
    4523             :                          const struct TALER_CoinSpendPublicKeyP *coin_pub,
    4524             :                          struct TALER_CoinPublicInfo *coin_info)
    4525             : {
    4526           0 :   struct PostgresClosure *pc = cls;
    4527           0 :   struct GNUNET_PQ_QueryParam params[] = {
    4528           0 :     GNUNET_PQ_query_param_auto_from_type (coin_pub),
    4529             :     GNUNET_PQ_query_param_end
    4530             :   };
    4531           0 :   struct GNUNET_PQ_ResultSpec rs[] = {
    4532           0 :     GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    4533             :                                           &coin_info->denom_pub_hash),
    4534           0 :     GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
    4535             :                                          &coin_info->denom_sig.rsa_signature),
    4536             :     GNUNET_PQ_result_spec_end
    4537             :   };
    4538             : 
    4539           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    4540             :               "Getting known coin data for coin %s\n",
    4541             :               TALER_B2S (coin_pub));
    4542           0 :   coin_info->coin_pub = *coin_pub;
    4543           0 :   if (NULL == session)
    4544           0 :     session = postgres_get_session (pc);
    4545           0 :   if (NULL == session)
    4546           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    4547           0 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    4548             :                                                    "get_known_coin",
    4549             :                                                    params,
    4550             :                                                    rs);
    4551             : }
    4552             : 
    4553             : 
    4554             : /**
    4555             :  * Retrieve the denomination of a known coin.
    4556             :  *
    4557             :  * @param cls the plugin closure
    4558             :  * @param session the database session handle
    4559             :  * @param coin_pub the public key of the coin to search for
    4560             :  * @param[out] denom_hash where to store the hash of the coins denomination
    4561             :  * @return transaction status code
    4562             :  */
    4563             : static enum GNUNET_DB_QueryStatus
    4564           0 : postgres_get_coin_denomination (
    4565             :   void *cls,
    4566             :   struct TALER_EXCHANGEDB_Session *session,
    4567             :   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    4568             :   struct GNUNET_HashCode *denom_hash)
    4569             : {
    4570           0 :   struct PostgresClosure *pc = cls;
    4571           0 :   struct GNUNET_PQ_QueryParam params[] = {
    4572           0 :     GNUNET_PQ_query_param_auto_from_type (coin_pub),
    4573             :     GNUNET_PQ_query_param_end
    4574             :   };
    4575           0 :   struct GNUNET_PQ_ResultSpec rs[] = {
    4576           0 :     GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    4577             :                                           denom_hash),
    4578             :     GNUNET_PQ_result_spec_end
    4579             :   };
    4580             : 
    4581           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    4582             :               "Getting coin denomination of coin %s\n",
    4583             :               TALER_B2S (coin_pub));
    4584           0 :   if (NULL == session)
    4585           0 :     session = postgres_get_session (pc);
    4586           0 :   if (NULL == session)
    4587           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    4588           0 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    4589             :                                                    "get_coin_denomination",
    4590             :                                                    params,
    4591             :                                                    rs);
    4592             : }
    4593             : 
    4594             : 
    4595             : /**
    4596             :  * Insert a coin we know of into the DB.  The coin can then be
    4597             :  * referenced by tables for deposits, refresh and refund
    4598             :  * functionality.
    4599             :  *
    4600             :  * @param cls plugin closure
    4601             :  * @param session the shared database session
    4602             :  * @param coin_info the public coin info
    4603             :  * @return query result status
    4604             :  */
    4605             : static enum GNUNET_DB_QueryStatus
    4606          27 : insert_known_coin (void *cls,
    4607             :                    struct TALER_EXCHANGEDB_Session *session,
    4608             :                    const struct TALER_CoinPublicInfo *coin_info)
    4609             : {
    4610          27 :   struct GNUNET_PQ_QueryParam params[] = {
    4611          27 :     GNUNET_PQ_query_param_auto_from_type (&coin_info->coin_pub),
    4612          27 :     GNUNET_PQ_query_param_auto_from_type (&coin_info->denom_pub_hash),
    4613          27 :     GNUNET_PQ_query_param_rsa_signature (coin_info->denom_sig.rsa_signature),
    4614             :     GNUNET_PQ_query_param_end
    4615             :   };
    4616             : 
    4617             :   (void) cls;
    4618          27 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    4619             :               "Creating known coin %s\n",
    4620             :               TALER_B2S (&coin_info->coin_pub));
    4621          27 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    4622             :                                              "insert_known_coin",
    4623             :                                              params);
    4624             : }
    4625             : 
    4626             : 
    4627             : /**
    4628             :  * Count the number of known coins by denomination.
    4629             :  *
    4630             :  * @param cls database connection plugin state
    4631             :  * @param session database session
    4632             :  * @param denom_pub_hash denomination to count by
    4633             :  * @return number of coins if non-negative, otherwise an `enum GNUNET_DB_QueryStatus`
    4634             :  */
    4635             : static long long
    4636           0 : postgres_count_known_coins (void *cls,
    4637             :                             struct TALER_EXCHANGEDB_Session *session,
    4638             :                             const struct GNUNET_HashCode *denom_pub_hash)
    4639             : {
    4640             :   uint64_t count;
    4641           0 :   struct GNUNET_PQ_QueryParam params[] = {
    4642           0 :     GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
    4643             :     GNUNET_PQ_query_param_end
    4644             :   };
    4645           0 :   struct GNUNET_PQ_ResultSpec rs[] = {
    4646           0 :     GNUNET_PQ_result_spec_uint64 ("count",
    4647             :                                   &count),
    4648             :     GNUNET_PQ_result_spec_end
    4649             :   };
    4650             :   enum GNUNET_DB_QueryStatus qs;
    4651             : 
    4652             :   (void) cls;
    4653           0 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    4654             :                                                  "count_known_coins",
    4655             :                                                  params,
    4656             :                                                  rs);
    4657           0 :   if (0 > qs)
    4658           0 :     return (long long) qs;
    4659           0 :   return (long long) count;
    4660             : }
    4661             : 
    4662             : 
    4663             : /**
    4664             :  * Make sure the given @a coin is known to the database.
    4665             :  *
    4666             :  * @param cls database connection plugin state
    4667             :  * @param session database session
    4668             :  * @param coin the coin that must be made known
    4669             :  * @return database transaction status, non-negative on success
    4670             :  */
    4671             : static enum TALER_EXCHANGEDB_CoinKnownStatus
    4672          27 : postgres_ensure_coin_known (void *cls,
    4673             :                             struct TALER_EXCHANGEDB_Session *session,
    4674             :                             const struct TALER_CoinPublicInfo *coin)
    4675             : {
    4676          27 :   struct PostgresClosure *pc = cls;
    4677             :   enum GNUNET_DB_QueryStatus qs;
    4678             :   struct GNUNET_HashCode denom_pub_hash;
    4679          27 :   struct GNUNET_PQ_QueryParam params[] = {
    4680          27 :     GNUNET_PQ_query_param_auto_from_type (&coin->coin_pub),
    4681             :     GNUNET_PQ_query_param_end
    4682             :   };
    4683          27 :   struct GNUNET_PQ_ResultSpec rs[] = {
    4684          27 :     GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    4685             :                                           &denom_pub_hash),
    4686             :     GNUNET_PQ_result_spec_end
    4687             :   };
    4688             : #if EXPLICIT_LOCKS
    4689             :   struct GNUNET_PQ_QueryParam no_params[] = {
    4690             :     GNUNET_PQ_query_param_end
    4691             :   };
    4692             : 
    4693             :   if (0 > (qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    4694             :                                                     "lock_known_coins",
    4695             :                                                     no_params)))
    4696             :     return qs;
    4697             : #endif
    4698             :   /* check if the coin is already known */
    4699          27 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    4700             :                                                  "get_known_coin_dh",
    4701             :                                                  params,
    4702             :                                                  rs);
    4703          27 :   switch (qs)
    4704             :   {
    4705           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    4706           0 :     return TALER_EXCHANGEDB_CKS_SOFT_FAIL;
    4707           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
    4708           0 :     return TALER_EXCHANGEDB_CKS_HARD_FAIL;
    4709           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    4710           0 :     if (0 == GNUNET_memcmp (&denom_pub_hash,
    4711             :                             &coin->denom_pub_hash))
    4712           0 :       return TALER_EXCHANGEDB_CKS_PRESENT;
    4713           0 :     GNUNET_break_op (0);
    4714           0 :     return TALER_EXCHANGEDB_CKS_CONFLICT;
    4715          27 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    4716          27 :     break;
    4717             :   }
    4718             : 
    4719             :   /* if not known, insert it */
    4720          27 :   qs = insert_known_coin (pc,
    4721             :                           session,
    4722             :                           coin);
    4723          27 :   switch (qs)
    4724             :   {
    4725           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    4726           0 :     return TALER_EXCHANGEDB_CKS_SOFT_FAIL;
    4727           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
    4728           0 :     return TALER_EXCHANGEDB_CKS_HARD_FAIL;
    4729           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    4730           0 :     GNUNET_break (0);
    4731           0 :     return TALER_EXCHANGEDB_CKS_HARD_FAIL;
    4732          27 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    4733          27 :     break;
    4734             :   }
    4735          27 :   return TALER_EXCHANGEDB_CKS_ADDED;
    4736             : }
    4737             : 
    4738             : 
    4739             : /**
    4740             :  * Insert information about deposited coin into the database.
    4741             :  *
    4742             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    4743             :  * @param session connection to the database
    4744             :  * @param exchange_timestamp time the exchange received the deposit request
    4745             :  * @param deposit deposit information to store
    4746             :  * @return query result status
    4747             :  */
    4748             : static enum GNUNET_DB_QueryStatus
    4749          25 : postgres_insert_deposit (void *cls,
    4750             :                          struct TALER_EXCHANGEDB_Session *session,
    4751             :                          struct GNUNET_TIME_Absolute exchange_timestamp,
    4752             :                          const struct TALER_EXCHANGEDB_Deposit *deposit)
    4753             : {
    4754          25 :   struct GNUNET_PQ_QueryParam params[] = {
    4755          25 :     GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
    4756          25 :     TALER_PQ_query_param_amount (&deposit->amount_with_fee),
    4757          25 :     TALER_PQ_query_param_absolute_time (&deposit->timestamp),
    4758          25 :     TALER_PQ_query_param_absolute_time (&deposit->refund_deadline),
    4759          25 :     TALER_PQ_query_param_absolute_time (&deposit->wire_deadline),
    4760          25 :     GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
    4761          25 :     GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract_terms),
    4762          25 :     GNUNET_PQ_query_param_auto_from_type (&deposit->h_wire),
    4763          25 :     GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
    4764          25 :     TALER_PQ_query_param_json (deposit->receiver_wire_account),
    4765          25 :     TALER_PQ_query_param_absolute_time (&exchange_timestamp),
    4766             :     GNUNET_PQ_query_param_end
    4767             :   };
    4768             : 
    4769             :   (void) cls;
    4770          25 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4771             :               "Inserting deposit to be executed at %s (%llu/%llu)\n",
    4772             :               GNUNET_STRINGS_absolute_time_to_string (deposit->wire_deadline),
    4773             :               (unsigned long long) deposit->wire_deadline.abs_value_us,
    4774             :               (unsigned long long) deposit->refund_deadline.abs_value_us);
    4775          25 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    4776             :                                              "insert_deposit",
    4777             :                                              params);
    4778             : }
    4779             : 
    4780             : 
    4781             : /**
    4782             :  * Insert information about refunded coin into the database.
    4783             :  *
    4784             :  * @param cls the @e cls of this struct with the plugin-specific state
    4785             :  * @param session connection to the database
    4786             :  * @param refund refund information to store
    4787             :  * @return query result status
    4788             :  */
    4789             : static enum GNUNET_DB_QueryStatus
    4790           1 : postgres_insert_refund (void *cls,
    4791             :                         struct TALER_EXCHANGEDB_Session *session,
    4792             :                         const struct TALER_EXCHANGEDB_Refund *refund)
    4793             : {
    4794           1 :   struct GNUNET_PQ_QueryParam params[] = {
    4795           1 :     GNUNET_PQ_query_param_auto_from_type (&refund->coin.coin_pub),
    4796           1 :     GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_pub),
    4797           1 :     GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_sig),
    4798           1 :     GNUNET_PQ_query_param_auto_from_type (&refund->details.h_contract_terms),
    4799           1 :     GNUNET_PQ_query_param_uint64 (&refund->details.rtransaction_id),
    4800           1 :     TALER_PQ_query_param_amount (&refund->details.refund_amount),
    4801             :     GNUNET_PQ_query_param_end
    4802             :   };
    4803             : 
    4804             :   (void) cls;
    4805           1 :   GNUNET_assert (GNUNET_YES ==
    4806             :                  TALER_amount_cmp_currency (&refund->details.refund_amount,
    4807             :                                             &refund->details.refund_fee));
    4808           1 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    4809             :                                              "insert_refund",
    4810             :                                              params);
    4811             : }
    4812             : 
    4813             : 
    4814             : /**
    4815             :  * Closure for #get_refunds_cb().
    4816             :  */
    4817             : struct SelectRefundContext
    4818             : {
    4819             :   /**
    4820             :    * Function to call on each result.
    4821             :    */
    4822             :   TALER_EXCHANGEDB_RefundCoinCallback cb;
    4823             : 
    4824             :   /**
    4825             :    * Closure for @a cb.
    4826             :    */
    4827             :   void *cb_cls;
    4828             : 
    4829             :   /**
    4830             :    * Plugin context.
    4831             :    */
    4832             :   struct PostgresClosure *pg;
    4833             : 
    4834             :   /**
    4835             :    * Set to #GNUNET_SYSERR on error.
    4836             :    */
    4837             :   int status;
    4838             : };
    4839             : 
    4840             : 
    4841             : /**
    4842             :  * Function to be called with the results of a SELECT statement
    4843             :  * that has returned @a num_results results.
    4844             :  *
    4845             :  * @param cls closure of type `struct SelectRefundContext *`
    4846             :  * @param result the postgres result
    4847             :  * @param num_results the number of results in @a result
    4848             :  */
    4849             : static void
    4850          34 : get_refunds_cb (void *cls,
    4851             :                 PGresult *result,
    4852             :                 unsigned int num_results)
    4853             : {
    4854          34 :   struct SelectRefundContext *srctx = cls;
    4855          34 :   struct PostgresClosure *pg = srctx->pg;
    4856             : 
    4857          35 :   for (unsigned int i = 0; i<num_results; i++)
    4858             :   {
    4859             :     struct TALER_Amount amount_with_fee;
    4860           1 :     struct GNUNET_PQ_ResultSpec rs[] = {
    4861           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    4862             :                                    &amount_with_fee),
    4863             :       GNUNET_PQ_result_spec_end
    4864             :     };
    4865             : 
    4866           1 :     if (GNUNET_OK !=
    4867           1 :         GNUNET_PQ_extract_result (result,
    4868             :                                   rs,
    4869             :                                   i))
    4870             :     {
    4871           0 :       GNUNET_break (0);
    4872           0 :       srctx->status = GNUNET_SYSERR;
    4873           0 :       return;
    4874             :     }
    4875           1 :     if (GNUNET_OK !=
    4876           1 :         srctx->cb (srctx->cb_cls,
    4877             :                    &amount_with_fee))
    4878           0 :       return;
    4879             :   }
    4880             : }
    4881             : 
    4882             : 
    4883             : /**
    4884             :  * Select refunds by @a coin_pub, @a merchant_pub and @a h_contract.
    4885             :  *
    4886             :  * @param cls closure of plugin
    4887             :  * @param session database handle to use
    4888             :  * @param coin_pub coin to get refunds for
    4889             :  * @param merchant_pub merchant to get refunds for
    4890             :  * @param h_contract contract (hash) to get refunds for
    4891             :  * @param cb function to call for each refund found
    4892             :  * @param cb_cls closure for @a cb
    4893             :  * @return query result status
    4894             :  */
    4895             : static enum GNUNET_DB_QueryStatus
    4896          34 : postgres_select_refunds_by_coin (
    4897             :   void *cls,
    4898             :   struct TALER_EXCHANGEDB_Session *session,
    4899             :   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    4900             :   const struct TALER_MerchantPublicKeyP *merchant_pub,
    4901             :   const struct GNUNET_HashCode *h_contract,
    4902             :   TALER_EXCHANGEDB_RefundCoinCallback cb,
    4903             :   void *cb_cls)
    4904             : {
    4905          34 :   struct PostgresClosure *pg = cls;
    4906             :   enum GNUNET_DB_QueryStatus qs;
    4907          34 :   struct GNUNET_PQ_QueryParam params[] = {
    4908          34 :     GNUNET_PQ_query_param_auto_from_type (coin_pub),
    4909          34 :     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
    4910          34 :     GNUNET_PQ_query_param_auto_from_type (h_contract),
    4911             :     GNUNET_PQ_query_param_end
    4912             :   };
    4913          34 :   struct SelectRefundContext srctx = {
    4914             :     .cb = cb,
    4915             :     .cb_cls = cb_cls,
    4916             :     .pg = pg,
    4917             :     .status = GNUNET_OK
    4918             :   };
    4919             : 
    4920          34 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    4921             :                                              "get_refunds_by_coin_and_contract",
    4922             :                                              params,
    4923             :                                              &get_refunds_cb,
    4924             :                                              &srctx);
    4925          34 :   if (GNUNET_SYSERR == srctx.status)
    4926           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    4927          34 :   return qs;
    4928             : }
    4929             : 
    4930             : 
    4931             : /**
    4932             :  * Lookup refresh melt commitment data under the given @a rc.
    4933             :  *
    4934             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    4935             :  * @param session database handle to use, NULL if not run in any transaction
    4936             :  * @param rc commitment hash to use to locate the operation
    4937             :  * @param[out] melt where to store the result; note that
    4938             :  *             melt->session.coin.denom_sig will be set to NULL
    4939             :  *             and is not fetched by this routine (as it is not needed by the client)
    4940             :  * @return transaction status
    4941             :  */
    4942             : static enum GNUNET_DB_QueryStatus
    4943           2 : postgres_get_melt (void *cls,
    4944             :                    struct TALER_EXCHANGEDB_Session *session,
    4945             :                    const struct TALER_RefreshCommitmentP *rc,
    4946             :                    struct TALER_EXCHANGEDB_Melt *melt)
    4947             : {
    4948           2 :   struct PostgresClosure *pg = cls;
    4949           2 :   struct GNUNET_PQ_QueryParam params[] = {
    4950           2 :     GNUNET_PQ_query_param_auto_from_type (rc),
    4951             :     GNUNET_PQ_query_param_end
    4952             :   };
    4953           2 :   struct GNUNET_PQ_ResultSpec rs[] = {
    4954           2 :     GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    4955             :                                           &melt->session.coin.
    4956             :                                           denom_pub_hash),
    4957           2 :     TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
    4958             :                                  &melt->melt_fee),
    4959           2 :     GNUNET_PQ_result_spec_uint32 ("noreveal_index",
    4960             :                                   &melt->session.noreveal_index),
    4961           2 :     GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
    4962             :                                           &melt->session.coin.coin_pub),
    4963           2 :     GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
    4964             :                                           &melt->session.coin_sig),
    4965           2 :     TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    4966             :                                  &melt->session.amount_with_fee),
    4967             :     GNUNET_PQ_result_spec_end
    4968             :   };
    4969             :   enum GNUNET_DB_QueryStatus qs;
    4970             : 
    4971           2 :   melt->session.coin.denom_sig.rsa_signature = NULL;
    4972           2 :   if (NULL == session)
    4973           0 :     session = postgres_get_session (pg);
    4974           2 :   if (NULL == session)
    4975           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    4976           2 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    4977             :                                                  "get_melt",
    4978             :                                                  params,
    4979             :                                                  rs);
    4980           2 :   melt->session.rc = *rc;
    4981           2 :   return qs;
    4982             : }
    4983             : 
    4984             : 
    4985             : /**
    4986             :  * Lookup noreveal index of a previous melt operation under the given
    4987             :  * @a rc.
    4988             :  *
    4989             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    4990             :  * @param session database handle to use
    4991             :  * @param rc commitment hash to use to locate the operation
    4992             :  * @param[out] noreveal_index returns the "gamma" value selected by the
    4993             :  *             exchange which is the index of the transfer key that is
    4994             :  *             not to be revealed to the exchange
    4995             :  * @return transaction status
    4996             :  */
    4997             : static enum GNUNET_DB_QueryStatus
    4998           0 : postgres_get_melt_index (void *cls,
    4999             :                          struct TALER_EXCHANGEDB_Session *session,
    5000             :                          const struct TALER_RefreshCommitmentP *rc,
    5001             :                          uint32_t *noreveal_index)
    5002             : {
    5003           0 :   struct GNUNET_PQ_QueryParam params[] = {
    5004           0 :     GNUNET_PQ_query_param_auto_from_type (rc),
    5005             :     GNUNET_PQ_query_param_end
    5006             :   };
    5007           0 :   struct GNUNET_PQ_ResultSpec rs[] = {
    5008           0 :     GNUNET_PQ_result_spec_uint32 ("noreveal_index",
    5009             :                                   noreveal_index),
    5010             :     GNUNET_PQ_result_spec_end
    5011             :   };
    5012             : 
    5013             :   (void) cls;
    5014           0 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    5015             :                                                    "get_melt_index",
    5016             :                                                    params,
    5017             :                                                    rs);
    5018             : }
    5019             : 
    5020             : 
    5021             : /**
    5022             :  * Store new refresh melt commitment data.
    5023             :  *
    5024             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    5025             :  * @param session database handle to use
    5026             :  * @param refresh_session session data to store
    5027             :  * @return query status for the transaction
    5028             :  */
    5029             : static enum GNUNET_DB_QueryStatus
    5030           1 : postgres_insert_melt (
    5031             :   void *cls,
    5032             :   struct TALER_EXCHANGEDB_Session *session,
    5033             :   const struct TALER_EXCHANGEDB_Refresh *refresh_session)
    5034             : {
    5035           1 :   struct GNUNET_PQ_QueryParam params[] = {
    5036           1 :     GNUNET_PQ_query_param_auto_from_type (&refresh_session->rc),
    5037           1 :     GNUNET_PQ_query_param_auto_from_type (&refresh_session->coin.coin_pub),
    5038           1 :     GNUNET_PQ_query_param_auto_from_type (&refresh_session->coin_sig),
    5039           1 :     TALER_PQ_query_param_amount (&refresh_session->amount_with_fee),
    5040           1 :     GNUNET_PQ_query_param_uint32 (&refresh_session->noreveal_index),
    5041             :     GNUNET_PQ_query_param_end
    5042             :   };
    5043             : 
    5044             :   (void) cls;
    5045           1 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    5046             :                                              "insert_melt",
    5047             :                                              params);
    5048             : }
    5049             : 
    5050             : 
    5051             : /**
    5052             :  * Store in the database which coin(s) the wallet wanted to create
    5053             :  * in a given refresh operation and all of the other information
    5054             :  * we learned or created in the /refresh/reveal step.
    5055             :  *
    5056             :  * @param cls the @e cls of this struct with the plugin-specific state
    5057             :  * @param session database connection
    5058             :  * @param rc identify commitment and thus refresh operation
    5059             :  * @param num_rrcs number of coins to generate, size of the @a rrcs array
    5060             :  * @param rrcs information about the new coins
    5061             :  * @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
    5062             :  * @param tprivs transfer private keys to store
    5063             :  * @param tp public key to store
    5064             :  * @return query status for the transaction
    5065             :  */
    5066             : static enum GNUNET_DB_QueryStatus
    5067           1 : postgres_insert_refresh_reveal (
    5068             :   void *cls,
    5069             :   struct TALER_EXCHANGEDB_Session *session,
    5070             :   const struct TALER_RefreshCommitmentP *rc,
    5071             :   uint32_t num_rrcs,
    5072             :   const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
    5073             :   unsigned int num_tprivs,
    5074             :   const struct TALER_TransferPrivateKeyP *tprivs,
    5075             :   const struct TALER_TransferPublicKeyP *tp)
    5076             : {
    5077             :   (void) cls;
    5078           1 :   if (TALER_CNC_KAPPA != num_tprivs + 1)
    5079             :   {
    5080           0 :     GNUNET_break (0);
    5081           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    5082             :   }
    5083           6 :   for (uint32_t i = 0; i<num_rrcs; i++)
    5084             :   {
    5085           5 :     const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
    5086             :     struct GNUNET_HashCode denom_pub_hash;
    5087             :     struct GNUNET_HashCode h_coin_ev;
    5088           5 :     struct GNUNET_PQ_QueryParam params[] = {
    5089           5 :       GNUNET_PQ_query_param_auto_from_type (rc),
    5090           5 :       GNUNET_PQ_query_param_uint32 (&i),
    5091           5 :       GNUNET_PQ_query_param_auto_from_type (&rrc->orig_coin_link_sig),
    5092           5 :       GNUNET_PQ_query_param_auto_from_type (&denom_pub_hash),
    5093           5 :       GNUNET_PQ_query_param_fixed_size (rrc->coin_ev,
    5094             :                                         rrc->coin_ev_size),
    5095           5 :       GNUNET_PQ_query_param_auto_from_type (&h_coin_ev),
    5096           5 :       GNUNET_PQ_query_param_rsa_signature (rrc->coin_sig.rsa_signature),
    5097             :       GNUNET_PQ_query_param_end
    5098             :     };
    5099             :     enum GNUNET_DB_QueryStatus qs;
    5100             : 
    5101           5 :     GNUNET_CRYPTO_rsa_public_key_hash (rrc->denom_pub.rsa_public_key,
    5102             :                                        &denom_pub_hash);
    5103           5 :     GNUNET_CRYPTO_hash (rrc->coin_ev,
    5104             :                         rrc->coin_ev_size,
    5105             :                         &h_coin_ev);
    5106           5 :     qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    5107             :                                              "insert_refresh_revealed_coin",
    5108             :                                              params);
    5109           5 :     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    5110           0 :       return qs;
    5111             :   }
    5112             : 
    5113             :   {
    5114           1 :     struct GNUNET_PQ_QueryParam params[] = {
    5115           1 :       GNUNET_PQ_query_param_auto_from_type (rc),
    5116           1 :       GNUNET_PQ_query_param_auto_from_type (tp),
    5117           1 :       GNUNET_PQ_query_param_fixed_size (tprivs,
    5118             :                                         num_tprivs * sizeof (struct
    5119             :                                                              TALER_TransferPrivateKeyP)),
    5120             :       GNUNET_PQ_query_param_end
    5121             :     };
    5122             : 
    5123           1 :     return GNUNET_PQ_eval_prepared_non_select (session->conn,
    5124             :                                                "insert_refresh_transfer_keys",
    5125             :                                                params);
    5126             :   }
    5127             : }
    5128             : 
    5129             : 
    5130             : /**
    5131             :  * Context where we aggregate data from the database.
    5132             :  * Closure for #add_revealed_coins().
    5133             :  */
    5134             : struct GetRevealContext
    5135             : {
    5136             :   /**
    5137             :    * Array of revealed coins we obtained from the DB.
    5138             :    */
    5139             :   struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs;
    5140             : 
    5141             :   /**
    5142             :    * Length of the @a rrcs array.
    5143             :    */
    5144             :   unsigned int rrcs_len;
    5145             : 
    5146             :   /**
    5147             :    * Set to an error code if we ran into trouble.
    5148             :    */
    5149             :   enum GNUNET_DB_QueryStatus qs;
    5150             : };
    5151             : 
    5152             : 
    5153             : /**
    5154             :  * Function to be called with the results of a SELECT statement
    5155             :  * that has returned @a num_results results.
    5156             :  *
    5157             :  * @param cls closure of type `struct GetRevealContext`
    5158             :  * @param result the postgres result
    5159             :  * @param num_results the number of results in @a result
    5160             :  */
    5161             : static void
    5162           2 : add_revealed_coins (void *cls,
    5163             :                     PGresult *result,
    5164             :                     unsigned int num_results)
    5165             : {
    5166           2 :   struct GetRevealContext *grctx = cls;
    5167             : 
    5168           2 :   if (0 == num_results)
    5169           1 :     return;
    5170           1 :   grctx->rrcs = GNUNET_new_array (num_results,
    5171             :                                   struct TALER_EXCHANGEDB_RefreshRevealedCoin);
    5172           1 :   grctx->rrcs_len = num_results;
    5173           6 :   for (unsigned int i = 0; i < num_results; i++)
    5174             :   {
    5175           5 :     struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &grctx->rrcs[i];
    5176             :     uint32_t off;
    5177           5 :     struct GNUNET_PQ_ResultSpec rs[] = {
    5178           5 :       GNUNET_PQ_result_spec_uint32 ("freshcoin_index",
    5179             :                                     &off),
    5180           5 :       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    5181             :                                             &rrc->denom_pub.rsa_public_key),
    5182           5 :       GNUNET_PQ_result_spec_auto_from_type ("link_sig",
    5183             :                                             &rrc->orig_coin_link_sig),
    5184           5 :       GNUNET_PQ_result_spec_variable_size ("coin_ev",
    5185           5 :                                            (void **) &rrc->coin_ev,
    5186             :                                            &rrc->coin_ev_size),
    5187           5 :       GNUNET_PQ_result_spec_rsa_signature ("ev_sig",
    5188             :                                            &rrc->coin_sig.rsa_signature),
    5189             :       GNUNET_PQ_result_spec_end
    5190             :     };
    5191             : 
    5192           5 :     if (GNUNET_OK !=
    5193           5 :         GNUNET_PQ_extract_result (result,
    5194             :                                   rs,
    5195             :                                   i))
    5196             :     {
    5197           0 :       GNUNET_break (0);
    5198           0 :       grctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
    5199           0 :       return;
    5200             :     }
    5201           5 :     if (off != i)
    5202             :     {
    5203           0 :       GNUNET_break (0);
    5204           0 :       grctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
    5205           0 :       return;
    5206             :     }
    5207             :   }
    5208             : }
    5209             : 
    5210             : 
    5211             : /**
    5212             :  * Lookup in the database the coins that we want to
    5213             :  * create in the given refresh operation.
    5214             :  *
    5215             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    5216             :  * @param session database connection
    5217             :  * @param rc identify commitment and thus refresh operation
    5218             :  * @param cb function to call with the results
    5219             :  * @param cb_cls closure for @a cb
    5220             :  * @return transaction status
    5221             :  */
    5222             : static enum GNUNET_DB_QueryStatus
    5223           2 : postgres_get_refresh_reveal (void *cls,
    5224             :                              struct TALER_EXCHANGEDB_Session *session,
    5225             :                              const struct TALER_RefreshCommitmentP *rc,
    5226             :                              TALER_EXCHANGEDB_RefreshCallback cb,
    5227             :                              void *cb_cls)
    5228             : {
    5229             :   struct GetRevealContext grctx;
    5230             :   enum GNUNET_DB_QueryStatus qs;
    5231             :   struct TALER_TransferPublicKeyP tp;
    5232             :   void *tpriv;
    5233             :   size_t tpriv_size;
    5234           2 :   struct GNUNET_PQ_QueryParam params[] = {
    5235           2 :     GNUNET_PQ_query_param_auto_from_type (rc),
    5236             :     GNUNET_PQ_query_param_end
    5237             :   };
    5238           2 :   struct GNUNET_PQ_ResultSpec rs[] = {
    5239           2 :     GNUNET_PQ_result_spec_auto_from_type ("transfer_pub",
    5240             :                                           &tp),
    5241           2 :     GNUNET_PQ_result_spec_variable_size ("transfer_privs",
    5242             :                                          &tpriv,
    5243             :                                          &tpriv_size),
    5244             :     GNUNET_PQ_result_spec_end
    5245             :   };
    5246             : 
    5247             :   (void) cls;
    5248             :   /* First get the coins */
    5249           2 :   memset (&grctx,
    5250             :           0,
    5251             :           sizeof (grctx));
    5252           2 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    5253             :                                              "get_refresh_revealed_coins",
    5254             :                                              params,
    5255             :                                              &add_revealed_coins,
    5256             :                                              &grctx);
    5257           2 :   switch (qs)
    5258             :   {
    5259           1 :   case GNUNET_DB_STATUS_HARD_ERROR:
    5260             :   case GNUNET_DB_STATUS_SOFT_ERROR:
    5261             :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    5262           1 :     goto cleanup;
    5263           1 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    5264             :   default:   /* can have more than one result */
    5265           1 :     break;
    5266             :   }
    5267           1 :   switch (grctx.qs)
    5268             :   {
    5269           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    5270             :   case GNUNET_DB_STATUS_SOFT_ERROR:
    5271           0 :     goto cleanup;
    5272           1 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    5273             :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:   /* should be impossible */
    5274           1 :     break;
    5275             :   }
    5276             : 
    5277             :   /* now also get the transfer keys (public and private) */
    5278           1 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    5279             :                                                  "get_refresh_transfer_keys",
    5280             :                                                  params,
    5281             :                                                  rs);
    5282           1 :   switch (qs)
    5283             :   {
    5284           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    5285             :   case GNUNET_DB_STATUS_SOFT_ERROR:
    5286             :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    5287           0 :     goto cleanup;
    5288           1 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    5289           1 :     break;
    5290           0 :   default:
    5291           0 :     GNUNET_assert (0);
    5292             :   }
    5293           1 :   if ( (0 != tpriv_size % sizeof (struct TALER_TransferPrivateKeyP)) ||
    5294           1 :        (TALER_CNC_KAPPA - 1 != tpriv_size / sizeof (struct
    5295             :                                                     TALER_TransferPrivateKeyP)) )
    5296             :   {
    5297           0 :     GNUNET_break (0);
    5298           0 :     qs = GNUNET_DB_STATUS_HARD_ERROR;
    5299           0 :     GNUNET_PQ_cleanup_result (rs);
    5300           0 :     goto cleanup;
    5301             :   }
    5302             : 
    5303             :   /* Pass result back to application */
    5304           1 :   cb (cb_cls,
    5305             :       grctx.rrcs_len,
    5306           1 :       grctx.rrcs,
    5307           1 :       tpriv_size / sizeof (struct TALER_TransferPrivateKeyP),
    5308             :       (const struct TALER_TransferPrivateKeyP *) tpriv,
    5309             :       &tp);
    5310           1 :   GNUNET_PQ_cleanup_result (rs);
    5311             : 
    5312           2 : cleanup:
    5313           7 :   for (unsigned int i = 0; i < grctx.rrcs_len; i++)
    5314             :   {
    5315           5 :     struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &grctx.rrcs[i];
    5316             : 
    5317           5 :     if (NULL != rrc->denom_pub.rsa_public_key)
    5318           5 :       GNUNET_CRYPTO_rsa_public_key_free (rrc->denom_pub.rsa_public_key);
    5319           5 :     if (NULL != rrc->coin_sig.rsa_signature)
    5320           5 :       GNUNET_CRYPTO_rsa_signature_free (rrc->coin_sig.rsa_signature);
    5321           5 :     GNUNET_free (rrc->coin_ev);
    5322             :   }
    5323           2 :   GNUNET_free (grctx.rrcs);
    5324             : 
    5325           2 :   return qs;
    5326             : }
    5327             : 
    5328             : 
    5329             : /**
    5330             :  * Closure for #add_ldl().
    5331             :  */
    5332             : struct LinkDataContext
    5333             : {
    5334             :   /**
    5335             :    * Function to call on each result.
    5336             :    */
    5337             :   TALER_EXCHANGEDB_LinkCallback ldc;
    5338             : 
    5339             :   /**
    5340             :    * Closure for @e ldc.
    5341             :    */
    5342             :   void *ldc_cls;
    5343             : 
    5344             :   /**
    5345             :    * Last transfer public key for which we have information in @e last.
    5346             :    * Only valid if @e last is non-NULL.
    5347             :    */
    5348             :   struct TALER_TransferPublicKeyP transfer_pub;
    5349             : 
    5350             :   /**
    5351             :    * Link data for @e transfer_pub
    5352             :    */
    5353             :   struct TALER_EXCHANGEDB_LinkList *last;
    5354             : 
    5355             :   /**
    5356             :    * Status, set to #GNUNET_SYSERR on errors,
    5357             :    */
    5358             :   int status;
    5359             : };
    5360             : 
    5361             : 
    5362             : /**
    5363             :  * Free memory of the link data list.
    5364             :  *
    5365             :  * @param cls the @e cls of this struct with the plugin-specific state (unused)
    5366             :  * @param ldl link data list to release
    5367             :  */
    5368             : static void
    5369           1 : free_link_data_list (void *cls,
    5370             :                      struct TALER_EXCHANGEDB_LinkList *ldl)
    5371             : {
    5372             :   struct TALER_EXCHANGEDB_LinkList *next;
    5373             : 
    5374             :   (void) cls;
    5375           6 :   while (NULL != ldl)
    5376             :   {
    5377           5 :     next = ldl->next;
    5378           5 :     if (NULL != ldl->denom_pub.rsa_public_key)
    5379           5 :       GNUNET_CRYPTO_rsa_public_key_free (ldl->denom_pub.rsa_public_key);
    5380           5 :     if (NULL != ldl->ev_sig.rsa_signature)
    5381           5 :       GNUNET_CRYPTO_rsa_signature_free (ldl->ev_sig.rsa_signature);
    5382           5 :     GNUNET_free (ldl);
    5383           5 :     ldl = next;
    5384             :   }
    5385           1 : }
    5386             : 
    5387             : 
    5388             : /**
    5389             :  * Function to be called with the results of a SELECT statement
    5390             :  * that has returned @a num_results results.
    5391             :  *
    5392             :  * @param cls closure of type `struct LinkDataContext *`
    5393             :  * @param result the postgres result
    5394             :  * @param num_results the number of results in @a result
    5395             :  */
    5396             : static void
    5397           1 : add_ldl (void *cls,
    5398             :          PGresult *result,
    5399             :          unsigned int num_results)
    5400             : {
    5401           1 :   struct LinkDataContext *ldctx = cls;
    5402             : 
    5403           6 :   for (int i = num_results - 1; i >= 0; i--)
    5404             :   {
    5405             :     struct TALER_EXCHANGEDB_LinkList *pos;
    5406             :     struct TALER_TransferPublicKeyP transfer_pub;
    5407             : 
    5408           5 :     pos = GNUNET_new (struct TALER_EXCHANGEDB_LinkList);
    5409             :     {
    5410           5 :       struct GNUNET_PQ_ResultSpec rs[] = {
    5411           5 :         GNUNET_PQ_result_spec_auto_from_type ("transfer_pub",
    5412             :                                               &transfer_pub),
    5413           5 :         GNUNET_PQ_result_spec_auto_from_type ("link_sig",
    5414             :                                               &pos->orig_coin_link_sig),
    5415           5 :         GNUNET_PQ_result_spec_rsa_signature ("ev_sig",
    5416             :                                              &pos->ev_sig.rsa_signature),
    5417           5 :         GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    5418             :                                               &pos->denom_pub.rsa_public_key),
    5419             :         GNUNET_PQ_result_spec_end
    5420             :       };
    5421             : 
    5422           5 :       if (GNUNET_OK !=
    5423           5 :           GNUNET_PQ_extract_result (result,
    5424             :                                     rs,
    5425             :                                     i))
    5426             :       {
    5427           0 :         GNUNET_break (0);
    5428           0 :         GNUNET_free (pos);
    5429           0 :         ldctx->status = GNUNET_SYSERR;
    5430           0 :         return;
    5431             :       }
    5432             :     }
    5433           5 :     if ( (NULL != ldctx->last) &&
    5434           4 :          (0 == GNUNET_memcmp (&transfer_pub,
    5435             :                               &ldctx->transfer_pub)) )
    5436             :     {
    5437           4 :       pos->next = ldctx->last;
    5438             :     }
    5439             :     else
    5440             :     {
    5441           1 :       if (NULL != ldctx->last)
    5442             :       {
    5443           0 :         ldctx->ldc (ldctx->ldc_cls,
    5444           0 :                     &ldctx->transfer_pub,
    5445           0 :                     ldctx->last);
    5446           0 :         free_link_data_list (cls,
    5447             :                              ldctx->last);
    5448             :       }
    5449           1 :       ldctx->transfer_pub = transfer_pub;
    5450             :     }
    5451           5 :     ldctx->last = pos;
    5452             :   }
    5453             : }
    5454             : 
    5455             : 
    5456             : /**
    5457             :  * Obtain the link data of a coin, that is the encrypted link
    5458             :  * information, the denomination keys and the signatures.
    5459             :  *
    5460             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    5461             :  * @param session database connection
    5462             :  * @param coin_pub public key of the coin
    5463             :  * @param ldc function to call for each session the coin was melted into
    5464             :  * @param ldc_cls closure for @a tdc
    5465             :  * @return transaction status code
    5466             :  */
    5467             : static enum GNUNET_DB_QueryStatus
    5468           1 : postgres_get_link_data (void *cls,
    5469             :                         struct TALER_EXCHANGEDB_Session *session,
    5470             :                         const struct TALER_CoinSpendPublicKeyP *coin_pub,
    5471             :                         TALER_EXCHANGEDB_LinkCallback ldc,
    5472             :                         void *ldc_cls)
    5473             : {
    5474           1 :   struct GNUNET_PQ_QueryParam params[] = {
    5475           1 :     GNUNET_PQ_query_param_auto_from_type (coin_pub),
    5476             :     GNUNET_PQ_query_param_end
    5477             :   };
    5478             :   enum GNUNET_DB_QueryStatus qs;
    5479             :   struct LinkDataContext ldctx;
    5480             : 
    5481           1 :   ldctx.ldc = ldc;
    5482           1 :   ldctx.ldc_cls = ldc_cls;
    5483           1 :   ldctx.last = NULL;
    5484           1 :   ldctx.status = GNUNET_OK;
    5485           1 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    5486             :                                              "get_link",
    5487             :                                              params,
    5488             :                                              &add_ldl,
    5489             :                                              &ldctx);
    5490           1 :   if (NULL != ldctx.last)
    5491             :   {
    5492           1 :     if (GNUNET_OK == ldctx.status)
    5493             :     {
    5494             :       /* call callback one more time! */
    5495           1 :       ldc (ldc_cls,
    5496             :            &ldctx.transfer_pub,
    5497           1 :            ldctx.last);
    5498             :     }
    5499           1 :     free_link_data_list (cls,
    5500             :                          ldctx.last);
    5501           1 :     ldctx.last = NULL;
    5502             :   }
    5503           1 :   if (GNUNET_OK != ldctx.status)
    5504           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    5505           1 :   return qs;
    5506             : }
    5507             : 
    5508             : 
    5509             : /**
    5510             :  * Closure for callbacks called from #postgres_get_coin_transactions()
    5511             :  */
    5512             : struct CoinHistoryContext
    5513             : {
    5514             :   /**
    5515             :    * Head of the coin's history list.
    5516             :    */
    5517             :   struct TALER_EXCHANGEDB_TransactionList *head;
    5518             : 
    5519             :   /**
    5520             :    * Public key of the coin we are building the history for.
    5521             :    */
    5522             :   const struct TALER_CoinSpendPublicKeyP *coin_pub;
    5523             : 
    5524             :   /**
    5525             :    * Closure for all callbacks of this database plugin.
    5526             :    */
    5527             :   void *db_cls;
    5528             : 
    5529             :   /**
    5530             :    * Database session we are using.
    5531             :    */
    5532             :   struct TALER_EXCHANGEDB_Session *session;
    5533             : 
    5534             :   /**
    5535             :    * Plugin context.
    5536             :    */
    5537             :   struct PostgresClosure *pg;
    5538             : 
    5539             :   /**
    5540             :    * Set to 'true' if the transaction failed.
    5541             :    */
    5542             :   bool failed;
    5543             : 
    5544             :   /**
    5545             :    * Set to 'true' if we found a deposit or melt (for invariant check).
    5546             :    */
    5547             :   bool have_deposit_or_melt;
    5548             : };
    5549             : 
    5550             : 
    5551             : /**
    5552             :  * Function to be called with the results of a SELECT statement
    5553             :  * that has returned @a num_results results.
    5554             :  *
    5555             :  * @param cls closure of type `struct CoinHistoryContext`
    5556             :  * @param result the postgres result
    5557             :  * @param num_results the number of results in @a result
    5558             :  */
    5559             : static void
    5560           2 : add_coin_deposit (void *cls,
    5561             :                   PGresult *result,
    5562             :                   unsigned int num_results)
    5563             : {
    5564           2 :   struct CoinHistoryContext *chc = cls;
    5565           2 :   struct PostgresClosure *pg = chc->pg;
    5566             : 
    5567           3 :   for (unsigned int i = 0; i < num_results; i++)
    5568             :   {
    5569             :     struct TALER_EXCHANGEDB_DepositListEntry *deposit;
    5570             :     struct TALER_EXCHANGEDB_TransactionList *tl;
    5571             :     uint64_t serial_id;
    5572             : 
    5573           1 :     chc->have_deposit_or_melt = true;
    5574           1 :     deposit = GNUNET_new (struct TALER_EXCHANGEDB_DepositListEntry);
    5575             :     {
    5576           1 :       uint8_t done = 0;
    5577           1 :       struct GNUNET_PQ_ResultSpec rs[] = {
    5578           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    5579             :                                      &deposit->amount_with_fee),
    5580           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
    5581             :                                      &deposit->deposit_fee),
    5582           1 :         TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
    5583             :                                             &deposit->timestamp),
    5584           1 :         TALER_PQ_result_spec_absolute_time ("refund_deadline",
    5585             :                                             &deposit->refund_deadline),
    5586           1 :         TALER_PQ_result_spec_absolute_time ("wire_deadline",
    5587             :                                             &deposit->wire_deadline),
    5588           1 :         GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    5589             :                                               &deposit->h_denom_pub),
    5590           1 :         GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
    5591             :                                               &deposit->merchant_pub),
    5592           1 :         GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
    5593             :                                               &deposit->h_contract_terms),
    5594           1 :         GNUNET_PQ_result_spec_auto_from_type ("h_wire",
    5595             :                                               &deposit->h_wire),
    5596           1 :         TALER_PQ_result_spec_json ("wire",
    5597             :                                    &deposit->receiver_wire_account),
    5598           1 :         GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
    5599             :                                               &deposit->csig),
    5600           1 :         GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
    5601             :                                       &serial_id),
    5602           1 :         GNUNET_PQ_result_spec_auto_from_type ("done",
    5603             :                                               &done),
    5604             :         GNUNET_PQ_result_spec_end
    5605             :       };
    5606             : 
    5607           1 :       if (GNUNET_OK !=
    5608           1 :           GNUNET_PQ_extract_result (result,
    5609             :                                     rs,
    5610             :                                     i))
    5611             :       {
    5612           0 :         GNUNET_break (0);
    5613           0 :         GNUNET_free (deposit);
    5614           0 :         chc->failed = true;
    5615           0 :         return;
    5616             :       }
    5617           1 :       deposit->done = (0 != done);
    5618             :     }
    5619           1 :     tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
    5620           1 :     tl->next = chc->head;
    5621           1 :     tl->type = TALER_EXCHANGEDB_TT_DEPOSIT;
    5622           1 :     tl->details.deposit = deposit;
    5623           1 :     tl->serial_id = serial_id;
    5624           1 :     chc->head = tl;
    5625             :   }
    5626             : }
    5627             : 
    5628             : 
    5629             : /**
    5630             :  * Function to be called with the results of a SELECT statement
    5631             :  * that has returned @a num_results results.
    5632             :  *
    5633             :  * @param cls closure of type `struct CoinHistoryContext`
    5634             :  * @param result the postgres result
    5635             :  * @param num_results the number of results in @a result
    5636             :  */
    5637             : static void
    5638           2 : add_coin_melt (void *cls,
    5639             :                PGresult *result,
    5640             :                unsigned int num_results)
    5641             : {
    5642           2 :   struct CoinHistoryContext *chc = cls;
    5643           2 :   struct PostgresClosure *pg = chc->pg;
    5644             : 
    5645           3 :   for (unsigned int i = 0; i<num_results; i++)
    5646             :   {
    5647             :     struct TALER_EXCHANGEDB_MeltListEntry *melt;
    5648             :     struct TALER_EXCHANGEDB_TransactionList *tl;
    5649             :     uint64_t serial_id;
    5650             : 
    5651           1 :     chc->have_deposit_or_melt = true;
    5652           1 :     melt = GNUNET_new (struct TALER_EXCHANGEDB_MeltListEntry);
    5653             :     {
    5654           1 :       struct GNUNET_PQ_ResultSpec rs[] = {
    5655           1 :         GNUNET_PQ_result_spec_auto_from_type ("rc",
    5656             :                                               &melt->rc),
    5657             :         /* oldcoin_index not needed */
    5658           1 :         GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    5659             :                                               &melt->h_denom_pub),
    5660           1 :         GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
    5661             :                                               &melt->coin_sig),
    5662           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    5663             :                                      &melt->amount_with_fee),
    5664           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",
    5665             :                                      &melt->melt_fee),
    5666           1 :         GNUNET_PQ_result_spec_uint64 ("melt_serial_id",
    5667             :                                       &serial_id),
    5668             :         GNUNET_PQ_result_spec_end
    5669             :       };
    5670             : 
    5671           1 :       if (GNUNET_OK !=
    5672           1 :           GNUNET_PQ_extract_result (result,
    5673             :                                     rs,
    5674             :                                     i))
    5675             :       {
    5676           0 :         GNUNET_break (0);
    5677           0 :         GNUNET_free (melt);
    5678           0 :         chc->failed = true;
    5679           0 :         return;
    5680             :       }
    5681             :     }
    5682           1 :     tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
    5683           1 :     tl->next = chc->head;
    5684           1 :     tl->type = TALER_EXCHANGEDB_TT_MELT;
    5685           1 :     tl->details.melt = melt;
    5686           1 :     tl->serial_id = serial_id;
    5687           1 :     chc->head = tl;
    5688             :   }
    5689             : }
    5690             : 
    5691             : 
    5692             : /**
    5693             :  * Function to be called with the results of a SELECT statement
    5694             :  * that has returned @a num_results results.
    5695             :  *
    5696             :  * @param cls closure of type `struct CoinHistoryContext`
    5697             :  * @param result the postgres result
    5698             :  * @param num_results the number of results in @a result
    5699             :  */
    5700             : static void
    5701           2 : add_coin_refund (void *cls,
    5702             :                  PGresult *result,
    5703             :                  unsigned int num_results)
    5704             : {
    5705           2 :   struct CoinHistoryContext *chc = cls;
    5706           2 :   struct PostgresClosure *pg = chc->pg;
    5707             : 
    5708           3 :   for (unsigned int i = 0; i<num_results; i++)
    5709             :   {
    5710             :     struct TALER_EXCHANGEDB_RefundListEntry *refund;
    5711             :     struct TALER_EXCHANGEDB_TransactionList *tl;
    5712             :     uint64_t serial_id;
    5713             : 
    5714           1 :     refund = GNUNET_new (struct TALER_EXCHANGEDB_RefundListEntry);
    5715             :     {
    5716           1 :       struct GNUNET_PQ_ResultSpec rs[] = {
    5717           1 :         GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
    5718             :                                               &refund->merchant_pub),
    5719           1 :         GNUNET_PQ_result_spec_auto_from_type ("merchant_sig",
    5720             :                                               &refund->merchant_sig),
    5721           1 :         GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
    5722             :                                               &refund->h_contract_terms),
    5723           1 :         GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
    5724             :                                       &refund->rtransaction_id),
    5725           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    5726             :                                      &refund->refund_amount),
    5727           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
    5728             :                                      &refund->refund_fee),
    5729           1 :         GNUNET_PQ_result_spec_uint64 ("refund_serial_id",
    5730             :                                       &serial_id),
    5731             :         GNUNET_PQ_result_spec_end
    5732             :       };
    5733             : 
    5734           1 :       if (GNUNET_OK !=
    5735           1 :           GNUNET_PQ_extract_result (result,
    5736             :                                     rs,
    5737             :                                     i))
    5738             :       {
    5739           0 :         GNUNET_break (0);
    5740           0 :         GNUNET_free (refund);
    5741           0 :         chc->failed = true;
    5742           0 :         return;
    5743             :       }
    5744             :     }
    5745           1 :     tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
    5746           1 :     tl->next = chc->head;
    5747           1 :     tl->type = TALER_EXCHANGEDB_TT_REFUND;
    5748           1 :     tl->details.refund = refund;
    5749           1 :     tl->serial_id = serial_id;
    5750           1 :     chc->head = tl;
    5751             :   }
    5752             : }
    5753             : 
    5754             : 
    5755             : /**
    5756             :  * Function to be called with the results of a SELECT statement
    5757             :  * that has returned @a num_results results.
    5758             :  *
    5759             :  * @param cls closure of type `struct CoinHistoryContext`
    5760             :  * @param result the postgres result
    5761             :  * @param num_results the number of results in @a result
    5762             :  */
    5763             : static void
    5764           2 : add_old_coin_recoup (void *cls,
    5765             :                      PGresult *result,
    5766             :                      unsigned int num_results)
    5767             : {
    5768           2 :   struct CoinHistoryContext *chc = cls;
    5769           2 :   struct PostgresClosure *pg = chc->pg;
    5770             : 
    5771           2 :   for (unsigned int i = 0; i<num_results; i++)
    5772             :   {
    5773             :     struct TALER_EXCHANGEDB_RecoupRefreshListEntry *recoup;
    5774             :     struct TALER_EXCHANGEDB_TransactionList *tl;
    5775             :     uint64_t serial_id;
    5776             : 
    5777           0 :     recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupRefreshListEntry);
    5778             :     {
    5779           0 :       struct GNUNET_PQ_ResultSpec rs[] = {
    5780           0 :         GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
    5781             :                                               &recoup->coin.coin_pub),
    5782           0 :         GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
    5783             :                                               &recoup->coin_sig),
    5784           0 :         GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
    5785             :                                               &recoup->coin_blind),
    5786           0 :         TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
    5787             :                                      &recoup->value),
    5788           0 :         TALER_PQ_result_spec_absolute_time ("timestamp",
    5789             :                                             &recoup->timestamp),
    5790           0 :         GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    5791             :                                               &recoup->coin.denom_pub_hash),
    5792           0 :         GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
    5793             :                                              &recoup->coin.denom_sig.
    5794             :                                              rsa_signature),
    5795           0 :         GNUNET_PQ_result_spec_uint64 ("recoup_refresh_uuid",
    5796             :                                       &serial_id),
    5797             :         GNUNET_PQ_result_spec_end
    5798             :       };
    5799             : 
    5800           0 :       if (GNUNET_OK !=
    5801           0 :           GNUNET_PQ_extract_result (result,
    5802             :                                     rs,
    5803             :                                     i))
    5804             :       {
    5805           0 :         GNUNET_break (0);
    5806           0 :         GNUNET_free (recoup);
    5807           0 :         chc->failed = true;
    5808           0 :         return;
    5809             :       }
    5810           0 :       recoup->old_coin_pub = *chc->coin_pub;
    5811             :     }
    5812           0 :     tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
    5813           0 :     tl->next = chc->head;
    5814           0 :     tl->type = TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP;
    5815           0 :     tl->details.old_coin_recoup = recoup;
    5816           0 :     tl->serial_id = serial_id;
    5817           0 :     chc->head = tl;
    5818             :   }
    5819             : }
    5820             : 
    5821             : 
    5822             : /**
    5823             :  * Function to be called with the results of a SELECT statement
    5824             :  * that has returned @a num_results results.
    5825             :  *
    5826             :  * @param cls closure of type `struct CoinHistoryContext`
    5827             :  * @param result the postgres result
    5828             :  * @param num_results the number of results in @a result
    5829             :  */
    5830             : static void
    5831           2 : add_coin_recoup (void *cls,
    5832             :                  PGresult *result,
    5833             :                  unsigned int num_results)
    5834             : {
    5835           2 :   struct CoinHistoryContext *chc = cls;
    5836           2 :   struct PostgresClosure *pg = chc->pg;
    5837             : 
    5838           3 :   for (unsigned int i = 0; i<num_results; i++)
    5839             :   {
    5840             :     struct TALER_EXCHANGEDB_RecoupListEntry *recoup;
    5841             :     struct TALER_EXCHANGEDB_TransactionList *tl;
    5842             :     uint64_t serial_id;
    5843             : 
    5844           1 :     recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupListEntry);
    5845             :     {
    5846           1 :       struct GNUNET_PQ_ResultSpec rs[] = {
    5847           1 :         GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
    5848             :                                               &recoup->reserve_pub),
    5849           1 :         GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
    5850             :                                               &recoup->coin_sig),
    5851           1 :         GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    5852             :                                               &recoup->h_denom_pub),
    5853           1 :         GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
    5854             :                                               &recoup->coin_blind),
    5855           1 :         TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
    5856             :                                      &recoup->value),
    5857           1 :         TALER_PQ_result_spec_absolute_time ("timestamp",
    5858             :                                             &recoup->timestamp),
    5859           1 :         GNUNET_PQ_result_spec_uint64 ("recoup_uuid",
    5860             :                                       &serial_id),
    5861             :         GNUNET_PQ_result_spec_end
    5862             :       };
    5863             : 
    5864           1 :       if (GNUNET_OK !=
    5865           1 :           GNUNET_PQ_extract_result (result,
    5866             :                                     rs,
    5867             :                                     i))
    5868             :       {
    5869           0 :         GNUNET_break (0);
    5870           0 :         GNUNET_free (recoup);
    5871           0 :         chc->failed = true;
    5872           0 :         return;
    5873             :       }
    5874             :     }
    5875           1 :     tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
    5876           1 :     tl->next = chc->head;
    5877           1 :     tl->type = TALER_EXCHANGEDB_TT_RECOUP;
    5878           1 :     tl->details.recoup = recoup;
    5879           1 :     tl->serial_id = serial_id;
    5880           1 :     chc->head = tl;
    5881             :   }
    5882             : }
    5883             : 
    5884             : 
    5885             : /**
    5886             :  * Function to be called with the results of a SELECT statement
    5887             :  * that has returned @a num_results results.
    5888             :  *
    5889             :  * @param cls closure of type `struct CoinHistoryContext`
    5890             :  * @param result the postgres result
    5891             :  * @param num_results the number of results in @a result
    5892             :  */
    5893             : static void
    5894           2 : add_coin_recoup_refresh (void *cls,
    5895             :                          PGresult *result,
    5896             :                          unsigned int num_results)
    5897             : {
    5898           2 :   struct CoinHistoryContext *chc = cls;
    5899           2 :   struct PostgresClosure *pg = chc->pg;
    5900             : 
    5901           2 :   for (unsigned int i = 0; i<num_results; i++)
    5902             :   {
    5903             :     struct TALER_EXCHANGEDB_RecoupRefreshListEntry *recoup;
    5904             :     struct TALER_EXCHANGEDB_TransactionList *tl;
    5905             :     uint64_t serial_id;
    5906             : 
    5907           0 :     recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupRefreshListEntry);
    5908             :     {
    5909           0 :       struct GNUNET_PQ_ResultSpec rs[] = {
    5910           0 :         GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
    5911             :                                               &recoup->old_coin_pub),
    5912           0 :         GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
    5913             :                                               &recoup->coin_sig),
    5914           0 :         GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
    5915             :                                               &recoup->coin_blind),
    5916           0 :         TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
    5917             :                                      &recoup->value),
    5918           0 :         TALER_PQ_result_spec_absolute_time ("timestamp",
    5919             :                                             &recoup->timestamp),
    5920           0 :         GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    5921             :                                               &recoup->coin.denom_pub_hash),
    5922           0 :         GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
    5923             :                                              &recoup->coin.denom_sig.
    5924             :                                              rsa_signature),
    5925           0 :         GNUNET_PQ_result_spec_uint64 ("recoup_refresh_uuid",
    5926             :                                       &serial_id),
    5927             :         GNUNET_PQ_result_spec_end
    5928             :       };
    5929             : 
    5930           0 :       if (GNUNET_OK !=
    5931           0 :           GNUNET_PQ_extract_result (result,
    5932             :                                     rs,
    5933             :                                     i))
    5934             :       {
    5935           0 :         GNUNET_break (0);
    5936           0 :         GNUNET_free (recoup);
    5937           0 :         chc->failed = true;
    5938           0 :         return;
    5939             :       }
    5940           0 :       recoup->coin.coin_pub = *chc->coin_pub;
    5941             :     }
    5942           0 :     tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
    5943           0 :     tl->next = chc->head;
    5944           0 :     tl->type = TALER_EXCHANGEDB_TT_RECOUP_REFRESH;
    5945           0 :     tl->details.recoup_refresh = recoup;
    5946           0 :     tl->serial_id = serial_id;
    5947           0 :     chc->head = tl;
    5948             :   }
    5949             : }
    5950             : 
    5951             : 
    5952             : /**
    5953             :  * Work we need to do.
    5954             :  */
    5955             : struct Work
    5956             : {
    5957             :   /**
    5958             :    * SQL prepared statement name.
    5959             :    */
    5960             :   const char *statement;
    5961             : 
    5962             :   /**
    5963             :    * Function to call to handle the result(s).
    5964             :    */
    5965             :   GNUNET_PQ_PostgresResultHandler cb;
    5966             : };
    5967             : 
    5968             : 
    5969             : /**
    5970             :  * Compile a list of all (historic) transactions performed with the given coin
    5971             :  * (/refresh/melt, /deposit, /refund and /recoup operations).
    5972             :  *
    5973             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    5974             :  * @param session database connection
    5975             :  * @param coin_pub coin to investigate
    5976             :  * @param include_recoup should recoup transactions be included in the @a tlp
    5977             :  * @param[out] tlp set to list of transactions, NULL if coin is fresh
    5978             :  * @return database transaction status
    5979             :  */
    5980             : static enum GNUNET_DB_QueryStatus
    5981           2 : postgres_get_coin_transactions (
    5982             :   void *cls,
    5983             :   struct TALER_EXCHANGEDB_Session *session,
    5984             :   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    5985             :   int include_recoup,
    5986             :   struct TALER_EXCHANGEDB_TransactionList **tlp)
    5987             : {
    5988           2 :   struct PostgresClosure *pg = cls;
    5989             :   static const struct Work work_op[] = {
    5990             :     /** #TALER_EXCHANGEDB_TT_DEPOSIT */
    5991             :     { "get_deposit_with_coin_pub",
    5992             :       &add_coin_deposit },
    5993             :     /** #TALER_EXCHANGEDB_TT_MELT */
    5994             :     { "get_refresh_session_by_coin",
    5995             :       &add_coin_melt },
    5996             :     /** #TALER_EXCHANGEDB_TT_REFUND */
    5997             :     { "get_refunds_by_coin",
    5998             :       &add_coin_refund },
    5999             :     { NULL, NULL }
    6000             :   };
    6001             :   static const struct Work work_wp[] = {
    6002             :     /** #TALER_EXCHANGEDB_TT_DEPOSIT */
    6003             :     { "get_deposit_with_coin_pub",
    6004             :       &add_coin_deposit },
    6005             :     /** #TALER_EXCHANGEDB_TT_MELT */
    6006             :     { "get_refresh_session_by_coin",
    6007             :       &add_coin_melt },
    6008             :     /** #TALER_EXCHANGEDB_TT_REFUND */
    6009             :     { "get_refunds_by_coin",
    6010             :       &add_coin_refund },
    6011             :     /** #TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP */
    6012             :     { "recoup_by_old_coin",
    6013             :       &add_old_coin_recoup },
    6014             :     /** #TALER_EXCHANGEDB_TT_RECOUP */
    6015             :     { "recoup_by_coin",
    6016             :       &add_coin_recoup },
    6017             :     /** #TALER_EXCHANGEDB_TT_RECOUP_REFRESH */
    6018             :     { "recoup_by_refreshed_coin",
    6019             :       &add_coin_recoup_refresh },
    6020             :     { NULL, NULL }
    6021             :   };
    6022           2 :   struct GNUNET_PQ_QueryParam params[] = {
    6023           2 :     GNUNET_PQ_query_param_auto_from_type (coin_pub),
    6024             :     GNUNET_PQ_query_param_end
    6025             :   };
    6026             :   enum GNUNET_DB_QueryStatus qs;
    6027             :   const struct Work *work;
    6028           2 :   struct CoinHistoryContext chc = {
    6029             :     .head = NULL,
    6030             :     .coin_pub = coin_pub,
    6031             :     .session = session,
    6032             :     .pg = pg,
    6033             :     .db_cls = cls
    6034             :   };
    6035             : 
    6036           2 :   work = (GNUNET_YES == include_recoup) ? work_wp : work_op;
    6037           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    6038             :               "Getting transactions for coin %s\n",
    6039             :               TALER_B2S (coin_pub));
    6040          14 :   for (unsigned int i = 0; NULL != work[i].statement; i++)
    6041             :   {
    6042          12 :     qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    6043          12 :                                                work[i].statement,
    6044             :                                                params,
    6045          12 :                                                work[i].cb,
    6046             :                                                &chc);
    6047          12 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    6048             :                 "Coin %s yielded %d transactions of type %s\n",
    6049             :                 TALER_B2S (coin_pub),
    6050             :                 qs,
    6051             :                 work[i].statement);
    6052          12 :     if ( (0 > qs) ||
    6053          12 :          (chc.failed) )
    6054             :     {
    6055           0 :       if (NULL != chc.head)
    6056           0 :         common_free_coin_transaction_list (cls,
    6057             :                                            chc.head);
    6058           0 :       *tlp = NULL;
    6059           0 :       if (chc.failed)
    6060           0 :         qs = GNUNET_DB_STATUS_HARD_ERROR;
    6061           0 :       return qs;
    6062             :     }
    6063             :   }
    6064           2 :   *tlp = chc.head;
    6065           2 :   if (NULL == chc.head)
    6066           0 :     return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
    6067           2 :   return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    6068             : }
    6069             : 
    6070             : 
    6071             : /**
    6072             :  * Closure for #handle_wt_result.
    6073             :  */
    6074             : struct WireTransferResultContext
    6075             : {
    6076             :   /**
    6077             :    * Function to call on each result.
    6078             :    */
    6079             :   TALER_EXCHANGEDB_AggregationDataCallback cb;
    6080             : 
    6081             :   /**
    6082             :    * Closure for @e cb.
    6083             :    */
    6084             :   void *cb_cls;
    6085             : 
    6086             :   /**
    6087             :    * Plugin context.
    6088             :    */
    6089             :   struct PostgresClosure *pg;
    6090             : 
    6091             :   /**
    6092             :    * Set to #GNUNET_SYSERR on serious errors.
    6093             :    */
    6094             :   int status;
    6095             : };
    6096             : 
    6097             : 
    6098             : /**
    6099             :  * Function to be called with the results of a SELECT statement
    6100             :  * that has returned @a num_results results.  Helper function
    6101             :  * for #postgres_lookup_wire_transfer().
    6102             :  *
    6103             :  * @param cls closure of type `struct WireTransferResultContext *`
    6104             :  * @param result the postgres result
    6105             :  * @param num_results the number of results in @a result
    6106             :  */
    6107             : static void
    6108           2 : handle_wt_result (void *cls,
    6109             :                   PGresult *result,
    6110             :                   unsigned int num_results)
    6111             : {
    6112           2 :   struct WireTransferResultContext *ctx = cls;
    6113           2 :   struct PostgresClosure *pg = ctx->pg;
    6114             : 
    6115           3 :   for (unsigned int i = 0; i<num_results; i++)
    6116             :   {
    6117             :     uint64_t rowid;
    6118             :     struct GNUNET_HashCode h_contract_terms;
    6119             :     struct GNUNET_HashCode h_wire;
    6120             :     struct TALER_CoinSpendPublicKeyP coin_pub;
    6121             :     struct TALER_MerchantPublicKeyP merchant_pub;
    6122             :     struct GNUNET_TIME_Absolute exec_time;
    6123             :     struct TALER_Amount amount_with_fee;
    6124             :     struct TALER_Amount deposit_fee;
    6125             :     struct TALER_DenominationPublicKey denom_pub;
    6126             :     json_t *wire;
    6127           1 :     struct GNUNET_PQ_ResultSpec rs[] = {
    6128           1 :       GNUNET_PQ_result_spec_uint64 ("aggregation_serial_id", &rowid),
    6129           1 :       GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
    6130             :                                             &h_contract_terms),
    6131           1 :       TALER_PQ_result_spec_json ("wire", &wire),
    6132           1 :       GNUNET_PQ_result_spec_auto_from_type ("h_wire", &h_wire),
    6133           1 :       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    6134             :                                             &denom_pub.rsa_public_key),
    6135           1 :       GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin_pub),
    6136           1 :       GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", &merchant_pub),
    6137           1 :       TALER_PQ_result_spec_absolute_time ("execution_date", &exec_time),
    6138           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", &amount_with_fee),
    6139           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit", &deposit_fee),
    6140             :       GNUNET_PQ_result_spec_end
    6141             :     };
    6142             : 
    6143           1 :     if (GNUNET_OK !=
    6144           1 :         GNUNET_PQ_extract_result (result,
    6145             :                                   rs,
    6146             :                                   i))
    6147             :     {
    6148           0 :       GNUNET_break (0);
    6149           0 :       ctx->status = GNUNET_SYSERR;
    6150           0 :       return;
    6151             :     }
    6152           1 :     ctx->cb (ctx->cb_cls,
    6153             :              rowid,
    6154             :              &merchant_pub,
    6155             :              &h_wire,
    6156             :              wire,
    6157             :              exec_time,
    6158             :              &h_contract_terms,
    6159             :              &denom_pub,
    6160             :              &coin_pub,
    6161             :              &amount_with_fee,
    6162             :              &deposit_fee);
    6163           1 :     GNUNET_PQ_cleanup_result (rs);
    6164             :   }
    6165             : }
    6166             : 
    6167             : 
    6168             : /**
    6169             :  * Lookup the list of Taler transactions that were aggregated
    6170             :  * into a wire transfer by the respective @a wtid.
    6171             :  *
    6172             :  * @param cls closure
    6173             :  * @param session database connection
    6174             :  * @param wtid the raw wire transfer identifier we used
    6175             :  * @param cb function to call on each transaction found
    6176             :  * @param cb_cls closure for @a cb
    6177             :  * @return query status of the transaction
    6178             :  */
    6179             : static enum GNUNET_DB_QueryStatus
    6180           2 : postgres_lookup_wire_transfer (
    6181             :   void *cls,
    6182             :   struct TALER_EXCHANGEDB_Session *session,
    6183             :   const struct TALER_WireTransferIdentifierRawP *wtid,
    6184             :   TALER_EXCHANGEDB_AggregationDataCallback cb,
    6185             :   void *cb_cls)
    6186             : {
    6187           2 :   struct PostgresClosure *pg = cls;
    6188           2 :   struct GNUNET_PQ_QueryParam params[] = {
    6189           2 :     GNUNET_PQ_query_param_auto_from_type (wtid),
    6190             :     GNUNET_PQ_query_param_end
    6191             :   };
    6192             :   struct WireTransferResultContext ctx;
    6193             :   enum GNUNET_DB_QueryStatus qs;
    6194             : 
    6195           2 :   ctx.cb = cb;
    6196           2 :   ctx.cb_cls = cb_cls;
    6197           2 :   ctx.pg = pg;
    6198           2 :   ctx.status = GNUNET_OK;
    6199             :   /* check if the melt record exists and get it */
    6200           2 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    6201             :                                              "lookup_transactions",
    6202             :                                              params,
    6203             :                                              &handle_wt_result,
    6204             :                                              &ctx);
    6205           2 :   if (GNUNET_OK != ctx.status)
    6206           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    6207           2 :   return qs;
    6208             : }
    6209             : 
    6210             : 
    6211             : /**
    6212             :  * Try to find the wire transfer details for a deposit operation.
    6213             :  * If we did not execute the deposit yet, return when it is supposed
    6214             :  * to be executed.
    6215             :  *
    6216             :  * @param cls closure
    6217             :  * @param session database connection
    6218             :  * @param h_contract_terms hash of the proposal data
    6219             :  * @param h_wire hash of merchant wire details
    6220             :  * @param coin_pub public key of deposited coin
    6221             :  * @param merchant_pub merchant public key
    6222             :  * @param cb function to call with the result
    6223             :  * @param cb_cls closure to pass to @a cb
    6224             :  * @return transaction status code
    6225             :  - */
    6226             : static enum GNUNET_DB_QueryStatus
    6227           2 : postgres_lookup_transfer_by_deposit (
    6228             :   void *cls,
    6229             :   struct TALER_EXCHANGEDB_Session *session,
    6230             :   const struct GNUNET_HashCode *h_contract_terms,
    6231             :   const struct GNUNET_HashCode *h_wire,
    6232             :   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    6233             :   const struct TALER_MerchantPublicKeyP *merchant_pub,
    6234             :   TALER_EXCHANGEDB_WireTransferByCoinCallback cb,
    6235             :   void *cb_cls)
    6236             : {
    6237           2 :   struct PostgresClosure *pg = cls;
    6238             :   enum GNUNET_DB_QueryStatus qs;
    6239           2 :   struct GNUNET_PQ_QueryParam params[] = {
    6240           2 :     GNUNET_PQ_query_param_auto_from_type (coin_pub),
    6241           2 :     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
    6242           2 :     GNUNET_PQ_query_param_auto_from_type (h_wire),
    6243           2 :     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
    6244             :     GNUNET_PQ_query_param_end
    6245             :   };
    6246             :   struct TALER_WireTransferIdentifierRawP wtid;
    6247             :   struct GNUNET_TIME_Absolute exec_time;
    6248             :   struct TALER_Amount amount_with_fee;
    6249             :   struct TALER_Amount deposit_fee;
    6250           2 :   struct GNUNET_PQ_ResultSpec rs[] = {
    6251           2 :     GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
    6252             :                                           &wtid),
    6253           2 :     TALER_PQ_result_spec_absolute_time ("execution_date",
    6254             :                                         &exec_time),
    6255           2 :     TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    6256             :                                  &amount_with_fee),
    6257           2 :     TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
    6258             :                                  &deposit_fee),
    6259             :     GNUNET_PQ_result_spec_end
    6260             :   };
    6261             : 
    6262             :   /* check if the melt record exists and get it */
    6263           2 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    6264             :                                                  "lookup_deposit_wtid",
    6265             :                                                  params,
    6266             :                                                  rs);
    6267           2 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    6268             :   {
    6269           1 :     cb (cb_cls,
    6270             :         &wtid,
    6271             :         &amount_with_fee,
    6272             :         &deposit_fee,
    6273             :         exec_time);
    6274           1 :     return qs;
    6275             :   }
    6276           1 :   if (0 > qs)
    6277           0 :     return qs;
    6278             : 
    6279           1 :   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
    6280           1 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    6281             :               "lookup_deposit_wtid returned 0 matching rows\n");
    6282             :   {
    6283             :     /* Check if transaction exists in deposits, so that we just
    6284             :        do not have a WTID yet, if so, do call the CB with a NULL wtid
    6285             :        and return #GNUNET_YES! */
    6286           1 :     struct GNUNET_PQ_QueryParam params2[] = {
    6287           1 :       GNUNET_PQ_query_param_auto_from_type (coin_pub),
    6288           1 :       GNUNET_PQ_query_param_auto_from_type (merchant_pub),
    6289           1 :       GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
    6290           1 :       GNUNET_PQ_query_param_auto_from_type (h_wire),
    6291             :       GNUNET_PQ_query_param_end
    6292             :     };
    6293             :     struct GNUNET_TIME_Absolute exec_time;
    6294             :     struct TALER_Amount amount_with_fee;
    6295             :     struct TALER_Amount deposit_fee;
    6296           1 :     struct GNUNET_PQ_ResultSpec rs2[] = {
    6297           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", &amount_with_fee),
    6298           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit", &deposit_fee),
    6299           1 :       TALER_PQ_result_spec_absolute_time ("wire_deadline", &exec_time),
    6300             :       GNUNET_PQ_result_spec_end
    6301             :     };
    6302             : 
    6303           1 :     qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    6304             :                                                    "get_deposit_for_wtid",
    6305             :                                                    params2,
    6306             :                                                    rs2);
    6307           1 :     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    6308             :     {
    6309             :       /* Ok, we're aware of the transaction, but it has not yet been
    6310             :          executed */
    6311           0 :       cb (cb_cls,
    6312             :           NULL,
    6313             :           &amount_with_fee,
    6314             :           &deposit_fee,
    6315             :           exec_time);
    6316           0 :       return qs;
    6317             :     }
    6318           1 :     return qs;
    6319             :   }
    6320             : }
    6321             : 
    6322             : 
    6323             : /**
    6324             :  * Function called to insert aggregation information into the DB.
    6325             :  *
    6326             :  * @param cls closure
    6327             :  * @param session database connection
    6328             :  * @param wtid the raw wire transfer identifier we used
    6329             :  * @param deposit_serial_id row in the deposits table for which this is aggregation data
    6330             :  * @return transaction status code
    6331             :  */
    6332             : static enum GNUNET_DB_QueryStatus
    6333          34 : postgres_insert_aggregation_tracking (
    6334             :   void *cls,
    6335             :   struct TALER_EXCHANGEDB_Session *session,
    6336             :   const struct TALER_WireTransferIdentifierRawP *wtid,
    6337             :   unsigned long long deposit_serial_id)
    6338             : {
    6339          34 :   uint64_t rid = deposit_serial_id;
    6340          34 :   struct GNUNET_PQ_QueryParam params[] = {
    6341          34 :     GNUNET_PQ_query_param_uint64 (&rid),
    6342          34 :     GNUNET_PQ_query_param_auto_from_type (wtid),
    6343             :     GNUNET_PQ_query_param_end
    6344             :   };
    6345             : 
    6346             :   (void) cls;
    6347          34 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    6348             :                                              "insert_aggregation_tracking",
    6349             :                                              params);
    6350             : }
    6351             : 
    6352             : 
    6353             : /**
    6354             :  * Obtain wire fee from database.
    6355             :  *
    6356             :  * @param cls closure
    6357             :  * @param session database connection
    6358             :  * @param type type of wire transfer the fee applies for
    6359             :  * @param date for which date do we want the fee?
    6360             :  * @param[out] start_date when does the fee go into effect
    6361             :  * @param[out] end_date when does the fee end being valid
    6362             :  * @param[out] wire_fee how high is the wire transfer fee
    6363             :  * @param[out] closing_fee how high is the closing fee
    6364             :  * @param[out] master_sig signature over the above by the exchange master key
    6365             :  * @return status of the transaction
    6366             :  */
    6367             : static enum GNUNET_DB_QueryStatus
    6368          26 : postgres_get_wire_fee (void *cls,
    6369             :                        struct TALER_EXCHANGEDB_Session *session,
    6370             :                        const char *type,
    6371             :                        struct GNUNET_TIME_Absolute date,
    6372             :                        struct GNUNET_TIME_Absolute *start_date,
    6373             :                        struct GNUNET_TIME_Absolute *end_date,
    6374             :                        struct TALER_Amount *wire_fee,
    6375             :                        struct TALER_Amount *closing_fee,
    6376             :                        struct TALER_MasterSignatureP *master_sig)
    6377             : {
    6378          26 :   struct PostgresClosure *pg = cls;
    6379          26 :   struct GNUNET_PQ_QueryParam params[] = {
    6380          26 :     GNUNET_PQ_query_param_string (type),
    6381          26 :     TALER_PQ_query_param_absolute_time (&date),
    6382             :     GNUNET_PQ_query_param_end
    6383             :   };
    6384          26 :   struct GNUNET_PQ_ResultSpec rs[] = {
    6385          26 :     TALER_PQ_result_spec_absolute_time ("start_date", start_date),
    6386          26 :     TALER_PQ_result_spec_absolute_time ("end_date", end_date),
    6387          26 :     TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee", wire_fee),
    6388          26 :     TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee", closing_fee),
    6389          26 :     GNUNET_PQ_result_spec_auto_from_type ("master_sig", master_sig),
    6390             :     GNUNET_PQ_result_spec_end
    6391             :   };
    6392             : 
    6393          26 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    6394             :                                                    "get_wire_fee",
    6395             :                                                    params,
    6396             :                                                    rs);
    6397             : }
    6398             : 
    6399             : 
    6400             : /**
    6401             :  * Insert wire transfer fee into database.
    6402             :  *
    6403             :  * @param cls closure
    6404             :  * @param session database connection
    6405             :  * @param type type of wire transfer this fee applies for
    6406             :  * @param start_date when does the fee go into effect
    6407             :  * @param end_date when does the fee end being valid
    6408             :  * @param wire_fee how high is the wire transfer fee
    6409             :  * @param closing_fee how high is the closing fee
    6410             :  * @param master_sig signature over the above by the exchange master key
    6411             :  * @return transaction status code
    6412             :  */
    6413             : static enum GNUNET_DB_QueryStatus
    6414           8 : postgres_insert_wire_fee (void *cls,
    6415             :                           struct TALER_EXCHANGEDB_Session *session,
    6416             :                           const char *type,
    6417             :                           struct GNUNET_TIME_Absolute start_date,
    6418             :                           struct GNUNET_TIME_Absolute end_date,
    6419             :                           const struct TALER_Amount *wire_fee,
    6420             :                           const struct TALER_Amount *closing_fee,
    6421             :                           const struct TALER_MasterSignatureP *master_sig)
    6422             : {
    6423           8 :   struct PostgresClosure *pg = cls;
    6424           8 :   struct GNUNET_PQ_QueryParam params[] = {
    6425           8 :     GNUNET_PQ_query_param_string (type),
    6426           8 :     TALER_PQ_query_param_absolute_time (&start_date),
    6427           8 :     TALER_PQ_query_param_absolute_time (&end_date),
    6428           8 :     TALER_PQ_query_param_amount (wire_fee),
    6429           8 :     TALER_PQ_query_param_amount (closing_fee),
    6430           8 :     GNUNET_PQ_query_param_auto_from_type (master_sig),
    6431             :     GNUNET_PQ_query_param_end
    6432             :   };
    6433             :   struct TALER_Amount wf;
    6434             :   struct TALER_Amount cf;
    6435             :   struct TALER_MasterSignatureP sig;
    6436             :   struct GNUNET_TIME_Absolute sd;
    6437             :   struct GNUNET_TIME_Absolute ed;
    6438             :   enum GNUNET_DB_QueryStatus qs;
    6439             : 
    6440           8 :   qs = postgres_get_wire_fee (pg,
    6441             :                               session,
    6442             :                               type,
    6443             :                               start_date,
    6444             :                               &sd,
    6445             :                               &ed,
    6446             :                               &wf,
    6447             :                               &cf,
    6448             :                               &sig);
    6449           8 :   if (qs < 0)
    6450           0 :     return qs;
    6451           8 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    6452             :   {
    6453           1 :     if (0 != GNUNET_memcmp (&sig,
    6454             :                             master_sig))
    6455             :     {
    6456           0 :       GNUNET_break (0);
    6457           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
    6458             :     }
    6459           1 :     if (0 != TALER_amount_cmp (wire_fee,
    6460             :                                &wf))
    6461             :     {
    6462           0 :       GNUNET_break (0);
    6463           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
    6464             :     }
    6465           1 :     if (0 != TALER_amount_cmp (closing_fee,
    6466             :                                &cf))
    6467             :     {
    6468           0 :       GNUNET_break (0);
    6469           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
    6470             :     }
    6471           1 :     if ( (sd.abs_value_us != start_date.abs_value_us) ||
    6472           1 :          (ed.abs_value_us != end_date.abs_value_us) )
    6473             :     {
    6474           0 :       GNUNET_break (0);
    6475           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
    6476             :     }
    6477             :     /* equal record already exists */
    6478           1 :     return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
    6479             :   }
    6480             : 
    6481           7 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    6482             :                                              "insert_wire_fee",
    6483             :                                              params);
    6484             : }
    6485             : 
    6486             : 
    6487             : /**
    6488             :  * Closure for #reserve_expired_cb().
    6489             :  */
    6490             : struct ExpiredReserveContext
    6491             : {
    6492             :   /**
    6493             :    * Function to call for each expired reserve.
    6494             :    */
    6495             :   TALER_EXCHANGEDB_ReserveExpiredCallback rec;
    6496             : 
    6497             :   /**
    6498             :    * Closure to give to @e rec.
    6499             :    */
    6500             :   void *rec_cls;
    6501             : 
    6502             :   /**
    6503             :    * Plugin context.
    6504             :    */
    6505             :   struct PostgresClosure *pg;
    6506             : 
    6507             :   /**
    6508             :    * Set to #GNUNET_SYSERR on error.
    6509             :    */
    6510             :   int status;
    6511             : };
    6512             : 
    6513             : 
    6514             : /**
    6515             :  * Function to be called with the results of a SELECT statement
    6516             :  * that has returned @a num_results results.
    6517             :  *
    6518             :  * @param cls closure
    6519             :  * @param result the postgres result
    6520             :  * @param num_results the number of results in @a result
    6521             :  */
    6522             : static void
    6523           0 : reserve_expired_cb (void *cls,
    6524             :                     PGresult *result,
    6525             :                     unsigned int num_results)
    6526             : {
    6527           0 :   struct ExpiredReserveContext *erc = cls;
    6528           0 :   struct PostgresClosure *pg = erc->pg;
    6529             :   int ret;
    6530             : 
    6531           0 :   ret = GNUNET_OK;
    6532           0 :   for (unsigned int i = 0; i<num_results; i++)
    6533             :   {
    6534             :     struct GNUNET_TIME_Absolute exp_date;
    6535             :     char *account_details;
    6536             :     struct TALER_ReservePublicKeyP reserve_pub;
    6537             :     struct TALER_Amount remaining_balance;
    6538           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
    6539           0 :       TALER_PQ_result_spec_absolute_time ("expiration_date",
    6540             :                                           &exp_date),
    6541           0 :       GNUNET_PQ_result_spec_string ("account_details",
    6542             :                                     &account_details),
    6543           0 :       GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
    6544             :                                             &reserve_pub),
    6545           0 :       TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
    6546             :                                    &remaining_balance),
    6547             :       GNUNET_PQ_result_spec_end
    6548             :     };
    6549             : 
    6550           0 :     if (GNUNET_OK !=
    6551           0 :         GNUNET_PQ_extract_result (result,
    6552             :                                   rs,
    6553             :                                   i))
    6554             :     {
    6555           0 :       GNUNET_break (0);
    6556           0 :       ret = GNUNET_SYSERR;
    6557           0 :       break;
    6558             :     }
    6559           0 :     ret = erc->rec (erc->rec_cls,
    6560             :                     &reserve_pub,
    6561             :                     &remaining_balance,
    6562             :                     account_details,
    6563             :                     exp_date);
    6564           0 :     GNUNET_PQ_cleanup_result (rs);
    6565           0 :     if (GNUNET_OK != ret)
    6566           0 :       break;
    6567             :   }
    6568           0 :   erc->status = ret;
    6569           0 : }
    6570             : 
    6571             : 
    6572             : /**
    6573             :  * Obtain information about expired reserves and their
    6574             :  * remaining balances.
    6575             :  *
    6576             :  * @param cls closure of the plugin
    6577             :  * @param session database connection
    6578             :  * @param now timestamp based on which we decide expiration
    6579             :  * @param rec function to call on expired reserves
    6580             :  * @param rec_cls closure for @a rec
    6581             :  * @return transaction status
    6582             :  */
    6583             : static enum GNUNET_DB_QueryStatus
    6584           0 : postgres_get_expired_reserves (void *cls,
    6585             :                                struct TALER_EXCHANGEDB_Session *session,
    6586             :                                struct GNUNET_TIME_Absolute now,
    6587             :                                TALER_EXCHANGEDB_ReserveExpiredCallback rec,
    6588             :                                void *rec_cls)
    6589             : {
    6590           0 :   struct PostgresClosure *pg = cls;
    6591           0 :   struct GNUNET_PQ_QueryParam params[] = {
    6592           0 :     TALER_PQ_query_param_absolute_time (&now),
    6593             :     GNUNET_PQ_query_param_end
    6594             :   };
    6595             :   struct ExpiredReserveContext ectx;
    6596             :   enum GNUNET_DB_QueryStatus qs;
    6597             : 
    6598           0 :   ectx.rec = rec;
    6599           0 :   ectx.rec_cls = rec_cls;
    6600           0 :   ectx.pg = pg;
    6601           0 :   ectx.status = GNUNET_OK;
    6602           0 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    6603             :                                              "get_expired_reserves",
    6604             :                                              params,
    6605             :                                              &reserve_expired_cb,
    6606             :                                              &ectx);
    6607           0 :   if (GNUNET_OK != ectx.status)
    6608           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    6609           0 :   return qs;
    6610             : }
    6611             : 
    6612             : 
    6613             : /**
    6614             :  * Insert reserve close operation into database.
    6615             :  *
    6616             :  * @param cls closure
    6617             :  * @param session database connection
    6618             :  * @param reserve_pub which reserve is this about?
    6619             :  * @param execution_date when did we perform the transfer?
    6620             :  * @param receiver_account to which account do we transfer?
    6621             :  * @param wtid wire transfer details
    6622             :  * @param amount_with_fee amount we charged to the reserve
    6623             :  * @param closing_fee how high is the closing fee
    6624             :  * @return transaction status code
    6625             :  */
    6626             : static enum GNUNET_DB_QueryStatus
    6627           1 : postgres_insert_reserve_closed (
    6628             :   void *cls,
    6629             :   struct TALER_EXCHANGEDB_Session *session,
    6630             :   const struct TALER_ReservePublicKeyP *reserve_pub,
    6631             :   struct GNUNET_TIME_Absolute execution_date,
    6632             :   const char *receiver_account,
    6633             :   const struct TALER_WireTransferIdentifierRawP *wtid,
    6634             :   const struct TALER_Amount *amount_with_fee,
    6635             :   const struct TALER_Amount *closing_fee)
    6636             : {
    6637             :   struct TALER_EXCHANGEDB_Reserve reserve;
    6638           1 :   struct GNUNET_PQ_QueryParam params[] = {
    6639           1 :     GNUNET_PQ_query_param_auto_from_type (reserve_pub),
    6640           1 :     TALER_PQ_query_param_absolute_time (&execution_date),
    6641           1 :     GNUNET_PQ_query_param_auto_from_type (wtid),
    6642           1 :     GNUNET_PQ_query_param_string (receiver_account),
    6643           1 :     TALER_PQ_query_param_amount (amount_with_fee),
    6644           1 :     TALER_PQ_query_param_amount (closing_fee),
    6645             :     GNUNET_PQ_query_param_end
    6646             :   };
    6647             :   enum TALER_AmountArithmeticResult ret;
    6648             :   enum GNUNET_DB_QueryStatus qs;
    6649             : 
    6650           1 :   qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    6651             :                                            "reserves_close_insert",
    6652             :                                            params);
    6653           1 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    6654           0 :     return qs;
    6655             : 
    6656             :   /* update reserve balance */
    6657           1 :   reserve.pub = *reserve_pub;
    6658           1 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    6659           1 :       (qs = postgres_reserves_get (cls,
    6660             :                                    session,
    6661             :                                    &reserve)))
    6662             :   {
    6663             :     /* Existence should have been checked before we got here... */
    6664           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    6665           0 :     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    6666           0 :       qs = GNUNET_DB_STATUS_HARD_ERROR;
    6667           0 :     return qs;
    6668             :   }
    6669           1 :   ret = TALER_amount_subtract (&reserve.balance,
    6670             :                                &reserve.balance,
    6671             :                                amount_with_fee);
    6672           1 :   if (ret < 0)
    6673             :   {
    6674             :     /* The reserve history was checked to make sure there is enough of a balance
    6675             :        left before we tried this; however, concurrent operations may have changed
    6676             :        the situation by now.  We should re-try the transaction.  */
    6677           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    6678             :                 "Closing of reserve `%s' refused due to balance mismatch. Retrying.\n",
    6679             :                 TALER_B2S (reserve_pub));
    6680           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    6681             :   }
    6682           1 :   GNUNET_break (TALER_AAR_RESULT_ZERO == ret);
    6683           1 :   return reserves_update (cls,
    6684             :                           session,
    6685             :                           &reserve);
    6686             : }
    6687             : 
    6688             : 
    6689             : /**
    6690             :  * Function called to insert wire transfer commit data into the DB.
    6691             :  *
    6692             :  * @param cls closure
    6693             :  * @param session database connection
    6694             :  * @param type type of the wire transfer (i.e. "iban")
    6695             :  * @param buf buffer with wire transfer preparation data
    6696             :  * @param buf_size number of bytes in @a buf
    6697             :  * @return query status code
    6698             :  */
    6699             : static enum GNUNET_DB_QueryStatus
    6700          13 : postgres_wire_prepare_data_insert (void *cls,
    6701             :                                    struct TALER_EXCHANGEDB_Session *session,
    6702             :                                    const char *type,
    6703             :                                    const char *buf,
    6704             :                                    size_t buf_size)
    6705             : {
    6706          13 :   struct GNUNET_PQ_QueryParam params[] = {
    6707          13 :     GNUNET_PQ_query_param_string (type),
    6708          13 :     GNUNET_PQ_query_param_fixed_size (buf, buf_size),
    6709             :     GNUNET_PQ_query_param_end
    6710             :   };
    6711             : 
    6712             :   (void) cls;
    6713          13 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    6714             :                                              "wire_prepare_data_insert",
    6715             :                                              params);
    6716             : }
    6717             : 
    6718             : 
    6719             : /**
    6720             :  * Function called to mark wire transfer commit data as finished.
    6721             :  *
    6722             :  * @param cls closure
    6723             :  * @param session database connection
    6724             :  * @param rowid which entry to mark as finished
    6725             :  * @return transaction status code
    6726             :  */
    6727             : static enum GNUNET_DB_QueryStatus
    6728          13 : postgres_wire_prepare_data_mark_finished (
    6729             :   void *cls,
    6730             :   struct TALER_EXCHANGEDB_Session *session,
    6731             :   uint64_t rowid)
    6732             : {
    6733          13 :   struct GNUNET_PQ_QueryParam params[] = {
    6734          13 :     GNUNET_PQ_query_param_uint64 (&rowid),
    6735             :     GNUNET_PQ_query_param_end
    6736             :   };
    6737             : 
    6738             :   (void) cls;
    6739          13 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    6740             :                                              "wire_prepare_data_mark_done",
    6741             :                                              params);
    6742             : }
    6743             : 
    6744             : 
    6745             : /**
    6746             :  * Function called to mark wire transfer commit data as failed.
    6747             :  *
    6748             :  * @param cls closure
    6749             :  * @param session database connection
    6750             :  * @param rowid which entry to mark as failed
    6751             :  * @return transaction status code
    6752             :  */
    6753             : static enum GNUNET_DB_QueryStatus
    6754           0 : postgres_wire_prepare_data_mark_failed (
    6755             :   void *cls,
    6756             :   struct TALER_EXCHANGEDB_Session *session,
    6757             :   uint64_t rowid)
    6758             : {
    6759           0 :   struct GNUNET_PQ_QueryParam params[] = {
    6760           0 :     GNUNET_PQ_query_param_uint64 (&rowid),
    6761             :     GNUNET_PQ_query_param_end
    6762             :   };
    6763             : 
    6764             :   (void) cls;
    6765           0 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    6766             :                                              "wire_prepare_data_mark_failed",
    6767             :                                              params);
    6768             : }
    6769             : 
    6770             : 
    6771             : /**
    6772             :  * Function called to get an unfinished wire transfer
    6773             :  * preparation data. Fetches at most one item.
    6774             :  *
    6775             :  * @param cls closure
    6776             :  * @param session database connection
    6777             :  * @param cb function to call for ONE unfinished item
    6778             :  * @param cb_cls closure for @a cb
    6779             :  * @return transaction status code
    6780             :  */
    6781             : static enum GNUNET_DB_QueryStatus
    6782          36 : postgres_wire_prepare_data_get (void *cls,
    6783             :                                 struct TALER_EXCHANGEDB_Session *session,
    6784             :                                 TALER_EXCHANGEDB_WirePreparationIterator cb,
    6785             :                                 void *cb_cls)
    6786             : {
    6787             :   enum GNUNET_DB_QueryStatus qs;
    6788          36 :   struct GNUNET_PQ_QueryParam params[] = {
    6789             :     GNUNET_PQ_query_param_end
    6790             :   };
    6791             :   uint64_t prewire_uuid;
    6792             :   char *type;
    6793          36 :   void *buf = NULL;
    6794             :   size_t buf_size;
    6795          36 :   struct GNUNET_PQ_ResultSpec rs[] = {
    6796          36 :     GNUNET_PQ_result_spec_uint64 ("prewire_uuid",
    6797             :                                   &prewire_uuid),
    6798          36 :     GNUNET_PQ_result_spec_string ("type",
    6799             :                                   &type),
    6800          36 :     GNUNET_PQ_result_spec_variable_size ("buf",
    6801             :                                          &buf,
    6802             :                                          &buf_size),
    6803             :     GNUNET_PQ_result_spec_end
    6804             :   };
    6805             : 
    6806             :   (void) cls;
    6807          36 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    6808             :                                                  "wire_prepare_data_get",
    6809             :                                                  params,
    6810             :                                                  rs);
    6811          36 :   if (0 >= qs)
    6812          23 :     return qs;
    6813          13 :   cb (cb_cls,
    6814             :       prewire_uuid,
    6815             :       type,
    6816             :       buf,
    6817             :       buf_size);
    6818          13 :   GNUNET_PQ_cleanup_result (rs);
    6819          13 :   return qs;
    6820             : }
    6821             : 
    6822             : 
    6823             : /**
    6824             :  * Start a transaction where we transiently violate the foreign
    6825             :  * constraints on the "wire_out" table as we insert aggregations
    6826             :  * and only add the wire transfer out at the end.
    6827             :  *
    6828             :  * @param cls the @e cls of this struct with the plugin-specific state
    6829             :  * @param session connection to use
    6830             :  * @return #GNUNET_OK on success
    6831             :  */
    6832             : static int
    6833          38 : postgres_start_deferred_wire_out (void *cls,
    6834             :                                   struct TALER_EXCHANGEDB_Session *session)
    6835             : {
    6836          38 :   struct GNUNET_PQ_ExecuteStatement es[] = {
    6837          38 :     GNUNET_PQ_make_execute ("SET CONSTRAINTS wire_out_ref DEFERRED"),
    6838             :     GNUNET_PQ_EXECUTE_STATEMENT_END
    6839             :   };
    6840             : 
    6841          38 :   postgres_preflight (cls,
    6842             :                       session);
    6843          38 :   if (GNUNET_OK !=
    6844          38 :       postgres_start (cls,
    6845             :                       session,
    6846             :                       "deferred wire out"))
    6847           0 :     return GNUNET_SYSERR;
    6848          38 :   if (GNUNET_OK !=
    6849          38 :       GNUNET_PQ_exec_statements (session->conn,
    6850             :                                  es))
    6851             :   {
    6852           0 :     TALER_LOG_ERROR (
    6853             :       "Failed to defer wire_out_ref constraint on transaction\n");
    6854           0 :     GNUNET_break (0);
    6855           0 :     postgres_rollback (cls,
    6856             :                        session);
    6857           0 :     return GNUNET_SYSERR;
    6858             :   }
    6859          38 :   return GNUNET_OK;
    6860             : }
    6861             : 
    6862             : 
    6863             : /**
    6864             :  * Store information about an outgoing wire transfer that was executed.
    6865             :  *
    6866             :  * @param cls closure
    6867             :  * @param session database connection
    6868             :  * @param date time of the wire transfer
    6869             :  * @param wtid subject of the wire transfer
    6870             :  * @param wire_account details about the receiver account of the wire transfer
    6871             :  * @param exchange_account_section configuration section of the exchange specifying the
    6872             :  *        exchange's bank account being used
    6873             :  * @param amount amount that was transmitted
    6874             :  * @return transaction status code
    6875             :  */
    6876             : static enum GNUNET_DB_QueryStatus
    6877          13 : postgres_store_wire_transfer_out (
    6878             :   void *cls,
    6879             :   struct TALER_EXCHANGEDB_Session *session,
    6880             :   struct GNUNET_TIME_Absolute date,
    6881             :   const struct TALER_WireTransferIdentifierRawP *wtid,
    6882             :   const json_t *wire_account,
    6883             :   const char *exchange_account_section,
    6884             :   const struct TALER_Amount *amount)
    6885             : {
    6886          13 :   struct GNUNET_PQ_QueryParam params[] = {
    6887          13 :     TALER_PQ_query_param_absolute_time (&date),
    6888          13 :     GNUNET_PQ_query_param_auto_from_type (wtid),
    6889          13 :     TALER_PQ_query_param_json (wire_account),
    6890          13 :     GNUNET_PQ_query_param_string (exchange_account_section),
    6891          13 :     TALER_PQ_query_param_amount (amount),
    6892             :     GNUNET_PQ_query_param_end
    6893             :   };
    6894             : 
    6895             :   (void) cls;
    6896          13 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    6897             :                                              "insert_wire_out",
    6898             :                                              params);
    6899             : }
    6900             : 
    6901             : 
    6902             : /**
    6903             :  * Function called to perform "garbage collection" on the
    6904             :  * database, expiring records we no longer require.
    6905             :  *
    6906             :  * @param cls closure
    6907             :  * @return #GNUNET_OK on success,
    6908             :  *         #GNUNET_SYSERR on DB errors
    6909             :  */
    6910             : static int
    6911           1 : postgres_gc (void *cls)
    6912             : {
    6913           1 :   struct PostgresClosure *pg = cls;
    6914             :   struct GNUNET_TIME_Absolute now;
    6915             :   struct GNUNET_TIME_Absolute long_ago;
    6916           1 :   struct GNUNET_PQ_QueryParam params_none[] = {
    6917             :     GNUNET_PQ_query_param_end
    6918             :   };
    6919           1 :   struct GNUNET_PQ_QueryParam params_time[] = {
    6920           1 :     TALER_PQ_query_param_absolute_time (&now),
    6921             :     GNUNET_PQ_query_param_end
    6922             :   };
    6923           1 :   struct GNUNET_PQ_QueryParam params_ancient_time[] = {
    6924           1 :     TALER_PQ_query_param_absolute_time (&long_ago),
    6925             :     GNUNET_PQ_query_param_end
    6926             :   };
    6927             :   struct GNUNET_PQ_Context *conn;
    6928             :   int ret;
    6929             : 
    6930           1 :   now = GNUNET_TIME_absolute_get ();
    6931           1 :   (void) GNUNET_TIME_round_abs (&now);
    6932             :   /* Keep wire fees for 10 years, that should always
    6933             :      be enough _and_ they are tiny so it does not
    6934             :      matter to make this tight */
    6935           1 :   long_ago = GNUNET_TIME_absolute_subtract (now,
    6936             :                                             GNUNET_TIME_relative_multiply (
    6937             :                                               GNUNET_TIME_UNIT_YEARS,
    6938             :                                               10));
    6939             :   {
    6940           1 :     struct GNUNET_PQ_PreparedStatement ps[] = {
    6941             :       /* Used in #postgres_gc() */
    6942           1 :       GNUNET_PQ_make_prepare ("gc_prewire",
    6943             :                               "DELETE"
    6944             :                               " FROM prewire"
    6945             :                               " WHERE finished=true;",
    6946             :                               0),
    6947           1 :       GNUNET_PQ_make_prepare ("gc_reserves",
    6948             :                               "DELETE"
    6949             :                               " FROM reserves"
    6950             :                               " WHERE gc_date < $1"
    6951             :                               "   AND current_balance_val = 0"
    6952             :                               "   AND current_balance_frac = 0;",
    6953             :                               1),
    6954           1 :       GNUNET_PQ_make_prepare ("gc_wire_fee",
    6955             :                               "DELETE"
    6956             :                               " FROM wire_fee"
    6957             :                               " WHERE end_date < $1;",
    6958             :                               1),
    6959           1 :       GNUNET_PQ_make_prepare ("gc_denominations",
    6960             :                               "DELETE"
    6961             :                               " FROM denominations"
    6962             :                               " WHERE expire_legal < $1;",
    6963             :                               1),
    6964             :       GNUNET_PQ_PREPARED_STATEMENT_END
    6965             :     };
    6966             : 
    6967           1 :     conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
    6968             :                                        "exchangedb-postgres",
    6969             :                                        NULL,
    6970             :                                        NULL,
    6971             :                                        ps);
    6972             :   }
    6973           1 :   if (NULL == conn)
    6974           0 :     return GNUNET_SYSERR;
    6975           1 :   ret = GNUNET_OK;
    6976           1 :   if ( (0 > GNUNET_PQ_eval_prepared_non_select (conn,
    6977             :                                                 "gc_reserves",
    6978           1 :                                                 params_time)) ||
    6979           1 :        (0 > GNUNET_PQ_eval_prepared_non_select (conn,
    6980             :                                                 "gc_prewire",
    6981           1 :                                                 params_none)) ||
    6982           1 :        (0 > GNUNET_PQ_eval_prepared_non_select (conn,
    6983             :                                                 "gc_wire_fee",
    6984             :                                                 params_ancient_time)) )
    6985           0 :     ret = GNUNET_SYSERR;
    6986             :   /* This one may fail due to foreign key constraints from
    6987             :      recoup and reserves_out tables to known_coins; these
    6988             :      are NOT using 'ON DROP CASCADE' and might keep denomination
    6989             :      keys alive for a bit longer, thus causing this statement
    6990           1 :      to fail. */(void) GNUNET_PQ_eval_prepared_non_select (conn,
    6991             :                                              "gc_denominations",
    6992             :                                              params_time);
    6993           1 :   GNUNET_PQ_disconnect (conn);
    6994           1 :   return ret;
    6995             : }
    6996             : 
    6997             : 
    6998             : /**
    6999             :  * Closure for #deposit_serial_helper_cb().
    7000             :  */
    7001             : struct DepositSerialContext
    7002             : {
    7003             : 
    7004             :   /**
    7005             :    * Callback to call.
    7006             :    */
    7007             :   TALER_EXCHANGEDB_DepositCallback cb;
    7008             : 
    7009             :   /**
    7010             :    * Closure for @e cb.
    7011             :    */
    7012             :   void *cb_cls;
    7013             : 
    7014             :   /**
    7015             :    * Plugin context.
    7016             :    */
    7017             :   struct PostgresClosure *pg;
    7018             : 
    7019             :   /**
    7020             :    * Status code, set to #GNUNET_SYSERR on hard errors.
    7021             :    */
    7022             :   int status;
    7023             : };
    7024             : 
    7025             : 
    7026             : /**
    7027             :  * Helper function to be called with the results of a SELECT statement
    7028             :  * that has returned @a num_results results.
    7029             :  *
    7030             :  * @param cls closure of type `struct DepositSerialContext`
    7031             :  * @param result the postgres result
    7032             :  * @param num_results the number of results in @a result
    7033             :  */
    7034             : static void
    7035           1 : deposit_serial_helper_cb (void *cls,
    7036             :                           PGresult *result,
    7037             :                           unsigned int num_results)
    7038             : {
    7039           1 :   struct DepositSerialContext *dsc = cls;
    7040           1 :   struct PostgresClosure *pg = dsc->pg;
    7041             : 
    7042           2 :   for (unsigned int i = 0; i<num_results; i++)
    7043             :   {
    7044             :     struct TALER_EXCHANGEDB_Deposit deposit;
    7045             :     struct GNUNET_TIME_Absolute exchange_timestamp;
    7046             :     struct TALER_DenominationPublicKey denom_pub;
    7047           1 :     uint8_t done = 0;
    7048             :     uint64_t rowid;
    7049           1 :     struct GNUNET_PQ_ResultSpec rs[] = {
    7050           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    7051             :                                    &deposit.amount_with_fee),
    7052           1 :       TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
    7053             :                                           &deposit.timestamp),
    7054           1 :       TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
    7055             :                                           &exchange_timestamp),
    7056           1 :       GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
    7057             :                                             &deposit.merchant_pub),
    7058           1 :       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    7059             :                                             &denom_pub.rsa_public_key),
    7060           1 :       GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
    7061             :                                             &deposit.coin.coin_pub),
    7062           1 :       GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
    7063             :                                             &deposit.csig),
    7064           1 :       TALER_PQ_result_spec_absolute_time ("refund_deadline",
    7065             :                                           &deposit.refund_deadline),
    7066           1 :       TALER_PQ_result_spec_absolute_time ("wire_deadline",
    7067             :                                           &deposit.wire_deadline),
    7068           1 :       GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
    7069             :                                             &deposit.h_contract_terms),
    7070           1 :       TALER_PQ_result_spec_json ("wire",
    7071             :                                  &deposit.receiver_wire_account),
    7072           1 :       GNUNET_PQ_result_spec_auto_from_type ("done",
    7073             :                                             &done),
    7074           1 :       GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
    7075             :                                     &rowid),
    7076             :       GNUNET_PQ_result_spec_end
    7077             :     };
    7078             :     int ret;
    7079             : 
    7080           1 :     if (GNUNET_OK !=
    7081           1 :         GNUNET_PQ_extract_result (result,
    7082             :                                   rs,
    7083             :                                   i))
    7084             :     {
    7085           0 :       GNUNET_break (0);
    7086           0 :       dsc->status = GNUNET_SYSERR;
    7087           0 :       return;
    7088             :     }
    7089           1 :     ret = dsc->cb (dsc->cb_cls,
    7090             :                    rowid,
    7091             :                    exchange_timestamp,
    7092             :                    deposit.timestamp,
    7093             :                    &deposit.merchant_pub,
    7094             :                    &denom_pub,
    7095             :                    &deposit.coin.coin_pub,
    7096             :                    &deposit.csig,
    7097             :                    &deposit.amount_with_fee,
    7098             :                    &deposit.h_contract_terms,
    7099             :                    deposit.refund_deadline,
    7100             :                    deposit.wire_deadline,
    7101           1 :                    deposit.receiver_wire_account,
    7102             :                    done);
    7103           1 :     GNUNET_PQ_cleanup_result (rs);
    7104           1 :     if (GNUNET_OK != ret)
    7105           0 :       break;
    7106             :   }
    7107             : }
    7108             : 
    7109             : 
    7110             : /**
    7111             :  * Select deposits above @a serial_id in monotonically increasing
    7112             :  * order.
    7113             :  *
    7114             :  * @param cls closure
    7115             :  * @param session database connection
    7116             :  * @param serial_id highest serial ID to exclude (select strictly larger)
    7117             :  * @param cb function to call on each result
    7118             :  * @param cb_cls closure for @a cb
    7119             :  * @return transaction status code
    7120             :  */
    7121             : static enum GNUNET_DB_QueryStatus
    7122           1 : postgres_select_deposits_above_serial_id (
    7123             :   void *cls,
    7124             :   struct TALER_EXCHANGEDB_Session *session,
    7125             :   uint64_t serial_id,
    7126             :   TALER_EXCHANGEDB_DepositCallback cb,
    7127             :   void *cb_cls)
    7128             : {
    7129           1 :   struct PostgresClosure *pg = cls;
    7130           1 :   struct GNUNET_PQ_QueryParam params[] = {
    7131           1 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    7132             :     GNUNET_PQ_query_param_end
    7133             :   };
    7134           1 :   struct DepositSerialContext dsc = {
    7135             :     .cb = cb,
    7136             :     .cb_cls = cb_cls,
    7137             :     .pg = pg,
    7138             :     .status = GNUNET_OK
    7139             :   };
    7140             :   enum GNUNET_DB_QueryStatus qs;
    7141             : 
    7142           1 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    7143             :                                              "audit_get_deposits_incr",
    7144             :                                              params,
    7145             :                                              &deposit_serial_helper_cb,
    7146             :                                              &dsc);
    7147           1 :   if (GNUNET_OK != dsc.status)
    7148           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    7149           1 :   return qs;
    7150             : }
    7151             : 
    7152             : 
    7153             : /**
    7154             :  * Closure for #refreshs_serial_helper_cb().
    7155             :  */
    7156             : struct RefreshsSerialContext
    7157             : {
    7158             : 
    7159             :   /**
    7160             :    * Callback to call.
    7161             :    */
    7162             :   TALER_EXCHANGEDB_RefreshesCallback cb;
    7163             : 
    7164             :   /**
    7165             :    * Closure for @e cb.
    7166             :    */
    7167             :   void *cb_cls;
    7168             : 
    7169             :   /**
    7170             :    * Plugin context.
    7171             :    */
    7172             :   struct PostgresClosure *pg;
    7173             : 
    7174             :   /**
    7175             :    * Status code, set to #GNUNET_SYSERR on hard errors.
    7176             :    */
    7177             :   int status;
    7178             : };
    7179             : 
    7180             : 
    7181             : /**
    7182             :  * Helper function to be called with the results of a SELECT statement
    7183             :  * that has returned @a num_results results.
    7184             :  *
    7185             :  * @param cls closure of type `struct RefreshsSerialContext`
    7186             :  * @param result the postgres result
    7187             :  * @param num_results the number of results in @a result
    7188             :  */
    7189             : static void
    7190           1 : refreshs_serial_helper_cb (void *cls,
    7191             :                            PGresult *result,
    7192             :                            unsigned int num_results)
    7193             : {
    7194           1 :   struct RefreshsSerialContext *rsc = cls;
    7195           1 :   struct PostgresClosure *pg = rsc->pg;
    7196             : 
    7197           2 :   for (unsigned int i = 0; i<num_results; i++)
    7198             :   {
    7199             :     struct TALER_DenominationPublicKey denom_pub;
    7200             :     struct TALER_CoinSpendPublicKeyP coin_pub;
    7201             :     struct TALER_CoinSpendSignatureP coin_sig;
    7202             :     struct TALER_Amount amount_with_fee;
    7203             :     uint32_t noreveal_index;
    7204             :     uint64_t rowid;
    7205             :     struct TALER_RefreshCommitmentP rc;
    7206           1 :     struct GNUNET_PQ_ResultSpec rs[] = {
    7207           1 :       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    7208             :                                             &denom_pub.rsa_public_key),
    7209           1 :       GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
    7210             :                                             &coin_pub),
    7211           1 :       GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
    7212             :                                             &coin_sig),
    7213           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    7214             :                                    &amount_with_fee),
    7215           1 :       GNUNET_PQ_result_spec_uint32 ("noreveal_index",
    7216             :                                     &noreveal_index),
    7217           1 :       GNUNET_PQ_result_spec_uint64 ("melt_serial_id",
    7218             :                                     &rowid),
    7219           1 :       GNUNET_PQ_result_spec_auto_from_type ("rc",
    7220             :                                             &rc),
    7221             :       GNUNET_PQ_result_spec_end
    7222             :     };
    7223             :     int ret;
    7224             : 
    7225           1 :     if (GNUNET_OK !=
    7226           1 :         GNUNET_PQ_extract_result (result,
    7227             :                                   rs,
    7228             :                                   i))
    7229             :     {
    7230           0 :       GNUNET_break (0);
    7231           0 :       rsc->status = GNUNET_SYSERR;
    7232           0 :       return;
    7233             :     }
    7234           1 :     ret = rsc->cb (rsc->cb_cls,
    7235             :                    rowid,
    7236             :                    &denom_pub,
    7237             :                    &coin_pub,
    7238             :                    &coin_sig,
    7239             :                    &amount_with_fee,
    7240             :                    noreveal_index,
    7241             :                    &rc);
    7242           1 :     GNUNET_PQ_cleanup_result (rs);
    7243           1 :     if (GNUNET_OK != ret)
    7244           0 :       break;
    7245             :   }
    7246             : }
    7247             : 
    7248             : 
    7249             : /**
    7250             :  * Select refresh sessions above @a serial_id in monotonically increasing
    7251             :  * order.
    7252             :  *
    7253             :  * @param cls closure
    7254             :  * @param session database connection
    7255             :  * @param serial_id highest serial ID to exclude (select strictly larger)
    7256             :  * @param cb function to call on each result
    7257             :  * @param cb_cls closure for @a cb
    7258             :  * @return transaction status code
    7259             :  */
    7260             : static enum GNUNET_DB_QueryStatus
    7261           1 : postgres_select_refreshes_above_serial_id (
    7262             :   void *cls,
    7263             :   struct TALER_EXCHANGEDB_Session *session,
    7264             :   uint64_t serial_id,
    7265             :   TALER_EXCHANGEDB_RefreshesCallback cb,
    7266             :   void *cb_cls)
    7267             : {
    7268           1 :   struct PostgresClosure *pg = cls;
    7269           1 :   struct GNUNET_PQ_QueryParam params[] = {
    7270           1 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    7271             :     GNUNET_PQ_query_param_end
    7272             :   };
    7273           1 :   struct RefreshsSerialContext rsc = {
    7274             :     .cb = cb,
    7275             :     .cb_cls = cb_cls,
    7276             :     .pg = pg,
    7277             :     .status = GNUNET_OK
    7278             :   };
    7279             :   enum GNUNET_DB_QueryStatus qs;
    7280             : 
    7281           1 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    7282             :                                              "audit_get_refresh_commitments_incr",
    7283             :                                              params,
    7284             :                                              &refreshs_serial_helper_cb,
    7285             :                                              &rsc);
    7286           1 :   if (GNUNET_OK != rsc.status)
    7287           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    7288           1 :   return qs;
    7289             : }
    7290             : 
    7291             : 
    7292             : /**
    7293             :  * Closure for #refunds_serial_helper_cb().
    7294             :  */
    7295             : struct RefundsSerialContext
    7296             : {
    7297             : 
    7298             :   /**
    7299             :    * Callback to call.
    7300             :    */
    7301             :   TALER_EXCHANGEDB_RefundCallback cb;
    7302             : 
    7303             :   /**
    7304             :    * Closure for @e cb.
    7305             :    */
    7306             :   void *cb_cls;
    7307             : 
    7308             :   /**
    7309             :    * Plugin context.
    7310             :    */
    7311             :   struct PostgresClosure *pg;
    7312             : 
    7313             :   /**
    7314             :    * Status code, set to #GNUNET_SYSERR on hard errors.
    7315             :    */
    7316             :   int status;
    7317             : };
    7318             : 
    7319             : 
    7320             : /**
    7321             :  * Helper function to be called with the results of a SELECT statement
    7322             :  * that has returned @a num_results results.
    7323             :  *
    7324             :  * @param cls closure of type `struct RefundsSerialContext`
    7325             :  * @param result the postgres result
    7326             :  * @param num_results the number of results in @a result
    7327             :  */
    7328             : static void
    7329           1 : refunds_serial_helper_cb (void *cls,
    7330             :                           PGresult *result,
    7331             :                           unsigned int num_results)
    7332             : {
    7333           1 :   struct RefundsSerialContext *rsc = cls;
    7334           1 :   struct PostgresClosure *pg = rsc->pg;
    7335             : 
    7336           2 :   for (unsigned int i = 0; i<num_results; i++)
    7337             :   {
    7338             :     struct TALER_EXCHANGEDB_Refund refund;
    7339             :     struct TALER_DenominationPublicKey denom_pub;
    7340             :     uint64_t rowid;
    7341           1 :     struct GNUNET_PQ_ResultSpec rs[] = {
    7342           1 :       GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
    7343             :                                             &refund.details.merchant_pub),
    7344           1 :       GNUNET_PQ_result_spec_auto_from_type ("merchant_sig",
    7345             :                                             &refund.details.merchant_sig),
    7346           1 :       GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
    7347             :                                             &refund.details.h_contract_terms),
    7348           1 :       GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
    7349             :                                     &refund.details.rtransaction_id),
    7350           1 :       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    7351             :                                             &denom_pub.rsa_public_key),
    7352           1 :       GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
    7353             :                                             &refund.coin.coin_pub),
    7354           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    7355             :                                    &refund.details.refund_amount),
    7356           1 :       GNUNET_PQ_result_spec_uint64 ("refund_serial_id",
    7357             :                                     &rowid),
    7358             :       GNUNET_PQ_result_spec_end
    7359             :     };
    7360             :     int ret;
    7361             : 
    7362           1 :     if (GNUNET_OK !=
    7363           1 :         GNUNET_PQ_extract_result (result,
    7364             :                                   rs,
    7365             :                                   i))
    7366             :     {
    7367           0 :       GNUNET_break (0);
    7368           0 :       rsc->status = GNUNET_SYSERR;
    7369           0 :       return;
    7370             :     }
    7371           1 :     ret = rsc->cb (rsc->cb_cls,
    7372             :                    rowid,
    7373             :                    &denom_pub,
    7374             :                    &refund.coin.coin_pub,
    7375             :                    &refund.details.merchant_pub,
    7376             :                    &refund.details.merchant_sig,
    7377             :                    &refund.details.h_contract_terms,
    7378             :                    refund.details.rtransaction_id,
    7379             :                    &refund.details.refund_amount);
    7380           1 :     GNUNET_PQ_cleanup_result (rs);
    7381           1 :     if (GNUNET_OK != ret)
    7382           0 :       break;
    7383             :   }
    7384             : }
    7385             : 
    7386             : 
    7387             : /**
    7388             :  * Select refunds above @a serial_id in monotonically increasing
    7389             :  * order.
    7390             :  *
    7391             :  * @param cls closure
    7392             :  * @param session database connection
    7393             :  * @param serial_id highest serial ID to exclude (select strictly larger)
    7394             :  * @param cb function to call on each result
    7395             :  * @param cb_cls closure for @a cb
    7396             :  * @return transaction status code
    7397             :  */
    7398             : static enum GNUNET_DB_QueryStatus
    7399           1 : postgres_select_refunds_above_serial_id (
    7400             :   void *cls,
    7401             :   struct TALER_EXCHANGEDB_Session *session,
    7402             :   uint64_t serial_id,
    7403             :   TALER_EXCHANGEDB_RefundCallback cb,
    7404             :   void *cb_cls)
    7405             : {
    7406           1 :   struct PostgresClosure *pg = cls;
    7407           1 :   struct GNUNET_PQ_QueryParam params[] = {
    7408           1 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    7409             :     GNUNET_PQ_query_param_end
    7410             :   };
    7411           1 :   struct RefundsSerialContext rsc = {
    7412             :     .cb = cb,
    7413             :     .cb_cls = cb_cls,
    7414             :     .pg = pg,
    7415             :     .status = GNUNET_OK
    7416             :   };
    7417             :   enum GNUNET_DB_QueryStatus qs;
    7418             : 
    7419           1 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    7420             :                                              "audit_get_refunds_incr",
    7421             :                                              params,
    7422             :                                              &refunds_serial_helper_cb,
    7423             :                                              &rsc);
    7424           1 :   if (GNUNET_OK != rsc.status)
    7425           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    7426           1 :   return qs;
    7427             : }
    7428             : 
    7429             : 
    7430             : /**
    7431             :  * Closure for #reserves_in_serial_helper_cb().
    7432             :  */
    7433             : struct ReservesInSerialContext
    7434             : {
    7435             : 
    7436             :   /**
    7437             :    * Callback to call.
    7438             :    */
    7439             :   TALER_EXCHANGEDB_ReserveInCallback cb;
    7440             : 
    7441             :   /**
    7442             :    * Closure for @e cb.
    7443             :    */
    7444             :   void *cb_cls;
    7445             : 
    7446             :   /**
    7447             :    * Plugin context.
    7448             :    */
    7449             :   struct PostgresClosure *pg;
    7450             : 
    7451             :   /**
    7452             :    * Status code, set to #GNUNET_SYSERR on hard errors.
    7453             :    */
    7454             :   int status;
    7455             : };
    7456             : 
    7457             : 
    7458             : /**
    7459             :  * Helper function to be called with the results of a SELECT statement
    7460             :  * that has returned @a num_results results.
    7461             :  *
    7462             :  * @param cls closure of type `struct ReservesInSerialContext`
    7463             :  * @param result the postgres result
    7464             :  * @param num_results the number of results in @a result
    7465             :  */
    7466             : static void
    7467           1 : reserves_in_serial_helper_cb (void *cls,
    7468             :                               PGresult *result,
    7469             :                               unsigned int num_results)
    7470             : {
    7471           1 :   struct ReservesInSerialContext *risc = cls;
    7472           1 :   struct PostgresClosure *pg = risc->pg;
    7473             : 
    7474           3 :   for (unsigned int i = 0; i<num_results; i++)
    7475             :   {
    7476             :     struct TALER_ReservePublicKeyP reserve_pub;
    7477             :     struct TALER_Amount credit;
    7478             :     char *sender_account_details;
    7479             :     struct GNUNET_TIME_Absolute execution_date;
    7480             :     uint64_t rowid;
    7481             :     uint64_t wire_reference;
    7482           2 :     struct GNUNET_PQ_ResultSpec rs[] = {
    7483           2 :       GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
    7484             :                                             &reserve_pub),
    7485           2 :       GNUNET_PQ_result_spec_uint64 ("wire_reference",
    7486             :                                     &wire_reference),
    7487           2 :       TALER_PQ_RESULT_SPEC_AMOUNT ("credit",
    7488             :                                    &credit),
    7489           2 :       TALER_PQ_result_spec_absolute_time ("execution_date",
    7490             :                                           &execution_date),
    7491           2 :       GNUNET_PQ_result_spec_string ("sender_account_details",
    7492             :                                     &sender_account_details),
    7493           2 :       GNUNET_PQ_result_spec_uint64 ("reserve_in_serial_id",
    7494             :                                     &rowid),
    7495             :       GNUNET_PQ_result_spec_end
    7496             :     };
    7497             :     int ret;
    7498             : 
    7499           2 :     if (GNUNET_OK !=
    7500           2 :         GNUNET_PQ_extract_result (result,
    7501             :                                   rs,
    7502             :                                   i))
    7503             :     {
    7504           0 :       GNUNET_break (0);
    7505           0 :       risc->status = GNUNET_SYSERR;
    7506           0 :       return;
    7507             :     }
    7508           2 :     ret = risc->cb (risc->cb_cls,
    7509             :                     rowid,
    7510             :                     &reserve_pub,
    7511             :                     &credit,
    7512             :                     sender_account_details,
    7513             :                     wire_reference,
    7514             :                     execution_date);
    7515           2 :     GNUNET_PQ_cleanup_result (rs);
    7516           2 :     if (GNUNET_OK != ret)
    7517           0 :       break;
    7518             :   }
    7519             : }
    7520             : 
    7521             : 
    7522             : /**
    7523             :  * Select inbound wire transfers into reserves_in above @a serial_id
    7524             :  * in monotonically increasing order.
    7525             :  *
    7526             :  * @param cls closure
    7527             :  * @param session database connection
    7528             :  * @param serial_id highest serial ID to exclude (select strictly larger)
    7529             :  * @param cb function to call on each result
    7530             :  * @param cb_cls closure for @a cb
    7531             :  * @return transaction status code
    7532             :  */
    7533             : static enum GNUNET_DB_QueryStatus
    7534           1 : postgres_select_reserves_in_above_serial_id (
    7535             :   void *cls,
    7536             :   struct TALER_EXCHANGEDB_Session *session,
    7537             :   uint64_t serial_id,
    7538             :   TALER_EXCHANGEDB_ReserveInCallback cb,
    7539             :   void *cb_cls)
    7540             : {
    7541           1 :   struct PostgresClosure *pg = cls;
    7542           1 :   struct GNUNET_PQ_QueryParam params[] = {
    7543           1 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    7544             :     GNUNET_PQ_query_param_end
    7545             :   };
    7546           1 :   struct ReservesInSerialContext risc = {
    7547             :     .cb = cb,
    7548             :     .cb_cls = cb_cls,
    7549             :     .pg = pg,
    7550             :     .status = GNUNET_OK
    7551             :   };
    7552             :   enum GNUNET_DB_QueryStatus qs;
    7553             : 
    7554           1 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    7555             :                                              "audit_reserves_in_get_transactions_incr",
    7556             :                                              params,
    7557             :                                              &reserves_in_serial_helper_cb,
    7558             :                                              &risc);
    7559           1 :   if (GNUNET_OK != risc.status)
    7560           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    7561           1 :   return qs;
    7562             : }
    7563             : 
    7564             : 
    7565             : /**
    7566             :  * Select inbound wire transfers into reserves_in above @a serial_id
    7567             :  * in monotonically increasing order by account.
    7568             :  *
    7569             :  * @param cls closure
    7570             :  * @param session database connection
    7571             :  * @param account_name name of the account to select by
    7572             :  * @param serial_id highest serial ID to exclude (select strictly larger)
    7573             :  * @param cb function to call on each result
    7574             :  * @param cb_cls closure for @a cb
    7575             :  * @return transaction status code
    7576             :  */
    7577             : static enum GNUNET_DB_QueryStatus
    7578           0 : postgres_select_reserves_in_above_serial_id_by_account (
    7579             :   void *cls,
    7580             :   struct TALER_EXCHANGEDB_Session *session,
    7581             :   const char *account_name,
    7582             :   uint64_t serial_id,
    7583             :   TALER_EXCHANGEDB_ReserveInCallback cb,
    7584             :   void *cb_cls)
    7585             : {
    7586           0 :   struct PostgresClosure *pg = cls;
    7587           0 :   struct GNUNET_PQ_QueryParam params[] = {
    7588           0 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    7589           0 :     GNUNET_PQ_query_param_string (account_name),
    7590             :     GNUNET_PQ_query_param_end
    7591             :   };
    7592           0 :   struct ReservesInSerialContext risc = {
    7593             :     .cb = cb,
    7594             :     .cb_cls = cb_cls,
    7595             :     .pg = pg,
    7596             :     .status = GNUNET_OK
    7597             :   };
    7598             :   enum GNUNET_DB_QueryStatus qs;
    7599             : 
    7600           0 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    7601             :                                              "audit_reserves_in_get_transactions_incr_by_account",
    7602             :                                              params,
    7603             :                                              &reserves_in_serial_helper_cb,
    7604             :                                              &risc);
    7605           0 :   if (GNUNET_OK != risc.status)
    7606           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    7607           0 :   return qs;
    7608             : }
    7609             : 
    7610             : 
    7611             : /**
    7612             :  * Closure for #reserves_out_serial_helper_cb().
    7613             :  */
    7614             : struct ReservesOutSerialContext
    7615             : {
    7616             : 
    7617             :   /**
    7618             :    * Callback to call.
    7619             :    */
    7620             :   TALER_EXCHANGEDB_WithdrawCallback cb;
    7621             : 
    7622             :   /**
    7623             :    * Closure for @e cb.
    7624             :    */
    7625             :   void *cb_cls;
    7626             : 
    7627             :   /**
    7628             :    * Plugin context.
    7629             :    */
    7630             :   struct PostgresClosure *pg;
    7631             : 
    7632             :   /**
    7633             :    * Status code, set to #GNUNET_SYSERR on hard errors.
    7634             :    */
    7635             :   int status;
    7636             : };
    7637             : 
    7638             : 
    7639             : /**
    7640             :  * Helper function to be called with the results of a SELECT statement
    7641             :  * that has returned @a num_results results.
    7642             :  *
    7643             :  * @param cls closure of type `struct ReservesOutSerialContext`
    7644             :  * @param result the postgres result
    7645             :  * @param num_results the number of results in @a result
    7646             :  */
    7647             : static void
    7648           1 : reserves_out_serial_helper_cb (void *cls,
    7649             :                                PGresult *result,
    7650             :                                unsigned int num_results)
    7651             : {
    7652           1 :   struct ReservesOutSerialContext *rosc = cls;
    7653           1 :   struct PostgresClosure *pg = rosc->pg;
    7654             : 
    7655           2 :   for (unsigned int i = 0; i<num_results; i++)
    7656             :   {
    7657             :     struct GNUNET_HashCode h_blind_ev;
    7658             :     struct TALER_DenominationPublicKey denom_pub;
    7659             :     struct TALER_ReservePublicKeyP reserve_pub;
    7660             :     struct TALER_ReserveSignatureP reserve_sig;
    7661             :     struct GNUNET_TIME_Absolute execution_date;
    7662             :     struct TALER_Amount amount_with_fee;
    7663             :     uint64_t rowid;
    7664           1 :     struct GNUNET_PQ_ResultSpec rs[] = {
    7665           1 :       GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
    7666             :                                             &h_blind_ev),
    7667           1 :       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    7668             :                                             &denom_pub.rsa_public_key),
    7669           1 :       GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
    7670             :                                             &reserve_pub),
    7671           1 :       GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
    7672             :                                             &reserve_sig),
    7673           1 :       TALER_PQ_result_spec_absolute_time ("execution_date",
    7674             :                                           &execution_date),
    7675           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    7676             :                                    &amount_with_fee),
    7677           1 :       GNUNET_PQ_result_spec_uint64 ("reserve_out_serial_id",
    7678             :                                     &rowid),
    7679             :       GNUNET_PQ_result_spec_end
    7680             :     };
    7681             :     int ret;
    7682             : 
    7683           1 :     if (GNUNET_OK !=
    7684           1 :         GNUNET_PQ_extract_result (result,
    7685             :                                   rs,
    7686             :                                   i))
    7687             :     {
    7688           0 :       GNUNET_break (0);
    7689           0 :       rosc->status = GNUNET_SYSERR;
    7690           0 :       return;
    7691             :     }
    7692           1 :     ret = rosc->cb (rosc->cb_cls,
    7693             :                     rowid,
    7694             :                     &h_blind_ev,
    7695             :                     &denom_pub,
    7696             :                     &reserve_pub,
    7697             :                     &reserve_sig,
    7698             :                     execution_date,
    7699             :                     &amount_with_fee);
    7700           1 :     GNUNET_PQ_cleanup_result (rs);
    7701           1 :     if (GNUNET_OK != ret)
    7702           0 :       break;
    7703             :   }
    7704             : }
    7705             : 
    7706             : 
    7707             : /**
    7708             :  * Select withdraw operations from reserves_out above @a serial_id
    7709             :  * in monotonically increasing order.
    7710             :  *
    7711             :  * @param cls closure
    7712             :  * @param session database connection
    7713             :  * @param serial_id highest serial ID to exclude (select strictly larger)
    7714             :  * @param cb function to call on each result
    7715             :  * @param cb_cls closure for @a cb
    7716             :  * @return transaction status code
    7717             :  */
    7718             : static enum GNUNET_DB_QueryStatus
    7719           1 : postgres_select_withdrawals_above_serial_id (
    7720             :   void *cls,
    7721             :   struct TALER_EXCHANGEDB_Session *session,
    7722             :   uint64_t serial_id,
    7723             :   TALER_EXCHANGEDB_WithdrawCallback cb,
    7724             :   void *cb_cls)
    7725             : {
    7726           1 :   struct PostgresClosure *pg = cls;
    7727           1 :   struct GNUNET_PQ_QueryParam params[] = {
    7728           1 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    7729             :     GNUNET_PQ_query_param_end
    7730             :   };
    7731           1 :   struct ReservesOutSerialContext rosc = {
    7732             :     .cb = cb,
    7733             :     .cb_cls = cb_cls,
    7734             :     .pg = pg,
    7735             :     .status = GNUNET_OK
    7736             :   };
    7737             :   enum GNUNET_DB_QueryStatus qs;
    7738             : 
    7739           1 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    7740             :                                              "audit_get_reserves_out_incr",
    7741             :                                              params,
    7742             :                                              &reserves_out_serial_helper_cb,
    7743             :                                              &rosc);
    7744           1 :   if (GNUNET_OK != rosc.status)
    7745           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    7746           1 :   return qs;
    7747             : }
    7748             : 
    7749             : 
    7750             : /**
    7751             :  * Closure for #wire_out_serial_helper_cb().
    7752             :  */
    7753             : struct WireOutSerialContext
    7754             : {
    7755             : 
    7756             :   /**
    7757             :    * Callback to call.
    7758             :    */
    7759             :   TALER_EXCHANGEDB_WireTransferOutCallback cb;
    7760             : 
    7761             :   /**
    7762             :    * Closure for @e cb.
    7763             :    */
    7764             :   void *cb_cls;
    7765             : 
    7766             :   /**
    7767             :    * Plugin context.
    7768             :    */
    7769             :   struct PostgresClosure *pg;
    7770             : 
    7771             :   /**
    7772             :    * Status code, set to #GNUNET_SYSERR on hard errors.
    7773             :    */
    7774             :   int status;
    7775             : };
    7776             : 
    7777             : 
    7778             : /**
    7779             :  * Helper function to be called with the results of a SELECT statement
    7780             :  * that has returned @a num_results results.
    7781             :  *
    7782             :  * @param cls closure of type `struct WireOutSerialContext`
    7783             :  * @param result the postgres result
    7784             :  * @param num_results the number of results in @a result
    7785             :  */
    7786             : static void
    7787           1 : wire_out_serial_helper_cb (void *cls,
    7788             :                            PGresult *result,
    7789             :                            unsigned int num_results)
    7790             : {
    7791           1 :   struct WireOutSerialContext *wosc = cls;
    7792           1 :   struct PostgresClosure *pg = wosc->pg;
    7793             : 
    7794           2 :   for (unsigned int i = 0; i<num_results; i++)
    7795             :   {
    7796             :     uint64_t rowid;
    7797             :     struct GNUNET_TIME_Absolute date;
    7798             :     struct TALER_WireTransferIdentifierRawP wtid;
    7799             :     json_t *wire;
    7800             :     struct TALER_Amount amount;
    7801           1 :     struct GNUNET_PQ_ResultSpec rs[] = {
    7802           1 :       GNUNET_PQ_result_spec_uint64 ("wireout_uuid",
    7803             :                                     &rowid),
    7804           1 :       TALER_PQ_result_spec_absolute_time ("execution_date",
    7805             :                                           &date),
    7806           1 :       GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
    7807             :                                             &wtid),
    7808           1 :       TALER_PQ_result_spec_json ("wire_target",
    7809             :                                  &wire),
    7810           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
    7811             :                                    &amount),
    7812             :       GNUNET_PQ_result_spec_end
    7813             :     };
    7814             :     int ret;
    7815             : 
    7816           1 :     if (GNUNET_OK !=
    7817           1 :         GNUNET_PQ_extract_result (result,
    7818             :                                   rs,
    7819             :                                   i))
    7820             :     {
    7821           0 :       GNUNET_break (0);
    7822           0 :       wosc->status = GNUNET_SYSERR;
    7823           0 :       return;
    7824             :     }
    7825           1 :     ret = wosc->cb (wosc->cb_cls,
    7826             :                     rowid,
    7827             :                     date,
    7828             :                     &wtid,
    7829             :                     wire,
    7830             :                     &amount);
    7831           1 :     GNUNET_PQ_cleanup_result (rs);
    7832           1 :     if (GNUNET_OK != ret)
    7833           0 :       break;
    7834             :   }
    7835             : }
    7836             : 
    7837             : 
    7838             : /**
    7839             :  * Function called to select all wire transfers the exchange
    7840             :  * executed.
    7841             :  *
    7842             :  * @param cls closure
    7843             :  * @param session database connection
    7844             :  * @param serial_id highest serial ID to exclude (select strictly larger)
    7845             :  * @param cb function to call for ONE unfinished item
    7846             :  * @param cb_cls closure for @a cb
    7847             :  * @return transaction status code
    7848             :  */
    7849             : static enum GNUNET_DB_QueryStatus
    7850           1 : postgres_select_wire_out_above_serial_id (
    7851             :   void *cls,
    7852             :   struct TALER_EXCHANGEDB_Session *session,
    7853             :   uint64_t serial_id,
    7854             :   TALER_EXCHANGEDB_WireTransferOutCallback cb,
    7855             :   void *cb_cls)
    7856             : {
    7857           1 :   struct PostgresClosure *pg = cls;
    7858           1 :   struct GNUNET_PQ_QueryParam params[] = {
    7859           1 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    7860             :     GNUNET_PQ_query_param_end
    7861             :   };
    7862           1 :   struct WireOutSerialContext wosc = {
    7863             :     .cb = cb,
    7864             :     .cb_cls = cb_cls,
    7865             :     .pg = pg,
    7866             :     .status = GNUNET_OK
    7867             :   };
    7868             :   enum GNUNET_DB_QueryStatus qs;
    7869             : 
    7870           1 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    7871             :                                              "audit_get_wire_incr",
    7872             :                                              params,
    7873             :                                              &wire_out_serial_helper_cb,
    7874             :                                              &wosc);
    7875           1 :   if (GNUNET_OK != wosc.status)
    7876           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    7877           1 :   return qs;
    7878             : }
    7879             : 
    7880             : 
    7881             : /**
    7882             :  * Function called to select all wire transfers the exchange
    7883             :  * executed by account.
    7884             :  *
    7885             :  * @param cls closure
    7886             :  * @param session database connection
    7887             :  * @param account_name account to select
    7888             :  * @param serial_id highest serial ID to exclude (select strictly larger)
    7889             :  * @param cb function to call for ONE unfinished item
    7890             :  * @param cb_cls closure for @a cb
    7891             :  * @return transaction status code
    7892             :  */
    7893             : static enum GNUNET_DB_QueryStatus
    7894           0 : postgres_select_wire_out_above_serial_id_by_account (
    7895             :   void *cls,
    7896             :   struct TALER_EXCHANGEDB_Session *session,
    7897             :   const char *account_name,
    7898             :   uint64_t serial_id,
    7899             :   TALER_EXCHANGEDB_WireTransferOutCallback cb,
    7900             :   void *cb_cls)
    7901             : {
    7902           0 :   struct PostgresClosure *pg = cls;
    7903           0 :   struct GNUNET_PQ_QueryParam params[] = {
    7904           0 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    7905           0 :     GNUNET_PQ_query_param_string (account_name),
    7906             :     GNUNET_PQ_query_param_end
    7907             :   };
    7908           0 :   struct WireOutSerialContext wosc = {
    7909             :     .cb = cb,
    7910             :     .cb_cls = cb_cls,
    7911             :     .pg = pg,
    7912             :     .status = GNUNET_OK
    7913             :   };
    7914             :   enum GNUNET_DB_QueryStatus qs;
    7915             : 
    7916           0 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    7917             :                                              "audit_get_wire_incr_by_account",
    7918             :                                              params,
    7919             :                                              &wire_out_serial_helper_cb,
    7920             :                                              &wosc);
    7921           0 :   if (GNUNET_OK != wosc.status)
    7922           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    7923           0 :   return qs;
    7924             : }
    7925             : 
    7926             : 
    7927             : /**
    7928             :  * Closure for #recoup_serial_helper_cb().
    7929             :  */
    7930             : struct RecoupSerialContext
    7931             : {
    7932             : 
    7933             :   /**
    7934             :    * Callback to call.
    7935             :    */
    7936             :   TALER_EXCHANGEDB_RecoupCallback cb;
    7937             : 
    7938             :   /**
    7939             :    * Closure for @e cb.
    7940             :    */
    7941             :   void *cb_cls;
    7942             : 
    7943             :   /**
    7944             :    * Plugin context.
    7945             :    */
    7946             :   struct PostgresClosure *pg;
    7947             : 
    7948             :   /**
    7949             :    * Status code, set to #GNUNET_SYSERR on hard errors.
    7950             :    */
    7951             :   int status;
    7952             : };
    7953             : 
    7954             : 
    7955             : /**
    7956             :  * Helper function to be called with the results of a SELECT statement
    7957             :  * that has returned @a num_results results.
    7958             :  *
    7959             :  * @param cls closure of type `struct RecoupSerialContext`
    7960             :  * @param result the postgres result
    7961             :  * @param num_results the number of results in @a result
    7962             :  */
    7963             : static void
    7964           2 : recoup_serial_helper_cb (void *cls,
    7965             :                          PGresult *result,
    7966             :                          unsigned int num_results)
    7967             : {
    7968           2 :   struct RecoupSerialContext *psc = cls;
    7969           2 :   struct PostgresClosure *pg = psc->pg;
    7970             : 
    7971           3 :   for (unsigned int i = 0; i<num_results; i++)
    7972             :   {
    7973             :     uint64_t rowid;
    7974             :     struct TALER_ReservePublicKeyP reserve_pub;
    7975             :     struct TALER_CoinPublicInfo coin;
    7976             :     struct TALER_CoinSpendSignatureP coin_sig;
    7977             :     struct TALER_DenominationBlindingKeyP coin_blind;
    7978             :     struct TALER_Amount amount;
    7979             :     struct TALER_DenominationPublicKey denom_pub;
    7980             :     struct GNUNET_HashCode h_blind_ev;
    7981             :     struct GNUNET_TIME_Absolute timestamp;
    7982           1 :     struct GNUNET_PQ_ResultSpec rs[] = {
    7983           1 :       GNUNET_PQ_result_spec_uint64 ("recoup_uuid",
    7984             :                                     &rowid),
    7985           1 :       TALER_PQ_result_spec_absolute_time ("timestamp",
    7986             :                                           &timestamp),
    7987           1 :       GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
    7988             :                                             &reserve_pub),
    7989           1 :       GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
    7990             :                                             &coin.coin_pub),
    7991           1 :       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    7992             :                                             &denom_pub.rsa_public_key),
    7993           1 :       GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
    7994             :                                             &coin_sig),
    7995           1 :       GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
    7996             :                                             &coin_blind),
    7997           1 :       GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
    7998             :                                             &h_blind_ev),
    7999           1 :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    8000             :                                             &coin.denom_pub_hash),
    8001           1 :       GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
    8002             :                                            &coin.denom_sig.rsa_signature),
    8003           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
    8004             :                                    &amount),
    8005             :       GNUNET_PQ_result_spec_end
    8006             :     };
    8007             :     int ret;
    8008             : 
    8009           1 :     if (GNUNET_OK !=
    8010           1 :         GNUNET_PQ_extract_result (result,
    8011             :                                   rs,
    8012             :                                   i))
    8013             :     {
    8014           0 :       GNUNET_break (0);
    8015           0 :       psc->status = GNUNET_SYSERR;
    8016           0 :       return;
    8017             :     }
    8018           1 :     ret = psc->cb (psc->cb_cls,
    8019             :                    rowid,
    8020             :                    timestamp,
    8021             :                    &amount,
    8022             :                    &reserve_pub,
    8023             :                    &coin,
    8024             :                    &denom_pub,
    8025             :                    &coin_sig,
    8026             :                    &coin_blind);
    8027           1 :     GNUNET_PQ_cleanup_result (rs);
    8028           1 :     if (GNUNET_OK != ret)
    8029           0 :       break;
    8030             :   }
    8031             : }
    8032             : 
    8033             : 
    8034             : /**
    8035             :  * Function called to select recoup requests the exchange
    8036             :  * received, ordered by serial ID (monotonically increasing).
    8037             :  *
    8038             :  * @param cls closure
    8039             :  * @param session database connection
    8040             :  * @param serial_id lowest serial ID to include (select larger or equal)
    8041             :  * @param cb function to call for ONE unfinished item
    8042             :  * @param cb_cls closure for @a cb
    8043             :  * @return transaction status code
    8044             :  */
    8045             : static enum GNUNET_DB_QueryStatus
    8046           2 : postgres_select_recoup_above_serial_id (
    8047             :   void *cls,
    8048             :   struct TALER_EXCHANGEDB_Session *session,
    8049             :   uint64_t serial_id,
    8050             :   TALER_EXCHANGEDB_RecoupCallback cb,
    8051             :   void *cb_cls)
    8052             : {
    8053           2 :   struct PostgresClosure *pg = cls;
    8054           2 :   struct GNUNET_PQ_QueryParam params[] = {
    8055           2 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    8056             :     GNUNET_PQ_query_param_end
    8057             :   };
    8058           2 :   struct RecoupSerialContext psc = {
    8059             :     .cb = cb,
    8060             :     .cb_cls = cb_cls,
    8061             :     .pg = pg,
    8062             :     .status = GNUNET_OK
    8063             :   };
    8064             :   enum GNUNET_DB_QueryStatus qs;
    8065             : 
    8066           2 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    8067             :                                              "recoup_get_incr",
    8068             :                                              params,
    8069             :                                              &recoup_serial_helper_cb,
    8070             :                                              &psc);
    8071           2 :   if (GNUNET_OK != psc.status)
    8072           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    8073           2 :   return qs;
    8074             : }
    8075             : 
    8076             : 
    8077             : /**
    8078             :  * Closure for #recoup_refresh_serial_helper_cb().
    8079             :  */
    8080             : struct RecoupRefreshSerialContext
    8081             : {
    8082             : 
    8083             :   /**
    8084             :    * Callback to call.
    8085             :    */
    8086             :   TALER_EXCHANGEDB_RecoupRefreshCallback cb;
    8087             : 
    8088             :   /**
    8089             :    * Closure for @e cb.
    8090             :    */
    8091             :   void *cb_cls;
    8092             : 
    8093             :   /**
    8094             :    * Plugin context.
    8095             :    */
    8096             :   struct PostgresClosure *pg;
    8097             : 
    8098             :   /**
    8099             :    * Status code, set to #GNUNET_SYSERR on hard errors.
    8100             :    */
    8101             :   int status;
    8102             : };
    8103             : 
    8104             : 
    8105             : /**
    8106             :  * Helper function to be called with the results of a SELECT statement
    8107             :  * that has returned @a num_results results.
    8108             :  *
    8109             :  * @param cls closure of type `struct RecoupRefreshSerialContext`
    8110             :  * @param result the postgres result
    8111             :  * @param num_results the number of results in @a result
    8112             :  */
    8113             : static void
    8114           0 : recoup_refresh_serial_helper_cb (void *cls,
    8115             :                                  PGresult *result,
    8116             :                                  unsigned int num_results)
    8117             : {
    8118           0 :   struct RecoupRefreshSerialContext *psc = cls;
    8119           0 :   struct PostgresClosure *pg = psc->pg;
    8120             : 
    8121           0 :   for (unsigned int i = 0; i<num_results; i++)
    8122             :   {
    8123             :     uint64_t rowid;
    8124             :     struct TALER_CoinSpendPublicKeyP old_coin_pub;
    8125             :     struct TALER_CoinPublicInfo coin;
    8126             :     struct TALER_CoinSpendSignatureP coin_sig;
    8127             :     struct TALER_DenominationBlindingKeyP coin_blind;
    8128             :     struct TALER_DenominationPublicKey denom_pub;
    8129             :     struct GNUNET_HashCode old_denom_pub_hash;
    8130             :     struct TALER_Amount amount;
    8131             :     struct GNUNET_HashCode h_blind_ev;
    8132             :     struct GNUNET_TIME_Absolute timestamp;
    8133           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
    8134           0 :       GNUNET_PQ_result_spec_uint64 ("recoup_refresh_uuid",
    8135             :                                     &rowid),
    8136           0 :       TALER_PQ_result_spec_absolute_time ("timestamp",
    8137             :                                           &timestamp),
    8138           0 :       GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
    8139             :                                             &old_coin_pub),
    8140           0 :       GNUNET_PQ_result_spec_auto_from_type ("old_denom_pub_hash",
    8141             :                                             &old_denom_pub_hash),
    8142           0 :       GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
    8143             :                                             &coin.coin_pub),
    8144           0 :       GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
    8145             :                                             &coin_sig),
    8146           0 :       GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
    8147             :                                             &coin_blind),
    8148           0 :       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
    8149             :                                             &denom_pub.rsa_public_key),
    8150           0 :       GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
    8151             :                                             &h_blind_ev),
    8152           0 :       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
    8153             :                                             &coin.denom_pub_hash),
    8154           0 :       GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
    8155             :                                            &coin.denom_sig.rsa_signature),
    8156           0 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
    8157             :                                    &amount),
    8158             :       GNUNET_PQ_result_spec_end
    8159             :     };
    8160             :     int ret;
    8161             : 
    8162           0 :     if (GNUNET_OK !=
    8163           0 :         GNUNET_PQ_extract_result (result,
    8164             :                                   rs,
    8165             :                                   i))
    8166             :     {
    8167           0 :       GNUNET_break (0);
    8168           0 :       psc->status = GNUNET_SYSERR;
    8169           0 :       return;
    8170             :     }
    8171           0 :     ret = psc->cb (psc->cb_cls,
    8172             :                    rowid,
    8173             :                    timestamp,
    8174             :                    &amount,
    8175             :                    &old_coin_pub,
    8176             :                    &old_denom_pub_hash,
    8177             :                    &coin,
    8178             :                    &denom_pub,
    8179             :                    &coin_sig,
    8180             :                    &coin_blind);
    8181           0 :     GNUNET_PQ_cleanup_result (rs);
    8182           0 :     if (GNUNET_OK != ret)
    8183           0 :       break;
    8184             :   }
    8185             : }
    8186             : 
    8187             : 
    8188             : /**
    8189             :  * Function called to select recoup requests the exchange received for
    8190             :  * refreshed coins, ordered by serial ID (monotonically increasing).
    8191             :  *
    8192             :  * @param cls closure
    8193             :  * @param session database connection
    8194             :  * @param serial_id lowest serial ID to include (select larger or equal)
    8195             :  * @param cb function to call for ONE unfinished item
    8196             :  * @param cb_cls closure for @a cb
    8197             :  * @return transaction status code
    8198             :  */
    8199             : static enum GNUNET_DB_QueryStatus
    8200           0 : postgres_select_recoup_refresh_above_serial_id (
    8201             :   void *cls,
    8202             :   struct TALER_EXCHANGEDB_Session *session,
    8203             :   uint64_t serial_id,
    8204             :   TALER_EXCHANGEDB_RecoupRefreshCallback cb,
    8205             :   void *cb_cls)
    8206             : {
    8207           0 :   struct PostgresClosure *pg = cls;
    8208           0 :   struct GNUNET_PQ_QueryParam params[] = {
    8209           0 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    8210             :     GNUNET_PQ_query_param_end
    8211             :   };
    8212           0 :   struct RecoupRefreshSerialContext psc = {
    8213             :     .cb = cb,
    8214             :     .cb_cls = cb_cls,
    8215             :     .pg = pg,
    8216             :     .status = GNUNET_OK
    8217             :   };
    8218             :   enum GNUNET_DB_QueryStatus qs;
    8219             : 
    8220           0 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    8221             :                                              "recoup_refresh_get_incr",
    8222             :                                              params,
    8223             :                                              &recoup_refresh_serial_helper_cb,
    8224             :                                              &psc);
    8225           0 :   if (GNUNET_OK != psc.status)
    8226           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    8227           0 :   return qs;
    8228             : }
    8229             : 
    8230             : 
    8231             : /**
    8232             :  * Closure for #reserve_closed_serial_helper_cb().
    8233             :  */
    8234             : struct ReserveClosedSerialContext
    8235             : {
    8236             : 
    8237             :   /**
    8238             :    * Callback to call.
    8239             :    */
    8240             :   TALER_EXCHANGEDB_ReserveClosedCallback cb;
    8241             : 
    8242             :   /**
    8243             :    * Closure for @e cb.
    8244             :    */
    8245             :   void *cb_cls;
    8246             : 
    8247             :   /**
    8248             :    * Plugin's context.
    8249             :    */
    8250             :   struct PostgresClosure *pg;
    8251             : 
    8252             :   /**
    8253             :    * Status code, set to #GNUNET_SYSERR on hard errors.
    8254             :    */
    8255             :   int status;
    8256             : };
    8257             : 
    8258             : 
    8259             : /**
    8260             :  * Helper function to be called with the results of a SELECT statement
    8261             :  * that has returned @a num_results results.
    8262             :  *
    8263             :  * @param cls closure of type `struct ReserveClosedSerialContext`
    8264             :  * @param result the postgres result
    8265             :  * @param num_results the number of results in @a result
    8266             :  */
    8267             : static void
    8268           0 : reserve_closed_serial_helper_cb (void *cls,
    8269             :                                  PGresult *result,
    8270             :                                  unsigned int num_results)
    8271             : {
    8272           0 :   struct ReserveClosedSerialContext *rcsc = cls;
    8273           0 :   struct PostgresClosure *pg = rcsc->pg;
    8274             : 
    8275           0 :   for (unsigned int i = 0; i<num_results; i++)
    8276             :   {
    8277             :     uint64_t rowid;
    8278             :     struct TALER_ReservePublicKeyP reserve_pub;
    8279             :     char *receiver_account;
    8280             :     struct TALER_WireTransferIdentifierRawP wtid;
    8281             :     struct TALER_Amount amount_with_fee;
    8282             :     struct TALER_Amount closing_fee;
    8283             :     struct GNUNET_TIME_Absolute execution_date;
    8284           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
    8285           0 :       GNUNET_PQ_result_spec_uint64 ("close_uuid",
    8286             :                                     &rowid),
    8287           0 :       GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
    8288             :                                             &reserve_pub),
    8289           0 :       TALER_PQ_result_spec_absolute_time ("execution_date",
    8290             :                                           &execution_date),
    8291           0 :       GNUNET_PQ_result_spec_auto_from_type ("wtid",
    8292             :                                             &wtid),
    8293           0 :       GNUNET_PQ_result_spec_string ("receiver_account",
    8294             :                                     &receiver_account),
    8295           0 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
    8296             :                                    &amount_with_fee),
    8297           0 :       TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
    8298             :                                    &closing_fee),
    8299             :       GNUNET_PQ_result_spec_end
    8300             :     };
    8301             :     int ret;
    8302             : 
    8303           0 :     if (GNUNET_OK !=
    8304           0 :         GNUNET_PQ_extract_result (result,
    8305             :                                   rs,
    8306             :                                   i))
    8307             :     {
    8308           0 :       GNUNET_break (0);
    8309           0 :       rcsc->status = GNUNET_SYSERR;
    8310           0 :       return;
    8311             :     }
    8312           0 :     ret = rcsc->cb (rcsc->cb_cls,
    8313             :                     rowid,
    8314             :                     execution_date,
    8315             :                     &amount_with_fee,
    8316             :                     &closing_fee,
    8317             :                     &reserve_pub,
    8318             :                     receiver_account,
    8319             :                     &wtid);
    8320           0 :     GNUNET_PQ_cleanup_result (rs);
    8321           0 :     if (GNUNET_OK != ret)
    8322           0 :       break;
    8323             :   }
    8324             : }
    8325             : 
    8326             : 
    8327             : /**
    8328             :  * Function called to select reserve close operations the aggregator
    8329             :  * triggered, ordered by serial ID (monotonically increasing).
    8330             :  *
    8331             :  * @param cls closure
    8332             :  * @param session database connection
    8333             :  * @param serial_id lowest serial ID to include (select larger or equal)
    8334             :  * @param cb function to call for ONE unfinished item
    8335             :  * @param cb_cls closure for @a cb
    8336             :  * @return transaction status code
    8337             :  */
    8338             : static enum GNUNET_DB_QueryStatus
    8339           0 : postgres_select_reserve_closed_above_serial_id (
    8340             :   void *cls,
    8341             :   struct TALER_EXCHANGEDB_Session *session,
    8342             :   uint64_t serial_id,
    8343             :   TALER_EXCHANGEDB_ReserveClosedCallback cb,
    8344             :   void *cb_cls)
    8345             : {
    8346           0 :   struct PostgresClosure *pg = cls;
    8347           0 :   struct GNUNET_PQ_QueryParam params[] = {
    8348           0 :     GNUNET_PQ_query_param_uint64 (&serial_id),
    8349             :     GNUNET_PQ_query_param_end
    8350             :   };
    8351           0 :   struct ReserveClosedSerialContext rcsc = {
    8352             :     .cb = cb,
    8353             :     .cb_cls = cb_cls,
    8354             :     .pg = pg,
    8355             :     .status = GNUNET_OK
    8356             :   };
    8357             :   enum GNUNET_DB_QueryStatus qs;
    8358             : 
    8359           0 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    8360             :                                              "reserves_close_get_incr",
    8361             :                                              params,
    8362             :                                              &reserve_closed_serial_helper_cb,
    8363             :                                              &rcsc);
    8364           0 :   if (GNUNET_OK != rcsc.status)
    8365           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    8366           0 :   return qs;
    8367             : }
    8368             : 
    8369             : 
    8370             : /**
    8371             :  * Function called to add a request for an emergency recoup for a
    8372             :  * coin.  The funds are to be added back to the reserve.  The function
    8373             :  * should return the @a deadline by which the exchange will trigger a
    8374             :  * wire transfer back to the customer's account for the reserve.
    8375             :  *
    8376             :  * @param cls closure
    8377             :  * @param session database connection
    8378             :  * @param reserve_pub public key of the reserve that is being refunded
    8379             :  * @param coin information about the coin
    8380             :  * @param coin_sig signature of the coin of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
    8381             :  * @param coin_blind blinding key of the coin
    8382             :  * @param amount total amount to be paid back
    8383             :  * @param h_blind_ev hash of the blinded coin's envelope (must match reserves_out entry)
    8384             :  * @param timestamp current time (rounded)
    8385             :  * @return transaction result status
    8386             :  */
    8387             : static enum GNUNET_DB_QueryStatus
    8388           2 : postgres_insert_recoup_request (
    8389             :   void *cls,
    8390             :   struct TALER_EXCHANGEDB_Session *session,
    8391             :   const struct TALER_ReservePublicKeyP *reserve_pub,
    8392             :   const struct TALER_CoinPublicInfo *coin,
    8393             :   const struct TALER_CoinSpendSignatureP *coin_sig,
    8394             :   const struct TALER_DenominationBlindingKeyP *coin_blind,
    8395             :   const struct TALER_Amount *amount,
    8396             :   const struct GNUNET_HashCode *h_blind_ev,
    8397             :   struct GNUNET_TIME_Absolute timestamp)
    8398             : {
    8399           2 :   struct PostgresClosure *pg = cls;
    8400             :   struct GNUNET_TIME_Absolute expiry;
    8401             :   struct TALER_EXCHANGEDB_Reserve reserve;
    8402           2 :   struct GNUNET_PQ_QueryParam params[] = {
    8403           2 :     GNUNET_PQ_query_param_auto_from_type (&coin->coin_pub),
    8404           2 :     GNUNET_PQ_query_param_auto_from_type (coin_sig),
    8405           2 :     GNUNET_PQ_query_param_auto_from_type (coin_blind),
    8406           2 :     TALER_PQ_query_param_amount (amount),
    8407           2 :     TALER_PQ_query_param_absolute_time (&timestamp),
    8408           2 :     GNUNET_PQ_query_param_auto_from_type (h_blind_ev),
    8409             :     GNUNET_PQ_query_param_end
    8410             :   };
    8411             :   enum GNUNET_DB_QueryStatus qs;
    8412             : 
    8413             :   /* now store actual recoup information */
    8414           2 :   qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    8415             :                                            "recoup_insert",
    8416             :                                            params);
    8417           2 :   if (0 > qs)
    8418             :   {
    8419           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    8420           0 :     return qs;
    8421             :   }
    8422             : 
    8423             :   /* Update reserve balance */
    8424           2 :   reserve.pub = *reserve_pub;
    8425           2 :   qs = postgres_reserves_get (cls,
    8426             :                               session,
    8427             :                               &reserve);
    8428           2 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    8429             :   {
    8430           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    8431           0 :     return qs;
    8432             :   }
    8433           2 :   if (0 >
    8434           2 :       TALER_amount_add (&reserve.balance,
    8435             :                         &reserve.balance,
    8436             :                         amount))
    8437             :   {
    8438           0 :     GNUNET_break (0);
    8439           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    8440             :   }
    8441           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    8442             :               "Inserting recoup for coin %s\n",
    8443             :               TALER_B2S (&coin->coin_pub));
    8444           2 :   expiry = GNUNET_TIME_absolute_add (timestamp,
    8445             :                                      pg->legal_reserve_expiration_time);
    8446           2 :   reserve.gc = GNUNET_TIME_absolute_max (expiry,
    8447             :                                          reserve.gc);
    8448           2 :   (void) GNUNET_TIME_round_abs (&reserve.gc);
    8449           2 :   expiry = GNUNET_TIME_absolute_add (timestamp,
    8450             :                                      pg->idle_reserve_expiration_time);
    8451           2 :   reserve.expiry = GNUNET_TIME_absolute_max (expiry,
    8452             :                                              reserve.expiry);
    8453           2 :   (void) GNUNET_TIME_round_abs (&reserve.expiry);
    8454           2 :   qs = reserves_update (cls,
    8455             :                         session,
    8456             :                         &reserve);
    8457           2 :   if (0 >= qs)
    8458             :   {
    8459           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    8460           0 :     return qs;
    8461             :   }
    8462           2 :   return qs;
    8463             : }
    8464             : 
    8465             : 
    8466             : /**
    8467             :  * Function called to add a request for an emergency recoup for a
    8468             :  * refreshed coin.  The funds are to be added back to the original coin
    8469             :  * (which is implied via @a h_blind_ev, see the prepared statement
    8470             :  * "recoup_by_old_coin" used in #postgres_get_coin_transactions()).
    8471             :  *
    8472             :  * @param cls closure
    8473             :  * @param session database connection
    8474             :  * @param coin public information about the refreshed coin
    8475             :  * @param coin_sig signature of the coin of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
    8476             :  * @param coin_blind blinding key of the coin
    8477             :  * @param h_blind_ev blinded envelope, as calculated by the exchange
    8478             :  * @param amount total amount to be paid back
    8479             :  * @param h_blind_ev hash of the blinded coin's envelope (must match reserves_out entry)
    8480             :  * @param timestamp a timestamp to store
    8481             :  * @return transaction result status
    8482             :  */
    8483             : static enum GNUNET_DB_QueryStatus
    8484           0 : postgres_insert_recoup_refresh_request (
    8485             :   void *cls,
    8486             :   struct TALER_EXCHANGEDB_Session *session,
    8487             :   const struct TALER_CoinPublicInfo *coin,
    8488             :   const struct TALER_CoinSpendSignatureP *coin_sig,
    8489             :   const struct TALER_DenominationBlindingKeyP *coin_blind,
    8490             :   const struct TALER_Amount *amount,
    8491             :   const struct GNUNET_HashCode *h_blind_ev,
    8492             :   struct GNUNET_TIME_Absolute timestamp)
    8493             : {
    8494           0 :   struct GNUNET_PQ_QueryParam params[] = {
    8495           0 :     GNUNET_PQ_query_param_auto_from_type (&coin->coin_pub),
    8496           0 :     GNUNET_PQ_query_param_auto_from_type (coin_sig),
    8497           0 :     GNUNET_PQ_query_param_auto_from_type (coin_blind),
    8498           0 :     TALER_PQ_query_param_amount (amount),
    8499           0 :     TALER_PQ_query_param_absolute_time (&timestamp),
    8500           0 :     GNUNET_PQ_query_param_auto_from_type (h_blind_ev),
    8501             :     GNUNET_PQ_query_param_end
    8502             :   };
    8503             :   enum GNUNET_DB_QueryStatus qs;
    8504             : 
    8505             :   (void) cls;
    8506             :   /* now store actual recoup information */
    8507           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    8508             :               "Inserting recoup-refresh for coin %s\n",
    8509             :               TALER_B2S (&coin->coin_pub));
    8510           0 :   qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
    8511             :                                            "recoup_refresh_insert",
    8512             :                                            params);
    8513           0 :   if (0 > qs)
    8514             :   {
    8515           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    8516           0 :     return qs;
    8517             :   }
    8518           0 :   return qs;
    8519             : }
    8520             : 
    8521             : 
    8522             : /**
    8523             :  * Obtain information about which reserve a coin was generated
    8524             :  * from given the hash of the blinded coin.
    8525             :  *
    8526             :  * @param cls closure
    8527             :  * @param session a session
    8528             :  * @param h_blind_ev hash of the blinded coin
    8529             :  * @param[out] reserve_pub set to information about the reserve (on success only)
    8530             :  * @return transaction status code
    8531             :  */
    8532             : static enum GNUNET_DB_QueryStatus
    8533           1 : postgres_get_reserve_by_h_blind (void *cls,
    8534             :                                  struct TALER_EXCHANGEDB_Session *session,
    8535             :                                  const struct GNUNET_HashCode *h_blind_ev,
    8536             :                                  struct TALER_ReservePublicKeyP *reserve_pub)
    8537             : {
    8538           1 :   struct GNUNET_PQ_QueryParam params[] = {
    8539           1 :     GNUNET_PQ_query_param_auto_from_type (h_blind_ev),
    8540             :     GNUNET_PQ_query_param_end
    8541             :   };
    8542           1 :   struct GNUNET_PQ_ResultSpec rs[] = {
    8543           1 :     GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
    8544             :                                           reserve_pub),
    8545             :     GNUNET_PQ_result_spec_end
    8546             :   };
    8547             : 
    8548             :   (void) cls;
    8549           1 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    8550             :                                                    "reserve_by_h_blind",
    8551             :                                                    params,
    8552             :                                                    rs);
    8553             : }
    8554             : 
    8555             : 
    8556             : /**
    8557             :  * Obtain information about which old coin a coin was refreshed
    8558             :  * given the hash of the blinded (fresh) coin.
    8559             :  *
    8560             :  * @param cls closure
    8561             :  * @param session a session
    8562             :  * @param h_blind_ev hash of the blinded coin
    8563             :  * @param[out] old_coin_pub set to information about the old coin (on success only)
    8564             :  * @return transaction status code
    8565             :  */
    8566             : static enum GNUNET_DB_QueryStatus
    8567           0 : postgres_get_old_coin_by_h_blind (void *cls,
    8568             :                                   struct TALER_EXCHANGEDB_Session *session,
    8569             :                                   const struct GNUNET_HashCode *h_blind_ev,
    8570             :                                   struct TALER_CoinSpendPublicKeyP *old_coin_pub)
    8571             : {
    8572           0 :   struct GNUNET_PQ_QueryParam params[] = {
    8573           0 :     GNUNET_PQ_query_param_auto_from_type (h_blind_ev),
    8574             :     GNUNET_PQ_query_param_end
    8575             :   };
    8576           0 :   struct GNUNET_PQ_ResultSpec rs[] = {
    8577           0 :     GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
    8578             :                                           old_coin_pub),
    8579             :     GNUNET_PQ_result_spec_end
    8580             :   };
    8581             : 
    8582             :   (void) cls;
    8583           0 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    8584             :                                                    "old_coin_by_h_blind",
    8585             :                                                    params,
    8586             :                                                    rs);
    8587             : }
    8588             : 
    8589             : 
    8590             : /**
    8591             :  * Store information that a denomination key was revoked
    8592             :  * in the database.
    8593             :  *
    8594             :  * @param cls closure
    8595             :  * @param session a session
    8596             :  * @param denom_pub_hash hash of the revoked denomination key
    8597             :  * @param master_sig signature affirming the revocation
    8598             :  * @return transaction status code
    8599             :  */
    8600             : static enum GNUNET_DB_QueryStatus
    8601           2 : postgres_insert_denomination_revocation (
    8602             :   void *cls,
    8603             :   struct TALER_EXCHANGEDB_Session *session,
    8604             :   const struct GNUNET_HashCode *denom_pub_hash,
    8605             :   const struct TALER_MasterSignatureP *master_sig)
    8606             : {
    8607           2 :   struct PostgresClosure *pc = cls;
    8608           2 :   struct GNUNET_PQ_QueryParam params[] = {
    8609           2 :     GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
    8610           2 :     GNUNET_PQ_query_param_auto_from_type (master_sig),
    8611             :     GNUNET_PQ_query_param_end
    8612             :   };
    8613             : 
    8614           2 :   if (NULL == session)
    8615           0 :     session = postgres_get_session (pc);
    8616           2 :   if (NULL == session)
    8617           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    8618             : 
    8619           2 :   return GNUNET_PQ_eval_prepared_non_select (session->conn,
    8620             :                                              "denomination_revocation_insert",
    8621             :                                              params);
    8622             : }
    8623             : 
    8624             : 
    8625             : /**
    8626             :  * Obtain information about a denomination key's revocation from
    8627             :  * the database.
    8628             :  *
    8629             :  * @param cls closure
    8630             :  * @param session a session
    8631             :  * @param denom_pub_hash hash of the revoked denomination key
    8632             :  * @param[out] master_sig signature affirming the revocation
    8633             :  * @param[out] rowid row where the information is stored
    8634             :  * @return transaction status code
    8635             :  */
    8636             : static enum GNUNET_DB_QueryStatus
    8637           1 : postgres_get_denomination_revocation (
    8638             :   void *cls,
    8639             :   struct TALER_EXCHANGEDB_Session *session,
    8640             :   const struct GNUNET_HashCode *denom_pub_hash,
    8641             :   struct TALER_MasterSignatureP *master_sig,
    8642             :   uint64_t *rowid)
    8643             : {
    8644           1 :   struct GNUNET_PQ_QueryParam params[] = {
    8645           1 :     GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
    8646             :     GNUNET_PQ_query_param_end
    8647             :   };
    8648           1 :   struct GNUNET_PQ_ResultSpec rs[] = {
    8649           1 :     GNUNET_PQ_result_spec_auto_from_type ("master_sig", master_sig),
    8650           1 :     GNUNET_PQ_result_spec_uint64 ("denom_revocations_serial_id", rowid),
    8651             :     GNUNET_PQ_result_spec_end
    8652             :   };
    8653             : 
    8654             :   (void) cls;
    8655           1 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    8656             :                                                    "denomination_revocation_get",
    8657             :                                                    params,
    8658             :                                                    rs);
    8659             : }
    8660             : 
    8661             : 
    8662             : /**
    8663             :  * Closure for #missing_wire_cb().
    8664             :  */
    8665             : struct MissingWireContext
    8666             : {
    8667             :   /**
    8668             :    * Function to call per result.
    8669             :    */
    8670             :   TALER_EXCHANGEDB_WireMissingCallback cb;
    8671             : 
    8672             :   /**
    8673             :    * Closure for @e cb.
    8674             :    */
    8675             :   void *cb_cls;
    8676             : 
    8677             :   /**
    8678             :    * Plugin context.
    8679             :    */
    8680             :   struct PostgresClosure *pg;
    8681             : 
    8682             :   /**
    8683             :    * Set to #GNUNET_SYSERR on error.
    8684             :    */
    8685             :   int status;
    8686             : };
    8687             : 
    8688             : 
    8689             : /**
    8690             :  * Invoke the callback for each result.
    8691             :  *
    8692             :  * @param cls a `struct MissingWireContext *`
    8693             :  * @param result SQL result
    8694             :  * @param num_results number of rows in @a result
    8695             :  */
    8696             : static void
    8697           1 : missing_wire_cb (void *cls,
    8698             :                  PGresult *result,
    8699             :                  unsigned int num_results)
    8700             : {
    8701           1 :   struct MissingWireContext *mwc = cls;
    8702           1 :   struct PostgresClosure *pg = mwc->pg;
    8703             : 
    8704           2 :   while (0 < num_results)
    8705             :   {
    8706             :     uint64_t rowid;
    8707             :     struct TALER_CoinSpendPublicKeyP coin_pub;
    8708             :     struct TALER_Amount amount;
    8709             :     json_t *wire;
    8710             :     struct GNUNET_TIME_Absolute deadline;
    8711             :     uint8_t tiny;
    8712             :     uint8_t done;
    8713           1 :     struct GNUNET_PQ_ResultSpec rs[] = {
    8714           1 :       GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
    8715             :                                     &rowid),
    8716           1 :       GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
    8717             :                                             &coin_pub),
    8718           1 :       TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
    8719             :                                    &amount),
    8720           1 :       TALER_PQ_result_spec_json ("wire",
    8721             :                                  &wire),
    8722           1 :       TALER_PQ_result_spec_absolute_time ("wire_deadline",
    8723             :                                           &deadline),
    8724           1 :       GNUNET_PQ_result_spec_auto_from_type ("tiny",
    8725             :                                             &tiny),
    8726           1 :       GNUNET_PQ_result_spec_auto_from_type ("done",
    8727             :                                             &done),
    8728             :       GNUNET_PQ_result_spec_end
    8729             :     };
    8730             : 
    8731           1 :     if (GNUNET_OK !=
    8732           1 :         GNUNET_PQ_extract_result (result,
    8733             :                                   rs,
    8734             :                                   --num_results))
    8735             :     {
    8736           0 :       GNUNET_break (0);
    8737           0 :       mwc->status = GNUNET_SYSERR;
    8738           0 :       return;
    8739             :     }
    8740           1 :     mwc->cb (mwc->cb_cls,
    8741             :              rowid,
    8742             :              &coin_pub,
    8743             :              &amount,
    8744             :              wire,
    8745             :              deadline,
    8746             :              tiny,
    8747             :              done);
    8748           1 :     GNUNET_PQ_cleanup_result (rs);
    8749             :   }
    8750             : }
    8751             : 
    8752             : 
    8753             : /**
    8754             :  * Select all of those deposits in the database for which we do
    8755             :  * not have a wire transfer (or a refund) and which should have
    8756             :  * been deposited between @a start_date and @a end_date.
    8757             :  *
    8758             :  * @param cls closure
    8759             :  * @param session a session
    8760             :  * @param start_date lower bound on the requested wire execution date
    8761             :  * @param end_date upper bound on the requested wire execution date
    8762             :  * @param cb function to call on all such deposits
    8763             :  * @param cb_cls closure for @a cb
    8764             :  * @return transaction status code
    8765             :  */
    8766             : static enum GNUNET_DB_QueryStatus
    8767           1 : postgres_select_deposits_missing_wire (void *cls,
    8768             :                                        struct TALER_EXCHANGEDB_Session *session,
    8769             :                                        struct GNUNET_TIME_Absolute start_date,
    8770             :                                        struct GNUNET_TIME_Absolute end_date,
    8771             :                                        TALER_EXCHANGEDB_WireMissingCallback cb,
    8772             :                                        void *cb_cls)
    8773             : {
    8774           1 :   struct PostgresClosure *pg = cls;
    8775           1 :   struct GNUNET_PQ_QueryParam params[] = {
    8776           1 :     TALER_PQ_query_param_absolute_time (&start_date),
    8777           1 :     TALER_PQ_query_param_absolute_time (&end_date),
    8778             :     GNUNET_PQ_query_param_end
    8779             :   };
    8780           1 :   struct MissingWireContext mwc = {
    8781             :     .cb = cb,
    8782             :     .cb_cls = cb_cls,
    8783             :     .pg = pg,
    8784             :     .status = GNUNET_OK
    8785             :   };
    8786             :   enum GNUNET_DB_QueryStatus qs;
    8787             : 
    8788           1 :   qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
    8789             :                                              "deposits_get_overdue",
    8790             :                                              params,
    8791             :                                              &missing_wire_cb,
    8792             :                                              &mwc);
    8793           1 :   if (GNUNET_OK != mwc.status)
    8794           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
    8795           1 :   return qs;
    8796             : }
    8797             : 
    8798             : 
    8799             : /**
    8800             :  * Check the last date an auditor was modified.
    8801             :  *
    8802             :  * @param cls closure
    8803             :  * @param session a session
    8804             :  * @param auditor_pub key to look up information for
    8805             :  * @param[out] last_date last modification date to auditor status
    8806             :  * @return transaction status code
    8807             :  */
    8808             : static enum GNUNET_DB_QueryStatus
    8809          11 : postgres_lookup_auditor_timestamp (
    8810             :   void *cls,
    8811             :   struct TALER_EXCHANGEDB_Session *session,
    8812             :   const struct TALER_AuditorPublicKeyP *auditor_pub,
    8813             :   struct GNUNET_TIME_Absolute *last_date)
    8814             : {
    8815          11 :   struct GNUNET_PQ_QueryParam params[] = {
    8816          11 :     GNUNET_PQ_query_param_auto_from_type (auditor_pub),
    8817             :     GNUNET_PQ_query_param_end
    8818             :   };
    8819          11 :   struct GNUNET_PQ_ResultSpec rs[] = {
    8820          11 :     TALER_PQ_result_spec_absolute_time ("last_change",
    8821             :                                         last_date),
    8822             :     GNUNET_PQ_result_spec_end
    8823             :   };
    8824             : 
    8825             :   (void) cls;
    8826          11 :   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    8827             :                                                    "lookup_auditor_timestamp",
    8828             :                                                    params,
    8829             :                                                    rs);
    8830             : }
    8831             : 
    8832             : 
    8833             : /**
    8834             :  * Lookup current state of an auditor.
    8835             :  *
    8836             :  * @param cls closure
    8837             :  * @param session a session
    8838             :  * @param auditor_pub key to look up information for
    8839             :  * @param[out] auditor_url set to the base URL of the auditor's REST API; memory to be
    8840             :  *            released by the caller!
    8841             :  * @param[out] enabled set if the auditor is currently in use
    8842             :  * @return transaction status code
    8843             :  */
    8844             : static enum GNUNET_DB_QueryStatus
    8845           0 : postgres_lookup_auditor_status (void *cls,
    8846             :                                 struct TALER_EXCHANGEDB_Session *session,
    8847             :                                 const struct
    8848             :                                 TALER_AuditorPublicKeyP *auditor_pub,
    8849             :                                 char **auditor_url,
    8850             :                                 bool *enabled)
    8851             : {
    8852           0 :   struct GNUNET_PQ_QueryParam params[] = {
    8853           0 :     GNUNET_PQ_query_param_auto_from_type (auditor_pub),
    8854             :     GNUNET_PQ_query_param_end
    8855             :   };
    8856           0 :   uint8_t enabled8 = 0;
    8857           0 :   struct GNUNET_PQ_ResultSpec rs[] = {
    8858           0 :     GNUNET_PQ_result_spec_string ("auditor_url",
    8859             :                                   auditor_url),
    8860           0 :     GNUNET_PQ_result_spec_auto_from_type ("is_active",
    8861             :                                           &enabled8),
    8862             :     GNUNET_PQ_result_spec_end
    8863             :   };
    8864             :   enum GNUNET_DB_QueryStatus qs;
    8865             : 
    8866             :   (void) cls;
    8867           0 :   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
    8868             :                                                  "lookup_auditor_status",
    8869             :                                                  params,
    8870             :                                                  rs);
    8871           0 :   *enabled = (0 != enabled8);
    8872           0 :   return qs;
    8873             : }
    8874             : 
    8875             : 
    8876             : /**
    8877             :  * Insert information about an auditor that will audit this exchange.
    8878             :  *
    8879             :  * @param cls closure
    8880             :  * @param session a session
    8881             :  * @param auditor_pub key of the auditor
    8882             :  * @param auditor_url base URL of the auditor's REST service
    8883             :  * @param auditor_name name of the auditor (for humans)
    8884             :  * @param start_date date when the auditor was added by the offline system
    8885             :  *                      (only to be used for replay detection)
    8886             :  * @return transaction status code
    8887             :  */
    8888             : static enum GNUNET_DB_QueryStatus
    8889           7 : postgres_insert_auditor (void *cls,
    8890             :                          struct TALER_EXCHANGEDB_Session *session,
    8891             :                          const struct TALER_AuditorPublicKeyP *auditor_pub,
    8892             :                          const char *auditor_url,
    8893             :                          const char *auditor_name,
    8894             :                          struct GNUNET_TIME_Absolute start_date)
    8895             : {
    8896           7 :   struct GNUNET_PQ_QueryParam params[] = {
    8897           7 :     GNUNET_PQ_query_param_auto_from_type (auditor_pub),
    8898           7 :     GNUNET_PQ_query_param_string (auditor_name),