Commit 887b594c authored by unknown's avatar unknown

Merge gshchepa@bk-internal.mysql.com:/home/bk/mysql-5.1-opt

into  devsrv-b.mysql.com:/data0/gshchepa/mysql-5.1-opt


sql/item.cc:
  Auto merged
parents c0d75796 1684d47d
...@@ -911,3 +911,31 @@ explain partitions select * from t1 where a>-2 and a <=0; ...@@ -911,3 +911,31 @@ explain partitions select * from t1 where a>-2 and a <=0;
id select_type table partitions type possible_keys key key_len ref rows Extra id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p3 ALL NULL NULL NULL NULL 4 Using where 1 SIMPLE t1 p3 ALL NULL NULL NULL NULL 4 Using where
drop table t1; drop table t1;
CREATE TABLE t1 ( recdate DATETIME NOT NULL )
PARTITION BY RANGE( TO_DAYS(recdate) ) (
PARTITION p0 VALUES LESS THAN ( TO_DAYS('2007-03-08') ),
PARTITION p1 VALUES LESS THAN ( TO_DAYS('2007-04-01') )
);
INSERT INTO t1 VALUES ('2007-03-01 12:00:00');
INSERT INTO t1 VALUES ('2007-03-07 12:00:00');
INSERT INTO t1 VALUES ('2007-03-08 12:00:00');
INSERT INTO t1 VALUES ('2007-03-15 12:00:00');
must use p0 only:
explain partitions select * from t1 where recdate < '2007-03-08 00:00:00';
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 2 Using where
drop table t1;
CREATE TABLE t1 ( recdate DATETIME NOT NULL )
PARTITION BY RANGE( YEAR(recdate) ) (
PARTITION p0 VALUES LESS THAN (2006),
PARTITION p1 VALUES LESS THAN (2007)
);
INSERT INTO t1 VALUES ('2005-03-01 12:00:00');
INSERT INTO t1 VALUES ('2005-03-01 12:00:00');
INSERT INTO t1 VALUES ('2006-03-01 12:00:00');
INSERT INTO t1 VALUES ('2006-03-01 12:00:00');
must use p0 only:
explain partitions select * from t1 where recdate < '2006-01-01 00:00:00';
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 2 Using where
drop table t1;
...@@ -657,6 +657,21 @@ b ...@@ -657,6 +657,21 @@ b
# #
# #
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (a int, b bit(2));
INSERT INTO t1 VALUES (3, 2), (2, 3), (2, 0), (3, 2), (3, 1);
SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a;
COUNT(DISTINCT b)
2
2
DROP TABLE t1;
create table t2 (a int, b bit(2), c char(10));
INSERT INTO t2 VALUES (3, 2, 'two'), (2, 3, 'three'), (2, 0, 'zero'),
(3, 2, 'two'), (3, 1, 'one');
SELECT COUNT(DISTINCT b,c) FROM t2 GROUP BY a;
COUNT(DISTINCT b,c)
2
2
DROP TABLE t2;
End of 5.0 tests End of 5.0 tests
create table t1(a bit(7)); create table t1(a bit(7));
insert into t1 values(0x40); insert into t1 values(0x40);
......
...@@ -761,3 +761,34 @@ insert into t1 values (-15),(-5),(5),(15),(-15),(-5),(5),(15); ...@@ -761,3 +761,34 @@ insert into t1 values (-15),(-5),(5),(15),(-15),(-5),(5),(15);
explain partitions select * from t1 where a>-2 and a <=0; explain partitions select * from t1 where a>-2 and a <=0;
drop table t1; drop table t1;
#
# BUG#27927 Partition pruning not optimal with TO_DAYS function
#
CREATE TABLE t1 ( recdate DATETIME NOT NULL )
PARTITION BY RANGE( TO_DAYS(recdate) ) (
PARTITION p0 VALUES LESS THAN ( TO_DAYS('2007-03-08') ),
PARTITION p1 VALUES LESS THAN ( TO_DAYS('2007-04-01') )
);
INSERT INTO t1 VALUES ('2007-03-01 12:00:00');
INSERT INTO t1 VALUES ('2007-03-07 12:00:00');
INSERT INTO t1 VALUES ('2007-03-08 12:00:00');
INSERT INTO t1 VALUES ('2007-03-15 12:00:00');
-- echo must use p0 only:
explain partitions select * from t1 where recdate < '2007-03-08 00:00:00';
drop table t1;
CREATE TABLE t1 ( recdate DATETIME NOT NULL )
PARTITION BY RANGE( YEAR(recdate) ) (
PARTITION p0 VALUES LESS THAN (2006),
PARTITION p1 VALUES LESS THAN (2007)
);
INSERT INTO t1 VALUES ('2005-03-01 12:00:00');
INSERT INTO t1 VALUES ('2005-03-01 12:00:00');
INSERT INTO t1 VALUES ('2006-03-01 12:00:00');
INSERT INTO t1 VALUES ('2006-03-01 12:00:00');
-- echo must use p0 only:
explain partitions select * from t1 where recdate < '2006-01-01 00:00:00';
drop table t1;
...@@ -304,6 +304,20 @@ SELECT b FROM t1 GROUP BY b; ...@@ -304,6 +304,20 @@ SELECT b FROM t1 GROUP BY b;
--disable_metadata --disable_metadata
DROP TABLE t1; DROP TABLE t1;
#
# BUG#30324 Wrong query result for COUNT(DISTINCT(bit_column))
#
CREATE TABLE t1 (a int, b bit(2));
INSERT INTO t1 VALUES (3, 2), (2, 3), (2, 0), (3, 2), (3, 1);
SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a;
DROP TABLE t1;
create table t2 (a int, b bit(2), c char(10));
INSERT INTO t2 VALUES (3, 2, 'two'), (2, 3, 'three'), (2, 0, 'zero'),
(3, 2, 'two'), (3, 1, 'one');
SELECT COUNT(DISTINCT b,c) FROM t2 GROUP BY a;
DROP TABLE t2;
--echo End of 5.0 tests --echo End of 5.0 tests
# #
......
...@@ -2075,6 +2075,11 @@ Item *Item_field::get_tmp_table_item(THD *thd) ...@@ -2075,6 +2075,11 @@ Item *Item_field::get_tmp_table_item(THD *thd)
return new_item; return new_item;
} }
longlong Item_field::val_int_endpoint(bool left_endp, bool *incl_endp)
{
longlong res= val_int();
return null_value? LONGLONG_MIN : res;
}
/* /*
Create an item from a string we KNOW points to a valid longlong Create an item from a string we KNOW points to a valid longlong
......
...@@ -569,6 +569,43 @@ class Item { ...@@ -569,6 +569,43 @@ class Item {
virtual enum_monotonicity_info get_monotonicity_info() const virtual enum_monotonicity_info get_monotonicity_info() const
{ return NON_MONOTONIC; } { return NON_MONOTONIC; }
/*
Convert "func_arg $CMP$ const" half-interval into "FUNC(func_arg) $CMP2$ const2"
SYNOPSIS
val_int_endpoint()
left_endp FALSE <=> The interval is "x < const" or "x <= const"
TRUE <=> The interval is "x > const" or "x >= const"
incl_endp IN TRUE <=> the comparison is '<' or '>'
FALSE <=> the comparison is '<=' or '>='
OUT The same but for the "F(x) $CMP$ F(const)" comparison
DESCRIPTION
This function is defined only for unary monotonic functions. The caller
supplies the source half-interval
x $CMP$ const
The value of const is supplied implicitly as the value this item's
argument, the form of $CMP$ comparison is specified through the
function's arguments. The calle returns the result interval
F(x) $CMP2$ F(const)
passing back F(const) as the return value, and the form of $CMP2$
through the out parameter. NULL values are assumed to be comparable and
be less than any non-NULL values.
RETURN
The output range bound, which equal to the value of val_int()
- If the value of the function is NULL then the bound is the
smallest possible value of LONGLONG_MIN
*/
virtual longlong val_int_endpoint(bool left_endp, bool *incl_endp)
{ DBUG_ASSERT(0); return 0; }
/* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */ /* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */
/* /*
Return double precision floating point representation of item. Return double precision floating point representation of item.
...@@ -1401,6 +1438,7 @@ class Item_field :public Item_ident ...@@ -1401,6 +1438,7 @@ class Item_field :public Item_ident
{ {
return MONOTONIC_STRICT_INCREASING; return MONOTONIC_STRICT_INCREASING;
} }
longlong val_int_endpoint(bool left_endp, bool *incl_endp);
Field *get_tmp_table_field() { return result_field; } Field *get_tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg) { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return result_field; }
bool get_date(MYSQL_TIME *ltime,uint fuzzydate); bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
......
...@@ -2483,6 +2483,23 @@ bool Item_sum_count_distinct::setup(THD *thd) ...@@ -2483,6 +2483,23 @@ bool Item_sum_count_distinct::setup(THD *thd)
count_field_types(select_lex, tmp_table_param, list, 0); count_field_types(select_lex, tmp_table_param, list, 0);
tmp_table_param->force_copy_fields= force_copy_fields; tmp_table_param->force_copy_fields= force_copy_fields;
DBUG_ASSERT(table == 0); DBUG_ASSERT(table == 0);
/*
Make create_tmp_table() convert BIT columns to BIGINT.
This is needed because BIT fields store parts of their data in table's
null bits, and we don't have methods to compare two table records, which
is needed by Unique which is used when HEAP table is used.
*/
{
List_iterator_fast<Item> li(list);
Item *item;
while ((item= li++))
{
if (item->type() == Item::FIELD_ITEM &&
((Item_field*)item)->field->type() == FIELD_TYPE_BIT)
item->marker=4;
}
}
if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
0, 0,
(select_lex->options | thd->options), (select_lex->options | thd->options),
......
...@@ -962,6 +962,44 @@ enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const ...@@ -962,6 +962,44 @@ enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const
} }
longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
longlong res;
if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
{
/* got NULL, leave the incl_endp intact */
return LONGLONG_MIN;
}
res=(longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
if (args[0]->field_type() == MYSQL_TYPE_DATE)
{
// TO_DAYS() is strictly monotonic for dates, leave incl_endp intact
return res;
}
/*
Handle the special but practically useful case of datetime values that
point to day bound ("strictly less" comparison stays intact):
col < '2007-09-15 00:00:00' -> TO_DAYS(col) < TO_DAYS('2007-09-15')
which is different from the general case ("strictly less" changes to
"less or equal"):
col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15')
*/
if (!left_endp && !(ltime.hour || ltime.minute || ltime.second ||
ltime.second_part))
; /* do nothing */
else
*incl_endp= TRUE;
return res;
}
longlong Item_func_dayofyear::val_int() longlong Item_func_dayofyear::val_int()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
...@@ -1152,7 +1190,7 @@ longlong Item_func_year::val_int() ...@@ -1152,7 +1190,7 @@ longlong Item_func_year::val_int()
Get information about this Item tree monotonicity Get information about this Item tree monotonicity
SYNOPSIS SYNOPSIS
Item_func_to_days::get_monotonicity_info() Item_func_year::get_monotonicity_info()
DESCRIPTION DESCRIPTION
Get information about monotonicity of the function represented by this item Get information about monotonicity of the function represented by this item
...@@ -1171,6 +1209,37 @@ enum_monotonicity_info Item_func_year::get_monotonicity_info() const ...@@ -1171,6 +1209,37 @@ enum_monotonicity_info Item_func_year::get_monotonicity_info() const
return NON_MONOTONIC; return NON_MONOTONIC;
} }
longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp)
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
{
/* got NULL, leave the incl_endp intact */
return LONGLONG_MIN;
}
/*
Handle the special but practically useful case of datetime values that
point to year bound ("strictly less" comparison stays intact) :
col < '2007-01-01 00:00:00' -> YEAR(col) < 2007
which is different from the general case ("strictly less" changes to
"less or equal"):
col < '2007-09-15 23:00:00' -> YEAR(col) <= 2007
*/
if (!left_endp && ltime.day == 1 && ltime.month == 1 &&
!(ltime.hour || ltime.minute || ltime.second || ltime.second_part))
; /* do nothing */
else
*incl_endp= TRUE;
return ltime.year;
}
longlong Item_func_unix_timestamp::val_int() longlong Item_func_unix_timestamp::val_int()
{ {
MYSQL_TIME ltime; MYSQL_TIME ltime;
......
...@@ -68,6 +68,7 @@ class Item_func_to_days :public Item_int_func ...@@ -68,6 +68,7 @@ class Item_func_to_days :public Item_int_func
maybe_null=1; maybe_null=1;
} }
enum_monotonicity_info get_monotonicity_info() const; enum_monotonicity_info get_monotonicity_info() const;
longlong val_int_endpoint(bool left_endp, bool *incl_endp);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
}; };
...@@ -248,6 +249,7 @@ class Item_func_year :public Item_int_func ...@@ -248,6 +249,7 @@ class Item_func_year :public Item_int_func
longlong val_int(); longlong val_int();
const char *func_name() const { return "year"; } const char *func_name() const { return "year"; }
enum_monotonicity_info get_monotonicity_info() const; enum_monotonicity_info get_monotonicity_info() const;
longlong val_int_endpoint(bool left_endp, bool *incl_endp);
void fix_length_and_dec() void fix_length_and_dec()
{ {
decimals=0; decimals=0;
......
...@@ -139,20 +139,6 @@ class partition_info : public Sql_alloc ...@@ -139,20 +139,6 @@ class partition_info : public Sql_alloc
*/ */
get_partitions_in_range_iter get_subpart_iter_for_interval; get_partitions_in_range_iter get_subpart_iter_for_interval;
/*
Valid iff
get_part_iter_for_interval=get_part_iter_for_interval_via_walking:
controls how we'll process "field < C" and "field > C" intervals.
If the partitioning function F is strictly increasing, then for any x, y
"x < y" => "F(x) < F(y)" (*), i.e. when we get interval "field < C"
we can perform partition pruning on the equivalent "F(field) < F(C)".
If the partitioning function not strictly increasing (it is simply
increasing), then instead of (*) we get "x < y" => "F(x) <= F(y)"
i.e. for interval "field < C" we can perform partition pruning for
"F(field) <= F(C)".
*/
bool range_analysis_include_bounds;
/******************************************** /********************************************
* INTERVAL ANALYSIS ENDS * INTERVAL ANALYSIS ENDS
********************************************/ ********************************************/
......
...@@ -2743,7 +2743,8 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info, ...@@ -2743,7 +2743,8 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
uint min_list_index= 0, max_list_index= part_info->no_list_values - 1; uint min_list_index= 0, max_list_index= part_info->no_list_values - 1;
longlong list_value; longlong list_value;
/* Get the partitioning function value for the endpoint */ /* Get the partitioning function value for the endpoint */
longlong part_func_value= part_val_int(part_info->part_expr); longlong part_func_value=
part_info->part_expr->val_int_endpoint(left_endpoint, &include_endpoint);
bool unsigned_flag= part_info->part_expr->unsigned_flag; bool unsigned_flag= part_info->part_expr->unsigned_flag;
DBUG_ENTER("get_list_array_idx_for_endpoint"); DBUG_ENTER("get_list_array_idx_for_endpoint");
...@@ -2887,7 +2888,9 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, ...@@ -2887,7 +2888,9 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
uint max_partition= part_info->no_parts - 1; uint max_partition= part_info->no_parts - 1;
uint min_part_id= 0, max_part_id= max_partition, loc_part_id; uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
/* Get the partitioning function value for the endpoint */ /* Get the partitioning function value for the endpoint */
longlong part_func_value= part_val_int(part_info->part_expr); longlong part_func_value=
part_info->part_expr->val_int_endpoint(left_endpoint, &include_endpoint);
bool unsigned_flag= part_info->part_expr->unsigned_flag; bool unsigned_flag= part_info->part_expr->unsigned_flag;
DBUG_ENTER("get_partition_id_range_for_endpoint"); DBUG_ENTER("get_partition_id_range_for_endpoint");
...@@ -6590,8 +6593,6 @@ void make_used_partitions_str(partition_info *part_info, String *parts_str) ...@@ -6590,8 +6593,6 @@ void make_used_partitions_str(partition_info *part_info, String *parts_str)
#ifdef WITH_PARTITION_STORAGE_ENGINE #ifdef WITH_PARTITION_STORAGE_ENGINE
static void set_up_range_analysis_info(partition_info *part_info) static void set_up_range_analysis_info(partition_info *part_info)
{ {
enum_monotonicity_info minfo;
/* Set the catch-all default */ /* Set the catch-all default */
part_info->get_part_iter_for_interval= NULL; part_info->get_part_iter_for_interval= NULL;
part_info->get_subpart_iter_for_interval= NULL; part_info->get_subpart_iter_for_interval= NULL;
...@@ -6603,11 +6604,8 @@ static void set_up_range_analysis_info(partition_info *part_info) ...@@ -6603,11 +6604,8 @@ static void set_up_range_analysis_info(partition_info *part_info)
switch (part_info->part_type) { switch (part_info->part_type) {
case RANGE_PARTITION: case RANGE_PARTITION:
case LIST_PARTITION: case LIST_PARTITION:
minfo= part_info->part_expr->get_monotonicity_info(); if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC)
if (minfo != NON_MONOTONIC)
{ {
part_info->range_analysis_include_bounds=
test(minfo == MONOTONIC_INCREASING);
part_info->get_part_iter_for_interval= part_info->get_part_iter_for_interval=
get_part_iter_for_interval_via_mapping; get_part_iter_for_interval_via_mapping;
goto setup_subparts; goto setup_subparts;
...@@ -6775,8 +6773,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, ...@@ -6775,8 +6773,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
index-in-ordered-array-of-list-constants (for LIST) space. index-in-ordered-array-of-list-constants (for LIST) space.
*/ */
store_key_image_to_rec(field, min_value, field_len); store_key_image_to_rec(field, min_value, field_len);
bool include_endp= part_info->range_analysis_include_bounds || bool include_endp= !test(flags & NEAR_MIN);
!test(flags & NEAR_MIN);
part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp); part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp);
part_iter->part_nums.cur= part_iter->part_nums.start; part_iter->part_nums.cur= part_iter->part_nums.start;
if (part_iter->part_nums.start == max_endpoint_val) if (part_iter->part_nums.start == max_endpoint_val)
...@@ -6790,8 +6787,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, ...@@ -6790,8 +6787,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
else else
{ {
store_key_image_to_rec(field, max_value, field_len); store_key_image_to_rec(field, max_value, field_len);
bool include_endp= part_info->range_analysis_include_bounds || bool include_endp= !test(flags & NEAR_MAX);
!test(flags & NEAR_MAX);
part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp); part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp);
if (part_iter->part_nums.start == part_iter->part_nums.end && if (part_iter->part_nums.start == part_iter->part_nums.end &&
!part_iter->ret_null_part) !part_iter->ret_null_part)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment