mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
Make marking/testing of top level item uniform
There where several different implementations of is_top_level_item(), with different variable names and tests. In some cases the code used 'is_top_level_item()' as a test, in other cases it accessed the variable directrly. This patch makes all usage of 'top_level_item' uniform. The new implementation stores the 'is_tol_level_item()' flag as part of base_flags. This saves 7 bytes in all items that previously stored the flag in it's own bool. I had to keep 'top_level_item()' virtual to ensure that Item_bool_const item's will not be updated. 'is_top_level_item()' is not virtual anymore.
This commit is contained in:
44
sql/item.h
44
sql/item.h
@@ -769,8 +769,8 @@ enum class item_base_t : item_flags_t
|
|||||||
FIXED= (1<<2), // Was fixed with fix_fields().
|
FIXED= (1<<2), // Was fixed with fix_fields().
|
||||||
IS_EXPLICIT_NAME= (1<<3), // The name of this Item was set by the user
|
IS_EXPLICIT_NAME= (1<<3), // The name of this Item was set by the user
|
||||||
// (or was auto generated otherwise)
|
// (or was auto generated otherwise)
|
||||||
IS_IN_WITH_CYCLE= (1<<4) // This item is in CYCLE clause
|
IS_IN_WITH_CYCLE= (1<<4), // This item is in CYCLE clause of WITH.
|
||||||
// of WITH.
|
AT_TOP_LEVEL= (1<<5) // At top (AND) level of item tree
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -1319,6 +1319,25 @@ public:
|
|||||||
{
|
{
|
||||||
set_maybe_null(maybe_null_arg);
|
set_maybe_null(maybe_null_arg);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
Mark the item that it is a top level item, or part of a top level AND item,
|
||||||
|
for WHERE and ON clauses:
|
||||||
|
Example: ... WHERE a=5 AND b=6; Both a=5 and b=6 are top level items
|
||||||
|
|
||||||
|
This is used to indicate that there is no distinction between if the
|
||||||
|
value of the item is FALSE or NULL..
|
||||||
|
This enables Item_cond_and and subquery related items to do special
|
||||||
|
"top level" optimizations.
|
||||||
|
*/
|
||||||
|
virtual void top_level_item()
|
||||||
|
{
|
||||||
|
base_flags|= item_base_t::AT_TOP_LEVEL;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Return TRUE if this item of top WHERE level (AND/OR)
|
||||||
|
*/
|
||||||
|
bool is_top_level_item() const
|
||||||
|
{ return (bool) (base_flags & item_base_t::AT_TOP_LEVEL); }
|
||||||
|
|
||||||
void set_typelib(const TYPELIB *typelib) override
|
void set_typelib(const TYPELIB *typelib) override
|
||||||
{
|
{
|
||||||
@@ -2027,25 +2046,6 @@ public:
|
|||||||
{
|
{
|
||||||
return type_handler()->Item_update_null_value(this);
|
return type_handler()->Item_update_null_value(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Inform the item that there will be no distinction between its result
|
|
||||||
being FALSE or NULL.
|
|
||||||
|
|
||||||
NOTE
|
|
||||||
This function will be called for eg. Items that are top-level AND-parts
|
|
||||||
of the WHERE clause. Items implementing this function (currently
|
|
||||||
Item_cond_and and subquery-related item) enable special optimizations
|
|
||||||
when they are "top level".
|
|
||||||
*/
|
|
||||||
virtual void top_level_item() {}
|
|
||||||
/*
|
|
||||||
Return TRUE if it is item of top WHERE level (AND/OR) and it is
|
|
||||||
important, return FALSE if it not important (we can not use to simplify
|
|
||||||
calculations) or not top level
|
|
||||||
*/
|
|
||||||
virtual bool is_top_level_item() const
|
|
||||||
{ return FALSE; /* not important */}
|
|
||||||
/*
|
/*
|
||||||
return IN/ALL/ANY subquery or NULL
|
return IN/ALL/ANY subquery or NULL
|
||||||
*/
|
*/
|
||||||
@@ -4420,6 +4420,8 @@ public:
|
|||||||
Item_bool_static(const char *str_arg, longlong i):
|
Item_bool_static(const char *str_arg, longlong i):
|
||||||
Item_bool(str_arg, i) {};
|
Item_bool(str_arg, i) {};
|
||||||
|
|
||||||
|
/* Don't mark static items as top level item */
|
||||||
|
virtual void top_level_item() override {}
|
||||||
void set_join_tab_idx(uint8 join_tab_idx_arg) override
|
void set_join_tab_idx(uint8 join_tab_idx_arg) override
|
||||||
{ DBUG_ASSERT(0); }
|
{ DBUG_ASSERT(0); }
|
||||||
};
|
};
|
||||||
|
@@ -1065,14 +1065,14 @@ int Arg_comparator::compare_row()
|
|||||||
// NULL was compared
|
// NULL was compared
|
||||||
switch (((Item_func*)owner)->functype()) {
|
switch (((Item_func*)owner)->functype()) {
|
||||||
case Item_func::NE_FUNC:
|
case Item_func::NE_FUNC:
|
||||||
break; // NE never aborts on NULL even if abort_on_null is set
|
break; // NE never aborts on NULL
|
||||||
case Item_func::LT_FUNC:
|
case Item_func::LT_FUNC:
|
||||||
case Item_func::LE_FUNC:
|
case Item_func::LE_FUNC:
|
||||||
case Item_func::GT_FUNC:
|
case Item_func::GT_FUNC:
|
||||||
case Item_func::GE_FUNC:
|
case Item_func::GE_FUNC:
|
||||||
return -1; // <, <=, > and >= always fail on NULL
|
return -1; // <, <=, > and >= always fail on NULL
|
||||||
case Item_func::EQ_FUNC:
|
case Item_func::EQ_FUNC:
|
||||||
if (((Item_func_eq*)owner)->abort_on_null)
|
if (owner->is_top_level_item())
|
||||||
return -1; // We do not need correct NULL returning
|
return -1; // We do not need correct NULL returning
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1189,12 +1189,6 @@ longlong Item_func_truth::val_int()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_in_optimizer::is_top_level_item() const
|
|
||||||
{
|
|
||||||
return args[1]->is_top_level_item();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Item_in_optimizer::fix_after_pullout(st_select_lex *new_parent,
|
void Item_in_optimizer::fix_after_pullout(st_select_lex *new_parent,
|
||||||
Item **ref, bool merge)
|
Item **ref, bool merge)
|
||||||
{
|
{
|
||||||
@@ -1379,7 +1373,8 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
|
|||||||
}
|
}
|
||||||
|
|
||||||
base_flags|= (item_base_t::FIXED |
|
base_flags|= (item_base_t::FIXED |
|
||||||
(args[1]->base_flags & item_base_t::MAYBE_NULL));
|
(args[1]->base_flags & (item_base_t::MAYBE_NULL |
|
||||||
|
item_base_t::AT_TOP_LEVEL)));
|
||||||
with_flags|= (item_with_t::SUBQUERY |
|
with_flags|= (item_with_t::SUBQUERY |
|
||||||
args[1]->with_flags |
|
args[1]->with_flags |
|
||||||
(args[0]->with_flags &
|
(args[0]->with_flags &
|
||||||
@@ -2065,7 +2060,7 @@ bool Item_func_between::eval_not_null_tables(void *opt_arg)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */
|
/* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */
|
||||||
if (pred_level && !negated)
|
if (is_top_level_item() && !negated)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* not_null_tables_cache == union(T1(e), intersection(T1(e1),T1(e2))) */
|
/* not_null_tables_cache == union(T1(e), intersection(T1(e1),T1(e2))) */
|
||||||
@@ -2467,6 +2462,10 @@ bool
|
|||||||
Item_func_if::fix_fields(THD *thd, Item **ref)
|
Item_func_if::fix_fields(THD *thd, Item **ref)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed() == 0);
|
DBUG_ASSERT(fixed() == 0);
|
||||||
|
/*
|
||||||
|
Mark that we don't care if args[0] is NULL or FALSE, we regard both cases as
|
||||||
|
false.
|
||||||
|
*/
|
||||||
args[0]->top_level_item();
|
args[0]->top_level_item();
|
||||||
|
|
||||||
if (Item_func::fix_fields(thd, ref))
|
if (Item_func::fix_fields(thd, ref))
|
||||||
@@ -4342,7 +4341,7 @@ Item_func_in::eval_not_null_tables(void *opt_arg)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* not_null_tables_cache == union(T1(e),union(T1(ei))) */
|
/* not_null_tables_cache == union(T1(e),union(T1(ei))) */
|
||||||
if (pred_level && negated)
|
if (is_top_level_item() && negated)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */
|
/* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */
|
||||||
@@ -4796,9 +4795,10 @@ bool Item_func_bit_and::fix_length_and_dec()
|
|||||||
|
|
||||||
Item_cond::Item_cond(THD *thd, Item_cond *item)
|
Item_cond::Item_cond(THD *thd, Item_cond *item)
|
||||||
:Item_bool_func(thd, item),
|
:Item_bool_func(thd, item),
|
||||||
abort_on_null(item->abort_on_null),
|
|
||||||
and_tables_cache(item->and_tables_cache)
|
and_tables_cache(item->and_tables_cache)
|
||||||
{
|
{
|
||||||
|
base_flags|= (item->base_flags & item_base_t::AT_TOP_LEVEL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
item->list will be copied by copy_andor_arguments() call
|
item->list will be copied by copy_andor_arguments() call
|
||||||
*/
|
*/
|
||||||
@@ -4806,7 +4806,7 @@ Item_cond::Item_cond(THD *thd, Item_cond *item)
|
|||||||
|
|
||||||
|
|
||||||
Item_cond::Item_cond(THD *thd, Item *i1, Item *i2):
|
Item_cond::Item_cond(THD *thd, Item *i1, Item *i2):
|
||||||
Item_bool_func(thd), abort_on_null(0)
|
Item_bool_func(thd)
|
||||||
{
|
{
|
||||||
list.push_back(i1, thd->mem_root);
|
list.push_back(i1, thd->mem_root);
|
||||||
list.push_back(i2, thd->mem_root);
|
list.push_back(i2, thd->mem_root);
|
||||||
@@ -4874,7 +4874,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
|
|||||||
((Item_cond*) item)->list.empty();
|
((Item_cond*) item)->list.empty();
|
||||||
item= *li.ref(); // new current item
|
item= *li.ref(); // new current item
|
||||||
}
|
}
|
||||||
if (abort_on_null)
|
if (is_top_level_item())
|
||||||
item->top_level_item();
|
item->top_level_item();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -4901,7 +4901,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
|
|||||||
if (item->can_eval_in_optimize() && !item->with_sp_var() &&
|
if (item->can_eval_in_optimize() && !item->with_sp_var() &&
|
||||||
!cond_has_datetime_is_null(item))
|
!cond_has_datetime_is_null(item))
|
||||||
{
|
{
|
||||||
if (item->eval_const_cond() == is_and_cond && top_level())
|
if (item->eval_const_cond() == is_and_cond && is_top_level_item())
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
a. This is "... AND true_cond AND ..."
|
a. This is "... AND true_cond AND ..."
|
||||||
@@ -4958,7 +4958,7 @@ Item_cond::eval_not_null_tables(void *opt_arg)
|
|||||||
if (item->can_eval_in_optimize() && !item->with_sp_var() &&
|
if (item->can_eval_in_optimize() && !item->with_sp_var() &&
|
||||||
!cond_has_datetime_is_null(item))
|
!cond_has_datetime_is_null(item))
|
||||||
{
|
{
|
||||||
if (item->eval_const_cond() == is_and_cond && top_level())
|
if (item->eval_const_cond() == is_and_cond && is_top_level_item())
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
a. This is "... AND true_cond AND ..."
|
a. This is "... AND true_cond AND ..."
|
||||||
@@ -5393,17 +5393,18 @@ void Item_cond_and::mark_as_condition_AND_part(TABLE_LIST *embedding)
|
|||||||
Evaluation of AND(expr, expr, expr ...).
|
Evaluation of AND(expr, expr, expr ...).
|
||||||
|
|
||||||
@note
|
@note
|
||||||
abort_if_null is set for AND expressions for which we don't care if the
|
There are AND expressions for which we don't care if the
|
||||||
result is NULL or 0. This is set for:
|
result is NULL or 0. This is the case for:
|
||||||
- WHERE clause
|
- WHERE clause
|
||||||
- HAVING clause
|
- HAVING clause
|
||||||
- IF(expression)
|
- IF(expression)
|
||||||
|
For these we mark them as "top_level_items"
|
||||||
|
|
||||||
@retval
|
@retval
|
||||||
1 If all expressions are true
|
1 If all expressions are true
|
||||||
@retval
|
@retval
|
||||||
0 If all expressions are false or if we find a NULL expression and
|
0 If any of the expressions are false or if we find a NULL expression and
|
||||||
'abort_on_null' is set.
|
this is a top_level_item.
|
||||||
@retval
|
@retval
|
||||||
NULL if all expression are either 1 or NULL
|
NULL if all expression are either 1 or NULL
|
||||||
*/
|
*/
|
||||||
@@ -5419,8 +5420,8 @@ longlong Item_cond_and::val_int()
|
|||||||
{
|
{
|
||||||
if (!item->val_bool())
|
if (!item->val_bool())
|
||||||
{
|
{
|
||||||
if (abort_on_null || !(null_value= item->null_value))
|
if (is_top_level_item() || !(null_value= item->null_value))
|
||||||
return 0; // return FALSE
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null_value ? 0 : 1;
|
return null_value ? 0 : 1;
|
||||||
|
@@ -411,7 +411,6 @@ public:
|
|||||||
void set_join_tab_idx(uint8 join_tab_idx_arg) override
|
void set_join_tab_idx(uint8 join_tab_idx_arg) override
|
||||||
{ args[1]->set_join_tab_idx(join_tab_idx_arg); }
|
{ args[1]->set_join_tab_idx(join_tab_idx_arg); }
|
||||||
void get_cache_parameters(List<Item> ¶meters) override;
|
void get_cache_parameters(List<Item> ¶meters) override;
|
||||||
bool is_top_level_item() const override;
|
|
||||||
bool eval_not_null_tables(void *opt_arg) override;
|
bool eval_not_null_tables(void *opt_arg) override;
|
||||||
bool find_not_null_fields(table_map allowed) override;
|
bool find_not_null_fields(table_map allowed) override;
|
||||||
void fix_after_pullout(st_select_lex *new_parent, Item **ref,
|
void fix_after_pullout(st_select_lex *new_parent, Item **ref,
|
||||||
@@ -631,12 +630,8 @@ public:
|
|||||||
|
|
||||||
class Item_func_not :public Item_bool_func
|
class Item_func_not :public Item_bool_func
|
||||||
{
|
{
|
||||||
bool abort_on_null;
|
|
||||||
public:
|
public:
|
||||||
Item_func_not(THD *thd, Item *a):
|
Item_func_not(THD *thd, Item *a): Item_bool_func(thd, a) {}
|
||||||
Item_bool_func(thd, a), abort_on_null(FALSE) {}
|
|
||||||
void top_level_item() override { abort_on_null= 1; }
|
|
||||||
bool is_top_level_item() const override { return abort_on_null; }
|
|
||||||
longlong val_int() override;
|
longlong val_int() override;
|
||||||
enum Functype functype() const override { return NOT_FUNC; }
|
enum Functype functype() const override { return NOT_FUNC; }
|
||||||
LEX_CSTRING func_name_cstring() const override
|
LEX_CSTRING func_name_cstring() const override
|
||||||
@@ -755,11 +750,10 @@ public:
|
|||||||
|
|
||||||
class Item_func_eq :public Item_bool_rowready_func2
|
class Item_func_eq :public Item_bool_rowready_func2
|
||||||
{
|
{
|
||||||
bool abort_on_null;
|
|
||||||
public:
|
public:
|
||||||
Item_func_eq(THD *thd, Item *a, Item *b):
|
Item_func_eq(THD *thd, Item *a, Item *b):
|
||||||
Item_bool_rowready_func2(thd, a, b),
|
Item_bool_rowready_func2(thd, a, b),
|
||||||
abort_on_null(false), in_equality_no(UINT_MAX)
|
in_equality_no(UINT_MAX)
|
||||||
{}
|
{}
|
||||||
longlong val_int() override;
|
longlong val_int() override;
|
||||||
enum Functype functype() const override { return EQ_FUNC; }
|
enum Functype functype() const override { return EQ_FUNC; }
|
||||||
@@ -770,7 +764,6 @@ public:
|
|||||||
static LEX_CSTRING name= {STRING_WITH_LEN("=") };
|
static LEX_CSTRING name= {STRING_WITH_LEN("=") };
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
void top_level_item() override { abort_on_null= true; }
|
|
||||||
Item *negated_item(THD *thd) override;
|
Item *negated_item(THD *thd) override;
|
||||||
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
|
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
|
||||||
bool link_item_fields,
|
bool link_item_fields,
|
||||||
@@ -956,15 +949,12 @@ protected:
|
|||||||
DTCollation cmp_collation;
|
DTCollation cmp_collation;
|
||||||
public:
|
public:
|
||||||
bool negated; /* <=> the item represents NOT <func> */
|
bool negated; /* <=> the item represents NOT <func> */
|
||||||
bool pred_level; /* <=> [NOT] <func> is used on a predicate level */
|
|
||||||
public:
|
public:
|
||||||
Item_func_opt_neg(THD *thd, Item *a, Item *b, Item *c):
|
Item_func_opt_neg(THD *thd, Item *a, Item *b, Item *c):
|
||||||
Item_bool_func(thd, a, b, c), negated(0), pred_level(0) {}
|
Item_bool_func(thd, a, b, c), negated(0) {}
|
||||||
Item_func_opt_neg(THD *thd, List<Item> &list):
|
Item_func_opt_neg(THD *thd, List<Item> &list):
|
||||||
Item_bool_func(thd, list), negated(0), pred_level(0) {}
|
Item_bool_func(thd, list), negated(0) {}
|
||||||
public:
|
public:
|
||||||
void top_level_item() override { pred_level= 1; }
|
|
||||||
bool is_top_level_item() const override { return pred_level; }
|
|
||||||
Item *neg_transformer(THD *thd) override
|
Item *neg_transformer(THD *thd) override
|
||||||
{
|
{
|
||||||
negated= !negated;
|
negated= !negated;
|
||||||
@@ -2800,11 +2790,9 @@ public:
|
|||||||
|
|
||||||
class Item_func_isnotnull :public Item_func_null_predicate
|
class Item_func_isnotnull :public Item_func_null_predicate
|
||||||
{
|
{
|
||||||
bool abort_on_null;
|
|
||||||
public:
|
public:
|
||||||
Item_func_isnotnull(THD *thd, Item *a):
|
Item_func_isnotnull(THD *thd, Item *a):
|
||||||
Item_func_null_predicate(thd, a), abort_on_null(0)
|
Item_func_null_predicate(thd, a) {}
|
||||||
{ }
|
|
||||||
longlong val_int() override;
|
longlong val_int() override;
|
||||||
enum Functype functype() const override { return ISNOTNULL_FUNC; }
|
enum Functype functype() const override { return ISNOTNULL_FUNC; }
|
||||||
LEX_CSTRING func_name_cstring() const override
|
LEX_CSTRING func_name_cstring() const override
|
||||||
@@ -2814,10 +2802,9 @@ public:
|
|||||||
}
|
}
|
||||||
enum precedence precedence() const override { return CMP_PRECEDENCE; }
|
enum precedence precedence() const override { return CMP_PRECEDENCE; }
|
||||||
table_map not_null_tables() const override
|
table_map not_null_tables() const override
|
||||||
{ return abort_on_null ? not_null_tables_cache : 0; }
|
{ return is_top_level_item() ? not_null_tables_cache : 0; }
|
||||||
Item *neg_transformer(THD *thd) override;
|
Item *neg_transformer(THD *thd) override;
|
||||||
void print(String *str, enum_query_type query_type) override;
|
void print(String *str, enum_query_type query_type) override;
|
||||||
void top_level_item() override { abort_on_null=1; }
|
|
||||||
Item *get_copy(THD *thd) override
|
Item *get_copy(THD *thd) override
|
||||||
{ return get_item_copy<Item_func_isnotnull>(thd, this); }
|
{ return get_item_copy<Item_func_isnotnull>(thd, this); }
|
||||||
};
|
};
|
||||||
@@ -3128,17 +3115,19 @@ class Item_cond :public Item_bool_func
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
List<Item> list;
|
List<Item> list;
|
||||||
bool abort_on_null;
|
|
||||||
table_map and_tables_cache;
|
table_map and_tables_cache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Item_cond() is only used to create top level items */
|
Item_cond(THD *thd): Item_bool_func(thd)
|
||||||
Item_cond(THD *thd): Item_bool_func(thd), abort_on_null(1)
|
{
|
||||||
{ const_item_cache=0; }
|
/* Item_cond() is only used to create top level items */
|
||||||
|
top_level_item();
|
||||||
|
const_item_cache=0;
|
||||||
|
}
|
||||||
Item_cond(THD *thd, Item *i1, Item *i2);
|
Item_cond(THD *thd, Item *i1, Item *i2);
|
||||||
Item_cond(THD *thd, Item_cond *item);
|
Item_cond(THD *thd, Item_cond *item);
|
||||||
Item_cond(THD *thd, List<Item> &nlist):
|
Item_cond(THD *thd, List<Item> &nlist):
|
||||||
Item_bool_func(thd), list(nlist), abort_on_null(0) {}
|
Item_bool_func(thd), list(nlist) {}
|
||||||
bool add(Item *item, MEM_ROOT *root)
|
bool add(Item *item, MEM_ROOT *root)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(item);
|
DBUG_ASSERT(item);
|
||||||
@@ -3185,8 +3174,6 @@ public:
|
|||||||
List<Item> &fields, uint flags) override;
|
List<Item> &fields, uint flags) override;
|
||||||
friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
|
friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
|
||||||
COND **conds);
|
COND **conds);
|
||||||
void top_level_item() override { abort_on_null=1; }
|
|
||||||
bool top_level() { return abort_on_null; }
|
|
||||||
void copy_andor_arguments(THD *thd, Item_cond *item);
|
void copy_andor_arguments(THD *thd, Item_cond *item);
|
||||||
bool walk(Item_processor processor, bool walk_subquery, void *arg) override;
|
bool walk(Item_processor processor, bool walk_subquery, void *arg) override;
|
||||||
Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override;
|
Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override;
|
||||||
@@ -3542,7 +3529,7 @@ public:
|
|||||||
}
|
}
|
||||||
enum precedence precedence() const override { return AND_PRECEDENCE; }
|
enum precedence precedence() const override { return AND_PRECEDENCE; }
|
||||||
table_map not_null_tables() const override
|
table_map not_null_tables() const override
|
||||||
{ return abort_on_null ? not_null_tables_cache: and_tables_cache; }
|
{ return is_top_level_item() ? not_null_tables_cache: and_tables_cache; }
|
||||||
Item *copy_andor_structure(THD *thd) override;
|
Item *copy_andor_structure(THD *thd) override;
|
||||||
Item *neg_transformer(THD *thd) override;
|
Item *neg_transformer(THD *thd) override;
|
||||||
void mark_as_condition_AND_part(TABLE_LIST *embedding) override;
|
void mark_as_condition_AND_part(TABLE_LIST *embedding) override;
|
||||||
|
@@ -1587,7 +1587,7 @@ bool Item_singlerow_subselect::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t
|
|||||||
|
|
||||||
Item_exists_subselect::Item_exists_subselect(THD *thd,
|
Item_exists_subselect::Item_exists_subselect(THD *thd,
|
||||||
st_select_lex *select_lex):
|
st_select_lex *select_lex):
|
||||||
Item_subselect(thd), upper_not(NULL), abort_on_null(0),
|
Item_subselect(thd), upper_not(NULL),
|
||||||
emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0)
|
emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("Item_exists_subselect::Item_exists_subselect");
|
DBUG_ENTER("Item_exists_subselect::Item_exists_subselect");
|
||||||
@@ -1672,7 +1672,6 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
|
|||||||
func= func_creator(all_arg);
|
func= func_creator(all_arg);
|
||||||
init(select_lex, new (thd->mem_root) select_exists_subselect(thd, this));
|
init(select_lex, new (thd->mem_root) select_exists_subselect(thd, this));
|
||||||
max_columns= 1;
|
max_columns= 1;
|
||||||
abort_on_null= 0;
|
|
||||||
reset();
|
reset();
|
||||||
//if test_limit will fail then error will be reported to client
|
//if test_limit will fail then error will be reported to client
|
||||||
test_limit(select_lex->master_unit());
|
test_limit(select_lex->master_unit());
|
||||||
@@ -2247,8 +2246,11 @@ bool Item_allany_subselect::is_maxmin_applicable(JOIN *join)
|
|||||||
Check if max/min optimization applicable: It is top item of
|
Check if max/min optimization applicable: It is top item of
|
||||||
WHERE condition.
|
WHERE condition.
|
||||||
*/
|
*/
|
||||||
return (abort_on_null || (upper_item && upper_item->is_top_level_item())) &&
|
return ((is_top_level_item() ||
|
||||||
!(join->select_lex->master_unit()->uncacheable & ~UNCACHEABLE_EXPLAIN) && !func->eqne_op();
|
(upper_item && upper_item->is_top_level_item())) &&
|
||||||
|
!(join->select_lex->master_unit()->uncacheable &
|
||||||
|
~UNCACHEABLE_EXPLAIN) &&
|
||||||
|
!func->eqne_op());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2318,7 +2320,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
|
|||||||
ref_pointer_array[0],
|
ref_pointer_array[0],
|
||||||
{STRING_WITH_LEN("<ref>")},
|
{STRING_WITH_LEN("<ref>")},
|
||||||
field_name));
|
field_name));
|
||||||
if (!abort_on_null && left_expr->maybe_null())
|
if (!is_top_level_item() && left_expr->maybe_null())
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
We can encounter "NULL IN (SELECT ...)". Wrap the added condition
|
We can encounter "NULL IN (SELECT ...)". Wrap the added condition
|
||||||
@@ -2351,7 +2353,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
|
|||||||
Item *orig_item= item;
|
Item *orig_item= item;
|
||||||
|
|
||||||
item= func->create(thd, expr, item);
|
item= func->create(thd, expr, item);
|
||||||
if (!abort_on_null && orig_item->maybe_null())
|
if (!is_top_level_item() && orig_item->maybe_null())
|
||||||
{
|
{
|
||||||
having= new (thd->mem_root) Item_is_not_null_test(thd, this, having);
|
having= new (thd->mem_root) Item_is_not_null_test(thd, this, having);
|
||||||
if (left_expr->maybe_null())
|
if (left_expr->maybe_null())
|
||||||
@@ -2373,7 +2375,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
|
|||||||
If we may encounter NULL IN (SELECT ...) and care whether subquery
|
If we may encounter NULL IN (SELECT ...) and care whether subquery
|
||||||
result is NULL or FALSE, wrap condition in a trig_cond.
|
result is NULL or FALSE, wrap condition in a trig_cond.
|
||||||
*/
|
*/
|
||||||
if (!abort_on_null && left_expr->maybe_null())
|
if (!is_top_level_item() && left_expr->maybe_null())
|
||||||
{
|
{
|
||||||
disable_cond_guard_for_const_null_left_expr(0);
|
disable_cond_guard_for_const_null_left_expr(0);
|
||||||
if (!(item= new (thd->mem_root) Item_func_trig_cond(thd, item,
|
if (!(item= new (thd->mem_root) Item_func_trig_cond(thd, item,
|
||||||
@@ -2403,7 +2405,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
|
|||||||
&select_lex->ref_pointer_array[0],
|
&select_lex->ref_pointer_array[0],
|
||||||
no_matter_name,
|
no_matter_name,
|
||||||
field_name));
|
field_name));
|
||||||
if (!abort_on_null && left_expr->maybe_null())
|
if (!is_top_level_item() && left_expr->maybe_null())
|
||||||
{
|
{
|
||||||
disable_cond_guard_for_const_null_left_expr(0);
|
disable_cond_guard_for_const_null_left_expr(0);
|
||||||
if (!(new_having= new (thd->mem_root)
|
if (!(new_having= new (thd->mem_root)
|
||||||
@@ -2602,7 +2604,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
|
|||||||
list_ref));
|
list_ref));
|
||||||
Item *col_item= new (thd->mem_root)
|
Item *col_item= new (thd->mem_root)
|
||||||
Item_cond_or(thd, item_eq, item_isnull);
|
Item_cond_or(thd, item_eq, item_isnull);
|
||||||
if (!abort_on_null && left_expr->element_index(i)->maybe_null() &&
|
if (!is_top_level_item() && left_expr->element_index(i)->maybe_null() &&
|
||||||
get_cond_guard(i))
|
get_cond_guard(i))
|
||||||
{
|
{
|
||||||
disable_cond_guard_for_const_null_left_expr(i);
|
disable_cond_guard_for_const_null_left_expr(i);
|
||||||
@@ -2621,7 +2623,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
|
|||||||
ref_pointer_array[i],
|
ref_pointer_array[i],
|
||||||
no_matter_name,
|
no_matter_name,
|
||||||
list_ref));
|
list_ref));
|
||||||
if (!abort_on_null && left_expr->element_index(i)->maybe_null() &&
|
if (!is_top_level_item() && left_expr->element_index(i)->maybe_null() &&
|
||||||
get_cond_guard(i) )
|
get_cond_guard(i) )
|
||||||
{
|
{
|
||||||
disable_cond_guard_for_const_null_left_expr(i);
|
disable_cond_guard_for_const_null_left_expr(i);
|
||||||
@@ -2662,7 +2664,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
|
|||||||
ref_pointer_array[i],
|
ref_pointer_array[i],
|
||||||
no_matter_name,
|
no_matter_name,
|
||||||
list_ref));
|
list_ref));
|
||||||
if (!abort_on_null && select_lex->ref_pointer_array[i]->maybe_null())
|
if (!is_top_level_item() && select_lex->ref_pointer_array[i]->maybe_null())
|
||||||
{
|
{
|
||||||
Item *having_col_item=
|
Item *having_col_item=
|
||||||
new (thd->mem_root)
|
new (thd->mem_root)
|
||||||
@@ -2694,7 +2696,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
|
|||||||
}
|
}
|
||||||
*having_item= and_items(thd, *having_item, having_col_item);
|
*having_item= and_items(thd, *having_item, having_col_item);
|
||||||
}
|
}
|
||||||
if (!abort_on_null && left_expr->element_index(i)->maybe_null() &&
|
if (!is_top_level_item() && left_expr->element_index(i)->maybe_null() &&
|
||||||
get_cond_guard(i))
|
get_cond_guard(i))
|
||||||
{
|
{
|
||||||
if (!(item= new (thd->mem_root)
|
if (!(item= new (thd->mem_root)
|
||||||
@@ -3663,7 +3665,7 @@ bool Item_in_subselect::init_cond_guards()
|
|||||||
{
|
{
|
||||||
DBUG_ASSERT(thd);
|
DBUG_ASSERT(thd);
|
||||||
uint cols_num= left_expr->cols();
|
uint cols_num= left_expr->cols();
|
||||||
if (!abort_on_null && !pushed_cond_guards &&
|
if (!is_top_level_item() && !pushed_cond_guards &&
|
||||||
(left_expr->maybe_null() || cols_num > 1))
|
(left_expr->maybe_null() || cols_num > 1))
|
||||||
{
|
{
|
||||||
if (!(pushed_cond_guards= (bool*)thd->alloc(sizeof(bool) * cols_num)))
|
if (!(pushed_cond_guards= (bool*)thd->alloc(sizeof(bool) * cols_num)))
|
||||||
@@ -4245,9 +4247,9 @@ bool subselect_uniquesubquery_engine::copy_ref_key(bool skip_constants)
|
|||||||
- NULL if select produces empty row set
|
- NULL if select produces empty row set
|
||||||
- FALSE otherwise.
|
- FALSE otherwise.
|
||||||
|
|
||||||
In some cases (IN subselect is a top level item, i.e. abort_on_null==TRUE)
|
In some cases (IN subselect is a top level item, i.e.
|
||||||
the caller doesn't distinguish between NULL and FALSE result and we just
|
is_top_level_item() == TRUE, the caller doesn't distinguish between NULL and
|
||||||
return FALSE.
|
FALSE result and we just return FALSE.
|
||||||
Otherwise we make a full table scan to see if there is at least one
|
Otherwise we make a full table scan to see if there is at least one
|
||||||
matching row.
|
matching row.
|
||||||
|
|
||||||
|
@@ -373,7 +373,6 @@ class Item_exists_subselect :public Item_subselect
|
|||||||
protected:
|
protected:
|
||||||
Item_func_not *upper_not;
|
Item_func_not *upper_not;
|
||||||
bool value; /* value of this item (boolean: exists/not-exists) */
|
bool value; /* value of this item (boolean: exists/not-exists) */
|
||||||
bool abort_on_null;
|
|
||||||
|
|
||||||
void init_length_and_dec();
|
void init_length_and_dec();
|
||||||
bool select_prepare_to_be_in();
|
bool select_prepare_to_be_in();
|
||||||
@@ -397,7 +396,7 @@ public:
|
|||||||
|
|
||||||
Item_exists_subselect(THD *thd_arg, st_select_lex *select_lex);
|
Item_exists_subselect(THD *thd_arg, st_select_lex *select_lex);
|
||||||
Item_exists_subselect(THD *thd_arg):
|
Item_exists_subselect(THD *thd_arg):
|
||||||
Item_subselect(thd_arg), upper_not(NULL), abort_on_null(0),
|
Item_subselect(thd_arg), upper_not(NULL),
|
||||||
emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0)
|
emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -424,8 +423,6 @@ public:
|
|||||||
bool fix_length_and_dec() override;
|
bool fix_length_and_dec() override;
|
||||||
void print(String *str, enum_query_type query_type) override;
|
void print(String *str, enum_query_type query_type) override;
|
||||||
bool select_transformer(JOIN *join) override;
|
bool select_transformer(JOIN *join) override;
|
||||||
void top_level_item() override { abort_on_null=1; }
|
|
||||||
bool is_top_level_item() const override { return abort_on_null; }
|
|
||||||
bool exists2in_processor(void *opt_arg) override;
|
bool exists2in_processor(void *opt_arg) override;
|
||||||
|
|
||||||
Item* expr_cache_insert_transformer(THD *thd, uchar *unused) override;
|
Item* expr_cache_insert_transformer(THD *thd, uchar *unused) override;
|
||||||
|
@@ -16362,9 +16362,9 @@ static void update_const_equal_items(THD *thd, COND *cond, JOIN_TAB *tab,
|
|||||||
Item *item;
|
Item *item;
|
||||||
while ((item= li++))
|
while ((item= li++))
|
||||||
update_const_equal_items(thd, item, tab,
|
update_const_equal_items(thd, item, tab,
|
||||||
(((Item_cond*) cond)->top_level() &&
|
cond->is_top_level_item() &&
|
||||||
((Item_cond*) cond)->functype() ==
|
((Item_cond*) cond)->functype() ==
|
||||||
Item_func::COND_AND_FUNC));
|
Item_func::COND_AND_FUNC);
|
||||||
}
|
}
|
||||||
else if (cond->type() == Item::FUNC_ITEM &&
|
else if (cond->type() == Item::FUNC_ITEM &&
|
||||||
((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
|
((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
|
||||||
|
Reference in New Issue
Block a user