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 */