This is an automated email from the ASF dual-hosted git repository.
libenchao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new c83ac69111 [CALCITE-6040] The operand type inference of
SqlMapValueConstructor is incorrect
c83ac69111 is described below
commit c83ac69111fd9e75af5e3615af29a72284667a4a
Author: Ran Tao <[email protected]>
AuthorDate: Thu Oct 12 16:19:27 2023 +0800
[CALCITE-6040] The operand type inference of SqlMapValueConstructor is
incorrect
---
.../calcite/sql/fun/SqlMapValueConstructor.java | 3 ++-
.../sql/fun/SqlMultisetValueConstructor.java | 9 ++++++++-
core/src/test/resources/sql/misc.iq | 16 ++++++++++++++++
.../org/apache/calcite/test/SqlOperatorTest.java | 21 +++++++++++++++++++++
4 files changed, 47 insertions(+), 2 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
b/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
index 7f3da3bdb2..a497471200 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
@@ -42,7 +42,8 @@ import static java.util.Objects.requireNonNull;
*/
public class SqlMapValueConstructor extends SqlMultisetValueConstructor {
public SqlMapValueConstructor() {
- super("MAP", SqlKind.MAP_VALUE_CONSTRUCTOR);
+ // no need to deduce NULL operand type
+ super("MAP", SqlKind.MAP_VALUE_CONSTRUCTOR, null);
}
@SuppressWarnings("argument.type.incompatible")
diff --git
a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
index 8efd45a3eb..acbafc97e0 100644
---
a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
+++
b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
@@ -28,6 +28,7 @@ import org.apache.calcite.sql.SqlWriter;
import org.apache.calcite.sql.type.InferTypes;
import org.apache.calcite.sql.type.OperandTypes;
import org.apache.calcite.sql.type.ReturnTypes;
+import org.apache.calcite.sql.type.SqlOperandTypeInference;
import org.apache.calcite.sql.type.SqlTypeUtil;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -54,12 +55,18 @@ public class SqlMultisetValueConstructor extends
SqlSpecialOperator {
}
protected SqlMultisetValueConstructor(String name, SqlKind kind) {
+ this(name, kind, InferTypes.FIRST_KNOWN);
+ }
+
+ protected SqlMultisetValueConstructor(
+ String name, SqlKind kind,
+ @Nullable SqlOperandTypeInference operandTypeInference) {
super(
name,
kind, MDX_PRECEDENCE,
false,
ReturnTypes.ARG0,
- InferTypes.FIRST_KNOWN,
+ operandTypeInference,
OperandTypes.VARIADIC);
}
diff --git a/core/src/test/resources/sql/misc.iq
b/core/src/test/resources/sql/misc.iq
index 8bdb345b22..74ee82abb8 100644
--- a/core/src/test/resources/sql/misc.iq
+++ b/core/src/test/resources/sql/misc.iq
@@ -2602,4 +2602,20 @@ FROM (
(1 row)
!ok
+
+# [CALCITE-6040] The operand type inference of SqlMapValueConstructor is
incorrect
+SELECT
+ map['foo', null],
+ map[null, 'foo'],
+ map[1, 'foo', 2, null],
+ map[1, null, 2, 'foo'];
++------------+------------+-----------------+-----------------+
+| EXPR$0 | EXPR$1 | EXPR$2 | EXPR$3 |
++------------+------------+-----------------+-----------------+
+| {foo=null} | {null=foo} | {1=foo, 2=null} | {1=null, 2=foo} |
++------------+------------+-----------------+-----------------+
+(1 row)
+
+!ok
+
# End misc.iq
diff --git a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
index fd11a31f05..bfc14daab7 100644
--- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
+++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
@@ -10442,6 +10442,27 @@ public class SqlOperatorTest {
f.checkScalar("map['washington', 1, 'obama', 44]",
"{washington=1, obama =44}",
"(CHAR(10) NOT NULL, INTEGER NOT NULL) MAP NOT NULL");
+
+ // check null key or null value
+ f.checkScalar("map['foo', null]",
+ "{foo=null}",
+ "(CHAR(3) NOT NULL, NULL) MAP NOT NULL");
+ f.checkScalar("map[null, 'foo']",
+ "{null=foo}",
+ "(NULL, CHAR(3) NOT NULL) MAP NOT NULL");
+ f.checkScalar("map[1, 'foo', 2, null]",
+ "{1=foo, 2=null}",
+ "(INTEGER NOT NULL, CHAR(3)) MAP NOT NULL");
+ f.checkScalar("map[1, null, 2, 'foo']",
+ "{1=null, 2=foo}",
+ "(INTEGER NOT NULL, CHAR(3)) MAP NOT NULL");
+ f.checkScalar("map[1, null, 2, null]",
+ "{1=null, 2=null}",
+ "(INTEGER NOT NULL, NULL) MAP NOT NULL");
+ f.checkScalar("map[null, 1, null, 2]",
+ "{null=2}",
+ "(NULL, INTEGER NOT NULL) MAP NOT NULL");
+
// elements cast
f.checkScalar("map['A', 1, 'ABC', 2]", "{A =1, ABC=2}",
"(CHAR(3) NOT NULL, INTEGER NOT NULL) MAP NOT NULL");