@@ -1543,17 +1543,17 @@ private RelNode getCorRel(CorRef corVar) {
15431543 /** Adds a value generator to satisfy the correlating variables used by
15441544 * a relational expression, if those variables are not already provided by
15451545 * its input. */
1546- private Frame maybeAddValueGenerator (RelNode rel , Frame frame ) {
1547- final CorelMap cm1 = new CorelMapBuilder ().build (frame .r , rel );
1546+ private Frame maybeAddValueGenerator (RelNode rel , Frame inputFrame ) {
1547+ final CorelMap cm1 = new CorelMapBuilder ().build (inputFrame .r , rel );
15481548 if (!cm1 .mapRefRelToCorRef .containsKey (rel )) {
1549- return frame ;
1549+ return inputFrame ;
15501550 }
15511551 final Collection <CorRef > needs = cm1 .mapRefRelToCorRef .get (rel );
1552- final ImmutableSortedSet <CorDef > haves = frame .corDefOutputs .keySet ();
1552+ final ImmutableSortedSet <CorDef > haves = inputFrame .corDefOutputs .keySet ();
15531553 if (hasAll (needs , haves )) {
1554- return frame ;
1554+ return inputFrame ;
15551555 }
1556- return decorrelateInputWithValueGenerator (rel , frame );
1556+ return decorrelateInputWithValueGenerator (rel , inputFrame );
15571557 }
15581558
15591559 /** Returns whether all of a collection of {@link CorRef}s are satisfied
@@ -1579,13 +1579,13 @@ private static boolean has(Collection<CorDef> corDefs, CorRef corr) {
15791579 return false ;
15801580 }
15811581
1582- private Frame decorrelateInputWithValueGenerator (RelNode rel , Frame frame ) {
1582+ private Frame decorrelateInputWithValueGenerator (RelNode rel , Frame inputFrame ) {
15831583 // currently only handles one input
15841584 assert rel .getInputs ().size () == 1 ;
1585- RelNode oldInput = frame .r ;
1585+ RelNode oldInput = inputFrame .r ;
15861586
15871587 final NavigableMap <CorDef , Integer > corDefOutputs =
1588- new TreeMap <>(frame .corDefOutputs );
1588+ new TreeMap <>(inputFrame .corDefOutputs );
15891589
15901590 final Collection <CorRef > corVarList = cm .mapRefRelToCorRef .get (rel );
15911591
@@ -1606,16 +1606,15 @@ private Frame decorrelateInputWithValueGenerator(RelNode rel, Frame frame) {
16061606 if (node instanceof RexInputRef ) {
16071607 map .put (def , ((RexInputRef ) node ).getIndex ());
16081608 } else {
1609- map .put (def ,
1610- frame .r .getRowType ().getFieldCount () + projects .size ());
1609+ map .put (def , inputFrame .r .getRowType ().getFieldCount () + projects .size ());
16111610 projects .add ((RexNode ) node );
16121611 }
16131612 }
16141613 }
16151614 // If all correlation variables are now satisfied, skip creating a value
16161615 // generator.
16171616 if (map .size () == corVarList .size ()) {
1618- map .putAll (frame .corDefOutputs );
1617+ map .putAll (inputFrame .corDefOutputs );
16191618 final RelNode r ;
16201619 if (!projects .isEmpty ()) {
16211620 relBuilder .push (oldInput )
@@ -1624,17 +1623,40 @@ private Frame decorrelateInputWithValueGenerator(RelNode rel, Frame frame) {
16241623 } else {
16251624 r = oldInput ;
16261625 }
1627- return register (rel .getInput (0 ), r ,
1628- frame .oldToNewOutputs , map );
1626+ return register (rel .getInput (0 ), r , inputFrame .oldToNewOutputs , map );
16291627 }
16301628 }
16311629
1632- int leftInputOutputCount = frame .r .getRowType ().getFieldCount ();
1630+ return createFrameWithValueGenerator (rel .getInput (0 ), inputFrame , corVarList , corDefOutputs );
1631+ }
1632+
1633+ /**
1634+ * Creates a new {@link Frame} for the given rel by joining its current
1635+ * decorrelated rel with a value generator that produces the required
1636+ * correlation variables.
1637+ *
1638+ * <p>The value generator is built from {@code corVarList} and joined with
1639+ * {@code frame.r} using an INNER join. The provided
1640+ * {@code corDefOutputs} map is updated to reflect the positions of all
1641+ * correlation definitions in the join output, and the resulting frame is
1642+ * registered for {@code rel}.
1643+ *
1644+ * @param rel target RelNode whose frame is updated to use the join of
1645+ * {@code frame.r} and the value generator
1646+ * @param frame existing Frame of the rel
1647+ * @param corVarList correlated variables that still need to be produced
1648+ * @param corDefOutputs mapping from {@link CorDef} to output positions; updated in place
1649+ * to include positions in the new join
1650+ * @return a new Frame describing {@code rel} after attaching the value generator
1651+ */
1652+ private Frame createFrameWithValueGenerator (RelNode rel , Frame frame ,
1653+ Collection <CorRef > corVarList , NavigableMap <CorDef , Integer > corDefOutputs ) {
1654+ int leftFieldCount = frame .r .getRowType ().getFieldCount ();
16331655
16341656 // can directly add positions into corDefOutputs since join
16351657 // does not change the output ordering from the inputs.
16361658 final RelNode valueGen =
1637- createValueGenerator (corVarList , leftInputOutputCount , corDefOutputs );
1659+ createValueGenerator (corVarList , leftFieldCount , corDefOutputs );
16381660 requireNonNull (valueGen , "valueGen" );
16391661
16401662 RelNode join =
@@ -1647,8 +1669,7 @@ private Frame decorrelateInputWithValueGenerator(RelNode rel, Frame frame) {
16471669 // Join or Filter does not change the old input ordering. All
16481670 // input fields from newLeftInput (i.e. the original input to the old
16491671 // Filter) are in the output and in the same position.
1650- return register (rel .getInput (0 ), join , frame .oldToNewOutputs ,
1651- corDefOutputs );
1672+ return register (rel , join , frame .oldToNewOutputs , corDefOutputs );
16521673 }
16531674
16541675 /** Finds a {@link RexInputRef} that is equivalent to a {@link CorRef},
@@ -1931,8 +1952,19 @@ private static boolean isWidening(RelDataType type, RelDataType type1) {
19311952 return null ;
19321953 }
19331954
1955+ Frame newLeftFrame = leftFrame ;
1956+ boolean joinConditionContainsFieldAccess = RexUtil .containsFieldAccess (rel .getCondition ());
1957+ if (joinConditionContainsFieldAccess && isCorVarDefined ) {
1958+ final CorelMap localCorelMap = new CorelMapBuilder ().build (rel );
1959+ final List <CorRef > corVarList = new ArrayList <>(localCorelMap .mapRefRelToCorRef .values ());
1960+ Collections .sort (corVarList );
1961+
1962+ final NavigableMap <CorDef , Integer > corDefOutputs = new TreeMap <>();
1963+ newLeftFrame = createFrameWithValueGenerator (oldLeft , leftFrame , corVarList , corDefOutputs );
1964+ }
1965+
19341966 RelNode newJoin = relBuilder
1935- .push (leftFrame .r )
1967+ .push (newLeftFrame .r )
19361968 .push (rightFrame .r )
19371969 .join (rel .getJoinType (),
19381970 decorrelateExpr (castNonNull (currentRel ), map , cm , rel .getCondition ()),
@@ -1944,25 +1976,23 @@ private static boolean isWidening(RelDataType type, RelDataType type1) {
19441976 Map <Integer , Integer > mapOldToNewOutputs = new HashMap <>();
19451977
19461978 int oldLeftFieldCount = oldLeft .getRowType ().getFieldCount ();
1947- int newLeftFieldCount = leftFrame .r .getRowType ().getFieldCount ();
1979+ int newLeftFieldCount = newLeftFrame .r .getRowType ().getFieldCount ();
19481980
19491981 int oldRightFieldCount = oldRight .getRowType ().getFieldCount ();
19501982 //noinspection AssertWithSideEffects
19511983 assert rel .getRowType ().getFieldCount ()
19521984 == oldLeftFieldCount + oldRightFieldCount ;
19531985
19541986 // Left input positions are not changed.
1955- mapOldToNewOutputs .putAll (leftFrame .oldToNewOutputs );
1956-
1987+ mapOldToNewOutputs .putAll (newLeftFrame .oldToNewOutputs );
19571988 // Right input positions are shifted by newLeftFieldCount.
19581989 for (int i = 0 ; i < oldRightFieldCount ; i ++) {
19591990 mapOldToNewOutputs .put (i + oldLeftFieldCount ,
19601991 requireNonNull (rightFrame .oldToNewOutputs .get (i )) + newLeftFieldCount );
19611992 }
19621993
19631994 final NavigableMap <CorDef , Integer > corDefOutputs =
1964- new TreeMap <>(leftFrame .corDefOutputs );
1965-
1995+ new TreeMap <>(newLeftFrame .corDefOutputs );
19661996 // Right input positions are shifted by newLeftFieldCount.
19671997 for (Map .Entry <CorDef , Integer > entry
19681998 : rightFrame .corDefOutputs .entrySet ()) {
0 commit comments