driver/mysql_proxy.cc (291 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, version 2.0
// (GPLv2), as published by the Free Software Foundation, with the
// following additional permissions:
//
// This program is distributed with certain software that is licensed
// under separate terms, as designated in a particular file or component
// or in the license documentation. Without limiting your rights under
// the GPLv2, the authors of this program hereby grant you an additional
// permission to link the program and your derivative works with the
// separately licensed software that they have included with the program.
//
// Without limiting the foregoing grant of rights under the GPLv2 and
// additional permission as to separately licensed software, this
// program is also subject to the Universal FOSS Exception, version 1.0,
// a copy of which can be found along with its FAQ at
// http://oss.oracle.com/licenses/universal-foss-exception.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License, version 2.0, for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// http://www.gnu.org/licenses/gpl-2.0.html.
#include "mysql_proxy.h"
#include <sstream>
#include <thread>
namespace {
const auto SOCKET_CLOSE_DELAY = std::chrono::milliseconds(100);
}
MYSQL_PROXY::MYSQL_PROXY(DBC* dbc, DataSource* ds) : CONNECTION_PROXY(dbc, ds) {
this->host = get_host_info_from_ds(ds);
}
MYSQL_PROXY::~MYSQL_PROXY() {
if (this->mysql) {
close();
}
}
uint64_t MYSQL_PROXY::num_rows(MYSQL_RES* res) {
return mysql_num_rows(res);
}
unsigned int MYSQL_PROXY::num_fields(MYSQL_RES* res) {
return mysql_num_fields(res);
}
MYSQL_FIELD* MYSQL_PROXY::fetch_field_direct(MYSQL_RES* res, unsigned int fieldnr) {
return mysql_fetch_field_direct(res, fieldnr);
}
MYSQL_ROW_OFFSET MYSQL_PROXY::row_tell(MYSQL_RES* res) {
return mysql_row_tell(res);
}
unsigned int MYSQL_PROXY::field_count() {
return mysql_field_count(mysql);
}
uint64_t MYSQL_PROXY::affected_rows() {
return mysql_affected_rows(mysql);
}
unsigned int MYSQL_PROXY::error_code() {
return mysql_errno(mysql);
}
const char* MYSQL_PROXY::error() {
return mysql_error(mysql);
}
const char* MYSQL_PROXY::sqlstate() {
return mysql_sqlstate(mysql);
}
unsigned long MYSQL_PROXY::thread_id() {
return mysql_thread_id(mysql);
}
int MYSQL_PROXY::set_character_set(const char* csname) {
return mysql_set_character_set(mysql, csname);
}
void MYSQL_PROXY::init() {
this->mysql = mysql_init(nullptr);
}
bool MYSQL_PROXY::change_user(const char* user, const char* passwd, const char* db) {
return mysql_change_user(mysql, user, passwd, db);
}
bool MYSQL_PROXY::real_connect(
const char* host, const char* user, const char* passwd,
const char* db, unsigned int port, const char* unix_socket,
unsigned long clientflag) {
const MYSQL* new_mysql = mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, clientflag);
return new_mysql != nullptr;
}
int MYSQL_PROXY::select_db(const char* db) {
return mysql_select_db(mysql, db);
}
int MYSQL_PROXY::query(const char* q) {
return mysql_query(mysql, q);
}
int MYSQL_PROXY::real_query(const char* q, unsigned long length) {
return mysql_real_query(mysql, q, length);
}
MYSQL_RES* MYSQL_PROXY::store_result() {
return mysql_store_result(mysql);
}
MYSQL_RES* MYSQL_PROXY::use_result() {
return mysql_use_result(mysql);
}
struct CHARSET_INFO* MYSQL_PROXY::get_character_set() const {
return this->mysql->charset;
}
void MYSQL_PROXY::get_character_set_info(MY_CHARSET_INFO* charset) {
mysql_get_character_set_info(mysql, charset);
}
bool MYSQL_PROXY::autocommit(bool auto_mode) {
return mysql_autocommit(mysql, auto_mode);
}
bool MYSQL_PROXY::commit() {
return mysql_commit(mysql);
}
bool MYSQL_PROXY::rollback() {
return mysql_rollback(mysql);
}
bool MYSQL_PROXY::more_results() {
return mysql_more_results(mysql);
}
int MYSQL_PROXY::next_result() {
return mysql_next_result(mysql);
}
int MYSQL_PROXY::stmt_next_result(MYSQL_STMT* stmt) {
return mysql_stmt_next_result(stmt);
}
void MYSQL_PROXY::close() {
mysql_close(mysql);
mysql = nullptr;
}
bool MYSQL_PROXY::real_connect_dns_srv(
const char* dns_srv_name, const char* user,
const char* passwd, const char* db, unsigned long client_flag) {
const MYSQL* new_mysql = mysql_real_connect_dns_srv(mysql, dns_srv_name, user, passwd, db, client_flag);
return new_mysql != nullptr;
}
int MYSQL_PROXY::ping() {
return mysql_ping(mysql);
}
int MYSQL_PROXY::get_option(mysql_option option, const void* arg) {
return mysql_get_option(mysql, option, arg);
}
int MYSQL_PROXY::options4(mysql_option option, const void* arg1, const void* arg2) {
return mysql_options4(mysql, option, arg1, arg2);
}
int MYSQL_PROXY::options(mysql_option option, const void* arg) {
return mysql_options(mysql, option, arg);
}
void MYSQL_PROXY::free_result(MYSQL_RES* result) {
mysql_free_result(result);
}
void MYSQL_PROXY::data_seek(MYSQL_RES* result, uint64_t offset) {
mysql_data_seek(result, offset);
}
MYSQL_ROW_OFFSET MYSQL_PROXY::row_seek(MYSQL_RES* result, MYSQL_ROW_OFFSET offset) {
return mysql_row_seek(result, offset);
}
MYSQL_FIELD_OFFSET MYSQL_PROXY::field_seek(MYSQL_RES* result, MYSQL_FIELD_OFFSET offset) {
return mysql_field_seek(result, offset);
}
MYSQL_ROW MYSQL_PROXY::fetch_row(MYSQL_RES* result) {
return mysql_fetch_row(result);
}
unsigned long* MYSQL_PROXY::fetch_lengths(MYSQL_RES* result) {
return mysql_fetch_lengths(result);
}
MYSQL_FIELD* MYSQL_PROXY::fetch_field(MYSQL_RES* result) {
return mysql_fetch_field(result);
}
unsigned long MYSQL_PROXY::real_escape_string(char* to, const char* from, unsigned long length) {
return mysql_real_escape_string(mysql, to, from, length);
}
bool MYSQL_PROXY::bind_param(unsigned n_params, MYSQL_BIND* binds, const char** names) {
return mysql_bind_param(mysql, n_params, binds, names);
}
MYSQL_STMT* MYSQL_PROXY::stmt_init() {
return mysql_stmt_init(mysql);
}
int MYSQL_PROXY::stmt_prepare(MYSQL_STMT* stmt, const char* query, unsigned long length) {
return mysql_stmt_prepare(stmt, query, length);
}
int MYSQL_PROXY::stmt_execute(MYSQL_STMT* stmt) {
return mysql_stmt_execute(stmt);
}
int MYSQL_PROXY::stmt_fetch(MYSQL_STMT* stmt) {
return mysql_stmt_fetch(stmt);
}
int MYSQL_PROXY::stmt_fetch_column(MYSQL_STMT* stmt, MYSQL_BIND* bind_arg, unsigned int column, unsigned long offset) {
return mysql_stmt_fetch_column(stmt, bind_arg, column, offset);
}
int MYSQL_PROXY::stmt_store_result(MYSQL_STMT* stmt) {
return mysql_stmt_store_result(stmt);
}
unsigned long MYSQL_PROXY::stmt_param_count(MYSQL_STMT* stmt) {
return mysql_stmt_param_count(stmt);
}
bool MYSQL_PROXY::stmt_bind_param(MYSQL_STMT* stmt, MYSQL_BIND* bnd) {
return mysql_stmt_bind_param(stmt, bnd);
}
bool MYSQL_PROXY::stmt_bind_named_param(MYSQL_STMT *stmt, MYSQL_BIND *binds,
unsigned n_params, const char **names) {
return mysql_stmt_bind_named_param(stmt, binds, n_params, names);
}
bool MYSQL_PROXY::stmt_bind_result(MYSQL_STMT* stmt, MYSQL_BIND* bnd) {
return mysql_stmt_bind_result(stmt, bnd);
}
bool MYSQL_PROXY::stmt_close(MYSQL_STMT* stmt) {
return mysql_stmt_close(stmt);
}
bool MYSQL_PROXY::stmt_reset(MYSQL_STMT* stmt) {
return mysql_stmt_reset(stmt);
}
bool MYSQL_PROXY::stmt_free_result(MYSQL_STMT* stmt) {
return mysql_stmt_free_result(stmt);
}
bool MYSQL_PROXY::stmt_send_long_data(MYSQL_STMT* stmt, unsigned int param_number, const char* data,
unsigned long length) {
return mysql_stmt_send_long_data(stmt, param_number, data, length);
}
MYSQL_RES* MYSQL_PROXY::stmt_result_metadata(MYSQL_STMT* stmt) {
return mysql_stmt_result_metadata(stmt);
}
unsigned int MYSQL_PROXY::stmt_errno(MYSQL_STMT* stmt) {
return mysql_stmt_errno(stmt);
}
const char* MYSQL_PROXY::stmt_error(MYSQL_STMT* stmt) {
return mysql_stmt_error(stmt);
}
MYSQL_ROW_OFFSET MYSQL_PROXY::stmt_row_seek(MYSQL_STMT* stmt, MYSQL_ROW_OFFSET offset) {
return mysql_stmt_row_seek(stmt, offset);
}
MYSQL_ROW_OFFSET MYSQL_PROXY::stmt_row_tell(MYSQL_STMT* stmt) {
return mysql_stmt_row_tell(stmt);
}
void MYSQL_PROXY::stmt_data_seek(MYSQL_STMT* stmt, uint64_t offset) {
mysql_stmt_data_seek(stmt, offset);
}
uint64_t MYSQL_PROXY::stmt_num_rows(MYSQL_STMT* stmt) {
return mysql_stmt_num_rows(stmt);
}
uint64_t MYSQL_PROXY::stmt_affected_rows(MYSQL_STMT* stmt) {
return mysql_stmt_affected_rows(stmt);
}
unsigned int MYSQL_PROXY::stmt_field_count(MYSQL_STMT* stmt) {
return mysql_stmt_field_count(stmt);
}
st_mysql_client_plugin* MYSQL_PROXY::client_find_plugin(const char* name, int type) {
return mysql_client_find_plugin(mysql, name, type);
}
bool MYSQL_PROXY::is_connected() {
return this->mysql != nullptr && this->mysql->net.vio;
}
void MYSQL_PROXY::set_last_error_code(unsigned int error_code) {
this->mysql->net.last_errno = error_code;
}
char* MYSQL_PROXY::get_last_error() const {
return this->mysql->net.last_error;
}
unsigned int MYSQL_PROXY::get_last_error_code() const {
return this->mysql->net.last_errno;
}
char* MYSQL_PROXY::get_sqlstate() const {
return this->mysql->net.sqlstate;
}
char* MYSQL_PROXY::get_server_version() const {
return this->mysql->server_version;
}
uint64_t MYSQL_PROXY::get_affected_rows() const {
return this->mysql->affected_rows;
}
void MYSQL_PROXY::set_affected_rows(uint64_t num_rows) {
this->mysql->affected_rows = num_rows;
}
char* MYSQL_PROXY::get_host_info() const {
return this->mysql->host_info;
}
std::string MYSQL_PROXY::get_host() {
return (this->mysql && this->mysql->host) ? this->mysql->host : this->host->get_host();
}
unsigned int MYSQL_PROXY::get_port() {
return (this->mysql) ? this->mysql->port : this->host->get_port();
}
unsigned long MYSQL_PROXY::get_max_packet() const {
return this->mysql->net.max_packet;
}
unsigned long MYSQL_PROXY::get_server_capabilities() const {
return this->mysql->server_capabilities;
}
unsigned int MYSQL_PROXY::get_server_status() const {
return this->mysql->server_status;
}
void MYSQL_PROXY::delete_ds() {
if (ds) {
delete ds;
ds = nullptr;
}
}
MYSQL* MYSQL_PROXY::move_mysql_connection() {
MYSQL* ret = this->mysql;
this->mysql = nullptr;
return ret;
}
void MYSQL_PROXY::set_connection(CONNECTION_PROXY* connection_proxy) {
close();
this->mysql = connection_proxy->move_mysql_connection();
// delete the ds initialized in CONNECTION_HANDLER::clone_dbc()
delete connection_proxy;
}
void MYSQL_PROXY::close_socket() {
MYLOG_DBC_TRACE(dbc, "Closing socket");
int ret = 0;
if (mysql->net.fd != INVALID_SOCKET && (ret = shutdown(mysql->net.fd, SHUT_RDWR))) {
MYLOG_DBC_TRACE(dbc, "shutdown() with return code: %d, error message: %s,", ret, strerror(socket_errno));
}
// Yield to main thread to handle socket shutdown
std::this_thread::sleep_for(SOCKET_CLOSE_DELAY);
if (mysql->net.fd != INVALID_SOCKET && (ret = ::closesocket(mysql->net.fd))) {
MYLOG_DBC_TRACE(dbc, "closesocket() with return code: %d, error message: %s,", ret, strerror(socket_errno));
}
}