-
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-5918] Add MAP function (enabled in Spark library) #3459
Conversation
e592b6c
to
752772f
Compare
return SqlStdOperatorTable.MAP_QUERY.createCall(s.end(this), args.get(0)); | ||
} else { | ||
// MAP function e.g. "MAP(1, 2)" equivalent to standard "MAP[1, 2]" | ||
return SqlLibraryOperators.MAP.createCall(s.end(this), args.getList()); |
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 think we can check if the size of args is an even number.
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 hope to retain the original parser logic here, because it will be detected later on OperandTypeChecker. And here is similar with spark's array handling and calcite array constructor. pls see: https://github.com/apache/calcite/pull/3141/files
Another benefit is that we can use some more human-readable error messages in predefined CalciteResource.
a993e1e
to
184d3f4
Compare
@@ -873,6 +874,7 @@ Builder populate2() { | |||
map.put(MAP_VALUE_CONSTRUCTOR, value); | |||
map.put(ARRAY_VALUE_CONSTRUCTOR, value); | |||
defineMethod(ARRAY, BuiltInMethod.ARRAYS_AS_LIST.method, NullPolicy.NONE); | |||
defineMethod(MAP, BuiltInMethod.MAP_FUNCTION.method, NullPolicy.NONE); |
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.
should we call it just MAP to be consistent with other functions?
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.
In fact, there is a MAP object in BuiltInMethod, occupy this name. but yes, if we rename that, we can use MAP. I have updated it.
@@ -5251,6 +5251,17 @@ public static Map mapFromArrays(List keysArray, List valuesArray) { | |||
return map; | |||
} | |||
|
|||
/** Support the MAP function. */ | |||
public static Map mapFunction(Object... args) { |
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.
same comment as above
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.
fixed.
core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
Outdated
Show resolved
Hide resolved
core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
Outdated
Show resolved
Hide resolved
@@ -568,6 +569,9 @@ public static SqlOperandTypeChecker variadic( | |||
public static final SqlSingleOperandTypeChecker MAP_FROM_ENTRIES = | |||
new MapFromEntriesOperandTypeChecker(); | |||
|
|||
public static final SqlSingleOperandTypeChecker MAP_FUNCTION = |
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.
same naming comment as above
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.
fixed.
core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
Outdated
Show resolved
Hide resolved
RelDataTypeFactory typeFactory, | ||
List<RelDataType> argTypes) { | ||
return Pair.of( | ||
typeFactory.leastRestrictive(Util.quotientList(argTypes, 2, 0)), |
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.
Where are these constants coming from and what do they signify?
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.
Util.quotientList(argTypes, 2, 0):
This extracts all elements at even indices from argTypes.
It represents the types of keys in the map as they are placed at even positions
e.g. 0, 2, 4, etc. details please see Util.quotientList.
std MapValueConstructor has same logic. see:
calcite/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
Line 90 in 5151168
typeFactory.leastRestrictive(Util.quotientList(argTypes, 2, 0)), |
I've added some comments here for better readability.
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.
Can we add UT for typeFactory.leastRestrictive
?
How about?
MAP('k1', 1, 'k2', 2.0, 'k3', '3')
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.
Can we add UT for
typeFactory.leastRestrictive
?How about?
MAP('k1', 1, 'k2', 2.0, 'k3', '3')
yes, added it. thanks for reviewing.
testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
Outdated
Show resolved
Hide resolved
184d3f4
to
03993a9
Compare
hi, @tanclary I have solved the comments and updated the PR. btw, I have rebased the main to use CALCITE-5570, I hope it won’t cause any trouble to your review. |
03993a9
to
3ae9c56
Compare
hi, @tanclary Sorry to pin you, I have solved the comments. could you help to re-check it? |
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 think this looks pretty good. Left one naming comment
@@ -97,7 +97,7 @@ public <T> RelNode translate(Queryable<T> queryable) { | |||
public RelNode translate(Expression expression) { | |||
if (expression instanceof MethodCallExpression) { | |||
final MethodCallExpression call = (MethodCallExpression) expression; | |||
BuiltInMethod method = BuiltInMethod.MAP.get(call.method); | |||
BuiltInMethod method = BuiltInMethod.FUNCTIONS_MAPS.get(call.method); |
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.
why call it FUNCTIONS_MAPS
?
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.
because this is a static field in BuiltInMethod
to store all the methods. it occupy 'MAP' name before, so I can't continue to use this name as our spark map method name, so i changed it, then we can use 'MAP' as method name as you suggested for consistency in naming. (I set 'MAP_FUNCTION' in BuiltInMethod
previously).
one disadvantage I can think of here is that it may cause compatibility issues? If there is an upper-layer application/engine use java reflection to call this field. But is this as expected?
I'm ok if we need to reset spark MAP method to 'MAP_FUNCTION' name in BuiltInMethod
and keep here unchanged. @tanclary what do you think?
1b9531e
to
84e97c1
Compare
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 think this looks good, you might find some of the sonarcloud reports helpful, it looks like they have some suggestions on refactoring the for
loops and providing types for the generic Map
, not sure how feasible these are in your case but you can just check and see if any of them prove useful.
Thanks for the reminder. I checked sonar report and problems are roughly divided into three categories:
I have modified 1, but 2 and 3 actually not applicable for us. 2: The methods of 3: is something like "CHAR(10) NOT NULL", there are multiple checkScalar, sonar wants us to define a variable and reuse it. In fact, it is not necessary. The current way of writing is more intuitive. If you agree with these, I will squash the commits. 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.
LGTM, think there might be some checkstyle issues but feel free to squash and ping me after!
97435b7
to
feb95fc
Compare
thank you all for patient reviewing! all comments are resolved. @tanclary Thanks for approve! could you help to merge it? so we can add it in up-coming 1.36. |
feb95fc
to
73ea5c7
Compare
Kudos, SonarCloud Quality Gate passed! |
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.
LGTM, sorry for the delay! Congrats on becoming a committer!
thanks tanner. you helped me to a lot. :) |
https://issues.apache.org/jira/browse/CALCITE-5918
the spark map function has 2 different points with calcite map constructor: