Xuyang Zhong created CALCITE-7431:
-------------------------------------
Summary: RelTraitSet#getTrait seems to mishandle RelCompositeTrait
Key: CALCITE-7431
URL: https://issues.apache.org/jira/browse/CALCITE-7431
Project: Calcite
Issue Type: Bug
Components: core
Affects Versions: 1.41.0
Reporter: Xuyang Zhong
Below is my test and an exception will be thrown:
{code:java}
RelBuilder b = RelBuilder.create(RelBuilderTest.config().build());
RelNode in = b
.scan("EMP")
.sort(3) // MGR asc
.project(b.field(3), b.alias(b.field(3), "MGR2")) // MGR, MGR as MGR2
.build();
// the following 3 line will all be failed
System.err.println(in.getTraitSet().getCollation());
System.err.println(in.getTraitSet().getCollations());
System.err.println((RelCollation)
in.getTraitSet().getTrait(RelCollationTraitDef.INSTANCE));
// the exception:
java.lang.ClassCastException: org.apache.calcite.plan.RelCompositeTrait cannot
be cast to org.apache.calcite.rel.RelCollation{code}
The reason is that at `{{{}return (T) getTrait(index);{}}}` in
`RelTraitSet#getTrait`. The trait we actually get is a
`{{{}RelCompositeTrait`{}}}, but it is cast to `{{{}RelCollation`{}}}, which
leads to a Java cast error.
I’m not sure whether this is by design: Callers of
`{{{}RelTraitSet#getTrait`{}}} have to be aware that the input trait may have
multiple values (`{{{}RelMultipleTrait`{}}}), and therefore should use
`{{{}#getTraits`{}}} instead. From my perspective, relying on callers to be
aware of this is not ideal. At the very least, `{{{}#getTrait{}}}` should
validate whether the trait is a `{{{}RelMultipleTrait{}}}` and explicitly
indicate that `{{{}#getTraits`{}}} should be used instead.
I encountered this issue because for the SQL below, in older versions,
`{{{}FilterProjectTransposeRule#Line187`{}}} would throw this error. Although
it was fixed in
[https://github.com/apache/calcite/pull/4704/changes#r2644415395], I found that
there still seem to be many places that call `{{{}#getTrait`{}}}
incorrectly—for example, `{{{}#getCollation()`{}}}, `{{{}#getCollations()`{}}},
and the handling of `{{{}RelDistribution`{}}}.
{code:java}
SELECT
*
FROM (
SELECT
task_status, task_status + 1
FROM ods_htg__prod_shop_govern_task__task
WHERE
task_date >= '2026-02-01' AND task_date < '2026-02-01'
-- this will convert the source to empty value source,
-- and empty value source will output multi collations
)
WHERE
task_status > 10 {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)