driver-mysql.c revision d13a8e21656e1b7005e094f7b9c9e3611105c648
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "lib.h"
685a84a0ccb55cb9359dcd57d9eb3b6b836034a2Timo Sirainen#include "ioloop.h"
5ab2ee0b9b7ad3867fcfd2a31fda0790370fbbbdTimo Sirainen#include "array.h"
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen#include "str.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "sql-api-private.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen#ifdef BUILD_MYSQL
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include <stdlib.h>
06b0c3be9905099038964b068216bbed155701deTimo Sirainen#include <unistd.h>
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include <time.h>
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#ifdef HAVE_ATTR_NULL
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen/* ugly way to tell clang that mysql.h is a system header and we don't want
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen to enable nonnull attributes for it by default.. */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen# 4 "driver-mysql.c" 3
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#endif
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include <mysql.h>
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#ifdef HAVE_ATTR_NULL
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen# 4 "driver-mysql.c" 3
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen# line 20
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen#endif
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include <errmsg.h>
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstruct mysql_db {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_db api;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen pool_t pool;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *user, *password, *dbname, *host, *unix_socket;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *ssl_cert, *ssl_key, *ssl_ca, *ssl_ca_path, *ssl_cipher;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *option_file, *option_group;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int port, client_flags;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen time_t last_success;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainen MYSQL *mysql;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int next_query_connection;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int ssl_set:1;
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen};
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstruct mysql_result {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct sql_result api;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen MYSQL_RES *result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen MYSQL_ROW row;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen MYSQL_FIELD *fields;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen unsigned int fields_count;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen my_ulonglong affected_rows;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen};
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainen
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainenstruct mysql_transaction_context {
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainen struct sql_transaction_context ctx;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen pool_t query_pool;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen const char *error;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen unsigned int failed:1;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen};
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenextern const struct sql_db driver_mysql_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenextern const struct sql_result driver_mysql_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenextern const struct sql_result driver_mysql_error_result;
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen
f635aa2fd6c47ec297cf68981203a8dc7f8a23c3Timo Sirainenstatic const char *mysql_prefix(struct mysql_db *db)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return t_strdup_printf("mysql(%s)", db->host);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
b57cd9928909b51fa473c3eea81442e296006438Timo Sirainenstatic int driver_mysql_connect(struct sql_db *_db)
b57cd9928909b51fa473c3eea81442e296006438Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct mysql_db *db = (struct mysql_db *)_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const char *unix_socket, *host;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned long client_flags = db->client_flags;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int secs_used;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen bool failed;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen i_assert(db->api.state == SQL_DB_STATE_DISCONNECTED);
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen sql_db_set_state(&db->api, SQL_DB_STATE_CONNECTING);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen if (*db->host == '/') {
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen unix_socket = db->host;
c87d1e148ae76cf20f3adc7fc84fd54219dc62d5Timo Sirainen host = NULL;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } else {
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen unix_socket = NULL;
c87d1e148ae76cf20f3adc7fc84fd54219dc62d5Timo Sirainen host = db->host;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->option_file != NULL) {
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen mysql_options(db->mysql, MYSQL_READ_DEFAULT_FILE,
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen db->option_file);
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen }
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen mysql_options(db->mysql, MYSQL_READ_DEFAULT_GROUP,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->option_group != NULL ? db->option_group : "client");
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen if (!db->ssl_set && (db->ssl_ca != NULL || db->ssl_ca_path != NULL)) {
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen#ifdef HAVE_MYSQL_SSL
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen mysql_ssl_set(db->mysql, db->ssl_key, db->ssl_cert,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->ssl_ca, db->ssl_ca_path
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#ifdef HAVE_MYSQL_SSL_CIPHER
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen , db->ssl_cipher
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen#endif
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen );
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen db->ssl_set = TRUE;
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen#else
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_fatal("mysql: SSL support not compiled in "
06b0c3be9905099038964b068216bbed155701deTimo Sirainen "(remove ssl_ca and ssl_ca_path settings)");
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen#endif
f635aa2fd6c47ec297cf68981203a8dc7f8a23c3Timo Sirainen }
06b0c3be9905099038964b068216bbed155701deTimo Sirainen
685a84a0ccb55cb9359dcd57d9eb3b6b836034a2Timo Sirainen alarm(SQL_CONNECT_TIMEOUT_SECS);
685a84a0ccb55cb9359dcd57d9eb3b6b836034a2Timo Sirainen#ifdef CLIENT_MULTI_RESULTS
685a84a0ccb55cb9359dcd57d9eb3b6b836034a2Timo Sirainen client_flags |= CLIENT_MULTI_RESULTS;
685a84a0ccb55cb9359dcd57d9eb3b6b836034a2Timo Sirainen#endif
685a84a0ccb55cb9359dcd57d9eb3b6b836034a2Timo Sirainen /* CLIENT_MULTI_RESULTS allows the use of stored procedures */
f635aa2fd6c47ec297cf68981203a8dc7f8a23c3Timo Sirainen failed = mysql_real_connect(db->mysql, host, db->user, db->password,
f635aa2fd6c47ec297cf68981203a8dc7f8a23c3Timo Sirainen db->dbname, db->port, unix_socket,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen client_flags) == NULL;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen secs_used = SQL_CONNECT_TIMEOUT_SECS - alarm(0);
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen if (failed) {
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen /* connecting could have taken a while. make sure that any
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen timeouts that get added soon will get a refreshed
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen timestamp. */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen io_loop_time_refresh();
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen if (db->api.connect_delay < secs_used)
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen db->api.connect_delay = secs_used;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_error("%s: Connect failed to database (%s): %s - "
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen "waiting for %u seconds before retry",
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen mysql_prefix(db), db->dbname,
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen mysql_error(db->mysql), db->api.connect_delay);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return -1;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen } else {
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen i_info("%s: Connected to database %s%s", mysql_prefix(db),
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen db->dbname, db->ssl_set ? " using SSL" : "");
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->last_success = ioloop_time;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen sql_db_set_state(&db->api, SQL_DB_STATE_IDLE);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_mysql_disconnect(struct sql_db *_db ATTR_UNUSED)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_mysql_parse_connect_string(struct mysql_db *db,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *connect_string)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *const *args, *name, *value;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char **field;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->ssl_cipher = "HIGH";
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen args = t_strsplit_spaces(connect_string, " ");
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen for (; *args != NULL; args++) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen value = strchr(*args, '=');
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (value == NULL) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_fatal("mysql: Missing value in connect string: %s",
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen *args);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen name = t_strdup_until(*args, value);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen value++;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen field = NULL;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (strcmp(name, "host") == 0 ||
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen strcmp(name, "hostaddr") == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen field = &db->host;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else if (strcmp(name, "user") == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen field = &db->user;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else if (strcmp(name, "password") == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen field = &db->password;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else if (strcmp(name, "dbname") == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen field = &db->dbname;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else if (strcmp(name, "port") == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->port = atoi(value);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else if (strcmp(name, "client_flags") == 0)
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen db->client_flags = atoi(value);
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen else if (strcmp(name, "ssl_cert") == 0)
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen field = &db->ssl_cert;
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen else if (strcmp(name, "ssl_key") == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen field = &db->ssl_key;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else if (strcmp(name, "ssl_ca") == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen field = &db->ssl_ca;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else if (strcmp(name, "ssl_ca_path") == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen field = &db->ssl_ca_path;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else if (strcmp(name, "ssl_cipher") == 0)
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen field = &db->ssl_cipher;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen else if (strcmp(name, "option_file") == 0)
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen field = &db->option_file;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen else if (strcmp(name, "option_group") == 0)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen field = &db->option_group;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen else
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_fatal("mysql: Unknown connect string: %s", name);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (field != NULL)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen *field = p_strdup(db->pool, value);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainen if (db->host == NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_fatal("mysql: No hosts given in connect string");
bc27fcd011f86208feaf73da9778a66ac7d7d3abTimo Sirainen
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainen db->mysql = mysql_init(NULL);
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainen if (db->mysql == NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_fatal("mysql_init() failed");
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic struct sql_db *driver_mysql_init_v(const char *connect_string)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mysql_db *db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen pool_t pool;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen pool = pool_alloconly_create("mysql driver", 1024);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db = p_new(pool, struct mysql_db, 1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->pool = pool;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->api = driver_mysql_db;
4c9c55e15f35474f53f11659e796c63b1c34e884Timo Sirainen
9222c96ab9f42b25d5d5260f9e7a42c694715b0aTimo Sirainen T_BEGIN {
9222c96ab9f42b25d5d5260f9e7a42c694715b0aTimo Sirainen driver_mysql_parse_connect_string(db, connect_string);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } T_END;
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainen return &db->api;
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_mysql_deinit_v(struct sql_db *_db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mysql_db *db = (struct mysql_db *)_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen _db->no_reconnect = TRUE;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen mysql_close(db->mysql);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_free(&_db->module_contexts);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen pool_unref(&db->pool);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic int driver_mysql_do_query(struct mysql_db *db, const char *query)
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen{
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen if (mysql_query(db->mysql, query) == 0)
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen return 0;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen /* failed */
13a8c553f293349248b161ff851743498916e26eTimo Sirainen switch (mysql_errno(db->mysql)) {
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen case CR_SERVER_GONE_ERROR:
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen case CR_SERVER_LOST:
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen break;
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen default:
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen break;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return -1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
c95fc202215d2451372599db7092b16459f360a3Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic const char *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_mysql_escape_string(struct sql_db *_db, const char *string)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct mysql_db *db = (struct mysql_db *)_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen size_t len = strlen(string);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen char *to;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (_db->state == SQL_DB_STATE_DISCONNECTED) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* try connecting */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (void)sql_connect(&db->api);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
c95fc202215d2451372599db7092b16459f360a3Timo Sirainen if (db->mysql == NULL) {
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen /* FIXME: we don't have a valid connection, so fallback
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen to using default escaping. the next query will most
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen likely fail anyway so it shouldn't matter that much
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen what we return here.. Anyway, this API needs
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen changing so that the escaping function could already
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen fail the query reliably. */
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen to = t_buffer_get(len * 2 + 1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen len = mysql_escape_string(to, string, len);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen t_buffer_alloc(len + 1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return to;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
3db8062598ce08e9320c84f77c267b9c70cb0809Timo Sirainen
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen to = t_buffer_get(len * 2 + 1);
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen len = mysql_real_escape_string(db->mysql, to, string, len);
3db8062598ce08e9320c84f77c267b9c70cb0809Timo Sirainen t_buffer_alloc(len + 1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return to;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_mysql_exec(struct sql_db *_db, const char *query)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct mysql_db *db = (struct mysql_db *)_db;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (driver_mysql_do_query(db, query) < 0) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen i_error("%s: Query '%s' failed: %s",
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen mysql_prefix(db), query, mysql_error(db->mysql));
eeea0a402bcd9533e9e359f2a2518e3216162151Timo Sirainen }
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic void driver_mysql_query(struct sql_db *db, const char *query,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen sql_query_callback_t *callback, void *context)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct sql_result *result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen result = sql_query_s(db, query);
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen result->callback = TRUE;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen callback(result, context);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen result->callback = FALSE;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen sql_result_unref(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainenstatic struct sql_result *
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainendriver_mysql_query_s(struct sql_db *_db, const char *query)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen struct mysql_db *db = (struct mysql_db *)_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct mysql_result *result;
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen int ret;
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen result = i_new(struct mysql_result, 1);
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen result->api = driver_mysql_result;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen if (driver_mysql_do_query(db, query) < 0)
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen result->api = driver_mysql_error_result;
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen else {
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen /* query ok */
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen result->affected_rows = mysql_affected_rows(db->mysql);
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen result->result = mysql_store_result(db->mysql);
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen#ifdef CLIENT_MULTI_RESULTS
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen /* Because we've enabled CLIENT_MULTI_RESULTS, we need to read
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen (ignore) extra results - there should not be any.
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen ret is: -1 = done, >0 = error, 0 = more results. */
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen while ((ret = mysql_next_result(db->mysql)) == 0) ;
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen#else
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen ret = -1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#endif
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a74e4a66db99a69cca71d7c5ac1feae46d92138fTimo Sirainen if (ret < 0 &&
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen (result->result != NULL || mysql_errno(db->mysql) == 0)) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen /* ok */
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen } else {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen /* failed */
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (result->result != NULL)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen mysql_free_result(result->result);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen result->api = driver_mysql_error_result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen }
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen }
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen result->api.db = _db;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen result->api.refcount = 1;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen return &result->api;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_mysql_result_free(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mysql_result *result = (struct mysql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(_result != &sql_not_connected_result);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (_result->callback)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
fedb73c7e918653877286ede0fe18029b3cce7d3Timo Sirainen
fedb73c7e918653877286ede0fe18029b3cce7d3Timo Sirainen if (result->result != NULL)
fedb73c7e918653877286ede0fe18029b3cce7d3Timo Sirainen mysql_free_result(result->result);
fedb73c7e918653877286ede0fe18029b3cce7d3Timo Sirainen i_free(result);
fedb73c7e918653877286ede0fe18029b3cce7d3Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a2550844936da8b78d7565b905a4dc5ffb3eef0eTimo Sirainenstatic int driver_mysql_result_next_row(struct sql_result *_result)
a2550844936da8b78d7565b905a4dc5ffb3eef0eTimo Sirainen{
a2550844936da8b78d7565b905a4dc5ffb3eef0eTimo Sirainen struct mysql_result *result = (struct mysql_result *)_result;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct mysql_db *db = (struct mysql_db *)_result->db;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen int ret;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (result->result == NULL) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* no results */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->row = mysql_fetch_row(result->result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (result->row != NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ret = 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (mysql_errno(db->mysql) != 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return -1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ret = 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen db->last_success = ioloop_time;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return ret;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void driver_mysql_result_fetch_fields(struct mysql_result *result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (result->fields != NULL)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->fields_count = mysql_num_fields(result->result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen result->fields = mysql_fetch_fields(result->result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic unsigned int
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_mysql_result_get_fields_count(struct sql_result *_result)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mysql_result *result = (struct mysql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_mysql_result_fetch_fields(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return result->fields_count;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_mysql_result_get_field_name(struct sql_result *_result, unsigned int idx)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mysql_result *result = (struct mysql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen driver_mysql_result_fetch_fields(result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(idx < result->fields_count);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return result->fields[idx].name;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic int driver_mysql_result_find_field(struct sql_result *_result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *field_name)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mysql_result *result = (struct mysql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int i;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen driver_mysql_result_fetch_fields(result);
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainen for (i = 0; i < result->fields_count; i++) {
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainen if (strcmp(result->fields[i].name, field_name) == 0)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return i;
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainen }
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainen return -1;
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainen}
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainen
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainenstatic const char *
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainendriver_mysql_result_get_field_value(struct sql_result *_result,
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainen unsigned int idx)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen struct mysql_result *result = (struct mysql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return (const char *)result->row[idx];
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const unsigned char *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_mysql_result_get_field_value_binary(struct sql_result *_result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int idx, size_t *size_r)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mysql_result *result = (struct mysql_result *)_result;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned long *lengths;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen lengths = mysql_fetch_lengths(result->result);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen *size_r = lengths[idx];
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return (const void *)result->row[idx];
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_mysql_result_find_field_value(struct sql_result *result,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *field_name)
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen int idx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen idx = driver_mysql_result_find_field(result, field_name);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (idx < 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return NULL;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return driver_mysql_result_get_field_value(result, idx);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic const char *const *
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainendriver_mysql_result_get_values(struct sql_result *_result)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct mysql_result *result = (struct mysql_result *)_result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen return (const char *const *)result->row;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic const char *driver_mysql_result_get_error(struct sql_result *_result)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct mysql_db *db = (struct mysql_db *)_result->db;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen const char *errstr;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen unsigned int idle_time;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen int err;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen err = mysql_errno(db->mysql);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen errstr = mysql_error(db->mysql);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if ((err == CR_SERVER_GONE_ERROR || err == CR_SERVER_LOST) &&
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen db->last_success != 0) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen idle_time = ioloop_time - db->last_success;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen errstr = t_strdup_printf("%s (idled for %u secs)",
59811ccfeb7dccc51e3be50c299c2ed853a1e2f3Timo Sirainen errstr, idle_time);
59811ccfeb7dccc51e3be50c299c2ed853a1e2f3Timo Sirainen }
59811ccfeb7dccc51e3be50c299c2ed853a1e2f3Timo Sirainen return errstr;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen}
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainenstatic struct sql_transaction_context *
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainendriver_mysql_transaction_begin(struct sql_db *db)
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen{
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen struct mysql_transaction_context *ctx;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen ctx = i_new(struct mysql_transaction_context, 1);
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen ctx->ctx.db = db;
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen ctx->query_pool = pool_alloconly_create("mysql transaction", 1024);
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen return &ctx->ctx;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen}
59811ccfeb7dccc51e3be50c299c2ed853a1e2f3Timo Sirainen
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainenstatic void
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainendriver_mysql_transaction_commit(struct sql_transaction_context *ctx,
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen sql_commit_callback_t *callback, void *context)
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen{
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen const char *error;
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen if (sql_transaction_commit_s(&ctx, &error) < 0)
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen callback(error, context);
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen else
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen callback(NULL, context);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic int ATTR_NULL(3)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainentransaction_send_query(struct mysql_transaction_context *ctx, const char *query,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen unsigned int *affected_rows_r)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct sql_result *_result;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen int ret = 0;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (ctx->failed)
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen return -1;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen
59811ccfeb7dccc51e3be50c299c2ed853a1e2f3Timo Sirainen _result = sql_query_s(ctx->ctx.db, query);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (sql_result_next_row(_result) < 0) {
59811ccfeb7dccc51e3be50c299c2ed853a1e2f3Timo Sirainen ctx->error = sql_result_get_error(_result);
59811ccfeb7dccc51e3be50c299c2ed853a1e2f3Timo Sirainen ctx->failed = TRUE;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen ret = -1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } else if (affected_rows_r != NULL) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct mysql_result *result = (struct mysql_result *)_result;
59811ccfeb7dccc51e3be50c299c2ed853a1e2f3Timo Sirainen
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen i_assert(result->affected_rows != (my_ulonglong)-1);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen *affected_rows_r = result->affected_rows;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen sql_result_unref(_result);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen return ret;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen}
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic int driver_mysql_try_commit_s(struct mysql_transaction_context *ctx)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen{
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen struct sql_transaction_context *_ctx = &ctx->ctx;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen /* try to use a transaction in any case,
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen even if it's not actually functional. */
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (transaction_send_query(ctx, "BEGIN", NULL) < 0) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (_ctx->db->state != SQL_DB_STATE_DISCONNECTED)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen return -1;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen /* we got disconnected, retry */
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen return 0;
bfdf0fd7b6186f64cbdcbf1cb2bf9c42a9007b77Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen while (_ctx->head != NULL) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (transaction_send_query(ctx, _ctx->head->query,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen _ctx->head->affected_rows) < 0)
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen return -1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen _ctx->head = _ctx->head->next;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (transaction_send_query(ctx, "COMMIT", NULL) < 0)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen return -1;
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainen return 1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainenstatic int
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainendriver_mysql_transaction_commit_s(struct sql_transaction_context *_ctx,
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen const char **error_r)
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct mysql_transaction_context *ctx =
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (struct mysql_transaction_context *)_ctx;
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen struct mysql_db *db = (struct mysql_db *)_ctx->db;
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen int ret = 1;
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen *error_r = NULL;
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen if (_ctx->head != NULL) {
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen ret = driver_mysql_try_commit_s(ctx);
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen *error_r = t_strdup(ctx->error);
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen if (ret == 0) {
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen i_info("%s: Disconnected from database, "
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen "retrying commit", db->dbname);
0ae010139a1bb3b29fbf117c5da1a6a6c6b7b5a0Timo Sirainen if (sql_connect(_ctx->db) >= 0) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ctx->failed = FALSE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ret = driver_mysql_try_commit_s(ctx);
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen }
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen sql_transaction_rollback(&_ctx);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen return ret <= 0 ? -1 : 0;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen}
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainenstatic void
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainendriver_mysql_transaction_rollback(struct sql_transaction_context *_ctx)
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen{
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen struct mysql_transaction_context *ctx =
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen (struct mysql_transaction_context *)_ctx;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen pool_unref(&ctx->query_pool);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_free(ctx);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic void
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainendriver_mysql_update(struct sql_transaction_context *_ctx, const char *query,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int *affected_rows)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainen struct mysql_transaction_context *ctx =
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen (struct mysql_transaction_context *)_ctx;
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen sql_transaction_add_query(&ctx->ctx, ctx->query_pool,
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen query, affected_rows);
1ac19c5c2b66a12f5598792aad15114ee3eb62e2Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenconst struct sql_db driver_mysql_db = {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen .name = "mysql",
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen .flags = SQL_DB_FLAG_BLOCKING | SQL_DB_FLAG_POOLED,
4371df92c07fb923aabca7e90d307eccac48b2d6Timo Sirainen
4371df92c07fb923aabca7e90d307eccac48b2d6Timo Sirainen .v = {
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_init_v,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_deinit_v,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_connect,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_disconnect,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_escape_string,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_exec,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_query,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_query_s,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_transaction_begin,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_transaction_commit,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_transaction_commit_s,
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen driver_mysql_transaction_rollback,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
driver_mysql_update
}
};
const struct sql_result driver_mysql_result = {
.v = {
driver_mysql_result_free,
driver_mysql_result_next_row,
driver_mysql_result_get_fields_count,
driver_mysql_result_get_field_name,
driver_mysql_result_find_field,
driver_mysql_result_get_field_value,
driver_mysql_result_get_field_value_binary,
driver_mysql_result_find_field_value,
driver_mysql_result_get_values,
driver_mysql_result_get_error
}
};
static int
driver_mysql_result_error_next_row(struct sql_result *result ATTR_UNUSED)
{
return -1;
}
const struct sql_result driver_mysql_error_result = {
.v = {
driver_mysql_result_free,
driver_mysql_result_error_next_row,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
driver_mysql_result_get_error
},
.failed_try_retry = TRUE
};
const char *driver_mysql_version = DOVECOT_VERSION;
void driver_mysql_init(void);
void driver_mysql_deinit(void);
void driver_mysql_init(void)
{
sql_driver_register(&driver_mysql_db);
}
void driver_mysql_deinit(void)
{
sql_driver_unregister(&driver_mysql_db);
}
#endif