diff options
Diffstat (limited to 'src/pq/pq_connect.c')
-rw-r--r-- | src/pq/pq_connect.c | 183 |
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 | |||
54 | pq_notice_processor_cb (void *arg, | 55 | pq_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 | */ |
72 | PGconn * | 85 | struct GNUNET_PQ_Context * |
73 | GNUNET_PQ_connect (const char *config_str) | 86 | GNUNET_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 | */ | ||
135 | void | ||
136 | GNUNET_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 | */ | ||
149 | void | ||
150 | GNUNET_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 | */ |
111 | PGconn * | 216 | struct GNUNET_PQ_Context * |
112 | GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, | 217 | GNUNET_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 | */ | ||
245 | void | ||
246 | GNUNET_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 */ |