rubenada commented on code in PR #4750:
URL: https://github.com/apache/calcite/pull/4750#discussion_r2701066249


##########
core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java:
##########
@@ -1953,51 +1946,98 @@ private static boolean isWidening(RelDataType type, 
RelDataType type1) {
     }
 
     Frame newLeftFrame = leftFrame;
+    Frame newRightFrame = rightFrame;
+    final NavigableMap<CorDef, Integer> leftCorDefOutputs = new TreeMap<>();
+    final NavigableMap<CorDef, Integer> rightCorDefOutputs = new TreeMap<>();
     boolean joinConditionContainsFieldAccess = 
RexUtil.containsFieldAccess(rel.getCondition());
-    if (joinConditionContainsFieldAccess && isCorVarDefined) {
-      final CorelMap localCorelMap = new CorelMapBuilder().build(rel);
-      final List<CorRef> corVarList = new 
ArrayList<>(localCorelMap.mapRefRelToCorRef.values());
-      Collections.sort(corVarList);
+    boolean generatesNullsOnRight = rel.getJoinType().generatesNullsOnRight();
+    boolean generatesNullsOnLeft = rel.getJoinType().generatesNullsOnLeft();
+
+    final CorelMap localCorelMap = new CorelMapBuilder().build(rel);
+    final List<CorRef> corVarList = new 
ArrayList<>(localCorelMap.mapRefRelToCorRef.values());
+    Collections.sort(corVarList);
+
+    if ((joinConditionContainsFieldAccess || generatesNullsOnRight) && 
isCorVarDefined) {
+      newLeftFrame =
+          createFrameWithValueGenerator(oldLeft, leftFrame, corVarList, 
leftCorDefOutputs);
+    }
 
-      final NavigableMap<CorDef, Integer> corDefOutputs = new TreeMap<>();
-      newLeftFrame = createFrameWithValueGenerator(oldLeft, leftFrame, 
corVarList, corDefOutputs);
+    if (generatesNullsOnLeft && isCorVarDefined) {
+      newRightFrame =
+          createFrameWithValueGenerator(oldRight, rightFrame, corVarList, 
rightCorDefOutputs);
     }
 
+    // Build join conditions: original condition + correlated variable 
conditions
+    final List<RexNode> joinConditions = new ArrayList<>();
+
+    // Add the original join condition
+    RexNode originalCond = decorrelateExpr(castNonNull(currentRel), map, cm, 
rel.getCondition());
+    if (!originalCond.isAlwaysTrue()) {
+      joinConditions.add(originalCond);
+    }
+
+    int newLeftFieldCount = newLeftFrame.r.getRowType().getFieldCount();
+
+    // For joins that generate nulls on the right (LEFT, FULL, LEFT_ASOF),
+    // add conditions to connect correlated variables from left and right
+    if (generatesNullsOnRight && !leftCorDefOutputs.isEmpty()) {
+      // Iterate over preserved right side, lookup value generators on 
nullable left side
+      final List<RexNode> conds =
+          buildCorDefJoinConditions(newRightFrame.corDefOutputs, 
leftCorDefOutputs,
+              newLeftFrame.r, newRightFrame.r, newLeftFieldCount, relBuilder, 
true);
+      joinConditions.addAll(conds);
+    }
+
+    // For joins that generate nulls on the left (RIGHT, FULL),
+    // add conditions to connect correlated variables from left and right
+    if (generatesNullsOnLeft && !rightCorDefOutputs.isEmpty()) {
+      // Iterate over preserved left side, lookup value generators on nullable 
right side
+      final List<RexNode> conds =
+          buildCorDefJoinConditions(newLeftFrame.corDefOutputs, 
rightCorDefOutputs,
+              newLeftFrame.r, newRightFrame.r, newLeftFieldCount, relBuilder, 
false);
+      joinConditions.addAll(conds);
+    }
+
+    RexNode finalCondition = joinConditions.isEmpty()
+        ? relBuilder.literal(true)
+        : RexUtil.composeConjunction(relBuilder.getRexBuilder(), 
joinConditions);
+
     RelNode newJoin = relBuilder
         .push(newLeftFrame.r)
-        .push(rightFrame.r)
-        .join(rel.getJoinType(),
-            decorrelateExpr(castNonNull(currentRel), map, cm, 
rel.getCondition()),
-            ImmutableSet.of())
+        .push(newRightFrame.r)
+        .join(rel.getJoinType(), finalCondition, ImmutableSet.of())
         .build();
 
-    // Create the mapping between the output of the old correlation rel
-    // and the new join rel
-    Map<Integer, Integer> mapOldToNewOutputs = new HashMap<>();
-
     int oldLeftFieldCount = oldLeft.getRowType().getFieldCount();
-    int newLeftFieldCount = newLeftFrame.r.getRowType().getFieldCount();
-
     int oldRightFieldCount = oldRight.getRowType().getFieldCount();
     //noinspection AssertWithSideEffects
     assert rel.getRowType().getFieldCount()
         == oldLeftFieldCount + oldRightFieldCount;
 
+    // Create the mapping between the output of the old correlation rel and 
the new join rel
     // Left input positions are not changed.
-    mapOldToNewOutputs.putAll(newLeftFrame.oldToNewOutputs);
+    Map<Integer, Integer> mapOldToNewOutputs = new 
HashMap<>(newLeftFrame.oldToNewOutputs);
     // Right input positions are shifted by newLeftFieldCount.
     for (int i = 0; i < oldRightFieldCount; i++) {
       mapOldToNewOutputs.put(i + oldLeftFieldCount,
-          requireNonNull(rightFrame.oldToNewOutputs.get(i)) + 
newLeftFieldCount);
+          requireNonNull(newRightFrame.oldToNewOutputs.get(i)) + 
newLeftFieldCount);
     }
 
-    final NavigableMap<CorDef, Integer> corDefOutputs =
-        new TreeMap<>(newLeftFrame.corDefOutputs);
+    final NavigableMap<CorDef, Integer> corDefOutputs = new 
TreeMap<>(newLeftFrame.corDefOutputs);
     // Right input positions are shifted by newLeftFieldCount.
-    for (Map.Entry<CorDef, Integer> entry
-        : rightFrame.corDefOutputs.entrySet()) {
-      corDefOutputs.put(entry.getKey(),
-          entry.getValue() + newLeftFieldCount);
+    for (Map.Entry<CorDef, Integer> entry : 
newRightFrame.corDefOutputs.entrySet()) {
+      if (generatesNullsOnRight) {
+        // For joins that generate nulls on the right (LEFT, FULL, LEFT_ASOF),
+        // prefer left side corDef (from value generator) because right side 
might be NULL
+        corDefOutputs.putIfAbsent(entry.getKey(), entry.getValue() + 
newLeftFieldCount);
+      } else if (generatesNullsOnLeft) {
+        // For joins that generate nulls on the left (RIGHT, FULL),

Review Comment:
   nit: The code in the `else if` block and the `else` look the same, maybe we 
could combine them? (keeping both comments for clarity)



-- 
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]

Reply via email to