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'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 'JJ')
DROP VIEW v1;
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';
DROP VIEW v1;
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)
The function checks whether a substitution of a field item for
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
@note
......@@ -4759,8 +4759,10 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
bool Item_field::subst_argument_checker(uchar **arg)
{
return (!(*arg) && (result_type() != STRING_RESULT)) ||
((*arg) && (**arg));
return *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)
First the function applies the analyzer to the Item_ref object. Then
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
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
nodes of the tree of the object
......@@ -6460,10 +6464,13 @@ Item* Item_ref::compile(Item_analyzer analyzer, uchar **arg_p,
/* Compile the Item we are referencing. */
DBUG_ASSERT((*ref) != NULL);
uchar *arg_v= *arg_p;
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);
if (*arg_p)
{
uchar *arg_v= *arg_p;
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. */
return (this->*transformer)(arg_t);
......@@ -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
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
@note
......@@ -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 res= (!(*arg) && (result_type() != STRING_RESULT)) ||
((*arg) && (**arg));
bool res= FALSE;
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 */
if (*arg)
**arg= (uchar) 0;
*arg= NULL;
return res;
}
......
......@@ -1094,12 +1094,23 @@ public:
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)
{
if (*arg)
*arg= NULL;
return TRUE;
{
return (*arg != NULL);
}
/*
@brief
Processor used to check acceptability of an item in the defining
......
......@@ -397,7 +397,10 @@ public:
}
Item *neg_transformer(THD *thd);
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
......
......@@ -352,6 +352,8 @@ Item *Item_func::transform(Item_transformer transformer, uchar *argument)
the old item is substituted for a new one.
After this the transformer is applied to the root node
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
nodes of the tree of the object
......@@ -369,7 +371,7 @@ Item *Item_func::compile(Item_analyzer analyzer, uchar **arg_p,
{
if (!(this->*analyzer)(arg_p))
return 0;
if (arg_count)
if (*arg_p && arg_count)
{
Item **arg,**arg_end;
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,
/*
The same parameter value of arg_p must be passed
to analyze any argument of the condition formula.
*/
*/
uchar *arg_v= *arg_p;
Item *new_item= (*arg)->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && *arg != new_item)
......
......@@ -251,6 +251,21 @@ public:
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
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,
as soon the field is not of a string type or the field reference is
an argument of a comparison predicate.
*/
uchar is_subst_valid= (uchar) 1;
uchar *is_subst_valid_ptr= &is_subst_valid;
uchar* is_subst_valid= (uchar *) Item::ANY_SUBST;
cond= cond->compile(&Item::subst_argument_checker,
&is_subst_valid_ptr,
&is_subst_valid,
&Item::equal_fields_propagator,
(uchar *) inherited);
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