[
https://issues.apache.org/jira/browse/CALCITE-4995?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17484634#comment-17484634
]
Ruben Q L commented on CALCITE-4995:
------------------------------------
Problem can be reproduced with the following test (to be added in
{{RelFieldTrimmerTest.java}}):
{code}
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-4995">[CALCITE-4995]
* AssertionError caused by RelFieldTrimmer on SEMI/ANTI join</a>. */
@Test void testSemiJoinAntiJoinFieldTrimmer() {
for (final JoinRelType joinType : new JoinRelType[]{JoinRelType.ANTI,
JoinRelType.SEMI}) {
final RelBuilder builder = RelBuilder.create(config().build());
final RelNode root = builder
.values(new String[]{"id"}, 1, 2).as("a")
.values(new String[]{"id"}, 2, 3).as("b")
.join(joinType,
builder.equals(
builder.field(2, "a", "id"),
builder.field(2, "b", "id")))
.values(new String[]{"id"}, 0, 2).as("c")
.join(joinType,
builder.equals(
builder.field(2, "a", "id"),
builder.field(2, "c", "id")))
.build();
final RelFieldTrimmer fieldTrimmer = new RelFieldTrimmer(null, builder);
final RelNode trimmed = fieldTrimmer.trim(root);
final String expected = ""
+ "LogicalJoin(condition=[=($0, $1)], joinType=[" +
joinType.lowerName + "])\n"
+ " LogicalJoin(condition=[=($0, $1)], joinType=[" +
joinType.lowerName + "])\n"
+ " LogicalValues(tuples=[[{ 1 }, { 2 }]])\n"
+ " LogicalValues(tuples=[[{ 2 }, { 3 }]])\n"
+ " LogicalValues(tuples=[[{ 0 }, { 2 }]])\n";
assertThat(trimmed, hasTree(expected));
}
}
{code}
> AssertionError caused by RelFieldTrimmer on SEMI/ANTI join
> ----------------------------------------------------------
>
> Key: CALCITE-4995
> URL: https://issues.apache.org/jira/browse/CALCITE-4995
> Project: Calcite
> Issue Type: Bug
> Components: core
> Affects Versions: 1.29.0
> Reporter: Ruben Q L
> Assignee: Ruben Q L
> Priority: Major
>
> It seems {{RelFieldTrimmer}} can cause an {{AssertionError}} (or later an
> {{ArrayIndexOutOfBoundsException}} if assertions are disabled) on certain
> plans involving SEMI/ANTI join (i.e. joins that do NOT project the RHS
> fields).
> The root cause seems to be the "early return" in
> {{RelFieldTrimmer#trimFields(Join join, ImmutableBitSet fieldsUsed,
> Set<RelDataTypeField> extraFields)}} when nothing has been trimmed inside
> join's inputs (so the join itself can be return as it is):
> {code:java}
> if (changeCount == 0
> && mapping.isIdentity()) {
> return result(join, Mappings.createIdentity(fieldCount));
> }
> {code}
> The problem is that this {{fieldCount}} is an addition of LHS + RHS fields (+
> system fields); but in case of a SEMI/ANTI the mappings to be returned must
> not consider RHS fields (since they are not projected by these join types).
> The problem only happens here (when the trimmer does not trim the join).
> Notice that, a few lines below, in the "other return scenario" of the method
> (when something has been trimmed), there is a special treatment of the
> mapping for ANTI/SEMI, so things will work fine in this case:
> {code:java}
> switch (join.getJoinType()) {
> case SEMI:
> case ANTI:
> // For SemiJoins and AntiJoins only map fields from the left-side
> if (join.getJoinType() == JoinRelType.SEMI) {
> relBuilder.semiJoin(newConditionExpr);
> } else {
> relBuilder.antiJoin(newConditionExpr);
> }
> Mapping inputMapping = inputMappings.get(0);
> mapping = Mappings.create(MappingType.INVERSE_SURJECTION,
> join.getRowType().getFieldCount(),
> newSystemFieldCount + inputMapping.getTargetCount());
> for (int i = 0; i < newSystemFieldCount; ++i) {
> mapping.set(i, i);
> }
> offset = systemFieldCount;
> newOffset = newSystemFieldCount;
> for (IntPair pair : inputMapping) {
> mapping.set(pair.source + offset, pair.target + newOffset);
> }
> break;
> default:
> relBuilder.join(join.getJoinType(), newConditionExpr);
> }
> relBuilder.hints(join.getHints());
> return result(relBuilder.build(), mapping);
> {code}
--
This message was sent by Atlassian Jira
(v8.20.1#820001)