github-actions[bot] commented on code in PR #65682:
URL: https://github.com/apache/doris/pull/65682#discussion_r3601957120
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraphv2/HyperGraph.java:
##########
@@ -385,15 +489,45 @@ public boolean addAlias(Alias alias, long subTreeNodes) {
if (bitmap == 0) {
bitmap = subTreeNodes;
addToReplaceMap = false;
- List<NamedExpression> aliasList =
nodeToLiteralAlias.get(bitmap);
- if (aliasList == null) {
- aliasList = new ArrayList<>(1);
- nodeToLiteralAlias.put(bitmap, aliasList);
+ // Constant aliases go into the current Project layer (set up
by
+ // buildForDPhyper) and will be flushed to
nodeToProjectedAliases
+ // keyed by the layer's subtree bitmap after the Project is
processed.
+ if (currentProjectedAliasLayer != null) {
+ currentProjectedAliasLayer.add(alias);
}
- aliasList.add(alias);
}
Preconditions.checkArgument(bitmap > 0, "slot must belong to some
table");
- slotToHyperNodeMap.put(aliasSlot, bitmap);
+ // Map nullable-side alias slots to subTreeNodes instead of the
minimal
+ // referenced bitmap. Otherwise a later join predicate like s=C.k
sees s as
+ // {B} (its input slot) and creates a {B}--{C} edge, allowing
DPHyp to join
+ // B and C before A — but s can only be emitted when {A,B} is
complete.
+ // Using subTreeNodes (e.g. {A,B}) forces the predicate edge to
require the
+ // full source subtree, matching the emission key in
nodeToProjectedAliases.
+ // Note: always use subTreeNodes for nullable-side aliases. A
Slot-forwarding
+ // alias (e.g. s=A.k) that shares a Project with expression
aliases cannot
+ // safely use the minimal bitmap — its layer only emits at {A,B},
so exposing
+ // it as {A} would let DPHyp form predicate edges before the alias
exists.
+ slotToHyperNodeMap.put(aliasSlot, isNullableSide ? subTreeNodes :
bitmap);
Review Comment:
[P1] Do not consume a projected alias across a split source endpoint
Mapping `s` to its full source bitmap still permits that bitmap to be split
between both children. For example:
```text
X LEFT JOIN
X
InnerJoin(A.k = C.k, s = C.t)
Project(A.k, B.k, coalesce(B.v, 0) AS s) // source {A,B}
InnerJoin(A.k = B.k)
A
B
C
```
DPHyp can build `{A,C}` via `A.k=C.k`, then combine `{A,C}` with `{B}` via
the A-B edge. At that point `processMissedEdges` adds the unused `{A,B}--{C}`
edge for `s=C.t`, because all of its reference nodes are in the union and it is
not enforced-order. `proposeJoin` therefore creates `s=C.t` while neither child
outputs ExprId `s`; only the later `proposeProject` call emits the `{A,B}`
layer. This can leave the selected alternative with a join predicate bound to a
missing child slot.
This is distinct from the earlier minimal-endpoint cases: the endpoint is
already `{A,B}`, but the missed-edge fallback consumes it while `{A,B}` is
split. Reject such alternatives unless the alias layer has materialized wholly
in one child (or safely substitute the predicate), and add a regression that
makes `{A,C}` a connected candidate.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]