1
0
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:
Monty
2021-07-03 03:39:15 +03:00
committed by Vicențiu Ciorbaru
parent f069aa1dc2
commit fcbb2a1df1
6 changed files with 82 additions and 93 deletions

View File

@@ -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); }
}; };

View File

@@ -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;

View File

@@ -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> &parameters) override; void get_cache_parameters(List<Item> &parameters) 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;

View File

@@ -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.

View File

@@ -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;

View File

@@ -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)