driver-mysql.c revision f635aa2fd6c47ec297cf68981203a8dc7f8a23c3
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek/* Copyright (c) 2003-2011 Dovecot authors, see the included COPYING file */
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;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekextern const struct sql_result driver_mysql_result;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekextern const struct sql_result driver_mysql_error_result;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekstatic const char *mysql_prefix(struct mysql_db *db)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic int driver_mysql_connect(struct sql_db *_db)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_assert(db->api.state == SQL_DB_STATE_DISCONNECTED);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose sql_db_set_state(&db->api, SQL_DB_STATE_CONNECTING);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_options(db->mysql, MYSQL_READ_DEFAULT_FILE,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_options(db->mysql, MYSQL_READ_DEFAULT_GROUP,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose db->option_group != NULL ? db->option_group : "client");
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (!db->ssl_set && (db->ssl_ca != NULL || db->ssl_ca_path != NULL)) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_ssl_set(db->mysql, db->ssl_key, db->ssl_cert,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose "(remove ssl_ca and ssl_ca_path settings)");
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 /* 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 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 i_info("%s: Connected to database %s%s", mysql_prefix(db),
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_disconnect(struct sql_db *_db ATTR_UNUSED)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_parse_connect_string(struct mysql_db *db,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose const char **field;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_fatal("mysql: Missing value in connect string: %s",
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_fatal("mysql: Unknown connect string: %s", name);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose i_fatal("mysql: No hosts given in connect string");
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic struct sql_db *driver_mysql_init_v(const char *connect_string)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose pool = pool_alloconly_create("mysql driver", 1024);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose driver_mysql_parse_connect_string(db, connect_string);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_deinit_v(struct sql_db *_db)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic int driver_mysql_do_query(struct mysql_db *db, const char *query)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* failed */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic const char *
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosedriver_mysql_escape_string(struct sql_db *_db, const char *string)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* try connecting */
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 len = mysql_real_escape_string(db->mysql, to, string, len);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_exec(struct sql_db *_db, const char *query)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose mysql_prefix(db), query, mysql_error(db->mysql));
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_query(struct sql_db *db, const char *query,
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic struct sql_result *
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosedriver_mysql_query_s(struct sql_db *_db, const char *query)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* query ok */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->affected_rows = mysql_affected_rows(db->mysql);
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 (result->result != NULL || mysql_errno(db->mysql) == 0)) {
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* failed */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_result_free(struct sql_result *_result)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_result *result = (struct mysql_result *)_result;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic int driver_mysql_result_next_row(struct sql_result *_result)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_result *result = (struct mysql_result *)_result;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose struct mysql_db *db = (struct mysql_db *)_result->db;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose /* no results */
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bosestatic void driver_mysql_result_fetch_fields(struct mysql_result *result)
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->fields_count = mysql_num_fields(result->result);
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose result->fields = mysql_fetch_fields(result->result);
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekstatic unsigned int
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekdriver_mysql_result_get_fields_count(struct sql_result *_result)
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstatic const char *
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekdriver_mysql_result_get_field_name(struct sql_result *_result, unsigned int idx)
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
933314e53fac878d1a9b126af216454172cb945aJakub Hrozekstatic int driver_mysql_result_find_field(struct sql_result *_result,
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
933314e53fac878d1a9b126af216454172cb945aJakub Hrozek unsigned int i;
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose if (strcmp(result->fields[i].name, field_name) == 0)
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstatic const char *
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekdriver_mysql_result_get_field_value(struct sql_result *_result,
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik unsigned int idx)
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstatic const unsigned char *
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekdriver_mysql_result_get_field_value_binary(struct sql_result *_result,
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek unsigned long *lengths;
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekstatic const char *
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekdriver_mysql_result_find_field_value(struct sql_result *result,
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik idx = driver_mysql_result_find_field(result, field_name);
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek return driver_mysql_result_get_field_value(result, idx);
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekstatic const char *const *
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekdriver_mysql_result_get_values(struct sql_result *_result)
295c8e301e31f9bf27d921f80c14dfa5864b2383Lukas Slebodnik struct mysql_result *result = (struct mysql_result *)_result;
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekstatic const char *driver_mysql_result_get_error(struct sql_result *_result)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek struct mysql_db *db = (struct mysql_db *)_result->db;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekdriver_mysql_transaction_begin(struct sql_db *db)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek ctx = i_new(struct mysql_transaction_context, 1);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek ctx->query_pool = pool_alloconly_create("mysql transaction", 1024);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekdriver_mysql_transaction_commit(struct sql_transaction_context *ctx,
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek sql_commit_callback_t *callback, void *context)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek if (sql_transaction_commit_s(&ctx, &error) < 0)
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozektransaction_send_query(struct mysql_transaction_context *ctx, const char *query,
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek struct mysql_result *result = (struct mysql_result *)_result;
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek i_assert(result->affected_rows != (my_ulonglong)-1);
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozekdriver_mysql_transaction_commit_s(struct sql_transaction_context *_ctx,
30dd3f3e063dded0ec9f58bc2535a94727d8e96dJakub Hrozek const char **error_r)
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 if (transaction_send_query(ctx, _ctx->head->query,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek ret = transaction_send_query(ctx, "COMMIT", NULL);
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozekdriver_mysql_transaction_rollback(struct sql_transaction_context *_ctx)
de2bad8ae08f09964834bda0f88db9de39f47c5cJakub Hrozekdriver_mysql_update(struct sql_transaction_context *_ctx, const char *query,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek sql_transaction_add_query(&ctx->ctx, ctx->query_pool,
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek .flags = SQL_DB_FLAG_BLOCKING | SQL_DB_FLAG_POOLED,
de2bad8ae08f09964834bda0f88db9de39f47c5cJakub Hrozekdriver_mysql_result_error_next_row(struct sql_result *result ATTR_UNUSED)
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozekconst struct sql_result driver_mysql_error_result = {