summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2015-03-12 18:12:15 +0400
committerAlexander Barkov <bar@mariadb.org>2015-03-12 18:12:15 +0400
commitbb3115b256113097bcfd0d80213e160339e4b00b (patch)
tree2130426378c4762344bda6aad5f8e5d16d6cf770
parent129c82bb5916d05ece4efad55e8dede3005559b4 (diff)
downloadmariadb-git-bb3115b256113097bcfd0d80213e160339e4b00b.tar.gz
MDEV-6990 GROUP_MIN_MAX optimization is not applied in some cases when it could
-rw-r--r--mysql-test/r/group_min_max.result54
-rw-r--r--mysql-test/t/group_min_max.test36
-rw-r--r--sql/field.cc32
-rw-r--r--sql/field.h26
-rw-r--r--sql/item_cmpfunc.h11
-rw-r--r--sql/opt_range.cc34
6 files changed, 163 insertions, 30 deletions
diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result
index 9421ea9e740..07de4f7ac9d 100644
--- a/mysql-test/r/group_min_max.result
+++ b/mysql-test/r/group_min_max.result
@@ -3727,3 +3727,57 @@ DROP TABLE t1;
#
# End of 10.0 tests
#
+#
+# Start of 10.1 tests
+#
+#
+# MDEV-6990 GROUP_MIN_MAX optimization is not applied in some cases when it could
+#
+CREATE TABLE t1 (id INT NOT NULL, a DATE, KEY(id,a)) 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');
+EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>='2001-01-04' GROUP BY id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL id 8 NULL 9 Using where; Using index for group-by
+EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104.0 GROUP BY id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL id 8 NULL 9 Using where; Using index for group-by
+EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL id 8 NULL 9 Using where; Using index for group-by
+SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>='2001-01-04' 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>=20010104.0 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>=20010104e0 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
+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 8c9be0ca8db..47d551f8241 100644
--- a/mysql-test/t/group_min_max.test
+++ b/mysql-test/t/group_min_max.test
@@ -1524,3 +1524,39 @@ DROP TABLE t1;
--echo # End of 10.0 tests
--echo #
+
+--echo #
+--echo # Start of 10.1 tests
+--echo #
+
+--echo #
+--echo # MDEV-6990 GROUP_MIN_MAX optimization is not applied in some cases when it could
+--echo #
+CREATE TABLE t1 (id INT NOT NULL, a DATE, KEY(id,a)) 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');
+EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>='2001-01-04' GROUP BY id;
+EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104.0 GROUP BY id;
+EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id;
+SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>='2001-01-04' GROUP BY id;
+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 # End of 10.1 tests
+--echo #
diff --git a/sql/field.cc b/sql/field.cc
index 83560003128..57721d39d32 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1246,6 +1246,18 @@ double Field::pos_in_interval_val_str(Field *min, Field *max, uint data_offset)
}
+/*
+ This handles all numeric and BIT data types.
+*/
+bool Field::can_optimize_group_min_max(const Item_bool_func2 *cond,
+ const Item *const_item)
+{
+ DBUG_ASSERT(cmp_type() != STRING_RESULT);
+ DBUG_ASSERT(cmp_type() != TIME_RESULT);
+ return const_item->cmp_type() != TIME_RESULT;
+}
+
+
/**
Numeric fields base class constructor.
*/
@@ -5257,6 +5269,14 @@ my_decimal *Field_temporal::val_decimal(my_decimal *d)
return TIME_to_my_decimal(&ltime, d);
}
+
+bool Field_temporal::can_optimize_group_min_max(const Item_bool_func2 *cond,
+ const Item *const_item)
+{
+ return true; // Field is of TIME_RESULT, which supersedes everything else.
+}
+
+
/****************************************************************************
** time type
** In string context: HH:MM:SS
@@ -6448,6 +6468,18 @@ uint32 Field_longstr::max_data_length() const
}
+bool Field_longstr::can_optimize_group_min_max(const Item_bool_func2 *cond,
+ const Item *const_item)
+{
+ // Can't use indexes when comparing a string to a number or a date
+ if (const_item->cmp_type() != STRING_RESULT)
+ return false;
+
+ // Don't use an index when comparing strings of different collations.
+ return charset() == ((Item_bool_func2*) cond)->compare_collation();
+}
+
+
double Field_string::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
diff --git a/sql/field.h b/sql/field.h
index cac9a156a95..ef0fa2765a4 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -39,6 +39,7 @@ class Relay_log_info;
class Field;
class Column_statistics;
class Column_statistics_collected;
+class Item_bool_func2;
enum enum_check_fields
{
@@ -963,6 +964,9 @@ public:
return (double) 0.5;
}
+ virtual bool can_optimize_group_min_max(const Item_bool_func2 *cond,
+ const Item *const_item);
+
friend int cre_myisam(char * name, register TABLE *form, uint options,
ulonglong auto_increment_value);
friend class Copy_field;
@@ -1154,6 +1158,8 @@ public:
int store_decimal(const my_decimal *d);
uint32 max_data_length() const;
bool match_collation_to_optimize_range() const { return true; }
+ bool can_optimize_group_min_max(const Item_bool_func2 *cond,
+ const Item *const_item);
};
/* base class for float and double and decimal (old one) */
@@ -1581,6 +1587,12 @@ public:
uint size_of() const { return sizeof(*this); }
uint32 max_display_length() { return 4; }
void move_field_offset(my_ptrdiff_t ptr_diff) {}
+ bool can_optimize_group_min_max(const Item_bool_func2 *cond,
+ const Item *const_item)
+ {
+ DBUG_ASSERT(0);
+ return false;
+ }
};
@@ -1613,6 +1625,8 @@ public:
{
return pos_in_interval_val_real(min, max);
}
+ bool can_optimize_group_min_max(const Item_bool_func2 *cond,
+ const Item *const_item);
};
@@ -2650,6 +2664,18 @@ public:
virtual const uchar *unpack(uchar *to, const uchar *from,
const uchar *from_end, uint param_data);
+ bool can_optimize_group_min_max(const Item_bool_func2 *cond,
+ const Item *const_item)
+ {
+ /*
+ Can't use GROUP_MIN_MAX optimization for ENUM and SET,
+ because the values are stored as numbers in index,
+ while MIN() and MAX() work as strings.
+ It would return the records with min and max enum numeric indexes.
+ "Bug#45300 MAX() and ENUM type" should be fixed first.
+ */
+ return false;
+ }
private:
int do_save_field_metadata(uchar *first_byte);
uint is_equal(Create_field *new_field);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 685e9105aa3..7aaef893415 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -131,6 +131,11 @@ 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;
+ }
};
@@ -419,6 +424,12 @@ public:
{
return (*arg != NULL);
}
+ 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);
+ }
};
/**
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 3cac6e5139e..8f691f4e5dc 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -13412,39 +13412,13 @@ check_group_min_max_predicates(Item *cond, Item_field *min_max_arg_item,
if (!simple_pred(pred, args, &inv))
DBUG_RETURN(FALSE);
- /* Check for compatible string comparisons - similar to get_mm_leaf. */
if (args[0] && args[1] && !args[2]) // this is a binary function
{
- if (args[1]->cmp_type() == TIME_RESULT &&
- min_max_arg_item->field->cmp_type() != TIME_RESULT)
+ 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);
-
- /*
- Can't use GROUP_MIN_MAX optimization for ENUM and SET,
- because the values are stored as numbers in index,
- while MIN() and MAX() work as strings.
- It would return the records with min and max enum numeric indexes.
- "Bug#45300 MAX() and ENUM type" should be fixed first.
- */
- if (min_max_arg_item->field->real_type() == MYSQL_TYPE_ENUM ||
- min_max_arg_item->field->real_type() == MYSQL_TYPE_SET)
- DBUG_RETURN(FALSE);
-
- if (min_max_arg_item->result_type() == STRING_RESULT &&
- /*
- Don't use an index when comparing strings of different collations.
- */
- ((args[1]->result_type() == STRING_RESULT &&
- image_type == Field::itRAW &&
- min_max_arg_item->field->charset() !=
- pred->compare_collation()) ||
- /*
- We can't always use indexes when comparing a string index to a
- number.
- */
- (args[1]->result_type() != STRING_RESULT &&
- min_max_arg_item->field->cmp_type() != args[1]->result_type())))
- DBUG_RETURN(FALSE);
}
}
else