summaryrefslogtreecommitdiff
path: root/sql/field.cc
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2016-03-23 08:26:40 +0400
committerAlexander Barkov <bar@mariadb.org>2016-03-23 08:26:40 +0400
commite4435b5ec304be1439475f6f6084fbf9f1fd9e1f (patch)
treef4ff2eb2f4c5fb4c0661d22f8e1c273b680769f8 /sql/field.cc
parentf66303dcf9fc9b7d5244be8b3c724387a5da7988 (diff)
downloadmariadb-git-e4435b5ec304be1439475f6f6084fbf9f1fd9e1f.tar.gz
MDEV-9604 crash in Item::save_in_field with empty enum value
1. Fixing Field_time::get_equal_const_item() to pass TIME_FUZZY_DATES and TIME_INVALID_DATES to get_time_with_conversion(). This is needed to make the recursively called Item::get_date() return non-NULL values on garbage input. This makes Field_time::get_equal_const_item() work consistently with how Item::val_time_packed() works. 2. Fixing Item::get_date() to return TIME'00:00:00' rather than DATE'0000-00-00' on empty or garbage input when: - TIME_FUZZY_DATES is enabled - The caller requested a TIME value (by passing TIME_TIME_ONLY). This is needed to avoid conversion of DATE'0000-00-00' to TIME in get_time_with_conversion(), which would erroneously try to subtract CURRENT_DATE from DATE'0000-00-00' and return TIME'-838:59:59' rather than the desired zero value TIME'00:00:00'. #1 and #2 fix these type of scripts to return one row with both MyISAM and InnoDB, with and without an index on t1.b: CREATE TABLE t1 (a ENUM('a'), b TIME, c INT, KEY(b)); INSERT INTO t1 VALUES ('','00:00:00',0); SELECT * FROM t1 WHERE b=''; SELECT * FROM t1 WHERE a=b; SELECT * FROM t1 IGNORE INDEX(b) WHERE b=''; SELECT * FROM t1 IGNORE INDEX(b) WHERE a=b; Additionally, #1 and #2 fix the originally reported in MDEV-9604 crash in Item::save_in_field(), because now execution goes through a different path, so save_in_field() is called for a Item_time_literal instance (which is non-NULL) rather than a Item_cache_str instance (which could return NULL without setting null_value). 3. Fixing Field_temporal::get_equal_const_item_datetime() to enable equal field propagation for DATETIME and TIMESTAMP in case of comparison (e.g. when ANY_SUBST), for symmetry with Field_newdate::get_equal_const_item(). This fixes a number of problems with empty set returned on comparison to empty/garbage input. Now all SELECT queries in this script return one row for MyISAM and InnoDB, with and without an index on t1.b: CREATE TABLE t1 (a ENUM('a'), b DATETIME, c INT, KEY(b)); INSERT INTO t1 VALUES ('','0000-00-00 00:00:00',0); SELECT * FROM t1 WHERE b=''; SELECT * FROM t1 WHERE a=b; SELECT * FROM t1 IGNORE INDEX(b) WHERE b=''; SELECT * FROM t1 IGNORE INDEX(b) WHERE a=b;
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc17
1 files changed, 16 insertions, 1 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 895f8a00f10..ffa7beb275b 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -5624,6 +5624,18 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd,
}
break;
case ANY_SUBST:
+ if (!is_temporal_type_with_date(const_item->field_type()))
+ {
+ MYSQL_TIME ltime;
+ if (const_item->get_date_with_conversion(&ltime,
+ TIME_FUZZY_DATES |
+ TIME_INVALID_DATES))
+ return NULL;
+ return new (thd->mem_root)
+ Item_datetime_literal_for_invalid_dates(thd, &ltime,
+ ltime.second_part ?
+ TIME_SECOND_PART_DIGITS : 0);
+ }
break;
}
return const_item;
@@ -5932,7 +5944,10 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx,
{
MYSQL_TIME ltime;
// Get the value of const_item with conversion from DATETIME to TIME
- if (const_item->get_time_with_conversion(thd, &ltime, TIME_TIME_ONLY))
+ if (const_item->get_time_with_conversion(thd, &ltime,
+ TIME_TIME_ONLY |
+ TIME_FUZZY_DATES |
+ TIME_INVALID_DATES))
return NULL;
/*
Replace a DATE/DATETIME constant to a TIME constant: