From 67de8c46a5ddbc13ef32a339cb8c3c3e5dcb77bd Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Tue, 13 Jun 2006 19:09:24 +0400 Subject: Fixed bug#16377: result of DATE/TIME functions were compared as strings which can lead to a wrong result. All date/time functions has the STRING result type thus their results are compared as strings. The string date representation allows a user to skip some of leading zeros. This can lead to wrong comparison result if a date/time function result is compared to such a string constant. The idea behind this bug fix is to compare results of date/time functions and data/time constants as ints, because that date/time representation is more exact. To achieve this the agg_cmp_type() is changed to take in the account that a date/time field or an date/time item should be compared as ints. This bug fix is partially back ported from 5.0. The agg_cmp_type() function now accepts THD as one of parameters. In addition, it now checks if a date/time field/function is present in the list. If so, it tries to coerce all constants to INT to make date/time comparison return correct result. The field for the constant coercion is taken from the Item_field or constructed from the Item_func. In latter case the constructed field will be freed after conversion of all constant items. Otherwise the result is same as before - aggregated with help of the item_cmp_type() function. From the Item_func_between::fix_length_and_dec() function removed the part which was converting date/time constants to int if possible. Now this is done by the agg_cmp_type() function. The new function result_as_longlong() is added to the Item class. It indicates that the item is a date/time item and result of it can be compared as int. Such items are date/time fields/functions. Correct val_int() methods are implemented for classes Item_date_typecast, Item_func_makedate, Item_time_typecast, Item_datetime_typecast. All these classes are derived from Item_str_func and Item_str_func::val_int() converts its string value to int without regard to the date/time type of these items. Arg_comparator::set_compare_func() and Arg_comparator::set_cmp_func() functions are changed to substitute result type of an item with the INT_RESULT if the item is a date/time item and another item is a constant. This is done to get a correct result of comparisons like date_time_function() = string_constant. --- sql/field.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'sql/field.cc') diff --git a/sql/field.cc b/sql/field.cc index a64eaad7308..ec4d4b4e4f5 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6841,7 +6841,11 @@ create_field::create_field(Field *old_field,Field *orig_field) bool Field::set_warning(const uint level, const uint code, int cuted_increment) { - THD *thd= table->in_use; + /* + If this field was created only for type conversion purposes it + will have table == NULL. + */ + THD *thd= table ? table->in_use : current_thd; if (thd->count_cuted_fields) { thd->cuted_fields+= cuted_increment; @@ -6876,7 +6880,8 @@ Field::set_datetime_warning(const uint level, const uint code, timestamp_type ts_type, int cuted_increment) { if (set_warning(level, code, cuted_increment)) - make_truncated_value_warning(table->in_use, str, str_length, ts_type); + make_truncated_value_warning(table ? table->in_use : current_thd, + str, str_length, ts_type); } @@ -6905,8 +6910,8 @@ Field::set_datetime_warning(const uint level, const uint code, { char str_nr[22]; char *str_end= longlong10_to_str(nr, str_nr, -10); - make_truncated_value_warning(table->in_use, str_nr, str_end - str_nr, - ts_type); + make_truncated_value_warning(table ? table->in_use : current_thd, + str_nr, str_end - str_nr, ts_type); } } @@ -6935,7 +6940,8 @@ Field::set_datetime_warning(const uint level, const uint code, /* DBL_DIG is enough to print '-[digits].E+###' */ char str_nr[DBL_DIG + 8]; uint str_len= my_sprintf(str_nr, (str_nr, "%g", nr)); - make_truncated_value_warning(table->in_use, str_nr, str_len, ts_type); + make_truncated_value_warning(table ? table->in_use : current_thd, + str_nr, str_len, ts_type); } } -- cgit v1.2.1 From a2261d57be6dac312b0ae599031210341f5fcf70 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Thu, 15 Jun 2006 01:48:41 +0400 Subject: Many files: After merge fix --- sql/field.cc | 82 ++++++++++++++++++++++++------------------------------------ 1 file changed, 32 insertions(+), 50 deletions(-) (limited to 'sql/field.cc') diff --git a/sql/field.cc b/sql/field.cc index 64f888eb24d..b0a0633b6ce 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4530,11 +4530,11 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) int error; bool have_smth_to_conv; my_bool in_dst_time_gap; - THD *thd= table->in_use; + THD *thd= table ? table->in_use : current_thd; /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */ have_smth_to_conv= (str_to_datetime(from, len, &l_time, - (table->in_use->variables.sql_mode & + (thd->variables.sql_mode & MODE_NO_ZERO_DATE) | MODE_NO_ZERO_IN_DATE, &error) > MYSQL_TIMESTAMP_ERROR); @@ -4599,7 +4599,7 @@ int Field_timestamp::store(longlong nr, bool unsigned_val) my_time_t timestamp= 0; int error; my_bool in_dst_time_gap; - THD *thd= table->in_use; + THD *thd= table ? table->in_use : current_thd; /* 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 & @@ -4653,7 +4653,7 @@ longlong Field_timestamp::val_int(void) { uint32 temp; TIME time_tmp; - THD *thd= table->in_use; + THD *thd= table ? table->in_use : current_thd; #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) @@ -4678,7 +4678,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr) { uint32 temp, temp2; TIME time_tmp; - THD *thd= table->in_use; + THD *thd= table ? table->in_use : current_thd; char *to; val_buffer->alloc(field_length+1); @@ -4749,7 +4749,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr) bool Field_timestamp::get_date(TIME *ltime, uint fuzzydate) { long temp; - THD *thd= table->in_use; + THD *thd= table ? table->in_use : current_thd; #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) temp=uint4korr(ptr); @@ -4832,7 +4832,8 @@ void Field_timestamp::sql_type(String &res) const void Field_timestamp::set_time() { - long tmp= (long) table->in_use->query_start(); + THD *thd= table ? table->in_use : current_thd; + long tmp= (long) thd->query_start(); set_notnull(); #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) @@ -5024,12 +5025,13 @@ String *Field_time::val_str(String *val_buffer, bool Field_time::get_date(TIME *ltime, uint fuzzydate) { long tmp; + THD *thd= table ? table->in_use : current_thd; if (!(fuzzydate & TIME_FUZZY_DATE)) { - push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, ER(ER_WARN_DATA_OUT_OF_RANGE), field_name, - table->in_use->row_count); + thd->row_count); return 1; } tmp=(long) sint3korr(ptr); @@ -5217,9 +5219,10 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs) TIME l_time; uint32 tmp; int error; + THD *thd= table ? table->in_use : current_thd; if (str_to_datetime(from, len, &l_time, TIME_FUZZY_DATE | - (table->in_use->variables.sql_mode & + (thd->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)), &error) <= MYSQL_TIMESTAMP_ERROR) @@ -5272,9 +5275,10 @@ int Field_date::store(longlong nr, bool unsigned_val) TIME not_used; int error; longlong initial_nr= nr; + THD *thd= table ? table->in_use : current_thd; nr= number_to_datetime(nr, ¬_used, (TIME_FUZZY_DATE | - (table->in_use->variables.sql_mode & + (thd->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES))), &error); @@ -5420,9 +5424,10 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) TIME l_time; long tmp; int error; + THD *thd= table ? table->in_use : current_thd; if (str_to_datetime(from, len, &l_time, (TIME_FUZZY_DATE | - (table->in_use->variables.sql_mode & + (thd->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES))), &error) <= MYSQL_TIMESTAMP_ERROR) @@ -5460,9 +5465,10 @@ int Field_newdate::store(longlong nr, bool unsigned_val) TIME l_time; longlong tmp; int error; + THD *thd= table ? table->in_use : current_thd; if (number_to_datetime(nr, &l_time, (TIME_FUZZY_DATE | - (table->in_use->variables.sql_mode & + (thd->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES))), &error) == LL(-1)) @@ -5605,10 +5611,11 @@ int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs) int error; ulonglong tmp= 0; enum enum_mysql_timestamp_type func_res; + THD *thd= table ? table->in_use : current_thd; func_res= str_to_datetime(from, len, &time_tmp, (TIME_FUZZY_DATE | - (table->in_use->variables.sql_mode & + (thd->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES))), &error); @@ -5655,9 +5662,10 @@ int Field_datetime::store(longlong nr, bool unsigned_val) TIME not_used; int error; longlong initial_nr= nr; + THD *thd= table ? table->in_use : current_thd; nr= number_to_datetime(nr, ¬_used, (TIME_FUZZY_DATE | - (table->in_use->variables.sql_mode & + (thd->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES))), &error); @@ -9076,10 +9084,10 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, const char *str, uint str_length, timestamp_type ts_type, int cuted_increment) { - if (table->in_use->really_abort_on_warning() || + THD *thd= table ? table->in_use : current_thd; + if (thd->really_abort_on_warning() || set_warning(level, code, cuted_increment)) - make_truncated_value_warning(table ? table->in_use : current_thd, - str, str_length, ts_type, + make_truncated_value_warning(thd, str, str_length, ts_type, field_name); } @@ -9106,13 +9114,13 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, longlong nr, timestamp_type ts_type, int cuted_increment) { - if (table->in_use->really_abort_on_warning() || + THD *thd= table ? table->in_use : current_thd; + if (thd->really_abort_on_warning() || set_warning(level, code, cuted_increment)) { char str_nr[22]; char *str_end= longlong10_to_str(nr, str_nr, -10); - make_truncated_value_warning(table ? table->in_use : current_thd, - str_nr, (uint) (str_end - str_nr), + make_truncated_value_warning(thd, str_nr, (uint) (str_end - str_nr), ts_type, field_name); } } @@ -9138,41 +9146,15 @@ void Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, double nr, timestamp_type ts_type) { - if (table->in_use->really_abort_on_warning() || + THD *thd= table ? table->in_use : current_thd; + if (thd->really_abort_on_warning() || set_warning(level, code, 1)) { /* DBL_DIG is enough to print '-[digits].E+###' */ char str_nr[DBL_DIG + 8]; uint str_len= my_sprintf(str_nr, (str_nr, "%g", nr)); - make_truncated_value_warning(table ? table->in_use : current_thd, - str_nr, str_len, ts_type, + make_truncated_value_warning(thd, str_nr, str_len, ts_type, field_name); } } -/* - maximum possible display length for blob - - SYNOPSIS - Field_blob::max_length() - - RETURN - length -*/ -uint32 Field_blob::max_length() -{ - switch (packlength) - { - case 1: - return 255 * field_charset->mbmaxlen; - case 2: - return 65535 * field_charset->mbmaxlen; - case 3: - return 16777215 * field_charset->mbmaxlen; - case 4: - return (uint32) 4294967295U; - default: - DBUG_ASSERT(0); // we should never go here - return 0; - } -} -- cgit v1.2.1