aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-03-21 14:45:19 +0000
committerChristian Grothoff <christian@grothoff.org>2012-03-21 14:45:19 +0000
commitdde852407a26aa2da817e87acc413fe1f50f81dd (patch)
tree28d255f66f55b71672552d2d4744fd7942a4e1ac /src
parent17c30ef801a526e67a09d761f137dd25ebea5fe7 (diff)
downloadgnunet-dde852407a26aa2da817e87acc413fe1f50f81dd.tar.gz
gnunet-dde852407a26aa2da817e87acc413fe1f50f81dd.zip
-using new mysql helper library also with datastore
Diffstat (limited to 'src')
-rw-r--r--src/datastore/Makefile.am1
-rw-r--r--src/datastore/plugin_datastore_mysql.c677
-rw-r--r--src/include/gnunet_mysql_lib.h49
-rw-r--r--src/mysql/mysql.c127
4 files changed, 196 insertions, 658 deletions
diff --git a/src/datastore/Makefile.am b/src/datastore/Makefile.am
index 44c5bbee4..9443e52be 100644
--- a/src/datastore/Makefile.am
+++ b/src/datastore/Makefile.am
@@ -100,6 +100,7 @@ libgnunet_plugin_datastore_sqlite_la_LDFLAGS = \
100libgnunet_plugin_datastore_mysql_la_SOURCES = \ 100libgnunet_plugin_datastore_mysql_la_SOURCES = \
101 plugin_datastore_mysql.c 101 plugin_datastore_mysql.c
102libgnunet_plugin_datastore_mysql_la_LIBADD = \ 102libgnunet_plugin_datastore_mysql_la_LIBADD = \
103 $(top_builddir)/src/mysql/libgnunetmysql.la \
103 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 104 $(top_builddir)/src/statistics/libgnunetstatistics.la \
104 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lz -lmysqlclient 105 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lz -lmysqlclient
105libgnunet_plugin_datastore_mysql_la_LDFLAGS = \ 106libgnunet_plugin_datastore_mysql_la_LDFLAGS = \
diff --git a/src/datastore/plugin_datastore_mysql.c b/src/datastore/plugin_datastore_mysql.c
index 76d6ad706..e2c77edd8 100644
--- a/src/datastore/plugin_datastore_mysql.c
+++ b/src/datastore/plugin_datastore_mysql.c
@@ -119,47 +119,12 @@
119#include "platform.h" 119#include "platform.h"
120#include "gnunet_datastore_plugin.h" 120#include "gnunet_datastore_plugin.h"
121#include "gnunet_util_lib.h" 121#include "gnunet_util_lib.h"
122#include <mysql/mysql.h> 122#include "gnunet_mysql_lib.h"
123 123
124#define DEBUG_MYSQL GNUNET_EXTRA_LOGGING 124#define DEBUG_MYSQL GNUNET_EXTRA_LOGGING
125 125
126#define MAX_DATUM_SIZE 65536 126#define MAX_DATUM_SIZE 65536
127 127
128/**
129 * Maximum number of supported parameters for a prepared
130 * statement. Increase if needed.
131 */
132#define MAX_PARAM 16
133
134/**
135 * Die with an error message that indicates
136 * a failure of the command 'cmd' with the message given
137 * by strerror(errno).
138 */
139#define DIE_MYSQL(cmd, dbh) do { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); GNUNET_abort(); } while(0);
140
141/**
142 * Log an error message at log-level 'level' that indicates
143 * a failure of the command 'cmd' on file 'filename'
144 * with the message given by strerror(errno).
145 */
146#define LOG_MYSQL(level, cmd, dbh) do { GNUNET_log(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); } while(0);
147
148
149struct GNUNET_MysqlStatementHandle
150{
151 struct GNUNET_MysqlStatementHandle *next;
152
153 struct GNUNET_MysqlStatementHandle *prev;
154
155 char *query;
156
157 MYSQL_STMT *statement;
158
159 int valid;
160
161};
162
163 128
164/** 129/**
165 * Context for all functions in this plugin. 130 * Context for all functions in this plugin.
@@ -174,64 +139,49 @@ struct Plugin
174 /** 139 /**
175 * Handle to talk to MySQL. 140 * Handle to talk to MySQL.
176 */ 141 */
177 MYSQL *dbf; 142 struct GNUNET_MYSQL_Context *mc;
178
179 /**
180 * We keep all prepared statements in a DLL. This is the head.
181 */
182 struct GNUNET_MysqlStatementHandle *shead;
183
184 /**
185 * We keep all prepared statements in a DLL. This is the tail.
186 */
187 struct GNUNET_MysqlStatementHandle *stail;
188
189 /**
190 * Filename of "my.cnf" (msyql configuration).
191 */
192 char *cnffile;
193 143
194 /** 144 /**
195 * Prepared statements. 145 * Prepared statements.
196 */ 146 */
197#define INSERT_ENTRY "INSERT INTO gn090 (repl,type,prio,anonLevel,expire,rvalue,hash,vhash,value) VALUES (?,?,?,?,?,?,?,?,?)" 147#define INSERT_ENTRY "INSERT INTO gn090 (repl,type,prio,anonLevel,expire,rvalue,hash,vhash,value) VALUES (?,?,?,?,?,?,?,?,?)"
198 struct GNUNET_MysqlStatementHandle *insert_entry; 148 struct GNUNET_MYSQL_StatementHandle *insert_entry;
199 149
200#define DELETE_ENTRY_BY_UID "DELETE FROM gn090 WHERE uid=?" 150#define DELETE_ENTRY_BY_UID "DELETE FROM gn090 WHERE uid=?"
201 struct GNUNET_MysqlStatementHandle *delete_entry_by_uid; 151 struct GNUNET_MYSQL_StatementHandle *delete_entry_by_uid;
202 152
203#define COUNT_ENTRY_BY_HASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash) WHERE hash=?" 153#define COUNT_ENTRY_BY_HASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash) WHERE hash=?"
204 struct GNUNET_MysqlStatementHandle *count_entry_by_hash; 154 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash;
205 155
206#define SELECT_ENTRY_BY_HASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash) WHERE hash=? ORDER BY uid LIMIT 1 OFFSET ?" 156#define SELECT_ENTRY_BY_HASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash) WHERE hash=? ORDER BY uid LIMIT 1 OFFSET ?"
207 struct GNUNET_MysqlStatementHandle *select_entry_by_hash; 157 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash;
208 158
209#define COUNT_ENTRY_BY_HASH_AND_VHASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=?" 159#define COUNT_ENTRY_BY_HASH_AND_VHASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=?"
210 struct GNUNET_MysqlStatementHandle *count_entry_by_hash_and_vhash; 160 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_and_vhash;
211 161
212#define SELECT_ENTRY_BY_HASH_AND_VHASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? ORDER BY uid LIMIT 1 OFFSET ?" 162#define SELECT_ENTRY_BY_HASH_AND_VHASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? ORDER BY uid LIMIT 1 OFFSET ?"
213 struct GNUNET_MysqlStatementHandle *select_entry_by_hash_and_vhash; 163 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_vhash;
214 164
215#define COUNT_ENTRY_BY_HASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=?" 165#define COUNT_ENTRY_BY_HASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=?"
216 struct GNUNET_MysqlStatementHandle *count_entry_by_hash_and_type; 166 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_and_type;
217 167
218#define SELECT_ENTRY_BY_HASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=? ORDER BY uid LIMIT 1 OFFSET ?" 168#define SELECT_ENTRY_BY_HASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=? ORDER BY uid LIMIT 1 OFFSET ?"
219 struct GNUNET_MysqlStatementHandle *select_entry_by_hash_and_type; 169 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_type;
220 170
221#define COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=?" 171#define COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=?"
222 struct GNUNET_MysqlStatementHandle *count_entry_by_hash_vhash_and_type; 172 struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_vhash_and_type;
223 173
224#define SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=? ORDER BY uid ASC LIMIT 1 OFFSET ?" 174#define SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=? ORDER BY uid ASC LIMIT 1 OFFSET ?"
225 struct GNUNET_MysqlStatementHandle *select_entry_by_hash_vhash_and_type; 175 struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_vhash_and_type;
226 176
227#define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE uid=?" 177#define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE uid=?"
228 struct GNUNET_MysqlStatementHandle *update_entry; 178 struct GNUNET_MYSQL_StatementHandle *update_entry;
229 179
230#define DEC_REPL "UPDATE gn090 SET repl=GREATEST (0, repl - 1) WHERE uid=?" 180#define DEC_REPL "UPDATE gn090 SET repl=GREATEST (0, repl - 1) WHERE uid=?"
231 struct GNUNET_MysqlStatementHandle *dec_repl; 181 struct GNUNET_MYSQL_StatementHandle *dec_repl;
232 182
233#define SELECT_SIZE "SELECT SUM(BIT_LENGTH(value) DIV 8) FROM gn090" 183#define SELECT_SIZE "SELECT SUM(BIT_LENGTH(value) DIV 8) FROM gn090"
234 struct GNUNET_MysqlStatementHandle *get_size; 184 struct GNUNET_MYSQL_StatementHandle *get_size;
235 185
236#define SELECT_IT_NON_ANONYMOUS "SELECT type,prio,anonLevel,expire,hash,value,uid "\ 186#define SELECT_IT_NON_ANONYMOUS "SELECT type,prio,anonLevel,expire,hash,value,uid "\
237 "FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) "\ 187 "FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) "\
@@ -239,13 +189,13 @@ struct Plugin
239 "(rvalue >= ? OR"\ 189 "(rvalue >= ? OR"\
240 " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) WHERE anonLevel=0 AND type=? AND rvalue>=?)) "\ 190 " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) WHERE anonLevel=0 AND type=? AND rvalue>=?)) "\
241 "ORDER BY rvalue ASC LIMIT 1" 191 "ORDER BY rvalue ASC LIMIT 1"
242 struct GNUNET_MysqlStatementHandle *zero_iter; 192 struct GNUNET_MYSQL_StatementHandle *zero_iter;
243 193
244#define SELECT_IT_EXPIRATION "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_expire) WHERE expire < ? ORDER BY expire ASC LIMIT 1" 194#define SELECT_IT_EXPIRATION "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_expire) WHERE expire < ? ORDER BY expire ASC LIMIT 1"
245 struct GNUNET_MysqlStatementHandle *select_expiration; 195 struct GNUNET_MYSQL_StatementHandle *select_expiration;
246 196
247#define SELECT_IT_PRIORITY "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_prio) ORDER BY prio ASC LIMIT 1" 197#define SELECT_IT_PRIORITY "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_prio) ORDER BY prio ASC LIMIT 1"
248 struct GNUNET_MysqlStatementHandle *select_priority; 198 struct GNUNET_MYSQL_StatementHandle *select_priority;
249 199
250#define SELECT_IT_REPLICATION "SELECT type,prio,anonLevel,expire,hash,value,uid "\ 200#define SELECT_IT_REPLICATION "SELECT type,prio,anonLevel,expire,hash,value,uid "\
251 "FROM gn090 FORCE INDEX (idx_repl_rvalue) "\ 201 "FROM gn090 FORCE INDEX (idx_repl_rvalue) "\
@@ -254,510 +204,15 @@ struct Plugin
254 " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_repl_rvalue) WHERE repl=? AND rvalue>=?)) "\ 204 " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_repl_rvalue) WHERE repl=? AND rvalue>=?)) "\
255 "ORDER BY rvalue ASC "\ 205 "ORDER BY rvalue ASC "\
256 "LIMIT 1" 206 "LIMIT 1"
257 struct GNUNET_MysqlStatementHandle *select_replication; 207 struct GNUNET_MYSQL_StatementHandle *select_replication;
258 208
259#define SELECT_MAX_REPL "SELECT MAX(repl) FROM gn090" 209#define SELECT_MAX_REPL "SELECT MAX(repl) FROM gn090"
260 struct GNUNET_MysqlStatementHandle *max_repl; 210 struct GNUNET_MYSQL_StatementHandle *max_repl;
261
262};
263
264
265/**
266 * Obtain the location of ".my.cnf".
267 *
268 * @param cfg our configuration
269 * @return NULL on error
270 */
271static char *
272get_my_cnf_path (const struct GNUNET_CONFIGURATION_Handle *cfg)
273{
274 char *cnffile;
275 char *home_dir;
276 struct stat st;
277
278#ifndef WINDOWS
279 struct passwd *pw;
280#endif
281 int configured;
282
283#ifndef WINDOWS
284 pw = getpwuid (getuid ());
285 if (!pw)
286 {
287 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "getpwuid");
288 return NULL;
289 }
290 if (GNUNET_YES ==
291 GNUNET_CONFIGURATION_have_value (cfg, "datastore-mysql", "CONFIG"))
292 {
293 GNUNET_assert (GNUNET_OK ==
294 GNUNET_CONFIGURATION_get_value_filename (cfg,
295 "datastore-mysql",
296 "CONFIG",
297 &cnffile));
298 configured = GNUNET_YES;
299 }
300 else
301 {
302 home_dir = GNUNET_strdup (pw->pw_dir);
303 GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir);
304 GNUNET_free (home_dir);
305 configured = GNUNET_NO;
306 }
307#else
308 home_dir = (char *) GNUNET_malloc (_MAX_PATH + 1);
309 plibc_conv_to_win_path ("~/", home_dir);
310 GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir);
311 GNUNET_free (home_dir);
312 configured = GNUNET_NO;
313#endif
314
315 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
316 _("Trying to use file `%s' for MySQL configuration.\n"), cnffile);
317 if ((0 != STAT (cnffile, &st)) || (0 != ACCESS (cnffile, R_OK)) ||
318 (!S_ISREG (st.st_mode)))
319 {
320 if (configured == GNUNET_YES)
321 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
322 _("Could not access file `%s': %s\n"), cnffile,
323 STRERROR (errno));
324 GNUNET_free (cnffile);
325 return NULL;
326 }
327 return cnffile;
328}
329
330
331/**
332 * Close database connection and all prepared statements (we got a DB
333 * disconnect error).
334 *
335 * @param plugin plugin context
336 */
337static int
338iclose (struct Plugin *plugin)
339{
340 struct GNUNET_MysqlStatementHandle *s;
341
342 for (s = plugin->shead; s != NULL; s = s->next)
343 {
344 if (s->valid)
345 {
346 mysql_stmt_close (s->statement);
347 s->valid = GNUNET_NO;
348 }
349 }
350 if (plugin->dbf != NULL)
351 {
352 mysql_close (plugin->dbf);
353 plugin->dbf = NULL;
354 }
355 return GNUNET_OK;
356}
357
358
359/**
360 * Open the connection with the database (and initialize
361 * our default options).
362 *
363 * @param plugin plugin context
364 * @return GNUNET_OK on success
365 */
366static int
367iopen (struct Plugin *plugin)
368{
369 char *mysql_dbname;
370 char *mysql_server;
371 char *mysql_user;
372 char *mysql_password;
373 unsigned long long mysql_port;
374 my_bool reconnect;
375 unsigned int timeout;
376
377 plugin->dbf = mysql_init (NULL);
378 if (plugin->dbf == NULL)
379 return GNUNET_SYSERR;
380 if (plugin->cnffile != NULL)
381 mysql_options (plugin->dbf, MYSQL_READ_DEFAULT_FILE, plugin->cnffile);
382 mysql_options (plugin->dbf, MYSQL_READ_DEFAULT_GROUP, "client");
383 reconnect = 0;
384 mysql_options (plugin->dbf, MYSQL_OPT_RECONNECT, &reconnect);
385 timeout = 120; /* in seconds */
386 mysql_options (plugin->dbf, MYSQL_OPT_CONNECT_TIMEOUT,
387 (const void *) &timeout);
388 mysql_options (plugin->dbf, MYSQL_SET_CHARSET_NAME, "UTF8");
389 timeout = 60; /* in seconds */
390 mysql_options (plugin->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);
391 mysql_options (plugin->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
392 mysql_dbname = NULL;
393 if (GNUNET_YES ==
394 GNUNET_CONFIGURATION_have_value (plugin->env->cfg, "datastore-mysql",
395 "DATABASE"))
396 GNUNET_assert (GNUNET_OK ==
397 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
398 "datastore-mysql",
399 "DATABASE",
400 &mysql_dbname));
401 else
402 mysql_dbname = GNUNET_strdup ("gnunet");
403 mysql_user = NULL;
404 if (GNUNET_YES ==
405 GNUNET_CONFIGURATION_have_value (plugin->env->cfg, "datastore-mysql",
406 "USER"))
407 {
408 GNUNET_assert (GNUNET_OK ==
409 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
410 "datastore-mysql",
411 "USER", &mysql_user));
412 }
413 mysql_password = NULL;
414 if (GNUNET_YES ==
415 GNUNET_CONFIGURATION_have_value (plugin->env->cfg, "datastore-mysql",
416 "PASSWORD"))
417 {
418 GNUNET_assert (GNUNET_OK ==
419 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
420 "datastore-mysql",
421 "PASSWORD",
422 &mysql_password));
423 }
424 mysql_server = NULL;
425 if (GNUNET_YES ==
426 GNUNET_CONFIGURATION_have_value (plugin->env->cfg, "datastore-mysql",
427 "HOST"))
428 {
429 GNUNET_assert (GNUNET_OK ==
430 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
431 "datastore-mysql",
432 "HOST",
433 &mysql_server));
434 }
435 mysql_port = 0;
436 if (GNUNET_YES ==
437 GNUNET_CONFIGURATION_have_value (plugin->env->cfg, "datastore-mysql",
438 "PORT"))
439 {
440 GNUNET_assert (GNUNET_OK ==
441 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg,
442 "datastore-mysql",
443 "PORT", &mysql_port));
444 }
445
446 GNUNET_assert (mysql_dbname != NULL);
447 mysql_real_connect (plugin->dbf, mysql_server, mysql_user, mysql_password,
448 mysql_dbname, (unsigned int) mysql_port, NULL,
449 CLIENT_IGNORE_SIGPIPE);
450 GNUNET_free_non_null (mysql_server);
451 GNUNET_free_non_null (mysql_user);
452 GNUNET_free_non_null (mysql_password);
453 GNUNET_free (mysql_dbname);
454 if (mysql_error (plugin->dbf)[0])
455 {
456 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_real_connect", plugin);
457 return GNUNET_SYSERR;
458 }
459 return GNUNET_OK;
460}
461
462
463/**
464 * Run the given MySQL statement.
465 *
466 * @param plugin plugin context
467 * @param statement SQL statement to run
468 * @return GNUNET_OK on success, GNUNET_SYSERR on error
469 */
470static int
471run_statement (struct Plugin *plugin, const char *statement)
472{
473 if ((NULL == plugin->dbf) && (GNUNET_OK != iopen (plugin)))
474 return GNUNET_SYSERR;
475 mysql_query (plugin->dbf, statement);
476 if (mysql_error (plugin->dbf)[0])
477 {
478 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_query", plugin);
479 iclose (plugin);
480 return GNUNET_SYSERR;
481 }
482 return GNUNET_OK;
483}
484 211
212#define GET_ALL_KEYS "SELECT hash from gn090"
213 struct GNUNET_MYSQL_StatementHandle *get_all_keys;
485 214
486/** 215};
487 * Create a prepared statement.
488 *
489 * @param plugin plugin context
490 * @param statement SQL statement text to prepare
491 * @return NULL on error
492 */
493static struct GNUNET_MysqlStatementHandle *
494prepared_statement_create (struct Plugin *plugin, const char *statement)
495{
496 struct GNUNET_MysqlStatementHandle *ret;
497
498 ret = GNUNET_malloc (sizeof (struct GNUNET_MysqlStatementHandle));
499 ret->query = GNUNET_strdup (statement);
500 GNUNET_CONTAINER_DLL_insert (plugin->shead, plugin->stail, ret);
501 return ret;
502}
503
504
505/**
506 * Prepare a statement for running.
507 *
508 * @param plugin plugin context
509 * @param ret handle to prepared statement
510 * @return GNUNET_OK on success
511 */
512static int
513prepare_statement (struct Plugin *plugin,
514 struct GNUNET_MysqlStatementHandle *ret)
515{
516 if (GNUNET_YES == ret->valid)
517 return GNUNET_OK;
518 if ((NULL == plugin->dbf) && (GNUNET_OK != iopen (plugin)))
519 return GNUNET_SYSERR;
520 ret->statement = mysql_stmt_init (plugin->dbf);
521 if (ret->statement == NULL)
522 {
523 iclose (plugin);
524 return GNUNET_SYSERR;
525 }
526 if (mysql_stmt_prepare (ret->statement, ret->query, strlen (ret->query)))
527 {
528 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql",
529 _("Failed to prepare statement `%s'\n"), ret->query);
530 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", plugin);
531 mysql_stmt_close (ret->statement);
532 ret->statement = NULL;
533 iclose (plugin);
534 return GNUNET_SYSERR;
535 }
536 ret->valid = GNUNET_YES;
537 return GNUNET_OK;
538
539}
540
541
542/**
543 * Bind the parameters for the given MySQL statement
544 * and run it.
545 *
546 * @param plugin plugin context
547 * @param s statement to bind and run
548 * @param ap arguments for the binding
549 * @return GNUNET_SYSERR on error, GNUNET_OK on success
550 */
551static int
552init_params (struct Plugin *plugin, struct GNUNET_MysqlStatementHandle *s,
553 va_list ap)
554{
555 MYSQL_BIND qbind[MAX_PARAM];
556 unsigned int pc;
557 unsigned int off;
558 enum enum_field_types ft;
559
560 pc = mysql_stmt_param_count (s->statement);
561 if (pc > MAX_PARAM)
562 {
563 /* increase internal constant! */
564 GNUNET_break (0);
565 return GNUNET_SYSERR;
566 }
567 memset (qbind, 0, sizeof (qbind));
568 off = 0;
569 ft = 0;
570 while ((pc > 0) && (-1 != (int) (ft = va_arg (ap, enum enum_field_types))))
571 {
572 qbind[off].buffer_type = ft;
573 switch (ft)
574 {
575 case MYSQL_TYPE_FLOAT:
576 qbind[off].buffer = va_arg (ap, float *);
577
578 break;
579 case MYSQL_TYPE_LONGLONG:
580 qbind[off].buffer = va_arg (ap, unsigned long long *);
581 qbind[off].is_unsigned = va_arg (ap, int);
582
583 break;
584 case MYSQL_TYPE_LONG:
585 qbind[off].buffer = va_arg (ap, unsigned int *);
586 qbind[off].is_unsigned = va_arg (ap, int);
587
588 break;
589 case MYSQL_TYPE_VAR_STRING:
590 case MYSQL_TYPE_STRING:
591 case MYSQL_TYPE_BLOB:
592 qbind[off].buffer = va_arg (ap, void *);
593 qbind[off].buffer_length = va_arg (ap, unsigned long);
594 qbind[off].length = va_arg (ap, unsigned long *);
595
596 break;
597 default:
598 /* unsupported type */
599 GNUNET_break (0);
600 return GNUNET_SYSERR;
601 }
602 pc--;
603 off++;
604 }
605 if (!((pc == 0) && (-1 != (int) ft) && (va_arg (ap, int) == -1)))
606 {
607 GNUNET_assert (0);
608 return GNUNET_SYSERR;
609 }
610 if (mysql_stmt_bind_param (s->statement, qbind))
611 {
612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
613 _("`%s' failed at %s:%d with error: %s\n"),
614 "mysql_stmt_bind_param", __FILE__, __LINE__,
615 mysql_stmt_error (s->statement));
616 iclose (plugin);
617 return GNUNET_SYSERR;
618 }
619 if (mysql_stmt_execute (s->statement))
620 {
621 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
622 _("`%s' for `%s' failed at %s:%d with error: %s\n"),
623 "mysql_stmt_execute", s->query, __FILE__, __LINE__,
624 mysql_stmt_error (s->statement));
625 iclose (plugin);
626 return GNUNET_SYSERR;
627 }
628 return GNUNET_OK;
629}
630
631
632/**
633 * Run a prepared SELECT statement.
634 *
635 * @param plugin plugin context
636 * @param s statement to run
637 * @param result_size number of elements in results array
638 * @param results pointer to already initialized MYSQL_BIND
639 * array (of sufficient size) for passing results
640 * @param ap pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
641 * values (size + buffer-reference for pointers); terminated
642 * with "-1"
643 * @return GNUNET_SYSERR on error, otherwise GNUNET_OK or GNUNET_NO (no result)
644 */
645static int
646prepared_statement_run_select_va (struct Plugin *plugin,
647 struct GNUNET_MysqlStatementHandle *s,
648 unsigned int result_size,
649 MYSQL_BIND * results, va_list ap)
650{
651 int ret;
652 unsigned int rsize;
653
654 if (GNUNET_OK != prepare_statement (plugin, s))
655 {
656 GNUNET_break (0);
657 return GNUNET_SYSERR;
658 }
659 if (GNUNET_OK != init_params (plugin, s, ap))
660 {
661 GNUNET_break (0);
662 return GNUNET_SYSERR;
663 }
664 rsize = mysql_stmt_field_count (s->statement);
665 if (rsize > result_size)
666 {
667 GNUNET_break (0);
668 return GNUNET_SYSERR;
669 }
670 if (mysql_stmt_bind_result (s->statement, results))
671 {
672 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
673 _("`%s' failed at %s:%d with error: %s\n"),
674 "mysql_stmt_bind_result", __FILE__, __LINE__,
675 mysql_stmt_error (s->statement));
676 iclose (plugin);
677 return GNUNET_SYSERR;
678 }
679 ret = mysql_stmt_fetch (s->statement);
680 if (ret == MYSQL_NO_DATA)
681 return GNUNET_NO;
682 if (ret != 0)
683 {
684 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
685 _("`%s' failed at %s:%d with error: %s\n"), "mysql_stmt_fetch",
686 __FILE__, __LINE__, mysql_stmt_error (s->statement));
687 iclose (plugin);
688 return GNUNET_SYSERR;
689 }
690 mysql_stmt_reset (s->statement);
691 return GNUNET_OK;
692}
693
694
695/**
696 * Run a prepared SELECT statement.
697 *
698 * @param plugin plugin context
699 * @param s statement to run
700 * @param result_size number of elements in results array
701 * @param results pointer to already initialized MYSQL_BIND
702 * array (of sufficient size) for passing results
703 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
704 * values (size + buffer-reference for pointers); terminated
705 * with "-1"
706 * @return GNUNET_SYSERR on error, otherwise
707 * the number of successfully affected (or queried) rows
708 */
709static int
710prepared_statement_run_select (struct Plugin *plugin,
711 struct GNUNET_MysqlStatementHandle *s,
712 unsigned int result_size, MYSQL_BIND * results,
713 ...)
714{
715 va_list ap;
716 int ret;
717
718 va_start (ap, results);
719 ret = prepared_statement_run_select_va (plugin, s, result_size, results, ap);
720 va_end (ap);
721 return ret;
722}
723
724
725/**
726 * Run a prepared statement that does NOT produce results.
727 *
728 * @param plugin plugin context
729 * @param s statement to run
730 * @param insert_id NULL or address where to store the row ID of whatever
731 * was inserted (only for INSERT statements!)
732 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
733 * values (size + buffer-reference for pointers); terminated
734 * with "-1"
735 * @return GNUNET_SYSERR on error, otherwise
736 * the number of successfully affected rows
737 */
738static int
739prepared_statement_run (struct Plugin *plugin,
740 struct GNUNET_MysqlStatementHandle *s,
741 unsigned long long *insert_id, ...)
742{
743 va_list ap;
744 int affected;
745
746 if (GNUNET_OK != prepare_statement (plugin, s))
747 return GNUNET_SYSERR;
748 va_start (ap, insert_id);
749 if (GNUNET_OK != init_params (plugin, s, ap))
750 {
751 va_end (ap);
752 return GNUNET_SYSERR;
753 }
754 va_end (ap);
755 affected = mysql_stmt_affected_rows (s->statement);
756 if (NULL != insert_id)
757 *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement);
758 mysql_stmt_reset (s->statement);
759 return affected;
760}
761 216
762 217
763/** 218/**
@@ -776,9 +231,9 @@ do_delete_entry (struct Plugin *plugin, unsigned long long uid)
776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting value %llu from gn090 table\n", 231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting value %llu from gn090 table\n",
777 uid); 232 uid);
778#endif 233#endif
779 ret = 234 ret = GNUNET_MYSQL_statement_run_prepared (plugin->mc,
780 prepared_statement_run (plugin, plugin->delete_entry_by_uid, NULL, 235 plugin->delete_entry_by_uid, NULL,
781 MYSQL_TYPE_LONGLONG, &uid, GNUNET_YES, -1); 236 MYSQL_TYPE_LONGLONG, &uid, GNUNET_YES, -1);
782 if (ret >= 0) 237 if (ret >= 0)
783 return GNUNET_OK; 238 return GNUNET_OK;
784 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 239 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
@@ -807,7 +262,7 @@ mysql_plugin_estimate_size (void *cls)
807 cbind[0].buffer = &total; 262 cbind[0].buffer = &total;
808 cbind[0].is_unsigned = GNUNET_NO; 263 cbind[0].is_unsigned = GNUNET_NO;
809 if (GNUNET_OK != 264 if (GNUNET_OK !=
810 prepared_statement_run_select (plugin, plugin->get_size, 1, cbind, -1)) 265 GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->get_size, 1, cbind, NULL, NULL, -1))
811 return 0; 266 return 0;
812 return total; 267 return total;
813} 268}
@@ -857,7 +312,7 @@ mysql_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size,
857 lsize = size; 312 lsize = size;
858 GNUNET_CRYPTO_hash (data, size, &vhash); 313 GNUNET_CRYPTO_hash (data, size, &vhash);
859 if (GNUNET_OK != 314 if (GNUNET_OK !=
860 prepared_statement_run (plugin, plugin->insert_entry, NULL, 315 GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->insert_entry, NULL,
861 MYSQL_TYPE_LONG, &irepl, GNUNET_YES, 316 MYSQL_TYPE_LONG, &irepl, GNUNET_YES,
862 MYSQL_TYPE_LONG, &type, GNUNET_YES, 317 MYSQL_TYPE_LONG, &type, GNUNET_YES,
863 MYSQL_TYPE_LONG, &ipriority, GNUNET_YES, 318 MYSQL_TYPE_LONG, &ipriority, GNUNET_YES,
@@ -917,8 +372,8 @@ mysql_plugin_update (void *cls, uint64_t uid, int delta,
917 vkey, delta, lexpire); 372 vkey, delta, lexpire);
918#endif 373#endif
919 ret = 374 ret =
920 prepared_statement_run (plugin, plugin->update_entry, NULL, 375 GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->update_entry, NULL,
921 MYSQL_TYPE_LONG, &delta, GNUNET_NO, 376 MYSQL_TYPE_LONG, &delta, GNUNET_NO,
922 MYSQL_TYPE_LONGLONG, &lexpire, GNUNET_YES, 377 MYSQL_TYPE_LONGLONG, &lexpire, GNUNET_YES,
923 MYSQL_TYPE_LONGLONG, &lexpire, GNUNET_YES, 378 MYSQL_TYPE_LONGLONG, &lexpire, GNUNET_YES,
924 MYSQL_TYPE_LONGLONG, &vkey, GNUNET_YES, -1); 379 MYSQL_TYPE_LONGLONG, &vkey, GNUNET_YES, -1);
@@ -942,7 +397,7 @@ mysql_plugin_update (void *cls, uint64_t uid, int delta,
942 * @param ... arguments to initialize stmt 397 * @param ... arguments to initialize stmt
943 */ 398 */
944static void 399static void
945execute_select (struct Plugin *plugin, struct GNUNET_MysqlStatementHandle *stmt, 400execute_select (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt,
946 PluginDatumProcessor proc, void *proc_cls, ...) 401 PluginDatumProcessor proc, void *proc_cls, ...)
947{ 402{
948 va_list ap; 403 va_list ap;
@@ -986,7 +441,7 @@ execute_select (struct Plugin *plugin, struct GNUNET_MysqlStatementHandle *stmt,
986 rbind[6].is_unsigned = 1; 441 rbind[6].is_unsigned = 1;
987 442
988 va_start (ap, proc_cls); 443 va_start (ap, proc_cls);
989 ret = prepared_statement_run_select_va (plugin, stmt, 7, rbind, ap); 444 ret = GNUNET_MYSQL_statement_run_prepared_select_va (plugin->mc, stmt, 7, rbind, NULL, NULL, ap);
990 va_end (ap); 445 va_end (ap);
991 if (ret <= 0) 446 if (ret <= 0)
992 { 447 {
@@ -1067,10 +522,10 @@ mysql_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key,
1067 if (vhash != NULL) 522 if (vhash != NULL)
1068 { 523 {
1069 ret = 524 ret =
1070 prepared_statement_run_select (plugin, 525 GNUNET_MYSQL_statement_run_prepared_select (plugin->mc,
1071 plugin-> 526 plugin->
1072 count_entry_by_hash_vhash_and_type, 1, 527 count_entry_by_hash_vhash_and_type, 1,
1073 cbind, MYSQL_TYPE_BLOB, key, hashSize, 528 cbind, NULL, NULL, MYSQL_TYPE_BLOB, key, hashSize,
1074 &hashSize, MYSQL_TYPE_BLOB, vhash, 529 &hashSize, MYSQL_TYPE_BLOB, vhash,
1075 hashSize2, &hashSize2, MYSQL_TYPE_LONG, 530 hashSize2, &hashSize2, MYSQL_TYPE_LONG,
1076 &type, GNUNET_YES, -1); 531 &type, GNUNET_YES, -1);
@@ -1078,9 +533,9 @@ mysql_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key,
1078 else 533 else
1079 { 534 {
1080 ret = 535 ret =
1081 prepared_statement_run_select (plugin, 536 GNUNET_MYSQL_statement_run_prepared_select (plugin->mc,
1082 plugin->count_entry_by_hash_and_type, 537 plugin->count_entry_by_hash_and_type,
1083 1, cbind, MYSQL_TYPE_BLOB, key, 538 1, cbind, NULL, NULL, MYSQL_TYPE_BLOB, key,
1084 hashSize, &hashSize, MYSQL_TYPE_LONG, 539 hashSize, &hashSize, MYSQL_TYPE_LONG,
1085 &type, GNUNET_YES, -1); 540 &type, GNUNET_YES, -1);
1086 } 541 }
@@ -1090,9 +545,9 @@ mysql_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key,
1090 if (vhash != NULL) 545 if (vhash != NULL)
1091 { 546 {
1092 ret = 547 ret =
1093 prepared_statement_run_select (plugin, 548 GNUNET_MYSQL_statement_run_prepared_select (plugin->mc,
1094 plugin->count_entry_by_hash_and_vhash, 549 plugin->count_entry_by_hash_and_vhash,
1095 1, cbind, MYSQL_TYPE_BLOB, key, 550 1, cbind, NULL, NULL, MYSQL_TYPE_BLOB, key,
1096 hashSize, &hashSize, MYSQL_TYPE_BLOB, 551 hashSize, &hashSize, MYSQL_TYPE_BLOB,
1097 vhash, hashSize2, &hashSize2, -1); 552 vhash, hashSize2, &hashSize2, -1);
1098 553
@@ -1100,8 +555,8 @@ mysql_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key,
1100 else 555 else
1101 { 556 {
1102 ret = 557 ret =
1103 prepared_statement_run_select (plugin, plugin->count_entry_by_hash, 1, 558 GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->count_entry_by_hash, 1,
1104 cbind, MYSQL_TYPE_BLOB, key, hashSize, 559 cbind, NULL, NULL, MYSQL_TYPE_BLOB, key, hashSize,
1105 &hashSize, -1); 560 &hashSize, -1);
1106 } 561 }
1107 } 562 }
@@ -1244,8 +699,8 @@ repl_proc (void *cls, const GNUNET_HashCode * key, uint32_t size,
1244 { 699 {
1245 oid = (unsigned long long) uid; 700 oid = (unsigned long long) uid;
1246 iret = 701 iret =
1247 prepared_statement_run (plugin, plugin->dec_repl, NULL, 702 GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->dec_repl, NULL,
1248 MYSQL_TYPE_LONGLONG, &oid, GNUNET_YES, -1); 703 MYSQL_TYPE_LONGLONG, &oid, GNUNET_YES, -1);
1249 if (iret == GNUNET_SYSERR) 704 if (iret == GNUNET_SYSERR)
1250 { 705 {
1251 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 706 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
@@ -1287,7 +742,7 @@ mysql_plugin_get_replication (void *cls, PluginDatumProcessor proc,
1287 results.is_unsigned = GNUNET_YES; 742 results.is_unsigned = GNUNET_YES;
1288 743
1289 if (1 != 744 if (1 !=
1290 prepared_statement_run_select (plugin, plugin->max_repl, 1, &results, -1)) 745 GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->max_repl, 1, &results, NULL, NULL, -1))
1291 { 746 {
1292 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 747 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1293 return; 748 return;
@@ -1324,19 +779,18 @@ mysql_plugin_get_keys (void *cls,
1324 MYSQL_BIND cbind[1]; 779 MYSQL_BIND cbind[1];
1325 unsigned long length; 780 unsigned long length;
1326 781
1327 statement = mysql_stmt_init (plugin->dbf); 782 statement = GNUNET_MYSQL_statement_get_stmt (plugin->mc,
783 plugin->get_all_keys);
1328 if (statement == NULL) 784 if (statement == NULL)
1329 { 785 {
1330 iclose (plugin); 786 GNUNET_MYSQL_statements_invalidate (plugin->mc);
1331 return; 787 return;
1332 } 788 }
1333 if (mysql_stmt_prepare (statement, query, strlen (query))) 789 if (mysql_stmt_prepare (statement, query, strlen (query)))
1334 { 790 {
1335 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql", 791 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql",
1336 _("Failed to prepare statement `%s'\n"), query); 792 _("Failed to prepare statement `%s'\n"), query);
1337 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", plugin); 793 GNUNET_MYSQL_statements_invalidate (plugin->mc);
1338 mysql_stmt_close (statement);
1339 iclose (plugin);
1340 return; 794 return;
1341 } 795 }
1342 GNUNET_assert (proc != NULL); 796 GNUNET_assert (proc != NULL);
@@ -1346,8 +800,7 @@ mysql_plugin_get_keys (void *cls,
1346 _("`%s' for `%s' failed at %s:%d with error: %s\n"), 800 _("`%s' for `%s' failed at %s:%d with error: %s\n"),
1347 "mysql_stmt_execute", query, __FILE__, __LINE__, 801 "mysql_stmt_execute", query, __FILE__, __LINE__,
1348 mysql_stmt_error (statement)); 802 mysql_stmt_error (statement));
1349 mysql_stmt_close (statement); 803 GNUNET_MYSQL_statements_invalidate (plugin->mc);
1350 iclose (plugin);
1351 return; 804 return;
1352 } 805 }
1353 memset (cbind, 0, sizeof (cbind)); 806 memset (cbind, 0, sizeof (cbind));
@@ -1362,7 +815,7 @@ mysql_plugin_get_keys (void *cls,
1362 _("`%s' failed at %s:%d with error: %s\n"), 815 _("`%s' failed at %s:%d with error: %s\n"),
1363 "mysql_stmt_bind_result", __FILE__, __LINE__, 816 "mysql_stmt_bind_result", __FILE__, __LINE__,
1364 mysql_stmt_error (statement)); 817 mysql_stmt_error (statement));
1365 iclose (plugin); 818 GNUNET_MYSQL_statements_invalidate (plugin->mc);
1366 return; 819 return;
1367 } 820 }
1368 while (0 == (ret = mysql_stmt_fetch (statement))) 821 while (0 == (ret = mysql_stmt_fetch (statement)))
@@ -1376,11 +829,10 @@ mysql_plugin_get_keys (void *cls,
1376 _("`%s' failed at %s:%d with error: %s\n"), 829 _("`%s' failed at %s:%d with error: %s\n"),
1377 "mysql_stmt_fetch", __FILE__, __LINE__, 830 "mysql_stmt_fetch", __FILE__, __LINE__,
1378 mysql_stmt_error (statement)); 831 mysql_stmt_error (statement));
1379 mysql_stmt_close (statement); 832 GNUNET_MYSQL_statements_invalidate (plugin->mc);
1380 iclose (plugin);
1381 return; 833 return;
1382 } 834 }
1383 mysql_stmt_close (statement); 835 mysql_stmt_reset (statement);
1384} 836}
1385 837
1386 838
@@ -1484,7 +936,7 @@ mysql_plugin_drop (void *cls)
1484{ 936{
1485 struct Plugin *plugin = cls; 937 struct Plugin *plugin = cls;
1486 938
1487 if (GNUNET_OK != run_statement (plugin, "DROP TABLE gn090")) 939 if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "DROP TABLE gn090"))
1488 return; /* error */ 940 return; /* error */
1489 plugin->env->duc (plugin->env->cls, 0); 941 plugin->env->duc (plugin->env->cls, 0);
1490} 942}
@@ -1505,16 +957,14 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
1505 957
1506 plugin = GNUNET_malloc (sizeof (struct Plugin)); 958 plugin = GNUNET_malloc (sizeof (struct Plugin));
1507 plugin->env = env; 959 plugin->env = env;
1508 plugin->cnffile = get_my_cnf_path (env->cfg); 960 plugin->mc = GNUNET_MYSQL_context_create (env->cfg, "datastore-mysql");
1509 if (GNUNET_OK != iopen (plugin)) 961 if (NULL == plugin->mc)
1510 { 962 {
1511 iclose (plugin);
1512 GNUNET_free_non_null (plugin->cnffile);
1513 GNUNET_free (plugin); 963 GNUNET_free (plugin);
1514 return NULL; 964 return NULL;
1515 } 965 }
1516#define MRUNS(a) (GNUNET_OK != run_statement (plugin, a) ) 966#define MRUNS(a) (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, a) )
1517#define PINIT(a,b) (NULL == (a = prepared_statement_create(plugin, b))) 967#define PINIT(a,b) (NULL == (a = GNUNET_MYSQL_statement_prepare (plugin->mc, b)))
1518 if (MRUNS 968 if (MRUNS
1519 ("CREATE TABLE IF NOT EXISTS gn090 (" 969 ("CREATE TABLE IF NOT EXISTS gn090 ("
1520 " repl INT(11) UNSIGNED NOT NULL DEFAULT 0," 970 " repl INT(11) UNSIGNED NOT NULL DEFAULT 0,"
@@ -1556,10 +1006,10 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
1556 PINIT (plugin->select_expiration, SELECT_IT_EXPIRATION) || 1006 PINIT (plugin->select_expiration, SELECT_IT_EXPIRATION) ||
1557 PINIT (plugin->select_priority, SELECT_IT_PRIORITY) || 1007 PINIT (plugin->select_priority, SELECT_IT_PRIORITY) ||
1558 PINIT (plugin->max_repl, SELECT_MAX_REPL) || 1008 PINIT (plugin->max_repl, SELECT_MAX_REPL) ||
1009 PINIT (plugin->get_all_keys, GET_ALL_KEYS) ||
1559 PINIT (plugin->select_replication, SELECT_IT_REPLICATION)) 1010 PINIT (plugin->select_replication, SELECT_IT_REPLICATION))
1560 { 1011 {
1561 iclose (plugin); 1012 GNUNET_MYSQL_context_destroy (plugin->mc);
1562 GNUNET_free_non_null (plugin->cnffile);
1563 GNUNET_free (plugin); 1013 GNUNET_free (plugin);
1564 return NULL; 1014 return NULL;
1565 } 1015 }
@@ -1593,19 +1043,10 @@ libgnunet_plugin_datastore_mysql_done (void *cls)
1593{ 1043{
1594 struct GNUNET_DATASTORE_PluginFunctions *api = cls; 1044 struct GNUNET_DATASTORE_PluginFunctions *api = cls;
1595 struct Plugin *plugin = api->cls; 1045 struct Plugin *plugin = api->cls;
1596 struct GNUNET_MysqlStatementHandle *s;
1597 1046
1598 iclose (plugin); 1047 GNUNET_MYSQL_context_destroy (plugin->mc);
1599 while (NULL != (s = plugin->shead))
1600 {
1601 GNUNET_CONTAINER_DLL_remove (plugin->shead, plugin->stail, s);
1602 GNUNET_free (s->query);
1603 GNUNET_free (s);
1604 }
1605 GNUNET_free_non_null (plugin->cnffile);
1606 GNUNET_free (plugin); 1048 GNUNET_free (plugin);
1607 GNUNET_free (api); 1049 GNUNET_free (api);
1608 mysql_library_end ();
1609 return NULL; 1050 return NULL;
1610} 1051}
1611 1052
diff --git a/src/include/gnunet_mysql_lib.h b/src/include/gnunet_mysql_lib.h
index 678b7669d..c232a0065 100644
--- a/src/include/gnunet_mysql_lib.h
+++ b/src/include/gnunet_mysql_lib.h
@@ -86,6 +86,31 @@ GNUNET_MYSQL_context_destroy (struct GNUNET_MYSQL_Context *mc);
86 86
87 87
88/** 88/**
89 * Close database connection and all prepared statements (we got a DB
90 * error). The connection will automatically be re-opened and
91 * statements will be re-prepared if they are needed again later.
92 *
93 * @param mc mysql context
94 */
95void
96GNUNET_MYSQL_statements_invalidate (struct GNUNET_MYSQL_Context *mc);
97
98
99/**
100 * Get internal handle for a prepared statement. This function should rarely
101 * be used, and if, with caution! On failures during the interaction with
102 * the handle, you must call 'GNUNET_MYSQL_statements_invalidate'!
103 *
104 * @param mc mysql context
105 * @param sh prepared statement to introspect
106 * @return MySQL statement handle, NULL on error
107 */
108MYSQL_STMT *
109GNUNET_MYSQL_statement_get_stmt (struct GNUNET_MYSQL_Context *mc,
110 struct GNUNET_MYSQL_StatementHandle *sh);
111
112
113/**
89 * Prepare a statement. Prepared statements are automatically discarded 114 * Prepare a statement. Prepared statements are automatically discarded
90 * when the MySQL context is destroyed. 115 * when the MySQL context is destroyed.
91 * 116 *
@@ -136,6 +161,30 @@ GNUNET_MYSQL_statement_run_prepared_select (struct GNUNET_MYSQL_Context *mc,
136 161
137 162
138/** 163/**
164 * Run a prepared SELECT statement.
165 *
166 * @param mc mysql context
167 * @param s statement to run
168 * @param result_size number of elements in results array
169 * @param results pointer to already initialized MYSQL_BIND
170 * array (of sufficient size) for passing results
171 * @param ap pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
172 * values (size + buffer-reference for pointers); terminated
173 * with "-1"
174 * @return GNUNET_SYSERR on error, otherwise
175 * the number of successfully affected (or queried) rows
176 */
177int
178GNUNET_MYSQL_statement_run_prepared_select_va (struct GNUNET_MYSQL_Context *mc,
179 struct GNUNET_MYSQL_StatementHandle *s,
180 unsigned int result_size,
181 MYSQL_BIND * results,
182 GNUNET_MYSQL_DataProcessor processor,
183 void *processor_cls,
184 va_list ap);
185
186
187/**
139 * Run a prepared statement that does NOT produce results. 188 * Run a prepared statement that does NOT produce results.
140 * 189 *
141 * @param mc mysql context 190 * @param mc mysql context
diff --git a/src/mysql/mysql.c b/src/mysql/mysql.c
index 1c3166dc7..67d2e63d2 100644
--- a/src/mysql/mysql.c
+++ b/src/mysql/mysql.c
@@ -315,12 +315,12 @@ GNUNET_MYSQL_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
315 315
316/** 316/**
317 * Close database connection and all prepared statements (we got a DB 317 * Close database connection and all prepared statements (we got a DB
318 * disconnect error). 318 * error).
319 * 319 *
320 * @param mc mysql context 320 * @param mc mysql context
321 */ 321 */
322static void 322void
323iclose (struct GNUNET_MYSQL_Context *mc) 323GNUNET_MYSQL_statements_invalidate (struct GNUNET_MYSQL_Context *mc)
324{ 324{
325 struct GNUNET_MYSQL_StatementHandle *sh; 325 struct GNUNET_MYSQL_StatementHandle *sh;
326 326
@@ -351,7 +351,7 @@ GNUNET_MYSQL_context_destroy (struct GNUNET_MYSQL_Context *mc)
351{ 351{
352 struct GNUNET_MYSQL_StatementHandle *sh; 352 struct GNUNET_MYSQL_StatementHandle *sh;
353 353
354 iclose (mc); 354 GNUNET_MYSQL_statements_invalidate (mc);
355 while (NULL != (sh = mc->shead)) 355 while (NULL != (sh = mc->shead))
356 { 356 {
357 GNUNET_CONTAINER_DLL_remove (mc->shead, mc->stail, sh); 357 GNUNET_CONTAINER_DLL_remove (mc->shead, mc->stail, sh);
@@ -402,7 +402,7 @@ GNUNET_MYSQL_statement_run (struct GNUNET_MYSQL_Context *mc,
402 if (mysql_error (mc->dbf)[0]) 402 if (mysql_error (mc->dbf)[0])
403 { 403 {
404 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_query", mc); 404 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_query", mc);
405 iclose (mc); 405 GNUNET_MYSQL_statements_invalidate (mc);
406 return GNUNET_SYSERR; 406 return GNUNET_SYSERR;
407 } 407 }
408 return GNUNET_OK; 408 return GNUNET_OK;
@@ -427,7 +427,7 @@ prepare_statement (struct GNUNET_MYSQL_Context *mc,
427 sh->statement = mysql_stmt_init (mc->dbf); 427 sh->statement = mysql_stmt_init (mc->dbf);
428 if (NULL == sh->statement) 428 if (NULL == sh->statement)
429 { 429 {
430 iclose (mc); 430 GNUNET_MYSQL_statements_invalidate (mc);
431 return GNUNET_SYSERR; 431 return GNUNET_SYSERR;
432 } 432 }
433 if (0 != mysql_stmt_prepare (sh->statement, sh->query, strlen (sh->query))) 433 if (0 != mysql_stmt_prepare (sh->statement, sh->query, strlen (sh->query)))
@@ -435,7 +435,7 @@ prepare_statement (struct GNUNET_MYSQL_Context *mc,
435 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", mc); 435 LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", mc);
436 mysql_stmt_close (sh->statement); 436 mysql_stmt_close (sh->statement);
437 sh->statement = NULL; 437 sh->statement = NULL;
438 iclose (mc); 438 GNUNET_MYSQL_statements_invalidate (mc);
439 return GNUNET_SYSERR; 439 return GNUNET_SYSERR;
440 } 440 }
441 sh->valid = GNUNET_YES; 441 sh->valid = GNUNET_YES;
@@ -444,6 +444,24 @@ prepare_statement (struct GNUNET_MYSQL_Context *mc,
444 444
445 445
446/** 446/**
447 * Get internal handle for a prepared statement. This function should rarely
448 * be used, and if, with caution! On failures during the interaction with
449 * the handle, you must call 'GNUNET_MYSQL_statements_invalidate'!
450 *
451 * @param mc mysql context
452 * @param sh prepared statement to introspect
453 * @return MySQL statement handle, NULL on error
454 */
455MYSQL_STMT *
456GNUNET_MYSQL_statement_get_stmt (struct GNUNET_MYSQL_Context *mc,
457 struct GNUNET_MYSQL_StatementHandle *sh)
458{
459 (void) prepare_statement (mc, sh);
460 return sh->statement;
461}
462
463
464/**
447 * Bind the parameters for the given MySQL statement 465 * Bind the parameters for the given MySQL statement
448 * and run it. 466 * and run it.
449 * 467 *
@@ -519,7 +537,7 @@ init_params (struct GNUNET_MYSQL_Context *mc,
519 _("`%s' failed at %s:%d with error: %s\n"), 537 _("`%s' failed at %s:%d with error: %s\n"),
520 "mysql_stmt_bind_param", __FILE__, __LINE__, 538 "mysql_stmt_bind_param", __FILE__, __LINE__,
521 mysql_stmt_error (sh->statement)); 539 mysql_stmt_error (sh->statement));
522 iclose (mc); 540 GNUNET_MYSQL_statements_invalidate (mc);
523 return GNUNET_SYSERR; 541 return GNUNET_SYSERR;
524 } 542 }
525 if (mysql_stmt_execute (sh->statement)) 543 if (mysql_stmt_execute (sh->statement))
@@ -529,75 +547,71 @@ init_params (struct GNUNET_MYSQL_Context *mc,
529 _("`%s' failed at %s:%d with error: %s\n"), 547 _("`%s' failed at %s:%d with error: %s\n"),
530 "mysql_stmt_execute", __FILE__, __LINE__, 548 "mysql_stmt_execute", __FILE__, __LINE__,
531 mysql_stmt_error (sh->statement)); 549 mysql_stmt_error (sh->statement));
532 iclose (mc); 550 GNUNET_MYSQL_statements_invalidate (mc);
533 return GNUNET_SYSERR; 551 return GNUNET_SYSERR;
534 } 552 }
535 return GNUNET_OK; 553 return GNUNET_OK;
536} 554}
537 555
538 556
557
539/** 558/**
540 * Run a prepared SELECT statement. 559 * Run a prepared SELECT statement.
541 * 560 *
542 * @param mc mysql context 561 * @param mc mysql context
543 * @param sh handle to SELECT statment 562 * @param s statement to run
544 * @param result_size number of elements in results array 563 * @param result_size number of elements in results array
545 * @param results pointer to already initialized MYSQL_BIND 564 * @param results pointer to already initialized MYSQL_BIND
546 * array (of sufficient size) for passing results 565 * array (of sufficient size) for passing results
547 * @param processor function to call on each result 566 * @param ap pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
548 * @param processor_cls extra argument to processor
549 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
550 * values (size + buffer-reference for pointers); terminated 567 * values (size + buffer-reference for pointers); terminated
551 * with "-1" 568 * with "-1"
552 * @return GNUNET_SYSERR on error, otherwise 569 * @return GNUNET_SYSERR on error, otherwise
553 * the number of successfully affected (or queried) rows 570 * the number of successfully affected (or queried) rows
554 */ 571 */
555int 572int
556GNUNET_MYSQL_statement_run_prepared_select (struct GNUNET_MYSQL_Context *mc, 573GNUNET_MYSQL_statement_run_prepared_select_va (struct GNUNET_MYSQL_Context *mc,
557 struct GNUNET_MYSQL_StatementHandle *sh, 574 struct GNUNET_MYSQL_StatementHandle *s,
558 unsigned int result_size, MYSQL_BIND * results, 575 unsigned int result_size,
559 GNUNET_MYSQL_DataProcessor processor, 576 MYSQL_BIND * results,
560 void *processor_cls, ...) 577 GNUNET_MYSQL_DataProcessor processor,
578 void *processor_cls,
579 va_list ap)
561{ 580{
562 va_list ap;
563 int ret; 581 int ret;
564 unsigned int rsize; 582 unsigned int rsize;
565 int total; 583 int total;
566 584
567 if (GNUNET_OK != prepare_statement (mc, sh)) 585 if (GNUNET_OK != prepare_statement (mc, s))
568 { 586 {
569 GNUNET_break (0); 587 GNUNET_break (0);
570 return GNUNET_SYSERR; 588 return GNUNET_SYSERR;
571 } 589 }
572 va_start (ap, processor_cls); 590 if (GNUNET_OK != init_params (mc, s, ap))
573 if (GNUNET_OK != init_params (mc, sh, ap))
574 { 591 {
575 GNUNET_break (0); 592 GNUNET_break (0);
576 va_end (ap);
577 return GNUNET_SYSERR; 593 return GNUNET_SYSERR;
578 } 594 }
579 va_end (ap); 595 rsize = mysql_stmt_field_count (s->statement);
580 rsize = mysql_stmt_field_count (sh->statement);
581 if (rsize > result_size) 596 if (rsize > result_size)
582 { 597 {
583 GNUNET_break (0); 598 GNUNET_break (0);
584 return GNUNET_SYSERR; 599 return GNUNET_SYSERR;
585 } 600 }
586 if (mysql_stmt_bind_result (sh->statement, results)) 601 if (mysql_stmt_bind_result (s->statement, results))
587 { 602 {
588 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, 603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
589 "mysql", 604 _("`%s' failed at %s:%d with error: %s\n"),
590 _("`%s' failed at %s:%d with error: %s\n"), 605 "mysql_stmt_bind_result", __FILE__, __LINE__,
591 "mysql_stmt_bind_result", __FILE__, __LINE__, 606 mysql_stmt_error (s->statement));
592 mysql_stmt_error (sh->statement)); 607 GNUNET_MYSQL_statements_invalidate (mc);
593 iclose (mc);
594 return GNUNET_SYSERR; 608 return GNUNET_SYSERR;
595 } 609 }
596 610
597 total = 0; 611 total = 0;
598 while (1) 612 while (1)
599 { 613 {
600 ret = mysql_stmt_fetch (sh->statement); 614 ret = mysql_stmt_fetch (s->statement);
601 if (ret == MYSQL_NO_DATA) 615 if (ret == MYSQL_NO_DATA)
602 break; 616 break;
603 if (ret != 0) 617 if (ret != 0)
@@ -606,21 +620,54 @@ GNUNET_MYSQL_statement_run_prepared_select (struct GNUNET_MYSQL_Context *mc,
606 "mysql", 620 "mysql",
607 _("`%s' failed at %s:%d with error: %s\n"), 621 _("`%s' failed at %s:%d with error: %s\n"),
608 "mysql_stmt_fetch", __FILE__, __LINE__, 622 "mysql_stmt_fetch", __FILE__, __LINE__,
609 mysql_stmt_error (sh->statement)); 623 mysql_stmt_error (s->statement));
610 iclose (mc); 624 GNUNET_MYSQL_statements_invalidate (mc);
611 return GNUNET_SYSERR; 625 return GNUNET_SYSERR;
612 } 626 }
613 if (processor != NULL)
614 if (GNUNET_OK != processor (processor_cls, rsize, results))
615 break;
616 total++; 627 total++;
628 if ( (NULL == processor) ||
629 (GNUNET_OK != processor (processor_cls, rsize, results)) )
630 break;
617 } 631 }
618 mysql_stmt_reset (sh->statement); 632 mysql_stmt_reset (s->statement);
619 return total; 633 return total;
620} 634}
621 635
622 636
623/** 637/**
638 * Run a prepared SELECT statement.
639 *
640 * @param mc mysql context
641 * @param sh handle to SELECT statment
642 * @param result_size number of elements in results array
643 * @param results pointer to already initialized MYSQL_BIND
644 * array (of sufficient size) for passing results
645 * @param processor function to call on each result
646 * @param processor_cls extra argument to processor
647 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
648 * values (size + buffer-reference for pointers); terminated
649 * with "-1"
650 * @return GNUNET_SYSERR on error, otherwise
651 * the number of successfully affected (or queried) rows
652 */
653int
654GNUNET_MYSQL_statement_run_prepared_select (struct GNUNET_MYSQL_Context *mc,
655 struct GNUNET_MYSQL_StatementHandle *sh,
656 unsigned int result_size, MYSQL_BIND * results,
657 GNUNET_MYSQL_DataProcessor processor,
658 void *processor_cls, ...)
659{
660 va_list ap;
661 int ret;
662
663 va_start (ap, processor_cls);
664 ret = GNUNET_MYSQL_statement_run_prepared_select_va (mc, sh, result_size, results, processor, processor_cls, ap);
665 va_end (ap);
666 return ret;
667}
668
669
670/**
624 * Run a prepared statement that does NOT produce results. 671 * Run a prepared statement that does NOT produce results.
625 * 672 *
626 * @param mc mysql context 673 * @param mc mysql context