summaryrefslogtreecommitdiff
path: root/sql-common
diff options
context:
space:
mode:
Diffstat (limited to 'sql-common')
-rw-r--r--sql-common/client.c200
-rw-r--r--sql-common/client_plugin.c22
-rw-r--r--sql-common/my_time.c264
-rw-r--r--sql-common/mysql_async.c72
4 files changed, 359 insertions, 199 deletions
diff --git a/sql-common/client.c b/sql-common/client.c
index b965c369a4c..d9d0f2fd095 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -38,10 +38,6 @@
#include "mysql.h"
-#ifndef __WIN__
-#include <netdb.h>
-#endif
-
/* Remove client convenience wrappers */
#undef max_allowed_packet
#undef net_buffer_length
@@ -62,6 +58,7 @@ my_bool net_flush(NET *net);
#else /*EMBEDDED_LIBRARY*/
#define CLI_MYSQL_REAL_CONNECT STDCALL mysql_real_connect
#endif /*EMBEDDED_LIBRARY*/
+
#include <my_sys.h>
#include <mysys_err.h>
#include <m_string.h>
@@ -70,6 +67,7 @@ my_bool net_flush(NET *net);
#include "mysqld_error.h"
#include "errmsg.h"
#include <violite.h>
+
#if !defined(__WIN__)
#include <my_pthread.h> /* because of signal() */
#endif /* !defined(__WIN__) */
@@ -77,14 +75,12 @@ my_bool net_flush(NET *net);
#include <sys/stat.h>
#include <signal.h>
#include <time.h>
+
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
+
#if !defined(__WIN__)
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
#ifdef HAVE_SELECT_H
# include <select.h>
#endif
@@ -96,9 +92,7 @@ my_bool net_flush(NET *net);
# include <sys/un.h>
#endif
-#if defined(__WIN__)
-#define perror(A)
-#else
+#ifndef _WIN32
#include <errno.h>
#define SOCKET_ERROR -1
#endif
@@ -118,6 +112,7 @@ my_bool net_flush(NET *net);
#define native_password_plugin_name "mysql_native_password"
#define old_password_plugin_name "mysql_old_password"
+
uint mysql_port=0;
char *mysql_unix_port= 0;
const char *unknown_sqlstate= "HY000";
@@ -131,7 +126,7 @@ const char *def_shared_memory_base_name= default_shared_memory_base_name;
static void mysql_close_free_options(MYSQL *mysql);
static void mysql_close_free(MYSQL *mysql);
static void mysql_prune_stmt_list(MYSQL *mysql);
-static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length);
+static int cli_report_progress(MYSQL *mysql, char *packet, uint length);
#if !defined(__WIN__)
static int wait_for_data(my_socket fd, uint timeout);
@@ -143,6 +138,37 @@ CHARSET_INFO *default_client_charset_info = &my_charset_latin1;
unsigned int mysql_server_last_errno;
char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
+/**
+ Convert the connect timeout option to a timeout value for VIO
+ functions (vio_socket_connect() and vio_io_wait()).
+
+ @param mysql Connection handle (client side).
+
+ @return The timeout value in milliseconds, or -1 if no timeout.
+*/
+
+static int get_vio_connect_timeout(MYSQL *mysql)
+{
+ int timeout_ms;
+ uint timeout_sec;
+
+ /*
+ A timeout of 0 means no timeout. Also, the connect_timeout
+ option value is in seconds, while VIO timeouts are measured
+ in milliseconds. Hence, check for a possible overflow. In
+ case of overflow, set to no timeout.
+ */
+ timeout_sec= mysql->options.connect_timeout;
+
+ if (!timeout_sec || (timeout_sec > INT_MAX/1000))
+ timeout_ms= -1;
+ else
+ timeout_ms= (int) (timeout_sec * 1000);
+
+ return timeout_ms;
+}
+
+
/****************************************************************************
A modified version of connect(). my_connect() allows you to specify
a timeout value, in seconds, that we should wait until we
@@ -744,7 +770,7 @@ restart:
DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %lu",
vio_description(net->vio),len));
#ifdef MYSQL_SERVER
- if (net->vio && vio_was_interrupted(net->vio))
+ if (net->vio && (net->last_errno == ER_NET_READ_INTERRUPTED))
return (packet_error);
#endif /*MYSQL_SERVER*/
end_server(mysql);
@@ -756,7 +782,7 @@ restart:
{
if (len > 3)
{
- uchar *pos= net->read_pos+1;
+ char *pos= (char*) net->read_pos+1;
uint last_errno=uint2korr(pos);
if (last_errno == 65535 &&
@@ -774,9 +800,9 @@ restart:
pos+=2;
len-=2;
- if (protocol_41(mysql) && (char) pos[0] == '#')
+ if (protocol_41(mysql) && pos[0] == '#')
{
- strmake_buf(net->sqlstate, (char*) pos+1);
+ strmake_buf(net->sqlstate, pos+1);
pos+= SQLSTATE_LENGTH+1;
}
else
@@ -790,7 +816,7 @@ restart:
}
(void) strmake(net->last_error,(char*) pos,
- min((uint) len,(uint) sizeof(net->last_error)-1));
+ MY_MIN((uint) len,(uint) sizeof(net->last_error)-1));
}
else
set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
@@ -1040,10 +1066,11 @@ static void cli_flush_use_result(MYSQL *mysql, my_bool flush_all_results)
1 error
*/
-static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length)
+static int cli_report_progress(MYSQL *mysql, char *pkt, uint length)
{
uint stage, max_stage, proc_length;
double progress;
+ uchar *packet= (uchar*)pkt;
uchar *start= packet;
if (length < 5)
@@ -1142,6 +1169,7 @@ static const char *default_options[]=
"ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
"multi-results", "multi-statements", "multi-queries", "secure-auth",
"report-data-truncation", "plugin-dir", "default-auth",
+ "bind-address", "ssl-crl", "ssl-crlpath",
"enable-cleartext-plugin",
NullS
};
@@ -1154,6 +1182,7 @@ enum option_id {
OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth,
+ OPT_bind_address, OPT_ssl_crl, OPT_ssl_crlpath,
OPT_enable_cleartext_plugin,
OPT_keep_this_one_last
};
@@ -1178,7 +1207,7 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd)
}
if (!(tmp= my_strdup(cmd,MYF(MY_WME))) ||
- insert_dynamic(options->init_commands, (uchar*)&tmp))
+ insert_dynamic(options->init_commands, &tmp))
{
my_free(tmp);
return 1;
@@ -1192,12 +1221,23 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd)
(OPTS)->extension= (struct st_mysql_options_extention *) \
my_malloc(sizeof(struct st_mysql_options_extention), \
MYF(MY_WME | MY_ZEROFILL)); \
- (OPTS)->extension->X= VAL;
+ (OPTS)->extension->X= (VAL);
#define EXTENSION_SET_STRING(OPTS, X, STR) \
if ((OPTS)->extension) \
my_free((OPTS)->extension->X); \
- EXTENSION_SET(OPTS, X, my_strdup((STR), MYF(MY_WME)));
+ EXTENSION_SET(OPTS, X, (STR) ? my_strdup((STR), MYF(MY_WME)) : NULL);
+
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
+#define SET_SSL_OPTION(OPTS, opt_var, arg) \
+ my_free((OPTS)->opt_var); \
+ (OPTS)->opt_var= arg ? my_strdup(arg, MYF(MY_WME)) : NULL;
+#define EXTENSION_SET_SSL_STRING(OPTS, X, STR) \
+ EXTENSION_SET_STRING((OPTS), X, (STR));
+#else
+#define SET_SSL_OPTION(OPTS, opt_var,arg) do { } while(0)
+#define EXTENSION_SET_SSL_STRING(OPTS, X, STR) do { } while(0)
+#endif /* defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) */
void mysql_read_default_options(struct st_mysql_options *options,
const char *filename,const char *group)
@@ -1301,35 +1341,27 @@ void mysql_read_default_options(struct st_mysql_options *options,
case OPT_return_found_rows:
options->client_flag|=CLIENT_FOUND_ROWS;
break;
-#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
case OPT_ssl_key:
- my_free(options->ssl_key);
- options->ssl_key = my_strdup(opt_arg, MYF(MY_WME));
+ SET_SSL_OPTION(options, ssl_key, opt_arg);
break;
case OPT_ssl_cert:
- my_free(options->ssl_cert);
- options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME));
+ SET_SSL_OPTION(options, ssl_cert, opt_arg);
break;
case OPT_ssl_ca:
- my_free(options->ssl_ca);
- options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME));
+ SET_SSL_OPTION(options, ssl_ca, opt_arg);
break;
case OPT_ssl_capath:
- my_free(options->ssl_capath);
- options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME));
+ SET_SSL_OPTION(options, ssl_capath, opt_arg);
break;
case OPT_ssl_cipher:
- my_free(options->ssl_cipher);
- options->ssl_cipher= my_strdup(opt_arg, MYF(MY_WME));
+ SET_SSL_OPTION(options, ssl_cipher, opt_arg);
+ break;
+ case OPT_ssl_crl:
+ EXTENSION_SET_SSL_STRING(options, ssl_crl, opt_arg);
+ break;
+ case OPT_ssl_crlpath:
+ EXTENSION_SET_SSL_STRING(options, ssl_crlpath, opt_arg);
break;
-#else
- case OPT_ssl_key:
- case OPT_ssl_cert:
- case OPT_ssl_ca:
- case OPT_ssl_capath:
- case OPT_ssl_cipher:
- break;
-#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
case OPT_character_sets_dir:
my_free(options->charset_dir);
options->charset_dir = my_strdup(opt_arg, MYF(MY_WME));
@@ -1384,7 +1416,7 @@ void mysql_read_default_options(struct st_mysql_options *options,
break;
case OPT_plugin_dir:
{
- char buff[FN_REFLEN], buff2[FN_REFLEN];
+ char buff[FN_REFLEN], buff2[FN_REFLEN], *buff2_ptr= buff2;
if (strlen(opt_arg) >= FN_REFLEN)
opt_arg[FN_REFLEN]= '\0';
if (my_realpath(buff, opt_arg, 0))
@@ -1394,7 +1426,7 @@ void mysql_read_default_options(struct st_mysql_options *options,
break;
}
convert_dirname(buff2, buff, NULL);
- EXTENSION_SET_STRING(options, plugin_dir, buff2);
+ EXTENSION_SET_STRING(options, plugin_dir, buff2_ptr);
}
break;
case OPT_default_auth:
@@ -1780,12 +1812,11 @@ mysql_init(MYSQL *mysql)
/*
- Fill in SSL part of MYSQL structure and set 'use_ssl' flag.
+ Fill in SSL part of MYSQL structure.
NB! Errors are not reported until you do mysql_real_connect.
+ use_ssl is set in send_client_reply_packet if any ssl option is set.
*/
-#define strdup_if_not_null(A) (A) == 0 ? 0 : my_strdup((A),MYF(MY_WME))
-
my_bool STDCALL
mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
const char *key __attribute__((unused)),
@@ -1794,20 +1825,17 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
const char *capath __attribute__((unused)),
const char *cipher __attribute__((unused)))
{
+ my_bool result= 0;
DBUG_ENTER("mysql_ssl_set");
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
- my_free(mysql->options.ssl_key);
- my_free(mysql->options.ssl_cert);
- my_free(mysql->options.ssl_ca);
- my_free(mysql->options.ssl_capath);
- my_free(mysql->options.ssl_cipher);
- mysql->options.ssl_key= strdup_if_not_null(key);
- mysql->options.ssl_cert= strdup_if_not_null(cert);
- mysql->options.ssl_ca= strdup_if_not_null(ca);
- mysql->options.ssl_capath= strdup_if_not_null(capath);
- mysql->options.ssl_cipher= strdup_if_not_null(cipher);
+ result= (mysql_options(mysql, MYSQL_OPT_SSL_KEY, key) |
+ mysql_options(mysql, MYSQL_OPT_SSL_CERT, cert) |
+ mysql_options(mysql, MYSQL_OPT_SSL_CA, ca) |
+ mysql_options(mysql, MYSQL_OPT_SSL_CAPATH, capath) |
+ mysql_options(mysql, MYSQL_OPT_SSL_CIPHER, cipher) ?
+ 1 : 0);
#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
- DBUG_RETURN(0);
+ DBUG_RETURN(result);
}
@@ -1829,6 +1857,11 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
my_free(mysql->options.ssl_ca);
my_free(mysql->options.ssl_capath);
my_free(mysql->options.ssl_cipher);
+ if (mysql->options.extension)
+ {
+ my_free(mysql->options.extension->ssl_crl);
+ my_free(mysql->options.extension->ssl_crlpath);
+ }
if (ssl_fd)
SSL_CTX_free(ssl_fd->ssl_context);
my_free(mysql->connector_fd);
@@ -1837,6 +1870,11 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
mysql->options.ssl_ca = 0;
mysql->options.ssl_capath = 0;
mysql->options.ssl_cipher= 0;
+ if (mysql->options.extension)
+ {
+ mysql->options.extension->ssl_crl = 0;
+ mysql->options.extension->ssl_crlpath = 0;
+ }
mysql->options.use_ssl = FALSE;
mysql->connector_fd = 0;
DBUG_VOID_RETURN;
@@ -2484,7 +2522,10 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
if (mysql->options.ssl_key || mysql->options.ssl_cert ||
mysql->options.ssl_ca || mysql->options.ssl_capath ||
- mysql->options.ssl_cipher)
+ mysql->options.ssl_cipher ||
+ (mysql->options.extension &&
+ (mysql->options.extension->ssl_crl ||
+ mysql->options.extension->ssl_crlpath)))
mysql->options.use_ssl= 1;
if (mysql->options.use_ssl)
mysql->client_flag|= CLIENT_SSL;
@@ -2545,7 +2586,11 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
options->ssl_ca,
options->ssl_capath,
options->ssl_cipher,
- &ssl_init_error)))
+ &ssl_init_error,
+ options->extension ?
+ options->extension->ssl_crl : NULL,
+ options->extension ?
+ options->extension->ssl_crlpath : NULL)))
{
set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
ER(CR_SSL_CONNECTION_ERROR), sslGetErrString(ssl_init_error));
@@ -2747,21 +2792,21 @@ void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info)
switch (vio->type) {
case VIO_TYPE_TCPIP:
info->protocol= MYSQL_VIO_TCP;
- info->socket= vio->sd;
+ info->socket= vio_fd(vio);
return;
case VIO_TYPE_SOCKET:
info->protocol= MYSQL_VIO_SOCKET;
- info->socket= vio->sd;
+ info->socket= vio_fd(vio);
return;
case VIO_TYPE_SSL:
{
struct sockaddr addr;
SOCKET_SIZE_TYPE addrlen= sizeof(addr);
- if (getsockname(vio->sd, &addr, &addrlen))
+ if (getsockname(vio_fd(vio), &addr, &addrlen))
return;
info->protocol= addr.sa_family == AF_UNIX ?
MYSQL_VIO_SOCKET : MYSQL_VIO_TCP;
- info->socket= vio->sd;
+ info->socket= vio_fd(vio);
return;
}
#ifdef _WIN32
@@ -2970,9 +3015,10 @@ connect_sync_or_async(MYSQL *mysql, NET *net, my_socket fd,
mysql->options.extension->async_context->active)
{
my_bool old_mode;
+ int vio_timeout= get_vio_connect_timeout(mysql);
vio_blocking(net->vio, FALSE, &old_mode);
return my_connect_async(mysql->options.extension->async_context, fd,
- name, namelen, mysql->options.connect_timeout);
+ name, namelen, vio_timeout);
}
return my_connect(fd, name, namelen, mysql->options.connect_timeout);
@@ -3325,7 +3371,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
/* Get version info */
mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
if (mysql->options.connect_timeout &&
- vio_poll_read(net->vio, mysql->options.connect_timeout))
+ (vio_io_wait(net->vio, VIO_IO_EVENT_READ,
+ get_vio_connect_timeout(mysql)) < 1))
{
set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
ER(CR_SERVER_LOST_EXTENDED),
@@ -3956,7 +4003,6 @@ mysql_send_query(MYSQL* mysql, const char* query, ulong length)
DBUG_RETURN(simple_command(mysql, COM_QUERY, (uchar*) query, length, 1));
}
-
int STDCALL
mysql_real_query(MYSQL *mysql, const char *query, ulong length)
{
@@ -4207,6 +4253,7 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
mysql->options.methods_to_use= option;
break;
case MYSQL_SET_CLIENT_IP:
+ my_free(mysql->options.client_ip);
mysql->options.client_ip= my_strdup(arg, MYF(MY_WME));
break;
case MYSQL_SECURE_AUTH:
@@ -4277,6 +4324,27 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
if (mysql->net.vio)
mysql->net.vio->async_context= ctxt;
break;
+ case MYSQL_OPT_SSL_KEY:
+ SET_SSL_OPTION(&mysql->options,ssl_key, arg);
+ break;
+ case MYSQL_OPT_SSL_CERT:
+ SET_SSL_OPTION(&mysql->options, ssl_cert, arg);
+ break;
+ case MYSQL_OPT_SSL_CA:
+ SET_SSL_OPTION(&mysql->options,ssl_ca, arg);
+ break;
+ case MYSQL_OPT_SSL_CAPATH:
+ SET_SSL_OPTION(&mysql->options,ssl_capath, arg);
+ break;
+ case MYSQL_OPT_SSL_CIPHER:
+ SET_SSL_OPTION(&mysql->options,ssl_cipher, arg);
+ break;
+ case MYSQL_OPT_SSL_CRL:
+ EXTENSION_SET_SSL_STRING(&mysql->options, ssl_crl, arg);
+ break;
+ case MYSQL_OPT_SSL_CRLPATH:
+ EXTENSION_SET_SSL_STRING(&mysql->options, ssl_crlpath, arg);
+ break;
default:
DBUG_RETURN(1);
}
@@ -4491,6 +4559,6 @@ my_socket STDCALL
mysql_get_socket(const MYSQL *mysql)
{
if (mysql->net.vio)
- return mysql->net.vio->sd;
+ return vio_fd(mysql->net.vio);
return INVALID_SOCKET;
}
diff --git a/sql-common/client_plugin.c b/sql-common/client_plugin.c
index 5b59c4e0e71..063fc5c6dc6 100644
--- a/sql-common/client_plugin.c
+++ b/sql-common/client_plugin.c
@@ -70,7 +70,7 @@ static uint plugin_version[MYSQL_CLIENT_MAX_PLUGINS]=
loading the same plugin twice in parallel.
*/
struct st_client_plugin_int *plugin_list[MYSQL_CLIENT_MAX_PLUGINS];
-static pthread_mutex_t LOCK_load_client_plugin;
+static mysql_mutex_t LOCK_load_client_plugin;
static int is_not_initialized(MYSQL *mysql, const char *name)
{
@@ -170,7 +170,7 @@ add_plugin(MYSQL *mysql, struct st_mysql_client_plugin *plugin, void *dlhandle,
goto err2;
}
- safe_mutex_assert_owner(&LOCK_load_client_plugin);
+ mysql_mutex_assert_owner(&LOCK_load_client_plugin);
p->next= plugin_list[plugin->type];
plugin_list[plugin->type]= p;
@@ -250,19 +250,19 @@ int mysql_client_plugin_init()
bzero(&mysql, sizeof(mysql)); /* dummy mysql for set_mysql_extended_error */
- pthread_mutex_init(&LOCK_load_client_plugin, MY_MUTEX_INIT_SLOW);
+ mysql_mutex_init(0, &LOCK_load_client_plugin, MY_MUTEX_INIT_SLOW);
init_alloc_root(&mem_root, 128, 128, MYF(0));
bzero(&plugin_list, sizeof(plugin_list));
initialized= 1;
- pthread_mutex_lock(&LOCK_load_client_plugin);
+ mysql_mutex_lock(&LOCK_load_client_plugin);
for (builtin= mysql_client_builtins; *builtin; builtin++)
add_plugin(&mysql, *builtin, 0, 0, unused);
- pthread_mutex_unlock(&LOCK_load_client_plugin);
+ mysql_mutex_unlock(&LOCK_load_client_plugin);
load_env_plugins(&mysql);
@@ -295,7 +295,7 @@ void mysql_client_plugin_deinit()
bzero(&plugin_list, sizeof(plugin_list));
initialized= 0;
free_root(&mem_root, MYF(0));
- pthread_mutex_destroy(&LOCK_load_client_plugin);
+ mysql_mutex_destroy(&LOCK_load_client_plugin);
DBUG_VOID_RETURN;
}
@@ -313,7 +313,7 @@ mysql_client_register_plugin(MYSQL *mysql,
if (is_not_initialized(mysql, plugin->name))
DBUG_RETURN(NULL);
- pthread_mutex_lock(&LOCK_load_client_plugin);
+ mysql_mutex_lock(&LOCK_load_client_plugin);
/* make sure the plugin wasn't loaded meanwhile */
if (find_plugin(plugin->name, plugin->type))
@@ -326,7 +326,7 @@ mysql_client_register_plugin(MYSQL *mysql,
else
plugin= add_plugin(mysql, plugin, 0, 0, unused);
- pthread_mutex_unlock(&LOCK_load_client_plugin);
+ mysql_mutex_unlock(&LOCK_load_client_plugin);
DBUG_RETURN(plugin);
}
@@ -348,7 +348,7 @@ mysql_load_plugin_v(MYSQL *mysql, const char *name, int type,
DBUG_RETURN (NULL);
}
- pthread_mutex_lock(&LOCK_load_client_plugin);
+ mysql_mutex_lock(&LOCK_load_client_plugin);
/* make sure the plugin wasn't loaded meanwhile */
if (type >= 0 && find_plugin(name, type))
@@ -401,13 +401,13 @@ mysql_load_plugin_v(MYSQL *mysql, const char *name, int type,
plugin= add_plugin(mysql, plugin, dlhandle, argc, args);
- pthread_mutex_unlock(&LOCK_load_client_plugin);
+ mysql_mutex_unlock(&LOCK_load_client_plugin);
DBUG_PRINT ("leave", ("plugin loaded ok"));
DBUG_RETURN (plugin);
err:
- pthread_mutex_unlock(&LOCK_load_client_plugin);
+ mysql_mutex_unlock(&LOCK_load_client_plugin);
DBUG_PRINT ("leave", ("plugin load error : %s", errmsg));
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate,
ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, errmsg);
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 05dcd773321..109bea7b4dd 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -203,6 +203,46 @@ static uint skip_digits(const char **str, const char *end)
return s - start;
}
+
+/**
+ Check datetime, date, or normalized time (i.e. time without days) range.
+ @param ltime Datetime value.
+ @returns
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+my_bool check_datetime_range(const MYSQL_TIME *ltime)
+{
+ /*
+ In case of MYSQL_TIMESTAMP_TIME hour value can be up to TIME_MAX_HOUR.
+ In case of MYSQL_TIMESTAMP_DATETIME it cannot be bigger than 23.
+ */
+ return
+ ltime->year > 9999 || ltime->month > 12 || ltime->day > 31 ||
+ ltime->minute > 59 || ltime->second > 59 ||
+ ltime->second_part > TIME_MAX_SECOND_PART ||
+ (ltime->hour >
+ (ltime->time_type == MYSQL_TIMESTAMP_TIME ? TIME_MAX_HOUR : 23));
+}
+
+
+static void get_microseconds(ulong *val, MYSQL_TIME_STATUS *status,
+ uint *number_of_fields,
+ const char **str, const char *end)
+{
+ const char *start= *str;
+ uint tmp= 0; /* For the case '10:10:10.' */
+ if (get_digits(&tmp, number_of_fields, str, end, 6))
+ status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
+ if ((status->precision= (*str - start)) < 6)
+ *val= tmp * log_10_int[6 - (*str - start)];
+ else
+ *val= tmp;
+ if (skip_digits(str, end))
+ status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
+}
+
+
/*
Convert a timestamp string to a MYSQL_TIME value.
@@ -217,9 +257,8 @@ static uint skip_digits(const char **str, const char *end)
TIME_NO_ZERO_IN_DATE Don't allow partial dates
TIME_NO_ZERO_DATE Don't allow 0000-00-00 date
TIME_INVALID_DATES Allow 2000-02-31
- was_cut 0 Value OK
- 1 If value was cut during conversion
- 2 check_date(date,flags) considers date invalid
+ status Conversion status
+
DESCRIPTION
At least the following formats are recogniced (based on number of digits)
@@ -230,20 +269,29 @@ static uint skip_digits(const char **str, const char *end)
The second part may have an optional .###### fraction part.
- RETURN VALUES
+ status->warnings is set to:
+ 0 Value OK
+ MYSQL_TIME_WARN_TRUNCATED If value was cut during conversion
+ MYSQL_TIME_WARN_OUT_OF_RANGE check_date(date,flags) considers date invalid
+
+ l_time->time_type is set as follows:
MYSQL_TIMESTAMP_NONE String wasn't a timestamp, like
[DD [HH:[MM:[SS]]]].fraction.
+ l_time is not changed.
MYSQL_TIMESTAMP_DATE DATE string (YY MM and DD parts ok)
MYSQL_TIMESTAMP_DATETIME Full timestamp
MYSQL_TIMESTAMP_ERROR Timestamp with wrong values.
All elements in l_time is set to 0
+ RETURN VALUES
+ 0 - Ok
+ 1 - Error
*/
#define MAX_DATE_PARTS 8
-enum enum_mysql_timestamp_type
+my_bool
str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
- ulonglong flags, int *was_cut)
+ ulonglong flags, MYSQL_TIME_STATUS *status)
{
const char *end=str+length, *pos;
uint number_of_fields= 0, digits, year_length, not_zero_date;
@@ -252,19 +300,20 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
if (flags & TIME_TIME_ONLY)
{
- enum enum_mysql_timestamp_type ret;
- ret= str_to_time(str, length, l_time, flags, was_cut);
+ my_bool ret= str_to_time(str, length, l_time, flags, status);
DBUG_RETURN(ret);
}
- *was_cut= 0;
+
+ my_time_status_init(status);
/* Skip space at start */
for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++)
;
if (str == end || ! my_isdigit(&my_charset_latin1, *str))
{
- *was_cut= 1;
- DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
+ status->warnings= MYSQL_TIME_WARN_TRUNCATED;
+ l_time->time_type= MYSQL_TIMESTAMP_NONE;
+ DBUG_RETURN(1);
}
/*
@@ -293,50 +342,49 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
(only numbers like [YY]YYMMDD[T][hhmmss[.uuuuuu]])
*/
year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
- *was_cut= get_digits(&l_time->year, &number_of_fields, &str, end, year_length)
- || get_digits(&l_time->month, &number_of_fields, &str, end, 2)
- || get_digits(&l_time->day, &number_of_fields, &str, end, 2)
- || get_maybe_T(&str, end)
- || get_digits(&l_time->hour, &number_of_fields, &str, end, 2)
- || get_digits(&l_time->minute, &number_of_fields, &str, end, 2)
- || get_digits(&l_time->second, &number_of_fields, &str, end, 2);
+ if (get_digits(&l_time->year, &number_of_fields, &str, end, year_length)
+ || get_digits(&l_time->month, &number_of_fields, &str, end, 2)
+ || get_digits(&l_time->day, &number_of_fields, &str, end, 2)
+ || get_maybe_T(&str, end)
+ || get_digits(&l_time->hour, &number_of_fields, &str, end, 2)
+ || get_digits(&l_time->minute, &number_of_fields, &str, end, 2)
+ || get_digits(&l_time->second, &number_of_fields, &str, end, 2))
+ status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
}
else
{
const char *start= str;
- *was_cut = get_number(&l_time->year, &number_of_fields, &str, end);
+ if (get_number(&l_time->year, &number_of_fields, &str, end))
+ status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
year_length= str - start;
- if (!*was_cut)
- *was_cut= get_punct(&str, end)
- || get_number(&l_time->month, &number_of_fields, &str, end)
- || get_punct(&str, end)
- || get_number(&l_time->day, &number_of_fields, &str, end)
- || get_date_time_separator(&number_of_fields, flags, &str, end)
- || get_number(&l_time->hour, &number_of_fields, &str, end)
- || get_punct(&str, end)
- || get_number(&l_time->minute, &number_of_fields, &str, end)
- || get_punct(&str, end)
- || get_number(&l_time->second, &number_of_fields, &str, end);
+ if (!status->warnings &&
+ (get_punct(&str, end)
+ || get_number(&l_time->month, &number_of_fields, &str, end)
+ || get_punct(&str, end)
+ || get_number(&l_time->day, &number_of_fields, &str, end)
+ || get_date_time_separator(&number_of_fields, flags, &str, end)
+ || get_number(&l_time->hour, &number_of_fields, &str, end)
+ || get_punct(&str, end)
+ || get_number(&l_time->minute, &number_of_fields, &str, end)
+ || get_punct(&str, end)
+ || get_number(&l_time->second, &number_of_fields, &str, end)))
+ status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
}
- if (number_of_fields < 3)
- *was_cut= 1;
-
/* we're ok if date part is correct. even if the rest is truncated */
- if (*was_cut && number_of_fields < 3)
- DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
+ if (number_of_fields < 3)
+ {
+ l_time->time_type= MYSQL_TIMESTAMP_NONE;
+ status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
+ DBUG_RETURN(TRUE);
+ }
- if (!*was_cut && str < end && *str == '.')
+ if (!status->warnings && str < end && *str == '.')
{
- uint second_part;
- const char *start= ++str;
- *was_cut= get_digits(&second_part, &number_of_fields, &str, end, 6);
- if (str - start < 6)
- second_part*= log_10_int[6 - (str - start)];
- l_time->second_part= second_part;
- if (skip_digits(&str, end))
- *was_cut= 1;
+ str++;
+ get_microseconds(&l_time->second_part, status,
+ &number_of_fields, &str, end);
}
not_zero_date = l_time->year || l_time->month || l_time->day ||
@@ -349,11 +397,11 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
if (l_time->year > 9999 || l_time->month > 12 || l_time->day > 31 ||
l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59)
{
- *was_cut= 1;
+ status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
goto err;
}
- if (check_date(l_time, not_zero_date, flags, was_cut))
+ if (check_date(l_time, not_zero_date, flags, &status->warnings))
goto err;
l_time->time_type= (number_of_fields <= 3 ?
@@ -363,16 +411,17 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
{
if (!my_isspace(&my_charset_latin1,*str))
{
- *was_cut= 1;
+ status->warnings= MYSQL_TIME_WARN_TRUNCATED;
break;
}
}
- DBUG_RETURN(l_time->time_type);
+ DBUG_RETURN(FALSE);
err:
bzero((char*) l_time, sizeof(*l_time));
- DBUG_RETURN(MYSQL_TIMESTAMP_ERROR);
+ l_time->time_type= MYSQL_TIMESTAMP_ERROR;
+ DBUG_RETURN(TRUE);
}
@@ -387,23 +436,26 @@ err:
There may be an optional [.second_part] after seconds
length Length of str
l_time Store result here
- warning Set MYSQL_TIME_WARN_TRUNCATED flag if the input string
- was cut during conversion, and/or
- MYSQL_TIME_WARN_OUT_OF_RANGE flag, if the value is
- out of range.
+ status Conversion status
+
NOTES
+
Because of the extra days argument, this function can only
work with times where the time arguments are in the above order.
+ status->warnings is set as follows:
+ MYSQL_TIME_WARN_TRUNCATED if the input string was cut during conversion,
+ and/or
+ MYSQL_TIME_WARN_OUT_OF_RANGE flag is set if the value is out of range.
+
RETURN
- MYSQL_TIMESTAMP_TIME
- MYSQL_TIMESTAMP_ERROR
+ FALSE on success
+ TRUE on error
*/
-enum enum_mysql_timestamp_type
-str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
- ulonglong fuzzydate, int *warning)
+my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
+ ulonglong fuzzydate, MYSQL_TIME_STATUS *status)
{
ulong date[5];
ulonglong value;
@@ -411,7 +463,7 @@ str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
my_bool found_days,found_hours, neg= 0;
uint UNINIT_VAR(state);
- *warning= 0;
+ my_time_status_init(status);
for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++)
length--;
if (str != end && *str == '-')
@@ -421,22 +473,20 @@ str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
length--;
}
if (str == end)
- return MYSQL_TIMESTAMP_ERROR;
+ {
+ status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
+ goto err;
+ }
/* Check first if this is a full TIMESTAMP */
if (length >= 12)
{ /* Probably full timestamp */
- int was_cut;
- enum enum_mysql_timestamp_type
- res= str_to_datetime(str, length, l_time,
+ (void) str_to_datetime(str, length, l_time,
(fuzzydate & ~TIME_TIME_ONLY) | TIME_DATETIME_ONLY,
- &was_cut);
- if ((int) res >= (int) MYSQL_TIMESTAMP_ERROR)
- {
- if (was_cut)
- *warning|= MYSQL_TIME_WARN_TRUNCATED;
- return res;
- }
+ status);
+ if (l_time->time_type >= MYSQL_TIMESTAMP_ERROR)
+ return l_time->time_type == MYSQL_TIMESTAMP_ERROR;
+ my_time_status_init(status);
}
l_time->neg= neg;
@@ -504,24 +554,15 @@ str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
fractional:
/* Get fractional second part */
- if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1]))
+ if (!status->warnings && str < end && *str == '.')
{
- int field_length= 5;
- str++; value=(uint) (uchar) (*str - '0');
- while (++str != end && my_isdigit(&my_charset_latin1, *str))
- {
- if (field_length-- > 0)
- value= value*10 + (uint) (uchar) (*str - '0');
- }
- if (field_length > 0)
- value*= (long) log_10_int[field_length];
- else if (field_length < 0)
- *warning|= MYSQL_TIME_WARN_TRUNCATED;
- date[4]= (ulong) value;
+ uint number_of_fields= 0;
+ str++;
+ get_microseconds(&date[4], status, &number_of_fields, &str, end);
}
else
- date[4]=0;
-
+ date[4]= 0;
+
/* Check for exponent part: E<gigit> | E<sign><digit> */
/* (may occur as result of %g formatting of time value) */
if ((end - str) > 1 &&
@@ -530,7 +571,10 @@ fractional:
((str[1] == '-' || str[1] == '+') &&
(end - str) > 2 &&
my_isdigit(&my_charset_latin1, str[2]))))
- return MYSQL_TIMESTAMP_ERROR;
+ {
+ status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
+ goto err;
+ }
if (internal_format_positions[7] != 255)
{
@@ -553,8 +597,11 @@ fractional:
if (date[0] > UINT_MAX || date[1] > UINT_MAX ||
date[2] > UINT_MAX || date[3] > UINT_MAX ||
date[4] > UINT_MAX)
- return MYSQL_TIMESTAMP_ERROR;
-
+ {
+ status->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ goto err;
+ }
+
l_time->year= 0; /* For protocol::store_time */
l_time->month= 0;
l_time->day= date[0];
@@ -565,9 +612,9 @@ fractional:
l_time->time_type= MYSQL_TIMESTAMP_TIME;
/* Check if the value is valid and fits into MYSQL_TIME range */
- if (check_time_range(l_time, 6, warning))
- return MYSQL_TIMESTAMP_ERROR;
-
+ if (check_time_range(l_time, 6, &status->warnings))
+ return TRUE;
+
/* Check if there is garbage at end of the MYSQL_TIME specification */
if (str != end)
{
@@ -575,12 +622,17 @@ fractional:
{
if (!my_isspace(&my_charset_latin1,*str))
{
- *warning|= MYSQL_TIME_WARN_TRUNCATED;
+ status->warnings|= MYSQL_TIME_WARN_TRUNCATED;
break;
}
} while (++str != end);
}
- return MYSQL_TIMESTAMP_TIME;
+ return FALSE;
+
+err:
+ bzero((char*) l_time, sizeof(*l_time));
+ l_time->time_type= MYSQL_TIMESTAMP_ERROR;
+ return TRUE;
}
@@ -610,7 +662,10 @@ int check_time_range(struct st_mysql_time *my_time, uint dec, int *warning)
999000, 999900, 999990, 999999};
if (my_time->minute >= 60 || my_time->second >= 60)
+ {
+ *warning|= MYSQL_TIME_WARN_TRUNCATED;
return 1;
+ }
hour= my_time->hour + (24*my_time->day);
@@ -1101,6 +1156,27 @@ int my_TIME_to_str(const MYSQL_TIME *l_time, char *to, uint digits)
}
+/**
+ Print a timestamp with an optional fractional part: XXXXX[.YYYYY]
+
+ @param tm The timestamp value to print.
+ @param OUT to The string pointer to print at.
+ @param dec Precision, in the range 0..6.
+ @return The length of the result string.
+*/
+int my_timeval_to_str(const struct timeval *tm, char *to, uint dec)
+{
+ char *pos= longlong10_to_str((longlong) tm->tv_sec, to, 10);
+ if (dec)
+ {
+ *pos++= '.';
+ pos= fmt_number((uint) sec_part_shift(tm->tv_usec, dec), pos, dec);
+ }
+ *pos= '\0';
+ return (int) (pos - to);
+}
+
+
/*
Convert datetime value specified as number to broken-down TIME
representation and form value of DATETIME type as side-effect.
@@ -1352,7 +1428,7 @@ double TIME_to_double(const MYSQL_TIME *my_time)
return my_time->neg ? -d : d;
}
-longlong pack_time(MYSQL_TIME *my_time)
+longlong pack_time(const MYSQL_TIME *my_time)
{
return ((((((my_time->year * 13ULL +
my_time->month) * 32ULL +
diff --git a/sql-common/mysql_async.c b/sql-common/mysql_async.c
index c7e720076ea..8f3a91e26fa 100644
--- a/sql-common/mysql_async.c
+++ b/sql-common/mysql_async.c
@@ -56,7 +56,7 @@ my_context_install_suspend_resume_hook(struct mysql_async_context *b,
/* Asynchronous connect(); socket must already be set non-blocking. */
int
my_connect_async(struct mysql_async_context *b, my_socket fd,
- const struct sockaddr *name, uint namelen, uint timeout)
+ const struct sockaddr *name, uint namelen, int vio_timeout)
{
int res;
size_socket s_err_size;
@@ -90,9 +90,13 @@ my_connect_async(struct mysql_async_context *b, my_socket fd,
return res;
#endif
b->events_to_wait_for|= MYSQL_WAIT_WRITE;
- b->timeout_value= timeout;
- if (timeout)
+ if (vio_timeout >= 0)
+ {
+ b->timeout_value= vio_timeout;
b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT;
+ }
+ else
+ b->timeout_value= 0;
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
my_context_yield(&b->async_context);
@@ -119,7 +123,7 @@ my_connect_async(struct mysql_async_context *b, my_socket fd,
ssize_t
my_recv_async(struct mysql_async_context *b, int fd,
- unsigned char *buf, size_t size, uint timeout)
+ unsigned char *buf, size_t size, int timeout)
{
ssize_t res;
@@ -129,7 +133,7 @@ my_recv_async(struct mysql_async_context *b, int fd,
if (res >= 0 || IS_BLOCKING_ERROR())
return res;
b->events_to_wait_for= MYSQL_WAIT_READ;
- if (timeout)
+ if (timeout >= 0)
{
b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT;
b->timeout_value= timeout;
@@ -147,7 +151,7 @@ my_recv_async(struct mysql_async_context *b, int fd,
ssize_t
my_send_async(struct mysql_async_context *b, int fd,
- const unsigned char *buf, size_t size, uint timeout)
+ const unsigned char *buf, size_t size, int timeout)
{
ssize_t res;
@@ -157,7 +161,7 @@ my_send_async(struct mysql_async_context *b, int fd,
if (res >= 0 || IS_BLOCKING_ERROR())
return res;
b->events_to_wait_for= MYSQL_WAIT_WRITE;
- if (timeout)
+ if (timeout >= 0)
{
b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT;
b->timeout_value= timeout;
@@ -174,16 +178,33 @@ my_send_async(struct mysql_async_context *b, int fd,
my_bool
-my_poll_read_async(struct mysql_async_context *b, uint timeout)
+my_io_wait_async(struct mysql_async_context *b, enum enum_vio_io_event event,
+ int timeout)
{
- b->events_to_wait_for= MYSQL_WAIT_READ | MYSQL_WAIT_TIMEOUT;
- b->timeout_value= timeout;
+ switch (event)
+ {
+ case VIO_IO_EVENT_READ:
+ b->events_to_wait_for = MYSQL_WAIT_READ;
+ break;
+ case VIO_IO_EVENT_WRITE:
+ b->events_to_wait_for = MYSQL_WAIT_WRITE;
+ break;
+ case VIO_IO_EVENT_CONNECT:
+ b->events_to_wait_for = MYSQL_WAIT_WRITE | IF_WIN(0, MYSQL_WAIT_EXCEPT);
+ break;
+ }
+
+ if (timeout >= 0)
+ {
+ b->events_to_wait_for |= MYSQL_WAIT_TIMEOUT;
+ b->timeout_value= timeout;
+ }
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
my_context_yield(&b->async_context);
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data);
- return (b->events_occured & MYSQL_WAIT_READ) ? 0 : 1;
+ return (b->events_occured & MYSQL_WAIT_TIMEOUT) ? 0 : 1;
}
@@ -239,32 +260,27 @@ my_ssl_write_async(struct mysql_async_context *b, SSL *ssl,
}
#endif /* HAVE_OPENSSL */
+/*
+ Legacy support of the MariaDB 5.5 version, where timeouts where only in
+ seconds resolution. Applications that use this will be asked to set a timeout
+ at the nearest higher whole-seconds value.
+*/
unsigned int STDCALL
mysql_get_timeout_value(const MYSQL *mysql)
{
- return mysql->options.extension->async_context->timeout_value;
+ unsigned int timeout= mysql->options.extension->async_context->timeout_value;
+ /* Avoid overflow. */
+ if (timeout > UINT_MAX - 999)
+ return (timeout - 1)/1000 + 1;
+ else
+ return (timeout+999)/1000;
}
-/*
- In 10.0, VIO timeouts are in milliseconds, so we support getting the
- millisecond timeout value from async applications.
-
- In 5.5, timeouts are always in seconds, but we support the 10.0 version
- that provides milliseconds, so applications can work with either version
- of the library easily.
-
- When merging this to 10.0, this function must be removed and the 10.0
- version used.
-*/
unsigned int STDCALL
mysql_get_timeout_value_ms(const MYSQL *mysql)
{
- unsigned int timeout= mysql->options.extension->async_context->timeout_value;
- if (timeout <= UINT_MAX / 1000)
- return timeout*1000;
- else
- return UINT_MAX;
+ return mysql->options.extension->async_context->timeout_value;
}