Commit 3d34cada authored by Igor Babaev's avatar Igor Babaev

Merge

parents d7fb598c 8e33aa9a
...@@ -4138,3 +4138,33 @@ Warning 1292 Truncated incorrect INTEGER value: 'VV' ...@@ -4138,3 +4138,33 @@ Warning 1292 Truncated incorrect INTEGER value: 'VV'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 'JJ') Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 'JJ')
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1; DROP TABLE t1;
#
# Bug#777745: crash with equality propagation
# over view fields
#
CREATE TABLE t1 (a int NOT NULL ) ;
INSERT INTO t1 VALUES (2), (1);
CREATE TABLE t2 (a int NOT NULL , b int NOT NULL) ;
INSERT INTO t2 VALUES (2,20),(2,30);
CREATE VIEW v2 AS SELECT * FROM t2;
EXPLAIN
SELECT * FROM t1,v2
WHERE v2.a = t1.a AND v2.a = 2 AND v2.a IS NULL AND t1.a != 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
SELECT * FROM t1,v2
WHERE v2.a = t1.a AND v2.a = 2 AND v2.a IS NULL AND t1.a != 0;
a a b
EXPLAIN
SELECT * FROM t1,v2
WHERE v2.a = t1.a AND v2.a = 2 AND v2.a+1 > 2 AND t1.a != 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
SELECT * FROM t1,v2
WHERE v2.a = t1.a AND v2.a = 2 AND v2.a+1 > 2 AND t1.a != 0;
a a b
2 2 20
2 2 30
DROP VIEW v2;
DROP TABLE t1,t2;
...@@ -4085,3 +4085,31 @@ SELECT * FROM v1 WHERE a > 'JJ' OR a AND a = 'VV'; ...@@ -4085,3 +4085,31 @@ SELECT * FROM v1 WHERE a > 'JJ' OR a AND a = 'VV';
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # Bug#777745: crash with equality propagation
--echo # over view fields
--echo #
CREATE TABLE t1 (a int NOT NULL ) ;
INSERT INTO t1 VALUES (2), (1);
CREATE TABLE t2 (a int NOT NULL , b int NOT NULL) ;
INSERT INTO t2 VALUES (2,20),(2,30);
CREATE VIEW v2 AS SELECT * FROM t2;
EXPLAIN
SELECT * FROM t1,v2
WHERE v2.a = t1.a AND v2.a = 2 AND v2.a IS NULL AND t1.a != 0;
SELECT * FROM t1,v2
WHERE v2.a = t1.a AND v2.a = 2 AND v2.a IS NULL AND t1.a != 0;
EXPLAIN
SELECT * FROM t1,v2
WHERE v2.a = t1.a AND v2.a = 2 AND v2.a+1 > 2 AND t1.a != 0;
SELECT * FROM t1,v2
WHERE v2.a = t1.a AND v2.a = 2 AND v2.a+1 > 2 AND t1.a != 0;
DROP VIEW v2;
DROP TABLE t1,t2;
...@@ -4733,7 +4733,7 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal) ...@@ -4733,7 +4733,7 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
The function checks whether a substitution of a field item for The function checks whether a substitution of a field item for
an equal item is valid. an equal item is valid.
@param arg *arg != NULL && **arg <-> the field is in the context @param arg *arg != NULL <-> the field is in the context
where substitution for an equal item is valid where substitution for an equal item is valid
@note @note
...@@ -4759,8 +4759,10 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal) ...@@ -4759,8 +4759,10 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
bool Item_field::subst_argument_checker(uchar **arg) bool Item_field::subst_argument_checker(uchar **arg)
{ {
return (!(*arg) && (result_type() != STRING_RESULT)) || return *arg &&
((*arg) && (**arg)); (*arg == (uchar *) Item::ANY_SUBST ||
result_type() != STRING_RESULT ||
(field->flags & BINARY_FLAG));
} }
...@@ -6437,9 +6439,11 @@ Item* Item_ref::transform(Item_transformer transformer, uchar *arg) ...@@ -6437,9 +6439,11 @@ Item* Item_ref::transform(Item_transformer transformer, uchar *arg)
First the function applies the analyzer to the Item_ref object. Then First the function applies the analyzer to the Item_ref object. Then
if the analizer succeeeds we first applies the compile method to the if the analizer succeeeds we first applies the compile method to the
object the Item_ref object is referencing. If this returns a new object the Item_ref object is referencing. If this returns a new
item the old item is substituted for a new one. After this the item the old item is substituted for a new one. After this the
transformer is applied to the Item_ref object itself. transformer is applied to the Item_ref object itself.
The compile function is not called if the analyzer returns NULL
in the parameter arg_p.
@param analyzer the analyzer callback function to be applied to the @param analyzer the analyzer callback function to be applied to the
nodes of the tree of the object nodes of the tree of the object
...@@ -6460,10 +6464,13 @@ Item* Item_ref::compile(Item_analyzer analyzer, uchar **arg_p, ...@@ -6460,10 +6464,13 @@ Item* Item_ref::compile(Item_analyzer analyzer, uchar **arg_p,
/* Compile the Item we are referencing. */ /* Compile the Item we are referencing. */
DBUG_ASSERT((*ref) != NULL); DBUG_ASSERT((*ref) != NULL);
uchar *arg_v= *arg_p; if (*arg_p)
Item *new_item= (*ref)->compile(analyzer, &arg_v, transformer, arg_t); {
if (new_item && *ref != new_item) uchar *arg_v= *arg_p;
current_thd->change_item_tree(ref, new_item); Item *new_item= (*ref)->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && *ref != new_item)
current_thd->change_item_tree(ref, new_item);
}
/* Transform this Item object. */ /* Transform this Item object. */
return (this->*transformer)(arg_t); return (this->*transformer)(arg_t);
...@@ -7365,7 +7372,7 @@ Item_equal *Item_direct_view_ref::find_item_equal(COND_EQUAL *cond_equal) ...@@ -7365,7 +7372,7 @@ Item_equal *Item_direct_view_ref::find_item_equal(COND_EQUAL *cond_equal)
The function checks whether a substitution of a reference to field item for The function checks whether a substitution of a reference to field item for
an equal item is valid. an equal item is valid.
@param arg *arg != NULL && **arg <-> the reference is in the context @param arg *arg != NULL <-> the reference is in the context
where substitution for an equal item is valid where substitution for an equal item is valid
@note @note
...@@ -7378,11 +7385,19 @@ Item_equal *Item_direct_view_ref::find_item_equal(COND_EQUAL *cond_equal) ...@@ -7378,11 +7385,19 @@ Item_equal *Item_direct_view_ref::find_item_equal(COND_EQUAL *cond_equal)
*/ */
bool Item_direct_view_ref::subst_argument_checker(uchar **arg) bool Item_direct_view_ref::subst_argument_checker(uchar **arg)
{ {
bool res= (!(*arg) && (result_type() != STRING_RESULT)) || bool res= FALSE;
((*arg) && (**arg)); if (*arg)
{
Item *item= real_item();
if (item->type() == FIELD_ITEM &&
(*arg == (uchar *) Item::ANY_SUBST ||
result_type() != STRING_RESULT ||
(((Item_field *) item)->field->flags & BINARY_FLAG)))
res= TRUE;
}
/* Block any substitution into the wrapped object */ /* Block any substitution into the wrapped object */
if (*arg) if (*arg)
**arg= (uchar) 0; *arg= NULL;
return res; return res;
} }
......
...@@ -1094,12 +1094,23 @@ public: ...@@ -1094,12 +1094,23 @@ public:
return FALSE; return FALSE;
} }
/*
The enumeration Subst_constraint is currently used only in implementations
of the virtual function subst_argument_checker.
*/
enum Subst_constraint
{
NO_SUBST= 0, /* No substitution for a field is allowed */
ANY_SUBST, /* Any substitution for a field is allowed */
IDENTITY_SUBST /* Substitution for a field is allowed if any two
different values of the field type are not equal */
};
virtual bool subst_argument_checker(uchar **arg) virtual bool subst_argument_checker(uchar **arg)
{ {
if (*arg) return (*arg != NULL);
*arg= NULL;
return TRUE;
} }
/* /*
@brief @brief
Processor used to check acceptability of an item in the defining Processor used to check acceptability of an item in the defining
......
...@@ -397,7 +397,10 @@ public: ...@@ -397,7 +397,10 @@ public:
} }
Item *neg_transformer(THD *thd); Item *neg_transformer(THD *thd);
virtual Item *negated_item(); virtual Item *negated_item();
bool subst_argument_checker(uchar **arg) { return TRUE; } bool subst_argument_checker(uchar **arg)
{
return (*arg != NULL);
}
}; };
class Item_func_not :public Item_bool_func class Item_func_not :public Item_bool_func
......
...@@ -352,6 +352,8 @@ Item *Item_func::transform(Item_transformer transformer, uchar *argument) ...@@ -352,6 +352,8 @@ Item *Item_func::transform(Item_transformer transformer, uchar *argument)
the old item is substituted for a new one. the old item is substituted for a new one.
After this the transformer is applied to the root node After this the transformer is applied to the root node
of the Item_func object. of the Item_func object.
The compile function is not called if the analyzer returns NULL
in the parameter arg_p.
@param analyzer the analyzer callback function to be applied to the @param analyzer the analyzer callback function to be applied to the
nodes of the tree of the object nodes of the tree of the object
...@@ -369,7 +371,7 @@ Item *Item_func::compile(Item_analyzer analyzer, uchar **arg_p, ...@@ -369,7 +371,7 @@ Item *Item_func::compile(Item_analyzer analyzer, uchar **arg_p,
{ {
if (!(this->*analyzer)(arg_p)) if (!(this->*analyzer)(arg_p))
return 0; return 0;
if (arg_count) if (*arg_p && arg_count)
{ {
Item **arg,**arg_end; Item **arg,**arg_end;
for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++) for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
...@@ -377,7 +379,7 @@ Item *Item_func::compile(Item_analyzer analyzer, uchar **arg_p, ...@@ -377,7 +379,7 @@ Item *Item_func::compile(Item_analyzer analyzer, uchar **arg_p,
/* /*
The same parameter value of arg_p must be passed The same parameter value of arg_p must be passed
to analyze any argument of the condition formula. to analyze any argument of the condition formula.
*/ */
uchar *arg_v= *arg_p; uchar *arg_v= *arg_p;
Item *new_item= (*arg)->compile(analyzer, &arg_v, transformer, arg_t); Item *new_item= (*arg)->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && *arg != new_item) if (new_item && *arg != new_item)
......
...@@ -251,6 +251,21 @@ public: ...@@ -251,6 +251,21 @@ public:
return FALSE; return FALSE;
} }
/*
By default only substitution for a field whose two different values
are never equal is allowed in the arguments of a function.
This is overruled for the direct arguments of comparison functions.
*/
bool subst_argument_checker(uchar **arg)
{
if (*arg)
{
*arg= (uchar *) Item::IDENTITY_SUBST;
return TRUE;
}
return FALSE;
}
/* /*
We assume the result of any function that has a TIMESTAMP argument to be We assume the result of any function that has a TIMESTAMP argument to be
timezone-dependent, since a TIMESTAMP value in both numeric and string timezone-dependent, since a TIMESTAMP value in both numeric and string
......
...@@ -9902,10 +9902,9 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, ...@@ -9902,10 +9902,9 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
as soon the field is not of a string type or the field reference is as soon the field is not of a string type or the field reference is
an argument of a comparison predicate. an argument of a comparison predicate.
*/ */
uchar is_subst_valid= (uchar) 1; uchar* is_subst_valid= (uchar *) Item::ANY_SUBST;
uchar *is_subst_valid_ptr= &is_subst_valid;
cond= cond->compile(&Item::subst_argument_checker, cond= cond->compile(&Item::subst_argument_checker,
&is_subst_valid_ptr, &is_subst_valid,
&Item::equal_fields_propagator, &Item::equal_fields_propagator,
(uchar *) inherited); (uchar *) inherited);
cond->update_used_tables(); cond->update_used_tables();
......
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