You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-08 14:02:17 +03:00
Initial aurora implementation
This commit is contained in:
@@ -21,6 +21,14 @@ IF(COMMAND CMAKE_POLICY)
|
||||
CMAKE_POLICY(SET CMP0003 NEW)
|
||||
ENDIF()
|
||||
|
||||
#Allow access to non existing targets
|
||||
IF(CMAKE_VERSION VERSION_GREATER "2.9.9")
|
||||
CMAKE_POLICY(SET CMP0026 OLD)
|
||||
CMAKE_POLICY(SET CMP0042 OLD)
|
||||
CMAKE_POLICY(SET CMP0045 OLD)
|
||||
ENDIF()
|
||||
|
||||
|
||||
SET(MARIADB_CONNECTOR_C_COPYRIGHT "2013-2015 MariaDB Corporation Ab")
|
||||
|
||||
### Options ###
|
||||
@@ -149,6 +157,10 @@ IF(CMAKE_HAVE_PTHREAD_H)
|
||||
SET(CMAKE_REQUIRED_INCLUDES pthread.h)
|
||||
ENDIF()
|
||||
|
||||
IF(DBUG_OFF)
|
||||
ADD_DEFINITIONS(-DDBUG_OFF=1)
|
||||
ENDIF()
|
||||
|
||||
IF(WIN32)
|
||||
SET(HAVE_THREADS 1)
|
||||
ADD_DEFINITIONS(-DHAVE_DLOPEN)
|
||||
|
@@ -1,12 +1,16 @@
|
||||
# plugin configuration
|
||||
|
||||
MACRO(REGISTER_PLUGIN name source struct type target allow)
|
||||
SET(PLUGIN_TYPE ${${name}})
|
||||
IF(NOT PLUGIN_TYPE STREQUAL "OFF")
|
||||
SET(PLUGIN_TYPE ${type})
|
||||
ENDIF()
|
||||
IF(PLUGINS)
|
||||
LIST(REMOVE_ITEM PLUGINS ${name})
|
||||
ENDIF()
|
||||
SET(${name}_PLUGIN_SOURCE ${source})
|
||||
MARK_AS_ADVANCED(${name}_PLUGIN_SOURCE})
|
||||
SET(${name}_PLUGIN_TYPE ${type})
|
||||
SET(${name}_PLUGIN_TYPE ${PLUGIN_TYPE})
|
||||
IF(NOT ${target} STREQUAL "")
|
||||
SET(${name}_PLUGIN_TARGET ${target})
|
||||
ENDIF()
|
||||
@@ -41,6 +45,7 @@ REGISTER_PLUGIN("TRACE_EXAMPLE" "${CMAKE_SOURCE_DIR}/plugins/trace/trace_example
|
||||
|
||||
#Connection
|
||||
REGISTER_PLUGIN("REPLICATION" "${CMAKE_SOURCE_DIR}/plugins/connection/replication.c" "connection_replication_plugin" "STATIC" "" 1)
|
||||
REGISTER_PLUGIN("AURORA" "${CMAKE_SOURCE_DIR}/plugins/connection/aurora.c" "connection_aurora_plugin" "STATIC" "" 1)
|
||||
|
||||
# Allow registration of additional plugins
|
||||
IF(PLUGIN_CONF_FILE)
|
||||
@@ -50,7 +55,7 @@ ENDIF()
|
||||
|
||||
SET(LIBMARIADB_SOURCES "")
|
||||
|
||||
MESSAGE(STATUS "Plugin configuration")
|
||||
MESSAGE(STATUS "Plugin configuration:")
|
||||
FOREACH(PLUGIN ${PLUGINS})
|
||||
IF(WITH_${PLUGIN}_PLUGIN AND ${${PLUGIN}_PLUGIN_CHG} GREATER 0)
|
||||
SET(${PLUGIN}_PLUGIN_TYPE ${WITH_${PLUGIN}_PLUGIN})
|
||||
|
@@ -52,6 +52,8 @@ struct st_mysql_options_extension {
|
||||
char *ssl_fp; /* finger print of server certificate */
|
||||
char *ssl_fp_list; /* white list of finger prints */
|
||||
char *ssl_pw; /* password for encrypted certificates */
|
||||
char *url; /* for connection handler we need to save URL for reconnect */
|
||||
my_bool read_only;
|
||||
};
|
||||
|
||||
#define OPT_HAS_EXT_VAL(a,key) \
|
||||
|
@@ -482,8 +482,8 @@ const char * STDCALL mysql_get_client_info(void);
|
||||
unsigned long STDCALL mysql_get_client_version(void);
|
||||
my_bool STDCALL mariadb_connection(MYSQL *mysql);
|
||||
const char * STDCALL mysql_get_server_name(MYSQL *mysql);
|
||||
CHARSET_INFO * STDCALL mysql_get_charset_by_name(const char *csname);
|
||||
CHARSET_INFO * STDCALL mysql_get_charset_by_nr(unsigned int csnr);
|
||||
CHARSET_INFO * STDCALL mariadb_get_charset_by_name(const char *csname);
|
||||
CHARSET_INFO * STDCALL mariadb_get_charset_by_nr(unsigned int csnr);
|
||||
size_t STDCALL mariadb_convert_string(const char *from, size_t *from_len, CHARSET_INFO *from_cs,
|
||||
char *to, size_t *to_len, CHARSET_INFO *to_cs, int *errorcode);
|
||||
int STDCALL mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...);
|
||||
@@ -493,6 +493,7 @@ my_socket STDCALL mysql_get_socket(const MYSQL *mysql);
|
||||
unsigned int STDCALL mysql_get_timeout_value(const MYSQL *mysql);
|
||||
unsigned int STDCALL mysql_get_timeout_value_ms(const MYSQL *mysql);
|
||||
int STDCALL mariadb_get_connection_type(MYSQL *mysql);
|
||||
my_bool STDCALL mysql_reconnect(MYSQL *mysql);
|
||||
|
||||
/* Async API */
|
||||
int STDCALL mysql_close_start(MYSQL *sock);
|
||||
@@ -628,6 +629,7 @@ struct st_mysql_methods {
|
||||
int (*db_stmt_fetch_to_bind)(MYSQL_STMT *stmt, unsigned char *row);
|
||||
void (*db_stmt_flush_unbuffered)(MYSQL_STMT *stmt);
|
||||
void (*set_error)(MYSQL *mysql, unsigned int error_nr, const char *sqlstate, const char *format, ...);
|
||||
my_bool (*reconnect)(MYSQL *mysql);
|
||||
};
|
||||
|
||||
/* synonyms/aliases functions */
|
||||
|
@@ -95,6 +95,7 @@ typedef struct st_ma_connection_plugin
|
||||
int (*options)(MYSQL *mysql, enum mysql_option, void *arg);
|
||||
int (*set_connection)(MYSQL *mysql,enum enum_server_command command, const char *arg,
|
||||
size_t length, my_bool skipp_check, void *opt_arg);
|
||||
my_bool (*reconnect)(MYSQL *mysql);
|
||||
} MARIADB_CONNECTION_PLUGIN;
|
||||
|
||||
#define MARIADB_DB_DRIVER(a) ((a)->ext_db)
|
||||
|
@@ -230,6 +230,7 @@ typedef struct st_connection_handler
|
||||
{
|
||||
struct st_ma_connection_plugin *plugin;
|
||||
void *data;
|
||||
my_bool active;
|
||||
my_bool free_data;
|
||||
} MA_CONNECTION_HANDLER;
|
||||
|
||||
|
@@ -34,6 +34,8 @@ SET(EXPORT_SYMBOLS
|
||||
mariadb_dyncol_val_double
|
||||
mariadb_dyncol_val_long
|
||||
mariadb_dyncol_val_str
|
||||
mariadb_get_charset_by_name
|
||||
mariadb_get_charset_by_nr
|
||||
mariadb_get_connection_type
|
||||
mysql_affected_rows
|
||||
mysql_autocommit
|
||||
@@ -124,6 +126,7 @@ SET(EXPORT_SYMBOLS
|
||||
mysql_query
|
||||
mysql_query_cont
|
||||
mysql_query_start
|
||||
mysql_reconnect
|
||||
mysql_read_query_result
|
||||
mysql_read_query_result_cont
|
||||
mysql_read_query_result_start
|
||||
|
@@ -124,11 +124,14 @@ struct st_mysql_methods MARIADB_DEFAULT_METHODS;
|
||||
|
||||
#define native_password_plugin_name "mysql_native_password"
|
||||
|
||||
#define IS_CONNHDLR_ACTIVE(mysql)\
|
||||
((mysql)->net.conn_hdlr && (mysql)->net.conn_hdlr->active)
|
||||
|
||||
static void end_server(MYSQL *mysql);
|
||||
static void mysql_close_memory(MYSQL *mysql);
|
||||
void read_user_name(char *name);
|
||||
static void append_wild(char *to,char *end,const char *wild);
|
||||
static my_bool mysql_reconnect(MYSQL *mysql);
|
||||
my_bool mysql_reconnect(MYSQL *mysql);
|
||||
static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length);
|
||||
|
||||
extern int mysql_client_plugin_init();
|
||||
@@ -354,13 +357,6 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
|
||||
|
||||
DBUG_PRINT("info", ("server_command: %d packet_size: %u", command, length));
|
||||
|
||||
if (mysql->net.conn_hdlr && mysql->net.conn_hdlr->data)
|
||||
{
|
||||
result= mysql->net.conn_hdlr->plugin->set_connection(mysql, command, arg, length, skipp_check, opt_arg);
|
||||
if (result== -1)
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
if (mysql->net.pvio == 0)
|
||||
{ /* Do reconnect if possible */
|
||||
if (mysql_reconnect(mysql))
|
||||
@@ -376,6 +372,14 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (IS_CONNHDLR_ACTIVE(mysql))
|
||||
{
|
||||
result= mysql->net.conn_hdlr->plugin->set_connection(mysql, command, arg, length, skipp_check, opt_arg);
|
||||
if (result== -1)
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
|
||||
CLEAR_CLIENT_ERROR(mysql);
|
||||
|
||||
mysql->info=0;
|
||||
@@ -384,13 +388,6 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
|
||||
if (!arg)
|
||||
arg="";
|
||||
|
||||
/* check if connection kills itself */
|
||||
if (command == COM_PROCESS_KILL)
|
||||
{
|
||||
unsigned long thread_id= uint4korr(arg);
|
||||
if (thread_id == mysql->thread_id)
|
||||
skipp_check= 1;
|
||||
}
|
||||
if (net_write_command(net,(uchar) command,arg,
|
||||
length ? length : (ulong) strlen(arg)))
|
||||
{
|
||||
@@ -660,7 +657,7 @@ enum option_val
|
||||
|
||||
#define OPT_SET_EXTENDED_VALUE_INT(OPTS, KEY, VAL) \
|
||||
CHECK_OPT_EXTENSION_SET(OPTS) \
|
||||
+ (OPTS)->extension->KEY= (VAL)
|
||||
(OPTS)->extension->KEY= (VAL)
|
||||
|
||||
|
||||
static TYPELIB option_types={array_elements(default_options)-1,
|
||||
@@ -1145,6 +1142,7 @@ mysql_init(MYSQL *mysql)
|
||||
bzero((char*) (mysql),sizeof(*(mysql)));
|
||||
mysql->options.connect_timeout=CONNECT_TIMEOUT;
|
||||
mysql->charset= default_charset_info;
|
||||
mysql->methods= &MARIADB_DEFAULT_METHODS;
|
||||
strmov(mysql->net.sqlstate, "00000");
|
||||
mysql->net.last_error[0]= mysql->net.last_errno= 0;
|
||||
|
||||
@@ -1291,9 +1289,38 @@ mysql_real_connect(MYSQL *mysql, const char *host, const char *user,
|
||||
const char *passwd, const char *db,
|
||||
uint port, const char *unix_socket,unsigned long client_flag)
|
||||
{
|
||||
char *end;
|
||||
|
||||
if (!mysql->methods)
|
||||
mysql->methods= &MARIADB_DEFAULT_METHODS;
|
||||
|
||||
if (host && (end= strstr(host, "://")))
|
||||
{
|
||||
MARIADB_CONNECTION_PLUGIN *plugin;
|
||||
char plugin_name[64];
|
||||
|
||||
bzero(plugin_name, 64);
|
||||
strncpy(plugin_name, host, MIN(end - host, 63));
|
||||
end+= 3;
|
||||
|
||||
if (!(plugin= (MARIADB_CONNECTION_PLUGIN *)mysql_client_find_plugin(mysql, plugin_name, MARIADB_CLIENT_CONNECTION_PLUGIN)))
|
||||
return NULL;
|
||||
|
||||
if (!(mysql->net.conn_hdlr= (MA_CONNECTION_HANDLER *)my_malloc(sizeof(MA_CONNECTION_HANDLER), MYF(MY_ZEROFILL))))
|
||||
{
|
||||
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* save URL for reconnect */
|
||||
OPT_SET_EXTENDED_VALUE_STR(&mysql->options, url, host);
|
||||
|
||||
mysql->net.conn_hdlr->plugin= plugin;
|
||||
|
||||
if (plugin && plugin->connect)
|
||||
return plugin->connect(mysql, end, user, passwd, db, port, unix_socket, client_flag);
|
||||
}
|
||||
|
||||
return mysql->methods->db_connect(mysql, host, user, passwd,
|
||||
db, port, unix_socket, client_flag);
|
||||
}
|
||||
@@ -1320,32 +1347,6 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
|
||||
|
||||
if (!mysql->methods)
|
||||
mysql->methods= &MARIADB_DEFAULT_METHODS;
|
||||
/* special case:
|
||||
* If hostname contains "://", e.g. "repl://localhost", we need to process connection
|
||||
* by connection plugin
|
||||
*/
|
||||
if (host && (end= strstr(host, "://")))
|
||||
{
|
||||
MARIADB_CONNECTION_PLUGIN *plugin;
|
||||
char plugin_name[64];
|
||||
|
||||
bzero(plugin_name, 64);
|
||||
strncpy(plugin_name, host, MIN(end - host, 63));
|
||||
end+= 3;
|
||||
if (!(plugin= (MARIADB_CONNECTION_PLUGIN *)mysql_client_find_plugin(mysql, plugin_name, MARIADB_CLIENT_CONNECTION_PLUGIN)))
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
if (!(mysql->net.conn_hdlr= (MA_CONNECTION_HANDLER *)my_malloc(sizeof(MA_CONNECTION_HANDLER), MYF(MY_ZEROFILL))))
|
||||
{
|
||||
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
mysql->net.conn_hdlr->plugin= plugin;
|
||||
|
||||
if (plugin->connect)
|
||||
return plugin->connect(mysql, end, user, passwd, db, port, unix_socket, client_flag);
|
||||
}
|
||||
|
||||
ma_set_connect_attrs(mysql);
|
||||
|
||||
@@ -1715,14 +1716,22 @@ my_suspend_hook(my_bool suspend, void *data)
|
||||
}
|
||||
|
||||
|
||||
static my_bool mysql_reconnect(MYSQL *mysql)
|
||||
my_bool STDCALL mysql_reconnect(MYSQL *mysql)
|
||||
{
|
||||
MYSQL tmp_mysql;
|
||||
struct my_hook_data hook_data;
|
||||
struct mysql_async_context *ctxt= NULL;
|
||||
LIST *li_stmt= mysql->stmts;
|
||||
|
||||
DBUG_ENTER("mysql_reconnect");
|
||||
|
||||
/* check if connection handler is active */
|
||||
if (IS_CONNHDLR_ACTIVE(mysql))
|
||||
{
|
||||
if (mysql->net.conn_hdlr->plugin && mysql->net.conn_hdlr->plugin->connect)
|
||||
DBUG_RETURN(mysql->net.conn_hdlr->plugin->reconnect(mysql));
|
||||
}
|
||||
|
||||
if (!mysql->reconnect ||
|
||||
(mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
|
||||
{
|
||||
@@ -1734,6 +1743,13 @@ static my_bool mysql_reconnect(MYSQL *mysql)
|
||||
|
||||
mysql_init(&tmp_mysql);
|
||||
tmp_mysql.options=mysql->options;
|
||||
if (mysql->net.conn_hdlr)
|
||||
{
|
||||
tmp_mysql.net.conn_hdlr= mysql->net.conn_hdlr;
|
||||
mysql->net.conn_hdlr= 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* don't reread options from configuration files */
|
||||
tmp_mysql.options.my_cnf_group= tmp_mysql.options.my_cnf_file= NULL;
|
||||
@@ -1762,6 +1778,17 @@ static my_bool mysql_reconnect(MYSQL *mysql)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
for (;li_stmt;li_stmt= li_stmt->next)
|
||||
{
|
||||
MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
|
||||
|
||||
if (stmt->state != MYSQL_STMT_INITTED)
|
||||
{
|
||||
stmt->state= MYSQL_STMT_INITTED;
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
tmp_mysql.reconnect= mysql->reconnect;
|
||||
tmp_mysql.free_me= mysql->free_me;
|
||||
tmp_mysql.stmts= mysql->stmts;
|
||||
@@ -1923,6 +1950,7 @@ static void mysql_close_options(MYSQL *mysql)
|
||||
my_free(mysql->options.extension->ssl_fp);
|
||||
my_free(mysql->options.extension->ssl_fp_list);
|
||||
my_free(mysql->options.extension->ssl_pw);
|
||||
my_free(mysql->options.extension->url);
|
||||
if(hash_inited(&mysql->options.extension->connect_attrs))
|
||||
hash_free(&mysql->options.extension->connect_attrs);
|
||||
if ((ctxt = mysql->options.extension->async_context) != 0)
|
||||
@@ -1985,7 +2013,8 @@ mysql_close(MYSQL *mysql)
|
||||
DBUG_ENTER("mysql_close");
|
||||
if (mysql) /* Some simple safety */
|
||||
{
|
||||
if (mysql->net.conn_hdlr && mysql->net.conn_hdlr->data)
|
||||
|
||||
if (IS_CONNHDLR_ACTIVE(mysql))
|
||||
{
|
||||
void *p= (void *)mysql->net.conn_hdlr;
|
||||
mysql->net.conn_hdlr->plugin->close(mysql);
|
||||
@@ -1998,6 +2027,7 @@ mysql_close(MYSQL *mysql)
|
||||
|
||||
/* reset the connection in all active statements */
|
||||
ma_invalidate_stmts(mysql, "mysql_close()");
|
||||
|
||||
mysql_close_memory(mysql);
|
||||
mysql_close_options(mysql);
|
||||
mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
|
||||
@@ -2048,7 +2078,9 @@ int mthd_my_read_query_result(MYSQL *mysql)
|
||||
DBUG_ENTER("mthd_my_read_query_result");
|
||||
|
||||
if (!mysql || (length = net_safe_read(mysql)) == packet_error)
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
free_old_query(mysql); /* Free old result */
|
||||
get_info:
|
||||
pos=(uchar*) mysql->net.read_pos;
|
||||
@@ -2496,7 +2528,6 @@ mysql_stat(MYSQL *mysql)
|
||||
DBUG_RETURN((char*) mysql->net.read_pos);
|
||||
}
|
||||
|
||||
|
||||
int STDCALL
|
||||
mysql_ping(MYSQL *mysql)
|
||||
{
|
||||
@@ -2510,7 +2541,6 @@ mysql_ping(MYSQL *mysql)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
char * STDCALL
|
||||
mysql_get_server_info(MYSQL *mysql)
|
||||
{
|
||||
@@ -2878,10 +2908,8 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
|
||||
OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_pw, (char *)arg1);
|
||||
break;
|
||||
case MARIADB_OPT_CONNECTION_READ_ONLY:
|
||||
if (mysql->net.conn_hdlr)
|
||||
DBUG_RETURN(mysql->net.conn_hdlr->plugin->options(mysql, MARIADB_OPT_CONNECTION_READ_ONLY, arg1));
|
||||
else
|
||||
return -1;
|
||||
OPT_SET_EXTENDED_VALUE_INT(&mysql->options, read_only, *(my_bool *)arg1);
|
||||
break;
|
||||
default:
|
||||
va_end(ap);
|
||||
DBUG_RETURN(-1);
|
||||
@@ -3278,6 +3306,15 @@ int STDCALL mariadb_get_connection_type(MYSQL *mysql)
|
||||
return (int)mysql->net.pvio->type;
|
||||
}
|
||||
|
||||
CHARSET_INFO * STDCALL mariadb_get_charset_by_name(const char *csname)
|
||||
{
|
||||
return (CHARSET_INFO *)mysql_find_charset_name(csname);
|
||||
}
|
||||
|
||||
CHARSET_INFO * STDCALL mariadb_get_charset_by_nr(unsigned int csnr)
|
||||
{
|
||||
return (CHARSET_INFO *)mysql_find_charset_nr(csnr);
|
||||
}
|
||||
/*
|
||||
* Default methods for a connection. These methods are
|
||||
* stored in mysql->methods and can be overwritten by
|
||||
@@ -3315,5 +3352,9 @@ struct st_mysql_methods MARIADB_DEFAULT_METHODS = {
|
||||
/* store values in bind buffer */
|
||||
mthd_stmt_fetch_to_bind,
|
||||
/* skip unbuffered stmt result */
|
||||
mthd_stmt_flush_unbuffered
|
||||
mthd_stmt_flush_unbuffered,
|
||||
/* set error */
|
||||
my_set_error,
|
||||
/* reconnect */
|
||||
mysql_reconnect
|
||||
};
|
||||
|
@@ -416,7 +416,6 @@ int store_param(MYSQL_STMT *stmt, int column, unsigned char **p)
|
||||
{
|
||||
DBUG_ENTER("store_param");
|
||||
DBUG_PRINT("info", ("column: %d type: %d", column, stmt->params[column].buffer_type));
|
||||
printf("type: %d\n", column, stmt->params[column].buffer_type);
|
||||
switch (stmt->params[column].buffer_type) {
|
||||
case MYSQL_TYPE_TINY:
|
||||
int1store(*p, *(uchar *)stmt->params[column].buffer);
|
||||
|
@@ -182,7 +182,9 @@ static my_bool net_realloc(NET *net, size_t length)
|
||||
/* Remove unwanted characters from connection */
|
||||
void net_clear(NET *net)
|
||||
{
|
||||
size_t len;
|
||||
DBUG_ENTER("net_clear");
|
||||
ma_pvio_has_data(net->pvio, &len);
|
||||
net->compress_pkt_nr= net->pkt_nr=0; /* Ready for new command */
|
||||
net->write_pos=net->buff;
|
||||
DBUG_VOID_RETURN;
|
||||
@@ -193,6 +195,7 @@ int net_flush(NET *net)
|
||||
{
|
||||
int error=0;
|
||||
DBUG_ENTER("net_flush");
|
||||
|
||||
if (net->buff != net->write_pos)
|
||||
{
|
||||
error=net_real_write(net,(char*) net->buff,
|
||||
|
@@ -13,10 +13,24 @@ IF(REPLICATION_PLUGIN_TYPE MATCHES "DYNAMIC")
|
||||
"FILE_DESCRIPTION:Connection plugin for master/slave environment")
|
||||
ENDIF()
|
||||
ADD_DEFINITIONS(-DHAVE_REPLICATION_DYNAMIC=1)
|
||||
ADD_LIBRARY(replication SHARED replication.c ${EXPORT_FILE})
|
||||
ADD_LIBRARY(replication SHARED ${replication_RC} replication.c ${EXPORT_FILE})
|
||||
SET(INSTALL_LIBS replication)
|
||||
ENDIF()
|
||||
|
||||
IF(REPLICATION_PLUGIN_TYPE MATCHES "DYNAMIC")
|
||||
IF(WIN32)
|
||||
SET_VERSION_INFO("TARGET:aurora"
|
||||
"FILE_TYPE:VFT_DLL"
|
||||
"SOURCE_FILE:plugins/connection/aurora.c"
|
||||
"ORIGINAL_FILE_NAME:aurora.dll"
|
||||
"FILE_DESCRIPTION:Connection plugin for Amazon AWS Aurora")
|
||||
ENDIF()
|
||||
ADD_DEFINITIONS(-DHAVE_AURORA_DYNAMIC=1)
|
||||
ADD_LIBRARY(aurora SHARED ${aurora_RC} aurora.c ${EXPORT_FILE})
|
||||
SET(INSTALL_LIBS ${INSTALL_LIBS} aurora)
|
||||
ENDIF()
|
||||
|
||||
|
||||
IF(INSTALL_LIBS)
|
||||
INSTALL(TARGETS
|
||||
${INSTALL_LIBS}
|
||||
|
820
plugins/connection/aurora.c
Normal file
820
plugins/connection/aurora.c
Normal file
@@ -0,0 +1,820 @@
|
||||
/************************************************************************************
|
||||
Copyright (C) 2015 MariaDB Corporation AB
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not see <http://www.gnu.org/licenses>
|
||||
or write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
|
||||
|
||||
Part of this code includes code from the PHP project which
|
||||
is freely available from http://www.php.net
|
||||
*************************************************************************************/
|
||||
|
||||
/* MariaDB Connection plugin for Aurora failover */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <errmsg.h>
|
||||
#include <ma_common.h>
|
||||
#include <mysql.h>
|
||||
#include <mysql/client_plugin.h>
|
||||
#include <string.h>
|
||||
#include <m_string.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
/* function prototypes */
|
||||
int aurora_init(char *errormsg, size_t errormsg_size,
|
||||
int unused __attribute__((unused)),
|
||||
va_list unused1 __attribute__((unused)));
|
||||
|
||||
MYSQL *aurora_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd,
|
||||
const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag);
|
||||
void aurora_close(MYSQL *mysql);
|
||||
int aurora_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
|
||||
size_t length, my_bool skipp_check, void *opt_arg);
|
||||
int aurora_set_options(MYSQL *msql, enum mysql_option option, void *arg);
|
||||
my_bool aurora_reconnect(MYSQL *mysql);
|
||||
|
||||
#define AURORA_MAX_INSTANCES 16
|
||||
|
||||
#define AURORA_UNKNOWN -1
|
||||
#define AURORA_PRIMARY 0
|
||||
#define AURORA_REPLICA 1
|
||||
#define AURORA_UNAVAILABLE 2
|
||||
|
||||
#define ENABLE_AURORA(mysql)\
|
||||
(mysql)->net.conn_hdlr->active= 1;
|
||||
#define DISABLE_AURORA(mysql)\
|
||||
(mysql)->net.conn_hdlr->active= 0;
|
||||
|
||||
#ifndef HAVE_REPLICATION_DYNAMIC
|
||||
MARIADB_CONNECTION_PLUGIN connection_aurora_plugin =
|
||||
#else
|
||||
MARIADB_CONNECTION_PLUGIN _mysql_client_plugin_declaration_ =
|
||||
#endif
|
||||
{
|
||||
MARIADB_CLIENT_CONNECTION_PLUGIN,
|
||||
MARIADB_CLIENT_CONNECTION_PLUGIN_INTERFACE_VERSION,
|
||||
"aurora",
|
||||
"Georg Richter",
|
||||
"MariaDB connection plugin for Aurora failover",
|
||||
{1, 0, 0},
|
||||
"LGPL",
|
||||
aurora_init,
|
||||
NULL,
|
||||
aurora_connect,
|
||||
aurora_close,
|
||||
aurora_set_options,
|
||||
aurora_command,
|
||||
aurora_reconnect
|
||||
};
|
||||
|
||||
typedef struct st_aurora_instance {
|
||||
char *host;
|
||||
int port;
|
||||
time_t blacklisted;
|
||||
int type;
|
||||
} AURORA_INSTANCE;
|
||||
|
||||
typedef struct st_conn_aurora {
|
||||
MARIADB_PVIO *pvio[2];
|
||||
MYSQL *mysql[2];
|
||||
my_bool active[2];
|
||||
char *url;
|
||||
unsigned int num_instances;
|
||||
AURORA_INSTANCE instance[AURORA_MAX_INSTANCES];
|
||||
char *username, *password, *database;
|
||||
unsigned int port;
|
||||
unsigned long client_flag;
|
||||
unsigned int last_instance_type; /* Primary or Replica */
|
||||
char primary_id[100];
|
||||
} AURORA;
|
||||
|
||||
#define AURORA_BLACKLIST_TIMEOUT 150
|
||||
|
||||
#define AURORA_IS_BLACKLISTED(a, i) \
|
||||
((time(NULL) - (a)->instance[(i)].blacklisted) < AURORA_BLACKLIST_TIMEOUT)
|
||||
|
||||
/* {{{ my_bool aurora_swutch_connection */
|
||||
my_bool aurora_switch_connection(MYSQL *mysql, AURORA *aurora, int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AURORA_REPLICA:
|
||||
if (aurora->mysql[AURORA_REPLICA])
|
||||
{
|
||||
mysql->net.pvio= aurora->pvio[AURORA_REPLICA];
|
||||
aurora->pvio[AURORA_REPLICA]->mysql= mysql;
|
||||
mysql->thread_id= aurora->mysql[AURORA_REPLICA]->thread_id;
|
||||
aurora->last_instance_type= AURORA_REPLICA;
|
||||
}
|
||||
break;
|
||||
case AURORA_PRIMARY:
|
||||
if (aurora->mysql[AURORA_PRIMARY])
|
||||
{
|
||||
if (aurora->mysql[AURORA_REPLICA])
|
||||
aurora->mysql[AURORA_REPLICA]->net.pvio->mysql= aurora->mysql[AURORA_REPLICA];
|
||||
mysql->net.pvio= aurora->pvio[AURORA_PRIMARY];
|
||||
mysql->thread_id= aurora->mysql[AURORA_PRIMARY]->thread_id;
|
||||
aurora->last_instance_type= AURORA_PRIMARY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ int aurora_init
|
||||
*
|
||||
* plugin initialization function
|
||||
*/
|
||||
int aurora_init(char *errormsg, size_t errormsg_size,
|
||||
int unused __attribute__((unused)),
|
||||
va_list unused1 __attribute__((unused)))
|
||||
{
|
||||
/* random generator initialization */
|
||||
#ifndef WIN32
|
||||
struct timeval tp;
|
||||
gettimeofday(&tp,NULL);
|
||||
srand(tp.tv_usec / 1000 + tp.tv_sec * 1000);
|
||||
#else
|
||||
srand(GetTickCount());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ void aurora_close_memory */
|
||||
void aurora_close_memory(AURORA *aurora)
|
||||
{
|
||||
free(aurora->url);
|
||||
free(aurora->username);
|
||||
free(aurora->password);
|
||||
free(aurora->database);
|
||||
free(aurora);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ my_bool aurora_parse_url
|
||||
*
|
||||
* parse url
|
||||
* Url has the following format:
|
||||
* instance1:port, instance2:port, .., instanceN:port
|
||||
*
|
||||
*/
|
||||
my_bool aurora_parse_url(const char *url, AURORA *aurora)
|
||||
{
|
||||
char *p, *c;
|
||||
int i;
|
||||
|
||||
if (!url || url[0] == 0)
|
||||
return 1;
|
||||
|
||||
bzero(aurora->instance, (AURORA_MAX_INSTANCES + 1) * sizeof(char *));
|
||||
bzero(&aurora->port, (AURORA_MAX_INSTANCES + 1) * sizeof(int));
|
||||
|
||||
if (aurora->url)
|
||||
free(aurora->url);
|
||||
|
||||
aurora->url= strdup(url);
|
||||
c= aurora->url;
|
||||
|
||||
/* get instances */
|
||||
while((c))
|
||||
{
|
||||
if (p= strchr(c, ','))
|
||||
{
|
||||
*p= '\0';
|
||||
p++;
|
||||
}
|
||||
if (*c)
|
||||
{
|
||||
aurora->instance[aurora->num_instances].host= c;
|
||||
aurora->num_instances++;
|
||||
}
|
||||
c= p;
|
||||
}
|
||||
|
||||
if (!aurora->num_instances)
|
||||
return 0;
|
||||
|
||||
/* check ports */
|
||||
for (i=0; i < aurora->num_instances && aurora->instance[i].host; i++)
|
||||
{
|
||||
aurora->instance[i].type= AURORA_UNKNOWN;
|
||||
|
||||
/* We need to be aware of IPv6 addresses: According to RFC3986 sect. 3.2.2
|
||||
hostnames have to be enclosed in square brackets if a port is given */
|
||||
if (aurora->instance[i].host[0]== '[' &&
|
||||
strchr(aurora->instance[i].host, ':') &&
|
||||
(p= strchr(aurora->instance[i].host,']')))
|
||||
{
|
||||
/* ignore first square bracket */
|
||||
memmove(aurora->instance[i].host,
|
||||
aurora->instance[i].host+1,
|
||||
strlen(aurora->instance[i].host) - 1);
|
||||
p= strchr(aurora->instance[i].host,']');
|
||||
*p= 0;
|
||||
p++;
|
||||
}
|
||||
else
|
||||
p= aurora->instance[i].host;
|
||||
if (p && (p= strchr(p, ':')))
|
||||
{
|
||||
*p= '\0';
|
||||
p++;
|
||||
aurora->instance[i].port= atoi(p);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ int aurora_get_instance_type
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* AURORA_PRIMARY
|
||||
* AURORA_REPLICA
|
||||
* -1 on error
|
||||
*/
|
||||
int aurora_get_instance_type(MYSQL *mysql)
|
||||
{
|
||||
int rc;
|
||||
char *query= "select variable_value from information_schema.global_variables where variable_name='INNODB_READ_ONLY' AND variable_value='OFF'";
|
||||
|
||||
if (!mysql_query(mysql, query))
|
||||
{
|
||||
MYSQL_RES *res= mysql_store_result(mysql);
|
||||
rc= mysql_num_rows(res) ? AURORA_PRIMARY : AURORA_REPLICA;
|
||||
mysql_free_result(res);
|
||||
return rc;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ my_bool aurora_get_primary_id
|
||||
*
|
||||
* try to find primary instance from slave by retrieving
|
||||
* primary_id information_schema.replica_host_status information
|
||||
*
|
||||
* If the function succeeds, primary_id will be copied into
|
||||
* aurora->primary_id
|
||||
*
|
||||
* Returns:
|
||||
* 1 on success
|
||||
* 0 if an error occured or primary_id couldn't be
|
||||
* found
|
||||
*/
|
||||
my_bool aurora_get_primary_id(MYSQL *mysql, AURORA *aurora)
|
||||
{
|
||||
my_bool rc= 0;
|
||||
|
||||
if (!mysql_query(mysql, "select server_id from information_schema.replica_host_status "
|
||||
"where session_id = 'MASTER_SESSION_ID'"))
|
||||
{
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if ((res= mysql_store_result(mysql)))
|
||||
{
|
||||
if ((row= mysql_fetch_row(res)))
|
||||
{
|
||||
if (row[0])
|
||||
{
|
||||
strcpy(aurora->primary_id, row[0]);
|
||||
rc= 1;
|
||||
}
|
||||
}
|
||||
mysql_free_result(res);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ unsigned int aurora_get_valid_instances
|
||||
*
|
||||
* returns the number of instances which are
|
||||
* not blacklisted or don't have a type assigned.
|
||||
*/
|
||||
static unsigned int aurora_get_valid_instances(AURORA *aurora, AURORA_INSTANCE **instances)
|
||||
{
|
||||
int i, valid_instances= 0;
|
||||
|
||||
memset(instances, 0, sizeof(AURORA_INSTANCE *) * AURORA_MAX_INSTANCES);
|
||||
|
||||
for (i=0; i < aurora->num_instances; i++)
|
||||
{
|
||||
if (aurora->instance[i].type != AURORA_UNAVAILABLE)
|
||||
{
|
||||
if (aurora->instance[i].type == AURORA_PRIMARY && aurora->active[AURORA_PRIMARY])
|
||||
continue;
|
||||
instances[valid_instances]= &aurora->instance[i];
|
||||
valid_instances++;
|
||||
}
|
||||
}
|
||||
return valid_instances;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ void aurora_refresh_blacklist() */
|
||||
void aurora_refresh_blacklist(AURORA *aurora)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < aurora->num_instances; i++)
|
||||
{
|
||||
if (aurora->instance[i].blacklisted &&
|
||||
!(AURORA_IS_BLACKLISTED(aurora, i)))
|
||||
{
|
||||
aurora->instance[i].blacklisted= 0;
|
||||
aurora->instance[i].type= AURORA_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ MYSQL *aurora_connect_instance() */
|
||||
MYSQL *aurora_connect_instance(AURORA *aurora, AURORA_INSTANCE *instance, MYSQL *mysql)
|
||||
{
|
||||
if (!mysql->methods->db_connect(mysql,
|
||||
instance->host,
|
||||
aurora->username,
|
||||
aurora->password,
|
||||
aurora->database,
|
||||
instance->port ? instance->port : aurora->port,
|
||||
NULL,
|
||||
aurora->client_flag))
|
||||
{
|
||||
/* connection not available */
|
||||
instance->blacklisted= time(NULL);
|
||||
instance->type= AURORA_UNAVAILABLE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check if we are slave or master */
|
||||
switch (aurora_get_instance_type(mysql))
|
||||
{
|
||||
case AURORA_PRIMARY:
|
||||
instance->type= AURORA_PRIMARY;
|
||||
return mysql;
|
||||
break;
|
||||
case AURORA_REPLICA:
|
||||
instance->type= AURORA_REPLICA;
|
||||
break;
|
||||
default:
|
||||
instance->type= AURORA_UNAVAILABLE;
|
||||
instance->blacklisted= time(NULL);
|
||||
return NULL;
|
||||
}
|
||||
if (!aurora->primary_id[0])
|
||||
aurora_get_primary_id(mysql, aurora);
|
||||
return mysql;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ void aurora_copy_mysql() */
|
||||
void aurora_copy_mysql(MYSQL *from, MYSQL *to)
|
||||
{
|
||||
LIST *li_stmt= to->stmts;
|
||||
|
||||
for (;li_stmt;li_stmt= li_stmt->next)
|
||||
{
|
||||
MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
|
||||
|
||||
if (stmt->state != MYSQL_STMT_INITTED)
|
||||
{
|
||||
stmt->state= MYSQL_STMT_INITTED;
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
from->free_me= to->free_me;
|
||||
from->reconnect= to->reconnect;
|
||||
from->net.conn_hdlr= to->net.conn_hdlr;
|
||||
from->stmts= to->stmts;
|
||||
to->stmts= NULL;
|
||||
|
||||
memset(&to->options, 0, sizeof(to->options));
|
||||
to->free_me= 0;
|
||||
to->net.conn_hdlr= 0;
|
||||
mysql_close(to);
|
||||
*to= *from;
|
||||
to->net.pvio= from->net.pvio;
|
||||
to->net.pvio->mysql= to;
|
||||
from->net.pvio= NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ my_bool aurora_find_replica() */
|
||||
my_bool aurora_find_replica(AURORA *aurora)
|
||||
{
|
||||
int valid_instances;
|
||||
my_bool replica_found= 0;
|
||||
AURORA_INSTANCE *instance[AURORA_MAX_INSTANCES];
|
||||
MYSQL mysql;
|
||||
// struct st_dynamic_array *init_command= aurora->mysql[AURORA_PRIMARY]->options.init_command;
|
||||
|
||||
if (aurora->num_instances < 2)
|
||||
return 0;
|
||||
|
||||
mysql_init(&mysql);
|
||||
mysql.options= aurora->mysql[AURORA_PRIMARY]->options;
|
||||
|
||||
/* don't execute init_command on slave */
|
||||
mysql.net.conn_hdlr= aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr;
|
||||
|
||||
valid_instances= aurora_get_valid_instances(aurora, instance);
|
||||
|
||||
while (valid_instances && !replica_found)
|
||||
{
|
||||
int random_pick= rand() % valid_instances;
|
||||
if ((aurora_connect_instance(aurora, instance[random_pick], &mysql)))
|
||||
{
|
||||
switch (instance[random_pick]->type) {
|
||||
case AURORA_REPLICA:
|
||||
if (!aurora->mysql[AURORA_REPLICA])
|
||||
{
|
||||
aurora->mysql[AURORA_REPLICA]= mysql_init(NULL);
|
||||
}
|
||||
aurora_copy_mysql(&mysql, aurora->mysql[AURORA_REPLICA]);
|
||||
aurora->active[AURORA_REPLICA]= 1;
|
||||
return 1;
|
||||
break;
|
||||
case AURORA_PRIMARY:
|
||||
aurora_copy_mysql(&mysql, aurora->mysql[AURORA_PRIMARY]);
|
||||
aurora->pvio[AURORA_PRIMARY]= aurora->mysql[AURORA_PRIMARY]->net.pvio;
|
||||
aurora->active[AURORA_PRIMARY]= 1;
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
mysql_close(&mysql);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
valid_instances= aurora_get_valid_instances(aurora, instance);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ AURORA_INSTANCE aurora_get_primary_id_instance() */
|
||||
AURORA_INSTANCE *aurora_get_primary_id_instance(AURORA *aurora)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!aurora->primary_id[0])
|
||||
return 0;
|
||||
|
||||
for (i=0; i < aurora->num_instances; i++)
|
||||
{
|
||||
if (!strncmp(aurora->instance[i].host, aurora->primary_id, strlen(aurora->primary_id)))
|
||||
return &aurora->instance[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ my_bool aurora_find_primary() */
|
||||
my_bool aurora_find_primary(AURORA *aurora)
|
||||
{
|
||||
int i;
|
||||
AURORA_INSTANCE *instance= NULL;
|
||||
MYSQL mysql;
|
||||
my_bool check_primary= 1;
|
||||
|
||||
if (!aurora->num_instances)
|
||||
return 0;
|
||||
|
||||
mysql_init(&mysql);
|
||||
mysql.options= aurora->mysql[AURORA_PRIMARY]->options;
|
||||
mysql.net.conn_hdlr= aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr;
|
||||
|
||||
for (i=0; i < aurora->num_instances; i++)
|
||||
{
|
||||
if (check_primary && aurora->primary_id[0])
|
||||
{
|
||||
if ((instance= aurora_get_primary_id_instance(aurora)) &&
|
||||
aurora_connect_instance(aurora, instance, &mysql) &&
|
||||
instance->type == AURORA_PRIMARY)
|
||||
{
|
||||
aurora_copy_mysql(&mysql, aurora->mysql[AURORA_PRIMARY]);
|
||||
aurora->active[AURORA_PRIMARY]= 1;
|
||||
return 1;
|
||||
}
|
||||
/* primary id connect failed, don't try again */
|
||||
aurora->primary_id[0]= 0;
|
||||
check_primary= 0;
|
||||
}
|
||||
if (aurora->instance[i].type != AURORA_UNAVAILABLE)
|
||||
{
|
||||
if (aurora_connect_instance(aurora, &aurora->instance[i], &mysql)
|
||||
&& aurora->instance[i].type == AURORA_PRIMARY)
|
||||
{
|
||||
aurora_copy_mysql(&mysql, aurora->mysql[AURORA_PRIMARY]);
|
||||
aurora->active[AURORA_PRIMARY]= 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ void aurora_close_replica() */
|
||||
void aurora_close_replica(MYSQL *mysql, AURORA *aurora)
|
||||
{
|
||||
if (aurora->mysql[AURORA_REPLICA])
|
||||
{
|
||||
aurora->mysql[AURORA_REPLICA]->net.pvio->mysql= aurora->mysql[AURORA_REPLICA];
|
||||
aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= 0;
|
||||
mysql_close(aurora->mysql[AURORA_REPLICA]);
|
||||
aurora->pvio[AURORA_REPLICA]= 0;
|
||||
aurora->mysql[AURORA_REPLICA]= NULL;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ MYSQL *aurora_connect */
|
||||
MYSQL *aurora_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd,
|
||||
const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)
|
||||
{
|
||||
AURORA *aurora= NULL;
|
||||
MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr;
|
||||
my_bool is_reconnect= 0;
|
||||
|
||||
if ((aurora= (AURORA *)hdlr->data))
|
||||
{
|
||||
aurora_refresh_blacklist(aurora);
|
||||
if (aurora->mysql[aurora->last_instance_type]->net.pvio)
|
||||
{
|
||||
SET_CLIENT_ERROR(mysql, CR_ALREADY_CONNECTED, SQLSTATE_UNKNOWN, 0);
|
||||
return NULL;
|
||||
}
|
||||
is_reconnect= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(aurora= (AURORA *)my_malloc(sizeof(AURORA), MYF(MY_ZEROFILL))))
|
||||
{
|
||||
mysql->methods->set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mysql->net.conn_hdlr->data= (void *)aurora;
|
||||
|
||||
aurora->mysql[AURORA_PRIMARY]= mysql;
|
||||
|
||||
if (aurora_parse_url(host, aurora))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (user)
|
||||
aurora->username= strdup(user);
|
||||
if (passwd)
|
||||
aurora->password= strdup(passwd);
|
||||
if (db)
|
||||
aurora->database= strdup(db);
|
||||
aurora->port= port;
|
||||
aurora->client_flag= client_flag;
|
||||
aurora->pvio[AURORA_PRIMARY]= aurora->pvio[AURORA_REPLICA]= NULL;
|
||||
hdlr->data= aurora;
|
||||
}
|
||||
|
||||
|
||||
/* In case of reconnect, close broken connection first */
|
||||
if (is_reconnect)
|
||||
{
|
||||
DISABLE_AURORA(mysql);
|
||||
switch (aurora->last_instance_type) {
|
||||
case AURORA_REPLICA:
|
||||
aurora_close_replica(mysql, aurora);
|
||||
aurora->pvio[AURORA_REPLICA]= NULL;
|
||||
break;
|
||||
case AURORA_PRIMARY:
|
||||
/* pvio will be closed in mysql_reconnect() */
|
||||
aurora->pvio[AURORA_PRIMARY]= NULL;
|
||||
aurora->primary_id[0]= 0;
|
||||
break;
|
||||
}
|
||||
aurora->active[aurora->last_instance_type]= 0;
|
||||
}
|
||||
|
||||
if (!aurora->active[AURORA_REPLICA])
|
||||
{
|
||||
if (aurora_find_replica(aurora))
|
||||
{
|
||||
aurora->pvio[AURORA_REPLICA]= aurora->mysql[AURORA_REPLICA]->net.pvio;
|
||||
aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= mysql->net.conn_hdlr;
|
||||
}
|
||||
else
|
||||
aurora->pvio[AURORA_REPLICA]= NULL;
|
||||
}
|
||||
|
||||
if (!aurora->active[AURORA_PRIMARY])
|
||||
{
|
||||
if (aurora_find_primary(aurora))
|
||||
{
|
||||
aurora->active[AURORA_PRIMARY]= 1;
|
||||
aurora->pvio[AURORA_PRIMARY]= aurora->mysql[AURORA_PRIMARY]->net.pvio;
|
||||
}
|
||||
}
|
||||
|
||||
aurora_switch_connection(mysql, aurora, AURORA_PRIMARY);
|
||||
ENABLE_AURORA(mysql);
|
||||
return mysql;
|
||||
error:
|
||||
aurora_close_memory(aurora);
|
||||
return NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ my_bool aurora_reconnect */
|
||||
my_bool aurora_reconnect(MYSQL *mysql)
|
||||
{
|
||||
AURORA *aurora;
|
||||
MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr;
|
||||
my_bool rc= 1;
|
||||
|
||||
aurora= (AURORA *)hdlr->data;
|
||||
|
||||
DISABLE_AURORA(mysql);
|
||||
switch (aurora->last_instance_type)
|
||||
{
|
||||
case AURORA_REPLICA:
|
||||
if (!(rc= mysql->methods->reconnect(aurora->mysql[aurora->last_instance_type])))
|
||||
aurora_switch_connection(mysql, aurora, AURORA_REPLICA);
|
||||
break;
|
||||
case AURORA_PRIMARY:
|
||||
if (!(rc= mysql->methods->reconnect(aurora->mysql[aurora->last_instance_type])))
|
||||
aurora_switch_connection(mysql, aurora, AURORA_PRIMARY);
|
||||
break;
|
||||
default:
|
||||
/* todo: error message */
|
||||
break;
|
||||
}
|
||||
ENABLE_AURORA(mysql);
|
||||
return rc;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ void aurora_close */
|
||||
void aurora_close(MYSQL *mysql)
|
||||
{
|
||||
MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr;
|
||||
AURORA *aurora= (AURORA *)hdlr->data;
|
||||
|
||||
aurora_switch_connection(mysql, aurora, AURORA_PRIMARY);
|
||||
|
||||
/* if the connection is not active yet, just return */
|
||||
if (!aurora->active[1])
|
||||
return;
|
||||
|
||||
if (aurora->mysql[AURORA_REPLICA])
|
||||
{
|
||||
/* we got options from primary, so don't free it twice */
|
||||
memset(&aurora->mysql[AURORA_REPLICA]->options, 0, sizeof(mysql->options));
|
||||
/* connection handler wull be freed in mysql_close() */
|
||||
aurora->mysql[AURORA_REPLICA]->net.conn_hdlr= 0;
|
||||
|
||||
mysql_close(aurora->mysql[AURORA_REPLICA]);
|
||||
}
|
||||
|
||||
if (aurora->mysql[AURORA_PRIMARY])
|
||||
{
|
||||
/* connection handler wull be freed in mysql_close() */
|
||||
aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr= 0;
|
||||
|
||||
aurora->mysql[AURORA_PRIMARY]->net.pvio= aurora->pvio[AURORA_PRIMARY];
|
||||
|
||||
mysql_close(aurora->mysql[AURORA_PRIMARY]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
if (aurora->mysql[AURORA_PRIMARY])
|
||||
{
|
||||
aurora->mysql[AURORA_PRIMARY]->net.pvio= aurora->pvio[AURORA_PRIMARY];
|
||||
aurora->mysql[AURORA_PRIMARY]->net.conn_hdlr= 0;
|
||||
mysql_close(aurora->mysql[AURORA_PRIMARY]);
|
||||
}
|
||||
*/
|
||||
/* free masrwe information */
|
||||
aurora_close_memory(aurora);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ my_bool is_replica_command */
|
||||
my_bool is_replica_command(const char *buffer, size_t buffer_len)
|
||||
{
|
||||
const char *buffer_end= buffer + buffer_len;
|
||||
|
||||
for (; buffer < buffer_end; ++buffer)
|
||||
{
|
||||
char c;
|
||||
if (isalpha(c=*buffer))
|
||||
{
|
||||
if (tolower(c) == 's')
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ my_bool is_replica_stmt */
|
||||
my_bool is_replica_stmt(MYSQL *mysql, const char *buffer)
|
||||
{
|
||||
unsigned long stmt_id= uint4korr(buffer);
|
||||
LIST *stmt_list= mysql->stmts;
|
||||
|
||||
for (; stmt_list; stmt_list= stmt_list->next)
|
||||
{
|
||||
MYSQL_STMT *stmt= (MYSQL_STMT *)stmt_list->data;
|
||||
if (stmt->stmt_id == stmt_id)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ int aurora_command */
|
||||
int aurora_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
|
||||
size_t length, my_bool skipp_check, void *opt_arg)
|
||||
{
|
||||
AURORA *aurora= (AURORA *)mysql->net.conn_hdlr->data;
|
||||
|
||||
/* if we don't have slave or slave became unavailable root traffic to master */
|
||||
if (!aurora->mysql[AURORA_REPLICA] || !OPT_HAS_EXT_VAL(mysql, read_only))
|
||||
{
|
||||
if (command != COM_INIT_DB)
|
||||
{
|
||||
aurora_switch_connection(mysql, aurora, AURORA_PRIMARY);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch(command) {
|
||||
case COM_INIT_DB:
|
||||
/* we need to change default database on primary and replica */
|
||||
if (aurora->mysql[AURORA_REPLICA] && aurora->last_instance_type != AURORA_REPLICA)
|
||||
{
|
||||
aurora_switch_connection(mysql, aurora, AURORA_REPLICA);
|
||||
DISABLE_AURORA(mysql);
|
||||
mysql_select_db(aurora->mysql[AURORA_REPLICA], arg);
|
||||
ENABLE_AURORA(mysql);
|
||||
aurora_switch_connection(mysql, aurora, AURORA_PRIMARY);
|
||||
}
|
||||
break;
|
||||
case COM_QUERY:
|
||||
case COM_STMT_PREPARE:
|
||||
if (aurora->mysql[AURORA_REPLICA] && aurora->last_instance_type != AURORA_REPLICA)
|
||||
aurora_switch_connection(mysql, aurora, AURORA_REPLICA);
|
||||
break;
|
||||
case COM_STMT_EXECUTE:
|
||||
case COM_STMT_FETCH:
|
||||
if (aurora->pvio[AURORA_REPLICA]->mysql->stmts && is_replica_stmt(aurora->pvio[AURORA_REPLICA]->mysql, arg))
|
||||
{
|
||||
if (aurora->last_instance_type != AURORA_REPLICA)
|
||||
aurora_switch_connection(mysql, aurora, AURORA_REPLICA);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aurora->last_instance_type != AURORA_PRIMARY)
|
||||
aurora_switch_connection(mysql, aurora, AURORA_PRIMARY);
|
||||
}
|
||||
|
||||
default:
|
||||
aurora_switch_connection(mysql, aurora, AURORA_PRIMARY);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ int aurora_set_options() */
|
||||
int aurora_set_options(MYSQL *mysql, enum mysql_option option, void *arg)
|
||||
{
|
||||
switch(option) {
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
@@ -70,7 +70,8 @@ MARIADB_CONNECTION_PLUGIN _mysql_client_plugin_declaration_ =
|
||||
repl_connect,
|
||||
repl_close,
|
||||
repl_set_options,
|
||||
repl_command
|
||||
repl_command,
|
||||
NULL
|
||||
};
|
||||
|
||||
typedef struct st_conn_repl {
|
||||
@@ -81,10 +82,20 @@ typedef struct st_conn_repl {
|
||||
char *url;
|
||||
char *host[2];
|
||||
int port[2];
|
||||
unsigned int current_type;
|
||||
} REPL_DATA;
|
||||
|
||||
#define SET_SLAVE(mysql, data) mysql->net.pvio= data->pvio[MARIADB_SLAVE]
|
||||
#define SET_MASTER(mysql, data) mysql->net.pvio= data->pvio[MARIADB_MASTER]
|
||||
#define SET_SLAVE(mysql, data)\
|
||||
{\
|
||||
mysql->net.pvio= data->pvio[MARIADB_SLAVE]; \
|
||||
data->current_type= MARIADB_SLAVE;\
|
||||
}
|
||||
|
||||
#define SET_MASTER(mysql, data)\
|
||||
{\
|
||||
mysql->net.pvio= data->pvio[MARIADB_MASTER];\
|
||||
data->current_type= MARIADB_MASTER;\
|
||||
}
|
||||
|
||||
|
||||
/* parse url
|
||||
@@ -108,9 +119,7 @@ my_bool repl_parse_url(const char *url, REPL_DATA *data)
|
||||
memset(data->host, 0, 2 * sizeof(char *));
|
||||
memset(data->port, 0, 2 * sizeof(int));
|
||||
|
||||
if (data->url)
|
||||
my_free(data->url);
|
||||
|
||||
if (!data->url)
|
||||
data->url= my_strdup(url, MYF(0));
|
||||
data->host[MARIADB_MASTER]= p= data->url;
|
||||
|
||||
@@ -150,10 +159,11 @@ my_bool repl_parse_url(const char *url, REPL_DATA *data)
|
||||
{
|
||||
/* We need to be aware of IPv6 addresses: According to RFC3986 sect. 3.2.2
|
||||
hostnames have to be enclosed in square brackets if a port is given */
|
||||
if (data->host[i][0]= '[' && strchr(data->host[i], ':') && (p= strchr(data->host[i],']')))
|
||||
if (data->host[i][0]== '[' && strchr(data->host[i], ':') && (p= strchr(data->host[i],']')))
|
||||
{
|
||||
/* ignore first square bracket */
|
||||
data->host[i]++;
|
||||
memmove(data->host[i], data->host[i]+1, strlen(data->host[i]) - 1);
|
||||
p= strchr(data->host[i],']');
|
||||
*p= 0;
|
||||
p++;
|
||||
}
|
||||
@@ -176,12 +186,18 @@ MYSQL *repl_connect(MYSQL *mysql, const char *host, const char *user, const char
|
||||
REPL_DATA *data= NULL;
|
||||
MA_CONNECTION_HANDLER *hdlr= mysql->net.conn_hdlr;
|
||||
|
||||
if ((data= (REPL_DATA *)hdlr->data))
|
||||
{
|
||||
ma_pvio_close(data->pvio[MARIADB_MASTER]);
|
||||
data->pvio[MARIADB_MASTER]= 0;
|
||||
repl_close(mysql);
|
||||
}
|
||||
|
||||
if (!(data= calloc(1, sizeof(REPL_DATA))))
|
||||
{
|
||||
mysql->methods->set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(data->pvio, 0, 2 * sizeof(MARIADB_PVIO *));
|
||||
|
||||
if (repl_parse_url(host, data))
|
||||
@@ -194,6 +210,7 @@ MYSQL *repl_connect(MYSQL *mysql, const char *host, const char *user, const char
|
||||
|
||||
data->pvio[MARIADB_MASTER]= mysql->net.pvio;
|
||||
hdlr->data= data;
|
||||
SET_MASTER(mysql, data);
|
||||
|
||||
/* to allow immediate access without connection delay, we will start
|
||||
* connecting to slave(s) in background */
|
||||
@@ -245,7 +262,6 @@ void repl_close(MYSQL *mysql)
|
||||
my_free(data->url);
|
||||
my_free(data);
|
||||
mysql->net.conn_hdlr->data= NULL;
|
||||
mysql_close(mysql);
|
||||
}
|
||||
|
||||
static my_bool is_slave_command(const char *buffer, size_t buffer_len)
|
||||
@@ -295,20 +311,20 @@ int repl_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
|
||||
case COM_QUERY:
|
||||
case COM_STMT_PREPARE:
|
||||
if (is_slave_command(arg, length))
|
||||
SET_SLAVE(mysql, data);
|
||||
SET_SLAVE(mysql, data)
|
||||
else
|
||||
SET_MASTER(mysql,data);
|
||||
SET_MASTER(mysql,data)
|
||||
break;
|
||||
case COM_STMT_EXECUTE:
|
||||
case COM_STMT_FETCH:
|
||||
if (data->pvio[MARIADB_SLAVE]->mysql->stmts && is_slave_stmt(data->pvio[MARIADB_SLAVE]->mysql, arg))
|
||||
SET_SLAVE(mysql, data);
|
||||
SET_SLAVE(mysql, data)
|
||||
else
|
||||
SET_MASTER(mysql,data);
|
||||
SET_MASTER(mysql,data)
|
||||
break;
|
||||
|
||||
default:
|
||||
SET_MASTER(mysql,data);
|
||||
SET_MASTER(mysql,data)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@@ -251,7 +251,7 @@ my_bool pvio_npipe_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo)
|
||||
0, /* no sharing */
|
||||
NULL, /* default security attributes */
|
||||
OPEN_EXISTING,
|
||||
0, /* default attributes */
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL)) != INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
|
@@ -21,7 +21,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/unittest/mytap)
|
||||
ADD_DEFINITIONS(-DLIBMARIADB)
|
||||
|
||||
SET(API_TESTS "async" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
|
||||
SET(API_TESTS "aurora" "async" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
|
||||
"sp" "result" "connection" "misc" "ps_new" "sqlite3" "thread" "dyncol")
|
||||
|
||||
# Get finger print from server certificate
|
||||
@@ -61,7 +61,7 @@ ENDIF()
|
||||
|
||||
FOREACH(API_TEST ${API_TESTS})
|
||||
ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c)
|
||||
TARGET_LINK_LIBRARIES(${API_TEST} mytap mariadbclient )
|
||||
TARGET_LINK_LIBRARIES(${API_TEST} mytap libmariadb)
|
||||
ADD_TEST(${API_TEST} ${EXECUTABLE_OUTPUT_PATH}/${API_TEST})
|
||||
SET_TESTS_PROPERTIES(${API_TEST} PROPERTIES TIMEOUT 120)
|
||||
ENDFOREACH(API_TEST)
|
||||
|
67
unittest/libmariadb/aurora.c
Normal file
67
unittest/libmariadb/aurora.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
*/
|
||||
|
||||
#include "my_test.h"
|
||||
|
||||
static int aurora1(MYSQL *mysql)
|
||||
{
|
||||
int rc;
|
||||
my_bool read_only= 1;
|
||||
char *primary, *replica;
|
||||
MYSQL_RES *res;
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
rc= mysql_query(mysql, "CREATE TABLE t1 (a int, b varchar(20))");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1, 'foo'), (2, 'bar')");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
primary= mysql->host;
|
||||
diag("primary: %s", primary);
|
||||
|
||||
mysql_options(mysql, MARIADB_OPT_CONNECTION_READ_ONLY, &read_only);
|
||||
|
||||
/* ensure, that this is a replica, so INSERT should fail */
|
||||
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (3, 'error')");
|
||||
if (rc)
|
||||
diag("Expected error: %s", mysql_error(mysql));
|
||||
|
||||
rc= mysql_query(mysql, "SELECT a, b FROM t1");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
res= mysql_store_result(mysql);
|
||||
|
||||
diag("Num_rows: %d", mysql_num_rows(res));
|
||||
mysql_free_result(res);
|
||||
|
||||
replica= mysql->host;
|
||||
diag("replica: %s", replica);
|
||||
diag("db: %s", mysql->db);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
struct my_tests_st my_tests[] = {
|
||||
{"aurora1", aurora1, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||
{NULL, NULL, 0, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
mysql_library_init(0,0,NULL);
|
||||
|
||||
if (argc > 1)
|
||||
get_options(argc, argv);
|
||||
|
||||
get_envvars();
|
||||
|
||||
run_tests(my_tests);
|
||||
|
||||
mysql_server_end();
|
||||
return(exit_status());
|
||||
}
|
@@ -55,13 +55,17 @@ static int test_conc75(MYSQL *my)
|
||||
{
|
||||
ulong thread_id= mysql_thread_id(mysql);
|
||||
/* force reconnect */
|
||||
mysql->reconnect= 1;
|
||||
diag("killing connection");
|
||||
mysql_kill(my, thread_id);
|
||||
sleep(1);
|
||||
sleep(2);
|
||||
mysql_ping(mysql);
|
||||
rc= mysql_query(mysql, "load data local infile './nonexistingfile.csv' into table a (`a`)");
|
||||
FAIL_IF(!test(mysql->options.client_flag | CLIENT_LOCAL_FILES), "client_flags not correct");
|
||||
diag("thread1: %d %d", thread_id, mysql_thread_id(mysql));
|
||||
FAIL_IF(thread_id == mysql_thread_id(mysql), "new thread id expected");
|
||||
diag("cs: %s", mysql->charset->csname);
|
||||
FAIL_IF(strcmp(mysql->charset->csname, "utf8"), "wrong character set");
|
||||
//diag("cs: %s", mysql->charset->csname);
|
||||
//FAIL_IF(strcmp(mysql->charset->csname, "utf8"), "wrong character set");
|
||||
}
|
||||
mysql_close(mysql);
|
||||
return OK;
|
||||
@@ -76,7 +80,12 @@ static int test_conc74(MYSQL *my)
|
||||
mysql= mysql_init(NULL);
|
||||
|
||||
|
||||
mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0| CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS);
|
||||
if (!mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0| CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS))
|
||||
{
|
||||
diag("Error: %s", mysql_error(mysql));
|
||||
mysql_close(mysql);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS a");
|
||||
check_mysql_rc(rc, mysql);
|
||||
@@ -128,7 +137,11 @@ static int test_conc70(MYSQL *my)
|
||||
int rc;
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
MYSQL *mysql= mysql_init(NULL);
|
||||
MYSQL *mysql;
|
||||
|
||||
SKIP_CONNECTION_HANDLER;
|
||||
|
||||
mysql= mysql_init(NULL);
|
||||
|
||||
rc= mysql_query(my, "SET @a:=@@max_allowed_packet");
|
||||
check_mysql_rc(rc, my);
|
||||
@@ -148,6 +161,14 @@ static int test_conc70(MYSQL *my)
|
||||
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (REPEAT('A', 1024 * 1024 * 20))");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
if (mysql_warning_count(mysql))
|
||||
{
|
||||
diag("server doesn't accept package size");
|
||||
return SKIP;
|
||||
}
|
||||
|
||||
sleep(20);
|
||||
|
||||
rc= mysql_query(mysql, "SELECT a FROM t1");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
@@ -175,7 +196,11 @@ static int test_conc68(MYSQL *my)
|
||||
int rc;
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
MYSQL *mysql= mysql_init(NULL);
|
||||
MYSQL *mysql;
|
||||
|
||||
SKIP_CONNECTION_HANDLER;
|
||||
|
||||
mysql= mysql_init(NULL);
|
||||
|
||||
rc= mysql_query(my, "SET @a:=@@max_allowed_packet");
|
||||
check_mysql_rc(rc, my);
|
||||
@@ -193,6 +218,11 @@ static int test_conc68(MYSQL *my)
|
||||
|
||||
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (REPEAT('A', 1024 * 1024 * 20))");
|
||||
check_mysql_rc(rc, mysql);
|
||||
if (mysql_warning_count(mysql))
|
||||
{
|
||||
diag("server doesn't accept package size");
|
||||
return SKIP;
|
||||
}
|
||||
|
||||
rc= mysql_query(mysql, "SELECT a FROM t1");
|
||||
check_mysql_rc(rc, mysql);
|
||||
@@ -504,6 +534,7 @@ static int test_mysql_insert_id(MYSQL *mysql)
|
||||
according to the manual, this might be 20 or 300, but it looks like
|
||||
auto_increment column takes priority over last_insert_id().
|
||||
*/
|
||||
diag("res: %d", res);
|
||||
FAIL_UNLESS(res == 20, "");
|
||||
/* If first autogenerated number fails and 2nd works: */
|
||||
rc= mysql_query(mysql, "drop table t2");
|
||||
@@ -618,12 +649,9 @@ static int bug_conc1(MYSQL *mysql)
|
||||
{
|
||||
mysql_real_connect(mysql, hostname, username, password, schema,
|
||||
port, socketname, 0);
|
||||
diag("errno: %d", mysql_errno(mysql));
|
||||
FAIL_IF(mysql_errno(mysql) != CR_ALREADY_CONNECTED,
|
||||
"Expected errno=CR_ALREADY_CONNECTED");
|
||||
FAIL_IF(strcmp(mysql_error(mysql), ER(CR_ALREADY_CONNECTED)) != 0,
|
||||
"Wrong error message");
|
||||
FAIL_IF(strcmp(ER(CR_ALREADY_CONNECTED), "Can't connect twice. Already connected") != 0,
|
||||
"wrong error message");
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -668,11 +696,14 @@ static int test_reconnect_maxpackage(MYSQL *my)
|
||||
{
|
||||
int rc;
|
||||
ulong max_packet= 0;
|
||||
MYSQL *mysql= mysql_init(NULL);
|
||||
MYSQL *mysql;
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
char *query;
|
||||
|
||||
SKIP_CONNECTION_HANDLER;
|
||||
mysql= mysql_init(NULL);
|
||||
|
||||
FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
|
||||
port, socketname,
|
||||
CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS), mysql_error(mysql));
|
||||
@@ -770,6 +801,8 @@ int main(int argc, char **argv)
|
||||
|
||||
get_envvars();
|
||||
|
||||
diag("user: %s", username);
|
||||
|
||||
run_tests(my_tests);
|
||||
|
||||
return(exit_status());
|
||||
|
@@ -679,7 +679,7 @@ static int test_utf16_utf32_noboms(MYSQL *mysql)
|
||||
|
||||
for (i= 0; i < sizeof(csname)/sizeof(char*); ++i)
|
||||
{
|
||||
csinfo[i]= mysql_find_charset_name(csname[i]);
|
||||
csinfo[i]= mariadb_get_charset_by_name(csname[i]);
|
||||
|
||||
if (csinfo[i] == NULL)
|
||||
{
|
||||
|
@@ -32,6 +32,7 @@ static int test_conc66(MYSQL *my)
|
||||
MYSQL *mysql= mysql_init(NULL);
|
||||
int rc;
|
||||
FILE *fp;
|
||||
char query[1024];
|
||||
|
||||
if (!(fp= fopen("./my.cnf", "w")))
|
||||
return FAIL;
|
||||
@@ -47,7 +48,8 @@ static int test_conc66(MYSQL *my)
|
||||
rc= mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "./my.cnf");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
rc= mysql_query(my, "GRANT ALL ON test.* TO 'conc66'@'localhost' IDENTIFIED BY 'test\";#test'");
|
||||
sprintf(query, "GRANT ALL ON %s.* TO 'conc66'@'%s' IDENTIFIED BY 'test\";#test'", schema, hostname);
|
||||
rc= mysql_query(my, query);
|
||||
check_mysql_rc(rc, my);
|
||||
rc= mysql_query(my, "FLUSH PRIVILEGES");
|
||||
check_mysql_rc(rc, my);
|
||||
@@ -57,7 +59,8 @@ static int test_conc66(MYSQL *my)
|
||||
diag("Error: %s", mysql_error(mysql));
|
||||
return FAIL;
|
||||
}
|
||||
rc= mysql_query(my, "DROP USER conc66@localhost");
|
||||
sprintf(query, "DROP user conc66@%s", hostname);
|
||||
rc= mysql_query(my, query);
|
||||
|
||||
check_mysql_rc(rc, my);
|
||||
mysql_close(mysql);
|
||||
@@ -561,6 +564,8 @@ static int test_reconnect(MYSQL *mysql)
|
||||
mysql_kill(mysql, mysql_thread_id(mysql1));
|
||||
sleep(4);
|
||||
|
||||
mysql_ping(mysql1);
|
||||
|
||||
rc= mysql_query(mysql1, "SELECT 1 FROM DUAL LIMIT 0");
|
||||
check_mysql_rc(rc, mysql1);
|
||||
diag("Thread_id after kill: %lu", mysql_thread_id(mysql1));
|
||||
@@ -649,6 +654,8 @@ static int test_conc118(MYSQL *mysql)
|
||||
rc= mysql_kill(mysql, mysql_thread_id(mysql));
|
||||
sleep(2);
|
||||
|
||||
mysql_ping(mysql);
|
||||
|
||||
rc= mysql_query(mysql, "SET @a:=1");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
@@ -657,12 +664,9 @@ static int test_conc118(MYSQL *mysql)
|
||||
rc= mysql_kill(mysql, mysql_thread_id(mysql));
|
||||
sleep(2);
|
||||
|
||||
mysql->host= "foo";
|
||||
|
||||
rc= mysql_query(mysql, "SET @a:=1");
|
||||
FAIL_IF(!rc, "error expected");
|
||||
|
||||
mysql->host= hostname;
|
||||
rc= mysql_query(mysql, "SET @a:=1");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
|
@@ -82,6 +82,13 @@ if (!(expr))\
|
||||
return FAIL;\
|
||||
}
|
||||
|
||||
#define SKIP_CONNECTION_HANDLER \
|
||||
if (hostname && strstr(hostname, "://"))\
|
||||
{\
|
||||
diag("Test skipped (connection handler)");\
|
||||
return SKIP;\
|
||||
}
|
||||
|
||||
/* connection options */
|
||||
#define TEST_CONNECTION_DEFAULT 1 /* default connection */
|
||||
#define TEST_CONNECTION_NONE 2 /* tests creates own connection */
|
||||
@@ -104,7 +111,7 @@ struct my_tests_st
|
||||
char *skipmsg;
|
||||
};
|
||||
|
||||
static char *schema = "test_c";
|
||||
static char *schema = 0;
|
||||
static char *hostname = 0;
|
||||
static char *password = 0;
|
||||
static unsigned int port = 0;
|
||||
@@ -368,18 +375,19 @@ int check_variable(MYSQL *mysql, char *variable, char *value)
|
||||
MYSQL *test_connect(struct my_tests_st *test) {
|
||||
MYSQL *mysql;
|
||||
char query[255];
|
||||
int i= 1;
|
||||
int i= 0;
|
||||
int timeout= 10;
|
||||
int truncation_report= 1;
|
||||
if (!(mysql = mysql_init(NULL))) {
|
||||
diag("%s", "mysql_init failed - exiting");
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, &i);
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&i);
|
||||
mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, &truncation_report);
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
|
||||
|
||||
/* option handling */
|
||||
if (test && test->options) {
|
||||
int i=0;
|
||||
|
||||
while (test->options[i].option)
|
||||
{
|
||||
@@ -403,6 +411,8 @@ MYSQL *test_connect(struct my_tests_st *test) {
|
||||
|
||||
/* change database or create if it doesn't exist */
|
||||
if (mysql_select_db(mysql, schema)) {
|
||||
diag("Error number: %d", mysql_errno(mysql));
|
||||
|
||||
if(mysql_errno(mysql) == 1049) {
|
||||
sprintf(query, "CREATE DATABASE %s", schema);
|
||||
if (mysql_query(mysql, query)) {
|
||||
@@ -425,11 +435,6 @@ static int reset_connection(MYSQL *mysql) {
|
||||
|
||||
rc= mysql_change_user(mysql, username, password, schema);
|
||||
check_mysql_rc(rc, mysql);
|
||||
if (mysql_get_server_version(mysql) < 50400)
|
||||
rc= mysql_query(mysql, "SET table_type='MyISAM'");
|
||||
else
|
||||
rc= mysql_query(mysql, "SET storage_engine='MyISAM'");
|
||||
check_mysql_rc(rc, mysql);
|
||||
rc= mysql_query(mysql, "SET sql_mode=''");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
@@ -452,6 +457,8 @@ void get_envvars() {
|
||||
password= envvar;
|
||||
if (!schema && (envvar= getenv("MYSQL_TEST_DB")))
|
||||
schema= envvar;
|
||||
if (!schema)
|
||||
schema= "testc";
|
||||
if (!port && (envvar= getenv("MYSQL_TEST_PORT")))
|
||||
port= atoi(envvar);
|
||||
if (!socketname && (envvar= getenv("MYSQL_TEST_SOCKET")))
|
||||
@@ -470,7 +477,8 @@ void run_tests(struct my_tests_st *test) {
|
||||
if ((mysql_default= test_connect(NULL)))
|
||||
{
|
||||
diag("Testing against MySQL Server %s", mysql_get_server_info(mysql_default));
|
||||
diag("Host %s", mysql_get_host_info(mysql_default));
|
||||
diag("Host: %s", mysql_get_host_info(mysql_default));
|
||||
diag("Client library: %s", mysql_get_client_info());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -64,7 +64,10 @@ static int test_conc83(MYSQL *my)
|
||||
/* 1. Status is inited, so prepare should work */
|
||||
|
||||
rc= mysql_kill(mysql, mysql_thread_id(mysql));
|
||||
sleep(2);
|
||||
sleep(5);
|
||||
|
||||
rc= mysql_ping(mysql);
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
rc= mysql_stmt_prepare(stmt, query, strlen(query));
|
||||
check_stmt_rc(rc, stmt);
|
||||
|
@@ -528,9 +528,8 @@ static int test_bug12744(MYSQL *mysql)
|
||||
rc= mysql_options(mysql, MYSQL_OPT_RECONNECT, "1");
|
||||
check_mysql_rc(rc, mysql);
|
||||
rc= mysql_kill(mysql, mysql_thread_id(mysql));
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
sleep(2);
|
||||
sleep(4);
|
||||
rc= mysql_ping(mysql);
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
|
Reference in New Issue
Block a user