diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/event_parse_data.cc | 12 | ||||
-rw-r--r-- | sql/field.cc | 112 | ||||
-rw-r--r-- | sql/field.h | 3 | ||||
-rw-r--r-- | sql/item.cc | 71 | ||||
-rw-r--r-- | sql/item.h | 6 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 93 | ||||
-rw-r--r-- | sql/item_create.cc | 117 | ||||
-rw-r--r-- | sql/item_func.cc | 71 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 124 | ||||
-rw-r--r-- | sql/item_timefunc.h | 94 | ||||
-rw-r--r-- | sql/log_event.cc | 4 | ||||
-rw-r--r-- | sql/mysql_priv.h | 32 | ||||
-rw-r--r-- | sql/set_var.cc | 2 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 4 | ||||
-rw-r--r-- | sql/sql_class.cc | 3 | ||||
-rw-r--r-- | sql/sql_string.cc | 2 | ||||
-rw-r--r-- | sql/sql_string.h | 2 | ||||
-rw-r--r-- | sql/time.cc | 29 |
18 files changed, 379 insertions, 402 deletions
diff --git a/sql/event_parse_data.cc b/sql/event_parse_data.cc index 04416232eb4..4555da44f18 100644 --- a/sql/event_parse_data.cc +++ b/sql/event_parse_data.cc @@ -198,7 +198,7 @@ Event_parse_data::check_dates(THD *thd, int previous_on_completion) int Event_parse_data::init_execute_at(THD *thd) { - my_bool not_used; + uint not_used; MYSQL_TIME ltime; my_time_t ltime_utc; @@ -215,7 +215,7 @@ Event_parse_data::init_execute_at(THD *thd) (starts_null && ends_null))); DBUG_ASSERT(starts_null && ends_null); - if ((not_used= item_execute_at->get_date(<ime, TIME_NO_ZERO_DATE))) + if (item_execute_at->get_date(<ime, TIME_NO_ZERO_DATE)) goto wrong_value; ltime_utc= TIME_to_timestamp(thd,<ime,¬_used); @@ -368,7 +368,7 @@ wrong_value: int Event_parse_data::init_starts(THD *thd) { - my_bool not_used; + uint not_used; MYSQL_TIME ltime; my_time_t ltime_utc; @@ -379,7 +379,7 @@ Event_parse_data::init_starts(THD *thd) if (item_starts->fix_fields(thd, &item_starts)) goto wrong_value; - if ((not_used= item_starts->get_date(<ime, TIME_NO_ZERO_DATE))) + if (item_starts->get_date(<ime, TIME_NO_ZERO_DATE)) goto wrong_value; ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used); @@ -422,7 +422,7 @@ wrong_value: int Event_parse_data::init_ends(THD *thd) { - my_bool not_used; + uint not_used; MYSQL_TIME ltime; my_time_t ltime_utc; @@ -434,7 +434,7 @@ Event_parse_data::init_ends(THD *thd) goto error_bad_params; DBUG_PRINT("info", ("convert to TIME")); - if ((not_used= item_ends->get_date(<ime, TIME_NO_ZERO_DATE))) + if (item_ends->get_date(<ime, TIME_NO_ZERO_DATE)) goto error_bad_params; ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used); diff --git a/sql/field.cc b/sql/field.cc index 731aaea4659..7e0d99bc9f5 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -47,6 +47,17 @@ template class List<Create_field>; template class List_iterator<Create_field>; #endif +static const char *zero_timestamp="0000-00-00 00:00:00.000000"; + +/* number of bytes to store second_part part of the TIMESTAMP(N) */ +static uint sec_part_bytes[MAX_DATETIME_PRECISION+1]= { 0, 1, 1, 2, 2, 3, 3 }; + +/* number of bytes to store DATETIME(N) */ +static uint datetime_hires_bytes[MAX_DATETIME_PRECISION+1]= { 5, 6, 6, 7, 7, 7, 8 }; + +/* number of bytes to store TIME(N) */ +static uint time_hires_bytes[MAX_DATETIME_PRECISION+1]= { 3, 4, 4, 5, 5, 5, 6 }; + uchar Field_null::null[1]={1}; const char field_separator=','; @@ -4693,6 +4704,7 @@ long Field_timestamp::get_timestamp(ulong *sec_part) const return tmp; } + int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, const Lazy_string *str, bool was_cut, bool have_smth_to_conv) @@ -4700,7 +4712,6 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, ASSERT_COLUMN_MARKED_FOR_WRITE; uint error = 0; my_time_t timestamp; - my_bool in_dst_time_gap; if (was_cut || !have_smth_to_conv) { @@ -4708,19 +4719,14 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, str, MYSQL_TIMESTAMP_DATETIME, 1); } + /* Only convert a correct date (not a zero date) */ if (have_smth_to_conv && l_time->month) { - if (!(timestamp= TIME_to_timestamp(thd, l_time, &in_dst_time_gap))) - { - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, - str, MYSQL_TIMESTAMP_DATETIME, !error); - error= 1; - } - else if (in_dst_time_gap) + uint conversion_error; + timestamp= TIME_to_timestamp(thd, l_time, &conversion_error); + if (conversion_error) { - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_INVALID_TIMESTAMP, + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, conversion_error, str, MYSQL_TIMESTAMP_DATETIME, !error); error= 1; } @@ -4736,7 +4742,7 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, int Field_timestamp::store_time(MYSQL_TIME *ltime,timestamp_type time_type) { - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; int unused; MYSQL_TIME l_time= *ltime; Lazy_string_time str(ltime); @@ -4753,7 +4759,7 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) int error; int have_smth_to_conv; Lazy_string_str str(from, len); - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */ have_smth_to_conv= (str_to_datetime(from, len, &l_time, @@ -4769,16 +4775,18 @@ int Field_timestamp::store(double nr) { MYSQL_TIME l_time; int error; - Lazy_string_dbl str(nr); - THD *thd= table ? table->in_use : current_thd; + Lazy_string_double str(nr); + THD *thd= table->in_use; /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */ + if (nr < 0 || nr > LONGLONG_MAX) + nr= LONGLONG_MAX; longlong tmp= number_to_datetime((longlong) floor(nr), &l_time, (thd->variables.sql_mode & MODE_NO_ZERO_DATE) | MODE_NO_ZERO_IN_DATE, &error); - l_time.second_part= (ulong)((nr-floor(nr))*1e6); - return store_TIME_with_warning(thd, &l_time, &str, error, tmp != LL(-1)); + l_time.second_part= (ulong)((nr-floor(nr))*TIME_SECOND_PART_FACTOR); + return store_TIME_with_warning(thd, &l_time, &str, error, tmp != -1); } @@ -4787,7 +4795,7 @@ int Field_timestamp::store(longlong nr, bool unsigned_val) MYSQL_TIME l_time; int error; Lazy_string_num str(nr); - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */ longlong tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode & @@ -4804,12 +4812,17 @@ double Field_timestamp::val_real(void) longlong Field_timestamp::val_int(void) { MYSQL_TIME time_tmp; - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; thd->time_zone_used= 1; ulong sec_part; uint32 temp= get_timestamp(&sec_part); + /* + Field_timestamp() and Field_timestamp_hres() shares this code. + This is why are also testing sec_part below. + */ + if (temp == 0 && sec_part == 0) return(0); @@ -4820,11 +4833,10 @@ longlong Field_timestamp::val_int(void) time_tmp.minute * 100 + time_tmp.second; } -static const char *zero_timestamp="0000-00-00 00:00:00.000000"; String *Field_timestamp::val_str(String *val_buffer, String *val_ptr) { uint32 temp2; - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; MYSQL_TIME time_tmp; char *to; @@ -4891,7 +4903,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr) bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate) { - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; thd->time_zone_used= 1; ulong sec_part; uint32 temp= get_timestamp(&sec_part); @@ -4961,7 +4973,7 @@ void Field_timestamp::sql_type(String &res) const int Field_timestamp::set_time() { - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; set_notnull(); store_TIME(thd->query_start(), 0); return 0; @@ -5052,12 +5064,6 @@ static longlong read_bigendian(const uchar *from, uint bytes) } } -static uint sec_part_bytes[MAX_DATETIME_PRECISION+1]= { 0, 1, 1, 2, 2, 3, 3 }; -static uint datetime_hires_bytes[MAX_DATETIME_PRECISION+1]= -{ 5, 6, 6, 7, 7, 7, 8 }; -static uint time_hires_bytes[MAX_DATETIME_PRECISION+1]= -{ 3, 4, 4, 5, 5, 5, 6 }; - void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) { mi_int4store(ptr, timestamp); @@ -5074,7 +5080,7 @@ long Field_timestamp_hires::get_timestamp(ulong *sec_part) const double Field_timestamp_hires::val_real(void) { MYSQL_TIME time_tmp; - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; thd->time_zone_used= 1; ulong sec_part; @@ -5119,7 +5125,7 @@ int Field_timestamp_hires::store_decimal(const my_decimal *d) int Field_timestamp_hires::set_time() { - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; set_notnull(); store_TIME(thd->query_start(), thd->query_start_sec_part()); return 0; @@ -5238,7 +5244,7 @@ int Field_temporal::store(const char *from,uint len,CHARSET_INFO *cs) MYSQL_TIME ltime; int error; enum enum_mysql_timestamp_type func_res; - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; Lazy_string_str str(from, len); func_res= str_to_datetime(from, len, <ime, @@ -5255,22 +5261,18 @@ int Field_temporal::store(double nr) { int error= 0; MYSQL_TIME ltime; - longlong tmp; - THD *thd= table ? table->in_use : current_thd; - Lazy_string_dbl str(nr); + THD *thd= table->in_use; + Lazy_string_double str(nr); - if (nr < 0.0 || nr > 99991231235959.0) - { - tmp= -1; - error= 1; - } - else - tmp= number_to_datetime((longlong) floor(nr), <ime, (TIME_FUZZY_DATE | - (thd->variables.sql_mode & - (MODE_NO_ZERO_IN_DATE | - MODE_NO_ZERO_DATE | - MODE_INVALID_DATES))), &error); - ltime.second_part= (ulong)((nr-floor(nr))*1e6); + if (nr < 0 || nr > LONGLONG_MAX) + nr= LONGLONG_MAX; + longlong tmp= number_to_datetime((longlong) floor(nr), <ime, + (TIME_FUZZY_DATE | + (thd->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | + MODE_NO_ZERO_DATE | + MODE_INVALID_DATES))), &error); + ltime.second_part= (ulong)((nr-floor(nr))*TIME_SECOND_PART_FACTOR); return store_TIME_with_warning(<ime, &str, error, tmp != -1); } @@ -5280,7 +5282,7 @@ int Field_temporal::store(longlong nr, bool unsigned_val) int error; MYSQL_TIME ltime; longlong tmp; - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; Lazy_string_num str(nr); tmp= number_to_datetime(nr, <ime, (TIME_FUZZY_DATE | @@ -5340,8 +5342,8 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) MYSQL_TIME ltime; Lazy_string_str str(from, len); int was_cut; - int have_smth_to_conv= str_to_datetime(from, len, <ime, TIME_TIME_ONLY, - &was_cut) > MYSQL_TIMESTAMP_ERROR; + int have_smth_to_conv= + str_to_time(from, len, <ime, &was_cut) > MYSQL_TIMESTAMP_ERROR; return store_TIME_with_warning(<ime, &str, was_cut, have_smth_to_conv); } @@ -5361,7 +5363,7 @@ int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type) int Field_time::store(double nr) { MYSQL_TIME ltime; - Lazy_string_dbl str(nr); + Lazy_string_double str(nr); int was_cut; int have_smth_to_conv= !number_to_time(nr, <ime, &was_cut); @@ -5405,7 +5407,6 @@ String *Field_time::val_str(String *val_buffer, { ASSERT_COLUMN_MARKED_FOR_READ; MYSQL_TIME ltime; - val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH); long tmp=(long) sint3korr(ptr); ltime.neg= 0; if (tmp < 0) @@ -5432,7 +5433,7 @@ String *Field_time::val_str(String *val_buffer, bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate) { - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; if (!(fuzzydate & (TIME_FUZZY_DATE|TIME_TIME_ONLY))) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, @@ -5751,7 +5752,6 @@ String *Field_date::val_str(String *val_buffer, { ASSERT_COLUMN_MARKED_FOR_READ; MYSQL_TIME ltime; - val_buffer->alloc(field_length); int32 tmp; if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) tmp=sint4korr(ptr); @@ -10085,7 +10085,7 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code, If this field was created only for type conversion purposes it will have table == NULL. */ - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; if (thd->count_cuted_fields) { thd->cuted_fields+= cuted_increment; @@ -10119,7 +10119,7 @@ void Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, const Lazy_string *str, timestamp_type ts_type, int cuted_increment) { - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; if ((thd->really_abort_on_warning() && level >= MYSQL_ERROR::WARN_LEVEL_WARN) || set_warning(level, code, cuted_increment)) diff --git a/sql/field.h b/sql/field.h index 75cf3858e6f..6361636771e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -149,7 +149,6 @@ public: virtual bool str_needs_quotes() { return FALSE; } virtual Item_result result_type () const=0; virtual Item_result cmp_type () const { return result_type(); } - virtual Item_result cast_to_int_type () const { return cmp_type(); } static bool type_can_have_key_part(enum_field_types); static enum_field_types field_type_merge(enum_field_types, enum_field_types); static Item_result result_merge_type(enum_field_types); @@ -1437,7 +1436,6 @@ public: {} enum_field_types type() const { return MYSQL_TYPE_DATETIME;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } - enum Item_result cmp_type () const { return TIME_RESULT; } uint decimals() const { return 0; } double val_real(void); longlong val_int(void); @@ -1934,7 +1932,6 @@ public: Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type); enum_field_types type() const { return MYSQL_TYPE_STRING; } enum Item_result cmp_type () const { return INT_RESULT; } - enum Item_result cast_to_int_type () const { return INT_RESULT; } enum ha_base_keytype key_type() const; int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); diff --git a/sql/item.cc b/sql/item.cc index 997ce821f9a..fd0be90c216 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -194,10 +194,11 @@ bool Item::val_bool() case STRING_RESULT: return val_real() != 0.0; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); return 0; // Wrong (but safe) } + return 0; // Wrong (but safe) } @@ -472,18 +473,17 @@ void Item::print_value(String *str) { switch (result_type()) { - default: - DBUG_ASSERT(0); case STRING_RESULT: - str->append('\''); - str->append(*ptr); - str->append('\''); + append_unescaped(str, ptr->ptr(), ptr->length()); break; case DECIMAL_RESULT: case REAL_RESULT: case INT_RESULT: str->append(*ptr); break; + case ROW_RESULT: + case TIME_RESULT: + DBUG_ASSERT(0); } } } @@ -533,7 +533,7 @@ void Item::rename(char *new_name) Item_result Item::cmp_type() const { - switch(field_type()) { + switch (field_type()) { case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: return DECIMAL_RESULT; @@ -1020,7 +1020,7 @@ err: bool Item::get_time(MYSQL_TIME *ltime) { - return get_date(ltime, TIME_TIME_ONLY); + return get_date(ltime, TIME_TIME_ONLY | TIME_FUZZY_DATE); } CHARSET_INFO *Item::default_charset() @@ -2187,10 +2187,11 @@ bool Item_field::val_bool_result() case STRING_RESULT: return result_field->val_real() != 0.0; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); return 0; // Shut up compiler } + return 0; } @@ -2748,8 +2749,6 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type, value.time= *tm; value.time.time_type= time_type; - decimals= value.time.second_part > 0 ? TIME_SECOND_PART_DIGITS : 0; - if (value.time.year > 9999 || value.time.month > 12 || value.time.day > 31 || (time_type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23) || @@ -2765,6 +2764,7 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type, state= TIME_VALUE; maybe_null= 0; max_length= max_length_arg; + decimals= tm->second_part > 0 ? TIME_SECOND_PART_DIGITS : 0; DBUG_VOID_RETURN; } @@ -2888,7 +2888,8 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) param_type= MYSQL_TYPE_NEWDECIMAL; break; } - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(0); set_null(); } @@ -3355,7 +3356,8 @@ Item_copy *Item_copy::create (Item *item) new Item_copy_uint (item) : new Item_copy_int (item); case DECIMAL_RESULT: return new Item_copy_decimal (item); - default: + case TIME_RESULT: + case ROW_RESULT: DBUG_ASSERT (0); } /* should not happen */ @@ -4810,10 +4812,11 @@ enum_field_types Item::field_type() const case DECIMAL_RESULT: return MYSQL_TYPE_NEWDECIMAL; case REAL_RESULT: return MYSQL_TYPE_DOUBLE; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); return MYSQL_TYPE_VARCHAR; } + return MYSQL_TYPE_VARCHAR; } @@ -6232,7 +6235,7 @@ bool Item_ref::val_bool_result() case STRING_RESULT: return result_field->val_real() != 0.0; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); } } @@ -6885,6 +6888,7 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) { bool is_null; Item **ref_copy= ref; + /* the following call creates a constant and puts it in new_item */ get_datetime_value(thd, &ref_copy, &new_item, comp_item, &is_null); if (is_null) new_item= new Item_null(name); @@ -6964,8 +6968,6 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) (Item*) new Item_decimal(name, result, length, decimals)); break; } - default: - DBUG_ASSERT(0); } if (new_item) thd->change_item_tree(ref, new_item); @@ -7045,20 +7047,24 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) field_val= field->val_decimal(&field_buf); return my_decimal_cmp(item_val, field_val); } + /* + We have to check field->cmp_type() instead of res_type, + as result_type() - and thus res_type - can never be TIME_RESULT (yet). + */ if (field->cmp_type() == TIME_RESULT) { - MYSQL_TIME field_time, item_time; - if (field->type() == MYSQL_TYPE_TIME) - { - field->get_time(&field_time); - item->get_time(&item_time); - } - else - { - field->get_date(&field_time, TIME_FUZZY_DATE | TIME_INVALID_DATES); - item->get_date(&item_time, TIME_FUZZY_DATE | TIME_INVALID_DATES); - } - return my_time_compare(&field_time, &item_time); + MYSQL_TIME field_time, item_time; + if (field->type() == MYSQL_TYPE_TIME) + { + field->get_time(&field_time); + item->get_time(&item_time); + } + else + { + field->get_date(&field_time, TIME_FUZZY_DATE | TIME_INVALID_DATES); + item->get_date(&item_time, TIME_FUZZY_DATE | TIME_INVALID_DATES); + } + return my_time_compare(&field_time, &item_time); } double result= item->val_real(); if (item->null_value) @@ -7101,11 +7107,8 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type) return new Item_cache_row(); case TIME_RESULT: return new Item_cache_int(MYSQL_TYPE_DATETIME); - default: - // should never be in real life - DBUG_ASSERT(0); - return 0; } + return 0; } void Item_cache::store(Item *item) @@ -7614,7 +7617,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item) case DECIMAL_RESULT: return MYSQL_TYPE_NEWDECIMAL; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); return MYSQL_TYPE_VAR_STRING; } diff --git a/sql/item.h b/sql/item.h index 275b876f521..3be654abdd8 100644 --- a/sql/item.h +++ b/sql/item.h @@ -568,7 +568,9 @@ public: { return save_in_field(field, 1); } virtual bool send(Protocol *protocol, String *str); virtual bool eq(const Item *, bool binary_cmp) const; + /* result_type() of an item specifies how the value should be returned */ virtual Item_result result_type() const { return REAL_RESULT; } + /* ... while cmp_type() specifies how it should be compared */ virtual Item_result cmp_type() const; virtual Item_result cast_to_int_type() const { return cmp_type(); } virtual enum_field_types string_field_type() const; @@ -731,6 +733,8 @@ public: /* This is also used to create fields in CREATE ... SELECT: */ virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } virtual const char *full_name() const { return name ? name : "???"; } + const char *field_name_or_null() + { return real_item()->type() == Item::FIELD_ITEM ? name : NULL; } /* *result* family of methods is analog of *val* family (see above) but @@ -1492,7 +1496,7 @@ public: } Item_result cast_to_int_type() const { - return field->cast_to_int_type(); + return field->cmp_type(); } enum_field_types field_type() const { diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index e7418c2a53a..e99835083a6 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -614,8 +614,6 @@ int Arg_comparator::set_compare_func(Item_result_field *item, Item_result type) } break; } - default: - DBUG_ASSERT(0); } return 0; } @@ -708,6 +706,18 @@ static ulonglong get_date_from_str(THD *thd, String *str, return pack_time(&l_time); } +/** + Prepare the comparator (set the comparison function) for comparing + items *a1 and *a2 in the context of 'type'. + + @param[in] owner_arg Item, peforming the comparison (e.g. Item_func_eq) + @param[in,out] a1 first argument to compare + @param[in,out] a2 second argument to compare + @param[in] type type context to compare in + + Both *a1 and *a2 can be replaced by this method - typically by constant + items, holding the cached converted value of the original (constant) item. +*/ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, Item **a1, Item **a2, @@ -791,19 +801,16 @@ void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg, func= comparator_matrix[TIME_RESULT][is_owner_equal_func()]; } - -/* +/** Retrieves correct DATETIME value from given item. - SYNOPSIS - get_datetime_value() - thd thread handle - item_arg [in/out] item to retrieve DATETIME value from - cache_arg [in/out] pointer to place to store the caching item to - warn_item [in] item for issuing the conversion warning - is_null [out] TRUE <=> the item_arg is null + @param[in] thd thread handle + @param[in,out] item_arg item to retrieve DATETIME value from + @param[in,out] cache_arg pointer to place to store the caching item to + @param[in] warn_item item for issuing the conversion warning + @param[out] is_null TRUE <=> the item_arg is null - DESCRIPTION + @details Retrieves the correct DATETIME value from given item for comparison by the compare_datetime() function. @@ -818,7 +825,10 @@ void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg, depending on the other operand (when comparing a string with a date, it's parsed as a date, when comparing a string with a time it's parsed as a time) - RETURN + If the item is a constant it is replaced by the Item_cache_int, that + holds the packed datetime value. + + @return MYSQL_TIME value, packed in a longlong, suitable for comparison. */ @@ -829,16 +839,15 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, longlong UNINIT_VAR(value); Item *item= **item_arg; enum_field_types f_type= warn_item->field_type(); - timestamp_type t_type= - f_type == MYSQL_TYPE_DATE ? MYSQL_TIMESTAMP_DATE : - f_type == MYSQL_TYPE_TIME ? MYSQL_TIMESTAMP_TIME : - MYSQL_TIMESTAMP_DATETIME; switch (item->cmp_type()) { case TIME_RESULT: /* if it's our Item_cache_int, as created below, we simply use the value */ if (item->result_type() == INT_RESULT) + { value= item->val_int(); + cache_arg= 0; + } else { MYSQL_TIME buf; @@ -872,7 +881,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, int was_cut; longlong res; - if (t_type == MYSQL_TIMESTAMP_TIME) + if (f_type == MYSQL_TYPE_TIME) res= number_to_time((double)value, &buf, &was_cut); else res= number_to_datetime(value, &buf, TIME_INVALID_DATES|TIME_FUZZY_DATE, @@ -880,8 +889,9 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, if (res == -1) { const Lazy_string_num str(value); - make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - &str, t_type, warn_item->name); + make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, &str, + mysql_type_to_time_type(f_type), + warn_item->field_name_or_null()); value= 0; } else @@ -903,7 +913,10 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, some insignificant zeros. */ bool error; - value= (longlong) get_date_from_str(thd, str, t_type, warn_item->name, &error); + value= (longlong) get_date_from_str(thd, str, + mysql_type_to_time_type(f_type), + warn_item->field_name_or_null(), + &error); /* If str did not contain a valid date according to the current SQL_MODE, get_date_from_str() has already thrown a warning, @@ -913,12 +926,23 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, } break; } - default: DBUG_ASSERT(0); + case ROW_RESULT: + DBUG_ASSERT(0); } if ((*is_null= item->null_value)) return ~(ulonglong) 0; - if (cache_arg && item->const_item() && item->type() != Item::CACHE_ITEM) + if (cache_arg && item->const_item()) { + /* + cache the packed datetime value in the Item_cache object. + Because the packed datetime value is longlong, we use Item_cache_int, + and it has result_type() == INT_RESULT. + But we create it to have field_type() == MYSQL_TYPE_TIME (or + MYSQL_TIMESTAMP_DATE or MYSQL_TYPE_DATETIME), and thus it will have + cmp_type() == TIME_RESULT. + As no other item can have this combination of cmp_type() and result_type(), + it allows us to identify our cache items, see 'case TIME_RESULT:' above. + */ Item_cache_int *cache= new Item_cache_int(f_type); cache->store(item, value); *cache_arg= cache; @@ -976,9 +1000,6 @@ int Arg_comparator::compare_e_datetime() bool a_is_null, b_is_null; longlong a_value, b_value; - if (set_null) - owner->null_value= 0; - /* Get DATE/DATETIME/TIME value of the 'a' item. */ a_value= get_datetime_value(thd, &a, &a_cache, *b, &a_is_null); @@ -1961,10 +1982,9 @@ bool Item_func_between::fix_fields(THD *thd, Item **ref) void Item_func_between::fix_length_and_dec() { + THD *thd= current_thd; max_length= 1; - int i; compare_as_dates= 0; - THD *thd= current_thd; /* As some compare functions are generated after sql_yacc, @@ -1980,7 +2000,7 @@ void Item_func_between::fix_length_and_dec() /* When comparing as date/time, we need to convert non-temporal values - (e.g. strings) to MYSQL_TIME. get_datetime_value() doees it + (e.g. strings) to MYSQL_TIME. get_datetime_value() does it automatically when one of the operands is a date/time. But here we may need to compare two strings as dates (str1 BETWEEN str2 AND date). For this to work, we need to know what date/time type we compare @@ -1988,7 +2008,7 @@ void Item_func_between::fix_length_and_dec() */ if (cmp_type == TIME_RESULT) { - for (i= 0; i < 3; i++) + for (int i= 0; i < 3; i++) { if (args[i]->cmp_type() == TIME_RESULT) { @@ -2149,7 +2169,7 @@ longlong Item_func_between::val_int() } break; } - default: + case ROW_RESULT: DBUG_ASSERT(0); null_value= 1; return 0; @@ -2203,7 +2223,7 @@ Item_func_ifnull::fix_length_and_dec() decimals= 0; break; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); } cached_field_type= agg_field_type(args, 2); @@ -2942,6 +2962,7 @@ void Item_func_coalesce::fix_length_and_dec() agg_result_type(&hybrid_type, args, arg_count); Item_result cmp_type; agg_cmp_type(&cmp_type, args, arg_count); + ///< @todo let result_type() return TIME_RESULT and remove this special case if (cmp_type == TIME_RESULT) { count_real_length(); @@ -2964,7 +2985,7 @@ void Item_func_coalesce::fix_length_and_dec() decimals= 0; break; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); } } @@ -3293,7 +3314,7 @@ cmp_item* cmp_item::get_comparator(Item_result type, return new cmp_item_row; case DECIMAL_RESULT: return new cmp_item_decimal; - default: + case TIME_RESULT: DBUG_ASSERT(0); break; } @@ -3741,9 +3762,9 @@ void Item_func_in::fix_length_and_dec() case DECIMAL_RESULT: array= new in_decimal(arg_count - 1); break; - default: + case TIME_RESULT: DBUG_ASSERT(0); - return; + break; } } if (array && !(thd->is_fatal_error)) // If not EOM diff --git a/sql/item_create.cc b/sql/item_create.cc index abf32543494..3cc875509a0 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -5044,7 +5044,7 @@ find_qualified_function_builder(THD *thd) return & Create_sp_func::s_singleton; } -static inline const char* item_name(Item *a, String *str) +static const char* item_name(Item *a, String *str) { if (a->name) return a->name; @@ -5053,15 +5053,33 @@ static inline const char* item_name(Item *a, String *str) return str->c_ptr_safe(); } -Item * -create_func_cast(THD *thd, Item *a, Cast_target cast_type, - const char *c_len, const char *c_dec, - CHARSET_INFO *cs) +static uint get_number(Item *a, const char *c_len, bool *err, + uint maximum, uint errcode) { - Item *UNINIT_VAR(res); + if (!c_len) + return 0; + + int unused; char buff[1024]; String buf(buff, sizeof(buff), system_charset_info); + ulonglong decoded_size= my_strtoll10(c_len, NULL, &unused); + uint len= min(decoded_size, UINT_MAX32); + + if (decoded_size > maximum) + { + my_error(errcode, MYF(0), len, item_name(a, &buf), maximum); + *err= true; + } + return len; +} + +Item *create_func_cast(THD *thd, Item *a, Cast_target cast_type, + const char *c_len, const char *c_dec, + CHARSET_INFO *cs) +{ + Item *UNINIT_VAR(res); + switch (cast_type) { case ITEM_CAST_BINARY: res= new (thd->mem_root) Item_func_binary(a); @@ -5078,20 +5096,11 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, case ITEM_CAST_TIME: case ITEM_CAST_DATETIME: { - uint len; - if (c_len) - { - errno= 0; - len= strtoul(c_len, NULL, 10); - if (errno != 0 || len > MAX_DATETIME_PRECISION) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), len, - item_name(a, &buf), MAX_DATETIME_PRECISION); - return NULL; - } - } - else - len= 0; + bool err= false; + uint len= get_number(a, c_len, &err, MAX_DATETIME_PRECISION, + ER_TOO_BIG_PRECISION); + if (err) + return NULL; if (cast_type == ITEM_CAST_TIME) res= new (thd->mem_root) Item_time_typecast(a, len); @@ -5101,72 +5110,40 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, } case ITEM_CAST_DECIMAL: { - ulong len= 0; - uint dec= 0; + bool err= false; + ulong len= get_number(a, c_len, &err, DECIMAL_MAX_PRECISION, + ER_TOO_BIG_PRECISION); + uint dec= get_number(a, c_dec, &err, DECIMAL_MAX_SCALE, + ER_TOO_BIG_SCALE); + if (err) + return NULL; - if (c_len) - { - ulong decoded_size; - errno= 0; - decoded_size= strtoul(c_len, NULL, 10); - if (errno != 0) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), decoded_size, - item_name(a, &buf), DECIMAL_MAX_PRECISION); - return NULL; - } - len= decoded_size; - } - - if (c_dec) - { - ulong decoded_size; - errno= 0; - decoded_size= strtoul(c_dec, NULL, 10); - if ((errno != 0) || (decoded_size > UINT_MAX)) - { - my_error(ER_TOO_BIG_SCALE, MYF(0), decoded_size, - item_name(a, &buf), DECIMAL_MAX_SCALE); - return NULL; - } - dec= decoded_size; - } - my_decimal_trim(&len, &dec); if (len < dec) { my_error(ER_M_BIGGER_THAN_D, MYF(0), ""); - return 0; - } - if (len > DECIMAL_MAX_PRECISION) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), len, - item_name(a, &buf), DECIMAL_MAX_PRECISION); - return 0; - } - if (dec > DECIMAL_MAX_SCALE) - { - my_error(ER_TOO_BIG_SCALE, MYF(0), dec, item_name(a, &buf), - DECIMAL_MAX_SCALE); - return 0; + return NULL; } + my_decimal_trim(&len, &dec); res= new (thd->mem_root) Item_decimal_typecast(a, len, dec); break; } case ITEM_CAST_CHAR: { - int len= -1; + uint len= ~0U; CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection); if (c_len) { - ulong decoded_size; - errno= 0; - decoded_size= strtoul(c_len, NULL, 10); - if ((errno != 0) || (decoded_size > MAX_FIELD_BLOBLENGTH)) + int err; + ulonglong decoded_size= my_strtoll10(c_len, NULL, &err); + if (decoded_size> MAX_FIELD_BLOBLENGTH) { - my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", MAX_FIELD_BLOBLENGTH); + char buff[1024]; + String buf(buff, sizeof(buff), system_charset_info); + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), + item_name(a, &buf), MAX_FIELD_BLOBLENGTH); return NULL; } - len= (int) decoded_size; + len= decoded_size; } res= new (thd->mem_root) Item_char_typecast(a, len, real_cs); break; diff --git a/sql/item_func.cc b/sql/item_func.cc index 9ee239b702b..870a481ce85 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -461,7 +461,7 @@ Field *Item_func::tmp_table_field(TABLE *table) field= Field_new_decimal::create_from_item(this); break; case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); field= 0; @@ -716,7 +716,8 @@ void Item_func_num1::find_num_type() break; case DECIMAL_RESULT: break; - default: + case TIME_RESULT: + case ROW_RESULT: DBUG_ASSERT(0); } DBUG_PRINT("info", ("Type: %s", @@ -773,7 +774,8 @@ String *Item_func_numhybrid::val_str(String *str) } case STRING_RESULT: return str_op(&str_value); - default: + case TIME_RESULT: + case ROW_RESULT: DBUG_ASSERT(0); } return str; @@ -808,7 +810,8 @@ double Item_func_numhybrid::val_real() return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(), &end_not_used, &err_not_used) : 0.0); } - default: + case TIME_RESULT: + case ROW_RESULT: DBUG_ASSERT(0); } return 0.0; @@ -843,7 +846,8 @@ longlong Item_func_numhybrid::val_int() CHARSET_INFO *cs= str_value.charset(); return (*(cs->cset->strtoll10))(cs, res->ptr(), &end, &err_not_used); } - default: + case TIME_RESULT: + case ROW_RESULT: DBUG_ASSERT(0); } return 0; @@ -881,7 +885,7 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) break; } case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); } return val; @@ -1340,7 +1344,9 @@ void Item_func_div::fix_length_and_dec() case DECIMAL_RESULT: result_precision(); break; - default: + case STRING_RESULT: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(0); } maybe_null= 1; // devision by zero @@ -1833,7 +1839,8 @@ void Item_func_int_val::find_num_type() hybrid_type= INT_RESULT; } break; - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(0); } DBUG_PRINT("info", ("Type: %s", @@ -2009,7 +2016,8 @@ void Item_func_round::fix_length_and_dec() unsigned_flag); break; } - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(0); /* This result type isn't handled */ } } @@ -2230,8 +2238,8 @@ void Item_func_min_max::fix_length_and_dec() set_if_bigger(decimals, args[i]->decimals); set_if_bigger(max_int_part, args[i]->decimal_int_part()); if (args[i]->maybe_null) - maybe_null=1; - cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); + maybe_null= 1; + cmp_type= item_cmp_type(cmp_type,args[i]->result_type()); if (args[i]->cmp_type() == TIME_RESULT) { if (!compare_as_dates || args[i]->field_type() == MYSQL_TYPE_DATETIME) @@ -2284,20 +2292,21 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, uint fuzzy_date) longlong res= get_datetime_value(thd, &arg, 0, compare_as_dates, &is_null); /* Check if we need to stop (because of error or KILL) and stop the loop */ - if (thd->is_error()) + if (thd->is_error() || args[i]->null_value) { null_value= 1; return 1; } - if ((null_value= args[i]->null_value)) - return 1; if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0) min_max= res; } unpack_time(min_max, ltime); if (compare_as_dates->field_type() == MYSQL_TYPE_DATE) + { ltime->time_type= MYSQL_TIMESTAMP_DATE; + ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; + } return 0; } @@ -2312,9 +2321,9 @@ String *Item_func_min_max::val_str(String *str) if (get_date(<ime, TIME_FUZZY_DATE)) return 0; - char buf[MAX_DATE_STRING_REP_LENGTH]; - int len= my_TIME_to_str(<ime, buf, decimals); - str->copy(buf, len, collation.collation); + str->alloc(MAX_DATE_STRING_REP_LENGTH); + str->set_charset(collation.collation); + str->length(my_TIME_to_str(<ime, const_cast<char*>(str->ptr()), decimals)); return str; } switch (cmp_type) { @@ -2367,7 +2376,7 @@ String *Item_func_min_max::val_str(String *str) return res; } case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); return 0; @@ -2955,7 +2964,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, to+= ALIGN_SIZE(sizeof(double)); break; case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); break; @@ -3030,7 +3039,7 @@ bool udf_handler::get_arguments() } break; case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); break; @@ -3634,7 +3643,7 @@ longlong Item_func_benchmark::val_int() (void) args[1]->val_decimal(&tmp_decimal); break; case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); return 0; @@ -3968,7 +3977,8 @@ double user_var_entry::val_real(my_bool *null_value) } case STRING_RESULT: return my_atof(value); // This is null terminated - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(1); // Impossible break; } @@ -3999,7 +4009,8 @@ longlong user_var_entry::val_int(my_bool *null_value) const int error; return my_strtoll10(value, (char**) 0, &error);// String is null terminated } - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(1); // Impossible break; } @@ -4031,7 +4042,8 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, case STRING_RESULT: if (str->copy(value, length, collation.collation)) str= 0; // EOM error - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(1); // Impossible break; } @@ -4058,7 +4070,8 @@ my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) case STRING_RESULT: str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val); break; - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(1); // Impossible break; } @@ -4115,7 +4128,7 @@ Item_func_set_user_var::check(bool use_result_field) break; } case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); break; @@ -4150,7 +4163,7 @@ void Item_func_set_user_var::save_item_result(Item *item) save_result.vdec= item->val_decimal_result(&decimal_buff); break; case ROW_RESULT: - default: + case TIME_RESULT: // Should never happen DBUG_ASSERT(0); break; @@ -4218,7 +4231,7 @@ Item_func_set_user_var::update() break; } case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); break; @@ -4669,7 +4682,7 @@ void Item_func_get_user_var::fix_length_and_dec() decimals= DECIMAL_MAX_SCALE; break; case ROW_RESULT: // Keep compiler happy - default: + case TIME_RESULT: DBUG_ASSERT(0); break; } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index a173f50e605..a32cfabcaa1 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -64,9 +64,12 @@ static bool make_datetime(MYSQL_TIME *ltime, String *str, uint decimals) 0 otherwise */ -static bool sec_to_time(double seconds, MYSQL_TIME *ltime) +bool Item_func_sec_to_time::sec_to_time(double seconds, MYSQL_TIME *ltime) { + Lazy_string_double str(seconds); uint sec; + const double max_sec_val= TIME_MAX_VALUE_SECONDS + + TIME_MAX_SECOND_PART/(double)TIME_SECOND_PART_FACTOR; bzero((char *)ltime, sizeof(*ltime)); @@ -75,32 +78,28 @@ static bool sec_to_time(double seconds, MYSQL_TIME *ltime) if (seconds < 0) { ltime->neg= 1; - if (seconds < -3020399) + if (seconds < -max_sec_val) goto overflow; seconds= -seconds; } - else if (seconds > 3020399) + else if (seconds > max_sec_val) goto overflow; sec= (uint) ((ulonglong) seconds % 3600); ltime->hour= (uint) (seconds/3600); ltime->minute= sec/60; ltime->second= sec % 60; - ltime->second_part= (ulong)((seconds - floor(seconds))*1e6); + ltime->second_part= (ulong)((seconds - floor(seconds))*TIME_SECOND_PART_FACTOR); return 0; overflow: - ltime->hour= TIME_MAX_HOUR; - ltime->minute= TIME_MAX_MINUTE; - ltime->second= TIME_MAX_SECOND; - - char buf[100]; - uint len= snprintf(buf, sizeof(buf), "%.80g", ltime->neg ? -seconds: seconds); + /* use check_time_range() to set ltime to the max value depending on dec */ + int unused; + ltime->hour= TIME_MAX_HOUR+1; + check_time_range(ltime, decimals, &unused); make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - buf, len, MYSQL_TIMESTAMP_TIME, - NullS); - + &str, MYSQL_TIMESTAMP_TIME, NullS); return 1; } @@ -908,7 +907,7 @@ longlong Item_func_dayofyear::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - if (get_arg0_date(<ime,TIME_NO_ZERO_DATE)) + if (get_arg0_date(<ime, TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE)) return 0; return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day) - calc_daynr(ltime.year,1,1) + 1; @@ -1180,7 +1179,7 @@ longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp) longlong Item_func_unix_timestamp::val_int() { MYSQL_TIME ltime; - my_bool not_used; + uint not_used; DBUG_ASSERT(fixed == 1); if (arg_count == 0) @@ -1430,15 +1429,12 @@ bool Item_func_from_days::get_date(MYSQL_TIME *ltime, uint fuzzy_date) void Item_func_curdate::fix_length_and_dec() { - collation.set(&my_charset_bin); - decimals=0; - max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - store_now_in_TIME(<ime); /* We don't need to set second_part and neg because they already 0 */ ltime.hour= ltime.minute= ltime.second= 0; ltime.time_type= MYSQL_TIMESTAMP_DATE; + Item_datefunc::fix_length_and_dec(); } /** @@ -1461,7 +1457,6 @@ void Item_func_curdate_utc::store_now_in_TIME(MYSQL_TIME *now_time) { THD *thd= current_thd; my_tz_UTC->gmt_sec_to_TIME(now_time, thd->query_start()); - thd->time_zone_used= 1; /* We are not flagging this query as using time zone, since it uses fixed UTC-SYSTEM time-zone. @@ -1488,14 +1483,6 @@ bool Item_func_curtime::fix_fields(THD *thd, Item **items) return Item_timefunc::fix_fields(thd, items); } -void Item_func_curtime::fix_length_and_dec() -{ - collation.set(&my_charset_bin); - store_now_in_TIME(<ime); - max_length= MAX_TIME_WIDTH + - (decimals ? min(decimals, TIME_SECOND_PART_DIGITS)+1 : 0); -} - bool Item_func_curtime::get_date(MYSQL_TIME *res, uint fuzzy_date __attribute__((unused))) { @@ -1558,15 +1545,6 @@ bool Item_func_now::fix_fields(THD *thd, Item **items) return Item_temporal_func::fix_fields(thd, items); } -void Item_func_now::fix_length_and_dec() -{ - collation.set(&my_charset_bin); - store_now_in_TIME(<ime); - max_length= MAX_DATETIME_WIDTH + - (decimals ? min(decimals, TIME_SECOND_PART_DIGITS)+1 : 0); -} - - /** Converts current time in my_time_t to MYSQL_TIME represenatation for local time zone. Defines time zone (local) used for whole NOW function. @@ -1621,9 +1599,7 @@ void Item_func_sysdate_local::store_now_in_TIME(MYSQL_TIME *now_time) bool Item_func_sysdate_local::get_date(MYSQL_TIME *res, uint fuzzy_date __attribute__((unused))) { - MYSQL_TIME ltime; - store_now_in_TIME(<ime); - *res= ltime; + store_now_in_TIME(res); return 0; } @@ -1819,11 +1795,9 @@ null_date: void Item_func_from_unixtime::fix_length_and_dec() { thd= current_thd; - collation.set(&my_charset_bin); - decimals= 0; - max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; maybe_null= 1; thd->time_zone_used= 1; + Item_temporal_func::fix_length_and_dec(); } @@ -1846,12 +1820,9 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime, void Item_func_convert_tz::fix_length_and_dec() { - collation.set(&my_charset_bin); - max_length= MAX_DATETIME_WIDTH; - decimals= args[0]->decimals; - if (decimals && decimals != NOT_FIXED_DEC) - max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; maybe_null= 1; + decimals= args[0]->decimals; + Item_temporal_func::fix_length_and_dec(); } @@ -1907,10 +1878,7 @@ void Item_func_convert_tz::cleanup() void Item_date_add_interval::fix_length_and_dec() { enum_field_types arg0_field_type; - - collation.set(&my_charset_bin); maybe_null=1; - max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; /* The field type for the result of an Item_date function is defined as @@ -1950,8 +1918,8 @@ void Item_date_add_interval::fix_length_and_dec() decimals= 6; else decimals= args[0]->decimals; - if (decimals) - max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; + + Item_temporal_func::fix_length_and_dec(); value.alloc(max_length); } @@ -1962,7 +1930,7 @@ bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { INTERVAL interval; - if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE|TIME_FUZZY_DATE) || + if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE | TIME_FUZZY_DATE) || get_interval_value(args[1], int_type, &value, &interval)) return (null_value=1); @@ -2159,13 +2127,13 @@ void Item_char_typecast::print(String *str, enum_query_type query_type) str->append(STRING_WITH_LEN("cast(")); args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as char")); - if (cast_length >= 0) + if (cast_length != ~0U) { str->append('('); char buffer[20]; // my_charset_bin is good enough for numbers String st(buffer, sizeof(buffer), &my_charset_bin); - st.set((ulonglong)cast_length, &my_charset_bin); + st.set(static_cast<ulonglong>(cast_length), &my_charset_bin); str->append(st); str->append(')'); } @@ -2212,7 +2180,7 @@ String *Item_char_typecast::val_str(String *str) and the result is longer than cast length, e.g. CAST('string' AS CHAR(1)) */ - if (cast_length >= 0) + if (cast_length != ~0U) { if (res->length() > (length= (uint32) res->charpos(cast_length))) { // Safe even if const arg @@ -2232,16 +2200,15 @@ String *Item_char_typecast::val_str(String *str) res->c_ptr_safe()); res->length((uint) length); } - else if (cast_cs == &my_charset_bin && res->length() < (uint) cast_length) + else if (cast_cs == &my_charset_bin && res->length() < cast_length) { - if (res->alloced_length() < (uint) cast_length) + if (res->alloced_length() < cast_length) { str_value.alloc(cast_length); str_value.copy(*res); res= &str_value; } - bzero((char*) res->ptr() + res->length(), - (uint) cast_length - res->length()); + bzero((char*) res->ptr() + res->length(), cast_length - res->length()); res->length(cast_length); } } @@ -2287,7 +2254,7 @@ void Item_char_typecast::fix_length_and_dec() from_cs != &my_charset_bin && cast_cs != &my_charset_bin); collation.set(cast_cs, DERIVATION_IMPLICIT); - char_length= (cast_length >= 0) ? cast_length : + char_length= (cast_length != ~0U) ? cast_length : args[0]->max_length / (cast_cs == &my_charset_bin ? 1 : args[0]->collation.collation->mbmaxlen); max_length= char_length * cast_cs->mbmaxlen; @@ -2381,7 +2348,6 @@ err: void Item_func_add_time::fix_length_and_dec() { enum_field_types arg0_field_type; - max_length= MAX_DATETIME_WIDTH; decimals= max(args[0]->decimals, args[1]->decimals); maybe_null= 1; @@ -2403,8 +2369,7 @@ void Item_func_add_time::fix_length_and_dec() cached_field_type= MYSQL_TYPE_DATETIME; else if (arg0_field_type == MYSQL_TYPE_TIME) cached_field_type= MYSQL_TYPE_TIME; - if (decimals) - max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; + Item_temporal_func::fix_length_and_dec(); } /** @@ -2531,15 +2496,15 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, uint fuzzy_date) MYSQL_TIME l_time1,l_time2,l_time3; Lazy_string_time str(&l_time3); - null_value= 0; + /* the following may be true in, for example, date_add(timediff(...), ... */ + if (fuzzy_date & TIME_NO_ZERO_IN_DATE) + goto null_date; + if (args[0]->get_time(&l_time1) || args[1]->get_time(&l_time2) || l_time1.time_type != l_time2.time_type) goto null_date; - if (fuzzy_date & TIME_NO_ZERO_IN_DATE) - goto null_date; - if (l_time1.neg != l_time2.neg) l_sign= -l_sign; @@ -2556,7 +2521,14 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, uint fuzzy_date) if (l_time1.neg && (seconds || microseconds)) l_time3.neg= 1-l_time3.neg; // Swap sign of result + /* + seconds is longlong, when casted to long it may become a small number + even if the original seconds value was too large and invalid. + as a workaround we limit seconds by a large invalid long number + ("invalid" means > TIME_MAX_SECOND) + */ set_if_smaller(seconds, INT_MAX32); + calc_time_from_sec(&l_time3, (long) seconds, microseconds); if ((fuzzy_date & TIME_NO_ZERO_DATE) && (seconds == 0) && (microseconds == 0)) @@ -2933,9 +2905,7 @@ void Item_func_str_to_date::fix_length_and_dec() { maybe_null= 1; cached_field_type= MYSQL_TYPE_DATETIME; - max_length= MAX_DATETIME_WIDTH + TIME_SECOND_PART_DIGITS; - cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; - decimals= AUTO_SEC_PART_DIGITS; + decimals= NOT_FIXED_DEC; if ((const_item= args[1]->const_item())) { char format_buff[64]; @@ -2948,31 +2918,25 @@ void Item_func_str_to_date::fix_length_and_dec() get_date_time_result_type(format->ptr(), format->length()); switch (cached_format_type) { case DATE_ONLY: - cached_timestamp_type= MYSQL_TIMESTAMP_DATE; cached_field_type= MYSQL_TYPE_DATE; - max_length= MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN; break; case TIME_MICROSECOND: decimals= 6; /* fall through */ case TIME_ONLY: - cached_timestamp_type= MYSQL_TIMESTAMP_TIME; cached_field_type= MYSQL_TYPE_TIME; - max_length= MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN; break; case DATE_TIME_MICROSECOND: decimals= 6; /* fall through */ case DATE_TIME: - cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; cached_field_type= MYSQL_TYPE_DATETIME; - max_length= MAX_DATETIME_WIDTH; break; } - if (decimals) - max_length+= decimals + 1; } } + cached_timestamp_type= mysql_type_to_time_type(cached_field_type); + Item_temporal_func::fix_length_and_dec(); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 9f45655add6..14275680d15 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -360,23 +360,35 @@ public: { return tmp_table_field_from_field_type(table, 0); } int save_in_field(Field *field, bool no_conversions) { return save_date_in_field(field); } + void fix_length_and_dec() + { + static const uint max_time_type_width[5]= + { MAX_DATETIME_WIDTH, MAX_DATETIME_WIDTH, MAX_DATE_WIDTH, + MAX_DATETIME_WIDTH, MIN_TIME_WIDTH }; + + max_length= max_time_type_width[mysql_type_to_time_type(field_type())+2]; + if (decimals) + { + if (decimals == NOT_FIXED_DEC) + max_length+= TIME_SECOND_PART_DIGITS + 1; + else + { + set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); + max_length+= decimals + 1; + } + } + } }; class Item_datefunc :public Item_temporal_func { public: - Item_datefunc() :Item_temporal_func() {} - Item_datefunc(Item *a) :Item_temporal_func(a) {} + Item_datefunc() :Item_temporal_func() { } + Item_datefunc(Item *a) :Item_temporal_func(a) { } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } const char *func_name() const { return "date"; } bool get_date(MYSQL_TIME *res, uint fuzzy_date) { return get_arg0_date(res, fuzzy_date); } - void fix_length_and_dec() - { - collation.set(&my_charset_bin); - decimals=0; - max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - } }; @@ -388,11 +400,6 @@ public: Item_timefunc(Item *a,Item *b) :Item_temporal_func(a,b) {} Item_timefunc(Item *a, Item *b, Item *c) :Item_temporal_func(a, b ,c) {} enum_field_types field_type() const { return MYSQL_TYPE_TIME; } - void fix_length_and_dec() - { - max_length= MAX_TIME_WIDTH + - (decimals ? min(decimals, TIME_SECOND_PART_DIGITS)+1 : 0); - } }; @@ -404,7 +411,11 @@ class Item_func_curtime :public Item_timefunc public: Item_func_curtime(uint dec) :Item_timefunc() { decimals= dec; } bool fix_fields(THD *, Item **); - void fix_length_and_dec(); + void fix_length_and_dec() + { + store_now_in_TIME(<ime); + Item_timefunc::fix_length_and_dec(); + } bool get_date(MYSQL_TIME *res, uint fuzzy_date); /* Abstract method that defines which time zone is used for conversion. @@ -472,7 +483,11 @@ class Item_func_now :public Item_temporal_func public: Item_func_now(uint dec) :Item_temporal_func() { decimals= dec; } bool fix_fields(THD *, Item **); - void fix_length_and_dec(); + void fix_length_and_dec() + { + store_now_in_TIME(<ime); + Item_temporal_func::fix_length_and_dec(); + } bool get_date(MYSQL_TIME *res, uint fuzzy_date); virtual void store_now_in_TIME(MYSQL_TIME *now_time)=0; }; @@ -591,16 +606,14 @@ class Item_func_convert_tz :public Item_temporal_func class Item_func_sec_to_time :public Item_timefunc { + bool sec_to_time(double seconds, MYSQL_TIME *ltime); public: Item_func_sec_to_time(Item *item) :Item_timefunc(item) {} bool get_date(MYSQL_TIME *res, uint fuzzy_date); void fix_length_and_dec() - { - collation.set(&my_charset_bin); + { maybe_null=1; decimals= args[0]->decimals; - if (decimals != NOT_FIXED_DEC) - set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); Item_timefunc::fix_length_and_dec(); } const char *func_name() const { return "sec_to_time"; } @@ -645,12 +658,12 @@ class Item_extract :public Item_int_func class Item_char_typecast :public Item_str_func { - int cast_length; + uint cast_length; CHARSET_INFO *cast_cs, *from_cs; bool charset_conversion; String tmp_value; public: - Item_char_typecast(Item *a, int length_arg, CHARSET_INFO *cs_arg) + Item_char_typecast(Item *a, uint length_arg, CHARSET_INFO *cs_arg) :Item_str_func(a), cast_length(length_arg), cast_cs(cs_arg) {} enum Functype functype() const { return CHAR_TYPECAST_FUNC; } bool eq(const Item *item, bool binary_cmp) const; @@ -667,6 +680,13 @@ public: Item_temporal_typecast(Item *a) :Item_temporal_func(a) {} virtual const char *cast_type() const = 0; void print(String *str, enum_query_type query_type); + void fix_length_and_dec() + { + maybe_null= 1; + if (decimals == NOT_FIXED_DEC) + decimals= args[0]->decimals; + Item_temporal_func::fix_length_and_dec(); + } }; class Item_date_typecast :public Item_temporal_typecast @@ -677,13 +697,6 @@ public: bool get_date(MYSQL_TIME *ltime, uint fuzzy_date); const char *cast_type() const { return "date"; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } - void fix_length_and_dec() - { - collation.set(&my_charset_bin); - decimals= 0; - max_length= MAX_DATE_WIDTH; - maybe_null= 1; - } }; @@ -696,20 +709,6 @@ public: bool get_date(MYSQL_TIME *ltime, uint fuzzy_date); const char *cast_type() const { return "time"; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } - void fix_length_and_dec() - { - collation.set(&my_charset_bin); - maybe_null= 1; - max_length= MIN_TIME_WIDTH; - if (decimals == NOT_FIXED_DEC) - { - decimals= args[0]->decimals; - if (decimals != NOT_FIXED_DEC) - set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); - } - if (decimals && decimals != NOT_FIXED_DEC) - max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; - } }; @@ -722,14 +721,6 @@ public: const char *cast_type() const { return "datetime"; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } bool get_date(MYSQL_TIME *ltime, uint fuzzy_date); - void fix_length_and_dec() - { - collation.set(&my_charset_bin); - maybe_null= 1; - max_length= MAX_DATETIME_WIDTH; - if (decimals && decimals != NOT_FIXED_DEC) - max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; - } }; class Item_func_makedate :public Item_temporal_func @@ -740,10 +731,9 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_DATE; } void fix_length_and_dec() { - decimals=0; - max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; /* It returns NULL when the second argument is less or equal to 0 */ maybe_null= 1; + Item_temporal_func::fix_length_and_dec(); } bool get_date(MYSQL_TIME *ltime, uint fuzzy_date); }; diff --git a/sql/log_event.cc b/sql/log_event.cc index 49f18b919d3..3aef379ad3a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1978,12 +1978,10 @@ end: delete td; } -#ifdef MYSQL_CLIENT void free_table_map_log_event(Table_map_log_event *event) { delete event; } -#endif void Log_event::print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info, @@ -3614,7 +3612,7 @@ bool Start_log_event_v3::write(IO_CACHE* file) int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version); memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN); if (!dont_set_created) - created= get_time(); + created= get_time(); // this sets when and when_sec_part as a side effect int4store(buff + ST_CREATED_OFFSET,created); return (write_header(file, sizeof(buff)) || my_b_safe_write(file, (uchar*) buff, sizeof(buff))); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index acdbac4ff68..035f546f37a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -733,11 +733,11 @@ public: void copy(String *dst) const { dst->set(num, &my_charset_bin); } }; -class Lazy_string_dbl: public Lazy_string +class Lazy_string_double: public Lazy_string { double num; public: - Lazy_string_dbl(double num_arg) : Lazy_string(), num(num_arg) {} + Lazy_string_double(double num_arg) : Lazy_string(), num(num_arg) {} void copy(String *dst) const { dst->set_real(num, NOT_FIXED_DEC, &my_charset_bin); } }; @@ -755,6 +755,19 @@ public: } }; +static inline enum enum_mysql_timestamp_type +mysql_type_to_time_type(enum enum_field_types mysql_type) +{ + switch(mysql_type) { + case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME; + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME; + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE; + default: return MYSQL_TIMESTAMP_ERROR; + } +} + #include "sql_list.h" #include "sql_map.h" #include "my_decimal.h" @@ -2212,7 +2225,7 @@ ulong convert_period_to_month(ulong period); ulong convert_month_to_period(ulong month); void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); -my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist); +my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code); timestamp_type str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time, uint flags); void localtime_to_TIME(MYSQL_TIME *to, struct tm *from); @@ -2257,19 +2270,6 @@ int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b); longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null); -static inline enum enum_mysql_timestamp_type -mysql_type_to_time_type(enum enum_field_types mysql_type) -{ - switch(mysql_type) { - case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME; - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME; - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE; - default: return MYSQL_TIMESTAMP_ERROR; - } -} - int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(uchar *,uint,char,char); void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, diff --git a/sql/set_var.cc b/sql/set_var.cc index 4ce85452f3e..376364bab60 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2999,7 +2999,7 @@ void sys_var_thd_lc_time_names::set_default(THD *thd, enum_var_type type) } /* - Handling of microseoncds given as seconds.part_seconds + Handling of microseconds given as seconds.part_seconds NOTES The argument to long query time is in seconds in decimal diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index a9880913c5e..0e014a1a00a 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5555,8 +5555,8 @@ ER_WARN_CANT_DROP_DEFAULT_KEYCACHE eng "Cannot drop default keycache" ger "Der vorgabemäßige Schlüssel-Cache kann nicht gelöscht werden" ER_TOO_BIG_DISPLAYWIDTH 42000 S1009 - eng "Display width out of range for column '%-.192s' (max = %lu)" - ger "Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%-.192s' (Maximum: %lu)" + eng "Display width out of range for '%-.192s' (max = %lu)" + ger "Anzeigebreite außerhalb des zulässigen Bereichs für '%-.192s' (Maximum: %lu)" ER_XAER_DUPID XAE08 eng "XAER_DUPID: The XID already exists" ger "XAER_DUPID: Die XID existiert bereits" diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7c7751f922f..94ab9f2dc41 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2338,7 +2338,8 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items) case DECIMAL_RESULT: op= &select_max_min_finder_subselect::cmp_decimal; break; - default: + case ROW_RESULT: + case TIME_RESULT: // This case should never be choosen DBUG_ASSERT(0); op= 0; diff --git a/sql/sql_string.cc b/sql/sql_string.cc index a41f4d52101..8d30055be5b 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -551,7 +551,7 @@ uint32 String::numchars() return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length); } -int String::charpos(int i,uint32 offset) +int String::charpos(longlong i,uint32 offset) { if (i <= 0) return i; diff --git a/sql/sql_string.h b/sql/sql_string.h index b15179bcbe5..e5d91c6ff6e 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -286,7 +286,7 @@ public: friend int stringcmp(const String *a,const String *b); friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); uint32 numchars(); - int charpos(int i,uint32 offset=0); + int charpos(longlong i,uint32 offset=0); int reserve(uint32 space_needed) { diff --git a/sql/time.cc b/sql/time.cc index 2badb77d14b..ba81fcc86c2 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -250,30 +250,36 @@ str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time, TIME_to_timestamp() thd - current thread t - datetime in broken-down representation, - in_dst_time_gap - pointer to bool which is set to true if t represents - value which doesn't exists (falls into the spring - time-gap) or to false otherwise. + error_code - 0, if the conversion was successful; + ER_WARN_DATA_OUT_OF_RANGE, if t contains datetime value + which is out of TIMESTAMP range; + ER_WARN_INVALID_TIMESTAMP, if t represents value which + doesn't exists (falls into the spring time-gap). RETURN Number seconds in UTC since start of Unix Epoch corresponding to t. - 0 - t contains datetime value which is out of TIMESTAMP range. + 0 - in case of ER_WARN_DATA_OUT_OF_RANGE */ -my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *in_dst_time_gap) +my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code) { my_time_t timestamp; + my_bool in_dst_time_gap= 0; - *in_dst_time_gap= 0; + *error_code= 0; thd->time_zone_used= 1; - timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap); + timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, &in_dst_time_gap); if (timestamp) { + if (in_dst_time_gap) + *error_code= ER_WARN_INVALID_TIMESTAMP; return timestamp; } /* If we are here we have range error. */ - return(0); + *error_code= ER_WARN_DATA_OUT_OF_RANGE; + return 0; } @@ -675,6 +681,7 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)), const MYSQL_TIME *l_time, String *str) { + str->alloc(MAX_DATE_STRING_REP_LENGTH); uint length= (uint) my_time_to_str(l_time, (char*) str->ptr(), 0); str->length(length); str->set_charset(&my_charset_bin); @@ -684,6 +691,7 @@ void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)), void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)), const MYSQL_TIME *l_time, String *str) { + str->alloc(MAX_DATE_STRING_REP_LENGTH); uint length= (uint) my_date_to_str(l_time, (char*) str->ptr()); str->length(length); str->set_charset(&my_charset_bin); @@ -693,6 +701,7 @@ void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)), void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)), const MYSQL_TIME *l_time, String *str) { + str->alloc(MAX_DATE_STRING_REP_LENGTH); uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr(), 0); str->length(length); str->set_charset(&my_charset_bin); @@ -776,7 +785,7 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL inter my_bool neg= ltime->neg; enum enum_mysql_timestamp_type time_type= ltime->time_type; - if (ltime->time_type != MYSQL_TIMESTAMP_TIME) + if (time_type != MYSQL_TIMESTAMP_TIME) ltime->day+= calc_daynr(ltime->year, ltime->month, 1) - 1; usec= COMBINE(ltime) + sign*COMBINE(&interval); @@ -791,7 +800,7 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL inter if (int_type != INTERVAL_DAY) ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date - daynr= ltime->day + 32*(ltime->month + 13*ltime->year); + daynr= usec/1000000/24/60/60; /* Day number from year 0 to 9999-12-31 */ if ((ulonglong) daynr > MAX_DAY_NUMBER) |