This is an automated email from the ASF dual-hosted git repository.
hongze pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push:
new 5ada462 [CALCITE-2787] Json aggregate calls with different null
clause get incorrectly merged during converting from SQL to relational algebra
5ada462 is described below
commit 5ada462e6f792deee7185ad2df8ec58380061d59
Author: Hongze Zhang <[email protected]>
AuthorDate: Fri Feb 22 22:32:24 2019 +0800
[CALCITE-2787] Json aggregate calls with different null clause get
incorrectly merged during converting from SQL to relational algebra
---
.../calcite/adapter/enumerable/RexImpTable.java | 13 +++-
.../org/apache/calcite/runtime/SqlFunctions.java | 3 +-
.../sql/fun/SqlJsonArrayAggAggFunction.java | 11 +---
.../sql/fun/SqlJsonObjectAggAggFunction.java | 11 +---
.../calcite/sql/fun/SqlStdOperatorTable.java | 6 +-
.../apache/calcite/test/SqlToRelConverterTest.xml | 10 +--
core/src/test/resources/sql/agg.iq | 77 +++++++++++++++++++++-
7 files changed, 100 insertions(+), 31 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index a8112d2..e44af2b 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -44,6 +44,7 @@ import org.apache.calcite.schema.ImplementableFunction;
import org.apache.calcite.schema.impl.AggregateFunctionImpl;
import org.apache.calcite.sql.SqlAggFunction;
import org.apache.calcite.sql.SqlBinaryOperator;
+import org.apache.calcite.sql.SqlJsonConstructorNullClause;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlJsonArrayAggAggFunction;
import org.apache.calcite.sql.fun.SqlJsonObjectAggAggFunction;
@@ -452,13 +453,19 @@ public class RexImpTable {
defineMethod(JSON_VALUE_ANY, BuiltInMethod.JSON_VALUE_ANY.method,
NullPolicy.NONE);
defineMethod(JSON_QUERY, BuiltInMethod.JSON_QUERY.method, NullPolicy.NONE);
defineMethod(JSON_OBJECT, BuiltInMethod.JSON_OBJECT.method,
NullPolicy.NONE);
+ defineMethod(JSON_ARRAY, BuiltInMethod.JSON_ARRAY.method, NullPolicy.NONE);
defineMethod(JSON_TYPE, BuiltInMethod.JSON_TYPE.method, NullPolicy.NONE);
defineMethod(JSON_DEPTH, BuiltInMethod.JSON_DEPTH.method, NullPolicy.NONE);
- aggMap.put(JSON_OBJECTAGG,
+
aggMap.put(JSON_OBJECTAGG.with(SqlJsonConstructorNullClause.ABSENT_ON_NULL),
JsonObjectAggImplementor
.supplierFor(BuiltInMethod.JSON_OBJECTAGG_ADD.method));
- defineMethod(JSON_ARRAY, BuiltInMethod.JSON_ARRAY.method, NullPolicy.NONE);
- aggMap.put(JSON_ARRAYAGG,
+ aggMap.put(JSON_OBJECTAGG.with(SqlJsonConstructorNullClause.NULL_ON_NULL),
+ JsonObjectAggImplementor
+ .supplierFor(BuiltInMethod.JSON_OBJECTAGG_ADD.method));
+ aggMap.put(JSON_ARRAYAGG.with(SqlJsonConstructorNullClause.ABSENT_ON_NULL),
+ JsonArrayAggImplementor
+ .supplierFor(BuiltInMethod.JSON_ARRAYAGG_ADD.method));
+ aggMap.put(JSON_ARRAYAGG.with(SqlJsonConstructorNullClause.NULL_ON_NULL),
JsonArrayAggImplementor
.supplierFor(BuiltInMethod.JSON_ARRAYAGG_ADD.method));
defineImplementor(IS_JSON_VALUE, NullPolicy.NONE,
diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index 2c35aba..fed1d97 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -73,7 +73,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.TimeZone;
@@ -2487,7 +2486,7 @@ public class SqlFunctions {
errorBehavior.toString()).ex();
}
} else {
- return !Objects.isNull(context.pathReturned);
+ return context.pathReturned != null;
}
}
diff --git
a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayAggAggFunction.java
b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayAggAggFunction.java
index 0569bea..6fcbc3f 100644
---
a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayAggAggFunction.java
+++
b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayAggAggFunction.java
@@ -34,7 +34,6 @@ import org.apache.calcite.sql.validate.SqlValidatorImpl;
import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.apache.calcite.util.Optionality;
-import java.util.Locale;
import java.util.Objects;
/**
@@ -43,9 +42,9 @@ import java.util.Objects;
public class SqlJsonArrayAggAggFunction extends SqlAggFunction {
private final SqlJsonConstructorNullClause nullClause;
- public SqlJsonArrayAggAggFunction(String name,
+ public SqlJsonArrayAggAggFunction(SqlKind kind,
SqlJsonConstructorNullClause nullClause) {
- super(name, null, SqlKind.JSON_ARRAYAGG, ReturnTypes.VARCHAR_2000, null,
+ super(kind + "_" + nullClause.name(), null, kind,
ReturnTypes.VARCHAR_2000, null,
OperandTypes.family(SqlTypeFamily.ANY), SqlFunctionCategory.SYSTEM,
false, false, Optionality.OPTIONAL);
this.nullClause = Objects.requireNonNull(nullClause);
@@ -70,10 +69,6 @@ public class SqlJsonArrayAggAggFunction extends
SqlAggFunction {
return validateOperands(validator, scope, call);
}
- @Override public String toString() {
- return getName() + String.format(Locale.ROOT, "<%s>", nullClause);
- }
-
@Override public SqlCall createCall(SqlLiteral functionQualifier,
SqlParserPos pos, SqlNode... operands) {
assert operands.length == 1 || operands.length == 2;
@@ -95,7 +90,7 @@ public class SqlJsonArrayAggAggFunction extends
SqlAggFunction {
public SqlJsonArrayAggAggFunction with(SqlJsonConstructorNullClause
nullClause) {
return this.nullClause == nullClause ? this
- : new SqlJsonArrayAggAggFunction(getName(), nullClause);
+ : new SqlJsonArrayAggAggFunction(getKind(), nullClause);
}
public SqlJsonConstructorNullClause getNullClause() {
diff --git
a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonObjectAggAggFunction.java
b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonObjectAggAggFunction.java
index d8b85c7..3955e0d 100644
---
a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonObjectAggAggFunction.java
+++
b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonObjectAggAggFunction.java
@@ -32,7 +32,6 @@ import org.apache.calcite.sql.validate.SqlValidatorImpl;
import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.apache.calcite.util.Optionality;
-import java.util.Locale;
import java.util.Objects;
/**
@@ -42,9 +41,9 @@ public class SqlJsonObjectAggAggFunction extends
SqlAggFunction {
private final SqlJsonConstructorNullClause nullClause;
/** Creates a SqlJsonObjectAggAggFunction. */
- public SqlJsonObjectAggAggFunction(String name,
+ public SqlJsonObjectAggAggFunction(SqlKind kind,
SqlJsonConstructorNullClause nullClause) {
- super(name, null, SqlKind.JSON_OBJECTAGG, ReturnTypes.VARCHAR_2000, null,
+ super(kind + "_" + nullClause.name(), null, kind,
ReturnTypes.VARCHAR_2000, null,
OperandTypes.family(SqlTypeFamily.CHARACTER, SqlTypeFamily.ANY),
SqlFunctionCategory.SYSTEM, false, false, Optionality.FORBIDDEN);
this.nullClause = Objects.requireNonNull(nullClause);
@@ -72,13 +71,9 @@ public class SqlJsonObjectAggAggFunction extends
SqlAggFunction {
return validateOperands(validator, scope, call);
}
- @Override public String toString() {
- return getName() + String.format(Locale.ROOT, "<%s>", nullClause);
- }
-
public SqlJsonObjectAggAggFunction with(SqlJsonConstructorNullClause
nullClause) {
return this.nullClause == nullClause ? this
- : new SqlJsonObjectAggAggFunction(getName(), nullClause);
+ : new SqlJsonObjectAggAggFunction(getKind(), nullClause);
}
public SqlJsonConstructorNullClause getNullClause() {
diff --git
a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index 2e5b66b..5843835 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -1309,14 +1309,14 @@ public class SqlStdOperatorTable extends
ReflectiveSqlOperatorTable {
public static final SqlFunction JSON_DEPTH = new SqlJsonDepthFunction();
public static final SqlJsonObjectAggAggFunction JSON_OBJECTAGG =
- new SqlJsonObjectAggAggFunction("JSON_OBJECTAGG",
+ new SqlJsonObjectAggAggFunction(SqlKind.JSON_OBJECTAGG,
SqlJsonConstructorNullClause.NULL_ON_NULL);
public static final SqlFunction JSON_ARRAY = new SqlJsonArrayFunction();
public static final SqlJsonArrayAggAggFunction JSON_ARRAYAGG =
- new SqlJsonArrayAggAggFunction("JSON_ARRAYAGG",
- SqlJsonConstructorNullClause.NULL_ON_NULL);
+ new SqlJsonArrayAggAggFunction(SqlKind.JSON_ARRAYAGG,
+ SqlJsonConstructorNullClause.ABSENT_ON_NULL);
public static final SqlBetweenOperator BETWEEN =
new SqlBetweenOperator(
diff --git
a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index 5c670bf..23367d9 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -5369,7 +5369,7 @@ from emp]]>
</Resource>
<Resource name="plan">
<![CDATA[
-LogicalAggregate(group=[{}], EXPR$0=[JSON_ARRAYAGG<ABSENT_ON_NULL>($0)])
+LogicalAggregate(group=[{}], EXPR$0=[JSON_ARRAYAGG_ABSENT_ON_NULL($0)])
LogicalProject($f0=[JSON_STRUCTURED_VALUE_EXPRESSION($1)])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
@@ -5382,7 +5382,7 @@ from emp]]>
</Resource>
<Resource name="plan">
<![CDATA[
-LogicalAggregate(group=[{}], EXPR$0=[JSON_ARRAYAGG<ABSENT_ON_NULL>($0) WITHIN
GROUP ([1])])
+LogicalAggregate(group=[{}], EXPR$0=[JSON_ARRAYAGG_ABSENT_ON_NULL($0) WITHIN
GROUP ([1])])
LogicalProject($f0=[JSON_STRUCTURED_VALUE_EXPRESSION($1)], ENAME=[$1])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
@@ -5395,7 +5395,7 @@ from emp]]>
</Resource>
<Resource name="plan">
<![CDATA[
-LogicalAggregate(group=[{}], EXPR$0=[JSON_ARRAYAGG<NULL_ON_NULL>($0) WITHIN
GROUP ([1])])
+LogicalAggregate(group=[{}], EXPR$0=[JSON_ARRAYAGG_NULL_ON_NULL($0) WITHIN
GROUP ([1])])
LogicalProject($f0=[JSON_STRUCTURED_VALUE_EXPRESSION($1)], ENAME=[$1])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
@@ -5408,7 +5408,7 @@ from emp]]>
</Resource>
<Resource name="plan">
<![CDATA[
-LogicalAggregate(group=[{}], EXPR$0=[JSON_ARRAYAGG<NULL_ON_NULL>($0) WITHIN
GROUP ([1])])
+LogicalAggregate(group=[{}], EXPR$0=[JSON_ARRAYAGG_NULL_ON_NULL($0) WITHIN
GROUP ([1])])
LogicalProject($f0=[JSON_STRUCTURED_VALUE_EXPRESSION($1)], ENAME=[$1])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
@@ -5433,7 +5433,7 @@ from emp]]>
</Resource>
<Resource name="plan">
<![CDATA[
-LogicalAggregate(group=[{}], EXPR$0=[JSON_OBJECTAGG<NULL_ON_NULL>($0, $1)])
+LogicalAggregate(group=[{}], EXPR$0=[JSON_OBJECTAGG_NULL_ON_NULL($0, $1)])
LogicalProject(ENAME=[$1], $f1=[JSON_STRUCTURED_VALUE_EXPRESSION($7)])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
diff --git a/core/src/test/resources/sql/agg.iq
b/core/src/test/resources/sql/agg.iq
index a1b52cd..83dcbca 100644
--- a/core/src/test/resources/sql/agg.iq
+++ b/core/src/test/resources/sql/agg.iq
@@ -2528,7 +2528,6 @@ select deptno, bit_and(empno), bit_or(empno) from
"scott".emp group by deptno;
!ok
# [CALCITE-2266] JSON_OBJECTAGG, JSON_ARRAYAGG
-
!use post
select gender, json_objectagg(ename: deptno absent on null) from emp group by
gender;
@@ -2582,7 +2581,7 @@ from emp group by gender;
(2 rows)
!ok
-EnumerableAggregate(group=[{0}], EXPR$1=[JSON_ARRAYAGG<ABSENT_ON_NULL>($1)
WITHIN GROUP ([2])], EXPR$2=[JSON_ARRAYAGG<ABSENT_ON_NULL>($1) WITHIN GROUP ([2
DESC])])
+EnumerableAggregate(group=[{0}], EXPR$1=[JSON_ARRAYAGG_ABSENT_ON_NULL($1)
WITHIN GROUP ([2])], EXPR$2=[JSON_ARRAYAGG_ABSENT_ON_NULL($1) WITHIN GROUP ([2
DESC])])
EnumerableCalc(expr#0..1=[{inputs}],
expr#2=[JSON_STRUCTURED_VALUE_EXPRESSION($t0)], GENDER=[$t1], $f1=[$t2],
DEPTNO=[$t0])
EnumerableUnion(all=[true])
EnumerableCalc(expr#0=[{inputs}], expr#1=[10], expr#2=['F'],
EXPR$1=[$t1], EXPR$2=[$t2])
@@ -2605,4 +2604,78 @@ EnumerableAggregate(group=[{0}],
EXPR$1=[JSON_ARRAYAGG<ABSENT_ON_NULL>($1) WITHI
EnumerableValues(tuples=[[{ 0 }]])
!plan
+# [CALCITE-2787] Json aggregate calls with different null clause get
incorrectly merged
+# during converting from SQL to relational algebra
+select gender,
+json_arrayagg(deptno),
+json_arrayagg(deptno null on null)
+from emp group by gender;
++--------+------------------+-----------------------+
+| GENDER | EXPR$1 | EXPR$2 |
++--------+------------------+-----------------------+
+| F | [10,30,30,50,60] | [10,30,30,50,60,null] |
+| M | [10,20,50] | [10,20,50] |
++--------+------------------+-----------------------+
+(2 rows)
+
+!ok
+EnumerableAggregate(group=[{0}], EXPR$1=[JSON_ARRAYAGG_ABSENT_ON_NULL($1)],
EXPR$2=[JSON_ARRAYAGG_NULL_ON_NULL($1)])
+ EnumerableCalc(expr#0..1=[{inputs}],
expr#2=[JSON_STRUCTURED_VALUE_EXPRESSION($t0)], GENDER=[$t1], $f1=[$t2])
+ EnumerableUnion(all=[true])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=[10], expr#2=['F'],
EXPR$1=[$t1], EXPR$2=[$t2])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=[10], expr#2=['M'],
EXPR$1=[$t1], EXPR$2=[$t2])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=[20], expr#2=['M'],
EXPR$1=[$t1], EXPR$2=[$t2])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=[30], expr#2=['F'],
EXPR$1=[$t1], EXPR$2=[$t2])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=[30], expr#2=['F'],
EXPR$1=[$t1], EXPR$2=[$t2])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=[50], expr#2=['M'],
EXPR$1=[$t1], EXPR$2=[$t2])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=[50], expr#2=['F'],
EXPR$1=[$t1], EXPR$2=[$t2])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=[60], expr#2=['F'],
EXPR$1=[$t1], EXPR$2=[$t2])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=[null:INTEGER], expr#2=['F'],
EXPR$1=[$t1], EXPR$2=[$t2])
+ EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+select gender,
+json_objectagg(ename: deptno),
+json_objectagg(ename: deptno absent on null)
+from emp group by gender;
++--------+--------------------------------------------------------------------+-------------------------------------------------------+
+| GENDER | EXPR$1
| EXPR$2 |
++--------+--------------------------------------------------------------------+-------------------------------------------------------+
+| F | {"Eve":50,"Grace":60,"Wilma":null,"Susan":30,"Alice":30,"Jane":10}
| {"Eve":50,"Grace":60,"Susan":30,"Alice":30,"Jane":10} |
+| M | {"Adam":50,"Bob":10,"Eric":20}
| {"Adam":50,"Bob":10,"Eric":20} |
++--------+--------------------------------------------------------------------+-------------------------------------------------------+
+(2 rows)
+
+!ok
+EnumerableAggregate(group=[{0}], EXPR$1=[JSON_OBJECTAGG_NULL_ON_NULL($1, $2)],
EXPR$2=[JSON_OBJECTAGG_ABSENT_ON_NULL($1, $2)])
+ EnumerableCalc(expr#0..2=[{inputs}],
expr#3=[JSON_STRUCTURED_VALUE_EXPRESSION($t1)], GENDER=[$t2], ENAME=[$t0],
$f2=[$t3])
+ EnumerableUnion(all=[true])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=['Jane'], expr#2=[10],
expr#3=['F'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=['Bob'], expr#2=[10],
expr#3=['M'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=['Eric'], expr#2=[20],
expr#3=['M'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=['Susan'], expr#2=[30],
expr#3=['F'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=['Alice'], expr#2=[30],
expr#3=['F'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=['Adam'], expr#2=[50],
expr#3=['M'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=['Eve'], expr#2=[50],
expr#3=['F'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=['Grace'], expr#2=[60],
expr#3=['F'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
+ EnumerableValues(tuples=[[{ 0 }]])
+ EnumerableCalc(expr#0=[{inputs}], expr#1=['Wilma'],
expr#2=[null:INTEGER], expr#3=['F'], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t3])
+ EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
# End agg.iq