fix(planner): Fix failing isDistinct for equivalent variables for logical properties#27241
fix(planner): Fix failing isDistinct for equivalent variables for logical properties#27241aaneja merged 1 commit intoprestodb:masterfrom
Conversation
Reviewer's GuideRefines logical key requirement satisfaction to account for normalized equivalent variables and extends the logical properties test harness to support custom assertions, adding a regression test that validates key normalization across joined tables and aggregation. Sequence diagram for key requirement satisfaction during join optimizationsequenceDiagram
actor Optimizer
participant TransformDistinctInnerJoinToRightEarlyOutJoin as TransformDistinctInnerJoinToRightEarlyOutJoin
participant LogicalPropertiesImpl as LogicalPropertiesImpl
participant Group as Group
participant KeyProperty as KeyProperty
participant EquivalenceClassProperty as EquivalenceClassProperty
participant MaxCardProperty as MaxCardProperty
Optimizer->>TransformDistinctInnerJoinToRightEarlyOutJoin: apply(ruleContext)
TransformDistinctInnerJoinToRightEarlyOutJoin->>LogicalPropertiesImpl: isDistinct(group)
LogicalPropertiesImpl->>Group: getMaxCardProperty()
Group-->>LogicalPropertiesImpl: maxCardProperty
LogicalPropertiesImpl->>MaxCardProperty: isAtMostOne()
MaxCardProperty-->>LogicalPropertiesImpl: false
LogicalPropertiesImpl->>Group: getKeyProperty()
Group-->>LogicalPropertiesImpl: keyProperty
LogicalPropertiesImpl->>Group: getEquivalenceClassProperty()
Group-->>LogicalPropertiesImpl: equivalenceClassProperty
LogicalPropertiesImpl->>LogicalPropertiesImpl: getNormalizedKey(keyRequirement, equivalenceClassProperty)
LogicalPropertiesImpl->>EquivalenceClassProperty: normalizeKey(keyRequirement)
EquivalenceClassProperty-->>LogicalPropertiesImpl: Optional_Key
LogicalPropertiesImpl->>KeyProperty: satisfiesKeyRequirement(normalizedKey)
KeyProperty-->>LogicalPropertiesImpl: true
LogicalPropertiesImpl-->>TransformDistinctInnerJoinToRightEarlyOutJoin: isDistinct = true
TransformDistinctInnerJoinToRightEarlyOutJoin-->>Optimizer: rule not reapplied, no infinite loop
Class diagram for updated logical key requirement satisfactionclassDiagram
class LogicalPropertiesImpl {
- keyProperty KeyProperty
- equivalenceClassProperty EquivalenceClassProperty
- maxCardProperty MaxCardProperty
+ keyRequirementSatisfied(keyRequirement Key) boolean
+ getNormalizedKey(keyRequirement Key, equivalenceClassProperty EquivalenceClassProperty) Optional_Key
}
class KeyProperty {
+ satisfiesKeyRequirement(keyRequirement Key) boolean
}
class EquivalenceClassProperty {
+ normalizeKey(keyRequirement Key) Optional_Key
}
class MaxCardProperty {
+ isAtMostOne() boolean
}
class Key
class Optional_Key
LogicalPropertiesImpl --> KeyProperty
LogicalPropertiesImpl --> EquivalenceClassProperty
LogicalPropertiesImpl --> MaxCardProperty
LogicalPropertiesImpl --> Optional_Key
KeyProperty --> Key
EquivalenceClassProperty --> Key
EquivalenceClassProperty --> Optional_Key
MaxCardProperty --> LogicalPropertiesImpl
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
@aaneja : Do you need any help with this ? Fixing TPC-DS Q95 is important. The fix looks plausible, but it would be great if we have some tests to validate. |
Was waiting for an internal run to finish - https://github.ibm.com/lakehouse/presto/issues/4435#issuecomment-178835976 I've added a new test that emulates the internal sub-plan similar to Q95. BeforeAfterThe |
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="presto-main-base/src/test/java/com/facebook/presto/sql/planner/iterative/rule/test/RuleAssert.java" line_range="193-196" />
<code_context>
}
- public void matches(LogicalProperties expectedLogicalProperties)
+ public void assertLogicalProperties(Consumer<LogicalProperties> matcher)
{
RuleApplication ruleApplication = applyRule();
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Add an explicit assertion when logical properties for the root group are missing to avoid obscure failures in matchers
The helper currently assumes `getLogicalProperties(...).get()` is always present; if logical properties are missing for the root group, tests will fail with a `NoSuchElementException`/`null` rather than a clear assertion. Please assert that the Optional is present (with a descriptive failure message) before invoking `matcher.accept(...)` so missing logical properties are reported explicitly.
Suggested implementation:
```java
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import static org.testng.Assert.assertTrue;
```
```java
Optional<LogicalProperties> rootNodeLogicalProperties = ruleApplication.getMemo()
.getLogicalProperties(ruleApplication.getMemo().getRootGroup());
assertTrue(
rootNodeLogicalProperties.isPresent(),
"Logical properties are missing for the root group; ensure they are computed before asserting.");
matcher.accept(rootNodeLogicalProperties.get());
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| public void assertLogicalProperties(Consumer<LogicalProperties> matcher) | ||
| { | ||
| RuleApplication ruleApplication = applyRule(); | ||
| TypeProvider types = ruleApplication.types; |
There was a problem hiding this comment.
suggestion (bug_risk): Add an explicit assertion when logical properties for the root group are missing to avoid obscure failures in matchers
The helper currently assumes getLogicalProperties(...).get() is always present; if logical properties are missing for the root group, tests will fail with a NoSuchElementException/null rather than a clear assertion. Please assert that the Optional is present (with a descriptive failure message) before invoking matcher.accept(...) so missing logical properties are reported explicitly.
Suggested implementation:
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import static org.testng.Assert.assertTrue; Optional<LogicalProperties> rootNodeLogicalProperties = ruleApplication.getMemo()
.getLogicalProperties(ruleApplication.getMemo().getRootGroup());
assertTrue(
rootNodeLogicalProperties.isPresent(),
"Logical properties are missing for the root group; ensure they are computed before asserting.");
matcher.accept(rootNodeLogicalProperties.get());
...-main-base/src/test/java/com/facebook/presto/sql/planner/iterative/rule/test/RuleAssert.java
Outdated
Show resolved
Hide resolved
where we were looking up the keyProperty on the input key while we should have been looking up based on the normalized key
Description, Motivation and Context
When using logical properties and the Iterative optimizer, the
KeyPropertyfor a Group may not always use the top-most output variables. It may be using a equivalent variable; which is why we should be normalized the test key using the equivalence classes before doing the comparisonImpact
The TransformDistinctInnerJoinToRightEarlyOutJoin rule was stuck in a loop for TPCDS Q95 when constraints are turned on
The underlying Group node's Key's do not directly refer to the newly added aggregation node's output variables,
so the
isDistinctcheck was failing causing the rule to re-apply and get stuckTest Plan
New test added
Contributor checklist
Release Notes
Summary by Sourcery
Bug Fixes:
Summary by Sourcery
Ensure logical key distinctness checks respect normalized equivalence classes and expand logical property testing to cover key normalization behavior.
Bug Fixes:
Enhancements:
Tests: