aboutsummaryrefslogtreecommitdiff
path: root/src/pq/pq_connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pq/pq_connect.c')
-rw-r--r--src/pq/pq_connect.c183
1 files changed, 153 insertions, 30 deletions
diff --git a/src/pq/pq_connect.c b/src/pq/pq_connect.c
index 79b9d6107..882df4f89 100644
--- a/src/pq/pq_connect.c
+++ b/src/pq/pq_connect.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V. 3 Copyright (C) 2017, 2019 GNUnet e.V.
4 4
5 GNUnet is free software: you can redistribute it and/or modify it 5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published 6 under the terms of the GNU Affero General Public License as published
@@ -23,8 +23,7 @@
23 * @author Christian Grothoff 23 * @author Christian Grothoff
24 */ 24 */
25#include "platform.h" 25#include "platform.h"
26#include "gnunet_util_lib.h" 26#include "pq.h"
27#include "gnunet_pq_lib.h"
28 27
29 28
30/** 29/**
@@ -40,12 +39,14 @@ pq_notice_receiver_cb (void *arg,
40 const PGresult *res) 39 const PGresult *res)
41{ 40{
42 /* do nothing, intentionally */ 41 /* do nothing, intentionally */
42 (void) arg;
43 (void) res;
43} 44}
44 45
45 46
46/** 47/**
47 * Function called by libpq whenever it wants to log something. 48 * Function called by libpq whenever it wants to log something.
48 * We log those using the Taler logger. 49 * We log those using the GNUnet logger.
49 * 50 *
50 * @param arg the SQL connection that was used 51 * @param arg the SQL connection that was used
51 * @param message information about some libpq event 52 * @param message information about some libpq event
@@ -54,6 +55,7 @@ static void
54pq_notice_processor_cb (void *arg, 55pq_notice_processor_cb (void *arg,
55 const char *message) 56 const char *message)
56{ 57{
58 (void) arg;
57 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, 59 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
58 "pq", 60 "pq",
59 "%s", 61 "%s",
@@ -64,68 +66,189 @@ pq_notice_processor_cb (void *arg,
64/** 66/**
65 * Create a connection to the Postgres database using @a config_str 67 * Create a connection to the Postgres database using @a config_str
66 * for the configuration. Initialize logging via GNUnet's log 68 * for the configuration. Initialize logging via GNUnet's log
67 * routines and disable Postgres's logger. 69 * routines and disable Postgres's logger. Also ensures that the
70 * statements in @a es are executed whenever we (re)connect to the
71 * database, and that the prepared statements in @a ps are "ready".
72 * If statements in @es fail that were created with
73 * #GNUNET_PQ_make_execute(), then the entire operation fails.
74 *
75 * The caller MUST ensure that @a es and @a ps remain allocated and
76 * initialized in memory until #GNUNET_PQ_disconnect() is called,
77 * as they may be needed repeatedly and no copy will be made.
68 * 78 *
69 * @param config_str configuration to use 79 * @param config_str configuration to use
80 * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated
81 * array of statements to execute upon EACH connection, can be NULL
82 * @param ps array of prepared statements to prepare, can be NULL
70 * @return NULL on error 83 * @return NULL on error
71 */ 84 */
72PGconn * 85struct GNUNET_PQ_Context *
73GNUNET_PQ_connect (const char *config_str) 86GNUNET_PQ_connect (const char *config_str,
87 const struct GNUNET_PQ_ExecuteStatement *es,
88 const struct GNUNET_PQ_PreparedStatement *ps)
74{ 89{
75 PGconn *conn; 90 struct GNUNET_PQ_Context *db;
91 unsigned int elen = 0;
92 unsigned int plen = 0;
93
94 if (NULL != es)
95 while (NULL != es[elen].sql)
96 elen++;
97 if (NULL != ps)
98 while (NULL != ps[plen].name)
99 plen++;
100
101 db = GNUNET_new (struct GNUNET_PQ_Context);
102 db->config_str = GNUNET_strdup (config_str);
103 if (0 != elen)
104 {
105 db->es = GNUNET_new_array (elen + 1,
106 struct GNUNET_PQ_ExecuteStatement);
107 memcpy (db->es,
108 es,
109 elen * sizeof (struct GNUNET_PQ_ExecuteStatement));
110 }
111 if (0 != plen)
112 {
113 db->ps = GNUNET_new_array (plen + 1,
114 struct GNUNET_PQ_PreparedStatement);
115 memcpy (db->ps,
116 ps,
117 plen * sizeof (struct GNUNET_PQ_PreparedStatement));
118 }
119 GNUNET_PQ_reconnect (db);
120 if (NULL == db->conn)
121 {
122 GNUNET_free (db->config_str);
123 GNUNET_free (db);
124 return NULL;
125 }
126 return db;
127}
128
129
130/**
131 * Reinitialize the database @a db if the connection is down.
132 *
133 * @param db database connection to reinitialize
134 */
135void
136GNUNET_PQ_reconnect_if_down (struct GNUNET_PQ_Context *db)
137{
138 if (CONNECTION_BAD != PQstatus (db->conn))
139 return;
140 GNUNET_PQ_reconnect (db);
141}
142
76 143
77 conn = PQconnectdb (config_str); 144/**
78 if ((NULL == conn) || 145 * Reinitialize the database @a db.
79 (CONNECTION_OK != 146 *
80 PQstatus (conn))) 147 * @param db database connection to reinitialize
148 */
149void
150GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db)
151{
152 if (NULL != db->conn)
153 PQfinish (db->conn);
154 db->conn = PQconnectdb (db->config_str);
155 if ((NULL == db->conn) ||
156 (CONNECTION_OK != PQstatus (db->conn)))
81 { 157 {
82 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, 158 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
83 "pq", 159 "pq",
84 "Database connection to '%s' failed: %s\n", 160 "Database connection to '%s' failed: %s\n",
85 config_str, 161 db->config_str,
86 (NULL != conn) ? 162 (NULL != db->conn) ?
87 PQerrorMessage (conn) 163 PQerrorMessage (db->conn)
88 : "PQconnectdb returned NULL"); 164 : "PQconnectdb returned NULL");
89 if (NULL != conn) 165 if (NULL != db->conn)
90 PQfinish (conn); 166 {
91 return NULL; 167 PQfinish (db->conn);
168 db->conn = NULL;
169 }
170 return;
92 } 171 }
93 PQsetNoticeReceiver (conn, 172 PQsetNoticeReceiver (db->conn,
94 &pq_notice_receiver_cb, 173 &pq_notice_receiver_cb,
95 conn); 174 db);
96 PQsetNoticeProcessor (conn, 175 PQsetNoticeProcessor (db->conn,
97 &pq_notice_processor_cb, 176 &pq_notice_processor_cb,
98 conn); 177 db);
99 return conn; 178 if ( (NULL != db->es) &&
179 (GNUNET_OK !=
180 GNUNET_PQ_exec_statements (db,
181 db->es)) )
182 {
183 PQfinish (db->conn);
184 db->conn = NULL;
185 return;
186 }
187 if ( (NULL != db->ps) &&
188 (GNUNET_OK !=
189 GNUNET_PQ_prepare_statements (db,
190 db->ps)) )
191 {
192 PQfinish (db->conn);
193 db->conn = NULL;
194 return;
195 }
100} 196}
101 197
102 198
103/** 199/**
104 * Connect to a postgres database using the configuration 200 * Connect to a postgres database using the configuration
105 * option "CONFIG" in @a section. 201 * option "CONFIG" in @a section. Also ensures that the
202 * statements in @a es are executed whenever we (re)connect to the
203 * database, and that the prepared statements in @a ps are "ready".
204 *
205 * The caller MUST ensure that @a es and @a ps remain allocated and
206 * initialized in memory until #GNUNET_PQ_disconnect() is called,
207 * as they may be needed repeatedly and no copy will be made.
106 * 208 *
107 * @param cfg configuration 209 * @param cfg configuration
108 * @param section configuration section to use to get Postgres configuration options 210 * @param section configuration section to use to get Postgres configuration options
211 * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated
212 * array of statements to execute upon EACH connection, can be NULL
213 * @param ps array of prepared statements to prepare, can be NULL
109 * @return the postgres handle, NULL on error 214 * @return the postgres handle, NULL on error
110 */ 215 */
111PGconn * 216struct GNUNET_PQ_Context *
112GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, 217GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
113 const char *section) 218 const char *section,
219 const struct GNUNET_PQ_ExecuteStatement *es,
220 const struct GNUNET_PQ_PreparedStatement *ps)
114{ 221{
115 PGconn *dbh; 222 struct GNUNET_PQ_Context *db;
116 char *conninfo; 223 char *conninfo;
117 224
118 /* Open database and precompile statements */
119 if (GNUNET_OK != 225 if (GNUNET_OK !=
120 GNUNET_CONFIGURATION_get_value_string (cfg, 226 GNUNET_CONFIGURATION_get_value_string (cfg,
121 section, 227 section,
122 "CONFIG", 228 "CONFIG",
123 &conninfo)) 229 &conninfo))
124 conninfo = NULL; 230 conninfo = NULL;
125 dbh = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo); 231 db = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo,
232 es,
233 ps);
126 GNUNET_free_non_null (conninfo); 234 GNUNET_free_non_null (conninfo);
127 return dbh; 235 return db;
128} 236}
129 237
130 238
239/**
240 * Disconnect from the database, destroying the prepared statements
241 * and releasing other associated resources.
242 *
243 * @param db database handle to disconnect (will be free'd)
244 */
245void
246GNUNET_PQ_disconnect (struct GNUNET_PQ_Context *db)
247{
248 GNUNET_free_non_null (db->es);
249 GNUNET_free_non_null (db->ps);
250 PQfinish (db->conn);
251 GNUNET_free (db);
252}
253
131/* end of pq/pq_connect.c */ 254/* end of pq/pq_connect.c */