diff options
Diffstat (limited to 'sql-common')
-rw-r--r-- | sql-common/client.c | 200 | ||||
-rw-r--r-- | sql-common/client_plugin.c | 22 | ||||
-rw-r--r-- | sql-common/my_time.c | 264 | ||||
-rw-r--r-- | sql-common/mysql_async.c | 72 |
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; } |