/*
This file is part of GNUnet
- (C) 2012 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2012 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
*/
/**
* @file mysql/mysql.c
* a failure of the command 'cmd' with the message given
* by strerror(errno).
*/
-#define DIE_MYSQL(cmd, dbh) do { GNUNET_log_from (GNUNET_ERROR_TYPE__ERROR, "mysql", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); GNUNET_abort(); } while(0);
+#define DIE_MYSQL(cmd, dbh) do { GNUNET_log_from (GNUNET_ERROR_TYPE__ERROR, "mysql", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); GNUNET_assert (0); } while(0);
/**
* Log an error message at log-level 'level' that indicates
*/
struct GNUNET_MYSQL_Context
{
-
+
/**
* Our configuration.
*/
const struct GNUNET_CONFIGURATION_Handle *cfg;
-
+
/**
* Our section.
*/
* Obtain the location of ".my.cnf".
*
* @param cfg our configuration
+ * @param section the section
* @return NULL on error
*/
static char *
get_my_cnf_path (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *section)
+ const char *section)
{
char *cnffile;
char *home_dir;
GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_ERROR, "mysql", "getpwuid");
return NULL;
}
- if (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (cfg, section, "CONFIG"))
+ if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, section, "CONFIG"))
{
GNUNET_assert (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- section,
+ GNUNET_CONFIGURATION_get_value_filename (cfg, section,
"CONFIG",
&cnffile));
configured = GNUNET_YES;
GNUNET_free (home_dir);
configured = GNUNET_NO;
#endif
- GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
- "mysql",
- _("Trying to use file `%s' for MySQL configuration.\n"), cnffile);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "mysql",
+ _("Trying to use file `%s' for MySQL configuration.\n"),
+ cnffile);
if ((0 != STAT (cnffile, &st)) || (0 != ACCESS (cnffile, R_OK)) ||
(!S_ISREG (st.st_mode)))
{
if (configured == GNUNET_YES)
- GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
- "mysql",
- _("Could not access file `%s': %s\n"), cnffile,
- STRERROR (errno));
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql",
+ _("Could not access file `%s': %s\n"), cnffile,
+ STRERROR (errno));
GNUNET_free (cnffile);
return NULL;
}
mysql_options (mc->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
mysql_dbname = NULL;
if (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section,
- "DATABASE"))
+ GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "DATABASE"))
GNUNET_assert (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (mc->cfg,
- mc->section,
+ GNUNET_CONFIGURATION_get_value_string (mc->cfg, mc->section,
"DATABASE",
&mysql_dbname));
else
mysql_dbname = GNUNET_strdup ("gnunet");
mysql_user = NULL;
if (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section,
- "USER"))
+ GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "USER"))
{
GNUNET_assert (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (mc->cfg,
- mc->section,
+ GNUNET_CONFIGURATION_get_value_string (mc->cfg, mc->section,
"USER", &mysql_user));
}
mysql_password = NULL;
if (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section,
- "PASSWORD"))
+ GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "PASSWORD"))
{
GNUNET_assert (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (mc->cfg,
- mc->section,
+ GNUNET_CONFIGURATION_get_value_string (mc->cfg, mc->section,
"PASSWORD",
&mysql_password));
}
mysql_server = NULL;
if (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section,
- "HOST"))
+ GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "HOST"))
{
GNUNET_assert (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (mc->cfg,
- mc->section,
+ GNUNET_CONFIGURATION_get_value_string (mc->cfg, mc->section,
"HOST",
&mysql_server));
}
mysql_port = 0;
if (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section,
- "PORT"))
+ GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "PORT"))
{
GNUNET_assert (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_number (mc->cfg,
- mc->section,
+ GNUNET_CONFIGURATION_get_value_number (mc->cfg, mc->section,
"PORT", &mysql_port));
}
*/
struct GNUNET_MYSQL_Context *
GNUNET_MYSQL_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *section)
+ const char *section)
{
struct GNUNET_MYSQL_Context *mc;
- mc = GNUNET_malloc (sizeof (struct GNUNET_MYSQL_Context));
+ mc = GNUNET_new (struct GNUNET_MYSQL_Context);
mc->cfg = cfg;
mc->section = section;
mc->cnffile = get_my_cnf_path (cfg, section);
-
+
return mc;
}
/**
* Close database connection and all prepared statements (we got a DB
- * disconnect error).
+ * error).
*
* @param mc mysql context
*/
-static void
-iclose (struct GNUNET_MYSQL_Context *mc)
+void
+GNUNET_MYSQL_statements_invalidate (struct GNUNET_MYSQL_Context *mc)
{
struct GNUNET_MYSQL_StatementHandle *sh;
/**
* Destroy a mysql context. Also frees all associated prepared statements.
- *
+ *
* @param mc context to destroy
*/
void
{
struct GNUNET_MYSQL_StatementHandle *sh;
- iclose (mc);
+ GNUNET_MYSQL_statements_invalidate (mc);
while (NULL != (sh = mc->shead))
{
GNUNET_CONTAINER_DLL_remove (mc->shead, mc->stail, sh);
*/
struct GNUNET_MYSQL_StatementHandle *
GNUNET_MYSQL_statement_prepare (struct GNUNET_MYSQL_Context *mc,
- const char *query)
+ const char *query)
{
struct GNUNET_MYSQL_StatementHandle *sh;
- sh = GNUNET_malloc (sizeof (struct GNUNET_MYSQL_StatementHandle));
+ sh = GNUNET_new (struct GNUNET_MYSQL_StatementHandle);
sh->query = GNUNET_strdup (query);
GNUNET_CONTAINER_DLL_insert (mc->shead, mc->stail, sh);
return sh;
* GNUNET_SYSERR if there was a problem
*/
int
-GNUNET_MYSQL_statement_run (struct GNUNET_MYSQL_Context *mc,
- const char *sql)
+GNUNET_MYSQL_statement_run (struct GNUNET_MYSQL_Context *mc, const char *sql)
{
if ((NULL == mc->dbf) && (GNUNET_OK != iopen (mc)))
return GNUNET_SYSERR;
if (mysql_error (mc->dbf)[0])
{
LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_query", mc);
- iclose (mc);
+ GNUNET_MYSQL_statements_invalidate (mc);
return GNUNET_SYSERR;
}
return GNUNET_OK;
sh->statement = mysql_stmt_init (mc->dbf);
if (NULL == sh->statement)
{
- iclose (mc);
+ GNUNET_MYSQL_statements_invalidate (mc);
return GNUNET_SYSERR;
}
if (0 != mysql_stmt_prepare (sh->statement, sh->query, strlen (sh->query)))
LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", mc);
mysql_stmt_close (sh->statement);
sh->statement = NULL;
- iclose (mc);
+ GNUNET_MYSQL_statements_invalidate (mc);
return GNUNET_SYSERR;
}
sh->valid = GNUNET_YES;
}
+/**
+ * Get internal handle for a prepared statement. This function should rarely
+ * be used, and if, with caution! On failures during the interaction with
+ * the handle, you must call 'GNUNET_MYSQL_statements_invalidate'!
+ *
+ * @param mc mysql context
+ * @param sh prepared statement to introspect
+ * @return MySQL statement handle, NULL on error
+ */
+MYSQL_STMT *
+GNUNET_MYSQL_statement_get_stmt (struct GNUNET_MYSQL_Context * mc,
+ struct GNUNET_MYSQL_StatementHandle * sh)
+{
+ (void) prepare_statement (mc, sh);
+ return sh->statement;
+}
+
+
/**
* Bind the parameters for the given MySQL statement
* and run it.
* @return GNUNET_SYSERR on error, GNUNET_OK on success
*/
static int
-init_params (struct GNUNET_MYSQL_Context *mc,
- struct GNUNET_MYSQL_StatementHandle *sh,
- va_list ap)
+init_params (struct GNUNET_MYSQL_Context *mc,
+ struct GNUNET_MYSQL_StatementHandle *sh, va_list ap)
{
MYSQL_BIND qbind[MAX_PARAM];
unsigned int pc;
}
if (mysql_stmt_bind_param (sh->statement, qbind))
{
- GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
- "mysql",
- _("`%s' failed at %s:%d with error: %s\n"),
- "mysql_stmt_bind_param", __FILE__, __LINE__,
- mysql_stmt_error (sh->statement));
- iclose (mc);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql",
+ _("`%s' failed at %s:%d with error: %s\n"),
+ "mysql_stmt_bind_param", __FILE__, __LINE__,
+ mysql_stmt_error (sh->statement));
+ GNUNET_MYSQL_statements_invalidate (mc);
return GNUNET_SYSERR;
}
if (mysql_stmt_execute (sh->statement))
{
- GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
- "mysql",
- _("`%s' failed at %s:%d with error: %s\n"),
- "mysql_stmt_execute", __FILE__, __LINE__,
- mysql_stmt_error (sh->statement));
- iclose (mc);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql",
+ _("`%s' failed at %s:%d with error: %s\n"),
+ "mysql_stmt_execute", __FILE__, __LINE__,
+ mysql_stmt_error (sh->statement));
+ GNUNET_MYSQL_statements_invalidate (mc);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
+
/**
* Run a prepared SELECT statement.
*
* @param mc mysql context
- * @param sh handle to SELECT statment
+ * @param s statement to run
* @param result_size number of elements in results array
* @param results pointer to already initialized MYSQL_BIND
* array (of sufficient size) for passing results
* @param processor function to call on each result
* @param processor_cls extra argument to processor
- * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
+ * @param ap pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
* values (size + buffer-reference for pointers); terminated
* with "-1"
* @return GNUNET_SYSERR on error, otherwise
* the number of successfully affected (or queried) rows
*/
int
-GNUNET_MYSQL_statement_run_prepared_select (struct GNUNET_MYSQL_Context *mc,
- struct GNUNET_MYSQL_StatementHandle *sh,
- unsigned int result_size, MYSQL_BIND * results,
- GNUNET_MYSQL_DataProcessor processor,
- void *processor_cls, ...)
+GNUNET_MYSQL_statement_run_prepared_select_va (struct GNUNET_MYSQL_Context *mc,
+ struct
+ GNUNET_MYSQL_StatementHandle *s,
+ unsigned int result_size,
+ MYSQL_BIND * results,
+ GNUNET_MYSQL_DataProcessor
+ processor, void *processor_cls,
+ va_list ap)
{
- va_list ap;
int ret;
unsigned int rsize;
int total;
- if (GNUNET_OK != prepare_statement (mc, sh))
+ if (GNUNET_OK != prepare_statement (mc, s))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
- va_start (ap, processor_cls);
- if (GNUNET_OK != init_params (mc, sh, ap))
+ if (GNUNET_OK != init_params (mc, s, ap))
{
GNUNET_break (0);
- va_end (ap);
return GNUNET_SYSERR;
}
- va_end (ap);
- rsize = mysql_stmt_field_count (sh->statement);
+ rsize = mysql_stmt_field_count (s->statement);
if (rsize > result_size)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
- if (mysql_stmt_bind_result (sh->statement, results))
+ if (mysql_stmt_bind_result (s->statement, results))
{
- GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
- "mysql",
- _("`%s' failed at %s:%d with error: %s\n"),
- "mysql_stmt_bind_result", __FILE__, __LINE__,
- mysql_stmt_error (sh->statement));
- iclose (mc);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("`%s' failed at %s:%d with error: %s\n"),
+ "mysql_stmt_bind_result", __FILE__, __LINE__,
+ mysql_stmt_error (s->statement));
+ GNUNET_MYSQL_statements_invalidate (mc);
return GNUNET_SYSERR;
}
total = 0;
while (1)
{
- ret = mysql_stmt_fetch (sh->statement);
+ ret = mysql_stmt_fetch (s->statement);
if (ret == MYSQL_NO_DATA)
break;
if (ret != 0)
{
- GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
- "mysql",
- _("`%s' failed at %s:%d with error: %s\n"),
- "mysql_stmt_fetch", __FILE__, __LINE__,
- mysql_stmt_error (sh->statement));
- iclose (mc);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql",
+ _("`%s' failed at %s:%d with error: %s\n"),
+ "mysql_stmt_fetch", __FILE__, __LINE__,
+ mysql_stmt_error (s->statement));
+ GNUNET_MYSQL_statements_invalidate (mc);
return GNUNET_SYSERR;
}
- if (processor != NULL)
- if (GNUNET_OK != processor (processor_cls, rsize, results))
- break;
total++;
+ if ((NULL == processor) ||
+ (GNUNET_OK != processor (processor_cls, rsize, results)))
+ break;
}
- mysql_stmt_reset (sh->statement);
+ mysql_stmt_reset (s->statement);
return total;
}
+/**
+ * Run a prepared SELECT statement.
+ *
+ * @param mc mysql context
+ * @param sh handle to SELECT statment
+ * @param result_size number of elements in results array
+ * @param results pointer to already initialized MYSQL_BIND
+ * array (of sufficient size) for passing results
+ * @param processor function to call on each result
+ * @param processor_cls extra argument to processor
+ * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
+ * values (size + buffer-reference for pointers); terminated
+ * with "-1"
+ * @return GNUNET_SYSERR on error, otherwise
+ * the number of successfully affected (or queried) rows
+ */
+int
+GNUNET_MYSQL_statement_run_prepared_select (struct GNUNET_MYSQL_Context *mc,
+ struct GNUNET_MYSQL_StatementHandle
+ *sh, unsigned int result_size,
+ MYSQL_BIND * results,
+ GNUNET_MYSQL_DataProcessor
+ processor, void *processor_cls, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start (ap, processor_cls);
+ ret =
+ GNUNET_MYSQL_statement_run_prepared_select_va (mc, sh, result_size,
+ results, processor,
+ processor_cls, ap);
+ va_end (ap);
+ return ret;
+}
+
+
/**
* Run a prepared statement that does NOT produce results.
*
*/
int
GNUNET_MYSQL_statement_run_prepared (struct GNUNET_MYSQL_Context *mc,
- struct GNUNET_MYSQL_StatementHandle *sh,
- unsigned long long *insert_id, ...)
+ struct GNUNET_MYSQL_StatementHandle *sh,
+ unsigned long long *insert_id, ...)
{
va_list ap;
int affected;
/* end of mysql.c */
-