diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 07de4f7ac9d..8562d1169ee 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -3779,5 +3779,95 @@ id MIN(a) MAX(a) 4 2001-01-04 2001-01-04 DROP TABLE t1; # +# MDEV-8229 GROUP_MIN_MAX is erroneously applied for BETWEEN in some cases +# +SET NAMES latin1; +CREATE TABLE t1 (id INT NOT NULL, a VARCHAR(20)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,'2001-01-01'); +INSERT INTO t1 VALUES (1,'2001-01-02'); +INSERT INTO t1 VALUES (1,'2001-01-03'); +INSERT INTO t1 VALUES (1,' 2001-01-04'); +INSERT INTO t1 VALUES (2,'2001-01-01'); +INSERT INTO t1 VALUES (2,'2001-01-02'); +INSERT INTO t1 VALUES (2,'2001-01-03'); +INSERT INTO t1 VALUES (2,' 2001-01-04'); +INSERT INTO t1 VALUES (3,'2001-01-01'); +INSERT INTO t1 VALUES (3,'2001-01-02'); +INSERT INTO t1 VALUES (3,'2001-01-03'); +INSERT INTO t1 VALUES (3,' 2001-01-04'); +INSERT INTO t1 VALUES (4,'2001-01-01'); +INSERT INTO t1 VALUES (4,'2001-01-02'); +INSERT INTO t1 VALUES (4,'2001-01-03'); +INSERT INTO t1 VALUES (4,' 2001-01-04'); +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN ' 2001-01-04' AND '2001-01-05' GROUP BY id; +id MIN(a) MAX(a) +1 2001-01-04 2001-01-03 +2 2001-01-04 2001-01-03 +3 2001-01-04 2001-01-03 +4 2001-01-04 2001-01-03 +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND '2001-01-05' GROUP BY id; +id MIN(a) MAX(a) +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND DATE'2001-01-05' GROUP BY id; +id MIN(a) MAX(a) +1 2001-01-04 2001-01-04 +2 2001-01-04 2001-01-04 +3 2001-01-04 2001-01-04 +4 2001-01-04 2001-01-04 +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND '2001-01-05' GROUP BY id; +id MIN(a) MAX(a) +1 2001-01-04 2001-01-04 +2 2001-01-04 2001-01-04 +3 2001-01-04 2001-01-04 +4 2001-01-04 2001-01-04 +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND DATE'2001-01-05' GROUP BY id; +id MIN(a) MAX(a) +1 2001-01-04 2001-01-04 +2 2001-01-04 2001-01-04 +3 2001-01-04 2001-01-04 +4 2001-01-04 2001-01-04 +ALTER TABLE t1 ADD KEY(id,a); +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN ' 2001-01-04' AND '2001-01-05' GROUP BY id; +id MIN(a) MAX(a) +1 2001-01-04 2001-01-03 +2 2001-01-04 2001-01-03 +3 2001-01-04 2001-01-03 +4 2001-01-04 2001-01-03 +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND '2001-01-05' GROUP BY id; +id MIN(a) MAX(a) +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND DATE'2001-01-05' GROUP BY id; +id MIN(a) MAX(a) +1 2001-01-04 2001-01-04 +2 2001-01-04 2001-01-04 +3 2001-01-04 2001-01-04 +4 2001-01-04 2001-01-04 +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND '2001-01-05' GROUP BY id; +id MIN(a) MAX(a) +1 2001-01-04 2001-01-04 +2 2001-01-04 2001-01-04 +3 2001-01-04 2001-01-04 +4 2001-01-04 2001-01-04 +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND DATE'2001-01-05' GROUP BY id; +id MIN(a) MAX(a) +1 2001-01-04 2001-01-04 +2 2001-01-04 2001-01-04 +3 2001-01-04 2001-01-04 +4 2001-01-04 2001-01-04 +EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN ' 2001-01-04' AND '2001-01-05' GROUP BY id; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL id 27 NULL 9 Using where; Using index for group-by +EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND '2001-01-05' GROUP BY id; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL id 27 NULL 9 Using where; Using index for group-by +EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND DATE'2001-01-05' GROUP BY id; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL id 27 NULL 16 Using where; Using index +EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND '2001-01-05' GROUP BY id; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL id 27 NULL 16 Using where; Using index +EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND DATE'2001-01-05' GROUP BY id; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL id 27 NULL 16 Using where; Using index +DROP TABLE t1; +# # End of 10.1 tests # diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index 47d551f8241..df20b80c778 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -1557,6 +1557,46 @@ SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104.0 GROUP BY id; SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id; DROP TABLE t1; +--echo # +--echo # MDEV-8229 GROUP_MIN_MAX is erroneously applied for BETWEEN in some cases +--echo # +SET NAMES latin1; +CREATE TABLE t1 (id INT NOT NULL, a VARCHAR(20)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,'2001-01-01'); +INSERT INTO t1 VALUES (1,'2001-01-02'); +INSERT INTO t1 VALUES (1,'2001-01-03'); +INSERT INTO t1 VALUES (1,' 2001-01-04'); +INSERT INTO t1 VALUES (2,'2001-01-01'); +INSERT INTO t1 VALUES (2,'2001-01-02'); +INSERT INTO t1 VALUES (2,'2001-01-03'); +INSERT INTO t1 VALUES (2,' 2001-01-04'); +INSERT INTO t1 VALUES (3,'2001-01-01'); +INSERT INTO t1 VALUES (3,'2001-01-02'); +INSERT INTO t1 VALUES (3,'2001-01-03'); +INSERT INTO t1 VALUES (3,' 2001-01-04'); +INSERT INTO t1 VALUES (4,'2001-01-01'); +INSERT INTO t1 VALUES (4,'2001-01-02'); +INSERT INTO t1 VALUES (4,'2001-01-03'); +INSERT INTO t1 VALUES (4,' 2001-01-04'); +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN ' 2001-01-04' AND '2001-01-05' GROUP BY id; +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND '2001-01-05' GROUP BY id; +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND DATE'2001-01-05' GROUP BY id; +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND '2001-01-05' GROUP BY id; +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND DATE'2001-01-05' GROUP BY id; +ALTER TABLE t1 ADD KEY(id,a); +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN ' 2001-01-04' AND '2001-01-05' GROUP BY id; +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND '2001-01-05' GROUP BY id; +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND DATE'2001-01-05' GROUP BY id; +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND '2001-01-05' GROUP BY id; +SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND DATE'2001-01-05' GROUP BY id; +EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN ' 2001-01-04' AND '2001-01-05' GROUP BY id; +EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND '2001-01-05' GROUP BY id; +EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND DATE'2001-01-05' GROUP BY id; +EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN DATE'2001-01-04' AND '2001-01-05' GROUP BY id; +EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a BETWEEN '2001-01-04' AND DATE'2001-01-05' GROUP BY id; +DROP TABLE t1; + + --echo # --echo # End of 10.1 tests --echo # diff --git a/sql/field.cc b/sql/field.cc index ba6d4ffdcd5..d03c20fad46 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1261,7 +1261,7 @@ bool Field::can_optimize_keypart_ref(const Item_func *cond, /* This handles all numeric and BIT data types. */ -bool Field::can_optimize_group_min_max(const Item_bool_func2 *cond, +bool Field::can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const { DBUG_ASSERT(cmp_type() != STRING_RESULT); @@ -5289,7 +5289,7 @@ bool Field_temporal::can_optimize_keypart_ref(const Item_func *cond, } -bool Field_temporal::can_optimize_group_min_max(const Item_bool_func2 *cond, +bool Field_temporal::can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const { return true; // Field is of TIME_RESULT, which supersedes everything else. @@ -6506,7 +6506,7 @@ bool Field_longstr::can_optimize_hash_join(const Item_func *cond, } -bool Field_longstr::can_optimize_group_min_max(const Item_bool_func2 *cond, +bool Field_longstr::can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const { /* diff --git a/sql/field.h b/sql/field.h index 4ca493eedfc..64a86782f65 100644 --- a/sql/field.h +++ b/sql/field.h @@ -40,7 +40,7 @@ class Field; class Column_statistics; class Column_statistics_collected; class Item_func; -class Item_bool_func2; +class Item_bool_func; enum enum_check_fields { @@ -986,7 +986,7 @@ public: { return can_optimize_keypart_ref(cond, item); } - virtual bool can_optimize_group_min_max(const Item_bool_func2 *cond, + virtual bool can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const; bool can_optimize_outer_join_table_elimination(const Item_func *cond, const Item *item) const @@ -1191,7 +1191,7 @@ public: bool match_collation_to_optimize_range() const { return true; } bool can_optimize_keypart_ref(const Item_func *cond, const Item *item) const; bool can_optimize_hash_join(const Item_func *cond, const Item *item) const; - bool can_optimize_group_min_max(const Item_bool_func2 *cond, + bool can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const; }; @@ -1625,7 +1625,7 @@ public: DBUG_ASSERT(0); return false; } - bool can_optimize_group_min_max(const Item_bool_func2 *cond, + bool can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const { DBUG_ASSERT(0); @@ -1664,7 +1664,7 @@ public: return pos_in_interval_val_real(min, max); } bool can_optimize_keypart_ref(const Item_func *cond, const Item *item) const; - bool can_optimize_group_min_max(const Item_bool_func2 *cond, + bool can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const; }; @@ -2721,7 +2721,7 @@ public: const uchar *from_end, uint param_data); bool can_optimize_keypart_ref(const Item_func *cond, const Item *item) const; - bool can_optimize_group_min_max(const Item_bool_func2 *cond, + bool can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const { /* diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index b077a52279d..c9b6b30f5b1 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -136,11 +136,6 @@ public: bool is_bool_type() { return true; } void fix_length_and_dec() { decimals=0; max_length=1; } uint decimal_precision() const { return 1; } - virtual bool can_optimize_group_min_max(Item_field *min_max_arg_item, - const Item *const_item) const - { - return false; - } }; @@ -338,12 +333,6 @@ public: Item_bool_func2::cleanup(); cmp.cleanup(); } - bool can_optimize_group_min_max(Item_field *min_max_arg_item, - const Item *const_item) const - { - return min_max_arg_item->field->can_optimize_group_min_max(this, - const_item); - } void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d8aeca349ec..57a08e33b90 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -13455,13 +13455,22 @@ check_group_min_max_predicates(Item *cond, Item_field *min_max_arg_item, if (!simple_pred(pred, args, &inv)) DBUG_RETURN(FALSE); - if (args[0] && args[1] && !args[2]) // this is a binary function + if (args[0] && args[1]) // this is a binary function or BETWEEN { DBUG_ASSERT(pred->is_bool_type()); Item_bool_func *bool_func= (Item_bool_func*) pred; - if (!bool_func->can_optimize_group_min_max(min_max_arg_item, - args[1])) - DBUG_RETURN(FALSE); + Field *field= min_max_arg_item->field; + if (!args[2]) // this is a binary function + { + if (!field->can_optimize_group_min_max(bool_func, args[1])) + DBUG_RETURN(FALSE); + } + else // this is BETWEEN + { + if (!field->can_optimize_group_min_max(bool_func, args[1]) || + !field->can_optimize_group_min_max(bool_func, args[2])) + DBUG_RETURN(FALSE); + } } } else