diff options
author | monty@narttu.mysql.fi <> | 2003-11-03 22:48:03 +0200 |
---|---|---|
committer | monty@narttu.mysql.fi <> | 2003-11-03 22:48:03 +0200 |
commit | 6b79cd5c23c33d36c6dba2c990b20af8a88f97c1 (patch) | |
tree | 68c6948d4fbd18bb59fa1aeafdce4a07a41b835f /sql | |
parent | dde384d9ea881353f04ee9827421c23ded4e8c29 (diff) | |
parent | 085b1c56084d99646f2e52aee42ef026b7526eeb (diff) | |
download | mariadb-git-6b79cd5c23c33d36c6dba2c990b20af8a88f97c1.tar.gz |
Merge
Diffstat (limited to 'sql')
54 files changed, 2228 insertions, 1595 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am index 69b9c58dd6d..0167124a892 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -63,7 +63,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ thr_malloc.cc item_create.cc item_subselect.cc \ item_row.cc item_geofunc.cc \ - field.cc key.cc sql_class.cc sql_list.cc \ + field.cc strfunc.cc key.cc sql_class.cc sql_list.cc \ net_serv.cc protocol.cc sql_state.c \ lock.cc my_lock.c \ sql_string.cc sql_manager.cc sql_map.cc \ diff --git a/sql/derror.cc b/sql/derror.cc index f5fe92da238..8d4f8e664e2 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -117,7 +117,7 @@ Check that the above file is the right version for this program!", point[i]= *point +uint2korr(head+10+i+i); } VOID(my_close(file,MYF(0))); - DBUG_RETURN(FALSE); + DBUG_RETURN(0); err: switch (funktpos) { @@ -136,7 +136,7 @@ err1: if (file != FERR) VOID(my_close(file,MYF(MY_WME))); unireg_abort(1); - return 1; + DEBUG_RETURN(1); // Impossible } /* read_texts */ diff --git a/sql/field.cc b/sql/field.cc index c30c06c6395..04e9c45327b 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -274,13 +274,14 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) return copy->length+(int) copy->strip; } -bool Field::get_date(TIME *ltime,bool fuzzydate) + +bool Field::get_date(TIME *ltime,uint fuzzydate) { char buff[40]; String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res; if (!(res=val_str(&tmp,&tmp2)) || - str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate,current_thd)<= - WRONG_TIMESTAMP_FULL) + str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) <= + TIMESTAMP_DATETIME_ERROR) return 1; return 0; } @@ -290,39 +291,44 @@ bool Field::get_time(TIME *ltime) char buff[40]; String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res; if (!(res=val_str(&tmp,&tmp2)) || - str_to_time(res->ptr(),res->length(),ltime,current_thd)) + str_to_time(res->ptr(),res->length(),ltime)) return 1; return 0; } +/* + This is called when storing a date in a string + + NOTES + Needs to be changed if/when we want to support different time formats +*/ -/* This is called when storing a date in a string */ void Field::store_time(TIME *ltime,timestamp_type type) { char buff[25]; - String tmp((char*) buff,sizeof(buff),&my_charset_bin); - DATETIME_FORMAT *tmp_format= 0; - bool is_time_only= 0; - switch (type) { case TIMESTAMP_NONE: - case WRONG_TIMESTAMP_FULL: + case TIMESTAMP_DATETIME_ERROR: store("",0,&my_charset_bin); // Probably an error - return; + break; case TIMESTAMP_DATE: - tmp_format= &t_datetime_frm(current_thd, DATE_FORMAT_TYPE).datetime_format; + sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day); + store(buff,10,&my_charset_bin); break; - case TIMESTAMP_FULL: - tmp_format=&t_datetime_frm(current_thd,DATETIME_FORMAT_TYPE).datetime_format; + case TIMESTAMP_DATETIME: + sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d", + ltime->year,ltime->month,ltime->day, + ltime->hour,ltime->minute,ltime->second); + store(buff,19,&my_charset_bin); break; case TIMESTAMP_TIME: - tmp_format= &t_datetime_frm(current_thd, TIME_FORMAT_TYPE).datetime_format; - is_time_only= 1; + { + ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d", + ltime->hour,ltime->minute,ltime->second)); + store(buff,(uint) length, &my_charset_bin); break; } - make_datetime(&tmp, ltime, is_time_only, 0, - tmp_format->format, tmp_format->format_length, 1); - store(tmp.ptr(),tmp.length(),&my_charset_bin); + } } @@ -2693,7 +2699,7 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) { - long tmp=(long) str_to_timestamp(from,len,current_thd); + long tmp=(long) str_to_timestamp(from,len); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -2908,7 +2914,7 @@ String *Field_timestamp::val_str(String *val_buffer, } -bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate) +bool Field_timestamp::get_date(TIME *ltime, uint fuzzydate) { long temp; #ifdef WORDS_BIGENDIAN @@ -2937,7 +2943,7 @@ bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate) ltime->second= start->tm_sec; ltime->second_part= 0; ltime->neg= 0; - ltime->time_type=TIMESTAMP_FULL; + ltime->time_type=TIMESTAMP_DATETIME; } return 0; } @@ -2951,7 +2957,7 @@ bool Field_timestamp::get_time(TIME *ltime) bool Field_timestamp::send_binary(Protocol *protocol) { TIME tm; - Field_timestamp::get_date(&tm, 1); + Field_timestamp::get_date(&tm, TIME_FUZZY_DATE); return protocol->store(&tm); } @@ -3027,7 +3033,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) TIME ltime; long tmp; int error= 0; - if (str_to_time(from,len,<ime,current_thd)) + if (str_to_time(from,len,<ime)) { tmp=0L; error= 1; @@ -3137,27 +3143,23 @@ String *Field_time::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { TIME ltime; - val_buffer->alloc(16); + val_buffer->alloc(19); long tmp=(long) sint3korr(ptr); - const char *sign=""; ltime.neg= 0; if (tmp < 0) { tmp= -tmp; ltime.neg= 1; } - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (current_thd, TIME_FORMAT_TYPE).datetime_format); ltime.day= (uint) 0; ltime.hour= (uint) (tmp/10000); ltime.minute= (uint) (tmp/100 % 100); ltime.second= (uint) (tmp % 100); - make_datetime(val_buffer, <ime, 0, 0, - tmp_format->format, - tmp_format->format_length, 1); + make_time((DATE_TIME_FORMAT*) 0, <ime, val_buffer); return val_buffer; } + bool Field_time::get_time(TIME *ltime) { long tmp=(long) sint3korr(ptr); @@ -3320,7 +3322,7 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs) TIME l_time; uint32 tmp; int error= 0; - if (str_to_TIME(from,len,&l_time,1,current_thd) <= WRONG_TIMESTAMP_FULL) + if (str_to_TIME(from,len,&l_time,1) <= TIMESTAMP_DATETIME_ERROR) { tmp=0; error= 1; @@ -3432,7 +3434,6 @@ String *Field_date::val_str(String *val_buffer, { TIME ltime; val_buffer->alloc(field_length); - val_buffer->length(field_length); int32 tmp; #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -3440,18 +3441,15 @@ String *Field_date::val_str(String *val_buffer, else #endif longget(tmp,ptr); - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (current_thd, DATE_FORMAT_TYPE).datetime_format); ltime.neg= 0; ltime.year= (int) ((uint32) tmp/10000L % 10000); ltime.month= (int) ((uint32) tmp/100 % 100); ltime.day= (int) ((uint32) tmp % 100); - make_datetime(val_buffer, <ime, 0, 0, - tmp_format->format, - tmp_format->format_length, 1); + make_date((DATE_TIME_FORMAT *) 0, <ime, val_buffer); return val_buffer; } + int Field_date::cmp(const char *a_ptr, const char *b_ptr) { int32 a,b; @@ -3507,7 +3505,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) TIME l_time; long tmp; int error= 0; - if (str_to_TIME(from,len,&l_time,1,current_thd) <= WRONG_TIMESTAMP_FULL) + if (str_to_TIME(from,len,&l_time,1) <= TIMESTAMP_DATETIME_ERROR) { tmp=0L; error= 1; @@ -3572,7 +3570,7 @@ int Field_newdate::store(longlong nr) void Field_newdate::store_time(TIME *ltime,timestamp_type type) { long tmp; - if (type == TIMESTAMP_DATE || type == TIMESTAMP_FULL) + if (type == TIMESTAMP_DATE || type == TIMESTAMP_DATETIME) tmp=ltime->year*16*32+ltime->month*32+ltime->day; else { @@ -3628,7 +3626,7 @@ String *Field_newdate::val_str(String *val_buffer, return val_buffer; } -bool Field_newdate::get_date(TIME *ltime,bool fuzzydate) +bool Field_newdate::get_date(TIME *ltime,uint fuzzydate) { if (is_null()) return 1; @@ -3676,7 +3674,7 @@ void Field_newdate::sql_type(String &res) const int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs) { - longlong tmp=str_to_datetime(from,len,1,current_thd); + longlong tmp=str_to_datetime(from,len,1); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -3730,7 +3728,7 @@ int Field_datetime::store(longlong nr) void Field_datetime::store_time(TIME *ltime,timestamp_type type) { longlong tmp; - if (type == TIMESTAMP_DATE || type == TIMESTAMP_FULL) + if (type == TIMESTAMP_DATE || type == TIMESTAMP_DATETIME) tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+ (ltime->hour*10000L+ltime->minute*100+ltime->second)); else @@ -3751,7 +3749,7 @@ void Field_datetime::store_time(TIME *ltime,timestamp_type type) bool Field_datetime::send_binary(Protocol *protocol) { TIME tm; - Field_datetime::get_date(&tm, 1); + Field_datetime::get_date(&tm, TIME_FUZZY_DATE); return protocol->store(&tm); } @@ -3822,14 +3820,14 @@ String *Field_datetime::val_str(String *val_buffer, return val_buffer; } -bool Field_datetime::get_date(TIME *ltime,bool fuzzydate) +bool Field_datetime::get_date(TIME *ltime, uint fuzzydate) { longlong tmp=Field_datetime::val_int(); uint32 part1,part2; part1=(uint32) (tmp/LL(1000000)); part2=(uint32) (tmp - (ulonglong) part1*LL(1000000)); - ltime->time_type= TIMESTAMP_FULL; + ltime->time_type= TIMESTAMP_DATETIME; ltime->neg= 0; ltime->second_part= 0; ltime->second= (int) (part2%100); @@ -4921,26 +4919,6 @@ void Field_enum::store_type(ulonglong value) } -uint find_enum(TYPELIB *lib,const char *x, uint length) -{ - const char *end=x+length; - while (end > x && my_isspace(system_charset_info,end[-1])) - end--; - - const char *i; - const char *j; - for (uint pos=0 ; (j=lib->type_names[pos]) ; pos++) - { - for (i=x ; i != end && - my_toupper(system_charset_info,*i) == - my_toupper(system_charset_info,*j) ; i++, j++) ; - if (i == end && ! *j) - return(pos+1); - } - return(0); -} - - /* ** Note. Storing a empty string in a enum field gives a warning ** (if there isn't a empty value in the enum) @@ -4958,7 +4936,11 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) from= tmpstr.ptr(); length= tmpstr.length(); } - uint tmp=find_enum(typelib,from,length); + + /* Remove end space */ + while (length > 0 && my_isspace(system_charset_info,from[length-1])) + length--; + uint tmp=find_type(typelib, from, length, 0); if (!tmp) { if (length < 6) // Can't be more than 99999 enums @@ -5111,49 +5093,8 @@ void Field_enum::sql_type(String &res) const For example "One,two,five" If one uses this string in a number context one gets the bits as a longlong number. - - If there was a value in string that wasn't in set, the 'err_pos' points to - the last invalid value found. 'err_len' will be set to length of the - error string. */ -ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos, - uint *err_len, bool *set_warning) -{ - const char *end= x + length; - *err_pos= 0; // No error yet - while (end > x && my_isspace(system_charset_info, end[-1])) - end--; - - *err_len= 0; - ulonglong found= 0; - if (x != end) - { - const char *start= x; - for (;;) - { - const char *pos= start; - uint var_len; - - for (; pos != end && *pos != field_separator; pos++) ; - var_len= (uint) (pos - start); - uint find= find_enum(lib, start, var_len); - if (!find) - { - *err_pos= (char*) start; - *err_len= var_len; - *set_warning= 1; - } - else - found|= ((longlong) 1 << (find - 1)); - if (pos == end) - break; - start= pos + 1; - } - } - return found; -} - int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) { @@ -5512,7 +5453,7 @@ create_field::create_field(Field *old_field,Field *orig_field) case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break; default: sql_type= FIELD_TYPE_LONG_BLOB; break; } - length /= charset->mbmaxlen; + length /= charset->mbmaxlen; // QQ: Probably not needed break; case FIELD_TYPE_STRING: case FIELD_TYPE_VAR_STRING: diff --git a/sql/field.h b/sql/field.h index e7d4bb2416a..692e64d1146 100644 --- a/sql/field.h +++ b/sql/field.h @@ -224,7 +224,7 @@ public: uint offset(); // Should be inline ... void copy_from_tmp(int offset); uint fill_cache_field(struct st_cache_field *copy); - virtual bool get_date(TIME *ltime,bool fuzzydate); + virtual bool get_date(TIME *ltime,uint fuzzydate); virtual bool get_time(TIME *ltime); virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } virtual bool has_charset(void) const { return FALSE; } @@ -647,7 +647,7 @@ public: longget(tmp,ptr); return tmp; } - bool get_date(TIME *ltime,bool fuzzydate); + bool get_date(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); }; @@ -735,7 +735,7 @@ public: void sql_type(String &str) const; bool store_for_compare() { return 1; } bool zero_pack() const { return 1; } - bool get_date(TIME *ltime,bool fuzzydate); + bool get_date(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); }; @@ -805,7 +805,7 @@ public: void sql_type(String &str) const; bool store_for_compare() { return 1; } bool zero_pack() const { return 1; } - bool get_date(TIME *ltime,bool fuzzydate); + bool get_date(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); }; @@ -1160,9 +1160,6 @@ uint pack_length_to_packflag(uint type); uint32 calc_pack_length(enum_field_types type,uint32 length); bool set_field_to_null(Field *field); bool set_field_to_null_with_conversions(Field *field, bool no_conversions); -uint find_enum(TYPELIB *typelib,const char *x, uint length); -ulonglong find_set(TYPELIB *typelib,const char *x, uint length, - char **err_pos, uint *err_len, bool *set_warning); bool test_if_int(const char *str, int length, const char *int_end, CHARSET_INFO *cs); diff --git a/sql/init.cc b/sql/init.cc index 8b15fef4ee3..033dfd72843 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -42,8 +42,6 @@ void unireg_init(ulong options) #endif VOID(strmov(reg_ext,".frm")); - for (i=0 ; i < 6 ; i++) // YYMMDDHHMMSS - dayord.pos[i]=i; specialflag=SPECIAL_SAME_DB_NAME; /* Make a tab of powers of 10 */ for (i=0,nr=1.0; i < array_elements(log_10) ; i++) diff --git a/sql/item.cc b/sql/item.cc index 421574ed636..24710654d4a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -46,8 +46,10 @@ Item::Item(): collation.set(default_charset(), DERIVATION_COERCIBLE); name= 0; decimals= 0; max_length= 0; - thd= current_thd; - next= thd->free_list; // Put in free list + + /* Put item in free list so that we can free all items at end */ + THD *thd= current_thd; + next= thd->free_list; thd->free_list= this; /* Item constructor can be called during execution other then SQL_COM @@ -69,7 +71,7 @@ Item::Item(): Used for duplicating lists in processing queries with temporary tables */ -Item::Item(THD *c_thd, Item &item): +Item::Item(THD *thd, Item &item): str_value(item.str_value), name(item.name), max_length(item.max_length), @@ -82,8 +84,7 @@ Item::Item(THD *c_thd, Item &item): fixed(item.fixed), collation(item.collation) { - next=c_thd->free_list; // Put in free list - thd= c_thd; + next= thd->free_list; // Put in free list thd->free_list= this; } @@ -183,13 +184,13 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const As a extra convenience the time structure is reset on error! */ -bool Item::get_date(TIME *ltime,bool fuzzydate) +bool Item::get_date(TIME *ltime,uint fuzzydate) { char buff[40]; String tmp(buff,sizeof(buff), &my_charset_bin),*res; if (!(res=val_str(&tmp)) || - str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate, thd) <= - WRONG_TIMESTAMP_FULL) + str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) <= + TIMESTAMP_DATETIME_ERROR) { bzero((char*) ltime,sizeof(*ltime)); return 1; @@ -207,7 +208,7 @@ bool Item::get_time(TIME *ltime) char buff[40]; String tmp(buff,sizeof(buff),&my_charset_bin),*res; if (!(res=val_str(&tmp)) || - str_to_time(res->ptr(),res->length(),ltime, thd)) + str_to_time(res->ptr(),res->length(),ltime)) { bzero((char*) ltime,sizeof(*ltime)); return 1; @@ -360,7 +361,7 @@ String *Item_field::str_result(String *str) return result_field->val_str(str,&str_value); } -bool Item_field::get_date(TIME *ltime,bool fuzzydate) +bool Item_field::get_date(TIME *ltime,uint fuzzydate) { if ((null_value=field->is_null()) || field->get_date(ltime,fuzzydate)) { @@ -370,7 +371,7 @@ bool Item_field::get_date(TIME *ltime,bool fuzzydate) return 0; } -bool Item_field::get_date_result(TIME *ltime,bool fuzzydate) +bool Item_field::get_date_result(TIME *ltime,uint fuzzydate) { if ((null_value=result_field->is_null()) || result_field->get_date(ltime,fuzzydate)) @@ -692,28 +693,25 @@ String *Item_param::query_val_str(String* str) } else { - DATETIME_FORMAT *tmp_format= 0; - bool is_time_only= 0; + char buff[40]; + String tmp(buff,sizeof(buff), &my_charset_bin); switch (ltime.time_type) { - case TIMESTAMP_NONE: - case WRONG_TIMESTAMP_FULL: - break; - case TIMESTAMP_DATE: - tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; - break; - case TIMESTAMP_FULL: - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; - break; - case TIMESTAMP_TIME: - { - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; - is_time_only= 1; - break; - } + case TIMESTAMP_NONE: + case TIMESTAMP_DATETIME_ERROR: + tmp.length(0); // Should never happen + break; + case TIMESTAMP_DATE: + make_date((DATE_TIME_FORMAT*) 0, <ime, &tmp); + break; + case TIMESTAMP_DATETIME: + make_datetime((DATE_TIME_FORMAT*) 0, <ime, &tmp); + break; + case TIMESTAMP_TIME: + make_time((DATE_TIME_FORMAT*) 0, <ime, &tmp); + break; } - make_datetime(str, <ime, is_time_only, 0, - tmp_format->format, tmp_format->format_length, 0); + str->append(tmp); } str->append('\''); } @@ -769,7 +767,7 @@ String* Item_ref_null_helper::val_str(String* s) owner->was_null|= null_value= (*ref)->null_value; return tmp; } -bool Item_ref_null_helper::get_date(TIME *ltime, bool fuzzydate) +bool Item_ref_null_helper::get_date(TIME *ltime, uint fuzzydate) { return (owner->was_null|= null_value= (*ref)->get_date(ltime, fuzzydate)); } @@ -990,6 +988,7 @@ enum_field_types Item::field_type() const FIELD_TYPE_DOUBLE); } + Field *Item::tmp_table_field_from_field_type(TABLE *table) { switch (field_type()) @@ -1366,7 +1365,7 @@ bool Item::send(Protocol *protocol, String *buffer) case MYSQL_TYPE_TIMESTAMP: { TIME tm; - get_date(&tm, 1); + get_date(&tm, TIME_FUZZY_DATE); if (!null_value) { if (type == MYSQL_TYPE_DATE) diff --git a/sql/item.h b/sql/item.h index dcefde05605..f473ca33676 100644 --- a/sql/item.h +++ b/sql/item.h @@ -114,14 +114,6 @@ public: my_bool fixed; /* If item fixed with fix_fields */ DTCollation collation; - - /* - thd is current_thd value. Like some other Item's fields it - will be a problem for using one Item in different threads - (as stored procedures may want to do in the future) - */ - THD *thd; - // alloc & destruct is done as start of select using sql_alloc Item(); /* @@ -132,7 +124,7 @@ public: top AND/OR ctructure of WHERE clause to protect it of optimisation changes in prepared statements */ - Item(THD *c_thd, Item &item); + Item(THD *thd, Item &item); virtual ~Item() { name=0; } /*lint -e1509 */ void set_name(const char *str,uint length, CHARSET_INFO *cs); void init_make_field(Send_field *tmp_field,enum enum_field_types type); @@ -185,9 +177,9 @@ public: void print_item_w_name(String *); virtual void update_used_tables() {} virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields) {} - virtual bool get_date(TIME *ltime,bool fuzzydate); + virtual bool get_date(TIME *ltime,uint fuzzydate); virtual bool get_time(TIME *ltime); - virtual bool get_date_result(TIME *ltime,bool fuzzydate) + virtual bool get_date_result(TIME *ltime,uint fuzzydate) { return get_date(ltime,fuzzydate); } virtual bool is_null() { return 0; } virtual void top_level_item() {} @@ -286,8 +278,8 @@ public: } Field *get_tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return result_field; } - bool get_date(TIME *ltime,bool fuzzydate); - bool get_date_result(TIME *ltime,bool fuzzydate); + bool get_date(TIME *ltime,uint fuzzydate); + bool get_date_result(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); bool is_null() { return field->is_null(); } Item *get_tmp_table_item(THD *thd); @@ -469,6 +461,13 @@ public: { collation.set(cs, dv); str_value.set(str,length,cs); + /* + We have to have a different max_length than 'length' here to + ensure that we get the right length if we do use the item + to create a new table. In this case max_length must be the maximum + number of chars for a string of this type because we in create_field:: + divide the max_length with mbmaxlen). + */ max_length= str_value.numchars()*cs->mbmaxlen; set_name(str, length, cs); decimals=NOT_FIXED_DEC; @@ -623,7 +622,7 @@ public: (void) (*ref)->val_int_result(); return (*ref)->null_value; } - bool get_date(TIME *ltime,bool fuzzydate) + bool get_date(TIME *ltime,uint fuzzydate) { return (null_value=(*ref)->get_date_result(ltime,fuzzydate)); } @@ -658,7 +657,7 @@ public: double val(); longlong val_int(); String* val_str(String* s); - bool get_date(TIME *ltime, bool fuzzydate); + bool get_date(TIME *ltime, uint fuzzydate); void print(String *str); }; diff --git a/sql/item_create.cc b/sql/item_create.cc index a25ccfe984b..5c44d8b00ff 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -450,7 +450,8 @@ Item *create_load_file(Item* a) } -Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs) +Item *create_func_cast(Item *a, Cast_target cast_type, int len, + CHARSET_INFO *cs) { Item *res; LINT_INIT(res); diff --git a/sql/item_func.cc b/sql/item_func.cc index bcb4ec9aa7f..e6120f2e93c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1323,8 +1323,8 @@ void Item_func_find_in_set::fix_length_and_dec() String *find=args[0]->val_str(&value); if (find) { - enum_value=find_enum(((Field_enum*) field)->typelib,find->ptr(), - find->length()); + enum_value= find_type(((Field_enum*) field)->typelib,find->ptr(), + find->length(), 0); enum_bit=0; if (enum_value) enum_bit=LL(1) << (enum_value-1); @@ -2146,8 +2146,8 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, } /* - When a user variable is updated (in a SET command or a query like SELECT @a:= - ). + When a user variable is updated (in a SET command or a query like + SELECT @a:= ). */ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, @@ -2506,14 +2506,15 @@ void Item_func_get_user_var::fix_length_and_dec() sql_set_variables() is what is called from 'case SQLCOM_SET_OPTION' in dispatch_command()). Instead of building a one-element list to pass to sql_set_variables(), we could instead manually call check() and update(); - this would save memory and time; but calling sql_set_variables() makes one - unique place to maintain (sql_set_variables()). + this would save memory and time; but calling sql_set_variables() makes + one unique place to maintain (sql_set_variables()). */ List<set_var_base> tmp_var_list; tmp_var_list.push_back(new set_var_user(new Item_func_set_user_var(name, new Item_null()))); - if (sql_set_variables(thd, &tmp_var_list)) /* this will create the variable */ + /* Create the variable */ + if (sql_set_variables(thd, &tmp_var_list)) goto err; if (!(var_entry= get_variable(&thd->user_vars, name, 0))) goto err; diff --git a/sql/item_func.h b/sql/item_func.h index b9498ed0b5d..6b43ebaccbe 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -127,9 +127,9 @@ public: void print_op(String *str); void print_args(String *str, uint from); void fix_num_length_and_dec(); - inline bool get_arg0_date(TIME *ltime,bool fuzzy_date) + inline bool get_arg0_date(TIME *ltime, uint fuzzy_date) { - return (null_value=args[0]->get_date(ltime,fuzzy_date)); + return (null_value=args[0]->get_date(ltime, fuzzy_date)); } inline bool get_arg0_time(TIME *ltime) { diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 00b1ebb0732..a7949511f02 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -361,7 +361,7 @@ public: String *val_str(String *); void fix_length_and_dec() { - max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen; + max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen; } const char *func_name() const { return "database"; } }; @@ -373,7 +373,7 @@ public: String *val_str(String *); void fix_length_and_dec() { - max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*system_charset_info->mbmaxlen; + max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*system_charset_info->mbmaxlen; } const char *func_name() const { return "user"; } }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 46d39b4ced6..cf71f2b3bef 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2003 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 @@ -25,310 +25,290 @@ #include <m_ctype.h> #include <time.h> -/* -** Todo: Move month and days to language files -*/ +/* TODO: Move month and days to language files */ #define MAX_DAY_NUMBER 3652424L -static String month_names[] = -{ - String("January", &my_charset_latin1), - String("February", &my_charset_latin1), - String("March", &my_charset_latin1), - String("April", &my_charset_latin1), - String("May", &my_charset_latin1), - String("June", &my_charset_latin1), - String("July", &my_charset_latin1), - String("August", &my_charset_latin1), - String("September", &my_charset_latin1), - String("October", &my_charset_latin1), - String("November", &my_charset_latin1), - String("December", &my_charset_latin1) +static const char *month_names[]= +{ + "January", "February", "March", "April", "May", "June", "July", "August", + "September", "October", "November", "December", NullS }; -static String day_names[] = + +TYPELIB month_names_typelib= +{ array_elements(month_names)-1,"", month_names }; + +static const char *day_names[]= +{ + "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" ,"Sunday", NullS +}; + +TYPELIB day_names_typelib= +{ array_elements(day_names)-1,"", day_names}; + + +enum date_time_format_types { - String("Monday", &my_charset_latin1), - String("Tuesday", &my_charset_latin1), - String("Wednesday", &my_charset_latin1), - String("Thursday", &my_charset_latin1), - String("Friday", &my_charset_latin1), - String("Saturday", &my_charset_latin1), - String("Sunday", &my_charset_latin1) + TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND }; -uint check_names(String *arr,int item_count,const char *val_ptr, - const char *val_end, uint *val, bool check_part) +/* + OPTIMIZATION TODO: + - Replace the switch with a function that should be called for each + date type. + - Remove sprintf and opencode the conversion, like we do in + Field_datetime. + + The reason for this functions existence is that as we don't have a + way to know if a datetime/time value has microseconds in them + we are now only adding microseconds to the output if the + value has microseconds. + + We can't use a standard make_date_time() for this as we don't know + if someone will use %f in the format specifier in which case we would get + the microseconds twice. +*/ + +static bool make_datetime(date_time_format_types format, TIME *ltime, + String *str) { - for (int i= 0; i < item_count; i++) - { - String *tmp=&arr[i]; - if (!my_strnncoll(&my_charset_latin1, - (const uchar *) val_ptr, 3, - (const uchar *) tmp->ptr(), 3)) - { - if (check_part) - { - *val= i+1; - return 3; - } + char *buff; + CHARSET_INFO *cs= &my_charset_bin; + uint length= 30; - int part_len= tmp->length() - 3; - int val_len= val_end - val_ptr - 3; - if (val_len < part_len) - return 0; - val_ptr+=3; - if (!my_strnncoll(&my_charset_latin1, - (const uchar *) val_ptr, part_len, - (const uchar *) tmp->ptr() + 3, part_len)) - { - *val= i+1; - return tmp->length(); - } - return 0; - } - } - return 0; -} + if (str->alloc(length)) + return 1; + buff= (char*) str->ptr(); -uint check_val_is_digit(const char *ptr, uint val_len, uint digit_count) -{ - uint i; - uint verify_count= (val_len < digit_count ? val_len : digit_count); - uint digit_found= 0; - for (i= 0; i < verify_count; i++) - { - if (!my_isdigit(&my_charset_latin1, *(ptr+i))) - break; - digit_found++; + switch (format) { + case TIME_ONLY: + length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d", + ltime->neg ? "-" : "", + ltime->hour, ltime->minute, ltime->second); + break; + case TIME_MICROSECOND: + length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d.%06d", + ltime->neg ? "-" : "", + ltime->hour, ltime->minute, ltime->second, + ltime->second_part); + break; + case DATE_ONLY: + length= cs->cset->snprintf(cs, buff, length, "%04d-%02d-%02d", + ltime->year, ltime->month, ltime->day); + break; + case DATE_TIME: + length= cs->cset->snprintf(cs, buff, length, + "%04d-%02d-%02d %02d:%02d:%02d", + ltime->year, ltime->month, ltime->day, + ltime->hour, ltime->minute, ltime->second); + break; + case DATE_TIME_MICROSECOND: + length= cs->cset->snprintf(cs, buff, length, + "%04d-%02d-%02d %02d:%02d:%02d.%06d", + ltime->year, ltime->month, ltime->day, + ltime->hour, ltime->minute, ltime->second, + ltime->second_part); + break; } - return digit_found; + + str->length(length); + str->set_charset(cs); + return 0; } /* Extract datetime value to TIME struct from string value according to format string. + + SYNOPSIS + extract_date_time() + format date/time format specification + val String to decode + length Length of string + l_time Store result here + + RETURN + 0 ok + 1 error */ -bool extract_datetime(const char *str_val, uint str_val_len, - const char *str_format, uint str_format_len, - TIME *l_time) + +static bool extract_date_time(DATE_TIME_FORMAT *format, + const char *val, uint length, TIME *l_time) { - char intbuff[15]; int weekday= 0, yearday= 0, daypart= 0, len; - int val_len= 0; int week_number= -1; - ulong length; CHARSET_INFO *cs= &my_charset_bin; - int err= 0; + int error= 0; bool usa_time= 0; bool sunday_first= 0; - const char *rT_format= "%H:%i:%s"; uint part_len= 0; - const char *val_ptr=str_val; - const char *val_end= str_val + str_val_len; - const char *ptr=str_format; - const char *end=ptr+ str_format_len; + const char *val_ptr= val; + const char *val_end= val + length; + const char *ptr= format->format.str; + const char *end= ptr+ format->format.length; + DBUG_ENTER("extract_date_time"); - DBUG_ENTER("extract_datetime"); - for (; ptr != end && val_ptr != val_end; ptr++) + bzero((char*) l_time, sizeof(*l_time)); + + for (; ptr != end && val != val_end; ptr++) { + if (*ptr == '%' && ptr+1 != end) { - val_len= val_end - val_ptr; - char *val_end1= (char *) val_end; + int val_len; + char *tmp; + + /* Skip pre-space between each argument */ + while (my_isspace(cs, *val) && val != val_end) + val++; + + val_len= (uint) (val_end - val); switch (*++ptr) { - case 'h': - case 'I': - case 'H': - l_time->hour= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - usa_time= (*ptr == 'I' || *ptr == 'h'); - val_ptr+=2; - break; - case 'k': - case 'l': - l_time->hour= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err) - return 1; - usa_time= (*ptr == 'l'); - val_ptr= val_end1; - break; - case 'e': - l_time->day= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err) - return 1; - val_ptr= val_end1; - break; - case 'c': - l_time->month= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err) - return 1; - val_ptr= val_end1; - break; + /* Year */ case 'Y': - l_time->year= my_strntoll(cs, val_ptr, - 4, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 4)) - return 1; - val_ptr+=4; + tmp= (char*) val + min(4, val_len); + l_time->year= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; case 'y': - l_time->year= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; + tmp= (char*) val + min(2, val_len); + l_time->year= (int) my_strtoll10(val, &tmp, &error); + val= tmp; l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); - val_ptr+=2; break; + + /* Month */ case 'm': - l_time->month= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - val_ptr+=2; + case 'c': + tmp= (char*) val + min(2, val_len); + l_time->month= (int) my_strtoll10(val, &tmp, &error); + val= tmp; + break; + case 'M': + case 'b': + if ((l_time->month= check_word(&month_names_typelib, + val, val_end, &val)) <= 0) + goto err; break; + /* Day */ case 'd': - l_time->day= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - val_ptr+=2; + case 'e': + tmp= (char*) val + min(2, val_len); + l_time->day= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; case 'D': - l_time->day= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_len < val_end1 - val_ptr + 2)) - return 1; - val_ptr= val_end1 + 2; + tmp= (char*) val + min(2, val_len); + l_time->day= (int) my_strtoll10(val, &tmp, &error); + /* Skip 'st, 'nd, 'th .. */ + val= tmp + min((int) (end-tmp), 2); + break; + + /* Hour */ + case 'h': + case 'I': + case 'l': + usa_time= 1; + /* fall through */ + case 'k': + case 'H': + tmp= (char*) val + min(2, val_len); + l_time->hour= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; + + /* Minute */ case 'i': - l_time->minute=my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - val_ptr+=2; + tmp= (char*) val + min(2, val_len); + l_time->minute= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; + + /* Second */ case 's': case 'S': - l_time->second= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - val_ptr+=2; + tmp= (char*) val + min(2, val_len); + l_time->second= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; - case 'M': - if (val_len < 3 || - !(part_len= check_names(month_names, 12 , val_ptr, - val_end, &l_time->month, 0))) - return 1; - val_ptr+= part_len; + + /* Second part */ + case 'f': + tmp= (char*) val_end; + l_time->second_part= my_strtoll10(val, &tmp, &error); + val= tmp; break; - case 'b': - if (val_len < 3 || - !(part_len= check_names(month_names, 12 , val_ptr, - val_end,(uint *) &l_time->month, 1))) - return 1; - val_ptr+= part_len; + + /* AM / PM */ + case 'p': + if (val_len < 2 || ! usa_time) + goto err; + if (!my_strnncoll(&my_charset_latin1, + (const uchar *) val, 2, + (const uchar *) "PM", 2)) + daypart= 12; + else if (my_strnncoll(&my_charset_latin1, + (const uchar *) val, 2, + (const uchar *) "AM", 2)) + goto err; break; + + /* Exotic things */ case 'W': - if (val_len < 3 || - !(part_len= check_names(day_names, 7 , val_ptr, - val_end,(uint *) &weekday, 0))) - return 1; - val_ptr+= part_len; - break; case 'a': - if (val_len < 3 || - !(part_len= check_names(day_names, 7 , val_ptr, - val_end,(uint *) &weekday, 1))) - return 1; - val_ptr+= part_len; + if ((weekday= check_word(&day_names_typelib, val, val_end, &val)) <= 0) + goto err; break; case 'w': - weekday= my_strntoll(cs, val_ptr, 1, 10, &val_end1, &err); - if (err) - return 1; - val_ptr++; + tmp= (char*) val + 1; + if ((weekday= (int) my_strtoll10(val, &tmp, &error)) <= 0 || + weekday >= 7) + goto err; + val= tmp; break; case 'j': - yearday= my_strntoll(cs, val_ptr, 3, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 3)) - return 1; - val_ptr+=3; - break; - case 'f': - l_time->second_part= my_strntoll(cs, val_ptr, 3, 10, &val_end1, &err); - if (err) - return 1; - val_ptr= val_end1; - break; - case 'p': - if (val_len < 2) - return 1; - if (!my_strnncoll(&my_charset_latin1, - (const uchar *) val_ptr, 2, - (const uchar *) "PM", 2)) - { - daypart= 12; - val_ptr+= 2; - } + tmp= (char*) val + min(val_len, 3); + yearday= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; + case 'U': - week_number= my_strntoll(cs, val_ptr, 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; sunday_first= 1; - val_ptr+=2; - break; + /* Fall through */ case 'u': - week_number= my_strntoll(cs, val_ptr, 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - sunday_first=0; - val_ptr+=2; - break; - case 'r': - case 'T': - usa_time= (*ptr == 'r'); - if (extract_datetime(val_ptr, val_end-val_ptr, - rT_format, strlen(rT_format), - l_time)) - return 1; - val_ptr+=8; + tmp= (char*) val + min(val_len, 2); + week_number= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; + default: - if (*val_ptr != *ptr) - return 1; - val_ptr++; + goto err; } + if (error) // Error from my_strtoll10 + goto err; } - else + else if (!my_isspace(cs, *ptr)) { - if (*val_ptr != *ptr) - return 1; - val_ptr++; + if (*val != *ptr) + goto err; + val++; } } if (usa_time) { if (l_time->hour > 12 || l_time->hour < 1) - return 1; + goto err; l_time->hour= l_time->hour%12+daypart; } if (yearday > 0) { uint days= calc_daynr(l_time->year,1,1) + yearday - 1; - if (days > 0 || days < MAX_DAY_NUMBER) - { - get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); - } + if (days <= 0 || days >= MAX_DAY_NUMBER) + goto err; + get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); } if (week_number >= 0 && weekday) @@ -337,7 +317,7 @@ bool extract_datetime(const char *str_val, uint str_val_len, uint weekday_b; if (weekday > 7 || weekday < 0) - return 1; + goto err; if (sunday_first) weekday = weekday%7; @@ -361,43 +341,43 @@ bool extract_datetime(const char *str_val, uint str_val_len, weekday =weekday - weekday_b - !sunday_first; days+= weekday; } - if (days > 0 || days < MAX_DAY_NUMBER) - { - get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); - } + if (days <= 0 || days >= MAX_DAY_NUMBER) + goto err; + get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); } if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59) - return 1; + goto err; DBUG_RETURN(0); -} +err: + DBUG_RETURN(1); +} /* - Print datetime string from TIME struct - according to format string. + Create a formated date/time value in a string */ - -String *make_datetime(String *str, TIME *l_time, - const bool is_time_only, - const bool add_second_frac, - const char *ptr, uint format_length, - bool set_len_to_zero) +bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, + timestamp_type type, String *str) { char intbuff[15]; uint days_i; uint hours_i; uint weekday; ulong length; - if (set_len_to_zero) - str->length(0); + const char *ptr, *end; + + str->length(0); + str->set_charset(&my_charset_bin); + if (l_time->neg) str->append("-", 1); - const char *end=ptr+format_length; + + end= (ptr= format->format.str) + format->format.length; for (; ptr != end ; ptr++) { if (*ptr != '%' || ptr+1 == end) @@ -407,29 +387,31 @@ String *make_datetime(String *str, TIME *l_time, switch (*++ptr) { case 'M': if (!l_time->month) - return 0; + return 1; str->append(month_names[l_time->month-1]); break; case 'b': if (!l_time->month) - return 0; - str->append(month_names[l_time->month-1].ptr(),3); + return 1; + str->append(month_names[l_time->month-1],3); break; case 'W': - if (is_time_only) - return 0; - weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),0); + if (type == TIMESTAMP_TIME) + return 1; + weekday= calc_weekday(calc_daynr(l_time->year,l_time->month, + l_time->day),0); str->append(day_names[weekday]); break; case 'a': - if (is_time_only) - return 0; - weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),0); - str->append(day_names[weekday].ptr(),3); + if (type == TIMESTAMP_TIME) + return 1; + weekday=calc_weekday(calc_daynr(l_time->year,l_time->month, + l_time->day),0); + str->append(day_names[weekday],3); break; case 'D': - if (is_time_only) - return 0; + if (type == TIMESTAMP_TIME) + return 1; length= int10_to_str(l_time->day, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 1, '0'); if (l_time->day >= 10 && l_time->day <= 19) @@ -496,9 +478,10 @@ String *make_datetime(String *str, TIME *l_time, str->append_with_prefill(intbuff, length, 2, '0'); break; case 'j': - if (is_time_only) - return 0; - length= int10_to_str(calc_daynr(l_time->year,l_time->month,l_time->day) - + if (type == TIMESTAMP_TIME) + return 1; + length= int10_to_str(calc_daynr(l_time->year,l_time->month, + l_time->day) - calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 3, '0'); break; @@ -529,12 +512,6 @@ String *make_datetime(String *str, TIME *l_time, case 's': length= int10_to_str(l_time->second, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 2, '0'); - if (add_second_frac) - { - str->append('.'); - length= int10_to_str(l_time->second_part, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 6, '0'); - } break; case 'T': length= my_sprintf(intbuff, @@ -549,8 +526,8 @@ String *make_datetime(String *str, TIME *l_time, case 'u': { uint year; - if (is_time_only) - return 0; + if (type == TIMESTAMP_TIME) + return 1; length= int10_to_str(calc_week(l_time, 0, (*ptr) == 'U', &year), intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 2, '0'); @@ -560,8 +537,8 @@ String *make_datetime(String *str, TIME *l_time, case 'V': { uint year; - if (is_time_only) - return 0; + if (type == TIMESTAMP_TIME) + return 1; length= int10_to_str(calc_week(l_time, 1, (*ptr) == 'V', &year), intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 2, '0'); @@ -571,27 +548,29 @@ String *make_datetime(String *str, TIME *l_time, case 'X': { uint year; - if (is_time_only) - return 0; + if (type == TIMESTAMP_TIME) + return 1; (void) calc_week(l_time, 1, (*ptr) == 'X', &year); length= int10_to_str(year, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 4, '0'); } break; case 'w': - if (is_time_only) - return 0; - weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),1); + if (type == TIMESTAMP_TIME) + return 1; + weekday=calc_weekday(calc_daynr(l_time->year,l_time->month, + l_time->day),1); length= int10_to_str(weekday, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 1, '0'); break; + default: str->append(*ptr); break; } } } - return str; + return 0; } @@ -691,21 +670,24 @@ longlong Item_func_month::val_int() return (longlong) ltime.month; } + String* Item_func_monthname::val_str(String* str) { + const char *name; uint month=(uint) Item_func_month::val_int(); + if (!month) // This is also true for NULL { null_value=1; return (String*) 0; } null_value=0; - - String *m=&month_names[month-1]; - str->copy(m->ptr(), m->length(), m->charset(), default_charset()); + name= month_names[month-1]; + str->set(name, strlen(name), system_charset_info); return str; } + // Returns the quarter of the year longlong Item_func_quarter::val_int() @@ -785,14 +767,17 @@ longlong Item_func_weekday::val_int() return (longlong) calc_weekday(tmp_value,odbc_type)+test(odbc_type); } + String* Item_func_dayname::val_str(String* str) { uint weekday=(uint) val_int(); // Always Item_func_daynr() + const char *name; + if (null_value) return (String*) 0; - String *d=&day_names[weekday]; - str->copy(d->ptr(), d->length(), d->charset(), default_charset()); + name= day_names[weekday]; + str->set(name, strlen(name), system_charset_info); return str; } @@ -808,7 +793,7 @@ longlong Item_func_year::val_int() longlong Item_func_unix_timestamp::val_int() { if (arg_count == 0) - return (longlong) thd->query_start(); + return (longlong) current_thd->query_start(); if (args[0]->type() == FIELD_ITEM) { // Optimize timestamp field Field *field=((Item_field*) args[0])->field; @@ -820,7 +805,7 @@ longlong Item_func_unix_timestamp::val_int() { return 0; /* purecov: inspected */ } - return (longlong) str_to_timestamp(str->ptr(),str->length(), thd); + return (longlong) str_to_timestamp(str->ptr(),str->length()); } @@ -840,15 +825,18 @@ longlong Item_func_time_to_sec::val_int() */ static bool get_interval_value(Item *args,interval_type int_type, - String *str_value, INTERVAL *t) + String *str_value, INTERVAL *interval) { long array[5],value; const char *str; uint32 length; - LINT_INIT(value); LINT_INIT(str); LINT_INIT(length); CHARSET_INFO *cs=str_value->charset(); - bzero((char*) t,sizeof(*t)); + LINT_INIT(value); + LINT_INIT(str); + LINT_INIT(length); + + bzero((char*) interval,sizeof(*interval)); if ((int) int_type <= INTERVAL_MICROSECOND) { value=(long) args->val_int(); @@ -856,7 +844,7 @@ static bool get_interval_value(Item *args,interval_type int_type, return 1; if (value < 0) { - t->neg=1; + interval->neg=1; value= -value; } } @@ -866,14 +854,14 @@ static bool get_interval_value(Item *args,interval_type int_type, if (!(res=args->val_str(str_value))) return (1); - /* record negative intervalls in t->neg */ + /* record negative intervalls in interval->neg */ str=res->ptr(); const char *end=str+res->length(); while (str != end && my_isspace(cs,*str)) str++; if (str != end && *str == '-') { - t->neg=1; + interval->neg=1; str++; } length=(uint32) (end-str); // Set up pointers to new str @@ -881,101 +869,101 @@ static bool get_interval_value(Item *args,interval_type int_type, switch (int_type) { case INTERVAL_YEAR: - t->year=value; + interval->year=value; break; case INTERVAL_MONTH: - t->month=value; + interval->month=value; break; case INTERVAL_DAY: - t->day=value; + interval->day=value; break; case INTERVAL_HOUR: - t->hour=value; + interval->hour=value; break; case INTERVAL_MICROSECOND: - t->second_part=value; + interval->second_part=value; break; case INTERVAL_MINUTE: - t->minute=value; + interval->minute=value; break; case INTERVAL_SECOND: - t->second=value; + interval->second=value; break; case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM if (get_interval_info(str,length,cs,2,array)) return (1); - t->year=array[0]; - t->month=array[1]; + interval->year=array[0]; + interval->month=array[1]; break; case INTERVAL_DAY_HOUR: if (get_interval_info(str,length,cs,2,array)) return (1); - t->day=array[0]; - t->hour=array[1]; + interval->day=array[0]; + interval->hour=array[1]; break; case INTERVAL_DAY_MICROSECOND: if (get_interval_info(str,length,cs,5,array)) return (1); - t->day=array[0]; - t->hour=array[1]; - t->minute=array[2]; - t->second=array[3]; - t->second_part=array[4]; + interval->day=array[0]; + interval->hour=array[1]; + interval->minute=array[2]; + interval->second=array[3]; + interval->second_part=array[4]; break; case INTERVAL_DAY_MINUTE: if (get_interval_info(str,length,cs,3,array)) return (1); - t->day=array[0]; - t->hour=array[1]; - t->minute=array[2]; + interval->day=array[0]; + interval->hour=array[1]; + interval->minute=array[2]; break; case INTERVAL_DAY_SECOND: if (get_interval_info(str,length,cs,4,array)) return (1); - t->day=array[0]; - t->hour=array[1]; - t->minute=array[2]; - t->second=array[3]; + interval->day=array[0]; + interval->hour=array[1]; + interval->minute=array[2]; + interval->second=array[3]; break; case INTERVAL_HOUR_MICROSECOND: if (get_interval_info(str,length,cs,4,array)) return (1); - t->hour=array[0]; - t->minute=array[1]; - t->second=array[2]; - t->second_part=array[3]; + interval->hour=array[0]; + interval->minute=array[1]; + interval->second=array[2]; + interval->second_part=array[3]; break; case INTERVAL_HOUR_MINUTE: if (get_interval_info(str,length,cs,2,array)) return (1); - t->hour=array[0]; - t->minute=array[1]; + interval->hour=array[0]; + interval->minute=array[1]; break; case INTERVAL_HOUR_SECOND: if (get_interval_info(str,length,cs,3,array)) return (1); - t->hour=array[0]; - t->minute=array[1]; - t->second=array[2]; + interval->hour=array[0]; + interval->minute=array[1]; + interval->second=array[2]; break; case INTERVAL_MINUTE_MICROSECOND: if (get_interval_info(str,length,cs,3,array)) return (1); - t->minute=array[0]; - t->second=array[1]; - t->second_part=array[2]; + interval->minute=array[0]; + interval->second=array[1]; + interval->second_part=array[2]; break; case INTERVAL_MINUTE_SECOND: if (get_interval_info(str,length,cs,2,array)) return (1); - t->minute=array[0]; - t->second=array[1]; + interval->minute=array[0]; + interval->second=array[1]; break; case INTERVAL_SECOND_MICROSECOND: if (get_interval_info(str,length,cs,2,array)) return (1); - t->second=array[0]; - t->second_part=array[1]; + interval->second=array[0]; + interval->second_part=array[1]; break; } return 0; @@ -984,34 +972,33 @@ static bool get_interval_value(Item *args,interval_type int_type, String *Item_date::val_str(String *str) { - DATETIME_FORMAT *tmp_format; TIME ltime; ulong value=(ulong) val_int(); if (null_value) - goto null_date; + return (String*) 0; + + if (str->alloc(11)) + { + null_value= 1; + return (String *) 0; + } ltime.year= (value/10000L) % 10000; ltime.month= (value/100)%100; ltime.day= (value%100); - ltime.neg=0; + ltime.neg= 0; ltime.time_type=TIMESTAMP_DATE; - tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; - if (make_datetime(str, <ime, 0, 0, - tmp_format->format, tmp_format->format_length, 1)) - return str; - - null_value= 1; -null_date: - return 0; + make_date((DATE_TIME_FORMAT *) 0, <ime, str); + return str; } int Item_date::save_in_field(Field *field, bool no_conversions) { TIME ltime; - timestamp_type t_type=TIMESTAMP_FULL; - if (get_date(<ime,1)) + timestamp_type t_type=TIMESTAMP_DATETIME; + if (get_date(<ime, TIME_FUZZY_DATE)) { if (null_value) return set_field_to_null(field); @@ -1039,11 +1026,11 @@ void Item_func_curdate::fix_length_and_dec() { struct tm start; - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=10*default_charset()->mbmaxlen; + max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - store_now_in_tm(thd->query_start(),&start); + store_now_in_tm(current_thd->query_start(),&start); value=(longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+ ((uint) start.tm_mon+1)*100+ @@ -1062,7 +1049,7 @@ void Item_func_curdate::fix_length_and_dec() bool Item_func_curdate::get_date(TIME *res, - bool fuzzy_date __attribute__((unused))) + uint fuzzy_date __attribute__((unused))) { *res=ltime; return 0; @@ -1091,19 +1078,19 @@ void Item_func_curdate_utc::store_now_in_tm(time_t now, struct tm *now_tm) String *Item_func_curtime::val_str(String *str) { - str_value.set(buff,buff_length,default_charset()); + str_value.set(buff, buff_length, &my_charset_bin); return &str_value; } + void Item_func_curtime::fix_length_and_dec() { struct tm start; - DATETIME_FORMAT *tmp_format; - String tmp((char*) buff,sizeof(buff),default_charset()); + String tmp((char*) buff,sizeof(buff), &my_charset_bin); TIME ltime; decimals=0; - store_now_in_tm(thd->query_start(),&start); + store_now_in_tm(current_thd->query_start(),&start); value=(longlong) ((ulong) ((uint) start.tm_hour)*10000L+ (ulong) (((uint) start.tm_min)*100L+ (uint) start.tm_sec)); @@ -1113,12 +1100,8 @@ void Item_func_curtime::fix_length_and_dec() ltime.second= start.tm_sec; ltime.second_part= 0; ltime.neg= 0; - ltime.time_type= TIMESTAMP_TIME; - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; - make_datetime(&tmp, <ime, 0, 0, - tmp_format->format, tmp_format->format_length, 1); - buff_length= tmp.length(); - max_length= buff_length; + make_time((DATE_TIME_FORMAT *) 0, <ime, &tmp); + max_length= buff_length= tmp.length(); } @@ -1144,7 +1127,7 @@ void Item_func_curtime_utc::store_now_in_tm(time_t now, struct tm *now_tm) String *Item_func_now::val_str(String *str) { - str_value.set(buff,buff_length,default_charset()); + str_value.set(buff,buff_length, &my_charset_bin); return &str_value; } @@ -1152,11 +1135,12 @@ String *Item_func_now::val_str(String *str) void Item_func_now::fix_length_and_dec() { struct tm start; - DATETIME_FORMAT *tmp_format; String tmp((char*) buff,sizeof(buff),&my_charset_bin); - + decimals=0; - store_now_in_tm(thd->query_start(),&start); + collation.set(&my_charset_bin); + + store_now_in_tm(current_thd->query_start(),&start); value=((longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+ (((uint) start.tm_mon+1)*100+ (uint) start.tm_mday))*(longlong) 1000000L+ @@ -1173,17 +1157,15 @@ void Item_func_now::fix_length_and_dec() ltime.second= start.tm_sec; ltime.second_part= 0; ltime.neg= 0; - ltime.time_type= TIMESTAMP_FULL; + ltime.time_type= TIMESTAMP_DATETIME; - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; - make_datetime(&tmp, <ime, 0, 0, - tmp_format->format, tmp_format->format_length, 1); - buff_length= tmp.length(); - max_length= buff_length; + make_datetime((DATE_TIME_FORMAT *) 0, <ime, &tmp); + max_length= buff_length= tmp.length(); } + bool Item_func_now::get_date(TIME *res, - bool fuzzy_date __attribute__((unused))) + uint fuzzy_date __attribute__((unused))) { *res=ltime; return 0; @@ -1193,7 +1175,7 @@ bool Item_func_now::get_date(TIME *res, int Item_func_now::save_in_field(Field *to, bool no_conversions) { to->set_notnull(); - to->store_time(<ime,TIMESTAMP_FULL); + to->store_time(<ime,TIMESTAMP_DATETIME); return 0; } @@ -1222,12 +1204,13 @@ String *Item_func_sec_to_time::val_str(String *str) { longlong seconds=(longlong) args[0]->val_int(); uint sec; - - DATETIME_FORMAT *tmp_format; TIME ltime; - if ((null_value=args[0]->null_value)) - goto null_date; + if ((null_value=args[0]->null_value) || str->alloc(19)) + { + null_value= 1; + return (String*) 0; + } ltime.neg= 0; if (seconds < 0) @@ -1242,14 +1225,8 @@ String *Item_func_sec_to_time::val_str(String *str) ltime.minute= sec/60; ltime.second= sec % 60; - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; - if (make_datetime(str, <ime, 0, 0, - tmp_format->format, tmp_format->format_length, 1)) - return str; - - null_value= 1; -null_date: - return (String*) 0; + make_time((DATE_TIME_FORMAT *) 0, <ime, str); + return str; } @@ -1359,9 +1336,9 @@ String *Item_func_date_format::val_str(String *str) { String *format; TIME l_time; - uint size,weekday; + uint size; - if (!date_or_time) + if (!is_time_format) { if (get_arg0_date(&l_time,1)) return 0; @@ -1369,10 +1346,8 @@ String *Item_func_date_format::val_str(String *str) else { String *res; - if (!(res=args[0]->val_str(str))) - goto null_date; - - if (str_to_time(res->ptr(),res->length(),&l_time, thd)) + if (!(res=args[0]->val_str(str)) || + (str_to_time(res->ptr(),res->length(),&l_time))) goto null_date; l_time.year=l_time.month=l_time.day=0; @@ -1391,10 +1366,13 @@ String *Item_func_date_format::val_str(String *str) if (str->alloc(size)) goto null_date; + DATE_TIME_FORMAT date_time_format; + date_time_format.format.str= (char*) format->ptr(); + date_time_format.format.length= format->length(); /* Create the result string */ - if (make_datetime(str, &l_time, 0, 0, - format->ptr(), format->length(), 1)) + if (!make_date_time(&date_time_format, &l_time, + is_time_format ? TIMESTAMP_TIME : TIMESTAMP_DATE, str)) return str; null_date: @@ -1406,10 +1384,8 @@ null_date: String *Item_func_from_unixtime::val_str(String *str) { struct tm tm_tmp,*start; - DATETIME_FORMAT *tmp_format; time_t tmp=(time_t) args[0]->val_int(); - uint32 l; - CHARSET_INFO *cs=default_charset(); + CHARSET_INFO *cs= &my_charset_bin; TIME ltime; if ((null_value=args[0]->null_value)) @@ -1427,14 +1403,13 @@ String *Item_func_from_unixtime::val_str(String *str) ltime.second_part= 0; ltime.neg=0; - l=20*cs->mbmaxlen+32; - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; - if (str->alloc(l) && make_datetime(str, <ime, 1, 0, - tmp_format->format, - tmp_format->format_length, 1)) - return str; - null_value= 1; + if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN)) + goto null_date; + make_datetime((DATE_TIME_FORMAT *) 0, <ime, str); + return str; + null_date: + null_value=1; return 0; } @@ -1456,7 +1431,7 @@ longlong Item_func_from_unixtime::val_int() } bool Item_func_from_unixtime::get_date(TIME *ltime, - bool fuzzy_date __attribute__((unused))) + uint fuzzy_date __attribute__((unused))) { time_t tmp=(time_t) (ulong) args[0]->val_int(); if ((null_value=args[0]->null_value)) @@ -1479,10 +1454,11 @@ bool Item_func_from_unixtime::get_date(TIME *ltime, void Item_date_add_interval::fix_length_and_dec() { enum_field_types arg0_field_type; - collation.set(default_charset()); + + collation.set(&my_charset_bin); maybe_null=1; - max_length=26*MY_CHARSET_BIN_MB_MAXLEN; - value.alloc(32); + max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; + value.alloc(max_length); /* The field type for the result of an Item_date function is defined as @@ -1512,10 +1488,11 @@ void Item_date_add_interval::fix_length_and_dec() /* Here arg[1] is a Item_interval object */ -bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) +bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date) { long period,sign; INTERVAL interval; + ltime->neg= 0; if (args[0]->get_date(ltime,0) || get_interval_value(args[1],int_type,&value,&interval)) @@ -1541,7 +1518,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) case INTERVAL_DAY_MINUTE: case INTERVAL_DAY_HOUR: long sec,days,daynr,microseconds,extra_sec; - ltime->time_type=TIMESTAMP_FULL; // Return full date + ltime->time_type=TIMESTAMP_DATETIME; // Return full date microseconds= ltime->second_part + sign*interval.second_part; extra_sec= microseconds/1000000L; microseconds= microseconds%1000000L; @@ -1616,23 +1593,26 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) String *Item_date_add_interval::val_str(String *str) { TIME ltime; - DATETIME_FORMAT *tmp_format; + enum date_time_format_types format; if (Item_date_add_interval::get_date(<ime,0)) return 0; if (ltime.time_type == TIMESTAMP_DATE) - tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; - else - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; - if (make_datetime(str, <ime, 1, ltime.second_part, - tmp_format->format, tmp_format->format_length, 1)) + format= DATE_ONLY; + else if (ltime.second_part) + format= DATE_TIME_MICROSECOND; + else + format= DATE_TIME; + + if (!make_datetime(format, <ime, str)) return str; null_value=1; return 0; } + longlong Item_date_add_interval::val_int() { TIME ltime; @@ -1715,7 +1695,7 @@ longlong Item_extract::val_int() else { String *res= args[0]->val_str(&value); - if (!res || str_to_time(res->ptr(),res->length(),<ime, thd)) + if (!res || str_to_time(res->ptr(),res->length(),<ime)) { null_value=1; return 0; @@ -1864,15 +1844,13 @@ void Item_char_typecast::fix_length_and_dec() max_length= char_length * cast_cs->mbmaxlen; } + String *Item_datetime_typecast::val_str(String *str) { TIME ltime; - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (thd, DATETIME_FORMAT_TYPE).datetime_format); - if (!get_arg0_date(<ime,1) && - make_datetime(str, <ime, 1, ltime.second_part, - tmp_format->format, tmp_format->format_length, 1)) + !make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME, + <ime, str)) return str; null_date: @@ -1892,12 +1870,10 @@ bool Item_time_typecast::get_time(TIME *ltime) String *Item_time_typecast::val_str(String *str) { TIME ltime; - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (thd, TIME_FORMAT_TYPE).datetime_format); if (!get_arg0_time(<ime) && - make_datetime(str, <ime, 0, ltime.second_part, - tmp_format->format, tmp_format->format_length, 1)) + !make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY, + <ime, str)) return str; null_value=1; @@ -1905,7 +1881,7 @@ String *Item_time_typecast::val_str(String *str) } -bool Item_date_typecast::get_date(TIME *ltime, bool fuzzy_date) +bool Item_date_typecast::get_date(TIME *ltime, uint fuzzy_date) { bool res= get_arg0_date(ltime,1); ltime->time_type= TIMESTAMP_DATE; @@ -1916,19 +1892,18 @@ bool Item_date_typecast::get_date(TIME *ltime, bool fuzzy_date) String *Item_date_typecast::val_str(String *str) { TIME ltime; - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (thd, DATE_FORMAT_TYPE).datetime_format); - if (!get_arg0_date(<ime,1) && - make_datetime(str, <ime, 1, 0, - tmp_format->format, tmp_format->format_length, 1)) - return str; + if (!get_arg0_date(<ime,1) && !str->alloc(11)) + { + make_date((DATE_TIME_FORMAT *) 0,<ime, str); + return str; + } -null_date: null_value=1; return 0; } + /* MAKEDATE(a,b) is a date function that creates a date value from a year and day value. @@ -1943,22 +1918,21 @@ String *Item_func_makedate::val_str(String *str) if (args[0]->null_value || args[1]->null_value || yearnr < 0 || daynr <= 0) - goto null_date; + goto err; days= calc_daynr(yearnr,1,1) + daynr - 1; - if (days > 0 || days < MAX_DAY_NUMBER) // Day number from year 0 to 9999-12-31 + // Day number from year 0 to 9999-12-31 + if (days >= 0 && days < MAX_DAY_NUMBER) { null_value=0; get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day); - - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (thd, DATE_FORMAT_TYPE).datetime_format); - if (make_datetime(str, &l_time, 1, 0, - tmp_format->format, tmp_format->format_length, 1)) - return str; + if (str->alloc(11)) + goto err; + make_date((DATE_TIME_FORMAT *) 0, &l_time, str); + return str; } -null_date: +err: null_value=1; return 0; } @@ -1968,11 +1942,11 @@ void Item_func_add_time::fix_length_and_dec() { enum_field_types arg0_field_type; decimals=0; - max_length=26*MY_CHARSET_BIN_MB_MAXLEN; + max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; /* - The field type for the result of an Item_func_add_time function is defined as - follows: + The field type for the result of an Item_func_add_time function is defined + as follows: - If first arg is a MYSQL_TYPE_DATETIME or MYSQL_TYPE_TIMESTAMP result is MYSQL_TYPE_DATETIME @@ -1991,7 +1965,8 @@ void Item_func_add_time::fix_length_and_dec() } /* - ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a time/datetime value + ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a + time/datetime value t: time_or_datetime_expression a: time_expression @@ -2005,7 +1980,6 @@ String *Item_func_add_time::val_str(String *str) bool is_time= 0; long microseconds, seconds, days= 0; int l_sign= sign; - DATETIME_FORMAT *tmp_format; null_value=0; l_time3.neg= 0; @@ -2021,7 +1995,7 @@ String *Item_func_add_time::val_str(String *str) { if (args[0]->get_time(&l_time1) || args[1]->get_time(&l_time2) || - l_time2.time_type == TIMESTAMP_FULL) + l_time2.time_type == TIMESTAMP_DATETIME) goto null_date; is_time= (l_time1.time_type == TIMESTAMP_TIME); if (is_time && (l_time2.neg == l_time1.neg && l_time1.neg)) @@ -2037,7 +2011,8 @@ String *Item_func_add_time::val_str(String *str) if (is_time) seconds+= l_time1.day*86400L; else - days+= calc_daynr((uint) l_time1.year,(uint) l_time1.month, (uint) l_time1.day); + days+= calc_daynr((uint) l_time1.year,(uint) l_time1.month, + (uint) l_time1.day); seconds= seconds + microseconds/1000000L; microseconds= microseconds%1000000L; days+= seconds/86400L; @@ -2070,21 +2045,19 @@ String *Item_func_add_time::val_str(String *str) calc_time_from_sec(&l_time3, seconds, microseconds); if (!is_time) { - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); if (l_time3.day && - make_datetime(str, &l_time3, 1, - l_time1.second_part || l_time2.second_part, - tmp_format->format, tmp_format->format_length, 1)) + !make_datetime(l_time1.second_part || l_time2.second_part ? + DATE_TIME_MICROSECOND : DATE_TIME, + &l_time3, str)) return str; goto null_date; } - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; l_time3.hour+= days*24; - if (make_datetime(str, &l_time3, 0, - l_time1.second_part || l_time2.second_part, - tmp_format->format, tmp_format->format_length, 1)) + if (!make_datetime(l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY, + &l_time3, str)) return str; null_date: @@ -2129,7 +2102,6 @@ String *Item_func_timediff::val_str(String *str) long days; int l_sign= 1; TIME l_time1 ,l_time2, l_time3; - DATETIME_FORMAT *tmp_format; null_value= 0; if (args[0]->get_time(&l_time1) || @@ -2176,10 +2148,9 @@ String *Item_func_timediff::val_str(String *str) calc_time_from_sec(&l_time3, seconds, microseconds); - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; - if (make_datetime(str, &l_time3, 0, - l_time1.second_part || l_time2.second_part, - tmp_format->format, tmp_format->format_length, 1)) + if (!make_datetime(l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY, + &l_time3, str)) return str; null_date: @@ -2196,7 +2167,6 @@ null_date: String *Item_func_maketime::val_str(String *str) { TIME ltime; - DATETIME_FORMAT *tmp_format; long hour= args[0]->val_int(); long minute= args[1]->val_int(); @@ -2206,8 +2176,9 @@ String *Item_func_maketime::val_str(String *str) args[1]->null_value || args[2]->null_value || minute > 59 || minute < 0 || - second > 59 || second < 0))) - goto null_date; + second > 59 || second < 0 || + str->alloc(19)))) + return 0; ltime.neg= 0; if (hour < 0) @@ -2218,21 +2189,19 @@ String *Item_func_maketime::val_str(String *str) ltime.hour= (ulong)hour; ltime.minute= (ulong)minute; ltime.second= (ulong)second; - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; - if (make_datetime(str, <ime, 0, 0, - tmp_format->format, tmp_format->format_length, 1)) - return str; - -null_date: - return 0; + make_time((DATE_TIME_FORMAT *) 0, <ime, str); + return str; } + /* - MICROSECOND(a) is a function ( extraction) that extracts the microseconds from a. + MICROSECOND(a) is a function ( extraction) that extracts the microseconds + from a. a: Datetime or time value Result: int value */ + longlong Item_func_microsecond::val_int() { TIME ltime; @@ -2241,78 +2210,103 @@ longlong Item_func_microsecond::val_int() return 0; } -/* - Array of MySQL date/time/datetime formats - Firts element is date format - Second element is time format - Third element is datetime format - Fourth is format name. -*/ - -const char *datetime_formats[4][5]= -{ - {"%m.%d.%Y", "%Y-%m-%d", "%Y-%m-%d", "%d.%m.%Y", "%Y%m%d"}, - {"%h:%i:%s %p", "%H:%i:%s", "%H:%i:%s", "%H.%i.%S", "%H%i%s"}, - {"%Y-%m-%d-%H.%i.%s", "%Y-%m-%d %H:%i:%s", "%Y-%m-%d %H:%i:%s", "%Y-%m-%d-%H.%i.%s", "%Y%m%d%H%i%s"}, - {"USA", "JIS", "ISO", "EUR", "INTERNAL"} -}; - - -/* - Return format string according format name. - If name is unknown, result is ISO format string -*/ String *Item_func_get_format::val_str(String *str) { - String *val=args[0]->val_str(str); - const char *format_str= datetime_formats[tm_format][ISO_FORMAT]; + const char *format_name; + KNOWN_DATE_TIME_FORMAT *format; + String *val= args[0]->val_str(str); + ulong val_len; - if (!args[0]->null_value) + if ((null_value= args[0]->null_value)) + return 0; + + val_len= val->length(); + for (format= &known_date_time_formats[0]; + (format_name= format->format_name); + format++) { - const char *val_ptr= val->ptr(); - uint val_len= val->length(); - for (int i= 0; i < 5; i++) + uint format_name_len; + format_name_len= strlen(format_name); + if (val_len == format_name_len && + !my_strnncoll(&my_charset_latin1, + (const uchar *) val->ptr(), val_len, + (const uchar *) format_name, val_len)) { - const char *name_format_str= datetime_formats[3][i]; - uint format_str_len= strlen(name_format_str); - if ( val_len == format_str_len && - !my_strnncoll(&my_charset_latin1, - (const uchar *) val_ptr, val_len, - (const uchar *) name_format_str, format_str_len)) - { - format_str= datetime_formats[tm_format][i]; - break; - } + const char *format_str= get_date_time_format_str(format, type); + str->set(format_str, strlen(format_str), &my_charset_bin); + return str; } } + null_value= 1; + return 0; +} + + +void Item_func_get_format::print(String *str) +{ + str->append(func_name()); + str->append('('); + + switch (type) { + case TIMESTAMP_DATE: + str->append("DATE, "); + break; + case TIMESTAMP_DATETIME: + str->append("DATETIME, "); + break; + case TIMESTAMP_TIME: + str->append("TIME, "); + break; + default: + DBUG_ASSERT(0); + } + args[0]->print(str); + str->append(')'); +} + + +bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date) +{ + DATE_TIME_FORMAT date_time_format; + char val_buff[64], format_buff[64]; + String val_str(val_buff, sizeof(val_buff), &my_charset_bin), *val; + String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format; + + val= args[0]->val_str(&val_str); + format= args[1]->val_str(&format_str); + if (args[0]->null_value || args[1]->null_value) + goto null_date; + null_value= 0; - str->length(0); - str->append(format_str); - return str; + bzero((char*) ltime, sizeof(ltime)); + date_time_format.format.str= (char*) format->ptr(); + date_time_format.format.length= format->length(); + if (extract_date_time(&date_time_format, val->ptr(), val->length(), + ltime)) + goto null_date; + return 0; + +null_date: + return (null_value=1); } String *Item_func_str_to_date::val_str(String *str) { TIME ltime; - bzero((char*) <ime, sizeof(ltime)); - DATETIME_FORMAT *tmp_format; - String *val=args[0]->val_str(str); - String *format=args[1]->val_str(str); - if (args[0]->null_value || args[1]->null_value || - extract_datetime(val->ptr(), val->length(), - format->ptr(), val->length(), - <ime)) - goto null_date; - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; - if (make_datetime(str, <ime, 0, 0, tmp_format->format, - tmp_format->format_length, 1)) - return str; + if (Item_func_str_to_date::get_date(<ime, TIME_FUZZY_DATE)) + return 0; -null_date: - null_value=1; + /* + The following DATE_TIME should be done dynamicly based on the + format string (wen it's a constant). For example, we should only return + microseconds if there was an %f in the format + */ + if (!make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME, + <ime, str)) + return str; return 0; } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index af71322ff0c..ef7fa1abfa0 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -29,7 +29,7 @@ public: const char *func_name() const { return "period_add"; } void fix_length_and_dec() { - max_length=6*default_charset()->mbmaxlen; + max_length=6*MY_CHARSET_BIN_MB_MAXLEN; } }; @@ -43,7 +43,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=6*default_charset()->mbmaxlen; + max_length=6*MY_CHARSET_BIN_MB_MAXLEN; } }; @@ -57,7 +57,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=6*default_charset()->mbmaxlen; + max_length=6*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -72,7 +72,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -86,16 +86,16 @@ public: double val() { return (double) Item_func_month::val_int(); } String *val_str(String *str) { - str->set(val_int(), default_charset()); + str->set(val_int(), &my_charset_bin); return null_value ? 0 : str; } const char *func_name() const { return "month"; } enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -110,9 +110,9 @@ public: enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=10*default_charset()->mbmaxlen; + max_length=10*my_charset_bin.mbmaxlen; maybe_null=1; } }; @@ -127,7 +127,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=3*default_charset()->mbmaxlen; + max_length=3*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -142,7 +142,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -157,7 +157,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -172,7 +172,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=1*default_charset()->mbmaxlen; + max_length=1*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -187,7 +187,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -202,7 +202,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -216,7 +216,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=6*default_charset()->mbmaxlen; + max_length=6*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -231,7 +231,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=4*default_charset()->mbmaxlen; + max_length=4*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -247,16 +247,16 @@ public: double val() { return (double) val_int(); } String *val_str(String *str) { - str->set(val_int(), default_charset()); + str->set(val_int(), &my_charset_bin); return null_value ? 0 : str; } const char *func_name() const { return "weekday"; } enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=1*default_charset()->mbmaxlen; + max_length=1*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -270,9 +270,9 @@ class Item_func_dayname :public Item_func_weekday enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=9*default_charset()->mbmaxlen; + max_length=9*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -289,7 +289,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=10*default_charset()->mbmaxlen; + max_length=10*MY_CHARSET_BIN_MB_MAXLEN; } }; @@ -303,7 +303,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=10*default_charset()->mbmaxlen; + max_length=10*MY_CHARSET_BIN_MB_MAXLEN; } }; @@ -322,14 +322,14 @@ public: const char *func_name() const { return "date"; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=10*default_charset()->mbmaxlen; + max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } int save_in_field(Field *to, bool no_conversions); Field *tmp_table_field(TABLE *t_arg) { - return (new Field_date(maybe_null, name, t_arg, default_charset())); + return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -343,7 +343,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_datetime(maybe_null, name, t_arg, default_charset())); + return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -366,7 +366,7 @@ public: void fix_length_and_dec(); Field *tmp_table_field(TABLE *t_arg) { - return (new Field_time(maybe_null, name, t_arg, default_charset())); + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); } /* Abstract method that defines which time zone is used for conversion. @@ -408,7 +408,7 @@ public: void set_result_from_tm(struct tm *now); longlong val_int() { return (value) ; } void fix_length_and_dec(); - bool get_date(TIME *res,bool fuzzy_date); + bool get_date(TIME *res, uint fuzzy_date); virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0; }; @@ -448,7 +448,7 @@ public: int save_in_field(Field *to, bool no_conversions); String *val_str(String *str); void fix_length_and_dec(); - bool get_date(TIME *res,bool fuzzy_date); + bool get_date(TIME *res, uint fuzzy_date); virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0; }; @@ -485,11 +485,11 @@ public: class Item_func_date_format :public Item_str_func { int fixed_length; - const bool date_or_time; + const bool is_time_format; String value; public: - Item_func_date_format(Item *a,Item *b,bool date_or_time_arg) - :Item_str_func(a,b),date_or_time(date_or_time_arg) {} + Item_func_date_format(Item *a,Item *b,bool is_time_format_arg) + :Item_str_func(a,b),is_time_format(is_time_format_arg) {} String *val_str(String *str); const char *func_name() const { return "date_format"; } void fix_length_and_dec(); @@ -507,11 +507,11 @@ class Item_func_from_unixtime :public Item_date_func const char *func_name() const { return "from_unixtime"; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=19*default_charset()->mbmaxlen; + max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } - bool get_date(TIME *res,bool fuzzy_date); + bool get_date(TIME *res, uint fuzzy_date); }; @@ -524,15 +524,15 @@ public: String *val_str(String *); void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); maybe_null=1; - max_length=13*default_charset()->mbmaxlen; + max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } const char *func_name() const { return "sec_to_time"; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_time(maybe_null, name, t_arg, default_charset())); + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -567,7 +567,7 @@ public: enum_field_types field_type() const { return cached_field_type; } double val() { return (double) val_int(); } longlong val_int(); - bool get_date(TIME *res,bool fuzzy_date); + bool get_date(TIME *res, uint fuzzy_date); void print(String *str); }; @@ -602,7 +602,7 @@ public: } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); max_length=args[0]->max_length; } virtual const char* cast_type() const= 0; @@ -631,12 +631,12 @@ class Item_date_typecast :public Item_typecast public: Item_date_typecast(Item *a) :Item_typecast(a) {} String *val_str(String *str); - bool get_date(TIME *ltime, bool fuzzy_date); + bool get_date(TIME *ltime, uint fuzzy_date); const char *cast_type() const { return "date"; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_date(maybe_null, name, t_arg, default_charset())); + return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -651,7 +651,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_TIME; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_time(maybe_null, name, t_arg, default_charset())); + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -665,7 +665,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_datetime(maybe_null, name, t_arg, default_charset())); + return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -679,7 +679,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=8*MY_CHARSET_BIN_MB_MAXLEN; + max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field(TABLE *t_arg) { @@ -728,7 +728,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=17*MY_CHARSET_BIN_MB_MAXLEN; + max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field(TABLE *t_arg) { @@ -747,11 +747,11 @@ public: void fix_length_and_dec() { decimals=0; - max_length=8*MY_CHARSET_BIN_MB_MAXLEN; + max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -769,44 +769,43 @@ public: }; -enum datetime_format +enum date_time_format { USA_FORMAT, JIS_FORMAT, ISO_FORMAT, EUR_FORMAT, INTERNAL_FORMAT }; - -enum datetime_format_types -{ - DATE_FORMAT_TYPE= 0, TIME_FORMAT_TYPE, DATETIME_FORMAT_TYPE -}; - - class Item_func_get_format :public Item_str_func { - const datetime_format_types tm_format; + const timestamp_type type; public: - Item_func_get_format(datetime_format_types type_arg1, Item *a) - :Item_str_func(a), tm_format(type_arg1) {} + Item_func_get_format(timestamp_type type_arg, Item *a) + :Item_str_func(a), type(type_arg) + {} String *val_str(String *str); const char *func_name() const { return "get_format"; } void fix_length_and_dec() { + maybe_null= 1; decimals=0; max_length=17*MY_CHARSET_BIN_MB_MAXLEN; } + void print(String *str); }; -class Item_func_str_to_date :public Item_str_func +class Item_func_str_to_date :public Item_date_func { public: Item_func_str_to_date(Item *a, Item *b) - :Item_str_func(a, b) {} + :Item_date_func(a, b) + {} String *val_str(String *str); + bool get_date(TIME *ltime, uint fuzzy_date); const char *func_name() const { return "str_to_date"; } void fix_length_and_dec() { + maybe_null= 1; decimals=0; - max_length=29*MY_CHARSET_BIN_MB_MAXLEN; + max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } }; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f71fca29f56..12c772e7253 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -756,6 +756,13 @@ bool open_log(MYSQL_LOG *log, const char *hostname, /* mysqld.cc */ extern void yyerror(const char*); +/* strfunc.cc */ +ulonglong find_set(TYPELIB *typelib,const char *x, uint length, + char **err_pos, uint *err_len, bool *set_warning); +uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match); +uint check_word(TYPELIB *lib, const char *val, const char *end, + const char **end_of_word); + /* External variables */ @@ -849,7 +856,6 @@ extern pthread_attr_t connection_attrib; extern I_List<THD> threads; extern I_List<NAMED_LIST> key_caches; extern MY_BITMAP temp_pool; -extern DATE_FORMAT dayord; extern String my_empty_string; extern String my_null_string; extern SHOW_VAR init_vars[],status_vars[], internal_vars[]; @@ -861,12 +867,8 @@ extern struct system_variables global_system_variables; extern struct system_variables max_system_variables; extern struct rand_struct sql_rand; -#define g_datetime_frm(a) (global_system_variables.datetime_formats[(a)]) -#define t_datetime_frm(a, b) ((a)->variables.datetime_formats[(b)]) - -extern const char *datetime_formats[4][5]; -extern const char *opt_datetime_format_names[3]; -extern const char *opt_datetime_formats[3]; +extern const char *opt_date_time_formats[]; +extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[]; extern String null_string; extern HASH open_cache; @@ -938,23 +940,26 @@ void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); void init_time(void); long my_gmt_sec(TIME *, long *current_timezone); -time_t str_to_timestamp(const char *str,uint length, THD *thd); -bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd); -longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd); +time_t str_to_timestamp(const char *str,uint length); +bool str_to_time(const char *str,uint length,TIME *l_time); +longlong str_to_datetime(const char *str,uint length, uint fuzzy_date); timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time, - bool fuzzy_date, THD *thd); + uint flags); void localtime_to_TIME(TIME *to, struct tm *from); void calc_time_from_sec(TIME *to, long seconds, long microseconds); -extern DATETIME_FORMAT *make_format(DATETIME_FORMAT *datetime_format, - datetime_format_types format_type, - const char *format_str, - uint format_length, bool is_alloc); -extern String *make_datetime(String *str, TIME *l_time, - const bool is_time_only, - const bool add_second_frac, - const char *ptr, uint format_length, - bool set_len_to_zero); +extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type, + const char *format_str, + uint format_length); +extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd, + DATE_TIME_FORMAT *format); +const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, + timestamp_type type); +extern bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, + timestamp_type type, String *str); +extern void make_time(DATE_TIME_FORMAT *format, TIME *l_time, String *str); +void make_date(DATE_TIME_FORMAT *format, TIME *l_time, String *str); +void make_datetime(DATE_TIME_FORMAT *format, TIME *l_time, String *str); int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(byte *,uint,char,char); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index eb632912575..1052eeaf11b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -318,10 +318,7 @@ char mysql_real_data_home[FN_REFLEN], language[LIBLEN],reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], max_sort_char,*mysqld_user,*mysqld_chroot, *opt_init_file; -const char *opt_datetime_formats[3]; -const char *opt_datetime_format_names[3]= {"date_format", - "time_format", - "datetime_format"}; +const char *opt_date_time_formats[3]; char *language_ptr, *default_collation_name, *default_character_set_name; char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; @@ -357,7 +354,6 @@ struct system_variables global_system_variables; struct system_variables max_system_variables; MY_TMPDIR mysql_tmpdir_list; -DATE_FORMAT dayord; MY_BITMAP temp_pool; CHARSET_INFO *system_charset_info, *files_charset_info ; @@ -921,9 +917,12 @@ void clean_up(bool print_message) #ifdef USE_RAID end_raid(); #endif - g_datetime_frm(DATE_FORMAT_TYPE).clean(); - g_datetime_frm(TIME_FORMAT_TYPE).clean(); - g_datetime_frm(DATETIME_FORMAT_TYPE).clean(); + my_free((char*) global_system_variables.date_format, + MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*) global_system_variables.time_format, + MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*) global_system_variables.datetime_format, + MYF(MY_ALLOW_ZERO_PTR)); if (defaults_argv) free_defaults(defaults_argv); free_tmpdir(&mysql_tmpdir_list); @@ -2019,33 +2018,46 @@ bool open_log(MYSQL_LOG *log, const char *hostname, } -int init_global_datetime_format(datetime_format_types format_type, bool is_alloc) +/* + Initialize one of the global date/time format variables + + SYNOPSIS + init_global_datetime_format() + format_type What kind of format should be supported + var_ptr Pointer to variable that should be updated + + NOTES + The default value is taken from either opt_date_time_formats[] or + the ISO format (ANSI SQL) + + RETURN + 0 ok + 1 error +*/ + +bool init_global_datetime_format(timestamp_type format_type, + DATE_TIME_FORMAT **var_ptr) { - const char *format_str= opt_datetime_formats[format_type]; - uint format_length= 0; - DATETIME_FORMAT *tmp_format= &g_datetime_frm(format_type).datetime_format; + /* Get command line option */ + const char *str= opt_date_time_formats[format_type]; + DATE_TIME_FORMAT *format; - if (format_str) + if (!str) // No specified format { - format_str= opt_datetime_formats[format_type]; - format_length= strlen(format_str); - } - else - { - format_str= datetime_formats[format_type][ISO_FORMAT]; - format_length= strlen(datetime_formats[format_type][ISO_FORMAT]); - opt_datetime_formats[format_type]= format_str; + str= get_date_time_format_str(&known_date_time_formats[ISO_FORMAT], + format_type); + /* + Set the "command line" option to point to the generated string so + that we can set global formats back to default + */ + opt_date_time_formats[format_type]= str; } - if (make_format(tmp_format, format_type, format_str, - format_length, is_alloc)) + if (!(*var_ptr= date_time_format_make(format_type, str, strlen(str)))) { - g_datetime_frm(format_type).name= opt_datetime_format_names[format_type]; - g_datetime_frm(format_type).name_length= - strlen(opt_datetime_format_names[format_type]); - g_datetime_frm(format_type).format_type= format_type; - return 0; + fprintf(stderr, "Wrong date/time format specifier: %s\n", str); + return 1; } - return 1; + return 0; } @@ -2160,17 +2172,12 @@ static int init_common_variables(const char *conf_file_name, int argc, } default_charset_info= default_collation; } - global_system_variables.collation_server= default_charset_info; - global_system_variables.collation_database= default_charset_info; - global_system_variables.collation_connection= default_charset_info; + /* Set collactions that depends on the default collation */ + global_system_variables.collation_server= default_charset_info; + global_system_variables.collation_database= default_charset_info; + global_system_variables.collation_connection= default_charset_info; global_system_variables.character_set_results= default_charset_info; - global_system_variables.character_set_client= default_charset_info; - global_system_variables.collation_connection= default_charset_info; - - if (init_global_datetime_format(DATE_FORMAT_TYPE, 1) || - init_global_datetime_format(TIME_FORMAT_TYPE, 1) || - init_global_datetime_format(DATETIME_FORMAT_TYPE, 1)) - return 1; + global_system_variables.character_set_client= default_charset_info; if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1)) return 1; @@ -4606,7 +4613,7 @@ The minimum value for this variable is 4096.", (gptr*) &max_system_variables.net_wait_timeout, 0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, {"expire_logs_days", OPT_EXPIRE_LOGS_DAYS, - "Logs will be rotated after expire-log-days days. ", + "Logs will be rotated after expire-log-days days ", (gptr*) &expire_logs_days, (gptr*) &expire_logs_days, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 99, 0, 1, 0}, @@ -4616,23 +4623,24 @@ The minimum value for this variable is 4096.", (gptr*) &max_system_variables.default_week_format, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3L, 0, 1, 0}, { "date-format", OPT_DATE_FORMAT, - "The DATE format.", - (gptr*) &opt_datetime_formats[DATE_FORMAT_TYPE], - (gptr*) &opt_datetime_formats[DATE_FORMAT_TYPE], + "The DATE format (For future).", + (gptr*) &opt_date_time_formats[TIMESTAMP_DATE], + (gptr*) &opt_date_time_formats[TIMESTAMP_DATE], 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "datetime-format", OPT_DATETIME_FORMAT, - "The DATETIME/TIMESTAMP format.", - (gptr*) &opt_datetime_formats[DATETIME_FORMAT_TYPE], - (gptr*) &opt_datetime_formats[DATETIME_FORMAT_TYPE], + "The DATETIME/TIMESTAMP format (for future).", + (gptr*) &opt_date_time_formats[TIMESTAMP_DATETIME], + (gptr*) &opt_date_time_formats[TIMESTAMP_DATETIME], 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "time-format", OPT_TIME_FORMAT, - "The TIME format.", - (gptr*) &opt_datetime_formats[TIME_FORMAT_TYPE], - (gptr*) &opt_datetime_formats[TIME_FORMAT_TYPE], + "The TIME format (for future).", + (gptr*) &opt_date_time_formats[TIMESTAMP_TIME], + (gptr*) &opt_date_time_formats[TIMESTAMP_TIME], 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; + struct show_var_st status_vars[]= { {"Aborted_clients", (char*) &aborted_threads, SHOW_LONG}, {"Aborted_connects", (char*) &aborted_connects, SHOW_LONG}, @@ -4944,6 +4952,8 @@ static void mysql_init_variables(void) national_charset_info= &my_charset_utf8_general_ci; table_alias_charset= &my_charset_bin; + opt_date_time_formats[0]= opt_date_time_formats[1]= opt_date_time_formats[2]= 0; + /* Things with default values that are not zero */ delay_key_write_options= (uint) DELAY_KEY_WRITE_ON; opt_specialflag= SPECIAL_ENGLISH; @@ -5001,11 +5011,6 @@ static void mysql_init_variables(void) /* Set default values for some option variables */ - global_system_variables.collation_server= default_charset_info; - global_system_variables.collation_database= default_charset_info; - global_system_variables.collation_connection= default_charset_info; - global_system_variables.character_set_results= default_charset_info; - global_system_variables.character_set_client= default_charset_info; global_system_variables.table_type= DB_TYPE_MYISAM; global_system_variables.tx_isolation= ISO_REPEATABLE_READ; global_system_variables.select_limit= (ulonglong) HA_POS_ERROR; @@ -5014,10 +5019,6 @@ static void mysql_init_variables(void) max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; - init_global_datetime_format(DATE_FORMAT_TYPE, 0); - init_global_datetime_format(TIME_FORMAT_TYPE, 0); - init_global_datetime_format(DATETIME_FORMAT_TYPE, 0); - /* Variables that depends on compile options */ #ifndef DBUG_OFF default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace", @@ -5626,7 +5627,7 @@ static void get_options(int argc,char **argv) exit(ho_error); if (argc > 0) { - fprintf(stderr, "%s: Too many arguments.\nUse --help to get a list of available options\n", my_progname); + fprintf(stderr, "%s: Too many arguments (first extra is '%s').\nUse --help to get a list of available options\n", my_progname, *argv); exit(ho_error); } @@ -5681,6 +5682,15 @@ static void get_options(int argc,char **argv) opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT; if (opt_log_queries_not_using_indexes) opt_specialflag|= SPECIAL_LOG_QUERIES_NOT_USING_INDEXES; + + if (init_global_datetime_format(TIMESTAMP_DATE, + &global_system_variables.date_format) || + init_global_datetime_format(TIMESTAMP_TIME, + &global_system_variables.time_format) || + init_global_datetime_format(TIMESTAMP_DATETIME, + &global_system_variables.datetime_format)) + exit(1); + /* Set up default values for a key cache */ KEY_CACHE_VAR *key_cache= &dflt_key_cache_var; dflt_key_cache_block_size= key_cache->block_size; diff --git a/sql/protocol.cc b/sql/protocol.cc index 0fe759cff67..d7a745d371d 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -833,12 +833,17 @@ bool Protocol_simple::store(TIME *tm) field_pos++; #endif char buff[40]; - String tmp((char*) buff,sizeof(buff),&my_charset_bin); - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (current_thd, DATETIME_FORMAT_TYPE).datetime_format); - make_datetime(&tmp, tm, 1, tm->second_part, - tmp_format->format, tmp_format->format_length, 1); - return net_store_data((char*) tmp.ptr(), tmp.length()); + uint length; + length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d", + (int) tm->year, + (int) tm->month, + (int) tm->day, + (int) tm->hour, + (int) tm->minute, + (int) tm->second)); + if (tm->second_part) + length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part)); + return net_store_data((char*) buff, length); } @@ -851,10 +856,7 @@ bool Protocol_simple::store_date(TIME *tm) #endif char buff[40]; String tmp((char*) buff,sizeof(buff),&my_charset_bin); - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (current_thd, DATE_FORMAT_TYPE).datetime_format); - make_datetime(&tmp, tm, 1, 0, - tmp_format->format, tmp_format->format_length, 1); + make_date((DATE_TIME_FORMAT *) 0, tm, &tmp); return net_store_data((char*) tmp.ptr(), tmp.length()); } @@ -873,14 +875,16 @@ bool Protocol_simple::store_time(TIME *tm) field_pos++; #endif char buff[40]; - String tmp((char*) buff,sizeof(buff),&my_charset_bin); - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (current_thd, TIME_FORMAT_TYPE).datetime_format); + uint length; uint day= (tm->year || tm->month) ? 0 : tm->day; - tm->hour= (long) day*24L+(long) tm->hour; - make_datetime(&tmp, tm, 0, tm->second_part, - tmp_format->format, tmp_format->format_length, 1); - return net_store_data((char*) tmp.ptr(), tmp.length()); + length= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d", + tm->neg ? "-" : "", + (long) day*24L+(long) tm->hour, + (int) tm->minute, + (int) tm->second)); + if (tm->second_part) + length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part)); + return net_store_data((char*) buff, length); } diff --git a/sql/set_var.cc b/sql/set_var.cc index 66c8ef87d5a..8d64a684476 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -299,14 +299,25 @@ sys_var_thd_ulong sys_tmp_table_size("tmp_table_size", &SV::tmp_table_size); sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", &SV::net_wait_timeout); - + #ifdef HAVE_INNOBASE_DB sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", &srv_max_buf_pool_modified_pct); #endif -/* - Variables that are bits in THD -*/ + +/* Time/date/datetime formats */ + +sys_var_thd_date_time_format sys_time_format("time_format", + &SV::time_format, + TIMESTAMP_TIME); +sys_var_thd_date_time_format sys_date_format("date_format", + &SV::date_format, + TIMESTAMP_DATE); +sys_var_thd_date_time_format sys_datetime_format("datetime_format", + &SV::datetime_format, + TIMESTAMP_DATETIME); + +/* Variables that are bits in THD */ static sys_var_thd_bit sys_autocommit("autocommit", set_option_autocommit, @@ -413,9 +424,8 @@ sys_var *sys_variables[]= &sys_collation_server, &sys_concurrent_insert, &sys_connect_timeout, - &g_datetime_frm(DATE_FORMAT_TYPE), - &g_datetime_frm(DATETIME_FORMAT_TYPE), - &g_datetime_frm(TIME_FORMAT_TYPE), + &sys_date_format, + &sys_datetime_format, &sys_default_week_format, &sys_delay_key_write, &sys_delayed_insert_limit, @@ -485,6 +495,7 @@ sys_var *sys_variables[]= &sys_rand_seed1, &sys_rand_seed2, &sys_range_alloc_block_size, + &sys_readonly, &sys_read_buff_size, &sys_read_rnd_buff_size, #ifdef HAVE_REPLICATION @@ -500,7 +511,6 @@ sys_var *sys_variables[]= &sys_slave_net_timeout, &sys_slave_skip_counter, #endif - &sys_readonly, &sys_slow_launch_time, &sys_sort_buffer, &sys_sql_big_tables, @@ -511,6 +521,7 @@ sys_var *sys_variables[]= &sys_table_cache_size, &sys_table_type, &sys_thread_cache_size, + &sys_time_format, &sys_timestamp, &sys_tmp_table_size, &sys_trans_alloc_block_size, @@ -556,9 +567,9 @@ struct show_var_st init_vars[]= { {sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS}, {sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS}, {"datadir", mysql_real_data_home, SHOW_CHAR}, - {"date_format", (char*) &g_datetime_frm(DATE_FORMAT_TYPE), SHOW_SYS}, - {"datetime_format", (char*) &g_datetime_frm(DATETIME_FORMAT_TYPE), SHOW_SYS}, - {"default_week_format", (char*) &sys_default_week_format, SHOW_SYS}, + {sys_date_format.name, (char*) &sys_date_format, SHOW_SYS}, + {sys_datetime_format.name, (char*) &sys_datetime_format, SHOW_SYS}, + {sys_default_week_format.name, (char*) &sys_default_week_format, SHOW_SYS}, {sys_delay_key_write.name, (char*) &sys_delay_key_write, SHOW_SYS}, {sys_delayed_insert_limit.name, (char*) &sys_delayed_insert_limit,SHOW_SYS}, {sys_delayed_insert_timeout.name, (char*) &sys_delayed_insert_timeout, SHOW_SYS}, @@ -720,7 +731,7 @@ struct show_var_st init_vars[]= { #endif {"thread_stack", (char*) &thread_stack, SHOW_LONG}, {sys_tx_isolation.name, (char*) &sys_tx_isolation, SHOW_SYS}, - {"time_format", (char*) &g_datetime_frm(TIME_FORMAT_TYPE), SHOW_SYS}, + {sys_time_format.name, (char*) &sys_time_format, SHOW_SYS}, #ifdef HAVE_TZNAME {"timezone", time_zone, SHOW_CHAR}, #endif @@ -744,71 +755,6 @@ bool sys_var::check(THD *thd, set_var *var) /* Functions to check and update variables */ -char *update_datetime_format(THD *thd, enum enum_var_type type, - enum datetime_format_types format_type, - DATETIME_FORMAT *tmp_format) -{ - char *old_value; - if (type == OPT_GLOBAL) - { - pthread_mutex_lock(&LOCK_global_system_variables); - old_value= g_datetime_frm(format_type).datetime_format.format; - g_datetime_frm(format_type).datetime_format= *tmp_format; - pthread_mutex_unlock(&LOCK_global_system_variables); - } - else - { - old_value= t_datetime_frm(thd,format_type).datetime_format.format; - t_datetime_frm(thd, format_type).datetime_format= *tmp_format; - } - return old_value; -} - - -bool sys_var_datetime_format::update(THD *thd, set_var *var) -{ - DATETIME_FORMAT tmp_format; - char *old_value; - uint new_length; - - if ((new_length= var->value->str_value.length())) - { - if (!make_format(&tmp_format, format_type, - var->value->str_value.ptr(), - new_length, 1)) - return 1; - } - - old_value= update_datetime_format(thd, var->type, format_type, &tmp_format); - my_free(old_value, MYF(MY_ALLOW_ZERO_PTR)); - return 0; -} - -byte *sys_var_datetime_format::value_ptr(THD *thd, enum_var_type type, - LEX_STRING *base) -{ - if (type == OPT_GLOBAL) - return (byte*) g_datetime_frm(format_type).datetime_format.format; - return (byte*) t_datetime_frm(thd, format_type).datetime_format.format; -} - -void sys_var_datetime_format::set_default(THD *thd, enum_var_type type) -{ - DATETIME_FORMAT tmp_format; - char *old_value; - uint new_length; - - if ((new_length= strlen(opt_datetime_formats[format_type]))) - { - if (!make_format(&tmp_format, format_type, - opt_datetime_formats[format_type], - new_length, 1)) - return; - } - - old_value= update_datetime_format(thd, type, format_type, &tmp_format); - my_free(old_value, MYF(MY_ALLOW_ZERO_PTR)); -} /* The following 3 functions need to be changed in 4.1 when we allow @@ -1226,8 +1172,8 @@ bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names) { if (!(res=var->value->val_str(&str)) || ((long) (var->save_result.ulong_value= - (ulong) find_type(res->c_ptr(), enum_names, 3)-1)) - < 0) + (ulong) find_type(enum_names, res->ptr(), + res->length(),1)-1)) < 0) { value= res ? res->c_ptr() : "NULL"; goto err; @@ -1341,8 +1287,12 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type, base),1); case SHOW_CHAR: { + Item_string *tmp; + pthread_mutex_lock(&LOCK_global_system_variables); char *str= (char*) value_ptr(thd, var_type, base); - return new Item_string(str, strlen(str), system_charset_info); + tmp= new Item_string(str, strlen(str), system_charset_info); + pthread_mutex_unlock(&LOCK_global_system_variables); + return tmp; } default: net_printf(thd, ER_VAR_CANT_BE_READ, name); @@ -1401,6 +1351,112 @@ byte *sys_var_thd_bit::value_ptr(THD *thd, enum_var_type type, } +/* Update a date_time format variable based on given value */ + +void sys_var_thd_date_time_format::update2(THD *thd, enum_var_type type, + DATE_TIME_FORMAT *new_value) +{ + DATE_TIME_FORMAT *old; + DBUG_ENTER("sys_var_date_time_format::update2"); + DBUG_DUMP("positions",(char*) new_value->positions, + sizeof(new_value->positions)); + + if (type == OPT_GLOBAL) + { + pthread_mutex_lock(&LOCK_global_system_variables); + old= (global_system_variables.*offset); + (global_system_variables.*offset)= new_value; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + { + old= (thd->variables.*offset); + (thd->variables.*offset)= new_value; + } + my_free((char*) old, MYF(MY_ALLOW_ZERO_PTR)); + DBUG_VOID_RETURN; +} + + +bool sys_var_thd_date_time_format::update(THD *thd, set_var *var) +{ + DATE_TIME_FORMAT *new_value; + /* We must make a copy of the last value to get it into normal memory */ + new_value= date_time_format_copy((THD*) 0, + var->save_result.date_time_format); + if (!new_value) + return 1; // Out of memory + update2(thd, var->type, new_value); // Can't fail + return 0; +} + + +bool sys_var_thd_date_time_format::check(THD *thd, set_var *var) +{ + char buff[80]; + String str(buff,sizeof(buff), system_charset_info), *res; + DATE_TIME_FORMAT *format; + + if (!(res=var->value->val_str(&str))) + res= &my_empty_string; + + if (!(format= date_time_format_make(date_time_type, + res->ptr(), res->length()))) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, res->c_ptr()); + return 1; + } + + /* + We must copy result to thread space to not get a memory leak if + update is aborted + */ + var->save_result.date_time_format= date_time_format_copy(thd, format); + my_free((char*) format, MYF(0)); + return var->save_result.date_time_format == 0; +} + + +void sys_var_thd_date_time_format::set_default(THD *thd, enum_var_type type) +{ + DATE_TIME_FORMAT *res= 0; + + if (type == OPT_GLOBAL) + { + const char *format; + if ((format= opt_date_time_formats[date_time_type])) + res= date_time_format_make(date_time_type, format, strlen(format)); + } + else + { + /* Make copy with malloc */ + res= date_time_format_copy((THD *) 0, global_system_variables.*offset); + } + + if (res) // Should always be true + update2(thd, type, res); +} + + +byte *sys_var_thd_date_time_format::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + if (type == OPT_GLOBAL) + { + char *res; + /* + We do a copy here just to be sure things will work even if someone + is modifying the original string while the copy is accessed + (Can't happen now in SQL SHOW, but this is a good safety for the future) + */ + res= thd->strmake((global_system_variables.*offset)->format.str, + (global_system_variables.*offset)->format.length); + return (byte*) res; + } + return (byte*) (thd->variables.*offset)->format.str; +} + + typedef struct old_names_map_st { const char *old_name; @@ -1409,17 +1465,17 @@ typedef struct old_names_map_st static my_old_conv old_conv[]= { - { "cp1251_koi8" , "cp1251" }, - { "cp1250_latin2" , "cp1250" }, - { "kam_latin2" , "keybcs2" }, - { "mac_latin2" , "MacRoman" }, - { "macce_latin2" , "MacCE" }, - { "pc2_latin2" , "pclatin2" }, - { "vga_latin2" , "pclatin1" }, - { "koi8_cp1251" , "koi8r" }, - { "win1251ukr_koi8_ukr" , "win1251ukr" }, - { "koi8_ukr_win1251ukr" , "koi8u" }, - { NULL , NULL } + { "cp1251_koi8" , "cp1251" }, + { "cp1250_latin2" , "cp1250" }, + { "kam_latin2" , "keybcs2" }, + { "mac_latin2" , "MacRoman" }, + { "macce_latin2" , "MacCE" }, + { "pc2_latin2" , "pclatin2" }, + { "vga_latin2" , "pclatin1" }, + { "koi8_cp1251" , "koi8r" }, + { "win1251ukr_koi8_ukr" , "win1251ukr" }, + { "koi8_ukr_win1251ukr" , "koi8u" }, + { NULL , NULL } }; CHARSET_INFO *get_old_charset_by_name(const char *name) diff --git a/sql/set_var.h b/sql/set_var.h index 16b2c1d5d37..c799eec750a 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -54,8 +54,6 @@ public: const char *name; sys_after_update_func after_update; - sys_var() - {} sys_var(const char *name_arg) :name(name_arg),after_update(0) {} sys_var(const char *name_arg,sys_after_update_func func) @@ -195,9 +193,6 @@ public: class sys_var_thd :public sys_var { public: - sys_var_thd() - :sys_var() - {} sys_var_thd(const char *name_arg) :sys_var(name_arg) {} @@ -621,46 +616,26 @@ public: }; -class sys_var_datetime_format :public sys_var_thd +class sys_var_thd_date_time_format :public sys_var_thd { + DATE_TIME_FORMAT *SV::*offset; + enum timestamp_type date_time_type; public: - enum datetime_format_types format_type; - DATETIME_FORMAT datetime_format; - sys_var_datetime_format(): sys_var_thd() + sys_var_thd_date_time_format(const char *name_arg, + DATE_TIME_FORMAT *SV::*offset_arg, + timestamp_type date_time_type_arg) + :sys_var_thd(name_arg), offset(offset_arg), + date_time_type(date_time_type_arg) {} - - void clean() - { - my_free(datetime_format.format, MYF(MY_ALLOW_ZERO_PTR)); - datetime_format.format=0; - } - - /* - It's for copying of global_system_variables structure - in THD constructor. - */ - inline sys_var_datetime_format& operator= (sys_var_datetime_format& s) - { - if (&s != this) - { - name= s.name; name_length= s.name_length; - datetime_format= s.datetime_format; - datetime_format.format= (my_strdup_with_length - (s.datetime_format.format, - s.datetime_format. - format_length, MYF(0))); - format_type= s.format_type; - } - return *this; - } - SHOW_TYPE type() { return SHOW_CHAR; } bool check_update_type(Item_result type) { return type != STRING_RESULT; /* Only accept strings */ } bool check_default(enum_var_type type) { return 0; } + bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); + void update2(THD *thd, enum_var_type type, DATE_TIME_FORMAT *new_value); byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); void set_default(THD *thd, enum_var_type type); }; @@ -718,6 +693,7 @@ public: CHARSET_INFO *charset; ulong ulong_value; ulonglong ulonglong_value; + DATE_TIME_FORMAT *date_time_format; } save_result; LEX_STRING base; /* for structs */ diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 2176fcbd441..c01df3b53cd 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -276,21 +276,26 @@ character-set=latin2 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 791060ac744..e67c430c4f7 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -270,21 +270,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 62e210f1016..5f77163eeda 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -278,21 +278,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index a0d746ce0ca..baecefb8494 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -252,36 +252,41 @@ character-set=latin1 "Reference '%-.64s' not supported (%s)", "Every derived table must have it's own alias", "Select %u was reduced during optimisation", -"Table '%-.64s' from one of SELECT's can not be used in %-.32s" -"Client does not support authentication protocol requested by server; consider upgrading MySQL client" -"All parts of a SPATIAL KEY must be NOT NULL" -"COLLATION '%s' is not valid for CHARACTER SET '%s'" -"Slave is already running" -"Slave has already been stopped" -"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)" -"Z_MEM_ERROR: Not enough memory available for zlib" -"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)" -"Z_DATA_ERROR: Input data was corrupted for zlib" -"%d line(s) was(were) cut by group_concat()" +"Table '%-.64s' from one of SELECT's can not be used in %-.32s", +"Client does not support authentication protocol requested by server; consider upgrading MySQL client", +"All parts of a SPATIAL KEY must be NOT NULL", +"COLLATION '%s' is not valid for CHARACTER SET '%s'", +"Slave is already running", +"Slave has already been stopped", +"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", +"ZLIB: Not enough memory available for zlib", +"ZLIB: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"ZLIB: Input data was corrupted for zlib", +"%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL. Otherwise you will get problems if you get an unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 0510e3fc76b..09e63ddd804 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -272,21 +272,26 @@ character-set=latin7 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 485cbe45724..0956db6681e 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -267,21 +267,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index c9760879f3c..2cc98971915 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -293,7 +293,12 @@ character-set=latin1 "Feld oder Verweis '%-.64s%s%-.64s%s%-.64s' im SELECT-Befehl Nr. %d wurde im SELECT-Befehl Nr. %d aufgelöst", "Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL", "Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn der Slave-Server unerwartet neu startet", -"SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert" -"Incorrect index name '%-.100s'", +"SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 90ab24610ff..84e48d2f284 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -267,21 +267,26 @@ character-set=greek "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index c456e9580b3..da71f4b7da6 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -269,21 +269,26 @@ character-set=latin2 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 09b533c0fb7..f960c6c043d 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -267,21 +267,27 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", + diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 15b8640cb29..d28cc026159 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -269,21 +269,26 @@ character-set=ujis "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index d31efc94d46..c5f2b8d59ba 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -267,21 +267,27 @@ character-set=euckr "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", + diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 515a322f136..1e9028de1d7 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -269,21 +269,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index faea5402fc6..d0a5e27b5c1 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -269,21 +269,27 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", + diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 2a7ea3accb8..17e6df6c443 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -271,21 +271,26 @@ character-set=latin2 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 1f3bbb5c02f..fdf428c9b6d 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -241,7 +241,7 @@ character-set=latin1 "Errado uso/colocação de '%s'", "Esta versão de MySQL não suporta ainda '%s'", "Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log", -"Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela" +"Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela", "Definição errada da chave estrangeira para '%-.64s': %s", "Referência da chave e referência da tabela não coincidem", "Operand should contain %d column(s)", @@ -268,21 +268,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Usando engine de armazenamento %s para tabela '%s'", "Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 78daafe04d1..8f4fdb3a702 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -252,7 +252,7 @@ character-set=latin2 "Unknown prepared statement handler (%ld) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", -"Converting column '%s' from %s to %s" +"Converting column '%s' from %s to %s", "Reference '%-.64s' not supported (%s)", "Every derived table must have it's own alias", "Select %u was reduced during optimisation", @@ -271,21 +271,26 @@ character-set=latin2 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 462afdfa782..2ef6a2c553b 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -269,21 +269,26 @@ character-set=koi8r "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s@%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s@%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ", "ðÏÌÅ ÉÌÉ ÓÓÙÌËÁ '%-.64s%s%-.64s%s%-.64s' ÉÚ SELECTÁ #%d ÂÙÌÁ ÎÁÊÄÅÎÁ × SELECTÅ #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "ëÅÛ ÚÁÐÒÏÓÏ× ÎÅ ÍÏÖÅÔ ÕÓÔÁÎÏ×ÉÔØ ÒÁÚÍÅÒ %lu, ÎÏ×ÙÊ ÒÁÚÍÅÒ ËÅÛÁ ÚÐÒÏÓÏ× - %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 9d12654f150..cddc1059f44 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -262,21 +262,26 @@ character-set=cp1250 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index dd222c2ef30..466e7d478b6 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -275,21 +275,26 @@ character-set=latin2 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index a21d306a3db..de8a245c7f9 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -242,7 +242,7 @@ character-set=latin1 "Equivocado uso/colocación de '%s'", "Esta versión de MySQL no soporta todavia '%s'", "Recibió fatal error %d: '%-.128s' del master cuando leyendo datos del binary log", -"Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla" +"Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Operand should contain %d column(s)", @@ -269,21 +269,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 4d3e69a5b0f..d8695db30a4 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -225,7 +225,7 @@ character-set=latin1 "Fick fel vid utförande av command på mastern: %-.128s", "Fick fel vid utförande av %s: %-.128s", "Felaktig använding av %s and %s", -"SELECT-kommandona har olika antal kolumner" +"SELECT-kommandona har olika antal kolumner", "Kan inte utföra kommandot emedan du har ett READ-lås", "Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat", "Option '%s' användes två gånger", @@ -267,21 +267,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Använder handler %s för tabell '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", -"Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Felaktigt %s namn '%-.100s'", +"tabell", +"databas", +"kolumn", +"index", +"katalog", +"Storleken av "Query cache" kunde inte sättas till %lu, ny storlek är %lu", +"Kolumn '%-.64s' kan inte vara del av ett FULLTEXT index", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 283700b7891..3a37ee02731 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -272,21 +272,26 @@ character-set=koi8u "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "óÔÏ×ÂÅÃØ ÁÂÏ ÐÏÓÉÌÁÎÎÑ '%-.64s%s%-.64s%s%-.64s' ¦Ú SELECTÕ #%d ÂÕÌÏ ÚÎÁÊÄÅÎÅ Õ SELECT¦ #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "ëÅÛ ÚÁÐÉÔ¦× ÎÅÓÐÒÏÍÏÖÅÎ ×ÓÔÁÎÏ×ÉÔÉ ÒÏÚÍ¦Ò %lu, ÎÏ×ÉÊ ÒÏÚÍ¦Ò ËÅÛÁ ÚÁÐÉÔ¦× - %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cc068451ecf..88a1d21354b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2210,7 +2210,8 @@ void get_key_map_from_key_list(key_map *map, TABLE *table, map->clear_all(); while ((name=it++)) { - if ((pos=find_type(name->c_ptr(), &table->keynames, 1+2)) <= 0) + if ((pos= find_type(&table->keynames, name->ptr(), name->length(), 1)) <= + 0) { my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(), table->real_name); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ed8eaba9128..ed01e1bb038 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -210,6 +210,12 @@ void THD::init(void) { pthread_mutex_lock(&LOCK_global_system_variables); variables= global_system_variables; + variables.time_format= date_time_format_copy((THD*) 0, + variables.time_format); + variables.date_format= date_time_format_copy((THD*) 0, + variables.date_format); + variables.datetime_format= date_time_format_copy((THD*) 0, + variables.datetime_format); pthread_mutex_unlock(&LOCK_global_system_variables); server_status= SERVER_STATUS_AUTOCOMMIT; options= thd_startup_options; @@ -281,9 +287,9 @@ void THD::cleanup(void) close_thread_tables(this); } close_temporary_tables(this); - variables.datetime_formats[DATE_FORMAT_TYPE].clean(); - variables.datetime_formats[TIME_FORMAT_TYPE].clean(); - variables.datetime_formats[DATETIME_FORMAT_TYPE].clean(); + my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR)); delete_dynamic(&user_var_events); hash_free(&user_vars); if (global_read_lock) diff --git a/sql/sql_class.h b/sql/sql_class.h index a103bab1d6c..c66ebb77020 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -421,7 +421,11 @@ struct system_variables CHARSET_INFO *collation_server; CHARSET_INFO *collation_database; CHARSET_INFO *collation_connection; - sys_var_datetime_format datetime_formats[3]; + + /* DATE, DATETIME and TIME formats */ + DATE_TIME_FORMAT *date_format; + DATE_TIME_FORMAT *datetime_format; + DATE_TIME_FORMAT *time_format; }; void free_tmp_table(THD *thd, TABLE *entry); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index b0f4b4ef574..b7d6c642398 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -609,7 +609,7 @@ bool mysql_change_db(THD *thd, const char *name) } if ((db_length > NAME_LEN) || check_db_name(dbname)) { - net_printf(thd,ER_WRONG_DB_NAME, dbname); + net_printf(thd, ER_WRONG_NAME, ER(ER_DATABASE), dbname); x_free(dbname); DBUG_RETURN(1); } @@ -675,7 +675,7 @@ int mysqld_show_create_db(THD *thd, char *dbname, if (check_db_name(dbname)) { - net_printf(thd,ER_WRONG_DB_NAME, dbname); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), dbname); DBUG_RETURN(1); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 93c4658d38c..a55b801a0fc 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -40,10 +40,18 @@ LEX_STRING tmp_table_alias= {(char*) "tmp-table",8}; pthread_key(LEX*,THR_LEX); +/* Longest standard keyword name */ #define TOCK_NAME_LENGTH 24 /* - The following is based on the latin1 character set, and is only + Map to default keyword characters. This is used to test if an identifer + is 'simple', in which case we don't have to do any character set conversions + on it +*/ +uchar *bin_ident_map= my_charset_bin.ident_map; + +/* + The following data is based on the latin1 character set, and is only used when comparing keywords */ @@ -66,6 +74,7 @@ uchar to_upper_lex[] = { 208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255 }; + inline int lex_casecmp(const char *s, const char *t, uint len) { while (len-- != 0 && @@ -410,15 +419,18 @@ inline static uint int_token(const char *str,uint length) } -// yylex remember the following states from the following yylex() -// MY_LEX_EOQ ; found end of query -// MY_LEX_OPERATOR_OR_IDENT ; last state was an ident, text or number -// (which can't be followed by a signed number) +/* + yylex remember the following states from the following yylex() + + - MY_LEX_EOQ Found end of query + - MY_LEX_OPERATOR_OR_IDENT Last state was an ident, text or number + (which can't be followed by a signed number) +*/ int yylex(void *arg, void *yythd) { reg1 uchar c; - int tokval; + int tokval, result_state; uint length; enum my_lex_states state,prev_state; LEX *lex= &(((THD *)yythd)->lex); @@ -503,6 +515,7 @@ int yylex(void *arg, void *yythd) #if defined(USE_MB) && defined(USE_MB_IDENT) if (use_mb(cs)) { + result_state= IDENT_QUOTED; if (my_mbcharlen(cs, yyGetLast()) > 1) { int l = my_ismbchar(cs, @@ -529,7 +542,15 @@ int yylex(void *arg, void *yythd) } else #endif - while (ident_map[c=yyGet()]) ; + { + result_state= bin_ident_map[c] ? IDENT : IDENT_QUOTED; + while (ident_map[c=yyGet()]) + { + /* If not simple character, mark that we must convert it */ + if (!bin_ident_map[c]) + result_state= IDENT_QUOTED; + } + } length= (uint) (lex->ptr - lex->tok_start)-1; if (lex->ignore_space) { @@ -560,8 +581,7 @@ int yylex(void *arg, void *yythd) (lex->charset=get_charset_by_csname(yylval->lex_str.str+1, MY_CS_PRIMARY,MYF(0)))) return(UNDERSCORE_CHARSET); - else - return(IDENT); + return(result_state); // IDENT or IDENT_QUOTED case MY_LEX_IDENT_SEP: // Found ident and now '.' yylval->lex_str.str=(char*) lex->ptr; @@ -611,21 +631,11 @@ int yylex(void *arg, void *yythd) } // fall through case MY_LEX_IDENT_START: // We come here after '.' + result_state= IDENT; #if defined(USE_MB) && defined(USE_MB_IDENT) if (use_mb(cs)) { - if (my_mbcharlen(cs, yyGetLast()) > 1) - { - int l = my_ismbchar(cs, - (const char *)lex->ptr-1, - (const char *)lex->end_of_query); - if (l == 0) - { - state = MY_LEX_CHAR; - continue; - } - lex->ptr += l - 1; - } + result_state= IDENT_QUOTED; while (ident_map[c=yyGet()]) { if (my_mbcharlen(cs, c) > 1) @@ -641,15 +651,17 @@ int yylex(void *arg, void *yythd) } else #endif - while (ident_map[c = yyGet()]) ; - + while (ident_map[c = yyGet()]) + { + /* If not simple character, mark that we must convert it */ + if (!bin_ident_map[c]) + result_state= IDENT_QUOTED; + } if (c == '.' && ident_map[yyPeek()]) lex->next_state=MY_LEX_IDENT_SEP;// Next is '.' - // fall through - case MY_LEX_FOUND_IDENT: // Complete ident - yylval->lex_str=get_token(lex,yyLength()); - return(IDENT); + yylval->lex_str= get_token(lex,yyLength()); + return(result_state); case MY_LEX_USER_VARIABLE_DELIMITER: { @@ -699,7 +711,7 @@ int yylex(void *arg, void *yythd) if (c == delim) yySkip(); // Skip end ` lex->next_state= MY_LEX_START; - return(IDENT); + return(IDENT_QUOTED); } case MY_LEX_INT_OR_REAL: // Compleat int or incompleat real if (c != '.') @@ -924,7 +936,13 @@ int yylex(void *arg, void *yythd) We should now be able to handle: [(global | local | session) .]variable_name */ - while (ident_map[c=yyGet()]) ; + result_state= IDENT; + while (ident_map[c=yyGet()]) + { + /* If not simple character, mark that we must convert it */ + if (!bin_ident_map[c]) + result_state= IDENT_QUOTED; + } if (c == '.') lex->next_state=MY_LEX_IDENT_SEP; length= (uint) (lex->ptr - lex->tok_start)-1; @@ -934,7 +952,7 @@ int yylex(void *arg, void *yythd) return(tokval); // Was keyword } yylval->lex_str=get_token(lex,length); - return(IDENT); + return(result_state); } } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f377714461d..d6f8e2f66c7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1041,7 +1041,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd) if (!db || check_db_name(db)) { - net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db ? db : "NULL"); goto err; } if (lower_case_table_names) @@ -1382,7 +1382,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, // null test to handle EOM if (!db || !strip_sp(db) || check_db_name(db)) { - net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db ? db : "NULL"); break; } if (check_access(thd,CREATE_ACL,db,0,1,0)) @@ -1398,7 +1398,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, // null test to handle EOM if (!db || !strip_sp(db) || check_db_name(db)) { - net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db ? db : "NULL"); break; } if (check_access(thd,DROP_ACL,db,0,1,0)) @@ -1999,7 +1999,7 @@ mysql_execute_command(THD *thd) #endif if (strlen(tables->real_name) > NAME_LEN) { - net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name); + net_printf(thd,ER_WRONG_NAME, ER(ER_TABLE), tables->real_name); break; } LOCK_ACTIVE_MI; @@ -2044,7 +2044,7 @@ mysql_execute_command(THD *thd) #endif if (strlen(tables->real_name) > NAME_LEN) { - net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias); + net_printf(thd, ER_WRONG_NAME, ER(ER_TABLE), tables->alias); res=0; break; } @@ -2176,7 +2176,7 @@ mysql_execute_command(THD *thd) ulong priv=0; if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN)) { - net_printf(thd,ER_WRONG_TABLE_NAME,lex->name); + net_printf(thd, ER_WRONG_NAME, ER(ER_TABLE), lex->name); res=0; break; } @@ -2750,7 +2750,7 @@ mysql_execute_command(THD *thd) remove_escape(db); // Fix escaped '_' if (check_db_name(db)) { - net_printf(thd,ER_WRONG_DB_NAME, db); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db); goto error; } #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -2915,7 +2915,7 @@ mysql_execute_command(THD *thd) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(thd,ER_WRONG_DB_NAME, lex->name); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), lex->name); break; } /* @@ -2943,7 +2943,7 @@ mysql_execute_command(THD *thd) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(thd,ER_WRONG_DB_NAME, lex->name); + net_printf(thd, ER_WRONG_NAME, ER(ER_DATABASE), lex->name); break; } /* @@ -2976,7 +2976,7 @@ mysql_execute_command(THD *thd) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(thd,ER_WRONG_DB_NAME, lex->name); + net_printf(thd, ER_WRONG_NAME, ER(ER_DATABASE), lex->name); break; } if (check_access(thd,ALTER_ACL,lex->name,0,1,0)) @@ -2993,7 +2993,7 @@ mysql_execute_command(THD *thd) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(thd,ER_WRONG_DB_NAME, lex->name); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), lex->name); break; } if (check_access(thd,DROP_ACL,lex->name,0,1,0)) @@ -4059,7 +4059,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, { char *not_used; uint not_used2; - bool not_used3; + bool not_used3; thd->cuted_fields=0; String str,*res; @@ -4089,7 +4089,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, { String str,*res; res=default_value->val_str(&str); - if (!find_enum(interval,res->ptr(),res->length())) + res->strip_sp(); + if (!find_type(interval, res->ptr(), res->length(), 0)) { net_printf(thd,ER_INVALID_DEFAULT,field_name); DBUG_RETURN(1); @@ -4242,7 +4243,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, if (check_table_name(table->table.str,table->table.length) || table->db.str && check_db_name(table->db.str)) { - net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str); + net_printf(thd, ER_WRONG_NAME, ER(ER_TABLE), table->table.str); DBUG_RETURN(0); } @@ -4596,7 +4597,7 @@ static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name) if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 || !test_if_hard_path(*filename_ptr)) { - my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr); + my_error(ER_WRONG_NAME, MYF(0), ER(ER_TABLE), *filename_ptr); return 1; } /* Fix is using unix filename format on dos */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index da62fc0a262..2fa08e2d649 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -332,7 +332,7 @@ SETUP_PARAM_FUNCTION(setup_param_datetime) tm.day= (uint) to[3]; tm.neg= 0; - param->set_time(&tm, TIMESTAMP_FULL); + param->set_time(&tm, TIMESTAMP_DATETIME); } *pos+= length; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 1a2021abf90..d2d1926ea06 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -437,7 +437,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, if (check_column_name(sql_field->field_name)) { - my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name); + my_error(ER_WRONG_NAME, MYF(0), ER(ER_COLUMN), sql_field->field_name); DBUG_RETURN(-1); } @@ -888,7 +888,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } if (!key_info->name || check_column_name(key_info->name)) { - my_error(ER_WRONG_INDEX_NAME, MYF(0), key_info->name); + my_error(ER_WRONG_NAME, MYF(0), ER(ER_INDEX), key_info->name); DBUG_RETURN(-1); } if (!(key_info->flags & HA_NULL_PART_KEY)) @@ -1777,7 +1777,7 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table, check_table_name(src_table,table_ident->table.length)) || table_ident->db.str && check_db_name((src_db= table_ident->db.str))) { - my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table); + my_error(ER_WRONG_NAME, MYF(0), ER(ER_TABLE), src_table); DBUG_RETURN(-1); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2036d13232f..bb37c58004f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -78,7 +78,7 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B) CHARSET_INFO *charset; thr_lock_type lock_type; interval_type interval; - datetime_format_types datetime_format_type; + timestamp_type date_time_type; st_select_lex *select_lex; chooser_compare_func_creator boolfunc2creator; } @@ -246,6 +246,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token HIGH_PRIORITY %token HOSTS_SYM %token IDENT +%token IDENT_QUOTED %token IGNORE_SYM %token IMPORT %token INDEX @@ -584,8 +585,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %right BINARY COLLATE_SYM %type <lex_str> - IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME - ULONGLONG_NUM field_ident select_alias ident ident_or_text + IDENT IDENT_QUOTED TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM + LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal NCHAR_STRING opt_component @@ -648,7 +649,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC UDA_CHAR_SUM UDA_FLOAT_SUM UDA_INT_SUM -%type <datetime_format_type> datetime_format_type; +%type <date_time_type> date_time_type; %type <interval> interval %type <db_type> table_types @@ -2631,7 +2632,7 @@ simple_expr: { $$= new Item_func_spatial_collection(* $3, Geometry::wkbGeometryCollection, Geometry::wkbPoint); } - | GET_FORMAT '(' datetime_format_type ',' expr ')' + | GET_FORMAT '(' date_time_type ',' expr ')' { $$= new Item_func_get_format($3, $5); } | HOUR_SYM '(' expr ')' { $$= new Item_func_hour($3); } @@ -3254,10 +3255,10 @@ interval: | YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; } | YEAR_SYM { $$=INTERVAL_YEAR; }; -datetime_format_type: - DATE_SYM {$$=DATE_FORMAT_TYPE;} - | TIME_SYM {$$=TIME_FORMAT_TYPE;} - | DATETIME {$$=DATETIME_FORMAT_TYPE;}; +date_time_type: + DATE_SYM {$$=TIMESTAMP_DATE;} + | TIME_SYM {$$=TIMESTAMP_TIME;} + | DATETIME {$$=TIMESTAMP_DATETIME;}; table_alias: /* empty */ @@ -4479,15 +4480,16 @@ table_ident: /* For Delphi */; IDENT_sys: - IDENT - { - THD *thd= YYTHD; - if (thd->charset_is_system_charset) - $$= $1; - else - thd->convert_string(&$$, system_charset_info, - $1.str, $1.length, thd->charset()); - } + IDENT { $$= $1; } + | IDENT_QUOTED + { + THD *thd= YYTHD; + if (thd->charset_is_system_charset) + $$= $1; + else + thd->convert_string(&$$, system_charset_info, + $1.str, $1.length, thd->charset()); + } ; TEXT_STRING_sys: diff --git a/sql/strfunc.cc b/sql/strfunc.cc new file mode 100644 index 00000000000..1db2124bcee --- /dev/null +++ b/sql/strfunc.cc @@ -0,0 +1,147 @@ +/* Copyright (C) 2003 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 */ + +/* Some useful string utility functions used by the MySQL server */ + +#include "mysql_priv.h" + +/* + Return bitmap for strings used in a set + + SYNOPSIS + find_set() + lib Strings in set + str Strings of set-strings separated by ',' + err_pos If error, set to point to start of wrong set string + err_len If error, set to the length of wrong set string + set_warning Set to 1 if some string in set couldn't be used + + NOTE + We delete all end space from str before comparison + + RETURN + bitmap of all sets found in x. + set_warning is set to 1 if there was any sets that couldn't be set +*/ + +static const char field_separator=','; + +ulonglong find_set(TYPELIB *lib, const char *str, uint length, char **err_pos, + uint *err_len, bool *set_warning) +{ + const char *end= str + length; + *err_pos= 0; // No error yet + while (end > str && my_isspace(system_charset_info, end[-1])) + end--; + + *err_len= 0; + ulonglong found= 0; + if (str != end) + { + const char *start= str; + for (;;) + { + const char *pos= start; + uint var_len; + + for (; pos != end && *pos != field_separator; pos++) ; + var_len= (uint) (pos - start); + uint find= find_type(lib, start, var_len, 0); + if (!find) + { + *err_pos= (char*) start; + *err_len= var_len; + *set_warning= 1; + } + else + found|= ((longlong) 1 << (find - 1)); + if (pos == end) + break; + start= pos + 1; + } + } + return found; +} + + +/* + Function to find a string in a TYPELIB + (Same format as mysys/typelib.c) + + SYNOPSIS + find_type() + lib TYPELIB (struct of pointer to values + count) + find String to find + length Length of string to find + part_match Allow part matching of value + + RETURN + 0 error + > 0 position in TYPELIB->type_names +1 +*/ + +uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match) +{ + uint found_count=0, found_pos=0; + const char *end= find+length; + const char *i; + const char *j; + for (uint pos=0 ; (j=lib->type_names[pos++]) ; ) + { + for (i=find ; i != end && + my_toupper(system_charset_info,*i) == + my_toupper(system_charset_info,*j) ; i++, j++) ; + if (i == end) + { + if (! *j) + return(pos); + found_count++; + found_pos= pos; + } + } + return(found_count == 1 && part_match ? found_count : 0); +} + + +/* + Check if the first word in a string is one of the ones in TYPELIB + + SYNOPSIS + check_word() + lib TYPELIB + val String to check + end End of input + end_of_word Store value of last used byte here if we found word + + RETURN + 0 No matching value + > 1 lib->type_names[#-1] matched + end_of_word will point to separator character/end in 'val' +*/ + +uint check_word(TYPELIB *lib, const char *val, const char *end, + const char **end_of_word) +{ + int res; + const char *ptr; + + /* Fiend end of word */ + for (ptr= val ; ptr < end && my_isalpha(&my_charset_latin1, *ptr) ; ptr++) + ; + if ((res=find_type(lib, val, (uint) (ptr - val), 1)) > 0) + *end_of_word= ptr; + return res; +} diff --git a/sql/structs.h b/sql/structs.h index d9be230c049..352823cceb2 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -20,15 +20,19 @@ struct st_table; class Field; -typedef struct st_date_format { /* How to print date */ - uint pos[6]; /* Positions to YY.MM.DD HH:MM:SS */ -} DATE_FORMAT; +typedef struct lex_string { + char *str; + uint length; +} LEX_STRING; + + +typedef struct st_date_time_format { + uchar positions[8]; + char time_separator; /* Separator between hour and minute */ + uint flag; /* For future */ + LEX_STRING format; +} DATE_TIME_FORMAT; -typedef struct st_datetime_format { - byte dt_pos[8]; - char *format; - uint format_length; -} DATETIME_FORMAT; typedef struct st_keyfile_info { /* used with ha_info() */ byte ref[MAX_REFLENGTH]; /* Pointer to current row */ @@ -115,8 +119,17 @@ typedef struct st_read_record { /* Parameter to read_record */ bool print_error, ignore_not_found_rows; } READ_RECORD; -enum timestamp_type { TIMESTAMP_NONE, WRONG_TIMESTAMP_FULL, TIMESTAMP_DATE, TIMESTAMP_FULL, - TIMESTAMP_TIME}; + +enum timestamp_type +{ + TIMESTAMP_NONE= -2, TIMESTAMP_DATETIME_ERROR= -1, + TIMESTAMP_DATE= 0, TIMESTAMP_DATETIME= 1, TIMESTAMP_TIME= 2 +}; + +/* Parameters to str_to_TIME */ +#define TIME_FUZZY_DATE 1 +#define TIME_DATETIME_ONLY 2 + typedef struct st_time { uint year,month,day,hour,minute,second; @@ -125,12 +138,21 @@ typedef struct st_time { timestamp_type time_type; } TIME; + typedef struct { long year,month,day,hour,minute,second,second_part; bool neg; } INTERVAL; +typedef struct st_known_date_time_format { + const char *format_name; + const char *date_format; + const char *datetime_format; + const char *time_format; +} KNOWN_DATE_TIME_FORMAT; + + enum SHOW_TYPE { SHOW_UNDEF, @@ -168,11 +190,6 @@ typedef struct show_var_st { } SHOW_VAR; -typedef struct lex_string { - char *str; - uint length; -} LEX_STRING; - typedef struct st_lex_user { LEX_STRING user, host, password; } LEX_USER; diff --git a/sql/time.cc b/sql/time.cc index f2e41afa560..4f2a2a23910 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -23,14 +23,9 @@ static ulong const days_at_timestart=719528; /* daynr at 1970.01.01 */ uchar *days_in_month= (uchar*) "\037\034\037\036\037\036\037\037\036\037\036\037"; - /* Init some variabels needed when using my_local_time */ /* Currently only my_time_zone is inited */ -bool parse_datetime_formats(datetime_format_types format_type, - const char *format_str, uint format_length, - byte *dt_pos); - static long my_time_zone=0; void init_time(void) @@ -282,6 +277,7 @@ ulong convert_period_to_month(ulong period) return a*12+b-1; } + ulong convert_month_to_period(ulong month) { ulong year; @@ -295,6 +291,13 @@ ulong convert_month_to_period(ulong month) } +/* Position for YYYY-DD-MM HH-MM-DD.FFFFFF AM in default format */ + +static uchar internal_format_positions[]= +{0, 1, 2, 3, 4, 5, 6, (uchar) 255}; + +static char time_separator=':'; + /* Convert a timestamp string to a TIME value. @@ -303,7 +306,9 @@ ulong convert_month_to_period(ulong month) str String to parse length Length of string l_time Date is stored here - fuzzy_date 1 if we should allow dates where one part is zero + 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. DESCRIPTION At least the following formats are recogniced (based on number of digits) @@ -312,161 +317,248 @@ ulong convert_month_to_period(ulong month) YYYYMMDDTHHMMSS where T is a the character T (ISO8601) Also dates where all parts are zero are allowed + The second part may have an optional .###### fraction part. + + NOTES + This function should work with a format position vector as long as the + following things holds: + - All date are kept together and all time parts are kept together + - Date and time parts must be separated by blank + - Second fractions must come after second part and be separated + by a '.'. (The second fractions are optional) + - AM/PM must come after second fractions (or after seconds if no fractions) + - Year must always been specified. + - If time is before date, then we will use datetime format only if + the argument consist of two parts, separated by space. + Otherwise we will assume the argument is a date. + - The hour part must be specified in hour-minute-second order. + RETURN VALUES TIMESTAMP_NONE String wasn't a timestamp, like [DD [HH:[MM:[SS]]]].fraction TIMESTAMP_DATE DATE string (YY MM and DD parts ok) - TIMESTAMP_FULL Full timestamp + TIMESTAMP_DATETIME Full timestamp + TIMESTAMP_DATETIME_ERROR Timestamp with wrong values */ +#define MAX_DATE_PARTS 8 + timestamp_type -str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date,THD *thd) +str_to_TIME(const char *str, uint length, TIME *l_time, uint flags) { - uint field_length= 0, year_length= 0, digits, i, number_of_fields; - uint date[7], date_len[7]; - uint not_zero_date; - bool is_internal_format= 0; - const char *pos; + uint field_length, year_length, digits, i, number_of_fields; + 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; + const char *pos, *last_field_pos; const char *end=str+length; - bool found_delimitier= 0; + const uchar *format_position; + bool found_delimitier= 0, found_space= 0; + DATE_TIME_FORMAT *format; DBUG_ENTER("str_to_TIME"); - DBUG_PRINT("enter",("str: %.*s",length,str)); + DBUG_PRINT("ENTER",("str: %.*s",length,str)); - // Skip garbage - for (; str != end && !my_isdigit(&my_charset_latin1, *str) ; str++) ; - if (str == end) + LINT_INIT(field_length); + LINT_INIT(year_length); + LINT_INIT(last_field_pos); + + // Skip space at start + for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++) + ; + if (str == end || ! my_isdigit(&my_charset_latin1, *str)) DBUG_RETURN(TIMESTAMP_NONE); + + is_internal_format= 0; + /* This has to be changed if want to activate different timestamp formats */ + format_position= internal_format_positions; + /* - Calculate first number of digits. + Calculate number of digits in first part. If length= 8 or >= 14 then year is of format YYYY. (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS) */ - for (pos=str; pos != end && my_isdigit(&my_charset_latin1,*pos) ; pos++) ; - /* Check for internal format */ - digits= (uint) (pos-str); + for (pos=str; pos != end && my_isdigit(&my_charset_latin1,*pos) ; pos++) + ; - if (pos == end || digits>=12) + digits= (uint) (pos-str); + start_loop= 0; // Start of scan loop + date_len[format_position[0]]= 0; // Length of year field + if (pos == end) { - is_internal_format= 1; + /* Found date in internal format (only numbers like YYYYMMDD) */ year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2; field_length=year_length-1; - date_len[0]= year_length; + is_internal_format= 1; + format_position= internal_format_positions; + } + else + { + if (format_position[0] >= 3) // If year is after HHMMDD + { + /* + If year is not in first part then we have to determinate if we got + a date field or a datetime field. + We do this by checking if there is two numbers separated by + space in the input. + */ + while (pos < end && !my_isspace(&my_charset_latin1, *pos)) + pos++; + while (pos < end && !my_isdigit(&my_charset_latin1, *pos)) + pos++; + if (pos == end) + { + if (flags & TIME_DATETIME_ONLY) + return TIMESTAMP_NONE; // Can't be a full datetime + /* Date field. Set hour, minutes and seconds to 0 */ + date[0]= date[1]= date[2]= date[3]= 0; + start_loop= 5; // Start with first date part + } + } } + + /* + Only allow space in the first "part" of the datetime field and: + - after days, part seconds + - before and after AM/PM (handled by code later) + + 2003-03-03 20:00:20 AM + 20:00:20.000000 AM 03-03-2000 + */ + i= max((uint) format_position[0], (uint) format_position[1]); + set_if_bigger(i, (uint) format_position[2]); + allow_space= ((1 << i) | (1 << format_position[6])); + allow_space&= (1 | 2 | 4 | 8); + not_zero_date= 0; - for (i=0 ; i < 6 && str != end && my_isdigit(&my_charset_latin1,*str) ; i++) + for (i = start_loop; + i < MAX_DATE_PARTS-1 && str != end && + my_isdigit(&my_charset_latin1,*str); + i++) { - if (!is_internal_format) - date_len[i]= 1; - uint tmp_value=(uint) (uchar) (*str++ - '0'); - while (str != end && my_isdigit(&my_charset_latin1,str[0]) - && (is_internal_format && field_length-- || !is_internal_format) ) + const char *start= str; + ulong tmp_value= (uint) (uchar) (*str++ - '0'); + while (str != end && my_isdigit(&my_charset_latin1,str[0]) && + (!is_internal_format || field_length--)) { - tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0'); + tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0'); str++; - if (!is_internal_format) - date_len[i]+= 1; } - if (i == 2 && *str == '.') + date_len[i]+= (uint) (str - start); + if (tmp_value > 999999) // Impossible date part DBUG_RETURN(TIMESTAMP_NONE); date[i]=tmp_value; not_zero_date|= tmp_value; - if (i == 2 && str != end && *str == 'T') + + /* Length-1 of next field */ + field_length= format_position[i+1] == 0 ? 3 : 1; + + if ((last_field_pos= str) == end) + { + i++; // Register last found part + break; + } + /* Allow a 'T' after day to allow CCYYMMDDT type of fields */ + if (i == format_position[2] && *str == 'T') + { str++; // ISO8601: CCYYMMDDThhmmss - else if ( i != 5 ) // Skip inter-field delimiters + continue; + } + if (i == format_position[5]) // Seconds { - while (str != end && - (my_ispunct(&my_charset_latin1,*str) || - my_isspace(&my_charset_latin1,*str))) + if (*str == '.') // Followed by part seconds { - // Only allow space between days and hours - if (my_isspace(&my_charset_latin1,*str) && i != 2) - DBUG_RETURN(TIMESTAMP_NONE); str++; - found_delimitier=1; // Should be a 'normal' date + field_length= 5; // 5 digits after first (=6) } + continue; + + /* No part seconds */ + date[++i]= 0; } - if (is_internal_format) - field_length=1; // Rest fields can only be 2 - } - /* Handle second fractions */ - if (i == 6 && (uint) (end-str) >= 2 && *str == '.' && - my_isdigit(&my_charset_latin1,str[1])) - { - str++; - uint tmp_value=(uint) (uchar) (*str - '0'); - field_length=5; - while (str++ != end && my_isdigit(&my_charset_latin1,str[0]) && - field_length--) - tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0'); - date[6]=tmp_value; - not_zero_date|= tmp_value; + while (str != end && + (my_ispunct(&my_charset_latin1,*str) || + my_isspace(&my_charset_latin1,*str))) + { + if (my_isspace(&my_charset_latin1,*str)) + { + if (!(allow_space & (1 << i))) + DBUG_RETURN(TIMESTAMP_NONE); + found_space= 1; + } + str++; + found_delimitier= 1; // Should be a 'normal' date + } + /* Check if next position is AM/PM */ + if (i == format_position[6]) // Seconds, time for AM/PM + { + i++; // Skip AM/PM part + if (format_position[7] != 255) // If using AM/PM + { + if (str+2 <= end && (str[1] == 'M' || str[1] == 'm')) + { + if (str[1] == 'p' || str[1] == 'P') + add_hours= 12; + else if (str[1] != 'a' || str[1] != 'A') + continue; // Not AM/PM + str+= 2; // Skip AM/PM + /* Skip space after AM/PM */ + while (str != end && my_isspace(&my_charset_latin1,*str)) + str++; + } + } + } + last_field_pos= str; } - else - date[6]=0; - - while (str != end && (my_ispunct(&my_charset_latin1,*str) || - my_isspace(&my_charset_latin1,*str))) - str++; + if (found_delimitier && !found_space && (flags & TIME_DATETIME_ONLY)) + DBUG_RETURN(TIMESTAMP_NONE); // Can't be a datetime - uint add_hours= 0; - if (!my_strnncoll(&my_charset_latin1, - (const uchar *)str, 2, - (const uchar *)"PM", 2)) - add_hours= 12; + str= last_field_pos; - number_of_fields=i; - while (i < 6) + number_of_fields= i - start_loop; + while (i < MAX_DATE_PARTS) date[i++]=0; if (!is_internal_format) { - byte *frm_pos; + year_length= date_len[(uint) format_position[0]]; + if (!year_length) // Year must be specified + DBUG_RETURN(TIMESTAMP_NONE); - if (number_of_fields <= 3) - { - frm_pos= t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format.dt_pos; - l_time->hour= 0; - l_time->minute= 0; - l_time->second= 0; - } - else + l_time->year= date[(uint) format_position[0]]; + l_time->month= date[(uint) format_position[1]]; + l_time->day= date[(uint) format_position[2]]; + l_time->hour= date[(uint) format_position[3]]; + l_time->minute= date[(uint) format_position[4]]; + l_time->second= date[(uint) format_position[5]]; + l_time->second_part= date[(uint) format_position[6]]; + if (format_position[7] != (uchar) 255) { - frm_pos= t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format.dt_pos; - l_time->hour= date[(int) frm_pos[3]]; - l_time->minute=date[(int) frm_pos[4]]; - l_time->second=date[(int) frm_pos[5]]; - if (frm_pos[6] == 1) - { - if (l_time->hour > 12) - DBUG_RETURN(WRONG_TIMESTAMP_FULL); - l_time->hour= l_time->hour%12 + add_hours; - } + if (l_time->hour > 12) + DBUG_RETURN(TIMESTAMP_DATETIME_ERROR); + l_time->hour= l_time->hour%12 + add_hours; } - - l_time->year= date[(int) frm_pos[0]]; - l_time->month= date[(int) frm_pos[1]]; - l_time->day= date[(int) frm_pos[2]]; - year_length= date_len[(int) frm_pos[0]]; } else { - l_time->year= date[0]; - l_time->month= date[1]; - l_time->day= date[2]; - l_time->hour= date[3]; - l_time->minute=date[4]; - l_time->second=date[5]; - } - l_time->second_part=date[6]; + l_time->year= date[0]; + l_time->month= date[1]; + l_time->day= date[2]; + l_time->hour= date[3]; + l_time->minute= date[4]; + l_time->second= date[5]; + l_time->second_part=date[6]; + } l_time->neg= 0; - if (year_length == 2 && i >=2 && (l_time->month || l_time->day)) - l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); + if (year_length == 2 && i >= format_position[1] && i >=format_position[2] && + (l_time->month || l_time->day)) + l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); if (number_of_fields < 3 || l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59 || - (!fuzzy_date && (l_time->month == 0 || l_time->day == 0))) + (!(flags & TIME_FUZZY_DATE) && (l_time->month == 0 || l_time->day == 0))) { /* Only give warning for a zero date if there is some garbage after */ if (!not_zero_date) // If zero date @@ -481,46 +573,46 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date,THD *thd) } } if (not_zero_date) - thd->cuted_fields++; - DBUG_RETURN(WRONG_TIMESTAMP_FULL); + current_thd->cuted_fields++; + DBUG_RETURN(TIMESTAMP_DATETIME_ERROR); } - if (str != end && thd->count_cuted_fields) + if (str != end && current_thd->count_cuted_fields) { for (; str != end ; str++) { if (!my_isspace(&my_charset_latin1,*str)) { - thd->cuted_fields++; + current_thd->cuted_fields++; break; } } } DBUG_RETURN(l_time->time_type= - (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_FULL)); + (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_DATETIME)); } -time_t str_to_timestamp(const char *str,uint length, THD *thd) +time_t str_to_timestamp(const char *str,uint length) { TIME l_time; long not_used; - if (str_to_TIME(str,length,&l_time,0,thd) <= WRONG_TIMESTAMP_FULL) + if (str_to_TIME(str,length,&l_time,0) <= TIMESTAMP_DATETIME_ERROR) return(0); if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR) { - thd->cuted_fields++; + current_thd->cuted_fields++; return(0); } return(my_gmt_sec(&l_time, ¬_used)); } -longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd) +longlong str_to_datetime(const char *str,uint length, uint fuzzy_date) { TIME l_time; - if (str_to_TIME(str,length,&l_time,fuzzy_date,thd) <= WRONG_TIMESTAMP_FULL) + if (str_to_TIME(str,length,&l_time,fuzzy_date) <= TIMESTAMP_DATETIME_ERROR) return(0); return (longlong) (l_time.year*LL(10000000000) + l_time.month*LL(100000000)+ @@ -542,22 +634,24 @@ longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd) length Length of str l_time Store result here + NOTES + Because of the extra days argument, this function can only + work with times where the time arguments are in the above order. + RETURN 0 ok 1 error */ -bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) +bool str_to_time(const char *str,uint length,TIME *l_time) { long date[5],value; - const char *end=str+length; + const char *end=str+length, *end_of_days; bool found_days,found_hours; uint state; - byte *frm_pos= t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format.dt_pos; l_time->neg=0; - for (; str != end && - !my_isdigit(&my_charset_latin1,*str) && *str != '-' ; str++) + for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++) length--; if (str != end && *str == '-') { @@ -571,37 +665,33 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) /* Check first if this is a full TIMESTAMP */ if (length >= 12) { // Probably full timestamp - enum timestamp_type tres= str_to_TIME(str,length,l_time,1,thd); - if (tres == TIMESTAMP_FULL) - return 0; - else if (tres == WRONG_TIMESTAMP_FULL) - return 1; + enum timestamp_type res= str_to_TIME(str,length,l_time, + (TIME_FUZZY_DATE | + TIME_DATETIME_ONLY)); + if ((int) res >= (int) TIMESTAMP_DATETIME_ERROR) + return res == TIMESTAMP_DATETIME_ERROR; } /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */ for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++) value=value*10L + (long) (*str - '0'); - /* Move to last space */ - if (str != end && *str == ' ') - { - while (++str != end && str[0] == ' ') - {} - str--; - } + /* Skipp all space after 'days' */ + end_of_days= str; + for (; str != end && my_isspace(&my_charset_latin1, str[0]) ; str++) + ; LINT_INIT(state); found_days=found_hours=0; - if ((uint) (end-str) > 1 && (*str == ' ' && - my_isdigit(&my_charset_latin1,str[1]))) - { // days ! - date[0]=value; - state=1; // Assume next is hours - found_days=1; - str++; // Skip space; - } - else if ((end-str) > 1 && *str == frm_pos[7] && - my_isdigit(&my_charset_latin1,str[1])) + if ((uint) (end-str) > 1 && str != end_of_days && + my_isdigit(&my_charset_latin1, *str)) + { // Found days part + date[0]= value; + state= 1; // Assume next is hours + found_days= 1; + } + else if ((end-str) > 1 && *str == time_separator && + my_isdigit(&my_charset_latin1, str[1])) { date[0]=0; // Assume we found hours date[1]=value; @@ -626,10 +716,10 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++) value=value*10L + (long) (*str - '0'); date[state++]=value; - if (state == 4 || (end-str) < 2 || *str != frm_pos[7] || + if (state == 4 || (end-str) < 2 || *str != time_separator || !my_isdigit(&my_charset_latin1,str[1])) break; - str++; // Skip ':' + str++; // Skip time_separator (':') } if (state != 4) @@ -644,7 +734,8 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) else bzero((char*) (date+state), sizeof(long)*(4-state)); } - fractional: + +fractional: /* Get fractional second part */ if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1])) { @@ -659,18 +750,21 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) else date[4]=0; - while (str != end && !my_isalpha(&my_charset_latin1,*str)) - str++; - - if ( (end-str)>= 2 && - !my_strnncoll(&my_charset_latin1, - (const uchar *)str, 2, - (const uchar *)"PM", 2) && - frm_pos[6] == 1) + if (internal_format_positions[7] != 255) { - uint days_i= date[1]/24; - uint hours_i= date[1]%24; - date[1]= hours_i%12 + 12 + 24*days_i; + /* Read a possible AM/PM */ + while (str != end && my_isspace(&my_charset_latin1, *str)) + str++; + if (str+2 <= end && (str[1] == 'M' || str[1] == 'm')) + { + if (str[1] == 'p' || str[1] == 'P') + { + str+= 2; + date[1]= date[1]%12 + 12; + } + else if (str[1] == 'a' || str[1] == 'A') + str+=2; + } } /* Some simple checks */ @@ -680,11 +774,11 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) return 1; } l_time->month=0; - l_time->day=date[0]; - l_time->hour=date[frm_pos[3] + 1]; - l_time->minute=date[frm_pos[4] + 1]; - l_time->second=date[frm_pos[5] + 1]; - l_time->second_part=date[4]; + l_time->day= date[0]; + l_time->hour= date[1]; + l_time->minute= date[2]; + l_time->second= date[3]; + l_time->second_part= date[4]; l_time->time_type= TIMESTAMP_TIME; /* Check if there is garbage at end of the TIME specification */ @@ -730,163 +824,404 @@ void calc_time_from_sec(TIME *to, long seconds, long microseconds) } -DATETIME_FORMAT *make_format(DATETIME_FORMAT *datetime_format, - datetime_format_types format_type, - const char *format_str, - uint format_length, bool is_alloc) -{ - if (format_length && - !parse_datetime_formats(format_type, format_str, - format_length, - datetime_format->dt_pos)) - { - if (is_alloc) - { - if (!(datetime_format->format= my_strdup_with_length(format_str, - format_length, - MYF(0)))) - return 0; - } - else - datetime_format->format= (char *) format_str; - datetime_format->format_length= format_length; - return datetime_format; - } - return 0; -} +/* + Parse a format string specification + SYNOPSIS + parse_date_time_format() + format_type Format of string (time, date or datetime) + format_str String to parse + format_length Length of string + date_time_format Format to fill in + + NOTES + Fills in date_time_format->positions for all date time parts. + + positions marks the position for a datetime element in the format string. + The position array elements are in the following order: + YYYY-DD-MM HH-MM-DD.FFFFFF AM + 0 1 2 3 4 5 6 7 + + If positions[0]= 5, it means that year will be the forth element to + read from the parsed date string. + + RETURN + 0 ok + 1 error +*/ -bool parse_datetime_formats(datetime_format_types format_type, - const char *format_str, uint format_length, - byte *dt_pos) +bool parse_date_time_format(timestamp_type format_type, + const char *format, uint format_length, + DATE_TIME_FORMAT *date_time_format) { - uint pos= 0; - dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]= - dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= -1; + uint offset= 0, separators= 0; + const char *ptr= format, *format_str; + const char *end= ptr+format_length; + uchar *dt_pos= date_time_format->positions; + /* need_p is set if we are using AM/PM format */ + bool need_p= 0, allow_separator= 0; + ulong part_map= 0, separator_map= 0; + const char *parts[16]; + + date_time_format->time_separator= 0; + date_time_format->flag= 0; // For future - const char *ptr=format_str; - const char *end=ptr+format_length; - bool need_p= 0; + /* + Fill position with 'dummy' arguments to found out if a format tag is + used twice (This limit's the format to 255 characters, but this is ok) + */ + dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]= + dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= 255; for (; ptr != end; ptr++) { if (*ptr == '%' && ptr+1 != end) { + uint position; + LINT_INIT(position); switch (*++ptr) { - case 'y': + case 'y': // Year case 'Y': - if (dt_pos[0] > -1) - return 1; - dt_pos[0]= pos; + position= 0; break; - case 'c': + case 'c': // Month case 'm': - if (dt_pos[1] > -1) - return 1; - dt_pos[1]= pos; + position= 1; break; case 'd': case 'e': - if (dt_pos[2] > -1) - return 1; - dt_pos[2]= pos; + position= 2; break; - case 'H': - case 'k': case 'h': case 'I': case 'l': - if (dt_pos[3] > -1) - return 1; - dt_pos[3]= pos; - need_p= (*ptr == 'h' || *ptr == 'l' || *ptr == 'I'); + need_p= 1; // Need AM/PM + /* Fall through */ + case 'k': + case 'H': + position= 3; break; case 'i': - if (dt_pos[4] > -1) - return 1; - dt_pos[4]= pos; + position= 4; break; case 's': case 'S': - if (dt_pos[5] > -1) - return 1; - dt_pos[5]= pos; + position= 5; + break; + case 'f': + position= 6; + if (dt_pos[5] != offset-1 || ptr[-2] != '.') + return 1; // Wrong usage of %f break; - case 'p': - if (dt_pos[6] > -1) - return 1; - /* %p should be last in format string */ - if (format_type == DATE_FORMAT_TYPE || - (pos != 6 && format_type == DATETIME_FORMAT_TYPE) || - (pos != 3 && format_type == TIME_FORMAT_TYPE)) - return 1; - dt_pos[6]= 1; + case 'p': // AM/PM + if (offset == 0) // Can't be first + return 0; + position= 7; break; default: - return 1; + return 1; // Unknown controll char } - if (dt_pos[6] == -1) - pos++; + if (dt_pos[position] != 255) // Don't allow same tag twice + return 1; + parts[position]= ptr-1; + + /* + If switching from time to date, ensure that all time parts + are used + */ + if (part_map && position <= 2 && !(part_map & (1 | 2 | 4))) + offset=5; + part_map|= (ulong) 1 << position; + dt_pos[position]= offset++; + allow_separator= 1; + } + else + { + /* + Don't allow any characters in format as this could easily confuse + the date reader + */ + if (!allow_separator) + return 1; // No separator here + allow_separator= 0; // Don't allow two separators + separators++; + /* Store in separator_map which parts are punct characters */ + if (my_ispunct(&my_charset_latin1, *ptr)) + separator_map|= (ulong) 1 << (offset-1); + else if (!my_isspace(&my_charset_latin1, *ptr)) + return 1; } } - if (pos > 5 && format_type == DATETIME_FORMAT_TYPE && - (dt_pos[0] + dt_pos[1] + dt_pos[2] + - dt_pos[3] + dt_pos[4] + dt_pos[5] != 15) || - pos > 2 && format_type == DATE_FORMAT_TYPE && - (dt_pos[0] + dt_pos[1] + dt_pos[2] != 3) || - pos > 2 && format_type == TIME_FORMAT_TYPE && - (dt_pos[3] + dt_pos[4] + dt_pos[5] != 3) || - (need_p && dt_pos[6] != 1)) - return 1; + /* If no %f, specify it after seconds. Move %p up, if necessary */ + if ((part_map & 32) && !(part_map & 64)) + { + dt_pos[6]= dt_pos[5] +1; + parts[6]= parts[5]; // For later test in (need_p) + if (dt_pos[6] == dt_pos[7]) // Move %p one step up if used + dt_pos[7]++; + } /* - Check for valid separators between date/time parst + Check that we have not used a non legal format specifier and that all + format specifiers have been used + + The last test is to ensure that %p is used if and only if + it's needed. */ - uint tmp_len= format_length; - if (dt_pos[6] == 1) + if ((format_type == TIMESTAMP_DATETIME && + !test_all_bits(part_map, (1 | 2 | 4 | 8 | 16 | 32))) || + (format_type == TIMESTAMP_DATE && part_map != (1 | 2 | 4)) || + (format_type == TIMESTAMP_TIME && + !test_all_bits(part_map, 8 | 16 | 32)) || + !allow_separator || // %option should be last + (need_p && dt_pos[6] +1 != dt_pos[7]) || + (need_p ^ (dt_pos[7] != 255))) + return 1; + + if (dt_pos[6] != 255) // If fractional seconds { - end= end - 2; - if (my_ispunct(&my_charset_latin1, *end) || my_isspace(&my_charset_latin1, *end)) - end--; - tmp_len= end - format_str; + /* remove fractional seconds from later tests */ + uint pos= dt_pos[6] -1; + /* Remove separator before %f from sep map */ + separator_map= ((separator_map & ((ulong) (1 << pos)-1)) | + ((separator_map & ~((ulong) (1 << pos)-1)) >> 1)); + if (part_map & 64) + { + separators--; // There is always a separator + need_p= 1; // force use of separators + } } + + /* + Remove possible separator before %p from sep_map + (This can either be at position 3, 4, 6 or 7) h.m.d.%f %p + */ + if (dt_pos[7] != 255) + { + if (need_p && parts[7] != parts[6]+2) + separators--; + } + /* + Calculate if %p is in first or last part of the datetime field + + At this point we have either %H-%i-%s %p 'year parts' or + 'year parts' &H-%i-%s %p" as %f was removed above + */ + offset= dt_pos[6] <= 3 ? 3 : 6; + /* Remove separator before %p from sep map */ + separator_map= ((separator_map & ((ulong) (1 << offset)-1)) | + ((separator_map & ~((ulong) (1 << offset)-1)) >> 1)); + + format_str= 0; switch (format_type) { - case DATE_FORMAT_TYPE: - case TIME_FORMAT_TYPE: - if ((tmp_len == 6 && - !my_strnncoll(&my_charset_bin, - (const uchar *) format_str, 6, - (const uchar *) datetime_formats - [format_type][INTERNAL_FORMAT], 6)) || - tmp_len == 8 && - my_ispunct(&my_charset_latin1, *(format_str+2)) && - my_ispunct(&my_charset_latin1, *(format_str+5))) + case TIMESTAMP_DATE: + format_str= known_date_time_formats[INTERNAL_FORMAT].date_format; + /* fall through */ + case TIMESTAMP_TIME: + if (!format_str) + format_str=known_date_time_formats[INTERNAL_FORMAT].time_format; + + /* + If there is no separators, allow the internal format as we can read + this. If separators are used, they must be between each part + */ + if (format_length == 6 && !need_p && + !my_strnncoll(&my_charset_bin, + (const uchar *) format, 6, + (const uchar *) format_str, 6)) + return 0; + if (separator_map == (1 | 2)) { - if (format_type == TIME_FORMAT_TYPE && tmp_len == 8) + if (format_type == TIMESTAMP_TIME) { - if (*(format_str+2) != *(format_str+5)) - return 1; - dt_pos[7]= *(format_str+2); + if (*(format+2) != *(format+5)) + break; // Error + /* Store the character used for time formats */ + date_time_format->time_separator= *(format+2); } return 0; } break; - case DATETIME_FORMAT_TYPE: - if ((tmp_len == 12 && + case TIMESTAMP_DATETIME: + /* + If there is no separators, allow the internal format as we can read + this. If separators are used, they must be between each part. + Between DATE and TIME we also allow space as separator + */ + if ((format_length == 12 && !need_p && !my_strnncoll(&my_charset_bin, - (const uchar *) format_str, 12, - (const uchar *) datetime_formats - [DATETIME_FORMAT_TYPE][INTERNAL_FORMAT], 12)) || - tmp_len == 17 && - my_ispunct(&my_charset_latin1, *(format_str+2)) && - my_ispunct(&my_charset_latin1, *(format_str+5)) && - my_ispunct(&my_charset_latin1, *(format_str+11)) && - my_ispunct(&my_charset_latin1, *(format_str+14)) && - (my_ispunct(&my_charset_latin1, *(format_str+8)) || - my_isspace(&my_charset_latin1, *(format_str+8)))) + (const uchar *) format, 12, + (const uchar*) known_date_time_formats[INTERNAL_FORMAT].datetime_format, + 12)) || + (separators == 5 && separator_map == (1 | 2 | 8 | 16))) return 0; break; - } - return 1; + default: + DBUG_ASSERT(1); + break; + } + return 1; // Error +} + + +/* + Create a DATE_TIME_FORMAT object from a format string specification + + SYNOPSIS + date_time_format_make() + format_type Format to parse (time, date or datetime) + format_str String to parse + format_length Length of string + + NOTES + The returned object should be freed with my_free() + + RETURN + NULL ponter: Error + new object +*/ + +DATE_TIME_FORMAT +*date_time_format_make(timestamp_type format_type, + const char *format_str, uint format_length) +{ + DATE_TIME_FORMAT tmp; + + if (format_length && format_length < 255 && + !parse_date_time_format(format_type, format_str, + format_length, &tmp)) + { + tmp.format.str= (char*) format_str; + tmp.format.length= format_length; + return date_time_format_copy((THD *)0, &tmp); + } + return 0; +} + + +/* + Create a copy of a DATE_TIME_FORMAT object + + SYNOPSIS + date_and_time_format_copy() + thd Set if variable should be allocated in thread mem + format format to copy + + NOTES + The returned object should be freed with my_free() + + RETURN + NULL ponter: Error + new object +*/ + +DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format) +{ + DATE_TIME_FORMAT *new_format; + ulong length= sizeof(*format) + format->format.length + 1; + + if (thd) + new_format= (DATE_TIME_FORMAT *) thd->alloc(length); + else + new_format= (DATE_TIME_FORMAT *) my_malloc(length, MYF(MY_WME)); + if (new_format) + { + /* Put format string after current pos */ + new_format->format.str= (char*) (new_format+1); + memcpy((char*) new_format->positions, (char*) format->positions, + sizeof(format->positions)); + new_format->time_separator= format->time_separator; + /* We make the string null terminated for easy printf in SHOW VARIABLES */ + memcpy((char*) new_format->format.str, format->format.str, + format->format.length); + new_format->format.str[format->format.length]= 0; + new_format->format.length= format->format.length; + } + return new_format; +} + + +KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]= +{ + {"USA", "%m.%d.%Y", "%Y-%m-%d %H.%i.%s", "%h:%i:%s %p" }, + {"JIS", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" }, + {"ISO", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" }, + {"EUR", "%d.%m.%Y", "%Y-%m-%d %H.%i.%s", "%H.%i.%s" }, + {"INTERNAL", "%Y%m%d", "%Y%m%d%H%i%s", "%H%i%s" }, + { 0, 0, 0, 0 } +}; + + +/* + Return format string according format name. + If name is unknown, result is NULL +*/ + +const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, + timestamp_type type) +{ + switch (type) { + case TIMESTAMP_DATE: + return format->date_format; + case TIMESTAMP_DATETIME: + return format->datetime_format; + case TIMESTAMP_TIME: + return format->time_format; + default: + DBUG_ASSERT(0); // Impossible + return 0; + } +} + +/**************************************************************************** + Functions to create default time/date/datetime strings + + NOTE: + For the moment the DATE_TIME_FORMAT argument is ignored becasue + MySQL doesn't support comparing of date/time/datetime strings that + are not in arbutary order as dates are compared as strings in some + context) +****************************************************************************/ + +void make_time(DATE_TIME_FORMAT *format, TIME *l_time, String *str) +{ + long length= my_sprintf((char*) str->ptr(), + ((char*) str->ptr(), + "%s%02d:%02d:%02d", + (l_time->neg ? "-" : ""), + l_time->hour, + l_time->minute, + l_time->second)); + str->length(length); + str->set_charset(&my_charset_bin); +} + + +void make_date(DATE_TIME_FORMAT *format, TIME *l_time, String *str) +{ + long length= my_sprintf((char*) str->ptr(), + ((char*) str->ptr(), + "%04d-%02d-%02d", + l_time->year, + l_time->month, + l_time->day)); + str->length(length); + str->set_charset(&my_charset_bin); +} + + +void make_datetime(DATE_TIME_FORMAT *format, TIME *l_time, String *str) +{ + long length= my_sprintf((char*) str->ptr(), + ((char*) str->ptr(), + "%04d-%02d-%02d %02d:%02d:%02d", + l_time->year, + l_time->month, + l_time->day, + l_time->hour, + l_time->minute, + l_time->second)); + str->length(length); + str->set_charset(&my_charset_bin); } diff --git a/sql/unireg.h b/sql/unireg.h index ef6a2f44ea7..66a274f3863 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -63,6 +63,10 @@ /* Max column width +1 */ #define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1) +#define MAX_DATE_WIDTH 10 /* YYYY-MM-DD */ +#define MAX_TIME_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */ +#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */ +#define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */ #define MAX_TABLES (sizeof(table_map)*8-2) /* Max tables in join */ #define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2)) |