summaryrefslogtreecommitdiff
path: root/sql-common
diff options
context:
space:
mode:
Diffstat (limited to 'sql-common')
-rw-r--r--sql-common/Makefile.am2
-rw-r--r--sql-common/client.c165
-rw-r--r--sql-common/my_time.c257
-rw-r--r--sql-common/my_user.c57
4 files changed, 442 insertions, 39 deletions
diff --git a/sql-common/Makefile.am b/sql-common/Makefile.am
index 6bd42d70e4f..d71523a741c 100644
--- a/sql-common/Makefile.am
+++ b/sql-common/Makefile.am
@@ -15,7 +15,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## Process this file with automake to create Makefile.in
-EXTRA_DIST = client.c pack.c my_time.c
+EXTRA_DIST = client.c pack.c my_time.c my_user.c
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/sql-common/client.c b/sql-common/client.c
index 3a598832253..cd50960164b 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -57,7 +57,7 @@
my_bool net_flush(NET *net);
#else /*EMBEDDED_LIBRARY*/
-#define CLI_MYSQL_REAL_CONNECT mysql_real_connect
+#define CLI_MYSQL_REAL_CONNECT STDCALL mysql_real_connect
#endif /*EMBEDDED_LIBRARY*/
#include <my_sys.h>
#include <mysys_err.h>
@@ -98,9 +98,6 @@ my_bool net_flush(NET *net);
# include <sys/un.h>
#endif
-#ifndef INADDR_NONE
-#define INADDR_NONE -1
-#endif
#if defined(MSDOS) || defined(__WIN__)
#define perror(A)
#else
@@ -602,7 +599,7 @@ net_safe_read(MYSQL *mysql)
DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d",
vio_description(net->vio),len));
#ifdef MYSQL_SERVER
- if (vio_was_interrupted(net->vio))
+ if (net->vio && vio_was_interrupted(net->vio))
return (packet_error);
#endif /*MYSQL_SERVER*/
end_server(mysql);
@@ -653,6 +650,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
NET *net= &mysql->net;
my_bool result= 1;
init_sigpipe_variables
+ DBUG_ENTER("cli_advanced_command");
/* Don't give sigpipe errors if the client doesn't want them */
set_sigpipe(mysql);
@@ -660,12 +658,13 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
if (mysql->net.vio == 0)
{ /* Do reconnect if possible */
if (mysql_reconnect(mysql))
- return 1;
+ DBUG_RETURN(1);
}
if (mysql->status != MYSQL_STATUS_READY)
{
+ DBUG_PRINT("error",("state: %d", mysql->status));
set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
- return 1;
+ DBUG_RETURN(1);
}
net->last_error[0]=0;
@@ -704,7 +703,8 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
1 : 0);
end:
reset_sigpipe(mysql);
- return result;
+ DBUG_PRINT("exit",("result: %d", result));
+ DBUG_RETURN(result);
}
void free_old_query(MYSQL *mysql)
@@ -715,6 +715,7 @@ void free_old_query(MYSQL *mysql)
init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
mysql->fields= 0;
mysql->field_count= 0; /* For API */
+ mysql->warning_count= 0;
mysql->info= 0;
DBUG_VOID_RETURN;
}
@@ -867,6 +868,8 @@ mysql_free_result(MYSQL_RES *result)
{
(*mysql->methods->flush_use_result)(mysql);
mysql->status=MYSQL_STATUS_READY;
+ if (mysql->unbuffered_fetch_owner)
+ *mysql->unbuffered_fetch_owner= TRUE;
}
}
free_rows(result->data);
@@ -893,6 +896,7 @@ static const char *default_options[]=
"replication-probe", "enable-reads-from-master", "repl-parse-query",
"ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
"multi-results", "multi-statements", "multi-queries", "secure-auth",
+ "report-data-truncation",
NullS
};
@@ -1104,6 +1108,9 @@ void mysql_read_default_options(struct st_mysql_options *options,
case 33: /* secure-auth */
options->secure_auth= TRUE;
break;
+ case 34: /* report-data-truncation */
+ options->report_data_truncation= opt_arg ? test(atoi(opt_arg)) : 1;
+ break;
default:
DBUG_PRINT("warning",("unknown option: %s",option[0]));
}
@@ -1421,7 +1428,7 @@ mysql_init(MYSQL *mysql)
mysql->free_me=1;
}
else
- bzero((char*) (mysql),sizeof(*(mysql)));
+ bzero((char*) (mysql), sizeof(*(mysql)));
mysql->options.connect_timeout= CONNECT_TIMEOUT;
mysql->last_used_con= mysql->next_slave= mysql->master = mysql;
mysql->charset=default_charset_info;
@@ -1448,6 +1455,25 @@ mysql_init(MYSQL *mysql)
#endif
mysql->options.methods_to_use= MYSQL_OPT_GUESS_CONNECTION;
+ mysql->options.report_data_truncation= TRUE; /* default */
+
+ /*
+ By default we don't reconnect because it could silently corrupt data (after
+ reconnection you potentially lose table locks, user variables, session
+ variables (transactions but they are specifically dealt with in
+ mysql_reconnect()).
+ This is a change: < 5.0.3 mysql->reconnect was set to 1 by default.
+ How this change impacts existing apps:
+ - existing apps which relyed on the default will see a behaviour change;
+ they will have to set reconnect=1 after mysql_real_connect().
+ - existing apps which explicitely asked for reconnection (the only way they
+ could do it was by setting mysql.reconnect to 1 after mysql_real_connect())
+ will not see a behaviour change.
+ - existing apps which explicitely asked for no reconnection
+ (mysql.reconnect=0) will not see a behaviour change.
+ */
+ mysql->reconnect= 0;
+
return mysql;
}
@@ -1467,6 +1493,7 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
const char *capath __attribute__((unused)),
const char *cipher __attribute__((unused)))
{
+ DBUG_ENTER("mysql_ssl_set");
#ifdef HAVE_OPENSSL
mysql->options.ssl_key= strdup_if_not_null(key);
mysql->options.ssl_cert= strdup_if_not_null(cert);
@@ -1474,7 +1501,7 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
mysql->options.ssl_capath= strdup_if_not_null(capath);
mysql->options.ssl_cipher= strdup_if_not_null(cipher);
#endif /* HAVE_OPENSSL */
- return 0;
+ DBUG_RETURN(0);
}
@@ -1489,6 +1516,8 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
{
struct st_VioSSLConnectorFd *st=
(struct st_VioSSLConnectorFd*) mysql->connector_fd;
+ DBUG_ENTER("mysql_ssl_free");
+
my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
@@ -1504,6 +1533,7 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
mysql->options.ssl_cipher= 0;
mysql->options.use_ssl = FALSE;
mysql->connector_fd = 0;
+ DBUG_VOID_RETURN;
}
#endif /* HAVE_OPENSSL */
@@ -1533,11 +1563,13 @@ static MYSQL_METHODS client_methods=
NULL,
cli_read_statistics,
cli_read_query_result,
- cli_read_change_user_result
+ cli_read_change_user_result,
+ cli_read_binary_rows
#endif
};
-MYSQL * STDCALL
+
+MYSQL *
CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,ulong client_flag)
@@ -1559,7 +1591,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
#ifdef HAVE_SYS_UN_H
struct sockaddr_un UNIXaddr;
#endif
-
init_sigpipe_variables
DBUG_ENTER("mysql_real_connect");
LINT_INIT(host_info);
@@ -1613,7 +1644,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
if (!unix_socket)
unix_socket=mysql->options.unix_socket;
- mysql->reconnect=1; /* Reconnect as default */
mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
/*
@@ -1668,7 +1698,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
ER(net->last_errno),socket_errno);
goto error;
}
- net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
+ net->vio= vio_new(sock, VIO_TYPE_SOCKET,
+ VIO_LOCALHOST | VIO_BUFFERED_READ);
bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
UNIXaddr.sun_family = AF_UNIX;
strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1);
@@ -1743,7 +1774,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
ER(net->last_errno),socket_errno);
goto error;
}
- net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
+ net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
bzero((char*) &sock_addr,sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
@@ -2111,7 +2142,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
for (; ptr<end; ptr++)
{
MYSQL_RES *res;
- if (mysql_real_query(mysql,*ptr, strlen(*ptr)))
+ if (mysql_real_query(mysql,*ptr, (ulong) strlen(*ptr)))
goto error;
if (mysql->fields)
{
@@ -2183,8 +2214,9 @@ my_bool mysql_reconnect(MYSQL *mysql)
DBUG_RETURN(1);
}
mysql_init(&tmp_mysql);
- tmp_mysql.options=mysql->options;
- tmp_mysql.rpl_pivot = mysql->rpl_pivot;
+ tmp_mysql.options= mysql->options;
+ tmp_mysql.rpl_pivot= mysql->rpl_pivot;
+
if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
mysql->db, mysql->port, mysql->unix_socket,
mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
@@ -2194,6 +2226,19 @@ my_bool mysql_reconnect(MYSQL *mysql)
strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
DBUG_RETURN(1);
}
+ if (mysql_set_character_set(&tmp_mysql, mysql->charset->csname))
+ {
+ DBUG_PRINT("error", ("mysql_set_character_set() failed"));
+ bzero((char*) &tmp_mysql.options,sizeof(tmp_mysql.options));
+ mysql_close(&tmp_mysql);
+ mysql->net.last_errno= tmp_mysql.net.last_errno;
+ strmov(mysql->net.last_error, tmp_mysql.net.last_error);
+ strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
+ DBUG_RETURN(1);
+ }
+
+ DBUG_PRINT("info", ("reconnect succeded"));
+ tmp_mysql.reconnect= 1;
tmp_mysql.free_me= mysql->free_me;
/*
@@ -2256,6 +2301,8 @@ mysql_select_db(MYSQL *mysql, const char *db)
static void mysql_close_free_options(MYSQL *mysql)
{
+ DBUG_ENTER("mysql_close_free_options");
+
my_free(mysql->options.user,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.host,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR));
@@ -2284,6 +2331,7 @@ static void mysql_close_free_options(MYSQL *mysql)
my_free(mysql->options.shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
#endif /* HAVE_SMEM */
bzero((char*) &mysql->options,sizeof(mysql->options));
+ DBUG_VOID_RETURN;
}
@@ -2293,8 +2341,12 @@ static void mysql_close_free(MYSQL *mysql)
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
+#if defined(EMBEDDED_LIBRARY) || MYSQL_VERSION_ID >= 50100
+ my_free(mysql->info_buffer,MYF(MY_ALLOW_ZERO_PTR));
+ mysql->info_buffer= 0;
+#endif
/* Clear pointers for better safety */
- mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
+ mysql->host_info= mysql->user= mysql->passwd= mysql->db= 0;
}
@@ -2430,10 +2482,7 @@ get_info:
if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
mysql->server_status|= SERVER_STATUS_IN_TRANS;
- mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
-
- if (!(fields=(*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,
- protocol_41(mysql) ? 7 : 5)))
+ if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5)))
DBUG_RETURN(1);
if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
(uint) field_count,0,
@@ -2441,7 +2490,7 @@ get_info:
DBUG_RETURN(1);
mysql->status= MYSQL_STATUS_GET_RESULT;
mysql->field_count= (uint) field_count;
- mysql->warning_count= 0;
+ DBUG_PRINT("exit",("ok"));
DBUG_RETURN(0);
}
@@ -2641,6 +2690,25 @@ mysql_fetch_row(MYSQL_RES *res)
}
+/**************************************************************************
+ Get column lengths of the current row
+ If one uses mysql_use_result, res->lengths contains the length information,
+ else the lengths are calculated from the offset between pointers.
+**************************************************************************/
+
+ulong * STDCALL
+mysql_fetch_lengths(MYSQL_RES *res)
+{
+ MYSQL_ROW column;
+
+ if (!(column=res->current_row))
+ return 0; /* Something is wrong */
+ if (res->data)
+ (*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
+ return res->lengths;
+}
+
+
int STDCALL
mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
{
@@ -2709,6 +2777,12 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
case MYSQL_SECURE_AUTH:
mysql->options.secure_auth= *(my_bool *) arg;
break;
+ case MYSQL_REPORT_DATA_TRUNCATION:
+ mysql->options.report_data_truncation= test(*(my_bool *) arg);
+ break;
+ case MYSQL_OPT_RECONNECT:
+ mysql->reconnect= *(my_bool *) arg;
+ break;
default:
DBUG_RETURN(1);
}
@@ -2737,8 +2811,49 @@ uint STDCALL mysql_errno(MYSQL *mysql)
return mysql->net.last_errno;
}
+
const char * STDCALL mysql_error(MYSQL *mysql)
{
return mysql->net.last_error;
}
+/*
+ mysql_set_character_set function sends SET NAMES cs_name to
+ the server (which changes character_set_client, character_set_result
+ and character_set_connection) and updates mysql->charset so other
+ functions like mysql_real_escape will work correctly.
+*/
+int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
+{
+ struct charset_info_st *cs;
+ const char *save_csdir= charsets_dir;
+
+ if (mysql->options.charset_dir)
+ charsets_dir= mysql->options.charset_dir;
+
+ if (strlen(cs_name) < MY_CS_NAME_SIZE &&
+ (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
+ {
+ char buff[MY_CS_NAME_SIZE + 10];
+ charsets_dir= save_csdir;
+ sprintf(buff, "SET NAMES %s", cs_name);
+ if (!mysql_real_query(mysql, buff, strlen(buff)))
+ {
+ mysql->charset= cs;
+ }
+ }
+ else
+ {
+ char cs_dir_name[FN_REFLEN];
+ get_charsets_dir(cs_dir_name);
+ mysql->net.last_errno= CR_CANT_READ_CHARSET;
+ strmov(mysql->net.sqlstate, unknown_sqlstate);
+ my_snprintf(mysql->net.last_error, sizeof(mysql->net.last_error) - 1,
+ ER(mysql->net.last_errno), cs_name, cs_dir_name);
+
+ }
+ charsets_dir= save_csdir;
+ return mysql->net.last_errno;
+}
+
+
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 3c46a944ba9..c9d39260761 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -47,6 +47,62 @@ uchar days_in_month[]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
static long my_time_zone=0;
+/* Calc days in one year. works with 0 <= year <= 99 */
+
+uint calc_days_in_year(uint year)
+{
+ return ((year & 3) == 0 && (year%100 || (year%400 == 0 && year)) ?
+ 366 : 365);
+}
+
+/*
+ Check datetime value for validity according to flags.
+
+ SYNOPSIS
+ check_date()
+ ltime Date to check.
+ not_zero_date ltime is not the zero date
+ flags flags to check
+ was_cut set to 2 if value was truncated.
+ NOTE: This is not touched if value was not truncated
+ NOTES
+ Here we assume that year and month is ok !
+ If month is 0 we allow any date. (This only happens if we allow zero
+ date parts in str_to_datetime())
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool check_date(const MYSQL_TIME *ltime, my_bool not_zero_date,
+ ulong flags, int *was_cut)
+{
+ if (not_zero_date)
+ {
+ if ((((flags & TIME_NO_ZERO_IN_DATE) || !(flags & TIME_FUZZY_DATE)) &&
+ (ltime->month == 0 || ltime->day == 0)) ||
+ (!(flags & TIME_INVALID_DATES) &&
+ ltime->month && ltime->day > days_in_month[ltime->month-1] &&
+ (ltime->month != 2 || calc_days_in_year(ltime->year) != 366 ||
+ ltime->day != 29)))
+ {
+ *was_cut= 2;
+ return TRUE;
+ }
+ }
+ else if (flags & TIME_NO_ZERO_DATE)
+ {
+ /*
+ We don't set *was_cut here to signal that the problem was a zero date
+ and not an invalid date
+ */
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
/*
Convert a timestamp string to a MYSQL_TIME value.
@@ -58,8 +114,12 @@ static long my_time_zone=0;
flags Bitmap of following items
TIME_FUZZY_DATE Set if we should allow partial dates
TIME_DATETIME_ONLY Set if we only allow full datetimes.
- was_cut Set to 1 if value was cut during conversion or to 0
- otherwise.
+ 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 Date part was within ranges but date was wrong
DESCRIPTION
At least the following formats are recogniced (based on number of digits)
@@ -104,11 +164,11 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
uint date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS];
uint add_hours= 0, start_loop;
ulong not_zero_date, allow_space;
- bool is_internal_format;
+ my_bool is_internal_format;
const char *pos, *last_field_pos;
const char *end=str+length;
const uchar *format_position;
- bool found_delimitier= 0, found_space= 0;
+ my_bool found_delimitier= 0, found_space= 0;
uint frac_pos, frac_len;
DBUG_ENTER("str_to_datetime");
DBUG_PRINT("ENTER",("str: %.*s",length,str));
@@ -349,8 +409,7 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
if (number_of_fields < 3 ||
l_time->year > 9999 || l_time->month > 12 ||
l_time->day > 31 || l_time->hour > 23 ||
- l_time->minute > 59 || l_time->second > 59 ||
- (!(flags & TIME_FUZZY_DATE) && (l_time->month == 0 || l_time->day == 0)))
+ l_time->minute > 59 || l_time->second > 59)
{
/* Only give warning for a zero date if there is some garbage after */
if (!not_zero_date) /* If zero date */
@@ -364,11 +423,13 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
}
}
}
- if (not_zero_date)
- *was_cut= 1;
+ *was_cut= test(not_zero_date);
goto err;
}
+ if (check_date(l_time, not_zero_date, flags, was_cut))
+ goto err;
+
l_time->time_type= (number_of_fields <= 3 ?
MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME);
@@ -414,12 +475,12 @@ err:
1 error
*/
-bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
- int *was_cut)
+my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
+ int *was_cut)
{
long date[5],value;
const char *end=str+length, *end_of_days;
- bool found_days,found_hours;
+ my_bool found_days,found_hours;
uint state;
l_time->neg=0;
@@ -602,7 +663,7 @@ void init_time(void)
time_t seconds;
struct tm *l_time,tm_tmp;
MYSQL_TIME my_time;
- bool not_used;
+ my_bool not_used;
seconds= (time_t) time((time_t*) 0);
localtime_r(&seconds,&tm_tmp);
@@ -668,7 +729,8 @@ long calc_daynr(uint year,uint month,uint day)
Time in UTC seconds since Unix Epoch representation.
*/
my_time_t
-my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
+my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone,
+ my_bool *in_dst_time_gap)
{
uint loop;
time_t tmp;
@@ -832,3 +894,172 @@ int my_TIME_to_str(const MYSQL_TIME *l_time, char *to)
return 0;
}
}
+
+
+/*
+ Convert datetime value specified as number to broken-down TIME
+ representation and form value of DATETIME type as side-effect.
+
+ SYNOPSIS
+ number_to_datetime()
+ nr - datetime value as number
+ time_res - pointer for structure for broken-down representation
+ flags - flags to use in validating date, as in str_to_datetime()
+ was_cut 0 Value ok
+ 1 If value was cut during conversion
+ 2 Date part was within ranges but date was wrong
+
+ DESCRIPTION
+ Convert a datetime value of formats YYMMDD, YYYYMMDD, YYMMDDHHMSS,
+ YYYYMMDDHHMMSS to broken-down TIME representation. Return value in
+ YYYYMMDDHHMMSS format as side-effect.
+
+ This function also checks if datetime value fits in DATETIME range.
+
+ RETURN VALUE
+ -1 Timestamp with wrong values
+ anything else DATETIME as integer in YYYYMMDDHHMMSS format
+ Datetime value in YYYYMMDDHHMMSS format.
+*/
+
+longlong number_to_datetime(longlong nr, MYSQL_TIME *time_res,
+ uint flags, int *was_cut)
+{
+ long part1,part2;
+
+ *was_cut= 0;
+
+ if (nr == LL(0) || nr >= LL(10000101000000))
+ goto ok;
+ if (nr < 101)
+ goto err;
+ if (nr <= (YY_PART_YEAR-1)*10000L+1231L)
+ {
+ nr= (nr+20000000L)*1000000L; /* YYMMDD, year: 2000-2069 */
+ goto ok;
+ }
+ if (nr < (YY_PART_YEAR)*10000L+101L)
+ goto err;
+ if (nr <= 991231L)
+ {
+ nr= (nr+19000000L)*1000000L; /* YYMMDD, year: 1970-1999 */
+ goto ok;
+ }
+ if (nr < 10000101L)
+ goto err;
+ if (nr <= 99991231L)
+ {
+ nr= nr*1000000L;
+ goto ok;
+ }
+ if (nr < 101000000L)
+ goto err;
+ if (nr <= (YY_PART_YEAR-1)*LL(10000000000)+LL(1231235959))
+ {
+ nr= nr+LL(20000000000000); /* YYMMDDHHMMSS, 2000-2069 */
+ goto ok;
+ }
+ if (nr < YY_PART_YEAR*LL(10000000000)+ LL(101000000))
+ goto err;
+ if (nr <= LL(991231235959))
+ nr= nr+LL(19000000000000); /* YYMMDDHHMMSS, 1970-1999 */
+
+ ok:
+ part1=(long) (nr/LL(1000000));
+ part2=(long) (nr - (longlong) part1*LL(1000000));
+ time_res->year= (int) (part1/10000L); part1%=10000L;
+ time_res->month= (int) part1 / 100;
+ time_res->day= (int) part1 % 100;
+ time_res->hour= (int) (part2/10000L); part2%=10000L;
+ time_res->minute=(int) part2 / 100;
+ time_res->second=(int) part2 % 100;
+
+ if (time_res->year <= 9999 && time_res->month <= 12 &&
+ time_res->day <= 31 && time_res->hour <= 23 &&
+ time_res->minute <= 59 && time_res->second <= 59 &&
+ !check_date(time_res, (nr != 0), flags, was_cut))
+ return nr;
+
+ /* Don't want to have was_cut get set if NO_ZERO_DATE was violated. */
+ if (!nr && (flags & TIME_NO_ZERO_DATE))
+ return LL(-1);
+
+ err:
+ *was_cut= 1;
+ return LL(-1);
+}
+
+
+/* Convert time value to integer in YYYYMMDDHHMMSS format */
+
+ulonglong TIME_to_ulonglong_datetime(const MYSQL_TIME *time)
+{
+ return ((ulonglong) (time->year * 10000UL +
+ time->month * 100UL +
+ time->day) * ULL(1000000) +
+ (ulonglong) (time->hour * 10000UL +
+ time->minute * 100UL +
+ time->second));
+}
+
+
+/* Convert TIME value to integer in YYYYMMDD format */
+
+ulonglong TIME_to_ulonglong_date(const MYSQL_TIME *time)
+{
+ return (ulonglong) (time->year * 10000UL + time->month * 100UL + time->day);
+}
+
+
+/*
+ Convert TIME value to integer in HHMMSS format.
+ This function doesn't take into account time->day member:
+ it's assumed that days have been converted to hours already.
+*/
+
+ulonglong TIME_to_ulonglong_time(const MYSQL_TIME *time)
+{
+ return (ulonglong) (time->hour * 10000UL +
+ time->minute * 100UL +
+ time->second);
+}
+
+
+/*
+ Convert struct TIME (date and time split into year/month/day/hour/...
+ to a number in format YYYYMMDDHHMMSS (DATETIME),
+ YYYYMMDD (DATE) or HHMMSS (TIME).
+
+ SYNOPSIS
+ TIME_to_ulonglong()
+
+ DESCRIPTION
+ The function is used when we need to convert value of time item
+ to a number if it's used in numeric context, i. e.:
+ SELECT NOW()+1, CURDATE()+0, CURTIMIE()+0;
+ SELECT ?+1;
+
+ NOTE
+ This function doesn't check that given TIME structure members are
+ in valid range. If they are not, return value won't reflect any
+ valid date either.
+*/
+
+ulonglong TIME_to_ulonglong(const MYSQL_TIME *time)
+{
+ switch (time->time_type) {
+ case MYSQL_TIMESTAMP_DATETIME:
+ return TIME_to_ulonglong_datetime(time);
+ case MYSQL_TIMESTAMP_DATE:
+ return TIME_to_ulonglong_date(time);
+ case MYSQL_TIMESTAMP_TIME:
+ return TIME_to_ulonglong_time(time);
+ case MYSQL_TIMESTAMP_NONE:
+ case MYSQL_TIMESTAMP_ERROR:
+ return ULL(0);
+ default:
+ DBUG_ASSERT(0);
+ }
+ return 0;
+}
+
diff --git a/sql-common/my_user.c b/sql-common/my_user.c
new file mode 100644
index 00000000000..c39f08e520f
--- /dev/null
+++ b/sql-common/my_user.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2005 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_user.h>
+#include <m_string.h>
+
+
+/*
+ Parse user value to user name and host name parts.
+
+ SYNOPSIS
+ user_id_str [IN] User value string (the source).
+ user_id_len [IN] Length of the user value.
+ user_name_str [OUT] Buffer to store user name part.
+ Must be not less than USERNAME_LENGTH + 1.
+ user_name_len [OUT] A place to store length of the user name part.
+ host_name_str [OUT] Buffer to store host name part.
+ Must be not less than HOSTNAME_LENGTH + 1.
+ host_name_len [OUT] A place to store length of the host name part.
+*/
+
+void parse_user(const char *user_id_str, uint user_id_len,
+ char *user_name_str, uint *user_name_len,
+ char *host_name_str, uint *host_name_len)
+{
+ char *p= strrchr(user_id_str, '@');
+
+ if (!p)
+ {
+ *user_name_len= 0;
+ *host_name_len= 0;
+ }
+ else
+ {
+ *user_name_len= p - user_id_str;
+ *host_name_len= user_id_len - *user_name_len - 1;
+
+ memcpy(user_name_str, user_id_str, *user_name_len);
+ memcpy(host_name_str, p + 1, *host_name_len);
+ }
+
+ user_name_str[*user_name_len]= 0;
+ host_name_str[*host_name_len]= 0;
+}