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 (24083B)


      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   struct GNUNET_TIME_Absolute now = {0};
    462   struct GNUNET_PQ_QueryParam params_time[] = {
    463     GNUNET_PQ_query_param_absolute_time (&now),
    464     GNUNET_PQ_query_param_end
    465   };
    466   struct GNUNET_PQ_Context *conn;
    467   enum GNUNET_DB_QueryStatus qs;
    468   struct GNUNET_PQ_PreparedStatement ps[] = {
    469     GNUNET_PQ_PREPARED_STATEMENT_END
    470   };
    471   struct GNUNET_PQ_ExecuteStatement es[] = {
    472     GNUNET_PQ_make_try_execute ("SET search_path TO auditor;"),
    473     GNUNET_PQ_EXECUTE_STATEMENT_END
    474   };
    475 
    476   now = GNUNET_TIME_absolute_get ();
    477   conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
    478                                      "auditordb-postgres",
    479                                      NULL,
    480                                      es,
    481                                      ps);
    482   if (NULL == conn)
    483     return GNUNET_SYSERR;
    484   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    485               "FIXME: Auditor GC not implemented (#9433)\n");
    486   qs = GNUNET_PQ_eval_prepared_non_select (conn,
    487                                            "gc_auditor",
    488                                            params_time);
    489   GNUNET_PQ_disconnect (conn);
    490   if (0 > qs)
    491   {
    492     GNUNET_break (0);
    493     return GNUNET_SYSERR;
    494   }
    495   return GNUNET_OK;
    496 }
    497 
    498 
    499 /**
    500  * Initialize Postgres database subsystem.
    501  *
    502  * @param cls a configuration instance
    503  * @return NULL on error, otherwise a `struct TALER_AUDITORDB_Plugin`
    504  */
    505 void *
    506 libtaler_plugin_auditordb_postgres_init (void *cls);
    507 
    508 /* Declaration used to squash compiler warning */
    509 void *
    510 libtaler_plugin_auditordb_postgres_init (void *cls)
    511 {
    512   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
    513   struct PostgresClosure *pg;
    514   struct TALER_AUDITORDB_Plugin *plugin;
    515 
    516   pg = GNUNET_new (struct PostgresClosure);
    517   pg->cfg = cfg;
    518   if (GNUNET_OK !=
    519       TALER_config_get_currency (cfg,
    520                                  "exchange",
    521                                  &pg->currency))
    522   {
    523     GNUNET_free (pg);
    524     return NULL;
    525   }
    526 
    527   plugin = GNUNET_new (struct TALER_AUDITORDB_Plugin);
    528   plugin->cls = pg;
    529   plugin->preflight = &postgres_preflight;
    530   plugin->drop_tables = &postgres_drop_tables;
    531   plugin->create_tables = &postgres_create_tables;
    532   plugin->event_listen = &postgres_event_listen;
    533   plugin->event_listen_cancel = &postgres_event_listen_cancel;
    534   plugin->event_notify = &postgres_event_notify;
    535   plugin->start = &postgres_start;
    536   plugin->commit = &postgres_commit;
    537   plugin->rollback = &postgres_rollback;
    538   plugin->gc = &postgres_gc;
    539 
    540   plugin->get_auditor_progress
    541     = &TAH_PG_get_auditor_progress;
    542 
    543   plugin->get_balance = &TAH_PG_get_balance;
    544   plugin->get_balances = &TAH_PG_get_balances;
    545 
    546   plugin->insert_auditor_progress
    547     = &TAH_PG_insert_auditor_progress;
    548   plugin->insert_balance
    549     = &TAH_PG_insert_balance;
    550   plugin->update_generic_suppressed
    551     = &TAH_PG_update_generic_suppressed;
    552   plugin->delete_generic
    553     = &TAH_PG_delete_generic;
    554   plugin->delete_wire_out_inconsistency_if_matching
    555     = &TAH_PG_delete_wire_out_inconsistency_if_matching;
    556 
    557   plugin->delete_auditor_closure_lag
    558     = &TAH_PG_delete_auditor_closure_lag;
    559 
    560   plugin->update_auditor_progress
    561     = &TAH_PG_update_auditor_progress;
    562   plugin->insert_deposit_confirmation
    563     = &TAH_PG_insert_deposit_confirmation;
    564   plugin->get_deposit_confirmations
    565     = &TAH_PG_get_deposit_confirmations;
    566 
    567   plugin->get_amount_arithmetic_inconsistency
    568     = &TAH_PG_get_amount_arithmetic_inconsistency;
    569   plugin->get_coin_inconsistency
    570     = &TAH_PG_get_coin_inconsistency;
    571   plugin->get_row_inconsistency
    572     = &TAH_PG_get_row_inconsistency;
    573 
    574 
    575   plugin->insert_amount_arithmetic_inconsistency
    576     = &TAH_PG_insert_amount_arithmetic_inconsistency;
    577   plugin->insert_coin_inconsistency
    578     = &TAH_PG_insert_coin_inconsistency;
    579   plugin->insert_row_inconsistency
    580     = &TAH_PG_insert_row_inconsistency;
    581 
    582   plugin->insert_reserve_info
    583     = &TAH_PG_insert_reserve_info;
    584   plugin->update_reserve_info
    585     = &TAH_PG_update_reserve_info;
    586   plugin->get_reserve_info
    587     = &TAH_PG_get_reserve_info;
    588   plugin->del_reserve_info
    589     = &TAH_PG_del_reserve_info;
    590 
    591   plugin->insert_pending_deposit
    592     = &TAH_PG_insert_pending_deposit;
    593   plugin->select_pending_deposits
    594     = &TAH_PG_select_pending_deposits;
    595   plugin->delete_pending_deposit
    596     = &TAH_PG_delete_pending_deposit;
    597 
    598   plugin->insert_purse_info
    599     = &TAH_PG_insert_purse_info;
    600   plugin->update_purse_info
    601     = &TAH_PG_update_purse_info;
    602   plugin->get_purse_info
    603     = &TAH_PG_get_purse_info;
    604   plugin->delete_purse_info
    605     = &TAH_PG_delete_purse_info;
    606   plugin->select_purse_expired
    607     = &TAH_PG_select_purse_expired;
    608 
    609   plugin->insert_denomination_balance
    610     = &TAH_PG_insert_denomination_balance;
    611   plugin->update_denomination_balance
    612     = &TAH_PG_update_denomination_balance;
    613   plugin->del_denomination_balance
    614     = &TAH_PG_del_denomination_balance;
    615   plugin->get_denomination_balance
    616     = &TAH_PG_get_denomination_balance;
    617 
    618   plugin->insert_historic_denom_revenue
    619     = &TAH_PG_insert_historic_denom_revenue;
    620 
    621   plugin->select_historic_denom_revenue
    622     = &TAH_PG_select_historic_denom_revenue;
    623 
    624   plugin->insert_historic_reserve_revenue
    625     = &TAH_PG_insert_historic_reserve_revenue;
    626   plugin->select_historic_reserve_revenue
    627     = &TAH_PG_select_historic_reserve_revenue;
    628 
    629 
    630   plugin->insert_emergency = &TAH_PG_insert_emergency;
    631   plugin->get_emergency = &TAH_PG_get_emergency;
    632 
    633   plugin->insert_emergency_by_count = &TAH_PG_insert_emergency_by_count;
    634   plugin->get_emergency_by_count = &TAH_PG_get_emergency_by_count;
    635 
    636 
    637   plugin->insert_denomination_key_validity_withdraw_inconsistency =
    638     &TAH_PG_insert_denomination_key_validity_withdraw_inconsistency;
    639   plugin->get_denomination_key_validity_withdraw_inconsistency =
    640     &TAH_PG_get_denomination_key_validity_withdraw_inconsistency;
    641 
    642   plugin->insert_purse_not_closed_inconsistencies =
    643     &TAH_PG_insert_purse_not_closed_inconsistencies;
    644   plugin->get_purse_not_closed_inconsistencies =
    645     &TAH_PG_get_purse_not_closed_inconsistencies;
    646 
    647 
    648   plugin->insert_reserve_balance_insufficient_inconsistency =
    649     &TAH_PG_insert_reserve_balance_insufficient_inconsistency;
    650   plugin->get_reserve_balance_insufficient_inconsistency =
    651     &TAH_PG_get_reserve_balance_insufficient_inconsistency;
    652 
    653   plugin->insert_bad_sig_losses = &TAH_PG_insert_bad_sig_losses;
    654   plugin->get_bad_sig_losses = &TAH_PG_get_bad_sig_losses;
    655 
    656   plugin->insert_auditor_closure_lags = &TAH_PG_insert_auditor_closure_lags;
    657   plugin->get_auditor_closure_lags = &TAH_PG_get_auditor_closure_lags;
    658 
    659   plugin->insert_reserve_in_inconsistency =
    660     &TAH_PG_insert_reserve_in_inconsistency;
    661   plugin->get_reserve_in_inconsistency
    662     = &TAH_PG_get_reserve_in_inconsistency;
    663   plugin->lookup_reserve_in_inconsistency
    664     = &TAH_PG_lookup_reserve_in_inconsistency;
    665 
    666   plugin->insert_reserve_not_closed_inconsistency =
    667     &TAH_PG_insert_reserve_not_closed_inconsistency;
    668   plugin->get_reserve_not_closed_inconsistency =
    669     &TAH_PG_get_reserve_not_closed_inconsistency;
    670 
    671   plugin->insert_denominations_without_sigs =
    672     &TAH_PG_insert_denominations_without_sigs;
    673   plugin->get_denominations_without_sigs =
    674     &TAH_PG_get_denominations_without_sigs;
    675 
    676   plugin->get_progress_points
    677     = &TAH_PG_get_progress_points;
    678 
    679 
    680   plugin->insert_misattribution_in_inconsistency =
    681     &TAH_PG_insert_misattribution_in_inconsistency;
    682   plugin->get_misattribution_in_inconsistency =
    683     &TAH_PG_get_misattribution_in_inconsistency;
    684 
    685   plugin->get_reserves = &TAH_PG_get_reserves;
    686   plugin->get_purses = &TAH_PG_get_purses;
    687 
    688   plugin->insert_denomination_pending = &TAH_PG_insert_denomination_pending;
    689   plugin->get_denomination_pending = &TAH_PG_get_denomination_pending;
    690 
    691   plugin->get_exchange_signkeys = &TAH_PG_get_exchange_signkeys;
    692 
    693   plugin->insert_wire_format_inconsistency =
    694     &TAH_PG_insert_wire_format_inconsistency;
    695   plugin->get_wire_format_inconsistency = &TAH_PG_get_wire_format_inconsistency;
    696 
    697   plugin->insert_early_aggregation
    698     = &TAH_PG_insert_early_aggregation;
    699   plugin->delete_early_aggregation
    700     = &TAH_PG_delete_early_aggregation;
    701 
    702   plugin->insert_wire_out_inconsistency
    703     = &TAH_PG_insert_wire_out_inconsistency;
    704   plugin->get_wire_out_inconsistency
    705     = &TAH_PG_get_wire_out_inconsistency;
    706   plugin->select_reserve_in_inconsistency
    707     = &TAH_PG_select_reserve_in_inconsistency;
    708   plugin->delete_reserve_in_inconsistency
    709     = &TAH_PG_delete_reserve_in_inconsistency;
    710   plugin->select_early_aggregations
    711     = &TAH_PG_select_early_aggregations;
    712 
    713   plugin->insert_reserve_balance_summary_wrong_inconsistency =
    714     &TAH_PG_insert_reserve_balance_summary_wrong_inconsistency;
    715   plugin->get_reserve_balance_summary_wrong_inconsistency =
    716     &TAH_PG_get_reserve_balance_summary_wrong_inconsistency;
    717 
    718 
    719   plugin->insert_row_minor_inconsistencies =
    720     &TAH_PG_insert_row_minor_inconsistencies;
    721   plugin->get_row_minor_inconsistencies = &TAH_PG_get_row_minor_inconsistencies;
    722 
    723   plugin->insert_fee_time_inconsistency = &TAH_PG_insert_fee_time_inconsistency;
    724   plugin->get_fee_time_inconsistency = &TAH_PG_get_fee_time_inconsistency;
    725 
    726   plugin->update_balance
    727     = &TAH_PG_update_balance;
    728 
    729   plugin->insert_exchange_signkey
    730     = &TAH_PG_insert_exchange_signkey;
    731 
    732   return plugin;
    733 }
    734 
    735 
    736 /**
    737  * Shutdown Postgres database subsystem.
    738  *
    739  * @param cls a `struct TALER_AUDITORDB_Plugin`
    740  * @return NULL (always)
    741  */
    742 void *
    743 libtaler_plugin_auditordb_postgres_done (void *cls);
    744 
    745 /* Declaration used to squash compiler warning */
    746 void *
    747 libtaler_plugin_auditordb_postgres_done (void *cls)
    748 {
    749   struct TALER_AUDITORDB_Plugin *plugin = cls;
    750   struct PostgresClosure *pg = plugin->cls;
    751 
    752   if (NULL != pg->conn)
    753     GNUNET_PQ_disconnect (pg->conn);
    754   GNUNET_free (pg->currency);
    755   GNUNET_free (pg);
    756   GNUNET_free (plugin);
    757   return NULL;
    758 }
    759 
    760 
    761 /* end of plugin_auditordb_postgres.c */