@@ -9827,6 +9827,92 @@ static inline bool derived_table_optimization_done(TABLE_LIST *table)
98279827}
98289828
98299829
9830+ /*
9831+ Queries of the form
9832+ SELECT ... FROM (SELECT constant AS alias_N FROM t0) dt ... WHERE EXISTS
9833+ (SELECT ... WHERE (dt.alias_N ...));
9834+ must force derived table dt to be materialized, or the WHERE EXISTS will
9835+ not filter rows correctly. If we allow derived table dt to be merged,
9836+ then references to dt.alias_N are replaced with their constant values
9837+ directly, so a WHERE EXISTS subquery will attempt to filter rows from the
9838+ outer query based on those constant values rather than the columns'
9839+ values computed during outer query evaluation.
9840+
9841+ This can't be done later, during DT_MERGE, because by that point the WHERE
9842+ EXISTS subquery has already had its WHERE clause updated with the field
9843+ from the merged query and it's impossible to detect that the merge should
9844+ be prevented by that time. Doing this here prevents merging from occurring
9845+ in any case.
9846+ */
9847+ static bool where_exists_depends_on_mergeable_derived (TABLE_LIST *derived,
9848+ SELECT_LEX *select_lex)
9849+ {
9850+ if (!derived->on_expr || !select_lex->where )
9851+ return false ;
9852+
9853+ /*
9854+ The WhereExistsVisitor visits the fields of the WHERE clause within a
9855+ subquery of an outer WHERE EXISTS clause. For each field found, it
9856+ checks to see if the same field is referenced in the derived table and
9857+ if so, blocks derived table merging.
9858+ */
9859+ class WhereExistsVisitor : public Field_enumerator
9860+ {
9861+ struct DerivedTableVisitor : public Field_enumerator
9862+ {
9863+ WhereExistsVisitor *outer{nullptr };
9864+ Item_field *where_exists_field{nullptr };
9865+
9866+ void visit_field (Item_field *derived_table_field) override
9867+ {
9868+ if (outer->block_merging || !derived_table_field->field_name )
9869+ return ;
9870+ outer->block_merging =
9871+ (derived_table_field->field_name .streq (where_exists_field->field_name ) &&
9872+ derived_table_field->table_name .streq (where_exists_field->table_name ));
9873+ }
9874+
9875+ public:
9876+ DerivedTableVisitor (WhereExistsVisitor *wev, Item_field *field)
9877+ : outer(wev)
9878+ , where_exists_field(field)
9879+ {
9880+ DBUG_ASSERT (outer);
9881+ DBUG_ASSERT (field);
9882+ }
9883+ };
9884+
9885+ Item *dt_expr{nullptr };
9886+
9887+ void visit_field (Item_field *where_exists_field) override
9888+ {
9889+ if (!dt_expr || !where_exists_field->field_name )
9890+ return ;
9891+ DerivedTableVisitor dt_visitor (this , where_exists_field);
9892+ dt_expr->walk (&Item::enumerate_field_refs_processor,
9893+ true , &dt_visitor);
9894+ }
9895+
9896+ public:
9897+ bool block_merging{false };
9898+
9899+ WhereExistsVisitor (Item *derived_expr)
9900+ : dt_expr(derived_expr)
9901+ {
9902+ DBUG_ASSERT (dt_expr);
9903+ }
9904+ };
9905+
9906+ // Visit each field in the WHERE clause of the subquery in the WHERE EXISTS
9907+ // and check to see if any field references a constant field from the given
9908+ // derived table of the outer query.
9909+ WhereExistsVisitor visitor (derived->on_expr );
9910+ select_lex->where ->walk (&Item::where_exists_processor,
9911+ true , &visitor);
9912+ return visitor.block_merging ;
9913+ }
9914+
9915+
98309916/* *
98319917 @brief
98329918 Initialize this derived table/view
@@ -9886,8 +9972,13 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view)
98869972
98879973 if (!derived_table_optimization_done (this ))
98889974 {
9975+ const bool force_materialization=
9976+ where_exists_depends_on_mergeable_derived (this ,
9977+ select_lex);
9978+
98899979 /* A subquery might be forced to be materialized due to a side-effect. */
9890- if (!is_materialized_derived () && unit->can_be_merged () &&
9980+ if (!force_materialization && !is_materialized_derived () &&
9981+ unit->can_be_merged () &&
98919982 /*
98929983 Following is special case of
98939984 SELECT * FROM (<limited-select>) WHERE ROWNUM() <= nnn
0 commit comments