Thanks, Konstantin.

I have logged https://issues.apache.org/jira/browse/CALCITE-4597 to make the 
policy configurable. Eventually I would like to allow empty row types 
throughout the system, but until then, rules and RelFieldTrimmer should follow 
Postel’s law [1] and accept empty row types but try not to produce them.

Julian

[1] https://en.wikipedia.org/wiki/Robustness_principle

> On May 5, 2021, at 12:51 AM, Konstantin Orlov <kor...@gridgain.com> wrote:
> 
>> Konstantin, can you log it, please
> 
> Yes, sure. Here it is [1]
> 
> [1] https://issues.apache.org/jira/browse/CALCITE-4596 
> <https://issues.apache.org/jira/browse/CALCITE-4596>
> 
> -- 
> Regards,
> Konstantin Orlov
> 
> 
> 
>> On 4 May 2021, at 21:29, Julian Hyde <jh...@apache.org> wrote:
>> 
>> Regardless of which direction we go (allowing zero-field record types, or 
>> disallowing them), Konstantin has found a bug. Konstantin, can you log it, 
>> please.
>> 
>> On 2021/04/29 14:25:27, Konstantin Orlov <kor...@gridgain.com> wrote: 
>>> Hi all.
>>> 
>>> I faced a problem preventing certain queries being planned because 
>>> RelFieldTrimmer throws 
>>> an ArrayIndexOutOfBoundsException with message "Index -1 out of bounds for 
>>> length 0”.
>>> 
>>> The problem is here [1]:
>>> 
>>>   // If they are asking for no fields, we can't give them what they want,
>>>   // because zero-column records are illegal. Give them the last field,
>>>   // which is unlikely to be a system field.
>>>   if (fieldsUsed.isEmpty()) {
>>>     fieldsUsed = ImmutableBitSet.range(fieldCount - 1, fieldCount);
>>>   }
>>> 
>>> In case fieldsUsed.isEmpty we returns last field, but it is currently 
>>> possible that fieldCount=0 as well.  
>>> 
>>> After some investigation I find out that the reason is empty record derived 
>>> as row type for Aggregate.
>>> It is possible when an aggregate has an empty group key and no aggregate 
>>> calls.
>>> 
>>> So the question is whether an empty record is a legal row type for an 
>>> aggregation node?
>>> 
>>> Below is a reproducer for this problem, just put it at RelFieldTrimmerTest:
>>> 
>>> @Test void test() {
>>>   class ContextImpl implements Context {
>>>     final Object target;
>>> 
>>>     ContextImpl(Object target) {
>>>       this.target = Objects.requireNonNull(target, "target");
>>>     }
>>> 
>>>     @Override public <T extends Object> @Nullable T unwrap(Class<T> clazz) {
>>>       if (clazz.isInstance(target)) {
>>>         return clazz.cast(target);
>>>       }
>>>       return null;
>>>     }
>>>   }
>>> 
>>>   // RelBuilder hides problem when simplifyValues=true, hence we need to 
>>> disable it
>>>   final RelBuilder builder = RelBuilder.create(config()
>>>       .context(new 
>>> ContextImpl(RelBuilder.Config.DEFAULT.withSimplifyValues(false))).build());
>>> 
>>>   final RelNode root =
>>>       builder.scan("EMP")
>>>           .aggregate(builder.groupKey())
>>>           .filter(builder.literal(false))
>>>           .project(builder.literal(42))
>>>           .build();
>>> 
>>>   final RelFieldTrimmer fieldTrimmer = new RelFieldTrimmer(null, builder);
>>>   fieldTrimmer.trim(root); // fails with ArrayIndexOutOfBoundsException: 
>>> Index -1 out of bounds for length 0
>>> }
>>> 
>>> 
>>> [1] 
>>> https://github.com/apache/calcite/blob/master/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java#L1197
>>> 
>>> -- 
>>> Regards,
>>> Konstantin Orlov
>>> 
>>> 
>>> 
>>> 
>>> 
> 

Reply via email to