donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

plugin_donaudb_postgres.c (5622B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 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 /**
     18  * @file plugin_donaudb_postgres.c
     19  * @brief Low-level (statement-level) Postgres database access for the donau
     20  * @author Johannes Casaburi
     21  */
     22 #include "donau_config.h"
     23 #include <poll.h>
     24 #include <pthread.h>
     25 #include <libpq-fe.h>
     26 #include "helper.h"
     27 
     28 /**
     29  * Set to 1 to enable Postgres auto_explain module. This will
     30  * slow down things a _lot_, but also provide extensive logging
     31  * in the Postgres database logger for performance analysis.
     32  */
     33 #define AUTO_EXPLAIN 0
     34 
     35 
     36 /**
     37  * Log a really unexpected PQ error with all the details we can get hold of.
     38  *
     39  * @param result PQ result object of the PQ operation that failed
     40  * @param conn SQL connection that was used
     41  */
     42 #define BREAK_DB_ERR(result,conn) do {                                  \
     43           GNUNET_break (0);                                                   \
     44           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                                \
     45                       "Database failure: %s/%s/%s/%s/%s",                     \
     46                       PQresultErrorField (result, PG_DIAG_MESSAGE_PRIMARY),   \
     47                       PQresultErrorField (result, PG_DIAG_MESSAGE_DETAIL),    \
     48                       PQresultErrorMessage (result),                          \
     49                       PQresStatus (PQresultStatus (result)),                  \
     50                       PQerrorMessage (conn));                                 \
     51 } while (0)
     52 
     53 
     54 /**
     55  * Connect to the database if the connection does not exist yet.
     56  *
     57  * @param pg the plugin-specific state
     58  * @return #GNUNET_OK on success
     59  */
     60 enum GNUNET_GenericReturnValue
     61 DONAUDB_internal_setup (struct DONAUDB_PostgresContext *pg)
     62 {
     63   if (NULL == pg->conn)
     64   {
     65 #if AUTO_EXPLAIN
     66     /* Enable verbose logging to see where queries do not
     67        properly use indices */
     68     struct GNUNET_PQ_ExecuteStatement es[] = {
     69       GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
     70       GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
     71       GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
     72       GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
     73       /* https://wiki.postgresql.org/wiki/Serializable suggests to really
     74          force the default to 'serializable' if SSI is to be used. */
     75       GNUNET_PQ_make_try_execute (
     76         "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
     77       GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
     78       GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
     79       GNUNET_PQ_make_try_execute ("SET search_path TO donau;"),
     80       GNUNET_PQ_EXECUTE_STATEMENT_END
     81     };
     82 #else
     83     struct GNUNET_PQ_ExecuteStatement es[] = {
     84       GNUNET_PQ_make_try_execute (
     85         "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
     86       GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
     87       GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
     88       GNUNET_PQ_make_try_execute ("SET autocommit=OFF;"),
     89       GNUNET_PQ_make_try_execute ("SET search_path TO donau;"),
     90       GNUNET_PQ_EXECUTE_STATEMENT_END
     91     };
     92 #endif
     93     struct GNUNET_PQ_Context *db_conn;
     94 
     95     db_conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
     96                                           "donaudb-postgres",
     97                                           NULL,
     98                                           es,
     99                                           NULL);
    100     if (NULL == db_conn)
    101       return GNUNET_SYSERR;
    102 
    103     pg->prep_gen++;
    104     pg->conn = db_conn;
    105   }
    106   if (NULL == pg->transaction_name)
    107     GNUNET_PQ_reconnect_if_down (pg->conn);
    108   return GNUNET_OK;
    109 }
    110 
    111 
    112 struct DONAUDB_PostgresContext *
    113 DONAUDB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
    114 {
    115   struct DONAUDB_PostgresContext *pg;
    116 
    117   pg = GNUNET_new (struct DONAUDB_PostgresContext);
    118   pg->cfg = cfg;
    119   if (GNUNET_OK !=
    120       GNUNET_CONFIGURATION_get_value_string (cfg,
    121                                              "donau",
    122                                              "BASE_URL",
    123                                              &pg->donau_url))
    124   {
    125     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    126                                "donau",
    127                                "BASE_URL");
    128     GNUNET_free (pg);
    129     return NULL;
    130   }
    131   if (GNUNET_OK !=
    132       TALER_config_get_currency (cfg,
    133                                  "donau",
    134                                  &pg->currency))
    135   {
    136     GNUNET_free (pg->donau_url);
    137     GNUNET_free (pg);
    138     return NULL;
    139   }
    140   if (GNUNET_OK !=
    141       DONAUDB_internal_setup (pg))
    142   {
    143     GNUNET_free (pg->donau_url);
    144     GNUNET_free (pg->currency);
    145     GNUNET_free (pg);
    146     return NULL;
    147   }
    148   return pg;
    149 }
    150 
    151 
    152 void
    153 DONAUDB_disconnect (struct DONAUDB_PostgresContext *pg)
    154 {
    155   if (NULL == pg)
    156     return;
    157   if (NULL != pg->conn)
    158   {
    159     GNUNET_PQ_disconnect (pg->conn);
    160     pg->conn = NULL;
    161   }
    162   GNUNET_free (pg->donau_url);
    163   GNUNET_free (pg->currency);
    164   GNUNET_free (pg);
    165 }
    166 
    167 
    168 /* end of plugin_donaudb_postgres.c */