diff options
Diffstat (limited to 'src/pq/pq_connect.c')
-rw-r--r-- | src/pq/pq_connect.c | 169 |
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 | |||
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,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 | */ |
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 | |||
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 | */ | ||
135 | void | ||
136 | GNUNET_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 | */ |
111 | PGconn * | 202 | struct GNUNET_PQ_Context * |
112 | GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, | 203 | GNUNET_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 | */ | ||
231 | void | ||
232 | GNUNET_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 */ |