driver-mysql.c revision f635aa2fd6c47ec297cf68981203a8dc7f8a23c3
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek/* Copyright (c) 2003-2011 Dovecot authors, see the included COPYING file */
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#include "lib.h"
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#include "ioloop.h"
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#include "array.h"
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#include "str.h"
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#include "sql-api-private.h"
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#ifdef BUILD_MYSQL
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#include <stdlib.h>
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#include <unistd.h>
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#include <time.h>
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#include <mysql.h>
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#include <errmsg.h>
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstruct mysql_db {
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek struct sql_db api;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek pool_t pool;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek const char *user, *password, *dbname, *host, *unix_socket;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek const char *ssl_cert, *ssl_key, *ssl_ca, *ssl_ca_path, *ssl_cipher;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek const char *option_file, *option_group;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek unsigned int port, client_flags;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek MYSQL *mysql;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek unsigned int next_query_connection;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek unsigned int ssl_set:1;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek};
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstruct mysql_result {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct sql_result api;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose MYSQL_RES *result;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose MYSQL_ROW row;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek MYSQL_FIELD *fields;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek unsigned int fields_count;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek my_ulonglong affected_rows;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek};
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstruct mysql_transaction_context {
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek struct sql_transaction_context ctx;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek pool_t query_pool;
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik const char *error;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek unsigned int failed:1;
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik};
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekextern const struct sql_db driver_mysql_db;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekextern const struct sql_result driver_mysql_result;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekextern const struct sql_result driver_mysql_error_result;
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekstatic const char *mysql_prefix(struct mysql_db *db)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek{
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek return t_strdup_printf("mysql(%s)", db->host);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic int driver_mysql_connect(struct sql_db *_db)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_db *db = (struct mysql_db *)_db;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose const char *unix_socket, *host;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose unsigned long client_flags = db->client_flags;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek unsigned int secs_used;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek bool failed;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_assert(db->api.state == SQL_DB_STATE_DISCONNECTED);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose sql_db_set_state(&db->api, SQL_DB_STATE_CONNECTING);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (*db->host == '/') {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose unix_socket = db->host;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose host = NULL;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose } else {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose unix_socket = NULL;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose host = db->host;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (db->option_file != NULL) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_options(db->mysql, MYSQL_READ_DEFAULT_FILE,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->option_file);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_options(db->mysql, MYSQL_READ_DEFAULT_GROUP,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->option_group != NULL ? db->option_group : "client");
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (!db->ssl_set && (db->ssl_ca != NULL || db->ssl_ca_path != NULL)) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose#ifdef HAVE_MYSQL_SSL
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_ssl_set(db->mysql, db->ssl_key, db->ssl_cert,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->ssl_ca, db->ssl_ca_path
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose#ifdef HAVE_MYSQL_SSL_CIPHER
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose , db->ssl_cipher
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose#endif
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose );
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->ssl_set = TRUE;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose#else
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_fatal("mysql: SSL support not compiled in "
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose "(remove ssl_ca and ssl_ca_path settings)");
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose#endif
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose alarm(SQL_CONNECT_TIMEOUT_SECS);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose#ifdef CLIENT_MULTI_RESULTS
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose client_flags |= CLIENT_MULTI_RESULTS;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose#endif
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* CLIENT_MULTI_RESULTS allows the use of stored procedures */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose failed = mysql_real_connect(db->mysql, host, db->user, db->password,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->dbname, db->port, unix_socket,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose client_flags) == NULL;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose secs_used = SQL_CONNECT_TIMEOUT_SECS - alarm(0);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (failed) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* connecting could have taken a while. make sure that any
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose timeouts that get added soon will get a refreshed
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose timestamp. */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose io_loop_time_refresh();
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (db->api.connect_delay < secs_used)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->api.connect_delay = secs_used;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_error("%s: Connect failed to database (%s): %s - "
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose "waiting for %u seconds before retry",
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_prefix(db), db->dbname,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_error(db->mysql), db->api.connect_delay);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return -1;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose } else {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_info("%s: Connected to database %s%s", mysql_prefix(db),
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->dbname, db->ssl_set ? " using SSL" : "");
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose sql_db_set_state(&db->api, SQL_DB_STATE_IDLE);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return 1;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_disconnect(struct sql_db *_db ATTR_UNUSED)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_parse_connect_string(struct mysql_db *db,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose const char *connect_string)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose const char *const *args, *name, *value;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose const char **field;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->ssl_cipher = "HIGH";
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose args = t_strsplit_spaces(connect_string, " ");
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose for (; *args != NULL; args++) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose value = strchr(*args, '=');
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (value == NULL) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_fatal("mysql: Missing value in connect string: %s",
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose *args);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose name = t_strdup_until(*args, value);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose value++;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = NULL;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (strcmp(name, "host") == 0 ||
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose strcmp(name, "hostaddr") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->host;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "user") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->user;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "password") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->password;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "dbname") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->dbname;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "port") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->port = atoi(value);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "client_flags") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->client_flags = atoi(value);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "ssl_cert") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->ssl_cert;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "ssl_key") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->ssl_key;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "ssl_ca") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->ssl_ca;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "ssl_ca_path") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->ssl_ca_path;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "ssl_cipher") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->ssl_cipher;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "option_file") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->option_file;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else if (strcmp(name, "option_group") == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose field = &db->option_group;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_fatal("mysql: Unknown connect string: %s", name);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (field != NULL)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose *field = p_strdup(db->pool, value);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (db->host == NULL)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_fatal("mysql: No hosts given in connect string");
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->mysql = mysql_init(NULL);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (db->mysql == NULL)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_fatal("mysql_init() failed");
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic struct sql_db *driver_mysql_init_v(const char *connect_string)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_db *db;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose pool_t pool;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose pool = pool_alloconly_create("mysql driver", 1024);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db = p_new(pool, struct mysql_db, 1);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->pool = pool;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->api = driver_mysql_db;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose T_BEGIN {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose driver_mysql_parse_connect_string(db, connect_string);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose } T_END;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return &db->api;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_deinit_v(struct sql_db *_db)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_db *db = (struct mysql_db *)_db;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose _db->no_reconnect = TRUE;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_close(db->mysql);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose array_free(&_db->module_contexts);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose pool_unref(&db->pool);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic int driver_mysql_do_query(struct mysql_db *db, const char *query)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (mysql_query(db->mysql, query) == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return 0;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* failed */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose switch (mysql_errno(db->mysql)) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose case CR_SERVER_GONE_ERROR:
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose case CR_SERVER_LOST:
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose break;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose default:
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose break;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return -1;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic const char *
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosedriver_mysql_escape_string(struct sql_db *_db, const char *string)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_db *db = (struct mysql_db *)_db;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose size_t len = strlen(string);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose char *to;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (_db->state == SQL_DB_STATE_DISCONNECTED) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* try connecting */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose (void)sql_connect(&db->api);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (db->mysql == NULL) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* FIXME: we don't have a valid connection, so fallback
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose to using default escaping. the next query will most
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose likely fail anyway so it shouldn't matter that much
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose what we return here.. Anyway, this API needs
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose changing so that the escaping function could already
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose fail the query reliably. */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose to = t_buffer_get(len * 2 + 1);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose len = mysql_escape_string(to, string, len);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose t_buffer_alloc(len + 1);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return to;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose to = t_buffer_get(len * 2 + 1);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose len = mysql_real_escape_string(db->mysql, to, string, len);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose t_buffer_alloc(len + 1);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return to;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_exec(struct sql_db *_db, const char *query)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_db *db = (struct mysql_db *)_db;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (driver_mysql_do_query(db, query) < 0) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_error("%s: Query '%s' failed: %s",
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_prefix(db), query, mysql_error(db->mysql));
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_query(struct sql_db *db, const char *query,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose sql_query_callback_t *callback, void *context)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct sql_result *result;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result = sql_query_s(db, query);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->callback = TRUE;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose callback(result, context);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->callback = FALSE;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose sql_result_unref(result);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic struct sql_result *
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosedriver_mysql_query_s(struct sql_db *_db, const char *query)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_db *db = (struct mysql_db *)_db;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_result *result;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose int ret;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result = i_new(struct mysql_result, 1);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->api = driver_mysql_result;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (driver_mysql_do_query(db, query) < 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->api = driver_mysql_error_result;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose else {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* query ok */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->affected_rows = mysql_affected_rows(db->mysql);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->result = mysql_store_result(db->mysql);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose#ifdef CLIENT_MULTI_RESULTS
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* Because we've enabled CLIENT_MULTI_RESULTS, we need to read
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose (ignore) extra results - there should not be any.
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose ret is: -1 = done, >0 = error, 0 = more results. */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose while ((ret = mysql_next_result(db->mysql)) == 0) ;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose#else
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose ret = -1;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose#endif
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (ret < 0 &&
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose (result->result != NULL || mysql_errno(db->mysql) == 0)) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* ok */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose } else {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* failed */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (result->result != NULL)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_free_result(result->result);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->api = driver_mysql_error_result;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->api.db = _db;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->api.refcount = 1;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return &result->api;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_result_free(struct sql_result *_result)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_result *result = (struct mysql_result *)_result;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_assert(_result != &sql_not_connected_result);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (_result->callback)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (result->result != NULL)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_free_result(result->result);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_free(result);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic int driver_mysql_result_next_row(struct sql_result *_result)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_result *result = (struct mysql_result *)_result;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_db *db = (struct mysql_db *)_result->db;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (result->result == NULL) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* no results */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return 0;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose }
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->row = mysql_fetch_row(result->result);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (result->row != NULL)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return 1;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return mysql_errno(db->mysql) != 0 ? -1 : 0;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_result_fetch_fields(struct mysql_result *result)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose{
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (result->fields != NULL)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->fields_count = mysql_num_fields(result->result);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->fields = mysql_fetch_fields(result->result);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose}
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekstatic unsigned int
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekdriver_mysql_result_get_fields_count(struct sql_result *_result)
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek{
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek driver_mysql_result_fetch_fields(result);
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek return result->fields_count;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek}
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstatic const char *
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekdriver_mysql_result_get_field_name(struct sql_result *_result, unsigned int idx)
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek{
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek driver_mysql_result_fetch_fields(result);
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek i_assert(idx < result->fields_count);
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek return result->fields[idx].name;
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek}
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek
933314e53fac878d1a9b126af216454172cb945aJakub Hrozekstatic int driver_mysql_result_find_field(struct sql_result *_result,
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek const char *field_name)
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek{
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek unsigned int i;
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek driver_mysql_result_fetch_fields(result);
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek for (i = 0; i < result->fields_count; i++) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (strcmp(result->fields[i].name, field_name) == 0)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose return i;
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek }
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek return -1;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek}
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstatic const char *
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekdriver_mysql_result_get_field_value(struct sql_result *_result,
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik unsigned int idx)
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik{
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek return (const char *)result->row[idx];
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek}
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstatic const unsigned char *
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekdriver_mysql_result_get_field_value_binary(struct sql_result *_result,
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek unsigned int idx, size_t *size_r)
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek{
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek unsigned long *lengths;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek lengths = mysql_fetch_lengths(result->result);
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek *size_r = lengths[idx];
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek return (const void *)result->row[idx];
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek}
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekstatic const char *
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekdriver_mysql_result_find_field_value(struct sql_result *result,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek const char *field_name)
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek{
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek int idx;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik idx = driver_mysql_result_find_field(result, field_name);
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek if (idx < 0)
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek return NULL;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek return driver_mysql_result_get_field_value(result, idx);
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek}
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekstatic const char *const *
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekdriver_mysql_result_get_values(struct sql_result *_result)
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek{
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik struct mysql_result *result = (struct mysql_result *)_result;
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik return (const char *const *)result->row;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek}
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstatic const char *driver_mysql_result_get_error(struct sql_result *_result)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek{
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek struct mysql_db *db = (struct mysql_db *)_result->db;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek return mysql_error(db->mysql);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek}
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekstatic struct sql_transaction_context *
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekdriver_mysql_transaction_begin(struct sql_db *db)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek{
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek struct mysql_transaction_context *ctx;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek ctx = i_new(struct mysql_transaction_context, 1);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek ctx->ctx.db = db;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek ctx->query_pool = pool_alloconly_create("mysql transaction", 1024);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek return &ctx->ctx;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek}
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekstatic void
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekdriver_mysql_transaction_commit(struct sql_transaction_context *ctx,
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek sql_commit_callback_t *callback, void *context)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek{
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek const char *error;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek if (sql_transaction_commit_s(&ctx, &error) < 0)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek callback(error, context);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek else
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek callback(NULL, context);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek}
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekstatic int
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozektransaction_send_query(struct mysql_transaction_context *ctx, const char *query,
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek unsigned int *affected_rows_r)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek{
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek struct sql_result *_result;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek int ret = 0;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek if (ctx->failed)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek return -1;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek _result = sql_query_s(ctx->ctx.db, query);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek if (sql_result_next_row(_result) < 0) {
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek ctx->error = sql_result_get_error(_result);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek ctx->failed = TRUE;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek ret = -1;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek } else if (affected_rows_r != NULL) {
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek i_assert(result->affected_rows != (my_ulonglong)-1);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek *affected_rows_r = result->affected_rows;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek }
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek sql_result_unref(_result);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek return ret;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek}
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekstatic int
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekdriver_mysql_transaction_commit_s(struct sql_transaction_context *_ctx,
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek const char **error_r)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek{
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek struct mysql_transaction_context *ctx =
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek (struct mysql_transaction_context *)_ctx;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek int ret = 0;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek *error_r = NULL;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek if (_ctx->head != NULL) {
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek /* try to use a transaction in any case,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek even if it doesn't work. */
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek (void)transaction_send_query(ctx, "BEGIN", NULL);
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek while (_ctx->head != NULL) {
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek if (transaction_send_query(ctx, _ctx->head->query,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek _ctx->head->affected_rows) < 0)
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek break;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek _ctx->head = _ctx->head->next;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek }
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek ret = transaction_send_query(ctx, "COMMIT", NULL);
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek *error_r = ctx->error;
de2bad8ae08f09964834bda0f88db9de39f47c5cJakub Hrozek }
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek sql_transaction_rollback(&_ctx);
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek return ret;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek}
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekstatic void
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekdriver_mysql_transaction_rollback(struct sql_transaction_context *_ctx)
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek{
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek struct mysql_transaction_context *ctx =
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek (struct mysql_transaction_context *)_ctx;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek pool_unref(&ctx->query_pool);
de2bad8ae08f09964834bda0f88db9de39f47c5cJakub Hrozek i_free(ctx);
de2bad8ae08f09964834bda0f88db9de39f47c5cJakub Hrozek}
de2bad8ae08f09964834bda0f88db9de39f47c5cJakub Hrozek
de2bad8ae08f09964834bda0f88db9de39f47c5cJakub Hrozekstatic void
de2bad8ae08f09964834bda0f88db9de39f47c5cJakub Hrozekdriver_mysql_update(struct sql_transaction_context *_ctx, const char *query,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek unsigned int *affected_rows)
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek{
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek struct mysql_transaction_context *ctx =
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek (struct mysql_transaction_context *)_ctx;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek sql_transaction_add_query(&ctx->ctx, ctx->query_pool,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek query, affected_rows);
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek}
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekconst struct sql_db driver_mysql_db = {
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek .name = "mysql",
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek .flags = SQL_DB_FLAG_BLOCKING | SQL_DB_FLAG_POOLED,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek .v = {
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_init_v,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_deinit_v,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_connect,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_disconnect,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_escape_string,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_exec,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_query,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_query_s,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_transaction_begin,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_transaction_commit,
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik driver_mysql_transaction_commit_s,
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik driver_mysql_transaction_rollback,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_update
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek }
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek};
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekconst struct sql_result driver_mysql_result = {
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek .v = {
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_result_free,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_result_next_row,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_result_get_fields_count,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_result_get_field_name,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_result_find_field,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_result_get_field_value,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_result_get_field_value_binary,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek driver_mysql_result_find_field_value,
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik driver_mysql_result_get_values,
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik driver_mysql_result_get_error
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek }
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek};
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekstatic int
de2bad8ae08f09964834bda0f88db9de39f47c5cJakub Hrozekdriver_mysql_result_error_next_row(struct sql_result *result ATTR_UNUSED)
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek{
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek return -1;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek}
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekconst struct sql_result driver_mysql_error_result = {
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek .v = {
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek driver_mysql_result_free,
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek driver_mysql_result_error_next_row,
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek NULL, NULL, NULL, NULL, NULL, NULL, NULL,
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek driver_mysql_result_get_error
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek },
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek .failed_try_retry = TRUE
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek};
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekconst char *driver_mysql_version = DOVECOT_VERSION;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekvoid driver_mysql_init(void);
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekvoid driver_mysql_deinit(void);
e2bd4f8a41b72aea0712ad21ad02ccebb707f536Stephen Gallagher
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekvoid driver_mysql_init(void)
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek{
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek sql_driver_register(&driver_mysql_db);
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek}
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekvoid driver_mysql_deinit(void)
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek{
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek sql_driver_unregister(&driver_mysql_db);
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek}
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek#endif
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek