Skip to content

Commit 6309f8d

Browse files
committed
[CALCITE-7440] Fix rel2sql correlation fallback without JDBC regressions
1 parent 7d4937e commit 6309f8d

File tree

2 files changed

+36
-33
lines changed

2 files changed

+36
-33
lines changed

core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,11 @@
5454
import org.apache.calcite.rel.type.RelDataTypeField;
5555
import org.apache.calcite.rex.RexBuilder;
5656
import org.apache.calcite.rex.RexCall;
57-
import org.apache.calcite.rex.RexCorrelVariable;
58-
import org.apache.calcite.rex.RexFieldAccess;
5957
import org.apache.calcite.rex.RexInputRef;
6058
import org.apache.calcite.rex.RexLiteral;
6159
import org.apache.calcite.rex.RexLocalRef;
6260
import org.apache.calcite.rex.RexNode;
6361
import org.apache.calcite.rex.RexProgram;
64-
import org.apache.calcite.rex.RexSubQuery;
6562
import org.apache.calcite.sql.JoinConditionType;
6663
import org.apache.calcite.sql.JoinType;
6764
import org.apache.calcite.sql.SqlAsofJoin;
@@ -560,7 +557,6 @@ public Result visit(Filter e) {
560557
visitInput(e, 0, isAnon(), ignoreClauses,
561558
ImmutableSet.of(Clause.HAVING));
562559
parseCorrelTable(e, x);
563-
parseCorrelVariables(e.getCondition());
564560
final Builder builder = x.builder(e);
565561
x.asSelect().setHaving(
566562
SqlUtil.andExpressions(x.asSelect().getHaving(),
@@ -573,7 +569,6 @@ public Result visit(Filter e) {
573569
}
574570
parseCorrelTable(e, x);
575571
final Builder builder = x.builder(e);
576-
parseCorrelVariables(e.getCondition());
577572
if (input instanceof Join) {
578573
final Context context = x.qualifiedContext();
579574
if (selectListRequired(context)) {
@@ -609,31 +604,6 @@ private static boolean selectListRequired(Context context) {
609604
return false;
610605
}
611606

612-
private void parseCorrelVariables(RexNode rexNode) {
613-
if (rexNode instanceof RexCorrelVariable) {
614-
final RexCorrelVariable correl = (RexCorrelVariable) rexNode;
615-
correlTableMap.putIfAbsent(
616-
correl.id,
617-
aliasContext(ImmutableMap.of(correl.id.getName(), correl.getType()), true));
618-
return;
619-
}
620-
if (rexNode instanceof RexSubQuery) {
621-
for (RexNode operand : ((RexSubQuery) rexNode).operands) {
622-
parseCorrelVariables(operand);
623-
}
624-
return;
625-
}
626-
if (rexNode instanceof RexFieldAccess) {
627-
parseCorrelVariables(((RexFieldAccess) rexNode).getReferenceExpr());
628-
return;
629-
}
630-
if (rexNode instanceof RexCall) {
631-
for (RexNode operand : ((RexCall) rexNode).operands) {
632-
parseCorrelVariables(operand);
633-
}
634-
}
635-
}
636-
637607
/**
638608
* Extracts the table name from a SqlNode if it represents a simple table reference.
639609
* Returns null for complex nodes like subqueries or joins.

core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,9 +1587,42 @@ public static SqlNode toSql(RexLiteral literal) {
15871587
}
15881588

15891589
protected Context getAliasContext(RexCorrelVariable variable) {
1590-
return requireNonNull(
1591-
correlTableMap.get(variable.id),
1592-
() -> "variable " + variable.id + " is not found");
1590+
Context context = correlTableMap.get(variable.id);
1591+
if (context == null) {
1592+
// Some rewrites can introduce a new correlation id that still points to
1593+
// the same outer scope. Reuse a compatible known context before failing.
1594+
context = findCompatibleCorrelContext(variable.id, variable.getType().getFieldCount());
1595+
if (context == null && correlTableMap.isEmpty()) {
1596+
context =
1597+
aliasContext(ImmutableMap.of(variable.id.getName(), variable.getType()), true);
1598+
}
1599+
if (context != null) {
1600+
correlTableMap.put(variable.id, context);
1601+
}
1602+
}
1603+
return requireNonNull(context, () -> "variable " + variable.id + " is not found");
1604+
}
1605+
1606+
private @Nullable Context findCompatibleCorrelContext(CorrelationId missingId,
1607+
int expectedFieldCount) {
1608+
Context fallback = null;
1609+
String fallbackName = null;
1610+
for (Map.Entry<CorrelationId, Context> entry : correlTableMap.entrySet()) {
1611+
final CorrelationId id = entry.getKey();
1612+
final Context context = entry.getValue();
1613+
if (id.equals(missingId)) {
1614+
continue;
1615+
}
1616+
if (context.fieldCount == expectedFieldCount) {
1617+
return context;
1618+
}
1619+
final String name = id.getName();
1620+
if (fallbackName == null || name.compareTo(fallbackName) < 0) {
1621+
fallbackName = name;
1622+
fallback = context;
1623+
}
1624+
}
1625+
return fallback;
15931626
}
15941627

15951628
/** Simple implementation of {@link Context} that cannot handle sub-queries

0 commit comments

Comments
 (0)