Bug#33546: Slowdown on re-evaluation of constant expressions.
Constant expressions in WHERE/HAVING/ON clauses aren't cached and evaluated for each row. This causes slowdown of query execution especially if constant UDF/SP function are used. Now WHERE/HAVING/ON expressions are analyzed in the top-bottom direction with help of the compile function. When analyzer meets a constant item it sets a flag for the tree transformer to cache the item and doesn't allow tree walker to go deeper. Thus, the topmost item of a constant expression if cached. This is done after all other optimizations were applied to WHERE/HAVING/ON expressions A helper function called cache_const_exprs is added to the JOIN class. It calls compile method with caching analyzer and transformer on WHERE, HAVING, ON expressions if they're present. The cache_const_expr_analyzer and cache_const_expr_transformer functions are added to the Item class. The first one check if the item can be cached and the second caches it if so. A new Item_cache_datetime class is derived from the Item_cache class. It caches both int and string values of the underlying item independently to avoid DATETIME aware int-to-string conversion. Thus it completely relies on the ability of the underlying item to correctly convert DATETIME value from int to string and vice versa. mysql-test/r/func_like.result: A test case result is corrected after fixing bug#33546. mysql-test/r/func_time.result: A test case result is corrected after fixing bug#33546. mysql-test/r/select.result: Added a test case for the bug#33546. mysql-test/r/subselect.result: A test case result is corrected after fixing bug#33546. mysql-test/r/udf.result: Added a test case for the bug#33546. mysql-test/t/select.test: Added a test case for the bug#33546. mysql-test/t/udf.test: Added a test case for the bug#33546. sql/item.cc: Bug#33546: Slowdown on re-evaluation of constant expressions. The cache_const_expr_analyzer and cache_const_expr_transformer functions are added to the Item class. The first one check if the item can be cached and the second caches it if so. Item_cache_datetime class implementation is added. sql/item.h: Bug#33546: Slowdown on re-evaluation of constant expressions. Item_ref and Item_cache classes now returns basic_const_item from underlying item. The cache_const_expr_analyzer and cache_const_expr_transformer functions are added to the Item class. sql/sql_select.cc: Bug#33546: Slowdown on re-evaluation of constant expressions. A helper function called cache_const_exprs is added to the JOIN class. It calls compile method with caching analyzer and transformer on WHERE, HAVING, ON expressions if they're present. sql/sql_select.h: Bug#33546: Slowdown on re-evaluation of constant expressions. A helper function called cache_const_exprs is added to the JOIN class.
This commit is contained in:
parent
9e5d1bb664
commit
987e146604
@ -10,7 +10,7 @@ explain extended select * from t1 where a like concat('abc','%');
|
|||||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
1 SIMPLE t1 index a a 13 NULL 5 20.00 Using where; Using index
|
1 SIMPLE t1 index a a 13 NULL 5 20.00 Using where; Using index
|
||||||
Warnings:
|
Warnings:
|
||||||
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` like concat('abc','%'))
|
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` like <cache>(concat('abc','%')))
|
||||||
select * from t1 where a like "abc%";
|
select * from t1 where a like "abc%";
|
||||||
a
|
a
|
||||||
abc
|
abc
|
||||||
|
@ -928,7 +928,6 @@ select f1 from t1 where cast("2006-1-1" as date) between f1 and cast('zzz' as da
|
|||||||
f1
|
f1
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1292 Incorrect datetime value: 'zzz'
|
Warning 1292 Incorrect datetime value: 'zzz'
|
||||||
Warning 1292 Incorrect datetime value: 'zzz'
|
|
||||||
select f1 from t1 where makedate(2006,1) between date(f1) and date(f3);
|
select f1 from t1 where makedate(2006,1) between date(f1) and date(f3);
|
||||||
f1
|
f1
|
||||||
2006-01-01
|
2006-01-01
|
||||||
|
@ -4423,9 +4423,14 @@ CREATE TABLE t1(a INT);
|
|||||||
INSERT INTO t1 VALUES (2),(3);
|
INSERT INTO t1 VALUES (2),(3);
|
||||||
# Should not crash
|
# Should not crash
|
||||||
SELECT 1 FROM t1 WHERE a <> 1 AND NOT
|
SELECT 1 FROM t1 WHERE a <> 1 AND NOT
|
||||||
ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1))
|
ROW(1,a) <=> ROW(1,(SELECT 1 FROM t1))
|
||||||
INTO @var0;
|
INTO @var0;
|
||||||
ERROR 21000: Subquery returns more than 1 row
|
ERROR 21000: Subquery returns more than 1 row
|
||||||
|
SELECT 1 FROM t1 WHERE a <> 1 AND NOT
|
||||||
|
ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1));
|
||||||
|
1
|
||||||
|
1
|
||||||
|
1
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
End of 5.0 tests
|
End of 5.0 tests
|
||||||
create table t1(a INT, KEY (a));
|
create table t1(a INT, KEY (a));
|
||||||
@ -4577,4 +4582,70 @@ field2
|
|||||||
15:13:38
|
15:13:38
|
||||||
drop table A,AA,B,BB;
|
drop table A,AA,B,BB;
|
||||||
#end of test for bug#45266
|
#end of test for bug#45266
|
||||||
|
#
|
||||||
|
# Bug#33546: Slowdown on re-evaluation of constant expressions.
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
|
||||||
|
CREATE TABLE t2 (b INT);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
|
SELECT * FROM t1 WHERE a = 1 + 1;
|
||||||
|
a
|
||||||
|
2
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a = 1 + 1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 100.00 Using where
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = <cache>((1 + 1)))
|
||||||
|
SELECT * FROM t1 HAVING a = 1 + 1;
|
||||||
|
a
|
||||||
|
2
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 HAVING a = 1 + 1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 100.00
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` having (`test`.`t1`.`a` = <cache>((1 + 1)))
|
||||||
|
SELECT * FROM t1, t2 WHERE a = b + (1 + 1);
|
||||||
|
a b
|
||||||
|
4 2
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a = b + (1 + 1);
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t2 system NULL NULL NULL NULL 1 100.00
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 100.00 Using where
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select `test`.`t1`.`a` AS `a`,'2' AS `b` from `test`.`t1` where (`test`.`t1`.`a` = <cache>(('2' + (1 + 1))))
|
||||||
|
SELECT * FROM t2 LEFT JOIN t1 ON a = b + 1;
|
||||||
|
b a
|
||||||
|
2 3
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t2 LEFT JOIN t1 ON a = b + 1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t2 system NULL NULL NULL NULL 1 100.00
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 100.00
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select '2' AS `b`,`test`.`t1`.`a` AS `a` from `test`.`t1` where 1
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a > UNIX_TIMESTAMP('2009-03-10 00:00:00');
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 100.00 Using where
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > <cache>(unix_timestamp('2009-03-10 00:00:00')))
|
||||||
|
CREATE FUNCTION f1() RETURNS INT DETERMINISTIC
|
||||||
|
BEGIN
|
||||||
|
SET @cnt := @cnt + 1;
|
||||||
|
RETURN 1;
|
||||||
|
END;|
|
||||||
|
SET @cnt := 0;
|
||||||
|
SELECT * FROM t1 WHERE a = f1();
|
||||||
|
a
|
||||||
|
1
|
||||||
|
SELECT @cnt;
|
||||||
|
@cnt
|
||||||
|
1
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a = f1();
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 100.00 Using where
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = <cache>(`f1`()))
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
DROP FUNCTION f1;
|
||||||
|
# End of bug#33546
|
||||||
End of 5.1 tests
|
End of 5.1 tests
|
||||||
|
@ -735,7 +735,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
|
|||||||
Warnings:
|
Warnings:
|
||||||
Note 1249 Select 3 was reduced during optimization
|
Note 1249 Select 3 was reduced during optimization
|
||||||
Note 1249 Select 2 was reduced during optimization
|
Note 1249 Select 2 was reduced during optimization
|
||||||
Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = (1 + 1))
|
Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = <cache>((1 + 1)))
|
||||||
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3);
|
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3);
|
||||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
1 PRIMARY t2 index NULL id 5 NULL 2 100.00 Using where; Using index
|
1 PRIMARY t2 index NULL id 5 NULL 2 100.00 Using where; Using index
|
||||||
|
@ -409,3 +409,18 @@ b
|
|||||||
1
|
1
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
End of 5.0 tests.
|
End of 5.0 tests.
|
||||||
|
#
|
||||||
|
# Bug#33546: Slowdown on re-evaluation of constant expressions.
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (f1 INT);
|
||||||
|
INSERT INTO t1 VALUES(1),(50);
|
||||||
|
CREATE FUNCTION myfunc_double RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
|
||||||
|
EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE f1=1 + myfunc_double(1);
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
|
||||||
|
Warnings:
|
||||||
|
Note 1003 select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`f1` = <cache>((1 + myfunc_double(1 AS `1`))))
|
||||||
|
DROP FUNCTION myfunc_double;
|
||||||
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
End of 5.1 tests.
|
||||||
|
@ -3767,9 +3767,14 @@ INSERT INTO t1 VALUES (2),(3);
|
|||||||
--echo # Should not crash
|
--echo # Should not crash
|
||||||
--error ER_SUBQUERY_NO_1_ROW
|
--error ER_SUBQUERY_NO_1_ROW
|
||||||
SELECT 1 FROM t1 WHERE a <> 1 AND NOT
|
SELECT 1 FROM t1 WHERE a <> 1 AND NOT
|
||||||
ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1))
|
ROW(1,a) <=> ROW(1,(SELECT 1 FROM t1))
|
||||||
INTO @var0;
|
INTO @var0;
|
||||||
|
|
||||||
|
# Query correctly return 2 rows since comparison a <=> fisrt_subquery is
|
||||||
|
# always false, thus the second query is never executed.
|
||||||
|
SELECT 1 FROM t1 WHERE a <> 1 AND NOT
|
||||||
|
ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1));
|
||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
|
||||||
@ -3918,4 +3923,38 @@ SELECT table1 .`time_key` field2 FROM B table1 LEFT JOIN BB JOIN A table5 ON
|
|||||||
|
|
||||||
drop table A,AA,B,BB;
|
drop table A,AA,B,BB;
|
||||||
--echo #end of test for bug#45266
|
--echo #end of test for bug#45266
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug#33546: Slowdown on re-evaluation of constant expressions.
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
|
||||||
|
CREATE TABLE t2 (b INT);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
|
SELECT * FROM t1 WHERE a = 1 + 1;
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a = 1 + 1;
|
||||||
|
SELECT * FROM t1 HAVING a = 1 + 1;
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 HAVING a = 1 + 1;
|
||||||
|
SELECT * FROM t1, t2 WHERE a = b + (1 + 1);
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a = b + (1 + 1);
|
||||||
|
SELECT * FROM t2 LEFT JOIN t1 ON a = b + 1;
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t2 LEFT JOIN t1 ON a = b + 1;
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a > UNIX_TIMESTAMP('2009-03-10 00:00:00');
|
||||||
|
|
||||||
|
delimiter |;
|
||||||
|
CREATE FUNCTION f1() RETURNS INT DETERMINISTIC
|
||||||
|
BEGIN
|
||||||
|
SET @cnt := @cnt + 1;
|
||||||
|
RETURN 1;
|
||||||
|
END;|
|
||||||
|
delimiter ;|
|
||||||
|
|
||||||
|
SET @cnt := 0;
|
||||||
|
SELECT * FROM t1 WHERE a = f1();
|
||||||
|
SELECT @cnt;
|
||||||
|
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a = f1();
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
DROP FUNCTION f1;
|
||||||
|
--echo # End of bug#33546
|
||||||
|
|
||||||
--echo End of 5.1 tests
|
--echo End of 5.1 tests
|
||||||
|
@ -449,3 +449,17 @@ SELECT IF( a = 1, a, a ) AS `b` FROM t1 ORDER BY field( `b`, 1 );
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
--echo End of 5.0 tests.
|
--echo End of 5.0 tests.
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug#33546: Slowdown on re-evaluation of constant expressions.
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (f1 INT);
|
||||||
|
INSERT INTO t1 VALUES(1),(50);
|
||||||
|
--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
|
||||||
|
eval CREATE FUNCTION myfunc_double RETURNS INTEGER SONAME "$UDF_EXAMPLE_LIB";
|
||||||
|
EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE f1=1 + myfunc_double(1);
|
||||||
|
DROP FUNCTION myfunc_double;
|
||||||
|
DROP TABLE t1;
|
||||||
|
--echo #
|
||||||
|
--echo End of 5.1 tests.
|
||||||
|
|
||||||
|
131
sql/item.cc
131
sql/item.cc
@ -5766,6 +5766,67 @@ bool Item::send(Protocol *protocol, String *buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check if an item is a constant one and can be cached.
|
||||||
|
|
||||||
|
@param arg [out] TRUE <=> Cache this item.
|
||||||
|
|
||||||
|
@return TRUE Go deeper in item tree.
|
||||||
|
@return FALSE Don't go deeper in item tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool Item::cache_const_expr_analyzer(uchar **arg)
|
||||||
|
{
|
||||||
|
bool *cache_flag= (bool*)*arg;
|
||||||
|
if (!*cache_flag)
|
||||||
|
{
|
||||||
|
Item *item= real_item();
|
||||||
|
/*
|
||||||
|
Cache constant items unless it's a basic constant, constant field or
|
||||||
|
a subselect (they use their own cache).
|
||||||
|
*/
|
||||||
|
if (const_item() &&
|
||||||
|
!(item->basic_const_item() || item->type() == Item::FIELD_ITEM ||
|
||||||
|
item->type() == SUBSELECT_ITEM ||
|
||||||
|
/*
|
||||||
|
Do not cache GET_USER_VAR() function as its const_item() may
|
||||||
|
return TRUE for the current thread but it still may change
|
||||||
|
during the execution.
|
||||||
|
*/
|
||||||
|
(item->type() == Item::FUNC_ITEM &&
|
||||||
|
((Item_func*)item)->functype() == Item_func::GUSERVAR_FUNC)))
|
||||||
|
*cache_flag= TRUE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Cache item if needed.
|
||||||
|
|
||||||
|
@param arg TRUE <=> Cache this item.
|
||||||
|
|
||||||
|
@return cache if cache needed.
|
||||||
|
@return this otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Item* Item::cache_const_expr_transformer(uchar *arg)
|
||||||
|
{
|
||||||
|
if (*(bool*)arg)
|
||||||
|
{
|
||||||
|
*((bool*)arg)= FALSE;
|
||||||
|
Item_cache *cache= Item_cache::get_cache(this);
|
||||||
|
if (!cache)
|
||||||
|
return NULL;
|
||||||
|
cache->setup(this);
|
||||||
|
cache->store(this);
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_field::send(Protocol *protocol, String *buffer)
|
bool Item_field::send(Protocol *protocol, String *buffer)
|
||||||
{
|
{
|
||||||
return protocol->store(result_field);
|
return protocol->store(result_field);
|
||||||
@ -7127,6 +7188,10 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type)
|
|||||||
case DECIMAL_RESULT:
|
case DECIMAL_RESULT:
|
||||||
return new Item_cache_decimal();
|
return new Item_cache_decimal();
|
||||||
case STRING_RESULT:
|
case STRING_RESULT:
|
||||||
|
if (item->field_type() == MYSQL_TYPE_DATE ||
|
||||||
|
item->field_type() == MYSQL_TYPE_DATETIME ||
|
||||||
|
item->field_type() == MYSQL_TYPE_TIME)
|
||||||
|
return new Item_cache_datetime(item->field_type());
|
||||||
return new Item_cache_str(item);
|
return new Item_cache_str(item);
|
||||||
case ROW_RESULT:
|
case ROW_RESULT:
|
||||||
return new Item_cache_row();
|
return new Item_cache_row();
|
||||||
@ -7208,6 +7273,72 @@ longlong Item_cache_int::val_int()
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Item_cache_datetime::cache_value_int()
|
||||||
|
{
|
||||||
|
value_cached= TRUE;
|
||||||
|
/* Assume here that the underlying item will do correct conversion.*/
|
||||||
|
int_value= example->val_int_result();
|
||||||
|
null_value= example->null_value;
|
||||||
|
unsigned_flag= example->unsigned_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Item_cache_datetime::cache_value()
|
||||||
|
{
|
||||||
|
str_value_cached= TRUE;
|
||||||
|
/* Assume here that the underlying item will do correct conversion.*/
|
||||||
|
String *res= example->str_result(&str_value);
|
||||||
|
if (res && res != &str_value)
|
||||||
|
str_value.copy(*res);
|
||||||
|
null_value= example->null_value;
|
||||||
|
unsigned_flag= example->unsigned_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Item_cache_datetime::store(Item *item, longlong val_arg)
|
||||||
|
{
|
||||||
|
/* An explicit values is given, save it. */
|
||||||
|
value_cached= TRUE;
|
||||||
|
int_value= val_arg;
|
||||||
|
null_value= item->null_value;
|
||||||
|
unsigned_flag= item->unsigned_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String *Item_cache_datetime::val_str(String *str)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!str_value_cached)
|
||||||
|
cache_value();
|
||||||
|
return &str_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
my_decimal *Item_cache_datetime::val_decimal(my_decimal *decimal_val)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value_int();
|
||||||
|
int2my_decimal(E_DEC_FATAL_ERROR, int_value, unsigned_flag, decimal_val);
|
||||||
|
return decimal_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Item_cache_datetime::val_real()
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value_int();
|
||||||
|
return (double) int_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
longlong Item_cache_datetime::val_int()
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
if (!value_cached)
|
||||||
|
cache_value_int();
|
||||||
|
return int_value;
|
||||||
|
}
|
||||||
|
|
||||||
void Item_cache_real::cache_value()
|
void Item_cache_real::cache_value()
|
||||||
{
|
{
|
||||||
value_cached= TRUE;
|
value_cached= TRUE;
|
||||||
|
38
sql/item.h
38
sql/item.h
@ -903,6 +903,9 @@ public:
|
|||||||
virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; }
|
virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; }
|
||||||
virtual bool is_expensive_processor(uchar *arg) { return 0; }
|
virtual bool is_expensive_processor(uchar *arg) { return 0; }
|
||||||
virtual bool register_field_in_read_map(uchar *arg) { return 0; }
|
virtual bool register_field_in_read_map(uchar *arg) { return 0; }
|
||||||
|
|
||||||
|
virtual bool cache_const_expr_analyzer(uchar **arg);
|
||||||
|
virtual Item* cache_const_expr_transformer(uchar *arg);
|
||||||
/*
|
/*
|
||||||
Check if a partition function is allowed
|
Check if a partition function is allowed
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
@ -2292,6 +2295,7 @@ public:
|
|||||||
if (ref && result_type() == ROW_RESULT)
|
if (ref && result_type() == ROW_RESULT)
|
||||||
(*ref)->bring_value();
|
(*ref)->bring_value();
|
||||||
}
|
}
|
||||||
|
bool basic_const_item() { return (*ref)->basic_const_item(); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2977,6 +2981,8 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void store(Item *item);
|
virtual void store(Item *item);
|
||||||
virtual void cache_value()= 0;
|
virtual void cache_value()= 0;
|
||||||
|
bool basic_const_item() const
|
||||||
|
{ return test(example && example->basic_const_item());}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -3127,6 +3133,38 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Item_cache_datetime: public Item_cache
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
String str_value;
|
||||||
|
ulonglong int_value;
|
||||||
|
bool str_value_cached;
|
||||||
|
public:
|
||||||
|
Item_cache_datetime(enum_field_types field_type_arg):
|
||||||
|
Item_cache(field_type_arg), int_value(0), str_value_cached(0)
|
||||||
|
{
|
||||||
|
cmp_context= STRING_RESULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void store(Item *item, longlong val_arg);
|
||||||
|
double val_real();
|
||||||
|
longlong val_int();
|
||||||
|
String* val_str(String *str);
|
||||||
|
my_decimal *val_decimal(my_decimal *);
|
||||||
|
enum Item_result result_type() const { return STRING_RESULT; }
|
||||||
|
bool result_as_longlong() { return TRUE; }
|
||||||
|
/*
|
||||||
|
In order to avoid INT <-> STRING conversion of a DATETIME value
|
||||||
|
two cache_value functions are introduced. One (cache_value) caches STRING
|
||||||
|
value, another (cache_value_int) - INT value. Thus this cache item
|
||||||
|
completely relies on the ability of the underlying item to do the
|
||||||
|
correct conversion.
|
||||||
|
*/
|
||||||
|
void cache_value_int();
|
||||||
|
void cache_value();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Item_type_holder used to store type. name, length of Item for UNIONS &
|
Item_type_holder used to store type. name, length of Item for UNIONS &
|
||||||
derived tables.
|
derived tables.
|
||||||
|
@ -1076,6 +1076,10 @@ JOIN::optimize()
|
|||||||
{
|
{
|
||||||
conds=new Item_int((longlong) 0,1); // Always false
|
conds=new Item_int((longlong) 0,1); // Always false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cache constant expressions in WHERE, HAVING, ON clauses. */
|
||||||
|
cache_const_exprs();
|
||||||
|
|
||||||
if (make_join_select(this, select, conds))
|
if (make_join_select(this, select, conds))
|
||||||
{
|
{
|
||||||
zero_result_cause=
|
zero_result_cause=
|
||||||
@ -17141,6 +17145,41 @@ bool JOIN::change_result(select_result *res)
|
|||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Cache constant expressions in WHERE, HAVING, ON conditions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void JOIN::cache_const_exprs()
|
||||||
|
{
|
||||||
|
bool cache_flag= FALSE;
|
||||||
|
bool *analyzer_arg= &cache_flag;
|
||||||
|
|
||||||
|
/* No need in cache if all tables are constant. */
|
||||||
|
if (const_tables == tables)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (conds)
|
||||||
|
conds->compile(&Item::cache_const_expr_analyzer, (uchar **)&analyzer_arg,
|
||||||
|
&Item::cache_const_expr_transformer, (uchar *)&cache_flag);
|
||||||
|
cache_flag= FALSE;
|
||||||
|
if (having)
|
||||||
|
having->compile(&Item::cache_const_expr_analyzer, (uchar **)&analyzer_arg,
|
||||||
|
&Item::cache_const_expr_transformer, (uchar *)&cache_flag);
|
||||||
|
|
||||||
|
for (JOIN_TAB *tab= join_tab + const_tables; tab < join_tab + tables ; tab++)
|
||||||
|
{
|
||||||
|
if (*tab->on_expr_ref)
|
||||||
|
{
|
||||||
|
cache_flag= FALSE;
|
||||||
|
(*tab->on_expr_ref)->compile(&Item::cache_const_expr_analyzer,
|
||||||
|
(uchar **)&analyzer_arg,
|
||||||
|
&Item::cache_const_expr_transformer,
|
||||||
|
(uchar *)&cache_flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@} (end of group Query_Optimizer)
|
@} (end of group Query_Optimizer)
|
||||||
*/
|
*/
|
||||||
|
@ -555,6 +555,7 @@ public:
|
|||||||
return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 ||
|
return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 ||
|
||||||
select_lex == unit->fake_select_lex));
|
select_lex == unit->fake_select_lex));
|
||||||
}
|
}
|
||||||
|
void cache_const_exprs();
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
TRUE if the query contains an aggregate function but has no GROUP
|
TRUE if the query contains an aggregate function but has no GROUP
|
||||||
|
Loading…
x
Reference in New Issue
Block a user