diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-10-11 20:55:59 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-10-11 23:36:09 +0200 |
commit | e3e21acb23283915c97e6ef1c167325f4592665c (patch) | |
tree | d6b677c2f53ffd8253b97be26bcf3a4301f69269 /src/pq | |
parent | 8ed3ad85fa8c0faa213157610379d69875b10ccb (diff) | |
download | gnunet-e3e21acb23283915c97e6ef1c167325f4592665c.tar.gz gnunet-e3e21acb23283915c97e6ef1c167325f4592665c.zip |
libgnunetpq API change to fix #5733
Diffstat (limited to 'src/pq')
-rw-r--r-- | src/pq/Makefile.am | 2 | ||||
-rw-r--r-- | src/pq/pq.c | 43 | ||||
-rw-r--r-- | src/pq/pq.h | 57 | ||||
-rw-r--r-- | src/pq/pq_connect.c | 169 | ||||
-rw-r--r-- | src/pq/pq_eval.c | 59 | ||||
-rw-r--r-- | src/pq/pq_exec.c | 15 | ||||
-rw-r--r-- | src/pq/pq_prepare.c | 39 | ||||
-rw-r--r-- | src/pq/pq_result_helper.c | 2 | ||||
-rw-r--r-- | src/pq/test_pq.c | 186 |
9 files changed, 391 insertions, 181 deletions
diff --git a/src/pq/Makefile.am b/src/pq/Makefile.am index 9270e6fe0..750a1d48d 100644 --- a/src/pq/Makefile.am +++ b/src/pq/Makefile.am | |||
@@ -22,7 +22,7 @@ libgnunetpq_la_LIBADD = -lpq \ | |||
22 | libgnunetpq_la_LDFLAGS = \ | 22 | libgnunetpq_la_LDFLAGS = \ |
23 | $(POSTGRESQL_LDFLAGS) \ | 23 | $(POSTGRESQL_LDFLAGS) \ |
24 | $(GN_LIB_LDFLAGS) \ | 24 | $(GN_LIB_LDFLAGS) \ |
25 | -version-info 0:0:0 | 25 | -version-info 1:0:0 |
26 | 26 | ||
27 | if ENABLE_TEST_RUN | 27 | if ENABLE_TEST_RUN |
28 | TESTS = \ | 28 | TESTS = \ |
diff --git a/src/pq/pq.c b/src/pq/pq.c index 7e97c8f72..d2b9a6174 100644 --- a/src/pq/pq.c +++ b/src/pq/pq.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | Copyright (C) 2014, 2015, 2016 GNUnet e.V. | 3 | Copyright (C) 2014, 2015, 2016, 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 |
@@ -25,33 +25,30 @@ | |||
25 | * @author Christian Grothoff | 25 | * @author Christian Grothoff |
26 | */ | 26 | */ |
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "gnunet_util_lib.h" | 28 | #include "pq.h" |
29 | #include "gnunet_pq_lib.h" | ||
30 | |||
31 | 29 | ||
32 | /** | 30 | /** |
33 | * Execute a prepared statement. | 31 | * Execute a prepared statement. |
34 | * | 32 | * |
35 | * @param db_conn database connection | 33 | * @param db database handle |
36 | * @param name name of the prepared statement | 34 | * @param name name of the prepared statement |
37 | * @param params parameters to the statement | 35 | * @param params parameters to the statement |
38 | * @return postgres result | 36 | * @return postgres result |
39 | */ | 37 | */ |
40 | PGresult * | 38 | PGresult * |
41 | GNUNET_PQ_exec_prepared (PGconn *db_conn, | 39 | GNUNET_PQ_exec_prepared (struct GNUNET_PQ_Context *db, |
42 | const char *name, | 40 | const char *name, |
43 | const struct GNUNET_PQ_QueryParam *params) | 41 | const struct GNUNET_PQ_QueryParam *params) |
44 | { | 42 | { |
45 | unsigned int len; | 43 | unsigned int len; |
46 | unsigned int i; | ||
47 | 44 | ||
48 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 45 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
49 | "Running prepared statement `%s' on %p\n", | 46 | "Running prepared statement `%s' on %p\n", |
50 | name, | 47 | name, |
51 | db_conn); | 48 | db); |
52 | /* count the number of parameters */ | 49 | /* count the number of parameters */ |
53 | len = 0; | 50 | len = 0; |
54 | for (i = 0; 0 != params[i].num_params; i++) | 51 | for (unsigned int i = 0; 0 != params[i].num_params; i++) |
55 | len += params[i].num_params; | 52 | len += params[i].num_params; |
56 | 53 | ||
57 | /* new scope to allow stack allocation without alloca */ | 54 | /* new scope to allow stack allocation without alloca */ |
@@ -67,10 +64,11 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn, | |||
67 | unsigned int soff; | 64 | unsigned int soff; |
68 | PGresult *res; | 65 | PGresult *res; |
69 | int ret; | 66 | int ret; |
67 | ConnStatusType status; | ||
70 | 68 | ||
71 | off = 0; | 69 | off = 0; |
72 | soff = 0; | 70 | soff = 0; |
73 | for (i = 0; 0 != params[i].num_params; i++) | 71 | for (unsigned int i = 0; 0 != params[i].num_params; i++) |
74 | { | 72 | { |
75 | const struct GNUNET_PQ_QueryParam *x = ¶ms[i]; | 73 | const struct GNUNET_PQ_QueryParam *x = ¶ms[i]; |
76 | 74 | ||
@@ -97,13 +95,24 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn, | |||
97 | "pq", | 95 | "pq", |
98 | "Executing prepared SQL statement `%s'\n", | 96 | "Executing prepared SQL statement `%s'\n", |
99 | name); | 97 | name); |
100 | res = PQexecPrepared (db_conn, | 98 | res = PQexecPrepared (db->conn, |
101 | name, | 99 | name, |
102 | len, | 100 | len, |
103 | (const char **) param_values, | 101 | (const char **) param_values, |
104 | param_lengths, | 102 | param_lengths, |
105 | param_formats, | 103 | param_formats, |
106 | 1); | 104 | 1); |
105 | if ( (PGRES_COMMAND_OK != PQresultStatus (res)) && | ||
106 | (CONNECTION_OK != (status = PQstatus (db->conn))) ) | ||
107 | { | ||
108 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
109 | "pq", | ||
110 | "Database disconnected on SQL statement `%s' (reconnecting)\n", | ||
111 | name); | ||
112 | GNUNET_PQ_reconnect (db); | ||
113 | res = NULL; | ||
114 | } | ||
115 | |||
107 | for (off = 0; off < soff; off++) | 116 | for (off = 0; off < soff; off++) |
108 | GNUNET_free (scratch[off]); | 117 | GNUNET_free (scratch[off]); |
109 | return res; | 118 | return res; |
@@ -120,9 +129,7 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn, | |||
120 | void | 129 | void |
121 | GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs) | 130 | GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs) |
122 | { | 131 | { |
123 | unsigned int i; | 132 | for (unsigned int i = 0; NULL != rs[i].conv; i++) |
124 | |||
125 | for (i = 0; NULL != rs[i].conv; i++) | ||
126 | if (NULL != rs[i].cleaner) | 133 | if (NULL != rs[i].cleaner) |
127 | rs[i].cleaner (rs[i].cls, | 134 | rs[i].cleaner (rs[i].cls, |
128 | rs[i].dst); | 135 | rs[i].dst); |
@@ -145,12 +152,12 @@ GNUNET_PQ_extract_result (PGresult *result, | |||
145 | struct GNUNET_PQ_ResultSpec *rs, | 152 | struct GNUNET_PQ_ResultSpec *rs, |
146 | int row) | 153 | int row) |
147 | { | 154 | { |
148 | unsigned int i; | 155 | if (NULL == result) |
149 | int ret; | 156 | return GNUNET_SYSERR; |
150 | 157 | for (unsigned int i = 0; NULL != rs[i].conv; i++) | |
151 | for (i = 0; NULL != rs[i].conv; i++) | ||
152 | { | 158 | { |
153 | struct GNUNET_PQ_ResultSpec *spec; | 159 | struct GNUNET_PQ_ResultSpec *spec; |
160 | int ret; | ||
154 | 161 | ||
155 | spec = &rs[i]; | 162 | spec = &rs[i]; |
156 | ret = spec->conv (spec->cls, | 163 | ret = spec->conv (spec->cls, |
diff --git a/src/pq/pq.h b/src/pq/pq.h new file mode 100644 index 000000000..b30f4f0d4 --- /dev/null +++ b/src/pq/pq.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2017, 2019 GNUnet e.V. | ||
4 | |||
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 | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file pq/pq.h | ||
22 | * @brief shared internal data structures of libgnunetpq | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #ifndef PQ_H | ||
26 | #define PQ_H | ||
27 | |||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_pq_lib.h" | ||
30 | |||
31 | /** | ||
32 | * Handle to Postgres database. | ||
33 | */ | ||
34 | struct GNUNET_PQ_Context | ||
35 | { | ||
36 | /** | ||
37 | * Actual connection. | ||
38 | */ | ||
39 | PGconn *conn; | ||
40 | |||
41 | /** | ||
42 | * Statements to execute upon connection. | ||
43 | */ | ||
44 | struct GNUNET_PQ_ExecuteStatement *es; | ||
45 | |||
46 | /** | ||
47 | * Prepared statements. | ||
48 | */ | ||
49 | struct GNUNET_PQ_PreparedStatement *ps; | ||
50 | |||
51 | /** | ||
52 | * Configuration to use to connect to the DB. | ||
53 | */ | ||
54 | char *config_str; | ||
55 | }; | ||
56 | |||
57 | #endif | ||
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 */ |
diff --git a/src/pq/pq_eval.c b/src/pq/pq_eval.c index 1d041f226..5bcf8ca0e 100644 --- a/src/pq/pq_eval.c +++ b/src/pq/pq_eval.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 | /** |
@@ -47,7 +46,7 @@ | |||
47 | * Check the @a result's error code to see what happened. | 46 | * Check the @a result's error code to see what happened. |
48 | * Also logs errors. | 47 | * Also logs errors. |
49 | * | 48 | * |
50 | * @param connection connection to execute the statement in | 49 | * @param db database to execute the statement with |
51 | * @param statement_name name of the statement that created @a result | 50 | * @param statement_name name of the statement that created @a result |
52 | * @param result result to check | 51 | * @param result result to check |
53 | * @return status code from the result, mapping PQ status | 52 | * @return status code from the result, mapping PQ status |
@@ -57,17 +56,31 @@ | |||
57 | * @deprecated (low level, let's see if we can do with just the high-level functions) | 56 | * @deprecated (low level, let's see if we can do with just the high-level functions) |
58 | */ | 57 | */ |
59 | enum GNUNET_DB_QueryStatus | 58 | enum GNUNET_DB_QueryStatus |
60 | GNUNET_PQ_eval_result (PGconn *connection, | 59 | GNUNET_PQ_eval_result (struct GNUNET_PQ_Context *db, |
61 | const char *statement_name, | 60 | const char *statement_name, |
62 | PGresult *result) | 61 | PGresult *result) |
63 | { | 62 | { |
64 | ExecStatusType est; | 63 | ExecStatusType est; |
65 | 64 | ||
65 | if (NULL == result) | ||
66 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
66 | est = PQresultStatus (result); | 67 | est = PQresultStatus (result); |
67 | if ((PGRES_COMMAND_OK != est) && | 68 | if ((PGRES_COMMAND_OK != est) && |
68 | (PGRES_TUPLES_OK != est)) | 69 | (PGRES_TUPLES_OK != est)) |
69 | { | 70 | { |
70 | const char *sqlstate; | 71 | const char *sqlstate; |
72 | ConnStatusType status; | ||
73 | |||
74 | if (CONNECTION_OK != (status = PQstatus (db->conn))) | ||
75 | { | ||
76 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | ||
77 | "pq", | ||
78 | "Database connection failed during query `%s': %d (reconnecting)\n", | ||
79 | statement_name, | ||
80 | status); | ||
81 | GNUNET_PQ_reconnect (db); | ||
82 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
83 | } | ||
71 | 84 | ||
72 | sqlstate = PQresultErrorField (result, | 85 | sqlstate = PQresultErrorField (result, |
73 | PG_DIAG_SQLSTATE); | 86 | PG_DIAG_SQLSTATE); |
@@ -94,7 +107,7 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
94 | PG_DIAG_MESSAGE_DETAIL), | 107 | PG_DIAG_MESSAGE_DETAIL), |
95 | PQresultErrorMessage (result), | 108 | PQresultErrorMessage (result), |
96 | PQresStatus (PQresultStatus (result)), | 109 | PQresStatus (PQresultStatus (result)), |
97 | PQerrorMessage (connection)); | 110 | PQerrorMessage (db->conn)); |
98 | return GNUNET_DB_STATUS_SOFT_ERROR; | 111 | return GNUNET_DB_STATUS_SOFT_ERROR; |
99 | } | 112 | } |
100 | if (0 == strcmp (sqlstate, | 113 | if (0 == strcmp (sqlstate, |
@@ -111,7 +124,7 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
111 | PG_DIAG_MESSAGE_DETAIL), | 124 | PG_DIAG_MESSAGE_DETAIL), |
112 | PQresultErrorMessage (result), | 125 | PQresultErrorMessage (result), |
113 | PQresStatus (PQresultStatus (result)), | 126 | PQresStatus (PQresultStatus (result)), |
114 | PQerrorMessage (connection)); | 127 | PQerrorMessage (db->conn)); |
115 | return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; | 128 | return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; |
116 | } | 129 | } |
117 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | 130 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, |
@@ -124,7 +137,7 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
124 | PG_DIAG_MESSAGE_DETAIL), | 137 | PG_DIAG_MESSAGE_DETAIL), |
125 | PQresultErrorMessage (result), | 138 | PQresultErrorMessage (result), |
126 | PQresStatus (PQresultStatus (result)), | 139 | PQresStatus (PQresultStatus (result)), |
127 | PQerrorMessage (connection)); | 140 | PQerrorMessage (db->conn)); |
128 | return GNUNET_DB_STATUS_HARD_ERROR; | 141 | return GNUNET_DB_STATUS_HARD_ERROR; |
129 | } | 142 | } |
130 | return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; | 143 | return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; |
@@ -136,7 +149,7 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
136 | * statement in @a connnection using the given @a params. Returns the | 149 | * statement in @a connnection using the given @a params. Returns the |
137 | * resulting session state. | 150 | * resulting session state. |
138 | * | 151 | * |
139 | * @param connection connection to execute the statement in | 152 | * @param db database to execute the statement with |
140 | * @param statement_name name of the statement | 153 | * @param statement_name name of the statement |
141 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | 154 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) |
142 | * @return status code from the result, mapping PQ status | 155 | * @return status code from the result, mapping PQ status |
@@ -148,17 +161,19 @@ GNUNET_PQ_eval_result (PGconn *connection, | |||
148 | * zero; if INSERT was successful, we return one. | 161 | * zero; if INSERT was successful, we return one. |
149 | */ | 162 | */ |
150 | enum GNUNET_DB_QueryStatus | 163 | enum GNUNET_DB_QueryStatus |
151 | GNUNET_PQ_eval_prepared_non_select (PGconn *connection, | 164 | GNUNET_PQ_eval_prepared_non_select (struct GNUNET_PQ_Context *db, |
152 | const char *statement_name, | 165 | const char *statement_name, |
153 | const struct GNUNET_PQ_QueryParam *params) | 166 | const struct GNUNET_PQ_QueryParam *params) |
154 | { | 167 | { |
155 | PGresult *result; | 168 | PGresult *result; |
156 | enum GNUNET_DB_QueryStatus qs; | 169 | enum GNUNET_DB_QueryStatus qs; |
157 | 170 | ||
158 | result = GNUNET_PQ_exec_prepared (connection, | 171 | result = GNUNET_PQ_exec_prepared (db, |
159 | statement_name, | 172 | statement_name, |
160 | params); | 173 | params); |
161 | qs = GNUNET_PQ_eval_result (connection, | 174 | if (NULL == result) |
175 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
176 | qs = GNUNET_PQ_eval_result (db, | ||
162 | statement_name, | 177 | statement_name, |
163 | result); | 178 | result); |
164 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) | 179 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) |
@@ -182,7 +197,7 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection, | |||
182 | * status including the number of results given to @a rh (possibly zero). | 197 | * status including the number of results given to @a rh (possibly zero). |
183 | * @a rh will not have been called if the return value is negative. | 198 | * @a rh will not have been called if the return value is negative. |
184 | * | 199 | * |
185 | * @param connection connection to execute the statement in | 200 | * @param db database to execute the statement with |
186 | * @param statement_name name of the statement | 201 | * @param statement_name name of the statement |
187 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | 202 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) |
188 | * @param rh function to call with the result set, NULL to ignore | 203 | * @param rh function to call with the result set, NULL to ignore |
@@ -191,7 +206,7 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection, | |||
191 | * codes to `enum GNUNET_DB_QueryStatus`. | 206 | * codes to `enum GNUNET_DB_QueryStatus`. |
192 | */ | 207 | */ |
193 | enum GNUNET_DB_QueryStatus | 208 | enum GNUNET_DB_QueryStatus |
194 | GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | 209 | GNUNET_PQ_eval_prepared_multi_select (struct GNUNET_PQ_Context *db, |
195 | const char *statement_name, | 210 | const char *statement_name, |
196 | const struct GNUNET_PQ_QueryParam *params, | 211 | const struct GNUNET_PQ_QueryParam *params, |
197 | GNUNET_PQ_PostgresResultHandler rh, | 212 | GNUNET_PQ_PostgresResultHandler rh, |
@@ -201,10 +216,12 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | |||
201 | enum GNUNET_DB_QueryStatus qs; | 216 | enum GNUNET_DB_QueryStatus qs; |
202 | unsigned int ret; | 217 | unsigned int ret; |
203 | 218 | ||
204 | result = GNUNET_PQ_exec_prepared (connection, | 219 | result = GNUNET_PQ_exec_prepared (db, |
205 | statement_name, | 220 | statement_name, |
206 | params); | 221 | params); |
207 | qs = GNUNET_PQ_eval_result (connection, | 222 | if (NULL == result) |
223 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
224 | qs = GNUNET_PQ_eval_result (db, | ||
208 | statement_name, | 225 | statement_name, |
209 | result); | 226 | result); |
210 | if (qs < 0) | 227 | if (qs < 0) |
@@ -230,7 +247,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | |||
230 | * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT. Returns the | 247 | * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT. Returns the |
231 | * resulting session status. | 248 | * resulting session status. |
232 | * | 249 | * |
233 | * @param connection connection to execute the statement in | 250 | * @param db database to execute the statement with |
234 | * @param statement_name name of the statement | 251 | * @param statement_name name of the statement |
235 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) | 252 | * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) |
236 | * @param[in,out] rs result specification to use for storing the result of the query | 253 | * @param[in,out] rs result specification to use for storing the result of the query |
@@ -238,7 +255,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, | |||
238 | * codes to `enum GNUNET_DB_QueryStatus`. | 255 | * codes to `enum GNUNET_DB_QueryStatus`. |
239 | */ | 256 | */ |
240 | enum GNUNET_DB_QueryStatus | 257 | enum GNUNET_DB_QueryStatus |
241 | GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection, | 258 | GNUNET_PQ_eval_prepared_singleton_select (struct GNUNET_PQ_Context *db, |
242 | const char *statement_name, | 259 | const char *statement_name, |
243 | const struct | 260 | const struct |
244 | GNUNET_PQ_QueryParam *params, | 261 | GNUNET_PQ_QueryParam *params, |
@@ -247,10 +264,12 @@ GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection, | |||
247 | PGresult *result; | 264 | PGresult *result; |
248 | enum GNUNET_DB_QueryStatus qs; | 265 | enum GNUNET_DB_QueryStatus qs; |
249 | 266 | ||
250 | result = GNUNET_PQ_exec_prepared (connection, | 267 | result = GNUNET_PQ_exec_prepared (db, |
251 | statement_name, | 268 | statement_name, |
252 | params); | 269 | params); |
253 | qs = GNUNET_PQ_eval_result (connection, | 270 | if (NULL == result) |
271 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
272 | qs = GNUNET_PQ_eval_result (db, | ||
254 | statement_name, | 273 | statement_name, |
255 | result); | 274 | result); |
256 | if (qs < 0) | 275 | if (qs < 0) |
diff --git a/src/pq/pq_exec.c b/src/pq/pq_exec.c index 00527151a..fd4feae53 100644 --- a/src/pq/pq_exec.c +++ b/src/pq/pq_exec.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 | /** |
@@ -67,14 +66,14 @@ GNUNET_PQ_make_try_execute (const char *sql) | |||
67 | /** | 66 | /** |
68 | * Request execution of an array of statements @a es from Postgres. | 67 | * Request execution of an array of statements @a es from Postgres. |
69 | * | 68 | * |
70 | * @param connection connection to execute the statements over | 69 | * @param db database to execute the statements with |
71 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared | 70 | * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared |
72 | * statements. | 71 | * statements. |
73 | * @return #GNUNET_OK on success (modulo statements where errors can be ignored) | 72 | * @return #GNUNET_OK on success (modulo statements where errors can be ignored) |
74 | * #GNUNET_SYSERR on error | 73 | * #GNUNET_SYSERR on error |
75 | */ | 74 | */ |
76 | int | 75 | int |
77 | GNUNET_PQ_exec_statements (PGconn *connection, | 76 | GNUNET_PQ_exec_statements (struct GNUNET_PQ_Context *db, |
78 | const struct GNUNET_PQ_ExecuteStatement *es) | 77 | const struct GNUNET_PQ_ExecuteStatement *es) |
79 | { | 78 | { |
80 | for (unsigned int i = 0; NULL != es[i].sql; i++) | 79 | for (unsigned int i = 0; NULL != es[i].sql; i++) |
@@ -84,8 +83,8 @@ GNUNET_PQ_exec_statements (PGconn *connection, | |||
84 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 83 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
85 | "Running statement `%s' on %p\n", | 84 | "Running statement `%s' on %p\n", |
86 | es[i].sql, | 85 | es[i].sql, |
87 | connection); | 86 | db); |
88 | result = PQexec (connection, | 87 | result = PQexec (db->conn, |
89 | es[i].sql); | 88 | es[i].sql); |
90 | if ((GNUNET_NO == es[i].ignore_errors) && | 89 | if ((GNUNET_NO == es[i].ignore_errors) && |
91 | (PGRES_COMMAND_OK != PQresultStatus (result))) | 90 | (PGRES_COMMAND_OK != PQresultStatus (result))) |
@@ -100,7 +99,7 @@ GNUNET_PQ_exec_statements (PGconn *connection, | |||
100 | PG_DIAG_MESSAGE_DETAIL), | 99 | PG_DIAG_MESSAGE_DETAIL), |
101 | PQresultErrorMessage (result), | 100 | PQresultErrorMessage (result), |
102 | PQresStatus (PQresultStatus (result)), | 101 | PQresStatus (PQresultStatus (result)), |
103 | PQerrorMessage (connection)); | 102 | PQerrorMessage (db->conn)); |
104 | PQclear (result); | 103 | PQclear (result); |
105 | return GNUNET_SYSERR; | 104 | return GNUNET_SYSERR; |
106 | } | 105 | } |
diff --git a/src/pq/pq_prepare.c b/src/pq/pq_prepare.c index 0facf100f..b7003fb69 100644 --- a/src/pq/pq_prepare.c +++ b/src/pq/pq_prepare.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 | /** |
@@ -53,16 +52,42 @@ GNUNET_PQ_make_prepare (const char *name, | |||
53 | /** | 52 | /** |
54 | * Request creation of prepared statements @a ps from Postgres. | 53 | * Request creation of prepared statements @a ps from Postgres. |
55 | * | 54 | * |
56 | * @param connection connection to prepare the statements for | 55 | * @param db database to prepare the statements for |
57 | * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared | 56 | * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared |
58 | * statements. | 57 | * statements. |
59 | * @return #GNUNET_OK on success, | 58 | * @return #GNUNET_OK on success, |
60 | * #GNUNET_SYSERR on error | 59 | * #GNUNET_SYSERR on error |
61 | */ | 60 | */ |
62 | int | 61 | int |
63 | GNUNET_PQ_prepare_statements (PGconn *connection, | 62 | GNUNET_PQ_prepare_statements (struct GNUNET_PQ_Context *db, |
64 | const struct GNUNET_PQ_PreparedStatement *ps) | 63 | const struct GNUNET_PQ_PreparedStatement *ps) |
65 | { | 64 | { |
65 | if (db->ps != ps) | ||
66 | { | ||
67 | /* add 'ps' to list db->ps of prepared statements to run on reconnect! */ | ||
68 | unsigned int olen = 0; /* length of existing 'db->ps' array */ | ||
69 | unsigned int nlen = 0; /* length of 'ps' array */ | ||
70 | struct GNUNET_PQ_PreparedStatement *rps; /* combined array */ | ||
71 | |||
72 | if (NULL != db->ps) | ||
73 | while (NULL != db->ps[olen].name) | ||
74 | olen++; | ||
75 | while (NULL != ps[nlen].name) | ||
76 | nlen++; | ||
77 | rps = GNUNET_new_array (olen + nlen + 1, | ||
78 | struct GNUNET_PQ_PreparedStatement); | ||
79 | if (NULL != db->ps) | ||
80 | memcpy (rps, | ||
81 | db->ps, | ||
82 | olen * sizeof (struct GNUNET_PQ_PreparedStatement)); | ||
83 | memcpy (&rps[olen], | ||
84 | ps, | ||
85 | nlen * sizeof (struct GNUNET_PQ_PreparedStatement)); | ||
86 | GNUNET_free_non_null (db->ps); | ||
87 | db->ps = rps; | ||
88 | } | ||
89 | |||
90 | /* actually prepare statements */ | ||
66 | for (unsigned int i = 0; NULL != ps[i].name; i++) | 91 | for (unsigned int i = 0; NULL != ps[i].name; i++) |
67 | { | 92 | { |
68 | PGresult *ret; | 93 | PGresult *ret; |
@@ -72,7 +97,7 @@ GNUNET_PQ_prepare_statements (PGconn *connection, | |||
72 | "Preparing SQL statement `%s' as `%s'\n", | 97 | "Preparing SQL statement `%s' as `%s'\n", |
73 | ps[i].sql, | 98 | ps[i].sql, |
74 | ps[i].name); | 99 | ps[i].name); |
75 | ret = PQprepare (connection, | 100 | ret = PQprepare (db->conn, |
76 | ps[i].name, | 101 | ps[i].name, |
77 | ps[i].sql, | 102 | ps[i].sql, |
78 | ps[i].num_arguments, | 103 | ps[i].num_arguments, |
@@ -84,7 +109,7 @@ GNUNET_PQ_prepare_statements (PGconn *connection, | |||
84 | _ ("PQprepare (`%s' as `%s') failed with error: %s\n"), | 109 | _ ("PQprepare (`%s' as `%s') failed with error: %s\n"), |
85 | ps[i].sql, | 110 | ps[i].sql, |
86 | ps[i].name, | 111 | ps[i].name, |
87 | PQerrorMessage (connection)); | 112 | PQerrorMessage (db->conn)); |
88 | PQclear (ret); | 113 | PQclear (ret); |
89 | return GNUNET_SYSERR; | 114 | return GNUNET_SYSERR; |
90 | } | 115 | } |
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c index cfb16ac12..1fb1e71c0 100644 --- a/src/pq/pq_result_helper.c +++ b/src/pq/pq_result_helper.c | |||
@@ -587,7 +587,7 @@ extract_abs_time (void *cls, | |||
587 | res = (int64_t *) PQgetvalue (result, | 587 | res = (int64_t *) PQgetvalue (result, |
588 | row, | 588 | row, |
589 | fnum); | 589 | fnum); |
590 | if (INT64_MAX == *res) | 590 | if (INT64_MAX == GNUNET_ntohll ((uint64_t) *res)) |
591 | *udst = GNUNET_TIME_UNIT_FOREVER_ABS; | 591 | *udst = GNUNET_TIME_UNIT_FOREVER_ABS; |
592 | else | 592 | else |
593 | udst->abs_value_us = GNUNET_ntohll ((uint64_t) *res); | 593 | udst->abs_value_us = GNUNET_ntohll ((uint64_t) *res); |
diff --git a/src/pq/test_pq.c b/src/pq/test_pq.c index 697d8e580..a103aca5d 100644 --- a/src/pq/test_pq.c +++ b/src/pq/test_pq.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | (C) 2015, 2016 GNUnet e.V. | 3 | (C) 2015, 2016, 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,75 +23,65 @@ | |||
23 | * @author Christian Grothoff <christian@grothoff.org> | 23 | * @author Christian Grothoff <christian@grothoff.org> |
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 | /** |
31 | * Setup prepared statements. | 30 | * Setup prepared statements. |
32 | * | 31 | * |
33 | * @param db_conn connection handle to initialize | 32 | * @param db database handle to initialize |
34 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | 33 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure |
35 | */ | 34 | */ |
36 | static int | 35 | static int |
37 | postgres_prepare (PGconn *db_conn) | 36 | postgres_prepare (struct GNUNET_PQ_Context *db) |
38 | { | 37 | { |
39 | PGresult *result; | 38 | struct GNUNET_PQ_PreparedStatement ps[] = { |
40 | 39 | GNUNET_PQ_make_prepare ("test_insert", | |
41 | #define PREPARE(name, sql, ...) \ | 40 | "INSERT INTO test_pq (" |
42 | do { \ | 41 | " pub" |
43 | result = PQprepare (db_conn, name, sql, __VA_ARGS__); \ | 42 | ",sig" |
44 | if (PGRES_COMMAND_OK != PQresultStatus (result)) \ | 43 | ",abs_time" |
45 | { \ | 44 | ",forever" |
46 | GNUNET_break (0); \ | 45 | ",hash" |
47 | PQclear (result); result = NULL; \ | 46 | ",vsize" |
48 | return GNUNET_SYSERR; \ | 47 | ",u16" |
49 | } \ | 48 | ",u32" |
50 | PQclear (result); result = NULL; \ | 49 | ",u64" |
51 | } while (0); | 50 | ") VALUES " |
51 | "($1, $2, $3, $4, $5, $6," | ||
52 | "$7, $8, $9);", | ||
53 | 9), | ||
54 | GNUNET_PQ_make_prepare ("test_select", | ||
55 | "SELECT" | ||
56 | " pub" | ||
57 | ",sig" | ||
58 | ",abs_time" | ||
59 | ",forever" | ||
60 | ",hash" | ||
61 | ",vsize" | ||
62 | ",u16" | ||
63 | ",u32" | ||
64 | ",u64" | ||
65 | " FROM test_pq" | ||
66 | " ORDER BY abs_time DESC " | ||
67 | " LIMIT 1;", | ||
68 | 0), | ||
69 | GNUNET_PQ_PREPARED_STATEMENT_END | ||
70 | }; | ||
52 | 71 | ||
53 | PREPARE ("test_insert", | 72 | return GNUNET_PQ_prepare_statements (db, |
54 | "INSERT INTO test_pq (" | 73 | ps); |
55 | " pub" | ||
56 | ",sig" | ||
57 | ",abs_time" | ||
58 | ",forever" | ||
59 | ",hash" | ||
60 | ",vsize" | ||
61 | ",u16" | ||
62 | ",u32" | ||
63 | ",u64" | ||
64 | ") VALUES " | ||
65 | "($1, $2, $3, $4, $5, $6," | ||
66 | "$7, $8, $9);", | ||
67 | 9, NULL); | ||
68 | PREPARE ("test_select", | ||
69 | "SELECT" | ||
70 | " pub" | ||
71 | ",sig" | ||
72 | ",abs_time" | ||
73 | ",forever" | ||
74 | ",hash" | ||
75 | ",vsize" | ||
76 | ",u16" | ||
77 | ",u32" | ||
78 | ",u64" | ||
79 | " FROM test_pq" | ||
80 | " ORDER BY abs_time DESC " | ||
81 | " LIMIT 1;", | ||
82 | 0, NULL); | ||
83 | return GNUNET_OK; | ||
84 | #undef PREPARE | ||
85 | } | 74 | } |
86 | 75 | ||
87 | 76 | ||
88 | /** | 77 | /** |
89 | * Run actual test queries. | 78 | * Run actual test queries. |
90 | * | 79 | * |
80 | * @param db database handle | ||
91 | * @return 0 on success | 81 | * @return 0 on success |
92 | */ | 82 | */ |
93 | static int | 83 | static int |
94 | run_queries (PGconn *conn) | 84 | run_queries (struct GNUNET_PQ_Context *db) |
95 | { | 85 | { |
96 | struct GNUNET_CRYPTO_RsaPublicKey *pub; | 86 | struct GNUNET_CRYPTO_RsaPublicKey *pub; |
97 | struct GNUNET_CRYPTO_RsaPublicKey *pub2 = NULL; | 87 | struct GNUNET_CRYPTO_RsaPublicKey *pub2 = NULL; |
@@ -155,7 +145,7 @@ run_queries (PGconn *conn) | |||
155 | GNUNET_PQ_result_spec_end | 145 | GNUNET_PQ_result_spec_end |
156 | }; | 146 | }; |
157 | 147 | ||
158 | result = GNUNET_PQ_exec_prepared (conn, | 148 | result = GNUNET_PQ_exec_prepared (db, |
159 | "test_insert", | 149 | "test_insert", |
160 | params_insert); | 150 | params_insert); |
161 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | 151 | if (PGRES_COMMAND_OK != PQresultStatus (result)) |
@@ -171,7 +161,7 @@ run_queries (PGconn *conn) | |||
171 | } | 161 | } |
172 | 162 | ||
173 | PQclear (result); | 163 | PQclear (result); |
174 | result = GNUNET_PQ_exec_prepared (conn, | 164 | result = GNUNET_PQ_exec_prepared (db, |
175 | "test_select", | 165 | "test_select", |
176 | params_select); | 166 | params_select); |
177 | if (1 != | 167 | if (1 != |
@@ -224,67 +214,71 @@ int | |||
224 | main (int argc, | 214 | main (int argc, |
225 | const char *const argv[]) | 215 | const char *const argv[]) |
226 | { | 216 | { |
227 | PGconn *conn; | 217 | struct GNUNET_PQ_ExecuteStatement es[] = { |
228 | PGresult *result; | 218 | GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq (" |
219 | " pub BYTEA NOT NULL" | ||
220 | ",sig BYTEA NOT NULL" | ||
221 | ",abs_time INT8 NOT NULL" | ||
222 | ",forever INT8 NOT NULL" | ||
223 | ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)" | ||
224 | ",vsize VARCHAR NOT NULL" | ||
225 | ",u16 INT2 NOT NULL" | ||
226 | ",u32 INT4 NOT NULL" | ||
227 | ",u64 INT8 NOT NULL" | ||
228 | ")"), | ||
229 | GNUNET_PQ_EXECUTE_STATEMENT_END | ||
230 | }; | ||
231 | struct GNUNET_PQ_Context *db; | ||
229 | int ret; | 232 | int ret; |
230 | 233 | ||
231 | GNUNET_log_setup ("test-pq", | 234 | GNUNET_log_setup ("test-pq", |
232 | "WARNING", | 235 | "WARNING", |
233 | NULL); | 236 | NULL); |
234 | conn = PQconnectdb ("postgres:///gnunetcheck"); | 237 | db = GNUNET_PQ_connect ("postgres:///gnunetcheck", |
235 | if (CONNECTION_OK != PQstatus (conn)) | 238 | es, |
239 | NULL); | ||
240 | if (CONNECTION_OK != PQstatus (db->conn)) | ||
236 | { | 241 | { |
237 | fprintf (stderr, | 242 | fprintf (stderr, |
238 | "Cannot run test, database connection failed: %s\n", | 243 | "Cannot run test, database connection failed: %s\n", |
239 | PQerrorMessage (conn)); | 244 | PQerrorMessage (db->conn)); |
240 | GNUNET_break (0); | 245 | GNUNET_break (0); |
241 | PQfinish (conn); | 246 | GNUNET_PQ_disconnect (db); |
242 | return 77; /* signal test was skipped */ | 247 | return 77; /* signal test was skipped */ |
243 | } | 248 | } |
244 | |||
245 | result = PQexec (conn, | ||
246 | "CREATE TEMPORARY TABLE IF NOT EXISTS test_pq (" | ||
247 | " pub BYTEA NOT NULL" | ||
248 | ",sig BYTEA NOT NULL" | ||
249 | ",abs_time INT8 NOT NULL" | ||
250 | ",forever INT8 NOT NULL" | ||
251 | ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)" | ||
252 | ",vsize VARCHAR NOT NULL" | ||
253 | ",u16 INT2 NOT NULL" | ||
254 | ",u32 INT4 NOT NULL" | ||
255 | ",u64 INT8 NOT NULL" | ||
256 | ")"); | ||
257 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | ||
258 | { | ||
259 | fprintf (stderr, | ||
260 | "Failed to create table: %s\n", | ||
261 | PQerrorMessage (conn)); | ||
262 | PQclear (result); | ||
263 | PQfinish (conn); | ||
264 | return 1; | ||
265 | } | ||
266 | PQclear (result); | ||
267 | if (GNUNET_OK != | 249 | if (GNUNET_OK != |
268 | postgres_prepare (conn)) | 250 | postgres_prepare (db)) |
269 | { | 251 | { |
270 | GNUNET_break (0); | 252 | GNUNET_break (0); |
271 | PQfinish (conn); | 253 | GNUNET_PQ_disconnect (db); |
272 | return 1; | 254 | return 1; |
273 | } | 255 | } |
274 | ret = run_queries (conn); | 256 | ret = run_queries (db); |
275 | result = PQexec (conn, | 257 | #if TEST_RESTART |
276 | "DROP TABLE test_pq"); | 258 | fprintf (stderr, "Please restart Postgres database now!\n"); |
277 | if (PGRES_COMMAND_OK != PQresultStatus (result)) | 259 | sleep (60); |
260 | ret = run_queries (db); | ||
261 | fprintf (stderr, "Result: %d (expect: 1 -- if you restarted the DB)\n", ret); | ||
262 | ret = run_queries (db); | ||
263 | fprintf (stderr, "Result: %d (expect: 0)\n", ret); | ||
264 | #endif | ||
278 | { | 265 | { |
279 | fprintf (stderr, | 266 | struct GNUNET_PQ_ExecuteStatement es[] = { |
280 | "Failed to create table: %s\n", | 267 | GNUNET_PQ_make_execute ("DROP TABLE test_pq"), |
281 | PQerrorMessage (conn)); | 268 | GNUNET_PQ_EXECUTE_STATEMENT_END |
282 | PQclear (result); | 269 | }; |
283 | PQfinish (conn); | 270 | |
284 | return 1; | 271 | if (GNUNET_OK != |
272 | GNUNET_PQ_exec_statements (db, | ||
273 | es)) | ||
274 | { | ||
275 | fprintf (stderr, | ||
276 | "Failed to drop table\n"); | ||
277 | GNUNET_PQ_disconnect (db); | ||
278 | return 1; | ||
279 | } | ||
285 | } | 280 | } |
286 | PQclear (result); | 281 | GNUNET_PQ_disconnect (db); |
287 | PQfinish (conn); | ||
288 | return ret; | 282 | return ret; |
289 | } | 283 | } |
290 | 284 | ||