summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2014-06-11 10:08:08 +0200
committerSergei Golubchik <sergii@pisem.net>2014-06-11 10:08:08 +0200
commit6e8d49b8f51a573fa13a40a9b0bffe5424830db6 (patch)
tree5f78e028b36ce27bedde8be77bde5adea2ad67fc /sql
parent2510f9c6066f8702fad6865330bf99031f9b4b60 (diff)
downloadmariadb-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.cc55
-rw-r--r--sql/field.h12
-rw-r--r--sql/sql_time.cc3
-rw-r--r--sql/sql_time.h1
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(&ltime, &str, was_cut, have_smth_to_conv);
}
-
-
+
+
+void Field_time::set_curdays(THD *thd)
+{
+ MYSQL_TIME ltime;
+ set_current_date(thd, &ltime);
+ 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);