diff options
Diffstat (limited to 'sql-common')
-rw-r--r-- | sql-common/Makefile.am | 2 | ||||
-rw-r--r-- | sql-common/client.c | 165 | ||||
-rw-r--r-- | sql-common/my_time.c | 257 | ||||
-rw-r--r-- | sql-common/my_user.c | 57 |
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; +} |