Skip to content
/ server Public
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions sql/item_cmpfunc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5736,6 +5736,45 @@ bool Item_cond::excl_dep_on_grouping_fields(st_select_lex *sel)
return true;
}

Item *Item_cond::simplify_cond(THD *thd)
{
List_iterator<Item> li(list);
Item *child;
while ((child= li++))
{
if (child->type() == Item::COND_ITEM)
{
Item *new_child= static_cast<Item_cond *>(child)->simplify_cond(thd);
if (new_child != child)
li.replace(new_child);
}
}
bool is_and= functype() == Item_func::COND_AND_FUNC;
bool is_or= functype() == Item_func::COND_OR_FUNC;
if (is_and || is_or)
{
List_iterator<Item> li2(list);
while ((child= li2++))
{
Item *real= child->real_item();
if (real->is_bool_literal())
{
bool v= real->val_bool();
if (is_and && v)
li2.remove();
if (is_and && !v)
return new (thd->mem_root) Item_bool(thd, false);
if (is_or && v)
return new (thd->mem_root) Item_bool(thd, true);
if (is_or && !v)
li2.remove();
}
}
if (list.is_empty())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the list ever be empty, given that you're removing one of the branches only if another branch exists?

I'd say no. And then this is dead code. And should be turned into an assert.

return new (thd->mem_root) Item_bool(thd, false);
}
return this;
}

void Item_cond_and::mark_as_condition_AND_part(TABLE_LIST *embedding)
{
Expand Down
1 change: 1 addition & 0 deletions sql/item_cmpfunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -3450,6 +3450,7 @@ class Item_cond :public Item_bool_func
Item *deep_copy(THD *thd) const override;
bool excl_dep_on_table(table_map tab_map) override;
bool excl_dep_on_grouping_fields(st_select_lex *sel) override;
Item *simplify_cond(THD *thd);

private:
void merge_sub_condition(List_iterator<Item>& li);
Expand Down
17 changes: 17 additions & 0 deletions sql/sql_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8223,6 +8223,23 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
DBUG_RETURN(TRUE); /* purecov: inspected */
}
item= *(it.ref()); // Item might have changed in fix_fields()
/*
If item is a SELECT-list COND_ITEM, rewrite it on the first time this
query is optimized to fold boolean expressions
*/
if (thd->lex->current_select->context_analysis_place == SELECT_LIST &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any specific reason why you're doing this only for the SELECT list expressions?
Why not do this during fix_fields for all Item_conds for example?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to mention one thing: When doing the optimization you are doing you need to check for NULL-ness!

SELECT true AND NULL FROM t1

should return NULL and not true.

item->type() == Item::COND_ITEM &&
thd->lex->current_select->first_cond_optimization)
{
Query_arena_stmt on_stmt_arena(thd);
Item *new_item= static_cast<Item_cond *>(item)->simplify_cond(thd);
if (new_item != item)
{
new_item->share_name_with(item);
it.replace(new_item);
item= new_item;
}
}
if (!ref.is_null())
{
ref[0]= item;
Expand Down