-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CALCITE-4603] Least restrictive for collections of collections #2413
Conversation
} | ||
if (sqlTypeName == SqlTypeName.MAP) { | ||
RelDataType keyType = leastRestrictive( | ||
Util.transform(types, t -> Objects.requireNonNull(t.getKeyType()))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the impression that, with this code, when trying to calculate an "impossible" leastRestrictive (e.g. between MAP and ARRAY, or MULTISET and VARCHAR), instead of returning null
(as it should per RelDataTypeFactory#leastRestrictive
contract), it would get a NPE.
Maybe this method should add a pre-check to verify that all the types in the list have the "expected" SqlTypeName (either MAP or MULTISET or ARRAY), before going on (and if the pre-check fails, return null
). WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for highlighting this.
Yes it definitely makes sense. The only thing is that it seems that casting from MULTISET
to ARRAY
and vice versa is allowed and even used in JdbcTest
. So I would go with check that either all the types have non null component info or all the types have keytype and valuetype
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just added the changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, seems good.
nitpick:
- I guess with the new code, the
Objects.requireNonNull
in the threeUtil.transform
is not necessary, since the null case has been checked (and early-exited) before. - The
isNullable |= type.isNullable();
computation could be integrated into the new "null key+value/component loop", to just have one "pre-computation loop" instead of two. - If
keyType
isnull
we could just returnnull
without computingvalueType
- You could add
final
tokeyType
,valueType
andtype
variables
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess with the new code, the Objects.requireNonNull in the three Util.transform is not necessary, since the null case has been checked (and early-exited) before.
Checkerframework
says that it is required for Util.transform
to have @NonNull RelDataType
, that's why it still makes sense to have Objects.requireNonNull
there, otherwise ./gradlew
with Objects.requireNonNull
will fail at these lines.
For others makes sense, thanks
I updated the code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason it complains is that RelDataType#getKeyType()
is nullable, while MapSqlType#getKeyType()
is non-nullable.
The checker is not sure if getKeyType()
is guaranteed to return the same value every time.
If you cast t
to MapSqlType
, then it would work without requireNonNull
.
An alternative approaches are:
a) Make leastRestrictive
return null
when null
is among its arguments. Currently leastRestrictive
would fail with NPE
b) Rework leastRestrictive
into builder-like API, so it could indicate to the caller that no more types are needed. The user could instantiate a couple of builders (e.g. key builder, value builder), iterate over the types, and build the common type (e.g. right inside for (RelDataType type: types)
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @vlsi
Do you think it makes to create a separate issue for an alternate approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is up to you :)
A minor note on the current issue: what do you think of splitting leastRestrictiveCollectionType
into leastRestrictiveMapType
and leastRestrictiveArrayType
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, after moving of isNullable |= type.isNullable();
into key+value/component loop such splittiing becomes more logic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
however it would be leastRestrictiveMapType
and leastRestrictiveArrayMultisetType
as the latest one is both for Array
and Multiset
…return null for impossible cases
… keyType is null without calculcation of valueType, use only one pre-computation loop
…tiveMapType and leastRestrictiveArrayMultisetType
LGTM |
core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java
Outdated
Show resolved
Hide resolved
…oryImpl.java Co-authored-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
The PR implements least restrictive for collection of collections for instance
and others mentioned in CALCITE-4603