challenger

OAuth 2.0-based authentication service that validates user can receive messages at a certain address
Log | Files | Refs | Submodules | README | LICENSE

pg.c (5647B)


      1 /*
      2   This file is part of Challenger
      3   (C) 2023 Taler Systems SA
      4 
      5   Challenger is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Lesser General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   Challenger is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of ANASTASISABILITY 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   Challenger; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file challengerdb/plugin_challengerdb_postgres.c
     18  * @brief database helper functions for postgres used by challenger
     19  * @author Christian Grothoff
     20  */
     21 struct CHALLENGERDB_PostgresContext;
     22 #define GNUNET_PQ_RECONNECT_CALLBACK_CLOSURE \
     23         struct CHALLENGERDB_PostgresContext
     24 #include <gnunet/gnunet_util_lib.h>
     25 #include <gnunet/gnunet_db_lib.h>
     26 #include <gnunet/gnunet_pq_lib.h>
     27 #include <taler/taler_pq_lib.h>
     28 #include "challenger_database_lib.h"
     29 #include "challenger_util.h"
     30 #include "pg_helper.h"
     31 
     32 /**
     33  * Counts how often we have established a fresh @e conn
     34  * to the database. Used to re-prepare statements.
     35  */
     36 unsigned long long CH_PG_prep_gen_;
     37 
     38 /**
     39  * Function called each time we connect or reconnect to the
     40  * database. Gives the application a chance to run some
     41  * per-connection initialization logic.
     42  *
     43  * @param pg database conntext in the auditor
     44  * @param pq database connection handle
     45  */
     46 static void
     47 reconnect_cb (struct CHALLENGERDB_PostgresContext *pg,
     48               struct GNUNET_PQ_Context *pq)
     49 {
     50 #if AUTO_EXPLAIN
     51   /* Enable verbose logging to see where queries do not
     52      properly use indices */
     53   struct GNUNET_PQ_ExecuteStatement es[] = {
     54     GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
     55     GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
     56     GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
     57     GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
     58     /* https://wiki.postgresql.org/wiki/Serializable suggests to really
     59        force the default to 'serializable' if SSI is to be used. */
     60     GNUNET_PQ_make_try_execute (
     61       "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
     62     GNUNET_PQ_make_execute ("SET search_path TO challenger;"),
     63     GNUNET_PQ_EXECUTE_STATEMENT_END
     64   };
     65 #else
     66   struct GNUNET_PQ_ExecuteStatement es[] = {
     67     /* https://wiki.postgresql.org/wiki/Serializable suggests to really
     68        force the default to 'serializable' if SSI is to be used. */
     69     GNUNET_PQ_make_try_execute (
     70       "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
     71     GNUNET_PQ_make_execute ("SET search_path TO challenger;"),
     72     GNUNET_PQ_EXECUTE_STATEMENT_END
     73   };
     74 #endif
     75 
     76   if (GNUNET_OK !=
     77       GNUNET_PQ_exec_statements (pq,
     78                                  es))
     79   {
     80     GNUNET_break (0);
     81     return;
     82   }
     83   CH_PG_prep_gen_++;
     84 }
     85 
     86 
     87 /**
     88  * Connect to the db if the connection does not exist yet.
     89  *
     90  * @param[in,out] pg the database state
     91  * @return #GNUNET_OK on success
     92  */
     93 static enum GNUNET_GenericReturnValue
     94 internal_setup (struct CHALLENGERDB_PostgresContext *pg)
     95 {
     96   struct GNUNET_PQ_Context *db_conn;
     97 
     98   if (NULL != pg->conn)
     99     return GNUNET_OK;
    100   db_conn = GNUNET_PQ_init (pg->cfg,
    101                             "challengerdb-postgres",
    102                             &reconnect_cb,
    103                             pg);
    104   if (NULL == db_conn)
    105     return GNUNET_SYSERR;
    106   if (0 == CH_PG_prep_gen_)
    107   {
    108     GNUNET_PQ_disconnect (db_conn);
    109     return GNUNET_SYSERR;
    110   }
    111   pg->conn = db_conn;
    112   return GNUNET_OK;
    113 }
    114 
    115 
    116 static struct CHALLENGERDB_PostgresContext *
    117 do_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
    118             bool check_current)
    119 {
    120   struct CHALLENGERDB_PostgresContext *pg;
    121 
    122   pg = GNUNET_new (struct CHALLENGERDB_PostgresContext);
    123   pg->cfg = cfg;
    124   if (GNUNET_OK !=
    125       GNUNET_CONFIGURATION_get_value_filename (cfg,
    126                                                "challengerdb-postgres",
    127                                                "SQL_DIR",
    128                                                &pg->sql_dir))
    129   {
    130     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    131                                "challengerdb-postgres",
    132                                "SQL_DIR");
    133     GNUNET_free (pg);
    134     return NULL;
    135   }
    136   if (GNUNET_OK !=
    137       internal_setup (pg))
    138   {
    139     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    140                 "Failed to ensure DB is initialized\n");
    141     CHALLENGERDB_disconnect (pg);
    142     return NULL;
    143   }
    144   if (check_current &&
    145       (GNUNET_OK !=
    146        GNUNET_PQ_check_current (pg->conn,
    147                                 "challenger-")) )
    148   {
    149     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    150                 "Database schema is not up-to-date. Try running challenger-dbinit or challenger-dbconfig!\n");
    151     CHALLENGERDB_disconnect (pg);
    152     return NULL;
    153   }
    154   return pg;
    155 }
    156 
    157 
    158 struct CHALLENGERDB_PostgresContext *
    159 CHALLENGERDB_connect (
    160   const struct GNUNET_CONFIGURATION_Handle *cfg)
    161 {
    162   return do_connect (cfg,
    163                      true);
    164 }
    165 
    166 
    167 struct CHALLENGERDB_PostgresContext *
    168 CHALLENGERDB_connect_admin (
    169   const struct GNUNET_CONFIGURATION_Handle *cfg)
    170 {
    171   return do_connect (cfg,
    172                      false);
    173 }
    174 
    175 
    176 void
    177 CHALLENGERDB_disconnect (struct CHALLENGERDB_PostgresContext *pg)
    178 {
    179   if (NULL == pg)
    180     return;
    181   if (NULL != pg->conn)
    182     GNUNET_PQ_disconnect (pg->conn);
    183   GNUNET_free (pg->sql_dir);
    184   GNUNET_free (pg);
    185 }
    186 
    187 
    188 /* end of pg.c */