[ 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)