exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

plugin_auditordb_postgres.c (24456B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2024 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  * @file plugin_auditordb_postgres.c
     18  * @brief Low-level (statement-level) Postgres database access for the auditor
     19  * @author Christian Grothoff
     20  * @author Gabor X Toth
     21  */
     22 #include "taler/platform.h"
     23 #include "taler/taler_pq_lib.h"
     24 #include <pthread.h>
     25 #include <libpq-fe.h>
     26 #include "pg_delete_auditor_closure_lag.h"
     27 #include "pg_delete_early_aggregation.h"
     28 #include "pg_delete_generic.h"
     29 #include "pg_delete_pending_deposit.h"
     30 #include "pg_delete_purse_info.h"
     31 #include "pg_delete_reserve_in_inconsistency.h"
     32 #include "pg_del_denomination_balance.h"
     33 #include "pg_del_reserve_info.h"
     34 #include "pg_get_auditor_progress.h"
     35 #include "pg_get_balance.h"
     36 #include "pg_get_balances.h"
     37 #include "pg_get_denomination_balance.h"
     38 #include "pg_get_deposit_confirmations.h"
     39 #include "pg_get_purse_info.h"
     40 #include "pg_get_reserve_info.h"
     41 #include "pg_get_wire_fee_summary.h"
     42 #include "pg_helper.h"
     43 #include "pg_insert_auditor_progress.h"
     44 #include "pg_insert_balance.h"
     45 #include "pg_insert_denomination_balance.h"
     46 #include "pg_insert_deposit_confirmation.h"
     47 #include "pg_insert_early_aggregation.h"
     48 #include "pg_insert_exchange_signkey.h"
     49 #include "pg_insert_historic_denom_revenue.h"
     50 #include "pg_insert_historic_reserve_revenue.h"
     51 #include "pg_insert_pending_deposit.h"
     52 #include "pg_insert_purse_info.h"
     53 #include "pg_insert_reserve_info.h"
     54 #include "pg_select_reserve_in_inconsistency.h"
     55 #include "pg_select_historic_denom_revenue.h"
     56 #include "pg_select_historic_reserve_revenue.h"
     57 #include "pg_get_progress_points.h"
     58 #include "pg_select_pending_deposits.h"
     59 #include "pg_select_purse_expired.h"
     60 #include "pg_update_generic_suppressed.h"
     61 #include "pg_update_auditor_progress.h"
     62 #include "pg_update_denomination_balance.h"
     63 #include "pg_update_purse_info.h"
     64 #include "pg_update_reserve_info.h"
     65 #include "pg_update_wire_fee_summary.h"
     66 #include "pg_get_amount_arithmetic_inconsistency.h"
     67 #include "pg_get_coin_inconsistency.h"
     68 #include "pg_get_row_inconsistency.h"
     69 #include "pg_update_balance.h"
     70 #include "pg_select_early_aggregations.h"
     71 
     72 #include "pg_insert_coin_inconsistency.h"
     73 #include "pg_insert_row_inconsistency.h"
     74 #include "pg_insert_amount_arithmetic_inconsistency.h"
     75 
     76 #include "pg_get_auditor_closure_lags.h"
     77 #include "pg_insert_auditor_closure_lags.h"
     78 
     79 #include "pg_get_emergency_by_count.h"
     80 #include "pg_insert_emergency_by_count.h"
     81 
     82 #include "pg_get_emergency.h"
     83 #include "pg_insert_emergency.h"
     84 
     85 #include "pg_get_bad_sig_losses.h"
     86 #include "pg_insert_bad_sig_losses.h"
     87 
     88 #include "pg_get_denomination_key_validity_withdraw_inconsistency.h"
     89 #include "pg_insert_denomination_key_validity_withdraw_inconsistency.h"
     90 
     91 #include "pg_get_fee_time_inconsistency.h"
     92 #include "pg_insert_fee_time_inconsistency.h"
     93 
     94 #include "pg_get_purse_not_closed_inconsistencies.h"
     95 #include "pg_insert_purse_not_closed_inconsistencies.h"
     96 
     97 #include "pg_get_reserve_balance_insufficient_inconsistency.h"
     98 #include "pg_insert_reserve_balance_insufficient_inconsistency.h"
     99 
    100 #include "pg_get_reserve_in_inconsistency.h"
    101 #include "pg_lookup_reserve_in_inconsistency.h"
    102 #include "pg_insert_reserve_in_inconsistency.h"
    103 
    104 #include "pg_get_reserve_not_closed_inconsistency.h"
    105 #include "pg_insert_reserve_not_closed_inconsistency.h"
    106 
    107 #include "pg_get_denominations_without_sigs.h"
    108 #include "pg_insert_denominations_without_sigs.h"
    109 
    110 #include "pg_get_misattribution_in_inconsistency.h"
    111 #include "pg_insert_misattribution_in_inconsistency.h"
    112 
    113 #include "pg_get_reserves.h"
    114 #include "pg_get_purses.h"
    115 
    116 #include "pg_get_denomination_pending.h"
    117 #include "pg_insert_denomination_pending.h"
    118 
    119 #include "pg_get_exchange_signkeys.h"
    120 
    121 #include "pg_get_wire_format_inconsistency.h"
    122 #include "pg_insert_wire_format_inconsistency.h"
    123 
    124 #include "pg_get_wire_out_inconsistency.h"
    125 #include "pg_insert_wire_out_inconsistency.h"
    126 #include "pg_delete_wire_out_inconsistency_if_matching.h"
    127 
    128 #include "pg_get_reserve_balance_summary_wrong_inconsistency.h"
    129 #include "pg_insert_reserve_balance_summary_wrong_inconsistency.h"
    130 
    131 #include "pg_get_row_minor_inconsistencies.h"
    132 #include "pg_insert_row_minor_inconsistencies.h"
    133 
    134 #define LOG(kind,...) GNUNET_log_from (kind, "taler-auditordb-postgres", \
    135                                        __VA_ARGS__)
    136 
    137 
    138 /**
    139  * Drop all auditor tables OR deletes recoverable auditor state.
    140  * This should only be used by testcases or when restarting the
    141  * auditor from scratch.
    142  *
    143  * @param cls the `struct PostgresClosure` with the plugin-specific state
    144  * @param drop_exchangelist drop all tables, including schema versioning
    145  *        and the exchange and deposit_confirmations table; NOT to be
    146  *        used when restarting the auditor
    147  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
    148  */
    149 static enum GNUNET_GenericReturnValue
    150 postgres_drop_tables (void *cls,
    151                       bool drop_exchangelist)
    152 {
    153   struct PostgresClosure *pc = cls;
    154   struct GNUNET_PQ_Context *conn;
    155   enum GNUNET_GenericReturnValue ret;
    156 
    157   conn = GNUNET_PQ_connect_with_cfg (pc->cfg,
    158                                      "auditordb-postgres",
    159                                      NULL,
    160                                      NULL,
    161                                      NULL);
    162   if (NULL == conn)
    163     return GNUNET_SYSERR;
    164   ret = GNUNET_PQ_exec_sql (conn,
    165                             (drop_exchangelist) ? "drop" : "restart");
    166   GNUNET_PQ_disconnect (conn);
    167   return ret;
    168 }
    169 
    170 
    171 /**
    172  * Create the necessary tables if they are not present
    173  *
    174  * @param cls the `struct PostgresClosure` with the plugin-specific state
    175  * @param support_partitions true to support partitioning
    176  * @param num_partitions number of partitions to use
    177  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
    178  */
    179 static enum GNUNET_GenericReturnValue
    180 postgres_create_tables (void *cls,
    181                         bool support_partitions,
    182                         uint32_t num_partitions)
    183 {
    184   struct PostgresClosure *pc = cls;
    185   enum GNUNET_GenericReturnValue ret = GNUNET_OK;
    186   struct GNUNET_PQ_Context *conn;
    187   struct GNUNET_PQ_QueryParam params[] = {
    188     support_partitions
    189     ? GNUNET_PQ_query_param_uint32 (&num_partitions)
    190     : GNUNET_PQ_query_param_null (),
    191     GNUNET_PQ_query_param_end
    192   };
    193   struct GNUNET_PQ_PreparedStatement ps[] = {
    194     GNUNET_PQ_make_prepare ("create_tables",
    195                             "SELECT"
    196                             " auditor.do_create_tables"
    197                             " ($1);"),
    198     GNUNET_PQ_PREPARED_STATEMENT_END
    199   };
    200   struct GNUNET_PQ_ExecuteStatement es[] = {
    201     GNUNET_PQ_make_try_execute ("SET search_path TO auditor;"),
    202     GNUNET_PQ_EXECUTE_STATEMENT_END
    203   };
    204 
    205   conn = GNUNET_PQ_connect_with_cfg (pc->cfg,
    206                                      "auditordb-postgres",
    207                                      "auditor-",
    208                                      es,
    209                                      ps);
    210   if (NULL == conn)
    211   {
    212     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    213                 "Failed to connect to database\n");
    214     return GNUNET_SYSERR;
    215   }
    216   if (0 >
    217       GNUNET_PQ_eval_prepared_non_select (conn,
    218                                           "create_tables",
    219                                           params))
    220   {
    221     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    222                 "Failed to run 'create_tables' prepared statement\n");
    223     ret = GNUNET_SYSERR;
    224   }
    225   if (GNUNET_OK == ret)
    226   {
    227     ret = GNUNET_PQ_exec_sql (conn,
    228                               "procedures");
    229     if (GNUNET_OK != ret)
    230       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    231                   "Failed to load stored procedures\n");
    232   }
    233   GNUNET_PQ_disconnect (conn);
    234   return ret;
    235 }
    236 
    237 
    238 /**
    239  * Register callback to be invoked on events of type @a es.
    240  *
    241  * @param cls database context to use
    242  * @param es specification of the event to listen for
    243  * @param timeout how long to wait for the event
    244  * @param cb function to call when the event happens, possibly
    245  *         mulrewardle times (until cancel is invoked)
    246  * @param cb_cls closure for @a cb
    247  * @return handle useful to cancel the listener
    248  */
    249 static struct GNUNET_DB_EventHandler *
    250 postgres_event_listen (void *cls,
    251                        const struct GNUNET_DB_EventHeaderP *es,
    252                        struct GNUNET_TIME_Relative timeout,
    253                        GNUNET_DB_EventCallback cb,
    254                        void *cb_cls)
    255 {
    256   struct PostgresClosure *pg = cls;
    257 
    258   return GNUNET_PQ_event_listen (pg->conn,
    259                                  es,
    260                                  timeout,
    261                                  cb,
    262                                  cb_cls);
    263 }
    264 
    265 
    266 /**
    267  * Stop notifications.
    268  *
    269  * @param eh handle to unregister.
    270  */
    271 static void
    272 postgres_event_listen_cancel (struct GNUNET_DB_EventHandler *eh)
    273 {
    274   GNUNET_PQ_event_listen_cancel (eh);
    275 }
    276 
    277 
    278 /**
    279  * Notify all that listen on @a es of an event.
    280  *
    281  * @param cls database context to use
    282  * @param es specification of the event to generate
    283  * @param extra additional event data provided
    284  * @param extra_size number of bytes in @a extra
    285  */
    286 static void
    287 postgres_event_notify (void *cls,
    288                        const struct GNUNET_DB_EventHeaderP *es,
    289                        const void *extra,
    290                        size_t extra_size)
    291 {
    292   struct PostgresClosure *pg = cls;
    293 
    294   return GNUNET_PQ_event_notify (pg->conn,
    295                                  es,
    296                                  extra,
    297                                  extra_size);
    298 }
    299 
    300 
    301 /**
    302  * Connect to the db if the connection does not exist yet.
    303  *
    304  * @param[in,out] pg the plugin-specific state
    305  * @return #GNUNET_OK on success
    306  */
    307 static enum GNUNET_GenericReturnValue
    308 setup_connection (struct PostgresClosure *pg)
    309 {
    310   struct GNUNET_PQ_ExecuteStatement es[] = {
    311     GNUNET_PQ_make_try_execute ("SET search_path TO auditor;"),
    312     GNUNET_PQ_EXECUTE_STATEMENT_END
    313   };
    314   struct GNUNET_PQ_Context *db_conn;
    315 
    316   if (NULL != pg->conn)
    317   {
    318     GNUNET_PQ_reconnect_if_down (pg->conn);
    319     return GNUNET_OK;
    320   }
    321   db_conn = GNUNET_PQ_connect_with_cfg2 (pg->cfg,
    322                                          "auditordb-postgres",
    323                                          "auditor-",
    324                                          es,
    325                                          NULL, /* prepared statements */
    326                                          GNUNET_PQ_FLAG_CHECK_CURRENT);
    327   if (NULL == db_conn)
    328     return GNUNET_SYSERR;
    329   pg->conn = db_conn;
    330   pg->prep_gen++;
    331   return GNUNET_OK;
    332 }
    333 
    334 
    335 /**
    336  * Do a pre-flight check that we are not in an uncommitted transaction.
    337  * If we are, rollback the previous transaction and output a warning.
    338  *
    339  * @param cls the `struct PostgresClosure` with the plugin-specific state
    340  * @return #GNUNET_OK on success,
    341  *         #GNUNET_NO if we rolled back an earlier transaction
    342  *         #GNUNET_SYSERR if we have no DB connection
    343  */
    344 static enum GNUNET_GenericReturnValue
    345 postgres_preflight (void *cls)
    346 {
    347   struct PostgresClosure *pg = cls;
    348   struct GNUNET_PQ_ExecuteStatement es[] = {
    349     GNUNET_PQ_make_execute ("ROLLBACK"),
    350     GNUNET_PQ_EXECUTE_STATEMENT_END
    351   };
    352 
    353   if ( (NULL == pg->conn) &&
    354        (GNUNET_OK !=
    355         setup_connection (pg)) )
    356     return GNUNET_SYSERR;
    357   if (NULL == pg->transaction_name)
    358     return GNUNET_OK; /* all good */
    359   if (GNUNET_OK ==
    360       GNUNET_PQ_exec_statements (pg->conn,
    361                                  es))
    362   {
    363     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    364                 "BUG: Preflight check rolled back transaction `%s'!\n",
    365                 pg->transaction_name);
    366   }
    367   else
    368   {
    369     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    370                 "BUG: Preflight check failed to rollback transaction `%s'!\n",
    371                 pg->transaction_name);
    372   }
    373   pg->transaction_name = NULL;
    374   return GNUNET_NO;
    375 }
    376 
    377 
    378 /**
    379  * Start a transaction.
    380  *
    381  * @param cls the `struct PostgresClosure` with the plugin-specific state
    382  * @return #GNUNET_OK on success
    383  */
    384 static enum GNUNET_GenericReturnValue
    385 postgres_start (void *cls)
    386 {
    387   struct PostgresClosure *pg = cls;
    388   struct GNUNET_PQ_ExecuteStatement es[] = {
    389     GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
    390     GNUNET_PQ_EXECUTE_STATEMENT_END
    391   };
    392 
    393   postgres_preflight (cls);
    394   if (GNUNET_OK !=
    395       GNUNET_PQ_exec_statements (pg->conn,
    396                                  es))
    397   {
    398     TALER_LOG_ERROR ("Failed to start transaction\n");
    399     GNUNET_break (0);
    400     return GNUNET_SYSERR;
    401   }
    402   return GNUNET_OK;
    403 }
    404 
    405 
    406 /**
    407  * Roll back the current transaction of a database connection.
    408  *
    409  * @param cls the `struct PostgresClosure` with the plugin-specific state
    410  */
    411 static void
    412 postgres_rollback (void *cls)
    413 {
    414   struct PostgresClosure *pg = cls;
    415   struct GNUNET_PQ_ExecuteStatement es[] = {
    416     GNUNET_PQ_make_execute ("ROLLBACK"),
    417     GNUNET_PQ_EXECUTE_STATEMENT_END
    418   };
    419 
    420   GNUNET_break (GNUNET_OK ==
    421                 GNUNET_PQ_exec_statements (pg->conn,
    422                                            es));
    423 }
    424 
    425 
    426 /**
    427  * Commit the current transaction of a database connection.
    428  *
    429  * @param cls the `struct PostgresClosure` with the plugin-specific state
    430  * @return transaction status code
    431  */
    432 static enum GNUNET_DB_QueryStatus
    433 postgres_commit (void *cls)
    434 {
    435   struct PostgresClosure *pg = cls;
    436   struct GNUNET_PQ_QueryParam params[] = {
    437     GNUNET_PQ_query_param_end
    438   };
    439 
    440   PREPARE (pg,
    441            "do_commit",
    442            "COMMIT");
    443   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
    444                                              "do_commit",
    445                                              params);
    446 }
    447 
    448 
    449 /**
    450  * Function called to perform "garbage collection" on the
    451  * database, expiring records we no longer require.
    452  *
    453  * @param cls closure
    454  * @return #GNUNET_OK on success,
    455  *         #GNUNET_SYSERR on DB errors
    456  */
    457 static enum GNUNET_GenericReturnValue
    458 postgres_gc (void *cls)
    459 {
    460   struct PostgresClosure *pg = cls;
    461   /* For now, we hard-code the cut-off date based on the
    462      common legal requirement to keep data for 10 years.
    463      Might make it configurable in the future. */
    464   struct GNUNET_TIME_Absolute cutoff
    465     = GNUNET_TIME_absolute_subtract (
    466         GNUNET_TIME_absolute_get (),
    467         GNUNET_TIME_relative_multiply (
    468           GNUNET_TIME_UNIT_YEARS,
    469           10));
    470   struct GNUNET_PQ_QueryParam params_time[] = {
    471     GNUNET_PQ_query_param_absolute_time (&cutoff),
    472     GNUNET_PQ_query_param_end
    473   };
    474   struct GNUNET_PQ_Context *conn;
    475   enum GNUNET_DB_QueryStatus qs;
    476   struct GNUNET_PQ_PreparedStatement ps[] = {
    477     GNUNET_PQ_make_prepare ("do_gc_auditor",
    478                             "CALL"
    479                             " auditor.auditor_do_gc_auditor"
    480                             " ($1);"),
    481     GNUNET_PQ_PREPARED_STATEMENT_END
    482   };
    483   struct GNUNET_PQ_ExecuteStatement es[] = {
    484     GNUNET_PQ_make_try_execute ("SET search_path TO auditor;"),
    485     GNUNET_PQ_EXECUTE_STATEMENT_END
    486   };
    487 
    488   conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
    489                                      "auditordb-postgres",
    490                                      NULL,
    491                                      es,
    492                                      ps);
    493   if (NULL == conn)
    494     return GNUNET_SYSERR;
    495   qs = GNUNET_PQ_eval_prepared_non_select (conn,
    496                                            "do_gc_auditor",
    497                                            params_time);
    498   GNUNET_PQ_disconnect (conn);
    499   if (0 > qs)
    500   {
    501     GNUNET_break (0);
    502     return GNUNET_SYSERR;
    503   }
    504   return GNUNET_OK;
    505 }
    506 
    507 
    508 /**
    509  * Initialize Postgres database subsystem.
    510  *
    511  * @param cls a configuration instance
    512  * @return NULL on error, otherwise a `struct TALER_AUDITORDB_Plugin`
    513  */
    514 void *
    515 libtaler_plugin_auditordb_postgres_init (void *cls);
    516 
    517 /* Declaration used to squash compiler warning */
    518 void *
    519 libtaler_plugin_auditordb_postgres_init (void *cls)
    520 {
    521   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
    522   struct PostgresClosure *pg;
    523   struct TALER_AUDITORDB_Plugin *plugin;
    524 
    525   pg = GNUNET_new (struct PostgresClosure);
    526   pg->cfg = cfg;
    527   if (GNUNET_OK !=
    528       TALER_config_get_currency (cfg,
    529                                  "exchange",
    530                                  &pg->currency))
    531   {
    532     GNUNET_free (pg);
    533     return NULL;
    534   }
    535 
    536   plugin = GNUNET_new (struct TALER_AUDITORDB_Plugin);
    537   plugin->cls = pg;
    538   plugin->preflight = &postgres_preflight;
    539   plugin->drop_tables = &postgres_drop_tables;
    540   plugin->create_tables = &postgres_create_tables;
    541   plugin->event_listen = &postgres_event_listen;
    542   plugin->event_listen_cancel = &postgres_event_listen_cancel;
    543   plugin->event_notify = &postgres_event_notify;
    544   plugin->start = &postgres_start;
    545   plugin->commit = &postgres_commit;
    546   plugin->rollback = &postgres_rollback;
    547   plugin->gc = &postgres_gc;
    548 
    549   plugin->get_auditor_progress
    550     = &TAH_PG_get_auditor_progress;
    551 
    552   plugin->get_balance = &TAH_PG_get_balance;
    553   plugin->get_balances = &TAH_PG_get_balances;
    554 
    555   plugin->insert_auditor_progress
    556     = &TAH_PG_insert_auditor_progress;
    557   plugin->insert_balance
    558     = &TAH_PG_insert_balance;
    559   plugin->update_generic_suppressed
    560     = &TAH_PG_update_generic_suppressed;
    561   plugin->delete_generic
    562     = &TAH_PG_delete_generic;
    563   plugin->delete_wire_out_inconsistency_if_matching
    564     = &TAH_PG_delete_wire_out_inconsistency_if_matching;
    565 
    566   plugin->delete_auditor_closure_lag
    567     = &TAH_PG_delete_auditor_closure_lag;
    568 
    569   plugin->update_auditor_progress
    570     = &TAH_PG_update_auditor_progress;
    571   plugin->insert_deposit_confirmation
    572     = &TAH_PG_insert_deposit_confirmation;
    573   plugin->get_deposit_confirmations
    574     = &TAH_PG_get_deposit_confirmations;
    575 
    576   plugin->get_amount_arithmetic_inconsistency
    577     = &TAH_PG_get_amount_arithmetic_inconsistency;
    578   plugin->get_coin_inconsistency
    579     = &TAH_PG_get_coin_inconsistency;
    580   plugin->get_row_inconsistency
    581     = &TAH_PG_get_row_inconsistency;
    582 
    583 
    584   plugin->insert_amount_arithmetic_inconsistency
    585     = &TAH_PG_insert_amount_arithmetic_inconsistency;
    586   plugin->insert_coin_inconsistency
    587     = &TAH_PG_insert_coin_inconsistency;
    588   plugin->insert_row_inconsistency
    589     = &TAH_PG_insert_row_inconsistency;
    590 
    591   plugin->insert_reserve_info
    592     = &TAH_PG_insert_reserve_info;
    593   plugin->update_reserve_info
    594     = &TAH_PG_update_reserve_info;
    595   plugin->get_reserve_info
    596     = &TAH_PG_get_reserve_info;
    597   plugin->del_reserve_info
    598     = &TAH_PG_del_reserve_info;
    599 
    600   plugin->insert_pending_deposit
    601     = &TAH_PG_insert_pending_deposit;
    602   plugin->select_pending_deposits
    603     = &TAH_PG_select_pending_deposits;
    604   plugin->delete_pending_deposit
    605     = &TAH_PG_delete_pending_deposit;
    606 
    607   plugin->insert_purse_info
    608     = &TAH_PG_insert_purse_info;
    609   plugin->update_purse_info
    610     = &TAH_PG_update_purse_info;
    611   plugin->get_purse_info
    612     = &TAH_PG_get_purse_info;
    613   plugin->delete_purse_info
    614     = &TAH_PG_delete_purse_info;
    615   plugin->select_purse_expired
    616     = &TAH_PG_select_purse_expired;
    617 
    618   plugin->insert_denomination_balance
    619     = &TAH_PG_insert_denomination_balance;
    620   plugin->update_denomination_balance
    621     = &TAH_PG_update_denomination_balance;
    622   plugin->del_denomination_balance
    623     = &TAH_PG_del_denomination_balance;
    624   plugin->get_denomination_balance
    625     = &TAH_PG_get_denomination_balance;
    626 
    627   plugin->insert_historic_denom_revenue
    628     = &TAH_PG_insert_historic_denom_revenue;
    629 
    630   plugin->select_historic_denom_revenue
    631     = &TAH_PG_select_historic_denom_revenue;
    632 
    633   plugin->insert_historic_reserve_revenue
    634     = &TAH_PG_insert_historic_reserve_revenue;
    635   plugin->select_historic_reserve_revenue
    636     = &TAH_PG_select_historic_reserve_revenue;
    637 
    638 
    639   plugin->insert_emergency = &TAH_PG_insert_emergency;
    640   plugin->get_emergency = &TAH_PG_get_emergency;
    641 
    642   plugin->insert_emergency_by_count = &TAH_PG_insert_emergency_by_count;
    643   plugin->get_emergency_by_count = &TAH_PG_get_emergency_by_count;
    644 
    645 
    646   plugin->insert_denomination_key_validity_withdraw_inconsistency =
    647     &TAH_PG_insert_denomination_key_validity_withdraw_inconsistency;
    648   plugin->get_denomination_key_validity_withdraw_inconsistency =
    649     &TAH_PG_get_denomination_key_validity_withdraw_inconsistency;
    650 
    651   plugin->insert_purse_not_closed_inconsistencies =
    652     &TAH_PG_insert_purse_not_closed_inconsistencies;
    653   plugin->get_purse_not_closed_inconsistencies =
    654     &TAH_PG_get_purse_not_closed_inconsistencies;
    655 
    656 
    657   plugin->insert_reserve_balance_insufficient_inconsistency =
    658     &TAH_PG_insert_reserve_balance_insufficient_inconsistency;
    659   plugin->get_reserve_balance_insufficient_inconsistency =
    660     &TAH_PG_get_reserve_balance_insufficient_inconsistency;
    661 
    662   plugin->insert_bad_sig_losses = &TAH_PG_insert_bad_sig_losses;
    663   plugin->get_bad_sig_losses = &TAH_PG_get_bad_sig_losses;
    664 
    665   plugin->insert_auditor_closure_lags = &TAH_PG_insert_auditor_closure_lags;
    666   plugin->get_auditor_closure_lags = &TAH_PG_get_auditor_closure_lags;
    667 
    668   plugin->insert_reserve_in_inconsistency =
    669     &TAH_PG_insert_reserve_in_inconsistency;
    670   plugin->get_reserve_in_inconsistency
    671     = &TAH_PG_get_reserve_in_inconsistency;
    672   plugin->lookup_reserve_in_inconsistency
    673     = &TAH_PG_lookup_reserve_in_inconsistency;
    674 
    675   plugin->insert_reserve_not_closed_inconsistency =
    676     &TAH_PG_insert_reserve_not_closed_inconsistency;
    677   plugin->get_reserve_not_closed_inconsistency =
    678     &TAH_PG_get_reserve_not_closed_inconsistency;
    679 
    680   plugin->insert_denominations_without_sigs =
    681     &TAH_PG_insert_denominations_without_sigs;
    682   plugin->get_denominations_without_sigs =
    683     &TAH_PG_get_denominations_without_sigs;
    684 
    685   plugin->get_progress_points
    686     = &TAH_PG_get_progress_points;
    687 
    688 
    689   plugin->insert_misattribution_in_inconsistency =
    690     &TAH_PG_insert_misattribution_in_inconsistency;
    691   plugin->get_misattribution_in_inconsistency =
    692     &TAH_PG_get_misattribution_in_inconsistency;
    693 
    694   plugin->get_reserves = &TAH_PG_get_reserves;
    695   plugin->get_purses = &TAH_PG_get_purses;
    696 
    697   plugin->insert_denomination_pending = &TAH_PG_insert_denomination_pending;
    698   plugin->get_denomination_pending = &TAH_PG_get_denomination_pending;
    699 
    700   plugin->get_exchange_signkeys = &TAH_PG_get_exchange_signkeys;
    701 
    702   plugin->insert_wire_format_inconsistency =
    703     &TAH_PG_insert_wire_format_inconsistency;
    704   plugin->get_wire_format_inconsistency = &TAH_PG_get_wire_format_inconsistency;
    705 
    706   plugin->insert_early_aggregation
    707     = &TAH_PG_insert_early_aggregation;
    708   plugin->delete_early_aggregation
    709     = &TAH_PG_delete_early_aggregation;
    710 
    711   plugin->insert_wire_out_inconsistency
    712     = &TAH_PG_insert_wire_out_inconsistency;
    713   plugin->get_wire_out_inconsistency
    714     = &TAH_PG_get_wire_out_inconsistency;
    715   plugin->select_reserve_in_inconsistency
    716     = &TAH_PG_select_reserve_in_inconsistency;
    717   plugin->delete_reserve_in_inconsistency
    718     = &TAH_PG_delete_reserve_in_inconsistency;
    719   plugin->select_early_aggregations
    720     = &TAH_PG_select_early_aggregations;
    721 
    722   plugin->insert_reserve_balance_summary_wrong_inconsistency =
    723     &TAH_PG_insert_reserve_balance_summary_wrong_inconsistency;
    724   plugin->get_reserve_balance_summary_wrong_inconsistency =
    725     &TAH_PG_get_reserve_balance_summary_wrong_inconsistency;
    726 
    727 
    728   plugin->insert_row_minor_inconsistencies =
    729     &TAH_PG_insert_row_minor_inconsistencies;
    730   plugin->get_row_minor_inconsistencies = &TAH_PG_get_row_minor_inconsistencies;
    731 
    732   plugin->insert_fee_time_inconsistency = &TAH_PG_insert_fee_time_inconsistency;
    733   plugin->get_fee_time_inconsistency = &TAH_PG_get_fee_time_inconsistency;
    734 
    735   plugin->update_balance
    736     = &TAH_PG_update_balance;
    737 
    738   plugin->insert_exchange_signkey
    739     = &TAH_PG_insert_exchange_signkey;
    740 
    741   return plugin;
    742 }
    743 
    744 
    745 /**
    746  * Shutdown Postgres database subsystem.
    747  *
    748  * @param cls a `struct TALER_AUDITORDB_Plugin`
    749  * @return NULL (always)
    750  */
    751 void *
    752 libtaler_plugin_auditordb_postgres_done (void *cls);
    753 
    754 /* Declaration used to squash compiler warning */
    755 void *
    756 libtaler_plugin_auditordb_postgres_done (void *cls)
    757 {
    758   struct TALER_AUDITORDB_Plugin *plugin = cls;
    759   struct PostgresClosure *pg = plugin->cls;
    760 
    761   if (NULL != pg->conn)
    762     GNUNET_PQ_disconnect (pg->conn);
    763   GNUNET_free (pg->currency);
    764   GNUNET_free (pg);
    765   GNUNET_free (plugin);
    766   return NULL;
    767 }
    768 
    769 
    770 /* end of plugin_auditordb_postgres.c */