summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRex <rex.johnston@mariadb.com>2023-05-02 13:08:31 +1100
committerRex <rex.johnston@mariadb.com>2023-05-02 14:17:06 +1100
commit3e033b3ab1b1eb3fee5825317fa3fe04f2d15f5b (patch)
treeddc295251bdbb8f78975dc46a7c1d95ec3d3ec99
parentddcc9d2281de9fa68525a6808e9181bbd6bf98e0 (diff)
downloadmariadb-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.h61
-rw-r--r--sql/item_cmpfunc.cc19
-rw-r--r--sql/item_cmpfunc.h15
-rw-r--r--sql/item_row.h5
-rw-r--r--sql/item_subselect.cc2
-rw-r--r--sql/item_subselect.h10
-rw-r--r--sql/share/errmsg-utf8.txt3
-rw-r--r--sql/sql_base.cc8
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);
}