This is an automated email from the ASF dual-hosted git repository.
zhenchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new ae47b72804 [CALCITE-7356] The MARK JOIN generated by
TopDownGeneralDecorrelator needs to be adapted to RelFieldTrimmer
ae47b72804 is described below
commit ae47b72804c3946e7349b857ff25ae97443a8f8c
Author: Zhen Chen <[email protected]>
AuthorDate: Tue Jan 20 06:48:23 2026 +0800
[CALCITE-7356] The MARK JOIN generated by TopDownGeneralDecorrelator needs
to be adapted to RelFieldTrimmer
---
.../apache/calcite/sql2rel/RelFieldTrimmer.java | 22 +++++++--
core/src/test/resources/sql/new-decorr.iq | 56 ++++++++++++++++++++++
2 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
index 864ee9d6a0..48cb1f0521 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -836,6 +836,11 @@ public TrimResult trimFields(
Join join,
ImmutableBitSet fieldsUsed,
Set<RelDataTypeField> extraFields) {
+ // If the column "mark" is included, it needs to be excluded first.
+ if (join.getJoinType() == JoinRelType.LEFT_MARK) {
+ int markIndex = join.getRowType().getFieldCount() - 1;
+ fieldsUsed = fieldsUsed.except(ImmutableBitSet.of(markIndex));
+ }
final int fieldCount = join.getSystemFieldList().size()
+ join.getLeft().getRowType().getFieldCount()
+ join.getRight().getRowType().getFieldCount();
@@ -957,17 +962,25 @@ public TrimResult trimFields(
switch (join.getJoinType()) {
case SEMI:
case ANTI:
- // For SemiJoins and AntiJoins only map fields from the left-side
+ case LEFT_MARK:
+ // For SemiJoins, AntiJoins and LeftMarkJoins only map fields from the
left-side.
+ // For LeftMarkJoins, the mark column is also mapped.
if (join.getJoinType() == JoinRelType.SEMI) {
relBuilder.semiJoin(newConditionExpr);
- } else {
+ } else if (join.getJoinType() == JoinRelType.ANTI) {
relBuilder.antiJoin(newConditionExpr);
+ } else {
+ relBuilder.join(join.getJoinType(), newConditionExpr,
join.getVariablesSet());
}
Mapping inputMapping = inputMappings.get(0);
+ int targetCount = newSystemFieldCount + inputMapping.getTargetCount();
+ if (join.getJoinType() == JoinRelType.LEFT_MARK) {
+ targetCount++;
+ }
mapping =
Mappings.create(MappingType.INVERSE_SURJECTION,
join.getRowType().getFieldCount(),
- newSystemFieldCount + inputMapping.getTargetCount());
+ targetCount);
for (int i = 0; i < newSystemFieldCount; ++i) {
mapping.set(i, i);
}
@@ -976,6 +989,9 @@ public TrimResult trimFields(
for (IntPair pair : inputMapping) {
mapping.set(pair.source + offset, pair.target + newOffset);
}
+ if (join.getJoinType() == JoinRelType.LEFT_MARK) {
+ mapping.set(join.getRowType().getFieldCount() - 1, targetCount - 1);
+ }
break;
case ASOF:
case LEFT_ASOF:
diff --git a/core/src/test/resources/sql/new-decorr.iq
b/core/src/test/resources/sql/new-decorr.iq
index 148d4721ac..d329c160ed 100644
--- a/core/src/test/resources/sql/new-decorr.iq
+++ b/core/src/test/resources/sql/new-decorr.iq
@@ -42,4 +42,60 @@ SELECT * FROM t0 WHERE t0a <
!ok
+# [CALCITE-7356] The MARK JOIN generated by TopDownGeneralDecorrelator needs
to be adapted to RelFieldTrimmer
+!use blank
+CREATE TABLE emps (
+ empid INTEGER NOT NULL,
+ deptno INTEGER NOT NULL,
+ name VARCHAR(10) NOT NULL,
+ salary DECIMAL(10, 2) NOT NULL,
+ commission INTEGER);
+(0 rows modified)
+
+!update
+
+INSERT INTO emps (empid, deptno, name, salary, commission) VALUES
+(100, 10, 'Bill', 10000.00, 1000),
+(200, 20, 'Eric', 8000.00, 500),
+(150, 10, 'Sebastian', 7000.00, NULL),
+(110, 10, 'Theodore', 11500.00, 250),
+(170, 30, 'Theodore', 11500.00, 250),
+(140, 10, 'Sebastian', 7000.00, NULL);
+(6 rows modified)
+
+!update
+
+SELECT empid, EXISTS(select * from (
+ SELECT e2.deptno FROM emps e2 where e1.commission = e2.commission) as table3
+ where table3.deptno <> e1.deptno)
+from emps e1 order by empid;
++-------+--------+
+| EMPID | EXPR$1 |
++-------+--------+
+| 100 | false |
+| 110 | true |
+| 140 | false |
+| 150 | false |
+| 170 | true |
+| 200 | false |
++-------+--------+
+(6 rows)
+
+!ok
+
+!if (use_new_decorr) {
+EnumerableSort(sort0=[$0], dir0=[ASC])
+ EnumerableCalc(expr#0..3=[{inputs}], EMPID=[$t0], EXPR$1=[$t3])
+ EnumerableHashJoin(condition=[AND(IS NOT DISTINCT FROM($1, $3), IS NOT
DISTINCT FROM($2, $4))], joinType=[left_mark])
+ EnumerableCalc(expr#0..4=[{inputs}], proj#0..1=[{exprs}],
COMMISSION=[$t4])
+ EnumerableTableScan(table=[[BLANK, EMPS]])
+ EnumerableCalc(expr#0..3=[{inputs}], proj#0..1=[{exprs}])
+ EnumerableHashJoin(condition=[AND(=($1, $3), <>($2, $0))],
joinType=[inner])
+ EnumerableAggregate(group=[{1, 4}])
+ EnumerableTableScan(table=[[BLANK, EMPS]])
+ EnumerableCalc(expr#0..4=[{inputs}], DEPTNO=[$t1], COMMISSION=[$t4])
+ EnumerableTableScan(table=[[BLANK, EMPS]])
+!plan
+!}
+
# End new-decorr.iq