summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuchen Pei <yuchen.pei@mariadb.com>2023-05-17 11:42:57 +1000
committerYuchen Pei <yuchen.pei@mariadb.com>2023-05-17 11:47:45 +1000
commitfe2b867b499273adb4a84569340d866deaf27b8e (patch)
tree03bb39e2ad896488f9a16d40d5d32c264848bb8b
parent88ed254c3e6709eb50624b45cfb9908f2086c64e (diff)
downloadmariadb-git-fe2b867b499273adb4a84569340d866deaf27b8e.tar.gz
MDEV-22534 PoC fix of segfault during 2nd ps execution
In the decorrelating-in transformation, if 1) we are in an ps execution and 2) the equalities picked out for the transformation intersect with the free list, skip the transformation. See also https://jira.mariadb.org/browse/MDEV-22534?focusedCommentId=258728&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-258728 for detailed analysis
-rw-r--r--sql/item_subselect.cc45
1 files changed, 34 insertions, 11 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 3833c48d562..f8f6ea79f8a 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -3099,6 +3099,14 @@ alloc_err:
return TRUE;
}
+bool intersects_free_list(Item *item, THD *thd)
+{
+ for (const Item *to_find= thd->free_list; to_find; to_find= to_find->next)
+ if (item->walk(&Item::find_item_processor, 1, (void *) to_find))
+ return true;
+ return false;
+}
+
bool Item_in_subselect::exists2in_processor(void *opt_arg)
{
THD *thd= (THD *)opt_arg;
@@ -3110,23 +3118,30 @@ bool Item_in_subselect::exists2in_processor(void *opt_arg)
Query_arena *arena= NULL, backup;
DBUG_ENTER("Item_in_subselect::exists2in_processor");
if (!optimizer_flag(thd, OPTIMIZER_SWITCH_EXISTS_TO_IN) ||
+ /* fixme: Not sure this check of top level item etc. is
+ necessary. */
(!is_top_level_item() &&
(!upper_not || !upper_not->is_top_level_item())) ||
- first_select->group_list.elements ||
- join->having ||
- !join->conds)
+ first_select->group_list.elements || /* skip if with group by */
+ join->having || /* skip if with having */
+ !join->conds) /* skip if no conds */
DBUG_RETURN(FALSE);
/* iterate over conditions, and check whether they can be moved out. */
if (find_inner_outer_equalities(&join->conds, eqs))
DBUG_RETURN(FALSE);
- arena= thd->activate_stmt_arena_if_needed(&backup);
- /* move out the conditions */
- if (left_expr->type() == Item::ROW_ITEM)
- for (uint i= 0; i < left_expr->cols(); i++)
- outer.push_back(left_expr->element_index(i));
- else
- outer.push_back(left_expr);
- const uint offset= first_select->item_list.elements;
+ /* If we are in the execution of a prepared statement, check for
+ intersection with the free list to avoid segfault. Note that the
+ check for prepared statement execution is necessary, otherwise it
+ will likely always find intersection thus abort the
+ transformation. */
+ if (thd->m_statement_state.m_parent_prepared_stmt)
+ {
+ for (uint i= 0; i < (uint) eqs.elements(); i++)
+ {
+ if (intersects_free_list(*eqs.at(i).eq_ref, thd))
+ DBUG_RETURN(FALSE);
+ }
+ }
/* check that the subquery has only dependencies we are going pull out */
{
List<Item> unused;
@@ -3141,6 +3156,14 @@ bool Item_in_subselect::exists2in_processor(void *opt_arg)
DBUG_ASSERT(prm.count >= (uint)eqs.elements());
will_be_correlated= prm.count > (uint)eqs.elements();
}
+ arena= thd->activate_stmt_arena_if_needed(&backup);
+ /* construct the items for left_expr */
+ if (left_expr->type() == Item::ROW_ITEM)
+ for (uint i= 0; i < left_expr->cols(); i++)
+ outer.push_back(left_expr->element_index(i));
+ else
+ outer.push_back(left_expr);
+ const uint offset= first_select->item_list.elements;
for (uint i= 0; i < (uint)eqs.elements(); i++)
{
Item **eq_ref= eqs.at(i).eq_ref;