diff options
author | Sergei Golubchik <sergii@pisem.net> | 2014-06-11 10:08:08 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2014-06-11 10:08:08 +0200 |
commit | 6e8d49b8f51a573fa13a40a9b0bffe5424830db6 (patch) | |
tree | 5f78e028b36ce27bedde8be77bde5adea2ad67fc /sql | |
parent | 2510f9c6066f8702fad6865330bf99031f9b4b60 (diff) | |
download | mariadb-git-6e8d49b8f51a573fa13a40a9b0bffe5424830db6.tar.gz |
MDEV-6065 MySQL Bug#13623473 "MISSING ROWS ON SELECT AND JOIN WITH TIME/DATETIME COMPARE"
fix for ref like "indexed_time = datetime"
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 55 | ||||
-rw-r--r-- | sql/field.h | 12 | ||||
-rw-r--r-- | sql/sql_time.cc | 3 | ||||
-rw-r--r-- | sql/sql_time.h | 1 |
4 files changed, 66 insertions, 5 deletions
diff --git a/sql/field.cc b/sql/field.cc index 13cad813b82..103a8920d7e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5316,12 +5316,41 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) } +/** + subtract a given number of days from DATETIME, return TIME + + optimized version of calc_time_diff() + + @note it might generate TIME values outside of the valid TIME range! +*/ +static void calc_datetime_days_diff(MYSQL_TIME *ltime, long days) +{ + long daydiff= calc_daynr(ltime->year, ltime->month, ltime->day) - days; + ltime->year= ltime->month= 0; + if (daydiff >=0 ) + ltime->day= daydiff; + else + { + longlong timediff= ((((daydiff * 24LL + + ltime->hour) * 60LL + + ltime->minute) * 60LL + + ltime->second) * 1000000LL + + ltime->second_part); + unpack_time(timediff, ltime); + } + ltime->time_type= MYSQL_TIMESTAMP_TIME; +} + + int Field_time::store_time_dec(MYSQL_TIME *ltime, uint dec) { MYSQL_TIME l_time= *ltime; ErrConvTime str(ltime); int was_cut= 0; + if (curdays && l_time.time_type != MYSQL_TIMESTAMP_TIME) + calc_datetime_days_diff(&l_time, curdays); + int have_smth_to_conv= !check_time_range(&l_time, decimals(), &was_cut); return store_TIME_with_warning(&l_time, &str, was_cut, have_smth_to_conv); } @@ -5356,8 +5385,30 @@ int Field_time::store(longlong nr, bool unsigned_val) return store_TIME_with_warning(<ime, &str, was_cut, have_smth_to_conv); } - - + + +void Field_time::set_curdays(THD *thd) +{ + MYSQL_TIME ltime; + set_current_date(thd, <ime); + curdays= calc_daynr(ltime.year, ltime.month, ltime.day); +} + + +Field *Field_time::new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit) +{ + THD *thd= get_thd(); + Field_time *res= + (Field_time*) Field::new_key_field(root, new_table, new_ptr, length, + new_null_ptr, new_null_bit); + if (!(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST) && res) + res->set_curdays(thd); + return res; +} + + double Field_time::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; diff --git a/sql/field.h b/sql/field.h index 2938209004d..b5f332f5edc 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1852,6 +1852,12 @@ public: class Field_time :public Field_temporal { + /* + when this Field_time instance is used for storing values for index lookups + (see class store_key, Field::new_key_field(), etc), the following + might be set to TO_DAYS(CURDATE()). See also Field_time::store_time_dec() + */ + long curdays; protected: virtual void store_TIME(MYSQL_TIME *ltime); int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, @@ -1861,7 +1867,7 @@ public: uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg) :Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg) + unireg_check_arg, field_name_arg), curdays(0) {} enum_field_types type() const { return MYSQL_TYPE_TIME;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; } @@ -1880,6 +1886,10 @@ public: uint32 pack_length() const { return 3; } void sql_type(String &str) const; uint size_of() const { return sizeof(*this); } + void set_curdays(THD *thd); + Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); }; diff --git a/sql/sql_time.cc b/sql/sql_time.cc index e0b17a918ee..cc824298bc5 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -1259,8 +1259,7 @@ mix_date_and_time(MYSQL_TIME *to, const MYSQL_TIME *from) /** Get current date in DATE format */ -static void -set_current_date(THD *thd, MYSQL_TIME *to) +void set_current_date(THD *thd, MYSQL_TIME *to) { thd->variables.time_zone->gmt_sec_to_TIME(to, thd->query_start()); thd->time_zone_used= 1; diff --git a/sql/sql_time.h b/sql/sql_time.h index 24a87922fa9..dc8e4668e1e 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -33,6 +33,7 @@ typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT; ulong convert_period_to_month(ulong period); ulong convert_month_to_period(ulong month); +void set_current_date(THD *thd, MYSQL_TIME *to); bool time_to_datetime(MYSQL_TIME *ltime); void time_to_daytime_interval(MYSQL_TIME *l_time); bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); |