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.c169
1 files changed, 139 insertions, 30 deletions
diff --git a/src/pq/pq_connect.c b/src/pq/pq_connect.c
index 79b9d6107..7599f4b15 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,175 @@ 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
76 129
77 conn = PQconnectdb (config_str); 130/**
78 if ((NULL == conn) || 131 * Reinitialize the database @a db.
79 (CONNECTION_OK != 132 *
80 PQstatus (conn))) 133 * @param db database connection to reinitialize
134 */
135void
136GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db)
137{
138 if (NULL != db->conn)
139 PQfinish (db->conn);
140 db->conn = PQconnectdb (db->config_str);
141 if ((NULL == db->conn) ||
142 (CONNECTION_OK != PQstatus (db->conn)))
81 { 143 {
82 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, 144 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
83 "pq", 145 "pq",
84 "Database connection to '%s' failed: %s\n", 146 "Database connection to '%s' failed: %s\n",
85 config_str, 147 db->config_str,
86 (NULL != conn) ? 148 (NULL != db->conn) ?
87 PQerrorMessage (conn) 149 PQerrorMessage (db->conn)
88 : "PQconnectdb returned NULL"); 150 : "PQconnectdb returned NULL");
89 if (NULL != conn) 151 if (NULL != db->conn)
90 PQfinish (conn); 152 {
91 return NULL; 153 PQfinish (db->conn);
154 db->conn = NULL;
155 }
156 return;
92 } 157 }
93 PQsetNoticeReceiver (conn, 158 PQsetNoticeReceiver (db->conn,
94 &pq_notice_receiver_cb, 159 &pq_notice_receiver_cb,
95 conn); 160 db);
96 PQsetNoticeProcessor (conn, 161 PQsetNoticeProcessor (db->conn,
97 &pq_notice_processor_cb, 162 &pq_notice_processor_cb,
98 conn); 163 db);
99 return conn; 164 if ( (NULL != db->es) &&
165 (GNUNET_OK !=
166 GNUNET_PQ_exec_statements (db,
167 db->es)) )
168 {
169 PQfinish (db->conn);
170 db->conn = NULL;
171 return;
172 }
173 if ( (NULL != db->ps) &&
174 (GNUNET_OK !=
175 GNUNET_PQ_prepare_statements (db,
176 db->ps)) )
177 {
178 PQfinish (db->conn);
179 db->conn = NULL;
180 return;
181 }
100} 182}
101 183
102 184
103/** 185/**
104 * Connect to a postgres database using the configuration 186 * Connect to a postgres database using the configuration
105 * option "CONFIG" in @a section. 187 * option "CONFIG" in @a section. Also ensures that the
188 * statements in @a es are executed whenever we (re)connect to the
189 * database, and that the prepared statements in @a ps are "ready".
190 *
191 * The caller MUST ensure that @a es and @a ps remain allocated and
192 * initialized in memory until #GNUNET_PQ_disconnect() is called,
193 * as they may be needed repeatedly and no copy will be made.
106 * 194 *
107 * @param cfg configuration 195 * @param cfg configuration
108 * @param section configuration section to use to get Postgres configuration options 196 * @param section configuration section to use to get Postgres configuration options
197 * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated
198 * array of statements to execute upon EACH connection, can be NULL
199 * @param ps array of prepared statements to prepare, can be NULL
109 * @return the postgres handle, NULL on error 200 * @return the postgres handle, NULL on error
110 */ 201 */
111PGconn * 202struct GNUNET_PQ_Context *
112GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, 203GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
113 const char *section) 204 const char *section,
205 const struct GNUNET_PQ_ExecuteStatement *es,
206 const struct GNUNET_PQ_PreparedStatement *ps)
114{ 207{
115 PGconn *dbh; 208 struct GNUNET_PQ_Context *db;
116 char *conninfo; 209 char *conninfo;
117 210
118 /* Open database and precompile statements */
119 if (GNUNET_OK != 211 if (GNUNET_OK !=
120 GNUNET_CONFIGURATION_get_value_string (cfg, 212 GNUNET_CONFIGURATION_get_value_string (cfg,
121 section, 213 section,
122 "CONFIG", 214 "CONFIG",
123 &conninfo)) 215 &conninfo))
124 conninfo = NULL; 216 conninfo = NULL;
125 dbh = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo); 217 db = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo,
218 es,
219 ps);
126 GNUNET_free_non_null (conninfo); 220 GNUNET_free_non_null (conninfo);
127 return dbh; 221 return db;
128} 222}
129 223
130 224
225/**
226 * Disconnect from the database, destroying the prepared statements
227 * and releasing other associated resources.
228 *
229 * @param db database handle to disconnect (will be free'd)
230 */
231void
232GNUNET_PQ_disconnect (struct GNUNET_PQ_Context *db)
233{
234 GNUNET_free_non_null (db->es);
235 GNUNET_free_non_null (db->ps);
236 PQfinish (db->conn);
237 GNUNET_free (db);
238}
239
131/* end of pq/pq_connect.c */ 240/* end of pq/pq_connect.c */