diff options
Diffstat (limited to 'src/namestore/plugin_namestore_postgres.c')
-rw-r--r-- | src/namestore/plugin_namestore_postgres.c | 566 |
1 files changed, 261 insertions, 305 deletions
diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c index 01dbf9e61..491cec1cb 100644 --- a/src/namestore/plugin_namestore_postgres.c +++ b/src/namestore/plugin_namestore_postgres.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of GNUnet | 2 | * This file is part of GNUnet |
3 | * Copyright (C) 2009-2013, 2016 GNUnet e.V. | 3 | * Copyright (C) 2009-2013, 2016, 2017 GNUnet e.V. |
4 | * | 4 | * |
5 | * GNUnet is free software; you can redistribute it and/or modify | 5 | * GNUnet is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published | 6 | * it under the terms of the GNU General Public License as published |
@@ -27,31 +27,10 @@ | |||
27 | #include "gnunet_namestore_plugin.h" | 27 | #include "gnunet_namestore_plugin.h" |
28 | #include "gnunet_namestore_service.h" | 28 | #include "gnunet_namestore_service.h" |
29 | #include "gnunet_gnsrecord_lib.h" | 29 | #include "gnunet_gnsrecord_lib.h" |
30 | #include "gnunet_postgres_lib.h" | ||
31 | #include "gnunet_pq_lib.h" | 30 | #include "gnunet_pq_lib.h" |
32 | #include "namestore.h" | 31 | #include "namestore.h" |
33 | 32 | ||
34 | 33 | ||
35 | /** | ||
36 | * After how many ms "busy" should a DB operation fail for good? | ||
37 | * A low value makes sure that we are more responsive to requests | ||
38 | * (especially PUTs). A high value guarantees a higher success | ||
39 | * rate (SELECTs in iterate can take several seconds despite LIMIT=1). | ||
40 | * | ||
41 | * The default value of 1s should ensure that users do not experience | ||
42 | * huge latencies while at the same time allowing operations to succeed | ||
43 | * with reasonable probability. | ||
44 | */ | ||
45 | #define BUSY_TIMEOUT_MS 1000 | ||
46 | |||
47 | |||
48 | /** | ||
49 | * Log an error message at log-level 'level' that indicates | ||
50 | * a failure of the command 'cmd' on file 'filename' | ||
51 | * with the message given by strerror(errno). | ||
52 | */ | ||
53 | #define LOG_POSTGRES(db, level, cmd) do { GNUNET_log_from (level, "namestore-postgres", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0) | ||
54 | |||
55 | #define LOG(kind,...) GNUNET_log_from (kind, "namestore-postgres", __VA_ARGS__) | 34 | #define LOG(kind,...) GNUNET_log_from (kind, "namestore-postgres", __VA_ARGS__) |
56 | 35 | ||
57 | 36 | ||
@@ -75,30 +54,6 @@ struct Plugin | |||
75 | 54 | ||
76 | 55 | ||
77 | /** | 56 | /** |
78 | * Create our database indices. | ||
79 | * | ||
80 | * @param dbh handle to the database | ||
81 | */ | ||
82 | static void | ||
83 | create_indices (PGconn * dbh) | ||
84 | { | ||
85 | /* create indices */ | ||
86 | if ( (GNUNET_OK != | ||
87 | GNUNET_POSTGRES_exec (dbh, | ||
88 | "CREATE INDEX IF NOT EXISTS ir_pkey_reverse ON ns097records (zone_private_key,pkey)")) || | ||
89 | (GNUNET_OK != | ||
90 | GNUNET_POSTGRES_exec (dbh, | ||
91 | "CREATE INDEX IF NOT EXISTS ir_pkey_iter ON ns097records (zone_private_key,rvalue)")) || | ||
92 | (GNUNET_OK != | ||
93 | GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS it_iter ON ns097records (rvalue)")) || | ||
94 | (GNUNET_OK != | ||
95 | GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_label ON ns097records (label)")) ) | ||
96 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
97 | _("Failed to create indices\n")); | ||
98 | } | ||
99 | |||
100 | |||
101 | /** | ||
102 | * Initialize the database connections and associated | 57 | * Initialize the database connections and associated |
103 | * data structures (create tables and indices | 58 | * data structures (create tables and indices |
104 | * as needed as well). | 59 | * as needed as well). |
@@ -109,10 +64,30 @@ create_indices (PGconn * dbh) | |||
109 | static int | 64 | static int |
110 | database_setup (struct Plugin *plugin) | 65 | database_setup (struct Plugin *plugin) |
111 | { | 66 | { |
112 | PGresult *res; | 67 | struct GNUNET_PQ_ExecuteStatement es_temporary = |
113 | 68 | GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS ns097records (" | |
114 | plugin->dbh = GNUNET_POSTGRES_connect (plugin->cfg, | 69 | " zone_private_key BYTEA NOT NULL DEFAULT ''," |
115 | "namestore-postgres"); | 70 | " pkey BYTEA DEFAULT ''," |
71 | " rvalue BYTEA NOT NULL DEFAULT ''," | ||
72 | " record_count INTEGER NOT NULL DEFAULT 0," | ||
73 | " record_data BYTEA NOT NULL DEFAULT ''," | ||
74 | " label TEXT NOT NULL DEFAULT ''" | ||
75 | ")" | ||
76 | "WITH OIDS"); | ||
77 | struct GNUNET_PQ_ExecuteStatement es_default = | ||
78 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS ns097records (" | ||
79 | " zone_private_key BYTEA NOT NULL DEFAULT ''," | ||
80 | " pkey BYTEA DEFAULT ''," | ||
81 | " rvalue BYTEA NOT NULL DEFAULT ''," | ||
82 | " record_count INTEGER NOT NULL DEFAULT 0," | ||
83 | " record_data BYTEA NOT NULL DEFAULT ''," | ||
84 | " label TEXT NOT NULL DEFAULT ''" | ||
85 | ")" | ||
86 | "WITH OIDS"); | ||
87 | const struct GNUNET_PQ_ExecuteStatement *cr; | ||
88 | |||
89 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, | ||
90 | "namestore-postgres"); | ||
116 | if (NULL == plugin->dbh) | 91 | if (NULL == plugin->dbh) |
117 | return GNUNET_SYSERR; | 92 | return GNUNET_SYSERR; |
118 | if (GNUNET_YES == | 93 | if (GNUNET_YES == |
@@ -120,80 +95,70 @@ database_setup (struct Plugin *plugin) | |||
120 | "namestore-postgres", | 95 | "namestore-postgres", |
121 | "TEMPORARY_TABLE")) | 96 | "TEMPORARY_TABLE")) |
122 | { | 97 | { |
123 | res = | 98 | cr = &es_temporary; |
124 | PQexec (plugin->dbh, | ||
125 | "CREATE TEMPORARY TABLE IF NOT EXISTS ns097records (" | ||
126 | " zone_private_key BYTEA NOT NULL DEFAULT ''," | ||
127 | " pkey BYTEA DEFAULT ''," | ||
128 | " rvalue BYTEA NOT NULL DEFAULT ''," | ||
129 | " record_count INTEGER NOT NULL DEFAULT 0," | ||
130 | " record_data BYTEA NOT NULL DEFAULT ''," | ||
131 | " label TEXT NOT NULL DEFAULT ''" | ||
132 | ")" "WITH OIDS"); | ||
133 | } | 99 | } |
134 | else | 100 | else |
135 | { | 101 | { |
136 | res = | 102 | cr = &es_default; |
137 | PQexec (plugin->dbh, | ||
138 | "CREATE TABLE IF NOT EXISTS ns097records (" | ||
139 | " zone_private_key BYTEA NOT NULL DEFAULT ''," | ||
140 | " pkey BYTEA DEFAULT ''," | ||
141 | " rvalue BYTEA NOT NULL DEFAULT ''," | ||
142 | " record_count INTEGER NOT NULL DEFAULT 0," | ||
143 | " record_data BYTEA NOT NULL DEFAULT ''," | ||
144 | " label TEXT NOT NULL DEFAULT ''" | ||
145 | ")" "WITH OIDS"); | ||
146 | } | 103 | } |
147 | if ( (NULL == res) || | 104 | |
148 | ((PQresultStatus (res) != PGRES_COMMAND_OK) && | ||
149 | (0 != strcmp ("42P07", /* duplicate table */ | ||
150 | PQresultErrorField | ||
151 | (res, | ||
152 | PG_DIAG_SQLSTATE))))) | ||
153 | { | 105 | { |
154 | (void) GNUNET_POSTGRES_check_result (plugin->dbh, res, | 106 | struct GNUNET_PQ_ExecuteStatement es[] = { |
155 | PGRES_COMMAND_OK, "CREATE TABLE", | 107 | *cr, |
156 | "ns097records"); | 108 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse " |
157 | PQfinish (plugin->dbh); | 109 | "ON ns097records (zone_private_key,pkey)"), |
158 | plugin->dbh = NULL; | 110 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter " |
159 | return GNUNET_SYSERR; | 111 | "ON ns097records (zone_private_key,rvalue)"), |
112 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS it_iter " | ||
113 | "ON ns097records (rvalue)"), | ||
114 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_label " | ||
115 | "ON ns097records (label)"), | ||
116 | GNUNET_PQ_EXECUTE_STATEMENT_END | ||
117 | }; | ||
118 | |||
119 | if (GNUNET_OK != | ||
120 | GNUNET_PQ_exec_statements (plugin->dbh, | ||
121 | es)) | ||
122 | { | ||
123 | PQfinish (plugin->dbh); | ||
124 | plugin->dbh = NULL; | ||
125 | return GNUNET_SYSERR; | ||
126 | } | ||
160 | } | 127 | } |
161 | create_indices (plugin->dbh); | 128 | |
162 | |||
163 | if ((GNUNET_OK != | ||
164 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
165 | "store_records", | ||
166 | "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label) VALUES " | ||
167 | "($1, $2, $3, $4, $5, $6)", 6)) || | ||
168 | (GNUNET_OK != | ||
169 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
170 | "delete_records", | ||
171 | "DELETE FROM ns097records WHERE zone_private_key=$1 AND label=$2", 2)) || | ||
172 | (GNUNET_OK != | ||
173 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
174 | "zone_to_name", | ||
175 | "SELECT record_count,record_data,label FROM ns097records" | ||
176 | " WHERE zone_private_key=$1 AND pkey=$2", 2)) || | ||
177 | (GNUNET_OK != | ||
178 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
179 | "iterate_zone", | ||
180 | "SELECT record_count,record_data,label FROM ns097records" | ||
181 | " WHERE zone_private_key=$1 ORDER BY rvalue LIMIT 1 OFFSET $2", 2)) || | ||
182 | (GNUNET_OK != | ||
183 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
184 | "iterate_all_zones", | ||
185 | "SELECT record_count,record_data,label,zone_private_key" | ||
186 | " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET $1", 1)) || | ||
187 | (GNUNET_OK != | ||
188 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
189 | "lookup_label", | ||
190 | "SELECT record_count,record_data,label" | ||
191 | " FROM ns097records WHERE zone_private_key=$1 AND label=$2", 2))) | ||
192 | { | 129 | { |
193 | PQfinish (plugin->dbh); | 130 | struct GNUNET_PQ_PreparedStatement ps[] = { |
194 | plugin->dbh = NULL; | 131 | GNUNET_PQ_make_prepare ("store_records", |
195 | return GNUNET_SYSERR; | 132 | "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label) VALUES " |
133 | "($1, $2, $3, $4, $5, $6)", 6), | ||
134 | GNUNET_PQ_make_prepare ("delete_records", | ||
135 | "DELETE FROM ns097records " | ||
136 | "WHERE zone_private_key=$1 AND label=$2", 2), | ||
137 | GNUNET_PQ_make_prepare ("zone_to_name", | ||
138 | "SELECT record_count,record_data,label FROM ns097records" | ||
139 | " WHERE zone_private_key=$1 AND pkey=$2", 2), | ||
140 | GNUNET_PQ_make_prepare ("iterate_zone", | ||
141 | "SELECT record_count,record_data,label FROM ns097records " | ||
142 | "WHERE zone_private_key=$1 ORDER BY rvalue LIMIT 1 OFFSET $2", 2), | ||
143 | GNUNET_PQ_make_prepare ("iterate_all_zones", | ||
144 | "SELECT record_count,record_data,label,zone_private_key" | ||
145 | " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET $1", 1), | ||
146 | GNUNET_PQ_make_prepare ("lookup_label", | ||
147 | "SELECT record_count,record_data,label " | ||
148 | "FROM ns097records WHERE zone_private_key=$1 AND label=$2", 2), | ||
149 | GNUNET_PQ_PREPARED_STATEMENT_END | ||
150 | }; | ||
151 | |||
152 | if (GNUNET_OK != | ||
153 | GNUNET_PQ_prepare_statements (plugin->dbh, | ||
154 | ps)) | ||
155 | { | ||
156 | PQfinish (plugin->dbh); | ||
157 | plugin->dbh = NULL; | ||
158 | return GNUNET_SYSERR; | ||
159 | } | ||
196 | } | 160 | } |
161 | |||
197 | return GNUNET_OK; | 162 | return GNUNET_OK; |
198 | } | 163 | } |
199 | 164 | ||
@@ -219,21 +184,21 @@ namestore_postgres_store_records (void *cls, | |||
219 | struct Plugin *plugin = cls; | 184 | struct Plugin *plugin = cls; |
220 | struct GNUNET_CRYPTO_EcdsaPublicKey pkey; | 185 | struct GNUNET_CRYPTO_EcdsaPublicKey pkey; |
221 | uint64_t rvalue; | 186 | uint64_t rvalue; |
222 | uint32_t rd_count_nbo = htonl ((uint32_t) rd_count); | 187 | uint32_t rd_count32 = (uint32_t) rd_count; |
223 | size_t data_size; | 188 | size_t data_size; |
224 | unsigned int i; | ||
225 | 189 | ||
226 | memset (&pkey, 0, sizeof (pkey)); | 190 | memset (&pkey, 0, sizeof (pkey)); |
227 | for (i=0;i<rd_count;i++) | 191 | for (unsigned int i=0;i<rd_count;i++) |
228 | if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type) | 192 | if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type) |
229 | { | 193 | { |
230 | GNUNET_break (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) == rd[i].data_size); | 194 | GNUNET_break (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) == rd[i].data_size); |
231 | GNUNET_memcpy (&pkey, | 195 | GNUNET_memcpy (&pkey, |
232 | rd[i].data, | 196 | rd[i].data, |
233 | rd[i].data_size); | 197 | rd[i].data_size); |
234 | break; | 198 | break; |
235 | } | 199 | } |
236 | rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); | 200 | rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, |
201 | UINT64_MAX); | ||
237 | data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd); | 202 | data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd); |
238 | if (data_size > 64 * 65536) | 203 | if (data_size > 64 * 65536) |
239 | { | 204 | { |
@@ -242,141 +207,134 @@ namestore_postgres_store_records (void *cls, | |||
242 | } | 207 | } |
243 | { | 208 | { |
244 | char data[data_size]; | 209 | char data[data_size]; |
245 | // FIXME: use libgnunetpq! | 210 | struct GNUNET_PQ_QueryParam params[] = { |
246 | const char *paramValues[] = { | 211 | GNUNET_PQ_query_param_auto_from_type (zone_key), |
247 | (const char *) zone_key, | 212 | GNUNET_PQ_query_param_auto_from_type (&pkey), |
248 | (const char *) &pkey, | 213 | GNUNET_PQ_query_param_uint64 (&rvalue), |
249 | (const char *) &rvalue, | 214 | GNUNET_PQ_query_param_uint32 (&rd_count32), |
250 | (const char *) &rd_count_nbo, | 215 | GNUNET_PQ_query_param_fixed_size (data, data_size), |
251 | (const char *) data, | 216 | GNUNET_PQ_query_param_string (label), |
252 | label | 217 | GNUNET_PQ_query_param_end |
253 | }; | ||
254 | int paramLengths[] = { | ||
255 | sizeof (*zone_key), | ||
256 | sizeof (pkey), | ||
257 | sizeof (rvalue), | ||
258 | sizeof (rd_count_nbo), | ||
259 | data_size, | ||
260 | strlen (label) | ||
261 | }; | 218 | }; |
262 | const int paramFormats[] = { 1, 1, 1, 1, 1, 1 }; | 219 | enum GNUNET_DB_QueryStatus res; |
263 | PGresult *res; | ||
264 | 220 | ||
265 | if (data_size != GNUNET_GNSRECORD_records_serialize (rd_count, rd, | 221 | if (data_size != |
266 | data_size, data)) | 222 | GNUNET_GNSRECORD_records_serialize (rd_count, rd, |
223 | data_size, data)) | ||
267 | { | 224 | { |
268 | GNUNET_break (0); | 225 | GNUNET_break (0); |
269 | return GNUNET_SYSERR; | 226 | return GNUNET_SYSERR; |
270 | } | 227 | } |
271 | 228 | ||
272 | res = | 229 | res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh, |
273 | PQexecPrepared (plugin->dbh, "store_records", 6, | 230 | "store_records", |
274 | paramValues, paramLengths, paramFormats, 1); | 231 | params); |
275 | if (GNUNET_OK != | 232 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != res) |
276 | GNUNET_POSTGRES_check_result (plugin->dbh, | ||
277 | res, | ||
278 | PGRES_COMMAND_OK, | ||
279 | "PQexecPrepared", | ||
280 | "store_records")) | ||
281 | return GNUNET_SYSERR; | 233 | return GNUNET_SYSERR; |
282 | PQclear (res); | ||
283 | return GNUNET_OK; | ||
284 | } | 234 | } |
235 | return GNUNET_OK; | ||
285 | } | 236 | } |
286 | 237 | ||
287 | 238 | ||
288 | /** | 239 | /** |
240 | * Closure for #parse_result_call_iterator. | ||
241 | */ | ||
242 | struct ParserContext | ||
243 | { | ||
244 | /** | ||
245 | * Function to call for each result. | ||
246 | */ | ||
247 | GNUNET_NAMESTORE_RecordIterator iter; | ||
248 | |||
249 | /** | ||
250 | * Closure for @e iter. | ||
251 | */ | ||
252 | void *iter_cls; | ||
253 | |||
254 | /** | ||
255 | * Zone key, NULL if part of record. | ||
256 | */ | ||
257 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key; | ||
258 | }; | ||
259 | |||
260 | |||
261 | /** | ||
289 | * A statement has been run. We should evaluate the result, and if possible | 262 | * A statement has been run. We should evaluate the result, and if possible |
290 | * call the given @a iter with the result. | 263 | * call the @a iter in @a cls with the result. |
291 | * | 264 | * |
292 | * @param plugin plugin context | 265 | * @param cls closure of type `struct ParserContext *` |
293 | * @param res result from the statement that was run (to be cleaned up) | 266 | * @param result the postgres result |
294 | * @param zone_key private key of the zone, could be NULL, in which case we should | 267 | * @param num_result the number of results in @a result |
295 | * get the zone from @a res | ||
296 | * @param iter iterator to call with the result | ||
297 | * @param iter_cls closure for @a iter | ||
298 | * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error | ||
299 | */ | 268 | */ |
300 | static int | 269 | static void |
301 | get_record_and_call_iterator (struct Plugin *plugin, | 270 | parse_result_call_iterator (void *cls, |
302 | PGresult *res, | 271 | PGresult *res, |
303 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, | 272 | unsigned int num_results) |
304 | GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) | ||
305 | { | 273 | { |
306 | const char *data; | 274 | struct ParserContext *pc = cls; |
307 | size_t data_size; | 275 | |
308 | uint32_t record_count; | 276 | for (unsigned int i=0;i<num_results;i++) |
309 | const char *label; | ||
310 | size_t label_len; | ||
311 | unsigned int cnt; | ||
312 | |||
313 | if (GNUNET_OK != | ||
314 | GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_TUPLES_OK, | ||
315 | "PQexecPrepared", | ||
316 | "iteration")) | ||
317 | { | ||
318 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
319 | "Failing lookup (postgres error)\n"); | ||
320 | return GNUNET_SYSERR; | ||
321 | } | ||
322 | if (0 == (cnt = PQntuples (res))) | ||
323 | { | ||
324 | /* no result */ | ||
325 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
326 | "Ending iteration (no more results)\n"); | ||
327 | PQclear (res); | ||
328 | return GNUNET_NO; | ||
329 | } | ||
330 | GNUNET_assert (1 == cnt); | ||
331 | GNUNET_assert (3 + ((NULL == zone_key) ? 1 : 0) == PQnfields (res)); | ||
332 | if (NULL == zone_key) | ||
333 | { | 277 | { |
334 | if (sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey) != PQgetlength (res, 0, 3)) | 278 | void *data; |
279 | size_t data_size; | ||
280 | uint32_t record_count; | ||
281 | char *label; | ||
282 | struct GNUNET_CRYPTO_EcdsaPrivateKey zk; | ||
283 | struct GNUNET_PQ_ResultSpec rs_with_zone[] = { | ||
284 | GNUNET_PQ_result_spec_uint32 ("record_count", &record_count), | ||
285 | GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size), | ||
286 | GNUNET_PQ_result_spec_string ("label", &label), | ||
287 | GNUNET_PQ_result_spec_auto_from_type ("zone_private_key", &zk), | ||
288 | GNUNET_PQ_result_spec_end | ||
289 | }; | ||
290 | struct GNUNET_PQ_ResultSpec rs_without_zone[] = { | ||
291 | GNUNET_PQ_result_spec_uint32 ("record_count", &record_count), | ||
292 | GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size), | ||
293 | GNUNET_PQ_result_spec_string ("label", &label), | ||
294 | GNUNET_PQ_result_spec_end | ||
295 | }; | ||
296 | struct GNUNET_PQ_ResultSpec *rs; | ||
297 | |||
298 | rs = (NULL == pc->zone_key) ? rs_with_zone : rs_without_zone; | ||
299 | if (GNUNET_YES != | ||
300 | GNUNET_PQ_extract_result (res, | ||
301 | rs, | ||
302 | i)) | ||
335 | { | 303 | { |
336 | GNUNET_break (0); | 304 | GNUNET_break (0); |
337 | PQclear (res); | 305 | return; |
338 | return GNUNET_SYSERR; | ||
339 | } | 306 | } |
340 | zone_key = (const struct GNUNET_CRYPTO_EcdsaPrivateKey *) PQgetvalue (res, 0, 3); | ||
341 | } | ||
342 | if (sizeof (uint32_t) != PQfsize (res, 0)) | ||
343 | { | ||
344 | GNUNET_break (0); | ||
345 | PQclear (res); | ||
346 | return GNUNET_SYSERR; | ||
347 | } | ||
348 | 307 | ||
349 | record_count = ntohl (*(uint32_t *) PQgetvalue (res, 0, 0)); | 308 | if (record_count > 64 * 1024) |
350 | data = PQgetvalue (res, 0, 1); | ||
351 | data_size = PQgetlength (res, 0, 1); | ||
352 | label = PQgetvalue (res, 0, 2); | ||
353 | label_len = PQgetlength (res, 0, 1); | ||
354 | if (record_count > 64 * 1024) | ||
355 | { | ||
356 | /* sanity check, don't stack allocate far too much just | ||
357 | because database might contain a large value here */ | ||
358 | GNUNET_break (0); | ||
359 | PQclear (res); | ||
360 | return GNUNET_SYSERR; | ||
361 | } | ||
362 | { | ||
363 | struct GNUNET_GNSRECORD_Data rd[record_count]; | ||
364 | char buf[label_len + 1]; | ||
365 | |||
366 | GNUNET_memcpy (buf, label, label_len); | ||
367 | buf[label_len] = '\0'; | ||
368 | if (GNUNET_OK != | ||
369 | GNUNET_GNSRECORD_records_deserialize (data_size, data, | ||
370 | record_count, rd)) | ||
371 | { | 309 | { |
310 | /* sanity check, don't stack allocate far too much just | ||
311 | because database might contain a large value here */ | ||
372 | GNUNET_break (0); | 312 | GNUNET_break (0); |
373 | PQclear (res); | 313 | GNUNET_PQ_cleanup_result (rs); |
374 | return GNUNET_SYSERR; | 314 | return; |
315 | } | ||
316 | |||
317 | { | ||
318 | struct GNUNET_GNSRECORD_Data rd[record_count]; | ||
319 | |||
320 | if (GNUNET_OK != | ||
321 | GNUNET_GNSRECORD_records_deserialize (data_size, | ||
322 | data, | ||
323 | record_count, | ||
324 | rd)) | ||
325 | { | ||
326 | GNUNET_break (0); | ||
327 | GNUNET_PQ_cleanup_result (rs); | ||
328 | return; | ||
329 | } | ||
330 | pc->iter (pc->iter_cls, | ||
331 | (NULL == pc->zone_key) ? &zk : pc->zone_key, | ||
332 | label, | ||
333 | record_count, | ||
334 | rd); | ||
375 | } | 335 | } |
376 | iter (iter_cls, zone_key, buf, record_count, rd); | 336 | GNUNET_PQ_cleanup_result (rs); |
377 | } | 337 | } |
378 | PQclear (res); | ||
379 | return GNUNET_OK; | ||
380 | } | 338 | } |
381 | 339 | ||
382 | 340 | ||
@@ -398,25 +356,25 @@ namestore_postgres_lookup_records (void *cls, | |||
398 | void *iter_cls) | 356 | void *iter_cls) |
399 | { | 357 | { |
400 | struct Plugin *plugin = cls; | 358 | struct Plugin *plugin = cls; |
401 | const char *paramValues[] = { | 359 | struct GNUNET_PQ_QueryParam params[] = { |
402 | (const char *) zone, | 360 | GNUNET_PQ_query_param_auto_from_type (zone), |
403 | label | 361 | GNUNET_PQ_query_param_string (label), |
362 | GNUNET_PQ_query_param_end | ||
404 | }; | 363 | }; |
405 | int paramLengths[] = { | 364 | struct ParserContext pc; |
406 | sizeof (*zone), | 365 | enum GNUNET_DB_QueryStatus res; |
407 | strlen (label) | 366 | |
408 | }; | 367 | pc.iter = iter; |
409 | const int paramFormats[] = { 1, 1 }; | 368 | pc.iter_cls = iter_cls; |
410 | PGresult *res; | 369 | pc.zone_key = NULL; |
411 | 370 | res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, | |
412 | res = PQexecPrepared (plugin->dbh, | 371 | "lookup_label", |
413 | "lookup_label", 2, | 372 | params, |
414 | paramValues, paramLengths, paramFormats, | 373 | &parse_result_call_iterator, |
415 | 1); | 374 | &pc); |
416 | return get_record_and_call_iterator (plugin, | 375 | if (res <= 0) |
417 | res, | 376 | return GNUNET_SYSERR; |
418 | zone, | 377 | return GNUNET_OK; |
419 | iter, iter_cls); | ||
420 | } | 378 | } |
421 | 379 | ||
422 | 380 | ||
@@ -435,53 +393,50 @@ static int | |||
435 | namestore_postgres_iterate_records (void *cls, | 393 | namestore_postgres_iterate_records (void *cls, |
436 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, | 394 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, |
437 | uint64_t offset, | 395 | uint64_t offset, |
438 | GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) | 396 | GNUNET_NAMESTORE_RecordIterator iter, |
397 | void *iter_cls) | ||
439 | { | 398 | { |
440 | struct Plugin *plugin = cls; | 399 | struct Plugin *plugin = cls; |
441 | uint64_t offset_be = GNUNET_htonll (offset); | 400 | enum GNUNET_DB_QueryStatus res; |
401 | struct ParserContext pc; | ||
442 | 402 | ||
403 | pc.iter = iter; | ||
404 | pc.iter_cls = iter_cls; | ||
405 | pc.zone_key = zone; | ||
443 | if (NULL == zone) | 406 | if (NULL == zone) |
444 | { | 407 | { |
445 | const char *paramValues[] = { | 408 | struct GNUNET_PQ_QueryParam params_without_zone[] = { |
446 | (const char *) &offset_be | 409 | GNUNET_PQ_query_param_uint64 (&offset), |
410 | GNUNET_PQ_query_param_end | ||
447 | }; | 411 | }; |
448 | int paramLengths[] = { | 412 | |
449 | sizeof (offset_be) | 413 | res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, |
450 | }; | 414 | "iterate_all_zones", |
451 | const int paramFormats[] = { 1 }; | 415 | params_without_zone, |
452 | PGresult *res; | 416 | &parse_result_call_iterator, |
453 | 417 | &pc); | |
454 | res = PQexecPrepared (plugin->dbh, | ||
455 | "iterate_all_zones", 1, | ||
456 | paramValues, paramLengths, paramFormats, | ||
457 | 1); | ||
458 | return get_record_and_call_iterator (plugin, | ||
459 | res, | ||
460 | NULL, | ||
461 | iter, iter_cls); | ||
462 | } | 418 | } |
463 | else | 419 | else |
464 | { | 420 | { |
465 | const char *paramValues[] = { | 421 | struct GNUNET_PQ_QueryParam params_with_zone[] = { |
466 | (const char *) zone, | 422 | GNUNET_PQ_query_param_auto_from_type (zone), |
467 | (const char *) &offset_be | 423 | GNUNET_PQ_query_param_uint64 (&offset), |
468 | }; | 424 | GNUNET_PQ_query_param_end |
469 | int paramLengths[] = { | ||
470 | sizeof (*zone), | ||
471 | sizeof (offset_be) | ||
472 | }; | 425 | }; |
473 | const int paramFormats[] = { 1, 1 }; | 426 | |
474 | PGresult *res; | 427 | res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, |
475 | 428 | "iterate_zone", | |
476 | res = PQexecPrepared (plugin->dbh, | 429 | params_with_zone, |
477 | "iterate_zone", 2, | 430 | &parse_result_call_iterator, |
478 | paramValues, paramLengths, paramFormats, | 431 | &pc); |
479 | 1); | ||
480 | return get_record_and_call_iterator (plugin, | ||
481 | res, | ||
482 | zone, | ||
483 | iter, iter_cls); | ||
484 | } | 432 | } |
433 | if (res < 0) | ||
434 | return GNUNET_SYSERR; | ||
435 | |||
436 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res) | ||
437 | return GNUNET_NO; | ||
438 | |||
439 | return GNUNET_OK; | ||
485 | } | 440 | } |
486 | 441 | ||
487 | 442 | ||
@@ -503,25 +458,26 @@ namestore_postgres_zone_to_name (void *cls, | |||
503 | GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) | 458 | GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) |
504 | { | 459 | { |
505 | struct Plugin *plugin = cls; | 460 | struct Plugin *plugin = cls; |
506 | const char *paramValues[] = { | 461 | struct GNUNET_PQ_QueryParam params[] = { |
507 | (const char *) zone, | 462 | GNUNET_PQ_query_param_auto_from_type (zone), |
508 | (const char *) value_zone | 463 | GNUNET_PQ_query_param_auto_from_type (value_zone), |
464 | GNUNET_PQ_query_param_end | ||
509 | }; | 465 | }; |
510 | int paramLengths[] = { | 466 | enum GNUNET_DB_QueryStatus res; |
511 | sizeof (*zone), | 467 | struct ParserContext pc; |
512 | sizeof (*value_zone) | 468 | |
513 | }; | 469 | pc.iter = iter; |
514 | const int paramFormats[] = { 1, 1 }; | 470 | pc.iter_cls = iter_cls; |
515 | PGresult *res; | 471 | pc.zone_key = zone; |
516 | 472 | ||
517 | res = PQexecPrepared (plugin->dbh, | 473 | res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, |
518 | "zone_to_name", 2, | 474 | "zone_to_name", |
519 | paramValues, paramLengths, paramFormats, | 475 | params, |
520 | 1); | 476 | &parse_result_call_iterator, |
521 | return get_record_and_call_iterator (plugin, | 477 | &pc); |
522 | res, | 478 | if (res < 0) |
523 | zone, | 479 | return GNUNET_SYSERR; |
524 | iter, iter_cls); | 480 | return GNUNET_OK; |
525 | } | 481 | } |
526 | 482 | ||
527 | 483 | ||
@@ -568,7 +524,7 @@ libgnunet_plugin_namestore_postgres_init (void *cls) | |||
568 | api->zone_to_name = &namestore_postgres_zone_to_name; | 524 | api->zone_to_name = &namestore_postgres_zone_to_name; |
569 | api->lookup_records = &namestore_postgres_lookup_records; | 525 | api->lookup_records = &namestore_postgres_lookup_records; |
570 | LOG (GNUNET_ERROR_TYPE_INFO, | 526 | LOG (GNUNET_ERROR_TYPE_INFO, |
571 | _("Postgres database running\n")); | 527 | "Postgres namestore plugin running\n"); |
572 | return api; | 528 | return api; |
573 | } | 529 | } |
574 | 530 | ||
@@ -589,7 +545,7 @@ libgnunet_plugin_namestore_postgres_done (void *cls) | |||
589 | plugin->cfg = NULL; | 545 | plugin->cfg = NULL; |
590 | GNUNET_free (api); | 546 | GNUNET_free (api); |
591 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 547 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
592 | "postgres plugin is finished\n"); | 548 | "Postgres namestore plugin is finished\n"); |
593 | return NULL; | 549 | return NULL; |
594 | } | 550 | } |
595 | 551 | ||