diff options
author | Rex <rex.johnston@mariadb.com> | 2023-05-02 13:08:31 +1100 |
---|---|---|
committer | Rex <rex.johnston@mariadb.com> | 2023-05-02 14:17:06 +1100 |
commit | 3e033b3ab1b1eb3fee5825317fa3fe04f2d15f5b (patch) | |
tree | ddc295251bdbb8f78975dc46a7c1d95ec3d3ec99 | |
parent | ddcc9d2281de9fa68525a6808e9181bbd6bf98e0 (diff) | |
download | mariadb-git-bb-10.4-MDEV-31130.tar.gz |
MDEV-31130 INSERT-SELECT with many when/case/if conditions running foreverbb-10.4-MDEV-31130
recursive column definitions in stacked materialized tables causes issues.
detect depth of walk in the item tree and terminate if too deep.
-rw-r--r-- | sql/item.h | 61 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 19 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 15 | ||||
-rw-r--r-- | sql/item_row.h | 5 | ||||
-rw-r--r-- | sql/item_subselect.cc | 2 | ||||
-rw-r--r-- | sql/item_subselect.h | 10 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 3 | ||||
-rw-r--r-- | sql/sql_base.cc | 8 |
8 files changed, 80 insertions, 43 deletions
diff --git a/sql/item.h b/sql/item.h index d04d77da666..3740199698f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1868,7 +1868,8 @@ public: 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 @@ protected: 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 @@ public: 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 @@ public: } 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 @@ public: } 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: { 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) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index fa96d95adb1..d0974bbd3f9 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -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); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 6706c2edf40..99ff74da7ae 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1264,7 +1264,8 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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; } diff --git a/sql/item_row.h b/sql/item_row.h index ea5a0f21d8b..44672d299ae 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -113,9 +113,10 @@ public: 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); } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index f88e1e7e101..14d2fa67ea8 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -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) diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 86c032dd1ce..cde51e58340 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -241,7 +241,8 @@ public: */ 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 @@ public: 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))) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 8bc2b784830..3146cfebeeb 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -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)" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 37336a83bfb..f49b0b66dc3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -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); } |