LCOV - code coverage report
Current view: top level - challengerdb - pg.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 68.0 % 50 34
Test Date: 2026-09-09 01:07:11 Functions: 100.0 % 6 6

            Line data    Source code
       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 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              :   Challenger; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              : */
      16              : /**
      17              :  * @file src/challengerdb/pg.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 challenger database context
      44              :  * @param pq database connection handle
      45              :  */
      46              : static void
      47           50 : 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           50 :   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           50 :     GNUNET_PQ_make_try_execute (
      70              :       "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
      71           50 :     GNUNET_PQ_make_execute ("SET search_path TO challenger;"),
      72              :     GNUNET_PQ_EXECUTE_STATEMENT_END
      73              :   };
      74              : #endif
      75              : 
      76           50 :   if (GNUNET_OK !=
      77           50 :       GNUNET_PQ_exec_statements (pq,
      78              :                                  es))
      79              :   {
      80            0 :     GNUNET_break (0);
      81            0 :     return;
      82              :   }
      83           50 :   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           50 : internal_setup (struct CHALLENGERDB_PostgresContext *pg)
      95              : {
      96              :   struct GNUNET_PQ_Context *db_conn;
      97              : 
      98           50 :   if (NULL != pg->conn)
      99            0 :     return GNUNET_OK;
     100           50 :   db_conn = GNUNET_PQ_init (pg->cfg,
     101              :                             "challengerdb-postgres",
     102              :                             &reconnect_cb,
     103              :                             pg);
     104           50 :   if (NULL == db_conn)
     105            0 :     return GNUNET_SYSERR;
     106           50 :   if (0 == CH_PG_prep_gen_)
     107              :   {
     108            0 :     GNUNET_PQ_disconnect (db_conn);
     109            0 :     return GNUNET_SYSERR;
     110              :   }
     111           50 :   pg->conn = db_conn;
     112           50 :   return GNUNET_OK;
     113              : }
     114              : 
     115              : 
     116              : static struct CHALLENGERDB_PostgresContext *
     117           50 : do_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
     118              :             bool check_current)
     119              : {
     120              :   struct CHALLENGERDB_PostgresContext *pg;
     121              : 
     122           50 :   pg = GNUNET_new (struct CHALLENGERDB_PostgresContext);
     123           50 :   pg->cfg = cfg;
     124           50 :   if (GNUNET_OK !=
     125           50 :       GNUNET_CONFIGURATION_get_value_filename (cfg,
     126              :                                                "challengerdb-postgres",
     127              :                                                "SQL_DIR",
     128              :                                                &pg->sql_dir))
     129              :   {
     130            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     131              :                                "challengerdb-postgres",
     132              :                                "SQL_DIR");
     133            0 :     GNUNET_free (pg);
     134            0 :     return NULL;
     135              :   }
     136           50 :   if (GNUNET_OK !=
     137           50 :       internal_setup (pg))
     138              :   {
     139            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     140              :                 "Failed to ensure DB is initialized\n");
     141            0 :     CHALLENGERDB_disconnect (pg);
     142            0 :     return NULL;
     143              :   }
     144           84 :   if (check_current &&
     145              :       (GNUNET_OK !=
     146           34 :        GNUNET_PQ_check_current (pg->conn,
     147              :                                 "challenger-")) )
     148              :   {
     149            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     150              :                 "Database schema is not up-to-date. Try running challenger-dbinit or challenger-dbconfig!\n");
     151            0 :     CHALLENGERDB_disconnect (pg);
     152            0 :     return NULL;
     153              :   }
     154           50 :   return pg;
     155              : }
     156              : 
     157              : 
     158              : struct CHALLENGERDB_PostgresContext *
     159           34 : CHALLENGERDB_connect (
     160              :   const struct GNUNET_CONFIGURATION_Handle *cfg)
     161              : {
     162           34 :   return do_connect (cfg,
     163              :                      true);
     164              : }
     165              : 
     166              : 
     167              : struct CHALLENGERDB_PostgresContext *
     168           16 : CHALLENGERDB_connect_admin (
     169              :   const struct GNUNET_CONFIGURATION_Handle *cfg)
     170              : {
     171           16 :   return do_connect (cfg,
     172              :                      false);
     173              : }
     174              : 
     175              : 
     176              : void
     177           50 : CHALLENGERDB_disconnect (struct CHALLENGERDB_PostgresContext *pg)
     178              : {
     179           50 :   if (NULL == pg)
     180            0 :     return;
     181           50 :   if (NULL != pg->conn)
     182           50 :     GNUNET_PQ_disconnect (pg->conn);
     183           50 :   GNUNET_free (pg->sql_dir);
     184           50 :   GNUNET_free (pg);
     185              : }
     186              : 
     187              : 
     188              : /* end of pg.c */
        

Generated by: LCOV version 2.0-1