-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove EnforceSingleRowNode support from PlanNodeDecorrelator #19932
Conversation
This is mostly cleanup, I don't think it's possible to produce wrong plan with this issue. |
Fixes #19002 |
This issue is closed. |
...ain/src/main/java/io/trino/sql/planner/iterative/rule/TransformCorrelatedScalarSubquery.java
Show resolved
Hide resolved
core/trino-main/src/main/java/io/trino/sql/planner/optimizations/PlanNodeDecorrelator.java
Show resolved
Hide resolved
...src/test/java/io/trino/sql/planner/iterative/rule/TestTransformCorrelatedScalarSubquery.java
Show resolved
Hide resolved
...src/test/java/io/trino/sql/planner/iterative/rule/TestTransformCorrelatedScalarSubquery.java
Show resolved
Hide resolved
@@ -124,7 +126,10 @@ public Result apply(CorrelatedJoinNode correlatedJoinNode, Captures captures, Co | |||
correlatedJoinNode.getInput(), | |||
rewrittenSubquery, | |||
correlatedJoinNode.getCorrelation(), | |||
producesSingleRow ? INNER : correlatedJoinNode.getType(), | |||
// EnforceSingleRowNode guarantees that exactly single matching row is produced |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no guarantee that there's an EnforceSingleRowNode, is there? All this rule cares about is whether the subplan is known to produce 0 or 1 row.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if there is no EnforceSingleRowNode, we exit earlier:
if (!searchFrom(subquery, context.getLookup())
.where(EnforceSingleRowNode.class::isInstance)
.recurseOnlyWhen(ProjectNode.class::isInstance)
.matches()) {
return Result.empty();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed that. It wasn't immediately visible in the diff. However, that should not be necessary for this rule to work in general, as far as I can tell. We omit that check and rely on the cardinality property of the subplan.
I guess my comment is that in order to future-proof this comment from non-local changes, we could just generalize it to say that the subplan is guaranteed to produce one row (regardless of how that's achieved), so this can be an inner join instead of a left join.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the rule insists on finding EnforceSingleRowNode because it also wants (needs?) to remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally for this rule we have two sub-rules like ...WithProjection
and WithoutProjection
as for example for TransformCorrelatedGlobalAggregationWithoutProjection
. However, I don't want to refactor this rule as part of this PR.
I guess my comment is that in order to future-proof this comment from non-local changes, we could just generalize it to say that the subplan is guaranteed to produce one row (regardless of how that's achieved), so this can be an inner join instead of a left join.
I don't think it can be generalized like that in a sense that EnforceSingleRowNode
is kind of special node, because:
- subplan might produce more than one row and
EnforceSingleRowOperator
will fail then. That check is preserved in decorrelated plan afterTransformCorrelatedScalarSubquery
. Such check is not needed while decorrelating viaPlanNodeDecorrelator
. - subplan might produce 0 rows and
EnforceSingleRowOperator
will produce null row then. This semantics is also preserved byTransformCorrelatedScalarSubquery
(and it's only possible to decorrelate such plan when join itself has no filter).
Overall, single-row cases are already handled by TransformCorrelatedJoinToJoin
(and PlanNodeDecorrelator
) while this rule is dedicated for decorrelation of EnforceSingleRowNode
fc1b290
to
0a306d2
Compare
EnforceSingleRowNode guarantees that exactly single row is produced. Therefore, PlanNodeDecorrelator was incorrectly removing EnforceSingleRowNode even if decorrelated subplan could produce 0 rows. Additionally, TransformCorrelatedJoinToJoin was competing with TransformCorrelatedScalarSubquery to decorrelate EnforceSingleRowNode. This changes removes support for EnforceSingleRowNode from PlanNodeDecorrelator and makes TransformCorrelatedScalarSubquery the only rule that (correctly) decorrelates that node.
0a306d2
to
f7b0429
Compare
EnforceSingleRowNode guarantees that exactly single row is produced. Therefore, PlanNodeDecorrelator was incorrectly removing EnforceSingleRowNode even if decorrelated subplan could produce 0 rows.
Additionally, TransformCorrelatedJoinToJoin was completing with TransformCorrelatedScalarSubquery to decorrelate EnforceSingleRowNode.
This changes removes support for EnforceSingleRowNode from PlanNodeDecorrelator and makes TransformCorrelatedScalarSubquery the only rule that (correctly) decorrelates that node.