Commit 3e033b3a authored by Rex's avatar Rex

MDEV-31130 INSERT-SELECT with many when/case/if conditions running forever

recursive column definitions in stacked materialized tables causes issues.
detect depth of walk in the item tree and terminate if too deep.
parent ddcc9d22
......@@ -1868,7 +1868,8 @@ class Item: public Value_source,
return type_handler()->charset_for_protocol(this);
};
virtual bool walk(Item_processor processor, bool walk_subquery, void *arg)
virtual bool walk(Item_processor processor, bool walk_subquery,
void *arg, uint depth= 0)
{
return (this->*processor)(arg);
}
......@@ -2595,15 +2596,17 @@ class Item_args
Item **args, *tmp_arg[2];
uint arg_count;
void set_arguments(THD *thd, List<Item> &list);
bool walk_args(Item_processor processor, bool walk_subquery, void *arg)
bool walk_args(Item_processor processor, bool walk_subquery, void *arg,
uint depth )
{
for (uint i= 0; i < arg_count; i++)
{
if (args[i]->walk(processor, walk_subquery, arg))
if (args[i]->walk(processor, walk_subquery, arg, depth+1))
return true;
}
return false;
}
bool transform_args(THD *thd, Item_transformer transformer, uchar *arg);
void propagate_equal_fields(THD *, const Item::Context &, COND_EQUAL *);
bool excl_dep_on_table(table_map tab_map)
......@@ -5294,12 +5297,20 @@ class Item_func_or_sum: public Item_result_field,
Item_func_or_sum(THD *thd, List<Item> &list):
Item_result_field(thd), Item_args(thd, list) { }
bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; }
bool walk(Item_processor processor, bool walk_subquery, void *arg)
#define MAX_WALK_DEPTH 70
bool walk(Item_processor processor, bool walk_subquery, void *arg, uint depth)
{
if (walk_args(processor, walk_subquery, arg))
if (depth > MAX_WALK_DEPTH)
{
my_error( ER_DERIVED_RECURSION_LIMIT, MYF(0), MAX_WALK_DEPTH, "derived limit" );
return true;
}
if (walk_args(processor, walk_subquery, arg, depth+1))
return true;
return (this->*processor)(arg);
}
/*
This method is used for debug purposes to print the name of an
item to the debug log. The second use of this method is as
......@@ -5488,10 +5499,11 @@ class Item_ref :public Item_ident,
}
bool is_json_type() { return (*ref)->is_json_type(); }
bool walk(Item_processor processor, bool walk_subquery, void *arg)
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0)
{
if (ref && *ref)
return (*ref)->walk(processor, walk_subquery, arg) ||
return (*ref)->walk(processor, walk_subquery, arg, depth+1) ||
(this->*processor)(arg);
else
return FALSE;
......@@ -5788,9 +5800,10 @@ class Item_cache_wrapper :public Item_result_field,
}
bool const_item() const { return orig_item->const_item(); }
table_map not_null_tables() const { return orig_item->not_null_tables(); }
bool walk(Item_processor processor, bool walk_subquery, void *arg)
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0)
{
return orig_item->walk(processor, walk_subquery, arg) ||
return orig_item->walk(processor, walk_subquery, arg, depth+1) ||
(this->*processor)(arg);
}
bool enumerate_field_refs_processor(void *arg)
......@@ -5899,9 +5912,10 @@ class Item_direct_view_ref :public Item_direct_ref
return (*ref)->const_item() && (null_ref_table == NO_NULL_TABLE);
}
TABLE *get_null_ref_table() const { return null_ref_table; }
bool walk(Item_processor processor, bool walk_subquery, void *arg)
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0)
{
return (*ref)->walk(processor, walk_subquery, arg) ||
return (*ref)->walk(processor, walk_subquery, arg, depth+1) ||
(this->*processor)(arg);
}
bool view_used_tables_processor(void *arg)
......@@ -6277,9 +6291,10 @@ class Item_copy :public Item,
virtual double val_real() = 0;
virtual longlong val_int() = 0;
virtual int save_in_field(Field *field, bool no_conversions) = 0;
bool walk(Item_processor processor, bool walk_subquery, void *args)
bool walk(Item_processor processor, bool walk_subquery, void *args,
uint depth= 0)
{
return (item->walk(processor, walk_subquery, args)) ||
return (item->walk(processor, walk_subquery, args, depth+1)) ||
(this->*processor)(args);
}
};
......@@ -6546,9 +6561,10 @@ class Item_default_value : public Item_field
bool check_func_default_processor(void *arg) { return true; }
bool register_field_in_read_map(void *arg);
bool walk(Item_processor processor, bool walk_subquery, void *args)
bool walk(Item_processor processor, bool walk_subquery, void *args,
uint depth= 0)
{
return (arg && arg->walk(processor, walk_subquery, args)) ||
return (arg && arg->walk(processor, walk_subquery, args, depth+1)) ||
(this->*processor)(args);
}
......@@ -6714,9 +6730,10 @@ class Item_insert_value : public Item_field
Item_field *field_for_view_update() { return 0; }
bool walk(Item_processor processor, bool walk_subquery, void *args)
bool walk(Item_processor processor, bool walk_subquery, void *args,
uint depth= 0)
{
return arg->walk(processor, walk_subquery, args) ||
return arg->walk(processor, walk_subquery, args, depth+1) ||
(this->*processor)(args);
}
bool check_partition_func_processor(void *int_arg) {return TRUE;}
......@@ -6972,11 +6989,12 @@ class Item_cache: public Item_fixed_hybrid,
return example->is_expensive_processor(arg);
}
virtual void set_null();
bool walk(Item_processor processor, bool walk_subquery, void *arg)
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0)
{
if (arg == STOP_PTR)
return FALSE;
if (example && example->walk(processor, walk_subquery, arg))
if (example && example->walk(processor, walk_subquery, arg, depth+1))
return TRUE;
return (this->*processor)(arg);
}
......@@ -7682,9 +7700,10 @@ class Item_direct_ref_to_item : public Item_direct_ref
{ m_item->update_used_tables(); }
bool const_item() const { return m_item->const_item(); }
table_map not_null_tables() const { return m_item->not_null_tables(); }
bool walk(Item_processor processor, bool walk_subquery, void *arg)
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0)
{
return m_item->walk(processor, walk_subquery, arg) ||
return m_item->walk(processor, walk_subquery, arg, depth+1) ||
(this->*processor)(arg);
}
bool enumerate_field_refs_processor(void *arg)
......
......@@ -2529,7 +2529,8 @@ void Item_func_nullif::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
bool Item_func_nullif::walk(Item_processor processor,
bool walk_subquery, void *arg)
bool walk_subquery, void *arg,
uint depth)
{
/*
No needs to iterate through args[2] when it's just a copy of args[0].
......@@ -2538,7 +2539,7 @@ bool Item_func_nullif::walk(Item_processor processor,
uint tmp_count= arg_count == 2 || args[0] == args[2] ? 2 : 3;
for (uint i= 0; i < tmp_count; i++)
{
if (args[i]->walk(processor, walk_subquery, arg))
if (args[i]->walk(processor, walk_subquery, arg, depth+1))
return true;
}
return (this->*processor)(arg);
......@@ -5030,14 +5031,15 @@ void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref,
}
bool Item_cond::walk(Item_processor processor, bool walk_subquery, void *arg)
bool Item_cond::walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth)
{
List_iterator_fast<Item> li(list);
Item *item;
while ((item= li++))
if (item->walk(processor, walk_subquery, arg))
if (item->walk(processor, walk_subquery, arg, depth+1))
return 1;
return Item_func::walk(processor, walk_subquery, arg);
return Item_func::walk(processor, walk_subquery, arg, depth+1);
}
/**
......@@ -7126,16 +7128,17 @@ bool Item_equal::fix_length_and_dec()
}
bool Item_equal::walk(Item_processor processor, bool walk_subquery, void *arg)
bool Item_equal::walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth)
{
Item *item;
Item_equal_fields_iterator it(*this);
while ((item= it++))
{
if (item->walk(processor, walk_subquery, arg))
if (item->walk(processor, walk_subquery, arg, depth+1))
return 1;
}
return Item_func::walk(processor, walk_subquery, arg);
return Item_func::walk(processor, walk_subquery, arg, depth+1);
}
......
......@@ -1264,7 +1264,8 @@ class Item_func_nullif :public Item_func_case_expression
my_decimal *decimal_op(my_decimal *);
bool native_op(THD *thd, Native *to);
bool fix_length_and_dec();
bool walk(Item_processor processor, bool walk_subquery, void *arg);
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0);
const char *func_name() const { return "nullif"; }
void print(String *str, enum_query_type query_type);
void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
......@@ -2784,10 +2785,10 @@ class Item_func_like :public Item_bool_func2
return this;
}
bool walk(Item_processor processor, bool walk_subquery, void *arg)
bool walk(Item_processor processor, bool walk_subquery, void *arg, uint depth)
{
return walk_args(processor, walk_subquery, arg)
|| escape_item->walk(processor, walk_subquery, arg)
return walk_args(processor, walk_subquery, arg, depth+1)
|| escape_item->walk(processor, walk_subquery, arg, depth+1)
|| (this->*processor)(arg);
}
......@@ -3014,7 +3015,8 @@ class Item_cond :public Item_bool_func
void top_level_item() { abort_on_null=1; }
bool top_level() { return abort_on_null; }
void copy_andor_arguments(THD *thd, Item_cond *item);
bool walk(Item_processor processor, bool walk_subquery, void *arg);
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0);
Item *do_transform(THD *thd, Item_transformer transformer, uchar *arg, bool toplevel);
Item *transform(THD *thd, Item_transformer transformer, uchar *arg)
{
......@@ -3215,7 +3217,8 @@ class Item_equal: public Item_bool_func
uint *and_level, table_map usable_tables,
SARGABLE_PARAM **sargables);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
bool walk(Item_processor processor, bool walk_subquery, void *arg);
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0);
Item *transform(THD *thd, Item_transformer transformer, uchar *arg);
virtual void print(String *str, enum_query_type query_type);
const Type_handler *compare_type_handler() const { return m_compare_handler; }
......
......@@ -113,9 +113,10 @@ class Item_row: public Item_fixed_hybrid,
table_map not_null_tables() const { return not_null_tables_cache; }
virtual void print(String *str, enum_query_type query_type);
bool walk(Item_processor processor, bool walk_subquery, void *arg)
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0)
{
if (walk_args(processor, walk_subquery, arg))
if (walk_args(processor, walk_subquery, arg, depth+1))
return true;
return (this->*processor)(arg);
}
......
......@@ -668,7 +668,7 @@ int walk_items_for_table_list(Item_processor processor,
bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
void *argument)
void *argument, uint depth)
{
if (!(unit->uncacheable & ~UNCACHEABLE_DEPENDENT) && engine->is_executed() &&
!unit->describe)
......
......@@ -241,7 +241,8 @@ class Item_subselect :public Item_result_field,
*/
virtual void reset_value_registration() {}
enum_parsing_place place() { return parsing_place; }
bool walk(Item_processor processor, bool walk_subquery, void *arg);
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0);
bool mark_as_eliminated_processor(void *arg);
bool eliminate_subselect_processor(void *arg);
bool enumerate_field_refs_processor(void *arg);
......@@ -753,10 +754,11 @@ class Item_in_subselect :public Item_exists_subselect
DBUG_VOID_RETURN;
}
bool walk(Item_processor processor, bool walk_subquery, void *arg)
bool walk(Item_processor processor, bool walk_subquery, void *arg,
uint depth= 0)
{
return left_expr->walk(processor, walk_subquery, arg) ||
Item_subselect::walk(processor, walk_subquery, arg);
return left_expr->walk(processor, walk_subquery, arg, depth+1) ||
Item_subselect::walk(processor, walk_subquery, arg, depth+1);
}
bool exists2in_processor(void *opt_arg __attribute__((unused)))
......
......@@ -9090,3 +9090,6 @@ ER_PERIOD_CONSTRAINT_DROP
ER_TOO_LONG_KEYPART 42000 S1009
chi "指定的索引部分太长;最大索引部分长度为 %u 个字节"
eng "Specified key part was too long; max key part length is %u bytes"
ER_DERIVED_RECURSION_LIMIT
chi "例程超出派生合并递归限制 %d(设置 derived_merge=off)"
eng "Derived Merged Recursive limit %d was exceeded for routine (set derived_merge=off)"
......@@ -6262,7 +6262,13 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
else
{
if (thd->column_usage == MARK_COLUMNS_READ)
it->walk(&Item::register_field_in_read_map, 0, 0);
{
if (it->walk(&Item::register_field_in_read_map, 0, 0))
{
// something went wrong,
fld= nullptr;
}
}
else
it->walk(&Item::register_field_in_write_map, 0, 0);
}
......
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