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