driver-mysql.c revision 3656c91dcb8336814bebd4500e81c3dde25233e6
/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "sql-api-private.h"
#ifdef BUILD_MYSQL
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <mysql.h>
#include <errmsg.h>
/* Abort connect() if it can't connect within this time. */
#define MYSQL_CONNECT_FAILURE_TIMEOUT 10
/* Minimum delay between reconnecting to same server */
#define CONNECT_MIN_DELAY 1
/* Maximum time to avoiding reconnecting to same server */
/* If no servers are connected but a query is requested, try reconnecting to
next server which has been disconnected longer than this (with a single
server setup this is really the "max delay" and the CONNECT_MAX_DELAY
is never used). */
#define CONNECT_RESET_DELAY 15
struct mysql_db {
const char *option_file, *option_group;
unsigned int port, client_flags;
unsigned int next_query_connection;
};
struct mysql_connection {
const char *host;
unsigned int connect_delay;
unsigned int connect_failure_count;
unsigned int connected:1;
unsigned int ssl_set:1;
};
struct mysql_result {
struct sql_result api;
struct mysql_connection *conn;
unsigned int fields_count;
};
struct mysql_transaction_context {
struct sql_transaction_context ctx;
const char *error;
unsigned int failed:1;
};
struct mysql_query_list {
struct mysql_query_list *next;
const char *query;
};
extern struct sql_db driver_mysql_db;
extern struct sql_result driver_mysql_result;
extern struct sql_result driver_mysql_error_result;
{
const char *unix_socket, *host;
bool failed;
return TRUE;
/* don't try reconnecting more than once a second */
return FALSE;
} else {
unix_socket = NULL;
}
db->option_file);
}
#ifdef HAVE_MYSQL_SSL
#ifdef HAVE_MYSQL_SSL_CIPHER
, db->ssl_cipher
#endif
);
#else
i_fatal("mysql: SSL support not compiled in "
"(remove ssl_ca and ssl_ca_path settings)");
#endif
}
alarm(0);
if (failed) {
if (conn->connect_failure_count > 0) {
/* increase delay between reconnections to this
server */
}
i_error("mysql: Connect failed to %s (%s): %s - "
"waiting for %u seconds before retry",
return FALSE;
} else {
i_info("mysql: Connected to %s%s (%s)",
conn->connect_failure_count = 0;
return TRUE;
}
}
{
struct mysql_connection *conn;
unsigned int i, count;
int ret = -1;
for (i = 0; i < count; i++) {
if (driver_mysql_connect(&conn[i]))
ret = 1;
}
return ret;
}
{
struct mysql_connection *conn;
i_fatal("mysql_init() failed");
}
{
}
const char *connect_string)
{
const char **field;
i_fatal("mysql: Missing value in connect string: %s",
*args);
}
value++;
else
}
i_fatal("mysql: No hosts given in connect string");
}
{
T_BEGIN {
} T_END;
}
{
struct mysql_connection *conn;
unsigned int i, count;
for (i = 0; i < count; i++)
(void)driver_mysql_connection_free(&conn[i]);
}
static enum sql_db_flags
{
return SQL_DB_FLAG_BLOCKING;
}
const char *query)
{
int i;
for (i = 0; i < 2; i++) {
if (!driver_mysql_connect(conn))
return 0;
return 1;
/* failed */
case CR_SERVER_GONE_ERROR:
case CR_SERVER_LOST:
/* connection lost - try immediate reconnect */
break;
default:
return -1;
}
}
/* connected -> lost it -> connected -> lost again */
return 0;
}
struct mysql_connection **conn_r)
{
struct mysql_connection *conn;
bool reset;
int ret;
/* go through the connections in round robin. if the connection
isn't available, try next one that is. */
i = start;
do {
if (ret != 0) {
/* success / failure */
return ret;
}
/* not connected, try next one */
i = (i + 1) % count;
} while (i != start);
if (reset)
break;
/* none are connected. connect_delays may have gotten too high,
reset all of them to see if some are still alive. */
for (i = 0; i < count; i++)
}
return 0;
}
static const char *
{
struct mysql_connection *conn;
unsigned int i, count;
char *to;
/* All the connections should be identical, so just use the first
connected one */
for (i = 0; i < count; i++) {
break;
}
if (i == count) {
/* so, try connecting.. */
for (i = 0; i < count; i++) {
if (driver_mysql_connect(&conn[i]))
break;
}
if (i == count) {
/* FIXME: we don't have a valid connection, so fallback
to using default escaping. the next query will most
likely fail anyway so it shouldn't matter that much
what we return here.. Anyway, this API needs
changing so that the escaping function could already
fail the query reliably. */
return to;
}
}
return to;
}
{
struct mysql_connection *conn;
}
{
struct sql_result *result;
}
static struct sql_result *
{
struct mysql_connection *conn;
struct mysql_result *result;
case 0:
/* not connected */
break;
case 1:
/* query ok */
break;
/* fallback */
case -1:
/* error */
break;
}
}
{
return;
}
{
/* no results */
return 0;
}
return 1;
}
{
return;
}
static unsigned int
{
return result->fields_count;
}
static const char *
{
}
const char *field_name)
{
unsigned int i;
for (i = 0; i < result->fields_count; i++) {
return i;
}
return -1;
}
static const char *
unsigned int idx)
{
}
static const unsigned char *
unsigned int idx ATTR_UNUSED,
{
/* FIXME */
return NULL;
}
static const char *
const char *field_name)
{
int idx;
if (idx < 0)
return NULL;
}
static const char *const *
{
}
{
}
static struct sql_transaction_context *
{
struct mysql_transaction_context *ctx;
}
static void
{
const char *error;
else
}
const char *query)
{
struct sql_result *result;
int ret = 0;
return -1;
if (sql_result_next_row(result) < 0) {
ret = -1;
}
return ret;
}
static int
const char **error_r)
{
struct mysql_transaction_context *ctx =
(struct mysql_transaction_context *)_ctx;
int ret = 0;
/* try to use a transaction in any case,
even if it doesn't work. */
break;
}
}
return ret;
}
static void
{
struct mysql_transaction_context *ctx =
(struct mysql_transaction_context *)_ctx;
}
static void
{
struct mysql_transaction_context *ctx =
(struct mysql_transaction_context *)_ctx;
struct mysql_query_list *list;
else
}
struct sql_db driver_mysql_db = {
"mysql",
MEMBER(v) {
}
};
struct sql_result driver_mysql_result = {
MEMBER(v) {
}
};
static int
{
return -1;
}
struct sql_result driver_mysql_error_result = {
MEMBER(v) {
}
};
void driver_mysql_init(void);
void driver_mysql_deinit(void);
void driver_mysql_init(void)
{
}
void driver_mysql_deinit(void)
{
}
#endif